Required for variable Vulkan bindings. The actual size must be specified when creating a Vulkan descriptor set.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/device.c | 68 ++++++++++++++++++++++++++++++++++++++ libs/vkd3d/resource.c | 14 ++++++++ libs/vkd3d/vkd3d_private.h | 9 +++++ 3 files changed, 91 insertions(+)
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 877512e3..a4c8bca8 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -2228,6 +2228,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)); @@ -3727,6 +3728,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: @@ -3782,6 +3787,69 @@ 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("Cannot track descriptor heap for unbounded arrays. Out of memory.\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; + + 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); + if (device->descriptor_heaps[i]->descriptors + size * device->descriptor_heaps[i]->desc.NumDescriptors + <= (const BYTE*)desc) + continue; + + return device->descriptor_heaps[i]->desc.NumDescriptors + - (uint32_t)(((const BYTE*)desc - device->descriptor_heaps[i]->descriptors) / size); + } + + 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 a9d4d464..f117efc8 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -3327,6 +3327,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);
@@ -3372,6 +3373,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); }
@@ -3504,6 +3511,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))) { @@ -3537,6 +3545,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/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 02184c87..28742a8b 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -1179,6 +1179,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, @@ -1190,6 +1194,11 @@ void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason, const char *message, ...) VKD3D_PRINTF_FUNC(3, 4) DECLSPEC_HIDDEN; struct d3d12_device *unsafe_impl_from_ID3D12Device(ID3D12Device *iface) DECLSPEC_HIDDEN;
+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);
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 70 +++++++++++++++++++++++++++++++------- libs/vkd3d/vkd3d_private.h | 4 ++- 2 files changed, 61 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 116a8a62..5cb95869 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -1363,10 +1363,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 +1384,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;
@@ -1881,7 +1891,7 @@ static void d3d12_command_list_invalidate_root_parameters(struct d3d12_command_l if (!bindings->root_signature) return;
- bindings->descriptor_set = VK_NULL_HANDLE; + bindings->descriptor_set_count = 0; bindings->descriptor_table_dirty_mask = bindings->descriptor_table_active_mask & bindings->root_signature->descriptor_table_mask; bindings->push_descriptor_dirty_mask = bindings->push_descriptor_active_mask & bindings->root_signature->push_descriptor_mask; } @@ -2565,8 +2575,10 @@ 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 && !bindings->in_use) + if (bindings->descriptor_set_count && !bindings->in_use) return;
/* We cannot modify bound descriptor sets. We need a new descriptor set if @@ -2581,8 +2593,41 @@ 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_set = d3d12_command_allocator_allocate_descriptor_set(list->allocator, - root_signature->vk_set_layouts[root_signature->main_set]); + bindings->descriptor_set_count = 0; + for (i = root_signature->main_set; i < root_signature->vk_set_count; ++i) + { + int unbounded_table = root_signature->vk_unbounded_set_tables[i]; + unsigned int variable_binding_size = 0; + if (unbounded_table >= 0) + { + 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 static_descriptor_count = root_signature->vk_set_layout_static_counts[i]; + 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 >= static_descriptor_count) + variable_binding_size = heap_size - static_descriptor_count; + else + WARN("Descriptor heap size %u is less than the variable binding offset %u.\n", variable_binding_size, + static_descriptor_count); + } + } + 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_table >= 0); + ++bindings->descriptor_set_count; + } bindings->in_use = false;
bindings->descriptor_table_dirty_mask |= bindings->descriptor_table_active_mask & root_signature->descriptor_table_mask; @@ -2819,7 +2864,7 @@ static void d3d12_command_list_update_push_descriptors(struct d3d12_command_list }
if (!vk_write_descriptor_set_from_root_descriptor(current_descriptor_write, - root_parameter, bindings->descriptor_set, vk_buffer_view, vk_buffer_info)) + root_parameter, bindings->descriptor_sets[0], vk_buffer_view, vk_buffer_info)) continue;
++descriptor_count; @@ -2849,7 +2894,7 @@ static void d3d12_command_list_update_uav_counter_descriptors(struct d3d12_comma uav_counter_count = state->uav_counter_count; 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->vk_set_layout))) + if (!(vk_descriptor_set = d3d12_command_allocator_allocate_descriptor_set(list->allocator, state->vk_set_layout, 0, false))) goto done;
for (i = 0; i < uav_counter_count; ++i) @@ -2911,10 +2956,11 @@ static void d3d12_command_list_update_descriptors(struct d3d12_command_list *lis
d3d12_command_list_update_push_descriptors(list, bind_point);
- if (bindings->descriptor_set) + if (bindings->descriptor_set_count) { VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point, - rs->vk_pipeline_layout, rs->main_set, 1, &bindings->descriptor_set, 0, NULL)); + rs->vk_pipeline_layout, rs->main_set, bindings->descriptor_set_count, bindings->descriptor_sets, + 0, NULL)); bindings->in_use = true; }
@@ -4229,7 +4275,7 @@ static void d3d12_command_list_set_root_cbv(struct d3d12_command_list *list, { d3d12_command_list_prepare_descriptors(list, bind_point); vk_write_descriptor_set_from_root_descriptor(&descriptor_write, - root_parameter, bindings->descriptor_set, NULL, &buffer_info); + root_parameter, bindings->descriptor_sets[0], NULL, &buffer_info); VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
assert(index < ARRAY_SIZE(bindings->push_descriptors)); @@ -4302,7 +4348,7 @@ static void d3d12_command_list_set_root_descriptor(struct d3d12_command_list *li { d3d12_command_list_prepare_descriptors(list, bind_point); vk_write_descriptor_set_from_root_descriptor(&descriptor_write, - root_parameter, bindings->descriptor_set, &vk_buffer_view, NULL); + root_parameter, bindings->descriptor_sets[0], &vk_buffer_view, NULL); VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
assert(index < ARRAY_SIZE(bindings->push_descriptors)); @@ -4949,7 +4995,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/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 28742a8b..d0275062 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -924,7 +924,9 @@ struct vkd3d_pipeline_bindings const struct d3d12_root_signature *root_signature;
VkPipelineBindPoint vk_bind_point; - VkDescriptorSet descriptor_set; + /* 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]; bool in_use;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_tables[D3D12_MAX_ROOT_COST];
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 72 ++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 19 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 5cb95869..7e17eb68 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 @@ -2636,19 +2637,24 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_descriptor_write, VkDescriptorImageInfo *vk_image_info, const struct d3d12_desc *descriptor, - uint32_t descriptor_range_magic, VkDescriptorSet vk_descriptor_set, - uint32_t vk_binding, unsigned int index) + const struct d3d12_root_descriptor_table_range *range, VkDescriptorSet *vk_descriptor_sets, + unsigned int index, bool bindless) { + 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_set; - vk_descriptor_write->dstBinding = vk_binding + index; - vk_descriptor_write->dstArrayElement = 0; + vk_descriptor_write->dstSet = vk_descriptor_sets[set]; + /* If bindless is true the descriptors use a single array binding. The value of + * range->descriptor_count is not necessarily UINT_MAX in this case. */ + vk_descriptor_write->dstBinding = bindless ? vk_binding : vk_binding + index; + vk_descriptor_write->dstArrayElement = bindless ? range->binding_offset + index : 0; vk_descriptor_write->descriptorCount = 1; vk_descriptor_write->descriptorType = descriptor->vk_descriptor_type; vk_descriptor_write->pImageInfo = NULL; @@ -2664,11 +2670,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(). */ - 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 == ~0u) + { + 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(!bindless) + 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) @@ -2716,10 +2736,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) @@ -2731,7 +2751,18 @@ 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 == ~0u) + { + int 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); + } + + for (j = 0; j < descriptor_count; ++j, ++descriptor) { unsigned int register_idx = range->base_register_idx + j;
@@ -2750,26 +2781,29 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list } }
+ /* Not all descriptors are necessarily valid 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->descriptor_magic, - bindings->descriptor_set, range->binding, j)) + current_image_info, descriptor, range, bindings->descriptor_sets, j, root_signature->bindless)) 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,