From b0d1fb7d987b603b6709128729d77a785f5532d3 Mon Sep 17 00:00:00 2001 From: Conor McCarthy Date: Thu, 14 Dec 2023 14:58:19 +1000 Subject: [PATCH] vkd3d: Use mutable descriptors if available. The mutable descriptor type allows six descriptor sets to be replaced with one set for CBV/SRV/UAV heaps. --- README | 2 +- configure.ac | 2 +- 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 + 7 files changed, 83 insertions(+), 10 deletions(-) diff --git a/README b/README index 01078723..5cb8ebb3 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ similar, but not identical, to Direct3D 12. Building vkd3d ============== -Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.2.148). +Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.3.228). Vkd3d generates some of its headers from IDL files. If you are using the release tarballs, then these headers are pre-generated and are included. If diff --git a/configure.ac b/configure.ac index c7e6994a..0b84b1ab 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ AS_IF([test "x$ac_cv_header_spirv_unified1_GLSL_std_450_h" != "xyes" \ -a "x$ac_cv_header_vulkan_GLSL_std_450_h" != "xyes"], [AC_MSG_ERROR([GLSL.std.450.h not found.])]) -VKD3D_CHECK_VULKAN_HEADER_VERSION([148], [AC_MSG_ERROR([Vulkan headers are too old, 1.2.148 is required.])]) +VKD3D_CHECK_VULKAN_HEADER_VERSION([228], [AC_MSG_ERROR([Vulkan headers are too old, 1.3.228 is required.])]) AC_CHECK_DECL([SpvCapabilityDemoteToHelperInvocationEXT],, [AC_MSG_ERROR([SPIR-V headers are too old.])], [ #ifdef HAVE_SPIRV_UNIFIED1_SPIRV_H diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 013b5d07..4c39d00d 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -3270,7 +3270,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 69a46e91..39b284ee 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 f4ce1cca..163dd6ce 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; @@ -4220,9 +4222,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; } } @@ -4248,6 +4252,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 1457ddf9..82782e7d 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 bf32d04c..2d27090b 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;