In legacy OpenGL or Direct3D11 APIs, resources can be bound to each slot separately.
Evidently, the driver of the legacy OpenGL or Direct3D11 APIs needs to allocate a block of memory, which contains all resource bindings, from the command buffer for each draw call. And the driver needs to provide the address of the allocated memory to the hardware before the draw call is issued.
Analogous to the pipeline state, it is not efficient to allocate a block of memory from the command buffer for each draw call. It is more efficient for the application to allocate and initialize a block of memory in advance, and reuse the memory at each frame.
This is the idea of of the descriptors in modern Vulkan or Direct3D12 APIs. The application allocates and initailzes a block of memory in advance, and provides the address of the memory to the hardware before the draw call is issued.
N/A | allocate memory | initailze memory | bind memeory |
---|---|---|---|
Vulkan | vkCreateDescriptorPool vkAllocateDescriptorSets |
vkUpdateDescriptorSets | vkCmdBindDescriptorSets |
Direct3D12 | ID3D12Device::CreateDescriptorHeap | ID3D12Device::CreateShaderResourceView ID3D12Device::CreateSampler ID3D12Device::CreateUnorderedAccessView |
ID3D12GraphicsCommandList::SetDescriptorHeaps ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable ID3D12GraphicsCommandList::SetComputeRootConstantBufferView ID3D12GraphicsCommandList::SetComputeRootDescriptorTable |
Since the descriptors are essentially blocks of memory, the descriptors in modern Vulkan or Direct3D12 APIs should be simply treated as assets, merely following the rules to store the vertex buffers of a mesh or the textures of a material.
Here is a typical pipeline layout of Vulkan.
location | type | readable name | introduction |
---|---|---|---|
set = 0 | N/A | global descriptor set | the vkUpdateDescriptorSets is used during rendering module initialization |
set = 0 binding = 0 | UNIFORM_BUFFER_DYNAMIC | per frame dynamic offset | dynamic offset of the unique global_upload_ringbuffer |
set = 0 binding = 1 | UNIFORM_BUFFER_DYNAMIC | per camera dynamic offset | dynamic offset of the unique global_upload_ringbuffer |
set = 0 binding = ... | UNIFORM_BUFFER_DYNAMIC | per ... dynamic offset | dynamic offset of the unique global_upload_ringbuffer |
set = 0 binding = 3 | UNIFORM_BUFFER_DYNAMIC | per drawcall dynamic offset | dynamic offset of the unique global_upload_ringbuffer |
set = 0 binding = 4 | COMBINED_IMAGE_SAMPLER | shadow maps | for example, the global shadow maps |
set = 0 binding = 5 | COMBINED_IMAGE_SAMPLER | LUTs | for example, the global LUTs |
-------- | -------- | -------- | -------- |
set = 1 | N/A | per mesh descriptor set | the vkUpdateDescriptorSets is used during mesh initialization |
set = 1 binding = 0 | UNIFORM_BUFFER | mesh arguments | for example, the immutable uniform buffer owned by the mesh |
-------- | -------- | -------- | -------- |
set = 2 | N/A | per material descriptor set | the vkUpdateDescriptorSets is used during material initialization |
set = 2 binding = 0 | UNIFORM_BUFFER | material arguments | for example, the immutable uniform buffer owned by the material |
set = 2 binding = 1 | COMBINED_IMAGE_SAMPLER | albedo map | the albedo map owned by the material |
Evidently, by using this pipeline layout, the vkUpdateDescriptorSets is always used during initialization and NEVER used during rendering.
In console, an analog of the ID3D12RootSignature in Direct3D12 can be used.