From ddc89bca32897d5d4ad81a9a566ba987f49c91de Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Tue, 15 Oct 2024 07:31:45 +1100 Subject: [PATCH] Updated vkd3d to 9dd42d15ddca66458042b5e4b7775fa054b4b0a2. --- libs/vkd3d/include/vkd3d_shader.h | 5 + libs/vkd3d/libs/vkd3d-shader/fx.c | 504 ++++++++++++- libs/vkd3d/libs/vkd3d-shader/ir.c | 678 +++++++++++------- .../libs/vkd3d-shader/vkd3d_shader_main.c | 14 + .../libs/vkd3d-shader/vkd3d_shader_private.h | 5 + 5 files changed, 909 insertions(+), 297 deletions(-) diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h index e22f236ecd1..5c0d13ea9e2 100644 --- a/libs/vkd3d/include/vkd3d_shader.h +++ b/libs/vkd3d/include/vkd3d_shader.h @@ -1181,6 +1181,11 @@ enum vkd3d_shader_source_type * the format used for Direct3D shader model 6 shaders. \since 1.9 */ VKD3D_SHADER_SOURCE_DXBC_DXIL, + /** + * Binary format used by Direct3D 9/10.x/11 effects. + * Input is a raw FX section without container. \since 1.14 + */ + VKD3D_SHADER_SOURCE_FX, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SOURCE_TYPE), }; diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c index cc18857a010..e98dfcf4f32 100644 --- a/libs/vkd3d/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d/libs/vkd3d-shader/fx.c @@ -470,26 +470,48 @@ static uint32_t get_fx_4_type_size(const struct hlsl_type *type) return type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float) * elements_count; } -static const uint32_t fx_4_numeric_base_type[] = +enum fx_4_type_constants +{ + /* Numeric types encoding */ + FX_4_NUMERIC_TYPE_FLOAT = 1, + FX_4_NUMERIC_TYPE_INT = 2, + FX_4_NUMERIC_TYPE_UINT = 3, + FX_4_NUMERIC_TYPE_BOOL = 4, + + FX_4_NUMERIC_CLASS_SCALAR = 1, + FX_4_NUMERIC_CLASS_VECTOR = 2, + FX_4_NUMERIC_CLASS_MATRIX = 3, + + FX_4_NUMERIC_BASE_TYPE_SHIFT = 3, + FX_4_NUMERIC_ROWS_SHIFT = 8, + FX_4_NUMERIC_COLUMNS_SHIFT = 11, + FX_4_NUMERIC_COLUMN_MAJOR_MASK = 0x4000, + + /* Object types */ + FX_4_OBJECT_TYPE_STRING = 1, + + /* Types */ + FX_4_TYPE_CLASS_NUMERIC = 1, + FX_4_TYPE_CLASS_OBJECT = 2, + FX_4_TYPE_CLASS_STRUCT = 3, +}; + +static const uint32_t fx_4_numeric_base_types[] = { - [HLSL_TYPE_HALF] = 1, - [HLSL_TYPE_FLOAT] = 1, - [HLSL_TYPE_INT ] = 2, - [HLSL_TYPE_UINT ] = 3, - [HLSL_TYPE_BOOL ] = 4, + [HLSL_TYPE_HALF ] = FX_4_NUMERIC_TYPE_FLOAT, + [HLSL_TYPE_FLOAT] = FX_4_NUMERIC_TYPE_FLOAT, + [HLSL_TYPE_INT ] = FX_4_NUMERIC_TYPE_INT, + [HLSL_TYPE_UINT ] = FX_4_NUMERIC_TYPE_UINT, + [HLSL_TYPE_BOOL ] = FX_4_NUMERIC_TYPE_BOOL, }; static uint32_t get_fx_4_numeric_type_description(const struct hlsl_type *type, struct fx_write_context *fx) { - static const unsigned int NUMERIC_BASE_TYPE_SHIFT = 3; - static const unsigned int NUMERIC_ROWS_SHIFT = 8; - static const unsigned int NUMERIC_COLUMNS_SHIFT = 11; - static const unsigned int NUMERIC_COLUMN_MAJOR_MASK = 0x4000; static const uint32_t numeric_type_class[] = { - [HLSL_CLASS_SCALAR] = 1, - [HLSL_CLASS_VECTOR] = 2, - [HLSL_CLASS_MATRIX] = 3, + [HLSL_CLASS_SCALAR] = FX_4_NUMERIC_CLASS_SCALAR, + [HLSL_CLASS_VECTOR] = FX_4_NUMERIC_CLASS_VECTOR, + [HLSL_CLASS_MATRIX] = FX_4_NUMERIC_CLASS_MATRIX, }; struct hlsl_ctx *ctx = fx->ctx; uint32_t value = 0; @@ -513,17 +535,17 @@ static uint32_t get_fx_4_numeric_type_description(const struct hlsl_type *type, case HLSL_TYPE_INT: case HLSL_TYPE_UINT: case HLSL_TYPE_BOOL: - value |= (fx_4_numeric_base_type[type->e.numeric.type] << NUMERIC_BASE_TYPE_SHIFT); + value |= (fx_4_numeric_base_types[type->e.numeric.type] << FX_4_NUMERIC_BASE_TYPE_SHIFT); break; default: hlsl_fixme(ctx, &ctx->location, "Not implemented for base type %u.", type->e.numeric.type); return 0; } - value |= (type->dimy & 0x7) << NUMERIC_ROWS_SHIFT; - value |= (type->dimx & 0x7) << NUMERIC_COLUMNS_SHIFT; + value |= (type->dimy & 0x7) << FX_4_NUMERIC_ROWS_SHIFT; + value |= (type->dimx & 0x7) << FX_4_NUMERIC_COLUMNS_SHIFT; if (type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR) - value |= NUMERIC_COLUMN_MAJOR_MASK; + value |= FX_4_NUMERIC_COLUMN_MAJOR_MASK; return value; } @@ -651,7 +673,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co case HLSL_CLASS_SCALAR: case HLSL_CLASS_VECTOR: case HLSL_CLASS_MATRIX: - put_u32_unaligned(buffer, 1); + put_u32_unaligned(buffer, FX_4_TYPE_CLASS_NUMERIC); break; case HLSL_CLASS_DEPTH_STENCIL_STATE: @@ -669,11 +691,11 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_STRING: - put_u32_unaligned(buffer, 2); + put_u32_unaligned(buffer, FX_4_TYPE_CLASS_OBJECT); break; case HLSL_CLASS_STRUCT: - put_u32_unaligned(buffer, 3); + put_u32_unaligned(buffer, FX_4_TYPE_CLASS_STRUCT); break; case HLSL_CLASS_ARRAY: @@ -794,7 +816,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co } else if (element_type->class == HLSL_CLASS_STRING) { - put_u32_unaligned(buffer, 1); + put_u32_unaligned(buffer, FX_4_OBJECT_TYPE_STRING); } else if (hlsl_is_numeric_type(element_type)) { @@ -1543,7 +1565,7 @@ static uint32_t write_fx_4_state_numeric_value(struct hlsl_ir_constant *value, s case HLSL_TYPE_INT: case HLSL_TYPE_UINT: case HLSL_TYPE_BOOL: - type = fx_4_numeric_base_type[data_type->e.numeric.type]; + type = fx_4_numeric_base_types[data_type->e.numeric.type]; break; default: type = 0; @@ -2814,3 +2836,441 @@ int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) vkd3d_unreachable(); } } + +struct fx_parser +{ + const uint8_t *ptr, *start, *end; + struct vkd3d_shader_message_context *message_context; + struct vkd3d_string_buffer buffer; + struct + { + const uint8_t *ptr; + const uint8_t *end; + uint32_t size; + } unstructured; + uint32_t buffer_count; + uint32_t object_count; + bool failed; +}; + +static uint32_t fx_parser_read_u32(struct fx_parser *parser) +{ + uint32_t ret; + + if ((parser->end - parser->ptr) < sizeof(uint32_t)) + { + parser->failed = true; + return 0; + } + + ret = *(uint32_t *)parser->ptr; + parser->ptr += sizeof(uint32_t); + + return ret; +} + +static void fx_parser_read_u32s(struct fx_parser *parser, void *dst, size_t size) +{ + uint32_t *ptr = dst; + size_t i; + + for (i = 0; i < size / sizeof(uint32_t); ++i) + ptr[i] = fx_parser_read_u32(parser); +} + +static void fx_parser_skip(struct fx_parser *parser, size_t size) +{ + if ((parser->end - parser->ptr) < size) + { + parser->ptr = parser->end; + parser->failed = true; + return; + } + parser->ptr += size; +} + +static void VKD3D_PRINTF_FUNC(3, 4) fx_parser_error(struct fx_parser *parser, enum vkd3d_shader_error error, + const char *format, ...) +{ + va_list args; + + va_start(args, format); + vkd3d_shader_verror(parser->message_context, NULL, error, format, args); + va_end(args); + + parser->failed = true; +} + +static int fx_2_parse(struct fx_parser *parser) +{ + fx_parser_error(parser, VKD3D_SHADER_ERROR_FX_NOT_IMPLEMENTED, "Parsing fx_2_0 binaries is not implemented.\n"); + + return -1; +} + +static void fx_parser_read_unstructured(struct fx_parser *parser, void *dst, uint32_t offset, size_t size) +{ + const uint8_t *ptr = parser->unstructured.ptr; + + memset(dst, 0, size); + if (offset >= parser->unstructured.size + || size > parser->unstructured.size - offset) + { + parser->failed = true; + return; + } + + ptr += offset; + memcpy(dst, ptr, size); +} + +static const char *fx_4_get_string(struct fx_parser *parser, uint32_t offset) +{ + const uint8_t *ptr = parser->unstructured.ptr; + const uint8_t *end = parser->unstructured.end; + + if (offset >= parser->unstructured.size) + { + parser->failed = true; + return ""; + } + + ptr += offset; + + while (ptr < end && *ptr) + ++ptr; + + if (*ptr) + { + parser->failed = true; + return ""; + } + + return (const char *)(parser->unstructured.ptr + offset); +} + +static void fx_parse_fx_4_numeric_variables(struct fx_parser *parser, uint32_t count) +{ + struct fx_4_numeric_variable + { + uint32_t name; + uint32_t type; + uint32_t semantic; + uint32_t offset; + uint32_t value; + uint32_t flags; + } var; + struct fx_4_type + { + uint32_t name; + uint32_t class; + uint32_t element_count; + uint32_t unpacked_size; + uint32_t stride; + uint32_t packed_size; + uint32_t typeinfo; + } type; + const char *name, *semantic, *type_name; + uint32_t i; + + for (i = 0; i < count; ++i) + { + fx_parser_read_u32s(parser, &var, sizeof(var)); + fx_parser_read_unstructured(parser, &type, var.type, sizeof(type)); + + name = fx_4_get_string(parser, var.name); + type_name = fx_4_get_string(parser, type.name); + + vkd3d_string_buffer_printf(&parser->buffer, " %s %s", type_name, name); + if (type.element_count) + vkd3d_string_buffer_printf(&parser->buffer, "[%u]", type.element_count); + if (var.semantic) + { + semantic = fx_4_get_string(parser, var.semantic); + vkd3d_string_buffer_printf(&parser->buffer, " : %s", semantic); + } + if (var.value) + { + unsigned int base_type, comp_count; + size_t j; + + if (type.class == FX_4_TYPE_CLASS_NUMERIC) + base_type = (type.typeinfo >> FX_4_NUMERIC_BASE_TYPE_SHIFT) & 0xf; + else + base_type = 0; + + vkd3d_string_buffer_printf(&parser->buffer, " = { "); + + comp_count = type.unpacked_size / sizeof(uint32_t); + for (j = 0; j < comp_count; ++j) + { + union hlsl_constant_value_component value; + + fx_parser_read_unstructured(parser, &value, var.value + j * sizeof(uint32_t), sizeof(uint32_t)); + + if (base_type == FX_4_NUMERIC_TYPE_FLOAT) + vkd3d_string_buffer_printf(&parser->buffer, "%f", value.f); + else if (base_type == FX_4_NUMERIC_TYPE_INT) + vkd3d_string_buffer_printf(&parser->buffer, "%d", value.i); + else if (base_type == FX_4_NUMERIC_TYPE_UINT) + vkd3d_string_buffer_printf(&parser->buffer, "%u", value.u); + else if (base_type == FX_4_NUMERIC_TYPE_BOOL) + vkd3d_string_buffer_printf(&parser->buffer, "%s", value.u ? "true" : "false" ); + else + vkd3d_string_buffer_printf(&parser->buffer, "%#x", value.u); + + if (j < comp_count - 1) + vkd3d_string_buffer_printf(&parser->buffer, ", "); + } + + vkd3d_string_buffer_printf(&parser->buffer, " }"); + } + vkd3d_string_buffer_printf(&parser->buffer, "; // Offset: %u, size %u.\n", var.offset, type.unpacked_size); + + if (fx_parser_read_u32(parser)) + { + fx_parser_error(parser, VKD3D_SHADER_ERROR_FX_NOT_IMPLEMENTED, "Parsing annotations is not implemented.\n"); + return; + } + } +} + +static void fx_parse_buffers(struct fx_parser *parser) +{ + struct fx_buffer + { + uint32_t name; + uint32_t size; + uint32_t flags; + uint32_t count; + uint32_t bind_point; + } buffer; + const char *name; + uint32_t i; + + if (parser->failed) + return; + + for (i = 0; i < parser->buffer_count; ++i) + { + fx_parser_read_u32s(parser, &buffer, sizeof(buffer)); + + name = fx_4_get_string(parser, buffer.name); + + vkd3d_string_buffer_printf(&parser->buffer, "cbuffer %s\n", name); + vkd3d_string_buffer_printf(&parser->buffer, "{\n"); + + if (fx_parser_read_u32(parser)) + { + fx_parser_error(parser, VKD3D_SHADER_ERROR_FX_NOT_IMPLEMENTED, "Parsing annotations is not implemented.\n"); + return; + } + + fx_parse_fx_4_numeric_variables(parser, buffer.count); + + vkd3d_string_buffer_printf(&parser->buffer, "}\n\n"); + } +} + +static void fx_4_parse_string_initializer(struct fx_parser *parser, uint32_t offset) +{ + const char *str = fx_4_get_string(parser, offset); + vkd3d_string_buffer_printf(&parser->buffer, "\"%s\"", str); +} + +static void fx_4_parse_objects(struct fx_parser *parser) +{ + struct fx_4_object_variable + { + uint32_t name; + uint32_t type; + uint32_t semantic; + uint32_t bind_point; + } var; + struct fx_4_type + { + uint32_t name; + uint32_t class; + uint32_t element_count; + uint32_t unpacked_size; + uint32_t stride; + uint32_t packed_size; + uint32_t typeinfo; + } type; + uint32_t i, j, value, element_count; + const char *name, *type_name; + + if (parser->failed) + return; + + for (i = 0; i < parser->object_count; ++i) + { + fx_parser_read_u32s(parser, &var, sizeof(var)); + fx_parser_read_unstructured(parser, &type, var.type, sizeof(type)); + + name = fx_4_get_string(parser, var.name); + type_name = fx_4_get_string(parser, type.name); + vkd3d_string_buffer_printf(&parser->buffer, "%s %s", type_name, name); + if (type.element_count) + vkd3d_string_buffer_printf(&parser->buffer, "[%u]", type.element_count); + vkd3d_string_buffer_printf(&parser->buffer, " = {\n"); + + element_count = max(type.element_count, 1); + for (j = 0; j < element_count; ++j) + { + switch (type.typeinfo) + { + case FX_4_OBJECT_TYPE_STRING: + vkd3d_string_buffer_printf(&parser->buffer, " "); + value = fx_parser_read_u32(parser); + fx_4_parse_string_initializer(parser, value); + break; + default: + fx_parser_error(parser, VKD3D_SHADER_ERROR_FX_NOT_IMPLEMENTED, + "Parsing object type %u is not implemented.\n", type.typeinfo); + return; + } + vkd3d_string_buffer_printf(&parser->buffer, ",\n"); + } + vkd3d_string_buffer_printf(&parser->buffer, "};\n"); + } +} + +static int fx_4_parse(struct fx_parser *parser) +{ + struct fx_4_header + { + uint32_t version; + uint32_t buffer_count; + uint32_t numeric_variable_count; + uint32_t object_count; + uint32_t shared_buffer_count; + uint32_t shared_numeric_variable_count; + uint32_t shared_object_count; + uint32_t technique_count; + uint32_t unstructured_size; + uint32_t string_count; + uint32_t texture_count; + uint32_t depth_stencil_state_count; + uint32_t blend_state_count; + uint32_t rasterizer_state_count; + uint32_t sampler_state_count; + uint32_t rtv_count; + uint32_t dsv_count; + uint32_t shader_count; + uint32_t inline_shader_count; + } header; + + fx_parser_read_u32s(parser, &header, sizeof(header)); + parser->buffer_count = header.buffer_count; + parser->object_count = header.object_count; + + if (parser->end - parser->ptr < header.unstructured_size) + { + parser->failed = true; + return -1; + } + + parser->unstructured.ptr = parser->ptr; + parser->unstructured.end = parser->ptr + header.unstructured_size; + parser->unstructured.size = header.unstructured_size; + fx_parser_skip(parser, header.unstructured_size); + + fx_parse_buffers(parser); + fx_4_parse_objects(parser); + + return parser->failed ? - 1 : 0; +} + +static int fx_5_parse(struct fx_parser *parser) +{ + struct fx_5_header + { + uint32_t version; + uint32_t buffer_count; + uint32_t numeric_variable_count; + uint32_t object_count; + uint32_t shared_buffer_count; + uint32_t shared_numeric_variable_count; + uint32_t shared_object_count; + uint32_t technique_count; + uint32_t unstructured_size; + uint32_t string_count; + uint32_t texture_count; + uint32_t depth_stencil_state_count; + uint32_t blend_state_count; + uint32_t rasterizer_state_count; + uint32_t sampler_state_count; + uint32_t rtv_count; + uint32_t dsv_count; + uint32_t shader_count; + uint32_t inline_shader_count; + uint32_t group_count; + uint32_t uav_count; + uint32_t interface_variable_count; + uint32_t interface_variable_element_count; + uint32_t class_instance_element_count; + } header; + + fx_parser_read_u32s(parser, &header, sizeof(header)); + parser->buffer_count = header.buffer_count; + parser->object_count = header.object_count; + + if (parser->end - parser->ptr < header.unstructured_size) + { + parser->failed = true; + return -1; + } + + parser->unstructured.ptr = parser->ptr; + parser->unstructured.end = parser->ptr + header.unstructured_size; + parser->unstructured.size = header.unstructured_size; + fx_parser_skip(parser, header.unstructured_size); + + fx_parse_buffers(parser); + fx_4_parse_objects(parser); + + return parser->failed ? - 1 : 0; +} + +int fx_parse(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) +{ + struct fx_parser parser = + { + .start = compile_info->source.code, + .ptr = compile_info->source.code, + .end = (uint8_t *)compile_info->source.code + compile_info->source.size, + .message_context = message_context, + }; + uint32_t version; + int ret; + + vkd3d_string_buffer_init(&parser.buffer); + + if (parser.end - parser.start < sizeof(version)) + return -1; + version = *(uint32_t *)parser.ptr; + + switch (version) + { + case 0xfeff0901: + ret = fx_2_parse(&parser); + break; + case 0xfeff1001: + case 0xfeff1011: + ret = fx_4_parse(&parser); + break; + case 0xfeff2001: + ret = fx_5_parse(&parser); + break; + default: + fx_parser_error(&parser, VKD3D_SHADER_ERROR_FX_INVALID_VERSION, + "Invalid effect binary version value 0x%08x.", version); + ret = -1; + } + + vkd3d_shader_code_from_string_buffer(out, &parser.buffer); + + return ret; +} diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index 9d24126fba8..0bcc3d0a1f7 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -6180,6 +6180,287 @@ static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *c ctx->status = VKD3D_ERROR_INVALID_SHADER; } +static void vsir_validate_register_without_indices(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + if (reg->idx_count != 0) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a register of type %#x.", + reg->idx_count, reg->type); +} + +static void vsir_validate_temp_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + struct validation_context_temp_data *data; + + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a TEMP register.", + reg->idx_count); + return; + } + + 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 >= ctx->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, ctx->program->temp_count); + return; + } + + data = &ctx->temps[reg->idx[0].offset]; + + if (reg->dimension == VSIR_DIMENSION_NONE) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension NONE for a TEMP register."); + return; + } + + /* TEMP registers can be scalar or vec4, provided that + * each individual register always appears with the same + * dimension. */ + if (data->dimension == VSIR_DIMENSION_NONE) + { + data->dimension = reg->dimension; + data->first_seen = ctx->instruction_idx; + } + else if (data->dimension != reg->dimension) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension %#x for a TEMP register: " + "it has already been seen with dimension %#x at instruction %zu.", + reg->dimension, data->dimension, data->first_seen); + } +} + +static void vsir_validate_rastout_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a RASTOUT register.", + reg->idx_count); + return; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for a RASTOUT register."); + + if (reg->idx[0].offset >= 3) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Invalid offset for a RASTOUT register."); +} + +static void vsir_validate_misctype_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a MISCTYPE register.", + reg->idx_count); + return; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for a MISCTYPE register."); + + if (reg->idx[0].offset >= 2) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Invalid offset for a MISCTYPE register."); +} + +static void vsir_validate_label_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, + "Invalid precision %#x for a LABEL register.", reg->precision); + + if (reg->data_type != VKD3D_DATA_UNUSED) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid data type %#x for a LABEL register.", reg->data_type); + + if (reg->dimension != VSIR_DIMENSION_NONE) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension %#x for a LABEL register.", reg->dimension); + + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a LABEL register.", reg->idx_count); + return; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for a LABEL register."); + + /* 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->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); +} + +static void vsir_validate_sampler_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, + "Invalid precision %#x for a SAMPLER register.", reg->precision); + + if (reg->data_type != VKD3D_DATA_UNUSED) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid data type %#x for a SAMPLER register.", reg->data_type); + + /* VEC4 is allowed in gather operations. */ + if (reg->dimension == VSIR_DIMENSION_SCALAR) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension SCALAR for a SAMPLER register."); + + if (reg->idx_count != 2) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a SAMPLER register.", reg->idx_count); + return; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for the descriptor index of a SAMPLER register."); +} + +static void vsir_validate_resource_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, + "Invalid precision %#x for a RESOURCE register.", reg->precision); + + if (reg->data_type != VKD3D_DATA_UNUSED) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid data type %#x for a RESOURCE register.", reg->data_type); + + if (reg->dimension != VSIR_DIMENSION_VEC4) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension %#x for a RESOURCE register.", reg->dimension); + + if (reg->idx_count != 2) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a RESOURCE register.", reg->idx_count); + return; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for the descriptor index of a RESOURCE register."); +} + +static void vsir_validate_uav_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, + "Invalid precision %#x for a UAV register.", + reg->precision); + + if (reg->data_type != VKD3D_DATA_UNUSED) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid data type %#x for a UAV register.", + reg->data_type); + + /* NONE is allowed in counter operations. */ + if (reg->dimension == VSIR_DIMENSION_SCALAR) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension %#x for a UAV register.", + reg->dimension); + + if (reg->idx_count != 2) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a UAV register.", + reg->idx_count); + return; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for the descriptor index of a UAV register."); +} + +static void vsir_validate_ssa_register(struct validation_context *ctx, + const struct vkd3d_shader_register *reg) +{ + struct validation_context_ssa_data *data; + + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid index count %u for a SSA register.", + reg->idx_count); + return; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Non-NULL relative address for a SSA register."); + + if (reg->idx[0].offset >= ctx->program->ssa_count) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "SSA register index %u exceeds the maximum count %u.", + reg->idx[0].offset, ctx->program->ssa_count); + return; + } + + data = &ctx->ssas[reg->idx[0].offset]; + + if (reg->dimension == VSIR_DIMENSION_NONE) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension NONE for a SSA register."); + return; + } + + /* SSA registers can be scalar or vec4, provided that each + * individual register always appears with the same + * dimension. */ + if (data->dimension == VSIR_DIMENSION_NONE) + { + data->dimension = reg->dimension; + data->data_type = reg->data_type; + data->first_seen = ctx->instruction_idx; + } + else + { + if (data->dimension != reg->dimension) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, + "Invalid dimension %#x for a SSA register: " + "it has already been seen with dimension %#x at instruction %zu.", + reg->dimension, data->dimension, data->first_seen); + + if (data_type_is_64_bit(data->data_type) != data_type_is_64_bit(reg->data_type)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid data type %#x for a SSA register: " + "it has already been seen with data type %#x at instruction %zu.", + reg->data_type, data->data_type, data->first_seen); + } +} + static void vsir_validate_src_param(struct validation_context *ctx, const struct vkd3d_shader_src_param *src); @@ -6218,298 +6499,59 @@ static void vsir_validate_register(struct validation_context *ctx, switch (reg->type) { case VKD3DSPR_TEMP: - { - struct validation_context_temp_data *data; - - if (reg->idx_count != 1) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a TEMP register.", - reg->idx_count); - break; - } - - 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 >= ctx->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, ctx->program->temp_count); - break; - } - - data = &ctx->temps[reg->idx[0].offset]; - - if (reg->dimension == VSIR_DIMENSION_NONE) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension NONE for a TEMP register."); - break; - } - - /* TEMP registers can be scalar or vec4, provided that - * each individual register always appears with the same - * dimension. */ - if (data->dimension == VSIR_DIMENSION_NONE) - { - data->dimension = reg->dimension; - data->first_seen = ctx->instruction_idx; - } - else if (data->dimension != reg->dimension) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a TEMP register: " - "it has already been seen with dimension %#x at instruction %zu.", - reg->dimension, data->dimension, data->first_seen); - } + vsir_validate_temp_register(ctx, reg); break; - } - - case VKD3DSPR_SSA: - { - struct validation_context_ssa_data *data; - - if (reg->idx_count != 1) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a SSA register.", - reg->idx_count); - break; - } - - if (reg->idx[0].rel_addr) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a SSA register."); - if (reg->idx[0].offset >= ctx->program->ssa_count) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "SSA register index %u exceeds the maximum count %u.", - reg->idx[0].offset, ctx->program->ssa_count); - break; - } - - data = &ctx->ssas[reg->idx[0].offset]; - - if (reg->dimension == VSIR_DIMENSION_NONE) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension NONE for a SSA register."); - break; - } - - /* SSA registers can be scalar or vec4, provided that each - * individual register always appears with the same - * dimension. */ - if (data->dimension == VSIR_DIMENSION_NONE) - { - data->dimension = reg->dimension; - data->data_type = reg->data_type; - data->first_seen = ctx->instruction_idx; - } - else - { - if (data->dimension != reg->dimension) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a SSA register: " - "it has already been seen with dimension %#x at instruction %zu.", - reg->dimension, data->dimension, data->first_seen); - - if (data_type_is_64_bit(data->data_type) != data_type_is_64_bit(reg->data_type)) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, "Invalid data type %#x for a SSA register: " - "it has already been seen with data type %#x at instruction %zu.", - reg->data_type, data->data_type, data->first_seen); - } + case VKD3DSPR_RASTOUT: + vsir_validate_rastout_register(ctx, reg); break; - } - case VKD3DSPR_LABEL: - if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, "Invalid precision %#x for a LABEL register.", - reg->precision); - - if (reg->data_type != VKD3D_DATA_UNUSED) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, "Invalid data type %#x for a LABEL register.", - reg->data_type); - - if (reg->dimension != VSIR_DIMENSION_NONE) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a LABEL register.", - reg->dimension); - - if (reg->idx_count != 1) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a LABEL register.", - reg->idx_count); - break; - } + case VKD3DSPR_DEPTHOUT: + vsir_validate_register_without_indices(ctx, reg); + break; - if (reg->idx[0].rel_addr) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a LABEL register."); - - /* 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->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); + case VKD3DSPR_MISCTYPE: + vsir_validate_misctype_register(ctx, reg); break; - case VKD3DSPR_NULL: - if (reg->idx_count != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a NULL register.", - reg->idx_count); + case VKD3DSPR_LABEL: + vsir_validate_label_register(ctx, reg); break; case VKD3DSPR_IMMCONST: - if (reg->idx_count != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a IMMCONST register.", - reg->idx_count); + vsir_validate_register_without_indices(ctx, reg); break; case VKD3DSPR_IMMCONST64: - if (reg->idx_count != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a IMMCONST64 register.", - reg->idx_count); + vsir_validate_register_without_indices(ctx, reg); break; - case VKD3DSPR_SAMPLER: - if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, - "Invalid precision %#x for a SAMPLER register.", - reg->precision); - - if (reg->data_type != VKD3D_DATA_UNUSED) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, - "Invalid data type %#x for a SAMPLER register.", - reg->data_type); - - /* VEC4 is allowed in gather operations. */ - if (reg->dimension == VSIR_DIMENSION_SCALAR) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, - "Invalid dimension SCALAR for a SAMPLER register."); - - if (reg->idx_count != 2) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a SAMPLER register.", - reg->idx_count); - break; - } + case VKD3DSPR_NULL: + vsir_validate_register_without_indices(ctx, reg); + break; - if (reg->idx[0].rel_addr) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "Non-NULL relative address for the descriptor index of a SAMPLER register."); + case VKD3DSPR_SAMPLER: + vsir_validate_sampler_register(ctx, reg); break; case VKD3DSPR_RESOURCE: - if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, - "Invalid precision %#x for a RESOURCE register.", - reg->precision); - - if (reg->data_type != VKD3D_DATA_UNUSED) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, - "Invalid data type %#x for a RESOURCE register.", - reg->data_type); - - if (reg->dimension != VSIR_DIMENSION_VEC4) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, - "Invalid dimension %#x for a RESOURCE register.", - reg->dimension); - - if (reg->idx_count != 2) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a RESOURCE register.", - reg->idx_count); - break; - } - - if (reg->idx[0].rel_addr) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "Non-NULL relative address for the descriptor index of a RESOURCE register."); + vsir_validate_resource_register(ctx, reg); break; case VKD3DSPR_UAV: - if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, - "Invalid precision %#x for a UAV register.", - reg->precision); - - if (reg->data_type != VKD3D_DATA_UNUSED) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, - "Invalid data type %#x for a UAV register.", - reg->data_type); - - /* NONE is allowed in counter operations. */ - if (reg->dimension == VSIR_DIMENSION_SCALAR) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, - "Invalid dimension %#x for a UAV register.", - reg->dimension); - - if (reg->idx_count != 2) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a UAV register.", - reg->idx_count); - break; - } - - if (reg->idx[0].rel_addr) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "Non-NULL relative address for the descriptor index of a UAV register."); - break; - - case VKD3DSPR_DEPTHOUT: - if (reg->idx_count != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a DEPTHOUT register.", - reg->idx_count); + vsir_validate_uav_register(ctx, reg); break; case VKD3DSPR_DEPTHOUTGE: - if (reg->idx_count != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a DEPTHOUTGE register.", - reg->idx_count); + vsir_validate_register_without_indices(ctx, reg); break; case VKD3DSPR_DEPTHOUTLE: - if (reg->idx_count != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a DEPTHOUTLE register.", - reg->idx_count); - break; - - case VKD3DSPR_RASTOUT: - if (reg->idx_count != 1) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a RASTOUT register.", - reg->idx_count); - break; - } - - if (reg->idx[0].rel_addr) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "Non-NULL relative address for a RASTOUT register."); - - if (reg->idx[0].offset >= 3) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "Invalid offset for a RASTOUT register."); + vsir_validate_register_without_indices(ctx, reg); break; - case VKD3DSPR_MISCTYPE: - if (reg->idx_count != 1) - { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, - "Invalid index count %u for a MISCTYPE register.", - reg->idx_count); - break; - } - - if (reg->idx[0].rel_addr) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "Non-NULL relative address for a MISCTYPE register."); - - if (reg->idx[0].offset >= 2) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, - "Invalid offset for a MISCTYPE register."); + case VKD3DSPR_SSA: + vsir_validate_ssa_register(ctx, reg); break; default: @@ -6707,20 +6749,60 @@ static bool vsir_validate_src_max_count(struct validation_context *ctx, return true; } +enum vsir_signature_type +{ + SIGNATURE_TYPE_INPUT, + SIGNATURE_TYPE_OUTPUT, + SIGNATURE_TYPE_PATCH_CONSTANT, +}; + +static const char * const signature_type_names[] = +{ + [SIGNATURE_TYPE_INPUT] = "input", + [SIGNATURE_TYPE_OUTPUT] = "output", + [SIGNATURE_TYPE_PATCH_CONSTANT] = "patch constant", +}; + +#define PS_BIT (1u << VKD3D_SHADER_TYPE_PIXEL) +#define VS_BIT (1u << VKD3D_SHADER_TYPE_VERTEX) +#define GS_BIT (1u << VKD3D_SHADER_TYPE_GEOMETRY) +#define HS_BIT (1u << VKD3D_SHADER_TYPE_HULL) +#define DS_BIT (1u << VKD3D_SHADER_TYPE_DOMAIN) +#define CS_BIT (1u << VKD3D_SHADER_TYPE_COMPUTE) + +static const struct sysval_validation_data_element +{ + unsigned int input; + unsigned int output; + unsigned int patch_constant; + enum vkd3d_shader_component_type data_type; + unsigned int component_count; +} +sysval_validation_data[] = +{ + [VKD3D_SHADER_SV_POSITION] = {PS_BIT | GS_BIT | HS_BIT | DS_BIT, VS_BIT | GS_BIT | HS_BIT | DS_BIT, 0, + VKD3D_SHADER_COMPONENT_FLOAT, 4}, + [VKD3D_SHADER_SV_CLIP_DISTANCE] = {PS_BIT | GS_BIT | HS_BIT | DS_BIT, PS_BIT | VS_BIT | GS_BIT | HS_BIT | DS_BIT, 0, + VKD3D_SHADER_COMPONENT_FLOAT, 4}, + [VKD3D_SHADER_SV_CULL_DISTANCE] = {PS_BIT | GS_BIT | HS_BIT | DS_BIT, PS_BIT | VS_BIT | GS_BIT | HS_BIT | DS_BIT, 0, + VKD3D_SHADER_COMPONENT_FLOAT, 4}, +}; + static void vsir_validate_signature_element(struct validation_context *ctx, - const struct shader_signature *signature, const char *signature_type, + const struct shader_signature *signature, enum vsir_signature_type signature_type, unsigned int idx) { + const char *signature_type_name = signature_type_names[signature_type]; const struct signature_element *element = &signature->elements[idx]; bool integer_type = false; if (element->register_count == 0) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, - "element %u of %s signature: Invalid zero register count.", idx, signature_type); + "element %u of %s signature: Invalid zero register count.", idx, signature_type_name); if (element->mask == 0 || (element->mask & ~0xf)) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, - "element %u of %s signature: Invalid mask %#x.", idx, signature_type, element->mask); + "element %u of %s signature: Invalid mask %#x.", idx, signature_type_name, element->mask); /* Here we'd likely want to validate that the usage mask is a subset of the * signature mask. Unfortunately the D3DBC parser sometimes violates this. @@ -6744,7 +6826,7 @@ static void vsir_validate_signature_element(struct validation_context *ctx, if (element->used_mask & ~0xf) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid usage mask %#x.", - idx, signature_type, element->used_mask); + idx, signature_type_name, element->used_mask); switch (element->sysval_semantic) { @@ -6776,10 +6858,56 @@ static void vsir_validate_signature_element(struct validation_context *ctx, default: validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid system value semantic %#x.", - idx, signature_type, element->sysval_semantic); + idx, signature_type_name, element->sysval_semantic); break; } + if (element->sysval_semantic < ARRAY_SIZE(sysval_validation_data)) + { + const struct sysval_validation_data_element *data = &sysval_validation_data[element->sysval_semantic]; + + if (data->input || data->output || data->patch_constant) + { + unsigned int mask; + + switch (signature_type) + { + case SIGNATURE_TYPE_INPUT: + mask = data->input; + break; + + case SIGNATURE_TYPE_OUTPUT: + mask = data->output; + break; + + case SIGNATURE_TYPE_PATCH_CONSTANT: + mask = data->patch_constant; + break; + + default: + vkd3d_unreachable(); + } + + if (!(mask & (1u << ctx->program->shader_version.type))) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid system value semantic %#x.", + idx, signature_type_name, element->sysval_semantic); + } + + if (data->component_count != 0) + { + if (element->component_type != data->data_type) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid data type %#x for system value semantic %#x.", + idx, signature_type_name, element->component_type, element->sysval_semantic); + + if (vsir_write_mask_component_count(element->mask) > data->component_count) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid mask %#x for system value semantic %#x.", + idx, signature_type_name, element->mask, element->sysval_semantic); + } + } + switch (element->component_type) { case VKD3D_SHADER_COMPONENT_INT: @@ -6793,29 +6921,29 @@ static void vsir_validate_signature_element(struct validation_context *ctx, default: validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid component type %#x.", - idx, signature_type, element->component_type); + idx, signature_type_name, element->component_type); break; } if (element->min_precision >= VKD3D_SHADER_MINIMUM_PRECISION_COUNT) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid minimum precision %#x.", - idx, signature_type, element->min_precision); + idx, signature_type_name, element->min_precision); if (element->interpolation_mode >= VKD3DSIM_COUNT) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid interpolation mode %#x.", - idx, signature_type, element->interpolation_mode); + idx, signature_type_name, element->interpolation_mode); if (integer_type && element->interpolation_mode != VKD3DSIM_NONE && element->interpolation_mode != VKD3DSIM_CONSTANT) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid interpolation mode %#x for integer component type.", - idx, signature_type, element->interpolation_mode); + idx, signature_type_name, element->interpolation_mode); } static void vsir_validate_signature(struct validation_context *ctx, - const struct shader_signature *signature, const char *signature_type) + const struct shader_signature *signature, enum vsir_signature_type signature_type) { unsigned int i; @@ -7373,9 +7501,9 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c "Patch constant signature is only valid for hull and domain shaders."); } - vsir_validate_signature(&ctx, &program->input_signature, "input"); - vsir_validate_signature(&ctx, &program->output_signature, "output"); - vsir_validate_signature(&ctx, &program->patch_constant_signature, "patch constant"); + vsir_validate_signature(&ctx, &program->input_signature, SIGNATURE_TYPE_INPUT); + vsir_validate_signature(&ctx, &program->output_signature, SIGNATURE_TYPE_OUTPUT); + vsir_validate_signature(&ctx, &program->patch_constant_signature, SIGNATURE_TYPE_PATCH_CONSTANT); if (!(ctx.temps = vkd3d_calloc(ctx.program->temp_count, sizeof(*ctx.temps)))) goto fail; diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c index cde8dc3146c..ca012d4948a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1710,6 +1710,10 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, { ret = compile_hlsl(compile_info, out, &message_context); } + else if (compile_info->source_type == VKD3D_SHADER_SOURCE_FX) + { + ret = fx_parse(compile_info, out, &message_context); + } else { uint64_t config_flags = vkd3d_shader_init_config_flags(); @@ -1942,6 +1946,7 @@ const enum vkd3d_shader_source_type *vkd3d_shader_get_supported_source_types(uns #ifdef VKD3D_SHADER_UNSUPPORTED_DXIL VKD3D_SHADER_SOURCE_DXBC_DXIL, #endif + VKD3D_SHADER_SOURCE_FX, }; TRACE("count %p.\n", count); @@ -2000,6 +2005,11 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( }; #endif + static const enum vkd3d_shader_target_type fx_types[] = + { + VKD3D_SHADER_TARGET_D3D_ASM, + }; + TRACE("source_type %#x, count %p.\n", source_type, count); switch (source_type) @@ -2022,6 +2032,10 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( return dxbc_dxil_types; #endif + case VKD3D_SHADER_SOURCE_FX: + *count = ARRAY_SIZE(fx_types); + return fx_types; + default: *count = 0; return NULL; diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 9ca3c328147..54b87373ed1 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -252,6 +252,9 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_MSL_INTERNAL = 10000, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND = 10001, + + VKD3D_SHADER_ERROR_FX_NOT_IMPLEMENTED = 11000, + VKD3D_SHADER_ERROR_FX_INVALID_VERSION = 11001, }; enum vkd3d_shader_opcode @@ -1605,6 +1608,8 @@ int dxil_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t co struct vkd3d_shader_message_context *message_context, struct vsir_program *program); int tpf_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t config_flags, struct vkd3d_shader_message_context *message_context, struct vsir_program *program); +int fx_parse(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); void free_dxbc_shader_desc(struct dxbc_shader_desc *desc); -- 2.45.2