diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index da6f29f1..3b93c690 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); } @@ -3659,6 +3684,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 fc96488c..b53bcbd7 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,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 { @@ -1216,6 +1252,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 3959ff84..28347b4a 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); } @@ -2347,6 +2357,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) @@ -5252,6 +5265,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 @@ -5292,6 +5315,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 @@ -5493,6 +5518,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type var_identifier %type name_opt + %type parameter %type param_list @@ -5505,6 +5531,10 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type semantic +%type state_block + +%type state_block_index_opt + %type switch_case %type field_type @@ -6649,22 +6679,54 @@ variable_decl: $$->reg_reservation = $3.reg_reservation; } -state: - any_identifier '=' expr ';' - { - vkd3d_free($1); - destroy_block($3); - } - state_block_start: %empty { ctx->in_state_block = 1; } +state_block_index_opt: + %empty + { + $$.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 @@ -6676,6 +6738,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 b1071c90..7521516b 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;