From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 39 +++++++++++++++++ libs/vkd3d-shader/hlsl.h | 47 ++++++++++++++++++++ libs/vkd3d-shader/hlsl.y | 75 ++++++++++++++++++++++++++++---- tests/hlsl/fx-syntax.shader_test | 2 +- 4 files changed, 154 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 73f01eb9f..b45b3b9a8 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -134,6 +134,26 @@ struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name) return hlsl_get_var(scope->upper, name); }
+static void free_state_block_entry(struct hlsl_state_block_entry *entry) +{ + vkd3d_free(entry->name); + vkd3d_free(entry->args); + hlsl_block_cleanup(entry->instrs); + vkd3d_free(entry->instrs); + vkd3d_free(entry); +} + +void hlsl_free_state_block(struct hlsl_state_block *state_block) +{ + unsigned int k; + + assert(state_block); + for (k = 0; k < state_block->count; ++k) + free_state_block_entry(state_block->entries[k]); + vkd3d_free(state_block->entries); + vkd3d_free(state_block); +} + void hlsl_free_var(struct hlsl_ir_var *decl) { unsigned int k; @@ -142,6 +162,11 @@ void hlsl_free_var(struct hlsl_ir_var *decl) hlsl_cleanup_semantic(&decl->semantic); for (k = 0; k <= HLSL_REGSET_LAST_OBJECT; ++k) vkd3d_free((void *)decl->objects_usage[k]); + if (decl->state_block) + { + hlsl_free_state_block(decl->state_block); + decl->state_block = NULL; + } vkd3d_free(decl); }
@@ -3639,6 +3664,20 @@ static void hlsl_ctx_cleanup(struct hlsl_ctx *ctx)
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) + { + LIST_FOR_EACH_ENTRY_SAFE(var, next_var, &scope->vars, struct hlsl_ir_var, scope_entry) + { + if (var->state_block) + { + hlsl_free_state_block(var->state_block); + var->state_block = NULL; + } + } + } + LIST_FOR_EACH_ENTRY_SAFE(scope, next_scope, &ctx->scopes, struct hlsl_scope, entry) { LIST_FOR_EACH_ENTRY_SAFE(var, next_var, &scope->vars, struct hlsl_ir_var, scope_entry) diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 85e080ccb..8b47453b4 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -423,6 +423,10 @@ struct hlsl_ir_var /* Scope that contains annotations for this variable. */ struct hlsl_scope *annotations;
+ /* The state block on the variable's declaration, if any. + * These are only really used for effect profiles. */ + struct hlsl_state_block *state_block; + /* Indexes of the IR instructions where the variable is first written and last read (liveness * range). The IR instructions are numerated starting from 2, because 0 means unused, and 1 * means function entry. */ @@ -458,6 +462,48 @@ struct hlsl_ir_var uint32_t is_separated_resource : 1; };
+/* This struct is used to represent the two main types of state block entries: + * Assignment: + * name = {args[0], args[1], ...}; + * - or - + * name = args[0] + * - or - + * name[lhs_array_size] = args[0] + * - or - + * name[lhs_array_size] = {args[0], args[1], ...}; + * FX function call: + * name(args[0], args[1], ...); + */ +struct hlsl_state_block_entry +{ + bool is_function_call; + + /* For assignments, the name in the lhs. For function calls, the name of the function. */ + char *name; + + /* Whether the lhs in an assignment is an array and, in that case, its size. */ + bool lhs_is_array; + unsigned int lhs_array_size; + + /* For assignments, instructions present in the rhs. For function calls, instructions present + * in the function arguments. */ + struct hlsl_block *instrs; + + /* For assignments, arguments of the rhs initializer. For function calls, the function + * arguments. */ + struct hlsl_ir_node **args; + unsigned int args_count; + + /* For assignments, whether the rhs is wrapped in braces or not. */ + bool rhs_braces; +}; + +struct hlsl_state_block +{ + struct hlsl_state_block_entry **entries; + size_t count, capacity; +}; + /* Sized array of variables representing a function's parameters. */ struct hlsl_func_parameters { @@ -1207,6 +1253,7 @@ void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new); void hlsl_free_attribute(struct hlsl_attribute *attr); void hlsl_free_instr(struct hlsl_ir_node *node); void hlsl_free_instr_list(struct list *list); +void hlsl_free_state_block(struct hlsl_state_block *state_block); void hlsl_free_type(struct hlsl_type *type); void hlsl_free_var(struct hlsl_ir_var *decl);
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ec8b3d22a..d4646a365 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -77,6 +77,8 @@ struct parse_variable_def struct hlsl_type *basic_type; uint32_t modifiers; struct vkd3d_shader_location modifiers_loc; + + struct hlsl_state_block *state_block; };
struct parse_function @@ -925,6 +927,8 @@ static void free_parse_variable_def(struct parse_variable_def *v) vkd3d_free(v->arrays.sizes); vkd3d_free(v->name); hlsl_cleanup_semantic(&v->semantic); + if (v->state_block) + hlsl_free_state_block(v->state_block); vkd3d_free(v); }
@@ -2349,6 +2353,9 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var free_parse_variable_def(v); continue; } + + var->state_block = v->state_block; + v->state_block = NULL; type = var->data_type;
if (v->initializer.args_count) @@ -5282,6 +5289,16 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, hlsl_release_string_buffer(ctx, string); }
+static bool state_block_add_entry(struct hlsl_state_block *state_block, struct hlsl_state_block_entry *entry) +{ + if (!vkd3d_array_reserve((void **)&state_block->entries, &state_block->capacity, state_block->count + 1, + sizeof(*state_block->entries))) + return false; + + state_block->entries[state_block->count++] = entry; + return true; +} + }
%locations @@ -5322,6 +5339,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct parse_attribute_list attr_list; struct hlsl_ir_switch_case *switch_case; struct hlsl_scope *scope; + struct hlsl_state_block *state_block; }
%token KW_BLENDSTATE @@ -5549,6 +5567,8 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type <variable_def> variable_def %type <variable_def> variable_def_typed
+%type <state_block> state_block + %%
hlsl_prog: @@ -6678,13 +6698,6 @@ variable_decl: $$->reg_reservation = $3.reg_reservation; }
-state: - any_identifier '=' expr ';' - { - vkd3d_free($1); - destroy_block($3); - } - state_block_start: %empty { @@ -6693,7 +6706,52 @@ state_block_start:
state_block: %empty - | state_block state + { + if (!($$ = hlsl_alloc(ctx, sizeof(*$$)))) + YYABORT; + } + | state_block any_identifier '[' C_INTEGER ']' '=' complex_initializer ';' + { + struct hlsl_state_block_entry *entry; + + if (!(entry = hlsl_alloc(ctx, sizeof(*entry)))) + YYABORT; + + entry->is_function_call = false; + + entry->name = $2; + entry->lhs_is_array = true; + entry->lhs_array_size = $4; + + entry->instrs = $7.instrs; + entry->args = $7.args; + entry->args_count = $7.args_count; + entry->rhs_braces = $7.braces; + + $$ = $1; + state_block_add_entry($$, entry); + } + | state_block any_identifier '=' complex_initializer ';' + { + struct hlsl_state_block_entry *entry; + + if (!(entry = hlsl_alloc(ctx, sizeof(*entry)))) + YYABORT; + + entry->is_function_call = false; + + entry->name = $2; + entry->lhs_is_array = false; + entry->lhs_array_size = 0; + + entry->instrs = $4.instrs; + entry->args = $4.args; + entry->args_count = $4.args_count; + entry->rhs_braces = $4.braces; + + $$ = $1; + state_block_add_entry($$, entry); + }
variable_def: variable_decl @@ -6705,6 +6763,7 @@ variable_def: | variable_decl '{' state_block_start state_block '}' { $$ = $1; + $$->state_block = $4; ctx->in_state_block = 0; }
diff --git a/tests/hlsl/fx-syntax.shader_test b/tests/hlsl/fx-syntax.shader_test index 9e8a78aa6..821735f2a 100644 --- a/tests/hlsl/fx-syntax.shader_test +++ b/tests/hlsl/fx-syntax.shader_test @@ -143,7 +143,7 @@ float4 main() : sv_target { return 0; }
% State blocks are valid for numeric types. -[pixel shader todo] +[pixel shader] float f { MaxAnisotropy = 3;