From 013e354b460b97426b9d71d4b860dc1d19cb009c Mon Sep 17 00:00:00 2001
From: Shaun Ren <sren@codeweavers.com>
Date: Mon, 7 Oct 2024 20:57:15 -0400
Subject: [PATCH 1/2] tests: Test struct single inheritance.

---
 Makefile.am                               |   1 +
 tests/hlsl/struct-inheritance.shader_test | 134 ++++++++++++++++++++++
 2 files changed, 135 insertions(+)
 create mode 100644 tests/hlsl/struct-inheritance.shader_test

diff --git a/Makefile.am b/Makefile.am
index f6e105e072..b8e4aa4bbd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -235,6 +235,7 @@ vkd3d_shader_tests = \
 	tests/hlsl/strings.shader_test \
 	tests/hlsl/struct-array.shader_test \
 	tests/hlsl/struct-assignment.shader_test \
+	tests/hlsl/struct-inheritance.shader_test \
 	tests/hlsl/struct-semantics.shader_test \
 	tests/hlsl/switch.shader_test \
 	tests/hlsl/swizzle-constant-prop.shader_test \
diff --git a/tests/hlsl/struct-inheritance.shader_test b/tests/hlsl/struct-inheritance.shader_test
new file mode 100644
index 0000000000..757a1674b7
--- /dev/null
+++ b/tests/hlsl/struct-inheritance.shader_test
@@ -0,0 +1,134 @@
+[pixel shader todo(sm<6)]
+
+struct a
+{
+    float4 aa;
+    float4 bb;
+};
+
+struct b : a
+{
+    float4 cc;
+};
+
+struct c : b
+{
+    float4 bb; // Shadows a.bb
+};
+
+c data;
+
+float4 main() : sv_target
+{
+    return data.aa + data.bb + data.cc;
+}
+
+[test]
+uniform 0  float4 1 0 0 0
+uniform 4  float4 0 2 0 0
+uniform 8  float4 0 0 3 0
+uniform 12 float4 0 0 0 4
+todo(sm<6) draw quad
+probe (0, 0) rgba (1, 0, 3, 4)
+
+% Test writing to a field derived from a base class.
+
+[pixel shader todo(sm<6)]
+
+struct a
+{
+    float4 aa;
+    float4 bb;
+};
+
+struct b : a
+{
+    float4 cc;
+};
+
+struct c : b
+{
+    float4 bb; // Shadows a.bb
+};
+
+c data;
+
+float4 main() : sv_target
+{
+    c data2 = data;
+    data2.aa = float4(-1, 0, 0, 0);
+    data2.bb = float4(0, 0, 0, -4);
+    return data2.aa + data2.bb + data2.cc;
+}
+
+[test]
+uniform 0  float4 1 0 0 0
+uniform 4  float4 0 2 0 0
+uniform 8  float4 0 0 3 0
+uniform 12 float4 0 0 0 4
+todo(sm<6) draw quad
+probe (0, 0) rgba (-1, 0, 3, -4)
+
+
+% Multiple concrete base types are not allowed.
+
+[pixel shader fail]
+
+struct a
+{
+    float4 aa;
+};
+
+struct b
+{
+    float4 bb;
+};
+
+struct c : a, b
+{
+    float4 cc;
+};
+
+float4 main() : sv_target
+{
+    return 0;
+}
+
+
+% The concrete base type must be a struct.
+
+[pixel shader fail]
+
+struct a : float4
+{
+    float4 aa;
+};
+
+float4 main() : sv_target
+{
+    return 0;
+}
+
+[pixel shader fail]
+
+struct a : vector<float, 4>
+{
+    float4 aa;
+};
+
+float4 main() : sv_target
+{
+    return 0;
+}
+
+[pixel shader fail]
+
+struct a : Buffer<float>
+{
+    float4 aa;
+};
+
+float4 main() : sv_target
+{
+    return 0;
+}
-- 
GitLab


From 069b8aac6472014fa177a7efd55a505b8a5f77e7 Mon Sep 17 00:00:00 2001
From: Shaun Ren <sren@codeweavers.com>
Date: Tue, 15 Oct 2024 16:50:08 -0400
Subject: [PATCH 2/2] vkd3d-shader/hlsl: Implement struct single inheritance.

Here, we implement single inheritance by inserting a field at the
beginning of the derived struct with name "$super".

For the following struct declarations

  struct a
  {
      float4 aa;
      float4 bb;
  };

  struct b : a
  {
      float4 cc;
  };

  struct c : b
  {
      float4 bb;
  };

this commit generates the following:

  struct a
  {
      float4 aa;
      float4 bb;
  };

  struct b
  {
      struct a $super;
      float4 cc;
  };

  struct c
  {
      struct b $super;
      float4 bb;
  };
---
 libs/vkd3d-shader/hlsl.y                  | 79 ++++++++++++++++++-----
 tests/hlsl/struct-inheritance.shader_test |  8 +--
 2 files changed, 68 insertions(+), 19 deletions(-)

diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index da8a1b870f..ee13e193d4 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -1208,6 +1208,32 @@ static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields,
     return true;
 }
 
+static bool add_record_access_recurse(struct hlsl_ctx *ctx, struct hlsl_block *block,
+        const char *name, const struct vkd3d_shader_location *loc)
+{
+    struct hlsl_ir_node *record = node_from_block(block);
+    const struct hlsl_type *type = record->data_type;
+    const struct hlsl_struct_field *field, *base;
+
+    if ((field = get_struct_field(type->e.record.fields, type->e.record.field_count, name)))
+    {
+        unsigned int field_idx = field - type->e.record.fields;
+
+        return add_record_access(ctx, block, record, field_idx, loc);
+    }
+    else if ((base = get_struct_field(type->e.record.fields, type->e.record.field_count, "$super")))
+    {
+        unsigned int base_idx = base - type->e.record.fields;
+
+        if (!add_record_access(ctx, block, record, base_idx, loc))
+            return false;
+        return add_record_access_recurse(ctx, block, name, loc);
+    }
+
+    hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Field \"%s\" is not defined.", name);
+    return false;
+}
+
 static bool add_typedef(struct hlsl_ctx *ctx, struct hlsl_type *const orig_type, struct list *list)
 {
     struct parse_variable_def *v, *v_next;
@@ -6590,6 +6616,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim,
 
 %type <switch_case> switch_case
 
+%type <type> base_optional
 %type <type> field_type
 %type <type> named_struct_spec
 %type <type> unnamed_struct_spec
@@ -6804,11 +6831,28 @@ struct_spec:
     | unnamed_struct_spec
 
 named_struct_spec:
-      KW_STRUCT any_identifier '{' fields_list '}'
+      KW_STRUCT any_identifier base_optional '{' fields_list '}'
         {
             bool ret;
 
-            $$ = hlsl_new_struct_type(ctx, $2, $4.fields, $4.count);
+            if ($3)
+            {
+                char *name;
+
+                if (!(name = hlsl_strdup(ctx, "$super")))
+                    YYABORT;
+                if (!hlsl_array_reserve(ctx, (void **)&$5.fields, &$5.capacity, 1 + $5.count, sizeof(*$5.fields)))
+                    YYABORT;
+                memmove(&$5.fields[1], $5.fields, $5.count * sizeof(*$5.fields));
+                ++$5.count;
+
+                memset(&$5.fields[0], 0, sizeof($5.fields[0]));
+                $5.fields[0].type = $3;
+                $5.fields[0].loc = @3;
+                $5.fields[0].name = name;
+            }
+
+            $$ = hlsl_new_struct_type(ctx, $2, $5.fields, $5.count);
 
             if (hlsl_get_var(ctx->cur_scope, $2))
             {
@@ -6835,6 +6879,23 @@ any_identifier:
     | TYPE_IDENTIFIER
     | NEW_IDENTIFIER
 
+/* TODO: Multiple inheritance support for interfaces. */
+base_optional:
+      %empty
+        {
+            $$ = NULL;
+        }
+    | ':' TYPE_IDENTIFIER
+        {
+            $$ = hlsl_get_type(ctx->cur_scope, $2, true, true);
+            if ($$->class != HLSL_CLASS_STRUCT)
+            {
+                hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Base type \"%s\" is not a struct.", $2);
+                YYABORT;
+            }
+            vkd3d_free($2);
+        }
+
 fields_list:
       %empty
         {
@@ -8825,19 +8886,7 @@ postfix_expr:
 
             if (node->data_type->class == HLSL_CLASS_STRUCT)
             {
-                struct hlsl_type *type = node->data_type;
-                const struct hlsl_struct_field *field;
-                unsigned int field_idx = 0;
-
-                if (!(field = get_struct_field(type->e.record.fields, type->e.record.field_count, $3)))
-                {
-                    hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Field \"%s\" is not defined.", $3);
-                    vkd3d_free($3);
-                    YYABORT;
-                }
-
-                field_idx = field - type->e.record.fields;
-                if (!add_record_access(ctx, $1, node, field_idx, &@2))
+                if (!add_record_access_recurse(ctx, $1, $3, &@2))
                 {
                     vkd3d_free($3);
                     YYABORT;
diff --git a/tests/hlsl/struct-inheritance.shader_test b/tests/hlsl/struct-inheritance.shader_test
index 757a1674b7..581d743dad 100644
--- a/tests/hlsl/struct-inheritance.shader_test
+++ b/tests/hlsl/struct-inheritance.shader_test
@@ -1,4 +1,4 @@
-[pixel shader todo(sm<6)]
+[pixel shader]
 
 struct a
 {
@@ -28,12 +28,12 @@ uniform 0  float4 1 0 0 0
 uniform 4  float4 0 2 0 0
 uniform 8  float4 0 0 3 0
 uniform 12 float4 0 0 0 4
-todo(sm<6) draw quad
+draw quad
 probe (0, 0) rgba (1, 0, 3, 4)
 
 % Test writing to a field derived from a base class.
 
-[pixel shader todo(sm<6)]
+[pixel shader]
 
 struct a
 {
@@ -66,7 +66,7 @@ uniform 0  float4 1 0 0 0
 uniform 4  float4 0 2 0 0
 uniform 8  float4 0 0 3 0
 uniform 12 float4 0 0 0 4
-todo(sm<6) draw quad
+draw quad
 probe (0, 0) rgba (-1, 0, 3, -4)
 
 
-- 
GitLab