From 4290d853974ec02025f622c356b69443daf91b2c Mon Sep 17 00:00:00 2001
From: Elizabeth Figura <zfigura@codeweavers.com>
Date: Mon, 4 Nov 2024 22:46:56 -0600
Subject: [PATCH] vkd3d-shader/hlsl: Write all writemask components for PSIZE
 and FOG outputs.

Matching fxc/d3dcompiler.
---
 libs/vkd3d-shader/hlsl_codegen.c | 26 +++++++++++++++++++++-----
 tests/vkd3d_shader_api.c         |  5 ++---
 2 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index 3f1ff5a600..832a378c75 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -6519,16 +6519,22 @@ static void generate_vsir_signature_entry(struct hlsl_ctx *ctx, struct vsir_prog
                 sysval = VKD3D_SHADER_SV_POSITION;
         }
 
+        mask = (1 << var->data_type->dimx) - 1;
+
         if (!ascii_strcasecmp(var->semantic.name, "PSIZE") && output
-                && program->shader_version.type == VKD3D_SHADER_TYPE_VERTEX && var->data_type->dimx > 1)
-            hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC,
-                    "PSIZE output must have only 1 component in this shader model.");
+                && program->shader_version.type == VKD3D_SHADER_TYPE_VERTEX)
+        {
+            if (var->data_type->dimx > 1)
+                hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC,
+                        "PSIZE output must have only 1 component in this shader model.");
+            /* For some reason the writemask has all components set. */
+            mask = VKD3DSP_WRITEMASK_ALL;
+        }
         if (!ascii_strcasecmp(var->semantic.name, "FOG") && output && program->shader_version.major < 3
                 && program->shader_version.type == VKD3D_SHADER_TYPE_VERTEX && var->data_type->dimx > 1)
             hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC,
                     "FOG output must have only 1 component in this shader model.");
 
-        mask = (1 << var->data_type->dimx) - 1;
         use_mask = mask; /* FIXME: retrieve use mask accurately. */
         component_type = VKD3D_SHADER_COMPONENT_FLOAT;
     }
@@ -7251,6 +7257,8 @@ static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx,
 
     if (deref->var->is_output_semantic)
     {
+        const char *semantic_name = deref->var->semantic.name;
+
         version.major = ctx->profile->major_version;
         version.minor = ctx->profile->minor_version;
         version.type = ctx->profile->type;
@@ -7260,7 +7268,7 @@ static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx,
             type = VKD3DSPR_TEMP;
             register_index = 0;
         }
-        else if (!sm1_register_from_semantic_name(&version, deref->var->semantic.name,
+        else if (!sm1_register_from_semantic_name(&version, semantic_name,
                 deref->var->semantic.index, true, &type, &register_index))
         {
             VKD3D_ASSERT(reg.allocated);
@@ -7269,6 +7277,14 @@ static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx,
         }
         else
             writemask = (1u << deref->var->data_type->dimx) - 1;
+
+        if (version.type == VKD3D_SHADER_TYPE_PIXEL && (!ascii_strcasecmp(semantic_name, "PSIZE")
+                || (!ascii_strcasecmp(semantic_name, "FOG") && version.major < 3)))
+        {
+            /* These are always 1-component, but for some reason are written
+             * with a writemask containing all components. */
+            writemask = VKD3DSP_WRITEMASK_ALL;
+        }
     }
     else
         VKD3D_ASSERT(reg.allocated);
diff --git a/tests/vkd3d_shader_api.c b/tests/vkd3d_shader_api.c
index 727b06c376..15223fb1de 100644
--- a/tests/vkd3d_shader_api.c
+++ b/tests/vkd3d_shader_api.c
@@ -438,7 +438,7 @@ static void check_signature_element(const struct vkd3d_shader_signature_element
     ok(element->component_type == expect->component_type, "Got component type %#x.\n", element->component_type);
     ok(element->register_index == expect->register_index, "Got register index %u.\n", element->register_index);
     ok(element->mask == expect->mask, "Got mask %#x.\n", element->mask);
-    todo_if (expect->used_mask != expect->mask)
+    todo_if (expect->used_mask != expect->mask && strcmp(expect->semantic_name, "PSIZE"))
         ok(element->used_mask == expect->used_mask, "Got used mask %#x.\n", element->used_mask);
     ok(element->min_precision == expect->min_precision, "Got minimum precision %#x.\n", element->min_precision);
 }
@@ -574,8 +574,7 @@ static void test_scan_signatures(void)
         {"TEXCOORD",        2, 0, VKD3D_SHADER_SV_NONE,     VKD3D_SHADER_COMPONENT_FLOAT, 3, 0xf, 0xf},
         {"COLOR",           0, 0, VKD3D_SHADER_SV_NONE,     VKD3D_SHADER_COMPONENT_FLOAT, 4, 0xf, 0xf},
         {"FOG",             0, 0, VKD3D_SHADER_SV_NONE,     VKD3D_SHADER_COMPONENT_FLOAT, 5, 0xf, 0xf},
-        /* FIXME: This doesn't match native, which always declares and writes all 4 components. */
-        {"PSIZE",           0, 0, VKD3D_SHADER_SV_NONE,     VKD3D_SHADER_COMPONENT_FLOAT, 6, 0x1, 0x1},
+        {"PSIZE",           0, 0, VKD3D_SHADER_SV_NONE,     VKD3D_SHADER_COMPONENT_FLOAT, 6, 0xf, 0x1},
     };
 
     static const char ps1_source[] =
-- 
GitLab