From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 86 ++++++++++++++++++++++++--- libs/vkd3d-shader/hlsl.h | 32 +++++++--- libs/vkd3d-shader/hlsl.y | 34 ++++++++--- libs/vkd3d-shader/hlsl_codegen.c | 49 ++++++++++++++- libs/vkd3d-shader/tpf.c | 2 + tests/hlsl/default-values.shader_test | 8 +-- 6 files changed, 181 insertions(+), 30 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index ed80e2b75..075eccf8a 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); @@ -1120,6 +1129,26 @@ struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct return var; }
+bool hlsl_init_var_default_values(struct hlsl_ctx *ctx, struct hlsl_ir_var *var) +{ + unsigned int component_count = hlsl_type_component_count(var->data_type); + + assert(!var->default_values); + if (!(var->default_values = hlsl_calloc(ctx, component_count, sizeof(*var->default_values)))) + return false; + return true; +} + +void hlsl_transfer_var_default_values(struct hlsl_ir_var *dst, struct hlsl_ir_var *src) +{ + assert(src->default_values); + assert(!dst->default_values); + assert(hlsl_type_component_count(src->data_type) == hlsl_type_component_count(dst->data_type)); + dst->default_values = 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) { @@ -2986,6 +3015,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 +3793,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 +3816,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..2969d5c35 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); @@ -1374,6 +1390,8 @@ struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned 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); +bool hlsl_init_var_default_values(struct hlsl_ctx *ctx, struct hlsl_ir_var *var); +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..563577e3d 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -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; } @@ -2254,7 +2261,8 @@ 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))) + if (!(var = hlsl_new_var(ctx, var_name, type, &v->loc, &new_semantic, modifiers, + &v->reg_reservation))) { hlsl_cleanup_semantic(&new_semantic); vkd3d_free(var_name); @@ -2385,6 +2393,18 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
if (v->initializer.args_count) { + bool save_default_values = (ctx->cur_buffer != ctx->globals_buffer) + || (var->storage_modifiers & HLSL_STORAGE_UNIFORM); + + if (save_default_values) + { + if (!(hlsl_init_var_default_values(ctx, var))) + { + free_parse_variable_def(v); + continue; + } + } + if (v->initializer.braces) { unsigned int size = initializer_size(&v->initializer); @@ -2415,7 +2435,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 +5656,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..96d24cc8f 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -210,14 +210,16 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, /* Use the synthetic name for the temp, rather than the uniform, so that we * 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))) + if (!(uniform = hlsl_new_var(ctx, temp->name, temp->data_type, &temp->loc, NULL, + temp->storage_modifiers, &temp->reg_reservation))) 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; + if (temp->default_values) + hlsl_transfer_var_default_values(uniform, temp);
if (!(new_name = hlsl_sprintf_alloc(ctx, "<temp-%s>", temp->name))) return; @@ -2518,6 +2520,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 +5509,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];