KhronosGroup / KhronosGroup/Vulkan-Docs

[Roadmap Feedback] Better batched Descriptor writing in VK_EXT_descriptor_heap

Open
#2,711 2 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.