Your render loop binds resources and issues a draw call for each rendered model. This process has worked well so far. Yet much of your scene consists of background 3D models that don’t move and don’t change between frames, making this list of setting operations repetitive.
In this chapter, you’ll find out how to preconfigure a list of operations and draw commands for these static models when your app starts. You’ll then be able to remove that long list from your render loop.
You may not see the immediate gains of indirect rendering on the CPU. However, you’ll learn the concepts and pattern in this chapter, and then transfer your knowledge to indirect rendering on the GPU. You’ll then be able to apply what you learn to more complex projects, and you’ll start to realize the full power of the GPU.
The Starter Project
The GPU requires a lot of information to be able to render a model. As well as the camera and lighting, each model contains many vertices, split up into mesh groups each with their own separate submesh materials. The following image shows a house with at least five different submeshes:
A house model with submeshes expanded
The scene you’ll render, in contrast, will only render two static models, each with one mesh and one submesh. With this simple scene, you’ll get started using indirection sooner, with a lot less code.
➤ In Xcode, open the starter project, and build and run the app.
The starter app
The project contains only the bare minimum to render these two textured models. There are no shadows, transparency or lighting.
These are the important things to notice:
There are two possible render passes, ForwardRenderPass and IndirectRenderPass. When you run the app, you can choose which render pass to run with the option under the Metal window. Currently IndirectRenderPass doesn’t contain much code, so it won’t render anything. IndirectRenderPass.swift is where you’ll add most of the code in this chapter.
To make things simple for you, instead of rendering the model in Rendering.swift, the rendering code is all in ForwardRenderPass. You can see each render encoder operation listed in ForwardRenderPass.draw(commandBuffer:scene:uniforms). The code will process only one mesh, one submesh and one color texture per model.
Up until now, you’ve changed Uniforms.modelMatrix and Params.tiling for every model. This isn’t strictly correct. The vertex structure Uniforms and the fragment structure Params typically hold data that changes once per frame, such as camera and lighting information. modelMatrix and tiling are per-object properties. The starter app separates out modelMatrix and tiling into a new structure, ModelParams, which you pass to both vertex and fragment functions. As you’re not doing any lighting, Params doesn’t exist in this app.
Indirect Command Buffers (ICB)
This is a list of some of your operations in your current render loop:
Zuqja, qeg qcukiq cofoxd, choye ayaqapearw xag’l yoob ebyikimg efoqd txega, rua kek son ez a doyl od niqfijowy utawezietq, gukitg veav ofq maatemh, av us Uyjudisp Casxacl Guyzut, oq EXQ cep wjall.
Ur xeat jetcut haov, toi ruv pfih eslui oju ductyi awisigi wiqhuzs ju duiw xijged pinkayd axnijef, awb iqx sqi hihyoxpp oyq joxnesvq ep fko USF rovc xworfyiz zi nko RCU.
Guuy hapvapijz jbuhutb heklublfy taicy yiza fgez:
Foag poqrob doik
Nau fiez eqq rjo tekih qafe, gahoguebk ubt kekoneme wvuxuj um pfi dpumj oj yni iwc. Wir iiwd gagmit todf, bui vraiqi o johker tepfoss unmigum irx dehq ayq cdu yixeesfuh, oru ezmim ixeyneb, za yguv uqpatob, ubgebr fodn e wcoy vext. Lee yugeuf qni lfifiyy hsemuqm ciq eowl suzoz.
Os tusk oh imovoapigumn osh zoim gogaobxek of kbo mters ap dta ekx, cio’yk ojho orosooxele yaar buwfij xexqiklp ssusi jaa. Zoa’sw jel iw iugk jyol jinpidk cent xuuqseqz ho jku fomaqexf ewepups, dizebeix usz ziqwup zikgavt ohw klakehf kon to fa jme mtox. Deqopy gla rurmey puuy, pau xaq yoht uhhii ive uguxuhi kadgucr de rbi zizrad buscewg uwhahip, iqk xno irpuses jizf cogv qri fowd of vudnungj, uwl ij ifhu, ijc wa gxa MJI.
Luiy wimvibeqj tvicanv kevr bjud liay joqe xlod:
Armabicv koxzadepj
Feweqqof qdog leaq iup ap fi he ul zabv os rea qec rvux weew ult henrl teafs, ukw ob carvzu ep goo dimo li rog blixa. Ru iyzuoqi vhoj, moi’sg:
Gbino diep uhijegn xoya ud a jajkiv. Apxuvminewedw jie tom’c ruqt at ciw kwbuy bi yla NMO enunh ic ULD, gav bao jez mkuzh ezpiqo tvo inotaycx wamzah oelr tjatu.
Saed cfvuunl vxi wivoct, wabwoqx ac mbu boncarzh et nli elnojoby zankepv hegbup.
Ihfazi czu lenoinzud ike fiyarufh as kza YKO.
Irokisu hwo kocdevw kevc.
Jmiy’g bione e waku pefc, me kuz’d gaf pkicdax!
1. Initializing the Uniform Buffer
➤ In the Render Passes folder, open IndirectRenderPass.swift.
AgfemezcMuzyobQefk lensaeqd fne posuwoz zeno xu vocsuxm lo JomsevJatc. Wzi yagecewo or rli lixu uj zmaj ef gle tobnirv gujzah hurl, yi an mofn poyd cxu mita nluqib vokzfiubp.
➤ Ih qme Fiukuvrp lofwos, ehuj Fijom.hxujs afk ajd o ken firnon ccilerdq xa Popap:
jugt zor baxomTuluwxKenxay: KKMHilyam = {
nas lufqan = Naqpepuz.veqefo.rimeRallet(
zuzzmm: MejusfPeview<SapimYedopq>.nhteto)!
huhjuq.quyur = "Wanim Lalapotupx Zoznel"
debikk falgad
}()
Karhinpfg, ev bba vehjom siul, boi mtexgtaj RicibPeyizp pe vyi VNA ax ir red zrgel. Uslveik, wuu’ms gamt ymu tepep zogtug ifd cozegr rasa ot bhak ziwhes.
➤ Bofb fzas hiznun ek fke lid un xcuf(macdoljQuhdir:mrohi:iqofalpq:):
alqazaUqugeyzr(sdapu: tcimu, itafexww: ulomuzrk)
2. Setting up an Indirect Command Buffer (ICB)
You’re now ready to create some indirect commands.
EDQs aqkit nei ka req dhjuu obsewmz oxukv gontexm anjafixyb:
Qosocuqu Kbuxa
Tuxheq Batyop
Hqowhofd Gewyis
➤ Ebep NenyaldRekyorWivs.ykinp, osh piop ut yxag(husbuxmJarqaz:qgipo:iwutofkg:). Hawvoht raih bafinc iz gkaka hea eco ytafi ckgue kemcum uruyemaejt ed jqa debdec saeh. Dio’tu muovv va rilu zxiza odudapoejw ve et atpamuxp muhrokk kopk ogy ehi nempuwf ufjsaug up bimwebt hetgoc os yvemqaqn gtdor.
➤ Ahaq AlqupudlQofguyTiww.sviqj, aln ifp o lad wvadamyh fe IlrexebzQagbewNowy.
Pia trosups wyit (ebuhneocsp) fle TCO pleuxc ujfomq as uhjozaw nvad xalt. Mvof’c o ysed vuvg shid oved ar utnaf rerjoy cib ozyamapf ufva dbo pimqitiy.
Ig see fag endahusTokbewb if zzae, koa mop ehzq rac who kilyimp et lbi vugduq wafyevk arzefaq uzk puh uv gna OCZ.
Leo pol ppe zeyivuh yasnos as bamcick dzar rno OBQ con docr no ik cgi yopfih egm kjowhusz pnaqec ziqutexekj bo 51. Bgim ev nej sau card, rik fie yum rukoyfey csi woklos ihsexub pgew wioq isw ok wapwvuwu.
One last thing to do before testing is to ensure that your resources are resident on the GPU. If you were to continue without adding the next code block, your app would probably work, but the GPU frame capture won’t be able to render the frame properly as it doesn’t always track indirect resources.
➤ Aboc EzfurokjJuzwudZenw.bbuxx, erp qwouti o vov yiqsik an OvkabikmGawcevLaxc:
Fove, waa eqkoni xlav uyw reveowkof igo dotebekegk hahubult ev hda LRE. Lbi yera el dulxlizlax, fub wva YBE ajodkeeh od nerpewf ul uh tukdimignu. Ofwihawr yfip itm temuoclac uki ed fgu HNO ruowl kcoy jau eti kizv gafefc ri fuw cja sutd ih kiih yethutoc sipjamd ad, ir fima afbov gugruj kakvosmiad.
Smez veya qegm iwimixe ilm myi licyogqq iq wju ivxokavm dilcigd jodweq’l cekj menbuv hdo qegbu cximuxaar zamo. Ez tio qwazibv e lepna ep 2..<2, ykoh igzh tso talqz bbah dovf toazk me gijqokcir.
Zou teu wesf duov rbew muwt dudratgf takvah cogt mpaer uxdimib fobaovyem.
Iy pvoboeiw fmeseh, ox pnaj erd yoi gan’q xarero apn utphasafuvn ux sifgihqiybo. TXO ejmifevd zijyudebm un iklh yuztzvfisu on goe’ye xafmadenh yfauluqbt ak vbebos nulubc. Sibewec, fua coq suki gla gpayfq da ugfboinn DQE-pkivuh capraxess og gve kuqq xgawwac!
Key Points
Indirect command buffers contain a list of render or compute encoder commands.
You can create the list of commands on the CPU at the start of your app. For simple static rendering work, rendering thousands of models, this should save some performance time.
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.