Newer
Older
{
storage_class = SpvStorageClassPrivate;
var_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
storage_class, VKD3D_TYPE_FLOAT, component_count, array_size);
Józef Kucia
committed
if (!entry)
{
vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class,
use_private_var ? VKD3D_TYPE_FLOAT : component_type, write_mask);
Józef Kucia
committed
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
Józef Kucia
committed
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
Józef Kucia
committed
}
if (use_private_var)
{
type_id = vkd3d_spirv_get_type_id(builder, component_type, input_component_count);
for (i = 0; i < max(array_size, 1); ++i)
{
struct vkd3d_shader_register dst_reg = *reg;
dst_reg.data_type = VKD3D_DATA_FLOAT;
val_id = input_id;
if (array_size)
{
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, type_id);
index = vkd3d_dxbc_compiler_get_constant_uint(compiler, i);
val_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, input_id, index);
dst_reg.idx[0].offset = i;
}
val_id = vkd3d_spirv_build_op_load(builder, type_id, val_id, SpvMemoryAccessMaskNone);
if (builtin && builtin->fixup_pfn)
val_id = builtin->fixup_pfn(compiler, val_id);
if (component_type != VKD3D_TYPE_FLOAT)
{
float_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, input_component_count);
val_id = vkd3d_spirv_build_op_bitcast(builder, float_type_id, val_id);
}
val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id,
Józef Kucia
committed
vkd3d_write_mask_from_component_count(input_component_count) << component_idx,
VKD3D_TYPE_FLOAT, VKD3D_NO_SWIZZLE, dst->write_mask);
vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst_reg, dst->write_mask, val_id);
}
return input_id;
static void vkd3d_dxbc_compiler_emit_input_register(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_register *reg = &dst->reg;
const struct vkd3d_spirv_builtin *builtin;
struct vkd3d_symbol reg_symbol;
struct rb_entry *entry;
uint32_t input_id;
assert(!reg->idx[0].rel_addr);
assert(!reg->idx[1].rel_addr);
assert(reg->idx[1].offset == ~0u);
if (!(builtin = get_spirv_builtin_for_register(reg->type)))
{
FIXME("Unhandled register %#x.\n", reg->type);
return;
}
/* vPrim may be declared in multiple hull shader phases. */
vkd3d_symbol_make_register(®_symbol, reg);
if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
return;
input_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassInput, 0);
vkd3d_symbol_set_register_info(®_symbol, input_id, SpvStorageClassInput,
builtin->component_type, vkd3d_write_mask_from_component_count(builtin->component_count));
reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size;
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, input_id, reg);
}
static void vkd3d_dxbc_compiler_emit_shader_phase_input(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_register *reg = &dst->reg;
struct vkd3d_symbol reg_symbol;
uint32_t val_id;
switch (reg->type)
{
case VKD3DSPR_INPUT:
vkd3d_dxbc_compiler_emit_input(compiler, dst, VKD3D_SIV_NONE, VKD3DSIM_NONE);
vkd3d_dxbc_compiler_emit_input_register(compiler, dst);
return;
case VKD3DSPR_FORKINSTID:
case VKD3DSPR_JOININSTID:
val_id = phase->instance_id;
break;
case VKD3DSPR_OUTPOINTID: /* Emitted in vkd3d_dxbc_compiler_emit_initial_declarations(). */
case VKD3DSPR_OUTCONTROLPOINT: /* See vkd3d_dxbc_compiler_leave_shader_phase(). */
default:
FIXME("Unhandled shader phase input register %#x.\n", reg->type);
return;
}
vkd3d_symbol_make_register(®_symbol, reg);
vkd3d_symbol_set_register_info(®_symbol, val_id,
SpvStorageClassMax /* Intermediate value */,
VKD3D_TYPE_UINT, VKD3DSP_WRITEMASK_0);
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, val_id, reg);
}
static unsigned int vkd3d_dxbc_compiler_get_output_variable_index(
struct vkd3d_dxbc_compiler *compiler, unsigned int register_idx)
{
if (register_idx == ~0u) /* oDepth */
return ARRAY_SIZE(compiler->private_output_variable) - 1;
assert(register_idx < ARRAY_SIZE(compiler->private_output_variable) - 1);
return register_idx;
}
static unsigned int get_shader_output_swizzle(const struct vkd3d_dxbc_compiler *compiler,
unsigned int register_idx)
{
const struct vkd3d_shader_compile_arguments *compile_args;
if (!(compile_args = compiler->compile_args))
return VKD3D_NO_SWIZZLE;
if (register_idx >= compile_args->output_swizzle_count)
return VKD3D_NO_SWIZZLE;
return compile_args->output_swizzles[register_idx];
}
static bool is_dual_source_blending(const struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_compile_arguments *compile_args = compiler->compile_args;
return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL
&& compile_args && compile_args->dual_source_blending;
}
static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_signature_element *e,
uint32_t *mask)
{
if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE)
{
FIXME("Invalid semantic index %u for clip/cull distance.\n", e->semantic_index);
return;
}
*mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
}
/* Emits arrayed SPIR-V built-in variables. */
static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_signature *output_signature = compiler->output_signature;
uint32_t clip_distance_mask = 0, clip_distance_id = 0;
uint32_t cull_distance_mask = 0, cull_distance_id = 0;
const struct vkd3d_spirv_builtin *builtin;
unsigned int i, count;
for (i = 0; i < output_signature->element_count; ++i)
{
const struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
switch (e->sysval_semantic)
{
case VKD3D_SV_CLIP_DISTANCE:
calculate_clip_or_cull_distance_mask(e, &clip_distance_mask);
break;
case VKD3D_SV_CULL_DISTANCE:
calculate_clip_or_cull_distance_mask(e, &cull_distance_mask);
break;
default:
break;
}
}
if (clip_distance_mask)
{
count = vkd3d_popcount(clip_distance_mask);
builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SIV_CLIP_DISTANCE);
clip_distance_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler,
builtin, SpvStorageClassOutput, count);
if (cull_distance_mask)
{
count = vkd3d_popcount(cull_distance_mask);
builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SIV_CULL_DISTANCE);
cull_distance_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler,
builtin, SpvStorageClassOutput, count);
for (i = 0; i < output_signature->element_count; ++i)
{
const struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
switch (e->sysval_semantic)
{
case VKD3D_SV_CLIP_DISTANCE:
compiler->output_info[i].id = clip_distance_id;
compiler->output_info[i].array_element_mask = clip_distance_mask;
case VKD3D_SV_CULL_DISTANCE:
compiler->output_info[i].id = cull_distance_id;
compiler->output_info[i].array_element_mask = cull_distance_mask;
default:
break;
}
}
}
static void vkd3d_dxbc_compiler_emit_output_register(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_register *reg = &dst->reg;
const struct vkd3d_spirv_builtin *builtin;
struct vkd3d_symbol reg_symbol;
uint32_t output_id;
assert(!reg->idx[0].rel_addr);
assert(!reg->idx[1].rel_addr);
assert(reg->idx[1].offset == ~0u);
if (!(builtin = get_spirv_builtin_for_register(reg->type)))
{
FIXME("Unhandled register %#x.\n", reg->type);
return;
}
output_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0);
vkd3d_symbol_make_register(®_symbol, reg);
vkd3d_symbol_set_register_info(®_symbol, output_id, SpvStorageClassOutput,
builtin->component_type, vkd3d_write_mask_from_component_count(builtin->component_count));
reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size;
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, output_id, reg);
}
static void vkd3d_dxbc_compiler_emit_output(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
Józef Kucia
committed
const struct vkd3d_shader_signature_element *signature_element;
const struct vkd3d_shader_signature *shader_signature;
const struct vkd3d_shader_register *reg = &dst->reg;
unsigned int component_idx, output_component_count;
const struct vkd3d_spirv_builtin *builtin;
Józef Kucia
committed
enum vkd3d_component_type component_type;
const struct vkd3d_shader_phase *phase;
struct vkd3d_symbol reg_symbol;
SpvStorageClass storage_class;
Józef Kucia
committed
struct rb_entry *entry = NULL;
unsigned int signature_idx;
bool use_private_variable;
unsigned int write_mask;
unsigned int array_size;
bool is_patch_constant;
Józef Kucia
committed
uint32_t id, var_id;
phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler);
is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE);
shader_signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
array_size = is_control_point_phase(phase) ? compiler->output_control_point_count : 0;
if (!(signature_element = vkd3d_find_signature_element_for_reg(shader_signature,
&signature_idx, reg->idx[0].offset, dst->write_mask)))
{
FIXME("No signature element for shader output, ignoring shader output.\n");
return;
}
builtin = vkd3d_get_spirv_builtin(compiler, dst->reg.type, sysval);
Józef Kucia
committed
write_mask = signature_element->mask & 0xff;
Józef Kucia
committed
component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
output_component_count = vkd3d_write_mask_component_count(signature_element->mask & 0xff);
Józef Kucia
committed
if (builtin)
{
component_type = builtin->component_type;
if (!builtin->spirv_array_size)
output_component_count = builtin->component_count;
Józef Kucia
committed
}
else
{
component_type = signature_element->component_type;
Józef Kucia
committed
}
Józef Kucia
committed
storage_class = SpvStorageClassOutput;
if ((use_private_variable = builtin && builtin->spirv_array_size))
write_mask = dst->write_mask;
else if (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_NO_SWIZZLE
|| needs_private_io_variable(shader_signature, signature_element->register_index,
builtin, &output_component_count, &write_mask))
{
use_private_variable = true;
write_mask = VKD3DSP_WRITEMASK_ALL;
}
else
{
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
}
vkd3d_symbol_make_register(®_symbol, reg);
if (compiler->output_info[signature_idx].id)
{
id = compiler->output_info[signature_idx].id;
if (compiler->output_info[signature_idx].array_element_mask)
{
use_private_variable = true;
write_mask = VKD3DSP_WRITEMASK_ALL;
entry = rb_get(&compiler->symbol_table, ®_symbol);
}
}
else if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
{
id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
if (builtin)
{
id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
vkd3d_dxbc_compiler_emit_register_execution_mode(compiler, &dst->reg);
if (component_idx)
FIXME("Unhandled component index %u.\n", component_idx);
}
else
{
unsigned int location = reg->idx[0].offset;
if (is_patch_constant)
location += compiler->output_signature->element_count;
id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
storage_class, component_type, output_component_count, array_size);
vkd3d_spirv_add_iface_variable(builder, id);
if (is_dual_source_blending(compiler) && reg->idx[0].offset < 2)
{
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, 0);
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationIndex, reg->idx[0].offset);
}
else
{
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, location);
if (component_idx)
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationComponent, component_idx);
}
if (is_patch_constant)
vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0);
vkd3d_dxbc_compiler_decorate_xfb_output(compiler, id, output_component_count, signature_element);
Józef Kucia
committed
}
compiler->output_info[signature_idx].id = id;
compiler->output_info[signature_idx].component_type = component_type;
if (use_private_variable)
Józef Kucia
committed
storage_class = SpvStorageClassPrivate;
Józef Kucia
committed
var_id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
else if (!use_private_variable)
var_id = id;
Józef Kucia
committed
else
var_id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
storage_class, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
if (!entry)
{
vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class,
use_private_variable ? VKD3D_TYPE_FLOAT : component_type, write_mask);
reg_symbol.info.reg.is_aggregate = use_private_variable ? false : array_size;
if (!use_private_variable && is_control_point_phase(phase))
reg_symbol.info.reg.member_idx = vkd3d_dxbc_compiler_get_invocation_id(compiler);
reg_symbol.info.reg.is_dynamically_indexed = true;
}
Józef Kucia
committed
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
}
if (use_private_variable)
Józef Kucia
committed
{
unsigned int idx = vkd3d_dxbc_compiler_get_output_variable_index(compiler, reg->idx[0].offset);
compiler->private_output_variable[idx] = var_id;
compiler->private_output_variable_write_mask[idx] |= dst->write_mask;
if (!compiler->epilogue_function_id)
compiler->epilogue_function_id = vkd3d_spirv_alloc_id(builder);
Józef Kucia
committed
}
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
static void vkd3d_dxbc_compiler_emit_shader_phase_output(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst,
enum vkd3d_shader_input_sysval_semantic sysval)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_register *reg = &dst->reg;
const struct vkd3d_spirv_builtin *builtin;
struct vkd3d_symbol reg_symbol;
uint32_t *variable_id;
variable_id = NULL;
if ((builtin = get_spirv_builtin_for_sysval(compiler, sysval)))
{
if (builtin->spirv_builtin == SpvBuiltInTessLevelOuter)
variable_id = &compiler->hs.tess_level_outer_id;
else if (builtin->spirv_builtin == SpvBuiltInTessLevelInner)
variable_id = &compiler->hs.tess_level_inner_id;
}
if (!variable_id)
{
FIXME("Unhandled shader phase output register %#x, sysval %#x.\n", reg->type, sysval);
return;
}
if (!*variable_id)
{
*variable_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, SpvStorageClassOutput, 0);
if (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE)
vkd3d_spirv_build_op_decorate(builder, *variable_id, SpvDecorationPatch, NULL, 0);
}
vkd3d_symbol_make_register(®_symbol, reg);
vkd3d_symbol_set_register_info(®_symbol, *variable_id, SpvStorageClassOutput,
builtin->component_type, vkd3d_write_mask_from_component_count(builtin->component_count));
reg_symbol.info.reg.member_idx = builtin->member_idx;
reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size;
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
}
static void vkd3d_dxbc_compiler_emit_store_shader_output(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_signature_element *output,
const struct vkd3d_shader_output_info *output_info,
uint32_t output_index_id, uint32_t val_id, unsigned int write_mask)
unsigned int dst_write_mask, use_mask, uninit_mask, swizzle, mask;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id;
unsigned int i, index;
uint32_t output_id;
dst_write_mask = output->mask & 0xff;
write_mask &= dst_write_mask;
use_mask = (output->mask >> 8) & 0xff;
if (!write_mask)
return;
if (output_info->component_type != VKD3D_TYPE_FLOAT)
{
type_id = vkd3d_spirv_get_type_id(builder, output_info->component_type, VKD3D_VEC4_SIZE);
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
}
swizzle = get_shader_output_swizzle(compiler, output->register_index);
uninit_mask = dst_write_mask & use_mask;
if (uninit_mask)
{
/* Set values to 0 for not initialized shader output components. */
write_mask |= uninit_mask;
zero_id = vkd3d_dxbc_compiler_get_constant_vector(compiler,
output_info->component_type, VKD3D_VEC4_SIZE, 0);
val_id = vkd3d_dxbc_compiler_emit_vector_shuffle(compiler,
zero_id, val_id, swizzle, uninit_mask, output_info->component_type,
vkd3d_write_mask_component_count(write_mask));
}
else
{
val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler,
val_id, VKD3DSP_WRITEMASK_ALL, output_info->component_type, swizzle, write_mask);
}
output_id = output_info->id;
if (output_index_id)
{
type_id = vkd3d_spirv_get_type_id(builder,
output_info->component_type, vkd3d_write_mask_component_count(dst_write_mask));
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
output_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, output_id, output_index_id);
}
if (!output_info->array_element_mask)
{
vkd3d_dxbc_compiler_emit_store(compiler,
output_id, dst_write_mask, output_info->component_type, SpvStorageClassOutput, write_mask, val_id);
return;
}
type_id = vkd3d_spirv_get_type_id(builder, output_info->component_type, 1);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
mask = output_info->array_element_mask;
mask &= (1u << (output->semantic_index * VKD3D_VEC4_SIZE)) - 1;
for (i = 0, index = vkd3d_popcount(mask); i < VKD3D_VEC4_SIZE; ++i)
{
if (!(write_mask & (VKD3DSP_WRITEMASK_0 << i)))
continue;
chain_id = vkd3d_spirv_build_op_access_chain1(builder,
ptr_type_id, output_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, index));
object_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id,
write_mask, output_info->component_type, VKD3D_NO_SWIZZLE, VKD3DSP_WRITEMASK_0 << i);
vkd3d_dxbc_compiler_emit_store(compiler, chain_id, VKD3DSP_WRITEMASK_0 << index,
output_info->component_type, SpvStorageClassOutput, VKD3DSP_WRITEMASK_0 << i, object_id);
++index;
}
}
static void vkd3d_dxbc_compiler_emit_shader_epilogue_function(struct vkd3d_dxbc_compiler *compiler)
{
uint32_t param_type_id[MAX_REG_OUTPUT + 1], param_id[MAX_REG_OUTPUT + 1] = {0};
uint32_t void_id, type_id, ptr_type_id, function_type_id, function_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_signature *signature;
const struct vkd3d_shader_phase *phase;
uint32_t output_index_id = 0;
bool is_patch_constant;
unsigned int i, count;
DWORD variable_idx;
STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_id));
STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_type_id));
STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_write_mask));
phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler);
is_patch_constant = phase && (phase->type == VKD3DSIH_HS_FORK_PHASE || phase->type == VKD3DSIH_HS_JOIN_PHASE);
signature = is_patch_constant ? compiler->patch_constant_signature : compiler->output_signature;
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
function_id = compiler->epilogue_function_id;
void_id = vkd3d_spirv_get_op_type_void(builder);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 4);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
for (i = 0, count = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
{
if (compiler->private_output_variable[i])
param_type_id[count++] = ptr_type_id;
}
function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, param_type_id, count);
vkd3d_spirv_build_op_function(builder, void_id, function_id,
SpvFunctionControlMaskNone, function_type_id);
for (i = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
{
if (compiler->private_output_variable[i])
param_id[i] = vkd3d_spirv_build_op_function_parameter(builder, ptr_type_id);
}
vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
for (i = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
{
if (compiler->private_output_variable[i])
param_id[i] = vkd3d_spirv_build_op_load(builder, type_id, param_id[i], SpvMemoryAccessMaskNone);
}
if (is_control_point_phase(phase))
output_index_id = vkd3d_dxbc_compiler_emit_load_invocation_id(compiler);
for (i = 0; i < signature->element_count; ++i)
{
variable_idx = vkd3d_dxbc_compiler_get_output_variable_index(compiler,
signature->elements[i].register_index);
if (!param_id[variable_idx])
continue;
vkd3d_dxbc_compiler_emit_store_shader_output(compiler,
&signature->elements[i], &compiler->output_info[i], output_index_id,
param_id[variable_idx], compiler->private_output_variable_write_mask[variable_idx]);
}
vkd3d_spirv_build_op_return(&compiler->spirv_builder);
vkd3d_spirv_build_op_function_end(builder);
memset(compiler->private_output_variable, 0, sizeof(compiler->private_output_variable));
memset(compiler->private_output_variable_write_mask, 0, sizeof(compiler->private_output_variable_write_mask));
compiler->epilogue_function_id = 0;
}
static void vkd3d_dxbc_compiler_emit_hull_shader_builtins(struct vkd3d_dxbc_compiler *compiler)
{
struct vkd3d_shader_dst_param dst;
memset(&dst, 0, sizeof(dst));
dst.reg.type = VKD3DSPR_OUTPOINTID;
dst.reg.idx[0].offset = ~0u;
dst.reg.idx[1].offset = ~0u;
dst.write_mask = VKD3DSP_WRITEMASK_0;
vkd3d_dxbc_compiler_emit_input_register(compiler, &dst);
}
static void vkd3d_dxbc_compiler_emit_initial_declarations(struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_transform_feedback_info *xfb_info = compiler->xfb_info;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
switch (compiler->shader_type)
{
case VKD3D_SHADER_TYPE_VERTEX:
vkd3d_spirv_set_execution_model(builder, SpvExecutionModelVertex);
break;
case VKD3D_SHADER_TYPE_HULL:
vkd3d_spirv_set_execution_model(builder, SpvExecutionModelTessellationControl);
vkd3d_dxbc_compiler_emit_hull_shader_builtins(compiler);
break;
case VKD3D_SHADER_TYPE_DOMAIN:
vkd3d_spirv_set_execution_model(builder, SpvExecutionModelTessellationEvaluation);
break;
case VKD3D_SHADER_TYPE_GEOMETRY:
vkd3d_spirv_set_execution_model(builder, SpvExecutionModelGeometry);
break;
case VKD3D_SHADER_TYPE_PIXEL:
vkd3d_spirv_set_execution_model(builder, SpvExecutionModelFragment);
vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeOriginUpperLeft, NULL, 0);
break;
case VKD3D_SHADER_TYPE_COMPUTE:
vkd3d_spirv_set_execution_model(builder, SpvExecutionModelGLCompute);
break;
default:
ERR("Invalid shader type %#x.\n", compiler->shader_type);
}
if (xfb_info && xfb_info->element_count)
{
vkd3d_spirv_enable_capability(builder, SpvCapabilityTransformFeedback);
vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeXfb, NULL, 0);
}
if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL)
vkd3d_spirv_builder_begin_main_function(builder);
vkd3d_dxbc_compiler_emit_shader_signature_outputs(compiler);
}
static size_t vkd3d_dxbc_compiler_get_current_function_location(struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_phase *phase;
if ((phase = vkd3d_dxbc_compiler_get_current_shader_phase(compiler)))
return phase->function_location;
return builder->main_function_location;
}
static void vkd3d_dxbc_compiler_emit_dcl_global_flags(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
unsigned int flags = instruction->flags;
if (flags & VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL)
{
vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeEarlyFragmentTests, NULL, 0);
flags &= ~VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL;
}
if (flags & ~(VKD3DSGF_REFACTORING_ALLOWED | VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS))
FIXME("Unhandled global flags %#x.\n", flags);
WARN("Unhandled global flags %#x.\n", flags);
static void vkd3d_dxbc_compiler_emit_dcl_temps(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
size_t function_location;
Józef Kucia
committed
uint32_t id;
function_location = vkd3d_dxbc_compiler_get_current_function_location(compiler);
vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
Józef Kucia
committed
assert(!compiler->temp_count);
compiler->temp_count = instruction->declaration.count;
for (i = 0; i < compiler->temp_count; ++i)
{
Józef Kucia
committed
id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->function_stream,
SpvStorageClassFunction, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
if (!i)
compiler->temp_id = id;
assert(id == compiler->temp_id + i);
vkd3d_spirv_build_op_name(builder, id, "r%u", i);
Józef Kucia
committed
vkd3d_spirv_end_function_stream_insertion(builder);
static void vkd3d_dxbc_compiler_emit_dcl_indexable_temp(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
const struct vkd3d_shader_indexable_temp *temp = &instruction->declaration.indexable_temp;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_register reg;
struct vkd3d_symbol reg_symbol;
size_t function_location;
uint32_t id;
if (temp->component_count != 4)
FIXME("Unhandled component count %u.\n", temp->component_count);
memset(®, 0, sizeof(reg));
reg.type = VKD3DSPR_IDXTEMP;
reg.idx[0].offset = temp->register_idx;
reg.idx[1].offset = ~0u;
function_location = vkd3d_dxbc_compiler_get_current_function_location(compiler);
vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->function_stream,
SpvStorageClassFunction, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE, temp->register_size);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, id, ®);
vkd3d_spirv_end_function_stream_insertion(builder);
vkd3d_symbol_make_register(®_symbol, ®);
vkd3d_symbol_set_register_info(®_symbol, id,
SpvStorageClassFunction, VKD3D_TYPE_FLOAT, VKD3DSP_WRITEMASK_ALL);
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
}
Józef Kucia
committed
static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_compiler *compiler)
{
const SpvStorageClass storage_class = SpvStorageClassPushConstant;
uint32_t vec4_id, length_id, struct_id, pointer_type_id, var_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int i, j, count, reg_idx, cb_size;
struct vkd3d_symbol reg_symbol;
uint32_t *member_ids;
count = 0;
Józef Kucia
committed
for (i = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
Józef Kucia
committed
const struct vkd3d_push_constant_buffer_binding *cb = &compiler->push_constants[i];
if (cb->reg.type)
++count;
}
if (!count)
return;
if (!(member_ids = vkd3d_calloc(count, sizeof(*member_ids))))
return;
vec4_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
Józef Kucia
committed
for (i = 0, j = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
Józef Kucia
committed
const struct vkd3d_push_constant_buffer_binding *cb = &compiler->push_constants[i];
if (!cb->reg.type)
continue;
cb_size = cb->reg.idx[1].offset;
length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, cb_size);
member_ids[j] = vkd3d_spirv_build_op_type_array(builder, vec4_id, length_id);
vkd3d_spirv_build_op_decorate1(builder, member_ids[j], SpvDecorationArrayStride, 16);
++j;
}
struct_id = vkd3d_spirv_build_op_type_struct(builder, member_ids, count);
vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0);
vkd3d_spirv_build_op_name(builder, struct_id, "push_cb");
vkd3d_free(member_ids);
pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
pointer_type_id, storage_class, 0);
Józef Kucia
committed
for (i = 0, j = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
Józef Kucia
committed
const struct vkd3d_push_constant_buffer_binding *cb = &compiler->push_constants[i];
if (!cb->reg.type)
continue;
reg_idx = cb->reg.idx[0].offset;
vkd3d_spirv_build_op_member_decorate1(builder, struct_id, j,
SpvDecorationOffset, cb->pc.offset);
vkd3d_spirv_build_op_member_name(builder, struct_id, j, "cb%u", reg_idx);
vkd3d_symbol_make_register(®_symbol, &cb->reg);
vkd3d_symbol_set_register_info(®_symbol, var_id,
storage_class, VKD3D_TYPE_FLOAT, VKD3DSP_WRITEMASK_ALL);
reg_symbol.info.reg.member_idx = j;
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
++j;
}
}
static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
uint32_t vec4_id, array_type_id, length_id, struct_id, pointer_type_id, var_id;
const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const SpvStorageClass storage_class = SpvStorageClassUniform;
const struct vkd3d_shader_register *reg = &cb->src.reg;
Józef Kucia
committed
struct vkd3d_push_constant_buffer_binding *push_cb;
struct vkd3d_symbol reg_symbol;
assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC));
if (cb->register_space)
FIXME("Unhandled register space %u.\n", cb->register_space);
Józef Kucia
committed
if ((push_cb = vkd3d_dxbc_compiler_find_push_constant_buffer(compiler, reg)))
Józef Kucia
committed
/* Push constant buffers are handled in
* vkd3d_dxbc_compiler_emit_push_constant_buffers().
*/
unsigned int cb_size_in_bytes = cb->size * VKD3D_VEC4_SIZE * sizeof(uint32_t);
if (cb_size_in_bytes > push_cb->pc.size)
WARN("Constant buffer size %u exceeds push constant size %u.\n",
cb_size_in_bytes, push_cb->pc.size);
vec4_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, cb->size);
array_type_id = vkd3d_spirv_build_op_type_array(builder, vec4_id, length_id);
vkd3d_spirv_build_op_decorate1(builder, array_type_id, SpvDecorationArrayStride, 16);
struct_id = vkd3d_spirv_build_op_type_struct(builder, &array_type_id, 1);
vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0);
vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0);
vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", cb->size);
pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
pointer_type_id, storage_class, 0);
vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler,
var_id, reg, VKD3D_SHADER_RESOURCE_BUFFER, false);
Józef Kucia
committed
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
Józef Kucia
committed
vkd3d_symbol_make_register(®_symbol, reg);
vkd3d_symbol_set_register_info(®_symbol, var_id,
storage_class, VKD3D_TYPE_FLOAT, VKD3DSP_WRITEMASK_ALL);
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
}
static void vkd3d_dxbc_compiler_emit_dcl_immediate_constant_buffer(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
const struct vkd3d_shader_immediate_constant_buffer *icb = instruction->declaration.icb;
uint32_t *elements, length_id, type_id, const_id, ptr_type_id, icb_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_register reg;
struct vkd3d_symbol reg_symbol;
unsigned int i;
if (!(elements = vkd3d_calloc(icb->vec4_count, sizeof(*elements))))
return;
for (i = 0; i < icb->vec4_count; ++i)
elements[i] = vkd3d_dxbc_compiler_get_constant(compiler,
VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE, &icb->data[4 * i]);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, icb->vec4_count);
Józef Kucia
committed
type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, icb->vec4_count);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
icb_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
ptr_type_id, SpvStorageClassPrivate, const_id);
vkd3d_spirv_build_op_name(builder, icb_id, "icb");
vkd3d_free(elements);
memset(®, 0, sizeof(reg));
reg.type = VKD3DSPR_IMMCONSTBUFFER;
vkd3d_symbol_make_register(®_symbol, ®);
vkd3d_symbol_set_register_info(®_symbol, icb_id,
SpvStorageClassPrivate, VKD3D_TYPE_FLOAT, VKD3DSP_WRITEMASK_ALL);
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
}
static void vkd3d_dxbc_compiler_emit_dcl_sampler(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
const struct vkd3d_shader_register *reg = &instruction->declaration.sampler.src.reg;
const SpvStorageClass storage_class = SpvStorageClassUniformConstant;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id, var_id;
struct vkd3d_symbol reg_symbol;
if (instruction->declaration.sampler.register_space)
FIXME("Unhandled register space %u.\n", instruction->declaration.sampler.register_space);
if (vkd3d_dxbc_compiler_has_combined_sampler(compiler, NULL, reg))
Józef Kucia
committed
type_id = vkd3d_spirv_get_op_type_sampler(builder);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
ptr_type_id, storage_class, 0);
vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler,
var_id, reg, VKD3D_SHADER_RESOURCE_NONE, false);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
vkd3d_symbol_make_register(®_symbol, reg);
vkd3d_symbol_set_register_info(®_symbol, var_id,
storage_class, VKD3D_TYPE_FLOAT, VKD3DSP_WRITEMASK_ALL);
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
}
static const struct vkd3d_spirv_resource_type *vkd3d_dxbc_compiler_enable_resource_type(
struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_resource_type resource_type, bool is_uav)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_spirv_resource_type *resource_type_info;
if (!(resource_type_info = vkd3d_get_spirv_resource_type(resource_type)))
return NULL;
if (resource_type_info->capability)
vkd3d_spirv_enable_capability(builder, resource_type_info->capability);
if (is_uav && resource_type_info->uav_capability)
vkd3d_spirv_enable_capability(builder, resource_type_info->uav_capability);
return resource_type_info;
Józef Kucia
committed
static SpvImageFormat image_format_for_image_read(enum vkd3d_component_type data_type)
{
/* The following formats are supported by Direct3D 11 hardware for UAV
* typed loads. A newer hardware may support more formats for UAV typed
* loads (see StorageImageReadWithoutFormat SPIR-V capability).
*/
switch (data_type)
{
case VKD3D_TYPE_FLOAT:
return SpvImageFormatR32f;
case VKD3D_TYPE_INT:
return SpvImageFormatR32i;
case VKD3D_TYPE_UINT:
return SpvImageFormatR32ui;
default:
FIXME("Unhandled type %#x.\n", data_type);
return SpvImageFormatUnknown;
}
}
Józef Kucia
committed
static uint32_t vkd3d_dxbc_compiler_get_image_type_id(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, const struct vkd3d_spirv_resource_type *resource_type_info,
enum vkd3d_component_type data_type, bool raw_structured, uint32_t depth)
Józef Kucia
committed
{
Józef Kucia
committed
const struct vkd3d_shader_scan_info *scan_info = compiler->scan_info;
Józef Kucia
committed
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t sampled_type_id;
Józef Kucia
committed
SpvImageFormat format;
format = SpvImageFormatUnknown;
if (reg->type == VKD3DSPR_UAV
&& (raw_structured || (scan_info->uav_read_mask & (1u << reg->idx[0].offset))))
Józef Kucia
committed
format = image_format_for_image_read(data_type);
Józef Kucia
committed
sampled_type_id = vkd3d_spirv_get_type_id(builder, data_type, 1);
return vkd3d_spirv_get_op_type_image(builder, sampled_type_id, resource_type_info->dim,