[PATCH vkd3d 3/8] vkd3d-shader/hlsl: Write SM4 signatures.

Zebediah Figura zfigura at codeweavers.com
Thu Aug 19 18:44:27 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 include/private/vkd3d_common.h   |  14 +++
 include/vkd3d_d3dcommon.idl      |  37 ++++++
 libs/vkd3d-shader/hlsl.h         |   6 +
 libs/vkd3d-shader/hlsl_codegen.c |  59 ++++++---
 libs/vkd3d-shader/hlsl_sm4.c     | 200 ++++++++++++++++++++++++++++++-
 5 files changed, 300 insertions(+), 16 deletions(-)

diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h
index 46a39b4d..18cc3cab 100644
--- a/include/private/vkd3d_common.h
+++ b/include/private/vkd3d_common.h
@@ -170,6 +170,20 @@ static inline int ascii_tolower(int c)
     return ascii_isupper(c) ? c - 'A' + 'a' : c;
 }
 
+static inline int ascii_strncasecmp(const char *a, const char *b, size_t n)
+{
+    int c_a, c_b;
+
+    while (n--)
+    {
+        c_a = ascii_tolower(*a++);
+        c_b = ascii_tolower(*b++);
+        if (c_a != c_b || !c_a)
+            return c_a - c_b;
+    }
+    return 0;
+}
+
 static inline int ascii_strcasecmp(const char *a, const char *b)
 {
     int c_a, c_b;
diff --git a/include/vkd3d_d3dcommon.idl b/include/vkd3d_d3dcommon.idl
index ed6f2705..4859d145 100644
--- a/include/vkd3d_d3dcommon.idl
+++ b/include/vkd3d_d3dcommon.idl
@@ -88,6 +88,43 @@ typedef enum D3D_CBUFFER_TYPE
     D3D_CT_RESOURCE_BIND_INFO,
 } D3D_CBUFFER_TYPE;
 
+typedef enum D3D_NAME
+{
+    D3D_NAME_UNDEFINED,
+    D3D_NAME_POSITION,
+    D3D_NAME_CLIP_DISTANCE,
+    D3D_NAME_CULL_DISTANCE,
+    D3D_NAME_RENDER_TARGET_ARRAY_INDEX,
+    D3D_NAME_VIEWPORT_ARRAY_INDEX,
+    D3D_NAME_VERTEX_ID,
+    D3D_NAME_PRIMITIVE_ID,
+    D3D_NAME_INSTANCE_ID,
+    D3D_NAME_IS_FRONT_FACE,
+    D3D_NAME_SAMPLE_INDEX,
+    D3D_NAME_FINAL_QUAD_EDGE_TESSFACTOR,
+    D3D_NAME_FINAL_QUAD_INSIDE_TESSFACTOR,
+    D3D_NAME_FINAL_TRI_EDGE_TESSFACTOR,
+    D3D_NAME_FINAL_TRI_INSIDE_TESSFACTOR,
+    D3D_NAME_FINAL_LINE_DETAIL_TESSFACTOR,
+    D3D_NAME_FINAL_LINE_DENSITY_TESSFACTOR,
+    D3D_NAME_BARYCENTRICS = 23,
+    D3D_NAME_SHADINGRATE,
+    D3D_NAME_CULLPRIMITIVE,
+    D3D_NAME_TARGET = 64,
+    D3D_NAME_DEPTH,
+    D3D_NAME_COVERAGE,
+    D3D_NAME_DEPTH_GREATER_EQUAL,
+    D3D_NAME_DEPTH_LESS_EQUAL,
+} D3D_NAME;
+
+typedef enum D3D_REGISTER_COMPONENT_TYPE
+{
+    D3D_REGISTER_COMPONENT_UNKNOWN,
+    D3D_REGISTER_COMPONENT_UINT32,
+    D3D_REGISTER_COMPONENT_SINT32,
+    D3D_REGISTER_COMPONENT_FLOAT32,
+} D3D_REGISTER_COMPONENT_TYPE;
+
 typedef enum _D3D_SHADER_INPUT_FLAGS
 {
     D3D_SIF_USERPACKED          = 0x01,
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index 41c16b07..9860ed7a 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -22,7 +22,9 @@
 
 #include "vkd3d_shader_private.h"
 #include "rbtree.h"
+#include "vkd3d_d3dcommon.h"
 #include "vkd3d_d3dx9shader.h"
+#include "sm4.h"
 
 /* The general IR structure is inspired by Mesa GLSL hir, even though the code
  * ends up being quite different in practice. Anyway, here comes the relevant
@@ -683,6 +685,10 @@ bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_sem
 bool hlsl_sm1_usage_from_semantic(const struct hlsl_semantic *semantic, D3DDECLUSAGE *usage, uint32_t *usage_idx);
 int hlsl_sm1_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out);
 
+bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx,
+        const struct hlsl_semantic *semantic, bool output, D3D_NAME *usage);
+bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic,
+        bool output, enum vkd3d_sm4_register_type *type, uint32_t *reg);
 int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out);
 
 int hlsl_lexer_compile(struct hlsl_ctx *ctx, const struct vkd3d_shader_code *hlsl);
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index b5f7832f..939b356c 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -1012,13 +1012,26 @@ static void allocate_temp_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functio
 
 static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, unsigned int *counter, bool output)
 {
+    static const char *shader_names[] =
+    {
+        [VKD3D_SHADER_TYPE_PIXEL] = "Pixel",
+        [VKD3D_SHADER_TYPE_VERTEX] = "Vertex",
+        [VKD3D_SHADER_TYPE_GEOMETRY] = "Geometry",
+        [VKD3D_SHADER_TYPE_HULL] = "Hull",
+        [VKD3D_SHADER_TYPE_DOMAIN] = "Domain",
+        [VKD3D_SHADER_TYPE_COMPUTE] = "Compute",
+    };
+
+    unsigned int type;
+    uint32_t reg;
+    bool builtin;
+
     assert(var->semantic.name);
 
     if (ctx->profile->major_version < 4)
     {
-        D3DSHADER_PARAM_REGISTER_TYPE type;
-        uint32_t reg, usage_idx;
         D3DDECLUSAGE usage;
+        uint32_t usage_idx;
 
         if (!hlsl_sm1_usage_from_semantic(&var->semantic, &usage, &usage_idx))
         {
@@ -1027,19 +1040,35 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var
             return;
         }
 
-        if (hlsl_sm1_register_from_semantic(ctx, &var->semantic, output, &type, &reg))
-        {
-            TRACE("%s %s semantic %s[%u] matches predefined register %#x[%u].\n",
-                    ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL ? "Pixel" : "Vertex", output ? "output" : "input",
-                    var->semantic.name, var->semantic.index, type, reg);
-        }
-        else
+        if ((!output && !var->last_read) || (output && !var->first_write))
+            return;
+
+        builtin = hlsl_sm1_register_from_semantic(ctx, &var->semantic, output, &type, &reg);
+    }
+    else
+    {
+        D3D_NAME usage;
+
+        if (!hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage))
         {
-            var->reg.allocated = true;
-            var->reg.id = (*counter)++;
-            var->reg.writemask = (1 << var->data_type->dimx) - 1;
-            TRACE("Allocated %s to %s.\n", var->name, debug_register(output ? 'o' : 'v', var->reg, var->data_type));
+            hlsl_error(ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC,
+                    "Invalid semantic '%s'.", var->semantic.name);
+            return;
         }
+        builtin = hlsl_sm4_register_from_semantic(ctx, &var->semantic, output, &type, &reg);
+    }
+
+    if (builtin)
+    {
+        TRACE("%s %s semantic %s[%u] matches predefined register %#x[%u].\n", shader_names[ctx->profile->type],
+                output ? "output" : "input", var->semantic.name, var->semantic.index, type, reg);
+    }
+    else
+    {
+        var->reg.allocated = true;
+        var->reg.id = (*counter)++;
+        var->reg.writemask = (1 << var->data_type->dimx) - 1;
+        TRACE("Allocated %s to %s.\n", var->name, debug_register(output ? 'o' : 'v', var->reg, var->data_type));
     }
 }
 
@@ -1050,9 +1079,9 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx)
 
     LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
     {
-        if (var->is_input_semantic && var->last_read)
+        if (var->is_input_semantic)
             allocate_semantic_register(ctx, var, &input_counter, false);
-        if (var->is_output_semantic && var->first_write)
+        if (var->is_output_semantic)
             allocate_semantic_register(ctx, var, &output_counter, true);
     }
 }
diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c
index 38c71626..894c513f 100644
--- a/libs/vkd3d-shader/hlsl_sm4.c
+++ b/libs/vkd3d-shader/hlsl_sm4.c
@@ -23,6 +23,201 @@
 #include "vkd3d_d3dcommon.h"
 #include "sm4.h"
 
+bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic,
+        bool output, enum vkd3d_sm4_register_type *type, uint32_t *reg)
+{
+    unsigned int i;
+
+    static const struct
+    {
+        const char *semantic;
+        bool output;
+        enum vkd3d_shader_type shader_type;
+        enum vkd3d_sm4_register_type type;
+        bool has_idx;
+    }
+    register_table[] =
+    {
+        {"sv_primitiveid",  false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SM4_RT_PRIMID, false},
+
+        /* Put sv_target in this table, instead of letting it fall through to
+         * default varying allocation, so that the register index matches the
+         * usage index. */
+        {"color",           true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_OUTPUT,     true},
+        {"depth",           true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_DEPTHOUT,   false},
+        {"sv_depth",        true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_DEPTHOUT,   false},
+        {"sv_target",       true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SM4_RT_OUTPUT,     true},
+    };
+
+    for (i = 0; i < ARRAY_SIZE(register_table); ++i)
+    {
+        if (!ascii_strcasecmp(semantic->name, register_table[i].semantic)
+                && output == register_table[i].output
+                && ctx->profile->type == register_table[i].shader_type)
+        {
+            *type = register_table[i].type;
+            *reg = register_table[i].has_idx ? semantic->index : ~0u;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic,
+        bool output, D3D_NAME *usage)
+{
+    unsigned int i;
+
+    static const struct
+    {
+        const char *name;
+        bool output;
+        enum vkd3d_shader_type shader_type;
+        D3DDECLUSAGE usage;
+    }
+    semantics[] =
+    {
+        {"position",                    false, VKD3D_SHADER_TYPE_GEOMETRY,  D3D_NAME_POSITION},
+        {"sv_position",                 false, VKD3D_SHADER_TYPE_GEOMETRY,  D3D_NAME_POSITION},
+        {"sv_primitiveid",              false, VKD3D_SHADER_TYPE_GEOMETRY,  D3D_NAME_PRIMITIVE_ID},
+
+        {"position",                    true,  VKD3D_SHADER_TYPE_GEOMETRY,  D3D_NAME_POSITION},
+        {"sv_position",                 true,  VKD3D_SHADER_TYPE_GEOMETRY,  D3D_NAME_POSITION},
+        {"sv_primitiveid",              true,  VKD3D_SHADER_TYPE_GEOMETRY,  D3D_NAME_PRIMITIVE_ID},
+
+        {"position",                    false, VKD3D_SHADER_TYPE_PIXEL,     D3D_NAME_POSITION},
+        {"sv_position",                 false, VKD3D_SHADER_TYPE_PIXEL,     D3D_NAME_POSITION},
+
+        {"color",                       true,  VKD3D_SHADER_TYPE_PIXEL,     D3D_NAME_TARGET},
+        {"depth",                       true,  VKD3D_SHADER_TYPE_PIXEL,     D3D_NAME_DEPTH},
+        {"sv_target",                   true,  VKD3D_SHADER_TYPE_PIXEL,     D3D_NAME_TARGET},
+        {"sv_depth",                    true,  VKD3D_SHADER_TYPE_PIXEL,     D3D_NAME_DEPTH},
+
+        {"sv_position",                 false, VKD3D_SHADER_TYPE_VERTEX,    D3D_NAME_UNDEFINED},
+
+        {"position",                    true,  VKD3D_SHADER_TYPE_VERTEX,    D3D_NAME_POSITION},
+        {"sv_position",                 true,  VKD3D_SHADER_TYPE_VERTEX,    D3D_NAME_POSITION},
+    };
+
+    for (i = 0; i < ARRAY_SIZE(semantics); ++i)
+    {
+        if (!ascii_strcasecmp(semantic->name, semantics[i].name)
+                && output == semantics[i].output
+                && ctx->profile->type == semantics[i].shader_type
+                && !ascii_strncasecmp(semantic->name, "sv_", 3))
+        {
+            *usage = semantics[i].usage;
+            return true;
+        }
+    }
+
+    if (!ascii_strncasecmp(semantic->name, "sv_", 3))
+        return false;
+
+    *usage = D3D_NAME_UNDEFINED;
+    return true;
+}
+
+static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, bool output)
+{
+    struct vkd3d_bytecode_buffer buffer = {0};
+    struct vkd3d_string_buffer *string;
+    const struct hlsl_ir_var *var;
+    size_t count_position;
+    unsigned int i;
+    bool ret;
+
+    count_position = put_u32(&buffer, 0);
+    put_u32(&buffer, 8); /* unknown */
+
+    LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
+    {
+        unsigned int width = (1u << var->data_type->dimx) - 1, use_mask;
+        enum vkd3d_sm4_register_type type;
+        uint32_t usage_idx, reg_idx;
+        D3D_NAME usage;
+
+        if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic))
+            continue;
+
+        ret = hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage);
+        assert(ret);
+        usage_idx = var->semantic.index;
+
+        if (!hlsl_sm4_register_from_semantic(ctx, &var->semantic, output, &type, &reg_idx))
+        {
+            assert(var->reg.allocated);
+            type = VKD3D_SM4_RT_INPUT;
+            reg_idx = var->reg.id;
+        }
+
+        use_mask = width; /* FIXME: accurately report use mask */
+        if (output)
+            use_mask = 0xf ^ use_mask;
+
+        /* Special pixel shader semantics (TARGET, DEPTH, COVERAGE). */
+        if (usage >= 64)
+            usage = 0;
+
+        put_u32(&buffer, 0); /* name */
+        put_u32(&buffer, usage_idx);
+        put_u32(&buffer, usage);
+        switch (var->data_type->base_type)
+        {
+            case HLSL_TYPE_FLOAT:
+            case HLSL_TYPE_HALF:
+                put_u32(&buffer, D3D_REGISTER_COMPONENT_FLOAT32);
+                break;
+
+            case HLSL_TYPE_INT:
+                put_u32(&buffer, D3D_REGISTER_COMPONENT_SINT32);
+                break;
+
+            case HLSL_TYPE_BOOL:
+            case HLSL_TYPE_UINT:
+                put_u32(&buffer, D3D_REGISTER_COMPONENT_UINT32);
+                break;
+
+            default:
+                if ((string = hlsl_type_to_string(ctx, var->data_type)))
+                    hlsl_error(ctx, var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+                            "Invalid data type %s for semantic variable %s.", string->buffer, var->name);
+                hlsl_release_string_buffer(ctx, string);
+                put_u32(&buffer, D3D_REGISTER_COMPONENT_UNKNOWN);
+        }
+        put_u32(&buffer, reg_idx);
+        put_u32(&buffer, vkd3d_make_u16(width, use_mask));
+    }
+
+    i = 0;
+    LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
+    {
+        const char *semantic = var->semantic.name;
+        size_t string_offset;
+        D3D_NAME usage;
+
+        if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic))
+            continue;
+
+        hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage);
+
+        if (usage == D3D_NAME_TARGET && !ascii_strcasecmp(semantic, "color"))
+            string_offset = put_string(&buffer, "SV_Target");
+        else if (usage == D3D_NAME_DEPTH && !ascii_strcasecmp(semantic, "depth"))
+            string_offset = put_string(&buffer, "SV_Depth");
+        else if (usage == D3D_NAME_POSITION && !ascii_strcasecmp(semantic, "position"))
+            string_offset = put_string(&buffer, "SV_Position");
+        else
+            string_offset = put_string(&buffer, semantic);
+        set_u32(&buffer, (2 + i++ * 6) * sizeof(uint32_t), string_offset);
+    }
+
+    set_u32(&buffer, count_position, i);
+
+    dxbc_writer_add_section(dxbc, output ? TAG_OSGN : TAG_ISGN, buffer.data, buffer.size);
+}
+
 static const struct hlsl_type *get_array_type(const struct hlsl_type *type)
 {
     if (type->type == HLSL_CLASS_ARRAY)
@@ -386,10 +581,13 @@ int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun
 
     dxbc_writer_init(&dxbc);
 
+    write_sm4_signature(ctx, &dxbc, false);
+    write_sm4_signature(ctx, &dxbc, true);
     write_sm4_rdef(ctx, &dxbc);
     write_sm4_shdr(ctx, &dxbc);
 
-    ret = dxbc_writer_write(&dxbc, out);
+    if (!(ret = ctx->result))
+        ret = dxbc_writer_write(&dxbc, out);
     for (i = 0; i < dxbc.section_count; ++i)
         vkd3d_free((void *)dxbc.sections[i].data);
     return ret;
-- 
2.32.0




More information about the wine-devel mailing list