diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index d8653dbf..e5e5eb54 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -794,6 +794,9 @@ static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct f case HLSL_CLASS_MATRIX: case HLSL_CLASS_STRUCT: /* FIXME: write actual initial value */ + if (var->default_values) + hlsl_fixme(fx->ctx, &var->loc, "Write default values.\n"); + offset = put_u32(buffer, 0); for (uint32_t i = 1; i < size / sizeof(uint32_t); ++i) @@ -1010,6 +1013,8 @@ static void write_fx_4_numeric_variable(struct hlsl_ir_var *var, bool shared, st { /* FIXME: write default value */ set_u32(buffer, value_offset, 0); + if (var->default_values) + hlsl_fixme(fx->ctx, &var->loc, "Write default values.\n"); put_u32(buffer, 0); /* Annotations count */ if (has_annotations(var)) diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 99214fba..998d3d2a 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -167,6 +167,8 @@ 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]); + 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); @@ -1247,6 +1249,7 @@ struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const cha list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); else list_add_tail(&ctx->globals->vars, &var->scope_entry); + var->is_synthetic = true; } return var; } @@ -3086,6 +3089,33 @@ 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:", var->name); + for (k = 0; k < component_count; ++k) + { + if (k % 4 == 0) + vkd3d_string_buffer_printf(&buffer, "\n "); + vkd3d_string_buffer_printf(&buffer, " 0x%08x", var->default_values[k].value.u); + } + vkd3d_string_buffer_printf(&buffer, "\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; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index ca648149..0d0d6750 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -396,6 +396,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; @@ -418,6 +426,15 @@ 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 pointer is NULL for others. */ + struct hlsl_default_value + { + /* Default value, in case the component is a numeric value. */ + 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. @@ -460,6 +477,7 @@ struct hlsl_ir_var uint32_t is_uniform : 1; uint32_t is_param : 1; uint32_t is_separated_resource : 1; + uint32_t is_synthetic : 1; }; /* This struct is used to represent assignments in state block entries: @@ -775,13 +793,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; @@ -1249,6 +1261,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); void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body); int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 0b742f12..4da802a0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1286,13 +1286,13 @@ static struct hlsl_block *make_block(struct hlsl_ctx *ctx, struct hlsl_ir_node * return block; } -static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, struct hlsl_block *block, - const struct vkd3d_shader_location *loc) +static union hlsl_constant_value_component evaluate_static_expression(struct hlsl_ctx *ctx, + struct hlsl_block *block, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) { + union hlsl_constant_value_component ret = {0}; struct hlsl_ir_constant *constant; struct hlsl_ir_node *node; struct hlsl_block expr; - unsigned int ret = 0; struct hlsl_src src; LIST_FOR_EACH_ENTRY(node, &block->instrs, struct hlsl_ir_node, entry) @@ -1305,29 +1305,32 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str case HLSL_IR_LOAD: case HLSL_IR_INDEX: continue; + case HLSL_IR_STORE: + if (hlsl_ir_store(node)->lhs.var->is_synthetic) + break; + /* fall-through */ case HLSL_IR_CALL: case HLSL_IR_IF: case HLSL_IR_LOOP: case HLSL_IR_JUMP: case HLSL_IR_RESOURCE_LOAD: case HLSL_IR_RESOURCE_STORE: - case HLSL_IR_STORE: case HLSL_IR_SWITCH: case HLSL_IR_STATEBLOCK_CONSTANT: hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Expected literal expression."); + break; } } if (!hlsl_clone_block(ctx, &expr, &ctx->static_initializers)) - return 0; + return ret; hlsl_block_add_block(&expr, block); - if (!add_implicit_conversion(ctx, &expr, node_from_block(&expr), - hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc)) + if (!add_implicit_conversion(ctx, &expr, node_from_block(&expr), dst_type, loc)) { hlsl_block_cleanup(&expr); - return 0; + return ret; } /* Wrap the node into a src to allow the reference to survive the multiple const passes. */ @@ -1339,7 +1342,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str if (node->type == HLSL_IR_CONSTANT) { constant = hlsl_ir_constant(node); - ret = constant->value.u[0].u; + ret = constant->value.u[0]; } else { @@ -1352,6 +1355,15 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str return ret; } +static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, struct hlsl_block *block, + const struct vkd3d_shader_location *loc) +{ + union hlsl_constant_value_component res; + + res = evaluate_static_expression(ctx, block, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc); + return res.u; +} + static bool expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2) { /* Scalar vars can be converted to pretty much everything */ @@ -2087,12 +2099,27 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i dst_comp_type = hlsl_type_get_component_type(ctx, dst->data_type, *store_index); - if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) - return; + if (dst->default_values) + { + struct hlsl_default_value default_value = {0}; - if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) - return; - hlsl_block_add_block(instrs, &block); + if (!hlsl_clone_block(ctx, &block, instrs)) + return; + default_value.value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); + + dst->default_values[*store_index] = default_value; + + hlsl_block_cleanup(&block); + } + else + { + 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); + } ++*store_index; } @@ -2348,6 +2375,7 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var { struct parse_variable_def *v, *v_next; struct hlsl_block *initializers; + unsigned int component_count; struct hlsl_ir_var *var; struct hlsl_type *type; @@ -2371,6 +2399,7 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var } type = var->data_type; + component_count = hlsl_type_component_count(type); var->state_blocks = v->state_blocks; var->state_block_count = v->state_block_count; @@ -2379,28 +2408,39 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var v->state_block_capacity = 0; v->state_blocks = NULL; - if (var->state_blocks && hlsl_type_component_count(type) != var->state_block_count) + if (var->state_blocks && component_count != var->state_block_count) { hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, - "Expected %u state blocks, but got %u.", - hlsl_type_component_count(type), var->state_block_count); + "Expected %u state blocks, but got %u.", component_count, var->state_block_count); free_parse_variable_def(v); continue; } if (v->initializer.args_count) { + bool is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) + || (var->storage_modifiers & HLSL_STORAGE_UNIFORM); + + if (is_default_values_initializer) + { + assert(!var->default_values); + if (!(var->default_values = hlsl_calloc(ctx, component_count, sizeof(*var->default_values)))) + { + free_parse_variable_def(v); + continue; + } + } + if (v->initializer.braces) { unsigned int size = initializer_size(&v->initializer); unsigned int store_index = 0; unsigned int k; - if (hlsl_type_component_count(type) != size) + if (component_count != size) { 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); + "Expected %u components in initializer, but got %u.", component_count, size); free_parse_variable_def(v); continue; } @@ -2420,10 +2460,18 @@ 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 (is_default_values_initializer) + { + hlsl_dump_var_default_values(var); + } + else if (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); + } } else if (var->storage_modifiers & HLSL_STORAGE_STATIC) { @@ -5718,8 +5766,7 @@ hlsl_prog: | hlsl_prog buffer_declaration buffer_body | hlsl_prog declaration_statement { - if (!list_empty(&$2->instrs)) - hlsl_fixme(ctx, &@2, "Uniform initializer."); + hlsl_block_add_block(&ctx->static_initializers, $2); destroy_block($2); } | hlsl_prog preproc_directive diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index bdb72a1f..9f682edd 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -218,6 +218,14 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, uniform->is_uniform = 1; uniform->is_param = temp->is_param; uniform->buffer = temp->buffer; + if (temp->default_values) + { + /* Transfer default values from the temp to the uniform. */ + assert(!uniform->default_values); + assert(hlsl_type_component_count(temp->data_type) == hlsl_type_component_count(uniform->data_type)); + uniform->default_values = temp->default_values; + temp->default_values = NULL; + } if (!(new_name = hlsl_sprintf_alloc(ctx, "", temp->name))) return; diff --git a/tests/hlsl/default-values.shader_test b/tests/hlsl/default-values.shader_test index 0427f659..f7590b5d 100644 --- a/tests/hlsl/default-values.shader_test +++ b/tests/hlsl/default-values.shader_test @@ -1,7 +1,7 @@ % Note that, except for effects, default values do not affect the execution. % The default values are intended to be obtained using reflection. -[pixel shader todo] +[pixel shader] float2 a = {1, 2}; float4x2 b = {1, 2, 3, 4, 5, 6, 7, 8}; @@ -17,7 +17,7 @@ if(sm<4) uniform 8 float4 10 20 0 0 if(sm>=4) uniform 0 float4 10 20 0 0 if(sm>=4) uniform 4 float4 10 30 50 70 if(sm>=4) uniform 8 float4 20 40 60 80 -todo(sm<6) draw quad +todo(glsl) draw quad probe all rgba (10, 20, 50, 60) @@ -28,7 +28,7 @@ float4 b = a; // initial value must be a literal expression. float4 main() : sv_target { return 0; } -[pixel shader fail(sm<6) todo] +[pixel shader fail(sm<6)] float a = 7; float4 b = {1, 2, a, 4}; // initial value must be a literal expression. @@ -49,7 +49,7 @@ 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. @@ -57,11 +57,11 @@ float4 main() : sv_target { return b; } [test] uniform 0 float4 10.0 20.0 30.0 40.0 -todo(sm<6) draw quad +todo(glsl) draw quad probe all rgba (10, 20, 30, 40) -[pixel shader todo] +[pixel shader] float4 a = {3, 5, float2(4, 4)}; // numeric type initializers are allowed. float4 main() : sv_target @@ -71,11 +71,11 @@ float4 main() : sv_target [test] uniform 0 float4 10.0 20.0 30.0 40.0 -todo(sm<6) draw quad +todo(glsl) draw quad probe all rgba (20, 40, 60, 80) -[pixel shader todo] +[pixel shader] int4 a[2] = {10, 20, float3x2(1, 2, 3, 4, 5, 6)}; // matrix numeric type initializers are allowed. float4 main() : sv_target @@ -88,11 +88,11 @@ if(sm<4) uniform 0 float4 10 20 30 40 if(sm<4) uniform 4 float4 50 60 70 80 if(sm>=4) uniform 0 int4 10 20 30 40 if(sm>=4) uniform 4 int4 50 60 70 80 -todo(sm<6) draw quad +todo(glsl) draw quad probe all rgba (100, 120, 140, 160) -[pixel shader todo] +[pixel shader] struct apple { float3 a[2]; @@ -111,7 +111,7 @@ if(sm<4) uniform 8 float4 70 90 0 0 if(sm<4) uniform 12 float4 80 100 0 0 if(sm>=4) uniform 8 int4 70 90 0 0 if(sm>=4) uniform 12 int4 80 100 0 0 -todo(sm<6) draw quad +todo(glsl) draw quad probe all rgba (70, 80, 90, 100) @@ -148,7 +148,7 @@ cbuffer buff float4 main() : sv_target { return 0; } -[pixel shader fail(sm<6) todo] +[pixel shader fail(sm<6)] cbuffer buff { float a = 7; @@ -236,7 +236,7 @@ float4 main() : sv_target } -[pixel shader todo] +[pixel shader] static const float3x2 mat = {10, 20, 30, 40, 50, 60}; static const float4 array[2] = {1, 2, 3, 4, 5, 6, 7, 8}; static const int idx = 1; diff --git a/tests/hlsl/strings.shader_test b/tests/hlsl/strings.shader_test index a0cdcd48..6954ef20 100644 --- a/tests/hlsl/strings.shader_test +++ b/tests/hlsl/strings.shader_test @@ -8,7 +8,7 @@ float4 main() : sv_target return 0; } -[pixel shader todo] +[pixel shader] typedef float4 sTring; sTring var = float4(1, 2, 3, 4);