I am porting a DX11 game engine to DX12, and have some questions about root signature usage. The engine clearly defines a global bind slot range for resources, to avoid using shader reflection. This means, that both the application, both the shaders explicitly know the binding slots for everything (constant buffers, textures, etc.). This would trivially translate to a global root signature in DX12, and I have created it as a big root signature like the following: There are 12 descriptor tables, so for every shader stage there are a sampler descriptor table and a CBV_SRV_UAV table. I though about keeping a "staging" descriptor heap, to which I would place descriptors at resource load time. Then when calling PSSetShaderResources(), which is a DX11-style function, the function would fill out a GPU-visible descriptor heap which is created to match the layout of the root signature tables. The nice thing about is that each frame I would only have a single call to set the root signature and to set root signature tables. The command list would just fill it with descriptors before rendering.
I've found out however, that filling out descriptor tables can only be done on the CPU timeline with ID3D12Device::CopyDescriptors(). This complicates things and I can only think of populating the GPU descriptor heap, and after each draw call, I would need to copy the whole table and CopyDescriptors() again when there is a new call to PSSetShaderResources(). Am I on the right path if I also want to keep DX11-style bindings?
I also thought about each shader having a custom root signature and only ever copying the descriptors which are required by the shader, but in this case I will need to rebind the whole root signature each time a shader changes. I would also have to do a shader reflection step and modify my shader-asset pipeline (because I don't want to depend on d3dcompiler when I run the engine) which I really want to avoid.
Which would be the preferred way? I read the Nvidia Do's and Don'ts but they say these which are contradicting in my case:
Minimize the number of Root Signature changes
Don’t bloat your root signature and descriptor tables to be able to reuse them
UPDATE: The second way (unique root signature with PSO) I would also have to bind resources strictly after I have set the right PSO, because the table is now unique.
↧