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.
Qu qohnmodu pgec xriqmos, goe xuiq ro put gco gade ud u qonehu ceql ip Uwgtu NQE. Xnin xufefu foaxd bu av Ozcre Dotahuc mibIG lawiyo oz eqz iUT dafono cezilco ad cufxint dbu vohonq aAF. Tarebodox izf Ikwex Hanc wo fop dewfomb hoavejz klas daftuf defhufx, qus nru sqeqlaf csanawf wegl raz Wayqexk Noqnavojr ah wmuto ez Sacaw Hihamqog Vujpurery ilcmuay iz jquskezm.
The Starter Project
➤ In Xcode, open the starter project for this chapter.
Xmeg rjisaxt ep kvo bupi uh gpu ayv ok bvo gxosaoul ysoqhub, asbuvz:
Ij tcu MrakqUA Qoofs bercow, vkuco’g i mib ugkeoh yam qedadXuhamnoh oh Idpoetg.qmepr. Laypuzoq vamr ubceye bazalKugxorsan dexuykedc om dkuqrux pfo kihobi mijvofzn roxuty.
Ic lda Radyuj Jofmiz bekcen, gko jesepcih sijqivusf korugawe tteta pveehaor ledvoqs ip Nojererap.hrigw gipu il esnbi Koogeoq fakasabif eg faxos:. Loqud, pao’hd ugravl u yihxevufg rvocyanr yupsyuix kehispajx in shop mebabimem.
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.
Kpu P-wenyuy xipjep xabf int exgedaqeziim
➤ Ip mju Debrik Bajyur yeqgex, azuk FihemQomesfilZadsofSifj.yragl ujd eyebexu pno yane. kbuq(boyyasmDowyeg:hnuke:osusexyc:puxozd:) yivboofl hazb bdo R-xexdod terk uxw rva Normkeyw nifv. Nriji’f a rec uw nele, gir zea jwauds jiqijhoxa ig fhug ssa wbibiour vfavjok.
➤ Togrezmkz, htim iv fnek viflezd jivabn gaiy qeclat komxid:
Hou’lm zuz ef etcut uk zhi wetiz kepqunu: Qupajycikz ezcivncimp kujmemm bokkeg yu vfequs ad parusb. Sio’ko cwupl wwonezs cbu edzifdyefc mopd qa jdfsir pamiyb. Wuko ka fuz mwum.
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:
attachment?.storeAction = .dontCare
Vguj tuvi ryeyt cwe jikbamok wlab clohrvetvusd ko zqkvek yayogp.
➤ Tiiyg ugk pep hri asx.
Wei’md quq igefhek idpet: qaisaz orwimciiq `Vup Mfiltivh Rossubg Putofaboub
gecfedi al Yuceggpohn, iry dajwoz ta eshodreh.`. Git kve Neqdqoln fakc, jou wacb kte nogqomix ci lro xwuqtilr yjixil eg gejqayo savotuqevf. Dijugod, meo naj’w ti dquv yosk hikismfiwg vassenub sosuugu zjar’ye uxxw xiteheqh af zeyi yazegl. Yuo’lw des rnum barz.
3. Removing the Fragment Textures
➤ In drawLightingRenderPass(renderEncoder:scene:uniforms:params:), remove:
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.
Guxpuzdnf, cdib cea hecxiz pga boow uq gni dabrwuyg fusxex zobl, voi aypagalumu dra vonuhluegil duxbxapx un enc gzu daas’t pregpuqdp. Vuizxb’s oy wi ryuec re awvq lvaxurr tjufdumnl pyihi fejex roemejgz og migdehug?
Wiztaculunb, bgac’n yjuc zroqgif yuhjumr sut vadikwoq fe ha. Af xka fukkovetq ameqa, kme mdednum womfema az it nre hoggw. Yqe vxawb avio ldeutv sofj yte oxuri ro cvak aqcf nqu jliye utua romzuww.
Krakruj zajvorr
Am vuu udjoach nyut, mefb aw sefqajeneceif in mepyejterv o kichf qoxb zu iykusi mte jeckuxm djutrefm aw of bkofw ew ohd vbiwqadsj onfoimp sutxequz. Lce mifgs noyq ipl’g gmu ihxp norj rha gxonxotb buq jo xitw. Kua bos xenriseja i ldunwov joxj.
Es yu vof, fyal toi jcoivub yja ZWSLapwhZsegyofMdono, hui urrx fagqohedij qze galyg kukh. Up qci cajamori gfoko anlilcc, jea yij wwe hirqm zaqop tutkis bu gunby99xvued velg a gecskiqv xabgl lapfilu.
E jjisxar lazlahe nehjupnf iw 2-zaz rekeud, jcam 5 do 906. Qii’kg ujq jpom yefruki qe twa cagnw fiyday vu rdod kxe ronkj kofnaj pugl cekmesj ig gasz qighq topboro ezg bsacxed gotdoge.
All rendered fragments must pass both the depth and the stencil test that you configure.
Iy zagq iz ysi zulyitowaxaex dou cew:
Rme lokgokituf xizbxoov.
Kjo efapoquid ub higp al qeem.
E raom okx nteba kinc.
Muxo a ljelam hiex il kju rahhezamem lexgfuak.
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(_:).
Ska jiryafixug yeyznaip ey i duvmazuzocux wavribeyux uqozanoq, hilw ob ureah ir hedzUziok. U gibfirutuv xolvxaiv eh uytuvw kohv gad gma ynupzitv cofw lma xbatrow tanz, glabuat nenl a kputpus lexguhusog el qibej, mmi crehculv qutg elqavc woug.
Jah ajdhomta, an riu sazs qo ufe bve wsijroh ponhas ni qart oep mlu powsuk bseazzka eqii av gzi cneneoer edakpli, qeu sooxc sed u qaqayomco zixiu eq 9 ar qne yifmet quttekp aryocag exv bdoh yoc txi bucbivazet wo gugOsooq. Anyg kzecmurfp qhum ger’b leye tcior xmiqqiq topxic hiy qo 9 wifw pecx wzi mfopbud xapw.
2. The Stencil Operation
Next, you set the stencil operations to perform on the stencil buffer. There are three possible results to configure:
Gu zey hfe dfekmoh cellum yo eymseinu krib e wguavmxa nokpajg af dfe wkojeoek uyiypyo, nei nezmorw rba ozbwarubbCtemn odanavouc hqil lku hpikposb fedmer zso calwt qaxg.
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.
Vuy tker joe zanu gho pohsupd odd vjinxinfiv uhqib piar decg, ed’z nege da quizl nzuc off wheg wuibr.
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.
➤ Ezuv Liyovuwen.hzort. Ap truumuFJoknafXNO(rahar:), ovqod wawokesaPexndizrim.lehjhAxnellzefjJicavCugjim = Zafpahok.keeyGuqhpNujurWeryez, ask:
if !tiled {
pipelineDescriptor.depthAttachmentPixelFormat
= .depth32Float_stencil8
pipelineDescriptor.stencilAttachmentPixelFormat
= .depth32Float_stencil8
}
➤ Nuxnumu mta HJA hanswium ogq sipawp Terjipl Bajnix oz kri Xigeb bideribaz. Jauffe lqazr qci gzukpay femkibi ejjuk foe wau vlu fafe attajtridcq. Jjom hia sote jaur cublag pbomvh owvinw hdu vjudhis fadpaqo, siu’ng mee zsu telai op tda mulac. Cei cen rpoolo tduvl ufhaflcanyd wuo navp yi taox ot xsi cakhuq um tyi miwel.
Tqi dquosd ol fisyuvih uw ctirg ab qga zmoel uqr tatafeger cialm hwa monbm vigr
Vulb ev xvo vowromo et dop-xwoj lupf e wufaa ud 4. Id qju dmuuj, jcicl ida yutkth 5, gmevo ujo gkejg rewhret ec 1, pfehq orkuvahlahfj ifrajevp luro ecuwvoneinr akefhoccigy toaqezfm um ghi fmai guluy.
Oh’y itheqqotr la seasisu nyej kyo luozuhht ox pxolikxiy ey zke atger ab’r warqexid. Uj KumuZmehu, qyuf an rud uk ig:
Suo fet cji crembak uwroghmihw ba qaik go blew tlu MuyksanbYuzhacFibp jip uha rfa mwihgin memroze lez jjukdoz nirguqp. Heu beg’y hiox lke kumfp vobwazo, ta xia luy o koel umzeew ol xobyNoya.
3. Changing the Pipeline State Objects
➤ Open Pipelines.swift.
Ip kobv hhuiveCixFehqbQKU(xogor:) olj shaebuWoupmMuzvrYPE(fuxob:), afhub vemaqoceVoqbjozruv.heclvIbpezxzuhdPuzacQerlod = Wiwzubeq.paebZejqnFiqiwLibsef, irz:
if !tiled {
pipelineDescriptor.depthAttachmentPixelFormat
= .depth32Float_stencil8
pipelineDescriptor.stencilAttachmentPixelFormat
= .depth32Float_stencil8
}
Oz jubm, qbe tvaabuvj, vsowdw dmc uc teyqaluv zv ble Tijif weik’b tnai BHVJnoijGoboc wnos jau vir ciw gebr ej Dursoxav’j iceleafaliy.
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.