From 45f18a7838551b57425346d7c3f52adb0fa9bdbe Mon Sep 17 00:00:00 2001 From: Francisco Casas Date: Mon, 24 Jun 2024 17:30:46 -0400 Subject: [PATCH] vkd3d-shader/hlsl: Parse the shader 'compile' syntax. The hlsl_ir_compile node is introduced to represent the "compile" syntax, and later the CompileShader() and ConstructGSWithSO() constructs. It basically represents a function call that remembers its arguments using hlsl_srcs and keeps its own instruction block, which is discarded when working on non-effect shaders. For shader compilations it can be asserted that args_count is 1, and that this argument (and the last node in hlsl_ir_effect_call.instrs) is a regular hlsl_ir_call pointing to the declaration of the function to be compiled. --- libs/vkd3d-shader/hlsl.c | 167 ++++++++++++++++++++++ libs/vkd3d-shader/hlsl.h | 33 +++++ libs/vkd3d-shader/hlsl.y | 169 +++++++++++++++++------ libs/vkd3d-shader/hlsl_codegen.c | 4 + libs/vkd3d-shader/vkd3d_shader_private.h | 2 + tests/hlsl/effect-compile.shader_test | 10 +- 6 files changed, 339 insertions(+), 46 deletions(-) diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 7a924183..856c356e 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -254,6 +254,45 @@ bool hlsl_type_is_resource(const struct hlsl_type *type) } } +bool hlsl_type_is_shader(const struct hlsl_type *type) +{ + switch (type->class) + { + case HLSL_CLASS_ARRAY: + return hlsl_type_is_shader(type->e.array.type); + + case HLSL_CLASS_COMPUTE_SHADER: + case HLSL_CLASS_DOMAIN_SHADER: + case HLSL_CLASS_GEOMETRY_SHADER: + case HLSL_CLASS_HULL_SHADER: + case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_VERTEX_SHADER: + return true; + + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_VECTOR: + case HLSL_CLASS_MATRIX: + case HLSL_CLASS_STRUCT: + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: + case HLSL_CLASS_PASS: + case HLSL_CLASS_RASTERIZER_STATE: + case HLSL_CLASS_RENDER_TARGET_VIEW: + case HLSL_CLASS_SAMPLER: + case HLSL_CLASS_STRING: + case HLSL_CLASS_TECHNIQUE: + case HLSL_CLASS_TEXTURE: + case HLSL_CLASS_UAV: + case HLSL_CLASS_CONSTANT_BUFFER: + case HLSL_CLASS_BLEND_STATE: + case HLSL_CLASS_VOID: + case HLSL_CLASS_NULL: + return false; + } + return false; +} + /* Only intended to be used for derefs (after copies have been lowered to components or vectors) or * resources, since for both their data types span across a single regset. */ static enum hlsl_regset type_get_regset(const struct hlsl_type *type) @@ -1808,6 +1847,54 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned return &swizzle->node; } +struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name, + struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs, + const struct vkd3d_shader_location *loc) +{ + const struct hlsl_profile_info *profile_info = NULL; + struct hlsl_ir_compile *compile; + struct hlsl_type *type = NULL; + unsigned int i; + + if (!(profile_info = hlsl_get_target_info(profile_name))) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Unknown profile \"%s\".", profile_name); + return NULL; + } + + if (profile_info->type == VKD3D_SHADER_TYPE_PIXEL) + type = hlsl_get_type(ctx->cur_scope, "PixelShader", true, true); + else if (profile_info->type == VKD3D_SHADER_TYPE_VERTEX) + type = hlsl_get_type(ctx->cur_scope, "VertexShader", true, true); + + if (!type) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile_name); + return NULL; + } + + if (!(compile = hlsl_alloc(ctx, sizeof(*compile)))) + return NULL; + + init_node(&compile->node, HLSL_IR_COMPILE, type, loc); + + compile->profile = profile_info; + + hlsl_block_init(&compile->instrs); + hlsl_block_add_block(&compile->instrs, args_instrs); + + compile->args_count = args_count; + if (!(compile->args = hlsl_alloc(ctx, sizeof(*compile->args) * args_count))) + { + vkd3d_free(compile); + return NULL; + } + for (i = 0; i < compile->args_count; ++i) + hlsl_src_from_node(&compile->args[i], args[i]); + + return &compile->node; +} + struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, struct vkd3d_shader_location *loc) { @@ -2158,6 +2245,43 @@ static struct hlsl_ir_node *clone_index(struct hlsl_ctx *ctx, struct clone_instr return dst; } +static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, + struct clone_instr_map *map, struct hlsl_ir_compile *compile) +{ + const char *profile_name = NULL; + struct hlsl_ir_node **args; + struct hlsl_ir_node *node; + struct hlsl_block block; + unsigned int i; + + if (!(clone_block(ctx, &block, &compile->instrs, map))) + return NULL; + + if (!(args = hlsl_alloc(ctx, sizeof(*args) * compile->args_count))) + { + hlsl_block_cleanup(&block); + return NULL; + } + for (i = 0; i < compile->args_count; ++i) + { + args[i] = map_instr(map, compile->args[i].node); + VKD3D_ASSERT(args[i]); + } + + if (compile->profile) + profile_name = compile->profile->name; + + if (!(node = hlsl_new_compile(ctx, profile_name, args, compile->args_count, &block, &compile->node.loc))) + { + hlsl_block_cleanup(&block); + vkd3d_free(args); + return NULL; + } + + vkd3d_free(args); + return node; +} + static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant) { @@ -2300,6 +2424,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, case HLSL_IR_SWIZZLE: return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr)); + case HLSL_IR_COMPILE: + return clone_compile(ctx, map, hlsl_ir_compile(instr)); + case HLSL_IR_STATEBLOCK_CONSTANT: return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); @@ -2717,6 +2844,8 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) [HLSL_IR_STORE ] = "HLSL_IR_STORE", [HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH", [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", + + [HLSL_IR_COMPILE] = "HLSL_IR_COMPILE", [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", [HLSL_IR_VSIR_INSTRUCTION_REF] = "HLSL_IR_VSIR_INSTRUCTION_REF", }; @@ -3166,6 +3295,25 @@ static void dump_ir_index(struct vkd3d_string_buffer *buffer, const struct hlsl_ vkd3d_string_buffer_printf(buffer, "]"); } +static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, + const struct hlsl_ir_compile *compile) +{ + unsigned int i; + + vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name); + + dump_block(ctx, buffer, &compile->instrs); + + vkd3d_string_buffer_printf(buffer, " %10s } (", ""); + for (i = 0; i < compile->args_count; ++i) + { + dump_src(buffer, &compile->args[i]); + if (i + 1 < compile->args_count) + vkd3d_string_buffer_printf(buffer, ", "); + } + vkd3d_string_buffer_printf(buffer, ")"); +} + static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_stateblock_constant *constant) { @@ -3265,6 +3413,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr)); break; + case HLSL_IR_COMPILE: + dump_ir_compile(ctx, buffer, hlsl_ir_compile(instr)); + break; + case HLSL_IR_STATEBLOCK_CONSTANT: dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); break; @@ -3484,6 +3636,17 @@ static void free_ir_index(struct hlsl_ir_index *index) vkd3d_free(index); } +static void free_ir_compile(struct hlsl_ir_compile *compile) +{ + unsigned int i; + + for (i = 0; i < compile->args_count; ++i) + hlsl_src_remove(&compile->args[i]); + + hlsl_block_cleanup(&compile->instrs); + vkd3d_free(compile); +} + static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant) { vkd3d_free(constant->name); @@ -3552,6 +3715,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) free_ir_switch(hlsl_ir_switch(node)); break; + case HLSL_IR_COMPILE: + free_ir_compile(hlsl_ir_compile(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 a4f84506..00d36e2b 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -324,6 +324,8 @@ enum hlsl_ir_node_type HLSL_IR_STORE, HLSL_IR_SWIZZLE, HLSL_IR_SWITCH, + + HLSL_IR_COMPILE, HLSL_IR_STATEBLOCK_CONSTANT, HLSL_IR_VSIR_INSTRUCTION_REF, @@ -864,6 +866,27 @@ struct hlsl_ir_string_constant char *string; }; +/* Represents shader compilation call for effects, such as "CompileShader()". + * + * Unlike hlsl_ir_call, it is not flattened, thus, it keeps track of its + * arguments and maintains its own instruction block. */ +struct hlsl_ir_compile +{ + struct hlsl_ir_node node; + + /* Special field to store the profile argument. */ + const struct hlsl_profile_info *profile; + + /* Block containing the instructions required by the arguments of the + * compilation call. */ + struct hlsl_block instrs; + + /* Arguments to the compilation call. For a "compile" or "CompileShader()" + * args[0] is an hlsl_ir_call to the specified function. */ + struct hlsl_src *args; + unsigned int args_count; +}; + /* 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 @@ -1170,6 +1193,12 @@ static inline struct hlsl_ir_switch *hlsl_ir_switch(const struct hlsl_ir_node *n return CONTAINING_RECORD(node, struct hlsl_ir_switch, node); } +static inline struct hlsl_ir_compile *hlsl_ir_compile(const struct hlsl_ir_node *node) +{ + VKD3D_ASSERT(node->type == HLSL_IR_COMPILE); + return CONTAINING_RECORD(node, struct hlsl_ir_compile, 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); @@ -1455,6 +1484,9 @@ bool hlsl_index_is_noncontiguous(struct hlsl_ir_index *index); bool hlsl_index_is_resource_access(struct hlsl_ir_index *index); bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index); +struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name, + struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs, + const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val, struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, @@ -1523,6 +1555,7 @@ unsigned int hlsl_type_minor_size(const struct hlsl_type *type); unsigned int hlsl_type_major_size(const struct hlsl_type *type); unsigned int hlsl_type_element_count(const struct hlsl_type *type); bool hlsl_type_is_resource(const struct hlsl_type *type); +bool hlsl_type_is_shader(const struct hlsl_type *type); unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset); bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2); diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 3bc2f084..93855990 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -628,6 +628,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx case HLSL_IR_RESOURCE_LOAD: case HLSL_IR_RESOURCE_STORE: case HLSL_IR_SWITCH: + case HLSL_IR_COMPILE: case HLSL_IR_STATEBLOCK_CONSTANT: hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Expected literal expression."); @@ -2735,13 +2736,15 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var if (v->initializer.args_count) { - unsigned int store_index = 0; bool is_default_values_initializer; + unsigned int store_index = 0; unsigned int size, k; is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) || (var->storage_modifiers & HLSL_STORAGE_UNIFORM) || ctx->cur_scope->annotations; + if (hlsl_type_is_shader(type)) + is_default_values_initializer = false; if (is_default_values_initializer) { @@ -2837,28 +2840,36 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var return initializers; } -static bool func_is_compatible_match(struct hlsl_ctx *ctx, - const struct hlsl_ir_function_decl *decl, const struct parse_initializer *args) +static bool func_is_compatible_match(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *decl, + bool is_compile, const struct parse_initializer *args) { - unsigned int i; + unsigned int i, k; - if (decl->parameters.count < args->args_count) - return false; - - for (i = 0; i < args->args_count; ++i) + k = 0; + for (i = 0; i < decl->parameters.count; ++i) { - if (!implicit_compatible_data_types(ctx, args->args[i]->data_type, decl->parameters.vars[i]->data_type)) + if (is_compile && !(decl->parameters.vars[i]->storage_modifiers & HLSL_STORAGE_UNIFORM)) + continue; + + if (k >= args->args_count) + { + if (!decl->parameters.vars[i]->default_values) + return false; + return true; + } + + if (!implicit_compatible_data_types(ctx, args->args[k]->data_type, decl->parameters.vars[i]->data_type)) return false; + + ++k; } - - if (args->args_count < decl->parameters.count && !decl->parameters.vars[args->args_count]->default_values) + if (k < args->args_count) return false; - return true; } static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, - const char *name, const struct parse_initializer *args, + const char *name, const struct parse_initializer *args, bool is_compile, const struct vkd3d_shader_location *loc) { struct hlsl_ir_function_decl *decl, *compatible_match = NULL; @@ -2871,7 +2882,7 @@ static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, LIST_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry) { - if (func_is_compatible_match(ctx, decl, args)) + if (func_is_compatible_match(ctx, decl, is_compile, args)) { if (compatible_match) { @@ -2892,26 +2903,35 @@ static struct hlsl_ir_node *hlsl_new_void_expr(struct hlsl_ctx *ctx, const struc return hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc); } -static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, - const struct parse_initializer *args, const struct vkd3d_shader_location *loc) +static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx, + struct hlsl_ir_function_decl *func, const struct parse_initializer *args, + bool is_compile, const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *call; - unsigned int i, j; + unsigned int i, j, k; VKD3D_ASSERT(args->args_count <= func->parameters.count); - for (i = 0; i < args->args_count; ++i) + k = 0; + for (i = 0; i < func->parameters.count; ++i) { struct hlsl_ir_var *param = func->parameters.vars[i]; - struct hlsl_ir_node *arg = args->args[i]; + struct hlsl_ir_node *arg; + + if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM)) + continue; + + if (k >= args->args_count) + break; + arg = args->args[k]; if (!hlsl_types_are_equal(arg->data_type, param->data_type)) { struct hlsl_ir_node *cast; if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc))) - return false; - args->args[i] = cast; + return NULL; + args->args[k] = cast; arg = cast; } @@ -2920,13 +2940,15 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu struct hlsl_ir_node *store; if (!(store = hlsl_new_simple_store(ctx, param, arg))) - return false; + return NULL; hlsl_block_add_instr(args->instrs, store); } + + ++k; } /* Add default values for the remaining parameters. */ - for (i = args->args_count; i < func->parameters.count; ++i) + for (; i < func->parameters.count; ++i) { struct hlsl_ir_var *param = func->parameters.vars[i]; unsigned int comp_count = hlsl_type_component_count(param->data_type); @@ -2934,6 +2956,9 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu VKD3D_ASSERT(param->default_values); + if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM)) + continue; + hlsl_init_simple_deref_from_var(¶m_deref, param); for (j = 0; j < comp_count; ++j) @@ -2947,20 +2972,23 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu { value.u[0] = param->default_values[j].number; if (!(comp = hlsl_new_constant(ctx, type, &value, loc))) - return false; + return NULL; hlsl_block_add_instr(args->instrs, comp); if (!hlsl_new_store_component(ctx, &store_block, ¶m_deref, j, comp)) - return false; + return NULL; hlsl_block_add_block(args->instrs, &store_block); } } } if (!(call = hlsl_new_call(ctx, func, loc))) - return false; + return NULL; hlsl_block_add_instr(args->instrs, call); + if (is_compile) + return call; + for (i = 0; i < args->args_count; ++i) { struct hlsl_ir_var *param = func->parameters.vars[i]; @@ -2975,11 +3003,11 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu "Output argument to \"%s\" is const.", func->func->name); if (!(load = hlsl_new_var_load(ctx, param, &arg->loc))) - return false; + return NULL; hlsl_block_add_instr(args->instrs, &load->node); if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &load->node)) - return false; + return NULL; } } @@ -3000,7 +3028,7 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu hlsl_block_add_instr(args->instrs, expr); } - return true; + return call; } static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, @@ -3167,7 +3195,7 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_acos(struct hlsl_ctx *ctx, @@ -3316,7 +3344,7 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_atan(struct hlsl_ctx *ctx, @@ -3509,7 +3537,7 @@ static bool write_cosh_or_sinh(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_cosh(struct hlsl_ctx *ctx, @@ -3736,7 +3764,7 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_distance(struct hlsl_ctx *ctx, @@ -3823,7 +3851,7 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_f16tof32(struct hlsl_ctx *ctx, @@ -3928,7 +3956,7 @@ static bool intrinsic_fwidth(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_ldexp(struct hlsl_ctx *ctx, @@ -4031,7 +4059,7 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, if (!(func = hlsl_compile_internal_function(ctx, "lit", body))) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_log(struct hlsl_ctx *ctx, @@ -4334,7 +4362,7 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_round(struct hlsl_ctx *ctx, @@ -4449,7 +4477,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_sqrt(struct hlsl_ctx *ctx, @@ -4525,7 +4553,7 @@ static bool intrinsic_tanh(struct hlsl_ctx *ctx, if (!func) return false; - return add_user_call(ctx, func, params, loc); + return !!add_user_call(ctx, func, params, false, loc); } static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, @@ -5004,9 +5032,9 @@ static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name, struct intrinsic_function *intrinsic; struct hlsl_ir_function_decl *decl; - if ((decl = find_function_call(ctx, name, args, loc))) + if ((decl = find_function_call(ctx, name, args, false, loc))) { - if (!add_user_call(ctx, decl, args, loc)) + if (!add_user_call(ctx, decl, args, false, loc)) goto fail; } else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions), @@ -5062,6 +5090,53 @@ fail: return NULL; } +static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const char *profile_name, + const char *function_name, struct parse_initializer *args, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_node *compile, *call_to_compile = NULL; + struct hlsl_ir_function_decl *decl; + + if (!ctx->in_state_block && ctx->cur_scope != ctx->globals) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE, + "Shader compilation statements must be in global scope or a state block."); + free_parse_initializer(args); + return NULL; + } + + if (!(decl = find_function_call(ctx, function_name, args, true, loc))) + { + if (rb_get(&ctx->functions, function_name)) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, + "No compatible \"%s\" declaration with %u uniform parameters found.", + function_name, args->args_count); + } + else + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, + "Function \"%s\" is not defined.", function_name); + } + free_parse_initializer(args); + return NULL; + } + + if (!(call_to_compile = add_user_call(ctx, decl, args, true, loc))) + { + free_parse_initializer(args); + return NULL; + } + + if (!(compile = hlsl_new_compile(ctx, profile_name, &call_to_compile, 1, args->instrs, loc))) + { + free_parse_initializer(args); + return NULL; + } + + free_parse_initializer(args); + return make_block(ctx, compile); +} + static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, struct parse_initializer *params, const struct vkd3d_shader_location *loc) { @@ -8393,6 +8468,18 @@ primary_expr: { $$ = $2; } + + | KW_COMPILE any_identifier var_identifier '(' func_arguments ')' + { + if (!($$ = add_shader_compilation(ctx, $2, $3, &$5, &@1))) + { + vkd3d_free($2); + vkd3d_free($3); + YYABORT; + } + vkd3d_free($2); + vkd3d_free($3); + } | var_identifier '(' func_arguments ')' { if (!($$ = add_call(ctx, $1, &$3, &@1))) diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 30694d98..b7f9c532 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4050,6 +4050,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) switch (instr->type) { case HLSL_IR_CONSTANT: + case HLSL_IR_COMPILE: case HLSL_IR_EXPR: case HLSL_IR_INDEX: case HLSL_IR_LOAD: @@ -4343,6 +4344,9 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop case HLSL_IR_CONSTANT: case HLSL_IR_STRING_CONSTANT: break; + case HLSL_IR_COMPILE: + /* Compile calls are skipped as they are only relevent to effects. */ + break; } } } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 93dff4e8..5f554225 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -152,6 +152,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_HLSL_UNKNOWN_MODIFIER = 5030, VKD3D_SHADER_ERROR_HLSL_INVALID_STATE_BLOCK_ENTRY = 5031, VKD3D_SHADER_ERROR_HLSL_FAILED_FORCED_UNROLL = 5032, + VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE = 5033, + VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE = 5034, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, diff --git a/tests/hlsl/effect-compile.shader_test b/tests/hlsl/effect-compile.shader_test index acfab529..94b3ae6e 100644 --- a/tests/hlsl/effect-compile.shader_test +++ b/tests/hlsl/effect-compile.shader_test @@ -1,5 +1,5 @@ % Test special "compile" keyword syntax to compile pixel and vertex shaders -[pixel shader todo] +[pixel shader] float4 fun() : sv_target { return 0; @@ -13,7 +13,7 @@ sampler sam float4 main() : sv_target { return 0; } -[pixel shader todo] +[pixel shader] float4 fun() : sv_target { return 0; @@ -31,7 +31,7 @@ float4 main() : sv_target { return 0; } % Only uniform arguments are expected, even if undefined identifiers are used. -[pixel shader todo] +[pixel shader] float4 fun(uniform float4 a, float4 b, uniform float4 c) : sv_target { return a + b + c; @@ -185,7 +185,7 @@ float4 main() : sv_target % Default values are allowed for uniform variables. -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] float4 fun(uniform float4 a, uniform float4 b = {1, 2, 3, 4}) : sv_target { return 8*a + b; @@ -202,7 +202,7 @@ technique10 T1 float4 main() : sv_target { return 0; } -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6)] float4 fun(float4 a : COLOR0 = {-1, -2, -3, -4}, uniform float4 b = {1, 2, 3, 4}) : sv_target { return 8*a + b;