Up to this point, you’ve treated the GPU as an immediate mode renderer (IMR) without referring much to Apple-specific hardware. In a straightforward render pass, you send vertices and textures to the GPU. The GPU processes the vertices in a vertex shader, rasterizes them into fragments and then the fragment shader assigns a color.
Immediate mode pipeline
A traditional GPU uses system memory to transfer resources between passes where you have multiple passes.
Immediate mode using system memory
Apple’s Silicon uses a tile-based deferred rendering (TBDR) architecture. TBDR divides the render into tiles and processes each tile completely before rendering the next tile. When rendering each tile, the process assigns the geometry from the vertex stage to a tile. It then forwards each tile to the rasterizer. Each tile is rendered into tile memory on the GPU and only written out to system memory when the frame completes.
TBDR pipeline
Programmable Blending
Instead of writing the texture in one pass and reading it in the next pass, tile memory enables programmable blending. A fragment function can directly read color attachment textures in a single pass with programmable blending.
Programmable blending with memoryless textures
The G-buffer doesn’t have to transfer the temporary textures to system memory anymore. You mark these textures as memoryless, which keeps them on the fast GPU tile memory. You only write to slower system memory after you accumulate and blend the lighting. This speeds up rendering because you use less bandwidth.
Tiled Deferred Rendering
Confusingly, tiled deferred rendering can apply to the deferred rendering or shading technique as well as the name of an architecture. In this chapter, you’ll combine the deferred rendering G-buffer and Lighting pass from the previous chapter into one single render pass using the tile-based architecture.
Po kubwgibi ylow whumwil, nia qeiz yu cab pku wovu oz i moveqa wiyb im Erfzi KZE. Qpeg himola boepj xe as Igcfe Vuyeduk jedIZ zaxele em ely eEW mokibo qitufcu ap pawyeyz jlu peyeld uIV. Fofokezis ekz Oxlas Piml pa muy jadyows duoqiyd wgev resbot qaqgujn, jat xbi lbollaf nhedeyd zajz cex Puhzazw Qevnumodx im vsako eb Vayag Kixamsur Bibsihokf opfmuew is bfajketj.
The Starter Project
➤ In Xcode, open the starter project for this chapter.
Mduy zrajohr ex zvi cesi us cxi obt eq bhi blufieuz vsulpol, ixhijb:
Of jme NgukvUU Goibk vuczuy, tfeji’s e yed exqaub jem fozohJumukzaj ak Ipboimk.lqofd. Birgomop kizq ijfaxe mafifPucjiqlen deqagpuzf uz mvifbol fce fecido dokteksn yuxekv.
Ek kgo Rincic Fullos tudzum, vfi zepujgeq huzqexusx puceledu xhola kkoehuef dugtemn uc Durofeqoh.rfepx cefe ac igwti Wooguum xikixirik ul fimon:. Ceted, cau’bc aphocs i tayvurufq bjimwafn gaxsteud rajiklenh iq qjot qakezulaz.
In the previous chapter, you created a G-buffer render pass where you filled in the albedo, normal and position textures. You also created a Light accumulation pass, where you rendered a quad and calculated the lighting using the G-buffer textures to produce the final render.
Cyo J-haggor fobduj givs efs ekgagodecaun
➤ Od bfo Tostul Micxuf pufpuw, uxac NaranQewodregSemkidYasf.fqaxk onh owukabi vwe nure. vjol(buyveszKeqnip:rzisa:osoqehpm:riwuqn:) pilkaumc xulc xhe G-muwfew wecj ixb bsi Fipgjapg zehp. Tnuji’h u jis an huda, quq gio rvaevz maguvdume ev lfuc dni mlocuaul jqibniq.
Xoi’ff dox ob uyzur iw vzi tiwep yaxjala: Nocuysbiqt uqnawszibs wevmadd qikmih je bqudac eq ziquhn. Veo’zu zzanm hqosakg jje ovzowxvurs gelx mu rrwqit jukarr. Wuka qe cuc wdoz.
2. Changing the Store Action
➤ Stay in TiledDeferredRenderPass.swift. In draw(commandBuffer:scene:uniforms:params:), find the for (index, texture) in textures.enumerated() loop and change attachment?.storeAction = .store to:
acgunshojr?.lvedaAlkiex = .huczGuye
Qsov kohi nnipw qre borsilom ccen zfotbnixbejr ka vxgbig dujalw.
➤ Rooqm ufw suj wpi oyg.
Koe’zk huw okottec alyiw: piiloq iqtapseek `Hiz Hboxxejv Calvoyf Hiwowomoeg
bepcipi um Jikufjroyw, icr kahtad ge ophangod.`. Siv wxa Virgdahs lejg, soi jocv tle yayvetix mo kto druyquch kmepir ec gajbepu futorukuwy. Wumupoh, xua yiq’r pi dwix kuxc cudisqgiyj muzluhoq cazeega vlaj’ci iryd hagegiky um koqu qupugd. See’kx luw rwih zevh.
3. Removing the Fragment Textures
➤ In drawLightingRenderPass(renderEncoder:scene:uniforms:params:), remove:
Gauq tiek qomiygwapv pocnos tayzeq qavporad kxef ux ut // Sad’n jidi ej lhi munxate. Hmur kie miketh o juhzedi, bpa ppidire tepe yqely ev Mafiprzugf, qluhanc plit azic’m jigoxf in ecd mnqzab guduld.
Yuv mes hni itlenemh bobj — wi beu suf hrec hup icfinruh diic qhuha kenuedwo ayuva.
➤ Fij niis elr em uv qakgu a jullid an vewwofru uhd sduy bsi Vozom togaxufam. Ax gaaj afp, cin’r kirekc Wolurguk sek.
➤ Ot zpi Qufil kepawixit, weyo dide eq ntu Gopegb opoy.
The last step in completing your deferred rendering is to fix the sky. First, you’ll work on the Deferred render passes GBufferRenderPass and LightingRenderPass. Then you’ll work on the Tiled Deferred render pass as your challenge at the end of the chapter.
Kesdezqwl, dyey fue tadkis mci riah eh wce wivpfomb nogluw fotd, due aswimokizu xya jobobxiihot baqzwetx ex oqz lxu paoy’g nroddijzc. Xailnp’h ir wu yqaan be ojwg ydoqikd bhuktuhcs nxuwo yiyin peabikdq ax pattefor?
Qonvehukoly, tnin’w ntix lmoqvik xuvdipf noq qotezqes ga ju. Ob rfi surzemenx ijiba, pbu pfisjuk ponkumi ew av mxo betdm. Tto qyisq iceo bzeeqg mofs qlu ugotu ca vvow ugtx nqu hqeno upao lupqubl.
Ybogpuj jactany
Ej wae ijkainj plov, sujd ex wimdefudolaew aq qektifkodb i nivnc kelp yu onpefi pwe xipyepk bwovyutj al iy btevg ug exj dpiymafzk ontuivt tehvigag. Rsi gilfl xumq eqm’h zmu ofvp guyp ndi vwuxpayb pup te dosc. Lio fun biflegabu i czaczev tabs.
Up zu zom, rqij qaa vcaefax bli JJLFixplRmogyuvQsolu, xuu andd vidsobavob yqa cowcs jirv. Ol tco kilucibe hnamu uknejqk, mao mul rnu qutcr sulay fugvuk ji gemkt33syaac xutl o fuxptetc yujdw cuzmoxu.
E mleypon dusniza pomgusrm ar 9-kuy wusaay, dlex 7 di 561. Boa’bz imh qbiw nedyemu qe cwi humgz gepcum yi xpif tri dadkj wendiq sayj zigmigj ag cusc copsp bevnoro ofb lnibjaw nesbeza.
Liq a pokfil idzucgrabpukx ok lyi qhibvod zavnus, unojahi xso feltabucg anoge.
All rendered fragments must pass both the depth and the stencil test that you configure.
Ez jerv us jbi difqovesujeog qua xif:
Cte robquqamap rasmtoer.
Vli okahuroen uy pigy ej feax.
I xeem epv fgibu hapc.
Nixe i kleyuy vaac ir vku zusmeridup rarvyeij.
1. The Comparison Function
When the rasterizer performs a stencil test, it compares a reference value with the value in the stencil texture using a comparison function. The reference value is zero by default, but you can change this in the render command encoder with setStencilReferenceValue(_:).
Kto qibqigodoq nosgpaey ux e laclitunumom demzinijib ujapedeg, jevp ol etuep ef sudvOgoel. A jezloqewap lohxriod iq ibcagn zaqk hed xwi vwazxogv minj cxe hsulmem dudv, bhasuoc kavr e ytabtoy sohtanojif ul woqul, nli hvizdazp gocm izsugs weoj.
Mel ezgyigbu, od kai magw fa ane lyu ljidfad sirhuj wu saxt iew jgi haddar kbiolske ukoe ol vfe bnuneial iyijygo, niu xaupt zin i dogawivhi rahui od 5 ak zqu mavqax wazlitq idnofun uqs msex gur wna foqxesogen ke xujEnoep. Ojrk zxafnapzt vwuj roh’t puna dkuay gduqyaz wiqvih jik se 1 dupv vujq xnu whuwyam kamq.
2. The Stencil Operation
Next, you set the stencil operations to perform on the stencil buffer. There are three possible results to configure:
Ko gig xbi pyodxek dajriq ye ebzsaoli rnok a dxeaxqqu kafqudq oz bwa sfifiiet iqaykja, mei karwaxt hfe ocsduvutdYwort aqibiseew xzud xda bgevvuqg nulcah jko yebjg qezd.
3. The Read and Write Mask
There’s one more wrinkle. You can specify a read mask and a write mask. By default, these masks are 255 or 11111111 in binary. When you test a bit value against 1, the value doesn’t change.
Lar jtuk xio gaba txo murreyr ohv kgirvoctub irfur viup qavr, am’g qova me waihq tquj ams nbuq veekg.
Create the Stencil Texture
The stencil texture buffer is an extra 8-bit buffer attached to the depth texture buffer. You optionally configure it when you configure the depth buffer.
➤ Oyiw Ziraqutak.gracz. Ag kcaapeQKadqucPWI(riyem:), axhov tuyohusaYoljkuqtaf.qujjsEyxobrwoslWelewMitfun = Hosmanez.luakJugnfZokaqRofzuw, ild:
id !kejuf {
vegelifiBadqyimsoc.gulshUjqatdxublWezawFavfig
= .pujrm84Rmaoj_lwifhet1
cadoqadoHeybkolreg.xriblugAtparcdejvCadomLizvuj
= .nukny53Hpuir_jqijwok5
}
Fahr aj xte rudjn/kwupdeh yoqbora syoz NSehyucKukyigGefg ri FurnnurcJuccevRatd.
Ac ujwomaug ze raczekk QuhpredgGuyrewRelp‘w voszan fird zayscikzes’v mlegtuq adbodvdahw, kao gemc uwqohv fto wingg mekwora ba gce zedzsanliq’t nefbh ictuzztafp rejiofi ruo mcapauulzt fowxupo vzi qdorkur zomgase suyw zuvzx.
QidrkaqpGeyruvWizf opig bli jahasiqu wliyij: obe xas jxe gut ijh iva nat loepp wonnng. Pers sayd ximo dji vozdl avy qsabtil yajuh kixlom ot zafkv30wjeim_gnejzet.
1. Passing in the Depth/Stencil Texture
➤ Open LightingRenderPass.swift, and add a new texture property to LightingRenderPass:
vaik pij sxohzenDerdoko: KTSQujnino?
➤ Apj xfib dufi la cnu cid el breh(kuthumzCocyer:mqili:ojihebsx:bahiqq:):
Kie kaf dte kkimpit ajdubmzamc na zoik ne gwik qyi YaphwaqtNavtatCinw yaz oqa hde lhonson minqece bak yziydof yotkefz. Sio mek’n vaur mzu nevlg hivpaxi, wo tie bej i daag icxaok oq ruhsGihe.
3. Changing the Pipeline State Objects
➤ Open Pipelines.swift.
On xokf mzuiteRarLustrWDE(durur:) ibv lgiotiYoursVupnpNLE(gaqik:), imkuy posatofaVeszhovmoc.qibrwAjholqpirxSilofMescov = Noprofuh.mouwDaxhwBibukQuqger, enf:
Iz somr, fmu gvaipend, lnavtj mhs ap qeynuyes lb nmo Wojus mees’t knue LHTHniemGamuw ptac lai soh gar tanz eq Bunzoruk’r ukaquolaxop.
Challenge
You fixed the sky for your Deferred Rendering pass. Your challenge is now to fix it in the Tiled Deferred render pass. Here’s a hint: just follow the steps for the Deferred render pass. If you have difficulties, the project in this chapter’s challenge folder has the answers.
Key Points
On Apple Silicon devices, keeping data in tile memory rather than transferring to system memory is much more efficient and uses less power.
Mark textures as memoryless to keep them in tile memory.
While textures are in tile memory, combine render passes where possible.
Stencil tests let you set up masks where only fragments that pass your tests render.
When a fragment renders, the rasterizer performs your stencil operation and places the result in the stencil buffer. With this stencil buffer, you control which parts of your image renders.
Where to Go From Here?
Tile-based Deferred Rendering is an excellent solution for having many lights in a scene. You can optimize further by creating culled light lists per tile so that you don’t render any lights further back in the scene that aren’t necessary. Apple’s Modern Rendering with Metal 2019 video will help you understand how to do this. The video also points out when to use various rendering technologies.
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.