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