From: Francisco Casas fcasas@codeweavers.com
--- Makefile.am | 1 + tests/hlsl/default-values.shader_test | 82 +++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/hlsl/default-values.shader_test
diff --git a/Makefile.am b/Makefile.am index f823cbc85..15cbfd7f6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -87,6 +87,7 @@ vkd3d_shader_tests = \ tests/hlsl/cross.shader_test \ tests/hlsl/d3dcolor-to-ubyte4.shader_test \ tests/hlsl/ddxddy.shader_test \ + tests/hlsl/default-values.shader_test \ tests/hlsl/determinant.shader_test \ tests/hlsl/discard.shader_test \ tests/hlsl/distance.shader_test \ diff --git a/tests/hlsl/default-values.shader_test b/tests/hlsl/default-values.shader_test new file mode 100644 index 000000000..af724689f --- /dev/null +++ b/tests/hlsl/default-values.shader_test @@ -0,0 +1,82 @@ +[pixel shader todo] +float2 a = {1, 2}; +float4x2 b = {1, 2, 3, 4, 5, 6, 7, 8}; + +float4 main() : sv_target +{ + return float4(a, b[2]); +} + + +[pixel shader fail(sm<6) todo] +float a = 7; +float4 b = a; // initial value must be a literal expression. + +float4 main() : sv_target { return 0; } + + +[pixel shader fail(sm<6) todo] +float a = 7; +float4 b = {1, 2, a, 4}; // initial value must be a literal expression. + +float4 main() : sv_target { return 0; } + + +[pixel shader fail] +Texture2D tex; +struct +{ + Texture2D t; + float a; +} apple = {tex, 4}; // initial value must be a literal expression. + +float4 main() : sv_target +{ + return 0; +} + + +[pixel shader todo] +static const float a = 7; +float4 b = {1, 2, a, 4}; // static constant values are allowed on the initializer. + +float4 main() : sv_target { return 0; } + + +[pixel shader todo] +float2 a = {1, 2}; +float4 b = {3, 5, float2(4, 4)}; // numeric type initializers are allowed. + +float4 main() : sv_target +{ + return 2 * b; +} + + +[pixel shader todo] +struct apple +{ + float3 a[2]; + int2x2 b; +} ap = {1, 2, 3, 4, 5, 6, 7.5, 8, 9, 10}; + +float4 main() : sv_target +{ + return float4(ap.b); +} + + +[require] +shader model >= 5.0 + + +% Default values for doubles don't seem to be saved properly. +[pixel shader todo] +double2 m = {1, 2}; +// double2 m; // Offset: 0 Size: 16 +// = 0x00000000 0x00000000 0x40000000 0x00000000 + +float4 main() : sv_target +{ + return m.y; +}
From: Francisco Casas fcasas@codeweavers.com
--- tests/hlsl/default-values.shader_test | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+)
diff --git a/tests/hlsl/default-values.shader_test b/tests/hlsl/default-values.shader_test index af724689f..911a683fa 100644 --- a/tests/hlsl/default-values.shader_test +++ b/tests/hlsl/default-values.shader_test @@ -66,6 +66,78 @@ float4 main() : sv_target }
+[pixel shader] +cbuffer buff +{ + float2 a = {1, 2}; + float4x2 b = {1, 2, 3, 4, 5, 6, 7, 8}; +} + +float4 main() : sv_target +{ + return float4(a, b[2]); +} + + +[pixel shader fail(sm<6) todo] +cbuffer buff +{ + float a = 7; + float4 b = a; // initial value must be a literal expression. +} + +float4 main() : sv_target { return 0; } + + +[pixel shader fail(sm<6) todo] +cbuffer buff +{ + float a = 7; + float4 b = {1, 2, a, 4}; // initial value must be a literal expression. +} + +float4 main() : sv_target { return 0; } + + +[pixel shader] +static const float a = 7; + +cbuffer buff +{ + float4 b = {1, 2, a, 4}; // static constant values are allowed on the initializer. +} + +float4 main() : sv_target { return 0; } + + +[pixel shader] +cbuffer buff +{ + float2 a = {1, 2}; + float4 b = {3, 5, float2(4, 4)}; // numeric type initializers are allowed. +} + +float4 main() : sv_target +{ + return 2 * b; +} + + +[pixel shader] +cbuffer buff +{ + struct apple + { + float3 a[2]; + int2x2 b; + } ap = {1, 2, 3, 4, 5, 6, 7.5, 8, 9, 10}; +} + +float4 main() : sv_target +{ + return float4(ap.b); +} + [require] shader model >= 5.0
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 100 +++++++++++++++++++++++--- libs/vkd3d-shader/hlsl.h | 33 ++++++--- libs/vkd3d-shader/hlsl.y | 34 +++++---- libs/vkd3d-shader/hlsl_codegen.c | 48 ++++++++++++- libs/vkd3d-shader/tpf.c | 2 + tests/hlsl/default-values.shader_test | 8 +-- 6 files changed, 188 insertions(+), 37 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index ed80e2b75..20b463117 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -163,6 +163,15 @@ void hlsl_free_var(struct hlsl_ir_var *decl) for (k = 0; k <= HLSL_REGSET_LAST_OBJECT; ++k) vkd3d_free((void *)decl->objects_usage[k]);
+ if (decl->default_values) + { + unsigned int component_count = hlsl_type_component_count(decl->data_type); + + for (k = 0; k < component_count; ++k) + hlsl_src_remove(&decl->default_values[k].src); + vkd3d_free(decl->default_values); + } + for (i = 0; i < decl->state_block_count; ++i) hlsl_free_state_block(decl->state_blocks[i]); vkd3d_free(decl->state_blocks); @@ -1084,7 +1093,7 @@ struct hlsl_ir_node *hlsl_new_copy(struct hlsl_ctx *ctx, struct hlsl_ir_node *no
struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type, const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, uint32_t modifiers, - const struct hlsl_reg_reservation *reg_reservation) + const struct hlsl_reg_reservation *reg_reservation, bool save_default_values) { struct hlsl_ir_var *var; unsigned int k; @@ -1117,9 +1126,39 @@ struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct } }
+ if (save_default_values) + { + unsigned int component_count = hlsl_type_component_count(type); + + if (!(var->default_values = hlsl_calloc(ctx, component_count, sizeof(*var->default_values)))) + { + hlsl_free_var(var); + return NULL; + } + } + return var; }
+void hlsl_transfer_var_default_values(struct hlsl_ir_var *dst, struct hlsl_ir_var *src) +{ + unsigned int component_count = hlsl_type_component_count(dst->data_type); + unsigned int k; + + if (!dst->default_values || !src->default_values) + return; + assert(component_count == hlsl_type_component_count(src->data_type)); + + for (k = 0; k < component_count; ++k) + { + hlsl_src_from_node(&dst->default_values[k].src, src->default_values[k].src.node); + hlsl_src_remove(&src->default_values[k].src); + } + vkd3d_free(src->default_values); + src->default_values = NULL; +} + + 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) { @@ -1142,7 +1181,7 @@ struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const cha
if (!(name_copy = hlsl_strdup(ctx, name))) return NULL; - var = hlsl_new_var(ctx, name_copy, type, loc, NULL, 0, NULL); + var = hlsl_new_var(ctx, name_copy, type, loc, NULL, 0, NULL, false); if (var) { if (dummy_scope) @@ -2986,6 +3025,45 @@ void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl vkd3d_string_buffer_cleanup(&buffer); }
+void hlsl_dump_var_default_values(const struct hlsl_ir_var *var) +{ + unsigned int k, component_count = hlsl_type_component_count(var->data_type); + struct vkd3d_string_buffer buffer; + + vkd3d_string_buffer_init(&buffer); + if (!var->default_values) + { + vkd3d_string_buffer_printf(&buffer, "var "%s" has no default values.\n", var->name); + vkd3d_string_buffer_trace(&buffer); + vkd3d_string_buffer_cleanup(&buffer); + return; + } + + vkd3d_string_buffer_printf(&buffer, "var "%s" default values:\n", var->name); + for (k = 0; k < component_count; ++k) + { + struct hlsl_default_value *def_value = &var->default_values[k]; + + if (def_value->is_constant) + { + vkd3d_string_buffer_printf(&buffer, " val: 0x%08x\n", def_value->value.u); + } + else if (def_value->src.node) + { + vkd3d_string_buffer_printf(&buffer, " src: "); + dump_src(&buffer, &def_value->src); + vkd3d_string_buffer_printf(&buffer, "\n"); + } + else + { + vkd3d_string_buffer_printf(&buffer, " (unknown)\n"); + } + } + + vkd3d_string_buffer_trace(&buffer); + vkd3d_string_buffer_cleanup(&buffer); +} + void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new) { struct hlsl_src *src, *next; @@ -3725,15 +3803,6 @@ static void hlsl_ctx_cleanup(struct hlsl_ctx *ctx) struct hlsl_type *type, *next_type; unsigned int i;
- hlsl_block_cleanup(&ctx->static_initializers); - - for (i = 0; i < ctx->source_files_count; ++i) - vkd3d_free((void *)ctx->source_files[i]); - vkd3d_free(ctx->source_files); - vkd3d_string_buffer_cache_cleanup(&ctx->string_buffers); - - rb_destroy(&ctx->functions, free_function_rb, NULL); - /* State blocks must be free before the variables, because they contain instructions that may * refer to them. */ LIST_FOR_EACH_ENTRY_SAFE(scope, next_scope, &ctx->scopes, struct hlsl_scope, entry) @@ -3757,6 +3826,15 @@ static void hlsl_ctx_cleanup(struct hlsl_ctx *ctx) vkd3d_free(scope); }
+ hlsl_block_cleanup(&ctx->static_initializers); + + for (i = 0; i < ctx->source_files_count; ++i) + vkd3d_free((void *)ctx->source_files[i]); + vkd3d_free(ctx->source_files); + vkd3d_string_buffer_cache_cleanup(&ctx->string_buffers); + + rb_destroy(&ctx->functions, free_function_rb, NULL); + LIST_FOR_EACH_ENTRY_SAFE(type, next_type, &ctx->types, struct hlsl_type, entry) hlsl_free_type(type);
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 3cb98b765..1196c463d 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -402,6 +402,14 @@ struct hlsl_reg_reservation unsigned int offset_index; };
+union hlsl_constant_value_component +{ + uint32_t u; + int32_t i; + float f; + double d; +}; + struct hlsl_ir_var { struct hlsl_type *data_type; @@ -424,6 +432,19 @@ struct hlsl_ir_var /* Scope that contains annotations for this variable. */ struct hlsl_scope *annotations;
+ /* Array of default values the variable was initialized with, one for each component. + * Only for variables that need it, such as uniforms and variables inside constant buffers. + * This value is NULL for others. */ + struct hlsl_default_value + { + /* Pointer to the instruction that contains the default value, only used before it is + * lowered into a constant. */ + struct hlsl_src src; + /* Whether the value could be lowered into a constant, and its value in that case. */ + bool is_constant; + union hlsl_constant_value_component value; + } *default_values; + /* A dynamic array containing the state block on the variable's declaration, if any. * An array variable may contain multiple state blocks. * A technique pass will always contain one. @@ -778,13 +799,7 @@ struct hlsl_ir_constant struct hlsl_ir_node node; struct hlsl_constant_value { - union hlsl_constant_value_component - { - uint32_t u; - int32_t i; - float f; - double d; - } u[4]; + union hlsl_constant_value_component u[4]; } value; /* Constant register of type 'c' where the constant value is stored for SM1. */ struct hlsl_reg reg; @@ -1252,6 +1267,7 @@ void hlsl_block_cleanup(struct hlsl_block *block); bool hlsl_clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block, const struct hlsl_block *src_block);
void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *func); +void hlsl_dump_var_default_values(const struct hlsl_ir_var *var);
int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out); @@ -1369,11 +1385,12 @@ struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr const struct vkd3d_shader_location *loc); struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type, const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, uint32_t modifiers, - const struct hlsl_reg_reservation *reg_reservation); + const struct hlsl_reg_reservation *reg_reservation, bool save_default_values); struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned int value, bool is_default, struct hlsl_block *body, const struct vkd3d_shader_location *loc); 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_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.y b/libs/vkd3d-shader/hlsl.y index 7fc35d4e1..cf0f4938e 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1099,7 +1099,7 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters "packoffset() is not allowed on function parameters.");
if (!(var = hlsl_new_var(ctx, param->name, param->type, loc, ¶m->semantic, param->modifiers, - ¶m->reg_reservation))) + ¶m->reg_reservation, false))) return false; var->is_param = 1;
@@ -1123,7 +1123,7 @@ static bool add_pass(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope * struct hlsl_type *type;
type = hlsl_get_type(ctx->globals, "pass", false, false); - if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) + if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL, false))) return false; var->annotations = annotations;
@@ -1153,7 +1153,7 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_sc struct hlsl_type *type;
type = hlsl_get_type(ctx->globals, typename, false, false); - if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) + if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL, false))) return false; var->scope = scope; var->annotations = annotations; @@ -1179,7 +1179,7 @@ static bool add_effect_group(struct hlsl_ctx *ctx, const char *name, struct hlsl struct hlsl_type *type;
type = hlsl_get_type(ctx->globals, "fxgroup", false, false); - if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) + if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL, false))) return false; var->scope = scope; var->annotations = annotations; @@ -2085,9 +2085,16 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) return;
- if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) - return; - hlsl_block_add_block(instrs, &block); + if (dst->default_values) + { + hlsl_src_from_node(&dst->default_values[*store_index].src, conv); + } + else + { + if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) + return; + hlsl_block_add_block(instrs, &block); + }
++*store_index; } @@ -2166,6 +2173,7 @@ static void declare_var(struct hlsl_ctx *ctx, struct parse_variable_def *v) struct hlsl_semantic new_semantic; uint32_t modifiers = v->modifiers; bool unbounded_res_array = false; + bool save_default_values; struct hlsl_ir_var *var; struct hlsl_type *type; bool local = true; @@ -2254,7 +2262,11 @@ static void declare_var(struct hlsl_ctx *ctx, struct parse_variable_def *v) } }
- if (!(var = hlsl_new_var(ctx, var_name, type, &v->loc, &new_semantic, modifiers, &v->reg_reservation))) + save_default_values = (ctx->cur_buffer != ctx->globals_buffer) + || (ctx->cur_scope == ctx->globals && !(modifiers & HLSL_STORAGE_STATIC)); + + if (!(var = hlsl_new_var(ctx, var_name, type, &v->loc, &new_semantic, modifiers, + &v->reg_reservation, save_default_values))) { hlsl_cleanup_semantic(&new_semantic); vkd3d_free(var_name); @@ -2415,7 +2427,7 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var add_assignment(ctx, v->initializer.instrs, &load->node, ASSIGN_OP_ASSIGN, v->initializer.args[0]); }
- if (var->storage_modifiers & HLSL_STORAGE_STATIC) + if (var->default_values || var->storage_modifiers & HLSL_STORAGE_STATIC) hlsl_block_add_block(&ctx->static_initializers, v->initializer.instrs); else hlsl_block_add_block(initializers, v->initializer.instrs); @@ -5636,9 +5648,7 @@ hlsl_prog: | hlsl_prog buffer_declaration buffer_body | hlsl_prog declaration_statement { - if (!list_empty(&$2->instrs)) - hlsl_fixme(ctx, &@2, "Uniform initializer."); - destroy_block($2); + hlsl_block_add_block(&ctx->static_initializers, $2); } | hlsl_prog preproc_directive | hlsl_prog global_technique diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index eaa72836d..d9e61bcc7 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -211,13 +211,14 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, * can write the uniform name into the shader reflection data. */
if (!(uniform = hlsl_new_var(ctx, temp->name, temp->data_type, - &temp->loc, NULL, temp->storage_modifiers, &temp->reg_reservation))) + &temp->loc, NULL, temp->storage_modifiers, &temp->reg_reservation, true))) return; list_add_before(&temp->scope_entry, &uniform->scope_entry); list_add_tail(&ctx->extern_vars, &uniform->extern_entry); uniform->is_uniform = 1; uniform->is_param = temp->is_param; uniform->buffer = temp->buffer; + hlsl_transfer_var_default_values(uniform, temp);
if (!(new_name = hlsl_sprintf_alloc(ctx, "<temp-%s>", temp->name))) return; @@ -318,7 +319,7 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir return NULL; } new_semantic.index = index; - if (!(ext_var = hlsl_new_var(ctx, new_name, type, loc, &new_semantic, modifiers, NULL))) + if (!(ext_var = hlsl_new_var(ctx, new_name, type, loc, &new_semantic, modifiers, NULL, false))) { vkd3d_free(new_name); hlsl_cleanup_semantic(&new_semantic); @@ -2518,6 +2519,48 @@ static bool validate_nonconstant_vector_store_derefs(struct hlsl_ctx *ctx, struc return false; }
+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; + + LIST_FOR_EACH_ENTRY(scope, &ctx->scopes, struct hlsl_scope, entry) + { + LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry) + { + if (!var->default_values) + continue; + + component_count = hlsl_type_component_count(var->data_type); + + for (k = 0; k < component_count; ++k) + { + struct hlsl_default_value *def_value = &var->default_values[k]; + struct hlsl_ir_node *node = def_value->src.node; + + if (!node) + continue; + if (node->type == HLSL_IR_CONSTANT) + { + def_value->is_constant = true; + def_value->value = hlsl_ir_constant(node)->value.u[0]; + } + else + { + /* It is hard to know whether this should be an error or a fixme. + * It depends on whether we have the same capabilities for folding constants as + * the native compliler. */ + hlsl_fixme(ctx, &node->loc, + "Lower default value to a constant for variable "%s", component %u.", + var->name, k); + } + hlsl_src_remove(&def_value->src); + } + } + } +} + /* Lower combined samples and sampler variables to synthesized separated textures and samplers. * That is, translate SM1-style samples in the source to SM4-style samples in the bytecode. */ static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) @@ -5465,6 +5508,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry lower_ir(ctx, lower_abs, body); }
+ lower_var_default_values(ctx); lower_ir(ctx, validate_nonconstant_vector_store_derefs, body);
do diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index d5019a5dd..f019208f8 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -3534,6 +3534,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) put_u32(&buffer, 0); /* type */ put_u32(&buffer, 0); /* FIXME: default value */
+ hlsl_dump_var_default_values(var); + if (profile->major_version >= 5) { put_u32(&buffer, 0); /* texture start */ diff --git a/tests/hlsl/default-values.shader_test b/tests/hlsl/default-values.shader_test index 911a683fa..eef0777bd 100644 --- a/tests/hlsl/default-values.shader_test +++ b/tests/hlsl/default-values.shader_test @@ -1,4 +1,4 @@ -[pixel shader todo] +[pixel shader] float2 a = {1, 2}; float4x2 b = {1, 2, 3, 4, 5, 6, 7, 8};
@@ -36,14 +36,14 @@ float4 main() : sv_target }
-[pixel shader todo] +[pixel shader] static const float a = 7; float4 b = {1, 2, a, 4}; // static constant values are allowed on the initializer.
float4 main() : sv_target { return 0; }
-[pixel shader todo] +[pixel shader] float2 a = {1, 2}; float4 b = {3, 5, float2(4, 4)}; // numeric type initializers are allowed.
@@ -53,7 +53,7 @@ float4 main() : sv_target }
-[pixel shader todo] +[pixel shader] struct apple { float3 a[2];
From: Francisco Casas fcasas@codeweavers.com
It is hard to initialize default values on add_assignment() and calling add_assignment() for initializers is not really necessary, we just need the implicit cast. --- libs/vkd3d-shader/hlsl.y | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index cf0f4938e..0de899722 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -2397,34 +2397,33 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
if (v->initializer.args_count) { - if (v->initializer.braces) - { - unsigned int size = initializer_size(&v->initializer); - unsigned int store_index = 0; - unsigned int k; + unsigned int store_index = 0; + unsigned int size, k;
- if (hlsl_type_component_count(type) != size) + if (!v->initializer.braces) + { + if (!(add_implicit_conversion(ctx, v->initializer.instrs, v->initializer.args[0], type, &v->loc))) { - hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, - "Expected %u components in initializer, but got %u.", - hlsl_type_component_count(type), size); free_parse_variable_def(v); continue; }
- for (k = 0; k < v->initializer.args_count; ++k) - { - initialize_var_components(ctx, v->initializer.instrs, var, - &store_index, v->initializer.args[k]); - } + v->initializer.args[0] = node_from_block(v->initializer.instrs); } - else + + size = initializer_size(&v->initializer); + if (hlsl_type_component_count(type) != size) { - struct hlsl_ir_load *load = hlsl_new_var_load(ctx, var, &var->loc); + hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, + "Expected %u components in initializer, but got %u.", + hlsl_type_component_count(type), size); + free_parse_variable_def(v); + continue; + }
- assert(v->initializer.args_count == 1); - hlsl_block_add_instr(v->initializer.instrs, &load->node); - add_assignment(ctx, v->initializer.instrs, &load->node, ASSIGN_OP_ASSIGN, v->initializer.args[0]); + for (k = 0; k < v->initializer.args_count; ++k) + { + initialize_var_components(ctx, v->initializer.instrs, var, &store_index, v->initializer.args[k]); }
if (var->default_values || var->storage_modifiers & HLSL_STORAGE_STATIC)
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/tpf.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index f019208f8..c1d243093 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -3558,6 +3558,34 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) set_u32(&buffer, var_offset, string_offset); write_sm4_type(ctx, &buffer, var->data_type); set_u32(&buffer, var_offset + 4 * sizeof(uint32_t), var->data_type->bytecode_offset); + + if (var->default_values) + { + unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC]; + unsigned int comp_count = hlsl_type_component_count(var->data_type); + unsigned int default_value_offset; + unsigned int k; + + default_value_offset = bytecode_reserve_bytes(&buffer, reg_size * sizeof(uint32_t)); + set_u32(&buffer, var_offset + 5 * sizeof(uint32_t), default_value_offset); + + for (k = 0; k < comp_count; ++k) + { + struct hlsl_type *comp_type = hlsl_type_get_component_type(ctx, var->data_type, k); + unsigned int comp_offset; + enum hlsl_regset regset; + + comp_offset = hlsl_type_get_component_offset(ctx, var->data_type, k, ®set); + if (regset == HLSL_REGSET_NUMERIC) + { + if (comp_type->base_type == HLSL_TYPE_DOUBLE) + hlsl_fixme(ctx, &var->loc, "Write double default values."); + + set_u32(&buffer, default_value_offset + comp_offset * sizeof(uint32_t), + var->default_values[k].value.u); + } + } + } ++j; } }
From: Francisco Casas fcasas@codeweavers.com
--- tests/hlsl/default-values.shader_test | 75 +++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/tests/hlsl/default-values.shader_test b/tests/hlsl/default-values.shader_test index eef0777bd..8723145fe 100644 --- a/tests/hlsl/default-values.shader_test +++ b/tests/hlsl/default-values.shader_test @@ -138,6 +138,81 @@ float4 main() : sv_target return float4(ap.b); }
+ +% For matrices, the values in the default values initializer end up in different components than for +% regular initializers. The values are assigned to the matrix components in Chinese reading order, +% i.e. the components of a whole column are assigned before the next column, unlike regular +% initializers where the components of each row are assigned before the next row. +[pixel shader] +int2x3 m = {1, 2, 3, 4, 5, 6}; +// int2x3 m; // Offset: 0 Size: 40 +// = 0x00000001 0x00000002 0x00000000 0x00000000 +// 0x00000003 0x00000004 0x00000000 0x00000000 +// 0x00000005 0x00000006 + +float4 main() : sv_target +{ + return m[0][0]; +} + + +% The same happens for numeric constructors. +[pixel shader] +int2x3 m = int2x3(1, 2, 3, 4, 5, 6); +// int2x3 m; // Offset: 0 Size: 40 +// = 0x00000001 0x00000002 0x00000000 0x00000000 +// 0x00000003 0x00000004 0x00000000 0x00000000 +// 0x00000005 0x00000006 + +float4 main() : sv_target +{ + return m[0][0]; +} + + +[pixel shader] +cbuffer buff +{ + row_major int2x3 m = {1, 2, 3, 4, 5, 6}; + // row_major int2x3 m; // Offset: 0 Size: 28 + // = 0x00000001 0x00000003 0x00000005 0x00000000 + // 0x00000002 0x00000004 0x00000006 +} + +float4 main() : sv_target +{ + return m[0][0]; +} + + +[pixel shader fail(sm>=6)] +struct +{ + float2 a[2]; + row_major int2x3 b; + float3 c[2]; +} apple = {100, 101, 110, 111, 1, 2, 3, 4, 5, 6, 200, 201, 202, 210, 211, 212}; +// struct +// { +// +// float2 a[2]; // Offset: 0 +// row_major int2x3 b; // Offset: 32 +// float3 c[2]; // Offset: 64 +// +// } apple; // Offset: 0 Size: 92 +// = 0x42c80000 0x42ca0000 0x00000000 0x00000000 +// 0x42dc0000 0x42de0000 0x00000000 0x00000000 +// 0x00000001 0x00000003 0x00000005 0x00000000 +// 0x00000002 0x00000004 0x00000006 0x00000000 +// 0x43480000 0x43490000 0x434a0000 0x00000000 +// 0x43520000 0x43530000 0x43540000 + +float4 main() : sv_target +{ + return float4(apple.c[0], 0); +} + + [require] shader model >= 5.0
From: Francisco Casas fcasas@codeweavers.com
---
Honestly I don't know when this broke, but seems we were only using this function for resources until now that we are writing default values. --- libs/vkd3d-shader/hlsl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 20b463117..35bcc9d97 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -509,12 +509,14 @@ unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_ty
switch (type->class) { - case HLSL_CLASS_SCALAR: case HLSL_CLASS_VECTOR: - case HLSL_CLASS_MATRIX: offset[HLSL_REGSET_NUMERIC] += idx; break;
+ case HLSL_CLASS_MATRIX: + offset[HLSL_REGSET_NUMERIC] += 4 * idx; + break; + case HLSL_CLASS_STRUCT: for (r = 0; r <= HLSL_REGSET_LAST; ++r) offset[r] += type->e.record.fields[idx].reg_offset[r]; @@ -534,6 +536,7 @@ unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_ty assert(idx == 0); break;
+ case HLSL_CLASS_SCALAR: default: vkd3d_unreachable(); }
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); } } }