vkd3d-shader/ir: Allow controlling point sprite through a parameter.

This commit is contained in:
Elizabeth Figura 2024-10-15 19:04:19 -05:00 committed by Henri Verbeet
parent 8a3fe9cd1e
commit a492d64fef
Notes: Henri Verbeet 2024-10-22 20:53:34 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1188
5 changed files with 246 additions and 0 deletions

View File

@ -700,6 +700,39 @@ enum vkd3d_shader_parameter_name
* \since 1.14
*/
VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX,
/**
* Whether texture coordinate inputs should take their values from the
* point coordinate.
*
* When this parameter is provided to a pixel shader, and the value is
* nonzero, any fragment shader input with the semantic name "TEXCOORD"
* takes its value from the point coordinates instead of from the previous
* shader. The point coordinates here are defined as a four-component vector
* whose X and Y components are the X and Y coordinates of the fragment
* within a point being rasterized, and whose Z and W components are zero.
*
* In GLSL, the X and Y components are drawn from gl_PointCoord; in SPIR-V,
* they are drawn from a variable with the BuiltinPointCoord decoration.
*
* This includes t# fragment shader inputs in shader model 2 shaders,
* as well as texture sampling in shader model 1 shaders.
*
* This parameter can be used to implement fixed function point sprite, as
* present in Direct3D versions 8 and 9, if the target environment does not
* support point sprite as part of its own fixed-function API (as Vulkan and
* core OpenGL).
*
* The data type for this parameter must be
* VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32.
*
* The default value is zero, i.e. use the original varyings.
*
* Only VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT is supported in this
* version of vkd3d-shader.
*
* \since 1.14
*/
VKD3D_SHADER_PARAMETER_NAME_POINT_SPRITE,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME),
};

View File

@ -1190,6 +1190,10 @@ static void shader_print_register(struct vkd3d_d3d_asm_compiler *compiler, const
vkd3d_string_buffer_printf(buffer, "vWaveLaneIndex");
break;
case VKD3DSPR_POINT_COORD:
vkd3d_string_buffer_printf(buffer, "vPointCoord");
break;
default:
vkd3d_string_buffer_printf(buffer, "%s<unhandled register type %#x>%s",
compiler->colours.error, reg->type, compiler->colours.reset);

View File

@ -264,6 +264,13 @@ static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigne
dst->reg.idx[0].offset = idx;
}
static void dst_param_init_temp_float4(struct vkd3d_shader_dst_param *dst, unsigned int idx)
{
vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1);
dst->reg.idx[0].offset = idx;
dst->reg.dimension = VSIR_DIMENSION_VEC4;
}
static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx)
{
vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
@ -6132,6 +6139,192 @@ static enum vkd3d_result vsir_program_insert_point_size_clamp(struct vsir_progra
return VKD3D_OK;
}
static bool has_texcoord_signature_element(const struct shader_signature *signature)
{
for (size_t i = 0; i < signature->element_count; ++i)
{
if (!ascii_strcasecmp(signature->elements[i].semantic_name, "TEXCOORD"))
return true;
}
return false;
}
/* Returns true if replacement was done. */
static bool replace_texcoord_with_point_coord(struct vsir_program *program,
struct vkd3d_shader_src_param *src, unsigned int coord_temp)
{
uint32_t prev_swizzle = src->swizzle;
const struct signature_element *e;
/* The input semantic may have a nontrivial mask, which we need to
* correct for. E.g. if the mask is .yz, and we read from .y, that needs
* to become .x. */
static const uint32_t inverse_swizzles[16] =
{
/* Use _ for "undefined" components, for clarity. */
#define VKD3D_SHADER_SWIZZLE__ VKD3D_SHADER_SWIZZLE_X
0,
/* .x */ VKD3D_SHADER_SWIZZLE(X, _, _, _),
/* .y */ VKD3D_SHADER_SWIZZLE(_, X, _, _),
/* .xy */ VKD3D_SHADER_SWIZZLE(X, Y, _, _),
/* .z */ VKD3D_SHADER_SWIZZLE(_, _, X, _),
/* .xz */ VKD3D_SHADER_SWIZZLE(X, _, Y, _),
/* .yz */ VKD3D_SHADER_SWIZZLE(_, X, Y, _),
/* .xyz */ VKD3D_SHADER_SWIZZLE(X, Y, Z, _),
/* .w */ VKD3D_SHADER_SWIZZLE(_, _, _, X),
/* .xw */ VKD3D_SHADER_SWIZZLE(X, _, _, Y),
/* .yw */ VKD3D_SHADER_SWIZZLE(_, X, _, Y),
/* .xyw */ VKD3D_SHADER_SWIZZLE(X, Y, _, Z),
/* .zw */ VKD3D_SHADER_SWIZZLE(_, _, X, Y),
/* .xzw */ VKD3D_SHADER_SWIZZLE(X, _, Y, Z),
/* .yzw */ VKD3D_SHADER_SWIZZLE(_, X, Y, Z),
/* .xyzw */ VKD3D_SHADER_SWIZZLE(X, Y, Z, W),
#undef VKD3D_SHADER_SWIZZLE__
};
if (src->reg.type != VKD3DSPR_INPUT)
return false;
e = &program->input_signature.elements[src->reg.idx[0].offset];
if (ascii_strcasecmp(e->semantic_name, "TEXCOORD"))
return false;
src->reg.type = VKD3DSPR_TEMP;
src->reg.idx[0].offset = coord_temp;
/* If the mask is already contiguous and zero-based, no need to remap
* the swizzle. */
if (!(e->mask & (e->mask + 1)))
return true;
src->swizzle = 0;
for (unsigned int i = 0; i < 4; ++i)
{
src->swizzle |= vsir_swizzle_get_component(inverse_swizzles[e->mask],
vsir_swizzle_get_component(prev_swizzle, i)) << VKD3D_SHADER_SWIZZLE_SHIFT(i);
}
return true;
}
static enum vkd3d_result vsir_program_insert_point_coord(struct vsir_program *program,
struct vsir_transformation_context *ctx)
{
const struct vkd3d_shader_parameter1 *sprite_parameter = NULL;
static const struct vkd3d_shader_location no_loc;
struct vkd3d_shader_instruction *ins;
bool used_texcoord = false;
unsigned int coord_temp;
size_t i, insert_pos;
if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL)
return VKD3D_OK;
for (i = 0; i < program->parameter_count; ++i)
{
const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i];
if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_POINT_SPRITE)
sprite_parameter = parameter;
}
if (!sprite_parameter)
return VKD3D_OK;
if (sprite_parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT)
{
vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
"Unsupported point sprite parameter type %#x.", sprite_parameter->type);
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
if (sprite_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32)
{
vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE,
"Invalid point sprite parameter data type %#x.", sprite_parameter->data_type);
return VKD3D_ERROR_INVALID_ARGUMENT;
}
if (!sprite_parameter->u.immediate_constant.u.u32)
return VKD3D_OK;
if (!has_texcoord_signature_element(&program->input_signature))
return VKD3D_OK;
/* VKD3DSPR_POINTCOORD is a two-component value; fill the remaining two
* components with zeroes. */
coord_temp = program->temp_count++;
/* Construct the new temp after all LABEL, DCL, and NOP instructions.
* We need to skip NOP instructions because they might result from removed
* DCLs, and there could still be DCLs after NOPs. */
for (i = 0; i < program->instructions.count; ++i)
{
ins = &program->instructions.elements[i];
if (!vsir_instruction_is_dcl(ins) && ins->opcode != VKD3DSIH_LABEL && ins->opcode != VKD3DSIH_NOP)
break;
}
insert_pos = i;
/* Replace each texcoord read with a read from the point coord. */
for (; i < program->instructions.count; ++i)
{
ins = &program->instructions.elements[i];
if (vsir_instruction_is_dcl(ins))
continue;
for (unsigned int j = 0; j < ins->src_count; ++j)
{
used_texcoord |= replace_texcoord_with_point_coord(program, &ins->src[j], coord_temp);
for (unsigned int k = 0; k < ins->src[j].reg.idx_count; ++k)
{
if (ins->src[j].reg.idx[k].rel_addr)
used_texcoord |= replace_texcoord_with_point_coord(program,
ins->src[j].reg.idx[k].rel_addr, coord_temp);
}
}
for (unsigned int j = 0; j < ins->dst_count; ++j)
{
for (unsigned int k = 0; k < ins->dst[j].reg.idx_count; ++k)
{
if (ins->dst[j].reg.idx[k].rel_addr)
used_texcoord |= replace_texcoord_with_point_coord(program,
ins->dst[j].reg.idx[k].rel_addr, coord_temp);
}
}
}
if (used_texcoord)
{
if (!shader_instruction_array_insert_at(&program->instructions, insert_pos, 2))
return VKD3D_ERROR_OUT_OF_MEMORY;
ins = &program->instructions.elements[insert_pos];
vsir_instruction_init_with_params(program, ins, &no_loc, VKD3DSIH_MOV, 1, 1);
dst_param_init_temp_float4(&ins->dst[0], coord_temp);
ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1;
vsir_src_param_init(&ins->src[0], VKD3DSPR_POINT_COORD, VKD3D_DATA_FLOAT, 0);
ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4;
ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE;
++ins;
vsir_instruction_init_with_params(program, ins, &no_loc, VKD3DSIH_MOV, 1, 1);
dst_param_init_temp_float4(&ins->dst[0], coord_temp);
ins->dst[0].write_mask = VKD3DSP_WRITEMASK_2 | VKD3DSP_WRITEMASK_3;
vsir_src_param_init(&ins->src[0], VKD3DSPR_IMMCONST, VKD3D_DATA_FLOAT, 0);
ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4;
++ins;
program->has_point_coord = true;
}
return VKD3D_OK;
}
struct validation_context
{
struct vkd3d_shader_message_context *message_context;
@ -7838,6 +8031,7 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t
vsir_transform(&ctx, vsir_program_insert_clip_planes);
vsir_transform(&ctx, vsir_program_insert_point_size);
vsir_transform(&ctx, vsir_program_insert_point_size_clamp);
vsir_transform(&ctx, vsir_program_insert_point_coord);
if (TRACE_ON())
vsir_program_trace(program);

View File

@ -3252,6 +3252,9 @@ static bool spirv_compiler_get_register_name(char *buffer, unsigned int buffer_s
case VKD3DSPR_WAVELANEINDEX:
snprintf(buffer, buffer_size, "vWaveLaneIndex");
break;
case VKD3DSPR_POINT_COORD:
snprintf(buffer, buffer_size, "vPointCoord");
break;
default:
FIXME("Unhandled register %#x.\n", reg->type);
snprintf(buffer, buffer_size, "unrecognized_%#x", reg->type);
@ -4886,6 +4889,8 @@ vkd3d_register_builtins[] =
{VKD3DSPR_TESSCOORD, {VKD3D_SHADER_COMPONENT_FLOAT, 3, SpvBuiltInTessCoord}},
{VKD3DSPR_POINT_COORD, {VKD3D_SHADER_COMPONENT_FLOAT, 2, SpvBuiltInPointCoord}},
{VKD3DSPR_COVERAGE, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleMask, NULL, 1}},
{VKD3DSPR_SAMPLEMASK, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSampleMask, NULL, 1}},
@ -10596,6 +10601,14 @@ static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler)
dst.reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE;
spirv_compiler_emit_output_register(compiler, &dst);
}
if (compiler->program->has_point_coord)
{
struct vkd3d_shader_dst_param dst;
vsir_dst_param_init(&dst, VKD3DSPR_POINT_COORD, VKD3D_DATA_FLOAT, 0);
spirv_compiler_emit_input_register(compiler, &dst);
}
}
static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *compiler)

View File

@ -648,6 +648,7 @@ enum vkd3d_shader_register_type
VKD3DSPR_WAVELANECOUNT,
VKD3DSPR_WAVELANEINDEX,
VKD3DSPR_PARAMETER,
VKD3DSPR_POINT_COORD,
VKD3DSPR_COUNT,
@ -1421,6 +1422,7 @@ struct vsir_program
unsigned int ssa_count;
bool use_vocp;
bool has_point_size;
bool has_point_coord;
enum vsir_control_flow_type cf_type;
enum vsir_normalisation_level normalisation_level;