From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 39 ++++++++++++ libs/vkd3d-shader/hlsl.h | 37 +++++++++++ libs/vkd3d-shader/hlsl.y | 77 ++++++++++++++++++++--- tests/hlsl/state-block-syntax.shader_test | 2 +- 4 files changed, 147 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index cba954c98..20213504e 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); }
@@ -3645,6 +3670,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 64111f3fc..0f6f0102a 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -422,6 +422,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. */ @@ -457,6 +461,38 @@ struct hlsl_ir_var uint32_t is_separated_resource : 1; };
+/* This struct is used to represent assignments in state block entries: + * name = {args[0], args[1], ...}; + * - or - + * name = args[0] + * - or - + * name[lhs_index] = args[0] + * - or - + * name[lhs_index] = {args[0], args[1], ...}; + */ +struct hlsl_state_block_entry +{ + /* For assignments, the name in the lhs. */ + char *name; + + /* Whether the lhs in the assignment is indexed and, in that case, its index. */ + bool lhs_has_index; + unsigned int lhs_index; + + /* Instructions present in the rhs. */ + struct hlsl_block *instrs; + + /* For assignments, arguments of the rhs initializer. */ + struct hlsl_ir_node **args; + unsigned int args_count; +}; + +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 +1243,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 52c217654..7f7dd6e41 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 @@ -114,6 +116,12 @@ struct parse_attribute_list const struct hlsl_attribute **attrs; };
+struct state_block_index +{ + bool has_index; + unsigned int index; +}; + }
%code provides @@ -931,6 +939,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); }
@@ -2355,6 +2365,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) @@ -5288,6 +5301,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 @@ -5328,6 +5351,8 @@ 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; + struct state_block_index state_block_index; }
%token KW_BLENDSTATE @@ -5528,6 +5553,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type <name> var_identifier %type <name> name_opt
+ %type <parameter> parameter
%type <parameters> param_list @@ -5540,6 +5566,10 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim,
%type <semantic> semantic
+%type <state_block> state_block + +%type <state_block_index> state_block_index_opt + %type <switch_case> switch_case
%type <type> field_type @@ -6684,22 +6714,54 @@ variable_decl: $$->reg_reservation = $3.reg_reservation; }
-state: - any_identifier '=' expr ';' +state_block_start: + %empty { - vkd3d_free($1); - destroy_block($3); + ctx->in_state_block = 1; }
-state_block_start: +state_block_index_opt: %empty { - ctx->in_state_block = 1; + $$.has_index = false; + $$.index = 0; } + | '[' C_INTEGER ']' + { + if ($2 < 0) + { + hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, + "State block array index is not a positive integer constant."); + YYABORT; + } + $$.has_index = true; + $$.index = $2; + }
state_block: %empty - | state_block state + { + if (!($$ = hlsl_alloc(ctx, sizeof(*$$)))) + YYABORT; + } + | state_block any_identifier state_block_index_opt '=' complex_initializer ';' + { + struct hlsl_state_block_entry *entry; + + if (!(entry = hlsl_alloc(ctx, sizeof(*entry)))) + YYABORT; + + entry->name = $2; + entry->lhs_has_index = $3.has_index; + entry->lhs_index = $3.index; + + entry->instrs = $5.instrs; + entry->args = $5.args; + entry->args_count = $5.args_count; + + $$ = $1; + state_block_add_entry($$, entry); + }
variable_def: variable_decl @@ -6711,6 +6773,7 @@ variable_def: | variable_decl '{' state_block_start state_block '}' { $$ = $1; + $$->state_block = $4; ctx->in_state_block = 0; }
diff --git a/tests/hlsl/state-block-syntax.shader_test b/tests/hlsl/state-block-syntax.shader_test index b1071c908..7521516b9 100644 --- a/tests/hlsl/state-block-syntax.shader_test +++ b/tests/hlsl/state-block-syntax.shader_test @@ -380,7 +380,7 @@ float4 main() : sv_target { return 0; }
% State block entries may have indexes. -[pixel shader todo] +[pixel shader] sampler sam { dogs[3] = 5;