KhronosGroup / KhronosGroup/Vulkan-Docs
[Roadmap Feedback] Better batched Descriptor writing in VK_EXT_descriptor_heap
- Dominant language
- JavaScript
- Stars
- 3.3k
- Forks
- 549
- Avg merge
- 5d 5h
- Merged PRs (30d)
- 2
Description
## Problem statement:
The Vulkan WG has been asking for VK_EXT_descriptor_heap feedback while its still an EXT.
Heaps are a massive improvement for my game engine compared to previous descriptor models. Especially vkWriteResourceDescriptorsEXT offering batched descriptor writes is nice for performance benefits, however the batching API introduces unnecessary friction and error potential.
The current struct design forces separately managing multiple parallel arrays that are linked via stable pointers making it difficult to build a batch write incrementally. For Image descriptors specifically the pointer chain is three levels deep: VkResourceDescriptorInfoEXT.data.pImage -> VkImageDescriptorInfoEXT.pView -> VkImageViewCreateInfo
This means the application requires managing:
- VkResourceDescriptorInfoEXT, VkHostAddressRangeEXT [Textures + Buffers] managed by resource updates index
- VkImageViewCreateInfo, VkImageDescriptorInfoEXT [Textures] managed by texture updates index
- VkDeviceAddressRangeEXT [Buffers] managed by buffer updates index
This is similar to the pointer stability problem vkUpdateDescriptorSets had re-introduced.
The design exposes even more friction when trying to only write the latest descriptor update for a resource because it forces obtaining/using decoupled index spaces for both the update Index and the specific resource Index!
## Use Case Example(s):
My Zig engine code
```zig
pub const DescUpdate = struct {
mainIndex: u32, // slot in descInfos and hostRanges
specificIndex: u32, // slot in devRanges or imgDescs and imgViews
};
// Descriptor Updates
descInfos: [DESC_POOL_MAX]vk.VkResourceDescriptorInfoEXT = undefined,
hostRanges: [DESC_POOL_MAX]vk.VkHostAddressRangeEXT = undefined,
// Buffer Updates
bufUpdates: SimpleMap(DescUpdate, rc.BUF_MAX * rc.MAX_IN_FLIGHT, u32, DESC_POOL_MAX, 0) = .{},
devRanges: [rc.BUF_MAX * MAX_IN_FLIGHT]vk.VkDeviceAddressRangeEXT = undefined,
// Image Updates
texUpdates: SimpleMap(DescUpdate, rc.TEX_MAX * rc.MAX_IN_FLIGHT, u32, DESC_POOL_MAX, 0) = .{},
imgViews: [rc.TEX_MAX * 2 * MAX_IN_FLIGHT]vk.VkImageViewCreateInfo = undefined,
imgDescs: [rc.TEX_MAX * 2 * MAX_IN_FLIGHT]vk.VkImageDescriptorInfoEXT = undefined,
pub fn queueTextureDescriptor(self: *DescriptorMan, texMeta: *const TextureMeta, texture: *Texture) !void {
if (texture.descIndex == null) texture.descIndex = try self.getFreeDescriptorIndex();
const descUpdate = self.getOrCreateUpdate(texture.descIndex.?, Texture);
self.imgViews[descUpdate.specificIndex] = vhF.getViewCreateInfo(texture.img, texMeta.viewType, texMeta.format, texMeta.subRange);
self.imgDescs[descUpdate.specificIndex] = vk.VkImageDescriptorInfoEXT{
.sType = vk.VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT,
.pView = &self.imgViews[descUpdate.specificIndex], // Pointer
.layout = vk.VK_IMAGE_LAYOUT_GENERAL,
};
self.descInfos[descUpdate.mainIndex] = vk.VkResourceDescriptorInfoEXT{
.sType = vk.VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT,
.type = if (texMeta.texType == .Color) vk.VK_DESCRIPTOR_TYPE_STORAGE_IMAGE else vk.VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.data = .{ .pImage = &self.imgDescs[descUpdate.specificIndex] }, // Pointer
};
}
pub fn updateDescriptors(self: *DescriptorMan, gpi: vk.VkDevice, flightId: u8) !void {
try vhF.check(vkFn.vkWriteResourceDescriptorsEXT.?(gpi, count, &self.descInfos, &self.hostRanges), "Failed to write Descriptor");
self.bufUpdates.clear();
self.texUpdates.clear();
}
```
## (Optional) Suggested Solution(s) :
For example flat structs per resource type that contain all needed data with no pointers and a single array passed to a (new) command something like:
```c
// One struct, one array something like:
typedef struct VkImageDescriptorWriteEXT {
VkHostAddressRangeEXT destination;
VkDescriptorType type;
VkImageViewCreateInfo view; // inlined, not pointed to
VkImageLayout layout;
} VkImageDescriptorWriteEXT;
typedef struct VkBufferDescriptorWriteEXT {
VkHostAddressRangeEXT destination;
VkDescriptorType type;
VkDeviceAddress address;
VkDeviceSize size;
} VkBufferDescriptorWriteEXT;
```
Note: VkImageViewCreateInfo contains a pNext chain, an inlined variant would require pNext to be NULL, or a flat struct without the chain.
Contributor guide
Research direction
No repository file or test is named. Start with the VK_EXT_descriptor_heap definition and vkWriteResourceDescriptorsEXT usage described in the issue, then compare the pointer-linked structures with the proposed flat write structs; done means a concrete, reviewed recommendation for the batching API.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, zig
- Domain
- backend-api-design, computer-graphics
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100