diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index 61437c59..6b71f354 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -2255,7 +2255,7 @@ static unsigned int decompose_fx_4_state_function_call(struct hlsl_ir_var *var, const struct function_component *comp = &components[i]; unsigned int arg_index = (i + 1) % entry->args_count; block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, comp->name, - comp->lhs_has_index, comp->lhs_index, arg_index); + comp->lhs_has_index, comp->lhs_index, true, arg_index); } hlsl_free_state_block_entry(entry); @@ -2301,7 +2301,7 @@ static unsigned int decompose_fx_4_state_block_expand_array(struct hlsl_ir_var * for (i = 1; i < array_size; ++i) { block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, - entry->name, true, i, 0); + entry->name, true, i, true, 0); } return array_size; diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index f4401bc5..ce3dd91f 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1907,6 +1907,59 @@ struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_ty return &compile->node; } +bool hlsl_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; +} + +struct hlsl_ir_node *hlsl_new_sampler_state(struct hlsl_ctx *ctx, + const struct hlsl_state_block *state_block, struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_sampler_state *sampler_state; + struct hlsl_type *type = ctx->builtin_types.sampler[HLSL_SAMPLER_DIM_GENERIC]; + + if (!(sampler_state = hlsl_alloc(ctx, sizeof(*sampler_state)))) + return NULL; + + init_node(&sampler_state->node, HLSL_IR_SAMPLER_STATE, type, loc); + + if (!(sampler_state->state_block = hlsl_alloc(ctx, sizeof(*sampler_state->state_block)))) + { + vkd3d_free(sampler_state); + return NULL; + } + + if (state_block) + { + for (unsigned int i = 0; i < state_block->count; ++i) + { + const struct hlsl_state_block_entry *src = state_block->entries[i]; + struct hlsl_state_block_entry *entry; + + if (!(entry = clone_stateblock_entry(ctx, src, src->name, src->lhs_has_index, src->lhs_index, false, 0))) + { + hlsl_free_instr(&sampler_state->node); + return NULL; + } + + if (!hlsl_state_block_add_entry(sampler_state->state_block, entry)) + { + hlsl_free_instr(&sampler_state->node); + return NULL; + } + } + } + + return &sampler_state->node; +} + struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, struct vkd3d_shader_location *loc) { @@ -2295,6 +2348,13 @@ static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, return node; } +static struct hlsl_ir_node *clone_sampler_state(struct hlsl_ctx *ctx, + struct clone_instr_map *map, struct hlsl_ir_sampler_state *sampler_state) +{ + return hlsl_new_sampler_state(ctx, sampler_state->state_block, + &sampler_state->node.loc); +} + static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant) { @@ -2302,8 +2362,8 @@ static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, } struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, - struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, - unsigned int lhs_index, unsigned int arg_index) + const struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, + unsigned int lhs_index, bool single_arg, unsigned int arg_index) { struct hlsl_state_block_entry *entry; struct clone_instr_map map = { 0 }; @@ -2319,7 +2379,11 @@ struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, return NULL; } - entry->args_count = 1; + if (single_arg) + entry->args_count = 1; + else + entry->args_count = src->args_count; + if (!(entry->args = hlsl_alloc(ctx, sizeof(*entry->args) * entry->args_count))) { hlsl_free_state_block_entry(entry); @@ -2332,7 +2396,16 @@ struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, hlsl_free_state_block_entry(entry); return NULL; } - clone_src(&map, entry->args, &src->args[arg_index]); + + if (single_arg) + { + clone_src(&map, entry->args, &src->args[arg_index]); + } + else + { + for (unsigned int i = 0; i < src->args_count; ++i) + clone_src(&map, &entry->args[i], &src->args[i]); + } vkd3d_free(map.instrs); return entry; @@ -2440,6 +2513,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, case HLSL_IR_COMPILE: return clone_compile(ctx, map, hlsl_ir_compile(instr)); + case HLSL_IR_SAMPLER_STATE: + return clone_sampler_state(ctx, map, hlsl_ir_sampler_state(instr)); + case HLSL_IR_STATEBLOCK_CONSTANT: return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); } @@ -2860,6 +2936,7 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", [HLSL_IR_COMPILE] = "HLSL_IR_COMPILE", + [HLSL_IR_SAMPLER_STATE] = "HLSL_IR_SAMPLER_STATE", [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", }; @@ -3337,6 +3414,12 @@ static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *bu vkd3d_string_buffer_printf(buffer, ")"); } +static void dump_ir_sampler_state(struct vkd3d_string_buffer *buffer, + const struct hlsl_ir_sampler_state *sampler_state) +{ + vkd3d_string_buffer_printf(buffer, "sampler_state {...}"); +} + static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_stateblock_constant *constant) { @@ -3440,6 +3523,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, dump_ir_compile(ctx, buffer, hlsl_ir_compile(instr)); break; + case HLSL_IR_SAMPLER_STATE: + dump_ir_sampler_state(buffer, hlsl_ir_sampler_state(instr)); + break; + case HLSL_IR_STATEBLOCK_CONSTANT: dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); break; @@ -3665,6 +3752,13 @@ static void free_ir_compile(struct hlsl_ir_compile *compile) vkd3d_free(compile); } +static void free_ir_sampler_state(struct hlsl_ir_sampler_state *sampler_state) +{ + if (sampler_state->state_block) + hlsl_free_state_block(sampler_state->state_block); + vkd3d_free(sampler_state); +} + static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant) { vkd3d_free(constant->name); @@ -3737,6 +3831,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) free_ir_compile(hlsl_ir_compile(node)); break; + case HLSL_IR_SAMPLER_STATE: + free_ir_sampler_state(hlsl_ir_sampler_state(node)); + break; + case HLSL_IR_STATEBLOCK_CONSTANT: free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node)); break; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 08313f64..066e0457 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -326,6 +326,7 @@ enum hlsl_ir_node_type HLSL_IR_SWITCH, HLSL_IR_COMPILE, + HLSL_IR_SAMPLER_STATE, HLSL_IR_STATEBLOCK_CONSTANT, }; @@ -899,6 +900,14 @@ struct hlsl_ir_compile unsigned int args_count; }; +/* Represents a state block initialized with the "sampler_state" keyword. */ +struct hlsl_ir_sampler_state +{ + struct hlsl_ir_node node; + + struct hlsl_state_block *state_block; +}; + /* Stateblock constants are undeclared values found on state blocks or technique passes descriptions, * that do not concern regular pixel, vertex, or compute shaders, except for parsing. */ struct hlsl_ir_stateblock_constant @@ -1212,6 +1221,12 @@ static inline struct hlsl_ir_compile *hlsl_ir_compile(const struct hlsl_ir_node return CONTAINING_RECORD(node, struct hlsl_ir_compile, node); } +static inline struct hlsl_ir_sampler_state *hlsl_ir_sampler_state(const struct hlsl_ir_node *node) +{ + VKD3D_ASSERT(node->type == HLSL_IR_SAMPLER_STATE); + return CONTAINING_RECORD(node, struct hlsl_ir_sampler_state, node); +}; + static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(const struct hlsl_ir_node *node) { VKD3D_ASSERT(node->type == HLSL_IR_STATEBLOCK_CONSTANT); @@ -1396,11 +1411,13 @@ bool hlsl_clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block, const 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); +bool hlsl_state_block_add_entry(struct hlsl_state_block *state_block, + struct hlsl_state_block_entry *entry); bool hlsl_validate_state_block_entry(struct hlsl_ctx *ctx, struct hlsl_state_block_entry *entry, const struct vkd3d_shader_location *loc); struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, - struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, - unsigned int lhs_index, unsigned int arg_index); + const struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, + unsigned int lhs_index, bool single_arg, unsigned int arg_index); void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *body); void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body); @@ -1510,6 +1527,8 @@ struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, struct hlsl_struct_field *fields, size_t field_count); struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned int components, struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_new_sampler_state(struct hlsl_ctx *ctx, + const struct hlsl_state_block *state_block, struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_string_constant(struct hlsl_ctx *ctx, const char *str, diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index f5a9816c..b4d9f098 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -437,6 +437,9 @@ static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct if (hlsl_types_are_equal(src_type, dst_type)) return node; + if (node->type == HLSL_IR_SAMPLER_STATE && dst_type->class == HLSL_CLASS_SAMPLER) + return node; + if (!implicit_compatible_data_types(ctx, src_type, dst_type)) { struct vkd3d_string_buffer *src_string, *dst_string; @@ -613,6 +616,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx case HLSL_IR_COMPILE: case HLSL_IR_CONSTANT: case HLSL_IR_EXPR: + case HLSL_IR_SAMPLER_STATE: case HLSL_IR_STRING_CONSTANT: case HLSL_IR_SWIZZLE: case HLSL_IR_LOAD: @@ -2352,7 +2356,7 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i if (hlsl_is_numeric_type(dst_comp_type)) { - if (src->type == HLSL_IR_COMPILE) + if (src->type == HLSL_IR_COMPILE || src->type == HLSL_IR_SAMPLER_STATE) { /* Default values are discarded if they contain an object * literal expression for a numeric component. */ @@ -2380,12 +2384,41 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i } else { - if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) - return; + if (src->type == HLSL_IR_SAMPLER_STATE) + { + /* Sampler states end up in the variable's state_blocks instead of + * being used to initialize its value. */ + struct hlsl_ir_sampler_state *sampler_state = hlsl_ir_sampler_state(src); - if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) - return; - hlsl_block_add_block(instrs, &block); + if (dst_comp_type->class != HLSL_CLASS_SAMPLER) + { + struct vkd3d_string_buffer *dst_string; + + dst_string = hlsl_type_to_string(ctx, dst_comp_type); + if (dst_string) + hlsl_error(ctx, &src->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Cannot assign sampler_state to %s.", dst_string->buffer); + hlsl_release_string_buffer(ctx, dst_string); + return; + } + + if (!hlsl_array_reserve(ctx, (void **)&dst->state_blocks, &dst->state_block_capacity, + dst->state_block_count + 1, sizeof(*dst->state_blocks))) + return; + + dst->state_blocks[dst->state_block_count] = sampler_state->state_block; + sampler_state->state_block = NULL; + ++dst->state_block_count; + } + 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; @@ -2724,6 +2757,8 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) || (var->storage_modifiers & HLSL_STORAGE_UNIFORM) || ctx->cur_scope->annotations; + if (hlsl_get_multiarray_element_type(type)->class == HLSL_CLASS_SAMPLER) + is_default_values_initializer = false; if (hlsl_type_is_shader(type)) is_default_values_initializer = false; @@ -2782,6 +2817,9 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var { hlsl_block_add_block(initializers, v->initializer.instrs); } + + if (var->state_blocks) + TRACE("Variable %s has %u state blocks.\n", var->name, var->state_block_count); } else if (var->storage_modifiers & HLSL_STORAGE_STATIC) { @@ -6174,16 +6212,6 @@ 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 @@ -7858,7 +7886,7 @@ state_block: vkd3d_free($5.args); $$ = $1; - state_block_add_entry($$, entry); + hlsl_state_block_add_entry($$, entry); } | state_block any_identifier '(' func_arguments ')' ';' { @@ -7886,7 +7914,7 @@ state_block: hlsl_validate_state_block_entry(ctx, entry, &@4); $$ = $1; - state_block_add_entry($$, entry); + hlsl_state_block_add_entry($$, entry); } state_block_list: @@ -8619,6 +8647,25 @@ primary_expr: } vkd3d_free($1); } + | KW_SAMPLER_STATE '{' state_block_start state_block '}' + { + struct hlsl_ir_node *sampler_state; + ctx->in_state_block = 0; + + if (!ctx->in_state_block && ctx->cur_scope != ctx->globals) + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE, + "sampler_state must be in global scope or a state block."); + + if (!(sampler_state = hlsl_new_sampler_state(ctx, $4, &@1))) + { + hlsl_free_state_block($4); + YYABORT; + } + hlsl_free_state_block($4); + + if (!($$ = make_block(ctx, sampler_state))) + YYABORT; + } | NEW_IDENTIFIER { if (ctx->in_state_block) diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 79482755..c5dd5e71 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4062,6 +4062,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) case HLSL_IR_RESOURCE_LOAD: case HLSL_IR_STRING_CONSTANT: case HLSL_IR_SWIZZLE: + case HLSL_IR_SAMPLER_STATE: if (list_empty(&instr->uses)) { list_remove(&instr->entry); @@ -4344,7 +4345,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop case HLSL_IR_STRING_CONSTANT: break; case HLSL_IR_COMPILE: - /* Compile calls are skipped as they are only relevent to effects. */ + case HLSL_IR_SAMPLER_STATE: + /* These types are skipped as they are only relevant to effects. */ break; } } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 8c53be49..a3535c08 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -161,6 +161,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT = 5036, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE = 5037, VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING = 5038, + VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE = 5039, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, diff --git a/tests/hlsl/sampler-state.shader_test b/tests/hlsl/sampler-state.shader_test index 77a26d66..595f617f 100644 --- a/tests/hlsl/sampler-state.shader_test +++ b/tests/hlsl/sampler-state.shader_test @@ -2,7 +2,7 @@ options: backcompat -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] sampler2D sam = sampler_state { texture = NULL; @@ -54,7 +54,7 @@ float4 main(): sv_target } -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] sampler sam[2] = { sampler_state @@ -88,7 +88,7 @@ sampler sam[2] = float4 main(): sv_target { return 0; } -[pixel shader todo] +[pixel shader] sampler sam { FOO = sampler_state {}; @@ -106,7 +106,7 @@ float4 main(): sv_target } -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] sampler sam = sampler_state { texture = NULL; @@ -121,7 +121,7 @@ float4 main(): sv_target } -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] sampler sam = sampler_state { foo = BAR; @@ -135,7 +135,7 @@ float4 main(): sv_target } -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] // default value initializers make it more permissive but if types don't match // then the whole initializer is discarded. float4 f = { @@ -208,7 +208,7 @@ float4 main(): sv_target shader model >= 5.0 options: backcompat -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] // Default values and sample_state work. // Requires sm5.