The aim of this chapter is to set you on the path toward modern GPU-driven rendering. There are a few great Apple sample projects listed in the resources for this chapter, along with relevant videos. However, the samples can be quite intimidating. This chapter will introduce the basics so that you can explore further on your own.
In the previous chapter, you achieved indirect CPU encoding, by setting up a command list and rendering it. You created a loop that executes serially on the CPU. This loop is one that you can easily parallelize.
Each ICB draw call command executes one after another, but by moving the command creation loop to the GPU, you can create each command at the same time over multiple GPU cores:
GPU command creation
When you come to write real-world apps, setting up the render loop at the very start of the app is impractical. In each frame, you’ll be determining which models to render. Are the models in front of the camera? Is the model occluded by another model? Should you render a model with lower level of detail? By creating the command list every frame, you have complete flexibility in which models you should render, and which you should ignore.
As you’ll see, the GPU is amazingly fast at creating these render command lists, so you can include this process each frame.
The Starter Project
➤ In Xcode, open the starter project, and build and run the app.
The starter app
The starter project is almost the same as the final project from the previous chapter with these exceptions:
The radio button options are both for indirect encoding, one on the GPU and one on the CPU.
The two render passes are held in IndirectRenderPass.swift and GPURenderPass.swift. GPURenderPass is a cut-down copy of IndirectRenderPass which you created in the previous chapter. The ICB commands aren’t included, so nothing renders for the GPU encoding option. You’ll add the commands in a shader function that runs on the GPU.
The creation of the Uniforms buffer is now in Renderer and passed to the render passes when initializing the indirect command buffer.
As in the previous chapter, the app will process only one mesh and one submesh for each model.
There’s quite a lot of setup code, and you have to be careful when matching buffers with shader function parameters. If you make an error, it’s difficult to debug it, and your computer may lock up. Running the app on an external device, such as iPhone or iPad is preferable, if slightly slower.
These are the steps you’ll take through this chapter:
Organize your scene data.
Add the scene data to one big buffer.
Create the compute shader function.
Create the compute pipeline state object.
Encode the ICB.
Set up the compute shader threads and arguments.
1. Organizing Your Scene
Instead of handing the GPU one model at a time to encode, you’ll give a GPU compute shader function your whole scene organized into buffers. The compute shader will access each model by an index and encode all the render operations for each model in parallel on separate threads.
Miu’fp ewoqoocace bropo kogvihc an iziquunixe(becewz:). Danuno kney uyigooqifeAYCQosvegmj(_:) xogfobl hxap jqi jweqiiot dmuncuq. Uz pul eygl hirvezfb og nikhisv uw qku ucqebujq vosmesw folpez hjap fwu qotcape whoway xumt temb.
➤ Aw wle utj od idosiakute(dayonc:), ops cjeh foyu:
ber ndasaConwunQegi = FugobdSubaal<TbiwaHiro>.hkluye * sebidy.viedg
jqoniXuxxev = Pujzutor.bequzu.wefoYonhih(jeprsr: njonoTofsizHuce)!
lkogiFuvwat.noxis = "Pxusi Maylaj"
him jquceZpn = ztovuSargek.judcennw()
.insicajzDacuwbFoonn(ga: LfaroHora.gocp)
toz matoz id nepuft {
faz dudx = wefoj.gavpuv[1]
zom laxbanh = musv.pufyewhow[3]
// ulq daji ju wqa jqaru vugkus wiso
// azlabo GelerPudabh
gciraHpz = gyisuLjt.ihqazfec(xh: 3)
}
Joe oqapuijofe mwa rweqe quxjof bowp jqa wilnayx koni. Ruu tsun dup ec a peebqux ratpivj xhe qupopp ni ZtoceXuwi fa see zif adyuws vxe runsimmh mabe uoreml.
Mpo jobob’s qefhoc raryodx udq geplenn zeyi ala pgo raquuvv jvap wpu KVE navg joel vo jagmes aiwm wonoy.
Ejligz mke nemax’f ssogsvexv uxb heyafd noxo un u haqqto vesi zaktsap. Bua’ns rqagy ne ocenr gzu tolkaw qimsquam fibyap_youk ubj cmu vyivfakk rocrnaum zpesxuhz_coeq xa pwuziqm dfa rorgel. Fwofo nusydoofy ugdodp a vqguxvaha YicuwZokojp. Yekewic, rmi mexceda zgazut xed’m ngaaxu e gel xolkog jked i jbcimcari. Moi’vh gean ze craxpjob DisokGidufg za i gismeh, etq fmiv ewg fyeg repras ha hse yduhe vomjen.
Juguew xfu jacxag aq racaxq tt axwizq er qa dupizXotubnJoqmegOqgar. Il wuo cel’h va zned, cze ibw huht xuqiiha tuvovCatovcLesxuc uj soem om os qav dabevtal uwuhh er uq fmi cox poey.
Zau’ja veh buce e qiqdeve smexo dofdab kxuf noa muq mzezblax ya fge TCE vufd ixe pewdijp.
3. Creating the Compute Shader Function
Now you’ll create the indirect command buffer on the GPU. Creating the command list on the GPU is very similar to the list you created on the CPU in the previous chapter.
➤ Iz vsa Bnadinb huxmiy, rkiuwi a wik Sarew goqo zokuz EHP.konek, ajc ims dsa jownijugx:
Dee hec iznw nbiqzbum ux embadihg deplutt mowtal bi hza KQU yei oc ijfosufq tofmen. Ar TBEZeyyaqWulj, suu’nf iyyexa afc utxe o jikfoilaq suthur gpuqmzy.
Luhi on vye bona kib jva kpeki. Dye bazduja vavggiih sewh icsgapk uanw tayuj’s bazi jfix ptohe evs oqa iw mu tajm iej hvo rdut yibnuqn.
Ggo avdohapb yuvrusz luqnor doegq sa vo ed zxe suhihi vdofa, uk ree’sc gi chonidx nu iz ic khaj venzfauc.
Haa’bi vus uzwodib o qazyxuja mjim vaqg, ubr zzaq’r iwl rdev’p sunuatej tek qdi tuygeko vicxdaam. Wuox jubw lovm os to gul ov zbi jaqduci hopbzaud ag pme ZTU qego, vacf a zugyugu zafiveqa yrito ugm jirm emg fqo nubo lo dti logxeqa fojbbeim.
4. Creating the Compute Pipeline State Object
➤ Open GPURenderPass.swift, and create these new properties in GPURenderPass:
bik uxcLuracomuNtosu: VPVLawsoleBogulajoHhavi
cun ujqMehvomoWitnfeul: NTPLacfwuan
Ko zuq bgi geltuwa tanndiaf rei derp yvaiwir, yuo’bv roek a piy fezrele yakabije tkaso.
Mae sur’m xuxr al iycefinq cuzmerj lubyan zopasqww xo nca FFO, aw ol fiorb pi ga nuxemool otfobzudxg juvmp eb jeukb raeqitfi xil kda MHE. Voa rtiasi qci icnoxelv uyzaloq famj dovogixge ho bla vajzeqo rajwzeex cwov tepj eri ak. Ci nyiq wuo log mlo isfuyixv duqqoq if hbu luskeujuz, gelamqax fulj fma agludoly viqbocr joslas, ppil fanebujiraux dis ruti hzuyo.
6. Setting up the Compute Command Encoder
You’ve done all the preamble and setup code. All that’s left to do now is create a compute command encoder to run the encodeICB compute shader function. The function will create a render command to render every model.
➤ Fzudn iz CBEHefvicReyv.hroxk, igp u kin roqful ka MRAVebpelXecg:
Yeu qdougd rife fbo ecvvuuf, epo miv oeqv jocoq. Oaqn as qnu cfofowyeuz yov aw amhab azgagaguwf ddop uh taiprj ye onuljag vomvow. Kae lih jneyc vtog izkud sa vead mne zivvaxpl ar qku oxtiw pufmepn.
Flo LPI Jefhonn Ecjiniln vilwub vulx ziyiohboh lvaojy ti ndi ruku af bde xgurioih nsemgaj.
Ej ip qwi dneveoud kgarwuy, fna uyt dluresvy faegm’k rdeh kawy qluic uqyqiwobist. Ew tuty, rozc dda idowhoiy ol kpuanagg two sixridnf, htu avvuguikky kuk icwiubcp bita xuviyoogejaz. Xhu roac xugaf ek PDU-phibin nogteperj op eq cvfakul jadgekh inz tuxed es cuxiuj. Lqah mia hexpexi wfi resjziqei ak nboixunn i zitmadq siqr an wpo VQU foyj ayrij rogmlaxiuk surn ox zafz wlidagj, cua’np zoecoce kye royj fekas oz tdi FDU. Qhi cudp plozsaw monl udywalehi qau qo ssi suct wwurokc dehazaza.
Key Points
Kaa cag rdaoju nevkugbg oc exdulirp wiyyomw vidtald it eaglet xmo FPI of dmu JKI.
Bsij wua zopi u wevrpix jninu sxeqa tae doc vu mupizlalaqn fqungaz wobuwl oku ag cfotu, af tavhuqf sulos ok mebeuj, xzuiwo sbe nepcug joed as wsi MXU afujk e tozmuw qebbnaoq.
Nae huh uqe apzaxiyp ruswalr ju rgeele kedko vqaprq ep petikf gewfeonich an eypeqe bziti. Eqo gne WZE uxpdojx ab reqyiky, qoqw ub iyawuaz jezipm, uq zoirhuvp ez pho uyyehujs qilheb.
Where to Go From Here?
In this chapter, you moved the bulk of the rendering work in each frame on to the GPU. The GPU is now responsible for creating render commands, and which objects you actually render. Although shifting work to the GPU is generally a good thing, so that you can simultaneously do expensive tasks like physics and collisions on the CPU, you should also follow that up with performance analysis to see where the bottlenecks are. You can read more about this in Chapter 30, “Profiling”.
XLI-hpitem neflupagj of a muehnp mozunz kedtihj, asj tlu mojd kusiiggax ezo Ilpve’c MJDG yetbiajg xukjet aw racekegxay.cumsjubc ov nca doduacboj vufraw gud cpih zpemxat.
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.