diff --git a/patches/vkd3d-latest/0001-Updated-vkd3d-to-44fffee5e1331e1c7e10489d84723c3b9da.patch b/patches/vkd3d-latest/0001-Updated-vkd3d-to-44fffee5e1331e1c7e10489d84723c3b9da.patch index 88dbc48e..0dcc2761 100644 --- a/patches/vkd3d-latest/0001-Updated-vkd3d-to-44fffee5e1331e1c7e10489d84723c3b9da.patch +++ b/patches/vkd3d-latest/0001-Updated-vkd3d-to-44fffee5e1331e1c7e10489d84723c3b9da.patch @@ -1,4 +1,4 @@ -From e8e77eb103448eaf3f4334f1e62d89ba83b97f78 Mon Sep 17 00:00:00 2001 +From 52953d19dee2161be20f9afb641e9b3d01cb8f2e Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Mon, 26 May 2025 07:03:34 +1000 Subject: [PATCH] Updated vkd3d to 44fffee5e1331e1c7e10489d84723c3b9dad7e17. @@ -98,5 +98,5 @@ index f2967835b62..f804c1f0c24 100644 { switch (part) -- -2.50.1 +2.51.0 diff --git a/patches/vkd3d-latest/0002-Updated-vkd3d-to-3b41d99fa9e80dda5844738a226f70f14f7.patch b/patches/vkd3d-latest/0002-Updated-vkd3d-to-3b41d99fa9e80dda5844738a226f70f14f7.patch index 4fdf4545..f544d84f 100644 --- a/patches/vkd3d-latest/0002-Updated-vkd3d-to-3b41d99fa9e80dda5844738a226f70f14f7.patch +++ b/patches/vkd3d-latest/0002-Updated-vkd3d-to-3b41d99fa9e80dda5844738a226f70f14f7.patch @@ -1,4 +1,4 @@ -From 1c686e92c185fcc9efa718e1a6ffe70a14a71a1e Mon Sep 17 00:00:00 2001 +From a299300b535557f8c54b066d082b1bb47ffce104 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 22 Aug 2025 07:26:18 +1000 Subject: [PATCH] Updated vkd3d to 3b41d99fa9e80dda5844738a226f70f14f778c8b. @@ -1925,5 +1925,5 @@ index e758c16b3d4..b63c5785770 100644 void vkd3d_shader_parser_warning(struct vkd3d_shader_parser *parser, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4); -- -2.50.1 +2.51.0 diff --git a/patches/vkd3d-latest/0003-Updated-vkd3d-to-d0098b0d5968d1969ec622b91fd360fd0ae.patch b/patches/vkd3d-latest/0003-Updated-vkd3d-to-d0098b0d5968d1969ec622b91fd360fd0ae.patch index 0541d7c5..722b9306 100644 --- a/patches/vkd3d-latest/0003-Updated-vkd3d-to-d0098b0d5968d1969ec622b91fd360fd0ae.patch +++ b/patches/vkd3d-latest/0003-Updated-vkd3d-to-d0098b0d5968d1969ec622b91fd360fd0ae.patch @@ -1,4 +1,4 @@ -From 53b2f2d25a1abd14e043e7c927ee16d8f454d970 Mon Sep 17 00:00:00 2001 +From 38b9415c7e850a1774d508232dd0e5e97e505eab Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Sat, 23 Aug 2025 07:27:59 +1000 Subject: [PATCH] Updated vkd3d to d0098b0d5968d1969ec622b91fd360fd0aec2328. @@ -129,5 +129,5 @@ index c2832a61f67..2d0510e5456 100644 if (flags) FIXME("Unrecognized flag(s) %#x.\n", flags); -- -2.50.1 +2.51.0 diff --git a/patches/vkd3d-latest/0004-Updated-vkd3d-to-158f8b3cf6ff528eb6897baf04db80f0db2.patch b/patches/vkd3d-latest/0004-Updated-vkd3d-to-158f8b3cf6ff528eb6897baf04db80f0db2.patch index e754205d..7f0ff0e4 100644 --- a/patches/vkd3d-latest/0004-Updated-vkd3d-to-158f8b3cf6ff528eb6897baf04db80f0db2.patch +++ b/patches/vkd3d-latest/0004-Updated-vkd3d-to-158f8b3cf6ff528eb6897baf04db80f0db2.patch @@ -1,4 +1,4 @@ -From eb3e25c8b5d02a3402438ac83002eb936563e85f Mon Sep 17 00:00:00 2001 +From b62327e3e6fae6a2df820e0160b04c1c54dfb68a Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Sat, 30 Aug 2025 07:08:53 +1000 Subject: [PATCH] Updated vkd3d to 158f8b3cf6ff528eb6897baf04db80f0db2b53f8. @@ -1755,5 +1755,5 @@ index 6bbd6533b74..b6055a50a99 100644 info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO; -- -2.50.1 +2.51.0 diff --git a/patches/vkd3d-latest/0005-Updated-vkd3d-to-979d7e4b85f2fb8db60219f4a2673fc8071.patch b/patches/vkd3d-latest/0005-Updated-vkd3d-to-979d7e4b85f2fb8db60219f4a2673fc8071.patch index e28535e7..20034037 100644 --- a/patches/vkd3d-latest/0005-Updated-vkd3d-to-979d7e4b85f2fb8db60219f4a2673fc8071.patch +++ b/patches/vkd3d-latest/0005-Updated-vkd3d-to-979d7e4b85f2fb8db60219f4a2673fc8071.patch @@ -1,4 +1,4 @@ -From 0834b82af4990aad006eb709f50090babb2bf1ee Mon Sep 17 00:00:00 2001 +From f6510f66601eba7d3dbe69168831429c930aa494 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Tue, 2 Sep 2025 07:37:13 +1000 Subject: [PATCH] Updated vkd3d to 979d7e4b85f2fb8db60219f4a2673fc807142ebd. @@ -361,5 +361,5 @@ index 97c0d0e73a8..a57c42b167d 100644 spirv_compiler_emit_descriptor_declarations(compiler); -- -2.50.1 +2.51.0 diff --git a/patches/vkd3d-latest/0006-Updated-vkd3d-to-d6bed4be377432e4c54e23abcd7863fefbe.patch b/patches/vkd3d-latest/0006-Updated-vkd3d-to-d6bed4be377432e4c54e23abcd7863fefbe.patch index 548591cf..41c5edb1 100644 --- a/patches/vkd3d-latest/0006-Updated-vkd3d-to-d6bed4be377432e4c54e23abcd7863fefbe.patch +++ b/patches/vkd3d-latest/0006-Updated-vkd3d-to-d6bed4be377432e4c54e23abcd7863fefbe.patch @@ -1,4 +1,4 @@ -From 923515f00841e6d45c1e91f8cf530bc5dabf7192 Mon Sep 17 00:00:00 2001 +From d6553ac0d36434c95def8553efc28663fb5f77a1 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 3 Sep 2025 08:08:18 +1000 Subject: [PATCH] Updated vkd3d to d6bed4be377432e4c54e23abcd7863fefbef94aa. @@ -1753,5 +1753,5 @@ index 4102fe53e67..698ad541359 100644 { return data_type == VSIR_DATA_I32 || data_type == VSIR_DATA_U8 || data_type == VSIR_DATA_U16 -- -2.50.1 +2.51.0 diff --git a/patches/vkd3d-latest/0007-Updated-vkd3d-to-2aefcf5d99cfb4836c3c6178be74061277b.patch b/patches/vkd3d-latest/0007-Updated-vkd3d-to-2aefcf5d99cfb4836c3c6178be74061277b.patch new file mode 100644 index 00000000..192a0ce4 --- /dev/null +++ b/patches/vkd3d-latest/0007-Updated-vkd3d-to-2aefcf5d99cfb4836c3c6178be74061277b.patch @@ -0,0 +1,175 @@ +From 154bd7a2207e5046788c9b5bf9419147fb01b6bb Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 4 Sep 2025 07:55:34 +1000 +Subject: [PATCH] Updated vkd3d to 2aefcf5d99cfb4836c3c6178be74061277b9d15c. + +--- + libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 6 ++--- + libs/vkd3d/libs/vkd3d-shader/dxil.c | 22 ++++++++++--------- + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 10 ++++++++- + .../libs/vkd3d-shader/vkd3d_shader_private.h | 2 +- + 4 files changed, 25 insertions(+), 15 deletions(-) + +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +index 58135e71f30..897803ecb56 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +@@ -834,7 +834,7 @@ static void shader_print_register(struct vkd3d_d3d_asm_compiler *compiler, const + && reg->type != VKD3DSPR_NULL + && reg->type != VKD3DSPR_DEPTHOUT) + { +- if (offset != ~0u) ++ if (reg->idx_count) + { + bool is_sm_5_1 = vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1); + +@@ -862,10 +862,10 @@ static void shader_print_register(struct vkd3d_d3d_asm_compiler *compiler, const + /* For descriptors in sm < 5.1 we move the reg->idx values up one slot + * to normalise with 5.1. + * Here we should ignore it if it's a descriptor in sm < 5.1. */ +- if (reg->idx[1].offset != ~0u && (!is_descriptor || is_sm_5_1)) ++ if (reg->idx_count > 1 && (!is_descriptor || is_sm_5_1)) + shader_print_subscript(compiler, reg->idx[1].offset, reg->idx[1].rel_addr); + +- if (reg->idx[2].offset != ~0u) ++ if (reg->idx_count > 2) + shader_print_subscript(compiler, reg->idx[2].offset, reg->idx[2].rel_addr); + } + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c +index 172204f2226..1678128da83 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c ++++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c +@@ -2475,7 +2475,7 @@ static void register_init_with_id(struct vkd3d_shader_register *reg, + reg->idx[0].offset = id; + } + +-static enum vsir_data_type vsir_data_type_from_dxil(const struct sm6_type *type) ++static enum vsir_data_type vsir_data_type_from_dxil(const struct sm6_type *type, struct sm6_parser *dxil) + { + if (type->class == TYPE_CLASS_INTEGER) + { +@@ -2492,7 +2492,8 @@ static enum vsir_data_type vsir_data_type_from_dxil(const struct sm6_type *type) + case 64: + return VSIR_DATA_U64; + default: +- FIXME("Unhandled width %u.\n", type->u.width); ++ vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED, ++ "Unhandled integer width %u.", type->u.width); + return VSIR_DATA_U32; + } + } +@@ -2507,12 +2508,14 @@ static enum vsir_data_type vsir_data_type_from_dxil(const struct sm6_type *type) + case 64: + return VSIR_DATA_F64; + default: +- FIXME("Unhandled width %u.\n", type->u.width); ++ vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED, ++ "Unhandled floating-point width %u.", type->u.width); + return VSIR_DATA_F32; + } + } + +- FIXME("Unhandled type %u.\n", type->class); ++ vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED, ++ "Unhandled type %#x.", type->class); + return VSIR_DATA_U32; + } + +@@ -2599,7 +2602,7 @@ static void sm6_register_from_value(struct vkd3d_shader_register *reg, const str + enum vsir_data_type data_type; + + scalar_type = sm6_type_get_scalar_type(value->type, 0); +- data_type = vsir_data_type_from_dxil(scalar_type); ++ data_type = vsir_data_type_from_dxil(scalar_type, sm6); + + switch (value->value_type) + { +@@ -3239,7 +3242,7 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co + dst->u.data = icb; + + icb->register_idx = sm6->icb_count++; +- icb->data_type = vsir_data_type_from_dxil(elem_type); ++ icb->data_type = vsir_data_type_from_dxil(elem_type, sm6); + icb->element_count = type->u.array.count; + icb->component_count = 1; + icb->is_null = !operands; +@@ -3693,7 +3696,7 @@ static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const stru + unsigned int count, unsigned int alignment, bool has_function_scope, unsigned int init, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) + { +- enum vsir_data_type data_type = vsir_data_type_from_dxil(elem_type); ++ enum vsir_data_type data_type = vsir_data_type_from_dxil(elem_type, sm6); + + if (ins) + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_DCL_INDEXABLE_TEMP); +@@ -4012,8 +4015,7 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) + return VKD3D_ERROR_INVALID_SHADER; + if ((version = record->operands[0]) != 1) + { +- FIXME("Unsupported format version %#"PRIx64".\n", version); +- vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED_BITCODE_FORMAT, ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED, + "Bitcode format version %#"PRIx64" is unsupported.", version); + return VKD3D_ERROR_INVALID_SHADER; + } +@@ -5183,7 +5185,7 @@ static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, enum dx_intr + + type = sm6_type_get_scalar_type(dst->type, 0); + VKD3D_ASSERT(type); +- src_param->reg.data_type = vsir_data_type_from_dxil(type); ++ src_param->reg.data_type = vsir_data_type_from_dxil(type, sm6); + if (data_type_is_64_bit(src_param->reg.data_type)) + src_param->swizzle = vsir_swizzle_64_from_32(src_param->swizzle); + else +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +index e20a12bb42d..41aeb7f22f6 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +@@ -4748,7 +4748,8 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * + } + + if (!strcmp(name, "tex2Dbias") +- || !strcmp(name, "tex2Dlod")) ++ || !strcmp(name, "tex2Dlod") ++ || !strcmp(name, "texCUBEbias")) + { + struct hlsl_ir_node *lod, *c; + +@@ -4900,6 +4901,12 @@ static bool intrinsic_texCUBE(struct hlsl_ctx *ctx, + return intrinsic_tex(ctx, params, loc, "texCUBE", HLSL_SAMPLER_DIM_CUBE); + } + ++static bool intrinsic_texCUBEbias(struct hlsl_ctx *ctx, ++ const struct parse_initializer *params, const struct vkd3d_shader_location *loc) ++{ ++ return intrinsic_tex(ctx, params, loc, "texCUBEbias", HLSL_SAMPLER_DIM_CUBE); ++} ++ + static bool intrinsic_texCUBEgrad(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { +@@ -5375,6 +5382,7 @@ intrinsic_functions[] = + {"tex3Dgrad", 4, false, intrinsic_tex3Dgrad}, + {"tex3Dproj", 2, false, intrinsic_tex3Dproj}, + {"texCUBE", -1, false, intrinsic_texCUBE}, ++ {"texCUBEbias", 2, false, intrinsic_texCUBEbias}, + {"texCUBEgrad", 4, false, intrinsic_texCUBEgrad}, + {"texCUBEproj", 2, false, intrinsic_texCUBEproj}, + {"transpose", 1, true, intrinsic_transpose}, +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index 698ad541359..9bf196b1fe2 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -213,7 +213,7 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT = 8005, + VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE = 8006, + VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB = 8007, +- VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED_BITCODE_FORMAT = 8008, ++ VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED = 8008, + VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL = 8009, + VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID = 8010, + VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE = 8011, +-- +2.51.0 + diff --git a/patches/vkd3d-latest/0008-Updated-vkd3d-to-0096ae43e114e5bab8a6ff1093b509588a4.patch b/patches/vkd3d-latest/0008-Updated-vkd3d-to-0096ae43e114e5bab8a6ff1093b509588a4.patch new file mode 100644 index 00000000..b0b766a2 --- /dev/null +++ b/patches/vkd3d-latest/0008-Updated-vkd3d-to-0096ae43e114e5bab8a6ff1093b509588a4.patch @@ -0,0 +1,1133 @@ +From 20e183247b7cd2ba19048f6a1b712c94b88dd548 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Fri, 5 Sep 2025 09:30:19 +1000 +Subject: [PATCH] Updated vkd3d to 0096ae43e114e5bab8a6ff1093b509588a49e38a. + +--- + libs/vkd3d/libs/vkd3d-shader/hlsl.h | 7 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 2 +- + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 375 ++++++++++++-------- + libs/vkd3d/libs/vkd3d-shader/ir.c | 51 +-- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 18 +- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 2 + + 6 files changed, 268 insertions(+), 187 deletions(-) + +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +index df1333f55a6..a3e8ccc1e2a 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +@@ -233,6 +233,9 @@ struct hlsl_type + /* Offset where the type's description starts in the output bytecode, in bytes. */ + size_t bytecode_offset; + ++ /* Offset where the type's packed description starts in the output bytecode, in bytes. */ ++ size_t packed_bytecode_offset; ++ + bool is_typedef; + + uint32_t is_minimum_precision : 1; +@@ -1184,8 +1187,8 @@ struct hlsl_ctx + } constant_defs; + /* 'c' registers where the constants expected by SM2 sincos are stored. */ + struct hlsl_reg d3dsincosconst1, d3dsincosconst2; +- /* Number of allocated SSA and temp IDs, used in translation to vsir. */ +- unsigned int ssa_count, temp_count; ++ /* Number of allocated registers, used in translation to vsir. */ ++ unsigned int ssa_count, temp_count, indexable_temp_count; + + /* Number of threads to be executed (on the X, Y, and Z dimensions) in a single thread group in + * compute shader profiles. It is set using the numthreads() attribute in the entry point. */ +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +index 41aeb7f22f6..d83ad9fe7d8 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +@@ -8115,7 +8115,7 @@ resource_format: + { + uint32_t modifiers = $1; + +- if (!($$ = apply_type_modifiers(ctx, $2, &modifiers, false, &@1))) ++ if (!($$ = apply_type_modifiers(ctx, $2, &modifiers, true, &@1))) + YYABORT; + } + +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +index 5d413c43374..9a682a7550d 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +@@ -175,12 +175,29 @@ static unsigned int hlsl_type_get_packed_size(const struct hlsl_type *type) + } + } + ++static unsigned int struct_field_get_packed_offset(const struct hlsl_type *record, unsigned int field_idx) ++{ ++ unsigned int offset = 0; ++ ++ VKD3D_ASSERT(record->class == HLSL_CLASS_STRUCT); ++ VKD3D_ASSERT(field_idx < record->e.record.field_count); ++ ++ for (unsigned int i = 0; i < field_idx; ++i) ++ { ++ struct hlsl_struct_field *field = &record->e.record.fields[i]; ++ offset = align(offset, hlsl_type_get_packed_alignment(field->type)) + hlsl_type_get_packed_size(field->type); ++ } ++ ++ return align(offset, hlsl_type_get_packed_alignment(record->e.record.fields[field_idx].type)); ++} ++ ++ + static struct hlsl_ir_node *hlsl_block_add_packed_index_offset_append(struct hlsl_ctx *ctx, + struct hlsl_block *block, struct hlsl_ir_node *prev_offset, struct hlsl_ir_node *idx, + struct hlsl_type *type, const struct vkd3d_shader_location *loc) + { + struct hlsl_ir_node *idx_offset = NULL, *c; +- unsigned int field_idx, offset, size, i; ++ unsigned int field_idx, offset, size; + + switch (type->class) + { +@@ -203,15 +220,7 @@ static struct hlsl_ir_node *hlsl_block_add_packed_index_offset_append(struct hls + + case HLSL_CLASS_STRUCT: + field_idx = hlsl_ir_constant(idx)->value.u[0].u; +- for (i = 0, offset = 0; i < field_idx; ++i) +- { +- struct hlsl_struct_field *field = &type->e.record.fields[i]; +- +- offset = align(offset, hlsl_type_get_packed_alignment(field->type)) +- + hlsl_type_get_packed_size(field->type); +- } +- +- offset = align(offset, hlsl_type_get_packed_alignment(type->e.record.fields[field_idx].type)); ++ offset = struct_field_get_packed_offset(type, field_idx); + idx_offset = hlsl_block_add_uint_constant(ctx, block, offset, loc); + break; + +@@ -5912,7 +5921,6 @@ struct register_allocator + { + uint32_t reg; + unsigned int writemask; +- unsigned int first_write, last_read; + + /* Two allocations with different mode can't share the same register. */ + int mode; +@@ -5922,11 +5930,7 @@ struct register_allocator + } *allocations; + size_t count, capacity; + +- /* Indexable temps are allocated separately and always keep their index regardless of their +- * lifetime. */ +- uint32_t indexable_count; +- +- /* Total number of registers allocated so far. Used to declare sm4 temp count. */ ++ /* Total number of registers allocated so far. */ + uint32_t reg_count; + + /* Special flag so allocations that can share registers prioritize those +@@ -5938,7 +5942,7 @@ struct register_allocator + }; + + static unsigned int get_available_writemask(const struct register_allocator *allocator, +- unsigned int first_write, unsigned int last_read, uint32_t reg_idx, int mode, bool vip) ++ uint32_t reg_idx, int mode, bool vip) + { + unsigned int writemask = VKD3DSP_WRITEMASK_ALL; + size_t i; +@@ -5947,12 +5951,7 @@ static unsigned int get_available_writemask(const struct register_allocator *all + { + const struct allocation *allocation = &allocator->allocations[i]; + +- /* We do not overlap if first write == last read: +- * this is the case where we are allocating the result of that +- * expression, e.g. "add r0, r0, r1". */ +- +- if (allocation->reg == reg_idx +- && first_write < allocation->last_read && last_read > allocation->first_write) ++ if (allocation->reg == reg_idx) + { + writemask &= ~allocation->writemask; + if (allocation->mode != mode) +@@ -5969,7 +5968,7 @@ static unsigned int get_available_writemask(const struct register_allocator *all + } + + static void record_allocation(struct hlsl_ctx *ctx, struct register_allocator *allocator, uint32_t reg_idx, +- unsigned int writemask, unsigned int first_write, unsigned int last_read, int mode, bool vip) ++ unsigned int writemask, int mode, bool vip) + { + struct allocation *allocation; + +@@ -5980,8 +5979,6 @@ static void record_allocation(struct hlsl_ctx *ctx, struct register_allocator *a + allocation = &allocator->allocations[allocator->count++]; + allocation->reg = reg_idx; + allocation->writemask = writemask; +- allocation->first_write = first_write; +- allocation->last_read = last_read; + allocation->mode = mode; + allocation->vip = vip; + +@@ -6000,8 +5997,7 @@ static void record_allocation(struct hlsl_ctx *ctx, struct register_allocator *a + * 'vip' can be used so that no new allocations can be made in the given register + * unless they are 'vip' as well. */ + static struct hlsl_reg allocate_register(struct hlsl_ctx *ctx, struct register_allocator *allocator, +- unsigned int first_write, unsigned int last_read, unsigned int reg_size, +- unsigned int component_count, int mode, bool force_align, bool vip) ++ unsigned int reg_size, unsigned int component_count, int mode, bool force_align, bool vip) + { + struct hlsl_reg ret = {.allocation_size = 1, .allocated = true}; + unsigned int required_size = force_align ? 4 : reg_size; +@@ -6014,8 +6010,7 @@ static struct hlsl_reg allocate_register(struct hlsl_ctx *ctx, struct register_a + { + for (uint32_t reg_idx = 0; reg_idx < allocator->reg_count; ++reg_idx) + { +- unsigned int available_writemask = get_available_writemask(allocator, +- first_write, last_read, reg_idx, mode, vip); ++ unsigned int available_writemask = get_available_writemask(allocator, reg_idx, mode, vip); + + if (vkd3d_popcount(available_writemask) >= pref) + { +@@ -6027,7 +6022,7 @@ static struct hlsl_reg allocate_register(struct hlsl_ctx *ctx, struct register_a + ret.writemask = hlsl_combine_writemasks(writemask, + vkd3d_write_mask_from_component_count(component_count)); + +- record_allocation(ctx, allocator, reg_idx, writemask, first_write, last_read, mode, vip); ++ record_allocation(ctx, allocator, reg_idx, writemask, mode, vip); + return ret; + } + } +@@ -6037,39 +6032,12 @@ static struct hlsl_reg allocate_register(struct hlsl_ctx *ctx, struct register_a + ret.id = allocator->reg_count; + ret.writemask = vkd3d_write_mask_from_component_count(component_count); + record_allocation(ctx, allocator, allocator->reg_count, +- vkd3d_write_mask_from_component_count(reg_size), first_write, last_read, mode, vip); +- return ret; +-} +- +-/* Allocate a register with writemask, while reserving reg_writemask. */ +-static struct hlsl_reg allocate_register_with_masks(struct hlsl_ctx *ctx, +- struct register_allocator *allocator, unsigned int first_write, unsigned int last_read, +- uint32_t reg_writemask, uint32_t writemask, int mode, bool vip) +-{ +- struct hlsl_reg ret = {0}; +- uint32_t reg_idx; +- +- VKD3D_ASSERT((reg_writemask & writemask) == writemask); +- +- for (reg_idx = 0;; ++reg_idx) +- { +- if ((get_available_writemask(allocator, first_write, last_read, +- reg_idx, mode, vip) & reg_writemask) == reg_writemask) +- break; +- } +- +- record_allocation(ctx, allocator, reg_idx, reg_writemask, first_write, last_read, mode, vip); +- +- ret.type = VKD3DSPR_TEMP; +- ret.id = reg_idx; +- ret.allocation_size = 1; +- ret.writemask = writemask; +- ret.allocated = true; ++ vkd3d_write_mask_from_component_count(reg_size), mode, vip); + return ret; + } + +-static bool is_range_available(const struct register_allocator *allocator, unsigned int first_write, +- unsigned int last_read, uint32_t reg_idx, unsigned int reg_size, int mode, bool vip) ++static bool is_range_available(const struct register_allocator *allocator, ++ uint32_t reg_idx, unsigned int reg_size, int mode, bool vip) + { + unsigned int last_reg_mask = (1u << (reg_size % 4)) - 1; + unsigned int writemask; +@@ -6077,18 +6045,18 @@ static bool is_range_available(const struct register_allocator *allocator, unsig + + for (i = 0; i < (reg_size / 4); ++i) + { +- writemask = get_available_writemask(allocator, first_write, last_read, reg_idx + i, mode, vip); ++ writemask = get_available_writemask(allocator, reg_idx + i, mode, vip); + if (writemask != VKD3DSP_WRITEMASK_ALL) + return false; + } +- writemask = get_available_writemask(allocator, first_write, last_read, reg_idx + (reg_size / 4), mode, vip); ++ writemask = get_available_writemask(allocator, reg_idx + (reg_size / 4), mode, vip); + if ((writemask & last_reg_mask) != last_reg_mask) + return false; + return true; + } + +-static struct hlsl_reg allocate_range(struct hlsl_ctx *ctx, struct register_allocator *allocator, +- unsigned int first_write, unsigned int last_read, unsigned int reg_size, int mode, bool vip) ++static struct hlsl_reg allocate_range(struct hlsl_ctx *ctx, ++ struct register_allocator *allocator, unsigned int reg_size, int mode, bool vip) + { + struct hlsl_reg ret = {0}; + uint32_t reg_idx; +@@ -6096,15 +6064,14 @@ static struct hlsl_reg allocate_range(struct hlsl_ctx *ctx, struct register_allo + + for (reg_idx = 0;; ++reg_idx) + { +- if (is_range_available(allocator, first_write, last_read, reg_idx, reg_size, mode, vip)) ++ if (is_range_available(allocator, reg_idx, reg_size, mode, vip)) + break; + } + + for (i = 0; i < reg_size / 4; ++i) +- record_allocation(ctx, allocator, reg_idx + i, VKD3DSP_WRITEMASK_ALL, first_write, last_read, mode, vip); ++ record_allocation(ctx, allocator, reg_idx + i, VKD3DSP_WRITEMASK_ALL, mode, vip); + if (reg_size % 4) +- record_allocation(ctx, allocator, reg_idx + (reg_size / 4), +- (1u << (reg_size % 4)) - 1, first_write, last_read, mode, vip); ++ record_allocation(ctx, allocator, reg_idx + (reg_size / 4), (1u << (reg_size % 4)) - 1, mode, vip); + + ret.type = allocator->type; + ret.id = reg_idx; +@@ -6113,22 +6080,17 @@ static struct hlsl_reg allocate_range(struct hlsl_ctx *ctx, struct register_allo + return ret; + } + +-static struct hlsl_reg allocate_numeric_registers_for_type(struct hlsl_ctx *ctx, struct register_allocator *allocator, +- unsigned int first_write, unsigned int last_read, const struct hlsl_type *type) ++static struct hlsl_reg allocate_numeric_registers_for_type(struct hlsl_ctx *ctx, ++ struct register_allocator *allocator, const struct hlsl_type *type) + { + unsigned int reg_size = type->reg_size[HLSL_REGSET_NUMERIC]; +- struct hlsl_reg ret; + + /* FIXME: We could potentially pack structs or arrays more efficiently... */ + + if (type->class <= HLSL_CLASS_VECTOR) +- ret = allocate_register(ctx, allocator, first_write, last_read, +- type->e.numeric.dimx, type->e.numeric.dimx, 0, false, false); ++ return allocate_register(ctx, allocator, type->e.numeric.dimx, type->e.numeric.dimx, 0, false, false); + else +- ret = allocate_range(ctx, allocator, first_write, last_read, reg_size, 0, false); +- if (allocator->type == VKD3DSPR_TEMP) +- ctx->temp_count = max(ctx->temp_count, ret.id + ret.allocation_size); +- return ret; ++ return allocate_range(ctx, allocator, reg_size, 0, false); + } + + static const char *debug_register(struct hlsl_reg reg, const struct hlsl_type *type) +@@ -6293,10 +6255,9 @@ static void calculate_resource_register_counts(struct hlsl_ctx *ctx) + } + } + +-static void allocate_instr_temp_register(struct hlsl_ctx *ctx, +- struct hlsl_ir_node *instr, struct register_allocator *allocator) ++static void allocate_instr_temp_register(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr) + { +- unsigned int reg_writemask = 0, dst_writemask = 0; ++ unsigned int dst_writemask = 0; + bool is_per_component = false; + + if (instr->reg.allocated || !instr->last_read) +@@ -6308,12 +6269,10 @@ static void allocate_instr_temp_register(struct hlsl_ctx *ctx, + { + case HLSL_OP1_COS_REDUCED: + dst_writemask = VKD3DSP_WRITEMASK_0; +- reg_writemask = ctx->profile->major_version < 3 ? (1 << 3) - 1 : VKD3DSP_WRITEMASK_0; + break; + + case HLSL_OP1_SIN_REDUCED: + dst_writemask = VKD3DSP_WRITEMASK_1; +- reg_writemask = ctx->profile->major_version < 3 ? (1 << 3) - 1 : VKD3DSP_WRITEMASK_1; + break; + + case HLSL_OP1_EXP2: +@@ -6335,11 +6294,13 @@ static void allocate_instr_temp_register(struct hlsl_ctx *ctx, + + VKD3D_ASSERT(instr->data_type->class <= HLSL_CLASS_VECTOR); + +- if (reg_writemask) ++ if (dst_writemask) + { +- instr->reg = allocate_register_with_masks(ctx, allocator, +- instr->index, instr->last_read, reg_writemask, dst_writemask, 0, false); +- ctx->temp_count = max(ctx->temp_count, instr->reg.id + 1); ++ instr->reg.writemask = dst_writemask; ++ instr->reg.allocation_size = 1; ++ instr->reg.allocated = true; ++ instr->reg.type = VKD3DSPR_TEMP; ++ instr->reg.id = ctx->temp_count++; + } + else if (is_per_component) + { +@@ -6348,8 +6309,6 @@ static void allocate_instr_temp_register(struct hlsl_ctx *ctx, + instr->reg.allocated = true; + instr->reg.type = VKD3DSPR_TEMP; + instr->reg.id = ctx->temp_count++; +- +- record_allocation(ctx, allocator, ctx->temp_count - 1, VKD3DSP_WRITEMASK_ALL, 1, UINT_MAX, 0, false); + } + else + { +@@ -6360,12 +6319,11 @@ static void allocate_instr_temp_register(struct hlsl_ctx *ctx, + instr->reg.id = ctx->ssa_count++; + } + +- TRACE("Allocated anonymous expression @%u to %s (liveness %u-%u).\n", instr->index, +- debug_register(instr->reg, instr->data_type), instr->index, instr->last_read); ++ TRACE("Allocated anonymous expression @%u to %s.\n", instr->index, ++ debug_register(instr->reg, instr->data_type)); + } + +-static void allocate_variable_temp_register(struct hlsl_ctx *ctx, +- struct hlsl_ir_var *var, struct register_allocator *allocator) ++static void allocate_variable_temp_register(struct hlsl_ctx *ctx, struct hlsl_ir_var *var) + { + struct hlsl_reg *reg = &var->regs[HLSL_REGSET_NUMERIC]; + +@@ -6376,7 +6334,7 @@ static void allocate_variable_temp_register(struct hlsl_ctx *ctx, + { + if (var->indexable) + { +- reg->id = allocator->indexable_count++; ++ reg->id = ctx->indexable_temp_count++; + reg->allocation_size = 1; + reg->writemask = 0; + reg->allocated = true; +@@ -6392,19 +6350,15 @@ static void allocate_variable_temp_register(struct hlsl_ctx *ctx, + reg->writemask = vkd3d_write_mask_from_component_count(var->data_type->e.numeric.dimx); + reg->allocated = true; + +- for (unsigned int i = 0; i < reg->allocation_size; ++i) +- record_allocation(ctx, allocator, ctx->temp_count + i, VKD3DSP_WRITEMASK_ALL, 1, UINT_MAX, 0, false); +- + ctx->temp_count += reg->allocation_size; + +- TRACE("Allocated %s to %s (liveness %u-%u).\n", var->name, +- debug_register(var->regs[HLSL_REGSET_NUMERIC], var->data_type), var->first_write, var->last_read); ++ TRACE("Allocated %s to %s.\n", var->name, ++ debug_register(var->regs[HLSL_REGSET_NUMERIC], var->data_type)); + } + } + } + +-static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, +- struct hlsl_block *block, struct register_allocator *allocator) ++static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, struct hlsl_block *block) + { + struct hlsl_ir_node *instr; + +@@ -6414,15 +6368,15 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, + if (ctx->profile->major_version >= 4 && instr->type == HLSL_IR_CONSTANT) + continue; + +- allocate_instr_temp_register(ctx, instr, allocator); ++ allocate_instr_temp_register(ctx, instr); + + switch (instr->type) + { + case HLSL_IR_IF: + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); +- allocate_temp_registers_recurse(ctx, &iff->then_block, allocator); +- allocate_temp_registers_recurse(ctx, &iff->else_block, allocator); ++ allocate_temp_registers_recurse(ctx, &iff->then_block); ++ allocate_temp_registers_recurse(ctx, &iff->else_block); + break; + } + +@@ -6431,21 +6385,21 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, + struct hlsl_ir_load *load = hlsl_ir_load(instr); + /* We need to at least allocate a variable for undefs. + * FIXME: We should probably find a way to remove them instead. */ +- allocate_variable_temp_register(ctx, load->src.var, allocator); ++ allocate_variable_temp_register(ctx, load->src.var); + break; + } + + case HLSL_IR_LOOP: + { + struct hlsl_ir_loop *loop = hlsl_ir_loop(instr); +- allocate_temp_registers_recurse(ctx, &loop->body, allocator); ++ allocate_temp_registers_recurse(ctx, &loop->body); + break; + } + + case HLSL_IR_STORE: + { + struct hlsl_ir_store *store = hlsl_ir_store(instr); +- allocate_variable_temp_register(ctx, store->lhs.var, allocator); ++ allocate_variable_temp_register(ctx, store->lhs.var); + break; + } + +@@ -6456,7 +6410,7 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { +- allocate_temp_registers_recurse(ctx, &c->body, allocator); ++ allocate_temp_registers_recurse(ctx, &c->body); + } + break; + } +@@ -6580,7 +6534,7 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, + break; + } + +- constant->reg = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type); ++ constant->reg = allocate_numeric_registers_for_type(ctx, allocator, type); + TRACE("Allocated constant @%u to %s.\n", instr->index, debug_register(constant->reg, type)); + + for (unsigned int x = 0, i = 0; x < 4; ++x) +@@ -6677,14 +6631,14 @@ static void allocate_sincos_const_registers(struct hlsl_ctx *ctx, struct hlsl_bl + { + type = hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4); + +- ctx->d3dsincosconst1 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type); ++ ctx->d3dsincosconst1 = allocate_numeric_registers_for_type(ctx, allocator, type); + TRACE("Allocated D3DSINCOSCONST1 to %s.\n", debug_register(ctx->d3dsincosconst1, type)); + record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 0, -1.55009923e-06f, &instr->loc); + record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 1, -2.17013894e-05f, &instr->loc); + record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 2, 2.60416674e-03f, &instr->loc); + record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 3, 2.60416680e-04f, &instr->loc); + +- ctx->d3dsincosconst2 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type); ++ ctx->d3dsincosconst2 = allocate_numeric_registers_for_type(ctx, allocator, type); + TRACE("Allocated D3DSINCOSCONST2 to %s.\n", debug_register(ctx->d3dsincosconst2, type)); + record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 0, -2.08333340e-02f, &instr->loc); + record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 1, -1.25000000e-01f, &instr->loc); +@@ -6721,15 +6675,14 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_block *bo + { + if (i < bind_count) + { +- if (get_available_writemask(&allocator_used, 1, UINT_MAX, +- reg_idx + i, 0, false) != VKD3DSP_WRITEMASK_ALL) ++ if (get_available_writemask(&allocator_used, reg_idx + i, 0, false) != VKD3DSP_WRITEMASK_ALL) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, + "Overlapping register() reservations on 'c%u'.", reg_idx + i); + } +- record_allocation(ctx, &allocator_used, reg_idx + i, VKD3DSP_WRITEMASK_ALL, 1, UINT_MAX, 0, false); ++ record_allocation(ctx, &allocator_used, reg_idx + i, VKD3DSP_WRITEMASK_ALL, 0, false); + } +- record_allocation(ctx, &allocator, reg_idx + i, VKD3DSP_WRITEMASK_ALL, 1, UINT_MAX, 0, false); ++ record_allocation(ctx, &allocator, reg_idx + i, VKD3DSP_WRITEMASK_ALL, 0, false); + } + + var->regs[HLSL_REGSET_NUMERIC].type = VKD3DSPR_CONST; +@@ -6753,7 +6706,7 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_block *bo + + if (!var->regs[HLSL_REGSET_NUMERIC].allocated) + { +- var->regs[HLSL_REGSET_NUMERIC] = allocate_range(ctx, &allocator, 1, UINT_MAX, alloc_size, 0, false); ++ var->regs[HLSL_REGSET_NUMERIC] = allocate_range(ctx, &allocator, alloc_size, 0, false); + TRACE("Allocated %s to %s.\n", var->name, + debug_register(var->regs[HLSL_REGSET_NUMERIC], var->data_type)); + } +@@ -6772,10 +6725,11 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_block *bo + * does not handle constants. */ + static void allocate_temp_registers(struct hlsl_ctx *ctx, struct hlsl_block *body, struct list *semantic_vars) + { +- struct register_allocator allocator = {.type = VKD3DSPR_TEMP}; + struct hlsl_scope *scope; + struct hlsl_ir_var *var; + ++ ctx->indexable_temp_count = 0; ++ + /* Reset variable temp register allocations. */ + LIST_FOR_EACH_ENTRY(scope, &ctx->scopes, struct hlsl_scope, entry) + { +@@ -6793,16 +6747,13 @@ static void allocate_temp_registers(struct hlsl_ctx *ctx, struct hlsl_block *bod + { + if (var->is_output_semantic) + { +- record_allocation(ctx, &allocator, 0, VKD3DSP_WRITEMASK_ALL, +- var->first_write, UINT_MAX, 0, false); + ctx->temp_count = 1; + break; + } + } + } + +- allocate_temp_registers_recurse(ctx, body, &allocator); +- vkd3d_free(allocator.allocations); ++ allocate_temp_registers_recurse(ctx, body); + } + + static enum vkd3d_shader_interpolation_mode sm4_get_interpolation_mode(struct hlsl_type *type, +@@ -6941,7 +6892,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var + if (special_interpolation) + mode = VKD3DSIM_NONE; + +- var->regs[HLSL_REGSET_NUMERIC] = allocate_register(ctx, allocator, 1, UINT_MAX, ++ var->regs[HLSL_REGSET_NUMERIC] = allocate_register(ctx, allocator, + reg_size, component_count, mode, var->force_align, vip_allocation); + + TRACE("Allocated %s to %s (mode %d).\n", var->name, +@@ -9763,8 +9714,6 @@ static bool sm1_generate_vsir_instr_expr(struct hlsl_ctx *ctx, struct vsir_progr + break; + + case HLSL_OP3_CMP: +- if (!hlsl_type_is_floating_point(type)) +- goto err; + generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VSIR_OP_CMP, 0, 0, true); + break; + +@@ -11735,6 +11684,7 @@ static bool sm4_generate_vsir_instr_ld(struct hlsl_ctx *ctx, + const struct vkd3d_shader_version *version = &program->shader_version; + const struct hlsl_ir_node *sample_index = load->sample_index.node; + const struct hlsl_ir_node *texel_offset = load->texel_offset.node; ++ const struct hlsl_ir_node *byte_offset = load->byte_offset.node; + const struct hlsl_ir_node *coords = load->coords.node; + unsigned int coords_writemask = VKD3DSP_WRITEMASK_ALL; + const struct hlsl_deref *resource = &load->resource; +@@ -11742,20 +11692,15 @@ static bool sm4_generate_vsir_instr_ld(struct hlsl_ctx *ctx, + enum hlsl_sampler_dim dim = load->sampling_dim; + bool tgsm = load->resource.var->is_tgsm; + struct vkd3d_shader_instruction *ins; ++ bool multisampled, raw, structured; + enum vkd3d_shader_opcode opcode; +- bool multisampled, raw; + + VKD3D_ASSERT(load->load_type == HLSL_RESOURCE_LOAD); + +- if (resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) +- { +- hlsl_fixme(ctx, &load->node.loc, "Structured buffer loads."); +- return false; +- } +- + multisampled = resource_type->class == HLSL_CLASS_TEXTURE + && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS + || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); ++ structured = resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER; + + if (!tgsm) + { +@@ -11766,15 +11711,19 @@ static bool sm4_generate_vsir_instr_ld(struct hlsl_ctx *ctx, + hlsl_fixme(ctx, &load->node.loc, "Load from structured TGSM."); + return false; + } ++ VKD3D_ASSERT(!(structured && multisampled)); + +- if (uav) ++ if (structured) ++ opcode = VSIR_OP_LD_STRUCTURED; ++ else if (uav) + opcode = VSIR_OP_LD_UAV_TYPED; + else if (raw) + opcode = VSIR_OP_LD_RAW; + else + opcode = multisampled ? VSIR_OP_LD2DMS : VSIR_OP_LD; + +- if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, 2 + multisampled))) ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, ++ &instr->loc, opcode, 1, 2 + multisampled + structured))) + return false; + + if (texel_offset && !sm4_generate_vsir_validate_texel_offset_aoffimmi(texel_offset)) +@@ -11802,10 +11751,15 @@ static bool sm4_generate_vsir_instr_ld(struct hlsl_ctx *ctx, + vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, coords_writemask); + + if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, +- &ins->src[1], resource, ins->dst[0].write_mask, &instr->loc)) ++ &ins->src[structured ? 2 : 1], resource, ins->dst[0].write_mask, &instr->loc)) + return false; + +- if (multisampled) ++ if (structured) ++ { ++ VKD3D_ASSERT(byte_offset); ++ vsir_src_from_hlsl_node(&ins->src[1], ctx, byte_offset, VKD3DSP_WRITEMASK_ALL); ++ } ++ else if (multisampled) + { + if (sample_index->type == HLSL_IR_CONSTANT) + vsir_src_from_hlsl_constant_value(&ins->src[2], ctx, +@@ -12889,6 +12843,9 @@ static void sm4_generate_vsir_add_dcl_texture(struct hlsl_ctx *ctx, + { + switch (component_type->sampler_dim) + { ++ case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER: ++ opcode = VSIR_OP_DCL_RESOURCE_STRUCTURED; ++ break; + case HLSL_SAMPLER_DIM_RAW_BUFFER: + opcode = VSIR_OP_DCL_RESOURCE_RAW; + break; +@@ -12944,7 +12901,7 @@ static void sm4_generate_vsir_add_dcl_texture(struct hlsl_ctx *ctx, + else if (component_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) + { + ins->structured = true; +- ins->resource_stride = 4 * component_type->e.resource.format->reg_size[HLSL_REGSET_NUMERIC]; ++ ins->resource_stride = hlsl_type_get_packed_size(component_type->e.resource.format); + ins->declaration.structured_resource.byte_stride = ins->resource_stride; + } + else +@@ -13214,14 +13171,16 @@ static enum D3D_RESOURCE_RETURN_TYPE sm4_data_type(const struct hlsl_type *type) + + static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type) + { ++ bool structured = type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER; ++ + switch (type->class) + { + case HLSL_CLASS_SAMPLER: + return D3D_SIT_SAMPLER; + case HLSL_CLASS_TEXTURE: +- return D3D_SIT_TEXTURE; ++ return structured ? D3D_SIT_STRUCTURED : D3D_SIT_TEXTURE; + case HLSL_CLASS_UAV: +- return D3D_SIT_UAV_RWTYPED; ++ return structured ? D3D_SIT_UAV_RWSTRUCTURED : D3D_SIT_UAV_RWTYPED; + default: + break; + } +@@ -13297,7 +13256,8 @@ static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type) + vkd3d_unreachable(); + } + +-static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, struct hlsl_type *type) ++static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, ++ struct hlsl_type *type, bool structured) + { + const struct hlsl_type *array_type = hlsl_get_multiarray_element_type(type); + const char *name = array_type->name ? array_type->name : ""; +@@ -13306,7 +13266,10 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b + size_t name_offset = 0; + size_t i; + +- if (type->bytecode_offset) ++ if (!structured && type->bytecode_offset) ++ return; ++ ++ if (structured && type->packed_bytecode_offset) + return; + + if (profile->major_version >= 5) +@@ -13328,7 +13291,7 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b + continue; + + field->name_bytecode_offset = put_string(buffer, field->name); +- write_sm4_type(ctx, buffer, field->type); ++ write_sm4_type(ctx, buffer, field->type, structured); + ++field_count; + } + +@@ -13337,15 +13300,29 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b + for (i = 0; i < array_type->e.record.field_count; ++i) + { + struct hlsl_struct_field *field = &array_type->e.record.fields[i]; ++ unsigned int field_type_offset, offset; + + if (!field->type->reg_size[HLSL_REGSET_NUMERIC]) + continue; + + put_u32(buffer, field->name_bytecode_offset); +- put_u32(buffer, field->type->bytecode_offset); +- put_u32(buffer, field->reg_offset[HLSL_REGSET_NUMERIC] * sizeof(float)); ++ ++ if (!structured) ++ field_type_offset = field->type->bytecode_offset; ++ else ++ field_type_offset = field->type->packed_bytecode_offset; ++ put_u32(buffer, field_type_offset); ++ ++ if (!structured) ++ offset = field->reg_offset[HLSL_REGSET_NUMERIC] * sizeof(float); ++ else ++ offset = struct_field_get_packed_offset(array_type, i); ++ put_u32(buffer, offset); + } +- type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); ++ if (!structured) ++ type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); ++ else ++ type->packed_bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); + put_u32(buffer, vkd3d_make_u32(1, hlsl_type_component_count(array_type))); + put_u32(buffer, vkd3d_make_u32(array_size, field_count)); + put_u32(buffer, fields_offset); +@@ -13353,7 +13330,11 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b + else + { + VKD3D_ASSERT(array_type->class <= HLSL_CLASS_LAST_NUMERIC); +- type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); ++ if (!structured) ++ type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); ++ else ++ type->packed_bytecode_offset = put_u32(buffer, ++ vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); + put_u32(buffer, vkd3d_make_u32(array_type->e.numeric.dimy, array_type->e.numeric.dimx)); + put_u32(buffer, vkd3d_make_u32(array_size, 0)); + put_u32(buffer, 1); +@@ -13372,9 +13353,9 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b + static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rdef) + { + uint32_t binding_desc_size = (hlsl_version_ge(ctx, 5, 1) ? 10 : 8) * sizeof(uint32_t); +- size_t cbuffers_offset, resources_offset, creator_offset, string_offset; +- unsigned int cbuffer_count = 0, extern_resources_count, i, j; ++ size_t buffers_offset, resources_offset, creator_offset, string_offset; + size_t cbuffer_position, resource_position, creator_position; ++ unsigned int buffer_count = 0, extern_resources_count, i, j; + const struct hlsl_profile_info *profile = ctx->profile; + struct vkd3d_bytecode_buffer buffer = {0}; + struct extern_resource *extern_resources; +@@ -13396,10 +13377,20 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry) + { + if (cbuffer->reg.allocated) +- ++cbuffer_count; ++ ++buffer_count; ++ } ++ ++ for (i = 0; i < extern_resources_count; ++i) ++ { ++ const struct extern_resource *resource = &extern_resources[i]; ++ ++ if (resource->buffer || resource->component_type->sampler_dim != HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) ++ continue; ++ ++ ++buffer_count; + } + +- put_u32(&buffer, cbuffer_count); ++ put_u32(&buffer, buffer_count); + cbuffer_position = put_u32(&buffer, 0); + put_u32(&buffer, extern_resources_count); + resource_position = put_u32(&buffer, 0); +@@ -13440,12 +13431,19 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + put_u32(&buffer, sm4_resource_type(resource->component_type)); + if (resource->regset == HLSL_REGSET_TEXTURES || resource->regset == HLSL_REGSET_UAVS) + { ++ bool structured = resource->component_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER; + unsigned int dimx = resource->component_type->e.resource.format->e.numeric.dimx; + + put_u32(&buffer, sm4_data_type(resource->component_type)); + put_u32(&buffer, sm4_rdef_resource_dimension(resource->component_type)); +- put_u32(&buffer, ~0u); /* FIXME: multisample count */ +- flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; ++ ++ if (structured) ++ put_u32(&buffer, hlsl_type_get_packed_size(resource->component_type->e.resource.format)); ++ else ++ put_u32(&buffer, ~0u); /* FIXME: multisample count */ ++ ++ if (!structured) ++ flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; + } + else + { +@@ -13474,8 +13472,8 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + + /* Buffers. */ + +- cbuffers_offset = bytecode_align(&buffer); +- set_u32(&buffer, cbuffer_position, cbuffers_offset); ++ buffers_offset = bytecode_align(&buffer); ++ set_u32(&buffer, cbuffer_position, buffers_offset); + LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry) + { + unsigned int var_count = 0; +@@ -13497,6 +13495,24 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + put_u32(&buffer, cbuffer->type == HLSL_BUFFER_CONSTANT ? D3D_CT_CBUFFER : D3D_CT_TBUFFER); + } + ++ for (i = 0; i < extern_resources_count; ++i) ++ { ++ const struct extern_resource *resource = &extern_resources[i]; ++ struct hlsl_type *resource_type; ++ ++ if (resource->buffer || resource->component_type->sampler_dim != HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) ++ continue; ++ ++ resource_type = resource->component_type->e.resource.format; ++ ++ put_u32(&buffer, 0); /* name */ ++ put_u32(&buffer, 1); /* var count */ ++ put_u32(&buffer, 0); /* variable offset */ ++ put_u32(&buffer, hlsl_type_get_packed_size(resource_type)); /* size */ ++ put_u32(&buffer, 0); /* FIXME: flags */ ++ put_u32(&buffer, D3D_CT_RESOURCE_BIND_INFO); ++ } ++ + i = 0; + LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry) + { +@@ -13504,7 +13520,18 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + continue; + + string_offset = put_string(&buffer, cbuffer->name); +- set_u32(&buffer, cbuffers_offset + i++ * 6 * sizeof(uint32_t), string_offset); ++ set_u32(&buffer, buffers_offset + i++ * 6 * sizeof(uint32_t), string_offset); ++ } ++ ++ for (j = 0; j < extern_resources_count; ++j) ++ { ++ const struct extern_resource *resource = &extern_resources[j]; ++ ++ if (resource->buffer || resource->component_type->sampler_dim != HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) ++ continue; ++ ++ string_offset = put_string(&buffer, resource->name); ++ set_u32(&buffer, buffers_offset + i++ * 6 * sizeof(uint32_t), string_offset); + } + + i = 0; +@@ -13515,7 +13542,7 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + if (!cbuffer->reg.allocated) + continue; + +- set_u32(&buffer, cbuffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start); ++ set_u32(&buffer, buffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start); + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +@@ -13554,7 +13581,7 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + + string_offset = put_string(&buffer, var->name); + set_u32(&buffer, var_offset, string_offset); +- write_sm4_type(ctx, &buffer, var->data_type); ++ write_sm4_type(ctx, &buffer, var->data_type, false); + set_u32(&buffer, var_offset + 4 * sizeof(uint32_t), var->data_type->bytecode_offset); + + if (var->default_values) +@@ -13597,6 +13624,42 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd + } + } + ++ for (j = 0; j < extern_resources_count; ++j) ++ { ++ const struct extern_resource *resource = &extern_resources[j]; ++ struct hlsl_type *resource_type; ++ size_t vars_start; ++ ++ if (resource->buffer || resource->component_type->sampler_dim != HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) ++ continue; ++ ++ resource_type = resource->component_type->e.resource.format; ++ ++ vars_start = bytecode_align(&buffer); ++ ++ set_u32(&buffer, buffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start); ++ ++ put_u32(&buffer, 0); /* name */ ++ put_u32(&buffer, 0); /* offset */ ++ put_u32(&buffer, hlsl_type_get_packed_size(resource_type)); ++ put_u32(&buffer, D3D_SVF_USED); ++ put_u32(&buffer, 0); /* type */ ++ put_u32(&buffer, 0); /* default value */ ++ ++ if (profile->major_version >= 5) ++ { ++ put_u32(&buffer, ~0u); /* texture start */ ++ put_u32(&buffer, 0); /* texture count */ ++ put_u32(&buffer, ~0u); /* sampler start */ ++ put_u32(&buffer, 0); /* sampler count */ ++ } ++ ++ string_offset = put_string(&buffer, "$Element"); ++ set_u32(&buffer, vars_start, string_offset); ++ write_sm4_type(ctx, &buffer, resource_type, true); ++ set_u32(&buffer, vars_start + 4 * sizeof(uint32_t), resource_type->packed_bytecode_offset); ++ } ++ + creator_offset = put_string(&buffer, vkd3d_shader_get_version(NULL, NULL)); + set_u32(&buffer, creator_position, creator_offset); + +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index b120801d5f9..3e06e887096 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -9758,9 +9758,10 @@ static void vsir_validate_ssa_register(struct validation_context *ctx, + + 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); ++ "Invalid data type \"%s\" (%#x) for SSA register %u: " ++ "it has already been seen with data type \"%s\" (%#x) at instruction %zu.", ++ vsir_data_type_get_name(reg->data_type, ""), reg->data_type, reg->idx[0].offset, ++ vsir_data_type_get_name(data->data_type, ""), data->data_type, data->first_seen); + } + } + +@@ -10008,7 +10009,8 @@ static void vsir_validate_dst_param(struct validation_context *ctx, + + default: + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid data type %#x for destination with saturate modifier.", dst->reg.data_type); ++ "Invalid data type \"%s\" (%#x) for destination with saturate modifier.", ++ vsir_data_type_get_name(dst->reg.data_type, ""), dst->reg.data_type); + break; + + } +@@ -10027,7 +10029,8 @@ static void vsir_validate_dst_param(struct validation_context *ctx, + case 15: + if (dst->reg.data_type != VSIR_DATA_F32) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid data type %#x for destination with shift.", dst->reg.data_type); ++ "Invalid data type \"%s\" (%#x) for destination with shift.", ++ vsir_data_type_get_name(dst->reg.data_type, ""), dst->reg.data_type); + break; + + default: +@@ -10165,7 +10168,8 @@ static void vsir_validate_src_param(struct validation_context *ctx, + { + if (!(src_modifier_data[src->modifiers].data_type_mask & (1u << src->reg.data_type))) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, +- "Source has invalid modifier %#x for data type %u.", src->modifiers, src->reg.data_type); ++ "Source has invalid modifier %#x for data type \"%s\" (%#x).", ++ src->modifiers, vsir_data_type_get_name(src->reg.data_type, ""), src->reg.data_type); + } + + switch (src->reg.type) +@@ -10817,7 +10821,7 @@ static void vsir_validate_hull_shader_phase(struct validation_context *ctx, + static void vsir_validate_elementwise_operation(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction, const bool types[VSIR_DATA_TYPE_COUNT]) + { +- enum vsir_data_type dst_data_type; ++ enum vsir_data_type dst_data_type, src_data_type; + unsigned int i; + + if (instruction->dst_count < 1) +@@ -10830,16 +10834,18 @@ static void vsir_validate_elementwise_operation(struct validation_context *ctx, + + if (!types[dst_data_type]) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid data type %#x for elementwise operation \"%s\" (%#x).", +- dst_data_type, vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); ++ "Invalid data type \"%s\" (%#x) for elementwise operation \"%s\" (%#x).", ++ vsir_data_type_get_name(dst_data_type, ""), dst_data_type, ++ vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + + for (i = 0; i < instruction->src_count; ++i) + { +- if (instruction->src[i].reg.data_type != dst_data_type) ++ if ((src_data_type = instruction->src[i].reg.data_type) != dst_data_type) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Data type %#x for operand %u doesn't match the destination data type %#x " ++ "Data type \"%s\" (%#x) for operand %u doesn't match the destination data type \"%s\" (%#x) " + "for elementwise operation \"%s\" (%#x).", +- instruction->src[i].reg.data_type, i, dst_data_type, ++ vsir_data_type_get_name(src_data_type, ""), src_data_type, i, ++ vsir_data_type_get_name(dst_data_type, ""), dst_data_type, + vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + } + } +@@ -10896,7 +10902,7 @@ static void vsir_validate_logic_elementwise_operation(struct validation_context + static void vsir_validate_comparison_operation(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction, const bool types[VSIR_DATA_TYPE_COUNT]) + { +- enum vsir_data_type dst_data_type, src_data_type; ++ enum vsir_data_type dst_data_type, src_data_type, data_type; + unsigned int i; + + if (instruction->dst_count < 1) +@@ -10906,8 +10912,9 @@ static void vsir_validate_comparison_operation(struct validation_context *ctx, + + if (dst_data_type != VSIR_DATA_U32 && dst_data_type != VSIR_DATA_BOOL) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid data type %#x for result of comparison operation \"%s\" (%#x).", +- dst_data_type, vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); ++ "Invalid data type \"%s\" (%#x) for result of comparison operation \"%s\" (%#x).", ++ vsir_data_type_get_name(dst_data_type, ""), dst_data_type, ++ vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + + if (instruction->src_count == 0) + return; +@@ -10919,16 +10926,18 @@ static void vsir_validate_comparison_operation(struct validation_context *ctx, + + if (!types[src_data_type]) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid data type %#x for comparison operation \"%s\" (%#x).", +- src_data_type, vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); ++ "Invalid data type \"%s\" (%#x) for comparison operation \"%s\" (%#x).", ++ vsir_data_type_get_name(src_data_type, ""), src_data_type, ++ vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + + for (i = 1; i < instruction->src_count; ++i) + { +- if (instruction->src[i].reg.data_type != src_data_type) ++ if ((data_type = instruction->src[i].reg.data_type) != src_data_type) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Data type %#x for operand %u doesn't match the first operands data type %#x " +- "for comparison operation \"%s\" (%#x).", +- instruction->src[i].reg.data_type, i, src_data_type, ++ "Data type \"%s\" (%#x) for operand %u doesn't match the first " ++ "operands data type \"%s\" (%#x) for comparison operation \"%s\" (%#x).", ++ vsir_data_type_get_name(data_type, ""), data_type, i, ++ vsir_data_type_get_name(src_data_type, ""), src_data_type, + vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + } + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 058a631f25e..9cd9aafb587 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -4145,10 +4145,11 @@ static uint32_t spirv_compiler_emit_register_addressing(struct spirv_compiler *c + addr_id = spirv_compiler_emit_load_src(compiler, reg_index->rel_addr, VKD3DSP_WRITEMASK_0); + if (reg_index->offset) + { +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_UINT, 1); +- addr_id = vkd3d_spirv_build_op_iadd(builder, type_id, +- addr_id, spirv_compiler_get_constant_uint(compiler, reg_index->offset)); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_U32, 1); ++ addr_id = vkd3d_spirv_build_op_iadd(builder, type_id, addr_id, ++ spirv_compiler_get_constant_uint(compiler, reg_index->offset)); + } ++ + return addr_id; + } + +@@ -4294,7 +4295,7 @@ static uint32_t spirv_compiler_get_descriptor_index(struct spirv_compiler *compi + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, ptr_type_id, ptr_id, offset_id, index_ids[2]; + +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_UINT, 1); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_U32, 1); + if (!(offset_id = compiler->descriptor_offset_ids[push_constant_index])) + { + index_ids[0] = compiler->descriptor_offsets_member_id; +@@ -4492,8 +4493,9 @@ static uint32_t spirv_compiler_emit_int_to_bool(struct spirv_compiler *compiler, + + VKD3D_ASSERT(!(condition & ~(VKD3D_SHADER_CONDITIONAL_OP_NZ | VKD3D_SHADER_CONDITIONAL_OP_Z))); + +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_BOOL, component_count); + op = condition & VKD3D_SHADER_CONDITIONAL_OP_Z ? SpvOpIEqual : SpvOpINotEqual; ++ + return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, type_id, val_id, + data_type == VSIR_DATA_U64 + ? spirv_compiler_get_constant_uint64_vector(compiler, 0, component_count) +@@ -4508,7 +4510,8 @@ static uint32_t spirv_compiler_emit_bool_to_int(struct spirv_compiler *compiler, + + true_id = spirv_compiler_get_constant_uint_vector(compiler, signedness ? 0xffffffff : 1, component_count); + false_id = spirv_compiler_get_constant_uint_vector(compiler, 0, component_count); +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_UINT, component_count); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_U32, component_count); ++ + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); + } + +@@ -4521,7 +4524,8 @@ static uint32_t spirv_compiler_emit_bool_to_int64(struct spirv_compiler *compile + true_id = spirv_compiler_get_constant_uint64_vector(compiler, signedness ? UINT64_MAX : 1, + component_count); + false_id = spirv_compiler_get_constant_uint64_vector(compiler, 0, component_count); +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_UINT64, component_count); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_U64, component_count); ++ + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); + } + +diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c +index e2123656557..24a28886b00 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c ++++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c +@@ -4225,6 +4225,7 @@ static void tpf_handle_instruction(struct tpf_compiler *tpf, const struct vkd3d_ + + case VSIR_OP_DCL: + case VSIR_OP_DCL_RESOURCE_RAW: ++ case VSIR_OP_DCL_RESOURCE_STRUCTURED: + case VSIR_OP_DCL_UAV_RAW: + case VSIR_OP_DCL_UAV_STRUCTURED: + case VSIR_OP_DCL_UAV_TYPED: +@@ -4308,6 +4309,7 @@ static void tpf_handle_instruction(struct tpf_compiler *tpf, const struct vkd3d_ + case VSIR_OP_LD: + case VSIR_OP_LD2DMS: + case VSIR_OP_LD_RAW: ++ case VSIR_OP_LD_STRUCTURED: + case VSIR_OP_LD_UAV_TYPED: + case VSIR_OP_LOG: + case VSIR_OP_LOOP: +-- +2.51.0 + diff --git a/patches/vkd3d-latest/0009-Updated-vkd3d-to-6607b94ad7ce77907a912923f39e6371d23.patch b/patches/vkd3d-latest/0009-Updated-vkd3d-to-6607b94ad7ce77907a912923f39e6371d23.patch new file mode 100644 index 00000000..6c234200 --- /dev/null +++ b/patches/vkd3d-latest/0009-Updated-vkd3d-to-6607b94ad7ce77907a912923f39e6371d23.patch @@ -0,0 +1,126 @@ +From 847e0c6da106b68aa30bf48575ad204f547b913a Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Tue, 9 Sep 2025 12:15:35 +1000 +Subject: [PATCH] Updated vkd3d to 6607b94ad7ce77907a912923f39e6371d23e339b. + +--- + libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 17 +++++++++++++++++ + libs/vkd3d/libs/vkd3d-shader/dxil.c | 8 ++++++++ + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 3 +-- + libs/vkd3d/libs/vkd3d-shader/msl.c | 6 ++++++ + .../libs/vkd3d-shader/vkd3d_shader_private.h | 6 ++++-- + 5 files changed, 36 insertions(+), 4 deletions(-) + +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +index 897803ecb56..e2fb8b12998 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +@@ -957,6 +957,22 @@ static void shader_print_reg_type(struct vkd3d_d3d_asm_compiler *compiler, + vkd3d_string_buffer_printf(buffer, ">%s", suffix); + } + ++static void shader_print_indexable_temp_data_type(struct vkd3d_d3d_asm_compiler *compiler, ++ const struct vkd3d_shader_indexable_temp *t) ++{ ++ struct vkd3d_string_buffer *buffer = &compiler->buffer; ++ ++ if (!(compiler->flags & VSIR_ASM_FLAG_DUMP_TYPES)) ++ return; ++ ++ if (t->component_count > 1) ++ vkd3d_string_buffer_printf(buffer, " component_count); ++ else ++ vkd3d_string_buffer_printf(buffer, " data_type); ++ vkd3d_string_buffer_printf(buffer, ">"); ++} ++ + static void shader_print_write_mask(struct vkd3d_d3d_asm_compiler *compiler, + const char *prefix, uint32_t mask, const char *suffix) + { +@@ -1511,6 +1527,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, + vkd3d_string_buffer_printf(buffer, " %sx%u%s", compiler->colours.reg, + ins->declaration.indexable_temp.register_idx, compiler->colours.reset); + shader_print_subscript(compiler, ins->declaration.indexable_temp.register_size, NULL); ++ shader_print_indexable_temp_data_type(compiler, &ins->declaration.indexable_temp); + shader_print_uint_literal(compiler, ", ", ins->declaration.indexable_temp.component_count, ""); + if (ins->declaration.indexable_temp.alignment) + shader_print_uint_literal(compiler, ", align ", ins->declaration.indexable_temp.alignment, ""); +diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c +index 1678128da83..fb2cde4501a 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c ++++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c +@@ -3698,6 +3698,14 @@ static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const stru + { + enum vsir_data_type data_type = vsir_data_type_from_dxil(elem_type, sm6); + ++ if (!(sm6->program->global_flags & VKD3DSGF_FORCE_NATIVE_LOW_PRECISION)) ++ { ++ if (data_type == VSIR_DATA_F16) ++ data_type = VSIR_DATA_F32; ++ else if (data_type == VSIR_DATA_U16) ++ data_type = VSIR_DATA_U32; ++ } ++ + if (ins) + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_DCL_INDEXABLE_TEMP); + else +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +index 9a682a7550d..ee21207a855 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +@@ -8817,9 +8817,8 @@ static enum vsir_data_type vsir_data_type_from_hlsl_type(struct hlsl_ctx *ctx, c + case HLSL_TYPE_DOUBLE: + return VSIR_DATA_F64; + case HLSL_TYPE_FLOAT: +- return VSIR_DATA_F32; + case HLSL_TYPE_HALF: +- return VSIR_DATA_F16; ++ return VSIR_DATA_F32; + case HLSL_TYPE_INT: + return VSIR_DATA_I32; + case HLSL_TYPE_UINT: +diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c +index fc8d482e08a..d9e22abdfc3 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/msl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/msl.c +@@ -1414,6 +1414,12 @@ static void msl_ret(struct msl_generator *gen, const struct vkd3d_shader_instruc + static void msl_dcl_indexable_temp(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) + { + const char *type = ins->declaration.indexable_temp.component_count == 4 ? "vkd3d_vec4" : "vkd3d_scalar"; ++ ++ if (ins->declaration.indexable_temp.initialiser) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled initialiser for indexable temporary %u.", ++ ins->declaration.indexable_temp.register_idx); ++ + msl_print_indent(gen->buffer, gen->indent); + vkd3d_string_buffer_printf(gen->buffer, "%s x%u[%u];\n", type, + ins->declaration.indexable_temp.register_idx, +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index 9bf196b1fe2..ae88d97f461 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -1863,7 +1863,8 @@ static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_ty + { + case VSIR_DATA_BOOL: + return VKD3D_SHADER_COMPONENT_BOOL; +- case VSIR_DATA_F16: /* Minimum precision. TODO: native 16-bit */ ++ case VSIR_DATA_F16: ++ return VKD3D_SHADER_COMPONENT_FLOAT16; + case VSIR_DATA_F32: + case VSIR_DATA_SNORM: + case VSIR_DATA_UNORM: +@@ -1872,7 +1873,8 @@ static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_ty + return VKD3D_SHADER_COMPONENT_DOUBLE; + case VSIR_DATA_I32: + return VKD3D_SHADER_COMPONENT_INT; +- case VSIR_DATA_U16: /* Minimum precision. TODO: native 16-bit */ ++ case VSIR_DATA_U16: ++ return VKD3D_SHADER_COMPONENT_UINT16; + case VSIR_DATA_U32: + return VKD3D_SHADER_COMPONENT_UINT; + case VSIR_DATA_U64: +-- +2.51.0 + diff --git a/patches/vkd3d-latest/0010-Updated-vkd3d-to-de2095fda435c5ed47e946cf4e18c68b148.patch b/patches/vkd3d-latest/0010-Updated-vkd3d-to-de2095fda435c5ed47e946cf4e18c68b148.patch new file mode 100644 index 00000000..6dd37287 --- /dev/null +++ b/patches/vkd3d-latest/0010-Updated-vkd3d-to-de2095fda435c5ed47e946cf4e18c68b148.patch @@ -0,0 +1,1793 @@ +From 4b9fa54600c3aaa1f06e6d226f79cc19627072b1 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 11 Sep 2025 06:55:40 +1000 +Subject: [PATCH] Updated vkd3d to de2095fda435c5ed47e946cf4e18c68b14856081. + +--- + libs/vkd3d/include/vkd3d_shader.h | 15 +- + .../libs/vkd3d-shader/hlsl_constant_ops.c | 160 +++++ + libs/vkd3d/libs/vkd3d-shader/ir.c | 559 ++++++++++++------ + libs/vkd3d/libs/vkd3d-shader/msl.c | 23 +- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 45 +- + .../libs/vkd3d-shader/vkd3d_shader_main.c | 198 ------- + .../libs/vkd3d-shader/vkd3d_shader_private.h | 71 ++- + .../vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c | 9 +- + 8 files changed, 651 insertions(+), 429 deletions(-) + +diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h +index a1f85dbbd05..3a2f54c8f22 100644 +--- a/libs/vkd3d/include/vkd3d_shader.h ++++ b/libs/vkd3d/include/vkd3d_shader.h +@@ -422,10 +422,17 @@ struct vkd3d_shader_code + { + /** + * Pointer to the code. Note that textual formats are not null-terminated. +- * Therefore \a size should not include a null terminator, when this +- * structure is passed as input to a vkd3d-shader function, and the +- * allocated string will not include a null terminator when this structure +- * is used as output. ++ * Therefore \a size should not include a null terminator when this ++ * structure is passed as input to a vkd3d-shader function, and \a size ++ * will not include a null terminator when this structure is used as ++ * output. ++ * ++ * For convenience, vkd3d_shader_preprocess() and vkd3d_shader_compile() ++ * will append a null terminator past the end of their output when ++ * outputting textual formats like VKD3D_SHADER_TARGET_D3D_ASM. This makes ++ * it safe to call functions like strlen() on \a code for such output, ++ * although doing so will obviously not account for any embedded null ++ * characters that may be present. + */ + const void *code; + /** Size of \a code, in bytes. */ +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c +index 4cd47a0632e..252ed51a4e4 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c +@@ -250,6 +250,36 @@ static bool fold_ceil(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, + return true; + } + ++static bool fold_cos(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, ++ const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src) ++{ ++ enum hlsl_base_type type = dst_type->e.numeric.type; ++ unsigned int k; ++ ++ VKD3D_ASSERT(type == src->node.data_type->e.numeric.type); ++ ++ for (k = 0; k < dst_type->e.numeric.dimx; ++k) ++ { ++ switch (type) ++ { ++ case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: ++ dst->u[k].f = cosf(src->value.u[k].f); ++ break; ++ ++ case HLSL_TYPE_DOUBLE: ++ dst->u[k].d = cos(src->value.u[k].d); ++ break; ++ ++ default: ++ FIXME("Fold 'cos' for type %s.\n", debug_hlsl_type(ctx, dst_type)); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static bool fold_exp2(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, + const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src) + { +@@ -478,6 +508,48 @@ static bool fold_rcp(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, cons + return true; + } + ++static bool fold_reinterpret(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, ++ const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src) ++{ ++ unsigned int k; ++ ++ for (k = 0; k < dst_type->e.numeric.dimx; ++k) ++ { ++ dst->u[k] = src->value.u[k]; ++ } ++ ++ return true; ++} ++ ++static bool fold_round(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, ++ const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src) ++{ ++ enum hlsl_base_type type = dst_type->e.numeric.type; ++ unsigned int k; ++ ++ VKD3D_ASSERT(type == src->node.data_type->e.numeric.type); ++ ++ for (k = 0; k < dst_type->e.numeric.dimx; ++k) ++ { ++ switch (type) ++ { ++ case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: ++ /* Somewhat unfortunately, constant folded round() rounds ++ * halfway cases towards positive infinity, as opposed to ++ * nearest even like vsir/TPF round_ne. */ ++ dst->u[k].f = floorf(src->value.u[k].f + 0.5f); ++ break; ++ ++ default: ++ FIXME("Fold 'round' for type %s.\n", debug_hlsl_type(ctx, dst_type)); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static bool fold_rsq(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, const struct hlsl_type *dst_type, + const struct hlsl_ir_constant *src, const struct vkd3d_shader_location *loc) + { +@@ -544,6 +616,36 @@ static bool fold_sat(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, cons + return true; + } + ++static bool fold_sin(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, ++ const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src) ++{ ++ enum hlsl_base_type type = dst_type->e.numeric.type; ++ unsigned int k; ++ ++ VKD3D_ASSERT(type == src->node.data_type->e.numeric.type); ++ ++ for (k = 0; k < dst_type->e.numeric.dimx; ++k) ++ { ++ switch (type) ++ { ++ case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: ++ dst->u[k].f = sinf(src->value.u[k].f); ++ break; ++ ++ case HLSL_TYPE_DOUBLE: ++ dst->u[k].d = sin(src->value.u[k].d); ++ break; ++ ++ default: ++ FIXME("Fold 'sin' for type %s.\n", debug_hlsl_type(ctx, dst_type)); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static bool fold_sqrt(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, const struct hlsl_type *dst_type, + const struct hlsl_ir_constant *src, const struct vkd3d_shader_location *loc) + { +@@ -974,6 +1076,44 @@ static bool fold_lshift(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, c + return true; + } + ++static bool fold_mad(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, const struct hlsl_type *dst_type, ++ const struct hlsl_ir_constant *src1, const struct hlsl_ir_constant *src2, const struct hlsl_ir_constant *src3) ++{ ++ enum hlsl_base_type type = dst_type->e.numeric.type; ++ unsigned int k; ++ ++ VKD3D_ASSERT(type == src1->node.data_type->e.numeric.type); ++ VKD3D_ASSERT(type == src2->node.data_type->e.numeric.type); ++ VKD3D_ASSERT(type == src3->node.data_type->e.numeric.type); ++ ++ for (k = 0; k < dst_type->e.numeric.dimx; ++k) ++ { ++ switch (type) ++ { ++ case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: ++ dst->u[k].f = fmaf(src1->value.u[k].f, src2->value.u[k].f, src3->value.u[k].f); ++ break; ++ ++ case HLSL_TYPE_DOUBLE: ++ dst->u[k].d = fma(src1->value.u[k].d, src2->value.u[k].d, src3->value.u[k].d); ++ break; ++ ++ case HLSL_TYPE_INT: ++ case HLSL_TYPE_MIN16UINT: ++ case HLSL_TYPE_UINT: ++ dst->u[k].u = src1->value.u[k].u * src2->value.u[k].u + src3->value.u[k].u; ++ break; ++ ++ default: ++ FIXME("Fold 'mad' for type %s.\n", debug_hlsl_type(ctx, dst_type)); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static bool fold_max(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, const struct hlsl_type *dst_type, + const struct hlsl_ir_constant *src1, const struct hlsl_ir_constant *src2) + { +@@ -1263,6 +1403,10 @@ bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + success = fold_ceil(ctx, &res, instr->data_type, arg1); + break; + ++ case HLSL_OP1_COS: ++ success = fold_cos(ctx, &res, instr->data_type, arg1); ++ break; ++ + case HLSL_OP1_EXP2: + success = fold_exp2(ctx, &res, instr->data_type, arg1); + break; +@@ -1291,6 +1435,14 @@ bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + success = fold_rcp(ctx, &res, instr->data_type, arg1, &instr->loc); + break; + ++ case HLSL_OP1_REINTERPRET: ++ success = fold_reinterpret(ctx, &res, instr->data_type, arg1); ++ break; ++ ++ case HLSL_OP1_ROUND: ++ success = fold_round(ctx, &res, instr->data_type, arg1); ++ break; ++ + case HLSL_OP1_RSQ: + success = fold_rsq(ctx, &res, instr->data_type, arg1, &instr->loc); + break; +@@ -1299,6 +1451,10 @@ bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + success = fold_sat(ctx, &res, instr->data_type, arg1); + break; + ++ case HLSL_OP1_SIN: ++ success = fold_sin(ctx, &res, instr->data_type, arg1); ++ break; ++ + case HLSL_OP1_SQRT: + success = fold_sqrt(ctx, &res, instr->data_type, arg1, &instr->loc); + break; +@@ -1373,6 +1529,10 @@ bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + success = fold_dp2add(ctx, &res, instr->data_type, arg1, arg2, arg3); + break; + ++ case HLSL_OP3_MAD: ++ success = fold_mad(ctx, &res, instr->data_type, arg1, arg2, arg3); ++ break; ++ + case HLSL_OP3_TERNARY: + success = fold_ternary(ctx, &res, instr->data_type, arg1, arg2, arg3); + break; +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index 3e06e887096..29bf62709eb 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -53,7 +53,9 @@ const char *vsir_data_type_get_name(enum vsir_data_type t, const char *error) + [VSIR_DATA_F16 ] = "half", + [VSIR_DATA_F32 ] = "float", + [VSIR_DATA_F64 ] = "double", ++ [VSIR_DATA_I16 ] = "i16", + [VSIR_DATA_I32 ] = "int", ++ [VSIR_DATA_I64 ] = "i64", + [VSIR_DATA_U8 ] = "uint8", + [VSIR_DATA_U16 ] = "uint16", + [VSIR_DATA_U32 ] = "uint", +@@ -416,6 +418,183 @@ const char *vsir_opcode_get_name(enum vkd3d_shader_opcode op, const char *error) + return error; + } + ++static struct vkd3d_shader_param_node *shader_param_allocator_node_create( ++ struct vkd3d_shader_param_allocator *allocator) ++{ ++ struct vkd3d_shader_param_node *node; ++ ++ if (!(node = vkd3d_malloc(offsetof(struct vkd3d_shader_param_node, param[allocator->count * allocator->stride])))) ++ return NULL; ++ node->next = NULL; ++ ++ return node; ++} ++ ++static void shader_param_allocator_init(struct vkd3d_shader_param_allocator *allocator, size_t count, size_t stride) ++{ ++ allocator->count = max(count, MAX_REG_OUTPUT); ++ allocator->stride = stride; ++ allocator->head = NULL; ++ allocator->current = NULL; ++ allocator->index = allocator->count; ++} ++ ++static void shader_param_allocator_destroy(struct vkd3d_shader_param_allocator *allocator) ++{ ++ struct vkd3d_shader_param_node *current = allocator->head; ++ ++ while (current) ++ { ++ struct vkd3d_shader_param_node *next = current->next; ++ vkd3d_free(current); ++ current = next; ++ } ++} ++ ++void *shader_param_allocator_get(struct vkd3d_shader_param_allocator *allocator, size_t count) ++{ ++ void *params; ++ ++ if (!allocator->current || count > allocator->count - allocator->index) ++ { ++ struct vkd3d_shader_param_node *next; ++ ++ allocator->count = max(allocator->count, count); ++ if (!(next = shader_param_allocator_node_create(allocator))) ++ return NULL; ++ if (allocator->current) ++ allocator->current->next = next; ++ else ++ allocator->head = next; ++ allocator->current = next; ++ allocator->index = 0; ++ } ++ ++ params = &allocator->current->param[allocator->index * allocator->stride]; ++ allocator->index += count; ++ ++ return params; ++} ++ ++bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *array, size_t reserve) ++{ ++ if (!vkd3d_array_reserve((void **)&array->elements, &array->capacity, reserve, sizeof(*array->elements))) ++ { ++ ERR("Failed to allocate instructions.\n"); ++ return false; ++ } ++ ++ return true; ++} ++ ++bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *array, size_t idx, size_t count) ++{ ++ VKD3D_ASSERT(idx <= array->count); ++ ++ if (!shader_instruction_array_reserve(array, array->count + count)) ++ return false; ++ ++ memmove(&array->elements[idx + count], &array->elements[idx], (array->count - idx) * sizeof(*array->elements)); ++ memset(&array->elements[idx], 0, count * sizeof(*array->elements)); ++ array->count += count; ++ ++ return true; ++} ++ ++bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *array, ++ struct vkd3d_shader_immediate_constant_buffer *icb) ++{ ++ if (!vkd3d_array_reserve((void **)&array->icbs, &array->icb_capacity, array->icb_count + 1, sizeof(*array->icbs))) ++ return false; ++ ++ array->icbs[array->icb_count++] = icb; ++ ++ return true; ++} ++ ++static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params( ++ struct vkd3d_shader_instruction_array *array, const struct vkd3d_shader_src_param *params, size_t count); ++ ++static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, ++ struct vkd3d_shader_instruction_array *array) ++{ ++ size_t i; ++ ++ for (i = 0; i < reg->idx_count; ++i) ++ { ++ if (!reg->idx[i].rel_addr) ++ continue; ++ ++ if (!(reg->idx[i].rel_addr = shader_instruction_array_clone_src_params(array, reg->idx[i].rel_addr, 1))) ++ return false; ++ } ++ ++ return true; ++} ++ ++static struct vkd3d_shader_dst_param *shader_instruction_array_clone_dst_params( ++ struct vkd3d_shader_instruction_array *array, const struct vkd3d_shader_dst_param *params, size_t count) ++{ ++ struct vkd3d_shader_dst_param *dst_params; ++ size_t i; ++ ++ if (!(dst_params = shader_dst_param_allocator_get(&array->dst_params, count))) ++ return NULL; ++ ++ memcpy(dst_params, params, count * sizeof(*params)); ++ for (i = 0; i < count; ++i) ++ { ++ if (!shader_register_clone_relative_addresses(&dst_params[i].reg, array)) ++ return NULL; ++ } ++ ++ return dst_params; ++} ++ ++static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params( ++ struct vkd3d_shader_instruction_array *array, const struct vkd3d_shader_src_param *params, size_t count) ++{ ++ struct vkd3d_shader_src_param *src_params; ++ size_t i; ++ ++ if (!(src_params = shader_src_param_allocator_get(&array->src_params, count))) ++ return NULL; ++ ++ memcpy(src_params, params, count * sizeof(*params)); ++ for (i = 0; i < count; ++i) ++ { ++ if (!shader_register_clone_relative_addresses(&src_params[i].reg, array)) ++ return NULL; ++ } ++ ++ return src_params; ++} ++ ++static void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *array) ++{ ++ unsigned int i; ++ ++ vkd3d_free(array->elements); ++ shader_param_allocator_destroy(&array->dst_params); ++ shader_param_allocator_destroy(&array->src_params); ++ for (i = 0; i < array->icb_count; ++i) ++ { ++ vkd3d_free(array->icbs[i]); ++ } ++ vkd3d_free(array->icbs); ++} ++ ++static bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *array, size_t reserve) ++{ ++ memset(array, 0, sizeof(*array)); ++ /* Size the parameter initial allocations so they are large enough for most shaders. The ++ * code path for chained allocations will be tested if a few shaders need to use it. */ ++ shader_param_allocator_init(&array->dst_params, reserve - reserve / 8u, sizeof(struct vkd3d_shader_dst_param)); ++ shader_param_allocator_init(&array->src_params, reserve * 2u, sizeof(struct vkd3d_shader_src_param)); ++ ++ return shader_instruction_array_reserve(array, reserve); ++} ++ + static int convert_parameter_info(const struct vkd3d_shader_compile_info *compile_info, + unsigned int *ret_count, const struct vkd3d_shader_parameter1 **ret_parameters) + { +@@ -907,6 +1086,23 @@ static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *i + vsir_instruction_init(ins, &location, VSIR_OP_NOP); + } + ++/* NOTE: Immediate constant buffers are not cloned, so the source must not be destroyed while the ++ * destination is in use. This seems like a reasonable requirement given how this is currently used. */ ++static bool vsir_program_iterator_clone_instruction(struct vsir_program_iterator *dst_it, ++ const struct vkd3d_shader_instruction *src) ++{ ++ struct vkd3d_shader_instruction *dst = vsir_program_iterator_current(dst_it); ++ ++ *dst = *src; ++ ++ if (dst->dst_count && !(dst->dst = shader_instruction_array_clone_dst_params(dst_it->array, ++ dst->dst, dst->dst_count))) ++ return false; ++ ++ return !dst->src_count || !!(dst->src = shader_instruction_array_clone_src_params(dst_it->array, ++ dst->src, dst->src_count)); ++} ++ + static bool get_opcode_from_rel_op(enum vkd3d_shader_rel_op rel_op, + enum vsir_data_type data_type, enum vkd3d_shader_opcode *opcode, bool *requires_swap) + { +@@ -2238,8 +2434,6 @@ struct hull_flattener + { + struct vsir_program *program; + +- unsigned int instance_count; +- unsigned int phase_body_idx; + enum vkd3d_shader_opcode phase; + struct vkd3d_shader_location last_ret_location; + unsigned int *ssa_map; +@@ -2251,68 +2445,6 @@ static bool flattener_is_in_fork_or_join_phase(const struct hull_flattener *flat + return flattener->phase == VSIR_OP_HS_FORK_PHASE || flattener->phase == VSIR_OP_HS_JOIN_PHASE; + } + +-struct shader_phase_location +-{ +- unsigned int index; +- unsigned int instance_count; +- unsigned int instruction_count; +-}; +- +-struct shader_phase_location_array +-{ +- /* Unlikely worst case: one phase for each component of each output register. */ +- struct shader_phase_location locations[MAX_REG_OUTPUT * VKD3D_VEC4_SIZE]; +- unsigned int count; +-}; +- +-static void flattener_eliminate_phase_related_dcls(struct hull_flattener *normaliser, unsigned int index, +- struct vkd3d_shader_instruction *ins, struct shader_phase_location_array *locations) +-{ +- struct shader_phase_location *loc; +- bool b; +- +- if (ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE) +- { +- b = flattener_is_in_fork_or_join_phase(normaliser); +- /* Reset the phase info. */ +- normaliser->phase_body_idx = ~0u; +- normaliser->phase = ins->opcode; +- normaliser->instance_count = 1; +- /* Leave the first occurrence and delete the rest. */ +- if (b) +- vkd3d_shader_instruction_make_nop(ins); +- return; +- } +- else if (ins->opcode == VSIR_OP_DCL_HS_FORK_PHASE_INSTANCE_COUNT +- || ins->opcode == VSIR_OP_DCL_HS_JOIN_PHASE_INSTANCE_COUNT) +- { +- normaliser->instance_count = ins->declaration.count + !ins->declaration.count; +- vkd3d_shader_instruction_make_nop(ins); +- return; +- } +- +- if (normaliser->phase == VSIR_OP_INVALID || vsir_instruction_is_dcl(ins)) +- return; +- +- if (normaliser->phase_body_idx == ~0u) +- normaliser->phase_body_idx = index; +- +- if (ins->opcode == VSIR_OP_RET) +- { +- normaliser->last_ret_location = ins->location; +- vkd3d_shader_instruction_make_nop(ins); +- if (locations->count >= ARRAY_SIZE(locations->locations)) +- { +- FIXME("Insufficient space for phase location.\n"); +- return; +- } +- loc = &locations->locations[locations->count++]; +- loc->index = normaliser->phase_body_idx; +- loc->instance_count = normaliser->instance_count; +- loc->instruction_count = index - normaliser->phase_body_idx; +- } +-} +- + static void flattener_fixup_ssa_register(struct hull_flattener *normaliser, + struct vkd3d_shader_register *reg, unsigned int instance_id) + { +@@ -2375,54 +2507,109 @@ static void flattener_fixup_registers(struct hull_flattener *normaliser, + flattener_fixup_register_indices(normaliser, &ins->dst[i].reg, instance_id); + } + +-static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normaliser, +- struct shader_phase_location_array *locations) ++static enum vkd3d_result flattener_replicate_location(struct hull_flattener *normaliser, ++ struct vsir_program_iterator *it, size_t instance_count, size_t instruction_count) + { +- struct vkd3d_shader_instruction_array *instructions = &normaliser->program->instructions; +- struct shader_phase_location *loc; +- unsigned int i, j, k, end, count; +- +- for (i = 0, count = 0; i < locations->count; ++i) +- count += (locations->locations[i].instance_count - 1) * locations->locations[i].instruction_count; ++ struct vsir_program_iterator dst_it, src_it, first_it; ++ struct vkd3d_shader_instruction *ins; ++ unsigned int i, j; ++ size_t count; + +- if (!shader_instruction_array_reserve(instructions, instructions->count + count)) ++ VKD3D_ASSERT(instance_count); ++ count = (instance_count - 1) * instruction_count; ++ if (!vsir_program_iterator_insert_before(it, &first_it, count)) + return VKD3D_ERROR_OUT_OF_MEMORY; +- end = instructions->count; +- instructions->count += count; + +- for (i = locations->count; i > 0; --i) ++ /* Make a copy of the non-dcl instructions for each instance. */ ++ dst_it = first_it; ++ for (i = 1; i < instance_count; ++i) ++ { ++ src_it = *it; ++ for (j = 0; j < instruction_count; ++j) ++ { ++ if (!vsir_program_iterator_clone_instruction(&dst_it, vsir_program_iterator_current(&src_it))) ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ ++ vsir_program_iterator_next(&dst_it); ++ vsir_program_iterator_next(&src_it); ++ } ++ } ++ /* Replace each reference to the instance id with a constant instance id. */ ++ *it = first_it; ++ for (i = 0; i < instance_count; ++i) + { +- loc = &locations->locations[i - 1]; +- j = loc->index + loc->instruction_count; +- memmove(&instructions->elements[j + count], &instructions->elements[j], +- (end - j) * sizeof(*instructions->elements)); +- end = j; +- count -= (loc->instance_count - 1) * loc->instruction_count; +- loc->index += count; ++ if (i) ++ memset(normaliser->ssa_map, 0xff, normaliser->orig_ssa_count * sizeof(*normaliser->ssa_map)); ++ ++ for (j = 0; j < instruction_count; ++j) ++ { ++ ins = vsir_program_iterator_current(it); ++ flattener_fixup_registers(normaliser, ins, i); ++ vsir_program_iterator_next(it); ++ } + } + +- for (i = 0, count = 0; i < locations->count; ++i) ++ return VKD3D_OK; ++} ++ ++static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normaliser) ++{ ++ struct vsir_program_iterator it = vsir_program_iterator(&normaliser->program->instructions); ++ struct vsir_program_iterator phase_body_it; ++ struct vkd3d_shader_instruction *ins; ++ bool b, phase_body_it_valid = false; ++ unsigned int instruction_count = 0; ++ unsigned int instance_count = 0; ++ enum vkd3d_result res; ++ ++ normaliser->phase = VSIR_OP_INVALID; ++ for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + { +- loc = &locations->locations[i]; +- /* Make a copy of the non-dcl instructions for each instance. */ +- for (j = 1; j < loc->instance_count; ++j) ++ if (ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE) + { +- for (k = 0; k < loc->instruction_count; ++k) +- { +- if (!shader_instruction_array_clone_instruction(instructions, +- loc->index + loc->instruction_count * j + k, loc->index + k)) +- return VKD3D_ERROR_OUT_OF_MEMORY; +- } ++ b = flattener_is_in_fork_or_join_phase(normaliser); ++ /* Reset the phase info. */ ++ phase_body_it_valid = false; ++ normaliser->phase = ins->opcode; ++ instance_count = 1; ++ instruction_count = 0; ++ /* Leave the first occurrence and delete the rest. */ ++ if (b) ++ vkd3d_shader_instruction_make_nop(ins); ++ continue; + } +- /* Replace each reference to the instance id with a constant instance id. */ +- for (j = 0; j < loc->instance_count; ++j) ++ else if (ins->opcode == VSIR_OP_DCL_HS_FORK_PHASE_INSTANCE_COUNT ++ || ins->opcode == VSIR_OP_DCL_HS_JOIN_PHASE_INSTANCE_COUNT) + { +- if (j != 0) +- memset(normaliser->ssa_map, 0xff, normaliser->orig_ssa_count * sizeof(*normaliser->ssa_map)); ++ instance_count = ins->declaration.count + !ins->declaration.count; ++ vkd3d_shader_instruction_make_nop(ins); ++ ++instruction_count; ++ continue; ++ } + +- for (k = 0; k < loc->instruction_count; ++k) +- flattener_fixup_registers(normaliser, +- &instructions->elements[loc->index + loc->instruction_count * j + k], j); ++ if (normaliser->phase == VSIR_OP_INVALID) ++ continue; ++ ++ if (!phase_body_it_valid && !vsir_instruction_is_dcl(ins)) ++ { ++ phase_body_it_valid = true; ++ phase_body_it = it; ++ instruction_count = 0; ++ } ++ ++ if (ins->opcode == VSIR_OP_RET) ++ { ++ normaliser->last_ret_location = ins->location; ++ vkd3d_shader_instruction_make_nop(ins); ++ it = phase_body_it; ++ if ((res = flattener_replicate_location(normaliser, &it, ++ instance_count, instruction_count)) < 0) ++ return res; ++ phase_body_it_valid = false; ++ } ++ else ++ { ++ ++instruction_count; + } + } + +@@ -2432,19 +2619,10 @@ static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normali + static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program, + struct vsir_transformation_context *ctx) + { +- struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); +- struct shader_phase_location_array locations; + struct hull_flattener flattener = {program}; + struct vkd3d_shader_instruction *ins; + enum vkd3d_result result = VKD3D_OK; +- unsigned int i; + +- flattener.phase = VSIR_OP_INVALID; +- locations.count = 0; +- for (ins = vsir_program_iterator_head(&it), i = 0; ins; ins = vsir_program_iterator_next(&it), ++i) +- { +- flattener_eliminate_phase_related_dcls(&flattener, i, ins, &locations); +- } + bitmap_clear(program->io_dcls, VKD3DSPR_FORKINSTID); + bitmap_clear(program->io_dcls, VKD3DSPR_JOININSTID); + +@@ -2452,8 +2630,7 @@ static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_pro + if (!(flattener.ssa_map = vkd3d_calloc(flattener.orig_ssa_count, sizeof(*flattener.ssa_map)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + +- result = flattener_flatten_phases(&flattener, &locations); +- ++ result = flattener_flatten_phases(&flattener); + vkd3d_free(flattener.ssa_map); + flattener.ssa_map = NULL; + +@@ -2519,8 +2696,8 @@ static void shader_dst_param_normalise_outpointid(struct vkd3d_shader_dst_param + } + + static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_point_normaliser *normaliser, +- const struct shader_signature *s, unsigned int input_control_point_count, unsigned int dst, +- const struct vkd3d_shader_location *location) ++ const struct shader_signature *s, unsigned int input_control_point_count, ++ struct vsir_program_iterator *dst_it, const struct vkd3d_shader_location *location) + { + struct vkd3d_shader_instruction *ins; + const struct signature_element *e; +@@ -2529,17 +2706,11 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p + for (i = 0; i < s->element_count; ++i) + count += !!s->elements[i].used_mask; + +- if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + count)) ++ if (!(ins = vsir_program_iterator_insert_before_and_move(dst_it, count))) + return VKD3D_ERROR_OUT_OF_MEMORY; +- +- memmove(&normaliser->instructions.elements[dst + count], &normaliser->instructions.elements[dst], +- (normaliser->instructions.count - dst) * sizeof(*normaliser->instructions.elements)); +- normaliser->instructions.count += count; +- +- ins = &normaliser->instructions.elements[dst]; + vsir_instruction_init(ins, location, VSIR_OP_HS_CONTROL_POINT_PHASE); + +- ++ins; ++ ins = vsir_program_iterator_next(dst_it); + + for (i = 0; i < s->element_count; ++i) + { +@@ -2571,7 +2742,7 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p + ins->src[0].reg.idx[0].rel_addr = normaliser->outpointid_param; + ins->src[0].reg.idx[1].offset = e->register_index; + +- ++ins; ++ ins = vsir_program_iterator_next(dst_it); + } + + vsir_instruction_init(ins, location, VSIR_OP_RET); +@@ -2643,8 +2814,8 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i + case VSIR_OP_HS_JOIN_PHASE: + /* ins may be relocated if the instruction array expands. */ + location = ins->location; +- ret = control_point_normaliser_emit_hs_input(&normaliser, &program->input_signature, +- input_control_point_count, i, &location); ++ ret = control_point_normaliser_emit_hs_input(&normaliser, ++ &program->input_signature, input_control_point_count, &it, &location); + program->instructions = normaliser.instructions; + program->normalisation_level = VSIR_NORMALISED_HULL_CONTROL_POINT_IO; + return ret; +@@ -4839,8 +5010,8 @@ struct vsir_cfg + { + struct vkd3d_shader_message_context *message_context; + struct vsir_program *program; +- size_t function_begin; +- size_t function_end; ++ struct vsir_program_iterator function_begin; ++ struct vsir_program_iterator function_end; + struct vsir_block *blocks; + struct vsir_block *entry; + size_t block_count; +@@ -5085,10 +5256,11 @@ static void vsir_cfg_dump_structured_program(struct vsir_cfg *cfg) + } + + static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context, struct vsir_cfg_emit_target *target, +- size_t *pos) ++ struct vkd3d_shader_message_context *message_context, ++ struct vsir_cfg_emit_target *target, struct vsir_program_iterator *it) + { + struct vsir_block *current_block = NULL; ++ struct vkd3d_shader_instruction *ins; + enum vkd3d_result ret; + size_t i; + +@@ -5097,7 +5269,7 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program + cfg->program = program; + cfg->block_count = program->block_count; + cfg->target = target; +- cfg->function_begin = *pos; ++ cfg->function_begin = *it; + + vsir_block_list_init(&cfg->order); + +@@ -5107,12 +5279,11 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program + if (TRACE_ON()) + vkd3d_string_buffer_init(&cfg->debug_buffer); + +- for (i = *pos; i < program->instructions.count; ++i) ++ for (ins = vsir_program_iterator_current(it); ins; ins = vsir_program_iterator_next(it)) + { +- struct vkd3d_shader_instruction *instruction = &program->instructions.elements[i]; + bool finish = false; + +- switch (instruction->opcode) ++ switch (ins->opcode) + { + case VSIR_OP_PHI: + case VSIR_OP_SWITCH_MONOLITHIC: +@@ -5120,7 +5291,7 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program + + case VSIR_OP_LABEL: + { +- unsigned int label = label_from_src_param(&instruction->src[0]); ++ unsigned int label = label_from_src_param(&ins->src[0]); + + VKD3D_ASSERT(!current_block); + VKD3D_ASSERT(label > 0); +@@ -5129,7 +5300,8 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program + VKD3D_ASSERT(current_block->label == 0); + if ((ret = vsir_block_init(current_block, label, program->block_count)) < 0) + goto fail; +- current_block->begin = &program->instructions.elements[i + 1]; ++ current_block->begin = vsir_program_iterator_next(it); ++ vsir_program_iterator_prev(it); + if (!cfg->entry) + cfg->entry = current_block; + break; +@@ -5138,7 +5310,7 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program + case VSIR_OP_BRANCH: + case VSIR_OP_RET: + VKD3D_ASSERT(current_block); +- current_block->end = instruction; ++ current_block->end = ins; + current_block = NULL; + break; + +@@ -5157,8 +5329,7 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program + break; + } + +- *pos = i; +- cfg->function_end = *pos; ++ cfg->function_end = *it; + + for (i = 0; i < cfg->block_count; ++i) + { +@@ -6655,13 +6826,13 @@ static enum vkd3d_result vsir_cfg_emit_structured_program(struct vsir_cfg *cfg) + } + + static enum vkd3d_result vsir_program_structurize_function(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context, struct vsir_cfg_emit_target *target, +- size_t *pos) ++ struct vkd3d_shader_message_context *message_context, ++ struct vsir_cfg_emit_target *target, struct vsir_program_iterator *it) + { + enum vkd3d_result ret; + struct vsir_cfg cfg; + +- if ((ret = vsir_cfg_init(&cfg, program, message_context, target, pos)) < 0) ++ if ((ret = vsir_cfg_init(&cfg, program, message_context, target, it)) < 0) + return ret; + + vsir_cfg_compute_dominators(&cfg); +@@ -6692,10 +6863,11 @@ out: + static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, + struct vsir_transformation_context *ctx) + { ++ struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); + struct vkd3d_shader_message_context *message_context = ctx->message_context; + struct vsir_cfg_emit_target target = {0}; ++ struct vkd3d_shader_instruction *ins; + enum vkd3d_result ret; +- size_t i; + + VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); + +@@ -6705,19 +6877,17 @@ static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, + if (!reserve_instructions(&target.instructions, &target.ins_capacity, program->instructions.count)) + return VKD3D_ERROR_OUT_OF_MEMORY; + +- for (i = 0; i < program->instructions.count;) ++ for (ins = vsir_program_iterator_head(&it); ins;) + { +- struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; +- + switch (ins->opcode) + { + case VSIR_OP_LABEL: + VKD3D_ASSERT(program->shader_version.type != VKD3D_SHADER_TYPE_HULL); + TRACE("Structurizing a non-hull shader.\n"); +- if ((ret = vsir_program_structurize_function(program, message_context, +- &target, &i)) < 0) ++ if ((ret = vsir_program_structurize_function(program, message_context, &target, &it)) < 0) + goto fail; +- VKD3D_ASSERT(i == program->instructions.count); ++ ins = vsir_program_iterator_current(&it); ++ VKD3D_ASSERT(!ins); + break; + + case VSIR_OP_HS_CONTROL_POINT_PHASE: +@@ -6726,17 +6896,17 @@ static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, + VKD3D_ASSERT(program->shader_version.type == VKD3D_SHADER_TYPE_HULL); + TRACE("Structurizing phase %u of a hull shader.\n", ins->opcode); + target.instructions[target.ins_count++] = *ins; +- ++i; +- if ((ret = vsir_program_structurize_function(program, message_context, +- &target, &i)) < 0) ++ vsir_program_iterator_next(&it); ++ if ((ret = vsir_program_structurize_function(program, message_context, &target, &it)) < 0) + goto fail; ++ ins = vsir_program_iterator_current(&it); + break; + + default: + if (!reserve_instructions(&target.instructions, &target.ins_capacity, target.ins_count + 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + target.instructions[target.ins_count++] = *ins; +- ++i; ++ ins = vsir_program_iterator_next(&it); + break; + } + } +@@ -6781,8 +6951,10 @@ static void register_map_undominated_use(struct vkd3d_shader_register *reg, stru + static enum vkd3d_result vsir_cfg_materialize_undominated_ssas_to_temps(struct vsir_cfg *cfg) + { + struct vsir_program *program = cfg->program; ++ struct vkd3d_shader_instruction *ins, *end; + struct ssas_to_temps_alloc alloc = {0}; + struct vsir_block **origin_blocks; ++ struct vsir_program_iterator it; + unsigned int j; + size_t i; + +@@ -6800,7 +6972,6 @@ static enum vkd3d_result vsir_cfg_materialize_undominated_ssas_to_temps(struct v + for (i = 0; i < cfg->block_count; ++i) + { + struct vsir_block *block = &cfg->blocks[i]; +- struct vkd3d_shader_instruction *ins; + + if (block->label == 0) + continue; +@@ -6818,7 +6989,6 @@ static enum vkd3d_result vsir_cfg_materialize_undominated_ssas_to_temps(struct v + for (i = 0; i < cfg->block_count; ++i) + { + struct vsir_block *block = &cfg->blocks[i]; +- struct vkd3d_shader_instruction *ins; + + if (block->label == 0) + continue; +@@ -6835,10 +7005,10 @@ static enum vkd3d_result vsir_cfg_materialize_undominated_ssas_to_temps(struct v + + TRACE("Emitting temps for %u values with undominated usage.\n", alloc.next_temp_idx - program->temp_count); + +- for (i = cfg->function_begin; i < cfg->function_end; ++i) ++ it = cfg->function_begin; ++ end = vsir_program_iterator_current(&cfg->function_end); ++ for (ins = vsir_program_iterator_current(&it); ins != end; ins = vsir_program_iterator_next(&it)) + { +- struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; +- + for (j = 0; j < ins->dst_count; ++j) + materialize_ssas_to_temps_process_reg(program, &alloc, &ins->dst[j].reg); + +@@ -6854,14 +7024,13 @@ done: + return VKD3D_OK; + } + +-static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps_in_function( +- struct vsir_program *program, struct vkd3d_shader_message_context *message_context, +- size_t *pos) ++static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps_in_function(struct vsir_program *program, ++ struct vkd3d_shader_message_context *message_context, struct vsir_program_iterator *it) + { + enum vkd3d_result ret; + struct vsir_cfg cfg; + +- if ((ret = vsir_cfg_init(&cfg, program, message_context, NULL, pos)) < 0) ++ if ((ret = vsir_cfg_init(&cfg, program, message_context, NULL, it)) < 0) + return ret; + + vsir_cfg_compute_dominators(&cfg); +@@ -6876,25 +7045,25 @@ static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps_in_f + static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps(struct vsir_program *program, + struct vsir_transformation_context *ctx) + { ++ struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); + struct vkd3d_shader_message_context *message_context = ctx->message_context; ++ struct vkd3d_shader_instruction *ins; + enum vkd3d_result ret; +- size_t i; + + VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); + +- for (i = 0; i < program->instructions.count;) ++ for (ins = vsir_program_iterator_head(&it); ins;) + { +- struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; +- + switch (ins->opcode) + { + case VSIR_OP_LABEL: + VKD3D_ASSERT(program->shader_version.type != VKD3D_SHADER_TYPE_HULL); + TRACE("Materializing undominated SSAs in a non-hull shader.\n"); + if ((ret = vsir_program_materialize_undominated_ssas_to_temps_in_function( +- program, message_context, &i)) < 0) ++ program, message_context, &it)) < 0) + return ret; +- VKD3D_ASSERT(i == program->instructions.count); ++ ins = vsir_program_iterator_current(&it); ++ VKD3D_ASSERT(!ins); + break; + + case VSIR_OP_HS_CONTROL_POINT_PHASE: +@@ -6902,14 +7071,15 @@ static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps(stru + case VSIR_OP_HS_JOIN_PHASE: + VKD3D_ASSERT(program->shader_version.type == VKD3D_SHADER_TYPE_HULL); + TRACE("Materializing undominated SSAs in phase %u of a hull shader.\n", ins->opcode); +- ++i; ++ vsir_program_iterator_next(&it); + if ((ret = vsir_program_materialize_undominated_ssas_to_temps_in_function( +- program, message_context, &i)) < 0) ++ program, message_context, &it)) < 0) + return ret; ++ ins = vsir_program_iterator_current(&it); + break; + + default: +- ++i; ++ ins = vsir_program_iterator_next(&it); + break; + } + } +@@ -9057,7 +9227,7 @@ struct validation_context + struct vkd3d_shader_message_context *message_context; + const struct vsir_program *program; + size_t instruction_idx; +- struct vkd3d_shader_location null_location; ++ struct vkd3d_shader_location location; + bool invalid_instruction_idx; + enum vkd3d_result status; + bool dcl_temps_found; +@@ -9116,13 +9286,12 @@ static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *c + + if (ctx->invalid_instruction_idx) + { +- vkd3d_shader_error(ctx->message_context, &ctx->null_location, error, "%s", buf.buffer); ++ vkd3d_shader_error(ctx->message_context, &ctx->location, error, "%s", buf.buffer); + WARN("VSIR validation error: %s\n", buf.buffer); + } + else + { +- const struct vkd3d_shader_instruction *ins = &ctx->program->instructions.elements[ctx->instruction_idx]; +- vkd3d_shader_error(ctx->message_context, &ins->location, error, ++ vkd3d_shader_error(ctx->message_context, &ctx->location, error, + "instruction %zu: %s", ctx->instruction_idx + 1, buf.buffer); + WARN("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer); + } +@@ -10995,19 +11164,21 @@ static void vsir_validate_cast_operation(struct validation_context *ctx, + + if (!src_types[src_data_type]) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid source data type %#x for cast operation \"%s\" (%#x).", +- src_data_type, vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); ++ "Invalid source data type \"%s\" (%#x) for cast operation \"%s\" (%#x).", ++ vsir_data_type_get_name(src_data_type, ""), src_data_type, ++ vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + + if (!dst_types[dst_data_type]) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid destination data type %#x for cast operation \"%s\" (%#x).", +- dst_data_type, vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); ++ "Invalid destination data type \"%s\" (%#x) for cast operation \"%s\" (%#x).", ++ vsir_data_type_get_name(dst_data_type, ""), dst_data_type, ++ vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + } + + static void vsir_validate_shift_operation(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) + { +- enum vsir_data_type data_type; ++ enum vsir_data_type dst_data_type, src_data_type; + + static const bool types[] = + { +@@ -11016,24 +11187,27 @@ static void vsir_validate_shift_operation(struct validation_context *ctx, + [VSIR_DATA_U64] = true, + }; + +- data_type = instruction->dst[0].reg.data_type; +- if ((size_t)data_type >= ARRAY_SIZE(types) || !types[data_type]) ++ dst_data_type = instruction->dst[0].reg.data_type; ++ if ((size_t)dst_data_type >= ARRAY_SIZE(types) || !types[dst_data_type]) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid destination data type %#x for shift operation \"%s\" (%#x).", +- data_type, vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); ++ "Invalid destination data type \"%s\" (%#x) for shift operation \"%s\" (%#x).", ++ vsir_data_type_get_name(dst_data_type, ""), dst_data_type, ++ vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + +- if (instruction->src[0].reg.data_type != data_type) ++ if ((src_data_type = instruction->src[0].reg.data_type) != dst_data_type) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Data type %#x for source operand 0 doesn't match destination data type %#x " ++ "Data type \"%s\" (%#x) for source operand 0 doesn't match destination data type \"%s\" (%#x) " + "for shift operation \"%s\" (%#x).", +- instruction->src[0].reg.data_type, data_type, ++ vsir_data_type_get_name(src_data_type, ""), src_data_type, ++ vsir_data_type_get_name(dst_data_type, ""), dst_data_type, + vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + +- data_type = instruction->src[1].reg.data_type; +- if ((size_t)data_type >= ARRAY_SIZE(types) || !types[data_type]) ++ src_data_type = instruction->src[1].reg.data_type; ++ if ((size_t)src_data_type >= ARRAY_SIZE(types) || !types[src_data_type]) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid source operand 1 data type %#x for shift operation \"%s\" (%#x).", +- data_type, vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); ++ "Invalid source operand 1 data type \"%s\" (%#x) for shift operation \"%s\" (%#x).", ++ vsir_data_type_get_name(src_data_type, ""), src_data_type, ++ vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode); + } + + static void vsir_validate_branch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) +@@ -11728,7 +11902,8 @@ static void vsir_validate_throw_invalid_dst_type_error_with_flags(struct validat + enum vsir_data_type dst_data_type = instruction->dst[0].reg.data_type; + + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid destination data type %#x for operation \"%s\" (%#x) with flags %#x.", dst_data_type, ++ "Invalid destination data type \"%s\" (%#x) for operation \"%s\" (%#x) with flags %#x.", ++ vsir_data_type_get_name(dst_data_type, ""), dst_data_type, + vsir_opcode_get_name(instruction->opcode, ""), instruction->opcode, instruction->flags); + } + +@@ -12029,7 +12204,7 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c + { + .message_context = message_context, + .program = program, +- .null_location = {.source_name = source_name}, ++ .location = {.source_name = source_name}, + .status = VKD3D_OK, + .phase = VSIR_OP_INVALID, + .invalid_instruction_idx = true, +@@ -12154,11 +12329,13 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c + for (ins = vsir_program_iterator_head(&it); ins && ctx.status != VKD3D_ERROR_OUT_OF_MEMORY; + ins = vsir_program_iterator_next(&it)) + { ++ ctx.location = ins->location; + vsir_validate_instruction(&ctx, ins); + ++ctx.instruction_idx; + } + + ctx.invalid_instruction_idx = true; ++ ctx.location = (struct vkd3d_shader_location){.source_name = source_name}; + + if (ctx.depth != 0) + validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "%zu nested blocks were not closed.", ctx.depth); +diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c +index d9e22abdfc3..9150e77e2c6 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/msl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/msl.c +@@ -943,8 +943,8 @@ static void msl_print_texel_offset(struct vkd3d_string_buffer *buffer, struct ms + + static void msl_ld(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) + { ++ unsigned int resource_id, resource_idx, resource_space, sample_count; + const struct msl_resource_type_info *resource_type_info; +- unsigned int resource_id, resource_idx, resource_space; + const struct vkd3d_shader_descriptor_info1 *descriptor; + const struct vkd3d_shader_descriptor_binding *binding; + enum vkd3d_shader_resource_type resource_type; +@@ -969,6 +969,7 @@ static void msl_ld(struct msl_generator *gen, const struct vkd3d_shader_instruct + { + resource_type = descriptor->resource_type; + resource_space = descriptor->register_space; ++ sample_count = descriptor->sample_count; + data_type = descriptor->resource_data_type; + } + else +@@ -977,6 +978,7 @@ static void msl_ld(struct msl_generator *gen, const struct vkd3d_shader_instruct + "Internal compiler error: Undeclared resource descriptor %u.", resource_id); + resource_space = 0; + resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; ++ sample_count = 1; + data_type = VSIR_DATA_F32; + } + +@@ -988,6 +990,16 @@ static void msl_ld(struct msl_generator *gen, const struct vkd3d_shader_instruct + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED, + "Texel fetches from resource type %#x are not supported.", resource_type); + ++ if (sample_count == 1) ++ { ++ /* Similar to the SPIR-V and GLSL targets, we map multi-sample ++ * textures with sample count 1 to their single-sample equivalents. */ ++ if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS) ++ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; ++ else if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY) ++ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY; ++ } ++ + if (!(resource_type_info = msl_get_resource_type_info(resource_type))) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, +@@ -1030,6 +1042,10 @@ static void msl_ld(struct msl_generator *gen, const struct vkd3d_shader_instruct + vkd3d_string_buffer_printf(read, ", "); + if (ins->opcode != VSIR_OP_LD2DMS) + msl_print_src_with_type(read, gen, &ins->src[0], VKD3DSP_WRITEMASK_3, VSIR_DATA_U32); ++ else if (sample_count == 1) ++ /* If the resource isn't a true multisample resource, this is the ++ * "lod" parameter instead of the "sample" parameter. */ ++ vkd3d_string_buffer_printf(read, "0"); + else + msl_print_src_with_type(read, gen, &ins->src[2], VKD3DSP_WRITEMASK_0, VSIR_DATA_U32); + } +@@ -1294,6 +1310,11 @@ static void msl_store_uav_typed(struct msl_generator *gen, const struct vkd3d_sh + data_type = VSIR_DATA_F32; + } + ++ if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS ++ || resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED, ++ "Storing to resource type %#x is not supported.", resource_type); ++ + if (!(resource_type_info = msl_get_resource_type_info(resource_type))) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 9cd9aafb587..756aab995a3 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -2553,8 +2553,9 @@ static uint32_t spirv_get_type_id_for_component_type(struct vkd3d_spirv_builder + case VKD3D_SHADER_COMPONENT_DOUBLE: + type_id = vkd3d_spirv_get_op_type_float(builder, 64); + break; ++ case VKD3D_SHADER_COMPONENT_INT64: + case VKD3D_SHADER_COMPONENT_UINT64: +- type_id = vkd3d_spirv_get_op_type_int(builder, 64, 0); ++ type_id = vkd3d_spirv_get_op_type_int(builder, 64, component_type == VKD3D_SHADER_COMPONENT_INT64); + break; + default: + FIXME("Unhandled component type %#x.\n", component_type); +@@ -3700,7 +3701,8 @@ static uint32_t spirv_compiler_get_constant64(struct spirv_compiler *compiler, + VKD3D_ASSERT(0 < component_count && component_count <= VKD3D_DVEC2_SIZE); + type_id = spirv_get_type_id_for_component_type(builder, component_type, component_count); + +- if (component_type != VKD3D_SHADER_COMPONENT_DOUBLE && component_type != VKD3D_SHADER_COMPONENT_UINT64) ++ if (component_type != VKD3D_SHADER_COMPONENT_DOUBLE && component_type != VKD3D_SHADER_COMPONENT_INT64 ++ && component_type != VKD3D_SHADER_COMPONENT_UINT64) + { + FIXME("Unhandled component_type %#x.\n", component_type); + return vkd3d_spirv_get_op_undef(builder, type_id); +@@ -4497,7 +4499,7 @@ static uint32_t spirv_compiler_emit_int_to_bool(struct spirv_compiler *compiler, + op = condition & VKD3D_SHADER_CONDITIONAL_OP_Z ? SpvOpIEqual : SpvOpINotEqual; + + return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, type_id, val_id, +- data_type == VSIR_DATA_U64 ++ data_type_is_64_bit(data_type) + ? spirv_compiler_get_constant_uint64_vector(compiler, 0, component_count) + : spirv_compiler_get_constant_uint_vector(compiler, 0, component_count)); + } +@@ -4537,7 +4539,8 @@ static uint32_t spirv_compiler_emit_bool_to_float(struct spirv_compiler *compile + + true_id = spirv_compiler_get_constant_float_vector(compiler, signedness ? -1.0f : 1.0f, component_count); + false_id = spirv_compiler_get_constant_float_vector(compiler, 0.0f, component_count); +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_F32, component_count); ++ + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); + } + +@@ -4549,7 +4552,8 @@ static uint32_t spirv_compiler_emit_bool_to_double(struct spirv_compiler *compil + + true_id = spirv_compiler_get_constant_double_vector(compiler, signedness ? -1.0 : 1.0, component_count); + false_id = spirv_compiler_get_constant_double_vector(compiler, 0.0, component_count); +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_DOUBLE, component_count); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_F64, component_count); ++ + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); + } + +@@ -4725,6 +4729,7 @@ static uint32_t spirv_compiler_emit_constant_array(struct spirv_compiler *compil + &icb->data[component_count * i]); + break; + case VSIR_DATA_F64: ++ case VSIR_DATA_I64: + case VSIR_DATA_U64: + { + uint64_t *data = (uint64_t *)icb->data; +@@ -5284,9 +5289,8 @@ static uint32_t spirv_compiler_emit_draw_parameter_fixup(struct spirv_compiler * + vkd3d_spirv_add_iface_variable(builder, base_var_id); + spirv_compiler_decorate_builtin(compiler, base_var_id, base); + +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_INT, 1); +- base_id = vkd3d_spirv_build_op_load(builder, +- type_id, base_var_id, SpvMemoryAccessMaskNone); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_I32, 1); ++ base_id = vkd3d_spirv_build_op_load(builder, type_id, base_var_id, SpvMemoryAccessMaskNone); + + return vkd3d_spirv_build_op_isub(builder, type_id, index_id, base_id); + } +@@ -5314,17 +5318,16 @@ static uint32_t sv_front_face_fixup(struct spirv_compiler *compiler, + } + + /* frag_coord.w = 1.0f / frag_coord.w */ +-static uint32_t frag_coord_fixup(struct spirv_compiler *compiler, +- uint32_t frag_coord_id) ++static uint32_t frag_coord_fixup(struct spirv_compiler *compiler, uint32_t frag_coord_id) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, w_id; + +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_FLOAT, 1); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_F32, 1); + w_id = vkd3d_spirv_build_op_composite_extract1(builder, type_id, frag_coord_id, 3); +- w_id = vkd3d_spirv_build_op_fdiv(builder, type_id, +- spirv_compiler_get_constant_float(compiler, 1.0f), w_id); +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE); ++ w_id = vkd3d_spirv_build_op_fdiv(builder, type_id, spirv_compiler_get_constant_float(compiler, 1.0f), w_id); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_F32, VKD3D_VEC4_SIZE); ++ + return vkd3d_spirv_build_op_composite_insert1(builder, type_id, w_id, frag_coord_id, 3); + } + +@@ -5530,7 +5533,8 @@ static uint32_t spirv_compiler_emit_load_invocation_id(struct spirv_compiler *co + uint32_t type_id, id; + + id = spirv_compiler_get_invocation_id(compiler); +- type_id = spirv_get_type_id_for_component_type(builder, VKD3D_SHADER_COMPONENT_INT, 1); ++ type_id = spirv_get_type_id(builder, VSIR_DATA_I32, 1); ++ + return vkd3d_spirv_build_op_load(builder, type_id, id, SpvMemoryAccessMaskNone); + } + +@@ -7628,11 +7632,12 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, + /* ITOD is not supported. Frontends which emit bool casts must use ITOF for double. */ + val_id = spirv_compiler_emit_bool_to_double(compiler, 1, val_id, instruction->opcode == VSIR_OP_ITOF); + } +- else if (dst->reg.data_type == VSIR_DATA_U16 || dst->reg.data_type == VSIR_DATA_U32) ++ else if (dst->reg.data_type == VSIR_DATA_I16 || dst->reg.data_type == VSIR_DATA_I32 ++ || dst->reg.data_type == VSIR_DATA_U16 || dst->reg.data_type == VSIR_DATA_U32) + { + val_id = spirv_compiler_emit_bool_to_int(compiler, 1, val_id, instruction->opcode == VSIR_OP_ITOI); + } +- else if (dst->reg.data_type == VSIR_DATA_U64) ++ else if (dst->reg.data_type == VSIR_DATA_I64 || dst->reg.data_type == VSIR_DATA_U64) + { + val_id = spirv_compiler_emit_bool_to_int64(compiler, 1, val_id, instruction->opcode == VSIR_OP_ITOI); + } +@@ -7728,7 +7733,7 @@ static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compil + condition_id = spirv_compiler_emit_int_to_bool(compiler, + VKD3D_SHADER_CONDITIONAL_OP_NZ, src[1].reg.data_type, component_count, src_ids[1]); + +- if (dst[0].reg.data_type == VSIR_DATA_U64) ++ if (data_type_is_64_bit(dst[0].reg.data_type)) + uint_max_id = spirv_compiler_get_constant_uint64_vector(compiler, UINT64_MAX, component_count); + else + uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, UINT_MAX, component_count); +@@ -7843,7 +7848,7 @@ static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *comp + unsigned int i, component_count; + enum GLSLstd450 glsl_inst; + +- if (src[0].reg.data_type == VSIR_DATA_U64 && (instruction->opcode == VSIR_OP_FIRSTBIT_HI ++ if (data_type_is_64_bit(src[0].reg.data_type) && (instruction->opcode == VSIR_OP_FIRSTBIT_HI + || instruction->opcode == VSIR_OP_FIRSTBIT_LO || instruction->opcode == VSIR_OP_FIRSTBIT_SHI)) + { + /* At least some drivers support this anyway, but if validation is enabled it will fail. */ +@@ -8254,7 +8259,7 @@ static void spirv_compiler_emit_bitfield_instruction(struct spirv_compiler *comp + + component_type = vkd3d_component_type_from_data_type(dst->reg.data_type); + type_id = spirv_get_type_id_for_component_type(builder, component_type, 1); +- size = (src[src_count - 1].reg.data_type == VSIR_DATA_U64) ? 0x40 : 0x20; ++ size = data_type_is_64_bit(src[src_count - 1].reg.data_type) ? 0x40 : 0x20; + mask_id = spirv_compiler_get_constant_uint(compiler, size - 1); + size_id = spirv_compiler_get_constant_uint(compiler, size); + +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +index 08450b4cf85..6949c1cd38f 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +@@ -2297,204 +2297,6 @@ void vkd3d_shader_set_log_callback(PFN_vkd3d_log callback) + vkd3d_dbg_set_log_callback(callback); + } + +-static struct vkd3d_shader_param_node *shader_param_allocator_node_create( +- struct vkd3d_shader_param_allocator *allocator) +-{ +- struct vkd3d_shader_param_node *node; +- +- if (!(node = vkd3d_malloc(offsetof(struct vkd3d_shader_param_node, param[allocator->count * allocator->stride])))) +- return NULL; +- node->next = NULL; +- return node; +-} +- +-static void shader_param_allocator_init(struct vkd3d_shader_param_allocator *allocator, +- size_t count, size_t stride) +-{ +- allocator->count = max(count, MAX_REG_OUTPUT); +- allocator->stride = stride; +- allocator->head = NULL; +- allocator->current = NULL; +- allocator->index = allocator->count; +-} +- +-static void shader_param_allocator_destroy(struct vkd3d_shader_param_allocator *allocator) +-{ +- struct vkd3d_shader_param_node *current = allocator->head; +- +- while (current) +- { +- struct vkd3d_shader_param_node *next = current->next; +- vkd3d_free(current); +- current = next; +- } +-} +- +-void *shader_param_allocator_get(struct vkd3d_shader_param_allocator *allocator, size_t count) +-{ +- void *params; +- +- if (!allocator->current || count > allocator->count - allocator->index) +- { +- struct vkd3d_shader_param_node *next; +- +- /* Monolithic switch has no definite parameter count limit. */ +- allocator->count = max(allocator->count, count); +- +- if (!(next = shader_param_allocator_node_create(allocator))) +- return NULL; +- if (allocator->current) +- allocator->current->next = next; +- else +- allocator->head = next; +- allocator->current = next; +- allocator->index = 0; +- } +- +- params = &allocator->current->param[allocator->index * allocator->stride]; +- allocator->index += count; +- return params; +-} +- +-bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, size_t reserve) +-{ +- memset(instructions, 0, sizeof(*instructions)); +- /* Size the parameter initial allocations so they are large enough for most shaders. The +- * code path for chained allocations will be tested if a few shaders need to use it. */ +- shader_param_allocator_init(&instructions->dst_params, reserve - reserve / 8u, +- sizeof(struct vkd3d_shader_dst_param)); +- shader_param_allocator_init(&instructions->src_params, reserve * 2u, sizeof(struct vkd3d_shader_src_param)); +- return shader_instruction_array_reserve(instructions, reserve); +-} +- +-bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, size_t reserve) +-{ +- if (!vkd3d_array_reserve((void **)&instructions->elements, &instructions->capacity, reserve, +- sizeof(*instructions->elements))) +- { +- ERR("Failed to allocate instructions.\n"); +- return false; +- } +- return true; +-} +- +-bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *instructions, +- size_t idx, size_t count) +-{ +- VKD3D_ASSERT(idx <= instructions->count); +- +- if (!shader_instruction_array_reserve(instructions, instructions->count + count)) +- return false; +- +- memmove(&instructions->elements[idx + count], &instructions->elements[idx], +- (instructions->count - idx) * sizeof(*instructions->elements)); +- memset(&instructions->elements[idx], 0, count * sizeof(*instructions->elements)); +- +- instructions->count += count; +- +- return true; +-} +- +-bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, +- struct vkd3d_shader_immediate_constant_buffer *icb) +-{ +- if (!vkd3d_array_reserve((void **)&instructions->icbs, &instructions->icb_capacity, instructions->icb_count + 1, +- sizeof(*instructions->icbs))) +- return false; +- instructions->icbs[instructions->icb_count++] = icb; +- return true; +-} +- +-static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params( +- struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_src_param *params, +- size_t count); +- +-static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, +- struct vkd3d_shader_instruction_array *instructions) +-{ +- unsigned int i; +- +- for (i = 0; i < reg->idx_count; ++i) +- { +- if (!reg->idx[i].rel_addr) +- continue; +- +- if (!(reg->idx[i].rel_addr = shader_instruction_array_clone_src_params(instructions, reg->idx[i].rel_addr, 1))) +- return false; +- } +- +- return true; +-} +- +-static struct vkd3d_shader_dst_param *shader_instruction_array_clone_dst_params( +- struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_dst_param *params, +- size_t count) +-{ +- struct vkd3d_shader_dst_param *dst_params; +- size_t i; +- +- if (!(dst_params = shader_dst_param_allocator_get(&instructions->dst_params, count))) +- return NULL; +- +- memcpy(dst_params, params, count * sizeof(*params)); +- for (i = 0; i < count; ++i) +- { +- if (!shader_register_clone_relative_addresses(&dst_params[i].reg, instructions)) +- return NULL; +- } +- +- return dst_params; +-} +- +-static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params( +- struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_src_param *params, +- size_t count) +-{ +- struct vkd3d_shader_src_param *src_params; +- size_t i; +- +- if (!(src_params = shader_src_param_allocator_get(&instructions->src_params, count))) +- return NULL; +- +- memcpy(src_params, params, count * sizeof(*params)); +- for (i = 0; i < count; ++i) +- { +- if (!shader_register_clone_relative_addresses(&src_params[i].reg, instructions)) +- return NULL; +- } +- +- return src_params; +-} +- +-/* NOTE: Immediate constant buffers are not cloned, so the source must not be destroyed while the +- * destination is in use. This seems like a reasonable requirement given how this is currently used. */ +-bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, +- size_t dst, size_t src) +-{ +- struct vkd3d_shader_instruction *ins = &instructions->elements[dst]; +- +- *ins = instructions->elements[src]; +- +- if (ins->dst_count && ins->dst && !(ins->dst = shader_instruction_array_clone_dst_params(instructions, +- ins->dst, ins->dst_count))) +- return false; +- +- return !ins->src_count || !!(ins->src = shader_instruction_array_clone_src_params(instructions, +- ins->src, ins->src_count)); +-} +- +-void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions) +-{ +- unsigned int i; +- +- vkd3d_free(instructions->elements); +- shader_param_allocator_destroy(&instructions->dst_params); +- shader_param_allocator_destroy(&instructions->src_params); +- for (i = 0; i < instructions->icb_count; ++i) +- vkd3d_free(instructions->icbs[i]); +- vkd3d_free(instructions->icbs); +-} +- + void vkd3d_shader_build_varying_map(const struct vkd3d_shader_signature *output_signature, + const struct vkd3d_shader_signature *input_signature, + unsigned int *ret_count, struct vkd3d_shader_varying_map *varyings) +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index ae88d97f461..c00a7825610 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -716,7 +716,9 @@ enum vsir_data_type + VSIR_DATA_F32, + VSIR_DATA_F64, + ++ VSIR_DATA_I16, + VSIR_DATA_I32, ++ VSIR_DATA_I64, + + VSIR_DATA_U8, + VSIR_DATA_U16, +@@ -738,8 +740,9 @@ const char *vsir_data_type_get_name(enum vsir_data_type t, const char *error); + + static inline bool data_type_is_integer(enum vsir_data_type data_type) + { +- return data_type == VSIR_DATA_I32 || data_type == VSIR_DATA_U8 || data_type == VSIR_DATA_U16 +- || data_type == VSIR_DATA_U32 || data_type == VSIR_DATA_U64; ++ return data_type == VSIR_DATA_I16 || data_type == VSIR_DATA_I32 || data_type == VSIR_DATA_I64 ++ || data_type == VSIR_DATA_U8 || data_type == VSIR_DATA_U16 || data_type == VSIR_DATA_U32 ++ || data_type == VSIR_DATA_U64; + } + + static inline bool data_type_is_bool(enum vsir_data_type data_type) +@@ -754,7 +757,7 @@ static inline bool data_type_is_floating_point(enum vsir_data_type data_type) + + static inline bool data_type_is_64_bit(enum vsir_data_type data_type) + { +- return data_type == VSIR_DATA_F64 || data_type == VSIR_DATA_U64; ++ return data_type == VSIR_DATA_F64 || data_type == VSIR_DATA_I64 || data_type == VSIR_DATA_U64; + } + + enum vsir_dimension +@@ -1441,15 +1444,11 @@ struct vkd3d_shader_instruction_array + struct vkd3d_shader_src_param *outpointid_param; + }; + +-bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, size_t reserve); + bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, size_t reserve); + bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *instructions, + size_t idx, size_t count); + bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, + struct vkd3d_shader_immediate_constant_buffer *icb); +-bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, +- size_t dst, size_t src); +-void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions); + + struct vsir_program_iterator + { +@@ -1512,6 +1511,28 @@ static inline bool vsir_program_iterator_insert_after(struct vsir_program_iterat + return shader_instruction_array_insert_at(it->array, it->idx + 1, count); + } + ++/* When insertion takes place, argument `it' is updated to point to the same ++ * instruction as before the insertion, and the optional argument `ins_it' is ++ * initialized to point to the first inserted instruction. ++ * A pointer to the first inserted instruction is returned. */ ++static inline struct vkd3d_shader_instruction *vsir_program_iterator_insert_before( ++ struct vsir_program_iterator *it, struct vsir_program_iterator *ins_it, size_t count) ++{ ++ VKD3D_ASSERT(it != ins_it); ++ VKD3D_ASSERT(it->idx != SIZE_MAX); ++ ++ if (!shader_instruction_array_insert_at(it->array, it->idx, count)) ++ return NULL; ++ ++ *ins_it = *it; ++ it->idx += count; ++ ++ return vsir_program_iterator_current(ins_it); ++} ++ ++/* When insertion takes place, argument `it' is updated to point to the first ++ * inserted instruction. A pointer to this first inserted instruction is ++ * returned. */ + static inline struct vkd3d_shader_instruction *vsir_program_iterator_insert_before_and_move( + struct vsir_program_iterator *it, size_t count) + { +@@ -1871,14 +1892,20 @@ static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_ty + return VKD3D_SHADER_COMPONENT_FLOAT; + case VSIR_DATA_F64: + return VKD3D_SHADER_COMPONENT_DOUBLE; ++ case VSIR_DATA_I16: ++ return VKD3D_SHADER_COMPONENT_INT16; + case VSIR_DATA_I32: + return VKD3D_SHADER_COMPONENT_INT; ++ case VSIR_DATA_I64: ++ return VKD3D_SHADER_COMPONENT_INT64; + case VSIR_DATA_U16: + return VKD3D_SHADER_COMPONENT_UINT16; + case VSIR_DATA_U32: + return VKD3D_SHADER_COMPONENT_UINT; + case VSIR_DATA_U64: + return VKD3D_SHADER_COMPONENT_UINT64; ++ case VSIR_DATA_UNUSED: ++ return VKD3D_SHADER_COMPONENT_VOID; + default: + FIXME("Unhandled data type %#x.\n", data_type); + /* fall-through */ +@@ -1891,23 +1918,41 @@ static inline enum vsir_data_type vsir_data_type_from_component_type(enum vkd3d_ + { + switch (component_type) + { +- case VKD3D_SHADER_COMPONENT_FLOAT: +- return VSIR_DATA_F32; ++ case VKD3D_SHADER_COMPONENT_VOID: ++ return VSIR_DATA_UNUSED; + case VKD3D_SHADER_COMPONENT_UINT: + return VSIR_DATA_U32; + case VKD3D_SHADER_COMPONENT_INT: + return VSIR_DATA_I32; ++ case VKD3D_SHADER_COMPONENT_FLOAT: ++ return VSIR_DATA_F32; ++ case VKD3D_SHADER_COMPONENT_BOOL: ++ return VSIR_DATA_BOOL; + case VKD3D_SHADER_COMPONENT_DOUBLE: + return VSIR_DATA_F64; +- default: +- FIXME("Unhandled component type %#x.\n", component_type); +- return VSIR_DATA_F32; ++ case VKD3D_SHADER_COMPONENT_UINT64: ++ return VSIR_DATA_U64; ++ case VKD3D_SHADER_COMPONENT_INT64: ++ return VSIR_DATA_I64; ++ case VKD3D_SHADER_COMPONENT_FLOAT16: ++ return VSIR_DATA_F16; ++ case VKD3D_SHADER_COMPONENT_UINT16: ++ return VSIR_DATA_U16; ++ case VKD3D_SHADER_COMPONENT_INT16: ++ return VSIR_DATA_I16; ++ case VKD3D_SHADER_COMPONENT_TYPE_FORCE_32BIT: ++ break; + } ++ ++ FIXME("Unhandled component type %#x.\n", component_type); ++ ++ return VSIR_DATA_UNUSED; + } + + static inline bool component_type_is_64_bit(enum vkd3d_shader_component_type component_type) + { +- return component_type == VKD3D_SHADER_COMPONENT_DOUBLE || component_type == VKD3D_SHADER_COMPONENT_UINT64; ++ return component_type == VKD3D_SHADER_COMPONENT_DOUBLE || component_type == VKD3D_SHADER_COMPONENT_INT64 ++ || component_type == VKD3D_SHADER_COMPONENT_UINT64; + } + + static inline unsigned int vsir_write_mask_get_component_idx(uint32_t write_mask) +diff --git a/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c b/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c +index 15c5b77c8df..fea8c2440d1 100644 +--- a/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c ++++ b/libs/vkd3d/libs/vkd3d-utils/vkd3d_utils_main.c +@@ -484,7 +484,10 @@ HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename + + if (!ret) + { +- if (FAILED(hr = vkd3d_blob_create((void *)preprocessed_code.code, preprocessed_code.size, preprocessed_blob))) ++ /* vkd3d-shader output is null-terminated, but the null terminator isn't ++ * included in the size. Increase the size to account for that. */ ++ if (FAILED(hr = vkd3d_blob_create((void *)preprocessed_code.code, ++ preprocessed_code.size + 1, preprocessed_blob))) + { + vkd3d_shader_free_shader_code(&preprocessed_code); + return hr; +@@ -1034,7 +1037,9 @@ HRESULT WINAPI D3DDisassemble(const void *data, SIZE_T data_size, + return hresult_from_vkd3d_result(ret); + } + +- if (FAILED(hr = vkd3d_blob_create((void *)output.code, output.size, blob))) ++ /* vkd3d-shader output is null-terminated, but the null terminator isn't ++ * included in the size. Increase the size to account for that. */ ++ if (FAILED(hr = vkd3d_blob_create((void *)output.code, output.size + 1, blob))) + vkd3d_shader_free_shader_code(&output); + + return hr; +-- +2.51.0 +