[PATCH vkd3d 2/2] vkd3d: Write a resource null descriptor to all applicable sets when one set is written.

Conor McCarthy cmccarthy at codeweavers.com
Mon Mar 21 10:25:10 CDT 2022


Binding a shader with the wrong null descriptor type works in Windows. The
introduction of Vulkan-backed heaps may cause a regression in clients which
do this, because the written index will remain unpopulated in all other sets,
but a shader may access it in one of them.

Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 libs/vkd3d/resource.c | 55 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c
index 01e0b67a..3c5024e3 100644
--- a/libs/vkd3d/resource.c
+++ b/libs/vkd3d/resource.c
@@ -2131,6 +2131,7 @@ void vkd3d_view_decref(struct vkd3d_view *view, struct d3d12_device *device)
         vkd3d_view_destroy(view, device);
 }
 
+/* TODO: write null descriptors to all applicable sets (invalid behaviour workaround). */
 static void d3d12_descriptor_heap_write_vk_descriptor_range(struct d3d12_descriptor_heap_vk_set *descriptor_set,
         struct d3d12_desc_copy_location *locations, unsigned int write_count)
 {
@@ -2178,6 +2179,47 @@ static void d3d12_descriptor_heap_write_vk_descriptor_range(struct d3d12_descrip
     }
 }
 
+static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_heap *descriptor_heap,
+        uint32_t dst_array_element, const struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct d3d12_descriptor_heap_vk_set *descriptor_set;
+    VkBufferView vk_buffer_view = VK_NULL_HANDLE;
+    enum vkd3d_vk_descriptor_set_index i;
+    VkDescriptorBufferInfo vk_cbv_info;
+
+    vk_cbv_info.buffer = VK_NULL_HANDLE;
+    vk_cbv_info.offset = 0;
+    vk_cbv_info.range = VK_WHOLE_SIZE;
+
+    /* Binding a shader with the wrong null descriptor type works in Windows.
+     * To support that here we need to write one to all Vulkan sets. */
+    for (i = VKD3D_SET_INDEX_UNIFORM_BUFFER; i <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++i)
+    {
+        descriptor_set = &descriptor_heap->vk_descriptor_sets[i];
+        descriptor_set->vk_descriptor_writes[0].dstArrayElement = dst_array_element;
+        descriptor_set->vk_descriptor_writes[0].descriptorCount = 1;
+        switch (i)
+        {
+            case VKD3D_SET_INDEX_UNIFORM_BUFFER:
+                descriptor_set->vk_descriptor_writes[0].pBufferInfo = &vk_cbv_info;
+                break;
+            case VKD3D_SET_INDEX_SAMPLED_IMAGE:
+            case VKD3D_SET_INDEX_STORAGE_IMAGE:
+                descriptor_set->vk_image_infos[0].imageView = VK_NULL_HANDLE;
+                break;
+            case VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER:
+            case VKD3D_SET_INDEX_STORAGE_TEXEL_BUFFER:
+                descriptor_set->vk_descriptor_writes[0].pTexelBufferView = &vk_buffer_view;
+                break;
+            default:
+                assert(false);
+                break;
+        }
+        VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, descriptor_set->vk_descriptor_writes, 0, NULL));
+    }
+}
+
 /* dst and src contain the same data unless another thread overwrites dst. The array index is
  * calculated from dst, and src is thread safe. */
 static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct d3d12_desc *src,
@@ -2186,6 +2228,7 @@ static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct
     struct d3d12_descriptor_heap_vk_set *descriptor_set;
     struct d3d12_descriptor_heap *descriptor_heap;
     const struct vkd3d_vk_device_procs *vk_procs;
+    bool is_null = false;
 
     descriptor_heap = vkd3d_gpu_descriptor_allocator_heap_from_descriptor(&device->gpu_descriptor_allocator, dst);
     descriptor_set = &descriptor_heap->vk_descriptor_sets[vkd3d_vk_descriptor_set_index_from_vk_descriptor_type(
@@ -2201,14 +2244,16 @@ static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct
     {
         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
             descriptor_set->vk_descriptor_writes[0].pBufferInfo = &src->u.vk_cbv_info;
+            is_null = !src->u.vk_cbv_info.buffer;
             break;
         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
-            descriptor_set->vk_image_infos[0].imageView = src->u.view_info.view->u.vk_image_view;
+            is_null = !(descriptor_set->vk_image_infos[0].imageView = src->u.view_info.view->u.vk_image_view);
             break;
         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
             descriptor_set->vk_descriptor_writes[0].pTexelBufferView = &src->u.view_info.view->u.vk_buffer_view;
+            is_null = !src->u.view_info.view->u.vk_buffer_view;
             break;
         case VK_DESCRIPTOR_TYPE_SAMPLER:
             descriptor_set->vk_image_infos[0].sampler = src->u.view_info.view->u.vk_sampler;
@@ -2217,6 +2262,14 @@ static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct
             ERR("Unhandled descriptor type %#x.\n", src->vk_descriptor_type);
             break;
     }
+    if (is_null && device->vk_info.EXT_robustness2)
+    {
+        d3d12_desc_write_vk_heap_null_descriptor(descriptor_heap,
+                descriptor_set->vk_descriptor_writes[0].dstArrayElement, device);
+        vkd3d_mutex_unlock(&descriptor_heap->vk_sets_mutex);
+        return;
+    }
+
     VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, descriptor_set->vk_descriptor_writes, 0, NULL));
 
     if (src->magic == VKD3D_DESCRIPTOR_MAGIC_UAV && src->u.view_info.view->vk_counter_view)
-- 
2.34.1




More information about the wine-devel mailing list