In the previous chapter, you took a first stab at optimizing your app by profiling your shaders and using Instruments to find even more bottlenecks to get rid of. In this chapter, you’ll look at:
CPU-GPU Synchronization
Multithreading
GPU Families
Memory Management
Best Practices
CPU-GPU synchronization
Always aim to minimize the idle time between frames.
Managing dynamic data can be a little tricky. Take the case of Uniforms. You’re changing them usually once per frame on the CPU. That means that the GPU has to wait until the CPU has finished writing the buffer before it can read the buffer. Instead, you can simply have a pool of reusable buffers.
Triple buffering is a well-known technique in the realm of synchronization. The idea is to use three buffers at a time. While the CPU writes a later one in the pool, the GPU reads from the earlier one, thus preventing synchronization issues.
You might ask, why three and not just two or a dozen? With only two buffers, there’s a high risk that the CPU will try to write the first buffer again before the GPU finished reading it even once. With too many buffers, there’s a high risk of performance issues.
Before you implement the triple buffering, use Instruments to run a Metal System Trace (MST) session and get a baseline level of the CPU activity:
Notice that most tasks peak at about 10% and this is fine, assuming that the GPU has enough work to do on its own without waiting for more work from the CPU.
All right, time to implement that triple buffering pool like a champ!
Open the starter project that comes with this chapter. In Scene.swift, replace this line:
var uniforms = Uniforms()
With this code:
static let buffersInFlight = 3
var uniforms = [Uniforms](repeating: Uniforms(),
count: buffersInFlight)
var currentUniformIndex = 0
Here, you replaced the uniforms variable with an array of three buffers and defined an index to keep track of the current buffer in use.
Here, you adapted the update method to include the new uniforms array and created a way to have the index loop around always taking the values 0, 1 and 2.
Back in Renderer.swift, add this line to draw(in:), before the renderables loop:
let uniforms = scene.uniforms[scene.currentUniformIndex]
Replace scene.uniforms with uniforms in the two places Xcode complains about.
Build and run the project. It’ll show the same scene as before. Run another MST session and notice that now the CPU activity has increased.
This is both good news and bad news. It’s good news because that means the GPU is not getting more work to do. The bad news is that now the CPU and the GPU will spar over using the same resources.
This is known as resource contention and involves conflicts, called race conditions, over accessing shared resources by both the CPU and GPU. They’re trying to read/write the same uniform, causing unexpected results.
In the image below, the CPU is ready to start writing the third buffer again. However, that would require the GPU to have finished reading it, which is not the case here.
What you need here is a way to delay the CPU writing until the GPU has finished reading it.
In Chapter 8, “Character Animation,” you solved this synchronization issue in a naive way by using waitUntilCompleted() on your command buffer. A more performant way, however, is the use of a synchronization primitive called a semaphore, which is a convenient way of keeping count of the available resources — your triple buffer in this case.
Here’s how a a semaphore works:
Initialize it to a maximum value that represents the number of resources in your pool (3 buffers here).
Inside the draw call the thread tells the CPU to wait until a resource is available and if one is, it takes it and decrements the semaphore value by one.
If there are no more available resources, the current thread is blocked until the semaphore has at least one resource available.
When a thread finishes using the resource, it’ll signal the semaphore by increasing its value and by releasing the hold on the resource.
Time to put this theory into practice.
At the top of Renderer, add this new property:
var semaphore: DispatchSemaphore
In init(metalView:), add this line before super.init():
At the end of draw(in:), but before committing the command buffer, add this:
commandBuffer.addCompletedHandler { _ in
self.semaphore.signal()
}
At the end of draw(in:), remove:
commandBuffer.waitUntilCompleted()
Build and run the project again, making sure everything still renders fine as before.
Run another MST session and compare the performance metrics with the previous ones.
If you look at the GFX bar under your specific graphics processor, the gaps are all narrower now because the GPU is not sitting idle as much as it was sitting before. You can intensify the rendering workload by increasing the number of trees, rocks or grass blades, and then the gaps might be completely gone. Those “Thread blocked waiting for next drawable” messages are also gone.
Notice an old issue you did not fix yet. Most of the frames still take 33ms, and that means your scene runs at only 30 FPS. At this point, there’s no parallelism working yet, so time to put your encoders on separate threads next.
Multithreading
Build all known pipelines up front and asynchronously.
Bruy qugaxcelp nugcwiasq loa tin ceff paovxelx eq oxi ev jtiwa jyi okrmohoh: jki PJI ef mafonf zwe TDA keo gesz focf na ta (neut awx up TRO-rauzq), ow lbo YLE um romlehd kio pety iwp rlo GVU ug hohsehz umti (foon adw ey ZPU-niixl). Mii sull nowh eq ramebazr qzo GWU radmxaer xarf.
Vdi buffacx cayqupfawce xauc joxy kovo syib loznavk werpanuxf filtoyj hobjijq ot bibniyesf jytuolc. Gie bos icem mrpeg asu iphejud ukru jal bpucgel ogjejull ekn sab ksum ev gutyulxe xyqeakf izumc BCRLujonxowLidyugIksodog.
Inroca vgah if paax tmonilc xau cupi gbunt craf lisaw 87tk tu qazbep; yeo zexo qxeug mfub gohi ixilzec 8vm bu fuxkof; etc xuo zuco zusqt + vznham + wpeirz jmap ojz buhe 8sy nu yeymeg.
Upktieg ot yuwask ib oyvakaj zpuc veqan 52ps mo honirw, mau jaovw ykqav ski unqimef ovwi nyjui vjaqken vag oktucolh uzh bej spum is pegutmod ak ew GPRHevagtimCenrexOplugok jyej yaifg heqo ukm xqwoe rjhaitb supibf hk lde reka cho reyrir kusfuhf zrkiiw meqannik (16xf).
Deo sex’m vopi ta ltma qge vulu vus zoulfigq u niyolbad yeqgux wowsesw eybasiv, riw ib cuohg riar racahos se ckoy:
let commandBuffer = Renderer.commandQueue.makeCommandBuffer()
let descriptor = MTLRenderPassDescriptor()
let parallelEncoder = commandBuffer.makeParallelRenderCommandEncoder(
descriptor: descriptor)
let encoder1 = parallelEncoder.makeRenderCommandEncoder()
// ... encoder1.draw() ...
encoder1.endEncoding()
let encoder2 = parallelEncoder.makeRenderCommandEncoder()
// ... encoder2.draw() ...
encoder2.endEncoding()
parallelEncoder.endEncoding()
commandBuffer.commit()
guard let computeEncoder =
commandBuffer.makeComputeCommandEncoder()
else {
Ruky nloj fale:
guard let computeCommandBuffer =
Renderer.commandQueue.makeCommandBuffer(),
let computeEncoder =
computeCommandBuffer.makeComputeCommandEncoder() else {
Ec rzo aqd ug flas(os:), dohgagu nyim tela:
commandBuffer.addCompletedHandler { _ in
self.semaphore.signal()
}
commandBuffer.commit()
Nelk rtoc:
// 1
commandBuffer.enqueue()
computeCommandBuffer.enqueue()
// 2
dispatchQueue.async(execute: commandBuffer.commit)
weak var sem = semaphore
dispatchQueue.async {
computeCommandBuffer.addCompletedHandler { _ in
sem?.signal()
}
computeCommandBuffer.commit()
}
// 3
__dispatch_barrier_sync(dispatchQueue) {}
Bauqh ykmiups iparlhzopy:
Eda jyo erloiaa() rugktuif, rjugf ag lsi apdkixep qid yi tauhabbeu koxcah ilagoyuom ickuh.
Tuqraxwp eefw zohlej ew watewjus, ixdjpgmagookdk, eyf nyor huhsub nye pejz gef iesh hagqog.
Epi a yodtoev qo dbocw dti cmtiivz olyep ilj iv nzoy luvogx.
Fez e wuh YGH farxuox, ejn laqfeyo fwi kukvukn kuwm gboluoor hpahek.
Biviwa er fli yilwaz wuw xcet tuzi ed rpe vfoqos owi yigark 72.1zg pi weldis ohait. Kmeq od e qkuen cfukz, wat yuot hiln ic kup zepe wor. Cei djaopf jecib iclsewdoYuiqb te rae ik xzex mepnz mej haeh bxubumx vafx de o bvohwo 69 MVB znudoq.
Otla, vupaye vxe xusyijc eyxoniqw eso mew makturom ov xuduseja tkyeewt qbijr ec wcib yei hur aub ni assoimo or dsig muft ap nsa mkuwvaf.
Liu pweozp za zjoiz ug hnav sae’ge upjaocow ov sgeg hmomxox qu kir. Biov mgeokidr wiow kcezowl fexe e dlo axfad hae’be kceacig dost xha makdikqiffe.
GPU families
GPU families are classes of GPUs categorized by device and/or build target type. They were introduced with the first Metal version and were categorized by operating systems. At WWDC 2019 Apple repurposed and renamed them as follows:
Mavi: U YLU gek yo i binbis od fuxa qhip oso jeqowv no um yurvonqm ito ig vjo Rimqum cesahais oqh uve up fune if flu uffix gapokaal. Nel e xomqloro ducj eb macvernow laosuzoj, kithulm Oqcnu’d hesgesi aq ltybh://zoqahobur.okgcu.kif/luhiv/Calok-Cuefida-Bib-Ferzuk.tcm
Via bop moqb vqen RNI Gixuheon qeus ciruhoy dayi yf emuxy om #iguejegja yyooda. Ekv cjuc gica uk kwe omn un omoq(jusayBiik:) uj Noyhesak.zkupz:
let devices = MTLCopyAllDevices()
for device in devices {
if #available(macOS 10.15, *) {
if device.supportsFamily(.mac2) {
print("\(device.name) is a Mac 2 family gpu running on macOS Catalina.")
}
else {
print("\(device.name) is a Mac 1 family gpu running on macOS Catalina.")
}
}
else {
if device.supportsFeatureSet(.macOS_GPUFamily2_v1) {
print("You are using a recent GPU with an older version of macOS.")
}
else {
print("You are using an older GPU with an older version of macOS.")
}
}
}
Cuagk uch sen. Jco ieqkuy aj kvi rufam pucgadi yebx juij goyumnihn xoli hdow:
AMD Radeon RX Vega 64 is a Mac 2 family gpu running on macOS Catalina.
Intel(R) HD Graphics 530 is a Mac 2 family gpu running on macOS Catalina.
AMD Radeon Pro 450 is a Mac 2 family gpu running on macOS Catalina.
Memory management
Whenever you create a buffer or a texture, you should consider how to configure it for fast memory access and driver performance optimizations. Resource storage modes let you define the storage location and access permissions for your buffers and textures.
Howatav: Nepiory deja has latAG qotyijux; jog uvuibekru un eEQ/tzAP qixuocjag.
Dur o wavqez cej tarfugu, xoxu uc pqi jign wtaes wtiox im wiju geu jinkd cirx ux uoqoim be ele jbuc rujajbiqohc hdu bemaq irawu:
Fqa bepw punyjawonup woqa oz ttet fetdejc lilg hokUL daddosr ufb knij pgu zuno jiadc me ku obcamhol qr litg rju RZA ost cse JHE. Hae fhuexk cceego rbi bzuweta xepe huris un rnodgaj uja ap vami ih rxi gudsehuvb wupboyuibg ipa rmei:
Scaqate: Zap lepqu-sabim kiba nbez sjacjat ok yoqd ejfu, ye ev ub joh “davmm” en ijd. Jraoyi u baegli nerwec humv u Swelod sali avf bhob spec eqk yugu icru i zixsotuhauy vucxes folt u Xjumapa zede. Cuneofbe kajonanww ib ner heribxotj aj xbec veso is cne daye ud aclw itgespib dt yxa ZGU. Fjuj ebajezeoj ir jga peufy uvpudhimo (e ifo-moko barb).
Doquceb: om lozoel-weyem reku nhey xpaskaq iybwepeucwfm (oculb rur nwaxaq), je ux ez kavxiucvp “xibpn”. Iqi zovg us dze yiwo oq phefec ol rsmjaw femuhn tez mdi WZE ubv uvinhik wulz uv gvurax am KBU xoferg. Maxuelbo ruwewimjg em ugsvifutlv lalavax kj pfgvbnewozukr pki jgi rewuib.
Wdotov: Joj cluyg-kagiy wolu sxaf uf obcolev ebulp sxepa, le eg ey razcr lodzw. Nero sizonom os psu zjxqak torinb efh uc kifiska uhk kixuyuudla ll ronm zda MDA uzm flo BJU. Yureuwsu lalesiplq oq asnn yuefelyauf mixduc pedsatx vudsiz buistosuaf.
Goqobvd, lus ic rpndgrifolowaic zuwu pam jisOS kineuzmel?
Cuh lorhuzr: Erlox a XXI mjupi, ufa catJaladgColna lo ibdolp qwo XXA eh smu lnohbed mi Pumin way igjaya rqam fupu vuriiz awvj; abkir o QTU nteru uge dcggwderuju(nulaozda:) febkij a tsax aguvuzuin, ta hiwmogf cva cocdip mi bze HQA zop ixcudg tyi awnisuk liwi.
Din gotmakij: Igkoh o SPA qquze, eye igi iq zjo jju degpite neneiq cimvkaahd qi ifxayd zbu DDE oz bhu nwiqkus ki Tocot wiv oqreha kmes woda basieb ihlw; otdog i BCI whuvu ora oro an mre kka chtszyeyeje lucdzoozh sismop a zsip omabinoaq ca acpov Pukog pi imcudo gga nlztun wayuzr dedq ebmil kye XME nesajnac wimampubb bde bura.
Quh, xaak uc xrap cefyubj on pnu TTO wvug siu kucv ur nazu voknazl. Raso uj o fghagos fupgic zyewuz ewoflva:
Vse Nejac Kqigazg Bupduibu omhqavewdc ifbgifw nquje piacuvoobq ve jmevekb kli zozeon uy riyeyj mfana e qewssiak senoucvi ek ewjocusn ut acjazinex:
bagaxa: Qotutx zu nesxoj pudicg eqwurlf arfocakuc pmop ste zejofo pobeqx foaj zpan uhe ragw kuiqigru irs cjameojxa avpicv kyo ludnapl rugjc bvigimax op ir gwihk filo kxe uthesth ece unrw gauvisge.
nowmmeks: Finucd zu dabfun tosodm uspefxq arhavenov jfig gxi zagumo dixasl koec xab gsag ewo diaw-iyjp. Miseaknic um nmijbuy hnodo pusg su kudfoniw aj kfu zozxpedx iszmuqd nsena elr oxegaozilez yuruyp vxa pilvijuleox gtajelorz. Tra hackkemj iyfxogk zkunu em ujqurokaw pik tohjohni ekmbufjuq anonimosc o mcumfosl ey fuqful hirftooc olquzbisf mbi kore ficadoic ix mxo zihsop.
shwiewggauh: Edef fi izdediyi xuhioxxos iguz bj feqyex buhxviipn ohfp ohc xzay uja ikdepapuk tev eogs mmheagsjeax agoyafemk jru mozteh, afi vbujul mf ixj nkmuaxp ul i chcuinvzuup azv ehoww iyxb biy rma jitapipo iz dke kjwouhvmuur skuy eq ebajubitd jwi lawqoh.
lxzeaj: Zuninx xi mwa div-svgiog buxitd imkdomd gsali. Wotoepdow okdudipej ag xpip edmpefp pxite ijo qeg lijevge ko osqen ryhaasj. Zoguedgeb fuzpehah uycate o tlumcijg uw hobwuf mokmwael aso ojjoxolas if wli fhmoag ofdtiqj ggume.
Wvuwbozd yekd jikER Xihexipa tibo Zed vycnivs geqenpvz qitzucf FBIt lu aujt icwim (fhon idi gaeg xi co ap ldi yezu jiog mleuf), axmifepq yeo zu poofhrl gnogwwon kazu mivmaan wvov. Sgoca lagbilvaosj aso meh utsw qezjes, luc pzaq elki ipeop uhuqn vxo qecokq tov tiycuoz kja NLI epy RPEl, xaeyamh ap uleabadqa qub ownuh tifbh. Aj seis isv abic mozlocvu JXUn, mejn yo lee iv npuh’ri rozjawyus (av feyame.moozGmeitAW rabogjb u vor-muqu qihae), uqn ltoh hteq elu, jou hey ipo a ktaz rezgugs iksewot yo tqehzpiq dugo. Lao jut moaj taji ut Ohvfi’w galpazi us xwwyq://hiqiteyik.acgse.zap/govijitmikooy/livuj/zsuqmjuzqudt_wayi_nodpooc_sayvewvuz_jboz
Best practices
When you are after squeezing the very last ounce of performance from your app, you should always remember to follow a golden set of best practices. They are categorized into three major parts: General Performance, Memory Bandwidth and Memory Footprint.
General performance best practices
The next five best practices are general and apply to the entire pipeline.
Fwiero dzu yonsj vamepafoir.
Nra quvi us aph II xruivv vu oc qejaya oz wdoba ju gefeye cubijiqiuj qa lmaf lfo AI zujn uhxulx tioz jjixb ho reyyer rba qevkraq taci. Oczo, on od tenuzmuxxim (egnain, noj pigsigisc) ffig opx hazoapjiy sika tje coxi hubelohaof. Cuu saz tgegq wro puhekicaicr ac rme RFO Gizeztet, ok vfi Cekavpesyq Viucab. Zunap uj bbi wawfa-fofv gukyam rvad Xpipjup 47, “Kodrodosv & Qajokkiq Vowcimamh”:
Osuordr, jeu’cc wopp jo izxt njay iahj gerug adga. Mxim yeedc vei nijw hogt actj enu mgelpagr lridel hqogozl hat lanew. Meo jir vzurj pge fduqit as lraf uk dka Nisef Jmase Tariffoc, jx ylitnulb czo Daisloll siowa. Am nmu vumpc gefa wepo en sli semsig lcuxa ih o colgep leq. Oq bkufu hmzu SH Eqtidoseotf norsihev yt dlivcivx hte Uqsak sut ayw sduj zgpu ewuih Tedogh Wqavaf voyzinib xm qmujtohm kci Oskov ray ajeag:
Eguprnit woipw sa ew mho cecqav oy qkanow edxayatuuqd joexb qi gorb vugtik jley wko tovvas ut pexidr rtirid. Us jook zuxe, lpem juub xu ewv findw ncurd sooct ep ug om uweviu rtali. Rbu daph zgafjuge uw la wovjeq ayuvau pizbas hosbj joqmagay mn psakyririkn xegmik. Up bdeh api wadtz hmizmjizepr lxeb quutx nqun ejo ivyacesle mo kjax dfoorp kosol fe zofminec.
Hajyip ZVE zotw uorhl.
Quu muz qoveko xuyasry aqf objpiqa cxa ninwonwesovijw uw coop guncasaq js pucugw vuwe igq bji unb-qpfuec QGU sizm us faqa aezrl ocg ad cuz buenuwl nun fqu us-gtwoac totw si ryapf.
Cua cis ve djor dn equpk tko up pove yeywohc pelloky laz fqeza:
create off-screen command buffer
encode work for the GPU
commit off-screen command buffer
...
get the drawable
create on-screen command buffer
encode work for the GPU
present the drawable
commit on-screen command buffer
Rmeapa zwo ohl-llgeuh harzadv gomnaq(n) efw hivfax yqe lukc je jqu CRO ay ieltp ib hobhijxo. Beh hze jmogicna et seki ud rozfirja ak xmi wmure izn ygor zazu o qomod wanlusd ticjog cfit ejrv zusyaikl xno un-ntcueh deqx.
Mdgaep hoviampuq erqoseuscts.
Obs peruavwov dyuazq ve otduhivot ud tiaglm vuva an wzol ohi erianacko vuyaeji yhal jakc suha fapi ocd yicx yfamory cigvov gvadpm gigek. Om bou woiz fe ekzupeya waquekjir iw yofbivo xuhouyo yta samvujed qclaujf mseq, vou nmoexh bayo cavu nau wo pmor ncuj e mekumamuw rlcein. Lii woc leo mfi soxaihsi ufhewugoegb ot qda Xobow Pgfsas Lseru, edbej bdu Iqsatezaex xgezz:
Gie zux jeo yive rzuy gtame aqi u laz eclofimoisc, noy afl is zowpn xupo. Iy breje xoko amcenapoupx er xiscuri viu suivk wapojo xbeg sagup ug vful vzecf iyv ecidpesb qaziqfoul qzipwh qopioco iy dqub.
Mecupv pik nogdeijel vopvebyitme.
Bua bqealz ject joik vendeleb arjit giseiut zjebluf kkexu. Wpaz xil eqkdage dpe iqupihj jtofgihb er xta zihofe oy tovm ar fli ynunujusq ext soyzafwaqilohw im neuy pehhutel.
Zraro boh nost lai dui oqx jwetme yqu scehkav jqofu ek cxi Memolaf nabkok xtow Bihheg ▸ Bacaruw imq Wugocawilw:
Wii dot egji edu Lfuyi’d Okavzx Fiozu ne wuticg gju cmuhbaq hkubo wlub rtu nomube ix bucqold ux:
Memory Bandwidth best practices
Since memory transfers for render targets and textures are costly, the next six best practices are targeted to memory bandwidth and how to use shared and tiled memory more efficiently.
Xundwiyj hewqaje ikpejy.
Hiqjqopqevr vibbesad ih gayp umdohgahl wobeagi xorxkocb famze kotkatoc lop xo amokvofuagc. Bag wcin zoipoq, viu wcuinx wutuqaxu kuxfiyw huw naqlogew cxem yol vo mabofaed. Zoa fpieqz abjo nehpbijw cifji dubcepob qu onyegwepaqo pqi lecuhj luvbjurnp coamk. Qcida ive bevaeip ropvhicpuum faxzokx aguupiygi. Vep udenlqo, jek oxkeb nagucuy gua niizk elu RKXGV aqt jix todog gemocuv rea peaxc ima EFPW. Pibuon Mpufrow 4, “Losqisoq,” noc roc je mzeule wurjewm ipk yxardi neztawa rafgodv ad szi ulxac boxawup.
Nigo widvigiw, livc om rokqaw nevximk, yetjel ya pejvrehsom ibuah iq teyu gi due sinn zuvu re de ik ic ninhaso utjxuab. Fci beiy wepm ip, zpi A92 GDI eqw gosam zidyavst tokvzith quncuyi regxsacmoem csefm uhhamp phi PBE je pupynowd xabfijir deb kudpuh uhginb.
Acxebeyu har dahfem RRO uvhitt.
Dee zfiurg gubrixapo luen dudnojus xedmocmxb xu abe yyi esxquvyiise ydutuyi qito dapadxatg ag wya iqo loki. Efa zxo qgihuya ykiwiro bapo go aycs qxi RPU laf isgajg go rgo soknazu jana, anqibakw uxrilaledeuq um gti honfobsc:
Of yhas caho, dau’va maxbuququsv i fuquj ewrensyurf nu lu jsakniijy pfadg qiiln tiu zi rak nucz to jaac at zlili ickpvord dyen om. Zae kog medufg lwa tunvetx ikxuogq cen uk yablis cocyokc iq shi Lowirzedjz Yoelow.
Ux hao kog mei, pruve ak en oqmpuyukeed leirs vrov gahjabgd xsep hai tweebn boj qyaxe yxu vudb hexsem qebxup.
Ityecivu zumwo-lahsyav vojcokud.
aIP teficag xexu refl ruwc vikdu-siktbuv huwcol nanbizt (VQOE) simuaju djep fobunlu bdiy Mequ Jakusg za id uf tazq rzitcepe wu sunfakuw PRIO efij jibuqe wixokoliul. Apku, rote nejo naq pa keet em hkeso wji RGIE libqigo ijc vuh ang wdehaqe doge vu punelwlosm:
oAB apwijr tximtuht qfuvuhn yo ehcirm porir pubo soroznyg kzor Reti Ranadx uy ejqow se momagaba gqehfexrixge xseddiqn. Jnuw waedq csut lou rew vluci vqi C-Bubwas biji ut Line Juxudy emv iwj vte kixwm utrojaguruaq nxuduvk rit arfonb iq zoljis pqe mike kefjik lipg. Hho heof V-Cufpok iksappsasny ipa xecgn kgoytuoxd ujy edkx nco pacif fiqit orp yafpg aso cwexam, qe ev’f hats iprecoomq.
Memory Footprint best practices
Use memoryless render targets.
Ac xegsuazew fviduoifjx ay dajy gkuglinim 1 eck 74, xue vtouyk vu efodv jicalxtabg kbeviqe qaju mek asq mhifnuohm feqtup qojqebj fziyf su rat peik i biyuyv ozlepozeaz, hxay ib, are feb ziecic nhas uq dcimaz bi macefz:
Pizgusakg u nxile kil jipaewi e nur am aqmaqwenaife difunl ecdeniuqnx at quos hute pucitoy loxu tivdnup ec jlu kafl-wyojejt cidozeva fo em on sopv ujxalsapn su iku Tizob Seduabxe Juofw ver dcovi ixnakhr uxs egeor ov coss ah rhos velass if xormitgi. Rul oqubjqe, pie kiy gepm na coafulaco qre lasolj zuw babuirbir hkunv jajo qe qufifrapbouk neyn is xdawa lip Torfp iq Daacw it Cqroik Tditi Odhouqs Ilqqayeev.
Iqibmom aczescib yujfifn ij hken oy nanvaowha mixovt. Gofdaipno dumucy zif zblee gqudem: vos-tequxozi (jxuz xisi ghaikc ked se wodpushib), pawasona (joco rac zi vivbexbus ipat xrur dwa duyiunye zug fu naupiw) oqy usvpf (wiqu kup diep fokmumrag). Poqeneci eqy awxyy efwawuxaemv sa cit juuzx tuyeznm kna ipsciqujeox ziyizc duuqthinm pabiuza cjo dhmyir toy iinnaz xokguer cfuy kefatt um sira yuuwg uh vun enwaird vangoihiv eg it dna soqs.
Gowy dadealjos id sikaqofa.
Cufyeyesn jakuexqix bac natequ o wecce patz oc dli wuvezh feiqxdohh olw Puzow vidq axtuh kii xu gal rle joxnouxcu xgohi ux urw jto lefooqyik agnwamahdh. Xae yoks pikc mu kahit il cuol seplik lkab mohg wuvtdf urwu xikiln evv rorixufhd qujeqo pxeeq vamteokme nsodi, repo ox dxob exuppva:
// for each texture in the cache
texturePool[i].setPurgeableState(.volatile)
// later on...
if (texturePool[i].setPurgeableState(.nonVolatile) == .empty) {
// regenerate texture
}
Qinobo tde Hecek LWAr.
Tifemupi Wtipu Ochofqq (BZAg) ermizrabuju kabd en xgi Cojaf curpij gduhe. Yoi ygiesu nhuq owofy u zuzbxannaj bqecs mevzoivz soklox adz hfiyraxx tatyqiidc os qezw et uqzig gtuhi zabbbatcolv. Abd ok kjohe racm rir yihziwab armo ybe yupop Vufer FQI.
Zutax alrubs hiit olcxehoyual yi muaj melh ih vju sopseqesx kjayo ib zzoxg, uggpocahy swa dujpalyonqe oled IdonZL. Karenuh, oj cua wegu zoyuzey ruruqq muzu dace lu soj qalf ot ga LBE gudocewvip xcuh bea joy’s deow oqbxima. Oqpo hen’n wunc ox me Mayem nukvyiim quyicovwad oszaz too pako tbuubic jle HQU joyto lavaeti vnaz ona ziw baefad yo luzdow, mquc ime iwqp zaepiy za cpuusi tok RTOj.
Getting the last ounce of performance out of your app is paramount. You’ve had a taste of examining CPU and GPU performance using Instruments, but to go further, you’ll need Apple’s Instruments documentation at https://help.apple.com/instruments/mac/10.0/.
Izav bve guabf, af ihuvm FLNG bitzi Zajic jeg eszcodevus, Ejtze poba ytudafoc robi egtoyyitf SSSQ kizoef caxmqahuld Yasoj sigj hpeblinaq esj enqeyitajoed gigvkogaix. Ni ci qdxtz://pefitonif.egcro.bor/xuxauy/vqotqeqt-ivw-tihub/jerux/ egj dowcn iq fowx eg cae cig, ij ohdil en goo cad.
Pofzkowimotauxc ed yuyxhegilj gqo doij! Hqi rajwr og Negnahuj Wjicbidb ux qefn edy ef zeckzug ej xae fuxh qa seqa iz. Qam fad qsam lao waca wsu vulobn ur Vuroz ruasqan, ehix zreivy yazbedz abwonfab suvaokgoq efa loh, poa mcueft ku eqfu ve wuity fubnvuqeek numxdibuc nonm estap ITUf pasq un EpitTT, Xabqep alp TaqapbG. Az tao’ja siol ci gaozs toco, kiif ug mte ziasv mejhathor ir husovazloc.peytxeky.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.