vkd3d-shader/hlsl: Reorder default values for matrices for SM4.

Default value initializers behave differently than regular initializers
for matrices on SM4 profiles.

While regular initializers assign the rhs elements in reading-order
(completing one row at the time), default initializers assing the rhs
elements in Chinese reading-order (completing one column at the time).

So after lowering a default value to a constant, the index of the
component to which this default value is stored is computed to meet
this expectation. This can be done because the default values.

For reference, compiling this shader:

    row_major int2x3 m = {1, 2, 3, 4, 5, 6};

    float4 main() : sv_target
    {
        return float4(m[0][0], 99, 99, 99);
    }

gives the following buffer definition:

    // cbuffer $Globals
    // {
    //
    //   row_major int2x3 m;                // Offset:    0 Size:    28
    //      = 0x00000001 0x00000003 0x00000005 0x00000000
    //        0x00000002 0x00000004 0x00000006
    //
    // }

Given that the matrix is column-major, m's default value is actually
{{1, 3, 5}, {2, 4, 6}}, unlike the {{1, 2, 3}, {4, 5, 6}} one would
expect in a regular initializer.

SM1 profiles assign the elements in regular reading order.
This commit is contained in:
Francisco Casas 2024-04-12 17:22:45 -04:00 committed by Henri Verbeet
parent ab01fedc5d
commit f5bfa728eb
Notes: Henri Verbeet 2024-06-11 16:55:09 +02:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/787
2 changed files with 48 additions and 2 deletions

View File

@ -2079,6 +2079,50 @@ static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool d
return true; return true;
} }
/* For some reason, for matrices, values from default value initializers end up in different
* components than from regular initializers. Default value initializers fill the matrix in
* vertical reading order (left-to-right top-to-bottom) instead of regular reading order
* (top-to-bottom left-to-right), so they have to be adjusted. */
static unsigned int get_component_index_from_default_initializer_index(struct hlsl_ctx *ctx,
struct hlsl_type *type, unsigned int index)
{
unsigned int element_comp_count, element, x, y, i;
unsigned int base = 0;
if (ctx->profile->major_version < 4)
return index;
switch (type->class)
{
case HLSL_CLASS_MATRIX:
x = index / type->dimy;
y = index % type->dimy;
return y * type->dimx + x;
case HLSL_CLASS_ARRAY:
element_comp_count = hlsl_type_component_count(type->e.array.type);
element = index / element_comp_count;
base = element * element_comp_count;
return base + get_component_index_from_default_initializer_index(ctx, type->e.array.type, index - base);
case HLSL_CLASS_STRUCT:
for (i = 0; i < type->e.record.field_count; ++i)
{
struct hlsl_type *field_type = type->e.record.fields[i].type;
element_comp_count = hlsl_type_component_count(field_type);
if (index - base < element_comp_count)
return base + get_component_index_from_default_initializer_index(ctx, field_type, index - base);
base += element_comp_count;
}
break;
default:
return index;
}
vkd3d_unreachable();
}
static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs, static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs,
struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src) struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src)
{ {
@ -2102,12 +2146,14 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i
if (dst->default_values) if (dst->default_values)
{ {
struct hlsl_default_value default_value = {0}; struct hlsl_default_value default_value = {0};
unsigned int dst_index;
if (!hlsl_clone_block(ctx, &block, instrs)) if (!hlsl_clone_block(ctx, &block, instrs))
return; return;
default_value.value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); default_value.value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc);
dst->default_values[*store_index] = default_value; dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index);
dst->default_values[dst_index] = default_value;
hlsl_block_cleanup(&block); hlsl_block_cleanup(&block);
} }

View File

@ -1872,7 +1872,7 @@ static void test_default_values_reflection(void)
unsigned int var_val = *((unsigned int *)var_desc.DefaultValue + k); unsigned int var_val = *((unsigned int *)var_desc.DefaultValue + k);
unsigned int expect_val = *((unsigned int *)expect->var_desc.DefaultValue + k); unsigned int expect_val = *((unsigned int *)expect->var_desc.DefaultValue + k);
todo_if(var_val != expect_val) ok(var_val == expect_val, "Expected default value 0x%08x, but got 0x%08x, at offset %u.\n", ok(var_val == expect_val, "Expected default value 0x%08x, but got 0x%08x, at offset %u.\n",
expect_val, var_val, 4 * k); expect_val, var_val, 4 * k);
} }
} }