[PATCH vkd3d 5/7] vkd3d: Create and write descriptor sets for root signature unbounded ranges.
Conor McCarthy
cmccarthy at codeweavers.com
Fri Aug 13 09:55:41 CDT 2021
Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
libs/vkd3d/command.c | 130 ++++++++++++++++++++++++-----
libs/vkd3d/device.c | 71 ++++++++++++++++
libs/vkd3d/resource.c | 14 ++++
libs/vkd3d/state.c | 166 +++++++++++++++++++++++++++++++++----
libs/vkd3d/vkd3d_private.h | 18 +++-
tests/d3d12.c | 4 +-
6 files changed, 362 insertions(+), 41 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index c4a7bf07..afa68e0e 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -1,6 +1,7 @@
/*
* Copyright 2016 Józef Kucia for CodeWeavers
* Copyright 2016 Henri Verbeet for CodeWeavers
+ * Copyright 2021 Conor McCarthy for Codeweavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1363,10 +1364,12 @@ static VkDescriptorPool d3d12_command_allocator_allocate_descriptor_pool(
}
static VkDescriptorSet d3d12_command_allocator_allocate_descriptor_set(
- struct d3d12_command_allocator *allocator, VkDescriptorSetLayout vk_set_layout)
+ struct d3d12_command_allocator *allocator, VkDescriptorSetLayout vk_set_layout,
+ uint32_t variable_binding_size, bool unbounded)
{
struct d3d12_device *device = allocator->device;
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+ VkDescriptorSetVariableDescriptorCountAllocateInfoEXT set_size;
struct VkDescriptorSetAllocateInfo set_desc;
VkDevice vk_device = device->vk_device;
VkDescriptorSet vk_descriptor_set;
@@ -1382,6 +1385,14 @@ static VkDescriptorSet d3d12_command_allocator_allocate_descriptor_set(
set_desc.descriptorPool = allocator->vk_descriptor_pool;
set_desc.descriptorSetCount = 1;
set_desc.pSetLayouts = &vk_set_layout;
+ if (unbounded)
+ {
+ set_desc.pNext = &set_size;
+ set_size.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT;
+ set_size.pNext = NULL;
+ set_size.descriptorSetCount = 1;
+ set_size.pDescriptorCounts = &variable_binding_size;
+ }
if ((vr = VK_CALL(vkAllocateDescriptorSets(vk_device, &set_desc, &vk_descriptor_set))) >= 0)
return vk_descriptor_set;
@@ -2565,6 +2576,8 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
{
struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point];
const struct d3d12_root_signature *root_signature = bindings->root_signature;
+ struct d3d12_device *device = list->device;
+ unsigned int i;
if (bindings->descriptor_set_count && !bindings->in_use)
return;
@@ -2581,9 +2594,44 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
* by an update command, or freed) between when the command is recorded
* and when the command completes executing on the queue."
*/
- bindings->descriptor_sets[0] = d3d12_command_allocator_allocate_descriptor_set(list->allocator,
- root_signature->vk_set_layouts[root_signature->main_set]);
- bindings->descriptor_set_count = 1;
+ bindings->descriptor_set_count = 0;
+ for (i = root_signature->main_set; i < root_signature->vk_set_count; ++i)
+ {
+ unsigned int unbounded_range_offset = root_signature->vk_set_layout_unbounded_offsets[i];
+ unsigned int unbounded_table = root_signature->vk_set_layout_table_indices[i];
+ unsigned int variable_binding_size = 0;
+
+ if (unbounded_range_offset != UINT_MAX)
+ {
+ const struct d3d12_desc *base_descriptor
+ = d3d12_desc_from_gpu_handle(bindings->descriptor_tables[unbounded_table]);
+ /* Descriptors may not be set, eg. WoW. */
+ if (base_descriptor)
+ {
+ unsigned int heap_size;
+ int rc;
+
+ rc = pthread_mutex_lock(&device->mutex);
+ if (rc)
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ heap_size = d3d12_device_descriptor_heap_size_from_descriptor(device, base_descriptor);
+ if (!rc)
+ pthread_mutex_unlock(&device->mutex);
+
+ if (heap_size >= unbounded_range_offset)
+ variable_binding_size = heap_size - unbounded_range_offset;
+ else
+ WARN("Descriptor heap size %u is less than the offset %u of an unbounded range in table %u, "
+ "vk set %u.\n", heap_size, unbounded_range_offset, unbounded_table, i);
+ }
+ }
+
+ bindings->descriptor_sets[bindings->descriptor_set_count] =
+ d3d12_command_allocator_allocate_descriptor_set(list->allocator,
+ root_signature->vk_set_layouts[i], variable_binding_size, unbounded_range_offset != UINT_MAX);
+ ++bindings->descriptor_set_count;
+ }
+
bindings->in_use = false;
bindings->descriptor_table_dirty_mask |= bindings->descriptor_table_active_mask & root_signature->descriptor_table_mask;
@@ -2598,13 +2646,14 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
uint32_t descriptor_range_magic = range->descriptor_magic;
const struct vkd3d_view *view = descriptor->u.view;
uint32_t vk_binding = range->binding;
+ uint32_t set = range->set;
if (descriptor->magic != descriptor_range_magic)
return false;
vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
vk_descriptor_write->pNext = NULL;
- vk_descriptor_write->dstSet = vk_descriptor_sets[0];
+ vk_descriptor_write->dstSet = vk_descriptor_sets[set];
vk_descriptor_write->dstBinding = use_array ? vk_binding : vk_binding + index;
vk_descriptor_write->dstArrayElement = use_array ? index : 0;
vk_descriptor_write->descriptorCount = 1;
@@ -2622,12 +2671,25 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
case VKD3D_DESCRIPTOR_MAGIC_SRV:
case VKD3D_DESCRIPTOR_MAGIC_UAV:
/* We use separate bindings for buffer and texture SRVs/UAVs.
- * See d3d12_root_signature_init(). */
- if (!use_array)
- vk_descriptor_write->dstBinding = vk_binding + 2 * index;
- if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
- && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
- ++vk_descriptor_write->dstBinding;
+ * See d3d12_root_signature_init(). For unbounded ranges the descriptors exist
+ * in two consecutive sets, otherwise they occur in pairs in one set. */
+ if (range->descriptor_count == UINT_MAX)
+ {
+ if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+ && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
+ {
+ vk_descriptor_write->dstSet = vk_descriptor_sets[set + 1];
+ vk_descriptor_write->dstBinding = 0;
+ }
+ }
+ else
+ {
+ if (!use_array)
+ vk_descriptor_write->dstBinding = vk_binding + 2 * index;
+ if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+ && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
+ ++vk_descriptor_write->dstBinding;
+ }
if (descriptor->vk_descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
|| descriptor->vk_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
@@ -2675,10 +2737,10 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
VkDevice vk_device = list->device->vk_device;
unsigned int i, j, k, descriptor_count;
struct d3d12_desc *descriptor;
+ unsigned int write_count = 0;
descriptor_table = root_signature_get_descriptor_table(root_signature, index);
- descriptor_count = 0;
current_descriptor_write = descriptor_writes;
current_image_info = image_infos;
for (i = 0; i < descriptor_table->range_count; ++i)
@@ -2687,7 +2749,31 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
descriptor = base_descriptor + range->offset;
- for (j = 0; j < range->descriptor_count; ++j, ++descriptor)
+ descriptor_count = range->descriptor_count;
+ if (descriptor_count == UINT_MAX)
+ {
+ int rc;
+
+ /* The first unbounded range of each type is written until the heap end is reached. Do not repeat. */
+ if (i && range[-1].descriptor_magic == range->descriptor_magic && range[-1].descriptor_count == UINT_MAX)
+ continue;
+
+ rc = pthread_mutex_lock(&list->device->mutex);
+ if (rc)
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ descriptor_count = d3d12_device_descriptor_heap_size_from_descriptor(list->device, descriptor);
+ if (!rc)
+ pthread_mutex_unlock(&list->device->mutex);
+
+ if (descriptor_count > range->vk_binding_count)
+ {
+ ERR("Heap descriptor count %u exceeds maximum Vulkan count %u. Reducing to the Vulkan maximum.\n",
+ descriptor_count, range->vk_binding_count);
+ descriptor_count = range->vk_binding_count;
+ }
+ }
+
+ for (j = 0; j < descriptor_count; ++j, ++descriptor)
{
unsigned int register_idx = range->base_register_idx + j;
@@ -2709,25 +2795,29 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
}
}
+ /* Not all descriptors are necessarily populated if the range is unbounded. */
+ if (!descriptor->magic)
+ continue;
+
if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write, current_image_info,
descriptor, range, bindings->descriptor_sets, j, root_signature->use_descriptor_arrays))
continue;
- ++descriptor_count;
+ ++write_count;
++current_descriptor_write;
++current_image_info;
- if (descriptor_count == ARRAY_SIZE(descriptor_writes))
+ if (write_count == ARRAY_SIZE(descriptor_writes))
{
- VK_CALL(vkUpdateDescriptorSets(vk_device, descriptor_count, descriptor_writes, 0, NULL));
- descriptor_count = 0;
+ VK_CALL(vkUpdateDescriptorSets(vk_device, write_count, descriptor_writes, 0, NULL));
+ write_count = 0;
current_descriptor_write = descriptor_writes;
current_image_info = image_infos;
}
}
}
- VK_CALL(vkUpdateDescriptorSets(vk_device, descriptor_count, descriptor_writes, 0, NULL));
+ VK_CALL(vkUpdateDescriptorSets(vk_device, write_count, descriptor_writes, 0, NULL));
}
static bool vk_write_descriptor_set_from_root_descriptor(VkWriteDescriptorSet *vk_descriptor_write,
@@ -2853,7 +2943,7 @@ static void d3d12_command_list_update_uav_counter_descriptors(struct d3d12_comma
if (!(vk_descriptor_writes = vkd3d_calloc(uav_counter_count, sizeof(*vk_descriptor_writes))))
return;
if (!(vk_descriptor_set = d3d12_command_allocator_allocate_descriptor_set(list->allocator,
- state->uav_counters.vk_set_layout)))
+ state->uav_counters.vk_set_layout, 0, false)))
goto done;
for (i = 0; i < uav_counter_count; ++i)
@@ -4954,7 +5044,7 @@ static void d3d12_command_list_clear_uav(struct d3d12_command_list *list,
}
if (!(write_set.dstSet = d3d12_command_allocator_allocate_descriptor_set(
- list->allocator, pipeline.vk_set_layout)))
+ list->allocator, pipeline.vk_set_layout, 0, false)))
{
ERR("Failed to allocate descriptor set.\n");
return;
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index 0fadb521..795ff899 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -2231,6 +2231,7 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface)
vkd3d_fence_worker_stop(&device->fence_worker, device);
d3d12_device_destroy_pipeline_cache(device);
d3d12_device_destroy_vkd3d_queues(device);
+ vkd3d_free(device->descriptor_heaps);
for (i = 0; i < ARRAY_SIZE(device->desc_mutex); ++i)
pthread_mutex_destroy(&device->desc_mutex[i]);
VK_CALL(vkDestroyDevice(device->vk_device, NULL));
@@ -3737,6 +3738,10 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
if ((device->parent = create_info->parent))
IUnknown_AddRef(device->parent);
+ device->descriptor_heap_capacity = 0;
+ device->descriptor_heap_count = 0;
+ device->descriptor_heaps = NULL;
+
return S_OK;
out_destroy_null_resources:
@@ -3792,6 +3797,72 @@ void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason,
device->removed_reason = reason;
}
+void d3d12_device_track_descriptor_heap(struct d3d12_device *device,
+ const struct d3d12_descriptor_heap *heap)
+{
+ if (!device->vk_info.EXT_descriptor_indexing)
+ return;
+
+ if (!vkd3d_array_reserve((void **)&device->descriptor_heaps, &device->descriptor_heap_capacity,
+ device->descriptor_heap_count + 1, sizeof(*device->descriptor_heaps)))
+ {
+ ERR("Out of memory. Cannot track descriptor heap for unbounded arrays.\n");
+ return;
+ }
+
+ device->descriptor_heaps[device->descriptor_heap_count++] = heap;
+ /* Do not increment the heap reference count. This reference is deleted on heap destruction. */
+}
+
+void d3d12_device_untrack_descriptor_heap(struct d3d12_device *device,
+ const struct d3d12_descriptor_heap *heap)
+{
+ size_t i;
+
+ if (!device->vk_info.EXT_descriptor_indexing)
+ return;
+
+ for (i = 0; i < device->descriptor_heap_count; ++i)
+ {
+ if (device->descriptor_heaps[i] != heap)
+ continue;
+
+ memmove(&device->descriptor_heaps[i], &device->descriptor_heaps[i + 1],
+ (device->descriptor_heap_count - i - 1) * sizeof(*device->descriptor_heaps));
+ --device->descriptor_heap_count;
+
+ return;
+ }
+
+ ERR("Attempted to untrack an already untracked heap.\n");
+}
+
+/* Return the available size from the specified descriptor to the heap end. */
+uint32_t d3d12_device_descriptor_heap_size_from_descriptor(struct d3d12_device *device,
+ const struct d3d12_desc *desc)
+{
+ size_t i;
+
+ for (i = 0; i < device->descriptor_heap_count; ++i)
+ {
+ unsigned int size;
+ size_t offset;
+
+ if (device->descriptor_heaps[i]->descriptors > (const BYTE*)desc)
+ continue;
+
+ size = d3d12_device_get_descriptor_handle_increment_size(device, device->descriptor_heaps[i]->desc.Type);
+ offset = ((const BYTE*)desc - device->descriptor_heaps[i]->descriptors) / size;
+ if (device->descriptor_heaps[i]->desc.NumDescriptors <= offset)
+ continue;
+
+ return device->descriptor_heaps[i]->desc.NumDescriptors - (uint32_t)offset;
+ }
+
+ ERR("Failed to find descriptor heap size from descriptor pointer.\n");
+ return 0;
+}
+
HRESULT vkd3d_create_thread(struct vkd3d_instance *instance,
PFN_vkd3d_thread thread_main, void *data, union vkd3d_thread_handle *thread)
{
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c
index 1ca23a90..5d768b30 100644
--- a/libs/vkd3d/resource.c
+++ b/libs/vkd3d/resource.c
@@ -3337,6 +3337,7 @@ static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHea
{
struct d3d12_device *device = heap->device;
unsigned int i;
+ int rc;
vkd3d_private_store_destroy(&heap->private_store);
@@ -3382,6 +3383,12 @@ static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHea
vkd3d_free(heap);
+ if ((rc = pthread_mutex_lock(&device->mutex)))
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ d3d12_device_untrack_descriptor_heap(device, heap);
+ if (!rc)
+ pthread_mutex_unlock(&device->mutex);
+
d3d12_device_release(device);
}
@@ -3514,6 +3521,7 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
size_t max_descriptor_count, descriptor_size;
struct d3d12_descriptor_heap *object;
HRESULT hr;
+ int rc;
if (!(descriptor_size = d3d12_device_get_descriptor_handle_increment_size(device, desc->Type)))
{
@@ -3547,6 +3555,12 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
memset(object->descriptors, 0, descriptor_size * desc->NumDescriptors);
+ if ((rc = pthread_mutex_lock(&device->mutex)))
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ d3d12_device_track_descriptor_heap(device, object);
+ if (!rc)
+ pthread_mutex_unlock(&device->mutex);
+
TRACE("Created descriptor heap %p.\n", object);
*descriptor_heap = object;
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c
index 58463e59..38948bf9 100644
--- a/libs/vkd3d/state.c
+++ b/libs/vkd3d/state.c
@@ -1,6 +1,7 @@
/*
* Copyright 2016 Józef Kucia for CodeWeavers
* Copyright 2016 Henri Verbeet for CodeWeavers
+ * Copyright 2021 Conor McCarthy for Codeweavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -325,6 +326,7 @@ struct d3d12_root_signature_info
static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_signature_info *info,
const D3D12_ROOT_DESCRIPTOR_TABLE *table, bool use_array)
{
+ bool unbounded = false;
unsigned int i;
for (i = 0; i < table->NumDescriptorRanges; ++i)
@@ -332,14 +334,33 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig
const D3D12_DESCRIPTOR_RANGE *range = &table->pDescriptorRanges[i];
unsigned int binding_count;
- if (range->NumDescriptors == 0xffffffff)
- {
- FIXME("Unhandled unbound descriptor range.\n");
- return E_NOTIMPL;
+ if (unbounded)
+ {
+ if (range->NumDescriptors != UINT_MAX)
+ {
+ ERR("Static range occurs after unbounded range.\n");
+ return E_INVALIDARG;
+ }
+ if (range->OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
+ {
+ ERR("Unbounded range with offset D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND occurs after "
+ "another unbounded range.\n");
+ return E_INVALIDARG;
+ }
}
binding_count = use_array ? 1 : range->NumDescriptors;
+ if (range->NumDescriptors == UINT_MAX)
+ {
+ if (!use_array)
+ {
+ FIXME("The device does not support unbounded descriptor ranges.\n");
+ return E_NOTIMPL;
+ }
+ unbounded = true;
+ }
+
switch (range->RangeType)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
@@ -515,6 +536,8 @@ struct vkd3d_descriptor_set_context
{
VkDescriptorSetLayoutBinding *current_binding;
VkDescriptorSetLayoutBinding *first_binding;
+ unsigned int table_index;
+ unsigned int unbounded_offset;
unsigned int descriptor_index;
uint32_t descriptor_binding;
};
@@ -533,7 +556,7 @@ static bool vkd3d_validate_descriptor_set_count(struct d3d12_device *device, uns
}
static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device,
- VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count,
+ VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, bool unbounded,
const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout);
static HRESULT d3d12_root_signature_append_descriptor_set_layout(struct d3d12_root_signature *root_signature,
@@ -548,9 +571,11 @@ static HRESULT d3d12_root_signature_append_descriptor_set_layout(struct d3d12_ro
return E_INVALIDARG;
if (FAILED(hr = vkd3d_create_descriptor_set_layout(root_signature->device,
- flags, context->descriptor_binding, context->first_binding,
+ flags, context->descriptor_binding, context->unbounded_offset != UINT_MAX, context->first_binding,
&root_signature->vk_set_layouts[root_signature->vk_set_count])))
return hr;
+ root_signature->vk_set_layout_table_indices[root_signature->vk_set_count] = context->table_index;
+ root_signature->vk_set_layout_unbounded_offsets[root_signature->vk_set_count] = context->unbounded_offset;
++root_signature->vk_set_count;
context->current_binding = context->first_binding;
@@ -575,6 +600,9 @@ static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature *
mapping->binding.set = root_signature->vk_set_count;
mapping->binding.binding = context->descriptor_binding++;
mapping->binding.count = descriptor_count;
+
+ if (context->unbounded_offset != UINT_MAX)
+ d3d12_root_signature_append_descriptor_set_layout(root_signature, context, 0);
}
static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature,
@@ -621,6 +649,15 @@ static uint32_t vkd3d_descriptor_magic_from_d3d12(D3D12_DESCRIPTOR_RANGE_TYPE ty
}
}
+static unsigned int vk_binding_count_from_descriptor_range(const struct d3d12_root_descriptor_table_range *range)
+{
+ if (range->descriptor_count != UINT_MAX)
+ return range->descriptor_count;
+
+ /* TODO: Calculate an upper bound from unbounded set counts and Vulkan device limits. */
+ return 1024;
+}
+
static HRESULT d3d12_root_signature_init_descriptor_array_binding(struct d3d12_root_signature *root_signature,
const struct d3d12_root_descriptor_table_range *range, D3D12_SHADER_VISIBILITY visibility,
struct vkd3d_descriptor_set_context *context)
@@ -629,28 +666,81 @@ static HRESULT d3d12_root_signature_init_descriptor_array_binding(struct d3d12_r
bool is_buffer = range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
enum vkd3d_shader_descriptor_type descriptor_type = range->type;
+ if (range->descriptor_count == UINT_MAX)
+ context->unbounded_offset = range->offset;
+
if (descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV || descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
{
if (!vk_binding_from_d3d12_descriptor_range(context->current_binding,
- descriptor_type, visibility, true, context->descriptor_binding, range->descriptor_count))
+ descriptor_type, visibility, true, context->descriptor_binding, range->vk_binding_count))
return E_NOTIMPL;
++context->current_binding;
d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->register_space,
- range->base_register_idx, true, shader_visibility, range->descriptor_count, context);
+ range->base_register_idx, true, shader_visibility, range->vk_binding_count, context);
}
if (!vk_binding_from_d3d12_descriptor_range(context->current_binding,
- descriptor_type, visibility, is_buffer, context->descriptor_binding, range->descriptor_count))
+ descriptor_type, visibility, is_buffer, context->descriptor_binding, range->vk_binding_count))
return E_NOTIMPL;
++context->current_binding;
d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->register_space,
- range->base_register_idx, is_buffer, shader_visibility, range->descriptor_count, context);
+ range->base_register_idx, is_buffer, shader_visibility, range->vk_binding_count, context);
+
+ context->unbounded_offset = UINT_MAX;
return S_OK;
}
+static void d3d12_root_signature_map_vk_unbounded_binding(struct d3d12_root_signature *root_signature,
+ const struct d3d12_root_descriptor_table_range *range, unsigned int binding_offset, bool buffer_descriptor,
+ enum vkd3d_shader_visibility shader_visibility, struct vkd3d_descriptor_set_context *context)
+{
+ struct vkd3d_shader_resource_binding *mapping
+ = &root_signature->descriptor_mapping[context->descriptor_index++];
+
+ mapping->type = range->type;
+ mapping->register_space = range->register_space;
+ mapping->register_index = range->base_register_idx;
+ mapping->shader_visibility = shader_visibility;
+ mapping->flags = buffer_descriptor ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
+ mapping->binding.set = root_signature->main_set + range->set + ((range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV
+ || range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) && !buffer_descriptor);
+ mapping->binding.binding = range->binding;
+ mapping->binding.count = range->vk_binding_count;
+}
+
+static void d3d12_root_signature_map_descriptor_unbounded_binding(struct d3d12_root_signature *root_signature,
+ const struct d3d12_root_descriptor_table_range *range, unsigned int binding_offset,
+ enum vkd3d_shader_visibility shader_visibility, struct vkd3d_descriptor_set_context *context)
+{
+ bool is_buffer = range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
+
+ if (range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV || range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
+ d3d12_root_signature_map_vk_unbounded_binding(root_signature, range,
+ binding_offset, true, shader_visibility, context);
+
+ d3d12_root_signature_map_vk_unbounded_binding(root_signature, range,
+ binding_offset, is_buffer, shader_visibility, context);
+}
+
+static int compare_range(const void *a, const void *b)
+{
+ const struct d3d12_root_descriptor_table_range *range_a = a, *range_b = b;
+ int unbounded_a, unbounded_b;
+
+ if (range_a->descriptor_magic != range_b->descriptor_magic)
+ return range_a->descriptor_magic - range_b->descriptor_magic;
+
+ unbounded_a = range_a->descriptor_count == UINT_MAX;
+ unbounded_b = range_b->descriptor_count == UINT_MAX;
+ if (unbounded_a != unbounded_b)
+ return unbounded_a - unbounded_b;
+
+ return range_a->offset - range_b->offset;
+}
+
static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_root_signature *root_signature,
const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context)
{
@@ -681,6 +771,8 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
if (!(table->ranges = vkd3d_calloc(table->range_count, sizeof(*table->ranges))))
return E_OUTOFMEMORY;
+ context->table_index = i;
+
for (j = 0; j < range_count; ++j)
{
const D3D12_DESCRIPTOR_RANGE *range = &p->u.DescriptorTable.pDescriptorRanges[j];
@@ -688,7 +780,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
if (range->OffsetInDescriptorsFromTableStart != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
offset = range->OffsetInDescriptorsFromTableStart;
- if (!vkd3d_bound_range(offset, range->NumDescriptors, UINT_MAX))
+ if (range->NumDescriptors != UINT_MAX && !vkd3d_bound_range(offset, range->NumDescriptors, UINT_MAX))
return E_INVALIDARG;
table->ranges[j].offset = offset;
@@ -701,18 +793,48 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
TRACE("Descriptor table %u, range %u, offset %u, type %#x, count %u.\n", i, j,
offset, range->RangeType, range->NumDescriptors);
+ /* If NumDescriptors == UINT_MAX, validation during counting ensures this offset is not used. */
offset += range->NumDescriptors;
}
+ qsort(table->ranges, range_count, sizeof(*table->ranges), compare_range);
+
for (j = 0; j < range_count; ++j)
{
struct d3d12_root_descriptor_table_range *range;
VkDescriptorSetLayoutBinding *cur_binding;
+ unsigned int offset;
+
range = &table->ranges[j];
+ range->set = root_signature->vk_set_count - root_signature->main_set;
+
if (root_signature->use_descriptor_arrays)
{
+ if (j && range->descriptor_magic == range[-1].descriptor_magic && range->descriptor_count == UINT_MAX
+ && range[-1].descriptor_count == UINT_MAX)
+ {
+ unsigned int rel_offset = range->offset - range[-1].offset;
+
+ if (rel_offset >= range[-1].vk_binding_count)
+ {
+ ERR("Available binding size of %u is insufficient for an offset of %u.\n",
+ range[-1].vk_binding_count, rel_offset);
+ continue;
+ }
+
+ range->set = range[-1].set;
+ range->binding = range[-1].binding;
+ range->vk_binding_count = range[-1].vk_binding_count - rel_offset;
+ d3d12_root_signature_map_descriptor_unbounded_binding(root_signature, range,
+ range->offset - offset, shader_visibility, context);
+ continue;
+ }
+
+ offset = range->offset;
+
range->binding = context->descriptor_binding;
+ range->vk_binding_count = vk_binding_count_from_descriptor_range(range);
if (FAILED(hr = d3d12_root_signature_init_descriptor_array_binding(root_signature,
range, p->ShaderVisibility, context)))
@@ -752,6 +874,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
++cur_binding;
}
+ table->ranges[j].vk_binding_count = table->ranges[j].descriptor_count;
table->ranges[j].binding = vk_binding;
context->current_binding = cur_binding;
@@ -849,7 +972,7 @@ static bool vk_binding_uses_partial_binding(const VkDescriptorSetLayoutBinding *
}
static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device,
- VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count,
+ VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, bool unbounded,
const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
@@ -868,7 +991,7 @@ static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device,
unsigned int i;
for (i = 0; i < binding_count; ++i)
- if (vk_binding_uses_partial_binding(&bindings[i]))
+ if (unbounded || vk_binding_uses_partial_binding(&bindings[i]))
break;
if (i < binding_count)
@@ -880,6 +1003,10 @@ static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device,
set_flags[i] = vk_binding_uses_partial_binding(&bindings[i])
? VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT : 0;
+ if (unbounded)
+ set_flags[binding_count - 1] = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
+ | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT;
+
flags_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
flags_info.pNext = NULL;
flags_info.bindingCount = binding_count;
@@ -909,6 +1036,9 @@ static HRESULT vkd3d_create_pipeline_layout(struct d3d12_device *device,
struct VkPipelineLayoutCreateInfo pipeline_layout_info;
VkResult vr;
+ if (!vkd3d_validate_descriptor_set_count(device, set_layout_count))
+ return E_INVALIDARG;
+
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_info.pNext = NULL;
pipeline_layout_info.flags = 0;
@@ -936,6 +1066,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
HRESULT hr;
memset(&context, 0, sizeof(context));
+ context.unbounded_offset = UINT_MAX;
binding_desc = NULL;
root_signature->ID3D12RootSignature_iface.lpVtbl = &d3d12_root_signature_vtbl;
@@ -999,6 +1130,8 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
goto fail;
}
+ root_signature->main_set = root_signature->vk_set_count;
+
if (FAILED(hr = d3d12_root_signature_init_push_constants(root_signature, desc,
root_signature->push_constant_ranges, &root_signature->push_constant_range_count)))
goto fail;
@@ -1007,8 +1140,6 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
if (FAILED(hr = d3d12_root_signature_init_root_descriptor_tables(root_signature, desc, &context)))
goto fail;
- root_signature->main_set = root_signature->vk_set_count;
-
if (FAILED(hr = d3d12_root_signature_append_descriptor_set_layout(root_signature, &context, 0)))
goto fail;
@@ -1652,7 +1783,7 @@ static HRESULT d3d12_pipeline_state_init_uav_counters(struct d3d12_pipeline_stat
/* Create a descriptor set layout for UAV counters. */
hr = vkd3d_create_descriptor_set_layout(device,
- 0, descriptor_binding, binding_desc, &state->uav_counters.vk_set_layout);
+ 0, descriptor_binding, false, binding_desc, &state->uav_counters.vk_set_layout);
vkd3d_free(binding_desc);
if (FAILED(hr))
{
@@ -3122,7 +3253,8 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d
{
set_binding.descriptorType = set_layouts[i].descriptor_type;
- if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0, 1, &set_binding, set_layouts[i].set_layout)))
+ if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0, 1, false,
+ &set_binding, set_layouts[i].set_layout)))
{
ERR("Failed to create descriptor set layout %u, hr %#x.\n", i, hr);
goto fail;
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index 0b326b11..d39893bb 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -54,7 +54,7 @@
#define VKD3D_MAX_SHADER_EXTENSIONS 2u
#define VKD3D_MAX_SHADER_STAGES 5u
#define VKD3D_MAX_VK_SYNC_OBJECTS 4u
-#define VKD3D_MAX_DESCRIPTOR_SETS 2u
+#define VKD3D_MAX_DESCRIPTOR_SETS 64u
struct d3d12_command_list;
struct d3d12_device;
@@ -647,6 +647,8 @@ struct d3d12_root_descriptor_table_range
{
unsigned int offset;
unsigned int descriptor_count;
+ unsigned int vk_binding_count;
+ uint32_t set;
uint32_t binding;
enum vkd3d_shader_descriptor_type type;
@@ -692,6 +694,8 @@ struct d3d12_root_signature
VkPipelineLayout vk_pipeline_layout;
uint32_t vk_set_count;
VkDescriptorSetLayout vk_set_layouts[VKD3D_MAX_DESCRIPTOR_SETS];
+ unsigned int vk_set_layout_unbounded_offsets[VKD3D_MAX_DESCRIPTOR_SETS];
+ unsigned int vk_set_layout_table_indices[VKD3D_MAX_DESCRIPTOR_SETS];
bool use_descriptor_arrays;
struct d3d12_root_parameter *parameters;
@@ -912,8 +916,9 @@ struct vkd3d_pipeline_bindings
const struct d3d12_root_signature *root_signature;
VkPipelineBindPoint vk_bind_point;
+ /* All descriptor sets at index > 1 are for unbounded D3D12 ranges. Set 0 or 1 may be unbounded too. */
size_t descriptor_set_count;
- VkDescriptorSet descriptor_sets[VKD3D_MAX_DESCRIPTOR_SETS - 1];
+ VkDescriptorSet descriptor_sets[VKD3D_MAX_DESCRIPTOR_SETS];
bool in_use;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_tables[D3D12_MAX_ROOT_COST];
@@ -1165,6 +1170,10 @@ struct d3d12_device
const struct vkd3d_format_compatibility_list *format_compatibility_lists;
struct vkd3d_null_resources null_resources;
struct vkd3d_uav_clear_state uav_clear_state;
+
+ size_t descriptor_heap_capacity;
+ size_t descriptor_heap_count;
+ const struct d3d12_descriptor_heap **descriptor_heaps;
};
HRESULT d3d12_device_create(struct vkd3d_instance *instance,
@@ -1175,6 +1184,11 @@ void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason,
const char *message, ...) VKD3D_PRINTF_FUNC(3, 4);
struct d3d12_device *unsafe_impl_from_ID3D12Device(ID3D12Device *iface);
+void d3d12_device_track_descriptor_heap(struct d3d12_device *device, const struct d3d12_descriptor_heap *heap);
+void d3d12_device_untrack_descriptor_heap(struct d3d12_device *device, const struct d3d12_descriptor_heap *heap);
+uint32_t d3d12_device_descriptor_heap_size_from_descriptor(struct d3d12_device *device,
+ const struct d3d12_desc *desc);
+
static inline HRESULT d3d12_device_query_interface(struct d3d12_device *device, REFIID iid, void **object)
{
return ID3D12Device_QueryInterface(&device->ID3D12Device_iface, iid, object);
diff --git a/tests/d3d12.c b/tests/d3d12.c
index 618c2291..bd3ef624 100644
--- a/tests/d3d12.c
+++ b/tests/d3d12.c
@@ -34887,7 +34887,6 @@ static void test_unbounded_resource_arrays(void)
root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters);
root_signature_desc.pParameters = root_parameters;
hr = create_root_signature(device, &root_signature_desc, &context.root_signature);
- todo
ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr);
if (FAILED(hr))
goto done;
@@ -34961,6 +34960,7 @@ static void test_unbounded_resource_arrays(void)
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
get_buffer_readback_with_command_list(output_buffers[i], DXGI_FORMAT_R32_UINT, &rb, queue, command_list);
/* Buffers at index >= 64 are aliased. */
+ todo_if(i != 10 && i != 74)
check_readback_data_uint(&rb, NULL, (i < 64 ? 63 - i : 127 - i) ^ 0x35, 0);
release_resource_readback(&rb);
reset_command_list(command_list, context.allocator);
@@ -35050,7 +35050,6 @@ static void test_unbounded_samplers(void)
root_signature_desc.pParameters = root_parameters;
hr = create_root_signature(device, &root_signature_desc, &context.root_signature);
- todo
ok(SUCCEEDED(hr), "Failed to create root signature, hr %#x.\n", hr);
if (FAILED(hr))
goto done;
@@ -35108,6 +35107,7 @@ static void test_unbounded_samplers(void)
{
unsigned int value = get_readback_uint(&rb, i, 0, 0);
unsigned int expected = (i & 1) ? 100 : 10;
+ todo_if(i & 1)
ok(value == expected, "Got %u, expected %u at %u.\n", value, expected, i);
}
release_resource_readback(&rb);
--
2.32.0
More information about the wine-devel
mailing list