-- v4: vkd3d: Use mutable descriptors if available.
From: Conor McCarthy cmccarthy@codeweavers.com
The mutable descriptor type allows six descriptor sets to be replaced with one set for CBV/SRV/UAV heaps. --- libs/vkd3d/command.c | 3 ++- libs/vkd3d/device.c | 40 +++++++++++++++++++++++++++++++++++++- libs/vkd3d/resource.c | 22 +++++++++++++++++---- libs/vkd3d/state.c | 23 ++++++++++++++++++++-- libs/vkd3d/vkd3d_private.h | 1 + 5 files changed, 81 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 15c8317b1..e9477c957 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -3266,7 +3266,8 @@ static void d3d12_command_list_bind_descriptor_heap(struct d3d12_command_list *l { VkDescriptorSet vk_descriptor_set = heap->vk_descriptor_sets[set].vk_set;
- if (!vk_descriptor_set) + /* Null vk_set_layout means set 0 uses mutable descriptors, and this set is unused. */ + if (!vk_descriptor_set || !list->device->vk_descriptor_heap_layouts[set].vk_set_layout) continue;
VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point, rs->vk_pipeline_layout, diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 5c801ca46..799133af4 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -94,6 +94,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker), VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable), VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing), + VK_EXTENSION(EXT_MUTABLE_DESCRIPTOR_TYPE, EXT_mutable_descriptor_type), VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2), VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation), VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export), @@ -106,13 +107,32 @@ static HRESULT vkd3d_create_vk_descriptor_heap_layout(struct d3d12_device *devic { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_info; + VkMutableDescriptorTypeCreateInfoEXT mutable_info; + VkMutableDescriptorTypeListEXT type_list; VkDescriptorSetLayoutCreateInfo set_desc; VkDescriptorBindingFlagsEXT set_flags; VkDescriptorSetLayoutBinding binding; VkResult vr;
+ static const VkDescriptorType descriptor_types[] = + { + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + }; + + if (device->vk_info.EXT_mutable_descriptor_type && index && index != VKD3D_SET_INDEX_UAV_COUNTER + && device->vk_descriptor_heap_layouts[index].applicable_heap_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) + { + device->vk_descriptor_heap_layouts[index].vk_set_layout = VK_NULL_HANDLE; + return S_OK; + } + binding.binding = 0; - binding.descriptorType = device->vk_descriptor_heap_layouts[index].type; + binding.descriptorType = (device->vk_info.EXT_mutable_descriptor_type && !index) + ? VK_DESCRIPTOR_TYPE_MUTABLE_EXT : device->vk_descriptor_heap_layouts[index].type; binding.descriptorCount = device->vk_descriptor_heap_layouts[index].count; binding.stageFlags = VK_SHADER_STAGE_ALL; binding.pImmutableSamplers = NULL; @@ -132,6 +152,17 @@ static HRESULT vkd3d_create_vk_descriptor_heap_layout(struct d3d12_device *devic flags_info.bindingCount = 1; flags_info.pBindingFlags = &set_flags;
+ if (binding.descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_EXT) + { + type_list.descriptorTypeCount = ARRAY_SIZE(descriptor_types); + type_list.pDescriptorTypes = descriptor_types; + mutable_info.sType = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT; + mutable_info.pNext = NULL; + mutable_info.mutableDescriptorTypeListCount = 1; + mutable_info.pMutableDescriptorTypeLists = &type_list; + flags_info.pNext = &mutable_info; + } + if ((vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL, &device->vk_descriptor_heap_layouts[index].vk_set_layout))) < 0) { @@ -763,6 +794,7 @@ struct vkd3d_physical_device_info VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features; VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features; VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore_features; + VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutable_features;
VkPhysicalDeviceFeatures2 features2; }; @@ -780,6 +812,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features; VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features; VkPhysicalDeviceTimelineSemaphoreFeaturesKHR *timeline_semaphore_features; + VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *mutable_features; VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features; VkPhysicalDeviceMaintenance3Properties *maintenance3_properties; VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb_properties; @@ -800,6 +833,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i vertex_divisor_features = &info->vertex_divisor_features; vertex_divisor_properties = &info->vertex_divisor_properties; timeline_semaphore_features = &info->timeline_semaphore_features; + mutable_features = &info->mutable_features; xfb_features = &info->xfb_features; xfb_properties = &info->xfb_properties;
@@ -823,6 +857,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i vk_prepend_struct(&info->features2, vertex_divisor_features); timeline_semaphore_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; vk_prepend_struct(&info->features2, timeline_semaphore_features); + mutable_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT; + vk_prepend_struct(&info->features2, mutable_features);
if (vulkan_info->KHR_get_physical_device_properties2) VK_CALL(vkGetPhysicalDeviceFeatures2KHR(physical_device, &info->features2)); @@ -1594,6 +1630,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, vulkan_info->EXT_shader_demote_to_helper_invocation = false; if (!physical_device_info->texel_buffer_alignment_features.texelBufferAlignment) vulkan_info->EXT_texel_buffer_alignment = false; + if (!physical_device_info->mutable_features.mutableDescriptorType) + vulkan_info->EXT_mutable_descriptor_type = false; if (!physical_device_info->timeline_semaphore_features.timelineSemaphore) vulkan_info->KHR_timeline_semaphore = false;
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index abbdfbe20..2f7a3d441 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -2470,12 +2470,14 @@ static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_hea { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct d3d12_descriptor_heap_vk_set *descriptor_set; - enum vkd3d_vk_descriptor_set_index set; + enum vkd3d_vk_descriptor_set_index set, end; unsigned int i = writes->count;
+ end = device->vk_info.EXT_mutable_descriptor_type ? VKD3D_SET_INDEX_UNIFORM_BUFFER + : VKD3D_SET_INDEX_STORAGE_IMAGE; /* Binding a shader with the wrong null descriptor type works in Windows. * To support that here we must write one to all applicable Vulkan sets. */ - for (set = VKD3D_SET_INDEX_UNIFORM_BUFFER; set <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++set) + for (set = VKD3D_SET_INDEX_UNIFORM_BUFFER; set <= end; ++set) { descriptor_set = &descriptor_heap->vk_descriptor_sets[set]; writes->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -4175,9 +4177,11 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_pool(struct d3d12_descrip
for (set = 0, pool_desc.poolSizeCount = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set) { - if (device->vk_descriptor_heap_layouts[set].applicable_heap_type == desc->Type) + if (device->vk_descriptor_heap_layouts[set].applicable_heap_type == desc->Type + && device->vk_descriptor_heap_layouts[set].vk_set_layout) { - pool_sizes[pool_desc.poolSizeCount].type = device->vk_descriptor_heap_layouts[set].type; + pool_sizes[pool_desc.poolSizeCount].type = (device->vk_info.EXT_mutable_descriptor_type && !set) + ? VK_DESCRIPTOR_TYPE_MUTABLE_EXT : device->vk_descriptor_heap_layouts[set].type; pool_sizes[pool_desc.poolSizeCount++].descriptorCount = desc->NumDescriptors; } } @@ -4203,6 +4207,16 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_set(struct d3d12_descript VkDescriptorSetAllocateInfo set_desc; VkResult vr;
+ if (!device->vk_descriptor_heap_layouts[set].vk_set_layout) + { + /* Set 0 uses mutable descriptors, and this set is unused. */ + if (!descriptor_heap->vk_descriptor_sets[0].vk_set) + d3d12_descriptor_heap_create_descriptor_set(descriptor_heap, device, 0); + descriptor_set->vk_set = descriptor_heap->vk_descriptor_sets[0].vk_set; + descriptor_set->vk_type = device->vk_descriptor_heap_layouts[set].type; + return S_OK; + } + set_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; set_desc.pNext = &set_size; set_desc.descriptorPool = descriptor_heap->vk_descriptor_pool; diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 9a039452c..84b6dd3be 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -848,7 +848,20 @@ static void vkd3d_descriptor_heap_binding_from_descriptor_range(const struct d3d const struct vkd3d_device_descriptor_limits *descriptor_limits = &root_signature->device->vk_info.descriptor_limits; unsigned int descriptor_set_size;
- switch (range->type) + if (root_signature->device->vk_info.EXT_mutable_descriptor_type) + { + if (range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER) + { + binding->set = VKD3D_SET_INDEX_SAMPLER; + descriptor_set_size = descriptor_limits->sampler_max_descriptors; + } + else + { + binding->set = 0; + descriptor_set_size = descriptor_limits->sampled_image_max_descriptors; + } + } + else switch (range->type) { case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV: binding->set = is_buffer ? VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER : VKD3D_SET_INDEX_SAMPLED_IMAGE; @@ -1368,8 +1381,14 @@ static unsigned int d3d12_root_signature_copy_descriptor_set_layouts(const struc
if (device->use_vk_heaps) { + VkDescriptorSetLayout mutable_layout = device->vk_descriptor_heap_layouts[0].vk_set_layout; + for (set = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set) - vk_set_layouts[i++] = device->vk_descriptor_heap_layouts[set].vk_set_layout; + { + VkDescriptorSetLayout vk_set_layout = device->vk_descriptor_heap_layouts[set].vk_set_layout; + /* All layouts must be valid, so if null, just set it to the mutable one. */ + vk_set_layouts[i++] = vk_set_layout ? vk_set_layout : mutable_layout; + } }
return i; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index e0eb9f3d3..a07499913 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -133,6 +133,7 @@ struct vkd3d_vulkan_info bool EXT_debug_marker; bool EXT_depth_clip_enable; bool EXT_descriptor_indexing; + bool EXT_mutable_descriptor_type; bool EXT_robustness2; bool EXT_shader_demote_to_helper_invocation; bool EXT_shader_stencil_export;
Another thing that `VK_EXT_mutable_descriptor_type` enables is flags `VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT` and `VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT`. How hard/useful would it be to support those? AFAIU using those bits we're less constrained by the total number of descriptors in unused heaps and by synchronization requirements.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d/device.c:
VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker), VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable), VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing),
- VK_EXTENSION(EXT_MUTABLE_DESCRIPTOR_TYPE, EXT_mutable_descriptor_type),
Enabling the extension is not enough. You also have to check and enable `VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT::mutableDescriptorType`. More in general, the Vulkan validation layer seems to have a few comments about your implementation (eventually we should probably consider enabling the validation layers in the CI).
On Mon Dec 18 15:58:25 2023 +0000, Giovanni Mascellani wrote:
Enabling the extension is not enough. You also have to check and enable `VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT::mutableDescriptorType`. More in general, the Vulkan validation layer seems to have a few comments about your implementation (eventually we should probably consider enabling the validation layers in the CI).
These are fixed by the changes I pushed earlier.
On Wed Dec 20 04:23:18 2023 +0000, Giovanni Mascellani wrote:
Another thing that `VK_EXT_mutable_descriptor_type` enables is flags `VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT` and `VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT`. How hard/useful would it be to support those? AFAIU using those bits we're less constrained by the total number of descriptors in unused heaps and by synchronization requirements.
Host-only d3d12 heaps are not backed by Vulkan descriptor sets at all, and this can't be changed in the current implementation due to how we handle the concurrent writes problem.
EXT_mutable_descriptor_type requires Vulkan-Headers 1.3.228. That's fine, but please update the README.