From 1ed5f1a4d0aefdcc801c99dbd27cffeda9c707df Mon Sep 17 00:00:00 2001
From: Shaun Ren <sren@codeweavers.com>
Date: Tue, 15 Oct 2024 16:33:21 -0400
Subject: [PATCH] vkd3d-shader/tpf: Write the patch constant function in hull
 shaders.

We use a single hs_fork_phase here for the patch constant function.
---
 libs/vkd3d-shader/hlsl_codegen.c         | 31 ++++++++++--------
 libs/vkd3d-shader/tpf.c                  | 41 ++++++++++++++++--------
 libs/vkd3d-shader/vkd3d_shader_private.h |  2 +-
 libs/vkd3d-utils/reflection.c            |  7 ++--
 tests/hlsl_d3d12.c                       |  9 +++---
 5 files changed, 55 insertions(+), 35 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index c626eb040f..4cf9d5eb84 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -6281,29 +6281,24 @@ void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body)
     } while (progress);
 }
 
-static void generate_vsir_signature_entry(struct hlsl_ctx *ctx,
-        struct vsir_program *program, bool output, struct hlsl_ir_var *var)
+static void generate_vsir_signature_entry(struct hlsl_ctx *ctx, struct vsir_program *program,
+        struct shader_signature *signature, bool output, struct hlsl_ir_var *var)
 {
     enum vkd3d_shader_sysval_semantic sysval = VKD3D_SHADER_SV_NONE;
     enum vkd3d_shader_component_type component_type;
     unsigned int register_index, mask, use_mask;
     const char *name = var->semantic.name;
     enum vkd3d_shader_register_type type;
-    struct shader_signature *signature;
     struct signature_element *element;
 
-    if (output)
-        signature = &program->output_signature;
-    else
-        signature = &program->input_signature;
-
     if (hlsl_version_ge(ctx, 4, 0))
     {
         struct vkd3d_string_buffer *string;
         bool has_idx, ret;
 
         ret = sm4_sysval_semantic_from_semantic_name(&sysval, &program->shader_version,
-                ctx->semantic_compat_mapping, ctx->domain, var->semantic.name, var->semantic.index, output, false);
+                ctx->semantic_compat_mapping, ctx->domain, var->semantic.name, var->semantic.index,
+                        output, signature == &program->patch_constant_signature);
         VKD3D_ASSERT(ret);
         if (sysval == ~0u)
             return;
@@ -6419,10 +6414,18 @@ static void generate_vsir_signature(struct hlsl_ctx *ctx,
 
     LIST_FOR_EACH_ENTRY(var, &func->extern_vars, struct hlsl_ir_var, extern_entry)
     {
-        if (var->is_input_semantic)
-            generate_vsir_signature_entry(ctx, program, false, var);
-        if (var->is_output_semantic)
-            generate_vsir_signature_entry(ctx, program, true, var);
+        if (func == ctx->patch_constant_func)
+        {
+            generate_vsir_signature_entry(ctx, program,
+                    &program->patch_constant_signature, var->is_output_semantic, var);
+        }
+        else
+        {
+            if (var->is_input_semantic)
+                generate_vsir_signature_entry(ctx, program, &program->input_signature, false, var);
+            if (var->is_output_semantic)
+                generate_vsir_signature_entry(ctx, program, &program->output_signature, true, var);
+        }
     }
 }
 
@@ -7408,6 +7411,8 @@ static void sm4_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
     }
 
     generate_vsir_signature(ctx, program, entry_func);
+    if (version.type == VKD3D_SHADER_TYPE_HULL)
+        generate_vsir_signature(ctx, program, ctx->patch_constant_func);
 }
 
 static struct hlsl_ir_jump *loop_unrolling_find_jump(struct hlsl_block *block, struct hlsl_ir_node *stop_point,
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c
index 10456f0e9c..a712f4b586 100644
--- a/libs/vkd3d-shader/tpf.c
+++ b/libs/vkd3d-shader/tpf.c
@@ -3212,18 +3212,12 @@ static void add_section(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc,
         ctx->result = buffer->status;
 }
 
-static void tpf_write_signature(struct tpf_compiler *tpf, bool output)
+static void tpf_write_signature(struct tpf_compiler *tpf, const struct shader_signature *signature, uint32_t tag)
 {
+    bool output = tag == TAG_OSGN || tag == TAG_PCSG;
     struct vkd3d_bytecode_buffer buffer = {0};
-    struct shader_signature *signature;
-    struct hlsl_ctx *ctx = tpf->ctx;
     unsigned int i;
 
-    if (output)
-        signature = &tpf->program->output_signature;
-    else
-        signature = &tpf->program->input_signature;
-
     put_u32(&buffer, signature->element_count);
     put_u32(&buffer, 8); /* unknown */
 
@@ -3257,7 +3251,7 @@ static void tpf_write_signature(struct tpf_compiler *tpf, bool output)
         set_u32(&buffer, (2 + i * 6) * sizeof(uint32_t), string_offset);
     }
 
-    add_section(ctx, &tpf->dxbc, output ? TAG_OSGN : TAG_ISGN, &buffer);
+    add_section(tpf->ctx, &tpf->dxbc, tag, &buffer);
 }
 
 static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type)
@@ -4794,7 +4788,8 @@ static void write_sm4_dcl_textures(const struct tpf_compiler *tpf, const struct
     }
 }
 
-static void write_sm4_dcl_semantic(const struct tpf_compiler *tpf, const struct hlsl_ir_var *var)
+static void tpf_write_dcl_semantic(const struct tpf_compiler *tpf,
+        const struct hlsl_ir_var *var, bool is_patch_constant_func)
 {
     const struct vkd3d_shader_version *version = &tpf->program->shader_version;
     const bool output = var->is_output_semantic;
@@ -4832,7 +4827,7 @@ static void write_sm4_dcl_semantic(const struct tpf_compiler *tpf, const struct
         instr.dsts[0].reg.dimension = VSIR_DIMENSION_SCALAR;
 
     sm4_sysval_semantic_from_semantic_name(&semantic, version, tpf->ctx->semantic_compat_mapping,
-            tpf->ctx->domain, var->semantic.name, var->semantic.index, output, false);
+            tpf->ctx->domain, var->semantic.name, var->semantic.index, output, is_patch_constant_func);
     if (semantic == ~0u)
         semantic = VKD3D_SHADER_SV_NONE;
 
@@ -4997,6 +4992,16 @@ static void tpf_write_hs_control_point_phase(const struct tpf_compiler *tpf)
     write_sm4_instruction(tpf, &instr);
 }
 
+static void tpf_write_hs_fork_phase(const struct tpf_compiler *tpf)
+{
+    struct sm4_instruction instr =
+    {
+        .opcode = VKD3D_SM5_OP_HS_FORK_PHASE,
+    };
+
+    write_sm4_instruction(tpf, &instr);
+}
+
 static void tpf_write_dcl_input_control_point_count(const struct tpf_compiler *tpf, const uint32_t count)
 {
     struct sm4_instruction instr =
@@ -6513,7 +6518,7 @@ static void tpf_write_shader_function(struct tpf_compiler *tpf, struct hlsl_ir_f
     {
         if ((var->is_input_semantic && var->last_read)
                 || (var->is_output_semantic && var->first_write))
-            write_sm4_dcl_semantic(tpf, var);
+            tpf_write_dcl_semantic(tpf, var, func == ctx->patch_constant_func);
     }
 
     if (tpf->program->shader_version.type == VKD3D_SHADER_TYPE_COMPUTE)
@@ -6613,6 +6618,12 @@ static void tpf_write_shdr(struct tpf_compiler *tpf, struct hlsl_ir_function_dec
 
     tpf_write_shader_function(tpf, entry_func);
 
+    if (version->type == VKD3D_SHADER_TYPE_HULL)
+    {
+        tpf_write_hs_fork_phase(tpf);
+        tpf_write_shader_function(tpf, ctx->patch_constant_func);
+    }
+
     set_u32(&buffer, token_count_position, bytecode_get_size(&buffer) / sizeof(uint32_t));
 
     add_section(ctx, &tpf->dxbc, TAG_SHDR, &buffer);
@@ -6717,8 +6728,10 @@ int tpf_compile(struct vsir_program *program, uint64_t config_flags,
     init_sm4_lookup_tables(&tpf.lookup);
     dxbc_writer_init(&tpf.dxbc);
 
-    tpf_write_signature(&tpf, false);
-    tpf_write_signature(&tpf, true);
+    tpf_write_signature(&tpf, &program->input_signature, TAG_ISGN);
+    tpf_write_signature(&tpf, &program->output_signature, TAG_OSGN);
+    if (ctx->profile->type == VKD3D_SHADER_TYPE_HULL)
+        tpf_write_signature(&tpf, &program->patch_constant_signature, TAG_PCSG);
     write_sm4_rdef(ctx, &tpf.dxbc);
     tpf_write_shdr(&tpf, entry_func);
     tpf_write_sfi0(&tpf);
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index 3c367c0867..0f606c375a 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -1924,7 +1924,7 @@ static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain,
 #define VKD3D_DXBC_HEADER_SIZE (8 * sizeof(uint32_t))
 #define VKD3D_DXBC_CHUNK_ALIGNMENT sizeof(uint32_t)
 
-#define DXBC_MAX_SECTION_COUNT 6
+#define DXBC_MAX_SECTION_COUNT 7
 
 struct dxbc_writer
 {
diff --git a/libs/vkd3d-utils/reflection.c b/libs/vkd3d-utils/reflection.c
index e8363ae436..d13ad700e4 100644
--- a/libs/vkd3d-utils/reflection.c
+++ b/libs/vkd3d-utils/reflection.c
@@ -512,9 +512,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetOutputParameterDesc(
 static HRESULT STDMETHODCALLTYPE d3d12_reflection_GetPatchConstantParameterDesc(
         ID3D12ShaderReflection *iface, UINT index, D3D12_SIGNATURE_PARAMETER_DESC *desc)
 {
-    FIXME("iface %p, index %u, desc %p stub!\n", iface, index, desc);
+    struct d3d12_reflection *reflection = impl_from_ID3D12ShaderReflection(iface);
 
-    return E_NOTIMPL;
+    TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
+
+    return get_signature_parameter(&reflection->signature_info.patch_constant, index, desc,
+            /* FIXME: check shader type */true);
 }
 
 static struct ID3D12ShaderReflectionVariable * STDMETHODCALLTYPE d3d12_reflection_GetVariableByName(
diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c
index 90d0c0efee..9b007aacee 100644
--- a/tests/hlsl_d3d12.c
+++ b/tests/hlsl_d3d12.c
@@ -2589,9 +2589,8 @@ static void test_signature_reflection(void)
                 "Got %u input parameters.\n", shader_desc.InputParameters);
         ok(shader_desc.OutputParameters == tests[i].output_count,
                 "Got %u output parameters.\n", shader_desc.OutputParameters);
-        todo_if(tests[i].patch_constant_count != 0)
-            ok(shader_desc.PatchConstantParameters == tests[i].patch_constant_count,
-                    "Got %u patch constant parameters.\n", shader_desc.PatchConstantParameters);
+        ok(shader_desc.PatchConstantParameters == tests[i].patch_constant_count,
+                "Got %u patch constant parameters.\n", shader_desc.PatchConstantParameters);
 
         for (unsigned int j = 0; j < shader_desc.InputParameters; ++j)
         {
@@ -2621,13 +2620,13 @@ static void test_signature_reflection(void)
         {
             vkd3d_test_push_context("Patch constant %u", j);
             hr = reflection->lpVtbl->GetPatchConstantParameterDesc(reflection, j, &desc);
-            todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+            ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
             check_signature_element(&desc, &tests[i].patch_constants[j], tests[i].signature_elements_todo);
             vkd3d_test_pop_context();
         }
 
         hr = reflection->lpVtbl->GetPatchConstantParameterDesc(reflection, shader_desc.PatchConstantParameters, &desc);
-        todo ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+        ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
 
         ID3D10Blob_Release(code);
         refcount = reflection->lpVtbl->Release(reflection);
-- 
GitLab