Newer
Older
{
return phase && phase->type == VKD3DSIH_HS_CONTROL_POINT_PHASE;
}
static void vkd3d_dxbc_compiler_emit_initial_declarations(struct vkd3d_dxbc_compiler *compiler);
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
Józef Kucia
committed
const struct vkd3d_shader_desc *shader_desc, uint32_t compiler_options,
const struct vkd3d_shader_interface_info *shader_interface,
const struct vkd3d_shader_compile_arguments *compile_args,
Józef Kucia
committed
const struct vkd3d_shader_scan_info *scan_info)
Józef Kucia
committed
const struct vkd3d_shader_signature *output_signature = &shader_desc->output_signature;
struct vkd3d_dxbc_compiler *compiler;
if (!(compiler = vkd3d_malloc(sizeof(*compiler))))
return NULL;
memset(compiler, 0, sizeof(*compiler));
Józef Kucia
committed
if (!(compiler->output_info = vkd3d_calloc(output_signature->element_count, sizeof(*compiler->output_info))))
{
vkd3d_free(compiler);
return NULL;
}
vkd3d_spirv_builder_init(&compiler->spirv_builder);
compiler->options = compiler_options;
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
if (shader_interface)
Józef Kucia
committed
{
compiler->xfb_info = vkd3d_find_struct(shader_interface->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];
compiler->compile_args = compile_args;
Józef Kucia
committed
compiler->scan_info = scan_info;
vkd3d_dxbc_compiler_emit_initial_declarations(compiler);
return compiler;
}
static enum vkd3d_shader_target vkd3d_dxbc_compiler_get_target(const struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_compile_arguments *args = compiler->compile_args;
return args ? args->target : VKD3D_SHADER_TARGET_SPIRV_VULKAN_1_0;
}
static bool vkd3d_dxbc_compiler_is_opengl_target(const struct vkd3d_dxbc_compiler *compiler)
{
return vkd3d_dxbc_compiler_get_target(compiler) == VKD3D_SHADER_TARGET_SPIRV_OPENGL_4_5;
}
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(
const struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg)
{
unsigned int reg_idx = reg->idx[0].offset;
unsigned int i;
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_index == reg_idx)
return current;
}
return NULL;
}
static bool vkd3d_dxbc_compiler_have_combined_sampler(const struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *resource, const struct vkd3d_shader_register *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->type == VKD3DSPR_UAV)
return false;
for (i = 0; i < shader_interface->combined_sampler_count; ++i)
{
combined_sampler = &shader_interface->combined_samplers[i];
if ((!resource || combined_sampler->resource_index == resource->idx[0].offset)
&& (!sampler || combined_sampler->sampler_index == sampler->idx[0].offset))
return true;
}
return false;
}
static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_binding(
struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg,
enum vkd3d_shader_resource_type resource_type, bool is_uav_counter)
Józef Kucia
committed
{
const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
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 reg_idx = reg->idx[0].offset;
unsigned int i;
Józef Kucia
committed
descriptor_type = VKD3D_SHADER_DESCRIPTOR_TYPE_UNKNOWN;
Józef Kucia
committed
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
FIXME("Unhandled register type %#x.\n", reg->type);
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);
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->offset)
FIXME("Atomic counter offsets are not supported yet.\n");
if (current->register_index == reg_idx)
return current->binding;
}
if (shader_interface->uav_counter_count)
FIXME("Could not find descriptor binding for UAV counter %u.\n", reg_idx);
}
else if (descriptor_type != VKD3D_SHADER_DESCRIPTOR_TYPE_UNKNOWN)
Józef Kucia
committed
{
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_index == reg_idx)
return current->binding;
Józef Kucia
committed
}
if (shader_interface->binding_count)
FIXME("Could not find binding for type %#x, register %u, shader type %#x.\n",
descriptor_type, reg_idx, compiler->shader_type);
Józef Kucia
committed
}
binding.set = 0;
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_emit_descriptor_binding_for_reg(struct vkd3d_dxbc_compiler *compiler,
uint32_t variable_id, const struct vkd3d_shader_register *reg,
enum vkd3d_shader_resource_type resource_type, bool is_uav_counter)
Józef Kucia
committed
{
struct vkd3d_shader_descriptor_binding binding;
Józef Kucia
committed
binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, resource_type, is_uav_counter);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding);
Józef Kucia
committed
}
static void 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));
vkd3d_free(s);
}
}
static uint32_t vkd3d_dxbc_compiler_get_constant(struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_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)
{
case VKD3D_TYPE_UINT:
case VKD3D_TYPE_INT:
case VKD3D_TYPE_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);
}
}
static uint32_t vkd3d_dxbc_compiler_get_constant_uint(struct vkd3d_dxbc_compiler *compiler,
uint32_t value)
{
return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_TYPE_UINT, 1, &value);
}
static uint32_t vkd3d_dxbc_compiler_get_constant_float(struct vkd3d_dxbc_compiler *compiler,
float value)
{
return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_TYPE_FLOAT, 1, (uint32_t *)&value);
}
static uint32_t vkd3d_dxbc_compiler_get_constant_vector(struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_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)
{
return vkd3d_dxbc_compiler_get_constant_vector(compiler, VKD3D_TYPE_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};
return vkd3d_dxbc_compiler_get_constant(compiler,
VKD3D_TYPE_FLOAT, component_count, (const uint32_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_OUTPOINTID:
snprintf(buffer, buffer_size, "vOutputControlPointID");
break;
case VKD3DSPR_DEPTHOUTGE:
case VKD3DSPR_DEPTHOUTLE:
snprintf(buffer, buffer_size, "oDepth");
break;
case VKD3DSPR_PRIMID:
snprintf(buffer, buffer_size, "vPrim");
break;
case VKD3DSPR_FORKINSTID:
snprintf(buffer, buffer_size, "vForkInstanceId");
break;
case VKD3DSPR_JOININSTID:
snprintf(buffer, buffer_size, "vJoinInstanceId");
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;
default:
FIXME("Unhandled register %#x.\n", reg->type);
Józef Kucia
committed
snprintf(buffer, buffer_size, "unrecognized_%#x", reg->type);
return false;
}
return true;
}
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,
enum vkd3d_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,
enum vkd3d_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);
}
Józef Kucia
committed
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
static uint32_t vkd3d_dxbc_compiler_emit_construct_vector(struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_component_type component_type, unsigned int component_count,
uint32_t val_id, unsigned int val_component_idx, unsigned int val_component_count)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t components[VKD3D_VEC4_SIZE];
uint32_t type_id, result_id;
unsigned int i;
assert(val_component_idx < val_component_count);
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
if (val_component_count == 1)
{
for (i = 0; i < component_count; ++i)
components[i] = val_id;
result_id = vkd3d_spirv_build_op_composite_construct(builder,
type_id, components, component_count);
}
else
{
for (i = 0; i < component_count; ++i)
components[i] = val_component_idx;
result_id = vkd3d_spirv_build_op_vector_shuffle(builder,
type_id, val_id, val_id, components, component_count);
}
return result_id;
}
Józef Kucia
committed
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
static uint32_t vkd3d_dxbc_compiler_emit_load_src(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_src_param *src, DWORD write_mask);
static uint32_t vkd3d_dxbc_compiler_emit_register_addressing(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register_index *reg_index)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, addr_id;
if (!reg_index->rel_addr)
return vkd3d_dxbc_compiler_get_constant_uint(compiler, reg_index->offset);
addr_id = vkd3d_dxbc_compiler_emit_load_src(compiler, reg_index->rel_addr, VKD3DSP_WRITEMASK_0);
if (reg_index->offset)
{
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_UINT, 1);
addr_id = vkd3d_spirv_build_op_iadd(builder, type_id,
addr_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, reg_index->offset));
}
return addr_id;
}
struct vkd3d_shader_register_info
{
uint32_t id;
SpvStorageClass storage_class;
enum vkd3d_component_type component_type;
unsigned int write_mask;
Józef Kucia
committed
uint32_t member_idx;
unsigned int structure_stride;
bool is_aggregate;
bool is_dynamically_indexed;
static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, struct vkd3d_shader_register_info *register_info)
{
struct vkd3d_symbol reg_symbol, *symbol;
struct rb_entry *entry;
assert(reg->type != VKD3DSPR_IMMCONST);
if (reg->type == VKD3DSPR_TEMP)
{
assert(reg->idx[0].offset < compiler->temp_count);
register_info->id = compiler->temp_id + reg->idx[0].offset;
register_info->storage_class = SpvStorageClassFunction;
register_info->member_idx = 0;
register_info->component_type = VKD3D_TYPE_FLOAT;
register_info->write_mask = VKD3DSP_WRITEMASK_ALL;
register_info->structure_stride = 0;
register_info->is_aggregate = false;
register_info->is_dynamically_indexed = false;
return true;
}
vkd3d_symbol_make_register(®_symbol, reg);
if (!(entry = rb_get(&compiler->symbol_table, ®_symbol)))
{
FIXME("Unrecognized register (%s).\n", debug_vkd3d_symbol(®_symbol));
memset(register_info, 0, sizeof(*register_info));
return false;
}
symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
register_info->id = symbol->id;
register_info->storage_class = symbol->info.reg.storage_class;
register_info->member_idx = symbol->info.reg.member_idx;
register_info->component_type = symbol->info.reg.component_type;
register_info->write_mask = symbol->info.reg.write_mask;
register_info->structure_stride = symbol->info.reg.structure_stride;
register_info->is_aggregate = symbol->info.reg.is_aggregate;
register_info->is_dynamically_indexed = symbol->info.reg.is_dynamically_indexed;
Józef Kucia
committed
return true;
}
static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, struct vkd3d_shader_register_info *register_info)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int component_count, index_count = 0;
Józef Kucia
committed
uint32_t type_id, ptr_type_id;
uint32_t indexes[2];
if (reg->type == VKD3DSPR_CONSTBUFFER)
{
assert(!reg->idx[0].rel_addr);
Józef Kucia
committed
indexes[index_count++] = vkd3d_dxbc_compiler_get_constant_uint(compiler, register_info->member_idx);
indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, ®->idx[1]);
}
else if (reg->type == VKD3DSPR_IMMCONSTBUFFER)
{
indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, ®->idx[0]);
}
else if (reg->type == VKD3DSPR_IDXTEMP)
{
indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, ®->idx[1]);
}
else if (register_info->is_aggregate)
struct vkd3d_shader_register_index reg_idx = reg->idx[0];
if (reg->idx[1].rel_addr)
FIXME("Relative addressing not implemented.\n");
if (register_info->is_dynamically_indexed)
{
indexes[index_count++] = vkd3d_spirv_build_op_load(builder,
vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_INT, 1),
register_info->member_idx, SpvMemoryAccessMaskNone);
}
else
{
reg_idx.offset = register_info->member_idx;
indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, ®_idx);
}
else
{
if (reg->idx[1].rel_addr || (reg->idx[1].offset == ~0u && reg->idx[0].rel_addr))
FIXME("Relative addressing not implemented.\n");
/* Handle arrayed registers, e.g. v[3][0]. */
if (reg->idx[1].offset != ~0u)
indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, ®->idx[0]);
}
if (index_count)
{
component_count = vkd3d_write_mask_component_count(register_info->write_mask);
type_id = vkd3d_spirv_get_type_id(builder, register_info->component_type, component_count);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, register_info->storage_class, type_id);
register_info->id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
register_info->id, indexes, index_count);
}
static uint32_t vkd3d_dxbc_compiler_get_register_id(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_register_info register_info;
if (vkd3d_dxbc_compiler_get_register_info(compiler, reg, ®ister_info))
vkd3d_dxbc_compiler_emit_dereference_register(compiler, reg, ®ister_info);
return register_info.id;
return vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
SpvStorageClassPrivate, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
static bool vkd3d_swizzle_is_equal(unsigned int dst_write_mask,
unsigned int swizzle, unsigned int write_mask)
{
return vkd3d_compact_swizzle(VKD3D_NO_SWIZZLE, dst_write_mask) == vkd3d_compact_swizzle(swizzle, write_mask);
}
static uint32_t vkd3d_dxbc_compiler_emit_swizzle(struct vkd3d_dxbc_compiler *compiler,
uint32_t val_id, unsigned int val_write_mask, enum vkd3d_component_type component_type,
unsigned int swizzle, unsigned int write_mask)
Józef Kucia
committed
{
unsigned int i, component_idx, component_count, val_component_count;
Józef Kucia
committed
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, components[VKD3D_VEC4_SIZE];
component_count = vkd3d_write_mask_component_count(write_mask);
val_component_count = vkd3d_write_mask_component_count(val_write_mask);
if (component_count == val_component_count
&& (component_count == 1 || vkd3d_swizzle_is_equal(val_write_mask, swizzle, write_mask)))
Józef Kucia
committed
return val_id;
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
Józef Kucia
committed
if (component_count == 1)
{
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
component_idx -= vkd3d_write_mask_get_component_idx(val_write_mask);
return vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx);
Józef Kucia
committed
}
if (val_component_count == 1)
{
for (i = 0, component_idx = 0; i < VKD3D_VEC4_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
{
assert(VKD3DSP_WRITEMASK_0 << vkd3d_swizzle_get_component(swizzle, i) == val_write_mask);
components[component_idx++] = val_id;
}
}
return vkd3d_spirv_build_op_composite_construct(builder, type_id, components, component_count);
}
Józef Kucia
committed
for (i = 0, component_idx = 0; i < VKD3D_VEC4_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
components[component_idx++] = vkd3d_swizzle_get_component(swizzle, i);
}
return vkd3d_spirv_build_op_vector_shuffle(builder,
type_id, val_id, val_id, components, component_count);
}
static uint32_t vkd3d_dxbc_compiler_emit_vector_shuffle(struct vkd3d_dxbc_compiler *compiler,
uint32_t vector1_id, uint32_t vector2_id, unsigned int swizzle, unsigned int write_mask,
enum vkd3d_component_type component_type, unsigned int component_count)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t components[VKD3D_VEC4_SIZE];
uint32_t type_id;
unsigned int i;
assert(component_count <= ARRAY_SIZE(components));
for (i = 0; i < component_count; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
components[i] = vkd3d_swizzle_get_component(swizzle, i);
else
components[i] = VKD3D_VEC4_SIZE + vkd3d_swizzle_get_component(swizzle, i);
}
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
return vkd3d_spirv_build_op_vector_shuffle(builder,
type_id, vector1_id, vector2_id, components, component_count);
}
static uint32_t vkd3d_dxbc_compiler_emit_load_constant(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
{
unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
uint32_t values[VKD3D_VEC4_SIZE] = {0};
unsigned int i, j;
assert(reg->type == VKD3DSPR_IMMCONST);
if (reg->immconst_type == VKD3D_IMMCONST_SCALAR)
for (i = 0; i < component_count; ++i)
values[i] = *reg->u.immconst_uint;
for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
values[j++] = reg->u.immconst_uint[vkd3d_swizzle_get_component(swizzle, i)];
}
return vkd3d_dxbc_compiler_get_constant(compiler,
vkd3d_component_type_from_data_type(reg->data_type), component_count, values);
}
static uint32_t vkd3d_dxbc_compiler_emit_load_scalar(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask,
const struct vkd3d_shader_register_info *reg_info)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id, indexes[1], reg_id, val_id;
unsigned int component_idx, reg_component_count;
enum vkd3d_component_type component_type;
assert(reg->type != VKD3DSPR_IMMCONST);
assert(vkd3d_write_mask_component_count(write_mask) == 1);
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
component_type = vkd3d_component_type_from_data_type(reg->data_type);
reg_component_count = vkd3d_write_mask_component_count(reg_info->write_mask);
if (!(reg_info->write_mask & (VKD3DSP_WRITEMASK_0 << component_idx)))
ERR("Invalid component_idx for register %#x, %u (write_mask %#x).\n",
reg->type, reg->idx[0].offset, reg_info->write_mask);
type_id = vkd3d_spirv_get_type_id(builder, reg_info->component_type, 1);
reg_id = reg_info->id;
if (reg_component_count != 1)
{
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, reg_info->storage_class, type_id);
indexes[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
reg_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder,
ptr_type_id, reg_id, indexes, ARRAY_SIZE(indexes));
}
val_id = vkd3d_spirv_build_op_load(builder, type_id, reg_id, SpvMemoryAccessMaskNone);
if (component_type != reg_info->component_type)
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
}
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_load_reg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_register_info reg_info;
enum vkd3d_component_type component_type;
Józef Kucia
committed
unsigned int component_count;
uint32_t type_id, val_id;
if (reg->type == VKD3DSPR_IMMCONST)
return vkd3d_dxbc_compiler_emit_load_constant(compiler, reg, swizzle, write_mask);
component_count = vkd3d_write_mask_component_count(write_mask);
component_type = vkd3d_component_type_from_data_type(reg->data_type);
if (!vkd3d_dxbc_compiler_get_register_info(compiler, reg, ®_info))
{
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id);
}
vkd3d_dxbc_compiler_emit_dereference_register(compiler, reg, ®_info);
/* Intermediate value (no storage class). */
if (reg_info.storage_class == SpvStorageClassMax)
{
val_id = reg_info.id;
}
else if (component_count == 1)
{
return vkd3d_dxbc_compiler_emit_load_scalar(compiler, reg, swizzle, write_mask, ®_info);
}
else
{
type_id = vkd3d_spirv_get_type_id(builder,
reg_info.component_type, vkd3d_write_mask_component_count(reg_info.write_mask));
val_id = vkd3d_spirv_build_op_load(builder, type_id, reg_info.id, SpvMemoryAccessMaskNone);
}
val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler,
val_id, reg_info.write_mask, reg_info.component_type, swizzle, write_mask);
if (component_type != reg_info.component_type)
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
}
return val_id;
}
static void vkd3d_dxbc_compiler_emit_execution_mode(struct vkd3d_dxbc_compiler *compiler,
SpvExecutionMode mode, const uint32_t *literals, unsigned int literal_count)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
vkd3d_spirv_build_op_execution_mode(&builder->execution_mode_stream,
builder->main_function_id, mode, literals, literal_count);
}
static void vkd3d_dxbc_compiler_emit_execution_mode1(struct vkd3d_dxbc_compiler *compiler,
SpvExecutionMode mode, const uint32_t literal)
{
vkd3d_dxbc_compiler_emit_execution_mode(compiler, mode, &literal, 1);
}
static uint32_t vkd3d_dxbc_compiler_emit_abs(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
if (reg->data_type == VKD3D_DATA_FLOAT)
{
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, component_count);
return vkd3d_spirv_build_op_glsl_std450_fabs(builder, type_id, val_id);
}
FIXME("Unhandled data type %#x.\n", reg->data_type);
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_neg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
type_id = vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, reg, write_mask);
if (reg->data_type == VKD3D_DATA_FLOAT)
return vkd3d_spirv_build_op_fnegate(builder, type_id, val_id);
else if (reg->data_type == VKD3D_DATA_INT)
return vkd3d_spirv_build_op_snegate(builder, type_id, val_id);
FIXME("Unhandled data type %#x.\n", reg->data_type);
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_src_modifier(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask,
enum vkd3d_shader_src_modifier modifier, uint32_t val_id)
{
switch (modifier)
{
case VKD3DSPSM_NONE:
break;
case VKD3DSPSM_NEG:
return vkd3d_dxbc_compiler_emit_neg(compiler, reg, write_mask, val_id);
case VKD3DSPSM_ABS:
return vkd3d_dxbc_compiler_emit_abs(compiler, reg, write_mask, val_id);
case VKD3DSPSM_ABSNEG:
val_id = vkd3d_dxbc_compiler_emit_abs(compiler, reg, write_mask, val_id);
return vkd3d_dxbc_compiler_emit_neg(compiler, reg, write_mask, val_id);
default:
FIXME("Unhandled src modifier %#x.\n", modifier);
break;
}
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_load_src(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_src_param *src, DWORD write_mask)
{
uint32_t val_id;
val_id = vkd3d_dxbc_compiler_emit_load_reg(compiler, &src->reg, src->swizzle, write_mask);
return vkd3d_dxbc_compiler_emit_src_modifier(compiler, &src->reg, write_mask, src->modifiers, val_id);
}
static uint32_t vkd3d_dxbc_compiler_emit_load_src_with_type(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_src_param *src, DWORD write_mask, enum vkd3d_component_type component_type)
{
struct vkd3d_shader_src_param src_param = *src;
src_param.reg.data_type = vkd3d_data_type_from_component_type(component_type);
return vkd3d_dxbc_compiler_emit_load_src(compiler, &src_param, write_mask);
}
static void vkd3d_dxbc_compiler_emit_store_scalar(struct vkd3d_dxbc_compiler *compiler,
uint32_t dst_id, unsigned int dst_write_mask, enum vkd3d_component_type component_type,
SpvStorageClass storage_class, unsigned int write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id, index[1];
unsigned int component_idx;
if (vkd3d_write_mask_component_count(dst_write_mask) > 1)
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
component_idx -= vkd3d_write_mask_get_component_idx(dst_write_mask);
index[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
dst_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder, ptr_type_id, dst_id, index, ARRAY_SIZE(index));
}
vkd3d_spirv_build_op_store(builder, dst_id, val_id, SpvMemoryAccessMaskNone);
}
static void vkd3d_dxbc_compiler_emit_store(struct vkd3d_dxbc_compiler *compiler,
uint32_t dst_id, unsigned int dst_write_mask, enum vkd3d_component_type component_type,
SpvStorageClass storage_class, unsigned int write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
Józef Kucia
committed
unsigned int component_count, dst_component_count;
uint32_t components[VKD3D_VEC4_SIZE];
unsigned int i, component_idx;
uint32_t type_id, dst_val_id;
assert(write_mask);
component_count = vkd3d_write_mask_component_count(write_mask);
if (component_count == 1)
{
return vkd3d_dxbc_compiler_emit_store_scalar(compiler,
dst_id, dst_write_mask, component_type, storage_class, write_mask, val_id);
}
Józef Kucia
committed
dst_component_count = vkd3d_write_mask_component_count(dst_write_mask);
if (dst_component_count != component_count)
Józef Kucia
committed
type_id = vkd3d_spirv_get_type_id(builder, component_type, dst_component_count);
dst_val_id = vkd3d_spirv_build_op_load(builder, type_id, dst_id, SpvMemoryAccessMaskNone);
assert(component_count <= ARRAY_SIZE(components));
for (i = 0, component_idx = 0; i < dst_component_count; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
components[i] = VKD3D_VEC4_SIZE + component_idx++;
else
components[i] = i;
}
val_id = vkd3d_spirv_build_op_vector_shuffle(builder,
type_id, dst_val_id, val_id, components, dst_component_count);
vkd3d_spirv_build_op_store(builder, dst_id, val_id, SpvMemoryAccessMaskNone);
}
static void vkd3d_dxbc_compiler_emit_store_reg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, unsigned int write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_register_info reg_info;
enum vkd3d_component_type component_type;
uint32_t type_id;
assert(reg->type != VKD3DSPR_IMMCONST);
if (!vkd3d_dxbc_compiler_get_register_info(compiler, reg, ®_info))
return;
vkd3d_dxbc_compiler_emit_dereference_register(compiler, reg, ®_info);