diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 8bed7303..bf80a9d0 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -2592,7 +2592,7 @@ 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) + uint32_t vk_binding, unsigned int index, bool use_array) { const struct vkd3d_view *view = descriptor->u.view; @@ -2602,8 +2602,8 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des 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->dstBinding = use_array ? vk_binding : vk_binding + index; + vk_descriptor_write->dstArrayElement = use_array ? index : 0; vk_descriptor_write->descriptorCount = 1; vk_descriptor_write->descriptorType = descriptor->vk_descriptor_type; vk_descriptor_write->pImageInfo = NULL; @@ -2620,7 +2620,8 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des 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 (!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; @@ -2707,7 +2708,7 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write, current_image_info, descriptor, range->descriptor_magic, - bindings->descriptor_set, range->binding, j)) + bindings->descriptor_set, range->binding, j, root_signature->use_descriptor_arrays)) continue; ++descriptor_count; diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 102201dc..5ab0af83 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -300,12 +300,12 @@ static enum vkd3d_shader_descriptor_type vkd3d_descriptor_type_from_d3d12_root_p static bool vk_binding_from_d3d12_descriptor_range(struct VkDescriptorSetLayoutBinding *binding_desc, const D3D12_DESCRIPTOR_RANGE *descriptor_range, D3D12_SHADER_VISIBILITY shader_visibility, - bool is_buffer, uint32_t vk_binding) + bool is_buffer, uint32_t vk_binding, unsigned int descriptor_count) { binding_desc->binding = vk_binding; binding_desc->descriptorType = vk_descriptor_type_from_d3d12_range_type(descriptor_range->RangeType, is_buffer); - binding_desc->descriptorCount = 1; + binding_desc->descriptorCount = descriptor_count; binding_desc->stageFlags = stage_flags_from_visibility(shader_visibility); binding_desc->pImmutableSamplers = NULL; @@ -323,13 +323,14 @@ 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) + const D3D12_ROOT_DESCRIPTOR_TABLE *table, bool use_array) { unsigned int i; for (i = 0; i < table->NumDescriptorRanges; ++i) { const D3D12_DESCRIPTOR_RANGE *range = &table->pDescriptorRanges[i]; + unsigned int binding_count; if (range->NumDescriptors == 0xffffffff) { @@ -337,6 +338,8 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig return E_NOTIMPL; } + binding_count = use_array ? 1 : range->NumDescriptors; + switch (range->RangeType) { case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: @@ -344,11 +347,11 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig * to preserve compatibility between Vulkan resource bindings for the same * root signature, we create descriptor set layouts with two bindings for * each SRV and UAV. */ - info->binding_count += range->NumDescriptors; + info->binding_count += binding_count; break; case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: /* As above. */ - info->binding_count += range->NumDescriptors; + info->binding_count += binding_count; break; case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: break; @@ -359,14 +362,14 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig return E_NOTIMPL; } - info->binding_count += range->NumDescriptors; + info->binding_count += binding_count; } return S_OK; } static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_info *info, - const D3D12_ROOT_SIGNATURE_DESC *desc) + const D3D12_ROOT_SIGNATURE_DESC *desc, bool use_array) { unsigned int i; HRESULT hr; @@ -381,7 +384,7 @@ static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_i { case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: if (FAILED(hr = d3d12_root_signature_info_count_descriptors(info, - &p->u.DescriptorTable))) + &p->u.DescriptorTable, use_array))) return hr; ++info->cost; break; @@ -518,7 +521,7 @@ struct vkd3d_descriptor_set_context static void 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, - struct vkd3d_descriptor_set_context *context) + unsigned int descriptor_count, struct vkd3d_descriptor_set_context *context) { struct vkd3d_shader_resource_binding *mapping = &root_signature->descriptor_mapping[context->descriptor_index++]; @@ -530,7 +533,7 @@ static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature * mapping->flags = buffer_descriptor ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE; mapping->binding.set = root_signature->vk_set_count; mapping->binding.binding = context->descriptor_binding++; - mapping->binding.count = 1; + mapping->binding.count = descriptor_count; } static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature, @@ -551,10 +554,10 @@ static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signat { if (duplicate_descriptors) d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, register_space, - base_register_idx + i, true, shader_visibility, context); + base_register_idx + i, true, shader_visibility, 1, context); d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, register_space, - base_register_idx + i, is_buffer_descriptor, shader_visibility, context); + base_register_idx + i, is_buffer_descriptor, shader_visibility, 1, context); } return first_binding; } @@ -577,6 +580,36 @@ static uint32_t vkd3d_descriptor_magic_from_d3d12(D3D12_DESCRIPTOR_RANGE_TYPE ty } } +static HRESULT d3d12_root_signature_init_descriptor_array_binding(struct d3d12_root_signature *root_signature, + const D3D12_DESCRIPTOR_RANGE *range, D3D12_SHADER_VISIBILITY visibility, + struct vkd3d_descriptor_set_context *context) +{ + enum vkd3d_shader_descriptor_type descriptor_type = vkd3d_descriptor_type_from_d3d12_range_type(range->RangeType); + enum vkd3d_shader_visibility shader_visibility = vkd3d_shader_visibility_from_d3d12(visibility); + bool is_buffer = descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV; + + 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, + range, visibility, true, context->descriptor_binding, range->NumDescriptors)) + return E_NOTIMPL; + ++context->current_binding; + + d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->RegisterSpace, + range->BaseShaderRegister, true, shader_visibility, range->NumDescriptors, context); + } + + if (!vk_binding_from_d3d12_descriptor_range(context->current_binding, + range, visibility, is_buffer, context->descriptor_binding, range->NumDescriptors)) + return E_NOTIMPL; + ++context->current_binding; + + d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->RegisterSpace, + range->BaseShaderRegister, is_buffer, shader_visibility, range->NumDescriptors, context); + + return S_OK; +} + 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) { @@ -584,6 +617,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo const D3D12_DESCRIPTOR_RANGE *range; unsigned int i, j, k, range_count; uint32_t vk_binding; + HRESULT hr; root_signature->descriptor_table_mask = 0; @@ -633,6 +667,17 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo range = &p->u.DescriptorTable.pDescriptorRanges[j]; + if (root_signature->use_descriptor_arrays) + { + table->ranges[j].binding = context->descriptor_binding; + + if (FAILED(hr = d3d12_root_signature_init_descriptor_array_binding(root_signature, + range, p->ShaderVisibility, context))) + return hr; + + continue; + } + cur_binding = context->current_binding; vk_binding = d3d12_root_signature_assign_vk_bindings(root_signature, @@ -652,14 +697,14 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo /* Assign binding for image view. */ if (!vk_binding_from_d3d12_descriptor_range(cur_binding, - range, p->ShaderVisibility, false, vk_current_binding + 1)) + range, p->ShaderVisibility, false, vk_current_binding + 1, 1)) return E_NOTIMPL; ++cur_binding; } if (!vk_binding_from_d3d12_descriptor_range(cur_binding, - range, p->ShaderVisibility, true, vk_current_binding)) + range, p->ShaderVisibility, true, vk_current_binding, 1)) return E_NOTIMPL; ++cur_binding; @@ -742,11 +787,32 @@ static HRESULT d3d12_root_signature_init_static_samplers(struct d3d12_root_signa return S_OK; } +static bool vk_binding_uses_partial_binding(const VkDescriptorSetLayoutBinding *binding) +{ + if (binding->descriptorCount == 1) + return false; + + switch (binding->descriptorType) + { + /* Types mapped in vk_descriptor_type_from_d3d12_range_type() from D3D12 SRV and UAV types, + * i.e. those which can be a buffer or an image. */ + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + return true; + default: + return false; + } +} + static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_info; + VkDescriptorBindingFlagsEXT *set_flags = NULL; VkDescriptorSetLayoutCreateInfo set_desc; VkResult vr; @@ -755,7 +821,35 @@ static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, set_desc.flags = flags; set_desc.bindingCount = binding_count; set_desc.pBindings = bindings; - if ((vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL, set_layout))) < 0) + if (device->vk_info.EXT_descriptor_indexing) + { + unsigned int i; + + for (i = 0; i < binding_count; ++i) + if (vk_binding_uses_partial_binding(&bindings[i])) + break; + + if (i < binding_count) + { + if (!(set_flags = vkd3d_malloc(binding_count * sizeof(*set_flags)))) + return E_OUTOFMEMORY; + + for (i = 0; i < binding_count; ++i) + set_flags[i] = vk_binding_uses_partial_binding(&bindings[i]) + ? VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT : 0; + + flags_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; + flags_info.pNext = NULL; + flags_info.bindingCount = binding_count; + flags_info.pBindingFlags = set_flags; + + set_desc.pNext = &flags_info; + } + } + + vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL, set_layout)); + vkd3d_free(set_flags); + if (vr < 0) { WARN("Failed to create Vulkan descriptor set layout, vr %d.\n", vr); return hresult_from_vk_result(vr); @@ -817,7 +911,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa | D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT)) FIXME("Ignoring root signature flags %#x.\n", desc->Flags); - if (FAILED(hr = d3d12_root_signature_info_from_desc(&info, desc))) + if (FAILED(hr = d3d12_root_signature_info_from_desc(&info, desc, device->vk_info.EXT_descriptor_indexing))) return hr; if (info.cost > D3D12_MAX_ROOT_COST) { @@ -828,6 +922,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa root_signature->binding_count = info.binding_count; root_signature->static_sampler_count = desc->NumStaticSamplers; root_signature->root_descriptor_count = info.root_descriptor_count; + root_signature->use_descriptor_arrays = device->vk_info.EXT_descriptor_indexing; hr = E_OUTOFMEMORY; root_signature->parameter_count = desc->NumParameters; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 70e3248f..deb8ee99 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -702,6 +702,7 @@ struct d3d12_root_signature VkPipelineLayout vk_pipeline_layout; uint32_t vk_set_count; VkDescriptorSetLayout vk_set_layouts[VKD3D_MAX_DESCRIPTOR_SETS]; + bool use_descriptor_arrays; struct d3d12_root_parameter *parameters; unsigned int parameter_count; diff --git a/tests/d3d12.c b/tests/d3d12.c index 9e61fd6c..bb66b864 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -34635,7 +34635,6 @@ static void test_resource_arrays(void) get_cpu_descriptor_handle(&context, heap, ARRAY_SIZE(input_buffers) + i)); } - todo context.pipeline_state = create_compute_pipeline_state(device, context.root_signature, shader_bytecode(cs_code, sizeof(cs_code))); if (!context.pipeline_state) @@ -34658,7 +34657,6 @@ static void test_resource_arrays(void) transition_sub_resource_state(command_list, output_buffers[i], 0, 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); - todo_if(i) check_readback_data_uint(&rb, NULL, uav_data[i], 0); release_resource_readback(&rb); reset_command_list(command_list, context.allocator);