From 1e4764d555c544a090f6de89a53a22a508475e54 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 27 Oct 2025 12:12:00 +0100 Subject: [PATCH] vkd3d-shader/dxil: Parse the f32 denormalization mode. --- libs/vkd3d-shader/d3dbc.c | 2 + libs/vkd3d-shader/dxil.c | 72 +++++++++++++++++++++++- libs/vkd3d-shader/hlsl.c | 2 + libs/vkd3d-shader/tpf.c | 3 + libs/vkd3d-shader/vkd3d_shader_private.h | 10 ++++ 5 files changed, 87 insertions(+), 2 deletions(-) diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 65c469e9a..18a1cc5dc 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1522,6 +1522,8 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, st code_size != ~(size_t)0 ? token_count / 4u + 4 : 16, VSIR_CF_STRUCTURED, normalisation_level)) return VKD3D_ERROR_OUT_OF_MEMORY; + program->f32_denorm_mode = VSIR_DENORM_FLUSH_TO_ZERO; + vkd3d_shader_parser_init(&sm1->p, message_context, compile_info->source_name); sm1->program = program; sm1->ptr = sm1->start; diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index c452a4621..b246be145 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -3360,8 +3360,7 @@ static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxi if (record->operands[4] > UINT_MAX) WARN("Invalid attributes id %#"PRIx64".\n", record->operands[4]); /* 1-based index. */ - if ((fn->u.function.attribs_id = record->operands[4])) - TRACE("Ignoring function attributes.\n"); + fn->u.function.attribs_id = record->operands[4]; /* These always seem to be zero. */ for (i = 5, j = 0; i < min(record->operand_count, max_count); ++i) @@ -10929,6 +10928,62 @@ static void sm6_parser_cleanup(struct sm6_parser *sm6) vkd3d_free(sm6->values); } +static enum vsir_denorm_mode sm6_function_get_denorm_mode(const struct sm6_function *function, + struct sm6_parser *dxil) +{ + unsigned int attribs_id = function->declaration->u.function.attribs_id; + const struct dxil_parameter_attribute *parameter_attribute; + size_t i, j, k; + + if (!attribs_id) + return VSIR_DENORM_FLUSH_TO_ZERO; + + if (attribs_id > dxil->parameter_attribute_count) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE, + "Invalid attribute id %u.", attribs_id); + return VSIR_DENORM_FLUSH_TO_ZERO; + } + + parameter_attribute = &dxil->parameter_attributes[attribs_id - 1]; + + for (i = 0; i < parameter_attribute->group_count; ++i) + { + for (j = 0; j < dxil->attribute_group_count; ++j) + { + struct dxil_attribute_group *attribute_group = &dxil->attribute_groups[j]; + + if (attribute_group->group_id != parameter_attribute->groups[i] + || attribute_group->parameter_idx != ~0u) + continue; + + for (k = 0; k < attribute_group->attribute_count; ++k) + { + struct dxil_attribute *attribute = &attribute_group->attributes[k]; + + if (attribute->kind != ATTRIBUTE_STRING_WITH_STRING_VALUE + || strcmp(attribute->key.string, "fp32-denorm-mode")) + continue; + + if (!strcmp(attribute->value.string, "preserve")) + return VSIR_DENORM_PRESERVE; + + if (!strcmp(attribute->value.string, "ftz")) + return VSIR_DENORM_FLUSH_TO_ZERO; + + if (!strcmp(attribute->value.string, "any")) + return VSIR_DENORM_ANY; + + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE, + "Invalid value for attribute `fp32-denorm-mode'."); + return VSIR_DENORM_FLUSH_TO_ZERO; + } + } + } + + return VSIR_DENORM_FLUSH_TO_ZERO; +} + static struct sm6_function *sm6_parser_get_function(const struct sm6_parser *sm6, const char *name) { size_t i; @@ -11209,8 +11264,12 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro goto fail; } + program->f32_denorm_mode = sm6_function_get_denorm_mode(fn, sm6); + if (version.type == VKD3D_SHADER_TYPE_HULL) { + enum vsir_denorm_mode cp_denorm_mode; + sm6_parser_add_instruction(sm6, VSIR_OP_HS_CONTROL_POINT_PHASE); if ((ret = sm6_function_emit_instructions(fn, sm6)) < 0) @@ -11226,6 +11285,15 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro goto fail; } + cp_denorm_mode = sm6_function_get_denorm_mode(fn, sm6); + + if (sm6->p.status >= 0 && program->f32_denorm_mode != cp_denorm_mode) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE, + "Patch constant denorm mode %u doesn't match control point denorm mode %u.", + program->f32_denorm_mode, cp_denorm_mode); + } + sm6_parser_add_instruction(sm6, VSIR_OP_HS_FORK_PHASE); if ((ret = sm6_function_emit_instructions(fn, sm6)) < 0) goto fail; diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 6bca2e1d1..641d25539 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -5296,6 +5296,8 @@ int hlsl_parse(const struct vkd3d_shader_compile_info *compile_info, if (!vsir_program_init(program, compile_info, &version, 0, VSIR_CF_STRUCTURED, normalisation_level)) return VKD3D_ERROR_OUT_OF_MEMORY; + program->f32_denorm_mode = VSIR_DENORM_FLUSH_TO_ZERO; + if ((ret = hlsl_ctx_parse(&ctx, &program->source_files, compile_info, profile, message_context)) < 0) { vsir_program_cleanup(program); diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 3eec61864..9232d5396 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2811,6 +2811,9 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, struct vsir_pro if (!vsir_program_init(program, compile_info, &version, token_count / 7u + 20, VSIR_CF_STRUCTURED, VSIR_NORMALISED_SM4)) return false; + + program->f32_denorm_mode = VSIR_DENORM_FLUSH_TO_ZERO; + vkd3d_shader_parser_init(&sm4->p, message_context, compile_info->source_name); sm4->ptr = sm4->start; sm4->program = program; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 935a819be..0f0e61377 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -232,6 +232,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_DXIL_DUPLICATED_BLOCK = 8022, VKD3D_SHADER_ERROR_DXIL_INVALID_STRING = 8023, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE_KIND = 8024, + VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE = 8025, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, @@ -1609,6 +1610,13 @@ enum vsir_normalisation_level VSIR_NORMALISED_SM6, }; +enum vsir_denorm_mode +{ + VSIR_DENORM_ANY = 0, + VSIR_DENORM_PRESERVE, + VSIR_DENORM_FLUSH_TO_ZERO, +}; + struct vkd3d_shader_descriptor_info1 { enum vkd3d_shader_descriptor_type type; @@ -1687,6 +1695,8 @@ struct vsir_program struct vkd3d_shader_param_allocator src_params; struct vkd3d_shader_param_allocator dst_params; + + enum vsir_denorm_mode f32_denorm_mode; }; enum vkd3d_result vsir_allocate_temp_registers(struct vsir_program *program,