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;
  };
This commit is contained in:
Shaun Ren 2024-10-15 16:50:08 -04:00 committed by Henri Verbeet
parent 013e354b46
commit 069b8aac64
Notes: Henri Verbeet 2024-10-16 21:47:12 +02:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1157
2 changed files with 68 additions and 19 deletions

View File

@ -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;

View File

@ -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)