From 1e3c1392bdc92c22cb5133bcb4297a4364ebca91 Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Thu, 3 Oct 2024 17:55:24 -0500 Subject: [PATCH] vkd3d-shader/ir: Allow controlling FFP point size clamping through vkd3d-shader parameters. --- include/vkd3d_shader.h | 33 +++++++++++ libs/vkd3d-shader/ir.c | 131 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 160 insertions(+), 4 deletions(-) diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 2e1414ca..e22f236e 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -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), }; diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 29f34887..9d24126f 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -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);