From: Francisco Casas fcasas@codeweavers.com
Default value initializers behave differently than regular initializers for matrices.
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 the default values to constants, they are reordered to meet this expectation. This can be done because the default values aren't used elsewhere[1].
Performing this reordering before lowering to constant values implies the need to move the hlsl_default_value in the array, which is not simple because they contain hlsl_src with list nodes.
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.
[1] If for some reason we want to do this before, we could turn var->default_values into an array of struct hlsl_default_value pointers, but seems like an overkill for now. --- libs/vkd3d-shader/hlsl.c | 56 ++++++++++++++++++++++++++++++++ libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl_codegen.c | 4 ++- 3 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 35bcc9d97..4c0b750bc 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1161,6 +1161,62 @@ void hlsl_transfer_var_default_values(struct hlsl_ir_var *dst, struct hlsl_ir_va src->default_values = NULL; }
+static void reorder_matrix_default_values(struct hlsl_ir_var *var, int dimx, int dimy, int start) +{ + struct hlsl_default_value aux[16]; + unsigned int i, x, y; + + for (i = 0; i < dimx * dimy; ++i) + { + /* structs that contain list nodes in use should not be copied by value. */ + assert(!var->default_values[start + i].src.node); + aux[i] = var->default_values[start + i]; + } + + for (i = 0; i < dimx * dimy; ++i) + { + y = i / dimx; + x = i % dimx; + var->default_values[start + i] = aux[x * dimy + y]; + } +} + +/* 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 + * Chinese 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. */ +void hlsl_reorder_default_values_in_matrices(struct hlsl_ir_var *var, struct hlsl_type *type, unsigned int start_comp) +{ + unsigned int element_comp_count, i; + + switch (type->class) + { + case HLSL_CLASS_MATRIX: + reorder_matrix_default_values(var, type->dimx, type->dimy, start_comp); + break; + + case HLSL_CLASS_ARRAY: + element_comp_count = hlsl_type_component_count(type->e.array.type); + for (i = 0; i < type->e.array.elements_count; ++i) + { + hlsl_reorder_default_values_in_matrices(var, type->e.array.type, start_comp); + start_comp += element_comp_count; + } + break; + + 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; + hlsl_reorder_default_values_in_matrices(var, field_type, start_comp); + start_comp += hlsl_type_component_count(field_type); + } + break; + + default: + break; + } +}
struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *template, struct hlsl_type *type, const struct vkd3d_shader_location *loc) diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 1196c463d..629cd42c0 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1391,6 +1391,7 @@ struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node *selector, struct list *cases, const struct vkd3d_shader_location *loc); void hlsl_transfer_var_default_values(struct hlsl_ir_var *dst, struct hlsl_ir_var *src); +void hlsl_reorder_default_values_in_matrices(struct hlsl_ir_var *var, struct hlsl_type *type, unsigned int start_comp);
void hlsl_error(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc, enum vkd3d_shader_error error, const char *fmt, ...) VKD3D_PRINTF_FUNC(4, 5); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index d9e61bcc7..409f179d6 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -2522,8 +2522,8 @@ static bool validate_nonconstant_vector_store_derefs(struct hlsl_ctx *ctx, struc static void lower_var_default_values(struct hlsl_ctx *ctx) { const struct hlsl_scope *scope; - const struct hlsl_ir_var *var; unsigned k, component_count; + struct hlsl_ir_var *var;
LIST_FOR_EACH_ENTRY(scope, &ctx->scopes, struct hlsl_scope, entry) { @@ -2557,6 +2557,8 @@ static void lower_var_default_values(struct hlsl_ctx *ctx) } hlsl_src_remove(&def_value->src); } + + hlsl_reorder_default_values_in_matrices(var, var->data_type, 0); } } }