Add a new sample VK_KHR_device_address_commands. #1547
Conversation
|
This seems to run just fine for me, but I do get one validation error: |
There was a problem hiding this comment.
Pull request overview
This PR adds a new Vulkan-Samples extension sample showcasing VK_KHR_device_address_commands, demonstrating a GPU-driven rendering path that records bind/fill/update/draw operations using device addresses (instead of VkBuffer handles), along with accompanying documentation and build/docs integration.
Changes:
- Added a new
device_address_commandsextension sample implementation (C++), including runtime loading ofVK_KHR_device_address_commandsentry points and address-range barriers. - Added GLSL + Slang shader implementations for compute-driven animation/culling and indirect drawing.
- Integrated the sample into the extensions README, Antora navigation, and the sample build order list.
Reviewed changes
Copilot reviewed 16 out of 22 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
samples/extensions/device_address_commands/device_address_commands.cpp |
New sample implementation using address-based fill/update/bind/draw + memory-range barriers |
samples/extensions/device_address_commands/device_address_commands.h |
Sample interface + shared constants and push-constant struct definitions |
samples/extensions/device_address_commands/CMakeLists.txt |
Build integration for the new sample and shader compilation inputs |
shaders/device_address_commands/glsl/update_objects.comp |
Compute shader (GLSL) that animates objects, culls, and emits indirect commands |
shaders/device_address_commands/glsl/render.vert |
Vertex shader (GLSL) reading camera/transforms via buffer references in push constants |
shaders/device_address_commands/glsl/render.frag |
Fragment shader (GLSL) outputting per-instance color |
shaders/device_address_commands/slang/update_objects.comp.slang |
Compute shader (Slang) equivalent using pointer-based access |
shaders/device_address_commands/slang/render.vert.slang |
Vertex shader (Slang) equivalent using pointer-based access |
shaders/device_address_commands/slang/render.frag.slang |
Fragment shader (Slang) equivalent |
samples/extensions/device_address_commands/README.adoc |
New tutorial-style documentation for the sample and extension concepts |
samples/extensions/README.adoc |
Adds the new sample to the Extensions samples README list |
samples/CMakeLists.txt |
Adds the sample to the global sample ordering list |
antora/modules/ROOT/nav.adoc |
Adds the new sample docs page to the Antora navigation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| VkBufferMemoryBarrier barrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; | ||
| barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | ||
| barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | ||
| barrier.buffer = dst.handle; | ||
| barrier.offset = 0; | ||
| barrier.size = VK_WHOLE_SIZE; | ||
| vkCmdPipelineBarrier(cmd->get_handle(), | ||
| VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, | ||
| 0, 0, nullptr, 1, &barrier, 0, nullptr); |
| // Buffer device address — requested through VkPhysicalDeviceVulkan12Features | ||
| // because we also request drawIndirectCount from the same struct. The spec | ||
| // forbids having both VkPhysicalDeviceVulkan12Features and the standalone | ||
| // VkPhysicalDeviceBufferDeviceAddressFeatures in the pNext chain at once. | ||
| REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDeviceBufferDeviceAddressFeatures, bufferDeviceAddress); |
| * sets required. A distance-based visibility test (also in the compute shader) sets | ||
| * instanceCount=0 for far objects, while vkCmdDrawIndexedIndirectCount2KHR reads the | ||
| * draw count from a device address previously written by vkCmdFillMemoryKHR. |
| // 1. Write VP matrix by address (replaces vkCmdUpdateBuffer) | ||
| vkCmdUpdateMemoryKHR(cmd, &{camera.address, sizeof(mat4)}, 0, 64, &vp); | ||
|
|
||
| // 2. Zero draw count by address (replaces vkCmdFillBuffer) | ||
| vkCmdFillMemoryKHR(cmd, &{draw_count.address, 4}, 0, 0u); |
| push constants. The two push-constant structs mirror each other between the | ||
| C++ host and the shader: | ||
|
|
||
| .Compute push constants (56 bytes, matching `DeviceAddressCommands::PushCompute`) |
| uint index_count; // = 24 | ||
| uint instance_count; // = 1 (visible) or 0 (culled) | ||
| uint first_index; // = 0 |
| OrbitParams* orbit_params; // 64-bit device address at offset 8 | ||
| float4x4* transforms; // 64-bit device address at offset 16 | ||
| DrawCmd* draw_cmds; // 64-bit device address at offset 24 | ||
| uint* draw_count; // 64-bit device address at offset 32 | ||
| float3 camera_pos; // offset 40 | ||
| float _pad; // offset 52 |
| float time; // 0 animation clock | ||
| float max_vis_dist; // 4 culling distance | ||
| OrbitParamsRef orbit_params; // 8 device address (64-bit) | ||
| TransformRef transforms; // 16 | ||
| DrawCmdsRef draw_cmds; // 24 | ||
| DrawCountRef draw_count; // 32 | ||
| vec3 camera_pos; // 40 | ||
| float _pad; // 52 | ||
| } pc; |
SaschaWillems
left a comment
There was a problem hiding this comment.
Sample is working for me on WIn11 and an nv RTX 4070.
I noticed a few naming/styling related thing in code that should be improved. But nothing functional.
| stages[0] = load_shader("device_address_commands", "render.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); | ||
| stages[1] = load_shader("device_address_commands", "render.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); | ||
|
|
||
| ci.pVertexInputState = &vis; |
There was a problem hiding this comment.
Minor style issue, but all other sample use proper variable names like this:
pipeline_create_info.pInputAssemblyState = &input_assembly_state;
pipeline_create_info.pRasterizationState = &rasterization_state;
pipeline_create_info.pColorBlendState = &color_blend_state;
pipeline_create_info.pMultisampleState = &multisample_state;
pipeline_create_info.pViewportState = &viewport_state;
pipeline_create_info.pDepthStencilState = &depth_stencil_state;
pipeline_create_info.pDynamicState = &dynamic_state;
pipeline_create_info.layout = pipeline_layout;
To stay consistent, this sample should follow the same rule.
| ci.pStages = stages.data(); | ||
| ci.stageCount = static_cast<uint32_t>(stages.size()); | ||
|
|
||
| VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), VK_NULL_HANDLE, |
There was a problem hiding this comment.
Looks like this file has been written with a fixed 80 column line width. That produces odd line breaks like these which also don't fall in line with the other samples.
| // ------------------------------------------------------------------------- | ||
| // VK_KHR_device_address_commands function pointers (loaded at runtime) | ||
| // ------------------------------------------------------------------------- | ||
| PFN_vkCmdFillMemoryKHR fn_vkCmdFillMemoryKHR{nullptr}; |
There was a problem hiding this comment.
No other sample uses the "fn_" prefix for declaring function pointers. As these are part of a separate namespace, they're not required anyway.
| // back through a buffer_reference pointer (no descriptor sets required). | ||
| // This is the address-based replacement for vkCmdUpdateBuffer. | ||
| // =========================================================================== | ||
| { |
There was a problem hiding this comment.
The scoped areas here feel superfluous. Are they really required?
|
|
||
| // VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT is required to call | ||
| // vkGetBufferDeviceAddress on memory bound to this buffer. | ||
| VkMemoryAllocateFlagsInfo mafi{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO}; |
There was a problem hiding this comment.
As noted earlier: Those variables should have proper names. Would also prefer to have designated initializers in here. So:
VkMemoryAllocateFlagsInfo mafi{.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO}
This requires updating Vulkan.
Tested in Ubuntu Linux on NVIDIA.
Description
Please include a summary of the change, new sample or fixed issue. Please also include relevant motivation and context.
Please read the contribution guidelines
Fixes #
General Checklist:
Please ensure the following points are checked:
Note: The Samples CI runs a number of checks including:
If this PR contains framework changes:
batchcommand line argument to make sure all samples still work properlySample Checklist
If your PR contains a new or modified sample, these further checks must be carried out in addition to the General Checklist: