Newer
Older
Henri Verbeet
committed
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 1);
w_id = vkd3d_spirv_build_op_composite_extract1(builder, type_id, frag_coord_id, 3);
w_id = vkd3d_spirv_build_op_fdiv(builder, type_id,
vkd3d_dxbc_compiler_get_constant_float(compiler, 1.0f), w_id);
Henri Verbeet
committed
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
return vkd3d_spirv_build_op_composite_insert1(builder, type_id, w_id, frag_coord_id, 3);
}
struct vkd3d_spirv_builtin
Henri Verbeet
committed
enum vkd3d_shader_component_type component_type;
unsigned int component_count;
SpvBuiltIn spirv_builtin;
vkd3d_spirv_builtin_fixup_pfn fixup_pfn;
unsigned int spirv_array_size;
unsigned int member_idx;
};
/*
* The following tables are based on the "14.6. Built-In Variables" section
* from the Vulkan spec.
*/
static const struct
{
enum vkd3d_shader_input_sysval_semantic sysval;
struct vkd3d_spirv_builtin builtin;
Henri Verbeet
committed
enum vkd3d_shader_spirv_environment environment;
vkd3d_system_value_builtins[] =
Henri Verbeet
committed
{VKD3D_SIV_VERTEX_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInVertexId},
VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5},
{VKD3D_SIV_INSTANCE_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInstanceId},
VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5},
Henri Verbeet
committed
{VKD3D_SIV_POSITION, {VKD3D_SHADER_COMPONENT_FLOAT, 4, SpvBuiltInPosition}},
{VKD3D_SIV_VERTEX_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInVertexIndex, sv_vertex_id_fixup}},
{VKD3D_SIV_INSTANCE_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInstanceIndex, sv_instance_id_fixup}},
Henri Verbeet
committed
{VKD3D_SIV_PRIMITIVE_ID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInPrimitiveId}},
Henri Verbeet
committed
{VKD3D_SIV_RENDER_TARGET_ARRAY_INDEX, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInLayer}},
{VKD3D_SIV_VIEWPORT_ARRAY_INDEX, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInViewportIndex}},
Henri Verbeet
committed
{VKD3D_SIV_IS_FRONT_FACE, {VKD3D_SHADER_COMPONENT_BOOL, 1, SpvBuiltInFrontFacing, sv_front_face_fixup}},
Henri Verbeet
committed
{VKD3D_SIV_SAMPLE_INDEX, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleId}},
Henri Verbeet
committed
{VKD3D_SIV_CLIP_DISTANCE, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInClipDistance, NULL, 1}},
{VKD3D_SIV_CULL_DISTANCE, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInCullDistance, NULL, 1}},
Henri Verbeet
committed
{VKD3D_SIV_QUAD_U0_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 0}},
{VKD3D_SIV_QUAD_V0_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 1}},
{VKD3D_SIV_QUAD_U1_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 2}},
{VKD3D_SIV_QUAD_V1_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 3}},
{VKD3D_SIV_QUAD_U_INNER_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelInner, NULL, 2, 0}},
{VKD3D_SIV_QUAD_V_INNER_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelInner, NULL, 2, 1}},
Henri Verbeet
committed
{VKD3D_SIV_TRIANGLE_U_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 0}},
{VKD3D_SIV_TRIANGLE_V_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 1}},
{VKD3D_SIV_TRIANGLE_W_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 2}},
{VKD3D_SIV_TRIANGLE_INNER_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelInner, NULL, 2, 0}},
Henri Verbeet
committed
{VKD3D_SIV_LINE_DETAIL_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 0}},
{VKD3D_SIV_LINE_DENSITY_TESS_FACTOR, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInTessLevelOuter, NULL, 4, 1}},
static const struct vkd3d_spirv_builtin vkd3d_pixel_shader_position_builtin =
{
Henri Verbeet
committed
VKD3D_SHADER_COMPONENT_FLOAT, 4, SpvBuiltInFragCoord, frag_coord_fixup,
};
static const struct
{
enum vkd3d_shader_register_type reg_type;
struct vkd3d_spirv_builtin builtin;
}
vkd3d_register_builtins[] =
{
Henri Verbeet
committed
{VKD3DSPR_THREADID, {VKD3D_SHADER_COMPONENT_INT, 3, SpvBuiltInGlobalInvocationId}},
{VKD3DSPR_LOCALTHREADID, {VKD3D_SHADER_COMPONENT_INT, 3, SpvBuiltInLocalInvocationId}},
{VKD3DSPR_LOCALTHREADINDEX, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInLocalInvocationIndex}},
{VKD3DSPR_THREADGROUPID, {VKD3D_SHADER_COMPONENT_INT, 3, SpvBuiltInWorkgroupId}},
Henri Verbeet
committed
{VKD3DSPR_GSINSTID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInvocationId}},
{VKD3DSPR_OUTPOINTID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInInvocationId}},
Henri Verbeet
committed
{VKD3DSPR_PRIMID, {VKD3D_SHADER_COMPONENT_INT, 1, SpvBuiltInPrimitiveId}},
Henri Verbeet
committed
{VKD3DSPR_TESSCOORD, {VKD3D_SHADER_COMPONENT_FLOAT, 3, SpvBuiltInTessCoord}},
Henri Verbeet
committed
{VKD3DSPR_COVERAGE, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleMask, NULL, 1}},
{VKD3DSPR_SAMPLEMASK, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleMask, NULL, 1}},
Henri Verbeet
committed
{VKD3DSPR_DEPTHOUT, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInFragDepth}},
{VKD3DSPR_DEPTHOUTGE, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInFragDepth}},
{VKD3DSPR_DEPTHOUTLE, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInFragDepth}},
static void vkd3d_dxbc_compiler_emit_register_execution_mode(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg)
{
switch (reg->type)
{
case VKD3DSPR_DEPTHOUTGE:
vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthGreater, NULL, 0);
break;
case VKD3DSPR_DEPTHOUTLE:
vkd3d_dxbc_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthLess, NULL, 0);
break;
default:
return;
}
}
static const struct vkd3d_spirv_builtin *get_spirv_builtin_for_sysval(
const struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_input_sysval_semantic sysval)
Henri Verbeet
committed
enum vkd3d_shader_spirv_environment environment;
unsigned int i;
if (!sysval)
return NULL;
/* In pixel shaders, SV_Position is mapped to SpvBuiltInFragCoord. */
if (sysval == VKD3D_SIV_POSITION && compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL)
return &vkd3d_pixel_shader_position_builtin;
Henri Verbeet
committed
environment = vkd3d_dxbc_compiler_get_target_environment(compiler);
for (i = 0; i < ARRAY_SIZE(vkd3d_system_value_builtins); ++i)
if (vkd3d_system_value_builtins[i].sysval == sysval
Henri Verbeet
committed
&& (!vkd3d_system_value_builtins[i].environment
|| vkd3d_system_value_builtins[i].environment == environment))
return &vkd3d_system_value_builtins[i].builtin;
}
FIXME("Unhandled builtin (sysval %#x).\n", sysval);
return NULL;
}
static const struct vkd3d_spirv_builtin *get_spirv_builtin_for_register(
enum vkd3d_shader_register_type reg_type)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(vkd3d_register_builtins); ++i)
{
if (vkd3d_register_builtins[i].reg_type == reg_type)
return &vkd3d_register_builtins[i].builtin;
return NULL;
}
static const struct vkd3d_spirv_builtin *vkd3d_get_spirv_builtin(const struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_shader_register_type reg_type, enum vkd3d_shader_input_sysval_semantic sysval)
{
const struct vkd3d_spirv_builtin *builtin;
if ((builtin = get_spirv_builtin_for_sysval(compiler, sysval)))
return builtin;
if ((builtin = get_spirv_builtin_for_register(reg_type)))
return builtin;
if (sysval != VKD3D_SIV_NONE || (reg_type != VKD3DSPR_OUTPUT && reg_type != VKD3DSPR_COLOROUT))
FIXME("Unhandled builtin (register type %#x, sysval %#x).\n", reg_type, sysval);
return NULL;
}
Józef Kucia
committed
static const struct vkd3d_shader_signature_element *vkd3d_find_signature_element_for_reg(
const struct vkd3d_shader_signature *signature, unsigned int *signature_element_index,
Józef Kucia
committed
unsigned int reg_idx, DWORD write_mask)
Józef Kucia
committed
{
unsigned int signature_idx;
for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
{
Józef Kucia
committed
if (signature->elements[signature_idx].register_index == reg_idx
&& (signature->elements[signature_idx].mask & write_mask) == write_mask)
Józef Kucia
committed
{
if (signature_element_index)
*signature_element_index = signature_idx;
return &signature->elements[signature_idx];
}
}
FIXME("Could not find shader signature element (register %u, write mask %#x).\n",
Józef Kucia
committed
reg_idx, write_mask);
Józef Kucia
committed
if (signature_element_index)
*signature_element_index = ~0u;
return NULL;
}
static uint32_t vkd3d_dxbc_compiler_get_invocation_id(struct vkd3d_dxbc_compiler *compiler)
{
struct vkd3d_shader_register r;
assert(compiler->shader_type == VKD3D_SHADER_TYPE_HULL);
memset(&r, 0, sizeof(r));
r.type = VKD3DSPR_OUTPOINTID;
r.idx[0].offset = ~0u;
r.idx[1].offset = ~0u;
return vkd3d_dxbc_compiler_get_register_id(compiler, &r);
}
static uint32_t vkd3d_dxbc_compiler_emit_load_invocation_id(struct vkd3d_dxbc_compiler *compiler)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, id;
id = vkd3d_dxbc_compiler_get_invocation_id(compiler);
Henri Verbeet
committed
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, 1);
return vkd3d_spirv_build_op_load(builder, type_id, id, SpvMemoryAccessMaskNone);
}
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
static void vkd3d_dxbc_compiler_emit_shader_phase_name(struct vkd3d_dxbc_compiler *compiler,
uint32_t id, const struct vkd3d_shader_phase *phase, const char *suffix)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const char *name;
if (!suffix)
suffix = "";
switch (phase->type)
{
case VKD3DSIH_HS_CONTROL_POINT_PHASE:
name = "control";
break;
case VKD3DSIH_HS_FORK_PHASE:
name = "fork";
break;
case VKD3DSIH_HS_JOIN_PHASE:
name = "join";
break;
default:
ERR("Invalid phase type %#x.\n", phase->type);
return;
}
vkd3d_spirv_build_op_name(builder, id, "%s%u%s", name, phase->idx, suffix);
}
static void vkd3d_dxbc_compiler_begin_shader_phase(struct vkd3d_dxbc_compiler *compiler,
struct vkd3d_shader_phase *phase)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t void_id, function_type_id;
unsigned int param_count;
uint32_t param_type_id;
if (phase->instance_count)
{
Henri Verbeet
committed
param_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
param_count = 1;
}
else
{
param_count = 0;
}
phase->function_id = vkd3d_spirv_alloc_id(builder);
void_id = vkd3d_spirv_get_op_type_void(builder);
function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, param_count);
vkd3d_spirv_build_op_function(builder, void_id, phase->function_id,
SpvFunctionControlMaskNone, function_type_id);
if (phase->instance_count)
phase->instance_id = vkd3d_spirv_build_op_function_parameter(builder, param_type_id);
vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
vkd3d_dxbc_compiler_emit_shader_phase_name(compiler, phase->function_id, phase, NULL);
}
static const struct vkd3d_shader_phase *vkd3d_dxbc_compiler_get_current_shader_phase(
struct vkd3d_dxbc_compiler *compiler)
{
struct vkd3d_shader_phase *phase;
if (!compiler->shader_phase_count)
return NULL;
phase = &compiler->shader_phases[compiler->shader_phase_count - 1];
if (!phase->function_id)
vkd3d_dxbc_compiler_begin_shader_phase(compiler, phase);
return phase;
}
static void vkd3d_dxbc_compiler_decorate_xfb_output(struct vkd3d_dxbc_compiler *compiler,
uint32_t id, unsigned int component_count, const struct vkd3d_shader_signature_element *signature_element)
{
const struct vkd3d_shader_transform_feedback_info *xfb_info = compiler->xfb_info;
const struct vkd3d_shader_transform_feedback_element *xfb_element;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int offset, stride, i;
if (!xfb_info)
return;
offset = 0;
xfb_element = NULL;
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 == signature_element->stream_index
&& !ascii_strcasecmp(e->semantic_name, signature_element->semantic_name)
&& e->semantic_index == signature_element->semantic_index)
{
xfb_element = e;
break;
}
}
if (!xfb_element)
return;
for (i = 0; xfb_element != &xfb_info->elements[i]; ++i)
if (xfb_info->elements[i].output_slot == xfb_element->output_slot)
offset += 4 * xfb_info->elements[i].component_count;
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
if (xfb_element->component_index || xfb_element->component_count > component_count)
{
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;
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;
Elizabeth Figura
committed
write_mask |= current->mask;
++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)
{
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;
unsigned int component_idx, input_component_count;
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;
struct vkd3d_symbol *symbol = NULL;
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
Elizabeth Figura
committed
write_mask = signature_element->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;
Elizabeth Figura
committed
input_component_count = vkd3d_write_mask_component_count(signature_element->mask);
component_idx = vkd3d_write_mask_get_component_idx(signature_element->mask);
}
if (!(use_private_var = builtin && builtin->fixup_pfn)
Henri Verbeet
committed
&& needs_private_io_variable(shader_signature, reg_idx, builtin, &input_component_count, &write_mask)
&& (compiler->shader_type != VKD3D_SHADER_TYPE_HULL
|| (reg->type != VKD3DSPR_INCONTROLPOINT && reg->type != VKD3DSPR_PATCHCONST)))
use_private_var = true;
else
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
Józef Kucia
committed
storage_class = SpvStorageClassInput;
vkd3d_symbol_make_register(®_symbol, reg);
Henri Verbeet
committed
if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
input_id = symbol->id;
Henri Verbeet
committed
else if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL
&& (reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_PATCHCONST))
Henri Verbeet
committed
/* Input/output registers from one phase can be used as inputs in
* subsequent phases. Specifically:
*
* - Control phase inputs are available as "vicp" in fork and join
* phases.
* - Control phase outputs are available as "vocp" in fork and join
* phases.
* - Fork phase patch constants are available as "vpc" in join
* phases.
*
* We handle "vicp" and "vpc" here by creating aliases to the shader's
* global inputs and outputs. We handle "vocp" in
* vkd3d_dxbc_compiler_leave_shader_phase(). */
tmp_symbol = reg_symbol;
Henri Verbeet
committed
if (reg->type == VKD3DSPR_PATCHCONST)
tmp_symbol.key.reg.type = VKD3DSPR_OUTPUT;
else
tmp_symbol.key.reg.type = VKD3DSPR_INPUT;
if ((entry = rb_get(&compiler->symbol_table, &tmp_symbol)))
symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
tmp_symbol = *symbol;
Henri Verbeet
committed
tmp_symbol.key.reg.type = reg->type;
vkd3d_dxbc_compiler_put_symbol(compiler, &tmp_symbol);
input_id = symbol->id;
Henri Verbeet
committed
else
{
if (reg->type == VKD3DSPR_PATCHCONST)
ERR("Patch constant register %u was not declared in a previous phase.\n", reg_idx);
else
ERR("Input control point register %u was not declared in a previous phase.\n", reg_idx);
}
if (!symbol || ~symbol->info.reg.dcl_mask & write_mask)
{
if (builtin)
{
input_id = vkd3d_dxbc_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size);
}
else
{
unsigned int location = reg_idx;
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);
if (reg->type == VKD3DSPR_PATCHCONST)
{
vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0);
location += compiler->input_signature->element_count;
}
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 (!symbol)
{
var_id = input_id;
if (use_private_var)
{
storage_class = SpvStorageClassPrivate;
var_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, array_size);
vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class,
use_private_var ? VKD3D_SHADER_COMPONENT_FLOAT : component_type,
use_private_var ? VKD3DSP_WRITEMASK_ALL : write_mask);
reg_symbol.info.reg.dcl_mask |= 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
}
else
{
symbol->info.reg.dcl_mask |= write_mask;
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 write_mask;
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);
write_mask = vkd3d_write_mask_from_component_count(builtin->component_count);
vkd3d_symbol_set_register_info(®_symbol, input_id,
SpvStorageClassInput, builtin->component_type, write_mask);
reg_symbol.info.reg.dcl_mask = write_mask;
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:
Henri Verbeet
committed
case VKD3DSPR_PATCHCONST:
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);
}
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
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 write_mask;
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);
write_mask = vkd3d_write_mask_from_component_count(builtin->component_count);
vkd3d_symbol_set_register_info(®_symbol, output_id,
SpvStorageClassOutput, builtin->component_type, write_mask);
reg_symbol.info.reg.dcl_mask = write_mask;
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);
}
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
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 *symbol = NULL;
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
Elizabeth Figura
committed
write_mask = signature_element->mask;
Józef Kucia
committed
component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
Elizabeth Figura
committed
output_component_count = vkd3d_write_mask_component_count(signature_element->mask);
Józef Kucia
committed
if (builtin)
{
component_type = builtin->component_type;
if (!builtin->spirv_array_size)
output_component_count = builtin->component_count;
component_idx = 0;
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)
&& (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;
else
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
vkd3d_symbol_make_register(®_symbol, reg);
if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
Henri Verbeet
committed
{
symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
id = symbol->id;
Henri Verbeet
committed
}
if (!symbol || ~symbol->info.reg.dcl_mask & write_mask)
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;
}
else 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);
}
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,