vkd3d-shader/ir: Allow controlling FFP point size clamping through vkd3d-shader parameters.

This commit is contained in:
Elizabeth Figura 2024-10-03 17:55:24 -05:00 committed by Henri Verbeet
parent ec53e325b6
commit 1e3c1392bd
Notes: Henri Verbeet 2024-10-10 23:00:15 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1146
2 changed files with 160 additions and 4 deletions

View File

@ -667,6 +667,39 @@ enum vkd3d_shader_parameter_name
* \since 1.14
*/
VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE,
/**
* Minimum point size.
*
* When this parameter is provided to a vertex, tessellation, or geometry
* shader, and the source shader writes point size or uses the
* VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE parameter, the point size will
* be clamped to the provided minimum value.
* If point size is not written in one of these ways,
* this parameter is ignored.
* If this parameter is not provided, the point size will not be clamped
* to a minimum size by vkd3d-shader.
*
* This parameter can be used to implement fixed function point size, as
* present in Direct3D versions 8 and 9, if the target environment does not
* support point size 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_FLOAT32.
*
* \since 1.14
*/
VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN,
/**
* Maximum point size.
*
* This parameter has identical behaviour to
* VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN, except that it provides
* the maximum size rather than the minimum.
*
* \since 1.14
*/
VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME),
};

View File

@ -203,6 +203,12 @@ static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned
src->reg.idx[0].offset = idx;
}
static void src_param_init_ssa_float(struct vkd3d_shader_src_param *src, unsigned int idx)
{
vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_FLOAT, 1);
src->reg.idx[0].offset = idx;
}
static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx)
{
vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
@ -244,6 +250,12 @@ static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned
dst->reg.idx[0].offset = idx;
}
static void dst_param_init_ssa_float(struct vkd3d_shader_dst_param *dst, unsigned int idx)
{
vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_FLOAT, 1);
dst->reg.idx[0].offset = idx;
}
static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx)
{
vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
@ -254,7 +266,6 @@ static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigne
{
vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
dst->reg.idx[0].offset = idx;
dst->write_mask = VKD3DSP_WRITEMASK_0;
}
void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
@ -5773,11 +5784,12 @@ static enum vkd3d_result insert_clip_planes_before_ret(struct vsir_program *prog
return VKD3D_OK;
}
static bool find_position_signature_idx(const struct shader_signature *signature, uint32_t *idx)
static bool find_sysval_signature_idx(const struct shader_signature *signature,
enum vkd3d_shader_sysval_semantic sysval, uint32_t *idx)
{
for (unsigned int i = 0; i < signature->element_count; ++i)
{
if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_POSITION)
if (signature->elements[i].sysval_semantic == sysval)
{
*idx = i;
return true;
@ -5842,7 +5854,7 @@ static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *pr
}
}
if (!find_position_signature_idx(signature, &position_signature_idx))
if (!find_sysval_signature_idx(signature, VKD3D_SHADER_SV_POSITION, &position_signature_idx))
{
vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC,
"Shader does not write position.");
@ -5994,6 +6006,116 @@ static enum vkd3d_result vsir_program_insert_point_size(struct vsir_program *pro
return VKD3D_OK;
}
static enum vkd3d_result vsir_program_insert_point_size_clamp(struct vsir_program *program,
struct vsir_transformation_context *ctx)
{
const struct vkd3d_shader_parameter1 *min_parameter = NULL, *max_parameter = NULL;
static const struct vkd3d_shader_location no_loc;
if (!program->has_point_size)
return VKD3D_OK;
if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX
&& program->shader_version.type != VKD3D_SHADER_TYPE_GEOMETRY
&& program->shader_version.type != VKD3D_SHADER_TYPE_HULL
&& program->shader_version.type != VKD3D_SHADER_TYPE_DOMAIN)
return VKD3D_OK;
for (unsigned int i = 0; i < program->parameter_count; ++i)
{
const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i];
if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN)
min_parameter = parameter;
else if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX)
max_parameter = parameter;
}
if (!min_parameter && !max_parameter)
return VKD3D_OK;
if (min_parameter && min_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32)
{
vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE,
"Invalid minimum point size parameter data type %#x.", min_parameter->data_type);
return VKD3D_ERROR_INVALID_ARGUMENT;
}
if (max_parameter && max_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32)
{
vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE,
"Invalid maximum point size parameter data type %#x.", max_parameter->data_type);
return VKD3D_ERROR_INVALID_ARGUMENT;
}
/* Replace writes to the point size by inserting a clamp before each write. */
for (size_t i = 0; i < program->instructions.count; ++i)
{
struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
const struct vkd3d_shader_location *loc;
unsigned int ssa_value;
bool clamp = false;
if (vsir_instruction_is_dcl(ins))
continue;
for (size_t j = 0; j < ins->dst_count; ++j)
{
struct vkd3d_shader_dst_param *dst = &ins->dst[j];
/* Note we run after I/O normalization. */
if (dst->reg.type == VKD3DSPR_RASTOUT)
{
dst_param_init_ssa_float(dst, program->ssa_count);
ssa_value = program->ssa_count++;
clamp = true;
}
}
if (!clamp)
continue;
if (!shader_instruction_array_insert_at(&program->instructions, i + 1, !!min_parameter + !!max_parameter))
return VKD3D_ERROR_OUT_OF_MEMORY;
loc = &program->instructions.elements[i].location;
ins = &program->instructions.elements[i + 1];
if (min_parameter)
{
vsir_instruction_init_with_params(program, ins, loc, VKD3DSIH_MAX, 1, 2);
src_param_init_ssa_float(&ins->src[0], ssa_value);
src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN, VKD3D_DATA_FLOAT);
if (max_parameter)
{
dst_param_init_ssa_float(&ins->dst[0], program->ssa_count);
ssa_value = program->ssa_count++;
}
else
{
vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VKD3D_DATA_FLOAT, 1);
ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE;
}
++ins;
++i;
}
if (max_parameter)
{
vsir_instruction_init_with_params(program, ins, loc, VKD3DSIH_MIN, 1, 2);
src_param_init_ssa_float(&ins->src[0], ssa_value);
src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX, VKD3D_DATA_FLOAT);
vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VKD3D_DATA_FLOAT, 1);
ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE;
++i;
}
}
return VKD3D_OK;
}
struct validation_context
{
struct vkd3d_shader_message_context *message_context;
@ -7366,6 +7488,7 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t
vsir_transform(&ctx, vsir_program_insert_alpha_test);
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);
if (TRACE_ON())
vsir_program_trace(program);