Newer
Older
Conor McCarthy
committed
Conor McCarthy
committed
struct vkd3d_symbol_descriptor_array_data
{
SpvStorageClass storage_class;
uint32_t contained_type_id;
};
struct vkd3d_symbol
{
struct rb_entry entry;
enum
{
VKD3D_SYMBOL_REGISTER,
VKD3D_SYMBOL_SAMPLER,
VKD3D_SYMBOL_COMBINED_SAMPLER,
Conor McCarthy
committed
VKD3D_SYMBOL_DESCRIPTOR_ARRAY,
} type;
union
{
struct vkd3d_symbol_register reg;
struct vkd3d_symbol_resource resource;
struct vkd3d_symbol_sampler sampler;
struct vkd3d_symbol_combined_sampler combined_sampler;
Conor McCarthy
committed
struct vkd3d_symbol_descriptor_array descriptor_array;
} key;
uint32_t id;
Conor McCarthy
committed
/* The array declaration which this symbol maps to, or NULL. */
const struct vkd3d_symbol *descriptor_array;
struct vkd3d_symbol_register_data reg;
struct vkd3d_symbol_resource_data resource;
struct vkd3d_symbol_sampler_data sampler;
Conor McCarthy
committed
struct vkd3d_symbol_descriptor_array_data descriptor_array;
} info;
};
static int vkd3d_symbol_compare(const void *key, const struct rb_entry *entry)
{
const struct vkd3d_symbol *a = key;
const struct vkd3d_symbol *b = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry);
int ret;
if ((ret = vkd3d_u32_compare(a->type, b->type)))
return ret;
return memcmp(&a->key, &b->key, sizeof(a->key));
}
static void vkd3d_symbol_free(struct rb_entry *entry, void *context)
{
struct vkd3d_symbol *s = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
vkd3d_free(s);
}
static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol,
const struct vkd3d_shader_register *reg)
{
symbol->type = VKD3D_SYMBOL_REGISTER;
memset(&symbol->key, 0, sizeof(symbol->key));
symbol->key.reg.type = reg->type;
if (vkd3d_shader_register_is_input(reg) && reg->idx[1].offset != ~0u)
symbol->key.reg.idx = reg->idx[1].offset;
else if (reg->type != VKD3DSPR_IMMCONSTBUFFER)
symbol->key.reg.idx = reg->idx[0].offset;
static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol,
uint32_t val_id, SpvStorageClass storage_class,
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type, DWORD write_mask)
{
symbol->id = val_id;
Conor McCarthy
committed
symbol->descriptor_array = NULL;
symbol->info.reg.storage_class = storage_class;
symbol->info.reg.member_idx = 0;
symbol->info.reg.component_type = component_type;
symbol->info.reg.write_mask = write_mask;
symbol->info.reg.dcl_mask = 0;
symbol->info.reg.structure_stride = 0;
symbol->info.reg.binding_base_idx = 0;
symbol->info.reg.is_aggregate = false;
symbol->info.reg.is_dynamically_indexed = false;
static void vkd3d_symbol_make_resource(struct vkd3d_symbol *symbol,
const struct vkd3d_shader_register *reg)
{
symbol->type = VKD3D_SYMBOL_RESOURCE;
memset(&symbol->key, 0, sizeof(symbol->key));
symbol->key.resource.type = reg->type;
symbol->key.resource.idx = reg->idx[0].offset;
}
static void vkd3d_symbol_make_sampler(struct vkd3d_symbol *symbol,
const struct vkd3d_shader_register *reg)
{
symbol->type = VKD3D_SYMBOL_SAMPLER;
memset(&symbol->key, 0, sizeof(symbol->key));
symbol->key.sampler.id = reg->idx[0].offset;
}
static void vkd3d_symbol_make_combined_sampler(struct vkd3d_symbol *symbol,
const struct vkd3d_shader_register *resource_reg, unsigned int sampler_space, unsigned int sampler_index)
{
symbol->type = VKD3D_SYMBOL_COMBINED_SAMPLER;
memset(&symbol->key, 0, sizeof(symbol->key));
symbol->key.combined_sampler.resource_type = resource_reg->type;
symbol->key.combined_sampler.resource_id = resource_reg->idx[0].offset;
symbol->key.combined_sampler.sampler_space = sampler_space;
symbol->key.combined_sampler.sampler_index = sampler_index;
static struct vkd3d_symbol *vkd3d_symbol_dup(const struct vkd3d_symbol *symbol)
{
struct vkd3d_symbol *s;
if (!(s = vkd3d_malloc(sizeof(*s))))
return NULL;
return memcpy(s, symbol, sizeof(*s));
}
static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol)
{
switch (symbol->type)
{
case VKD3D_SYMBOL_REGISTER:
return vkd3d_dbg_sprintf("register %#x, %u",
symbol->key.reg.type, symbol->key.reg.idx);
case VKD3D_SYMBOL_RESOURCE:
return vkd3d_dbg_sprintf("resource %#x, %u",
symbol->key.resource.type, symbol->key.resource.idx);
case VKD3D_SYMBOL_SAMPLER:
return vkd3d_dbg_sprintf("sampler %u",
symbol->key.sampler.id);
default:
return vkd3d_dbg_sprintf("type %#x", symbol->type);
}
}
size_t stream_location;
unsigned int id;
uint32_t merge_block_id;
uint32_t else_block_id;
};
struct vkd3d_loop_cf_info
{
uint32_t header_block_id;
uint32_t continue_block_id;
uint32_t merge_block_id;
};
struct vkd3d_switch_cf_info
{
size_t stream_location;
uint32_t selector_id;
uint32_t merge_block_id;
uint32_t default_block_id;
uint32_t *case_blocks;
size_t case_blocks_size;
unsigned int case_block_count;
};
struct vkd3d_control_flow_info
{
union
{
struct vkd3d_if_cf_info if_;
struct vkd3d_switch_cf_info switch_;
enum
{
VKD3D_BLOCK_IF,
VKD3D_BLOCK_SWITCH,
} current_block;
bool inside_block;
Józef Kucia
committed
struct vkd3d_push_constant_buffer_binding
{
struct vkd3d_shader_register reg;
Józef Kucia
committed
struct vkd3d_shader_push_constant_buffer pc;
Elizabeth Figura
committed
unsigned int size;
struct vkd3d_shader_phase
{
Henri Verbeet
committed
enum vkd3d_shader_opcode type;
unsigned int idx;
unsigned int instance_count;
uint32_t function_id;
uint32_t instance_id;
size_t function_location;
struct vkd3d_shader_spec_constant
{
enum vkd3d_shader_parameter_name name;
uint32_t id;
};
struct vkd3d_hull_shader_variables
{
uint32_t tess_level_outer_id;
uint32_t tess_level_inner_id;
uint32_t patch_constants_id;
struct vkd3d_dxbc_compiler
{
struct vkd3d_spirv_builder spirv_builder;
Henri Verbeet
committed
struct vkd3d_shader_message_context *message_context;
Henri Verbeet
committed
const struct vkd3d_shader_location *location;
Henri Verbeet
committed
bool failed;
bool strip_debug;
bool ssbo_uavs;
struct rb_tree symbol_table;
uint32_t temp_id;
unsigned int temp_count;
struct vkd3d_hull_shader_variables hs;
uint32_t sample_positions_id;
enum vkd3d_shader_type shader_type;
unsigned int branch_id;
unsigned int switch_id;
unsigned int control_flow_depth;
struct vkd3d_control_flow_info *control_flow_info;
size_t control_flow_info_size;
Józef Kucia
committed
struct vkd3d_shader_interface_info shader_interface;
struct vkd3d_shader_descriptor_offset_info offset_info;
Conor McCarthy
committed
uint32_t descriptor_offsets_member_id;
uint32_t push_constants_var_id;
uint32_t *descriptor_offset_ids;
Józef Kucia
committed
struct vkd3d_push_constant_buffer_binding *push_constants;
const struct vkd3d_shader_spirv_target_info *spirv_target_info;
Józef Kucia
committed
bool after_declarations_section;
Józef Kucia
committed
const struct vkd3d_shader_signature *input_signature;
Józef Kucia
committed
const struct vkd3d_shader_signature *output_signature;
const struct vkd3d_shader_signature *patch_constant_signature;
const struct vkd3d_shader_transform_feedback_info *xfb_info;
struct vkd3d_shader_output_info
Józef Kucia
committed
{
uint32_t id;
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type;
uint32_t array_element_mask;
Józef Kucia
committed
} *output_info;
uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
uint32_t private_output_variable_array_idx[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
uint32_t private_output_variable_write_mask[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
uint32_t epilogue_function_id;
Józef Kucia
committed
uint32_t binding_idx;
Henri Verbeet
committed
const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info;
unsigned int input_control_point_count;
unsigned int output_control_point_count;
Henri Verbeet
committed
bool use_vocp;
unsigned int shader_phase_count;
struct vkd3d_shader_phase *shader_phases;
size_t shader_phases_size;
uint32_t current_spec_constant_id;
unsigned int spec_constant_count;
struct vkd3d_shader_spec_constant *spec_constants;
size_t spec_constants_size;
enum vkd3d_shader_compile_option_formatting_flags formatting;
Conor McCarthy
committed
struct vkd3d_string_buffer_cache string_buffers;
static bool is_control_point_phase(const struct vkd3d_shader_phase *phase)
{
return phase && phase->type == VKD3DSIH_HS_CONTROL_POINT_PHASE;
}
static void vkd3d_dxbc_compiler_emit_initial_declarations(struct vkd3d_dxbc_compiler *compiler);
static const char *vkd3d_dxbc_compiler_get_entry_point_name(const struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
return info && info->entry_point ? info->entry_point : "main";
}
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
const struct vkd3d_shader_desc *shader_desc, const struct vkd3d_shader_compile_info *compile_info,
Henri Verbeet
committed
const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info,
Henri Verbeet
committed
struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location)
const struct vkd3d_shader_signature *patch_constant_signature = &shader_desc->patch_constant_signature;
Józef Kucia
committed
const struct vkd3d_shader_signature *output_signature = &shader_desc->output_signature;
Henri Verbeet
committed
const struct vkd3d_shader_interface_info *shader_interface;
const struct vkd3d_shader_descriptor_offset_info *offset_info;
Henri Verbeet
committed
const struct vkd3d_shader_spirv_target_info *target_info;
struct vkd3d_dxbc_compiler *compiler;
unsigned int max_element_count;
if (!(compiler = vkd3d_malloc(sizeof(*compiler))))
return NULL;
memset(compiler, 0, sizeof(*compiler));
Henri Verbeet
committed
compiler->message_context = message_context;
Henri Verbeet
committed
compiler->location = location;
Józef Kucia
committed
Henri Verbeet
committed
if ((target_info = vkd3d_find_struct(compile_info->next, SPIRV_TARGET_INFO)))
{
switch (target_info->environment)
{
case VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5:
case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0:
break;
default:
WARN("Invalid target environment %#x.\n", target_info->environment);
vkd3d_free(compiler);
return NULL;
}
compiler->spirv_target_info = target_info;
}
max_element_count = max(output_signature->element_count, patch_constant_signature->element_count);
if (!(compiler->output_info = vkd3d_calloc(max_element_count, sizeof(*compiler->output_info))))
Józef Kucia
committed
{
vkd3d_free(compiler);
return NULL;
}
vkd3d_spirv_builder_init(&compiler->spirv_builder, vkd3d_dxbc_compiler_get_entry_point_name(compiler));
compiler->formatting = VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT
| VKD3D_SHADER_COMPILE_OPTION_FORMATTING_HEADER;
for (i = 0; i < compile_info->option_count; ++i)
{
const struct vkd3d_shader_compile_option *option = &compile_info->options[i];
switch (option->name)
{
case VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG:
compiler->strip_debug = !!option->value;
break;
case VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV:
if (option->value == VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV_STORAGE_TEXEL_BUFFER)
compiler->ssbo_uavs = false;
else if (option->value == VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV_STORAGE_BUFFER)
compiler->ssbo_uavs = true;
else
WARN("Ignoring unrecognised value %#x for option %#x.\n", option->value, option->name);
break;
case VKD3D_SHADER_COMPILE_OPTION_FORMATTING:
compiler->formatting = option->value;
break;
default:
WARN("Ignoring unrecognised option %#x with value %#x.\n", option->name, option->value);
break;
}
}
rb_init(&compiler->symbol_table, vkd3d_symbol_compare);
compiler->shader_type = shader_version->type;
Józef Kucia
committed
compiler->input_signature = &shader_desc->input_signature;
compiler->output_signature = &shader_desc->output_signature;
compiler->patch_constant_signature = &shader_desc->patch_constant_signature;
Józef Kucia
committed
Henri Verbeet
committed
if ((shader_interface = vkd3d_find_struct(compile_info->next, INTERFACE_INFO)))
Józef Kucia
committed
{
compiler->xfb_info = vkd3d_find_struct(compile_info->next, TRANSFORM_FEEDBACK_INFO);
compiler->shader_interface = *shader_interface;
Józef Kucia
committed
if (shader_interface->push_constant_buffer_count)
Józef Kucia
committed
if (!(compiler->push_constants = vkd3d_calloc(shader_interface->push_constant_buffer_count,
sizeof(*compiler->push_constants))))
{
vkd3d_dxbc_compiler_destroy(compiler);
return NULL;
}
Józef Kucia
committed
for (i = 0; i < shader_interface->push_constant_buffer_count; ++i)
compiler->push_constants[i].pc = shader_interface->push_constant_buffers[i];
if ((offset_info = vkd3d_find_struct(shader_interface->next, DESCRIPTOR_OFFSET_INFO)))
{
compiler->offset_info = *offset_info;
Conor McCarthy
committed
if (compiler->offset_info.descriptor_table_count && !(compiler->descriptor_offset_ids = vkd3d_calloc(
compiler->offset_info.descriptor_table_count, sizeof(*compiler->descriptor_offset_ids))))
{
vkd3d_dxbc_compiler_destroy(compiler);
return NULL;
}
Henri Verbeet
committed
compiler->scan_descriptor_info = scan_descriptor_info;
Józef Kucia
committed
Conor McCarthy
committed
vkd3d_string_buffer_cache_init(&compiler->string_buffers);
vkd3d_dxbc_compiler_emit_initial_declarations(compiler);
return compiler;
}
static bool vkd3d_dxbc_compiler_use_storage_buffer(const struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_symbol_resource_data *resource)
{
return compiler->ssbo_uavs && resource->resource_type_info->resource_type == VKD3D_SHADER_RESOURCE_BUFFER;
}
Henri Verbeet
committed
static enum vkd3d_shader_spirv_environment vkd3d_dxbc_compiler_get_target_environment(
const struct vkd3d_dxbc_compiler *compiler)
const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
Henri Verbeet
committed
return info ? info->environment : VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
static bool vkd3d_dxbc_compiler_is_opengl_target(const struct vkd3d_dxbc_compiler *compiler)
{
Henri Verbeet
committed
return vkd3d_dxbc_compiler_get_target_environment(compiler) == VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5;
static bool vkd3d_dxbc_compiler_is_target_extension_supported(const struct vkd3d_dxbc_compiler *compiler,
Henri Verbeet
committed
enum vkd3d_shader_spirv_extension extension)
const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
unsigned int i;
Henri Verbeet
committed
for (i = 0; info && i < info->extension_count; ++i)
Henri Verbeet
committed
if (info->extensions[i] == extension)
return true;
}
return false;
}
static bool vkd3d_dxbc_compiler_check_shader_visibility(const struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_shader_visibility visibility)
{
switch (visibility)
{
case VKD3D_SHADER_VISIBILITY_ALL:
return true;
case VKD3D_SHADER_VISIBILITY_VERTEX:
return compiler->shader_type == VKD3D_SHADER_TYPE_VERTEX;
case VKD3D_SHADER_VISIBILITY_HULL:
return compiler->shader_type == VKD3D_SHADER_TYPE_HULL;
case VKD3D_SHADER_VISIBILITY_DOMAIN:
return compiler->shader_type == VKD3D_SHADER_TYPE_DOMAIN;
case VKD3D_SHADER_VISIBILITY_GEOMETRY:
return compiler->shader_type == VKD3D_SHADER_TYPE_GEOMETRY;
case VKD3D_SHADER_VISIBILITY_PIXEL:
return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL;
case VKD3D_SHADER_VISIBILITY_COMPUTE:
return compiler->shader_type == VKD3D_SHADER_TYPE_COMPUTE;
default:
ERR("Invalid shader visibility %#x.\n", visibility);
return false;
}
}
Józef Kucia
committed
static struct vkd3d_push_constant_buffer_binding *vkd3d_dxbc_compiler_find_push_constant_buffer(
Elizabeth Figura
committed
const struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_constant_buffer *cb)
Conor McCarthy
committed
unsigned int register_space = cb->range.space;
unsigned int reg_idx = cb->range.first;
Conor McCarthy
committed
if (cb->range.first != cb->range.last)
return NULL;
Józef Kucia
committed
for (i = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
Józef Kucia
committed
struct vkd3d_push_constant_buffer_binding *current = &compiler->push_constants[i];
if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->pc.shader_visibility))
continue;
if (current->pc.register_space == register_space && current->pc.register_index == reg_idx)
return current;
}
return NULL;
}
static bool vkd3d_dxbc_compiler_has_combined_sampler(const struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_resource *resource, const struct vkd3d_shader_sampler *sampler)
const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
const struct vkd3d_shader_combined_resource_sampler *combined_sampler;
unsigned int i;
if (!shader_interface->combined_sampler_count)
return false;
if (resource && (resource->reg.reg.type == VKD3DSPR_UAV || resource->range.last != resource->range.first))
return false;
if (sampler && sampler->range.first != sampler->range.last)
return false;
for (i = 0; i < shader_interface->combined_sampler_count; ++i)
{
combined_sampler = &shader_interface->combined_samplers[i];
if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, combined_sampler->shader_visibility))
continue;
if ((!resource || (combined_sampler->resource_space == resource->range.space
&& combined_sampler->resource_index == resource->range.first))
Conor McCarthy
committed
&& (!sampler || (combined_sampler->sampler_space == sampler->range.space
&& combined_sampler->sampler_index == sampler->range.first)))
return true;
}
return false;
}
Henri Verbeet
committed
static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_dxbc_compiler_error(struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_shader_error error, const char *format, ...)
{
va_list args;
va_start(args, format);
Henri Verbeet
committed
vkd3d_shader_verror(compiler->message_context, compiler->location, error, format, args);
Henri Verbeet
committed
va_end(args);
compiler->failed = true;
}
Conor McCarthy
committed
static struct vkd3d_string_buffer *vkd3d_shader_register_range_string(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register_range *range)
{
struct vkd3d_string_buffer *buffer = vkd3d_string_buffer_get(&compiler->string_buffers);
if (!buffer)
return NULL;
if (range->last != ~0u)
vkd3d_string_buffer_printf(buffer, "[%u:%u]", range->first, range->last);
else
vkd3d_string_buffer_printf(buffer, "[%u:*]", range->first);
return buffer;
}
static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_binding(
struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg,
const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type,
Conor McCarthy
committed
bool is_uav_counter, struct vkd3d_descriptor_binding_address *binding_address)
Józef Kucia
committed
{
const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
unsigned int register_last = (range->last == ~0u) ? range->first : range->last;
const struct vkd3d_shader_descriptor_offset *binding_offsets;
Józef Kucia
committed
enum vkd3d_shader_descriptor_type descriptor_type;
enum vkd3d_shader_binding_flag resource_type_flag;
struct vkd3d_shader_descriptor_binding binding;
Józef Kucia
committed
unsigned int i;
if (reg->type == VKD3DSPR_CONSTBUFFER)
Józef Kucia
committed
descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
Józef Kucia
committed
else if (reg->type == VKD3DSPR_RESOURCE)
Józef Kucia
committed
descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV;
Józef Kucia
committed
else if (reg->type == VKD3DSPR_UAV)
Józef Kucia
committed
descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV;
Józef Kucia
committed
else if (reg->type == VKD3DSPR_SAMPLER)
Józef Kucia
committed
descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER;
Józef Kucia
committed
else
{
Józef Kucia
committed
FIXME("Unhandled register type %#x.\n", reg->type);
vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE,
"Encountered invalid/unhandled register type %#x.", reg->type);
}
Józef Kucia
committed
resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER
? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
if (is_uav_counter)
{
assert(descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV);
binding_offsets = compiler->offset_info.uav_counter_offsets;
for (i = 0; i < shader_interface->uav_counter_count; ++i)
{
const struct vkd3d_shader_uav_counter_binding *current = &shader_interface->uav_counters[i];
if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->shader_visibility))
continue;
if (current->register_space != range->space || current->register_index > range->first
|| current->binding.count <= register_last - current->register_index)
continue;
if (current->offset)
FIXME("Atomic counter offsets are not supported yet.\n");
vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
"Descriptor binding for UAV counter %u, space %u has unsupported ‘offset’ %u.",
range->first, range->space, current->offset);
binding_address->binding_base_idx = current->register_index
- (binding_offsets ? binding_offsets[i].static_offset : 0);
binding_address->push_constant_index = binding_offsets ? binding_offsets[i].dynamic_offset_index : ~0u;
return current->binding;
}
if (shader_interface->uav_counter_count)
Henri Verbeet
committed
{
FIXME("Could not find descriptor binding for UAV counter %u, space %u.\n", range->first, range->space);
Henri Verbeet
committed
vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND,
"Could not find descriptor binding for UAV counter %u, space %u.", range->first, range->space);
Henri Verbeet
committed
}
Józef Kucia
committed
{
binding_offsets = compiler->offset_info.binding_offsets;
for (i = 0; i < shader_interface->binding_count; ++i)
Józef Kucia
committed
{
const struct vkd3d_shader_resource_binding *current = &shader_interface->bindings[i];
Józef Kucia
committed
if (!(current->flags & resource_type_flag))
continue;
if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->shader_visibility))
continue;
if (current->type != descriptor_type || current->register_space != range->space
|| current->register_index > range->first
|| current->binding.count <= register_last - current->register_index)
continue;
Conor McCarthy
committed
binding_address->binding_base_idx = current->register_index
- (binding_offsets ? binding_offsets[i].static_offset : 0);
binding_address->push_constant_index = binding_offsets ? binding_offsets[i].dynamic_offset_index : ~0u;
return current->binding;
Józef Kucia
committed
}
if (shader_interface->binding_count)
Henri Verbeet
committed
{
Conor McCarthy
committed
struct vkd3d_string_buffer *buffer = vkd3d_shader_register_range_string(compiler, range);
const char *range_str = buffer ? buffer->buffer : "";
FIXME("Could not find descriptor binding for type %#x, space %u, registers %s, shader type %#x.\n",
descriptor_type, range->space, range_str, compiler->shader_type);
Henri Verbeet
committed
vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND,
Conor McCarthy
committed
"Could not find descriptor binding for type %#x, space %u, registers %s, shader type %#x.",
descriptor_type, range->space, range_str, compiler->shader_type);
vkd3d_string_buffer_release(&compiler->string_buffers, buffer);
Henri Verbeet
committed
}
Józef Kucia
committed
}
Conor McCarthy
committed
binding_address->binding_base_idx = range->first;
binding_address->push_constant_index = ~0u;
binding.set = 0;
binding.count = 1;
binding.binding = compiler->binding_idx++;
return binding;
Józef Kucia
committed
}
static void vkd3d_dxbc_compiler_emit_descriptor_binding(struct vkd3d_dxbc_compiler *compiler,
uint32_t variable_id, const struct vkd3d_shader_descriptor_binding *binding)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
vkd3d_spirv_build_op_decorate1(builder, variable_id, SpvDecorationDescriptorSet, binding->set);
vkd3d_spirv_build_op_decorate1(builder, variable_id, SpvDecorationBinding, binding->binding);
}
static void vkd3d_dxbc_compiler_decorate_nonuniform(struct vkd3d_dxbc_compiler *compiler,
uint32_t expression_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
vkd3d_spirv_enable_capability(builder, SpvCapabilityShaderNonUniformEXT);
vkd3d_spirv_build_op_decorate(builder, expression_id, SpvDecorationNonUniformEXT, NULL, 0);
}
Conor McCarthy
committed
static const struct vkd3d_symbol *vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_symbol *symbol)
{
struct vkd3d_symbol *s;
s = vkd3d_symbol_dup(symbol);
if (rb_put(&compiler->symbol_table, s, &s->entry) == -1)
{
ERR("Failed to insert symbol entry (%s).\n", debug_vkd3d_symbol(symbol));
Conor McCarthy
committed
return NULL;
Conor McCarthy
committed
return s;
static uint32_t vkd3d_dxbc_compiler_get_constant(struct vkd3d_dxbc_compiler *compiler,
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type, unsigned int component_count, const uint32_t *values)
uint32_t type_id, scalar_type_id, component_ids[VKD3D_VEC4_SIZE];
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int i;
assert(0 < component_count && component_count <= VKD3D_VEC4_SIZE);
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
switch (component_type)
{
Henri Verbeet
committed
case VKD3D_SHADER_COMPONENT_UINT:
case VKD3D_SHADER_COMPONENT_INT:
case VKD3D_SHADER_COMPONENT_FLOAT:
break;
default:
FIXME("Unhandled component_type %#x.\n", component_type);
return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id);
}
if (component_count == 1)
{
return vkd3d_spirv_get_op_constant(builder, type_id, *values);
scalar_type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
for (i = 0; i < component_count; ++i)
component_ids[i] = vkd3d_spirv_get_op_constant(builder, scalar_type_id, values[i]);
return vkd3d_spirv_get_op_constant_composite(builder, type_id, component_ids, component_count);
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
static uint32_t vkd3d_dxbc_compiler_get_constant64(struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_shader_component_type component_type, unsigned int component_count, const uint64_t *values)
{
uint32_t type_id, scalar_type_id, component_ids[VKD3D_DVEC2_SIZE];
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int i;
assert(0 < component_count && component_count <= VKD3D_DVEC2_SIZE);
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
if (component_type != VKD3D_SHADER_COMPONENT_DOUBLE)
{
FIXME("Unhandled component_type %#x.\n", component_type);
return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id);
}
if (component_count == 1)
{
return vkd3d_spirv_get_op_constant64(builder, type_id, *values);
}
else
{
scalar_type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
for (i = 0; i < component_count; ++i)
component_ids[i] = vkd3d_spirv_get_op_constant64(builder, scalar_type_id, values[i]);
return vkd3d_spirv_get_op_constant_composite(builder, type_id, component_ids, component_count);
}
}
static uint32_t vkd3d_dxbc_compiler_get_constant_uint(struct vkd3d_dxbc_compiler *compiler,
uint32_t value)
{
Henri Verbeet
committed
return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_SHADER_COMPONENT_UINT, 1, &value);
static uint32_t vkd3d_dxbc_compiler_get_constant_float(struct vkd3d_dxbc_compiler *compiler,
float value)
{
Henri Verbeet
committed
return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_SHADER_COMPONENT_FLOAT, 1, (uint32_t *)&value);
static uint32_t vkd3d_dxbc_compiler_get_constant_vector(struct vkd3d_dxbc_compiler *compiler,
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type, unsigned int component_count, uint32_t value)
{
const uint32_t values[] = {value, value, value, value};
return vkd3d_dxbc_compiler_get_constant(compiler, component_type, component_count, values);
}
Józef Kucia
committed
static uint32_t vkd3d_dxbc_compiler_get_constant_uint_vector(struct vkd3d_dxbc_compiler *compiler,
uint32_t value, unsigned int component_count)
{
Henri Verbeet
committed
return vkd3d_dxbc_compiler_get_constant_vector(compiler, VKD3D_SHADER_COMPONENT_UINT, component_count, value);
Józef Kucia
committed
}
static uint32_t vkd3d_dxbc_compiler_get_constant_float_vector(struct vkd3d_dxbc_compiler *compiler,
float value, unsigned int component_count)
{
const float values[] = {value, value, value, value};
Henri Verbeet
committed
return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_SHADER_COMPONENT_FLOAT,
component_count, (const uint32_t *)values);
}
static uint32_t vkd3d_dxbc_compiler_get_constant_double_vector(struct vkd3d_dxbc_compiler *compiler,
double value, unsigned int component_count)
{
const double values[] = {value, value};
return vkd3d_dxbc_compiler_get_constant64(compiler, VKD3D_SHADER_COMPONENT_DOUBLE,
component_count, (const uint64_t *)values);
}
static uint32_t vkd3d_dxbc_compiler_get_type_id_for_reg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
return vkd3d_spirv_get_type_id(builder,
vkd3d_component_type_from_data_type(reg->data_type),
vkd3d_write_mask_component_count(write_mask));
}
static uint32_t vkd3d_dxbc_compiler_get_type_id_for_dst(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst)
{
return vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, &dst->reg, dst->write_mask);
}
Józef Kucia
committed
static bool vkd3d_dxbc_compiler_get_register_name(char *buffer, unsigned int buffer_size,
const struct vkd3d_shader_register *reg)
unsigned int idx;
idx = reg->idx[1].offset != ~0u ? reg->idx[1].offset : reg->idx[0].offset;
switch (reg->type)
{
case VKD3DSPR_RESOURCE:
snprintf(buffer, buffer_size, "t%u", reg->idx[0].offset);
break;
case VKD3DSPR_UAV:
snprintf(buffer, buffer_size, "u%u", reg->idx[0].offset);
break;
case VKD3DSPR_SAMPLER:
snprintf(buffer, buffer_size, "s%u", reg->idx[0].offset);
break;
case VKD3DSPR_CONSTBUFFER:
Józef Kucia
committed
snprintf(buffer, buffer_size, "cb%u_%u", reg->idx[0].offset, reg->idx[1].offset);
break;
case VKD3DSPR_INPUT:
snprintf(buffer, buffer_size, "v%u", idx);
case VKD3DSPR_INCONTROLPOINT:
snprintf(buffer, buffer_size, "vicp%u", idx);
break;
case VKD3DSPR_OUTPUT:
case VKD3DSPR_COLOROUT:
snprintf(buffer, buffer_size, "o%u", idx);
case VKD3DSPR_DEPTHOUTGE:
case VKD3DSPR_DEPTHOUTLE:
snprintf(buffer, buffer_size, "oDepth");
break;
case VKD3DSPR_FORKINSTID:
snprintf(buffer, buffer_size, "vForkInstanceId");
break;
case VKD3DSPR_JOININSTID:
snprintf(buffer, buffer_size, "vJoinInstanceId");
break;
Henri Verbeet
committed
case VKD3DSPR_GSINSTID:
snprintf(buffer, buffer_size, "vGSInstanceID");
break;
case VKD3DSPR_PATCHCONST:
snprintf(buffer, buffer_size, "vpc%u", idx);
break;
case VKD3DSPR_TESSCOORD:
snprintf(buffer, buffer_size, "vDomainLocation");
break;
Józef Kucia
committed
snprintf(buffer, buffer_size, "vThreadID");
case VKD3DSPR_LOCALTHREADID:
snprintf(buffer, buffer_size, "vThreadIDInGroup");
break;
case VKD3DSPR_LOCALTHREADINDEX:
snprintf(buffer, buffer_size, "vThreadIDInGroupFlattened");
break;
case VKD3DSPR_THREADGROUPID:
snprintf(buffer, buffer_size, "vThreadGroupID");
break;
case VKD3DSPR_GROUPSHAREDMEM:
snprintf(buffer, buffer_size, "g%u", reg->idx[0].offset);
break;
case VKD3DSPR_IDXTEMP:
snprintf(buffer, buffer_size, "x%u", idx);
break;
case VKD3DSPR_COVERAGE:
snprintf(buffer, buffer_size, "vCoverage");
break;
case VKD3DSPR_SAMPLEMASK:
snprintf(buffer, buffer_size, "oMask");
break;
case VKD3DSPR_OUTPOINTID:
case VKD3DSPR_PRIMID:
/* SPIRV-Tools disassembler generates names for SPIR-V built-ins. */
return false;
case VKD3DSPR_OUTSTENCILREF:
snprintf(buffer, buffer_size, "oStencilRef");
break;
default:
FIXME("Unhandled register %#x.\n", reg->type);
Józef Kucia
committed
snprintf(buffer, buffer_size, "unrecognized_%#x", reg->type);
return false;
}
return true;
}
/* TODO: UAV counters: vkd3d_spirv_build_op_name(builder, counter_var_id, "u%u_counter", reg->idx[0].offset); */
static void vkd3d_dxbc_compiler_emit_register_debug_name(struct vkd3d_spirv_builder *builder,
uint32_t id, const struct vkd3d_shader_register *reg)
{
char debug_name[256];
Józef Kucia
committed
if (vkd3d_dxbc_compiler_get_register_name(debug_name, ARRAY_SIZE(debug_name), reg))
vkd3d_spirv_build_op_name(builder, id, "%s", debug_name);
}
static uint32_t vkd3d_dxbc_compiler_emit_variable(struct vkd3d_dxbc_compiler *compiler,
struct vkd3d_spirv_stream *stream, SpvStorageClass storage_class,
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type, unsigned int component_count)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id;
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0);
static uint32_t vkd3d_dxbc_compiler_emit_array_variable(struct vkd3d_dxbc_compiler *compiler,
struct vkd3d_spirv_stream *stream, SpvStorageClass storage_class,
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type, unsigned int component_count, unsigned int array_length)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, length_id, ptr_type_id;
if (!array_length)
return vkd3d_dxbc_compiler_emit_variable(compiler,
stream, storage_class, component_type, component_count);
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, array_length);
type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0);
}
static const struct vkd3d_shader_parameter *vkd3d_dxbc_compiler_get_shader_parameter(
struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_parameter_name name)
{
const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
for (i = 0; info && i < info->parameter_count; ++i)
if (info->parameters[i].name == name)
return &info->parameters[i];
}
return NULL;
}
static const struct vkd3d_spec_constant_info
{
enum vkd3d_shader_parameter_name name;
uint32_t default_value;
const char *debug_name;
}
vkd3d_shader_parameters[] =
{
{VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, 1, "sample_count"},
};
static const struct vkd3d_spec_constant_info *get_spec_constant_info(enum vkd3d_shader_parameter_name name)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(vkd3d_shader_parameters); ++i)
{
if (vkd3d_shader_parameters[i].name == name)
return &vkd3d_shader_parameters[i];
}