From 82444703e4bb0fced141fe404676c05190f192a1 Mon Sep 17 00:00:00 2001 From: spencer-lunarg Date: Thu, 18 Dec 2025 03:29:55 -0500 Subject: [PATCH] VK_EXT_descriptor_heap --- README.adoc | 2 + antora/modules/ROOT/nav.adoc | 1 + chapters/descriptor_heap.adoc | 421 ++++++++++++++++++ chapters/images/descriptor_heap_binding.svg | 4 + .../descriptor_heap_blob_example_buffer.svg | 4 + .../descriptor_heap_blob_example_image.svg | 4 + .../descriptor_heap_constant_offset.svg | 4 + .../descriptor_heap_descriptor_example.svg | 4 + .../descriptor_heap_indirect_address.svg | 4 + .../images/descriptor_heap_indirect_index.svg | 4 + .../descriptor_heap_indirect_index_array.svg | 4 + .../images/descriptor_heap_push_address.svg | 4 + chapters/images/descriptor_heap_push_data.svg | 4 + .../images/descriptor_heap_push_index.svg | 4 + .../descriptor_heap_resource_heap_data.svg | 4 + .../images/descriptor_heap_sample_heap.svg | 4 + .../images/descriptor_heap_untyped_access.svg | 4 + .../images/descriptor_heap_untyped_stride.svg | 4 + 18 files changed, 484 insertions(+) create mode 100644 chapters/descriptor_heap.adoc create mode 100644 chapters/images/descriptor_heap_binding.svg create mode 100644 chapters/images/descriptor_heap_blob_example_buffer.svg create mode 100644 chapters/images/descriptor_heap_blob_example_image.svg create mode 100644 chapters/images/descriptor_heap_constant_offset.svg create mode 100644 chapters/images/descriptor_heap_descriptor_example.svg create mode 100644 chapters/images/descriptor_heap_indirect_address.svg create mode 100644 chapters/images/descriptor_heap_indirect_index.svg create mode 100644 chapters/images/descriptor_heap_indirect_index_array.svg create mode 100644 chapters/images/descriptor_heap_push_address.svg create mode 100644 chapters/images/descriptor_heap_push_data.svg create mode 100644 chapters/images/descriptor_heap_push_index.svg create mode 100644 chapters/images/descriptor_heap_resource_heap_data.svg create mode 100644 chapters/images/descriptor_heap_sample_heap.svg create mode 100644 chapters/images/descriptor_heap_untyped_access.svg create mode 100644 chapters/images/descriptor_heap_untyped_stride.svg diff --git a/README.adoc b/README.adoc index 7249667..7159490 100644 --- a/README.adoc +++ b/README.adoc @@ -134,6 +134,8 @@ The Vulkan Guide content is also viewable from https://docs.vulkan.org/guide/lat === xref:{chapters}descriptor_buffer.adoc[Descriptor Buffers (VK_EXT_descriptor_buffer)] +=== xref:{chapters}descriptor_heap.adoc[Descriptor Heaps (VK_EXT_descriptor_heap)] + === xref:{chapters}location_component_interface.adoc[Location and Component Interface] === xref:{chapters}push_constants.adoc[Push Constants] diff --git a/antora/modules/ROOT/nav.adoc b/antora/modules/ROOT/nav.adoc index 9e82269..00b878a 100644 --- a/antora/modules/ROOT/nav.adoc +++ b/antora/modules/ROOT/nav.adoc @@ -52,6 +52,7 @@ *** xref:{chapters}descriptor_arrays.adoc[] *** xref:{chapters}descriptor_dynamic_offset.adoc[] *** xref:{chapters}descriptor_buffer.adoc[] +*** xref:{chapters}descriptor_heap.adoc[] *** xref:{chapters}location_component_interface.adoc[] *** xref:{chapters}push_constants.adoc[] *** xref:{chapters}ways_to_provide_spirv.adoc[] diff --git a/chapters/descriptor_heap.adoc b/chapters/descriptor_heap.adoc new file mode 100644 index 0000000..b2ea9df --- /dev/null +++ b/chapters/descriptor_heap.adoc @@ -0,0 +1,421 @@ +// Copyright 2025 The Khronos Group, Inc. +// SPDX-License-Identifier: CC-BY-4.0 + +ifndef::chapters[:chapters:] +ifndef::images[:images: images/] + +[[descriptor-heap]] += Descriptor Heap + +This chapter aims to illustrate better how link:https://github.com/KhronosGroup/Vulkan-Docs/blob/main/proposals/VK_EXT_descriptor_heap.adoc[VK_EXT_descriptor_heap] mapping of memory works. + +The goal here is **not** to show a real example or recommended usage, but instead help understand how the API is mapping data to the shader, so that afterwards you can use this API in any way you want. + +== What is a descriptor + +A "descriptor" is just small, opaque, data structure that describes how to access the data for your link:https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-resources[resource variables] in your shader. + +This data structure is defined internally by a driver. Prior to `VK_EXT_descriptor_buffer`/`VK_EXT_descriptor_heap` this was abstracted away, but now the application has full control to manage these "descriptor" data structures. + +As an example, for some drivers a `VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER` descriptor is just 16 bytes of data. These 16 bytes for the "descriptor" might encode the virtual address, stride and other meta data in order to read the uniform buffer in the shader. + +Here is a example of what a "descriptor" could look like: + +[source,c++] +---- +0x12345678 0xFFFF0001 0x10101010 0x11223344 +---- + +It is **not important** at all to the developer what the binary data of a descriptor means. What **is important** is understanding that unlike Vulkan 1.0, the driver is now just handing you back an opaque, internal data structure. Instead of having a `VkDescriptorSet` object the driver controls, the application is now responsible to manage that this data is at the correct spot in memory for the GPU to read from. + +=== Multiple descriptors for a single resource + +A descriptor is not always a 1-to-1 relationship with resources such as `VkBuffer`. For example, if there is a 1024 byte `VkBuffer`, it could be divided up into 3 descriptors by setting different offsets and ranges for it. + +image::{images}descriptor_heap_descriptor_example.svg[descriptor_heap_descriptor_example.svg] + +In this image each `Descriptor Blob` is just an indirection pointing to where in the `VkBuffer` the shader will access memory. + +In Vulkan 1.0, the application could not explicitly manage these `Descriptor Blobs`, but with `VK_EXT_descriptor_heap`, the application now controls their corresponding memory allocations. + +== How do we get the descriptor binary blob + +For uniform and storage buffers, you first need to create a `VkBuffer`. + +* With Vulkan 1.0 you would call `vkUpdateDescriptorSets` where the driver would handle it for you. +* With `VK_EXT_descriptor_buffer` you call `vkGetBufferDeviceAddress()` to get the `VkBuffer`'s address, then provide it along with a range to `vkGetDescriptorEXT()`. +* With `VK_EXT_descriptor_heap` it is the same, but the address and range are provided to `vkWriteResourceDescriptorsEXT()` + +image::{images}descriptor_heap_blob_example_buffer.svg[descriptor_heap_blob_example_buffer.svg] + +For sampled image, the same idea applies, except there is no `VkImageView` object for `VK_EXT_descriptor_heap` anymore. +Instead the `VkImageViewCreateInfo` is directly handed to `vkWriteResourceDescriptorsEXT()` where it generates the descriptor there. + +image::{images}descriptor_heap_blob_example_image.svg[descriptor_heap_blob_example_image.svg] + +== The heap + +With `VK_EXT_descriptor_heap` there are explicitly two heaps: + +* one for samplers +* one for other resources (buffers, images, acceleration structures, etc) + +The heap is not a 1:1 relationship with `VkDescriptorSets` and instead should contain all descriptors used in a command buffer. + +== Allocating the heap + +After we have our various descriptors, we need a heap to transfer them to. This is simply done by allocating a `VkBuffer` with the `VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT` (and `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT`) usage flags. + +This `VkBuffer` is now your descriptor heap, the only thing left is to move your descriptor binary blobs into it. + +== Getting descriptors in the heap + +After calling `vkWriteResourceDescriptorsEXT()` to get the descriptor data, we still need to get that data into the heap memory. + +There are 3 ways to copy the descriptors into the heap memory: + +1. If your heap memory is host visible, then using `vkMapMemory()` on the heap, the descriptors can be copied with a simple `memcpy()`. +2. If your heap memory is host visible, set the `vkWriteResourceDescriptorsEXT() pDescriptors->address` to point directly to the descriptor heap. +3. The descriptors can also be transfered on the GPU. This could be done with something like `vkCmdCopyBuffer()` or even writting it from inside a shader directly. + +[NOTE] +==== +Make sure if writing to the heap on the GPU, prior to reading descriptors from the heap on the GPU, to properly synchronized with `VK_ACCESS_2_RESOURCE_HEAP_READ_BIT_EXT` or `VK_ACCESS_2_SAMPLER_HEAP_READ_BIT_EXT`. +==== + +[[descriptor-heap-size]] +=== Descriptor Size + +Each `VkDescriptorType` is going to have a different size for its descriptor blob + +For simplicity, there are few `VkPhysicalDeviceDescriptorHeapPropertiesEXT` values that can be used: + +* `samplerDescriptorSize` +* `bufferDescriptorSize` +* `imageDescriptorSize` + +For some specific use cases it is useful to be able to pack specific descriptors into memory more tightly than this when the implementation allows for this with `vkGetPhysicalDeviceDescriptorSizeEXT`. + +== Binding to the Command Buffer + +When recording the `vkCommandBuffer` we need an equivalent to `vkCmdBindDescriptorSets()` (or `vkCmdBindDescriptorBuffersEXT()`). + +There are 2 basically identical calls, one for each heap - `vkCmdBindSamplerHeapEXT()` and `vkCmdBindResourceHeapEXT()` + +The provided `heapRange` field provides the memory range of the heap to bind. + +There is also a "reserved range" provided. This is memory that the driver will use for internal descriptors it needs. (It is very invalid to access it.) + +[NOTE] +==== +The `minResourceHeapReservedRange` and `minSamplerHeapReservedRange` properties are used to determine how much reserved memory is required. +==== + +The following shows an example (with simple values) of binding both heaps: + +[source,c++] +---- +vkCmdBindResourceHeapEXT( + heapRange.address = 0x1000 + heapRange.size = 0x80 + reservedRangeOffset = 0x40 + reservedRangeSize = 0x20 +); + +vkCmdBindSamplerHeapEXT( + heapRange.address = 0x4020 + heapRange.size = 0x60 + reservedRangeOffset = 0 + reservedRangeSize = 0x20 +); +---- + +image::{images}descriptor_heap_binding.svg[descriptor_heap_binding.svg] + +This also shows how the application has control of where the driver's reserved range ends up. + +=== Rebinding a new heap + +When you call `vkCmdBindResourceHeapEXT()` multiple times in a command buffer, the driver has to swap heaps, which is costly and should be avoided. + +The goal of `VK_EXT_descriptor_heap` is that now the application knows where the heap is bound, it can copy the memory to the correct offset in the heap. + +== Mapping the Heap to exisiting shaders + +To allow applications to easily transition to using `VK_EXT_descriptor_heap`, no shaders have to be modified to use it. + +`VkDescriptorSetLayout` and `VkPipelineLayout` are no longer required with `VK_EXT_descriptor_heap`, instead `VkShaderDescriptorSetAndBindingMappingInfoEXT` is used to map the location in the bound heap to the `DescriptorSet`/`Binding` decoration in the SPIR-V. + +This mapping is provided at `vkCreate*Pipelines()` or `vkCreateShadersEXT()` time. + +=== VkDescriptorMappingSourceEXT + +The first time you look at `VkDescriptorMappingSourceEXT` and all the options, it can be bit overwhelming. It is best to mentally categorize them into 3 types: + +* **Heap Access** +** VK_DESCRIPTOR_MAPPING_SOURCE_**HEAP**_WITH_CONSTANT_OFFSET_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_**HEAP**_WITH_PUSH_INDEX_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_**HEAP**_WITH_INDIRECT_INDEX_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_**HEAP**_WITH_INDIRECT_INDEX_ARRAY_EXT +* **Inline Access** +** VK_DESCRIPTOR_MAPPING_SOURCE_RESOURCE_HEAP_DATA_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_DATA_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT +* **Shader Record** (Ray Tracing) +** VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_**SHADER_RECORD**_INDEX_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_**SHADER_RECORD**_DATA_EXT +** VK_DESCRIPTOR_MAPPING_SOURCE_**SHADER_RECORD**_ADDRESS_EXT + +=== VkDescriptorMappingSourceEXT Heap Access + +To try and give a visual example how these mappings work, first let's setup our heap with 8 descriptors pointing to 8 possible payloads of data. + +In this example, we have a single uniform buffer storing 8 `uvec4` + +We are also using a descriptor to reference each of them separately in order to help make it obvious in the below example which data is actually read. + +image::{images}descriptor_heap_sample_heap.svg[descriptor_heap_sample_heap.svg] + +[NOTE] +==== +The fact that both the descriptor and the uvec4 are both are 16 bytes is just a coincidence. Real applications would not only bind 16 bytes of memory per descriptor as that would be wasteful. +==== + +From here, our shader will attempt to read from 2 descriptors from an array: + +[source,glsl] +---- +// VkDescriptorSetAndBindingMappingEXT::descriptorSet = 0; +// VkDescriptorSetAndBindingMappingEXT::firstBinding = 0; +// VkDescriptorSetAndBindingMappingEXT::bindingCount = 2; +layout(set = 0, binding = 0) uniform UBO { + uvec4 payload; +} u_buffers[2]; + +void main() { + // This example is to figure out what value x and y would be + uvec4 x = u_buffers[0].payload; + uvec4 y = u_buffers[1].payload; +} +---- + +==== VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT + +image::{images}descriptor_heap_constant_offset.svg[descriptor_heap_constant_offset.svg] + +The results are: `x == vec4(2)` and `y == vec4(6)` + +The formula is `offset = heapOffset + (shaderIndex * heapArrayStride)` + +`shaderIndex`, in this and all below cases, is just each index into our descriptor array (`u_buffers[]`) since we are at set/binding 0 + +---- +u_buffers[0] offset = 0x20 + (0 * 0x40) +u_buffers[1] offset = 0x20 + (1 * 0x40) +---- + +==== VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT + +image::{images}descriptor_heap_push_index.svg[descriptor_heap_push_index.svg] + +The results are: `x == vec4(4)` and `y == vec4(5)` + +The formula is `offset = heapOffset + (pushIndex * heapIndexStride) + (shaderIndex * heapArrayStride)` + +The `pushOffset = 8` sets `pushIndex` to `0x10` + +---- +u_buffers[0] offset = 0x20 + (0x10 * 2) + (0 * 0x10) +u_buffers[1] offset = 0x20 + (0x10 * 2) + (1 * 0x10) +---- + +==== VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT + +image::{images}descriptor_heap_indirect_index.svg[descriptor_heap_indirect_index.svg] + +The results are: `x == vec4(3)` and `y == vec4(5)` + +The formula is `offset = heapOffset + (indirectIndex * heapIndexStride) + (shaderIndex * heapArrayStride)` + +The `pushOffset = 16` sets `indirectAddress` to `0x4000` which must be a valid `VkDeviceAddress` of memory backing some `VkBuffer`. The `addressOffset` of `0x40` is applied to that `indirectAddress` to get `0x4040`. We see at `0x4040` the uint32_t value of `0x20`, which becomes the `indirectIndex`. + +---- +u_buffers[0] offset = 0x10 + (0x20 * 1) + (0 * 0x20) +u_buffers[1] offset = 0x10 + (0x20 * 1) + (1 * 0x20) +---- + +==== VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT + +image::{images}descriptor_heap_indirect_index_array.svg[descriptor_heap_indirect_index_array.svg] + +The results are: `x == vec4(6)` and `y == vec4(2)` + +The formula is `offset = heapOffset + (indirectIndex × heapIndexStride)` + +Like the previous example, the `pushOffset = 16` sets `indirectAddress` to `0x4000` plus `addressOffset` of `0x40` is applied to that `indirectAddress` to get `0x4040`. + +From `0x4040`, each `shaderIndex` jumps to the next uint32_t and gets the offset from the indirect uniform buffer. + +---- +u_buffers[0] offset = 0x00 + (0x20 * 1) +u_buffers[1] offset = 0x00 + (0x60 * 1) +---- + +=== VkDescriptorMappingSourceEXT Inline Access + +For these mappings, it is similar to xref:{chapters}extensions/VK_EXT_inline_uniform_block.adoc#VK_EXT_inline_uniform_block[VK_EXT_inline_uniform_block] where the data is read without a descriptor. + +There 2 main restrictions are these have to be Uniform Buffers (read only) and there is no arrays of descriptors in the shader. + +The new shader code looks like: + +[source,glsl] +---- +// VkDescriptorSetAndBindingMappingEXT::bindingCount = 1; +layout(set = 0, binding = 0) uniform UBO { + uvec4 payload[2]; +} u_buffer; + +void main() { + // This example is to figure out what value x and y would be + uvec4 x = u_buffer.payload[0]; + uvec4 y = u_buffer.payload[1]; +} +---- + +==== VK_DESCRIPTOR_MAPPING_SOURCE_RESOURCE_HEAP_DATA_EXT + +image::{images}descriptor_heap_resource_heap_data.svg[descriptor_heap_resource_heap_data.svg] + +The results are: `x == vec4(2)` and `y == vec4(3)` + +The the `pushOffset = 12` gets the offset `0x10` which is applied to the `heapOffset` of `0x80` to make a final offset of `0x90` + +From an offset of `0x90` the remaining offsets depends on where the shader accesses into `u_buffer`. + +Since `payload[1]` is has a 16 (0x10) byte offset into the `u_buffer` struct, it effectively is grabbing `0x90 + 0x10` here. + +==== VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_DATA_EXT + +Using the same shader as the previous example, this just removes the heap and loads directly from the push data. + +image::{images}descriptor_heap_push_data.svg[descriptor_heap_push_data.svg] + +The results are: `x == vec4(2)` and `y == vec4(3)` + +==== VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT + +image::{images}descriptor_heap_push_address.svg[descriptor_heap_push_address.svg] + +The results are: `x == vec4(2)` and `y == vec4(3)` + +This is similar to the previous example, just with an extra level of indirection + +==== VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT + +image::{images}descriptor_heap_indirect_address.svg[descriptor_heap_indirect_address.svg] + +The results are: `x == vec4(2)` and `y == vec4(3)` + +This is similar to the previous example, just with yet-another level of indirection + + +=== VkDescriptorMappingSourceEXT Shader Record + +[NOTE] +==== +todo - Add Ray Tracing section +==== + +== Untyped shader model + +The above usage of `VkShaderDescriptorSetAndBindingMappingInfoEXT` was designed to allow backwards compatibility. + +There is also a new "untyped" way to use `VK_EXT_descriptor_heap`. The word "untyped" refers to using the link:https://github.com/KhronosGroup/SPIRV-Guide/blob/main/chapters/untyped_pointers.md[VK_KHR_shader_untyped_pointers] extension to have "untyped pointers" to the descriptors. + +Using this GLSL as an example: + +[source,glsl] +---- +// Typed +// +// Standard way to provide the set/binding location +layout(set = 0, binding = 0) buffer SSBO { + vec4 payload; +} s_buffers[]; + +layout(set = 0, binding = 1) buffer UBO { + vec4 payload; +} u_buffers[]; + +// ----- + +// Untyped +// +// Both are bound to the heap +layout(descriptor_heap) buffer SSBO { + vec4 payload; +} s_buffers[]; + +layout(descriptor_heap) uniform UBO { + vec4 payload; +} u_buffers[]; +---- + +=== Mapping the Heap to Untyped Pointers shaders + +With "untyped" the descriptor array is just bound where the heap is. + +If the shader code looks like: + +[source,glsl] +---- +// VkPhysicalDeviceDescriptorHeapPropertiesEXT::bufferDescriptorSize == 16 (0x10) +layout(descriptor_heap) buffer SSBO { + vec4 payload; +} s_buffers[]; + +void main() { + s_buffers[6].payload = vec4(1.0); +} +---- + +the mapping now looks like: + +image::{images}descriptor_heap_untyped_access.svg[descriptor_heap_untyped_access.svg] + +=== Mastering strides for each descriptor type + +As <>, descriptors will have different sizes, this means the array stride is going to be different for each descriptor array in the shader. + +[NOTE] +==== +If coming from DX12/HLSL, all the descriptor array are the same size, while this may be a bit more convenient, it is much more wasteful of memory. +==== + +[source,glsl] +---- +// VK_DESCRIPTOR_TYPE_SAMPLER +layout(descriptor_heap) uniform sampler Samplers[]; + +// VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE +layout(descriptor_heap) uniform texture2D Textures[]; + +// VK_DESCRIPTOR_TYPE_STORAGE_BUFFER +layout(descriptor_heap) buffer ssbo { + uint data; +} Buffers[]; +---- + +Here if we would access `Samplers[3]`, `Textures[3]`, or `Buffer[3]` the offset from the heap starting address can be different. + +In this example if the descriptor sizes are: + +* bufferDescriptorSize = 16 +* samplerDescriptorSize = 32 +* imageDescriptorSize = 64 + +we would use that size as an array stride inside the heap. + +image::{images}descriptor_heap_untyped_stride.svg[descriptor_heap_untyped_stride.svg] diff --git a/chapters/images/descriptor_heap_binding.svg b/chapters/images/descriptor_heap_binding.svg new file mode 100644 index 0000000..a8812f0 --- /dev/null +++ b/chapters/images/descriptor_heap_binding.svg @@ -0,0 +1,4 @@ + + + +
unbound
unbound
unbound
VkBuffer
(Resource Heap)
VkBuffer
(Sampler Heap)
reserved
bound
bound
bound
0x1000
0x4000
0x1040
0x1060
0x1080
reserved
0x4020
0x4040
0x1020
0x4060
0x4080
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_blob_example_buffer.svg b/chapters/images/descriptor_heap_blob_example_buffer.svg new file mode 100644 index 0000000..598fd0b --- /dev/null +++ b/chapters/images/descriptor_heap_blob_example_buffer.svg @@ -0,0 +1,4 @@ + + + +
VkBuffer
Descriptor Blob
driver internal VkDescriptorPool memory
uninitialized
Descriptor Blob
vkUpdateDescriptorSets()
offset
range
vkGetDescriptorEXT()
VkBuffer
offset
range
vkGetBufferDeviceAddress()
address
pDescriptor
application-allocated buffer
Descriptor Blob
vkWriteResourceDescriptorsEXT()
VkBuffer
offset
range
vkGetBufferDeviceAddress()
address
pDescriptors[i]
application-allocated buffer
Vulkan 1.0
VK_EXT_descriptor_buffer
VK_EXT_descriptor_heap
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_blob_example_image.svg b/chapters/images/descriptor_heap_blob_example_image.svg new file mode 100644 index 0000000..7f1e925 --- /dev/null +++ b/chapters/images/descriptor_heap_blob_example_image.svg @@ -0,0 +1,4 @@ + + + +

Descriptor Blob
driver internal VkDescriptorPool memory

uninitialized

Descriptor Blob
vkUpdateDescriptorSets()
VkImageLayout
vkGetDescriptorEXT()
pDescriptor
application-allocated buffer

Descriptor Blob
vkWriteResourceDescriptorsEXT()
pDescriptors[i]
application-allocated buffer
Vulkan 1.0
VK_EXT_descriptor_buffer
VK_EXT_descriptor_heap
VkImageLayout
VkImageLayout
VkImageCreateInfo
VkImage
VkImageViewCreateInfo
VkImageView
VkImageCreateInfo
VkImage
VkImageViewCreateInfo
VkImageView
VkImageCreateInfo
VkImage
VkImageViewCreateInfo
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_constant_offset.svg b/chapters/images/descriptor_heap_constant_offset.svg new file mode 100644 index 0000000..a05d2a8 --- /dev/null +++ b/chapters/images/descriptor_heap_constant_offset.svg @@ -0,0 +1,4 @@ + + + +
VkDescriptorMappingSourceConstantOffsetEXT::heapOffset = 0x20
VkDescriptorMappingSourceConstantOffsetEXT::heapArrayStride = 0x40

u_buffers[0]
u_buffers[1]
VkBuffer
(Resource Heap)
0x1000
0x1040
0x1060
0x1080
0x1020
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
Descriptor Blob D
Descriptor Blob E
Descriptor Blob F
Descriptor Blob G
Descriptor Blob H
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_descriptor_example.svg b/chapters/images/descriptor_heap_descriptor_example.svg new file mode 100644 index 0000000..14bbc19 --- /dev/null +++ b/chapters/images/descriptor_heap_descriptor_example.svg @@ -0,0 +1,4 @@ + + + +
0x1000
0x1200
0x1300
0x1400
0x1100
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
1024 bytes bound to a VkBuffer
Offset = 0
Range = 0x100
Offset = 0x200
Range = 0x200
Offset = 0x100
Range = 0x300
Descriptor A
Descriptor B
Descriptor C
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_indirect_address.svg b/chapters/images/descriptor_heap_indirect_address.svg new file mode 100644 index 0000000..7cdac9d --- /dev/null +++ b/chapters/images/descriptor_heap_indirect_address.svg @@ -0,0 +1,4 @@ + + + +
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20parent%3D%221%22%20style%3D%22text%3Bhtml%3D1%3BwhiteSpace%3Dwrap%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dleft%3BverticalAlign%3Dmiddle%3Brounded%3D0%3B%22%20value%3D%22%26lt%3Bfont%20style%3D%26quot%3Bfont-size%3A%2015px%3B%26quot%3B%26gt%3BVkDescriptorMappingSourceConstantOffsetEXT%3A%3A%26lt%3Bb%20style%3D%26quot%3B%26quot%3B%26gt%3B%26lt%3Bfont%20style%3D%26quot%3Bcolor%3A%20rgb(255%2C%200%2C%200)%3B%26quot%3B%26gt%3BheapOffset%26lt%3B%2Ffont%26gt%3B%26lt%3B%2Fb%26gt%3B%20%3D%20%26lt%3Bb%20style%3D%26quot%3B%26quot%3B%26gt%3B%26lt%3Bfont%20style%3D%26quot%3Bcolor%3A%20rgb(0%2C%200%2C%20153)%3B%26quot%3B%26gt%3B0x20%26lt%3B%2Ffont%26gt%3B%26lt%3B%2Fb%26gt%3B%26lt%3B%2Ffont%26gt%3B%26lt%3Bdiv%26gt%3B%26lt%3Bdiv%26gt%3B%26lt%3Bfont%20style%3D%26quot%3Bfont-size%3A%2015px%3B%26quot%3B%26gt%3BVkDescriptorMappingSourceConstantOffsetEXT%3A%3A%26lt%3Bb%26gt%3B%26lt%3Bfont%20style%3D%26quot%3Bcolor%3A%20rgb(255%2C%200%2C%200)%3B%26quot%3B%26gt%3BheapArrayStride%26lt%3B%2Ffont%26gt%3B%26lt%3B%2Fb%26gt%3B%20%3D%20%26lt%3Bb%26gt%3B%26lt%3Bfont%20style%3D%26quot%3Bcolor%3A%20rgb(0%2C%200%2C%20153)%3B%26quot%3B%26gt%3B0x40%26lt%3B%2Ffont%26gt%3B%26lt%3B%2Fb%26gt%3B%26lt%3B%2Ffont%26gt%3B%26lt%3B%2Fdiv%26gt%3B%26lt%3B%2Fdiv%26gt%3B%26lt%3Bdiv%26gt%3B%26lt%3Bbr%26gt%3B%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2270%22%20width%3D%22550%22%20x%3D%22455%22%20y%3D%22540%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%223%22%20edge%3D%221%22%20parent%3D%221%22%20style%3D%22endArrow%3Dnone%3Bdashed%3D1%3Bhtml%3D1%3BdashPattern%3D1%203%3BstrokeWidth%3D2%3Brounded%3D0%3B%22%20value%3D%22%22%3E%3CmxGeometry%20height%3D%2250%22%20relative%3D%221%22%20width%3D%2250%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%221000%22%20y%3D%22599.1700000000001%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22450%22%20y%3D%22599.1700000000001%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
vkCmdPushDataEXT was called and set the internal push data as
0x0000
0x4010
0
8
16
0x2000
0x0000
24
VkBuffer
(Uniform Buffer)
0x8000
uvec4(1)
0x8020
0x8040
u_buffer
VkBuffer
(Uniform Buffer)
0x4000
0x2000
0x4000
0x0000
0x8010
0x4010
0x4020
VkDescriptorMappingSourceIndirectAddressEXT::pushOffset = 16
VkDescriptorMappingSourceIndirectAddressEXT::addressOffset = 8

uvec4(2)
uvec4(3)
uvec4(4)
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_indirect_index.svg b/chapters/images/descriptor_heap_indirect_index.svg new file mode 100644 index 0000000..1de0e7d --- /dev/null +++ b/chapters/images/descriptor_heap_indirect_index.svg @@ -0,0 +1,4 @@ + + + +
VkDescriptorMappingSourceIndirectIndexEXT::heapOffset = 0x10
VkDescriptorMappingSourceIndirectIndexEXT::pushOffset = 16
VkDescriptorMappingSourceIndirectIndexEXT::addressOffset = 0x40
VkDescriptorMappingSourceIndirectIndexEXT::heapIndexStride = 1
VkDescriptorMappingSourceIndirectIndexEXT::heapArrayStride = 0x20

0x0000
vkCmdPushDataEXT was called and set the internal push data as
0x4000
0
4
8
12
16
20
0x2000
0x0000
24
28
VkBuffer
(Uniform Buffer)
0x4000
0x4040
0x4060
0x4020
uninitialized
0x20
uninitialized
u_buffers[0]
u_buffers[1]
VkBuffer
(Resource Heap)
0x1000
0x1040
0x1060
0x1080
0x1020
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
Descriptor Blob D
Descriptor Blob E
Descriptor Blob F
Descriptor Blob G
Descriptor Blob I
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_indirect_index_array.svg b/chapters/images/descriptor_heap_indirect_index_array.svg new file mode 100644 index 0000000..b0cc0a2 --- /dev/null +++ b/chapters/images/descriptor_heap_indirect_index_array.svg @@ -0,0 +1,4 @@ + + + +
VkDescriptorMappingSourceIndirectIndexArrayEXT::heapOffset = 0
VkDescriptorMappingSourceIndirectIndexArrayEXT::pushOffset = 16
VkDescriptorMappingSourceIndirectIndexArrayEXT::addressOffset = 0x40
VkDescriptorMappingSourceIndirectIndexArrayEXT::heapIndexStride = 1

VkBuffer
(Uniform Buffer)
0x4040
0x4050
0x4048
0x60
0x20
0x00
0x40
0x0000
vkCmdPushDataEXT was called and set the internal push data as
0x4000
0
4
8
12
16
20
0x2000
0x0000
24
28
u_buffers[1]
u_buffers[0]
VkBuffer
(Resource Heap)
0x1000
0x1040
0x1060
0x1080
0x1020
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
Descriptor Blob D
Descriptor Blob E
Descriptor Blob F
Descriptor Blob G
Descriptor Blob H
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_push_address.svg b/chapters/images/descriptor_heap_push_address.svg new file mode 100644 index 0000000..dc2e701 --- /dev/null +++ b/chapters/images/descriptor_heap_push_address.svg @@ -0,0 +1,4 @@ + + + +
pushAddressOffset = 16
vkCmdPushDataEXT was called and set the internal push data as
0x0000
0x4010
0
8
16
0x2000
0x0000
24
VkBuffer
(Uniform Buffer)
0x4000
uvec4(1)
uvec4(2)
uvec4(3)
uvec4(4)
0x4020
0x4040
u_buffer
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_push_data.svg b/chapters/images/descriptor_heap_push_data.svg new file mode 100644 index 0000000..bb40277 --- /dev/null +++ b/chapters/images/descriptor_heap_push_data.svg @@ -0,0 +1,4 @@ + + + +
pushDataOffset = 0x16

vkCmdPushDataEXT was called and set the internal push data as
0
48
16
32
u_buffer
uvec4(1)
uvec4(2)
uvec4(3)
uvec4(4)
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_push_index.svg b/chapters/images/descriptor_heap_push_index.svg new file mode 100644 index 0000000..fb0bdb2 --- /dev/null +++ b/chapters/images/descriptor_heap_push_index.svg @@ -0,0 +1,4 @@ + + + +
VkDescriptorMappingSourcePushIndexEXT::heapOffset = 0x20
VkDescriptorMappingSourcePushIndexEXT::pushOffset = 8
VkDescriptorMappingSourcePushIndexEXT::heapIndexStride = 2
VkDescriptorMappingSourcePushIndexEXT::heapArrayStride = 0x10

0x40
vkCmdPushDataEXT was called and set the internal push data as
0x30
0x40
0
4
8
12
16
20
0x40
0x20
0x10
0x00
0x00
24
28
u_buffers[0]
u_buffers[1]
VkBuffer
(Resource Heap)
0x1000
0x1040
0x1060
0x1080
0x1020
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
Descriptor Blob D
Descriptor Blob E
Descriptor Blob F
Descriptor Blob G
Descriptor Blob H
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_resource_heap_data.svg b/chapters/images/descriptor_heap_resource_heap_data.svg new file mode 100644 index 0000000..51381ef --- /dev/null +++ b/chapters/images/descriptor_heap_resource_heap_data.svg @@ -0,0 +1,4 @@ + + + +
VkDescriptorMappingSourceHeapDataEXT::heapOffset = 0x80
VkDescriptorMappingSourceHeapDataEXT::pushOffset = 12
vkCmdPushDataEXT was called and set the internal push data as
0
4
8
12
16
20
24
28
u_buffer
VkBuffer
(Resource Heap)
0x1000
0x1040
0x1060
0x1080
0x1020
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
Descriptor Blob D
Descriptor Blob E
Descriptor Blob F
Descriptor Blob G
Descriptor Blob H
uvec4(1)
uvec4(2)
uvec4(3)
uvec4(4)
0x20
0x10
0
0
0
0
0x40
0
0x10A0
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_sample_heap.svg b/chapters/images/descriptor_heap_sample_heap.svg new file mode 100644 index 0000000..ad4c32d --- /dev/null +++ b/chapters/images/descriptor_heap_sample_heap.svg @@ -0,0 +1,4 @@ + + + +
0x8000
0x8040
0x8060
0x8080
0x8020
uvec4(0)
uvec4(1)
uvec4(2)
uvec4(3)
uvec4(4)
uvec4(5)
uvec4(6)
uvec4(7)
VkBuffer
(Resource Heap)
0x1000
0x1040
0x1060
0x1080
0x1020
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
Descriptor Blob D
Descriptor Blob E
Descriptor Blob F
Descriptor Blob G
Descriptor Blob H
VkBuffer
(Uniform Buffer)
Simple buffer, filled with eight uvec4 (16 bytes wide)
Each descriptor is 16 bytes, and points to single uvec4
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_untyped_access.svg b/chapters/images/descriptor_heap_untyped_access.svg new file mode 100644 index 0000000..eeae6b8 --- /dev/null +++ b/chapters/images/descriptor_heap_untyped_access.svg @@ -0,0 +1,4 @@ + + + +
unbound
VkBuffer
(Resource Heap)
reserved
bound
(uninitialized)
0x1000
0x1040
0x1060
0x1080
0x1020
Descriptor Blob A
Descriptor Blob B
Descriptor Blob C
Descriptor Blob D
VkBuffer
(Storage Buffer)
0x2000
0x2040
0x2020
undef
undef
Writes vec4(1)
undef
bufferDescriptorSize * [6] = 96 (0x60
We access at offset of:
Descriptor Blob C
Encodes address of 0x2020
address bound to
VkCommandBuffer
\ No newline at end of file diff --git a/chapters/images/descriptor_heap_untyped_stride.svg b/chapters/images/descriptor_heap_untyped_stride.svg new file mode 100644 index 0000000..25b1a92 --- /dev/null +++ b/chapters/images/descriptor_heap_untyped_stride.svg @@ -0,0 +1,4 @@ + + + +
Buffers[0]
Buffers[1]
Buffers[2]
Buffers[3]
VkBuffer
(Resource Heap)
0x1000
0x1040
0x1060
0x1080
0x1020
bufferDescriptorSize     = 0x10 (16)
samplerDescriptorSize = 0x20 (32)
imageDescriptorSize    = 0x40 (64)
address bound to
VkCommandBuffer
0x10A0
0x10C0
0x10E0
0x1100
Samplers[0]
Samplers[1]
Samplers[2]
Samplers[3]
Textures[0]
Textures[1]
Textures[2]
Textures[3]
\ No newline at end of file