mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-11-27 09:22:14 +00:00
vkd3d-shader/ir: Allow controlling point sprite through a parameter.
This commit is contained in:
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
@ -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),
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user