From 98def3214bd373d086a19794c8150158583ed052 Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Fri, 7 Jun 2024 17:32:56 -0500 Subject: [PATCH] vkd3d-shader: Introduce struct vkd3d_shader_parameter_info and struct vkd3d_shader_parameter1. As the newly added documentation describes, this reroll serves two purposes: * to allow shader parameters to be used for any target type (which allows using parameters for things like Direct3D 8-9 alpha test), * to allow the union in struct vkd3d_shader_parameter to contain types larger than 32 bits (by specifying them indirectly through a pointer). --- include/vkd3d_shader.h | 58 ++++++++++++++++++++ libs/vkd3d-shader/d3dbc.c | 2 +- libs/vkd3d-shader/dxil.c | 11 ++-- libs/vkd3d-shader/hlsl_codegen.c | 2 +- libs/vkd3d-shader/ir.c | 68 +++++++++++++++++++++++- libs/vkd3d-shader/spirv.c | 16 +++--- libs/vkd3d-shader/tpf.c | 8 +-- libs/vkd3d-shader/vkd3d_shader_private.h | 7 ++- 8 files changed, 153 insertions(+), 19 deletions(-) diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index d3afcc11..a754a3d0 100644 --- a/include/vkd3d_shader.h +++ b/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), }; @@ -503,6 +508,20 @@ struct vkd3d_shader_parameter } u; }; +struct vkd3d_shader_parameter1 +{ + enum vkd3d_shader_parameter_name name; + enum vkd3d_shader_parameter_type type; + enum vkd3d_shader_parameter_data_type data_type; + union + { + struct vkd3d_shader_parameter_immediate_constant immediate_constant; + struct vkd3d_shader_parameter_specialization_constant specialization_constant; + 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 +2013,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 +2134,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-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 4522d56c..abfbd461 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/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-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 2176debc..bf581928 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/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-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 7e4f1686..02884df9 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/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-shader/ir.c b/libs/vkd3d-shader/ir.c index e5432cb3..a9cfa49b 100644 --- a/libs/vkd3d-shader/ir.c +++ b/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); diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index a5ace95e..d5a3bafd 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2418,6 +2418,8 @@ 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; bool prolog_emitted; struct shader_signature input_signature; @@ -3290,16 +3292,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; @@ -3396,7 +3397,7 @@ static uint32_t spirv_compiler_get_spec_constant(struct spirv_compiler *compiler static uint32_t spirv_compiler_emit_uint_shader_parameter(struct spirv_compiler *compiler, enum vkd3d_shader_parameter_name name) { - const struct vkd3d_shader_parameter *parameter; + const struct vkd3d_shader_parameter1 *parameter; if (!(parameter = spirv_compiler_get_shader_parameter(compiler, name))) { @@ -10570,6 +10571,9 @@ 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; + if (program->block_count && !spirv_compiler_init_blocks(compiler, program->block_count)) return VKD3D_ERROR_OUT_OF_MEMORY; diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index a3938d32..3a9a402e 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/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); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index f01f88c5..25a9c649 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1362,6 +1362,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 +1381,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,