libs/vkd3d: Duplicate Vulkan descriptors for SRVs and UAVs.

Vulkan has different descriptor types for buffers and textures.
Therefore, we do not know the exact Vulkan descriptor type for D3D12 SRV
and UAV descriptors up front. This information can be extracted from
shaders when creating PSOs but creating incompatible Vulkan descriptor
set layouts for PSOs with the same root signature would introduce a lot
of complexity.

In order to preserve compatibility between resource bindings for PSOs
with the same root signature we duplicate Vulkan descriptors for SRVs
and UAVs (a buffer view and an image view descriptor). This strategy may
be reasonable for small root signatures.
This commit is contained in:
Józef Kucia 2017-08-08 17:09:35 +02:00
parent 1b02322c1d
commit 2665cbe522
4 changed files with 95 additions and 32 deletions

View File

@ -61,6 +61,7 @@ struct vkd3d_shader_resource_binding
{
enum vkd3d_descriptor_type type;
unsigned int register_index;
bool is_buffer;
uint32_t descriptor_set;
uint32_t binding;

View File

@ -1682,11 +1682,13 @@ struct vkd3d_descriptor_binding
};
static struct vkd3d_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_binding(
struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg)
struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg,
enum vkd3d_shader_resource_type resource_type)
{
enum vkd3d_descriptor_type descriptor_type;
struct vkd3d_descriptor_binding vk_binding;
unsigned int reg_idx = reg->idx[0].offset;
bool is_buffer_resource;
unsigned int i;
descriptor_type = VKD3D_DESCRIPTOR_TYPE_UNKNOWN;
@ -1701,13 +1703,15 @@ static struct vkd3d_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_bindin
else
FIXME("Unhandled register type %#x.\n", reg->type);
is_buffer_resource = resource_type == VKD3D_SHADER_RESOURCE_BUFFER;
if (descriptor_type != VKD3D_DESCRIPTOR_TYPE_UNKNOWN)
{
for (i = 0; i < compiler->binding_count; ++i)
{
const struct vkd3d_shader_resource_binding *current = &compiler->bindings[i];
if (current->type == descriptor_type && current->register_index == reg_idx)
if (current->type == descriptor_type && current->register_index == reg_idx
&& current->is_buffer == is_buffer_resource)
{
vk_binding.set = current->descriptor_set;
vk_binding.binding = current->binding;
@ -1724,12 +1728,13 @@ static struct vkd3d_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_bindin
}
static void vkd3d_dxbc_compiler_emit_descriptor_binding(struct vkd3d_dxbc_compiler *compiler,
uint32_t variable_id, const struct vkd3d_shader_register *reg)
uint32_t variable_id, const struct vkd3d_shader_register *reg,
enum vkd3d_shader_resource_type resource_type)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_descriptor_binding vk_binding;
vk_binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg);
vk_binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, resource_type);
vkd3d_spirv_build_op_decorate1(builder, variable_id, SpvDecorationDescriptorSet, vk_binding.set);
vkd3d_spirv_build_op_decorate1(builder, variable_id, SpvDecorationBinding, vk_binding.binding);
}
@ -2701,7 +2706,7 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
pointer_type_id, storage_class, 0);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, reg);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, reg, VKD3D_SHADER_RESOURCE_BUFFER);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
@ -2759,7 +2764,7 @@ static void vkd3d_dxbc_compiler_emit_dcl_sampler(struct vkd3d_dxbc_compiler *com
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
ptr_type_id, storage_class, 0);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, reg);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, reg, VKD3D_SHADER_RESOURCE_NONE);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
@ -2863,7 +2868,7 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
ptr_type_id, storage_class, 0);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, reg);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, reg, semantic->resource_type);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);

View File

@ -2274,12 +2274,12 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootSignature(ID3D12
static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_descriptor_write,
VkDescriptorImageInfo *vk_image_info, struct d3d12_desc *descriptor,
VkDescriptorSet vk_descriptor_set, uint32_t vk_binding)
VkDescriptorSet vk_descriptor_set, uint32_t vk_binding, unsigned int index)
{
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;
vk_descriptor_write->dstBinding = vk_binding + index;
vk_descriptor_write->dstArrayElement = 0;
vk_descriptor_write->descriptorCount = 1;
vk_descriptor_write->descriptorType = descriptor->vk_descriptor_type;
@ -2287,6 +2287,17 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
vk_descriptor_write->pBufferInfo = NULL;
vk_descriptor_write->pTexelBufferView = NULL;
if (descriptor->magic == VKD3D_DESCRIPTOR_MAGIC_SRV
|| descriptor->magic == 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;
}
if (descriptor->magic == VKD3D_DESCRIPTOR_MAGIC_CBV)
{
vk_descriptor_write->pBufferInfo = &descriptor->u.vk_cbv_info;
@ -2369,7 +2380,7 @@ static void d3d12_command_list_set_descriptor_table(struct d3d12_command_list *l
for (j = 0; j < range->descriptor_count; ++j, ++descriptor)
{
if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write,
current_image_info, descriptor, descriptor_set, range->binding + j))
current_image_info, descriptor, descriptor_set, range->binding, j))
continue;
++descriptor_count;

View File

@ -221,14 +221,15 @@ static enum vkd3d_shader_visibility vkd3d_shader_visibility_from_d3d12(D3D12_SHA
}
}
static VkDescriptorType vk_descriptor_type_from_d3d12_range_type(D3D12_DESCRIPTOR_RANGE_TYPE type)
static VkDescriptorType vk_descriptor_type_from_d3d12_range_type(D3D12_DESCRIPTOR_RANGE_TYPE type,
bool is_buffer)
{
switch (type)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
return is_buffer ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; /* FIXME: Add support for images. */
return is_buffer ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
@ -292,10 +293,12 @@ static enum vkd3d_descriptor_type vkd3d_descriptor_type_from_d3d12_root_paramete
}
static bool vk_binding_from_d3d12_descriptor_range(struct VkDescriptorSetLayoutBinding *binding_desc,
const D3D12_DESCRIPTOR_RANGE *descriptor_range, uint32_t vk_binding)
const D3D12_DESCRIPTOR_RANGE *descriptor_range, D3D12_SHADER_VISIBILITY shader_visibility,
bool is_buffer, uint32_t vk_binding)
{
binding_desc->binding = vk_binding;
binding_desc->descriptorType = vk_descriptor_type_from_d3d12_range_type(descriptor_range->RangeType);
binding_desc->descriptorType
= vk_descriptor_type_from_d3d12_range_type(descriptor_range->RangeType, is_buffer);
binding_desc->descriptorCount = 1;
if (descriptor_range->RegisterSpace)
@ -306,6 +309,9 @@ static bool vk_binding_from_d3d12_descriptor_range(struct VkDescriptorSetLayoutB
if (descriptor_range->OffsetInDescriptorsFromTableStart != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
FIXME("Unhandled offset %#x.\n", descriptor_range->OffsetInDescriptorsFromTableStart);
binding_desc->stageFlags = stage_flags_from_visibility(shader_visibility);
binding_desc->pImmutableSamplers = NULL;
return true;
}
@ -500,26 +506,44 @@ static HRESULT d3d12_root_signature_init_push_constants(struct d3d12_root_signat
return S_OK;
}
static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature,
enum vkd3d_descriptor_type descriptor_type, unsigned int base_register_idx,
unsigned int binding_count, uint32_t *descriptor_idx)
static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature *root_signature,
enum vkd3d_descriptor_type descriptor_type, unsigned int register_idx,
bool buffer_descriptor, uint32_t *descriptor_idx)
{
uint32_t first_binding, binding;
unsigned int i;
first_binding = *descriptor_idx;
for (i = 0; i < binding_count; ++i)
{
binding = *descriptor_idx;
uint32_t binding = *descriptor_idx;
root_signature->descriptor_mapping[binding].type = descriptor_type;
root_signature->descriptor_mapping[binding].register_index = base_register_idx + i;
root_signature->descriptor_mapping[binding].register_index = register_idx;
root_signature->descriptor_mapping[binding].is_buffer = buffer_descriptor;
root_signature->descriptor_mapping[binding].descriptor_set = 0;
root_signature->descriptor_mapping[binding].binding = binding;
*descriptor_idx += 1;
}
static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature,
enum vkd3d_descriptor_type descriptor_type, unsigned int base_register_idx,
unsigned int binding_count, bool duplicate_descriptors, uint32_t *descriptor_idx)
{
bool is_buffer_descriptor;
uint32_t first_binding;
unsigned int i;
is_buffer_descriptor = descriptor_type == VKD3D_DESCRIPTOR_TYPE_CBV;
duplicate_descriptors = (descriptor_type == VKD3D_DESCRIPTOR_TYPE_SRV
|| descriptor_type == VKD3D_DESCRIPTOR_TYPE_UAV)
&& duplicate_descriptors;
first_binding = *descriptor_idx;
for (i = 0; i < binding_count; ++i)
{
if (duplicate_descriptors)
d3d12_root_signature_append_vk_binding(root_signature, descriptor_type,
base_register_idx + i, true, descriptor_idx);
d3d12_root_signature_append_vk_binding(root_signature, descriptor_type,
base_register_idx + i, is_buffer_descriptor, descriptor_idx);
}
return first_binding;
}
@ -564,6 +588,12 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
goto fail;
}
/* XXX: Vulkan buffer and image descriptors have different types. In order
* 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.descriptor_count += info.srv_count + info.uav_count;
if (!(binding_desc = vkd3d_calloc(info.descriptor_count, sizeof(*binding_desc))))
{
hr = E_OUTOFMEMORY;
@ -619,19 +649,35 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
vk_binding = d3d12_root_signature_assign_vk_bindings(root_signature,
vkd3d_descriptor_type_from_d3d12_range_type(descriptor_range->RangeType),
descriptor_range->BaseShaderRegister, descriptor_range->NumDescriptors,
&descriptor_idx);
true, &descriptor_idx);
/* Unroll descriptor range. */
for (k = 0; k < descriptor_range->NumDescriptors; ++k)
{
if (!vk_binding_from_d3d12_descriptor_range(cur_binding, descriptor_range, vk_binding + k))
uint32_t vk_current_binding = vk_binding + k;
if (descriptor_range->RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV
|| descriptor_range->RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)
{
vk_current_binding = vk_binding + 2 * k;
/* Assign binding for image view. */
if (!vk_binding_from_d3d12_descriptor_range(cur_binding,
descriptor_range, p->ShaderVisibility, false, vk_current_binding + 1))
{
hr = E_NOTIMPL;
goto fail;
}
cur_binding->stageFlags = stage_flags_from_visibility(p->ShaderVisibility);
cur_binding->pImmutableSamplers = NULL;
++cur_binding;
}
if (!vk_binding_from_d3d12_descriptor_range(cur_binding,
descriptor_range, p->ShaderVisibility, true, vk_current_binding))
{
hr = E_NOTIMPL;
goto fail;
}
++cur_binding;
}
@ -654,7 +700,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
}
cur_binding->binding = d3d12_root_signature_assign_vk_bindings(root_signature,
vkd3d_descriptor_type_from_d3d12_root_parameter_type(p->ParameterType),
p->u.Descriptor.ShaderRegister, 1, &descriptor_idx);
p->u.Descriptor.ShaderRegister, 1, false, &descriptor_idx);
cur_binding->descriptorType = vk_descriptor_type_from_d3d12_root_parameter(p->ParameterType);
cur_binding->descriptorCount = 1;
cur_binding->stageFlags = stage_flags_from_visibility(p->ShaderVisibility);
@ -692,7 +738,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
goto fail;
cur_binding->binding = d3d12_root_signature_assign_vk_bindings(root_signature,
VKD3D_DESCRIPTOR_TYPE_SAMPLER, s->ShaderRegister, 1, &descriptor_idx);
VKD3D_DESCRIPTOR_TYPE_SAMPLER, s->ShaderRegister, 1, false, &descriptor_idx);
cur_binding->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
cur_binding->descriptorCount = 1;
cur_binding->stageFlags = stage_flags_from_visibility(s->ShaderVisibility);