Newer
Older
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
{
FIXME("Unhandled component range %u, %u.\n", xfb_element->component_index, xfb_element->component_count);
return;
}
if (xfb_element->output_slot < xfb_info->buffer_stride_count)
{
stride = xfb_info->buffer_strides[xfb_element->output_slot];
}
else
{
stride = 0;
for (i = 0; i < xfb_info->element_count; ++i)
{
const struct vkd3d_shader_transform_feedback_element *e = &xfb_info->elements[i];
if (e->stream_index == xfb_element->stream_index && e->output_slot == xfb_element->output_slot)
stride += 4 * e->component_count;
}
}
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationXfbBuffer, xfb_element->output_slot);
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationXfbStride, stride);
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationOffset, offset);
}
static uint32_t vkd3d_dxbc_compiler_emit_builtin_variable(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_spirv_builtin *builtin, SpvStorageClass storage_class, unsigned int array_size)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t id;
array_size = max(array_size, builtin->spirv_array_size);
id = vkd3d_dxbc_compiler_emit_array_variable(compiler,
&builder->global_stream, storage_class,
builtin->component_type, builtin->component_count, array_size);
vkd3d_spirv_add_iface_variable(builder, id);
vkd3d_dxbc_compiler_decorate_builtin(compiler, id, builtin->spirv_builtin);
if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && storage_class == SpvStorageClassInput
Henri Verbeet
committed
&& builtin->component_type != VKD3D_SHADER_COMPONENT_FLOAT
&& builtin->component_type != VKD3D_SHADER_COMPONENT_BOOL)
vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationFlat, NULL, 0);
return id;
}
static bool needs_private_io_variable(const struct vkd3d_shader_signature *signature,
unsigned int reg_idx, const struct vkd3d_spirv_builtin *builtin,
unsigned int *component_count, unsigned int *out_write_mask)
{
unsigned int write_mask = 0;
bool have_sysval = false;
unsigned int i, count;
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
if (*component_count == VKD3D_VEC4_SIZE)
return false;
for (i = 0, count = 0; i < signature->element_count; ++i)
{
const struct vkd3d_shader_signature_element *current = &signature->elements[i];
if (current->register_index != reg_idx)
continue;
write_mask |= current->mask & 0xff;
++count;
if (current->sysval_semantic)
have_sysval = true;
}
if (count == 1)
return false;
if (builtin || have_sysval)
return true;
if (!vkd3d_bitmask_is_contiguous(write_mask))
{
FIXME("Write mask %#x is non-contiguous.\n", write_mask);
return true;
}
assert(vkd3d_write_mask_component_count(write_mask) >= *component_count);
*component_count = vkd3d_write_mask_component_count(write_mask);
*out_write_mask = write_mask;
return false;
}
static uint32_t vkd3d_dxbc_compiler_emit_input(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval,
enum vkd3d_shader_interpolation_mode interpolation_mode)
unsigned int component_idx, component_count, input_component_count;
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;
Józef Kucia
committed
const struct vkd3d_shader_register *reg = &dst->reg;
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type;
uint32_t type_id, ptr_type_id, float_type_id;
const struct vkd3d_spirv_builtin *builtin;
uint32_t val_id, input_id, var_id;
struct vkd3d_symbol reg_symbol;
struct vkd3d_symbol tmp_symbol;
SpvStorageClass storage_class;
Józef Kucia
committed
struct rb_entry *entry = NULL;
bool use_private_var = false;
unsigned int array_size;
unsigned int reg_idx;
uint32_t i, index;
assert(!reg->idx[0].rel_addr);
assert(!reg->idx[1].rel_addr);
if (reg->idx[1].offset != ~0u)
{
array_size = reg->idx[0].offset;
reg_idx = reg->idx[1].offset;
}
else
{
array_size = 0;
reg_idx = reg->idx[0].offset;
}
shader_signature = reg->type == VKD3DSPR_PATCHCONST
? compiler->patch_constant_signature : compiler->input_signature;
if (!(signature_element = vkd3d_find_signature_element_for_reg(shader_signature,
NULL, reg_idx, dst->write_mask)))
{
FIXME("No signature element for shader input, ignoring shader input.\n");
return 0;
}
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && !sysval && signature_element->sysval_semantic)
sysval = vkd3d_siv_from_sysval(signature_element->sysval_semantic);
builtin = get_spirv_builtin_for_sysval(compiler, sysval);
Józef Kucia
committed
write_mask = signature_element->mask & 0xff;
Józef Kucia
committed
component_count = vkd3d_write_mask_component_count(dst->write_mask);
if (builtin)
{
component_type = builtin->component_type;
input_component_count = builtin->component_count;
Józef Kucia
committed
component_idx = 0;
}
else
{
component_type = signature_element->component_type;
input_component_count = vkd3d_write_mask_component_count(signature_element->mask & 0xff);
component_idx = vkd3d_write_mask_get_component_idx(signature_element->mask & 0xff);
}
if ((use_private_var = builtin && builtin->fixup_pfn))
{
component_count = VKD3D_VEC4_SIZE;
write_mask = VKD3DSP_WRITEMASK_ALL;
}
else if (needs_private_io_variable(shader_signature, reg_idx, builtin, &input_component_count, &write_mask))
{
use_private_var = true;
component_count = VKD3D_VEC4_SIZE;
write_mask = VKD3DSP_WRITEMASK_ALL;
else
{
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
}
Józef Kucia
committed
storage_class = SpvStorageClassInput;
vkd3d_symbol_make_register(®_symbol, reg);
input_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
entry = rb_get(&compiler->symbol_table, ®_symbol);
}
else if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
{
input_id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
input_id = 0;
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && reg->type == VKD3DSPR_INCONTROLPOINT)
{
tmp_symbol = reg_symbol;
tmp_symbol.key.reg.type = VKD3DSPR_INPUT;
if ((entry = rb_get(&compiler->symbol_table, &tmp_symbol)))
{
tmp_symbol = *RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry);
tmp_symbol.key.reg.type = VKD3DSPR_INCONTROLPOINT;
vkd3d_dxbc_compiler_put_symbol(compiler, &tmp_symbol);
input_id = tmp_symbol.id;
}
}
if (!entry)
{
unsigned int location = reg_idx;
if (reg->type == VKD3DSPR_PATCHCONST)
location += compiler->input_signature->element_count;
input_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
storage_class, component_type, input_component_count, array_size);
vkd3d_spirv_add_iface_variable(builder, input_id);
vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, location);
if (component_idx)
vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationComponent, component_idx);
vkd3d_dxbc_compiler_emit_interpolation_decorations(compiler, input_id, interpolation_mode);
}
if (reg->type == VKD3DSPR_PATCHCONST)
vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0);
if (entry || !use_private_var)
{
var_id = input_id;
}
{
storage_class = SpvStorageClassPrivate;
var_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
Henri Verbeet
committed
storage_class, VKD3D_SHADER_COMPONENT_FLOAT, component_count, array_size);
Józef Kucia
committed
if (!entry)
{
vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class,
Henri Verbeet
committed
use_private_var ? VKD3D_SHADER_COMPONENT_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);
Henri Verbeet
committed
if (component_type != VKD3D_SHADER_COMPONENT_FLOAT)
{
Henri Verbeet
committed
float_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_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_SHADER_COMPONENT_FLOAT, VKD3D_SHADER_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:
case VKD3DSPR_INCONTROLPOINT:
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 */,
Henri Verbeet
committed
VKD3D_SHADER_COMPONENT_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_spirv_target_info *info;
if (!(info = compiler->spirv_target_info))
return VKD3D_SHADER_NO_SWIZZLE;
if (register_idx >= info->output_swizzle_count)
return VKD3D_SHADER_NO_SWIZZLE;
return info->output_swizzles[register_idx];
static bool is_dual_source_blending(const struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && info && info->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);
}
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
static uint32_t calculate_sysval_array_mask(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_signature *signature, enum vkd3d_shader_input_sysval_semantic sysval)
{
const struct vkd3d_shader_signature_element *e;
const struct vkd3d_spirv_builtin *sig_builtin;
const struct vkd3d_spirv_builtin *builtin;
uint32_t signature_idx, mask = 0;
if (!(builtin = get_spirv_builtin_for_sysval(compiler, sysval)))
{
FIXME("Unhandled sysval %#x.\n", sysval);
return 0;
}
for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
{
e = &signature->elements[signature_idx];
sig_builtin = get_spirv_builtin_for_sysval(compiler,
vkd3d_siv_from_sysval_indexed(e->sysval_semantic, e->semantic_index));
if (sig_builtin && sig_builtin->spirv_builtin == builtin->spirv_builtin)
mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * sig_builtin->member_idx);
}
return mask;
}
/* 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)
{
Henri Verbeet
committed
case VKD3D_SHADER_SV_CLIP_DISTANCE:
calculate_clip_or_cull_distance_mask(e, &clip_distance_mask);
break;
Henri Verbeet
committed
case VKD3D_SHADER_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)
{
Henri Verbeet
committed
case VKD3D_SHADER_SV_CLIP_DISTANCE:
compiler->output_info[i].id = clip_distance_id;
Henri Verbeet
committed
compiler->output_info[i].component_type = VKD3D_SHADER_COMPONENT_FLOAT;
compiler->output_info[i].array_element_mask = clip_distance_mask;
Henri Verbeet
committed
case VKD3D_SHADER_SV_CULL_DISTANCE:
compiler->output_info[i].id = cull_distance_id;
Henri Verbeet
committed
compiler->output_info[i].component_type = VKD3D_SHADER_COMPONENT_FLOAT;
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);
}
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
static uint32_t vkd3d_dxbc_compiler_emit_shader_phase_builtin_variable(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_phase *phase, const struct vkd3d_spirv_builtin *builtin)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t *variable_id, id;
variable_id = NULL;
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 && *variable_id)
return *variable_id;
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, id, SpvDecorationPatch, NULL, 0);
if (variable_id)
*variable_id = id;
return id;
}
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;
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type;
const struct vkd3d_spirv_builtin *builtin;
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 = VKD3DSP_WRITEMASK_ALL;
else if (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE
|| needs_private_io_variable(shader_signature, signature_element->register_index,
builtin, &output_component_count, &write_mask)
|| is_patch_constant)
{
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;
Henri Verbeet
committed
entry = rb_get(&compiler->symbol_table, ®_symbol);
Henri Verbeet
committed
else if (!use_private_variable && (entry = rb_get(&compiler->symbol_table, ®_symbol)))
{
id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
}
if (builtin)
{
if (phase)
id = vkd3d_dxbc_compiler_emit_shader_phase_builtin_variable(compiler, phase, builtin);
else
id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
if (builtin->spirv_array_size)
compiler->output_info[signature_idx].array_element_mask =
calculate_sysval_array_mask(compiler, shader_signature, sysval);
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);
Henri Verbeet
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;
Henri Verbeet
committed
if (entry)
Józef Kucia
committed
var_id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
else if (!use_private_variable)
var_id = id;
else if (is_patch_constant)
var_id = compiler->hs.patch_constants_id;
Józef Kucia
committed
else
var_id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
Henri Verbeet
committed
storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
Józef Kucia
committed
if (!entry)
{
vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class,
Henri Verbeet
committed
use_private_variable ? VKD3D_SHADER_COMPONENT_FLOAT : component_type, write_mask);
reg_symbol.info.reg.is_aggregate = use_private_variable ? is_patch_constant : 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;
}
else if (is_patch_constant)
{
reg_symbol.info.reg.member_idx = reg->idx[0].offset;
}
Józef Kucia
committed
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
if (!is_patch_constant)
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
Józef Kucia
committed
}
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 (is_patch_constant)
compiler->private_output_variable_array_idx[idx] = vkd3d_dxbc_compiler_get_constant_uint(
compiler, reg->idx[0].offset);
if (!compiler->epilogue_function_id)
compiler->epilogue_function_id = vkd3d_spirv_alloc_id(builder);
Józef Kucia
committed
}
static uint32_t vkd3d_dxbc_compiler_get_output_array_index(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_signature_element *e)
{
enum vkd3d_shader_input_sysval_semantic sysval;
const struct vkd3d_spirv_builtin *builtin;
sysval = vkd3d_siv_from_sysval_indexed(e->sysval_semantic, e->semantic_index);
builtin = get_spirv_builtin_for_sysval(compiler, sysval);
switch (sysval)
{
case VKD3D_SIV_LINE_DETAIL_TESS_FACTOR:
case VKD3D_SIV_LINE_DENSITY_TESS_FACTOR:
return builtin->member_idx;
default:
return e->semantic_index;
}
}
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, array_idx;
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;
Henri Verbeet
committed
if (output_info->component_type != VKD3D_SHADER_COMPONENT_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;
array_idx = vkd3d_dxbc_compiler_get_output_array_index(compiler, output);
mask &= (1u << (array_idx * 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_SHADER_NO_SWIZZLE, VKD3DSP_WRITEMASK_0 << i);
vkd3d_dxbc_compiler_emit_store(compiler, chain_id, VKD3DSP_WRITEMASK_0,
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_array_idx));
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;
function_id = compiler->epilogue_function_id;
void_id = vkd3d_spirv_get_op_type_void(builder);
Henri Verbeet
committed
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 4);
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
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_array_idx, 0, sizeof(compiler->private_output_variable_array_idx));
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_hull_shader_patch_constants(struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_signature *signature = compiler->patch_constant_signature;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t register_count = 0;
unsigned int signature_idx;
for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
register_count = max(register_count, signature->elements[signature_idx].register_index + 1);
if (!register_count)
return;
compiler->hs.patch_constants_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
Henri Verbeet
committed
SpvStorageClassPrivate, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, register_count);
vkd3d_spirv_build_op_name(builder, compiler->hs.patch_constants_id, "opc");
}
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);
vkd3d_dxbc_compiler_emit_hull_shader_patch_constants(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);
builder->invocation_count = 1;
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;
}