From 9a5b8e1dc86435ee994f9c960ede88767f5da27f Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 24 Jan 2024 12:27:59 +1100 Subject: [PATCH] Updated vkd3d to bf628f0c74ae839bb20266cd10e07d1504ebc1bf. --- libs/vkd3d/libs/vkd3d-shader/dxbc.c | 5 - libs/vkd3d/libs/vkd3d-shader/dxil.c | 104 +++++-- libs/vkd3d/libs/vkd3d-shader/fx.c | 168 ++++++++++- libs/vkd3d/libs/vkd3d-shader/hlsl.c | 7 +- libs/vkd3d/libs/vkd3d-shader/hlsl.h | 3 + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 113 +++++-- libs/vkd3d/libs/vkd3d-shader/ir.c | 284 ++++++++++++------ libs/vkd3d/libs/vkd3d-shader/spirv.c | 72 ++++- libs/vkd3d/libs/vkd3d-shader/tpf.c | 8 +- .../libs/vkd3d-shader/vkd3d_shader_private.h | 12 +- libs/vkd3d/libs/vkd3d/device.c | 12 +- libs/vkd3d/libs/vkd3d/resource.c | 2 +- 12 files changed, 595 insertions(+), 195 deletions(-) diff --git a/libs/vkd3d/libs/vkd3d-shader/dxbc.c b/libs/vkd3d/libs/vkd3d-shader/dxbc.c index edb65d2e92f..37ebc73c099 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxbc.c @@ -552,14 +552,9 @@ static int shdr_handler(const struct vkd3d_shader_dxbc_section_desc *section, void free_shader_desc(struct vkd3d_shader_desc *desc) { - size_t i; - shader_signature_cleanup(&desc->input_signature); shader_signature_cleanup(&desc->output_signature); shader_signature_cleanup(&desc->patch_constant_signature); - for (i = 0; i < desc->block_name_count; ++i) - vkd3d_free((void *)desc->block_names[i]); - vkd3d_free(desc->block_names); } int shader_extract_from_dxbc(const struct vkd3d_shader_code *dxbc, diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c index 15cc380f5f2..2a0ff61cfeb 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -342,6 +342,12 @@ enum dx_intrinsic_opcode DX_FIRST_BIT_LO = 32, DX_FIRST_BIT_HI = 33, DX_FIRST_BIT_SHI = 34, + DX_FMAX = 35, + DX_FMIN = 36, + DX_IMAX = 37, + DX_IMIN = 38, + DX_UMAX = 39, + DX_UMIN = 40, DX_CREATE_HANDLE = 57, DX_CBUFFER_LOAD_LEGACY = 59, DX_BUFFER_LOAD = 68, @@ -1628,7 +1634,7 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) break; } - if (!ascii_strcasecmp(struct_name, "dx.types.Handle")) + if (!strcmp(struct_name, "dx.types.Handle")) sm6->handle_type = type; type->u.struc->name = struct_name; @@ -3546,6 +3552,41 @@ static void sm6_parser_emit_dx_unary(struct sm6_parser *sm6, enum dx_intrinsic_o instruction_dst_param_init_ssa_scalar(ins, sm6); } +static enum vkd3d_shader_opcode map_dx_binary_op(enum dx_intrinsic_opcode op, const struct sm6_type *type) +{ + switch (op) + { + case DX_FMAX: + return type->u.width == 64 ? VKD3DSIH_DMAX : VKD3DSIH_MAX; + case DX_FMIN: + return type->u.width == 64 ? VKD3DSIH_DMIN : VKD3DSIH_MIN; + case DX_IMAX: + return VKD3DSIH_IMAX; + case DX_IMIN: + return VKD3DSIH_IMIN; + case DX_UMAX: + return VKD3DSIH_UMAX; + case DX_UMIN: + return VKD3DSIH_UMIN; + default: + vkd3d_unreachable(); + } +} + +static void sm6_parser_emit_dx_binary(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + struct vkd3d_shader_instruction *ins = state->ins; + struct vkd3d_shader_src_param *src_params; + + vsir_instruction_init(ins, &sm6->p.location, map_dx_binary_op(op, operands[0]->type)); + src_params = instruction_src_params_alloc(ins, 2, sm6); + src_param_init_from_value(&src_params[0], operands[0]); + src_param_init_from_value(&src_params[1], operands[1]); + + instruction_dst_param_init_ssa_scalar(ins, sm6); +} + static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { @@ -3776,38 +3817,45 @@ struct sm6_dx_opcode_info H -> handle v -> void o -> overloaded + R -> matches the return type */ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = { - [DX_BFREV ] = {"m0", "m", sm6_parser_emit_dx_unary}, + [DX_BFREV ] = {"m", "R", sm6_parser_emit_dx_unary}, [DX_BUFFER_LOAD ] = {"o", "Hii", sm6_parser_emit_dx_buffer_load}, [DX_CBUFFER_LOAD_LEGACY ] = {"o", "Hi", sm6_parser_emit_dx_cbuffer_load}, [DX_COUNT_BITS ] = {"i", "m", sm6_parser_emit_dx_unary}, [DX_CREATE_HANDLE ] = {"H", "ccib", sm6_parser_emit_dx_create_handle}, - [DX_DERIV_COARSEX ] = {"e0", "e", sm6_parser_emit_dx_unary}, - [DX_DERIV_COARSEY ] = {"e0", "e", sm6_parser_emit_dx_unary}, - [DX_DERIV_FINEX ] = {"e0", "e", sm6_parser_emit_dx_unary}, - [DX_DERIV_FINEY ] = {"e0", "e", sm6_parser_emit_dx_unary}, - [DX_EXP ] = {"g0", "g", sm6_parser_emit_dx_unary}, + [DX_DERIV_COARSEX ] = {"e", "R", sm6_parser_emit_dx_unary}, + [DX_DERIV_COARSEY ] = {"e", "R", sm6_parser_emit_dx_unary}, + [DX_DERIV_FINEX ] = {"e", "R", sm6_parser_emit_dx_unary}, + [DX_DERIV_FINEY ] = {"e", "R", sm6_parser_emit_dx_unary}, + [DX_EXP ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_FIRST_BIT_HI ] = {"i", "m", sm6_parser_emit_dx_unary}, [DX_FIRST_BIT_LO ] = {"i", "m", sm6_parser_emit_dx_unary}, [DX_FIRST_BIT_SHI ] = {"i", "m", sm6_parser_emit_dx_unary}, - [DX_FRC ] = {"g0", "g", sm6_parser_emit_dx_unary}, + [DX_FMAX ] = {"g", "RR", sm6_parser_emit_dx_binary}, + [DX_FMIN ] = {"g", "RR", sm6_parser_emit_dx_binary}, + [DX_FRC ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_IMAX ] = {"m", "RR", sm6_parser_emit_dx_binary}, + [DX_IMIN ] = {"m", "RR", sm6_parser_emit_dx_binary}, [DX_LEGACY_F16TOF32 ] = {"f", "i", sm6_parser_emit_dx_unary}, [DX_LEGACY_F32TOF16 ] = {"i", "f", sm6_parser_emit_dx_unary}, [DX_LOAD_INPUT ] = {"o", "ii8i", sm6_parser_emit_dx_load_input}, - [DX_LOG ] = {"g0", "g", sm6_parser_emit_dx_unary}, - [DX_ROUND_NE ] = {"g0", "g", sm6_parser_emit_dx_unary}, - [DX_ROUND_NI ] = {"g0", "g", sm6_parser_emit_dx_unary}, - [DX_ROUND_PI ] = {"g0", "g", sm6_parser_emit_dx_unary}, - [DX_ROUND_Z ] = {"g0", "g", sm6_parser_emit_dx_unary}, - [DX_RSQRT ] = {"g0", "g", sm6_parser_emit_dx_unary}, - [DX_SQRT ] = {"g0", "g", sm6_parser_emit_dx_unary}, + [DX_LOG ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_ROUND_NE ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_ROUND_NI ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_ROUND_PI ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_ROUND_Z ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_RSQRT ] = {"g", "R", sm6_parser_emit_dx_unary}, + [DX_SQRT ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_STORE_OUTPUT ] = {"v", "ii8o", sm6_parser_emit_dx_store_output}, + [DX_UMAX ] = {"m", "RR", sm6_parser_emit_dx_binary}, + [DX_UMIN ] = {"m", "RR", sm6_parser_emit_dx_binary}, }; static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_value *value, char info_type, - bool is_return) + const struct sm6_type *ret_type, bool is_return) { const struct sm6_type *type = value->type; @@ -3843,23 +3891,14 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc case 'o': /* TODO: some type checking may be possible */ return true; + case 'R': + return type == ret_type; default: FIXME("Unhandled operand code '%c'.\n", info_type); return false; } } -static bool operand_types_match(struct sm6_value *dst, const struct sm6_value **operands, unsigned int operand_count, - char index_char) -{ - unsigned int i = index_char - '0'; - - assert(i < 10); - if (i >= operand_count) - return false; - return dst->type == operands[i]->type; -} - static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const char *name, const struct sm6_value **operands, unsigned int operand_count, struct sm6_value *dst) { @@ -3869,8 +3908,7 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_ info = &sm6_dx_op_table[op]; assert(info->ret_type[0]); - if (!sm6_parser_validate_operand_type(sm6, dst, info->ret_type[0], true) - || (info->ret_type[1] && !operand_types_match(dst, operands, operand_count, info->ret_type[1]))) + if (!sm6_parser_validate_operand_type(sm6, dst, info->ret_type[0], NULL, true)) { WARN("Failed to validate return type for dx intrinsic id %u, '%s'.\n", op, name); /* Return type validation failure is not so critical. We only need to set @@ -3880,7 +3918,7 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_ for (i = 0; i < operand_count; ++i) { const struct sm6_value *value = operands[i]; - if (!sm6_parser_validate_operand_type(sm6, value, info->operand_info[i], false)) + if (!sm6_parser_validate_operand_type(sm6, value, info->operand_info[i], dst->type, false)) { WARN("Failed to validate operand %u for dx intrinsic id %u, '%s'.\n", i + 1, op, name); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, @@ -5489,7 +5527,7 @@ static enum vkd3d_result sm6_function_emit_blocks(const struct sm6_function *fun { unsigned int i; - sm6->p.shader_desc.block_count = function->block_count; + sm6->p.program.block_count = function->block_count; for (i = 0; i < function->block_count; ++i) { @@ -6726,7 +6764,7 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) sm6->entry_point = value->u.function.name; if (!sm6_metadata_value_is_string(entry_node->operands[1]) - || ascii_strcasecmp(sm6->entry_point, entry_node->operands[1]->u.string_value)) + || strcmp(sm6->entry_point, entry_node->operands[1]->u.string_value)) { WARN("Entry point function name %s mismatch.\n", sm6->entry_point); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH, @@ -6916,7 +6954,7 @@ static struct sm6_function *sm6_parser_get_function(const struct sm6_parser *sm6 { size_t i; for (i = 0; i < sm6->function_count; ++i) - if (!ascii_strcasecmp(sm6->functions[i].declaration->u.function.name, name)) + if (!strcmp(sm6->functions[i].declaration->u.function.name, name)) return &sm6->functions[i]; return NULL; } diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c index 17b9627b6bd..e1459f76c14 100644 --- a/libs/vkd3d/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d/libs/vkd3d-shader/fx.c @@ -43,6 +43,15 @@ static void string_storage_destroy(struct rb_entry *entry, void *context) vkd3d_free(string_entry); } +struct fx_write_context; + +struct fx_write_context_ops +{ + uint32_t (*write_string)(const char *string, struct fx_write_context *fx); + void (*write_technique)(struct hlsl_ir_var *var, struct fx_write_context *fx); + void (*write_pass)(struct hlsl_ir_var *var, struct fx_write_context *fx); +}; + struct fx_write_context { struct hlsl_ctx *ctx; @@ -58,15 +67,29 @@ struct fx_write_context uint32_t technique_count; uint32_t group_count; int status; + + const struct fx_write_context_ops *ops; }; -static void fx_write_context_init(struct hlsl_ctx *ctx, struct fx_write_context *fx) +static uint32_t write_string(const char *string, struct fx_write_context *fx) +{ + return fx->ops->write_string(string, fx); +} + +static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + fx->ops->write_pass(var, fx); +} + +static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_context_ops *ops, + struct fx_write_context *fx) { unsigned int version = ctx->profile->major_version; memset(fx, 0, sizeof(*fx)); fx->ctx = ctx; + fx->ops = ops; if (version == 2) { fx->min_technique_version = 9; @@ -104,7 +127,7 @@ static bool technique_matches_version(const struct hlsl_ir_var *var, const struc return type->e.version >= fx->min_technique_version && type->e.version <= fx->max_technique_version; } -static uint32_t fx_put_raw_string(struct fx_write_context *fx, const char *string) +static uint32_t write_fx_4_string(const char *string, struct fx_write_context *fx) { struct string_entry *string_entry; struct rb_entry *entry; @@ -130,25 +153,42 @@ static uint32_t fx_put_raw_string(struct fx_write_context *fx, const char *strin return string_entry->offset; } -static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) +static void write_fx_4_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; uint32_t name_offset; - name_offset = fx_put_raw_string(fx, var->name); + name_offset = write_string(var->name, fx); + put_u32(buffer, name_offset); + put_u32(buffer, 0); /* Assignment count. */ + put_u32(buffer, 0); /* Annotation count. */ + + /* TODO: annotations */ + /* TODO: assignments */ +} + +static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->structured; + uint32_t name_offset; + + name_offset = write_string(var->name, fx); put_u32(buffer, name_offset); put_u32(buffer, 0); /* Annotation count. */ put_u32(buffer, 0); /* Assignment count. */ + + /* TODO: annotations */ + /* TODO: assignments */ } -static void write_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) +static void write_fx_4_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; uint32_t name_offset, count = 0; struct hlsl_ir_var *pass; uint32_t count_offset; - name_offset = fx_put_raw_string(fx, var->name); + name_offset = write_string(var->name, fx); put_u32(buffer, name_offset); count_offset = put_u32(buffer, 0); put_u32(buffer, 0); /* Annotation count. */ @@ -176,11 +216,9 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context * LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry) { - const struct hlsl_type *type = var->data_type; - - if (type->base_type == HLSL_TYPE_TECHNIQUE && type->e.version == 10) + if (technique_matches_version(var, fx)) { - write_technique(var, fx); + fx->ops->write_technique(var, fx); ++fx->technique_count; } } @@ -192,7 +230,7 @@ static void write_techniques(struct hlsl_scope *scope, struct fx_write_context * static void write_group(struct hlsl_scope *scope, const char *name, struct fx_write_context *fx) { struct vkd3d_bytecode_buffer *buffer = &fx->structured; - uint32_t name_offset = fx_put_raw_string(fx, name); + uint32_t name_offset = write_string(name, fx); uint32_t count_offset, count; put_u32(buffer, name_offset); @@ -231,13 +269,114 @@ static void write_groups(struct hlsl_scope *scope, struct fx_write_context *fx) } } +static uint32_t write_fx_2_string(const char *string, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + const char *s = string ? string : ""; + uint32_t size, offset; + + size = strlen(s) + 1; + offset = put_u32(buffer, size); + bytecode_put_bytes(buffer, s, size); + return offset; +} + +static void write_fx_2_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->structured; + uint32_t name_offset, count_offset, count = 0; + struct hlsl_ir_var *pass; + + name_offset = write_string(var->name, fx); + put_u32(buffer, name_offset); + put_u32(buffer, 0); /* Annotation count. */ + count_offset = put_u32(buffer, 0); /* Pass count. */ + + /* FIXME: annotations */ + + LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry) + { + write_pass(pass, fx); + ++count; + } + + set_u32(buffer, count_offset, count); +} + +static const struct fx_write_context_ops fx_2_ops = +{ + .write_string = write_fx_2_string, + .write_technique = write_fx_2_technique, + .write_pass = write_fx_2_pass, +}; + +static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) +{ + struct vkd3d_bytecode_buffer buffer = { 0 }; + struct vkd3d_bytecode_buffer *structured; + uint32_t offset, size, technique_count; + struct fx_write_context fx; + + fx_write_context_init(ctx, &fx_2_ops, &fx); + structured = &fx.structured; + + /* First entry is always zeroed and skipped. */ + put_u32(&fx.unstructured, 0); + + put_u32(&buffer, 0xfeff0901); /* Version. */ + offset = put_u32(&buffer, 0); + + put_u32(structured, 0); /* Parameter count */ + technique_count = put_u32(structured, 0); + put_u32(structured, 0); /* Unknown */ + put_u32(structured, 0); /* Object count */ + + /* TODO: parameters */ + + write_techniques(ctx->globals, &fx); + set_u32(structured, technique_count, fx.technique_count); + + put_u32(structured, 0); /* String count */ + put_u32(structured, 0); /* Resource count */ + + /* TODO: strings */ + /* TODO: resources */ + + size = align(fx.unstructured.size, 4); + set_u32(&buffer, offset, size); + + bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size); + bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size); + + vkd3d_free(fx.unstructured.data); + vkd3d_free(fx.structured.data); + + if (!fx.status) + { + out->code = buffer.data; + out->size = buffer.size; + } + + if (fx.status < 0) + ctx->result = fx.status; + + return fx_write_context_cleanup(&fx); +} + +static const struct fx_write_context_ops fx_4_ops = +{ + .write_string = write_fx_4_string, + .write_technique = write_fx_4_technique, + .write_pass = write_fx_4_pass, +}; + static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { struct vkd3d_bytecode_buffer buffer = { 0 }; struct fx_write_context fx; uint32_t size_offset, size; - fx_write_context_init(ctx, &fx); + fx_write_context_init(ctx, &fx_4_ops, &fx); put_u32(&fx.unstructured, 0); /* Empty string placeholder. */ @@ -297,7 +436,7 @@ static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) struct fx_write_context fx; uint32_t size_offset, size; - fx_write_context_init(ctx, &fx); + fx_write_context_init(ctx, &fx_4_ops, &fx); put_u32(&fx.unstructured, 0); /* Empty string placeholder. */ @@ -359,8 +498,7 @@ int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { if (ctx->profile->major_version == 2) { - hlsl_fixme(ctx, &ctx->location, "Writing fx_2_0 binaries is not implemented."); - return VKD3D_ERROR_NOT_IMPLEMENTED; + return hlsl_fx_2_write(ctx, out); } else if (ctx->profile->major_version == 4) { diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c index 6a5a6d0e3c1..04c37498d84 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c @@ -953,6 +953,8 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, type->modifiers |= default_majority; type->sampler_dim = old->sampler_dim; type->is_minimum_precision = old->is_minimum_precision; + type->sample_count = old->sample_count; + switch (old->class) { case HLSL_CLASS_ARRAY: @@ -1002,11 +1004,11 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, } case HLSL_CLASS_OBJECT: - { if (type->base_type == HLSL_TYPE_TECHNIQUE) type->e.version = old->e.version; + if (old->base_type == HLSL_TYPE_TEXTURE || old->base_type == HLSL_TYPE_UAV) + type->e.resource_format = old->e.resource_format; break; - } default: break; @@ -3366,6 +3368,7 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) {"vector", HLSL_CLASS_VECTOR, HLSL_TYPE_FLOAT, 4, 1}, {"matrix", HLSL_CLASS_MATRIX, HLSL_TYPE_FLOAT, 4, 4}, {"fxgroup", HLSL_CLASS_OBJECT, HLSL_TYPE_EFFECT_GROUP, 1, 1}, + {"pass", HLSL_CLASS_OBJECT, HLSL_TYPE_PASS, 1, 1}, {"STRING", HLSL_CLASS_OBJECT, HLSL_TYPE_STRING, 1, 1}, {"TEXTURE", HLSL_CLASS_OBJECT, HLSL_TYPE_TEXTURE, 1, 1}, {"PIXELSHADER", HLSL_CLASS_OBJECT, HLSL_TYPE_PIXELSHADER, 1, 1}, diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h index 8bc98b99e8a..984ac7e4883 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h @@ -95,6 +95,7 @@ enum hlsl_base_type HLSL_TYPE_UAV, HLSL_TYPE_PIXELSHADER, HLSL_TYPE_VERTEXSHADER, + HLSL_TYPE_PASS, HLSL_TYPE_TECHNIQUE, HLSL_TYPE_EFFECT_GROUP, HLSL_TYPE_STRING, @@ -408,6 +409,8 @@ struct hlsl_ir_var struct list extern_entry; /* Scope that variable itself defines, used to provide a container for techniques and passes. */ struct hlsl_scope *scope; + /* Scope that contains annotations for this variable. */ + struct hlsl_scope *annotations; /* Indexes of the IR instructions where the variable is first written and last read (liveness * range). The IR instructions are numerated starting from 2, because 0 means unused, and 1 diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y index c308916e07e..8dc353e11c0 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -292,6 +292,21 @@ static bool implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_typ return hlsl_types_are_componentwise_equal(ctx, src, dst); } +static void check_condition_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *cond) +{ + const struct hlsl_type *type = cond->data_type; + + if (type->class > HLSL_CLASS_LAST_NUMERIC || type->dimx > 1 || type->dimy > 1) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, type))) + hlsl_error(ctx, &cond->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Condition type '%s' is not a scalar numeric type.", string->buffer); + hlsl_release_string_buffer(ctx, string); + } +} + static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) { @@ -431,6 +446,9 @@ static bool append_conditional_break(struct hlsl_ctx *ctx, struct hlsl_block *co return true; condition = node_from_block(cond_block); + + check_condition_type(ctx, condition); + if (!(not = hlsl_new_unary_expr(ctx, HLSL_OP1_LOGIC_NOT, condition, &condition->loc))) return false; hlsl_block_add_instr(cond_block, not); @@ -1096,8 +1114,33 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters return true; } +static bool add_pass(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *annotations, + const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_var *var; + struct hlsl_type *type; + + type = hlsl_get_type(ctx->globals, "pass", false, false); + if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) + return false; + var->annotations = annotations; + + if (!hlsl_add_var(ctx, var, false)) + { + struct hlsl_ir_var *old = hlsl_get_var(ctx->cur_scope, var->name); + + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED, + "Identifier \"%s\" was already declared in this scope.", var->name); + hlsl_note(ctx, &old->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously declared here.", old->name); + hlsl_free_var(var); + return false; + } + + return true; +} + static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope, - const char *typename, const struct vkd3d_shader_location *loc) + struct hlsl_scope *annotations, const char *typename, const struct vkd3d_shader_location *loc) { struct hlsl_ir_var *var; struct hlsl_type *type; @@ -1106,6 +1149,7 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_sc if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) return false; var->scope = scope; + var->annotations = annotations; if (!hlsl_add_var(ctx, var, false)) { @@ -1122,7 +1166,7 @@ static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_sc } static bool add_effect_group(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope, - const struct vkd3d_shader_location *loc) + struct hlsl_scope *annotations, const struct vkd3d_shader_location *loc) { struct hlsl_ir_var *var; struct hlsl_type *type; @@ -1131,6 +1175,7 @@ static bool add_effect_group(struct hlsl_ctx *ctx, const char *name, struct hlsl if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL))) return false; var->scope = scope; + var->annotations = annotations; if (!hlsl_add_var(ctx, var, false)) { @@ -4999,6 +5044,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls struct hlsl_attribute *attr; struct parse_attribute_list attr_list; struct hlsl_ir_switch_case *switch_case; + struct hlsl_scope *scope; } %token KW_BLENDSTATE @@ -5124,6 +5170,8 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls %token STRING %token TYPE_IDENTIFIER +%type annotations_opt + %type arrays %type assign_op @@ -5240,7 +5288,33 @@ name_opt: | any_identifier pass: - KW_PASS name_opt '{' '}' + KW_PASS name_opt annotations_opt '{' '}' + { + if (!add_pass(ctx, $2, $3, &@1)) + YYABORT; + } + +annotations_list: + variables_def_typed ';' + | annotations_list variables_def_typed ';' + +annotations_opt: + %empty + { + $$ = NULL; + } + | '<' scope_start '>' + { + hlsl_pop_scope(ctx); + $$ = NULL; + } + | '<' scope_start annotations_list '>' + { + struct hlsl_scope *scope = ctx->cur_scope; + + hlsl_pop_scope(ctx); + $$ = scope; + } pass_list: pass @@ -5251,17 +5325,17 @@ passes: | scope_start pass_list technique9: - KW_TECHNIQUE name_opt '{' passes '}' + KW_TECHNIQUE name_opt annotations_opt '{' passes '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx); - if (!add_technique(ctx, $2, scope, "technique", &@1)) + if (!add_technique(ctx, $2, scope, $3, "technique", &@1)) YYABORT; } technique10: - KW_TECHNIQUE10 name_opt '{' passes '}' + KW_TECHNIQUE10 name_opt annotations_opt '{' passes '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx); @@ -5270,12 +5344,12 @@ technique10: hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique10' keyword is invalid for this profile."); - if (!add_technique(ctx, $2, scope, "technique10", &@1)) + if (!add_technique(ctx, $2, scope, $3, "technique10", &@1)) YYABORT; } technique11: - KW_TECHNIQUE11 name_opt '{' passes '}' + KW_TECHNIQUE11 name_opt annotations_opt '{' passes '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx); @@ -5284,7 +5358,7 @@ technique11: hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'technique11' keyword is invalid for this profile."); - if (!add_technique(ctx, $2, scope, "technique11", &@1)) + if (!add_technique(ctx, $2, scope, $3, "technique11", &@1)) YYABORT; } @@ -5302,11 +5376,11 @@ group_techniques: | group_techniques group_technique effect_group: - KW_FXGROUP any_identifier '{' scope_start group_techniques '}' + KW_FXGROUP any_identifier annotations_opt '{' scope_start group_techniques '}' { struct hlsl_scope *scope = ctx->cur_scope; hlsl_pop_scope(ctx); - if (!(add_effect_group(ctx, $2, scope, &@2))) + if (!(add_effect_group(ctx, $2, scope, $3, &@2))) YYABORT; } @@ -6689,6 +6763,15 @@ selection_statement: } } + check_condition_type(ctx, condition); + + if (!(condition = add_cast(ctx, $4, condition, hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL), &@4))) + { + destroy_block($6.then_block); + destroy_block($6.else_block); + YYABORT; + } + if (!(instr = hlsl_new_if(ctx, condition, $6.then_block, $6.else_block, &@2))) { destroy_block($6.then_block); @@ -6697,15 +6780,7 @@ selection_statement: } destroy_block($6.then_block); destroy_block($6.else_block); - if (condition->data_type->dimx > 1 || condition->data_type->dimy > 1) - { - struct vkd3d_string_buffer *string; - if ((string = hlsl_type_to_string(ctx, condition->data_type))) - hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "if condition type %s is not scalar.", string->buffer); - hlsl_release_string_buffer(ctx, string); - } $$ = $4; hlsl_block_add_instr($$, instr); } diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index a797e49308a..865a292cd62 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -26,6 +26,11 @@ bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_v void vsir_program_cleanup(struct vsir_program *program) { + size_t i; + + for (i = 0; i < program->block_name_count; ++i) + vkd3d_free((void *)program->block_names[i]); + vkd3d_free(program->block_names); shader_instruction_array_destroy(&program->instructions); } @@ -47,6 +52,19 @@ static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *i vsir_instruction_init(ins, &location, VKD3DSIH_NOP); } +static void remove_dcl_temps(struct vsir_program *program) +{ + unsigned int i; + + for (i = 0; i < program->instructions.count; ++i) + { + struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; + + if (ins->handler_idx == VKD3DSIH_DCL_TEMPS) + vkd3d_shader_instruction_make_nop(ins); + } +} + static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg, unsigned int instance_id) { @@ -154,9 +172,6 @@ struct hull_flattener { struct vkd3d_shader_instruction_array instructions; - unsigned int max_temp_count; - unsigned int temp_dcl_idx; - unsigned int instance_count; unsigned int phase_body_idx; enum vkd3d_shader_opcode phase; @@ -214,21 +229,6 @@ static void flattener_eliminate_phase_related_dcls(struct hull_flattener *normal vkd3d_shader_instruction_make_nop(ins); return; } - else if (ins->handler_idx == VKD3DSIH_DCL_TEMPS && normaliser->phase != VKD3DSIH_INVALID) - { - /* Leave only the first temp declaration and set it to the max count later. */ - if (!normaliser->max_temp_count) - { - normaliser->max_temp_count = ins->declaration.count; - normaliser->temp_dcl_idx = index; - } - else - { - normaliser->max_temp_count = max(normaliser->max_temp_count, ins->declaration.count); - vkd3d_shader_instruction_make_nop(ins); - } - return; - } if (normaliser->phase == VKD3DSIH_INVALID || shader_instruction_is_dcl(ins)) return; @@ -382,9 +382,6 @@ static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd if (flattener.phase != VKD3DSIH_INVALID) { - if (flattener.temp_dcl_idx) - instructions->elements[flattener.temp_dcl_idx].declaration.count = flattener.max_temp_count; - if (!shader_instruction_array_reserve(&flattener.instructions, flattener.instructions.count + 1)) return VKD3D_ERROR_OUT_OF_MEMORY; vsir_instruction_init(&instructions->elements[instructions->count++], &flattener.last_ret_location, VKD3DSIH_RET); @@ -581,9 +578,6 @@ struct io_normaliser struct shader_signature *output_signature; struct shader_signature *patch_constant_signature; - unsigned int max_temp_count; - unsigned int temp_dcl_idx; - unsigned int instance_count; unsigned int phase_body_idx; enum vkd3d_shader_opcode phase; @@ -2224,6 +2218,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_parser *parser) { + struct vsir_program *program = &parser->program; struct cf_flattener flattener = {0}; enum vkd3d_result result; @@ -2233,10 +2228,10 @@ static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_par if (result >= 0) { vkd3d_free(parser->program.instructions.elements); - parser->program.instructions.elements = flattener.instructions; - parser->program.instructions.capacity = flattener.instruction_capacity; - parser->program.instructions.count = flattener.instruction_count; - parser->shader_desc.block_count = flattener.block_id; + program->instructions.elements = flattener.instructions; + program->instructions.capacity = flattener.instruction_capacity; + program->instructions.count = flattener.instruction_count; + program->block_count = flattener.block_id; } else { @@ -2245,8 +2240,8 @@ static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_par vkd3d_free(flattener.control_flow_info); /* Simpler to always free these in free_shader_desc(). */ - parser->shader_desc.block_names = flattener.block_names; - parser->shader_desc.block_name_count = flattener.block_name_count; + program->block_names = flattener.block_names; + program->block_name_count = flattener.block_name_count; return result; } @@ -2257,41 +2252,48 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, struct vkd3d_shader_instruction_array *instructions = &parser->program.instructions; enum vkd3d_result result = VKD3D_OK; - if (parser->shader_desc.is_dxil) - return result; + remove_dcl_temps(&parser->program); - if (parser->program.shader_version.type != VKD3D_SHADER_TYPE_PIXEL - && (result = remap_output_signature(parser, compile_info)) < 0) - return result; - - if (parser->program.shader_version.type == VKD3D_SHADER_TYPE_HULL - && (result = instruction_array_flatten_hull_shader_phases(instructions)) >= 0) + if (!parser->shader_desc.is_dxil) { - result = instruction_array_normalise_hull_shader_control_point_io(instructions, - &parser->shader_desc.input_signature); - } - if (result >= 0) - result = shader_normalise_io_registers(parser); + if (parser->program.shader_version.type != VKD3D_SHADER_TYPE_PIXEL) + { + if ((result = remap_output_signature(parser, compile_info)) < 0) + return result; + } - if (result >= 0) - result = instruction_array_normalise_flat_constants(&parser->program); + if (parser->program.shader_version.type == VKD3D_SHADER_TYPE_HULL) + { + if ((result = instruction_array_flatten_hull_shader_phases(instructions)) < 0) + return result; + + if ((result = instruction_array_normalise_hull_shader_control_point_io(instructions, + &parser->shader_desc.input_signature)) < 0) + return result; + } + + if ((result = shader_normalise_io_registers(parser)) < 0) + return result; + + if ((result = instruction_array_normalise_flat_constants(&parser->program)) < 0) + return result; - if (result >= 0) remove_dead_code(&parser->program); - if (result >= 0) - result = flatten_control_flow_constructs(parser); + if ((result = flatten_control_flow_constructs(parser)) < 0) + return result; - if (result >= 0) - result = normalise_combined_samplers(parser); + if ((result = normalise_combined_samplers(parser)) < 0) + return result; + } - if (result >= 0 && TRACE_ON()) + if (TRACE_ON()) vkd3d_shader_trace(&parser->program); - if (result >= 0 && !parser->failed) - result = vsir_validate(parser); + if (!parser->failed && (result = vsir_validate(parser)) < 0) + return result; - if (result >= 0 && parser->failed) + if (parser->failed) result = VKD3D_ERROR_INVALID_SHADER; return result; @@ -2304,7 +2306,6 @@ struct validation_context size_t instruction_idx; bool invalid_instruction_idx; bool dcl_temps_found; - unsigned int temp_count; enum vkd3d_shader_opcode phase; enum cf_type { @@ -2312,6 +2313,7 @@ struct validation_context CF_TYPE_STRUCTURED, CF_TYPE_BLOCKS, } cf_type; + bool inside_block; struct validation_context_temp_data { @@ -2365,11 +2367,7 @@ static void vsir_validate_src_param(struct validation_context *ctx, static void vsir_validate_register(struct validation_context *ctx, const struct vkd3d_shader_register *reg) { - unsigned int i, temp_count = ctx->temp_count; - - /* SM1-3 shaders do not include a DCL_TEMPS instruction. */ - if (ctx->program->shader_version.major <= 3) - temp_count = ctx->program->temp_count; + unsigned int i; if (reg->type >= VKD3DSPR_COUNT) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, "Invalid register type %#x.", @@ -2414,18 +2412,13 @@ static void vsir_validate_register(struct validation_context *ctx, if (reg->idx[0].rel_addr) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a TEMP register."); - if (reg->idx[0].offset >= temp_count) + if (reg->idx[0].offset >= ctx->parser->program.temp_count) { validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "TEMP register index %u exceeds the maximum count %u.", - reg->idx[0].offset, temp_count); + reg->idx[0].offset, ctx->parser->program.temp_count); break; } - /* program->temp_count might be smaller then temp_count if the - * parser made a mistake; we still don't want to overflow the - * array. */ - if (reg->idx[0].offset >= ctx->program->temp_count) - break; data = &ctx->temps[reg->idx[0].offset]; if (reg->dimension == VSIR_DIMENSION_NONE) @@ -2524,9 +2517,10 @@ static void vsir_validate_register(struct validation_context *ctx, /* Index == 0 is invalid, but it is temporarily allowed * for intermediate stages. Once we support validation * dialects we can selectively check for that. */ - if (reg->idx[0].offset > ctx->parser->shader_desc.block_count) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "LABEL register index %u exceeds the maximum count %u.", - reg->idx[0].offset, ctx->parser->shader_desc.block_count); + if (reg->idx[0].offset > ctx->program->block_count) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "LABEL register index %u exceeds the maximum count %u.", + reg->idx[0].offset, ctx->program->block_count); break; case VKD3DSPR_NULL: @@ -2601,21 +2595,39 @@ static void vsir_validate_dst_param(struct validation_context *ctx, dst->shift); } - if (dst->reg.type == VKD3DSPR_SSA && dst->reg.idx[0].offset < ctx->program->ssa_count) + switch (dst->reg.type) { - struct validation_context_ssa_data *data = &ctx->ssas[dst->reg.idx[0].offset]; + case VKD3DSPR_SSA: + if (dst->reg.idx[0].offset < ctx->parser->program.ssa_count) + { + struct validation_context_ssa_data *data = &ctx->ssas[dst->reg.idx[0].offset]; - if (data->write_mask == 0) - { - data->write_mask = dst->write_mask; - data->first_assigned = ctx->instruction_idx; - } - else - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE, - "SSA register is already assigned at instruction %zu.", - data->first_assigned); - } + if (data->write_mask == 0) + { + data->write_mask = dst->write_mask; + data->first_assigned = ctx->instruction_idx; + } + else + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE, + "SSA register is already assigned at instruction %zu.", + data->first_assigned); + } + } + break; + + case VKD3DSPR_IMMCONST: + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid IMMCONST register used as destination parameter."); + break; + + case VKD3DSPR_IMMCONST64: + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid IMMCONST64 register used as destination parameter."); + break; + + default: + break; } } @@ -2636,13 +2648,21 @@ static void vsir_validate_src_param(struct validation_context *ctx, validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Source has invalid modifiers %#x.", src->modifiers); - if (src->reg.type == VKD3DSPR_SSA && src->reg.idx[0].offset < ctx->program->ssa_count) + switch (src->reg.type) { - struct validation_context_ssa_data *data = &ctx->ssas[src->reg.idx[0].offset]; - unsigned int i; + case VKD3DSPR_SSA: + if (src->reg.idx[0].offset < ctx->parser->program.ssa_count) + { + struct validation_context_ssa_data *data = &ctx->ssas[src->reg.idx[0].offset]; + unsigned int i; - for (i = 0; i < VKD3D_VEC4_SIZE; ++i) - data->read_mask |= (1u << vsir_swizzle_get_component(src->swizzle, i)); + for (i = 0; i < VKD3D_VEC4_SIZE; ++i) + data->read_mask |= (1u << vsir_swizzle_get_component(src->swizzle, i)); + } + break; + + default: + break; } } @@ -2752,7 +2772,6 @@ static void vsir_validate_instruction(struct validation_context *ctx) instruction->handler_idx); ctx->phase = instruction->handler_idx; ctx->dcl_temps_found = false; - ctx->temp_count = 0; return; default: @@ -2781,6 +2800,33 @@ static void vsir_validate_instruction(struct validation_context *ctx) ctx->cf_type = CF_TYPE_STRUCTURED; } + if (ctx->cf_type == CF_TYPE_BLOCKS && !vsir_instruction_is_dcl(instruction)) + { + switch (instruction->handler_idx) + { + case VKD3DSIH_LABEL: + if (ctx->inside_block) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid LABEL instruction inside a block."); + ctx->inside_block = true; + break; + + case VKD3DSIH_RET: + case VKD3DSIH_BRANCH: + case VKD3DSIH_SWITCH_MONOLITHIC: + if (!ctx->inside_block) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x outside any block.", + instruction->handler_idx); + ctx->inside_block = false; + break; + + default: + if (!ctx->inside_block) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x outside any block.", + instruction->handler_idx); + break; + } + } + switch (instruction->handler_idx) { case VKD3DSIH_DCL_TEMPS: @@ -2793,7 +2839,6 @@ static void vsir_validate_instruction(struct validation_context *ctx) "Invalid DCL_TEMPS count %u, expected at most %u.", instruction->declaration.count, ctx->program->temp_count); ctx->dcl_temps_found = true; - ctx->temp_count = instruction->declaration.count; break; case VKD3DSIH_IF: @@ -2988,6 +3033,62 @@ static void vsir_validate_instruction(struct validation_context *ctx) break; } + case VKD3DSIH_PHI: + { + unsigned int incoming_count; + + vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); + vsir_validate_dst_count(ctx, instruction, 1); + vsir_validate_src_min_count(ctx, instruction, 2); + if (instruction->src_count % 2 != 0) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, + "Invalid source count %u for a PHI instruction, it must be an even number.", + instruction->src_count); + incoming_count = instruction->src_count / 2; + + if (!register_is_ssa(&instruction->dst[0].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid destination of type %#x in PHI instruction, expected SSA.", + instruction->dst[0].reg.type); + + if (instruction->dst[0].reg.dimension != VSIR_DIMENSION_SCALAR) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid destination dimension %#x in PHI instruction, expected scalar.", + instruction->dst[0].reg.dimension); + + if (instruction->dst[0].modifiers != VKD3DSPDM_NONE) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, + "Invalid modifiers %#x for the destination of a PHI instruction, expected none.", + instruction->dst[0].modifiers); + + if (instruction->dst[0].shift != 0) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT, + "Invalid shift %#x for the destination of a PHI instruction, expected none.", + instruction->dst[0].shift); + + for (i = 0; i < incoming_count; ++i) + { + unsigned int value_idx = 2 * i; + unsigned int label_idx = 2 * i + 1; + + if (!register_is_constant(&instruction->src[value_idx].reg) && !register_is_ssa(&instruction->src[value_idx].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid value register for incoming %zu of type %#x in PHI instruction, " + "expected SSA, IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); + + if (instruction->src[value_idx].reg.dimension != VSIR_DIMENSION_SCALAR) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid value dimension %#x for incoming %zu in PHI instruction, expected scalar.", + instruction->src[value_idx].reg.dimension, i); + + if (!vsir_register_is_label(&instruction->src[label_idx].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid label register for case %zu of type %#x in PHI instruction, " + "expected LABEL.", i, instruction->src[value_idx].reg.type); + } + break; + } + default: break; } @@ -3020,6 +3121,9 @@ enum vkd3d_result vsir_validate(struct vkd3d_shader_parser *parser) if (ctx.depth != 0) validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "%zu nested blocks were not closed.", ctx.depth); + if (ctx.inside_block) + validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Last block was not closed."); + for (i = 0; i < ctx.program->ssa_count; ++i) { struct validation_context_ssa_data *data = &ctx.ssas[i]; diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c index e99724ca21c..3b2e45829fd 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -2328,6 +2328,7 @@ struct spirv_compiler uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */ uint32_t private_output_variable_write_mask[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */ uint32_t epilogue_function_id; + uint32_t discard_function_id; uint32_t binding_idx; @@ -7626,16 +7627,39 @@ static void spirv_compiler_emit_retc(struct spirv_compiler *compiler, vkd3d_spirv_build_op_label(builder, merge_block_id); } -static void spirv_compiler_emit_kill(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) +static uint32_t spirv_compiler_get_discard_function_id(struct spirv_compiler *compiler) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t target_id, merge_block_id; - target_id = vkd3d_spirv_alloc_id(builder); - merge_block_id = spirv_compiler_emit_conditional_branch(compiler, instruction, target_id); + if (!compiler->discard_function_id) + compiler->discard_function_id = vkd3d_spirv_alloc_id(builder); - vkd3d_spirv_build_op_label(builder, target_id); + return compiler->discard_function_id; +} + +static void spirv_compiler_emit_discard_function(struct spirv_compiler *compiler) +{ + uint32_t void_id, bool_id, function_type_id, condition_id, target_block_id, merge_block_id; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + + vkd3d_spirv_build_op_name(builder, compiler->discard_function_id, "discard"); + + void_id = vkd3d_spirv_get_op_type_void(builder); + bool_id = vkd3d_spirv_get_op_type_bool(builder); + function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, &bool_id, 1); + + vkd3d_spirv_build_op_function(builder, void_id, compiler->discard_function_id, + SpvFunctionControlMaskNone, function_type_id); + condition_id = vkd3d_spirv_build_op_function_parameter(builder, bool_id); + + vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); + + target_block_id = vkd3d_spirv_alloc_id(builder); + merge_block_id = vkd3d_spirv_alloc_id(builder); + vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone); + vkd3d_spirv_build_op_branch_conditional(builder, condition_id, target_block_id, merge_block_id); + + vkd3d_spirv_build_op_label(builder, target_block_id); if (spirv_compiler_is_target_extension_supported(compiler, VKD3D_SHADER_SPIRV_EXTENSION_EXT_DEMOTE_TO_HELPER_INVOCATION)) @@ -7650,6 +7674,26 @@ static void spirv_compiler_emit_kill(struct spirv_compiler *compiler, } vkd3d_spirv_build_op_label(builder, merge_block_id); + vkd3d_spirv_build_op_return(builder); + vkd3d_spirv_build_op_function_end(builder); +} + +static void spirv_compiler_emit_discard(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_src_param *src = instruction->src; + uint32_t condition_id, void_id; + + /* discard is not a block terminator in VSIR, and emitting it as such in SPIR-V would cause + * a mismatch between the VSIR structure and the SPIR-V one, which would cause problems if + * structurisation is necessary. Therefore we emit it as a function call. */ + condition_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0); + condition_id = spirv_compiler_emit_int_to_bool(compiler, + instruction->flags, src->reg.data_type, 1, 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); } static bool spirv_compiler_init_blocks(struct spirv_compiler *compiler, unsigned int block_count) @@ -9515,7 +9559,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, break; case VKD3DSIH_DISCARD: case VKD3DSIH_TEXKILL: - spirv_compiler_emit_kill(compiler, instruction); + spirv_compiler_emit_discard(compiler, instruction); break; case VKD3DSIH_LABEL: spirv_compiler_emit_label(compiler, instruction); @@ -9635,7 +9679,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_RESOURCE_RAW: case VKD3DSIH_DCL_RESOURCE_STRUCTURED: case VKD3DSIH_DCL_SAMPLER: - case VKD3DSIH_DCL_TEMPS: case VKD3DSIH_DCL_UAV_RAW: case VKD3DSIH_DCL_UAV_STRUCTURED: case VKD3DSIH_DCL_UAV_TYPED: @@ -9747,7 +9790,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, compiler->location.column = 0; compiler->location.line = 1; - if (parser->shader_desc.block_count && !spirv_compiler_init_blocks(compiler, parser->shader_desc.block_count)) + if (program->block_count && !spirv_compiler_init_blocks(compiler, program->block_count)) return VKD3D_ERROR_OUT_OF_MEMORY; instructions = program->instructions; @@ -9760,11 +9803,11 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, memset(&shader_desc->output_signature, 0, sizeof(shader_desc->output_signature)); memset(&shader_desc->patch_constant_signature, 0, sizeof(shader_desc->patch_constant_signature)); compiler->use_vocp = program->use_vocp; - compiler->block_names = parser->shader_desc.block_names; - compiler->block_name_count = parser->shader_desc.block_name_count; + compiler->block_names = program->block_names; + compiler->block_name_count = program->block_name_count; - compiler->input_control_point_count = shader_desc->input_control_point_count; - compiler->output_control_point_count = shader_desc->output_control_point_count; + compiler->input_control_point_count = program->input_control_point_count; + compiler->output_control_point_count = program->output_control_point_count; if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) spirv_compiler_emit_shader_signature_outputs(compiler); @@ -9802,6 +9845,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, } } + if (compiler->discard_function_id) + spirv_compiler_emit_discard_function(compiler); + if (compiler->epilogue_function_id) { vkd3d_spirv_build_op_name(builder, compiler->epilogue_function_id, "epilogue"); diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index df10cd254d6..50146c2c7c9 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -1051,7 +1051,7 @@ static void shader_sm4_read_dcl_input_primitive(struct vkd3d_shader_instruction { ins->declaration.primitive_type.type = VKD3D_PT_PATCH; ins->declaration.primitive_type.patch_vertex_count = primitive_type - VKD3D_SM5_INPUT_PT_PATCH1 + 1; - priv->p.shader_desc.input_control_point_count = ins->declaration.primitive_type.patch_vertex_count; + priv->p.program.input_control_point_count = ins->declaration.primitive_type.patch_vertex_count; } else if (primitive_type >= ARRAY_SIZE(input_primitive_type_table)) { @@ -1060,7 +1060,7 @@ static void shader_sm4_read_dcl_input_primitive(struct vkd3d_shader_instruction else { ins->declaration.primitive_type.type = input_primitive_type_table[primitive_type].vkd3d_type; - priv->p.shader_desc.input_control_point_count = input_primitive_type_table[primitive_type].control_point_count; + priv->p.program.input_control_point_count = input_primitive_type_table[primitive_type].control_point_count; } if (ins->declaration.primitive_type.type == VKD3D_PT_UNDEFINED) @@ -1174,9 +1174,9 @@ static void shader_sm5_read_control_point_count(struct vkd3d_shader_instruction >> VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT; if (opcode == VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT) - priv->p.shader_desc.input_control_point_count = ins->declaration.count; + priv->p.program.input_control_point_count = ins->declaration.count; else - priv->p.shader_desc.output_control_point_count = ins->declaration.count; + priv->p.program.output_control_point_count = ins->declaration.count; } static void shader_sm5_read_dcl_tessellator_domain(struct vkd3d_shader_instruction *ins, uint32_t opcode, diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 2d5e25d7f05..115a7d8c83b 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1020,17 +1020,10 @@ struct vkd3d_shader_desc struct shader_signature output_signature; struct shader_signature patch_constant_signature; - unsigned int input_control_point_count, output_control_point_count; - - unsigned int block_count; - struct { uint32_t used, external; } flat_constant_count[3]; - - const char **block_names; - size_t block_name_count; }; struct vkd3d_shader_register_semantic @@ -1271,9 +1264,14 @@ struct vsir_program struct vkd3d_shader_version shader_version; struct vkd3d_shader_instruction_array instructions; + unsigned int input_control_point_count, output_control_point_count; + unsigned int block_count; unsigned int temp_count; unsigned int ssa_count; bool use_vocp; + + const char **block_names; + size_t block_name_count; }; bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve); diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c index 75efa41fd32..2b8558175e0 100644 --- a/libs/vkd3d/libs/vkd3d/device.c +++ b/libs/vkd3d/libs/vkd3d/device.c @@ -594,7 +594,7 @@ static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance, if (FAILED(hr = vkd3d_init_vk_global_procs(instance, create_info->pfn_vkGetInstanceProcAddr))) { - ERR("Failed to initialize Vulkan global procs, hr %#x.\n", hr); + ERR("Failed to initialise Vulkan global procs, hr %s.\n", debugstr_hresult(hr)); return hr; } @@ -674,7 +674,7 @@ static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance, if (FAILED(hr = vkd3d_load_vk_instance_procs(&instance->vk_procs, vk_global_procs, vk_instance))) { - ERR("Failed to load instance procs, hr %#x.\n", hr); + ERR("Failed to load instance procs, hr %s.\n", debugstr_hresult(hr)); if (instance->vk_procs.vkDestroyInstance) instance->vk_procs.vkDestroyInstance(vk_instance, NULL); if (instance->libvulkan) @@ -2071,7 +2071,7 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device, if (FAILED(hr = vkd3d_load_vk_device_procs(&device->vk_procs, vk_procs, vk_device))) { - ERR("Failed to load device procs, hr %#x.\n", hr); + ERR("Failed to load device procs, hr %s.\n", debugstr_hresult(hr)); if (device->vk_procs.vkDestroyDevice) device->vk_procs.vkDestroyDevice(vk_device, NULL); return hr; @@ -2081,7 +2081,7 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device, if (FAILED(hr = d3d12_device_create_vkd3d_queues(device, &device_queue_info))) { - ERR("Failed to create queues, hr %#x.\n", hr); + ERR("Failed to create queues, hr %s.\n", debugstr_hresult(hr)); device->vk_procs.vkDestroyDevice(vk_device, NULL); return hr; } @@ -4404,7 +4404,7 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, if (device->use_vk_heaps && FAILED(hr = vkd3d_create_thread(device->vkd3d_instance, device_worker_main, device, &device->worker_thread))) { - WARN("Failed to create worker thread, hr %#x.\n", hr); + WARN("Failed to create worker thread, hr %s.\n", debugstr_hresult(hr)); goto out_cleanup_descriptor_heap_layouts; } @@ -4582,7 +4582,7 @@ HRESULT vkd3d_join_thread(struct vkd3d_instance *instance, union vkd3d_thread_ha if (instance->join_thread) { if (FAILED(hr = instance->join_thread(thread->handle))) - ERR("Failed to join thread, hr %#x.\n", hr); + ERR("Failed to join thread, hr %s.\n", debugstr_hresult(hr)); } else { diff --git a/libs/vkd3d/libs/vkd3d/resource.c b/libs/vkd3d/libs/vkd3d/resource.c index f9e50335fa8..a360b0ef4dd 100644 --- a/libs/vkd3d/libs/vkd3d/resource.c +++ b/libs/vkd3d/libs/vkd3d/resource.c @@ -4923,7 +4923,7 @@ HRESULT vkd3d_init_null_resources(struct vkd3d_null_resources *null_resources, return vkd3d_init_null_resources_data(null_resources, device); fail: - ERR("Failed to initialize NULL resources, hr %#x.\n", hr); + ERR("Failed to initialise NULL resources, hr %s.\n", debugstr_hresult(hr)); vkd3d_destroy_null_resources(null_resources, device); return hr; } -- 2.43.0