From e7e5e0e85ccf11074ec59e202e30924fbad10df2 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Mon, 15 Jul 2024 10:03:30 +1000 Subject: [PATCH] Updated vkd3d to 5a53b739959db74e8dcce023a7d49356b9008e92. --- libs/vkd3d/include/vkd3d_shader.h | 217 ++++++++++++++ libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 2 +- libs/vkd3d/libs/vkd3d-shader/dxil.c | 11 +- libs/vkd3d/libs/vkd3d-shader/hlsl.y | 12 + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 2 +- libs/vkd3d/libs/vkd3d-shader/ir.c | 280 +++++++++++++++++- libs/vkd3d/libs/vkd3d-shader/spirv.c | 99 ++++++- libs/vkd3d/libs/vkd3d-shader/tpf.c | 46 ++- .../libs/vkd3d-shader/vkd3d_shader_private.h | 8 +- 9 files changed, 649 insertions(+), 28 deletions(-) diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h index d3afcc11b16..4acb622468a 100644 --- a/libs/vkd3d/include/vkd3d_shader.h +++ b/libs/vkd3d/include/vkd3d_shader.h @@ -105,6 +105,11 @@ enum vkd3d_shader_structure_type * \since 1.10 */ VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO, + /** + * The structure is a vkd3d_shader_parameter_info structure. + * \since 1.13 + */ + VKD3D_SHADER_STRUCTURE_TYPE_PARAMETER_INFO, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE), }; @@ -453,44 +458,167 @@ enum vkd3d_shader_binding_flag VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_BINDING_FLAG), }; +/** + * The manner in which a parameter value is provided to the shader, used in + * struct vkd3d_shader_parameter and struct vkd3d_shader_parameter1. + */ enum vkd3d_shader_parameter_type { VKD3D_SHADER_PARAMETER_TYPE_UNKNOWN, + /** The parameter value is embedded directly in the shader. */ VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT, + /** + * The parameter value is provided to the shader via a specialization + * constant. This value is only supported for the SPIR-V target type. + */ VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT, + /** + * The parameter value is provided to the shader as part of a uniform + * buffer. + * + * \since 1.13 + */ + VKD3D_SHADER_PARAMETER_TYPE_BUFFER, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_TYPE), }; +/** + * The format of data provided to the shader, used in + * struct vkd3d_shader_parameter and struct vkd3d_shader_parameter1. + */ enum vkd3d_shader_parameter_data_type { VKD3D_SHADER_PARAMETER_DATA_TYPE_UNKNOWN, + /** The parameter is provided as a 32-bit unsigned integer. */ VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32, + /** The parameter is provided as a 32-bit float. \since 1.13 */ + VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_DATA_TYPE), }; +/** + * Names a specific shader parameter, used in + * struct vkd3d_shader_parameter and struct vkd3d_shader_parameter1. + */ enum vkd3d_shader_parameter_name { VKD3D_SHADER_PARAMETER_NAME_UNKNOWN, + /** + * The sample count of the framebuffer, as returned by the HLSL function + * GetRenderTargetSampleCount() or the GLSL builtin gl_NumSamples. + * + * This parameter should be specified when compiling to SPIR-V, which + * provides no builtin ability to query this information from the shader. + * + * The default value is 1. + * + * The data type for this parameter must be + * VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32. + */ VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, + /** + * Alpha test comparison function. When this parameter is provided, if the + * alpha component of the pixel shader colour output at location 0 fails the + * test, as defined by this function and the reference value provided by + * VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, the fragment will be + * discarded. + * + * This parameter, along with VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, + * can be used to implement fixed function alpha test, as present in + * Direct3D versions up to 9, if the target environment does not support + * alpha test as part of its own fixed-function API (as Vulkan and core + * OpenGL). + * + * The default value is VKD3D_SHADER_COMPARISON_FUNC_ALWAYS. + * + * The data type for this parameter must be + * VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32. The value specified must be + * a member of enum vkd3d_shader_comparison_func. + * + * Only VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT is supported in this + * version of vkd3d-shader. + * + * \since 1.13 + */ + VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_FUNC, + /** + * Alpha test reference value. + * See VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_FUNC for documentation of + * alpha test. + * + * The default value is zero. + * + * \since 1.13 + */ + VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME), }; +/** + * The value of an immediate constant parameter, used in + * struct vkd3d_shader_parameter and struct vkd3d_shader_parameter1. + */ struct vkd3d_shader_parameter_immediate_constant { union { + /** + * The value if the parameter's data type is + * VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32. + */ uint32_t u32; + /** + * The value if the parameter's data type is + * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32. + * + * \since 1.13 + */ + float f32; } u; }; +/** + * The linkage of a specialization constant parameter, used in + * struct vkd3d_shader_parameter and struct vkd3d_shader_parameter1. + */ struct vkd3d_shader_parameter_specialization_constant { + /** The ID of the specialization constant. */ uint32_t id; }; +/** + * The linkage of a parameter specified through a uniform buffer, used in + * struct vkd3d_shader_parameter1. + */ +struct vkd3d_shader_parameter_buffer +{ + /** + * The set of the uniform buffer descriptor. If the target environment does + * not support descriptor sets, this value must be set to 0. + */ + unsigned int set; + /** The binding index of the uniform buffer descriptor. */ + unsigned int binding; + /** The byte offset of the parameter within the buffer. */ + uint32_t offset; +}; + +/** + * An individual shader parameter. + * + * This structure is an earlier version of struct vkd3d_shader_parameter1 + * which supports fewer parameter types; + * refer to that structure for usage information. + * + * Only the following types may be used with this structure: + * + * - VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT + * - VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT + */ struct vkd3d_shader_parameter { enum vkd3d_shader_parameter_name name; @@ -503,6 +631,56 @@ struct vkd3d_shader_parameter } u; }; +/** + * An individual shader parameter. + * + * This structure is used in struct vkd3d_shader_parameter_info; see there for + * explanation of shader parameters. + * + * For example, to specify the rasterizer sample count to the shader via an + * unsigned integer specialization constant with ID 3, + * set the following members: + * + * - \a name = VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT + * - \a type = VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT + * - \a data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32 + * - \a u.specialization_constant.id = 3 + * + * This structure is an extended version of struct vkd3d_shader_parameter. + */ +struct vkd3d_shader_parameter1 +{ + /** The builtin parameter to be mapped. */ + enum vkd3d_shader_parameter_name name; + /** How the parameter will be provided to the shader. */ + enum vkd3d_shader_parameter_type type; + /** + * The data type of the supplied parameter, which determines how it is to + * be interpreted. + */ + enum vkd3d_shader_parameter_data_type data_type; + union + { + /** + * Additional information if \a type is + * VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT. + */ + struct vkd3d_shader_parameter_immediate_constant immediate_constant; + /** + * Additional information if \a type is + * VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT. + */ + struct vkd3d_shader_parameter_specialization_constant specialization_constant; + /** + * Additional information if \a type is + * VKD3D_SHADER_PARAMETER_TYPE_BUFFER. + */ + struct vkd3d_shader_parameter_buffer buffer; + void *_pointer_pad; + uint32_t _pad[4]; + } u; +}; + /** * Symbolic register indices for mapping uniform constant register sets in * legacy Direct3D bytecode to constant buffer views in the target environment. @@ -1994,6 +2172,44 @@ struct vkd3d_shader_varying_map_info unsigned int varying_count; }; +/** + * Interface information regarding a builtin shader parameter. + * + * Like compile options specified with struct vkd3d_shader_compile_option, + * parameters are used to specify certain values which are not part of the + * source shader bytecode but which need to be specified in the shader bytecode + * in the target format. + * Unlike struct vkd3d_shader_compile_option, however, this structure allows + * parameters to be specified in a variety of different ways, as described by + * enum vkd3d_shader_parameter_type. + * + * This structure is an extended version of struct vkd3d_shader_parameter as + * used in struct vkd3d_shader_spirv_target_info, which allows more parameter + * types to be used, and also allows specifying parameters when compiling + * shaders to target types other than SPIR-V. If this structure is chained + * along with vkd3d_shader_spirv_target_info, any parameters specified in the + * latter structure are ignored. + * + * This structure is passed to vkd3d_shader_compile() and extends + * vkd3d_shader_compile_info. + * + * This structure contains only input parameters. + * + * \since 1.13 + */ +struct vkd3d_shader_parameter_info +{ + /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_PARAMETER_INFO. */ + enum vkd3d_shader_structure_type type; + /** Optional pointer to a structure containing further parameters. */ + const void *next; + + /** Pointer to an array of dynamic parameters for this shader instance. */ + const struct vkd3d_shader_parameter1 *parameters; + /** Size, in elements, of \ref parameters. */ + unsigned int parameter_count; +}; + #ifdef LIBVKD3D_SHADER_SOURCE # define VKD3D_SHADER_API VKD3D_EXPORT #else @@ -2077,6 +2293,7 @@ VKD3D_SHADER_API const enum vkd3d_shader_target_type *vkd3d_shader_get_supported * - vkd3d_shader_descriptor_offset_info * - vkd3d_shader_hlsl_source_info * - vkd3d_shader_interface_info + * - vkd3d_shader_parameter_info * - vkd3d_shader_preprocess_info * - vkd3d_shader_scan_combined_resource_sampler_info * - vkd3d_shader_scan_descriptor_info diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c index 4522d56c5c9..abfbd461b33 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c @@ -1272,7 +1272,7 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, st sm1->end = &code[token_count]; /* Estimate instruction count to avoid reallocation in most shaders. */ - if (!vsir_program_init(program, &version, code_size != ~(size_t)0 ? token_count / 4u + 4 : 16)) + if (!vsir_program_init(program, compile_info, &version, code_size != ~(size_t)0 ? token_count / 4u + 4 : 16)) return VKD3D_ERROR_OUT_OF_MEMORY; vkd3d_shader_parser_init(&sm1->p, program, message_context, compile_info->source_name); diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c index 2176debc7d2..bf581928a9e 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -10206,12 +10206,13 @@ static struct sm6_function *sm6_parser_get_function(const struct sm6_parser *sm6 return NULL; } -static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_program *program, const char *source_name, +static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_program *program, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context, struct dxbc_shader_desc *dxbc_desc) { size_t count, length, function_count, expected_function_count, byte_code_size = dxbc_desc->byte_code_size; + const struct vkd3d_shader_location location = {.source_name = compile_info->source_name}; struct shader_signature *patch_constant_signature, *output_signature, *input_signature; - const struct vkd3d_shader_location location = {.source_name = source_name}; uint32_t version_token, dxil_version, token_count, magic; const uint32_t *byte_code = dxbc_desc->byte_code; unsigned int chunk_offset, chunk_size; @@ -10302,9 +10303,9 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro /* Estimate instruction count to avoid reallocation in most shaders. */ count = max(token_count, 400) - 400; - if (!vsir_program_init(program, &version, (count + (count >> 2)) / 2u + 10)) + if (!vsir_program_init(program, compile_info, &version, (count + (count >> 2)) / 2u + 10)) return VKD3D_ERROR_OUT_OF_MEMORY; - vkd3d_shader_parser_init(&sm6->p, program, message_context, source_name); + vkd3d_shader_parser_init(&sm6->p, program, message_context, compile_info->source_name); sm6->ptr = &sm6->start[1]; sm6->bitpos = 2; @@ -10565,7 +10566,7 @@ int dxil_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t co dxbc_desc.byte_code = byte_code; } - ret = sm6_parser_init(&sm6, program, compile_info->source_name, message_context, &dxbc_desc); + ret = sm6_parser_init(&sm6, program, compile_info, message_context, &dxbc_desc); free_dxbc_shader_desc(&dxbc_desc); vkd3d_free(byte_code); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y index 7b058a65bc1..56736a65306 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -4065,6 +4065,17 @@ static bool intrinsic_radians(struct hlsl_ctx *ctx, return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, arg, rad, loc); } +static bool intrinsic_rcp(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_node *arg; + + if (!(arg = intrinsic_float_convert_arg(ctx, params, params->args[0], loc))) + return false; + + return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_RCP, arg, loc); +} + static bool intrinsic_reflect(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { @@ -4760,6 +4771,7 @@ intrinsic_functions[] = {"normalize", 1, true, intrinsic_normalize}, {"pow", 2, true, intrinsic_pow}, {"radians", 1, true, intrinsic_radians}, + {"rcp", 1, true, intrinsic_rcp}, {"reflect", 2, true, intrinsic_reflect}, {"refract", 3, true, intrinsic_refract}, {"round", 1, true, intrinsic_round}, diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c index 7e4f168675e..02884df9d76 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c @@ -5691,7 +5691,7 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl version.major = ctx->profile->major_version; version.minor = ctx->profile->minor_version; version.type = ctx->profile->type; - if (!vsir_program_init(program, &version, 0)) + if (!vsir_program_init(program, NULL, &version, 0)) { ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; return; diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index e5432cb35ce..be9e4219d6a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -19,9 +19,73 @@ #include "vkd3d_shader_private.h" #include "vkd3d_types.h" -bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve) +static int convert_parameter_info(const struct vkd3d_shader_compile_info *compile_info, + unsigned int *ret_count, const struct vkd3d_shader_parameter1 **ret_parameters) +{ + const struct vkd3d_shader_spirv_target_info *spirv_info; + struct vkd3d_shader_parameter1 *parameters; + + *ret_count = 0; + *ret_parameters = NULL; + + if (!(spirv_info = vkd3d_find_struct(compile_info->next, SPIRV_TARGET_INFO)) || !spirv_info->parameter_count) + return VKD3D_OK; + + if (!(parameters = vkd3d_calloc(spirv_info->parameter_count, sizeof(*parameters)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + for (unsigned int i = 0; i < spirv_info->parameter_count; ++i) + { + const struct vkd3d_shader_parameter *src = &spirv_info->parameters[i]; + struct vkd3d_shader_parameter1 *dst = ¶meters[i]; + + dst->name = src->name; + dst->type = src->type; + dst->data_type = src->data_type; + + if (src->type == VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + { + dst->u.immediate_constant = src->u.immediate_constant; + } + else if (src->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT) + { + dst->u.specialization_constant = src->u.specialization_constant; + } + else + { + ERR("Invalid parameter type %#x.\n", src->type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + } + + *ret_count = spirv_info->parameter_count; + *ret_parameters = parameters; + + return VKD3D_OK; +} + +bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, + const struct vkd3d_shader_version *version, unsigned int reserve) { memset(program, 0, sizeof(*program)); + + if (compile_info) + { + const struct vkd3d_shader_parameter_info *parameter_info; + + if ((parameter_info = vkd3d_find_struct(compile_info->next, PARAMETER_INFO))) + { + program->parameter_count = parameter_info->parameter_count; + program->parameters = parameter_info->parameters; + } + else + { + if (convert_parameter_info(compile_info, &program->parameter_count, &program->parameters) < 0) + return false; + program->free_parameters = true; + } + } + program->shader_version = *version; return shader_instruction_array_init(&program->instructions, reserve); } @@ -30,6 +94,8 @@ void vsir_program_cleanup(struct vsir_program *program) { size_t i; + if (program->free_parameters) + vkd3d_free((void *)program->parameters); for (i = 0; i < program->block_name_count; ++i) vkd3d_free((void *)program->block_names[i]); vkd3d_free(program->block_names); @@ -666,6 +732,12 @@ static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigne dst->write_mask = VKD3DSP_WRITEMASK_0; } +static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsigned int idx) +{ + vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); + src->reg.idx[0].offset = idx; +} + static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) { vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); @@ -678,6 +750,12 @@ static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32 src->reg.u.immconst_u32[0] = value; } +static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type) +{ + vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1); + src->reg.idx[0].offset = idx; +} + void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, enum vkd3d_shader_opcode opcode) { @@ -5282,6 +5360,203 @@ static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps(stru return VKD3D_OK; } +static bool find_colour_signature_idx(const struct shader_signature *signature, uint32_t *index) +{ + for (unsigned int i = 0; i < signature->element_count; ++i) + { + if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_TARGET + && !signature->elements[i].register_index) + { + *index = i; + return true; + } + } + + return false; +} + +static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *program, + const struct vkd3d_shader_instruction *ret, enum vkd3d_shader_comparison_func compare_func, + const struct vkd3d_shader_parameter1 *ref, uint32_t colour_signature_idx, uint32_t colour_temp, size_t *ret_pos) +{ + struct vkd3d_shader_instruction_array *instructions = &program->instructions; + size_t pos = ret - instructions->elements; + struct vkd3d_shader_instruction *ins; + + static const struct + { + enum vkd3d_shader_opcode float_opcode; + enum vkd3d_shader_opcode uint_opcode; + bool swap; + } + opcodes[] = + { + [VKD3D_SHADER_COMPARISON_FUNC_EQUAL] = {VKD3DSIH_EQO, VKD3DSIH_IEQ}, + [VKD3D_SHADER_COMPARISON_FUNC_NOT_EQUAL] = {VKD3DSIH_NEO, VKD3DSIH_INE}, + [VKD3D_SHADER_COMPARISON_FUNC_GREATER_EQUAL] = {VKD3DSIH_GEO, VKD3DSIH_UGE}, + [VKD3D_SHADER_COMPARISON_FUNC_LESS] = {VKD3DSIH_LTO, VKD3DSIH_ULT}, + [VKD3D_SHADER_COMPARISON_FUNC_LESS_EQUAL] = {VKD3DSIH_GEO, VKD3DSIH_UGE, true}, + [VKD3D_SHADER_COMPARISON_FUNC_GREATER] = {VKD3DSIH_LTO, VKD3DSIH_ULT, true}, + }; + + if (compare_func == VKD3D_SHADER_COMPARISON_FUNC_NEVER) + { + if (!shader_instruction_array_insert_at(&program->instructions, pos, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + ins = &program->instructions.elements[pos]; + + vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_DISCARD, 0, 1); + ins->flags = VKD3D_SHADER_CONDITIONAL_OP_Z; + src_param_init_const_uint(&ins->src[0], 0); + + *ret_pos = pos + 1; + return VKD3D_OK; + } + + if (!shader_instruction_array_insert_at(&program->instructions, pos, 3)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = &program->instructions.elements[pos]; + + switch (ref->data_type) + { + case VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32: + vsir_instruction_init_with_params(program, ins, &ret->location, opcodes[compare_func].float_opcode, 1, 2); + src_param_init_temp_float(&ins->src[opcodes[compare_func].swap ? 1 : 0], colour_temp); + src_param_init_parameter(&ins->src[opcodes[compare_func].swap ? 0 : 1], + VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, VKD3D_DATA_FLOAT); + break; + + case VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32: + vsir_instruction_init_with_params(program, ins, &ret->location, opcodes[compare_func].uint_opcode, 1, 2); + src_param_init_temp_uint(&ins->src[opcodes[compare_func].swap ? 1 : 0], colour_temp); + src_param_init_parameter(&ins->src[opcodes[compare_func].swap ? 0 : 1], + VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, VKD3D_DATA_UINT); + break; + + default: + FIXME("Unhandled parameter data type %#x.\n", ref->data_type); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + + dst_param_init_ssa_bool(&ins->dst[0], program->ssa_count); + ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W); + ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W); + + ++ins; + vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_DISCARD, 0, 1); + ins->flags = VKD3D_SHADER_CONDITIONAL_OP_Z; + src_param_init_ssa_bool(&ins->src[0], program->ssa_count); + + ++program->ssa_count; + + ++ins; + vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_MOV, 1, 1); + vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VKD3D_DATA_FLOAT, 1); + ins->dst[0].reg.idx[0].offset = colour_signature_idx; + ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->dst[0].write_mask = program->output_signature.elements[colour_signature_idx].mask; + src_param_init_temp_float(&ins->src[0], colour_temp); + ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; + + *ret_pos = pos + 3; + return VKD3D_OK; +} + +static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *program, + struct vkd3d_shader_message_context *message_context) +{ + const struct vkd3d_shader_parameter1 *func = NULL, *ref = NULL; + static const struct vkd3d_shader_location no_loc; + enum vkd3d_shader_comparison_func compare_func; + uint32_t colour_signature_idx, colour_temp; + struct vkd3d_shader_instruction *ins; + size_t new_pos; + int ret; + + if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL) + return VKD3D_OK; + + if (!find_colour_signature_idx(&program->output_signature, &colour_signature_idx) + || !(program->output_signature.elements[colour_signature_idx].mask & VKD3DSP_WRITEMASK_3)) + return VKD3D_OK; + + for (unsigned int i = 0; i < program->parameter_count; ++i) + { + const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i]; + + if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_FUNC) + func = parameter; + else if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF) + ref = parameter; + } + + if (!func || !ref) + return VKD3D_OK; + + if (func->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + { + vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "Unsupported alpha test function parameter type %#x.\n", func->type); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + if (func->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) + { + vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid alpha test function parameter data type %#x.\n", func->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + compare_func = func->u.immediate_constant.u.u32; + + if (compare_func == VKD3D_SHADER_COMPARISON_FUNC_ALWAYS) + return VKD3D_OK; + + /* We're going to be reading from the output, so we need to go + * through the whole shader and convert it to a temp. */ + + if (compare_func != VKD3D_SHADER_COMPARISON_FUNC_NEVER) + colour_temp = program->temp_count++; + + for (size_t i = 0; i < program->instructions.count; ++i) + { + ins = &program->instructions.elements[i]; + + if (vsir_instruction_is_dcl(ins)) + continue; + + if (ins->opcode == VKD3DSIH_RET) + { + if ((ret = insert_alpha_test_before_ret(program, ins, compare_func, + ref, colour_signature_idx, colour_temp, &new_pos)) < 0) + return ret; + i = new_pos; + continue; + } + + /* No need to convert it if the comparison func is NEVER; we don't + * read from the output in that case. */ + if (compare_func == VKD3D_SHADER_COMPARISON_FUNC_NEVER) + continue; + + for (size_t j = 0; j < ins->dst_count; ++j) + { + struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + + /* Note we run after I/O normalization. */ + if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == colour_signature_idx) + { + dst->reg.type = VKD3DSPR_TEMP; + dst->reg.idx[0].offset = colour_temp; + } + } + } + + return VKD3D_OK; +} + struct validation_context { struct vkd3d_shader_message_context *message_context; @@ -6274,6 +6549,9 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t return result; } + if ((result = vsir_program_insert_alpha_test(program, message_context)) < 0) + return result; + if (TRACE_ON()) vkd3d_shader_trace(program); diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c index 524fb8e9b1f..72a6f1e60dc 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -2418,6 +2418,13 @@ struct spirv_compiler uint32_t *descriptor_offset_ids; struct vkd3d_push_constant_buffer_binding *push_constants; const struct vkd3d_shader_spirv_target_info *spirv_target_info; + const struct vkd3d_shader_parameter1 *parameters; + unsigned int parameter_count; + + struct + { + uint32_t buffer_id; + } *spirv_parameter_info; bool prolog_emitted; struct shader_signature input_signature; @@ -3290,16 +3297,15 @@ static uint32_t spirv_compiler_emit_array_variable(struct spirv_compiler *compil return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0); } -static const struct vkd3d_shader_parameter *spirv_compiler_get_shader_parameter( +static const struct vkd3d_shader_parameter1 *spirv_compiler_get_shader_parameter( struct spirv_compiler *compiler, enum vkd3d_shader_parameter_name name) { - const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info; unsigned int i; - for (i = 0; info && i < info->parameter_count; ++i) + for (i = 0; i < compiler->parameter_count; ++i) { - if (info->parameters[i].name == name) - return &info->parameters[i]; + if (compiler->parameters[i].name == name) + return &compiler->parameters[i]; } return NULL; @@ -3314,6 +3320,7 @@ static const struct vkd3d_spec_constant_info vkd3d_shader_parameters[] = { {VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, 1, "sample_count"}, + {VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, 0, "alpha_test_ref"}, }; static const struct vkd3d_spec_constant_info *get_spec_constant_info(enum vkd3d_shader_parameter_name name) @@ -3352,7 +3359,7 @@ static uint32_t spirv_compiler_alloc_spec_constant_id(struct spirv_compiler *com } static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compiler, - enum vkd3d_shader_parameter_name name, uint32_t spec_id) + enum vkd3d_shader_parameter_name name, uint32_t spec_id, enum vkd3d_data_type type) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_spec_constant_info *info; @@ -3361,7 +3368,7 @@ static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compile info = get_spec_constant_info(name); default_value = info ? info->default_value : 0; - type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); + type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); id = vkd3d_spirv_build_op_spec_constant(builder, type_id, default_value); vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationSpecId, spec_id); @@ -3380,7 +3387,7 @@ static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compile } static uint32_t spirv_compiler_get_spec_constant(struct spirv_compiler *compiler, - enum vkd3d_shader_parameter_name name, uint32_t spec_id) + enum vkd3d_shader_parameter_name name, uint32_t spec_id, enum vkd3d_data_type type) { unsigned int i; @@ -3390,13 +3397,29 @@ static uint32_t spirv_compiler_get_spec_constant(struct spirv_compiler *compiler return compiler->spec_constants[i].id; } - return spirv_compiler_emit_spec_constant(compiler, name, spec_id); + return spirv_compiler_emit_spec_constant(compiler, name, spec_id, type); +} + +static uint32_t spirv_compiler_get_buffer_parameter(struct spirv_compiler *compiler, + const struct vkd3d_shader_parameter1 *parameter, enum vkd3d_data_type type) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + unsigned int index = parameter - compiler->parameters; + uint32_t type_id, ptr_id, ptr_type_id; + + type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id); + ptr_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, + compiler->spirv_parameter_info[index].buffer_id, + spirv_compiler_get_constant_uint(compiler, 0)); + return vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone); } -static uint32_t spirv_compiler_emit_uint_shader_parameter(struct spirv_compiler *compiler, +static uint32_t spirv_compiler_emit_shader_parameter(struct spirv_compiler *compiler, enum vkd3d_shader_parameter_name name) { - const struct vkd3d_shader_parameter *parameter; + const struct vkd3d_shader_parameter1 *parameter; + enum vkd3d_data_type type = VKD3D_DATA_UINT; if (!(parameter = spirv_compiler_get_shader_parameter(compiler, name))) { @@ -3405,15 +3428,28 @@ static uint32_t spirv_compiler_emit_uint_shader_parameter(struct spirv_compiler } if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) - return spirv_compiler_get_constant_uint(compiler, parameter->u.immediate_constant.u.u32); + { + if (parameter->data_type == VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32) + return spirv_compiler_get_constant_float(compiler, parameter->u.immediate_constant.u.f32); + else + return spirv_compiler_get_constant_uint(compiler, parameter->u.immediate_constant.u.u32); + } + + if (parameter->data_type == VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32) + type = VKD3D_DATA_FLOAT; + else + type = VKD3D_DATA_UINT; + if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT) - return spirv_compiler_get_spec_constant(compiler, name, parameter->u.specialization_constant.id); + return spirv_compiler_get_spec_constant(compiler, name, parameter->u.specialization_constant.id, type); + if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_BUFFER) + return spirv_compiler_get_buffer_parameter(compiler, parameter, type); FIXME("Unhandled parameter type %#x.\n", parameter->type); default_parameter: return spirv_compiler_get_spec_constant(compiler, - name, spirv_compiler_alloc_spec_constant_id(compiler)); + name, spirv_compiler_alloc_spec_constant_id(compiler), type); } static uint32_t spirv_compiler_emit_construct_vector(struct spirv_compiler *compiler, @@ -4188,6 +4224,8 @@ static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler, return spirv_compiler_emit_load_constant64(compiler, reg, swizzle, write_mask); else if (reg->type == VKD3DSPR_UNDEF) return spirv_compiler_emit_load_undef(compiler, reg, write_mask); + else if (reg->type == VKD3DSPR_PARAMETER) + return spirv_compiler_emit_shader_parameter(compiler, reg->idx[0].offset); component_count = vsir_write_mask_component_count(write_mask); component_type = vkd3d_component_type_from_data_type(reg->data_type); @@ -8129,6 +8167,8 @@ static void spirv_compiler_emit_discard(struct spirv_compiler *compiler, if (src->reg.data_type != VKD3D_DATA_BOOL) condition_id = spirv_compiler_emit_int_to_bool(compiler, instruction->flags, src->reg.data_type, 1, condition_id); + else if (instruction->flags & VKD3D_SHADER_CONDITIONAL_OP_Z) + condition_id = vkd3d_spirv_build_op_logical_not(builder, vkd3d_spirv_get_op_type_bool(builder), condition_id); void_id = vkd3d_spirv_get_op_type_void(builder); vkd3d_spirv_build_op_function_call(builder, void_id, spirv_compiler_get_discard_function_id(compiler), &condition_id, 1); @@ -9525,7 +9565,7 @@ static uint32_t spirv_compiler_emit_query_sample_count(struct spirv_compiler *co if (src->reg.type == VKD3DSPR_RASTERIZER) { - val_id = spirv_compiler_emit_uint_shader_parameter(compiler, + val_id = spirv_compiler_emit_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT); } else @@ -10570,6 +10610,35 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct spirv_compiler_emit_descriptor_declarations(compiler); + compiler->parameter_count = program->parameter_count; + compiler->parameters = program->parameters; + compiler->spirv_parameter_info = vkd3d_calloc(compiler->parameter_count, sizeof(*compiler->spirv_parameter_info)); + for (i = 0; i < compiler->parameter_count; ++i) + { + const struct vkd3d_shader_parameter1 *parameter = &compiler->parameters[i]; + + if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_BUFFER) + { + uint32_t type_id, struct_id, ptr_type_id, var_id; + + type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); + + struct_id = vkd3d_spirv_build_op_type_struct(builder, &type_id, 1); + vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0); + vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, + SpvDecorationOffset, parameter->u.buffer.offset); + + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, struct_id); + var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, + ptr_type_id, SpvStorageClassUniform, 0); + + vkd3d_spirv_build_op_decorate1(builder, var_id, SpvDecorationDescriptorSet, parameter->u.buffer.set); + vkd3d_spirv_build_op_decorate1(builder, var_id, SpvDecorationBinding, parameter->u.buffer.binding); + + compiler->spirv_parameter_info[i].buffer_id = var_id; + } + } + if (program->block_count && !spirv_compiler_init_blocks(compiler, program->block_count)) return VKD3D_ERROR_OUT_OF_MEMORY; diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index a7c37215e5e..3a9a402e8e2 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -2493,7 +2493,7 @@ fail: } static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, struct vsir_program *program, - const uint32_t *byte_code, size_t byte_code_size, const char *source_name, + const uint32_t *byte_code, size_t byte_code_size, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_version version; @@ -2552,9 +2552,9 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, struct vsir_pro version.minor = VKD3D_SM4_VERSION_MINOR(version_token); /* Estimate instruction count to avoid reallocation in most shaders. */ - if (!vsir_program_init(program, &version, token_count / 7u + 20)) + if (!vsir_program_init(program, compile_info, &version, token_count / 7u + 20)) return false; - vkd3d_shader_parser_init(&sm4->p, program, message_context, source_name); + vkd3d_shader_parser_init(&sm4->p, program, message_context, compile_info->source_name); sm4->ptr = sm4->start; init_sm4_lookup_tables(&sm4->lookup); @@ -2651,7 +2651,7 @@ int tpf_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t con } if (!shader_sm4_init(&sm4, program, dxbc_desc.byte_code, dxbc_desc.byte_code_size, - compile_info->source_name, message_context)) + compile_info, message_context)) { WARN("Failed to initialise shader parser.\n"); free_dxbc_shader_desc(&dxbc_desc); @@ -5189,6 +5189,44 @@ static void write_sm4_expr(const struct tpf_writer *tpf, const struct hlsl_ir_ex } break; + case HLSL_OP1_RCP: + switch (dst_type->e.numeric.type) + { + case HLSL_TYPE_FLOAT: + /* SM5 comes with a RCP opcode */ + if (tpf->ctx->profile->major_version >= 5) + { + write_sm4_unary_op(tpf, VKD3D_SM5_OP_RCP, &expr->node, arg1, 0); + } + else + { + /* For SM4, implement as DIV dst, 1.0, src */ + struct sm4_instruction instr; + struct hlsl_constant_value one; + + assert(type_is_float(dst_type)); + + memset(&instr, 0, sizeof(instr)); + instr.opcode = VKD3D_SM4_OP_DIV; + + sm4_dst_from_node(&instr.dsts[0], &expr->node); + instr.dst_count = 1; + + for (unsigned int i = 0; i < 4; i++) + one.u[i].f = 1.0f; + sm4_src_from_constant_value(&instr.srcs[0], &one, dst_type->dimx, instr.dsts[0].write_mask); + sm4_src_from_node(tpf, &instr.srcs[1], arg1, instr.dsts[0].write_mask); + instr.src_count = 2; + + write_sm4_instruction(tpf, &instr); + } + break; + + default: + hlsl_fixme(tpf->ctx, &expr->node.loc, "SM4 %s rcp expression.", dst_type_string->buffer); + } + break; + case HLSL_OP1_REINTERPRET: write_sm4_unary_op(tpf, VKD3D_SM4_OP_MOV, &expr->node, arg1, 0); break; diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 96e613669a6..bf9759ebbbf 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -619,6 +619,7 @@ enum vkd3d_shader_register_type VKD3DSPR_SSA, VKD3DSPR_WAVELANECOUNT, VKD3DSPR_WAVELANEINDEX, + VKD3DSPR_PARAMETER, VKD3DSPR_COUNT, @@ -1362,6 +1363,10 @@ struct vsir_program struct shader_signature output_signature; struct shader_signature patch_constant_signature; + unsigned int parameter_count; + const struct vkd3d_shader_parameter1 *parameters; + bool free_parameters; + unsigned int input_control_point_count, output_control_point_count; unsigned int flat_constant_count[3]; unsigned int block_count; @@ -1377,7 +1382,8 @@ void vsir_program_cleanup(struct vsir_program *program); int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); -bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve); +bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, + const struct vkd3d_shader_version *version, unsigned int reserve); enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, -- 2.43.0