vkd3d: Store only a single vkd3d descriptor type in each Vulkan descriptor set.

We currently create statically sized descriptor pools, shared among
different descriptor types. Once we're unable to allocate a descriptor
set from a pool, we create a new pool. The unfortunate but predictable
consequence is that when we run out of descriptors of one type, we waste
any unallocated descriptors of the other types.

Dynamically adjusting the pool sizes could mitigate the issue, but it
seems non-trivial to handle all the edge cases, particularly in
situations where the descriptor count ratios change significantly
between frames. Instead, by storing only a single vkd3d descriptor type
in each Vulkan descriptor set we're able to create separate descriptor
pools for each vkd3d descriptor type, which also avoids the issue.

The main drawback of using separate descriptor sets for each descriptor
type is that we can no longer pack all bounded descriptor ranges into a
single descriptor set, potentially leaving fewer descriptor sets
available for unbounded ranges. That seems worth it, but we may end up
having to switch to a more complicated strategy if this ends up being a
problem on Vulkan implementations with a very limited number of
available descriptor sets.
This commit is contained in:
Conor McCarthy 2024-09-16 16:47:18 +10:00 committed by Henri Verbeet
parent 01117c716d
commit 4a94bfc2f6
Notes: Henri Verbeet 2024-12-05 21:35:35 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1088
3 changed files with 131 additions and 90 deletions

View File

@ -2805,15 +2805,8 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
break;
}
if (range->descriptor_count == UINT_MAX)
{
vk_descriptor_write->dstSet = vk_descriptor_sets[set + 1];
vk_descriptor_write->dstBinding = 0;
}
else
{
vk_descriptor_write->dstBinding += use_array ? 1 : range->descriptor_count;
}
vk_descriptor_write->dstSet = vk_descriptor_sets[range->image_set];
vk_descriptor_write->dstBinding = use_array ? range->image_binding : range->image_binding + index;
vk_image_info->sampler = VK_NULL_HANDLE;
vk_image_info->imageView = u.view->v.u.vk_image_view;
@ -2934,10 +2927,11 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
}
static bool vk_write_descriptor_set_from_root_descriptor(VkWriteDescriptorSet *vk_descriptor_write,
const struct d3d12_root_parameter *root_parameter, VkDescriptorSet vk_descriptor_set,
const struct d3d12_root_parameter *root_parameter, const VkDescriptorSet *vk_descriptor_sets,
VkBufferView *vk_buffer_view, const VkDescriptorBufferInfo *vk_buffer_info)
{
const struct d3d12_root_descriptor *root_descriptor;
VkDescriptorSet vk_descriptor_set;
switch (root_parameter->parameter_type)
{
@ -2956,6 +2950,7 @@ static bool vk_write_descriptor_set_from_root_descriptor(VkWriteDescriptorSet *v
}
root_descriptor = &root_parameter->u.descriptor;
vk_descriptor_set = vk_descriptor_sets ? vk_descriptor_sets[root_descriptor->set] : VK_NULL_HANDLE;
vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
vk_descriptor_write->pNext = NULL;
@ -3011,7 +3006,7 @@ static void d3d12_command_list_update_push_descriptors(struct d3d12_command_list
}
if (!vk_write_descriptor_set_from_root_descriptor(&descriptor_writes[descriptor_count],
root_parameter, bindings->descriptor_sets[0], vk_buffer_view, vk_buffer_info))
root_parameter, bindings->descriptor_sets, vk_buffer_view, vk_buffer_info))
continue;
++descriptor_count;
@ -4612,8 +4607,7 @@ static void d3d12_command_list_set_root_cbv(struct d3d12_command_list *list,
if (vk_info->KHR_push_descriptor)
{
vk_write_descriptor_set_from_root_descriptor(&descriptor_write,
root_parameter, VK_NULL_HANDLE, NULL, &buffer_info);
vk_write_descriptor_set_from_root_descriptor(&descriptor_write, root_parameter, NULL, NULL, &buffer_info);
VK_CALL(vkCmdPushDescriptorSetKHR(list->vk_command_buffer, bindings->vk_bind_point,
root_signature->vk_pipeline_layout, 0, 1, &descriptor_write));
}
@ -4621,7 +4615,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_sets[0], NULL, &buffer_info);
root_parameter, bindings->descriptor_sets, NULL, &buffer_info);
VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
VKD3D_ASSERT(index < ARRAY_SIZE(bindings->push_descriptors));
@ -4685,8 +4679,7 @@ static void d3d12_command_list_set_root_descriptor(struct d3d12_command_list *li
if (vk_info->KHR_push_descriptor)
{
vk_write_descriptor_set_from_root_descriptor(&descriptor_write,
root_parameter, VK_NULL_HANDLE, &vk_buffer_view, NULL);
vk_write_descriptor_set_from_root_descriptor(&descriptor_write, root_parameter, NULL, &vk_buffer_view, NULL);
VK_CALL(vkCmdPushDescriptorSetKHR(list->vk_command_buffer, bindings->vk_bind_point,
root_signature->vk_pipeline_layout, 0, 1, &descriptor_write));
}
@ -4694,7 +4687,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_sets[0], &vk_buffer_view, NULL);
root_parameter, bindings->descriptor_sets, &vk_buffer_view, NULL);
VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
VKD3D_ASSERT(index < ARRAY_SIZE(bindings->push_descriptors));

View File

@ -717,6 +717,7 @@ struct vk_binding_array
VkDescriptorSetLayoutBinding *bindings;
size_t capacity, count;
unsigned int descriptor_set;
unsigned int table_index;
unsigned int unbounded_offset;
VkDescriptorSetLayoutCreateFlags flags;
@ -754,14 +755,24 @@ static bool vk_binding_array_add_binding(struct vk_binding_array *array,
return true;
}
static void vk_binding_array_make_unbound(struct vk_binding_array *array,
unsigned int offset, unsigned int table_index)
{
array->unbounded_offset = offset;
array->table_index = table_index;
}
struct vkd3d_descriptor_set_context
{
struct vk_binding_array vk_bindings[VKD3D_MAX_DESCRIPTOR_SETS];
struct vk_binding_array *current_binding_array[VKD3D_SHADER_DESCRIPTOR_TYPE_COUNT];
unsigned int table_index;
unsigned int unbounded_offset;
unsigned int descriptor_index;
unsigned int uav_counter_index;
unsigned int push_constant_index;
struct vk_binding_array *push_descriptor_set;
bool push_descriptor;
};
static void descriptor_set_context_cleanup(struct vkd3d_descriptor_set_context *context)
@ -786,46 +797,65 @@ static bool vkd3d_validate_descriptor_set_count(struct d3d12_device *device, uns
return true;
}
static struct vk_binding_array *d3d12_root_signature_current_vk_binding_array(
struct d3d12_root_signature *root_signature, struct vkd3d_descriptor_set_context *context)
static struct vk_binding_array *d3d12_root_signature_append_vk_binding_array(
struct d3d12_root_signature *root_signature, VkDescriptorSetLayoutCreateFlags flags,
struct vkd3d_descriptor_set_context *context)
{
struct vk_binding_array *array;
unsigned int set;
if (root_signature->vk_set_count >= ARRAY_SIZE(context->vk_bindings))
return NULL;
return &context->vk_bindings[root_signature->vk_set_count];
}
static void d3d12_root_signature_append_vk_binding_array(struct d3d12_root_signature *root_signature,
VkDescriptorSetLayoutCreateFlags flags, struct vkd3d_descriptor_set_context *context)
{
struct vk_binding_array *array;
if (!(array = d3d12_root_signature_current_vk_binding_array(root_signature, context)) || !array->count)
return;
array->table_index = context->table_index;
array->unbounded_offset = context->unbounded_offset;
set = root_signature->vk_set_count++;
array = &context->vk_bindings[set];
array->descriptor_set = set;
array->unbounded_offset = UINT_MAX;
array->flags = flags;
++root_signature->vk_set_count;
return array;
}
static struct vk_binding_array *d3d12_root_signature_vk_binding_array_for_type(
struct d3d12_root_signature *root_signature, enum vkd3d_shader_descriptor_type descriptor_type,
struct vkd3d_descriptor_set_context *context)
{
struct vk_binding_array *array, **current;
if (context->push_descriptor)
{
if (!context->push_descriptor_set)
context->push_descriptor_set = d3d12_root_signature_append_vk_binding_array(root_signature,
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, context);
return context->push_descriptor_set;
}
current = context->current_binding_array;
if (!(array = current[descriptor_type]))
{
array = d3d12_root_signature_append_vk_binding_array(root_signature, 0, context);
current[descriptor_type] = array;
}
return array;
}
static HRESULT d3d12_root_signature_append_vk_binding(struct d3d12_root_signature *root_signature,
enum vkd3d_shader_descriptor_type descriptor_type, unsigned int register_space,
unsigned int register_idx, bool buffer_descriptor, enum vkd3d_shader_visibility shader_visibility,
unsigned int descriptor_count, struct vkd3d_descriptor_set_context *context,
const VkSampler *immutable_sampler, unsigned int *binding_idx)
struct vk_binding_array *array, enum vkd3d_shader_descriptor_type descriptor_type,
unsigned int register_space, unsigned int register_idx, bool buffer_descriptor,
enum vkd3d_shader_visibility shader_visibility, unsigned int descriptor_count,
struct vkd3d_descriptor_set_context *context, const VkSampler *immutable_sampler)
{
struct vkd3d_shader_descriptor_offset *offset = root_signature->descriptor_offsets
? &root_signature->descriptor_offsets[context->descriptor_index] : NULL;
struct vkd3d_shader_resource_binding *mapping;
struct vk_binding_array *array;
VkDescriptorType vk_descriptor_type;
unsigned int idx;
if (!(array = d3d12_root_signature_current_vk_binding_array(root_signature, context))
|| !(vk_binding_array_add_binding(&context->vk_bindings[root_signature->vk_set_count],
vk_descriptor_type_from_vkd3d_descriptor_type(descriptor_type, buffer_descriptor), descriptor_count,
stage_flags_from_vkd3d_shader_visibility(shader_visibility), immutable_sampler, &idx)))
vk_descriptor_type = vk_descriptor_type_from_vkd3d_descriptor_type(descriptor_type, buffer_descriptor);
if (!vk_binding_array_add_binding(array, vk_descriptor_type, descriptor_count,
stage_flags_from_vkd3d_shader_visibility(shader_visibility), immutable_sampler, &idx))
return E_OUTOFMEMORY;
mapping = &root_signature->descriptor_mapping[context->descriptor_index++];
@ -834,7 +864,7 @@ static HRESULT d3d12_root_signature_append_vk_binding(struct d3d12_root_signatur
mapping->register_index = 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->vk_set_count;
mapping->binding.set = array->descriptor_set;
mapping->binding.binding = idx;
mapping->binding.count = descriptor_count;
if (offset)
@ -843,12 +873,6 @@ static HRESULT d3d12_root_signature_append_vk_binding(struct d3d12_root_signatur
offset->dynamic_offset_index = ~0u;
}
if (context->unbounded_offset != UINT_MAX)
d3d12_root_signature_append_vk_binding_array(root_signature, 0, context);
if (binding_idx)
*binding_idx = idx;
return S_OK;
}
@ -911,7 +935,7 @@ static unsigned int vk_binding_count_from_descriptor_range(const struct d3d12_ro
}
static HRESULT d3d12_root_signature_init_descriptor_table_binding(struct d3d12_root_signature *root_signature,
const struct d3d12_root_descriptor_table_range *range, D3D12_SHADER_VISIBILITY visibility,
struct d3d12_root_descriptor_table_range *range, D3D12_SHADER_VISIBILITY visibility,
unsigned int vk_binding_array_count, unsigned int bindings_per_range,
struct vkd3d_descriptor_set_context *context)
{
@ -919,34 +943,49 @@ static HRESULT d3d12_root_signature_init_descriptor_table_binding(struct d3d12_r
bool is_buffer = range->type != VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER;
enum vkd3d_shader_descriptor_type descriptor_type = range->type;
unsigned int i, register_space = range->register_space;
struct vk_binding_array *array;
HRESULT hr;
if (range->descriptor_count == UINT_MAX)
context->unbounded_offset = range->offset;
if (!(array = d3d12_root_signature_vk_binding_array_for_type(root_signature, descriptor_type, context)))
return E_OUTOFMEMORY;
range->set = array->descriptor_set - root_signature->main_set;
range->binding = array->count;
for (i = 0; i < bindings_per_range; ++i)
{
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature, descriptor_type,
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature, array, descriptor_type,
register_space, range->base_register_idx + i, is_buffer, shader_visibility,
vk_binding_array_count, context, NULL, NULL)))
vk_binding_array_count, context, NULL)))
return hr;
}
if (range->descriptor_count == UINT_MAX)
{
vk_binding_array_make_unbound(array, range->offset, context->table_index);
context->current_binding_array[descriptor_type] = NULL;
}
if (descriptor_type != VKD3D_SHADER_DESCRIPTOR_TYPE_SRV && descriptor_type != VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
{
context->unbounded_offset = UINT_MAX;
return S_OK;
}
if (!(array = d3d12_root_signature_vk_binding_array_for_type(root_signature, descriptor_type, context)))
return E_OUTOFMEMORY;
range->image_set = array->descriptor_set - root_signature->main_set;
range->image_binding = array->count;
for (i = 0; i < bindings_per_range; ++i)
{
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature, descriptor_type,
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature, array, descriptor_type,
register_space, range->base_register_idx + i, false, shader_visibility,
vk_binding_array_count, context, NULL, NULL)))
vk_binding_array_count, context, NULL)))
return hr;
}
context->unbounded_offset = UINT_MAX;
if (range->descriptor_count == UINT_MAX)
{
vk_binding_array_make_unbound(array, range->offset, context->table_index);
context->current_binding_array[descriptor_type] = NULL;
}
return S_OK;
}
@ -1199,16 +1238,16 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
if (use_vk_heaps)
{
/* set, binding and vk_binding_count are not used. */
/* set, binding, image_set, image_binding, and vk_binding_count are not used. */
range->set = 0;
range->binding = 0;
range->image_set = 0;
range->image_binding = 0;
range->vk_binding_count = 0;
d3d12_root_signature_map_descriptor_heap_binding(root_signature, range, shader_visibility, context);
continue;
}
range->set = root_signature->vk_set_count - root_signature->main_set;
if (root_signature->use_descriptor_arrays)
{
if (j && range->type != table->ranges[j - 1].type)
@ -1229,6 +1268,8 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
range->set = base_range->set;
range->binding = base_range->binding;
range->image_set = base_range->image_set;
range->image_binding = base_range->image_binding;
range->vk_binding_count = base_range->vk_binding_count - rel_offset;
d3d12_root_signature_map_descriptor_unbounded_binding(root_signature, range,
rel_offset, shader_visibility, context);
@ -1251,8 +1292,6 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
bindings_per_range = range->descriptor_count;
}
range->binding = context->vk_bindings[root_signature->vk_set_count].count;
if (FAILED(hr = d3d12_root_signature_init_descriptor_table_binding(root_signature, range,
p->ShaderVisibility, vk_binding_array_count, bindings_per_range, context)))
return hr;
@ -1266,7 +1305,9 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
static HRESULT d3d12_root_signature_init_root_descriptors(struct d3d12_root_signature *root_signature,
const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context)
{
unsigned int binding, i;
enum vkd3d_shader_descriptor_type descriptor_type;
struct vk_binding_array *array;
unsigned int i;
HRESULT hr;
root_signature->push_descriptor_mask = 0;
@ -1281,14 +1322,19 @@ static HRESULT d3d12_root_signature_init_root_descriptors(struct d3d12_root_sign
root_signature->push_descriptor_mask |= 1u << i;
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature,
vkd3d_descriptor_type_from_d3d12_root_parameter_type(p->ParameterType),
p->u.Descriptor.RegisterSpace, p->u.Descriptor.ShaderRegister, true,
vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility), 1, context, NULL, &binding)))
return hr;
descriptor_type = vkd3d_descriptor_type_from_d3d12_root_parameter_type(p->ParameterType);
if (!(array = d3d12_root_signature_vk_binding_array_for_type(root_signature, descriptor_type, context)))
return E_OUTOFMEMORY;
root_signature->parameters[i].parameter_type = p->ParameterType;
root_signature->parameters[i].u.descriptor.binding = binding;
root_signature->parameters[i].u.descriptor.set = array->descriptor_set;
root_signature->parameters[i].u.descriptor.binding = array->count;
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature, array, descriptor_type,
p->u.Descriptor.RegisterSpace, p->u.Descriptor.ShaderRegister, true,
vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility), 1, context, NULL)))
return hr;
}
return S_OK;
@ -1298,10 +1344,19 @@ static HRESULT d3d12_root_signature_init_static_samplers(struct d3d12_root_signa
struct d3d12_device *device, const D3D12_ROOT_SIGNATURE_DESC *desc,
struct vkd3d_descriptor_set_context *context)
{
struct vk_binding_array *array;
unsigned int i;
HRESULT hr;
VKD3D_ASSERT(root_signature->static_sampler_count == desc->NumStaticSamplers);
if (!desc->NumStaticSamplers)
return S_OK;
if (!(array = d3d12_root_signature_vk_binding_array_for_type(root_signature,
VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, context)))
return E_OUTOFMEMORY;
for (i = 0; i < desc->NumStaticSamplers; ++i)
{
const D3D12_STATIC_SAMPLER_DESC *s = &desc->pStaticSamplers[i];
@ -1309,16 +1364,13 @@ static HRESULT d3d12_root_signature_init_static_samplers(struct d3d12_root_signa
if (FAILED(hr = vkd3d_create_static_sampler(device, s, &root_signature->static_samplers[i])))
return hr;
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature,
if (FAILED(hr = d3d12_root_signature_append_vk_binding(root_signature, array,
VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, s->RegisterSpace, s->ShaderRegister, false,
vkd3d_shader_visibility_from_d3d12(s->ShaderVisibility), 1, context,
&root_signature->static_samplers[i], NULL)))
&root_signature->static_samplers[i])))
return hr;
}
if (device->use_vk_heaps)
d3d12_root_signature_append_vk_binding_array(root_signature, 0, context);
return S_OK;
}
@ -1456,8 +1508,6 @@ static HRESULT d3d12_root_signature_create_descriptor_set_layouts(struct d3d12_r
unsigned int i;
HRESULT hr;
d3d12_root_signature_append_vk_binding_array(root_signature, 0, context);
if (!vkd3d_validate_descriptor_set_count(root_signature->device, root_signature->vk_set_count))
return E_INVALIDARG;
@ -1518,7 +1568,6 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
HRESULT hr;
memset(&context, 0, sizeof(context));
context.unbounded_offset = UINT_MAX;
root_signature->ID3D12RootSignature_iface.lpVtbl = &d3d12_root_signature_vtbl;
root_signature->refcount = 1;
@ -1580,17 +1629,11 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
sizeof(*root_signature->static_samplers))))
goto fail;
context.push_descriptor = vk_info->KHR_push_descriptor;
if (FAILED(hr = d3d12_root_signature_init_root_descriptors(root_signature, desc, &context)))
goto fail;
/* We use KHR_push_descriptor for root descriptor parameters. */
if (vk_info->KHR_push_descriptor)
{
d3d12_root_signature_append_vk_binding_array(root_signature,
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, &context);
}
root_signature->main_set = root_signature->vk_set_count;
root_signature->main_set = !!context.push_descriptor_set;
context.push_descriptor = false;
if (FAILED(hr = d3d12_root_signature_init_push_constants(root_signature, desc,
root_signature->push_constant_ranges, &root_signature->push_constant_range_count)))

View File

@ -65,6 +65,8 @@
* this number to prevent excessive pool memory use. */
#define VKD3D_MAX_VIRTUAL_HEAP_DESCRIPTORS_PER_TYPE (16 * 1024u)
#define VKD3D_SHADER_DESCRIPTOR_TYPE_COUNT (VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER + 1)
extern uint64_t object_global_serial_id;
struct d3d12_command_list;
@ -899,6 +901,8 @@ struct d3d12_root_descriptor_table_range
unsigned int vk_binding_count;
uint32_t set;
uint32_t binding;
uint32_t image_set;
uint32_t image_binding;
enum vkd3d_shader_descriptor_type type;
uint32_t descriptor_magic;
@ -920,6 +924,7 @@ struct d3d12_root_constant
struct d3d12_root_descriptor
{
uint32_t set;
uint32_t binding;
};