From dab36ebe1e6d22d3bc0f23ae9458cd0a2010dd78 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 3 Aug 2023 08:55:55 +1000 Subject: [PATCH] Updated vkd3d-latest patchset --- ...771e442af16228a977eebba82224f06f6d02.patch | 4 +- ...-2a3413e0f01524f2068bce12100906eb220.patch | 3576 ++++++++++-- ...-b4bb3931c5e7e59496c07c2d4e3b6cfd3bf.patch | 5119 +++++++++++++++++ ...-d4d960cb8b4f503ce3de51d9f29267ca938.patch | 28 - ...-3bafd036bb53bf211cb8b05651835aba6fb.patch | 3733 ------------ patches/vkd3d-latest/definition | 2 +- 6 files changed, 8372 insertions(+), 4090 deletions(-) create mode 100644 patches/vkd3d-latest/0003-Updated-vkd3d-to-b4bb3931c5e7e59496c07c2d4e3b6cfd3bf.patch delete mode 100644 patches/vkd3d-latest/0003-Updated-vkd3d-to-d4d960cb8b4f503ce3de51d9f29267ca938.patch delete mode 100644 patches/vkd3d-latest/0004-Updated-vkd3d-to-3bafd036bb53bf211cb8b05651835aba6fb.patch diff --git a/patches/vkd3d-latest/0001-Update-vkd3d-to-771e442af16228a977eebba82224f06f6d02.patch b/patches/vkd3d-latest/0001-Update-vkd3d-to-771e442af16228a977eebba82224f06f6d02.patch index a54d7616..fc2dd35f 100644 --- a/patches/vkd3d-latest/0001-Update-vkd3d-to-771e442af16228a977eebba82224f06f6d02.patch +++ b/patches/vkd3d-latest/0001-Update-vkd3d-to-771e442af16228a977eebba82224f06f6d02.patch @@ -1,7 +1,7 @@ -From 708e3732ca7672cdde41f3662664265de7f4129e Mon Sep 17 00:00:00 2001 +From 226088587d4ba04bd8f9ee05b300ce7d03377187 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 17 May 2023 08:35:40 +1000 -Subject: [PATCH] Update vkd3d to 771e442af16228a977eebba82224f06f6d0202fe +Subject: [PATCH 1/3] Update vkd3d to 771e442af16228a977eebba82224f06f6d0202fe (1.8) --- diff --git a/patches/vkd3d-latest/0002-Updated-vkd3d-to-2a3413e0f01524f2068bce12100906eb220.patch b/patches/vkd3d-latest/0002-Updated-vkd3d-to-2a3413e0f01524f2068bce12100906eb220.patch index 4fed832b..75b39b31 100644 --- a/patches/vkd3d-latest/0002-Updated-vkd3d-to-2a3413e0f01524f2068bce12100906eb220.patch +++ b/patches/vkd3d-latest/0002-Updated-vkd3d-to-2a3413e0f01524f2068bce12100906eb220.patch @@ -1,35 +1,36 @@ -From 420b1f91c16ada4b3e8183cced1d4b60310b85cf Mon Sep 17 00:00:00 2001 +From ef302da9a91d5d7d4456506303ce3f3964f9081f Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 28 Jun 2023 16:27:03 +1000 -Subject: [PATCH] Updated vkd3d to 2a3413e0f01524f2068bce12100906eb2200c965. +Subject: [PATCH 2/3] Updated vkd3d to + 2a3413e0f01524f2068bce12100906eb2200c965. --- include/d3d12.idl | 4 +- libs/vkd3d/Makefile.in | 1 + - libs/vkd3d/include/private/vkd3d_common.h | 2 + + libs/vkd3d/include/private/vkd3d_common.h | 7 + .../include/private/vkd3d_shader_utils.h | 63 + libs/vkd3d/include/vkd3d.h | 35 + libs/vkd3d/include/vkd3d_shader.h | 116 +- libs/vkd3d/libs/vkd3d-common/debug.c | 17 +- libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 48 +- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 311 ++++- + libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 311 ++- libs/vkd3d/libs/vkd3d-shader/dxbc.c | 16 +- - libs/vkd3d/libs/vkd3d-shader/dxil.c | 919 +++++++++++++ - libs/vkd3d/libs/vkd3d-shader/hlsl.c | 59 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.h | 19 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.y | 1196 ++++++++++------- - libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 189 ++- - .../libs/vkd3d-shader/hlsl_constant_ops.c | 363 +++-- - libs/vkd3d/libs/vkd3d-shader/spirv.c | 21 +- - libs/vkd3d/libs/vkd3d-shader/tpf.c | 37 +- - .../libs/vkd3d-shader/vkd3d_shader_main.c | 164 ++- - .../libs/vkd3d-shader/vkd3d_shader_private.h | 20 + - libs/vkd3d/libs/vkd3d/command.c | 222 ++- + libs/vkd3d/libs/vkd3d-shader/dxil.c | 2313 +++++++++++++++++ + libs/vkd3d/libs/vkd3d-shader/hlsl.c | 161 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.h | 32 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 1323 ++++++---- + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 384 ++- + .../libs/vkd3d-shader/hlsl_constant_ops.c | 363 ++- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 26 +- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 372 ++- + .../libs/vkd3d-shader/vkd3d_shader_main.c | 164 +- + .../libs/vkd3d-shader/vkd3d_shader_private.h | 29 + + libs/vkd3d/libs/vkd3d/command.c | 222 +- libs/vkd3d/libs/vkd3d/device.c | 2 + libs/vkd3d/libs/vkd3d/resource.c | 51 +- libs/vkd3d/libs/vkd3d/state.c | 10 +- libs/vkd3d/libs/vkd3d/vkd3d_private.h | 47 +- - 25 files changed, 3143 insertions(+), 789 deletions(-) + 25 files changed, 5088 insertions(+), 1029 deletions(-) create mode 100644 libs/vkd3d/include/private/vkd3d_shader_utils.h create mode 100644 libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -61,7 +62,7 @@ index 1ba0e9f71e1..f647af11d07 100644 libs/vkd3d-shader/hlsl.c \ libs/vkd3d-shader/hlsl.l \ diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h -index 1ac23b4a085..da15ee23fd3 100644 +index 1ac23b4a085..0263fc47297 100644 --- a/libs/vkd3d/include/private/vkd3d_common.h +++ b/libs/vkd3d/include/private/vkd3d_common.h @@ -20,6 +20,7 @@ @@ -80,6 +81,18 @@ index 1ac23b4a085..da15ee23fd3 100644 #ifdef _MSC_VER #include +@@ -171,6 +173,11 @@ static inline bool vkd3d_bound_range(size_t start, size_t count, size_t limit) + #endif + } + ++static inline bool vkd3d_object_range_overflow(size_t start, size_t count, size_t size) ++{ ++ return (~(size_t)0 - start) / size < count; ++} ++ + static inline uint16_t vkd3d_make_u16(uint8_t low, uint8_t high) + { + return low | ((uint16_t)high << 8); diff --git a/libs/vkd3d/include/private/vkd3d_shader_utils.h b/libs/vkd3d/include/private/vkd3d_shader_utils.h new file mode 100644 index 00000000000..00052a89988 @@ -946,10 +959,10 @@ index 3e3f06faeb5..716b7bdb721 100644 ret = VKD3D_ERROR_INVALID_ARGUMENT; diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c new file mode 100644 -index 00000000000..67dcd26a0e0 +index 00000000000..53a4c2da4ba --- /dev/null +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c -@@ -0,0 +1,919 @@ +@@ -0,0 +1,2313 @@ +/* + * Copyright 2023 Conor McCarthy for CodeWeavers + * @@ -1014,6 +1027,159 @@ index 00000000000..67dcd26a0e0 + ABBREV_BLOB = 5, +}; + ++enum bitcode_address_space ++{ ++ ADDRESS_SPACE_DEFAULT, ++ ADDRESS_SPACE_DEVICEMEM, ++ ADDRESS_SPACE_CBUFFER, ++ ADDRESS_SPACE_GROUPSHARED, ++}; ++ ++enum bitcode_module_code ++{ ++ MODULE_CODE_VERSION = 1, ++ MODULE_CODE_GLOBALVAR = 7, ++ MODULE_CODE_FUNCTION = 8, ++}; ++ ++enum bitcode_constant_code ++{ ++ CST_CODE_SETTYPE = 1, ++ CST_CODE_NULL = 2, ++ CST_CODE_UNDEF = 3, ++ CST_CODE_INTEGER = 4, ++ CST_CODE_FLOAT = 6, ++ CST_CODE_STRING = 8, ++ CST_CODE_CE_GEP = 12, ++ CST_CODE_CE_INBOUNDS_GEP = 20, ++ CST_CODE_DATA = 22, ++}; ++ ++enum bitcode_function_code ++{ ++ FUNC_CODE_DECLAREBLOCKS = 1, ++ FUNC_CODE_INST_BINOP = 2, ++ FUNC_CODE_INST_CAST = 3, ++ FUNC_CODE_INST_RET = 10, ++ FUNC_CODE_INST_BR = 11, ++ FUNC_CODE_INST_SWITCH = 12, ++ FUNC_CODE_INST_PHI = 16, ++ FUNC_CODE_INST_ALLOCA = 19, ++ FUNC_CODE_INST_LOAD = 20, ++ FUNC_CODE_INST_EXTRACTVAL = 26, ++ FUNC_CODE_INST_CMP2 = 28, ++ FUNC_CODE_INST_VSELECT = 29, ++ FUNC_CODE_INST_CALL = 34, ++ FUNC_CODE_INST_ATOMICRMW = 38, ++ FUNC_CODE_INST_LOADATOMIC = 41, ++ FUNC_CODE_INST_GEP = 43, ++ FUNC_CODE_INST_STORE = 44, ++ FUNC_CODE_INST_STOREATOMIC = 45, ++ FUNC_CODE_INST_CMPXCHG = 46, ++}; ++ ++enum bitcode_type_code ++{ ++ TYPE_CODE_NUMENTRY = 1, ++ TYPE_CODE_VOID = 2, ++ TYPE_CODE_FLOAT = 3, ++ TYPE_CODE_DOUBLE = 4, ++ TYPE_CODE_LABEL = 5, ++ TYPE_CODE_INTEGER = 7, ++ TYPE_CODE_POINTER = 8, ++ TYPE_CODE_HALF = 10, ++ TYPE_CODE_ARRAY = 11, ++ TYPE_CODE_VECTOR = 12, ++ TYPE_CODE_METADATA = 16, ++ TYPE_CODE_STRUCT_ANON = 18, ++ TYPE_CODE_STRUCT_NAME = 19, ++ TYPE_CODE_STRUCT_NAMED = 20, ++ TYPE_CODE_FUNCTION = 21, ++}; ++ ++enum bitcode_value_symtab_code ++{ ++ VST_CODE_ENTRY = 1, ++ VST_CODE_BBENTRY = 2, ++}; ++ ++struct sm6_pointer_info ++{ ++ const struct sm6_type *type; ++ enum bitcode_address_space addr_space; ++}; ++ ++struct sm6_struct_info ++{ ++ const char *name; ++ unsigned int elem_count; ++ const struct sm6_type *elem_types[]; ++}; ++ ++struct sm6_function_info ++{ ++ const struct sm6_type *ret_type; ++ unsigned int param_count; ++ const struct sm6_type *param_types[]; ++}; ++ ++struct sm6_array_info ++{ ++ unsigned int count; ++ const struct sm6_type *elem_type; ++}; ++ ++enum sm6_type_class ++{ ++ TYPE_CLASS_VOID, ++ TYPE_CLASS_INTEGER, ++ TYPE_CLASS_FLOAT, ++ TYPE_CLASS_POINTER, ++ TYPE_CLASS_STRUCT, ++ TYPE_CLASS_FUNCTION, ++ TYPE_CLASS_VECTOR, ++ TYPE_CLASS_ARRAY, ++ TYPE_CLASS_LABEL, ++ TYPE_CLASS_METADATA, ++}; ++ ++struct sm6_type ++{ ++ enum sm6_type_class class; ++ union ++ { ++ unsigned int width; ++ struct sm6_pointer_info pointer; ++ struct sm6_struct_info *struc; ++ struct sm6_function_info *function; ++ struct sm6_array_info array; ++ } u; ++}; ++ ++enum sm6_value_type ++{ ++ VALUE_TYPE_FUNCTION, ++ VALUE_TYPE_REG, ++}; ++ ++struct sm6_function_data ++{ ++ const char *name; ++ bool is_prototype; ++ unsigned int attribs_id; ++}; ++ ++struct sm6_value ++{ ++ const struct sm6_type *type; ++ enum sm6_value_type value_type; ++ union ++ { ++ struct sm6_function_data function; ++ struct vkd3d_shader_register reg; ++ } u; ++}; ++ +struct dxil_record +{ + unsigned int code; @@ -1021,6 +1187,27 @@ index 00000000000..67dcd26a0e0 + uint64_t operands[]; +}; + ++struct sm6_symbol ++{ ++ unsigned int id; ++ const char *name; ++}; ++ ++struct sm6_block ++{ ++ struct vkd3d_shader_instruction *instructions; ++ size_t instruction_capacity; ++ size_t instruction_count; ++}; ++ ++struct sm6_function ++{ ++ const struct sm6_value *declaration; ++ ++ struct sm6_block *blocks[1]; ++ size_t block_count; ++}; ++ +struct dxil_block +{ + const struct dxil_block *parent; @@ -1058,6 +1245,19 @@ index 00000000000..67dcd26a0e0 + size_t abbrev_capacity; + size_t abbrev_count; + ++ struct sm6_type *types; ++ size_t type_count; ++ ++ struct sm6_symbol *global_symbols; ++ size_t global_symbol_count; ++ ++ struct sm6_function *functions; ++ size_t function_count; ++ ++ struct sm6_value *values; ++ size_t value_count; ++ size_t value_capacity; ++ + struct vkd3d_shader_parser p; +}; + @@ -1080,6 +1280,12 @@ index 00000000000..67dcd26a0e0 + struct dxil_abbrev abbrev; +}; + ++static size_t size_add_with_overflow_check(size_t a, size_t b) ++{ ++ size_t i = a + b; ++ return (i < a) ? SIZE_MAX : i; ++} ++ +static struct sm6_parser *sm6_parser(struct vkd3d_shader_parser *parser) +{ + return CONTAINING_RECORD(parser, struct sm6_parser, p); @@ -1580,10 +1786,10 @@ index 00000000000..67dcd26a0e0 + return VKD3D_ERROR_INVALID_SHADER; +} + -+static unsigned int sm6_parser_compute_global_abbrev_count_for_block_id(struct sm6_parser *sm6, ++static size_t sm6_parser_compute_global_abbrev_count_for_block_id(struct sm6_parser *sm6, + unsigned int block_id) +{ -+ unsigned int i, count; ++ size_t i, count; + + for (i = 0, count = 0; i < sm6->abbrev_count; ++i) + count += sm6->abbrevs[i]->block_id == block_id; @@ -1593,7 +1799,7 @@ index 00000000000..67dcd26a0e0 + +static void dxil_block_destroy(struct dxil_block *block) +{ -+ unsigned int i; ++ size_t i; + + for (i = 0; i < block->record_count; ++i) + vkd3d_free(block->records[i]); @@ -1615,7 +1821,7 @@ index 00000000000..67dcd26a0e0 +static enum vkd3d_result dxil_block_init(struct dxil_block *block, const struct dxil_block *parent, + struct sm6_parser *sm6) +{ -+ unsigned int i, abbrev_count = 0; ++ size_t i, abbrev_count = 0; + enum vkd3d_result ret; + + block->parent = parent; @@ -1657,15 +1863,1142 @@ index 00000000000..67dcd26a0e0 + return ret; +} + -+static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, unsigned int count) ++static size_t dxil_block_compute_function_count(const struct dxil_block *root) +{ -+ unsigned int i; ++ size_t i, count; ++ ++ for (i = 0, count = 0; i < root->child_block_count; ++i) ++ count += root->child_blocks[i]->id == FUNCTION_BLOCK; ++ ++ return count; ++} ++ ++static size_t dxil_block_compute_module_decl_count(const struct dxil_block *block) ++{ ++ size_t i, count; ++ ++ for (i = 0, count = 0; i < block->record_count; ++i) ++ count += block->records[i]->code == MODULE_CODE_FUNCTION; ++ return count; ++} ++ ++static size_t dxil_block_compute_constants_count(const struct dxil_block *block) ++{ ++ size_t i, count; ++ ++ for (i = 0, count = 0; i < block->record_count; ++i) ++ count += block->records[i]->code != CST_CODE_SETTYPE; ++ return count; ++} ++ ++static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, size_t count) ++{ ++ size_t i; + + for (i = 0; i < count; ++i) + vkd3d_free(abbrevs[i]); + vkd3d_free(abbrevs); +} + ++static const struct dxil_block *sm6_parser_get_level_one_block(const struct sm6_parser *sm6, ++ enum bitcode_block_id id, bool *is_unique) ++{ ++ const struct dxil_block *block, *found = NULL; ++ size_t i; ++ ++ for (i = 0, *is_unique = true; i < sm6->root_block.child_block_count; ++i) ++ { ++ block = sm6->root_block.child_blocks[i]; ++ if (block->id != id) ++ continue; ++ ++ if (!found) ++ found = block; ++ else ++ *is_unique = false; ++ } ++ ++ return found; ++} ++ ++static char *dxil_record_to_string(const struct dxil_record *record, unsigned int offset) ++{ ++ unsigned int i; ++ char *str; ++ ++ assert(offset <= record->operand_count); ++ if (!(str = vkd3d_calloc(record->operand_count - offset + 1, 1))) ++ return NULL; ++ ++ for (i = offset; i < record->operand_count; ++i) ++ str[i - offset] = record->operands[i]; ++ ++ return str; ++} ++ ++static bool dxil_record_validate_operand_min_count(const struct dxil_record *record, unsigned int min_count, ++ struct sm6_parser *sm6) ++{ ++ if (record->operand_count >= min_count) ++ return true; ++ ++ WARN("Invalid operand count %u for code %u.\n", record->operand_count, record->code); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, ++ "Invalid operand count %u for record code %u.", record->operand_count, record->code); ++ return false; ++} ++ ++static void dxil_record_validate_operand_max_count(const struct dxil_record *record, unsigned int max_count, ++ struct sm6_parser *sm6) ++{ ++ if (record->operand_count <= max_count) ++ return; ++ ++ WARN("Ignoring %u extra operands for code %u.\n", record->operand_count - max_count, record->code); ++ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, ++ "Ignoring %u extra operands for record code %u.", record->operand_count - max_count, record->code); ++} ++ ++static bool dxil_record_validate_operand_count(const struct dxil_record *record, unsigned int min_count, ++ unsigned int max_count, struct sm6_parser *sm6) ++{ ++ dxil_record_validate_operand_max_count(record, max_count, sm6); ++ return dxil_record_validate_operand_min_count(record, min_count, sm6); ++} ++ ++static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) ++{ ++ const struct dxil_record *record; ++ size_t i, type_count, type_index; ++ const struct dxil_block *block; ++ char *struct_name = NULL; ++ unsigned int j, count; ++ struct sm6_type *type; ++ uint64_t type_id; ++ bool is_unique; ++ ++ sm6->p.location.line = 0; ++ sm6->p.location.column = 0; ++ ++ if (!(block = sm6_parser_get_level_one_block(sm6, TYPE_BLOCK, &is_unique))) ++ { ++ WARN("No type definitions found.\n"); ++ return VKD3D_OK; ++ } ++ if (!is_unique) ++ WARN("Ignoring invalid extra type table(s).\n"); ++ ++ sm6->p.location.line = block->id; ++ ++ type_count = 0; ++ for (i = 0; i < block->record_count; ++i) ++ type_count += block->records[i]->code != TYPE_CODE_NUMENTRY && block->records[i]->code != TYPE_CODE_STRUCT_NAME; ++ ++ /* The type array must not be relocated. */ ++ if (!(sm6->types = vkd3d_calloc(type_count, sizeof(*sm6->types)))) ++ { ++ ERR("Failed to allocate type array.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ for (i = 0; i < block->record_count; ++i) ++ { ++ sm6->p.location.column = i; ++ record = block->records[i]; ++ ++ type = &sm6->types[sm6->type_count]; ++ type_index = sm6->type_count; ++ ++ switch (record->code) ++ { ++ case TYPE_CODE_ARRAY: ++ case TYPE_CODE_VECTOR: ++ if (!dxil_record_validate_operand_count(record, 2, 2, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ ++ type->class = record->code == TYPE_CODE_ARRAY ? TYPE_CLASS_ARRAY : TYPE_CLASS_VECTOR; ++ ++ if (!(type->u.array.count = record->operands[0])) ++ { ++ TRACE("Setting unbounded for type %zu.\n", type_index); ++ type->u.array.count = UINT_MAX; ++ } ++ ++ if ((type_id = record->operands[1]) >= type_count) ++ { ++ WARN("Invalid contained type id %"PRIu64" for type %zu.\n", type_id, type_index); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ type->u.array.elem_type = &sm6->types[type_id]; ++ break; ++ ++ case TYPE_CODE_DOUBLE: ++ dxil_record_validate_operand_max_count(record, 0, sm6); ++ type->class = TYPE_CLASS_FLOAT; ++ type->u.width = 64; ++ break; ++ ++ case TYPE_CODE_FLOAT: ++ dxil_record_validate_operand_max_count(record, 0, sm6); ++ type->class = TYPE_CLASS_FLOAT; ++ type->u.width = 32; ++ break; ++ ++ case TYPE_CODE_FUNCTION: ++ if (!dxil_record_validate_operand_min_count(record, 2, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ if (record->operands[0]) ++ FIXME("Unhandled vararg function type %zu.\n", type_index); ++ ++ type->class = TYPE_CLASS_FUNCTION; ++ ++ if ((type_id = record->operands[1]) >= type_count) ++ { ++ WARN("Invalid return type id %"PRIu64" for type %zu.\n", type_id, type_index); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ count = record->operand_count - 2; ++ if (vkd3d_object_range_overflow(sizeof(type->u.function), count, sizeof(type->u.function->param_types[0])) ++ || !(type->u.function = vkd3d_malloc(offsetof(struct sm6_function_info, param_types[count])))) ++ { ++ ERR("Failed to allocate function parameter types.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ type->u.function->ret_type = &sm6->types[type_id]; ++ type->u.function->param_count = count; ++ for (j = 0; j < count; ++j) ++ { ++ if ((type_id = record->operands[j + 2]) >= type_count) ++ { ++ WARN("Invalid parameter type id %"PRIu64" for type %zu.\n", type_id, type_index); ++ vkd3d_free(type->u.function); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ type->u.function->param_types[j] = &sm6->types[type_id]; ++ } ++ break; ++ ++ case TYPE_CODE_HALF: ++ dxil_record_validate_operand_max_count(record, 0, sm6); ++ type->class = TYPE_CLASS_FLOAT; ++ type->u.width = 16; ++ break; ++ ++ case TYPE_CODE_INTEGER: ++ { ++ uint64_t width; ++ ++ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ ++ type->class = TYPE_CLASS_INTEGER; ++ ++ switch ((width = record->operands[0])) ++ { ++ case 1: ++ case 8: ++ case 16: ++ case 32: ++ case 64: ++ break; ++ default: ++ WARN("Invalid integer width %"PRIu64" for type %zu.\n", width, type_index); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ type->u.width = width; ++ break; ++ } ++ ++ case TYPE_CODE_LABEL: ++ type->class = TYPE_CLASS_LABEL; ++ break; ++ ++ case TYPE_CODE_METADATA: ++ type->class = TYPE_CLASS_METADATA; ++ break; ++ ++ case TYPE_CODE_NUMENTRY: ++ continue; ++ ++ case TYPE_CODE_POINTER: ++ if (!dxil_record_validate_operand_count(record, 1, 2, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ ++ type->class = TYPE_CLASS_POINTER; ++ ++ if ((type_id = record->operands[0]) >= type_count) ++ { ++ WARN("Invalid pointee type id %"PRIu64" for type %zu.\n", type_id, type_index); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ type->u.pointer.type = &sm6->types[type_id]; ++ type->u.pointer.addr_space = (record->operand_count > 1) ? record->operands[1] : ADDRESS_SPACE_DEFAULT; ++ break; ++ ++ case TYPE_CODE_STRUCT_ANON: ++ case TYPE_CODE_STRUCT_NAMED: ++ if (!dxil_record_validate_operand_min_count(record, 2, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ if (record->code == TYPE_CODE_STRUCT_NAMED && !struct_name) ++ { ++ WARN("Missing struct name before struct type %zu.\n", type_index); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ type->class = TYPE_CLASS_STRUCT; ++ ++ count = record->operand_count - 1; ++ if (vkd3d_object_range_overflow(sizeof(type->u.struc), count, sizeof(type->u.struc->elem_types[0])) ++ || !(type->u.struc = vkd3d_malloc(offsetof(struct sm6_struct_info, elem_types[count])))) ++ { ++ ERR("Failed to allocate struct element types.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ if (record->operands[0]) ++ FIXME("Ignoring struct packed attribute.\n"); ++ ++ type->u.struc->elem_count = count; ++ for (j = 0; j < count; ++j) ++ { ++ if ((type_id = record->operands[j + 1]) >= type_count) ++ { ++ WARN("Invalid contained type id %"PRIu64" for type %zu.\n", type_id, type_index); ++ vkd3d_free(type->u.struc); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ type->u.struc->elem_types[j] = &sm6->types[type_id]; ++ } ++ ++ if (record->code == TYPE_CODE_STRUCT_ANON) ++ { ++ type->u.struc->name = NULL; ++ break; ++ } ++ ++ type->u.struc->name = struct_name; ++ struct_name = NULL; ++ break; ++ ++ case TYPE_CODE_STRUCT_NAME: ++ if (!(struct_name = dxil_record_to_string(record, 0))) ++ { ++ ERR("Failed to allocate struct name.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ if (!struct_name[0]) ++ WARN("Struct name is empty for type %zu.\n", type_index); ++ continue; ++ ++ case TYPE_CODE_VOID: ++ dxil_record_validate_operand_max_count(record, 0, sm6); ++ type->class = TYPE_CLASS_VOID; ++ break; ++ ++ default: ++ FIXME("Unhandled type %u at index %zu.\n", record->code, type_index); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++sm6->type_count; ++ } ++ ++ assert(sm6->type_count == type_count); ++ ++ if (struct_name) ++ { ++ WARN("Unused struct name %s.\n", struct_name); ++ vkd3d_free(struct_name); ++ } ++ ++ return VKD3D_OK; ++} ++ ++static inline bool sm6_type_is_void(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_VOID; ++} ++ ++static inline bool sm6_type_is_integer(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_INTEGER; ++} ++ ++static inline bool sm6_type_is_floating_point(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_FLOAT; ++} ++ ++static inline bool sm6_type_is_numeric(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_INTEGER || type->class == TYPE_CLASS_FLOAT; ++} ++ ++static inline bool sm6_type_is_pointer(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_POINTER; ++} ++ ++static bool sm6_type_is_numeric_aggregate(const struct sm6_type *type) ++{ ++ unsigned int i; ++ ++ switch (type->class) ++ { ++ case TYPE_CLASS_ARRAY: ++ case TYPE_CLASS_VECTOR: ++ return sm6_type_is_numeric(type->u.array.elem_type); ++ ++ case TYPE_CLASS_STRUCT: ++ /* Do not handle nested structs. Support can be added if they show up. */ ++ for (i = 0; i < type->u.struc->elem_count; ++i) ++ if (!sm6_type_is_numeric(type->u.struc->elem_types[i])) ++ return false; ++ return true; ++ ++ default: ++ return false; ++ } ++} ++ ++static inline bool sm6_type_is_struct(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_STRUCT; ++} ++ ++static inline bool sm6_type_is_function(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_FUNCTION; ++} ++ ++static inline bool sm6_type_is_function_pointer(const struct sm6_type *type) ++{ ++ return sm6_type_is_pointer(type) && sm6_type_is_function(type->u.pointer.type); ++} ++ ++static inline bool sm6_type_is_handle(const struct sm6_type *type) ++{ ++ return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.Handle"); ++} ++ ++static inline const struct sm6_type *sm6_type_get_element_type(const struct sm6_type *type) ++{ ++ return (type->class == TYPE_CLASS_ARRAY || type->class == TYPE_CLASS_VECTOR) ? type->u.array.elem_type : type; ++} ++ ++static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type *type, ++ enum bitcode_address_space addr_space, struct sm6_parser *sm6) ++{ ++ size_t i, start = type - sm6->types; ++ const struct sm6_type *pointer_type; ++ ++ /* DXC seems usually to place the pointer type immediately after its pointee. */ ++ for (i = (start + 1) % sm6->type_count; i != start; i = (i + 1) % sm6->type_count) ++ { ++ pointer_type = &sm6->types[i]; ++ if (sm6_type_is_pointer(pointer_type) && pointer_type->u.pointer.type == type ++ && pointer_type->u.pointer.addr_space == addr_space) ++ return pointer_type; ++ } ++ ++ return NULL; ++} ++ ++static const struct sm6_type *sm6_parser_get_type(struct sm6_parser *sm6, uint64_t type_id) ++{ ++ if (type_id >= sm6->type_count) ++ { ++ WARN("Invalid type index %"PRIu64" at %zu.\n", type_id, sm6->value_count); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID, ++ "DXIL type id %"PRIu64" is invalid.", type_id); ++ return NULL; ++ } ++ return &sm6->types[type_id]; ++} ++ ++static int global_symbol_compare(const void *a, const void *b) ++{ ++ return vkd3d_u32_compare(((const struct sm6_symbol *)a)->id, ((const struct sm6_symbol *)b)->id); ++} ++ ++static enum vkd3d_result sm6_parser_symtab_init(struct sm6_parser *sm6) ++{ ++ const struct dxil_record *record; ++ const struct dxil_block *block; ++ struct sm6_symbol *symbol; ++ size_t i, count; ++ bool is_unique; ++ ++ sm6->p.location.line = 0; ++ sm6->p.location.column = 0; ++ ++ if (!(block = sm6_parser_get_level_one_block(sm6, VALUE_SYMTAB_BLOCK, &is_unique))) ++ { ++ /* There should always be at least one symbol: the name of the entry point function. */ ++ WARN("No value symtab block found.\n"); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ if (!is_unique) ++ FIXME("Ignoring extra value symtab block(s).\n"); ++ ++ sm6->p.location.line = block->id; ++ ++ for (i = 0, count = 0; i < block->record_count; ++i) ++ count += block->records[i]->code == VST_CODE_ENTRY; ++ ++ if (!(sm6->global_symbols = vkd3d_calloc(count, sizeof(*sm6->global_symbols)))) ++ { ++ ERR("Failed to allocate global symbols.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ for (i = 0; i < block->record_count; ++i) ++ { ++ sm6->p.location.column = i; ++ record = block->records[i]; ++ ++ if (record->code != VST_CODE_ENTRY) ++ { ++ FIXME("Unhandled symtab code %u.\n", record->code); ++ continue; ++ } ++ if (!dxil_record_validate_operand_min_count(record, 1, sm6)) ++ continue; ++ ++ symbol = &sm6->global_symbols[sm6->global_symbol_count]; ++ symbol->id = record->operands[0]; ++ if (!(symbol->name = dxil_record_to_string(record, 1))) ++ { ++ ERR("Failed to allocate symbol name.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++sm6->global_symbol_count; ++ } ++ ++ sm6->p.location.column = block->record_count; ++ ++ qsort(sm6->global_symbols, sm6->global_symbol_count, sizeof(*sm6->global_symbols), global_symbol_compare); ++ for (i = 1; i < sm6->global_symbol_count; ++i) ++ { ++ if (sm6->global_symbols[i].id == sm6->global_symbols[i - 1].id) ++ { ++ WARN("Invalid duplicate symbol id %u.\n", sm6->global_symbols[i].id); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ } ++ ++ return VKD3D_OK; ++} ++ ++static const char *sm6_parser_get_global_symbol_name(const struct sm6_parser *sm6, size_t id) ++{ ++ size_t i, start; ++ ++ /* id == array index is normally true */ ++ i = start = id % sm6->global_symbol_count; ++ do ++ { ++ if (sm6->global_symbols[i].id == id) ++ return sm6->global_symbols[i].name; ++ i = (i + 1) % sm6->global_symbol_count; ++ } while (i != start); ++ ++ return NULL; ++} ++ ++static inline bool sm6_value_is_dx_intrinsic_dcl(const struct sm6_value *fn) ++{ ++ assert(fn->value_type == VALUE_TYPE_FUNCTION); ++ return fn->u.function.is_prototype && !strncmp(fn->u.function.name, "dx.op.", 6); ++} ++ ++static inline struct sm6_value *sm6_parser_get_current_value(const struct sm6_parser *sm6) ++{ ++ assert(sm6->value_count < sm6->value_capacity); ++ return &sm6->values[sm6->value_count]; ++} ++ ++static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type *type) ++{ ++ if (type->class == TYPE_CLASS_INTEGER) ++ { ++ switch (type->u.width) ++ { ++ case 8: ++ return VKD3D_DATA_UINT8; ++ case 32: ++ return VKD3D_DATA_UINT; ++ default: ++ FIXME("Unhandled width %u.\n", type->u.width); ++ return VKD3D_DATA_UINT; ++ } ++ } ++ else if (type->class == TYPE_CLASS_FLOAT) ++ { ++ switch (type->u.width) ++ { ++ case 32: ++ return VKD3D_DATA_FLOAT; ++ case 64: ++ return VKD3D_DATA_DOUBLE; ++ default: ++ FIXME("Unhandled width %u.\n", type->u.width); ++ return VKD3D_DATA_FLOAT; ++ } ++ } ++ ++ FIXME("Unhandled type %u.\n", type->class); ++ return VKD3D_DATA_UINT; ++} ++ ++/* Recurse through the block tree while maintaining a current value count. The current ++ * count is the sum of the global count plus all declarations within the current function. ++ * Store into value_capacity the highest count seen. */ ++static size_t sm6_parser_compute_max_value_count(struct sm6_parser *sm6, ++ const struct dxil_block *block, size_t value_count) ++{ ++ size_t i, old_value_count = value_count; ++ ++ if (block->id == MODULE_BLOCK) ++ value_count = size_add_with_overflow_check(value_count, dxil_block_compute_module_decl_count(block)); ++ ++ for (i = 0; i < block->child_block_count; ++i) ++ value_count = sm6_parser_compute_max_value_count(sm6, block->child_blocks[i], value_count); ++ ++ switch (block->id) ++ { ++ case CONSTANTS_BLOCK: ++ /* Function local constants are contained in a child block of the function block. */ ++ value_count = size_add_with_overflow_check(value_count, dxil_block_compute_constants_count(block)); ++ break; ++ case FUNCTION_BLOCK: ++ /* A function must start with a block count, which emits no value. This formula is likely to ++ * overestimate the value count somewhat, but this should be no problem. */ ++ value_count = size_add_with_overflow_check(value_count, max(block->record_count, 1u) - 1); ++ sm6->value_capacity = max(sm6->value_capacity, value_count); ++ /* The value count returns to its previous value after handling a function. */ ++ if (value_count < SIZE_MAX) ++ value_count = old_value_count; ++ break; ++ default: ++ break; ++ } ++ ++ return value_count; ++} ++ ++static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxil_record *record) ++{ ++ const unsigned int max_count = 15; ++ const struct sm6_type *ret_type; ++ struct sm6_value *fn; ++ unsigned int i, j; ++ ++ if (!dxil_record_validate_operand_count(record, 8, max_count, sm6)) ++ return false; ++ ++ fn = sm6_parser_get_current_value(sm6); ++ fn->value_type = VALUE_TYPE_FUNCTION; ++ if (!(fn->u.function.name = sm6_parser_get_global_symbol_name(sm6, sm6->value_count))) ++ { ++ WARN("Missing symbol name for function %zu.\n", sm6->value_count); ++ fn->u.function.name = ""; ++ } ++ ++ if (!(fn->type = sm6_parser_get_type(sm6, record->operands[0]))) ++ return false; ++ if (!sm6_type_is_function(fn->type)) ++ { ++ WARN("Type is not a function.\n"); ++ return false; ++ } ++ ret_type = fn->type->u.function->ret_type; ++ ++ if (!(fn->type = sm6_type_get_pointer_to_type(fn->type, ADDRESS_SPACE_DEFAULT, sm6))) ++ { ++ WARN("Failed to get pointer type for type %u.\n", fn->type->class); ++ return false; ++ } ++ ++ if (record->operands[1]) ++ WARN("Ignoring calling convention %#"PRIx64".\n", record->operands[1]); ++ ++ fn->u.function.is_prototype = !!record->operands[2]; ++ ++ if (record->operands[3]) ++ WARN("Ignoring linkage %#"PRIx64".\n", record->operands[3]); ++ ++ if (record->operands[4] > UINT_MAX) ++ WARN("Invalid attributes id %#"PRIx64".\n", record->operands[4]); ++ /* 1-based index. */ ++ if ((fn->u.function.attribs_id = record->operands[4])) ++ TRACE("Ignoring function attributes.\n"); ++ ++ /* These always seem to be zero. */ ++ for (i = 5, j = 0; i < min(record->operand_count, max_count); ++i) ++ j += !!record->operands[i]; ++ if (j) ++ WARN("Ignoring %u operands.\n", j); ++ ++ if (sm6_value_is_dx_intrinsic_dcl(fn) && !sm6_type_is_void(ret_type) && !sm6_type_is_numeric(ret_type) ++ && !sm6_type_is_numeric_aggregate(ret_type) && !sm6_type_is_handle(ret_type)) ++ { ++ WARN("Unexpected return type for dx intrinsic function '%s'.\n", fn->u.function.name); ++ } ++ ++ ++sm6->value_count; ++ ++ return true; ++} ++ ++static inline uint64_t decode_rotated_signed_value(uint64_t value) ++{ ++ if (value != 1) ++ { ++ bool neg = value & 1; ++ value >>= 1; ++ return neg ? -value : value; ++ } ++ return value << 63; ++} ++ ++static inline float bitcast_uint64_to_float(uint64_t value) ++{ ++ union ++ { ++ uint32_t uint32_value; ++ float float_value; ++ } u; ++ ++ u.uint32_value = value; ++ return u.float_value; ++} ++ ++static inline double bitcast_uint64_to_double(uint64_t value) ++{ ++ union ++ { ++ uint64_t uint64_value; ++ double double_value; ++ } u; ++ ++ u.uint64_value = value; ++ return u.double_value; ++} ++ ++static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) ++{ ++ enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; ++ const struct sm6_type *type, *elem_type; ++ enum vkd3d_data_type reg_data_type; ++ const struct dxil_record *record; ++ struct sm6_value *dst; ++ size_t i, value_idx; ++ uint64_t value; ++ ++ for (i = 0, type = NULL; i < block->record_count; ++i) ++ { ++ sm6->p.location.column = i; ++ record = block->records[i]; ++ value_idx = sm6->value_count; ++ ++ if (record->code == CST_CODE_SETTYPE) ++ { ++ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ ++ if (!(type = sm6_parser_get_type(sm6, record->operands[0]))) ++ return VKD3D_ERROR_INVALID_SHADER; ++ ++ elem_type = sm6_type_get_element_type(type); ++ if (sm6_type_is_numeric(elem_type)) ++ { ++ reg_data_type = vkd3d_data_type_from_sm6_type(elem_type); ++ reg_type = elem_type->u.width > 32 ? VKD3DSPR_IMMCONST64 : VKD3DSPR_IMMCONST; ++ } ++ else ++ { ++ reg_data_type = VKD3D_DATA_UNUSED; ++ reg_type = VKD3DSPR_INVALID; ++ } ++ ++ if (i == block->record_count - 1) ++ WARN("Unused SETTYPE record.\n"); ++ ++ continue; ++ } ++ ++ if (!type) ++ { ++ WARN("Constant record %zu has no type.\n", value_idx); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ dst = sm6_parser_get_current_value(sm6); ++ dst->type = type; ++ dst->value_type = VALUE_TYPE_REG; ++ dst->u.reg.type = reg_type; ++ dst->u.reg.immconst_type = VKD3D_IMMCONST_SCALAR; ++ dst->u.reg.data_type = reg_data_type; ++ ++ switch (record->code) ++ { ++ case CST_CODE_NULL: ++ /* Register constant data is already zero-filled. */ ++ break; ++ ++ case CST_CODE_INTEGER: ++ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ ++ if (!sm6_type_is_integer(type)) ++ { ++ WARN("Invalid integer of non-integer type %u at constant idx %zu.\n", type->class, value_idx); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ value = decode_rotated_signed_value(record->operands[0]); ++ if (type->u.width <= 32) ++ dst->u.reg.u.immconst_uint[0] = value & ((1ull << type->u.width) - 1); ++ else ++ dst->u.reg.u.immconst_uint64[0] = value; ++ ++ break; ++ ++ case CST_CODE_FLOAT: ++ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; ++ ++ if (!sm6_type_is_floating_point(type)) ++ { ++ WARN("Invalid float of non-fp type %u at constant idx %zu.\n", type->class, value_idx); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ if (type->u.width == 16) ++ FIXME("Half float type is not supported yet.\n"); ++ else if (type->u.width == 32) ++ dst->u.reg.u.immconst_float[0] = bitcast_uint64_to_float(record->operands[0]); ++ else if (type->u.width == 64) ++ dst->u.reg.u.immconst_double[0] = bitcast_uint64_to_double(record->operands[0]); ++ else ++ vkd3d_unreachable(); ++ ++ break; ++ ++ case CST_CODE_DATA: ++ WARN("Unhandled constant array.\n"); ++ break; ++ ++ default: ++ FIXME("Unhandled constant code %u.\n", record->code); ++ break; ++ } ++ ++ ++sm6->value_count; ++ } ++ ++ return VKD3D_OK; ++} ++ ++static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) ++{ ++ const struct dxil_block *block = &sm6->root_block; ++ const struct dxil_record *record; ++ uint64_t version; ++ size_t i; ++ ++ sm6->p.location.line = block->id; ++ sm6->p.location.column = 0; ++ ++ for (i = 0; i < block->record_count; ++i) ++ { ++ sm6->p.location.column = i; ++ record = block->records[i]; ++ switch (record->code) ++ { ++ case MODULE_CODE_FUNCTION: ++ if (!sm6_parser_declare_function(sm6, record)) ++ { ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL, ++ "A DXIL function declaration is invalid."); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ break; ++ ++ case MODULE_CODE_GLOBALVAR: ++ FIXME("Global variables are not implemented yet.\n"); ++ break; ++ ++ case MODULE_CODE_VERSION: ++ dxil_record_validate_operand_count(record, 1, 1, sm6); ++ 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, ++ "Bitcode format version %#"PRIx64" is unsupported.", version); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ return VKD3D_OK; ++} ++ ++static const struct sm6_value *sm6_parser_next_function_definition(struct sm6_parser *sm6) ++{ ++ size_t i, count = sm6->function_count; ++ ++ for (i = 0; i < sm6->value_count; ++i) ++ { ++ if (sm6_type_is_function_pointer(sm6->values[i].type) && !sm6->values[i].u.function.is_prototype && !count--) ++ break; ++ } ++ if (i == sm6->value_count) ++ return NULL; ++ ++ ++sm6->function_count; ++ return &sm6->values[i]; ++} ++ ++static struct sm6_block *sm6_block_create() ++{ ++ struct sm6_block *block = vkd3d_calloc(1, sizeof(*block)); ++ return block; ++} ++ ++static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record, ++ struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) ++{ ++ if (!dxil_record_validate_operand_count(record, 0, 1, sm6)) ++ return; ++ ++ if (record->operand_count) ++ FIXME("Non-void return is not implemented.\n"); ++ ++ ins->handler_idx = VKD3DSIH_NOP; ++} ++ ++static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, ++ struct sm6_function *function) ++{ ++ struct vkd3d_shader_instruction *ins; ++ const struct dxil_record *record; ++ struct sm6_block *code_block; ++ struct sm6_value *dst; ++ size_t i, block_idx; ++ bool ret_found; ++ enum ++ { ++ RESULT_VALUE, ++ RESULT_TERMINATE, ++ } result_type; ++ ++ if (sm6->function_count) ++ { ++ FIXME("Multiple functions are not supported yet.\n"); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ if (!(function->declaration = sm6_parser_next_function_definition(sm6))) ++ { ++ WARN("Failed to find definition to match function body.\n"); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ if (block->record_count < 2) ++ { ++ /* It should contain at least a block count and a RET instruction. */ ++ WARN("Invalid function block record count %zu.\n", block->record_count); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ if (block->records[0]->code != FUNC_CODE_DECLAREBLOCKS || !block->records[0]->operand_count ++ || block->records[0]->operands[0] > UINT_MAX) ++ { ++ WARN("Block count declaration not found or invalid.\n"); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ if (!(function->block_count = block->records[0]->operands[0])) ++ { ++ WARN("Function contains no blocks.\n"); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ if (function->block_count > 1) ++ { ++ FIXME("Branched shaders are not supported yet.\n"); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ if (!(function->blocks[0] = sm6_block_create())) ++ { ++ ERR("Failed to allocate code block.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ code_block = function->blocks[0]; ++ ++ for (i = 1, block_idx = 0, ret_found = false; i < block->record_count; ++i) ++ { ++ sm6->p.location.column = i; ++ ++ /* block->record_count - 1 is the instruction count, but some instructions ++ * can emit >1 IR instruction, so extra may be used. */ ++ if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity, ++ max(code_block->instruction_count + 1, block->record_count), sizeof(*code_block->instructions))) ++ { ++ ERR("Failed to allocate instructions.\n"); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ ins = &code_block->instructions[code_block->instruction_count]; ++ ins->handler_idx = VKD3DSIH_INVALID; ++ ++ dst = sm6_parser_get_current_value(sm6); ++ dst->type = NULL; ++ dst->value_type = VALUE_TYPE_REG; ++ result_type = RESULT_VALUE; ++ ++ record = block->records[i]; ++ switch (record->code) ++ { ++ case FUNC_CODE_INST_RET: ++ sm6_parser_emit_ret(sm6, record, code_block, ins); ++ result_type = RESULT_TERMINATE; ++ ret_found = true; ++ break; ++ default: ++ FIXME("Unhandled dxil instruction %u.\n", record->code); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ if (result_type == RESULT_TERMINATE) ++ { ++ ++block_idx; ++ code_block = (block_idx < function->block_count) ? function->blocks[block_idx] : NULL; ++ } ++ if (code_block) ++ code_block->instruction_count += ins->handler_idx != VKD3DSIH_NOP; ++ else ++ assert(ins->handler_idx == VKD3DSIH_NOP); ++ sm6->value_count += !!dst->type; ++ } ++ ++ if (!ret_found) ++ { ++ WARN("Function contains no RET instruction.\n"); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ return VKD3D_OK; ++} ++ ++static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const struct dxil_block *block, ++ unsigned int level) ++{ ++ size_t i, old_value_count = sm6->value_count; ++ struct sm6_function *function; ++ enum vkd3d_result ret; ++ ++ for (i = 0; i < block->child_block_count; ++i) ++ { ++ if ((ret = sm6_parser_module_init(sm6, block->child_blocks[i], level + 1)) < 0) ++ return ret; ++ } ++ ++ sm6->p.location.line = block->id; ++ sm6->p.location.column = 0; ++ ++ switch (block->id) ++ { ++ case CONSTANTS_BLOCK: ++ return sm6_parser_constants_init(sm6, block); ++ ++ case FUNCTION_BLOCK: ++ function = &sm6->functions[sm6->function_count]; ++ if ((ret = sm6_parser_function_init(sm6, block, function)) < 0) ++ return ret; ++ /* The value index returns to its previous value after handling a function. It's usually nonzero ++ * at the start because of global constants/variables/function declarations. Function constants ++ * occur in a child block, so value_count is already saved before they are emitted. */ ++ memset(&sm6->values[old_value_count], 0, (sm6->value_count - old_value_count) * sizeof(*sm6->values)); ++ sm6->value_count = old_value_count; ++ break; ++ ++ case BLOCKINFO_BLOCK: ++ case MODULE_BLOCK: ++ case PARAMATTR_BLOCK: ++ case PARAMATTR_GROUP_BLOCK: ++ case VALUE_SYMTAB_BLOCK: ++ case METADATA_BLOCK: ++ case METADATA_ATTACHMENT_BLOCK: ++ case TYPE_BLOCK: ++ break; ++ ++ default: ++ FIXME("Unhandled block id %u.\n", block->id); ++ break; ++ } ++ ++ return VKD3D_OK; ++} ++ ++static void sm6_type_table_cleanup(struct sm6_type *types, size_t count) ++{ ++ size_t i; ++ ++ if (!types) ++ return; ++ ++ for (i = 0; i < count; ++i) ++ { ++ switch (types[i].class) ++ { ++ case TYPE_CLASS_STRUCT: ++ vkd3d_free((void *)types[i].u.struc->name); ++ vkd3d_free(types[i].u.struc); ++ break; ++ case TYPE_CLASS_FUNCTION: ++ vkd3d_free(types[i].u.function); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ vkd3d_free(types); ++} ++ ++static void sm6_symtab_cleanup(struct sm6_symbol *symbols, size_t count) ++{ ++ size_t i; ++ ++ for (i = 0; i < count; ++i) ++ vkd3d_free((void *)symbols[i].name); ++ vkd3d_free(symbols); ++} ++ ++static void sm6_block_destroy(struct sm6_block *block) ++{ ++ vkd3d_free(block->instructions); ++ vkd3d_free(block); ++} ++ ++static void sm6_functions_cleanup(struct sm6_function *functions, size_t count) ++{ ++ size_t i, j; ++ ++ for (i = 0; i < count; ++i) ++ { ++ for (j = 0; j < functions[i].block_count; ++j) ++ sm6_block_destroy(functions[i].blocks[j]); ++ } ++ vkd3d_free(functions); ++} ++ +static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) +{ + struct sm6_parser *sm6 = sm6_parser(parser); @@ -1673,6 +3006,10 @@ index 00000000000..67dcd26a0e0 + dxil_block_destroy(&sm6->root_block); + dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); + shader_instruction_array_destroy(&parser->instructions); ++ sm6_type_table_cleanup(sm6->types, sm6->type_count); ++ sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); ++ sm6_functions_cleanup(sm6->functions, sm6->function_count); ++ vkd3d_free(sm6->values); + free_shader_desc(&parser->shader_desc); + vkd3d_free(sm6); +} @@ -1687,7 +3024,8 @@ index 00000000000..67dcd26a0e0 +{ + const struct vkd3d_shader_location location = {.source_name = source_name}; + uint32_t version_token, dxil_version, token_count, magic; -+ unsigned int count, length, chunk_offset, chunk_size; ++ unsigned int chunk_offset, chunk_size; ++ size_t count, length, function_count; + enum bitcode_block_abbreviation abbr; + struct vkd3d_shader_version version; + struct dxil_block *block; @@ -1709,9 +3047,9 @@ index 00000000000..67dcd26a0e0 + + if (token_count < 6 || count < token_count) + { -+ WARN("Invalid token count %u (word count %u).\n", token_count, count); ++ WARN("Invalid token count %u (word count %zu).\n", token_count, count); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, -+ "DXIL chunk token count %#x is invalid (word count %u).", token_count, count); ++ "DXIL chunk token count %#x is invalid (word count %zu).", token_count, count); + return VKD3D_ERROR_INVALID_SHADER; + } + @@ -1799,17 +3137,86 @@ index 00000000000..67dcd26a0e0 + length = sm6->ptr - sm6->start - block->start; + if (length != block->length) + { -+ WARN("Invalid block length %u; expected %u.\n", length, block->length); ++ WARN("Invalid block length %zu; expected %u.\n", length, block->length); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH, -+ "Root block ends with length %u but indicated length is %u.", length, block->length); ++ "Root block ends with length %zu but indicated length is %u.", length, block->length); + } + if (sm6->ptr != sm6->end) + { -+ unsigned int expected_length = sm6->end - sm6->start; ++ size_t expected_length = sm6->end - sm6->start; + length = sm6->ptr - sm6->start; -+ WARN("Invalid module length %u; expected %u.\n", length, expected_length); ++ WARN("Invalid module length %zu; expected %zu.\n", length, expected_length); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH, -+ "Module ends with length %u but indicated length is %u.", length, expected_length); ++ "Module ends with length %zu but indicated length is %zu.", length, expected_length); ++ } ++ ++ if ((ret = sm6_parser_type_table_init(sm6)) < 0) ++ { ++ if (ret == VKD3D_ERROR_OUT_OF_MEMORY) ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, ++ "Out of memory parsing DXIL type table."); ++ else if (ret == VKD3D_ERROR_INVALID_SHADER) ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE, ++ "DXIL type table is invalid."); ++ else ++ vkd3d_unreachable(); ++ return ret; ++ } ++ ++ if ((ret = sm6_parser_symtab_init(sm6)) < 0) ++ { ++ if (ret == VKD3D_ERROR_OUT_OF_MEMORY) ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, ++ "Out of memory parsing DXIL value symbol table."); ++ else if (ret == VKD3D_ERROR_INVALID_SHADER) ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB, ++ "DXIL value symbol table is invalid."); ++ else ++ vkd3d_unreachable(); ++ return ret; ++ } ++ ++ function_count = dxil_block_compute_function_count(&sm6->root_block); ++ if (!(sm6->functions = vkd3d_calloc(function_count, sizeof(*sm6->functions)))) ++ { ++ ERR("Failed to allocate function array.\n"); ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, ++ "Out of memory allocating DXIL function array."); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ if (sm6_parser_compute_max_value_count(sm6, &sm6->root_block, 0) == SIZE_MAX) ++ { ++ WARN("Value array count overflowed.\n"); ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, ++ "Overflow occurred in the DXIL module value count."); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ if (!(sm6->values = vkd3d_calloc(sm6->value_capacity, sizeof(*sm6->values)))) ++ { ++ ERR("Failed to allocate value array.\n"); ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, ++ "Out of memory allocating DXIL value array."); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ if ((ret = sm6_parser_globals_init(sm6)) < 0) ++ { ++ WARN("Failed to load global declarations.\n"); ++ return ret; ++ } ++ ++ if ((ret = sm6_parser_module_init(sm6, &sm6->root_block, 0)) < 0) ++ { ++ if (ret == VKD3D_ERROR_OUT_OF_MEMORY) ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, ++ "Out of memory parsing DXIL module."); ++ else if (ret == VKD3D_ERROR_INVALID_SHADER) ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, ++ "DXIL module is invalid."); ++ else ++ vkd3d_unreachable(); ++ return ret; + } + + dxil_block_destroy(&sm6->root_block); @@ -1870,10 +3277,121 @@ index 00000000000..67dcd26a0e0 + return ret; +} diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -index ba5bcfbfaf0..4e9af15c1be 100644 +index ba5bcfbfaf0..ab508502623 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -@@ -1432,7 +1432,7 @@ struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *v +@@ -430,6 +430,51 @@ struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl + return type; + } + ++unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, ++ enum hlsl_regset regset, unsigned int index) ++{ ++ struct hlsl_type *next_type; ++ unsigned int offset = 0; ++ unsigned int idx; ++ ++ while (!type_is_single_component(type)) ++ { ++ next_type = type; ++ idx = traverse_path_from_component_index(ctx, &next_type, &index); ++ ++ switch (type->class) ++ { ++ case HLSL_CLASS_SCALAR: ++ case HLSL_CLASS_VECTOR: ++ case HLSL_CLASS_MATRIX: ++ if (regset == HLSL_REGSET_NUMERIC) ++ offset += idx; ++ break; ++ ++ case HLSL_CLASS_STRUCT: ++ offset += type->e.record.fields[idx].reg_offset[regset]; ++ break; ++ ++ case HLSL_CLASS_ARRAY: ++ if (regset == HLSL_REGSET_NUMERIC) ++ offset += idx * align(type->e.array.type->reg_size[regset], 4); ++ else ++ offset += idx * type->e.array.type->reg_size[regset]; ++ break; ++ ++ case HLSL_CLASS_OBJECT: ++ assert(idx == 0); ++ break; ++ ++ default: ++ vkd3d_unreachable(); ++ } ++ type = next_type; ++ } ++ ++ return offset; ++} ++ + static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_var *var, + unsigned int path_len) + { +@@ -524,7 +569,9 @@ struct hlsl_type *hlsl_deref_get_type(struct hlsl_ctx *ctx, const struct hlsl_de + unsigned int i; + + assert(deref); +- assert(!deref->offset.node); ++ ++ if (deref->offset.node) ++ return deref->data_type; + + type = deref->var->data_type; + for (i = 0; i < deref->path_len; ++i) +@@ -626,6 +673,7 @@ struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *ba + type->e.array.type = basic_type; + type->dimx = basic_type->dimx; + type->dimy = basic_type->dimy; ++ type->sampler_dim = basic_type->sampler_dim; + hlsl_type_calculate_reg_size(ctx, type); + + list_add_tail(&ctx->types, &type->entry); +@@ -992,20 +1040,31 @@ struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *tem + struct vkd3d_string_buffer *string; + struct hlsl_ir_var *var; + static LONG counter; +- const char *name; + + if (!(string = hlsl_get_string_buffer(ctx))) + return NULL; + vkd3d_string_buffer_printf(string, "<%s-%u>", template, InterlockedIncrement(&counter)); +- if (!(name = hlsl_strdup(ctx, string->buffer))) +- { +- hlsl_release_string_buffer(ctx, string); +- return NULL; +- } +- var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL); ++ var = hlsl_new_synthetic_var_named(ctx, string->buffer, type, loc, true); + hlsl_release_string_buffer(ctx, string); ++ return var; ++} ++ ++struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const char *name, ++ struct hlsl_type *type, const struct vkd3d_shader_location *loc, bool dummy_scope) ++{ ++ struct hlsl_ir_var *var; ++ const char *name_copy; ++ ++ if (!(name_copy = hlsl_strdup(ctx, name))) ++ return NULL; ++ var = hlsl_new_var(ctx, name_copy, type, loc, NULL, 0, NULL); + if (var) +- list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); ++ { ++ if (dummy_scope) ++ list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); ++ else ++ list_add_tail(&ctx->globals->vars, &var->scope_entry); ++ } + return var; + } + +@@ -1432,7 +1491,7 @@ struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *v } struct hlsl_ir_node *hlsl_new_jump(struct hlsl_ctx *ctx, enum hlsl_ir_jump_type type, @@ -1882,7 +3400,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 { struct hlsl_ir_jump *jump; -@@ -1440,6 +1440,7 @@ struct hlsl_ir_node *hlsl_new_jump(struct hlsl_ctx *ctx, enum hlsl_ir_jump_type +@@ -1440,6 +1499,7 @@ struct hlsl_ir_node *hlsl_new_jump(struct hlsl_ctx *ctx, enum hlsl_ir_jump_type return NULL; init_node(&jump->node, HLSL_IR_JUMP, NULL, loc); jump->type = type; @@ -1890,7 +3408,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 return &jump->node; } -@@ -1585,9 +1586,9 @@ static struct hlsl_ir_node *clone_if(struct hlsl_ctx *ctx, struct clone_instr_ma +@@ -1585,9 +1645,9 @@ static struct hlsl_ir_node *clone_if(struct hlsl_ctx *ctx, struct clone_instr_ma return dst; } @@ -1902,7 +3420,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 } static struct hlsl_ir_node *clone_load(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_load *src) -@@ -1728,7 +1729,7 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, +@@ -1728,7 +1788,7 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, return clone_index(ctx, map, hlsl_ir_index(instr)); case HLSL_IR_JUMP: @@ -1911,7 +3429,39 @@ index ba5bcfbfaf0..4e9af15c1be 100644 case HLSL_IR_LOAD: return clone_load(ctx, map, hlsl_ir_load(instr)); -@@ -2123,18 +2124,18 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) +@@ -2065,6 +2125,31 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru + } + } + ++struct vkd3d_string_buffer *hlsl_component_to_string(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var, ++ unsigned int index) ++{ ++ struct hlsl_type *type = var->data_type, *current_type; ++ struct vkd3d_string_buffer *buffer; ++ unsigned int element_index; ++ ++ if (!(buffer = hlsl_get_string_buffer(ctx))) ++ return NULL; ++ ++ vkd3d_string_buffer_printf(buffer, "%s", var->name); ++ ++ while (!type_is_single_component(type)) ++ { ++ current_type = type; ++ element_index = traverse_path_from_component_index(ctx, &type, &index); ++ if (current_type->class == HLSL_CLASS_STRUCT) ++ vkd3d_string_buffer_printf(buffer, ".%s", current_type->e.record.fields[element_index].name); ++ else ++ vkd3d_string_buffer_printf(buffer, "[%u]", element_index); ++ } ++ ++ return buffer; ++} ++ + const char *debug_hlsl_type(struct hlsl_ctx *ctx, const struct hlsl_type *type) + { + struct vkd3d_string_buffer *string; +@@ -2123,18 +2208,18 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) { static const char * const names[] = { @@ -1942,7 +3492,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 }; if (type >= ARRAY_SIZE(names)) -@@ -2146,10 +2147,11 @@ const char *hlsl_jump_type_to_string(enum hlsl_ir_jump_type type) +@@ -2146,10 +2231,11 @@ const char *hlsl_jump_type_to_string(enum hlsl_ir_jump_type type) { static const char * const names[] = { @@ -1958,7 +3508,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 }; assert(type < ARRAY_SIZE(names)); -@@ -2337,7 +2339,11 @@ const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op) +@@ -2337,7 +2423,11 @@ const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op) [HLSL_OP1_COS] = "cos", [HLSL_OP1_COS_REDUCED] = "cos_reduced", [HLSL_OP1_DSX] = "dsx", @@ -1970,7 +3520,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 [HLSL_OP1_EXP2] = "exp2", [HLSL_OP1_FRACT] = "fract", [HLSL_OP1_LOG2] = "log2", -@@ -2418,8 +2424,12 @@ static void dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_i +@@ -2418,8 +2508,12 @@ static void dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_i vkd3d_string_buffer_printf(buffer, "continue"); break; @@ -1985,7 +3535,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 break; case HLSL_IR_JUMP_RETURN: -@@ -2703,6 +2713,7 @@ static void free_ir_if(struct hlsl_ir_if *if_node) +@@ -2703,6 +2797,7 @@ static void free_ir_if(struct hlsl_ir_if *if_node) static void free_ir_jump(struct hlsl_ir_jump *jump) { @@ -1993,7 +3543,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 vkd3d_free(jump); } -@@ -3127,8 +3138,8 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) +@@ -3127,8 +3222,8 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) for (bt = 0; bt <= HLSL_TYPE_LAST_SCALAR; ++bt) { @@ -2003,7 +3553,7 @@ index ba5bcfbfaf0..4e9af15c1be 100644 switch (bt) { -@@ -3148,6 +3159,8 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) +@@ -3148,6 +3243,8 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) break; default: @@ -2013,10 +3563,18 @@ index ba5bcfbfaf0..4e9af15c1be 100644 } diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -index bce48e94b24..17ac36a57c6 100644 +index bce48e94b24..1a4b995abbf 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -@@ -502,7 +502,11 @@ enum hlsl_ir_expr_op +@@ -422,6 +422,7 @@ struct hlsl_ir_var + uint32_t is_output_semantic : 1; + uint32_t is_uniform : 1; + uint32_t is_param : 1; ++ uint32_t is_separated_resource : 1; + }; + + /* Sized array of variables representing a function's parameters. */ +@@ -502,7 +503,11 @@ enum hlsl_ir_expr_op HLSL_OP1_COS, HLSL_OP1_COS_REDUCED, /* Reduced range [-pi, pi] */ HLSL_OP1_DSX, @@ -2028,7 +3586,7 @@ index bce48e94b24..17ac36a57c6 100644 HLSL_OP1_EXP2, HLSL_OP1_FLOOR, HLSL_OP1_FRACT, -@@ -558,7 +562,8 @@ enum hlsl_ir_jump_type +@@ -558,7 +563,8 @@ enum hlsl_ir_jump_type { HLSL_IR_JUMP_BREAK, HLSL_IR_JUMP_CONTINUE, @@ -2038,7 +3596,7 @@ index bce48e94b24..17ac36a57c6 100644 HLSL_IR_JUMP_RETURN, }; -@@ -566,6 +571,8 @@ struct hlsl_ir_jump +@@ -566,6 +572,8 @@ struct hlsl_ir_jump { struct hlsl_ir_node node; enum hlsl_ir_jump_type type; @@ -2047,7 +3605,21 @@ index bce48e94b24..17ac36a57c6 100644 }; struct hlsl_ir_swizzle -@@ -803,7 +810,11 @@ struct hlsl_ctx +@@ -600,9 +608,11 @@ struct hlsl_deref + * components, within the pertaining regset), from the start of the variable, of the part + * referenced. + * The path is lowered to this single offset -- whose value may vary between SM1 and SM4 -- +- * before writing the bytecode. */ ++ * before writing the bytecode. ++ * Since the type information cannot longer be retrieved from the offset alone, the type is ++ * stored in the data_type field. */ + struct hlsl_src offset; +- enum hlsl_regset offset_regset; ++ struct hlsl_type *data_type; + }; + + struct hlsl_ir_load +@@ -803,7 +813,11 @@ struct hlsl_ctx * Only used for SM1 profiles. */ struct hlsl_constant_defs { @@ -2060,7 +3632,16 @@ index bce48e94b24..17ac36a57c6 100644 size_t count, size; } constant_defs; /* Number of temp. registers required for the shader to run, i.e. the largest temp register -@@ -1120,7 +1131,7 @@ struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *cond +@@ -1055,6 +1069,8 @@ const char *debug_hlsl_writemask(unsigned int writemask); + const char *debug_hlsl_swizzle(unsigned int swizzle, unsigned int count); + + struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const struct hlsl_type *type); ++struct vkd3d_string_buffer *hlsl_component_to_string(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var, ++ unsigned int index); + struct vkd3d_string_buffer *hlsl_modifiers_to_string(struct hlsl_ctx *ctx, unsigned int modifiers); + const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type); + +@@ -1120,7 +1136,7 @@ struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *cond struct hlsl_block *then_block, struct hlsl_block *else_block, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_int_constant(struct hlsl_ctx *ctx, int32_t n, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_jump(struct hlsl_ctx *ctx, @@ -2069,7 +3650,7 @@ index bce48e94b24..17ac36a57c6 100644 void hlsl_init_simple_deref_from_var(struct hlsl_deref *deref, struct hlsl_ir_var *var); -@@ -1132,6 +1143,8 @@ struct hlsl_ir_load *hlsl_new_load_parent(struct hlsl_ctx *ctx, const struct hls +@@ -1132,6 +1148,8 @@ struct hlsl_ir_load *hlsl_new_load_parent(struct hlsl_ctx *ctx, const struct hls const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_load_component(struct hlsl_ctx *ctx, struct hlsl_block *block, const struct hlsl_deref *deref, unsigned int comp, const struct vkd3d_shader_location *loc); @@ -2078,8 +3659,26 @@ index bce48e94b24..17ac36a57c6 100644 struct hlsl_ir_node *hlsl_new_simple_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs); struct hlsl_ir_node *hlsl_new_store_index(struct hlsl_ctx *ctx, const struct hlsl_deref *lhs, +@@ -1156,6 +1174,8 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned in + struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc); + struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *template, + struct hlsl_type *type, const struct vkd3d_shader_location *loc); ++struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const char *name, ++ struct hlsl_type *type, const struct vkd3d_shader_location *loc, bool dummy_scope); + struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, + unsigned int sample_count); + struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format); +@@ -1187,6 +1207,8 @@ unsigned int hlsl_type_component_count(const struct hlsl_type *type); + unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type, enum hlsl_regset regset); + struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl_type *type, + unsigned int index); ++unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, ++ enum hlsl_regset regset, unsigned int index); + bool hlsl_type_is_row_major(const struct hlsl_type *type); + unsigned int hlsl_type_minor_size(const struct hlsl_type *type); + unsigned int hlsl_type_major_size(const struct hlsl_type *type); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -index 0e07fe578e1..42fa2129e40 100644 +index 0e07fe578e1..6bf87f8f916 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -53,7 +53,7 @@ struct parse_initializer @@ -2113,12 +3712,14 @@ index 0e07fe578e1..42fa2129e40 100644 }; enum parse_assign_op -@@ -134,6 +138,36 @@ static struct hlsl_ir_node *node_from_list(struct list *list) - return LIST_ENTRY(list_tail(list), struct hlsl_ir_node, entry); +@@ -129,9 +133,34 @@ static void yyerror(YYLTYPE *loc, void *scanner, struct hlsl_ctx *ctx, const cha + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "%s", s); } +-static struct hlsl_ir_node *node_from_list(struct list *list) +static struct hlsl_ir_node *node_from_block(struct hlsl_block *block) -+{ + { +- return LIST_ENTRY(list_tail(list), struct hlsl_ir_node, entry); + return LIST_ENTRY(list_tail(&block->instrs), struct hlsl_ir_node, entry); +} + @@ -2145,12 +3746,10 @@ index 0e07fe578e1..42fa2129e40 100644 + if ((block = hlsl_alloc(ctx, sizeof(*block)))) + hlsl_block_init(block); + return block; -+} -+ + } + static struct list *make_empty_list(struct hlsl_ctx *ctx) - { - struct list *list; -@@ -149,6 +183,12 @@ static void destroy_instr_list(struct list *list) +@@ -149,6 +178,12 @@ static void destroy_instr_list(struct list *list) vkd3d_free(list); } @@ -2163,7 +3762,7 @@ index 0e07fe578e1..42fa2129e40 100644 static bool hlsl_types_are_componentwise_compatible(struct hlsl_ctx *ctx, struct hlsl_type *src, struct hlsl_type *dst) { -@@ -273,9 +313,6 @@ static bool implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_typ +@@ -273,9 +308,6 @@ static bool implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_typ return hlsl_types_are_componentwise_equal(ctx, src, dst); } @@ -2173,7 +3772,7 @@ index 0e07fe578e1..42fa2129e40 100644 static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) { -@@ -333,7 +370,7 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, +@@ -333,7 +365,7 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, dst_comp_type = hlsl_type_get_component_type(ctx, dst_type, dst_idx); @@ -2182,7 +3781,7 @@ index 0e07fe578e1..42fa2129e40 100644 return NULL; if (!(cast = hlsl_new_cast(ctx, component_load, dst_comp_type, loc))) -@@ -405,29 +442,29 @@ static DWORD add_modifiers(struct hlsl_ctx *ctx, DWORD modifiers, DWORD mod, +@@ -405,29 +437,29 @@ static DWORD add_modifiers(struct hlsl_ctx *ctx, DWORD modifiers, DWORD mod, return modifiers | mod; } @@ -2218,7 +3817,7 @@ index 0e07fe578e1..42fa2129e40 100644 return true; } -@@ -454,10 +491,10 @@ static bool attribute_list_has_duplicates(const struct parse_attribute_list *att +@@ -454,10 +486,10 @@ static bool attribute_list_has_duplicates(const struct parse_attribute_list *att return false; } @@ -2232,7 +3831,7 @@ index 0e07fe578e1..42fa2129e40 100644 struct hlsl_ir_node *loop; unsigned int i; -@@ -476,7 +513,7 @@ static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const +@@ -476,7 +508,7 @@ static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const } else { @@ -2241,7 +3840,7 @@ index 0e07fe578e1..42fa2129e40 100644 } } else if (!strcmp(attr->name, "loop") -@@ -491,38 +528,34 @@ static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const +@@ -491,38 +523,34 @@ static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const } } @@ -2294,7 +3893,7 @@ index 0e07fe578e1..42fa2129e40 100644 return NULL; } -@@ -539,7 +572,7 @@ static unsigned int initializer_size(const struct parse_initializer *initializer +@@ -539,7 +567,7 @@ static unsigned int initializer_size(const struct parse_initializer *initializer static void free_parse_initializer(struct parse_initializer *initializer) { @@ -2303,7 +3902,7 @@ index 0e07fe578e1..42fa2129e40 100644 vkd3d_free(initializer->args); } -@@ -625,7 +658,7 @@ static struct hlsl_ir_node *get_swizzle(struct hlsl_ctx *ctx, struct hlsl_ir_nod +@@ -625,7 +653,7 @@ static struct hlsl_ir_node *get_swizzle(struct hlsl_ctx *ctx, struct hlsl_ir_nod return NULL; } @@ -2312,7 +3911,7 @@ index 0e07fe578e1..42fa2129e40 100644 struct hlsl_ir_node *return_value, const struct vkd3d_shader_location *loc) { struct hlsl_type *return_type = ctx->cur_function->return_type; -@@ -637,7 +670,7 @@ static bool add_return(struct hlsl_ctx *ctx, struct list *instrs, +@@ -637,7 +665,7 @@ static bool add_return(struct hlsl_ctx *ctx, struct list *instrs, { struct hlsl_ir_node *store; @@ -2321,7 +3920,7 @@ index 0e07fe578e1..42fa2129e40 100644 return false; if (!(store = hlsl_new_simple_store(ctx, ctx->cur_function->return_var, return_value))) -@@ -656,14 +689,14 @@ static bool add_return(struct hlsl_ctx *ctx, struct list *instrs, +@@ -656,14 +684,14 @@ static bool add_return(struct hlsl_ctx *ctx, struct list *instrs, hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RETURN, "Void functions cannot return a value."); } @@ -2339,7 +3938,27 @@ index 0e07fe578e1..42fa2129e40 100644 unsigned int comp, const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *load, *store; -@@ -704,7 +737,7 @@ static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct +@@ -686,7 +714,7 @@ static struct hlsl_ir_node *add_load_component(struct hlsl_ctx *ctx, struct list + return load; + } + +-static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *record, ++static bool add_record_access(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *record, + unsigned int idx, const struct vkd3d_shader_location *loc) + { + struct hlsl_ir_node *index, *c; +@@ -695,16 +723,16 @@ static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct + + if (!(c = hlsl_new_uint_constant(ctx, idx, loc))) + return false; +- list_add_tail(instrs, &c->entry); ++ hlsl_block_add_instr(block, c); + + if (!(index = hlsl_new_index(ctx, record, c, loc))) + return false; +- list_add_tail(instrs, &index->entry); ++ hlsl_block_add_instr(block, index); + return true; } @@ -2348,7 +3967,7 @@ index 0e07fe578e1..42fa2129e40 100644 enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc); -@@ -830,6 +863,16 @@ static bool shader_is_sm_5_1(const struct hlsl_ctx *ctx) +@@ -830,6 +858,16 @@ static bool shader_is_sm_5_1(const struct hlsl_ctx *ctx) return ctx->profile->major_version == 5 && ctx->profile->minor_version >= 1; } @@ -2365,7 +3984,7 @@ index 0e07fe578e1..42fa2129e40 100644 static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields, struct hlsl_type *type, unsigned int modifiers, struct list *defs) { -@@ -1020,7 +1063,7 @@ static struct hlsl_reg_reservation parse_packoffset(struct hlsl_ctx *ctx, const +@@ -1020,7 +1058,7 @@ static struct hlsl_reg_reservation parse_packoffset(struct hlsl_ctx *ctx, const struct hlsl_reg_reservation reservation = {0}; char *endptr; @@ -2374,7 +3993,7 @@ index 0e07fe578e1..42fa2129e40 100644 return reservation; reservation.offset_index = strtoul(reg_string + 1, &endptr, 10); -@@ -1097,20 +1140,50 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str +@@ -1097,20 +1135,50 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str { struct hlsl_ir_constant *constant; struct hlsl_ir_node *node; @@ -2409,7 +4028,7 @@ index 0e07fe578e1..42fa2129e40 100644 + return 0; + hlsl_block_add_block(&expr, block); + -+ if (!add_implicit_conversion(ctx, &expr.instrs, node_from_list(&expr.instrs), ++ if (!add_implicit_conversion(ctx, &expr.instrs, node_from_block(&expr), hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc)) + { + hlsl_block_cleanup(&expr); @@ -2425,11 +4044,11 @@ index 0e07fe578e1..42fa2129e40 100644 } while (progress); - node = node_from_list(&block->instrs); -+ node = node_from_list(&expr.instrs); ++ node = node_from_block(&expr); if (node->type == HLSL_IR_CONSTANT) { constant = hlsl_ir_constant(node); -@@ -1119,9 +1192,11 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str +@@ -1119,9 +1187,11 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str else { hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, @@ -2442,7 +4061,7 @@ index 0e07fe578e1..42fa2129e40 100644 return ret; } -@@ -1284,7 +1359,7 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, +@@ -1284,7 +1354,7 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, { if (operands[j]) { @@ -2451,7 +4070,7 @@ index 0e07fe578e1..42fa2129e40 100644 return NULL; cell_operands[j] = load; -@@ -1334,12 +1409,12 @@ static void check_integer_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node * +@@ -1334,23 +1404,23 @@ static void check_integer_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node * } } @@ -2465,17 +4084,35 @@ index 0e07fe578e1..42fa2129e40 100644 + return add_expr(ctx, block_to_list(block), op, args, arg->data_type, loc); } - static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, -@@ -1347,7 +1422,7 @@ static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct +-static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) { check_integer_type(ctx, arg); - return add_unary_arithmetic_expr(ctx, instrs, op, arg, loc); -+ return add_unary_arithmetic_expr(ctx, list_to_block(instrs), op, arg, loc); ++ return add_unary_arithmetic_expr(ctx, block, op, arg, loc); } - static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, -@@ -1378,7 +1453,7 @@ static struct hlsl_type *get_common_numeric_type(struct hlsl_ctx *ctx, const str +-static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) + { + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; +@@ -1359,10 +1429,10 @@ static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct + bool_type = hlsl_get_numeric_type(ctx, arg->data_type->class, HLSL_TYPE_BOOL, + arg->data_type->dimx, arg->data_type->dimy); + +- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg, bool_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg, bool_type, loc))) + return NULL; + +- return add_expr(ctx, instrs, op, args, bool_type, loc); ++ return add_expr(ctx, block_to_list(block), op, args, bool_type, loc); + } + + static struct hlsl_type *get_common_numeric_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *arg1, +@@ -1378,7 +1448,7 @@ static struct hlsl_type *get_common_numeric_type(struct hlsl_ctx *ctx, const str return hlsl_get_numeric_type(ctx, type, base, dimx, dimy); } @@ -2484,7 +4121,7 @@ index 0e07fe578e1..42fa2129e40 100644 enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { -@@ -1387,24 +1462,13 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str +@@ -1387,49 +1457,26 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str common_type = get_common_numeric_type(ctx, arg1, arg2, loc); @@ -2497,8 +4134,9 @@ index 0e07fe578e1..42fa2129e40 100644 return NULL; - return add_expr(ctx, instrs, op, args, common_type, loc); --} -- ++ return add_expr(ctx, block_to_list(block), op, args, common_type, loc); + } + -static struct list *add_binary_arithmetic_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, - enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) -{ @@ -2508,11 +4146,13 @@ index 0e07fe578e1..42fa2129e40 100644 - vkd3d_free(list2); - add_binary_arithmetic_expr(ctx, list1, op, arg1, arg2, loc); - return list1; -+ return add_expr(ctx, block_to_list(block), op, args, common_type, loc); - } - - static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, -@@ -1414,19 +1478,7 @@ static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct +-} +- +-static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, + const struct vkd3d_shader_location *loc) + { check_integer_type(ctx, arg1); check_integer_type(ctx, arg2); @@ -2529,14 +4169,29 @@ index 0e07fe578e1..42fa2129e40 100644 - add_binary_bitwise_expr(ctx, list1, op, arg1, arg2, loc); - - return list1; -+ return add_binary_arithmetic_expr(ctx, list_to_block(instrs), op, arg1, arg2, loc); ++ return add_binary_arithmetic_expr(ctx, block, op, arg1, arg2, loc); } - static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct list *instrs, -@@ -1454,17 +1506,6 @@ static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, str - return add_expr(ctx, instrs, op, args, return_type, loc); - } +-static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, + const struct vkd3d_shader_location *loc) + { +@@ -1445,27 +1492,16 @@ static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, str + common_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); + return_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); +- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) + return NULL; + +- return add_expr(ctx, instrs, op, args, return_type, loc); +-} +- -static struct list *add_binary_comparison_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, - enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) -{ @@ -2546,13 +4201,28 @@ index 0e07fe578e1..42fa2129e40 100644 - vkd3d_free(list2); - add_binary_comparison_expr(ctx, list1, op, arg1, arg2, loc); - return list1; --} -- - static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, ++ return add_expr(ctx, block_to_list(block), op, args, return_type, loc); + } + +-static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) -@@ -1488,18 +1529,6 @@ static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct - return add_expr(ctx, instrs, op, args, common_type, loc); + { +@@ -1479,28 +1515,16 @@ static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct + + common_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); + +- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) + return NULL; + +- return add_expr(ctx, instrs, op, args, common_type, loc); ++ return add_expr(ctx, block_to_list(block), op, args, common_type, loc); } -static struct list *add_binary_logical_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, @@ -2567,11 +4237,25 @@ index 0e07fe578e1..42fa2129e40 100644 - return list1; -} - - static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct list *instrs, +-static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) -@@ -1531,19 +1560,7 @@ static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct l - return add_expr(ctx, instrs, op, args, return_type, loc); + { +@@ -1522,28 +1546,16 @@ static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct l + return_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); + integer_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_INT, dimx, dimy); + +- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, return_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, return_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, integer_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, integer_type, loc))) + return NULL; + +- return add_expr(ctx, instrs, op, args, return_type, loc); ++ return add_expr(ctx, block_to_list(block), op, args, return_type, loc); } -static struct list *add_binary_shift_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, @@ -2591,7 +4275,7 @@ index 0e07fe578e1..42fa2129e40 100644 struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { enum hlsl_base_type base = expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); -@@ -1557,8 +1574,7 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct lis +@@ -1557,8 +1569,7 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct lis struct vkd3d_string_buffer *string; if ((string = hlsl_type_to_string(ctx, arg1->data_type))) @@ -2601,7 +4285,7 @@ index 0e07fe578e1..42fa2129e40 100644 hlsl_release_string_buffer(ctx, string); return NULL; } -@@ -1568,8 +1584,7 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct lis +@@ -1568,8 +1579,7 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct lis struct vkd3d_string_buffer *string; if ((string = hlsl_type_to_string(ctx, arg2->data_type))) @@ -2611,7 +4295,7 @@ index 0e07fe578e1..42fa2129e40 100644 hlsl_release_string_buffer(ctx, string); return NULL; } -@@ -1589,13 +1604,60 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct lis +@@ -1589,13 +1599,60 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct lis common_type = hlsl_get_vector_type(ctx, base, dim); ret_type = hlsl_get_scalar_type(ctx, base); @@ -2627,13 +4311,13 @@ index 0e07fe578e1..42fa2129e40 100644 + return add_expr(ctx, block_to_list(instrs), op, args, ret_type, loc); +} + -+static struct list *add_binary_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, -+ enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) ++static struct hlsl_block *add_binary_expr_merge(struct hlsl_ctx *ctx, struct hlsl_block *block1, ++ struct hlsl_block *block2, enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) +{ -+ struct hlsl_ir_node *arg1 = node_from_list(list1), *arg2 = node_from_list(list2); ++ struct hlsl_ir_node *arg1 = node_from_block(block1), *arg2 = node_from_block(block2); + -+ list_move_tail(list1, list2); -+ vkd3d_free(list2); ++ hlsl_block_add_block(block1, block2); ++ destroy_block(block2); + + switch (op) + { @@ -2641,41 +4325,41 @@ index 0e07fe578e1..42fa2129e40 100644 + case HLSL_OP2_DIV: + case HLSL_OP2_MOD: + case HLSL_OP2_MUL: -+ add_binary_arithmetic_expr(ctx, list_to_block(list1), op, arg1, arg2, loc); ++ add_binary_arithmetic_expr(ctx, block1, op, arg1, arg2, loc); + break; + + case HLSL_OP2_BIT_AND: + case HLSL_OP2_BIT_OR: + case HLSL_OP2_BIT_XOR: -+ add_binary_bitwise_expr(ctx, list1, op, arg1, arg2, loc); ++ add_binary_bitwise_expr(ctx, block1, op, arg1, arg2, loc); + break; + + case HLSL_OP2_LESS: + case HLSL_OP2_GEQUAL: + case HLSL_OP2_EQUAL: + case HLSL_OP2_NEQUAL: -+ add_binary_comparison_expr(ctx, list1, op, arg1, arg2, loc); ++ add_binary_comparison_expr(ctx, block1, op, arg1, arg2, loc); + break; + + case HLSL_OP2_LOGIC_AND: + case HLSL_OP2_LOGIC_OR: -+ add_binary_logical_expr(ctx, list1, op, arg1, arg2, loc); ++ add_binary_logical_expr(ctx, block1, op, arg1, arg2, loc); + break; + + case HLSL_OP2_LSHIFT: + case HLSL_OP2_RSHIFT: -+ add_binary_shift_expr(ctx, list1, op, arg1, arg2, loc); ++ add_binary_shift_expr(ctx, block1, op, arg1, arg2, loc); + break; + + default: + vkd3d_unreachable(); + } + -+ return list1; ++ return block1; } static enum hlsl_ir_expr_op op_from_assignment(enum parse_assign_op op) -@@ -1663,7 +1725,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in +@@ -1663,7 +1720,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in if (assign_op == ASSIGN_OP_SUB) { @@ -2684,7 +4368,7 @@ index 0e07fe578e1..42fa2129e40 100644 return NULL; assign_op = ASSIGN_OP_ADD; } -@@ -1672,7 +1734,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in +@@ -1672,7 +1729,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in enum hlsl_ir_expr_op op = op_from_assignment(assign_op); assert(op); @@ -2693,7 +4377,7 @@ index 0e07fe578e1..42fa2129e40 100644 return NULL; } -@@ -1779,7 +1841,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in +@@ -1779,7 +1836,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in return NULL; list_add_tail(instrs, &cell->entry); @@ -2702,7 +4386,41 @@ index 0e07fe578e1..42fa2129e40 100644 return NULL; if (!hlsl_init_deref_from_index_chain(ctx, &deref, cell)) -@@ -1853,7 +1915,7 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem +@@ -1820,10 +1877,10 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + return copy; + } + +-static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrement, bool post, ++static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool decrement, bool post, + const struct vkd3d_shader_location *loc) + { +- struct hlsl_ir_node *lhs = node_from_list(instrs); ++ struct hlsl_ir_node *lhs = node_from_block(block); + struct hlsl_ir_node *one; + + if (lhs->data_type->modifiers & HLSL_MODIFIER_CONST) +@@ -1832,9 +1889,9 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem + + if (!(one = hlsl_new_int_constant(ctx, 1, loc))) + return false; +- list_add_tail(instrs, &one->entry); ++ hlsl_block_add_instr(block, one); + +- if (!add_assignment(ctx, instrs, lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) ++ if (!add_assignment(ctx, block_to_list(block), lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) + return false; + + if (post) +@@ -1843,7 +1900,7 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem + + if (!(copy = hlsl_new_copy(ctx, lhs))) + return false; +- list_add_tail(instrs, ©->entry); ++ hlsl_block_add_instr(block, copy); + + /* Post increment/decrement expressions are considered const. */ + if (!(copy->data_type = hlsl_type_clone(ctx, copy->data_type, 0, HLSL_MODIFIER_CONST))) +@@ -1853,7 +1910,7 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem return true; } @@ -2711,7 +4429,7 @@ index 0e07fe578e1..42fa2129e40 100644 struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src) { unsigned int src_comp_count = hlsl_type_component_count(src->data_type); -@@ -1868,17 +1930,17 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct list *instrs, +@@ -1868,17 +1925,17 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_type *dst_comp_type; struct hlsl_block block; @@ -2732,7 +4450,7 @@ index 0e07fe578e1..42fa2129e40 100644 ++*store_index; } -@@ -1924,211 +1986,234 @@ static bool type_has_numeric_components(struct hlsl_type *type) +@@ -1924,211 +1981,234 @@ static bool type_has_numeric_components(struct hlsl_type *type) return false; } @@ -3059,7 +4777,8 @@ index 0e07fe578e1..42fa2129e40 100644 + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Semantics are not allowed on local variables."); + } -+ + +- if (!hlsl_add_var(ctx, var, local)) + if ((var->storage_modifiers & HLSL_STORAGE_STATIC) && type_has_numeric_components(var->data_type) + && type_has_object_components(var->data_type, false)) + { @@ -3079,8 +4798,7 @@ index 0e07fe578e1..42fa2129e40 100644 + if (!hlsl_add_var(ctx, var, local)) + { + struct hlsl_ir_var *old = hlsl_get_var(ctx->cur_scope, var->name); - -- if (!hlsl_add_var(ctx, var, local)) ++ + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED, + "Variable \"%s\" was already declared in this scope.", var->name); + hlsl_note(ctx, &old->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously declared here.", old->name); @@ -3125,7 +4843,7 @@ index 0e07fe578e1..42fa2129e40 100644 if (v->initializer.args_count) { -@@ -2143,8 +2228,7 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t +@@ -2143,8 +2223,7 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, "Expected %u components in initializer, but got %u.", hlsl_type_component_count(type), size); @@ -3135,7 +4853,7 @@ index 0e07fe578e1..42fa2129e40 100644 continue; } -@@ -2159,16 +2243,14 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t +@@ -2159,16 +2238,14 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t struct hlsl_ir_load *load = hlsl_new_var_load(ctx, var, &var->loc); assert(v->initializer.args_count == 1); @@ -3157,7 +4875,7 @@ index 0e07fe578e1..42fa2129e40 100644 } else if (var->storage_modifiers & HLSL_STORAGE_STATIC) { -@@ -2178,32 +2260,33 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t +@@ -2178,32 +2255,33 @@ static struct list *declare_vars(struct hlsl_ctx *ctx, struct hlsl_type *basic_t if (type_has_object_components(var->data_type, false)) { @@ -3196,7 +4914,7 @@ index 0e07fe578e1..42fa2129e40 100644 vkd3d_free(var_list); return statements_list; } -@@ -2286,7 +2369,7 @@ static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, +@@ -2286,7 +2364,7 @@ static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, return arg; type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); @@ -3205,7 +4923,7 @@ index 0e07fe578e1..42fa2129e40 100644 } static bool convert_args(struct hlsl_ctx *ctx, const struct parse_initializer *params, -@@ -2298,7 +2381,7 @@ static bool convert_args(struct hlsl_ctx *ctx, const struct parse_initializer *p +@@ -2298,7 +2376,7 @@ static bool convert_args(struct hlsl_ctx *ctx, const struct parse_initializer *p { struct hlsl_ir_node *new_arg; @@ -3214,7 +4932,7 @@ index 0e07fe578e1..42fa2129e40 100644 return false; params->args[i] = new_arg; } -@@ -2394,25 +2477,25 @@ static bool intrinsic_all(struct hlsl_ctx *ctx, +@@ -2394,18 +2472,18 @@ static bool intrinsic_all(struct hlsl_ctx *ctx, if (!(one = hlsl_new_float_constant(ctx, 1.0f, loc))) return false; @@ -3236,15 +4954,7 @@ index 0e07fe578e1..42fa2129e40 100644 return false; if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, load, mul, loc))) - return false; - } - -- return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, mul, zero, loc); -+ return !!add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_NEQUAL, mul, zero, loc); - } - - static bool intrinsic_any(struct hlsl_ctx *ctx, -@@ -2431,28 +2514,28 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, +@@ -2431,7 +2509,7 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, { if (!(zero = hlsl_new_float_constant(ctx, 0.0f, loc))) return false; @@ -3253,11 +4963,7 @@ index 0e07fe578e1..42fa2129e40 100644 if (!(dot = add_binary_dot_expr(ctx, params->instrs, arg, arg, loc))) return false; - -- return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, dot, zero, loc); -+ return !!add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_NEQUAL, dot, zero, loc); - } - else if (arg->data_type->base_type == HLSL_TYPE_BOOL) +@@ -2442,14 +2520,14 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, { if (!(bfalse = hlsl_new_bool_constant(ctx, false, loc))) return false; @@ -3273,12 +4979,8 @@ index 0e07fe578e1..42fa2129e40 100644 + if (!(load = hlsl_add_load_component(ctx, block_to_list(params->instrs), arg, i, loc))) return false; -- if (!(or = add_binary_bitwise_expr(ctx, params->instrs, HLSL_OP2_BIT_OR, or, load, loc))) -+ if (!(or = add_binary_bitwise_expr(ctx, block_to_list(params->instrs), HLSL_OP2_BIT_OR, or, load, loc))) - return false; - } - -@@ -2491,7 +2574,7 @@ static bool intrinsic_asfloat(struct hlsl_ctx *ctx, + if (!(or = add_binary_bitwise_expr(ctx, params->instrs, HLSL_OP2_BIT_OR, or, load, loc))) +@@ -2491,7 +2569,7 @@ static bool intrinsic_asfloat(struct hlsl_ctx *ctx, data_type = convert_numeric_type(ctx, data_type, HLSL_TYPE_FLOAT); operands[0] = params->args[0]; @@ -3287,7 +4989,7 @@ index 0e07fe578e1..42fa2129e40 100644 } static bool intrinsic_asuint(struct hlsl_ctx *ctx, -@@ -2527,7 +2610,7 @@ static bool intrinsic_asuint(struct hlsl_ctx *ctx, +@@ -2527,7 +2605,7 @@ static bool intrinsic_asuint(struct hlsl_ctx *ctx, data_type = convert_numeric_type(ctx, data_type, HLSL_TYPE_UINT); operands[0] = params->args[0]; @@ -3296,7 +4998,7 @@ index 0e07fe578e1..42fa2129e40 100644 } static bool intrinsic_clamp(struct hlsl_ctx *ctx, -@@ -2544,6 +2627,34 @@ static bool intrinsic_clamp(struct hlsl_ctx *ctx, +@@ -2544,6 +2622,34 @@ static bool intrinsic_clamp(struct hlsl_ctx *ctx, return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MIN, max, params->args[2], loc); } @@ -3331,7 +5033,7 @@ index 0e07fe578e1..42fa2129e40 100644 static bool intrinsic_cos(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { -@@ -2571,34 +2682,34 @@ static bool intrinsic_cross(struct hlsl_ctx *ctx, +@@ -2571,34 +2677,34 @@ static bool intrinsic_cross(struct hlsl_ctx *ctx, cast_type = hlsl_get_vector_type(ctx, base, 3); @@ -3373,7 +5075,7 @@ index 0e07fe578e1..42fa2129e40 100644 if (!(mul2 = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, arg1_swzl2, arg2_swzl2, loc))) return false; -@@ -2617,6 +2728,28 @@ static bool intrinsic_ddx(struct hlsl_ctx *ctx, +@@ -2617,6 +2723,28 @@ static bool intrinsic_ddx(struct hlsl_ctx *ctx, return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_DSX, arg, loc); } @@ -3402,7 +5104,7 @@ index 0e07fe578e1..42fa2129e40 100644 static bool intrinsic_ddy(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { -@@ -2628,6 +2761,28 @@ static bool intrinsic_ddy(struct hlsl_ctx *ctx, +@@ -2628,6 +2756,28 @@ static bool intrinsic_ddy(struct hlsl_ctx *ctx, return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_DSY, arg, loc); } @@ -3431,7 +5133,7 @@ index 0e07fe578e1..42fa2129e40 100644 static bool intrinsic_distance(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { -@@ -2668,7 +2823,7 @@ static bool intrinsic_exp(struct hlsl_ctx *ctx, +@@ -2668,7 +2818,7 @@ static bool intrinsic_exp(struct hlsl_ctx *ctx, /* 1/ln(2) */ if (!(coeff = hlsl_new_float_constant(ctx, 1.442695f, loc))) return false; @@ -3440,7 +5142,7 @@ index 0e07fe578e1..42fa2129e40 100644 if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, coeff, params->args[0], loc))) return false; -@@ -2715,7 +2870,7 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer +@@ -2715,7 +2865,7 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer if (!(zero = hlsl_new_constant(ctx, div->data_type, &zero_value, loc))) return false; @@ -3449,12 +5151,8 @@ index 0e07fe578e1..42fa2129e40 100644 if (!(abs = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_ABS, div, loc))) return false; -@@ -2726,10 +2881,10 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer - if (!(neg_frac = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, frac, loc))) - return false; - -- if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, div, zero, loc))) -+ if (!(ge = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_GEQUAL, div, zero, loc))) +@@ -2729,7 +2879,7 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer + if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, div, zero, loc))) return false; - if (!(select = hlsl_add_conditional(ctx, params->instrs, ge, frac, neg_frac))) @@ -3462,7 +5160,7 @@ index 0e07fe578e1..42fa2129e40 100644 return false; return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, select, y, loc); -@@ -2806,7 +2961,7 @@ static bool intrinsic_lerp(struct hlsl_ctx *ctx, +@@ -2806,7 +2956,7 @@ static bool intrinsic_lerp(struct hlsl_ctx *ctx, } static struct hlsl_ir_node * add_pow_expr(struct hlsl_ctx *ctx, @@ -3471,7 +5169,7 @@ index 0e07fe578e1..42fa2129e40 100644 const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *log, *mul; -@@ -2861,15 +3016,15 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, +@@ -2861,15 +3011,15 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, init_value.u[3].f = 1.0f; if (!(init = hlsl_new_constant(ctx, ret_type, &init_value, loc))) return false; @@ -3490,7 +5188,7 @@ index 0e07fe578e1..42fa2129e40 100644 /* Diffuse component. */ if (!(diffuse = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MAX, n_l, zero, loc))) -@@ -2877,31 +3032,31 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, +@@ -2877,7 +3027,7 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, if (!hlsl_new_store_component(ctx, &block, &var_deref, 1, diffuse)) return false; @@ -3498,18 +5196,8 @@ index 0e07fe578e1..42fa2129e40 100644 + hlsl_block_add_block(params->instrs, &block); /* Specular component. */ -- if (!(n_h_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_h, zero, loc))) -+ if (!(n_h_neg = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, n_h, zero, loc))) - return false; - -- if (!(n_l_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_l, zero, loc))) -+ if (!(n_l_neg = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, n_l, zero, loc))) - return false; - -- if (!(specular_or = add_binary_logical_expr(ctx, params->instrs, HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) -+ if (!(specular_or = add_binary_logical_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) - return false; - + if (!(n_h_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_h, zero, loc))) +@@ -2892,16 +3042,16 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, if (!(specular_pow = add_pow_expr(ctx, params->instrs, n_h, m, loc))) return false; @@ -3529,7 +5217,7 @@ index 0e07fe578e1..42fa2129e40 100644 return true; } -@@ -3013,10 +3168,10 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, +@@ -3013,10 +3163,10 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, ret_type = hlsl_get_scalar_type(ctx, base); } @@ -3542,7 +5230,7 @@ index 0e07fe578e1..42fa2129e40 100644 return false; if (!(var = hlsl_new_synthetic_var(ctx, "mul", matrix_type, loc))) -@@ -3034,10 +3189,12 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, +@@ -3034,10 +3184,12 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, { struct hlsl_ir_node *value1, *value2, *mul; @@ -3557,7 +5245,7 @@ index 0e07fe578e1..42fa2129e40 100644 return false; if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, value1, value2, loc))) -@@ -3056,15 +3213,15 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, +@@ -3056,15 +3208,15 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, if (!hlsl_new_store_component(ctx, &block, &var_deref, j * matrix_type->dimx + i, instr)) return false; @@ -3576,7 +5264,7 @@ index 0e07fe578e1..42fa2129e40 100644 } static bool intrinsic_normalize(struct hlsl_ctx *ctx, -@@ -3169,22 +3326,22 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, +@@ -3169,14 +3321,14 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, if (!(zero = hlsl_new_constant(ctx, hlsl_get_scalar_type(ctx, arg->data_type->base_type), &zero_value, loc))) return false; @@ -3585,8 +5273,7 @@ index 0e07fe578e1..42fa2129e40 100644 /* Check if 0 < arg, cast bool to int */ -- if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, zero, arg, loc))) -+ if (!(lt = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, zero, arg, loc))) + if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, zero, arg, loc))) return false; - if (!(op1 = add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) @@ -3594,9 +5281,8 @@ index 0e07fe578e1..42fa2129e40 100644 return false; /* Check if arg < 0, cast bool to int and invert (meaning true is -1) */ - -- if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, arg, zero, loc))) -+ if (!(lt = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, arg, zero, loc))) +@@ -3184,7 +3336,7 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, + if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, arg, zero, loc))) return false; - if (!(op2 = add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) @@ -3604,7 +5290,7 @@ index 0e07fe578e1..42fa2129e40 100644 return false; if (!(neg = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, op2, loc))) -@@ -3229,7 +3386,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, +@@ -3229,7 +3381,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, if (!(one = hlsl_new_float_constant(ctx, 1.0, loc))) return false; @@ -3613,7 +5299,7 @@ index 0e07fe578e1..42fa2129e40 100644 if (!(p_denom = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_DIV, one, p_denom, loc))) return false; -@@ -3242,11 +3399,11 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, +@@ -3242,11 +3394,11 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, if (!(minus_two = hlsl_new_float_constant(ctx, -2.0, loc))) return false; @@ -3627,14 +5313,7 @@ index 0e07fe578e1..42fa2129e40 100644 if (!(res = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, minus_two, p, loc))) return false; -@@ -3283,13 +3440,13 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, - if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) - return false; - -- if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, -+ if (!(ge = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_GEQUAL, - params->args[1], params->args[0], loc))) - return false; +@@ -3289,7 +3441,7 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, type = ge->data_type; type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); @@ -3643,7 +5322,7 @@ index 0e07fe578e1..42fa2129e40 100644 } static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, -@@ -3308,7 +3465,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * +@@ -3308,7 +3460,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * if (params->args_count == 4) { @@ -3652,7 +5331,7 @@ index 0e07fe578e1..42fa2129e40 100644 } sampler_type = params->args[0]->data_type; -@@ -3324,7 +3481,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * +@@ -3324,7 +3476,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * hlsl_release_string_buffer(ctx, string); } @@ -3661,7 +5340,7 @@ index 0e07fe578e1..42fa2129e40 100644 hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, hlsl_sampler_dim_count(dim)), loc))) coords = params->args[1]; -@@ -3335,7 +3492,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * +@@ -3335,7 +3487,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * if (!(load = hlsl_new_resource_load(ctx, &load_params, loc))) return false; @@ -3670,7 +5349,7 @@ index 0e07fe578e1..42fa2129e40 100644 return true; } -@@ -3369,7 +3526,7 @@ static bool intrinsic_transpose(struct hlsl_ctx *ctx, +@@ -3369,7 +3521,7 @@ static bool intrinsic_transpose(struct hlsl_ctx *ctx, if ((string = hlsl_type_to_string(ctx, arg_type))) hlsl_error(ctx, &arg->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, @@ -3679,7 +5358,7 @@ index 0e07fe578e1..42fa2129e40 100644 string->buffer); hlsl_release_string_buffer(ctx, string); return false; -@@ -3377,7 +3534,7 @@ static bool intrinsic_transpose(struct hlsl_ctx *ctx, +@@ -3377,7 +3529,7 @@ static bool intrinsic_transpose(struct hlsl_ctx *ctx, if (arg_type->class == HLSL_CLASS_SCALAR) { @@ -3688,7 +5367,7 @@ index 0e07fe578e1..42fa2129e40 100644 return true; } -@@ -3393,18 +3550,18 @@ static bool intrinsic_transpose(struct hlsl_ctx *ctx, +@@ -3393,18 +3545,18 @@ static bool intrinsic_transpose(struct hlsl_ctx *ctx, { struct hlsl_block block; @@ -3710,7 +5389,7 @@ index 0e07fe578e1..42fa2129e40 100644 return true; } -@@ -3444,13 +3601,13 @@ static bool intrinsic_d3dcolor_to_ubyte4(struct hlsl_ctx *ctx, +@@ -3444,13 +3596,13 @@ static bool intrinsic_d3dcolor_to_ubyte4(struct hlsl_ctx *ctx, if (!(c = hlsl_new_float_constant(ctx, 255.0f + (0.5f / 256.0f), loc))) return false; @@ -3726,7 +5405,7 @@ index 0e07fe578e1..42fa2129e40 100644 arg = swizzle; } -@@ -3458,7 +3615,7 @@ static bool intrinsic_d3dcolor_to_ubyte4(struct hlsl_ctx *ctx, +@@ -3458,7 +3610,7 @@ static bool intrinsic_d3dcolor_to_ubyte4(struct hlsl_ctx *ctx, if (!(ret = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, arg, c, loc))) return false; @@ -3735,7 +5414,7 @@ index 0e07fe578e1..42fa2129e40 100644 return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_TRUNC, ret, loc); return true; -@@ -3482,10 +3639,15 @@ intrinsic_functions[] = +@@ -3482,10 +3634,15 @@ intrinsic_functions[] = {"asfloat", 1, true, intrinsic_asfloat}, {"asuint", -1, true, intrinsic_asuint}, {"clamp", 3, true, intrinsic_clamp}, @@ -3751,7 +5430,7 @@ index 0e07fe578e1..42fa2129e40 100644 {"distance", 2, true, intrinsic_distance}, {"dot", 2, true, intrinsic_dot}, {"exp", 1, true, intrinsic_exp}, -@@ -3549,7 +3711,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, +@@ -3549,7 +3706,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, { struct hlsl_ir_node *cast; @@ -3760,7 +5439,7 @@ index 0e07fe578e1..42fa2129e40 100644 goto fail; args->args[i] = cast; arg = cast; -@@ -3561,13 +3723,13 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, +@@ -3561,13 +3718,13 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, if (!(store = hlsl_new_simple_store(ctx, param, arg))) goto fail; @@ -3776,7 +5455,7 @@ index 0e07fe578e1..42fa2129e40 100644 for (i = 0; i < decl->parameters.count; ++i) { -@@ -3584,9 +3746,9 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, +@@ -3584,9 +3741,9 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, if (!(load = hlsl_new_var_load(ctx, param, &arg->loc))) goto fail; @@ -3788,7 +5467,7 @@ index 0e07fe578e1..42fa2129e40 100644 goto fail; } } -@@ -3597,7 +3759,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, +@@ -3597,7 +3754,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, if (!(load = hlsl_new_var_load(ctx, decl->return_var, loc))) goto fail; @@ -3797,7 +5476,7 @@ index 0e07fe578e1..42fa2129e40 100644 } else { -@@ -3606,7 +3768,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, +@@ -3606,7 +3763,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, if (!(expr = hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc))) goto fail; @@ -3806,7 +5485,7 @@ index 0e07fe578e1..42fa2129e40 100644 } } else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions), -@@ -3655,7 +3817,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, +@@ -3655,14 +3812,14 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, goto fail; } vkd3d_free(args->args); @@ -3815,7 +5494,15 @@ index 0e07fe578e1..42fa2129e40 100644 fail: free_parse_initializer(args); -@@ -3692,10 +3854,10 @@ static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type + return NULL; + } + +-static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, ++static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, + struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + struct hlsl_ir_load *load; +@@ -3692,7 +3849,7 @@ static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type if (!(load = hlsl_new_var_load(ctx, var, loc))) return NULL; @@ -3823,12 +5510,8 @@ index 0e07fe578e1..42fa2129e40 100644 + hlsl_block_add_instr(params->instrs, &load->node); vkd3d_free(params->args); -- return params->instrs; -+ return block_to_list(params->instrs); - } - - static unsigned int hlsl_offset_dim_count(enum hlsl_sampler_dim dim) -@@ -4272,6 +4434,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type + return params->instrs; +@@ -4272,6 +4429,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type char *name; DWORD modifiers; struct hlsl_ir_node *instr; @@ -3836,60 +5519,80 @@ index 0e07fe578e1..42fa2129e40 100644 struct list *list; struct parse_fields fields; struct parse_function function; -@@ -4404,33 +4567,23 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type - %type bitand_expr - %type bitor_expr - %type bitxor_expr +@@ -4399,38 +4557,13 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type + %token C_INTEGER + %token PRE_LINE + +-%type add_expr +-%type assignment_expr +-%type bitand_expr +-%type bitor_expr +-%type bitxor_expr -%type compound_statement - %type conditional_expr +-%type conditional_expr %type declaration %type declaration_statement -%type discard_statement - %type equality_expr +-%type equality_expr -%type expr -%type expr_optional -%type expr_statement - %type initializer_expr +-%type initializer_expr -%type jump_statement - %type logicand_expr - %type logicor_expr +-%type logicand_expr +-%type logicor_expr -%type loop_statement - %type mul_expr - %type postfix_expr +-%type mul_expr +-%type postfix_expr %type primary_expr - %type relational_expr +-%type relational_expr -%type selection_statement - %type shift_expr +-%type shift_expr -%type statement -%type statement_list -%type struct_declaration +%type struct_declaration_without_vars %type type_specs - %type unary_expr +-%type unary_expr %type variables_def -%type variables_def_optional +%type variables_def_typed %token VAR_IDENTIFIER %token NEW_IDENTIFIER -@@ -4446,6 +4599,16 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type +@@ -4446,6 +4579,31 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %type attribute_list %type attribute_list_optional ++%type add_expr ++%type assignment_expr ++%type bitand_expr ++%type bitor_expr ++%type bitxor_expr +%type compound_statement ++%type conditional_expr ++%type equality_expr +%type expr +%type expr_optional +%type expr_statement ++%type initializer_expr +%type jump_statement ++%type logicand_expr ++%type logicor_expr +%type loop_statement ++%type mul_expr ++%type postfix_expr ++%type relational_expr ++%type shift_expr +%type selection_statement +%type statement +%type statement_list ++%type unary_expr + %type boolean %type buffer_type -@@ -4493,6 +4656,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type +@@ -4493,6 +4651,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %type type_spec %type variable_decl %type variable_def @@ -3897,7 +5600,7 @@ index 0e07fe578e1..42fa2129e40 100644 %% -@@ -4561,25 +4725,19 @@ preproc_directive: +@@ -4561,25 +4720,19 @@ preproc_directive: } } @@ -3932,7 +5635,7 @@ index 0e07fe578e1..42fa2129e40 100644 } struct_spec: -@@ -4702,7 +4860,7 @@ attribute: +@@ -4702,7 +4855,7 @@ attribute: } $$->name = $2; list_init(&$$->instrs); @@ -3941,7 +5644,7 @@ index 0e07fe578e1..42fa2129e40 100644 vkd3d_free($4.instrs); $$->loc = @$; $$->args_count = $4.args_count; -@@ -4758,15 +4916,15 @@ func_declaration: +@@ -4758,15 +4911,15 @@ func_declaration: "Function \"%s\" is already defined.", decl->func->name); hlsl_note(ctx, &decl->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously defined here.", decl->func->name); @@ -3960,7 +5663,7 @@ index 0e07fe578e1..42fa2129e40 100644 /* Semantics are taken from whichever definition has a body. * We can't just replace the hlsl_ir_var pointers, though: if -@@ -4943,7 +5101,7 @@ func_prototype: +@@ -4943,7 +5096,7 @@ func_prototype: compound_statement: '{' '}' { @@ -3969,7 +5672,7 @@ index 0e07fe578e1..42fa2129e40 100644 YYABORT; } | '{' scope_start statement_list '}' -@@ -5261,7 +5419,12 @@ type_no_void: +@@ -5261,7 +5414,12 @@ type_no_void: { validate_texture_format_type(ctx, $3, &@3); @@ -3983,7 +5686,16 @@ index 0e07fe578e1..42fa2129e40 100644 $$ = hlsl_new_texture_type(ctx, $1, $3, 0); } | texture_ms_type '<' type ',' shift_expr '>' -@@ -5325,7 +5488,7 @@ type_no_void: +@@ -5270,7 +5428,7 @@ type_no_void: + struct hlsl_block block; + + hlsl_block_init(&block); +- list_move_tail(&block.instrs, $5); ++ hlsl_block_add_block(&block, $5); + + sample_count = evaluate_static_expression_as_uint(ctx, &block, &@5); + +@@ -5325,7 +5483,7 @@ type_no_void: $$ = hlsl_get_type(ctx->cur_scope, $1, true, true); if ($$->is_minimum_precision) { @@ -3992,7 +5704,7 @@ index 0e07fe578e1..42fa2129e40 100644 { hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Target profile doesn't support minimum-precision types."); -@@ -5354,7 +5517,7 @@ type: +@@ -5354,7 +5512,7 @@ type: declaration_statement: declaration @@ -4001,7 +5713,7 @@ index 0e07fe578e1..42fa2129e40 100644 | typedef { if (!($$ = make_empty_list(ctx))) -@@ -5416,23 +5579,12 @@ type_spec: +@@ -5416,23 +5574,12 @@ type_spec: } declaration: @@ -4027,7 +5739,7 @@ index 0e07fe578e1..42fa2129e40 100644 variables_def: variable_def { -@@ -5446,6 +5598,33 @@ variables_def: +@@ -5446,6 +5593,33 @@ variables_def: list_add_tail($$, &$3->entry); } @@ -4061,7 +5773,7 @@ index 0e07fe578e1..42fa2129e40 100644 variable_decl: any_identifier arrays colon_attribute { -@@ -5461,7 +5640,7 @@ state: +@@ -5461,7 +5635,7 @@ state: any_identifier '=' expr ';' { vkd3d_free($1); @@ -4070,7 +5782,7 @@ index 0e07fe578e1..42fa2129e40 100644 } state_block_start: -@@ -5487,6 +5666,38 @@ variable_def: +@@ -5487,6 +5661,38 @@ variable_def: ctx->in_state_block = 0; } @@ -4109,7 +5821,7 @@ index 0e07fe578e1..42fa2129e40 100644 arrays: %empty { -@@ -5495,17 +5706,12 @@ arrays: +@@ -5495,17 +5701,12 @@ arrays: } | '[' expr ']' arrays { @@ -4129,16 +5841,20 @@ index 0e07fe578e1..42fa2129e40 100644 $$ = $4; -@@ -5622,7 +5828,7 @@ complex_initializer: +@@ -5618,10 +5819,10 @@ complex_initializer: + $$.args_count = 1; + if (!($$.args = hlsl_alloc(ctx, sizeof(*$$.args)))) + { +- destroy_instr_list($1); ++ destroy_block($1); YYABORT; } - $$.args[0] = node_from_list($1); -- $$.instrs = $1; -+ $$.instrs = list_to_block($1); +- $$.args[0] = node_from_list($1); ++ $$.args[0] = node_from_block($1); + $$.instrs = $1; $$.braces = false; } - | '{' complex_initializer_list '}' -@@ -5653,7 +5859,7 @@ complex_initializer_list: +@@ -5653,7 +5854,7 @@ complex_initializer_list: $$.args = new_args; for (i = 0; i < $3.args_count; ++i) $$.args[$$.args_count++] = $3.args[i]; @@ -4147,25 +5863,38 @@ index 0e07fe578e1..42fa2129e40 100644 free_parse_initializer(&$3); } -@@ -5670,7 +5876,7 @@ initializer_expr_list: +@@ -5666,10 +5867,10 @@ initializer_expr_list: + $$.args_count = 1; + if (!($$.args = hlsl_alloc(ctx, sizeof(*$$.args)))) + { +- destroy_instr_list($1); ++ destroy_block($1); YYABORT; } - $$.args[0] = node_from_list($1); -- $$.instrs = $1; -+ $$.instrs = list_to_block($1); +- $$.args[0] = node_from_list($1); ++ $$.args[0] = node_from_block($1); + $$.instrs = $1; $$.braces = false; } - | initializer_expr_list ',' initializer_expr -@@ -5686,7 +5892,7 @@ initializer_expr_list: +@@ -5681,13 +5882,13 @@ initializer_expr_list: + if (!(new_args = hlsl_realloc(ctx, $$.args, ($$.args_count + 1) * sizeof(*$$.args)))) + { + free_parse_initializer(&$$); +- destroy_instr_list($3); ++ destroy_block($3); + YYABORT; } $$.args = new_args; - $$.args[$$.args_count++] = node_from_list($3); +- $$.args[$$.args_count++] = node_from_list($3); - list_move_tail($$.instrs, $3); -+ list_move_tail(&$$.instrs->instrs, $3); - vkd3d_free($3); +- vkd3d_free($3); ++ $$.args[$$.args_count++] = node_from_block($3); ++ hlsl_block_add_block($$.instrs, $3); ++ destroy_block($3); } -@@ -5705,15 +5911,17 @@ statement_list: + boolean: +@@ -5705,15 +5906,17 @@ statement_list: | statement_list statement { $$ = $1; @@ -4186,7 +5915,7 @@ index 0e07fe578e1..42fa2129e40 100644 | jump_statement | selection_statement | loop_statement -@@ -5721,47 +5929,47 @@ statement: +@@ -5721,47 +5924,47 @@ statement: jump_statement: KW_RETURN expr ';' { @@ -4255,7 +5984,7 @@ index 0e07fe578e1..42fa2129e40 100644 if (condition->data_type->dimx > 1 || condition->data_type->dimy > 1) { struct vkd3d_string_buffer *string; -@@ -5772,7 +5980,7 @@ selection_statement: +@@ -5772,7 +5975,7 @@ selection_statement: hlsl_release_string_buffer(ctx, string); } $$ = $3; @@ -4264,7 +5993,7 @@ index 0e07fe578e1..42fa2129e40 100644 } if_body: -@@ -5803,14 +6011,14 @@ loop_statement: +@@ -5803,14 +6006,14 @@ loop_statement: } | attribute_list_optional KW_FOR '(' scope_start declaration expr_statement expr_optional ')' statement { @@ -4281,7 +6010,7 @@ index 0e07fe578e1..42fa2129e40 100644 YYABORT; } | expr -@@ -5826,7 +6034,7 @@ func_arguments: +@@ -5826,7 +6029,7 @@ func_arguments: { $$.args = NULL; $$.args_count = 0; @@ -4290,7 +6019,7 @@ index 0e07fe578e1..42fa2129e40 100644 YYABORT; $$.braces = false; } -@@ -5880,7 +6088,7 @@ primary_expr: +@@ -5880,7 +6083,7 @@ primary_expr: } | '(' expr ')' { @@ -4299,39 +6028,150 @@ index 0e07fe578e1..42fa2129e40 100644 } | var_identifier '(' func_arguments ')' { -@@ -5974,10 +6182,10 @@ postfix_expr: +@@ -5915,11 +6118,14 @@ primary_expr: + + postfix_expr: + primary_expr ++ { ++ $$ = list_to_block($1); ++ } + | postfix_expr OP_INC + { + if (!add_increment(ctx, $1, false, true, &@2)) + { +- destroy_instr_list($1); ++ destroy_block($1); + YYABORT; + } + $$ = $1; +@@ -5928,14 +6134,14 @@ postfix_expr: + { + if (!add_increment(ctx, $1, true, true, &@2)) + { +- destroy_instr_list($1); ++ destroy_block($1); + YYABORT; + } + $$ = $1; + } + | postfix_expr '.' any_identifier + { +- struct hlsl_ir_node *node = node_from_list($1); ++ struct hlsl_ir_node *node = node_from_block($1); + + if (node->data_type->class == HLSL_CLASS_STRUCT) + { +@@ -5963,7 +6169,7 @@ postfix_expr: + hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Invalid swizzle \"%s\".", $3); + YYABORT; + } +- list_add_tail($1, &swizzle->entry); ++ hlsl_block_add_instr($1, swizzle); + $$ = $1; + } + else +@@ -5974,17 +6180,17 @@ postfix_expr: } | postfix_expr '[' expr ']' { - struct hlsl_ir_node *array = node_from_list($1), *index = node_from_list($3); -+ struct hlsl_ir_node *array = node_from_list($1), *index = node_from_block($3); ++ struct hlsl_ir_node *array = node_from_block($1), *index = node_from_block($3); - list_move_head($1, $3); - vkd3d_free($3); -+ list_move_head($1, &$3->instrs); -+ destroy_block($3); ++ hlsl_block_add_block($3, $1); ++ destroy_block($1); - if (!add_array_access(ctx, $1, array, index, &@2)) +- if (!add_array_access(ctx, $1, array, index, &@2)) ++ if (!add_array_access(ctx, block_to_list($3), array, index, &@2)) { -@@ -6027,7 +6235,7 @@ postfix_expr: +- destroy_instr_list($1); ++ destroy_block($3); + YYABORT; + } +- $$ = $1; ++ $$ = $3; + } + + /* var_modifiers is necessary to avoid shift/reduce conflicts. */ +@@ -6025,14 +6231,14 @@ postfix_expr: + } + | postfix_expr '.' any_identifier '(' func_arguments ')' { - struct hlsl_ir_node *object = node_from_list($1); +- struct hlsl_ir_node *object = node_from_list($1); ++ struct hlsl_ir_node *object = node_from_block($1); - list_move_tail($1, $5.instrs); -+ list_move_tail($1, &$5.instrs->instrs); ++ hlsl_block_add_block($1, $5.instrs); vkd3d_free($5.instrs); - if (!add_method_call(ctx, $1, object, $3, &$5, &@3)) -@@ -6066,7 +6274,7 @@ unary_expr: +- if (!add_method_call(ctx, $1, object, $3, &$5, &@3)) ++ if (!add_method_call(ctx, block_to_list($1), object, $3, &$5, &@3)) + { +- hlsl_free_instr_list($1); ++ destroy_block($1); + vkd3d_free($5.args); + YYABORT; + } +@@ -6046,7 +6252,7 @@ unary_expr: + { + if (!add_increment(ctx, $2, false, false, &@1)) + { +- destroy_instr_list($2); ++ destroy_block($2); + YYABORT; + } + $$ = $2; +@@ -6055,7 +6261,7 @@ unary_expr: + { + if (!add_increment(ctx, $2, true, false, &@1)) + { +- destroy_instr_list($2); ++ destroy_block($2); + YYABORT; + } + $$ = $2; +@@ -6066,23 +6272,23 @@ unary_expr: } | '-' unary_expr { - add_unary_arithmetic_expr(ctx, $2, HLSL_OP1_NEG, node_from_list($2), &@1); -+ add_unary_arithmetic_expr(ctx, list_to_block($2), HLSL_OP1_NEG, node_from_list($2), &@1); ++ add_unary_arithmetic_expr(ctx, $2, HLSL_OP1_NEG, node_from_block($2), &@1); $$ = $2; } | '~' unary_expr -@@ -6130,119 +6338,118 @@ mul_expr: + { +- add_unary_bitwise_expr(ctx, $2, HLSL_OP1_BIT_NOT, node_from_list($2), &@1); ++ add_unary_bitwise_expr(ctx, $2, HLSL_OP1_BIT_NOT, node_from_block($2), &@1); + $$ = $2; + } + | '!' unary_expr + { +- add_unary_logical_expr(ctx, $2, HLSL_OP1_LOGIC_NOT, node_from_list($2), &@1); ++ add_unary_logical_expr(ctx, $2, HLSL_OP1_LOGIC_NOT, node_from_block($2), &@1); + $$ = $2; + } + /* var_modifiers is necessary to avoid shift/reduce conflicts. */ + | '(' var_modifiers type arrays ')' unary_expr + { +- struct hlsl_type *src_type = node_from_list($6)->data_type; ++ struct hlsl_type *src_type = node_from_block($6)->data_type; + struct hlsl_type *dst_type; + unsigned int i; + +@@ -6118,9 +6324,9 @@ unary_expr: + YYABORT; + } + +- if (!add_cast(ctx, $6, node_from_list($6), dst_type, &@3)) ++ if (!add_cast(ctx, block_to_list($6), node_from_block($6), dst_type, &@3)) + { +- hlsl_free_instr_list($6); ++ destroy_block($6); + YYABORT; + } + $$ = $6; +@@ -6130,131 +6336,132 @@ mul_expr: unary_expr | mul_expr '*' unary_expr { @@ -4361,7 +6201,7 @@ index 0e07fe578e1..42fa2129e40 100644 struct hlsl_ir_node *neg; - if (!(neg = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, node_from_list($3), &@2))) -+ if (!(neg = add_unary_arithmetic_expr(ctx, list_to_block($3), HLSL_OP1_NEG, node_from_list($3), &@2))) ++ if (!(neg = add_unary_arithmetic_expr(ctx, $3, HLSL_OP1_NEG, node_from_block($3), &@2))) YYABORT; - list_add_tail($3, &neg->entry); - $$ = add_binary_arithmetic_expr_merge(ctx, $1, $3, HLSL_OP2_ADD, &@2); @@ -4462,36 +6302,106 @@ index 0e07fe578e1..42fa2129e40 100644 | logicor_expr '?' expr ':' assignment_expr { - struct hlsl_ir_node *cond = node_from_list($1), *first = node_from_list($3), *second = node_from_list($5); -+ struct hlsl_ir_node *cond = node_from_list($1), *first = node_from_block($3), *second = node_from_list($5); ++ struct hlsl_ir_node *cond = node_from_block($1); ++ struct hlsl_ir_node *first = node_from_block($3); ++ struct hlsl_ir_node *second = node_from_block($5); struct hlsl_type *common_type; - list_move_tail($1, $3); -+ list_move_tail($1, &$3->instrs); - list_move_tail($1, $5); +- list_move_tail($1, $5); - vkd3d_free($3); +- vkd3d_free($5); ++ hlsl_block_add_block($1, $3); ++ hlsl_block_add_block($1, $5); + destroy_block($3); - vkd3d_free($5); ++ destroy_block($5); if (!(common_type = get_common_numeric_type(ctx, first, second, &@3))) -@@ -6326,9 +6533,12 @@ assign_op: + YYABORT; - expr: - assignment_expr -+ { -+ $$ = list_to_block($1); -+ } +- if (!(first = add_implicit_conversion(ctx, $1, first, common_type, &@3))) ++ if (!(first = add_implicit_conversion(ctx, block_to_list($1), first, common_type, &@3))) + YYABORT; + +- if (!(second = add_implicit_conversion(ctx, $1, second, common_type, &@5))) ++ if (!(second = add_implicit_conversion(ctx, block_to_list($1), second, common_type, &@5))) + YYABORT; + +- if (!hlsl_add_conditional(ctx, $1, cond, first, second)) ++ if (!hlsl_add_conditional(ctx, block_to_list($1), cond, first, second)) + YYABORT; + $$ = $1; + } +@@ -6264,16 +6471,16 @@ assignment_expr: + conditional_expr + | unary_expr assign_op assignment_expr + { +- struct hlsl_ir_node *lhs = node_from_list($1), *rhs = node_from_list($3); ++ struct hlsl_ir_node *lhs = node_from_block($1), *rhs = node_from_block($3); + + if (lhs->data_type->modifiers & HLSL_MODIFIER_CONST) + { + hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_MODIFIES_CONST, "Statement modifies a const expression."); + YYABORT; + } +- list_move_tail($3, $1); +- vkd3d_free($1); +- if (!add_assignment(ctx, $3, lhs, $2, rhs)) ++ hlsl_block_add_block($3, $1); ++ destroy_block($1); ++ if (!add_assignment(ctx, block_to_list($3), lhs, $2, rhs)) + YYABORT; + $$ = $3; + } +@@ -6329,6 +6536,6 @@ expr: | expr ',' assignment_expr { $$ = $1; - list_move_tail($$, $3); -+ list_move_tail(&$$->instrs, $3); - vkd3d_free($3); +- vkd3d_free($3); ++ hlsl_block_add_block($$, $3); ++ destroy_block($3); } diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -index 765b1907426..8927e291183 100644 +index 765b1907426..09a3ea4ca08 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -@@ -666,7 +666,7 @@ static void insert_early_return_break(struct hlsl_ctx *ctx, +@@ -97,6 +97,7 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str + static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, struct hlsl_block *block, + const struct hlsl_deref *deref, const struct vkd3d_shader_location *loc) + { ++ enum hlsl_regset regset = hlsl_type_get_regset(deref->data_type); + struct hlsl_ir_node *offset = NULL; + struct hlsl_type *type; + unsigned int i; +@@ -111,7 +112,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st + struct hlsl_block idx_block; + + if (!(offset = new_offset_from_path_index(ctx, &idx_block, type, offset, deref->path[i].node, +- deref->offset_regset, loc))) ++ regset, loc))) + return NULL; + + hlsl_block_add_block(block, &idx_block); +@@ -126,7 +127,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st + static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_deref *deref, + struct hlsl_ir_node *instr) + { +- const struct hlsl_type *type; ++ struct hlsl_type *type; + struct hlsl_ir_node *offset; + struct hlsl_block block; + +@@ -145,7 +146,7 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der + return true; + } + +- deref->offset_regset = hlsl_type_get_regset(type); ++ deref->data_type = type; + + if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &instr->loc))) + return false; +@@ -666,7 +667,7 @@ static void insert_early_return_break(struct hlsl_ctx *ctx, return; list_add_after(&cf_instr->entry, &load->node.entry); @@ -4500,7 +6410,34 @@ index 765b1907426..8927e291183 100644 return; hlsl_block_add_instr(&then_block, jump); -@@ -1889,7 +1889,7 @@ static bool split_matrix_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr +@@ -1689,7 +1690,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ + { + struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr); + +- if (!(load->resource.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) ++ if (!load->resource.var->is_uniform) + { + hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, + "Loaded resource must have a single uniform source."); +@@ -1704,7 +1705,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ + + if (load->sampler.var) + { +- if (!(load->sampler.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) ++ if (!load->sampler.var->is_uniform) + { + hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, + "Resource load sampler must have a single uniform source."); +@@ -1722,7 +1723,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ + { + struct hlsl_ir_resource_store *store = hlsl_ir_resource_store(instr); + +- if (!(store->resource.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) ++ if (!store->resource.var->is_uniform) + { + hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, + "Accessed resource must have a single uniform source."); +@@ -1889,7 +1890,7 @@ static bool split_matrix_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr if (rhs->type != HLSL_IR_LOAD) { @@ -4509,7 +6446,105 @@ index 765b1907426..8927e291183 100644 return false; } -@@ -2584,6 +2584,61 @@ static bool lower_float_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr +@@ -2066,6 +2067,97 @@ static bool lower_nonconstant_vector_derefs(struct hlsl_ctx *ctx, struct hlsl_ir + return false; + } + ++/* Lower combined samples and sampler variables to synthesized separated textures and samplers. ++ * That is, translate SM1-style samples in the source to SM4-style samples in the bytecode. */ ++static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++{ ++ struct hlsl_ir_resource_load *load; ++ struct vkd3d_string_buffer *name; ++ struct hlsl_ir_var *var; ++ unsigned int i; ++ ++ if (instr->type != HLSL_IR_RESOURCE_LOAD) ++ return false; ++ load = hlsl_ir_resource_load(instr); ++ ++ switch (load->load_type) ++ { ++ case HLSL_RESOURCE_LOAD: ++ case HLSL_RESOURCE_GATHER_RED: ++ case HLSL_RESOURCE_GATHER_GREEN: ++ case HLSL_RESOURCE_GATHER_BLUE: ++ case HLSL_RESOURCE_GATHER_ALPHA: ++ case HLSL_RESOURCE_SAMPLE_CMP: ++ case HLSL_RESOURCE_SAMPLE_CMP_LZ: ++ case HLSL_RESOURCE_SAMPLE_GRAD: ++ return false; ++ ++ case HLSL_RESOURCE_SAMPLE: ++ case HLSL_RESOURCE_SAMPLE_LOD: ++ case HLSL_RESOURCE_SAMPLE_LOD_BIAS: ++ break; ++ } ++ if (load->sampler.var) ++ return false; ++ ++ if (!hlsl_type_is_resource(load->resource.var->data_type)) ++ { ++ hlsl_fixme(ctx, &instr->loc, "Lower combined samplers within structs."); ++ return false; ++ } ++ ++ assert(hlsl_type_get_regset(load->resource.var->data_type) == HLSL_REGSET_SAMPLERS); ++ ++ if (!(name = hlsl_get_string_buffer(ctx))) ++ return false; ++ vkd3d_string_buffer_printf(name, "%s", load->resource.var->name); ++ ++ TRACE("Lowering to separate resource %s.\n", debugstr_a(name->buffer)); ++ ++ if (!(var = hlsl_get_var(ctx->globals, name->buffer))) ++ { ++ struct hlsl_type *texture_array_type = hlsl_new_texture_type(ctx, load->sampling_dim, ++ hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4), 0); ++ ++ /* Create (possibly multi-dimensional) texture array type with the same dims as the sampler array. */ ++ struct hlsl_type *arr_type = load->resource.var->data_type; ++ for (i = 0; i < load->resource.path_len; ++i) ++ { ++ assert(arr_type->class == HLSL_CLASS_ARRAY); ++ texture_array_type = hlsl_new_array_type(ctx, texture_array_type, arr_type->e.array.elements_count); ++ arr_type = arr_type->e.array.type; ++ } ++ ++ if (!(var = hlsl_new_synthetic_var_named(ctx, name->buffer, texture_array_type, &instr->loc, false))) ++ { ++ hlsl_release_string_buffer(ctx, name); ++ return false; ++ } ++ var->is_uniform = 1; ++ var->is_separated_resource = true; ++ ++ list_add_tail(&ctx->extern_vars, &var->extern_entry); ++ } ++ hlsl_release_string_buffer(ctx, name); ++ ++ if (load->sampling_dim != var->data_type->sampler_dim) ++ { ++ hlsl_error(ctx, &load->node.loc, VKD3D_SHADER_ERROR_HLSL_INCONSISTENT_SAMPLER, ++ "Cannot split combined samplers from \"%s\" if they have different usage dimensions.", ++ load->resource.var->name); ++ hlsl_note(ctx, &var->loc, VKD3D_SHADER_LOG_ERROR, "First use as combined sampler is here."); ++ return false; ++ ++ } ++ ++ hlsl_copy_deref(ctx, &load->sampler, &load->resource); ++ load->resource.var = var; ++ assert(hlsl_deref_get_type(ctx, &load->resource)->base_type == HLSL_TYPE_TEXTURE); ++ assert(hlsl_deref_get_type(ctx, &load->sampler)->base_type == HLSL_TYPE_SAMPLER); ++ ++ return true; ++} ++ + /* Lower DIV to RCP + MUL. */ + static bool lower_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) + { +@@ -2584,6 +2676,61 @@ static bool lower_float_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr return true; } @@ -4571,7 +6606,7 @@ index 765b1907426..8927e291183 100644 static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { switch (instr->type) -@@ -2848,8 +2903,15 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop +@@ -2848,8 +2995,15 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop index->idx.node->last_read = last_read; break; } @@ -4588,7 +6623,103 @@ index 765b1907426..8927e291183 100644 break; } } -@@ -3192,10 +3254,33 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, +@@ -3034,7 +3188,7 @@ static const char *debug_register(char class, struct hlsl_reg reg, const struct + return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask)); + } + +-static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++static bool track_object_components_sampler_dim(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) + { + struct hlsl_ir_resource_load *load; + struct hlsl_ir_var *var; +@@ -3046,15 +3200,16 @@ static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_n + + load = hlsl_ir_resource_load(instr); + var = load->resource.var; ++ + regset = hlsl_type_get_regset(hlsl_deref_get_type(ctx, &load->resource)); ++ if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) ++ return false; + + if (regset == HLSL_REGSET_SAMPLERS) + { + enum hlsl_sampler_dim dim; + + assert(!load->sampler.var); +- if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) +- return false; + + dim = var->objects_usage[regset][index].sampler_dim; + if (dim != load->sampling_dim) +@@ -3072,25 +3227,37 @@ static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_n + return false; + } + } +- var->objects_usage[regset][index].used = true; +- var->objects_usage[regset][index].sampler_dim = load->sampling_dim; + } +- else +- { +- if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) +- return false; ++ var->objects_usage[regset][index].sampler_dim = load->sampling_dim; + +- var->objects_usage[regset][index].used = true; +- var->objects_usage[regset][index].sampler_dim = load->sampling_dim; ++ return false; ++} + +- if (load->sampler.var) +- { +- var = load->sampler.var; +- if (!hlsl_regset_index_from_deref(ctx, &load->sampler, HLSL_REGSET_SAMPLERS, &index)) +- return false; ++static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++{ ++ struct hlsl_ir_resource_load *load; ++ struct hlsl_ir_var *var; ++ enum hlsl_regset regset; ++ unsigned int index; + +- var->objects_usage[HLSL_REGSET_SAMPLERS][index].used = true; +- } ++ if (instr->type != HLSL_IR_RESOURCE_LOAD) ++ return false; ++ ++ load = hlsl_ir_resource_load(instr); ++ var = load->resource.var; ++ ++ regset = hlsl_type_get_regset(hlsl_deref_get_type(ctx, &load->resource)); ++ if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) ++ return false; ++ ++ var->objects_usage[regset][index].used = true; ++ if (load->sampler.var) ++ { ++ var = load->sampler.var; ++ if (!hlsl_regset_index_from_deref(ctx, &load->sampler, HLSL_REGSET_SAMPLERS, &index)) ++ return false; ++ ++ var->objects_usage[HLSL_REGSET_SAMPLERS][index].used = true; + } + + return false; +@@ -3110,9 +3277,12 @@ static void calculate_resource_register_counts(struct hlsl_ctx *ctx) + { + for (i = 0; i < type->reg_size[k]; ++i) + { +- /* Samplers are only allocated until the last used one. */ ++ bool is_separated = var->is_separated_resource; ++ ++ /* Samplers (and textures separated from them) are only allocated until the last ++ * used one. */ + if (var->objects_usage[k][i].used) +- var->regs[k].bind_count = (k == HLSL_REGSET_SAMPLERS) ? i + 1 : type->reg_size[k]; ++ var->regs[k].bind_count = (k == HLSL_REGSET_SAMPLERS || is_separated) ? i + 1 : type->reg_size[k]; + } + } + } +@@ -3192,10 +3362,33 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, } } @@ -4623,7 +6754,7 @@ index 765b1907426..8927e291183 100644 struct hlsl_ir_node *instr; LIST_FOR_EACH_ENTRY(instr, &block->instrs, struct hlsl_ir_node, entry) -@@ -3206,66 +3291,52 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, +@@ -3206,66 +3399,52 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, { struct hlsl_ir_constant *constant = hlsl_ir_constant(instr); const struct hlsl_type *type = instr->data_type; @@ -4727,7 +6858,7 @@ index 765b1907426..8927e291183 100644 } break; -@@ -3297,8 +3368,6 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functi +@@ -3297,8 +3476,6 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functi struct register_allocator allocator = {0}; struct hlsl_ir_var *var; @@ -4736,7 +6867,7 @@ index 765b1907426..8927e291183 100644 LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { if (var->is_uniform && var->last_read) -@@ -3315,6 +3384,8 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functi +@@ -3315,6 +3492,8 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functi } } @@ -4745,7 +6876,111 @@ index 765b1907426..8927e291183 100644 vkd3d_free(allocator.allocations); } -@@ -4062,6 +4133,10 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry +@@ -3497,7 +3676,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) + + LIST_FOR_EACH_ENTRY(var1, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +- if (!var1->is_uniform || var1->data_type->class == HLSL_CLASS_OBJECT) ++ if (!var1->is_uniform || hlsl_type_is_resource(var1->data_type)) + continue; + + buffer = var1->buffer; +@@ -3508,7 +3687,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) + { + unsigned int var1_reg_size, var2_reg_size; + +- if (!var2->is_uniform || var2->data_type->class == HLSL_CLASS_OBJECT) ++ if (!var2->is_uniform || hlsl_type_is_resource(var2->data_type)) + continue; + + if (var1 == var2 || var1->buffer != var2->buffer) +@@ -3558,7 +3737,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx) + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +- if (var->is_uniform && var->data_type->class != HLSL_CLASS_OBJECT) ++ if (var->is_uniform && !hlsl_type_is_resource(var->data_type)) + { + if (var->is_param) + var->buffer = ctx->params_buffer; +@@ -3618,7 +3797,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx) + } + + static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum hlsl_regset regset, +- uint32_t index) ++ uint32_t index, bool allocated_only) + { + const struct hlsl_ir_var *var; + unsigned int start, count; +@@ -3632,6 +3811,9 @@ static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum + * bound there even if the reserved vars aren't used. */ + start = var->reg_reservation.reg_index; + count = var->data_type->reg_size[regset]; ++ ++ if (!var->regs[regset].allocated && allocated_only) ++ continue; + } + else if (var->regs[regset].allocated) + { +@@ -3672,6 +3854,7 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) + if (count == 0) + continue; + ++ /* The variable was already allocated if it has a reservation. */ + if (var->regs[regset].allocated) + { + const struct hlsl_ir_var *reserved_object, *last_reported = NULL; +@@ -3690,7 +3873,10 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) + { + index = var->regs[regset].id + i; + +- reserved_object = get_allocated_object(ctx, regset, index); ++ /* get_allocated_object() may return "var" itself, but we ++ * actually want that, otherwise we'll end up reporting the ++ * same conflict between the same two variables twice. */ ++ reserved_object = get_allocated_object(ctx, regset, index, true); + if (reserved_object && reserved_object != var && reserved_object != last_reported) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS, +@@ -3709,7 +3895,7 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) + + while (available < count) + { +- if (get_allocated_object(ctx, regset, index)) ++ if (get_allocated_object(ctx, regset, index, false)) + available = 0; + else + ++available; +@@ -3853,6 +4039,7 @@ bool hlsl_regset_index_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref + bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, unsigned int *offset) + { + struct hlsl_ir_node *offset_node = deref->offset.node; ++ enum hlsl_regset regset; + unsigned int size; + + if (!offset_node) +@@ -3869,8 +4056,9 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref + return false; + + *offset = hlsl_ir_constant(offset_node)->value.u[0].u; ++ regset = hlsl_type_get_regset(deref->data_type); + +- size = deref->var->data_type->reg_size[deref->offset_regset]; ++ size = deref->var->data_type->reg_size[regset]; + if (*offset >= size) + { + hlsl_error(ctx, &deref->offset.node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS, +@@ -3900,7 +4088,8 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere + struct hlsl_reg ret = var->regs[HLSL_REGSET_NUMERIC]; + unsigned int offset = hlsl_offset_from_deref_safe(ctx, deref); + +- assert(deref->offset_regset == HLSL_REGSET_NUMERIC); ++ assert(deref->data_type); ++ assert(deref->data_type->class <= HLSL_CLASS_LAST_NUMERIC); + + ret.id += offset / 4; + +@@ -4062,6 +4251,10 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, "Entry point \"%s\" is missing a [numthreads] attribute.", entry_func->func->name); @@ -4756,6 +6991,29 @@ index 765b1907426..8927e291183 100644 hlsl_transform_ir(ctx, lower_broadcasts, body, NULL); while (hlsl_transform_ir(ctx, fold_redundant_casts, body, NULL)); do +@@ -4094,6 +4287,12 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + hlsl_transform_ir(ctx, lower_casts_to_bool, body, NULL); + hlsl_transform_ir(ctx, lower_int_dot, body, NULL); + ++ hlsl_transform_ir(ctx, validate_static_object_references, body, NULL); ++ hlsl_transform_ir(ctx, track_object_components_sampler_dim, body, NULL); ++ if (profile->major_version >= 4) ++ hlsl_transform_ir(ctx, lower_combined_samples, body, NULL); ++ hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); ++ + if (profile->major_version < 4) + { + hlsl_transform_ir(ctx, lower_division, body, NULL); +@@ -4107,9 +4306,6 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + hlsl_transform_ir(ctx, lower_abs, body, NULL); + } + +- hlsl_transform_ir(ctx, validate_static_object_references, body, NULL); +- hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); +- + /* TODO: move forward, remove when no longer needed */ + transform_derefs(ctx, replace_deref_path_with_offset, body); + while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL)); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c index 301113c8477..01c438ae212 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c @@ -5318,7 +7576,7 @@ index 301113c8477..01c438ae212 100644 default: diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c -index 3542b5fac51..5535a6503d6 100644 +index 3542b5fac51..9725a5c7e25 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -3217,7 +3217,7 @@ static bool spirv_compiler_get_register_info(const struct spirv_compiler *compil @@ -5330,7 +7588,19 @@ index 3542b5fac51..5535a6503d6 100644 register_info->descriptor_array = NULL; register_info->member_idx = 0; register_info->component_type = VKD3D_SHADER_COMPONENT_FLOAT; -@@ -5258,8 +5258,7 @@ static void spirv_compiler_emit_dcl_global_flags(struct spirv_compiler *compiler +@@ -3998,6 +3998,11 @@ static void spirv_compiler_emit_interpolation_decorations(struct spirv_compiler + vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading); + vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationSample, NULL, 0); + break; ++ case VKD3DSIM_LINEAR_NOPERSPECTIVE_SAMPLE: ++ vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationNoPerspective, NULL, 0); ++ vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading); ++ vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationSample, NULL, 0); ++ break; + default: + FIXME("Unhandled interpolation mode %#x.\n", mode); + break; +@@ -5258,8 +5263,7 @@ static void spirv_compiler_emit_dcl_global_flags(struct spirv_compiler *compiler WARN("Unhandled global flags %#x.\n", flags); } @@ -5340,7 +7610,7 @@ index 3542b5fac51..5535a6503d6 100644 { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; size_t function_location; -@@ -5270,11 +5269,11 @@ static void spirv_compiler_emit_dcl_temps(struct spirv_compiler *compiler, +@@ -5270,11 +5274,11 @@ static void spirv_compiler_emit_dcl_temps(struct spirv_compiler *compiler, vkd3d_spirv_begin_function_stream_insertion(builder, function_location); assert(!compiler->temp_count); @@ -5355,7 +7625,7 @@ index 3542b5fac51..5535a6503d6 100644 if (!i) compiler->temp_id = id; assert(id == compiler->temp_id + i); -@@ -6236,9 +6235,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) +@@ -6236,9 +6240,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) vkd3d_spirv_build_op_function_end(builder); @@ -5365,7 +7635,7 @@ index 3542b5fac51..5535a6503d6 100644 if (is_in_control_point_phase(compiler)) { if (compiler->epilogue_function_id) -@@ -9103,9 +9099,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, +@@ -9103,9 +9104,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_GLOBAL_FLAGS: spirv_compiler_emit_dcl_global_flags(compiler, instruction); break; @@ -5375,7 +7645,7 @@ index 3542b5fac51..5535a6503d6 100644 case VKD3DSIH_DCL_INDEXABLE_TEMP: spirv_compiler_emit_dcl_indexable_temp(compiler, instruction); break; -@@ -9426,6 +9419,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, +@@ -9426,6 +9424,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, spirv_compiler_emit_cut_stream(compiler, instruction); break; case VKD3DSIH_DCL_HS_MAX_TESSFACTOR: @@ -5383,7 +7653,7 @@ index 3542b5fac51..5535a6503d6 100644 case VKD3DSIH_HS_DECLS: case VKD3DSIH_NOP: /* nothing to do */ -@@ -9448,6 +9442,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, +@@ -9448,6 +9447,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, enum vkd3d_result result = VKD3D_OK; unsigned int i; @@ -5394,7 +7664,7 @@ index 3542b5fac51..5535a6503d6 100644 compiler->location.line = 1; diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index d066b13ee4e..290fdcb3f62 100644 +index d066b13ee4e..801c688a297 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -989,6 +989,8 @@ static void shader_sm4_read_declaration_count(struct vkd3d_shader_instruction *i @@ -5414,7 +7684,447 @@ index d066b13ee4e..290fdcb3f62 100644 if ((ret = shader_extract_from_dxbc(&compile_info->source, message_context, compile_info->source_name, shader_desc)) < 0) { -@@ -4369,11 +4372,31 @@ static void write_sm4_expr(struct hlsl_ctx *ctx, +@@ -2967,47 +2970,154 @@ static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *typ + } + } + ++struct extern_resource ++{ ++ /* var is only not NULL if this resource is a whole variable, so it may be responsible for more ++ * than one component. */ ++ const struct hlsl_ir_var *var; ++ ++ char *name; ++ struct hlsl_type *data_type; ++ bool is_user_packed; ++ ++ enum hlsl_regset regset; ++ unsigned int id, bind_count; ++}; ++ + static int sm4_compare_extern_resources(const void *a, const void *b) + { +- const struct hlsl_ir_var *aa = *(const struct hlsl_ir_var **)a; +- const struct hlsl_ir_var *bb = *(const struct hlsl_ir_var **)b; +- enum hlsl_regset aa_regset, bb_regset; ++ const struct extern_resource *aa = (const struct extern_resource *)a; ++ const struct extern_resource *bb = (const struct extern_resource *)b; ++ int r; + +- aa_regset = hlsl_type_get_regset(aa->data_type); +- bb_regset = hlsl_type_get_regset(bb->data_type); ++ if ((r = vkd3d_u32_compare(aa->regset, bb->regset))) ++ return r; + +- if (aa_regset != bb_regset) +- return aa_regset - bb_regset; ++ return vkd3d_u32_compare(aa->id, bb->id); ++} ++ ++static void sm4_free_extern_resources(struct extern_resource *extern_resources, unsigned int count) ++{ ++ unsigned int i; + +- return aa->regs[aa_regset].id - bb->regs[bb_regset].id; ++ for (i = 0; i < count; ++i) ++ vkd3d_free(extern_resources[i].name); ++ vkd3d_free(extern_resources); + } + +-static const struct hlsl_ir_var **sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count) ++static const char *string_skip_tag(const char *string) + { +- const struct hlsl_ir_var **extern_resources = NULL; ++ if (!strncmp(string, "", strlen(""))) ++ return string + strlen(""); ++ return string; ++} ++ ++static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count) ++{ ++ bool separate_components = ctx->profile->major_version == 5 && ctx->profile->minor_version == 0; ++ struct extern_resource *extern_resources = NULL; + const struct hlsl_ir_var *var; + enum hlsl_regset regset; + size_t capacity = 0; ++ char *name; + + *count = 0; + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +- if (!hlsl_type_is_resource(var->data_type)) +- continue; +- regset = hlsl_type_get_regset(var->data_type); +- if (!var->regs[regset].allocated) +- continue; +- +- if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, +- sizeof(*extern_resources)))) ++ if (separate_components) + { +- *count = 0; +- return NULL; ++ unsigned int component_count = hlsl_type_component_count(var->data_type); ++ unsigned int k, regset_offset; ++ ++ for (k = 0; k < component_count; ++k) ++ { ++ struct hlsl_type *component_type = hlsl_type_get_component_type(ctx, var->data_type, k); ++ struct vkd3d_string_buffer *name_buffer; ++ ++ if (!hlsl_type_is_resource(component_type)) ++ continue; ++ ++ regset = hlsl_type_get_regset(component_type); ++ regset_offset = hlsl_type_get_component_offset(ctx, var->data_type, regset, k); ++ ++ if (regset_offset > var->regs[regset].bind_count) ++ continue; ++ ++ if (var->objects_usage[regset][regset_offset].used) ++ { ++ if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, ++ sizeof(*extern_resources)))) ++ { ++ sm4_free_extern_resources(extern_resources, *count); ++ *count = 0; ++ return NULL; ++ } ++ ++ if (!(name_buffer = hlsl_component_to_string(ctx, var, k))) ++ { ++ sm4_free_extern_resources(extern_resources, *count); ++ *count = 0; ++ return NULL; ++ } ++ if (!(name = hlsl_strdup(ctx, string_skip_tag(name_buffer->buffer)))) ++ { ++ sm4_free_extern_resources(extern_resources, *count); ++ *count = 0; ++ hlsl_release_string_buffer(ctx, name_buffer); ++ return NULL; ++ } ++ hlsl_release_string_buffer(ctx, name_buffer); ++ ++ extern_resources[*count].var = NULL; ++ ++ extern_resources[*count].name = name; ++ extern_resources[*count].data_type = component_type; ++ extern_resources[*count].is_user_packed = false; ++ ++ extern_resources[*count].regset = regset; ++ extern_resources[*count].id = var->regs[regset].id + regset_offset; ++ extern_resources[*count].bind_count = 1; ++ ++ ++*count; ++ } ++ } + } ++ else ++ { ++ if (!hlsl_type_is_resource(var->data_type)) ++ continue; ++ regset = hlsl_type_get_regset(var->data_type); ++ if (!var->regs[regset].allocated) ++ continue; ++ ++ if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, ++ sizeof(*extern_resources)))) ++ { ++ sm4_free_extern_resources(extern_resources, *count); ++ *count = 0; ++ return NULL; ++ } ++ ++ if (!(name = hlsl_strdup(ctx, string_skip_tag(var->name)))) ++ { ++ sm4_free_extern_resources(extern_resources, *count); ++ *count = 0; ++ return NULL; ++ } ++ ++ extern_resources[*count].var = var; + +- extern_resources[*count] = var; +- ++*count; ++ extern_resources[*count].name = name; ++ extern_resources[*count].data_type = var->data_type; ++ extern_resources[*count].is_user_packed = !!var->reg_reservation.reg_type; ++ ++ extern_resources[*count].regset = regset; ++ extern_resources[*count].id = var->regs[regset].id; ++ extern_resources[*count].bind_count = var->regs[regset].bind_count; ++ ++ ++*count; ++ } + } + + qsort(extern_resources, *count, sizeof(*extern_resources), sm4_compare_extern_resources); +@@ -3020,8 +3130,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + size_t cbuffers_offset, resources_offset, creator_offset, string_offset; + size_t cbuffer_position, resource_position, creator_position; + const struct hlsl_profile_info *profile = ctx->profile; +- const struct hlsl_ir_var **extern_resources; + struct vkd3d_bytecode_buffer buffer = {0}; ++ struct extern_resource *extern_resources; + const struct hlsl_buffer *cbuffer; + const struct hlsl_ir_var *var; + +@@ -3075,18 +3185,15 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + + for (i = 0; i < extern_resources_count; ++i) + { +- enum hlsl_regset regset; ++ const struct extern_resource *resource = &extern_resources[i]; + uint32_t flags = 0; + +- var = extern_resources[i]; +- regset = hlsl_type_get_regset(var->data_type); +- +- if (var->reg_reservation.reg_type) ++ if (resource->is_user_packed) + flags |= D3D_SIF_USERPACKED; + + put_u32(&buffer, 0); /* name */ +- put_u32(&buffer, sm4_resource_type(var->data_type)); +- if (regset == HLSL_REGSET_SAMPLERS) ++ put_u32(&buffer, sm4_resource_type(resource->data_type)); ++ if (resource->regset == HLSL_REGSET_SAMPLERS) + { + put_u32(&buffer, 0); + put_u32(&buffer, 0); +@@ -3094,15 +3201,15 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + } + else + { +- unsigned int dimx = hlsl_type_get_component_type(ctx, var->data_type, 0)->e.resource_format->dimx; ++ unsigned int dimx = hlsl_type_get_component_type(ctx, resource->data_type, 0)->e.resource_format->dimx; + +- put_u32(&buffer, sm4_resource_format(var->data_type)); +- put_u32(&buffer, sm4_rdef_resource_dimension(var->data_type)); ++ put_u32(&buffer, sm4_resource_format(resource->data_type)); ++ put_u32(&buffer, sm4_rdef_resource_dimension(resource->data_type)); + put_u32(&buffer, ~0u); /* FIXME: multisample count */ + flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; + } +- put_u32(&buffer, var->regs[regset].id); +- put_u32(&buffer, var->regs[regset].bind_count); ++ put_u32(&buffer, resource->id); ++ put_u32(&buffer, resource->bind_count); + put_u32(&buffer, flags); + } + +@@ -3128,9 +3235,9 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + + for (i = 0; i < extern_resources_count; ++i) + { +- var = extern_resources[i]; ++ const struct extern_resource *resource = &extern_resources[i]; + +- string_offset = put_string(&buffer, var->name); ++ string_offset = put_string(&buffer, resource->name); + set_u32(&buffer, resources_offset + i * 8 * sizeof(uint32_t), string_offset); + } + +@@ -3236,7 +3343,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + + add_section(dxbc, TAG_RDEF, &buffer); + +- vkd3d_free(extern_resources); ++ sm4_free_extern_resources(extern_resources, extern_resources_count); + } + + static enum vkd3d_sm4_resource_type sm4_resource_dimension(const struct hlsl_type *type) +@@ -3346,8 +3453,9 @@ struct sm4_instruction + + static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *reg, + unsigned int *writemask, enum vkd3d_sm4_swizzle_type *swizzle_type, +- const struct hlsl_deref *deref, const struct hlsl_type *data_type) ++ const struct hlsl_deref *deref) + { ++ const struct hlsl_type *data_type = hlsl_deref_get_type(ctx, deref); + const struct hlsl_ir_var *var = deref->var; + + if (var->is_uniform) +@@ -3362,7 +3470,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r + *swizzle_type = VKD3D_SM4_SWIZZLE_VEC4; + reg->idx[0] = var->regs[HLSL_REGSET_TEXTURES].id; + reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); +- assert(deref->offset_regset == HLSL_REGSET_TEXTURES); ++ assert(regset == HLSL_REGSET_TEXTURES); + reg->idx_count = 1; + *writemask = VKD3DSP_WRITEMASK_ALL; + } +@@ -3374,7 +3482,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r + *swizzle_type = VKD3D_SM4_SWIZZLE_VEC4; + reg->idx[0] = var->regs[HLSL_REGSET_UAVS].id; + reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); +- assert(deref->offset_regset == HLSL_REGSET_UAVS); ++ assert(regset == HLSL_REGSET_UAVS); + reg->idx_count = 1; + *writemask = VKD3DSP_WRITEMASK_ALL; + } +@@ -3386,7 +3494,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r + *swizzle_type = VKD3D_SM4_SWIZZLE_NONE; + reg->idx[0] = var->regs[HLSL_REGSET_SAMPLERS].id; + reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); +- assert(deref->offset_regset == HLSL_REGSET_SAMPLERS); ++ assert(regset == HLSL_REGSET_SAMPLERS); + reg->idx_count = 1; + *writemask = VKD3DSP_WRITEMASK_ALL; + } +@@ -3484,11 +3592,11 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r + } + + static void sm4_src_from_deref(struct hlsl_ctx *ctx, struct sm4_src_register *src, +- const struct hlsl_deref *deref, const struct hlsl_type *data_type, unsigned int map_writemask) ++ const struct hlsl_deref *deref, unsigned int map_writemask) + { + unsigned int writemask; + +- sm4_register_from_deref(ctx, &src->reg, &writemask, &src->swizzle_type, deref, data_type); ++ sm4_register_from_deref(ctx, &src->reg, &writemask, &src->swizzle_type, deref); + if (src->swizzle_type == VKD3D_SM4_SWIZZLE_VEC4) + src->swizzle = hlsl_map_swizzle(hlsl_swizzle_from_writemask(writemask), map_writemask); + } +@@ -3689,9 +3797,11 @@ static void write_sm4_dcl_constant_buffer(struct vkd3d_bytecode_buffer *buffer, + write_sm4_instruction(buffer, &instr); + } + +-static void write_sm4_dcl_samplers(struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_var *var) ++static void write_sm4_dcl_samplers(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, ++ const struct extern_resource *resource) + { +- unsigned int i, count = var->data_type->reg_size[HLSL_REGSET_SAMPLERS]; ++ struct hlsl_type *component_type; ++ unsigned int i; + struct sm4_instruction instr = + { + .opcode = VKD3D_SM4_OP_DCL_SAMPLER, +@@ -3701,38 +3811,44 @@ static void write_sm4_dcl_samplers(struct vkd3d_bytecode_buffer *buffer, const s + .dst_count = 1, + }; + +- if (var->data_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON) ++ component_type = hlsl_type_get_component_type(ctx, resource->data_type, 0); ++ ++ if (component_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON) + instr.opcode |= VKD3D_SM4_SAMPLER_COMPARISON << VKD3D_SM4_SAMPLER_MODE_SHIFT; + +- for (i = 0; i < count; ++i) ++ assert(resource->regset == HLSL_REGSET_SAMPLERS); ++ ++ for (i = 0; i < resource->bind_count; ++i) + { +- if (!var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) ++ if (resource->var && !resource->var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) + continue; + +- instr.dsts[0].reg.idx[0] = var->regs[HLSL_REGSET_SAMPLERS].id + i; ++ instr.dsts[0].reg.idx[0] = resource->id + i; + write_sm4_instruction(buffer, &instr); + } + } + + static void write_sm4_dcl_textures(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, +- const struct hlsl_ir_var *var, bool uav) ++ const struct extern_resource *resource, bool uav) + { + enum hlsl_regset regset = uav ? HLSL_REGSET_UAVS : HLSL_REGSET_TEXTURES; +- unsigned int i, count = var->data_type->reg_size[regset]; + struct hlsl_type *component_type; + struct sm4_instruction instr; ++ unsigned int i; + +- component_type = hlsl_type_get_component_type(ctx, var->data_type, 0); ++ assert(resource->regset == regset); + +- for (i = 0; i < count; ++i) ++ component_type = hlsl_type_get_component_type(ctx, resource->data_type, 0); ++ ++ for (i = 0; i < resource->bind_count; ++i) + { +- if (!var->objects_usage[regset][i].used) ++ if (resource->var && !resource->var->objects_usage[regset][i].used) + continue; + + instr = (struct sm4_instruction) + { + .dsts[0].reg.type = uav ? VKD3D_SM5_RT_UAV : VKD3D_SM4_RT_RESOURCE, +- .dsts[0].reg.idx = {var->regs[regset].id + i}, ++ .dsts[0].reg.idx = {resource->id + i}, + .dsts[0].reg.idx_count = 1, + .dst_count = 1, + +@@ -3742,11 +3858,11 @@ static void write_sm4_dcl_textures(struct hlsl_ctx *ctx, struct vkd3d_bytecode_b + + if (uav) + { +- switch (var->data_type->sampler_dim) ++ switch (resource->data_type->sampler_dim) + { + case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER: + instr.opcode = VKD3D_SM5_OP_DCL_UAV_STRUCTURED; +- instr.byte_stride = var->data_type->e.resource_format->reg_size[HLSL_REGSET_NUMERIC] * 4; ++ instr.byte_stride = resource->data_type->e.resource_format->reg_size[HLSL_REGSET_NUMERIC] * 4; + break; + default: + instr.opcode = VKD3D_SM5_OP_DCL_UAV_TYPED; +@@ -4008,11 +4124,11 @@ static void write_sm4_binary_op_with_two_destinations(struct vkd3d_bytecode_buff + } + + static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, +- const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, +- const struct hlsl_deref *resource, const struct hlsl_ir_node *coords, +- const struct hlsl_ir_node *sample_index, const struct hlsl_ir_node *texel_offset, +- enum hlsl_sampler_dim dim) ++ const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, ++ const struct hlsl_ir_node *coords, const struct hlsl_ir_node *sample_index, ++ const struct hlsl_ir_node *texel_offset, enum hlsl_sampler_dim dim) + { ++ const struct hlsl_type *resource_type = hlsl_deref_get_type(ctx, resource); + bool multisampled = resource_type->base_type == HLSL_TYPE_TEXTURE + && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); + bool uav = (hlsl_type_get_regset(resource_type) == HLSL_REGSET_UAVS); +@@ -4052,7 +4168,7 @@ static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buf + + sm4_src_from_node(&instr.srcs[0], coords, coords_writemask); + +- sm4_src_from_deref(ctx, &instr.srcs[1], resource, resource_type, instr.dsts[0].writemask); ++ sm4_src_from_deref(ctx, &instr.srcs[1], resource, instr.dsts[0].writemask); + + instr.src_count = 2; + +@@ -4089,7 +4205,6 @@ static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buf + static void write_sm4_sample(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, + const struct hlsl_ir_resource_load *load) + { +- const struct hlsl_type *resource_type = load->resource.var->data_type; + const struct hlsl_ir_node *texel_offset = load->texel_offset.node; + const struct hlsl_ir_node *coords = load->coords.node; + const struct hlsl_deref *resource = &load->resource; +@@ -4142,8 +4257,8 @@ static void write_sm4_sample(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer + instr.dst_count = 1; + + sm4_src_from_node(&instr.srcs[0], coords, VKD3DSP_WRITEMASK_ALL); +- sm4_src_from_deref(ctx, &instr.srcs[1], resource, resource_type, instr.dsts[0].writemask); +- sm4_src_from_deref(ctx, &instr.srcs[2], sampler, sampler->var->data_type, VKD3DSP_WRITEMASK_ALL); ++ sm4_src_from_deref(ctx, &instr.srcs[1], resource, instr.dsts[0].writemask); ++ sm4_src_from_deref(ctx, &instr.srcs[2], sampler, VKD3DSP_WRITEMASK_ALL); + instr.src_count = 3; + + if (load->load_type == HLSL_RESOURCE_SAMPLE_LOD +@@ -4313,7 +4428,7 @@ static void write_sm4_store_uav_typed(struct hlsl_ctx *ctx, struct vkd3d_bytecod + memset(&instr, 0, sizeof(instr)); + instr.opcode = VKD3D_SM5_OP_STORE_UAV_TYPED; + +- sm4_register_from_deref(ctx, &instr.dsts[0].reg, &instr.dsts[0].writemask, NULL, dst, dst->var->data_type); ++ sm4_register_from_deref(ctx, &instr.dsts[0].reg, &instr.dsts[0].writemask, NULL, dst); + instr.dst_count = 1; + + sm4_src_from_node(&instr.srcs[0], coords, VKD3DSP_WRITEMASK_ALL); +@@ -4369,11 +4484,31 @@ static void write_sm4_expr(struct hlsl_ctx *ctx, write_sm4_unary_op(buffer, VKD3D_SM4_OP_DERIV_RTX, &expr->node, arg1, 0); break; @@ -5446,7 +8156,7 @@ index d066b13ee4e..290fdcb3f62 100644 case HLSL_OP1_EXP2: assert(type_is_float(dst_type)); write_sm4_unary_op(buffer, VKD3D_SM4_OP_EXP, &expr->node, arg1, 0); -@@ -4780,19 +4803,13 @@ static void write_sm4_jump(struct hlsl_ctx *ctx, +@@ -4780,19 +4915,13 @@ static void write_sm4_jump(struct hlsl_ctx *ctx, instr.opcode = VKD3D_SM4_OP_BREAK; break; @@ -5468,7 +8178,7 @@ index d066b13ee4e..290fdcb3f62 100644 break; } -@@ -4800,7 +4817,7 @@ static void write_sm4_jump(struct hlsl_ctx *ctx, +@@ -4800,7 +4929,7 @@ static void write_sm4_jump(struct hlsl_ctx *ctx, vkd3d_unreachable(); default: @@ -5477,7 +8187,152 @@ index d066b13ee4e..290fdcb3f62 100644 return; } -@@ -5016,7 +5033,7 @@ static void write_sm4_resource_store(struct hlsl_ctx *ctx, +@@ -4839,7 +4968,7 @@ static void write_sm4_load(struct hlsl_ctx *ctx, + + instr.opcode = VKD3D_SM4_OP_MOVC; + +- sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, type, instr.dsts[0].writemask); ++ sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, instr.dsts[0].writemask); + + memset(&value, 0xff, sizeof(value)); + sm4_src_from_constant_value(&instr.srcs[1], &value, type->dimx, instr.dsts[0].writemask); +@@ -4851,7 +4980,7 @@ static void write_sm4_load(struct hlsl_ctx *ctx, + { + instr.opcode = VKD3D_SM4_OP_MOV; + +- sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, type, instr.dsts[0].writemask); ++ sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, instr.dsts[0].writemask); + instr.src_count = 1; + } + +@@ -4875,8 +5004,7 @@ static void write_sm4_loop(struct hlsl_ctx *ctx, + } + + static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, +- const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, +- const struct hlsl_deref *resource, const struct hlsl_deref *sampler, ++ const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, const struct hlsl_deref *sampler, + const struct hlsl_ir_node *coords, unsigned int swizzle, const struct hlsl_ir_node *texel_offset) + { + struct sm4_src_register *src; +@@ -4906,10 +5034,10 @@ static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer + } + } + +- sm4_src_from_deref(ctx, &instr.srcs[instr.src_count++], resource, resource_type, instr.dsts[0].writemask); ++ sm4_src_from_deref(ctx, &instr.srcs[instr.src_count++], resource, instr.dsts[0].writemask); + + src = &instr.srcs[instr.src_count++]; +- sm4_src_from_deref(ctx, src, sampler, sampler->var->data_type, VKD3DSP_WRITEMASK_ALL); ++ sm4_src_from_deref(ctx, src, sampler, VKD3DSP_WRITEMASK_ALL); + src->reg.dim = VKD3D_SM4_DIMENSION_VEC4; + src->swizzle_type = VKD3D_SM4_SWIZZLE_SCALAR; + src->swizzle = swizzle; +@@ -4920,34 +5048,16 @@ static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer + static void write_sm4_resource_load(struct hlsl_ctx *ctx, + struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_load *load) + { +- const struct hlsl_type *resource_type = load->resource.var->data_type; + const struct hlsl_ir_node *texel_offset = load->texel_offset.node; + const struct hlsl_ir_node *sample_index = load->sample_index.node; + const struct hlsl_ir_node *coords = load->coords.node; + +- if (!hlsl_type_is_resource(resource_type)) ++ if (load->sampler.var && !load->sampler.var->is_uniform) + { +- hlsl_fixme(ctx, &load->node.loc, "Separate object fields as new variables."); ++ hlsl_fixme(ctx, &load->node.loc, "Sample using non-uniform sampler variable."); + return; + } + +- if (load->sampler.var) +- { +- const struct hlsl_type *sampler_type = load->sampler.var->data_type; +- +- if (!hlsl_type_is_resource(sampler_type)) +- { +- hlsl_fixme(ctx, &load->node.loc, "Separate object fields as new variables."); +- return; +- } +- +- if (!load->sampler.var->is_uniform) +- { +- hlsl_fixme(ctx, &load->node.loc, "Sample using non-uniform sampler variable."); +- return; +- } +- } +- + if (!load->resource.var->is_uniform) + { + hlsl_fixme(ctx, &load->node.loc, "Load from non-uniform resource variable."); +@@ -4957,7 +5067,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, + switch (load->load_type) + { + case HLSL_RESOURCE_LOAD: +- write_sm4_ld(ctx, buffer, resource_type, &load->node, &load->resource, ++ write_sm4_ld(ctx, buffer, &load->node, &load->resource, + coords, sample_index, texel_offset, load->sampling_dim); + break; + +@@ -4967,32 +5077,29 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, + case HLSL_RESOURCE_SAMPLE_LOD: + case HLSL_RESOURCE_SAMPLE_LOD_BIAS: + case HLSL_RESOURCE_SAMPLE_GRAD: +- if (!load->sampler.var) +- { +- hlsl_fixme(ctx, &load->node.loc, "SM4 combined sample expression."); +- return; +- } ++ /* Combined sample expressions were lowered. */ ++ assert(load->sampler.var); + write_sm4_sample(ctx, buffer, load); + break; + + case HLSL_RESOURCE_GATHER_RED: +- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, +- &load->sampler, coords, HLSL_SWIZZLE(X, X, X, X), texel_offset); ++ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, ++ HLSL_SWIZZLE(X, X, X, X), texel_offset); + break; + + case HLSL_RESOURCE_GATHER_GREEN: +- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, +- &load->sampler, coords, HLSL_SWIZZLE(Y, Y, Y, Y), texel_offset); ++ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, ++ HLSL_SWIZZLE(Y, Y, Y, Y), texel_offset); + break; + + case HLSL_RESOURCE_GATHER_BLUE: +- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, +- &load->sampler, coords, HLSL_SWIZZLE(Z, Z, Z, Z), texel_offset); ++ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, ++ HLSL_SWIZZLE(Z, Z, Z, Z), texel_offset); + break; + + case HLSL_RESOURCE_GATHER_ALPHA: +- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, +- &load->sampler, coords, HLSL_SWIZZLE(W, W, W, W), texel_offset); ++ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, ++ HLSL_SWIZZLE(W, W, W, W), texel_offset); + break; + } + } +@@ -5000,13 +5107,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, + static void write_sm4_resource_store(struct hlsl_ctx *ctx, + struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_store *store) + { +- const struct hlsl_type *resource_type = store->resource.var->data_type; +- +- if (!hlsl_type_is_resource(resource_type)) +- { +- hlsl_fixme(ctx, &store->node.loc, "Separate object fields as new variables."); +- return; +- } ++ struct hlsl_type *resource_type = hlsl_deref_get_type(ctx, &store->resource); + + if (!store->resource.var->is_uniform) + { +@@ -5016,7 +5117,7 @@ static void write_sm4_resource_store(struct hlsl_ctx *ctx, if (resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) { @@ -5486,6 +8341,59 @@ index d066b13ee4e..290fdcb3f62 100644 return; } +@@ -5033,7 +5134,7 @@ static void write_sm4_store(struct hlsl_ctx *ctx, + memset(&instr, 0, sizeof(instr)); + instr.opcode = VKD3D_SM4_OP_MOV; + +- sm4_register_from_deref(ctx, &instr.dsts[0].reg, &writemask, NULL, &store->lhs, rhs->data_type); ++ sm4_register_from_deref(ctx, &instr.dsts[0].reg, &writemask, NULL, &store->lhs); + instr.dsts[0].writemask = hlsl_combine_writemasks(writemask, store->writemask); + instr.dst_count = 1; + +@@ -5144,8 +5245,8 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + const struct hlsl_ir_function_decl *entry_func, struct dxbc_writer *dxbc) + { + const struct hlsl_profile_info *profile = ctx->profile; +- const struct hlsl_ir_var **extern_resources; + struct vkd3d_bytecode_buffer buffer = {0}; ++ struct extern_resource *extern_resources; + unsigned int extern_resources_count, i; + const struct hlsl_buffer *cbuffer; + const struct hlsl_ir_var *var; +@@ -5177,17 +5278,14 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + + for (i = 0; i < extern_resources_count; ++i) + { +- enum hlsl_regset regset; ++ const struct extern_resource *resource = &extern_resources[i]; + +- var = extern_resources[i]; +- regset = hlsl_type_get_regset(var->data_type); +- +- if (regset == HLSL_REGSET_SAMPLERS) +- write_sm4_dcl_samplers(&buffer, var); +- else if (regset == HLSL_REGSET_TEXTURES) +- write_sm4_dcl_textures(ctx, &buffer, var, false); +- else if (regset == HLSL_REGSET_UAVS) +- write_sm4_dcl_textures(ctx, &buffer, var, true); ++ if (resource->regset == HLSL_REGSET_SAMPLERS) ++ write_sm4_dcl_samplers(ctx, &buffer, resource); ++ else if (resource->regset == HLSL_REGSET_TEXTURES) ++ write_sm4_dcl_textures(ctx, &buffer, resource, false); ++ else if (resource->regset == HLSL_REGSET_UAVS) ++ write_sm4_dcl_textures(ctx, &buffer, resource, true); + } + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) +@@ -5210,7 +5308,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + + add_section(dxbc, TAG_SHDR, &buffer); + +- vkd3d_free(extern_resources); ++ sm4_free_extern_resources(extern_resources, extern_resources_count); + } + + int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c index 343fdb2252e..33d8c60e59a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c @@ -5767,10 +8675,10 @@ index 343fdb2252e..33d8c60e59a 100644 *count = ARRAY_SIZE(dxbc_tpf_types); return dxbc_tpf_types; diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index 406d53a3391..85fca964227 100644 +index 406d53a3391..0e93f3a556a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -145,8 +145,21 @@ enum vkd3d_shader_error +@@ -145,8 +145,29 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE = 7002, VKD3D_SHADER_ERROR_D3DBC_INVALID_RESOURCE_TYPE = 7003, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY = 7004, @@ -5784,15 +8692,31 @@ index 406d53a3391..85fca964227 100644 + VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_OFFSET = 8002, + VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE = 8003, + VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE = 8004, ++ 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_INVALID_FUNCTION_DCL = 8009, ++ VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID = 8010, ++ VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE = 8011, + + VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, + VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, + VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH = 8302, + VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH = 8303, ++ VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304, }; enum vkd3d_shader_opcode -@@ -802,6 +815,7 @@ struct signature_element +@@ -516,6 +537,7 @@ enum vkd3d_data_type + VKD3D_DATA_DOUBLE, + VKD3D_DATA_CONTINUED, + VKD3D_DATA_UNUSED, ++ VKD3D_DATA_UINT8, + }; + + enum vkd3d_immconst_type +@@ -802,6 +824,7 @@ struct signature_element struct shader_signature { struct signature_element *elements; @@ -5800,7 +8724,7 @@ index 406d53a3391..85fca964227 100644 unsigned int element_count; }; -@@ -811,9 +825,12 @@ struct vkd3d_shader_desc +@@ -811,9 +834,12 @@ struct vkd3d_shader_desc { const uint32_t *byte_code; size_t byte_code_size; @@ -5813,7 +8737,7 @@ index 406d53a3391..85fca964227 100644 }; struct vkd3d_shader_register_semantic -@@ -1167,6 +1184,8 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi +@@ -1167,6 +1193,8 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser); int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser); @@ -5822,7 +8746,7 @@ index 406d53a3391..85fca964227 100644 void free_shader_desc(struct vkd3d_shader_desc *desc); -@@ -1339,6 +1358,7 @@ static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain, +@@ -1339,6 +1367,7 @@ static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain, } #define VKD3D_DXBC_HEADER_SIZE (8 * sizeof(uint32_t)) diff --git a/patches/vkd3d-latest/0003-Updated-vkd3d-to-b4bb3931c5e7e59496c07c2d4e3b6cfd3bf.patch b/patches/vkd3d-latest/0003-Updated-vkd3d-to-b4bb3931c5e7e59496c07c2d4e3b6cfd3bf.patch new file mode 100644 index 00000000..47996b9d --- /dev/null +++ b/patches/vkd3d-latest/0003-Updated-vkd3d-to-b4bb3931c5e7e59496c07c2d4e3b6cfd3bf.patch @@ -0,0 +1,5119 @@ +From 7a3d9f859ea9571d19d388781f91855a4e06f122 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 3 Aug 2023 08:38:38 +1000 +Subject: [PATCH 3/3] Updated vkd3d to + b4bb3931c5e7e59496c07c2d4e3b6cfd3bf91cf1. + +--- + include/d3d12.idl | 66 +++ + libs/vkd3d/include/private/vkd3d_common.h | 15 + + libs/vkd3d/include/vkd3d_shader.h | 59 ++- + libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 104 +++- + libs/vkd3d/libs/vkd3d-shader/dxil.c | 59 ++- + libs/vkd3d/libs/vkd3d-shader/hlsl.c | 32 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.h | 4 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 494 ++++++++++++------ + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 152 +++--- + libs/vkd3d/libs/vkd3d-shader/ir.c | 159 +++++- + libs/vkd3d/libs/vkd3d-shader/preproc.l | 140 +++-- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 164 ++++-- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 83 ++- + .../libs/vkd3d-shader/vkd3d_shader_main.c | 9 + + .../libs/vkd3d-shader/vkd3d_shader_private.h | 15 +- + libs/vkd3d/libs/vkd3d/command.c | 451 +++++++++------- + libs/vkd3d/libs/vkd3d/device.c | 20 +- + libs/vkd3d/libs/vkd3d/resource.c | 238 ++++++++- + libs/vkd3d/libs/vkd3d/vkd3d_private.h | 55 +- + 19 files changed, 1756 insertions(+), 563 deletions(-) + +diff --git a/include/d3d12.idl b/include/d3d12.idl +index c6064939e1f..5811608b94f 100644 +--- a/include/d3d12.idl ++++ b/include/d3d12.idl +@@ -44,6 +44,7 @@ const UINT D3D12_DEFAULT_STENCIL_WRITE_MASK = 0xff; + const UINT D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND = 0xffffffff; + cpp_quote("#define D3D12_FLOAT32_MAX (3.402823466e+38f)") + const UINT D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT = 32; ++const UINT D3D12_PACKED_TILE = 0xffffffff; + const UINT D3D12_UAV_SLOT_COUNT = 64; + const UINT D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT = 4096; + const UINT D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT = 4096; +@@ -72,6 +73,7 @@ const UINT D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT = 4096; + const UINT D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE = 4; + const UINT D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256; + const UINT D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT = 512; ++const UINT D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES = 65536; + const UINT D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT = 4096; + const UINT D3D12_VS_INPUT_REGISTER_COUNT = 32; + const UINT D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE = 16; +@@ -1853,6 +1855,24 @@ typedef struct D3D12_WRITEBUFFERIMMEDIATE_PARAMETER + UINT32 Value; + } D3D12_WRITEBUFFERIMMEDIATE_PARAMETER; + ++typedef enum D3D12_PROTECTED_RESOURCE_SESSION_FLAGS ++{ ++ D3D12_PROTECTED_RESOURCE_SESSION_FLAG_NONE = 0, ++} D3D12_PROTECTED_RESOURCE_SESSION_FLAGS; ++cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(D3D12_PROTECTED_RESOURCE_SESSION_FLAGS);") ++ ++typedef enum D3D12_PROTECTED_SESSION_STATUS ++{ ++ D3D12_PROTECTED_SESSION_STATUS_OK = 0, ++ D3D12_PROTECTED_SESSION_STATUS_INVALID = 1, ++} D3D12_PROTECTED_SESSION_STATUS; ++ ++typedef struct D3D12_PROTECTED_RESOURCE_SESSION_DESC ++{ ++ UINT NodeMask; ++ D3D12_PROTECTED_RESOURCE_SESSION_FLAGS Flags; ++} D3D12_PROTECTED_RESOURCE_SESSION_DESC; ++ + [ + uuid(c4fec28f-7966-4e95-9f94-f431cb56c3b8), + object, +@@ -2214,6 +2234,41 @@ interface ID3D12GraphicsCommandList2 : ID3D12GraphicsCommandList1 + const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes); + } + ++[ ++ uuid(a1533d18-0ac1-4084-85b9-89a96116806b), ++ object, ++ local, ++ pointer_default(unique) ++] ++interface ID3D12ProtectedSession : ID3D12DeviceChild ++{ ++ HRESULT GetStatusFence(REFIID riid, void **fence); ++ ++ D3D12_PROTECTED_SESSION_STATUS GetSessionStatus(); ++} ++ ++[ ++ uuid(6cd696f4-f289-40cc-8091-5a6c0a099c3d), ++ object, ++ local, ++ pointer_default(unique) ++] ++interface ID3D12ProtectedResourceSession : ID3D12ProtectedSession ++{ ++ D3D12_PROTECTED_RESOURCE_SESSION_DESC GetDesc(); ++} ++ ++[ ++ uuid(6fda83a7-b84c-4e38-9ac8-c7bd22016b3d), ++ object, ++ local, ++ pointer_default(unique) ++] ++interface ID3D12GraphicsCommandList3 : ID3D12GraphicsCommandList2 ++{ ++ void SetProtectedResourceSession(ID3D12ProtectedResourceSession *protected_resource_session); ++} ++ + typedef enum D3D12_TILE_RANGE_FLAGS + { + D3D12_TILE_RANGE_FLAG_NONE = 0x0, +@@ -2378,6 +2433,17 @@ interface ID3D12Fence : ID3D12Pageable + HRESULT Signal(UINT64 value); + } + ++[ ++ uuid(433685fe-e22b-4ca0-a8db-b5b4f4dd0e4a), ++ object, ++ local, ++ pointer_default(unique) ++] ++interface ID3D12Fence1 : ID3D12Fence ++{ ++ D3D12_FENCE_FLAGS GetCreationFlags(); ++} ++ + [ + uuid(6102dee4-af59-4b09-b999-b44d73f09b24), + object, +diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h +index 0263fc47297..f7d98f327f1 100644 +--- a/libs/vkd3d/include/private/vkd3d_common.h ++++ b/libs/vkd3d/include/private/vkd3d_common.h +@@ -193,6 +193,21 @@ static inline int vkd3d_u32_compare(uint32_t x, uint32_t y) + return (x > y) - (x < y); + } + ++static inline bool bitmap_clear(uint32_t *map, unsigned int idx) ++{ ++ return map[idx >> 5] &= ~(1u << (idx & 0x1f)); ++} ++ ++static inline bool bitmap_set(uint32_t *map, unsigned int idx) ++{ ++ return map[idx >> 5] |= (1u << (idx & 0x1f)); ++} ++ ++static inline bool bitmap_is_set(const uint32_t *map, unsigned int idx) ++{ ++ return map[idx >> 5] & (1u << (idx & 0x1f)); ++} ++ + static inline int ascii_isupper(int c) + { + return 'A' <= c && c <= 'Z'; +diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h +index 6c17a07b9d2..d6653d18e56 100644 +--- a/libs/vkd3d/include/vkd3d_shader.h ++++ b/libs/vkd3d/include/vkd3d_shader.h +@@ -139,6 +139,14 @@ enum vkd3d_shader_compile_option_formatting_flags + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_FORMATTING_FLAGS), + }; + ++enum vkd3d_shader_compile_option_pack_matrix_order ++{ ++ VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_ROW_MAJOR = 0x00000001, ++ VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_COLUMN_MAJOR = 0x00000002, ++ ++ VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_ORDER), ++}; ++ + enum vkd3d_shader_compile_option_name + { + /** +@@ -169,6 +177,15 @@ enum vkd3d_shader_compile_option_name + * \since 1.7 + */ + VKD3D_SHADER_COMPILE_OPTION_WRITE_TESS_GEOM_POINT_SIZE = 0x00000006, ++ /** ++ * This option specifies default matrix packing order. It's only supported for HLSL source type. ++ * Explicit variable modifiers or pragmas will take precedence. ++ * ++ * \a value is a member of enum vkd3d_shader_compile_option_pack_matrix_order. ++ * ++ * \since 1.9 ++ */ ++ VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_ORDER = 0x00000007, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_NAME), + }; +@@ -332,6 +349,25 @@ struct vkd3d_shader_parameter + } u; + }; + ++/** ++ * Symbolic register indices for mapping uniform constant register sets in ++ * legacy Direct3D bytecode to constant buffer views in the target environment. ++ * ++ * Members of this enumeration are used in ++ * \ref vkd3d_shader_resource_binding.register_index. ++ * ++ * \since 1.9 ++ */ ++enum vkd3d_shader_d3dbc_constant_register ++{ ++ /** The float constant register set, c# in Direct3D assembly. */ ++ VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER = 0x0, ++ /** The integer constant register set, i# in Direct3D assembly. */ ++ VKD3D_SHADER_D3DBC_INT_CONSTANT_REGISTER = 0x1, ++ /** The boolean constant register set, b# in Direct3D assembly. */ ++ VKD3D_SHADER_D3DBC_BOOL_CONSTANT_REGISTER = 0x2, ++}; ++ + /** + * Describes the mapping of a single resource or resource array to its binding + * point in the target environment. +@@ -356,7 +392,14 @@ struct vkd3d_shader_resource_binding + * support multiple register spaces, this parameter must be set to 0. + */ + unsigned int register_space; +- /** Register index of the DXBC resource. */ ++ /** ++ * Register index of the Direct3D resource. ++ * ++ * For legacy Direct3D shaders, vkd3d-shader maps each constant register ++ * set to a single constant buffer view. This parameter names the register ++ * set to map, and must be a member of ++ * enum vkd3d_shader_d3dbc_constant_register. ++ */ + unsigned int register_index; + /** Shader stage(s) to which the resource is visible. */ + enum vkd3d_shader_visibility shader_visibility; +@@ -1330,6 +1373,20 @@ struct vkd3d_shader_descriptor_info + * A chained structure enumerating the descriptors declared by a shader. + * + * This structure extends vkd3d_shader_compile_info. ++ * ++ * When scanning a legacy Direct3D shader, vkd3d-shader enumerates each ++ * constant register set used by the shader as a single constant buffer ++ * descriptor, as follows: ++ * - The \ref vkd3d_shader_descriptor_info.type field is set to ++ * VKD3D_SHADER_DESCRIPTOR_TYPE_CBV. ++ * - The \ref vkd3d_shader_descriptor_info.register_space field is set to zero. ++ * - The \ref vkd3d_shader_descriptor_info.register_index field is set to a ++ * member of enum vkd3d_shader_d3dbc_constant_register denoting which set ++ * is used. ++ * - The \ref vkd3d_shader_descriptor_info.count field is set to one. ++ * ++ * In summary, there may be up to three such descriptors, one for each register ++ * set used by the shader: float, integer, and boolean. + */ + struct vkd3d_shader_scan_descriptor_info + { +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +index 369112ce18d..fe739339bd1 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +@@ -214,6 +214,9 @@ struct vkd3d_shader_sm1_parser + bool abort; + + struct vkd3d_shader_parser p; ++ ++#define MAX_CONSTANT_COUNT 8192 ++ uint32_t constant_def_mask[3][MAX_CONSTANT_COUNT / 32]; + }; + + /* This table is not order or position dependent. */ +@@ -729,12 +732,60 @@ static bool add_signature_element_from_semantic(struct vkd3d_shader_sm1_parser * + semantic->usage_idx, sysval, reg->idx[0].offset, true, mask); + } + +-static void shader_sm1_scan_register(struct vkd3d_shader_sm1_parser *sm1, const struct vkd3d_shader_register *reg, unsigned int mask) ++static void record_constant_register(struct vkd3d_shader_sm1_parser *sm1, ++ enum vkd3d_shader_d3dbc_constant_register set, uint32_t index, bool from_def) + { ++ struct vkd3d_shader_desc *desc = &sm1->p.shader_desc; ++ ++ desc->flat_constant_count[set].used = max(desc->flat_constant_count[set].used, index + 1); ++ if (from_def) ++ { ++ /* d3d shaders have a maximum of 8192 constants; we should not overrun ++ * this array. */ ++ assert((index / 32) <= ARRAY_SIZE(sm1->constant_def_mask[set])); ++ bitmap_set(sm1->constant_def_mask[set], index); ++ } ++} ++ ++static void shader_sm1_scan_register(struct vkd3d_shader_sm1_parser *sm1, ++ const struct vkd3d_shader_register *reg, unsigned int mask, bool from_def) ++{ ++ struct vkd3d_shader_desc *desc = &sm1->p.shader_desc; + uint32_t register_index = reg->idx[0].offset; + +- if (reg->type == VKD3DSPR_TEMP) +- sm1->p.shader_desc.temp_count = max(sm1->p.shader_desc.temp_count, register_index + 1); ++ switch (reg->type) ++ { ++ case VKD3DSPR_TEMP: ++ desc->temp_count = max(desc->temp_count, register_index + 1); ++ break; ++ ++ case VKD3DSPR_CONST: ++ record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, register_index, from_def); ++ break; ++ ++ case VKD3DSPR_CONST2: ++ record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 2048 + register_index, from_def); ++ break; ++ ++ case VKD3DSPR_CONST3: ++ record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 4096 + register_index, from_def); ++ break; ++ ++ case VKD3DSPR_CONST4: ++ record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 6144 + register_index, from_def); ++ break; ++ ++ case VKD3DSPR_CONSTINT: ++ record_constant_register(sm1, VKD3D_SHADER_D3DBC_INT_CONSTANT_REGISTER, register_index, from_def); ++ break; ++ ++ case VKD3DSPR_CONSTBOOL: ++ record_constant_register(sm1, VKD3D_SHADER_D3DBC_BOOL_CONSTANT_REGISTER, register_index, from_def); ++ break; ++ ++ default: ++ break; ++ } + + add_signature_element_from_register(sm1, reg, false, mask); + } +@@ -1076,16 +1127,19 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str + { + shader_sm1_read_dst_param(sm1, &p, dst_param); + shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_FLOAT); ++ shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); + } + else if (ins->handler_idx == VKD3DSIH_DEFB) + { + shader_sm1_read_dst_param(sm1, &p, dst_param); + shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_SCALAR, VKD3D_DATA_UINT); ++ shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); + } + else if (ins->handler_idx == VKD3DSIH_DEFI) + { + shader_sm1_read_dst_param(sm1, &p, dst_param); + shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_INT); ++ shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); + } + else + { +@@ -1093,7 +1147,7 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str + if (ins->dst_count) + { + shader_sm1_read_dst_param(sm1, &p, dst_param); +- shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask); ++ shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, false); + } + + /* Predication token */ +@@ -1104,7 +1158,7 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str + for (i = 0; i < ins->src_count; ++i) + { + shader_sm1_read_src_param(sm1, &p, &src_params[i]); +- shader_sm1_scan_register(sm1, &src_params[i].reg, mask_from_swizzle(src_params[i].swizzle)); ++ shader_sm1_scan_register(sm1, &src_params[i].reg, mask_from_swizzle(src_params[i].swizzle), false); + } + } + +@@ -1212,12 +1266,30 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, + return VKD3D_OK; + } + ++static uint32_t get_external_constant_count(struct vkd3d_shader_sm1_parser *sm1, ++ enum vkd3d_shader_d3dbc_constant_register set) ++{ ++ unsigned int j; ++ ++ /* Find the highest constant index which is not written by a DEF ++ * instruction. We can't (easily) use an FFZ function for this since it ++ * needs to be limited by the highest used register index. */ ++ for (j = sm1->p.shader_desc.flat_constant_count[set].used; j > 0; --j) ++ { ++ if (!bitmap_is_set(sm1->constant_def_mask[set], j - 1)) ++ return j; ++ } ++ ++ return 0; ++} ++ + int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser) + { + struct vkd3d_shader_instruction_array *instructions; + struct vkd3d_shader_instruction *ins; + struct vkd3d_shader_sm1_parser *sm1; ++ unsigned int i; + int ret; + + if (!(sm1 = vkd3d_calloc(1, sizeof(*sm1)))) +@@ -1257,6 +1329,9 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi + + *parser = &sm1->p; + ++ for (i = 0; i < ARRAY_SIZE(sm1->p.shader_desc.flat_constant_count); ++i) ++ sm1->p.shader_desc.flat_constant_count[i].external = get_external_constant_count(sm1, i); ++ + return sm1->p.failed ? VKD3D_ERROR_INVALID_SHADER : VKD3D_OK; + } + +@@ -1959,7 +2034,12 @@ static void write_sm1_sampler_dcls(struct hlsl_ctx *ctx, struct vkd3d_bytecode_b + if (var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) + { + sampler_dim = var->objects_usage[HLSL_REGSET_SAMPLERS][i].sampler_dim; +- assert(sampler_dim != HLSL_SAMPLER_DIM_GENERIC); ++ if (sampler_dim == HLSL_SAMPLER_DIM_GENERIC) ++ { ++ /* These can appear in sm4-style combined sample instructions. */ ++ hlsl_fixme(ctx, &var->loc, "Generic samplers need to be lowered."); ++ continue; ++ } + + reg_id = var->regs[HLSL_REGSET_SAMPLERS].id + i; + write_sm1_sampler_dcl(ctx, buffer, reg_id, sampler_dim); +@@ -2362,7 +2442,6 @@ static void write_sm1_instructions(struct hlsl_ctx *ctx, struct vkd3d_bytecode_b + int hlsl_sm1_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) + { + struct vkd3d_bytecode_buffer buffer = {0}; +- int ret; + + put_u32(&buffer, sm1_version(ctx->profile->type, ctx->profile->major_version, ctx->profile->minor_version)); + +@@ -2375,10 +2454,17 @@ int hlsl_sm1_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun + + put_u32(&buffer, D3DSIO_END); + +- if (!(ret = buffer.status)) ++ if (buffer.status) ++ ctx->result = buffer.status; ++ ++ if (!ctx->result) + { + out->code = buffer.data; + out->size = buffer.size; + } +- return ret; ++ else ++ { ++ vkd3d_free(buffer.data); ++ } ++ return ctx->result; + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c +index 53a4c2da4ba..f9efe47f95d 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c ++++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c +@@ -208,6 +208,7 @@ struct sm6_value + { + const struct sm6_type *type; + enum sm6_value_type value_type; ++ bool is_undefined; + union + { + struct sm6_function_data function; +@@ -1726,8 +1727,16 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const + WARN("Unhandled constant array.\n"); + break; + ++ case CST_CODE_UNDEF: ++ dxil_record_validate_operand_max_count(record, 0, sm6); ++ dst->u.reg.type = VKD3DSPR_UNDEF; ++ /* Mark as explicitly undefined, not the result of a missing constant code or instruction. */ ++ dst->is_undefined = true; ++ break; ++ + default: + FIXME("Unhandled constant code %u.\n", record->code); ++ dst->u.reg.type = VKD3DSPR_UNDEF; + break; + } + +@@ -1737,6 +1746,27 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const + return VKD3D_OK; + } + ++static struct vkd3d_shader_instruction *sm6_parser_require_space(struct sm6_parser *sm6, size_t extra) ++{ ++ if (!shader_instruction_array_reserve(&sm6->p.instructions, sm6->p.instructions.count + extra)) ++ { ++ ERR("Failed to allocate instruction.\n"); ++ return NULL; ++ } ++ return &sm6->p.instructions.elements[sm6->p.instructions.count]; ++} ++ ++/* Space should be reserved before calling this. It is intended to require no checking of the returned pointer. */ ++static struct vkd3d_shader_instruction *sm6_parser_add_instruction(struct sm6_parser *sm6, ++ enum vkd3d_shader_opcode handler_idx) ++{ ++ struct vkd3d_shader_instruction *ins = sm6_parser_require_space(sm6, 1); ++ assert(ins); ++ shader_instruction_init(ins, handler_idx); ++ ++sm6->p.instructions.count; ++ return ins; ++} ++ + static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) + { + const struct dxil_block *block = &sm6->root_block; +@@ -1767,7 +1797,8 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) + break; + + case MODULE_CODE_VERSION: +- dxil_record_validate_operand_count(record, 1, 1, sm6); ++ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) ++ return VKD3D_ERROR_INVALID_SHADER; + if ((version = record->operands[0]) != 1) + { + FIXME("Unsupported format version %#"PRIx64".\n", version); +@@ -1931,6 +1962,21 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const + return VKD3D_OK; + } + ++static bool sm6_block_emit_instructions(struct sm6_block *block, struct sm6_parser *sm6) ++{ ++ struct vkd3d_shader_instruction *ins = sm6_parser_require_space(sm6, block->instruction_count + 1); ++ ++ if (!ins) ++ return false; ++ ++ memcpy(ins, block->instructions, block->instruction_count * sizeof(*block->instructions)); ++ sm6->p.instructions.count += block->instruction_count; ++ ++ sm6_parser_add_instruction(sm6, VKD3DSIH_RET); ++ ++ return true; ++} ++ + static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const struct dxil_block *block, + unsigned int level) + { +@@ -2065,6 +2111,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t + struct vkd3d_shader_version version; + struct dxil_block *block; + enum vkd3d_result ret; ++ unsigned int i; + + count = byte_code_size / sizeof(*byte_code); + if (count < 6) +@@ -2254,6 +2301,16 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t + return ret; + } + ++ for (i = 0; i < sm6->function_count; ++i) ++ { ++ if (!sm6_block_emit_instructions(sm6->functions[i].blocks[0], sm6)) ++ { ++ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, ++ "Out of memory emitting shader instructions."); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ } ++ + dxil_block_destroy(&sm6->root_block); + + return VKD3D_OK; +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +index ab508502623..4ed7712b0aa 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +@@ -2544,6 +2544,8 @@ static void dump_ir_resource_load(struct vkd3d_string_buffer *buffer, const stru + [HLSL_RESOURCE_GATHER_GREEN] = "gather_green", + [HLSL_RESOURCE_GATHER_BLUE] = "gather_blue", + [HLSL_RESOURCE_GATHER_ALPHA] = "gather_alpha", ++ [HLSL_RESOURCE_SAMPLE_INFO] = "sample_info", ++ [HLSL_RESOURCE_RESINFO] = "resinfo", + }; + + assert(load->load_type < ARRAY_SIZE(type_names)); +@@ -2551,8 +2553,11 @@ static void dump_ir_resource_load(struct vkd3d_string_buffer *buffer, const stru + dump_deref(buffer, &load->resource); + vkd3d_string_buffer_printf(buffer, ", sampler = "); + dump_deref(buffer, &load->sampler); +- vkd3d_string_buffer_printf(buffer, ", coords = "); +- dump_src(buffer, &load->coords); ++ if (load->coords.node) ++ { ++ vkd3d_string_buffer_printf(buffer, ", coords = "); ++ dump_src(buffer, &load->coords); ++ } + if (load->sample_index.node) + { + vkd3d_string_buffer_printf(buffer, ", sample index = "); +@@ -3296,9 +3301,11 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) + } + } + +-static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const char *source_name, ++static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info *compile_info, + const struct hlsl_profile_info *profile, struct vkd3d_shader_message_context *message_context) + { ++ unsigned int i; ++ + memset(ctx, 0, sizeof(*ctx)); + + ctx->profile = profile; +@@ -3307,7 +3314,7 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const char *source_name, + + if (!(ctx->source_files = hlsl_alloc(ctx, sizeof(*ctx->source_files)))) + return false; +- if (!(ctx->source_files[0] = hlsl_strdup(ctx, source_name ? source_name : ""))) ++ if (!(ctx->source_files[0] = hlsl_strdup(ctx, compile_info->source_name ? compile_info->source_name : ""))) + { + vkd3d_free(ctx->source_files); + return false; +@@ -3346,6 +3353,19 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const char *source_name, + return false; + ctx->cur_buffer = ctx->globals_buffer; + ++ for (i = 0; i < compile_info->option_count; ++i) ++ { ++ const struct vkd3d_shader_compile_option *option = &compile_info->options[i]; ++ ++ if (option->name == VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_ORDER) ++ { ++ if (option->value == VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_ROW_MAJOR) ++ ctx->matrix_majority = HLSL_MODIFIER_ROW_MAJOR; ++ else if (option->value == VKD3D_SHADER_COMPILE_OPTION_PACK_MATRIX_COLUMN_MAJOR) ++ ctx->matrix_majority = HLSL_MODIFIER_COLUMN_MAJOR; ++ } ++ } ++ + return true; + } + +@@ -3380,6 +3400,8 @@ static void hlsl_ctx_cleanup(struct hlsl_ctx *ctx) + vkd3d_free((void *)buffer->name); + vkd3d_free(buffer); + } ++ ++ vkd3d_free(ctx->constant_defs.regs); + } + + int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d_shader_compile_info *compile_info, +@@ -3421,7 +3443,7 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d + return VKD3D_ERROR_INVALID_ARGUMENT; + } + +- if (!hlsl_ctx_init(&ctx, compile_info->source_name, profile, message_context)) ++ if (!hlsl_ctx_init(&ctx, compile_info, profile, message_context)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if ((ret = hlsl_lexer_compile(&ctx, hlsl)) == 2) +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +index 1a4b995abbf..b1928312066 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +@@ -634,6 +634,8 @@ enum hlsl_resource_load_type + HLSL_RESOURCE_GATHER_GREEN, + HLSL_RESOURCE_GATHER_BLUE, + HLSL_RESOURCE_GATHER_ALPHA, ++ HLSL_RESOURCE_SAMPLE_INFO, ++ HLSL_RESOURCE_RESINFO, + }; + + struct hlsl_ir_resource_load +@@ -1074,7 +1076,7 @@ struct vkd3d_string_buffer *hlsl_component_to_string(struct hlsl_ctx *ctx, const + struct vkd3d_string_buffer *hlsl_modifiers_to_string(struct hlsl_ctx *ctx, unsigned int modifiers); + const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type); + +-struct hlsl_ir_node *hlsl_add_conditional(struct hlsl_ctx *ctx, struct list *instrs, ++struct hlsl_ir_node *hlsl_add_conditional(struct hlsl_ctx *ctx, struct hlsl_block *block, + struct hlsl_ir_node *condition, struct hlsl_ir_node *if_true, struct hlsl_ir_node *if_false); + void hlsl_add_function(struct hlsl_ctx *ctx, char *name, struct hlsl_ir_function_decl *decl); + bool hlsl_add_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *decl, bool local_var); +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +index 6bf87f8f916..0695f7864bf 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +@@ -146,14 +146,6 @@ static struct list *block_to_list(struct hlsl_block *block) + return &block->instrs; + } + +-static struct hlsl_block *list_to_block(struct list *list) +-{ +- /* This is a temporary hack to ease the transition from lists to blocks. +- * It takes advantage of the fact that an allocated hlsl_block pointer is +- * byte-compatible with an allocated list pointer. */ +- return CONTAINING_RECORD(list, struct hlsl_block, instrs); +-} +- + static struct hlsl_block *make_empty_block(struct hlsl_ctx *ctx) + { + struct hlsl_block *block; +@@ -172,12 +164,6 @@ static struct list *make_empty_list(struct hlsl_ctx *ctx) + return list; + } + +-static void destroy_instr_list(struct list *list) +-{ +- hlsl_free_instr_list(list); +- vkd3d_free(list); +-} +- + static void destroy_block(struct hlsl_block *block) + { + hlsl_block_cleanup(block); +@@ -308,7 +294,7 @@ static bool implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_typ + return hlsl_types_are_componentwise_equal(ctx, src, dst); + } + +-static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct hlsl_block *block, + struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) + { + struct hlsl_type *src_type = node->data_type; +@@ -345,7 +331,7 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, + { + struct hlsl_ir_node *component_load; + struct hlsl_type *dst_comp_type; +- struct hlsl_block block; ++ struct hlsl_block store_block; + unsigned int src_idx; + + if (broadcast) +@@ -365,21 +351,21 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, + + dst_comp_type = hlsl_type_get_component_type(ctx, dst_type, dst_idx); + +- if (!(component_load = hlsl_add_load_component(ctx, instrs, node, src_idx, loc))) ++ if (!(component_load = hlsl_add_load_component(ctx, block_to_list(block), node, src_idx, loc))) + return NULL; + + if (!(cast = hlsl_new_cast(ctx, component_load, dst_comp_type, loc))) + return NULL; +- list_add_tail(instrs, &cast->entry); ++ hlsl_block_add_instr(block, cast); + +- if (!hlsl_new_store_component(ctx, &block, &var_deref, dst_idx, cast)) ++ if (!hlsl_new_store_component(ctx, &store_block, &var_deref, dst_idx, cast)) + return NULL; +- list_move_tail(instrs, &block.instrs); ++ hlsl_block_add_block(block, &store_block); + } + + if (!(load = hlsl_new_var_load(ctx, var, loc))) + return NULL; +- list_add_tail(instrs, &load->node.entry); ++ hlsl_block_add_instr(block, &load->node); + + return &load->node; + } +@@ -387,12 +373,12 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, + { + if (!(cast = hlsl_new_cast(ctx, node, dst_type, loc))) + return NULL; +- list_add_tail(instrs, &cast->entry); ++ hlsl_block_add_instr(block, cast); + return cast; + } + } + +-static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct hlsl_block *block, + struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) + { + struct hlsl_type *src_type = node->data_type; +@@ -418,7 +404,7 @@ static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct + hlsl_warning(ctx, loc, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION, "Implicit truncation of %s type.", + src_type->class == HLSL_CLASS_VECTOR ? "vector" : "matrix"); + +- return add_cast(ctx, instrs, node, dst_type, loc); ++ return add_cast(ctx, block, node, dst_type, loc); + } + + static DWORD add_modifiers(struct hlsl_ctx *ctx, DWORD modifiers, DWORD mod, +@@ -665,7 +651,7 @@ static bool add_return(struct hlsl_ctx *ctx, struct hlsl_block *block, + { + struct hlsl_ir_node *store; + +- if (!(return_value = add_implicit_conversion(ctx, block_to_list(block), return_value, return_type, loc))) ++ if (!(return_value = add_implicit_conversion(ctx, block, return_value, return_type, loc))) + return false; + + if (!(store = hlsl_new_simple_store(ctx, ctx->cur_function->return_var, return_value))) +@@ -736,7 +722,7 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, + const struct vkd3d_shader_location *loc); + +-static bool add_array_access(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *array, ++static bool add_array_access(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *array, + struct hlsl_ir_node *index, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *expr_type = array->data_type, *index_type = index->data_type; +@@ -759,13 +745,13 @@ static bool add_array_access(struct hlsl_ctx *ctx, struct list *instrs, struct h + return false; + } + +- if (!(index = add_implicit_conversion(ctx, instrs, index, ++ if (!(index = add_implicit_conversion(ctx, block, index, + hlsl_get_vector_type(ctx, HLSL_TYPE_UINT, dim_count), &index->loc))) + return false; + + if (!(return_index = hlsl_new_index(ctx, array, index, loc))) + return false; +- list_add_tail(instrs, &return_index->entry); ++ hlsl_block_add_instr(block, return_index); + + return true; + } +@@ -778,7 +764,7 @@ static bool add_array_access(struct hlsl_ctx *ctx, struct list *instrs, struct h + + if (!(cast = hlsl_new_cast(ctx, index, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), &index->loc))) + return false; +- list_add_tail(instrs, &cast->entry); ++ hlsl_block_add_instr(block, cast); + index = cast; + + if (expr_type->class != HLSL_CLASS_ARRAY && expr_type->class != HLSL_CLASS_VECTOR && expr_type->class != HLSL_CLASS_MATRIX) +@@ -792,7 +778,7 @@ static bool add_array_access(struct hlsl_ctx *ctx, struct list *instrs, struct h + + if (!(return_index = hlsl_new_index(ctx, array, index, loc))) + return false; +- list_add_tail(instrs, &return_index->entry); ++ hlsl_block_add_instr(block, return_index); + + return true; + } +@@ -1117,17 +1103,17 @@ static struct hlsl_ir_function_decl *get_func_decl(struct rb_tree *funcs, + return NULL; + } + +-static struct list *make_list(struct hlsl_ctx *ctx, struct hlsl_ir_node *node) ++static struct hlsl_block *make_block(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr) + { +- struct list *list; ++ struct hlsl_block *block; + +- if (!(list = make_empty_list(ctx))) ++ if (!(block = make_empty_block(ctx))) + { +- hlsl_free_instr(node); ++ hlsl_free_instr(instr); + return NULL; + } +- list_add_tail(list, &node->entry); +- return list; ++ hlsl_block_add_instr(block, instr); ++ return block; + } + + static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, struct hlsl_block *block, +@@ -1165,7 +1151,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str + return 0; + hlsl_block_add_block(&expr, block); + +- if (!add_implicit_conversion(ctx, &expr.instrs, node_from_block(&expr), ++ if (!add_implicit_conversion(ctx, &expr, node_from_block(&expr), + hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc)) + { + hlsl_block_cleanup(&expr); +@@ -1323,7 +1309,7 @@ static bool expr_common_shape(struct hlsl_ctx *ctx, struct hlsl_type *t1, struct + return true; + } + +-static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, ++static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS], + struct hlsl_type *type, const struct vkd3d_shader_location *loc) + { +@@ -1347,38 +1333,38 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, + for (i = 0; i < type->dimy * type->dimx; ++i) + { + struct hlsl_ir_node *value, *cell_operands[HLSL_MAX_OPERANDS] = { NULL }; +- struct hlsl_block block; ++ struct hlsl_block store_block; + unsigned int j; + + for (j = 0; j < HLSL_MAX_OPERANDS; j++) + { + if (operands[j]) + { +- if (!(load = hlsl_add_load_component(ctx, instrs, operands[j], i, loc))) ++ if (!(load = hlsl_add_load_component(ctx, block_to_list(block), operands[j], i, loc))) + return NULL; + + cell_operands[j] = load; + } + } + +- if (!(value = add_expr(ctx, instrs, op, cell_operands, scalar_type, loc))) ++ if (!(value = add_expr(ctx, block, op, cell_operands, scalar_type, loc))) + return NULL; + +- if (!hlsl_new_store_component(ctx, &block, &var_deref, i, value)) ++ if (!hlsl_new_store_component(ctx, &store_block, &var_deref, i, value)) + return NULL; +- list_move_tail(instrs, &block.instrs); ++ hlsl_block_add_block(block, &store_block); + } + + if (!(var_load = hlsl_new_var_load(ctx, var, loc))) + return NULL; +- list_add_tail(instrs, &var_load->node.entry); ++ hlsl_block_add_instr(block, &var_load->node); + + return &var_load->node; + } + + if (!(expr = hlsl_new_expr(ctx, op, operands, type, loc))) + return NULL; +- list_add_tail(instrs, &expr->entry); ++ hlsl_block_add_instr(block, expr); + + return expr; + } +@@ -1409,7 +1395,7 @@ static struct hlsl_ir_node *add_unary_arithmetic_expr(struct hlsl_ctx *ctx, stru + { + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {arg}; + +- return add_expr(ctx, block_to_list(block), op, args, arg->data_type, loc); ++ return add_expr(ctx, block, op, args, arg->data_type, loc); + } + + static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, +@@ -1429,10 +1415,10 @@ static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct + bool_type = hlsl_get_numeric_type(ctx, arg->data_type->class, HLSL_TYPE_BOOL, + arg->data_type->dimx, arg->data_type->dimy); + +- if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg, bool_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block, arg, bool_type, loc))) + return NULL; + +- return add_expr(ctx, block_to_list(block), op, args, bool_type, loc); ++ return add_expr(ctx, block, op, args, bool_type, loc); + } + + static struct hlsl_type *get_common_numeric_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *arg1, +@@ -1457,13 +1443,13 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str + + common_type = get_common_numeric_type(ctx, arg1, arg2, loc); + +- if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block, arg1, common_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, block, arg2, common_type, loc))) + return NULL; + +- return add_expr(ctx, block_to_list(block), op, args, common_type, loc); ++ return add_expr(ctx, block, op, args, common_type, loc); + } + + static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, +@@ -1492,13 +1478,13 @@ static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, str + common_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); + return_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); + +- if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block, arg1, common_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, block, arg2, common_type, loc))) + return NULL; + +- return add_expr(ctx, block_to_list(block), op, args, return_type, loc); ++ return add_expr(ctx, block, op, args, return_type, loc); + } + + static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, +@@ -1515,13 +1501,13 @@ static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct + + common_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); + +- if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block, arg1, common_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, block, arg2, common_type, loc))) + return NULL; + +- return add_expr(ctx, block_to_list(block), op, args, common_type, loc); ++ return add_expr(ctx, block, op, args, common_type, loc); + } + + static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, +@@ -1546,13 +1532,13 @@ static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct h + return_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); + integer_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_INT, dimx, dimy); + +- if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, return_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, block, arg1, return_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, integer_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, block, arg2, integer_type, loc))) + return NULL; + +- return add_expr(ctx, block_to_list(block), op, args, return_type, loc); ++ return add_expr(ctx, block, op, args, return_type, loc); + } + + static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct hlsl_block *instrs, +@@ -1599,13 +1585,13 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct hls + common_type = hlsl_get_vector_type(ctx, base, dim); + ret_type = hlsl_get_scalar_type(ctx, base); + +- if (!(args[0] = add_implicit_conversion(ctx, block_to_list(instrs), arg1, common_type, loc))) ++ if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) + return NULL; + +- if (!(args[1] = add_implicit_conversion(ctx, block_to_list(instrs), arg2, common_type, loc))) ++ if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) + return NULL; + +- return add_expr(ctx, block_to_list(instrs), op, args, ret_type, loc); ++ return add_expr(ctx, instrs, op, args, ret_type, loc); + } + + static struct hlsl_block *add_binary_expr_merge(struct hlsl_ctx *ctx, struct hlsl_block *block1, +@@ -1711,7 +1697,7 @@ static bool invert_swizzle(unsigned int *swizzle, unsigned int *writemask, unsig + return true; + } + +-static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *lhs, ++static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *lhs, + enum parse_assign_op assign_op, struct hlsl_ir_node *rhs) + { + struct hlsl_type *lhs_type = lhs->data_type; +@@ -1720,7 +1706,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + + if (assign_op == ASSIGN_OP_SUB) + { +- if (!(rhs = add_unary_arithmetic_expr(ctx, list_to_block(instrs), HLSL_OP1_NEG, rhs, &rhs->loc))) ++ if (!(rhs = add_unary_arithmetic_expr(ctx, block, HLSL_OP1_NEG, rhs, &rhs->loc))) + return NULL; + assign_op = ASSIGN_OP_ADD; + } +@@ -1729,14 +1715,14 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + enum hlsl_ir_expr_op op = op_from_assignment(assign_op); + + assert(op); +- if (!(rhs = add_binary_arithmetic_expr(ctx, list_to_block(instrs), op, lhs, rhs, &rhs->loc))) ++ if (!(rhs = add_binary_arithmetic_expr(ctx, block, op, lhs, rhs, &rhs->loc))) + return NULL; + } + + if (lhs_type->class <= HLSL_CLASS_LAST_NUMERIC) + writemask = (1 << lhs_type->dimx) - 1; + +- if (!(rhs = add_implicit_conversion(ctx, instrs, rhs, lhs_type, &rhs->loc))) ++ if (!(rhs = add_implicit_conversion(ctx, block, rhs, lhs_type, &rhs->loc))) + return NULL; + + while (lhs->type != HLSL_IR_LOAD && lhs->type != HLSL_IR_INDEX) +@@ -1765,7 +1751,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + { + return NULL; + } +- list_add_tail(instrs, &new_swizzle->entry); ++ hlsl_block_add_instr(block, new_swizzle); + + lhs = swizzle->val.node; + rhs = new_swizzle; +@@ -1811,7 +1797,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + hlsl_cleanup_deref(&resource_deref); + return NULL; + } +- list_add_tail(instrs, &store->entry); ++ hlsl_block_add_instr(block, store); + hlsl_cleanup_deref(&resource_deref); + } + else if (lhs->type == HLSL_IR_INDEX && hlsl_index_is_noncontiguous(hlsl_ir_index(lhs))) +@@ -1830,13 +1816,13 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + + if (!(c = hlsl_new_uint_constant(ctx, i, &lhs->loc))) + return NULL; +- list_add_tail(instrs, &c->entry); ++ hlsl_block_add_instr(block, c); + + if (!(cell = hlsl_new_index(ctx, &row->node, c, &lhs->loc))) + return NULL; +- list_add_tail(instrs, &cell->entry); ++ hlsl_block_add_instr(block, cell); + +- if (!(load = hlsl_add_load_component(ctx, instrs, rhs, k++, &rhs->loc))) ++ if (!(load = hlsl_add_load_component(ctx, block_to_list(block), rhs, k++, &rhs->loc))) + return NULL; + + if (!hlsl_init_deref_from_index_chain(ctx, &deref, cell)) +@@ -1847,7 +1833,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + hlsl_cleanup_deref(&deref); + return NULL; + } +- list_add_tail(instrs, &store->entry); ++ hlsl_block_add_instr(block, store); + hlsl_cleanup_deref(&deref); + } + } +@@ -1864,7 +1850,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + hlsl_cleanup_deref(&deref); + return NULL; + } +- list_add_tail(instrs, &store->entry); ++ hlsl_block_add_instr(block, store); + hlsl_cleanup_deref(&deref); + } + +@@ -1873,7 +1859,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in + * the last instruction in the list, we do need to copy. */ + if (!(copy = hlsl_new_copy(ctx, rhs))) + return NULL; +- list_add_tail(instrs, ©->entry); ++ hlsl_block_add_instr(block, copy); + return copy; + } + +@@ -1891,7 +1877,7 @@ static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool d + return false; + hlsl_block_add_instr(block, one); + +- if (!add_assignment(ctx, block_to_list(block), lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) ++ if (!add_assignment(ctx, block, lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) + return false; + + if (post) +@@ -1930,7 +1916,7 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i + + dst_comp_type = hlsl_type_get_component_type(ctx, dst->data_type, *store_index); + +- if (!(conv = add_implicit_conversion(ctx, block_to_list(instrs), load, dst_comp_type, &src->loc))) ++ if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) + return; + + if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) +@@ -2183,14 +2169,14 @@ static void declare_var(struct hlsl_ctx *ctx, struct parse_variable_def *v) + } + } + +-static struct list *initialize_vars(struct hlsl_ctx *ctx, struct list *var_list) ++static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var_list) + { + struct parse_variable_def *v, *v_next; +- struct list *statements_list; ++ struct hlsl_block *initializers; + struct hlsl_ir_var *var; + struct hlsl_type *type; + +- if (!(statements_list = make_empty_list(ctx))) ++ if (!(initializers = make_empty_block(ctx))) + { + LIST_FOR_EACH_ENTRY_SAFE(v, v_next, var_list, struct parse_variable_def, entry) + { +@@ -2239,13 +2225,13 @@ static struct list *initialize_vars(struct hlsl_ctx *ctx, struct list *var_list) + + assert(v->initializer.args_count == 1); + hlsl_block_add_instr(v->initializer.instrs, &load->node); +- add_assignment(ctx, block_to_list(v->initializer.instrs), &load->node, ASSIGN_OP_ASSIGN, v->initializer.args[0]); ++ add_assignment(ctx, v->initializer.instrs, &load->node, ASSIGN_OP_ASSIGN, v->initializer.args[0]); + } + + if (var->storage_modifiers & HLSL_STORAGE_STATIC) + hlsl_block_add_block(&ctx->static_initializers, v->initializer.instrs); + else +- list_move_tail(statements_list, &v->initializer.instrs->instrs); ++ hlsl_block_add_block(initializers, v->initializer.instrs); + } + else if (var->storage_modifiers & HLSL_STORAGE_STATIC) + { +@@ -2266,7 +2252,7 @@ static struct list *initialize_vars(struct hlsl_ctx *ctx, struct list *var_list) + } + hlsl_block_add_instr(&ctx->static_initializers, zero); + +- if (!(cast = add_cast(ctx, &ctx->static_initializers.instrs, zero, var->data_type, &var->loc))) ++ if (!(cast = add_cast(ctx, &ctx->static_initializers, zero, var->data_type, &var->loc))) + { + free_parse_variable_def(v); + continue; +@@ -2283,7 +2269,7 @@ static struct list *initialize_vars(struct hlsl_ctx *ctx, struct list *var_list) + } + + vkd3d_free(var_list); +- return statements_list; ++ return initializers; + } + + struct find_function_call_args +@@ -2364,7 +2350,7 @@ static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, + return arg; + + type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); +- return add_implicit_conversion(ctx, block_to_list(params->instrs), arg, type, loc); ++ return add_implicit_conversion(ctx, params->instrs, arg, type, loc); + } + + static bool convert_args(struct hlsl_ctx *ctx, const struct parse_initializer *params, +@@ -2376,7 +2362,7 @@ static bool convert_args(struct hlsl_ctx *ctx, const struct parse_initializer *p + { + struct hlsl_ir_node *new_arg; + +- if (!(new_arg = add_implicit_conversion(ctx, block_to_list(params->instrs), params->args[i], type, loc))) ++ if (!(new_arg = add_implicit_conversion(ctx, params->instrs, params->args[i], type, loc))) + return false; + params->args[i] = new_arg; + } +@@ -2569,7 +2555,7 @@ static bool intrinsic_asfloat(struct hlsl_ctx *ctx, + data_type = convert_numeric_type(ctx, data_type, HLSL_TYPE_FLOAT); + + operands[0] = params->args[0]; +- return add_expr(ctx, block_to_list(params->instrs), HLSL_OP1_REINTERPRET, operands, data_type, loc); ++ return add_expr(ctx, params->instrs, HLSL_OP1_REINTERPRET, operands, data_type, loc); + } + + static bool intrinsic_asuint(struct hlsl_ctx *ctx, +@@ -2605,7 +2591,7 @@ static bool intrinsic_asuint(struct hlsl_ctx *ctx, + data_type = convert_numeric_type(ctx, data_type, HLSL_TYPE_UINT); + + operands[0] = params->args[0]; +- return add_expr(ctx, block_to_list(params->instrs), HLSL_OP1_REINTERPRET, operands, data_type, loc); ++ return add_expr(ctx, params->instrs, HLSL_OP1_REINTERPRET, operands, data_type, loc); + } + + static bool intrinsic_clamp(struct hlsl_ctx *ctx, +@@ -2677,10 +2663,10 @@ static bool intrinsic_cross(struct hlsl_ctx *ctx, + + cast_type = hlsl_get_vector_type(ctx, base, 3); + +- if (!(arg1_cast = add_implicit_conversion(ctx, block_to_list(params->instrs), arg1, cast_type, loc))) ++ if (!(arg1_cast = add_implicit_conversion(ctx, params->instrs, arg1, cast_type, loc))) + return false; + +- if (!(arg2_cast = add_implicit_conversion(ctx, block_to_list(params->instrs), arg2, cast_type, loc))) ++ if (!(arg2_cast = add_implicit_conversion(ctx, params->instrs, arg2, cast_type, loc))) + return false; + + if (!(arg1_swzl1 = hlsl_new_swizzle(ctx, HLSL_SWIZZLE(Z, X, Y, Z), 3, arg1_cast, loc))) +@@ -2879,7 +2865,7 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer + if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, div, zero, loc))) + return false; + +- if (!(select = hlsl_add_conditional(ctx, block_to_list(params->instrs), ge, frac, neg_frac))) ++ if (!(select = hlsl_add_conditional(ctx, params->instrs, ge, frac, neg_frac))) + return false; + + return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, select, y, loc); +@@ -3042,7 +3028,7 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, + if (!(specular_pow = add_pow_expr(ctx, params->instrs, n_h, m, loc))) + return false; + +- if (!(load = hlsl_add_conditional(ctx, block_to_list(params->instrs), specular_or, zero, specular_pow))) ++ if (!(load = hlsl_add_conditional(ctx, params->instrs, specular_or, zero, specular_pow))) + return false; + + if (!hlsl_new_store_component(ctx, &block, &var_deref, 2, load)) +@@ -3163,10 +3149,10 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, + ret_type = hlsl_get_scalar_type(ctx, base); + } + +- if (!(cast1 = add_implicit_conversion(ctx, block_to_list(params->instrs), arg1, cast_type1, loc))) ++ if (!(cast1 = add_implicit_conversion(ctx, params->instrs, arg1, cast_type1, loc))) + return false; + +- if (!(cast2 = add_implicit_conversion(ctx, block_to_list(params->instrs), arg2, cast_type2, loc))) ++ if (!(cast2 = add_implicit_conversion(ctx, params->instrs, arg2, cast_type2, loc))) + return false; + + if (!(var = hlsl_new_synthetic_var(ctx, "mul", matrix_type, loc))) +@@ -3216,7 +3202,7 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, + return false; + hlsl_block_add_instr(params->instrs, &load->node); + +- return !!add_implicit_conversion(ctx, block_to_list(params->instrs), &load->node, ret_type, loc); ++ return !!add_implicit_conversion(ctx, params->instrs, &load->node, ret_type, loc); + } + + static bool intrinsic_normalize(struct hlsl_ctx *ctx, +@@ -3328,7 +3314,7 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, + if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, zero, arg, loc))) + return false; + +- if (!(op1 = add_implicit_conversion(ctx, block_to_list(params->instrs), lt, int_type, loc))) ++ if (!(op1 = add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) + return false; + + /* Check if arg < 0, cast bool to int and invert (meaning true is -1) */ +@@ -3336,7 +3322,7 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, + if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, arg, zero, loc))) + return false; + +- if (!(op2 = add_implicit_conversion(ctx, block_to_list(params->instrs), lt, int_type, loc))) ++ if (!(op2 = add_implicit_conversion(ctx, params->instrs, lt, int_type, loc))) + return false; + + if (!(neg = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, op2, loc))) +@@ -3441,7 +3427,7 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, + + type = ge->data_type; + type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); +- return !!add_implicit_conversion(ctx, block_to_list(params->instrs), ge, type, loc); ++ return !!add_implicit_conversion(ctx, params->instrs, ge, type, loc); + } + + static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, +@@ -3476,7 +3462,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * + hlsl_release_string_buffer(ctx, string); + } + +- if (!(coords = add_implicit_conversion(ctx, block_to_list(params->instrs), params->args[1], ++ if (!(coords = add_implicit_conversion(ctx, params->instrs, params->args[1], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, hlsl_sampler_dim_count(dim)), loc))) + coords = params->args[1]; + +@@ -3684,7 +3670,14 @@ static int intrinsic_function_name_compare(const void *a, const void *b) + return strcmp(a, func->name); + } + +-static struct list *add_call(struct hlsl_ctx *ctx, const char *name, ++static struct hlsl_ir_node *hlsl_new_void_expr(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = {0}; ++ ++ return hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc); ++} ++ ++static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name, + struct parse_initializer *args, const struct vkd3d_shader_location *loc) + { + struct intrinsic_function *intrinsic; +@@ -3706,7 +3699,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, + { + struct hlsl_ir_node *cast; + +- if (!(cast = add_cast(ctx, block_to_list(args->instrs), arg, param->data_type, &arg->loc))) ++ if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc))) + goto fail; + args->args[i] = cast; + arg = cast; +@@ -3743,7 +3736,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, + goto fail; + hlsl_block_add_instr(args->instrs, &load->node); + +- if (!add_assignment(ctx, block_to_list(args->instrs), arg, ASSIGN_OP_ASSIGN, &load->node)) ++ if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &load->node)) + goto fail; + } + } +@@ -3758,10 +3751,9 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, + } + else + { +- struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = {0}; + struct hlsl_ir_node *expr; + +- if (!(expr = hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc))) ++ if (!(expr = hlsl_new_void_expr(ctx, loc))) + goto fail; + hlsl_block_add_instr(args->instrs, expr); + } +@@ -3812,7 +3804,7 @@ static struct list *add_call(struct hlsl_ctx *ctx, const char *name, + goto fail; + } + vkd3d_free(args->args); +- return block_to_list(args->instrs); ++ return args->instrs; + + fail: + free_parse_initializer(args); +@@ -3890,7 +3882,7 @@ static bool raise_invalid_method_object_type(struct hlsl_ctx *ctx, const struct + return false; + } + +-static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++static bool add_load_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *object_type = object->data_type; +@@ -3918,7 +3910,7 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, stru + } + if (multisampled) + { +- if (!(load_params.sample_index = add_implicit_conversion(ctx, instrs, params->args[1], ++ if (!(load_params.sample_index = add_implicit_conversion(ctx, block, params->args[1], + hlsl_get_scalar_type(ctx, HLSL_TYPE_INT), loc))) + return false; + } +@@ -3926,7 +3918,7 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, stru + assert(offset_dim); + if (params->args_count > 1 + multisampled) + { +- if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[1 + multisampled], ++ if (!(load_params.texel_offset = add_implicit_conversion(ctx, block, params->args[1 + multisampled], + hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) + return false; + } +@@ -3936,7 +3928,7 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, stru + } + + /* +1 for the mipmap level for non-multisampled textures */ +- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[0], ++ if (!(load_params.coords = add_implicit_conversion(ctx, block, params->args[0], + hlsl_get_vector_type(ctx, HLSL_TYPE_INT, sampler_dim + !multisampled), loc))) + return false; + +@@ -3945,11 +3937,11 @@ static bool add_load_method_call(struct hlsl_ctx *ctx, struct list *instrs, stru + + if (!(load = hlsl_new_resource_load(ctx, &load_params, loc))) + return false; +- list_add_tail(instrs, &load->entry); ++ hlsl_block_add_instr(block, load); + return true; + } + +-static bool add_sample_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++static bool add_sample_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *object_type = object->data_type; +@@ -3986,13 +3978,13 @@ static bool add_sample_method_call(struct hlsl_ctx *ctx, struct list *instrs, st + return false; + } + +- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], ++ if (!(load_params.coords = add_implicit_conversion(ctx, block, params->args[1], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + return false; + + if (offset_dim && params->args_count > 2) + { +- if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[2], ++ if (!(load_params.texel_offset = add_implicit_conversion(ctx, block, params->args[2], + hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) + return false; + } +@@ -4008,12 +4000,12 @@ static bool add_sample_method_call(struct hlsl_ctx *ctx, struct list *instrs, st + + if (!(load = hlsl_new_resource_load(ctx, &load_params, loc))) + return false; +- list_add_tail(instrs, &load->entry); ++ hlsl_block_add_instr(block, load); + + return true; + } + +-static bool add_sample_cmp_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++static bool add_sample_cmp_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *object_type = object->data_type; +@@ -4056,17 +4048,17 @@ static bool add_sample_cmp_method_call(struct hlsl_ctx *ctx, struct list *instrs + return false; + } + +- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], ++ if (!(load_params.coords = add_implicit_conversion(ctx, block, params->args[1], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + return false; + +- if (!(load_params.cmp = add_implicit_conversion(ctx, instrs, params->args[2], ++ if (!(load_params.cmp = add_implicit_conversion(ctx, block, params->args[2], + hlsl_get_scalar_type(ctx, HLSL_TYPE_FLOAT), loc))) + load_params.cmp = params->args[2]; + + if (offset_dim && params->args_count > 3) + { +- if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[2], ++ if (!(load_params.texel_offset = add_implicit_conversion(ctx, block, params->args[2], + hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) + return false; + } +@@ -4082,12 +4074,12 @@ static bool add_sample_cmp_method_call(struct hlsl_ctx *ctx, struct list *instrs + + if (!(load = hlsl_new_resource_load(ctx, &load_params, loc))) + return false; +- list_add_tail(instrs, &load->entry); ++ hlsl_block_add_instr(block, load); + + return true; + } + +-static bool add_gather_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++static bool add_gather_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *object_type = object->data_type; +@@ -4154,7 +4146,7 @@ static bool add_gather_method_call(struct hlsl_ctx *ctx, struct list *instrs, st + } + else if (offset_dim && params->args_count > 2) + { +- if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[2], ++ if (!(load_params.texel_offset = add_implicit_conversion(ctx, block, params->args[2], + hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) + return false; + } +@@ -4179,7 +4171,7 @@ static bool add_gather_method_call(struct hlsl_ctx *ctx, struct list *instrs, st + return false; + } + +- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], ++ if (!(load_params.coords = add_implicit_conversion(ctx, block, params->args[1], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + return false; + +@@ -4189,11 +4181,187 @@ static bool add_gather_method_call(struct hlsl_ctx *ctx, struct list *instrs, st + + if (!(load = hlsl_new_resource_load(ctx, &load_params, loc))) + return false; +- list_add_tail(instrs, &load->entry); ++ hlsl_block_add_instr(block, load); ++ return true; ++} ++ ++static bool add_assignment_from_component(struct hlsl_ctx *ctx, struct hlsl_block *instrs, struct hlsl_ir_node *dest, ++ struct hlsl_ir_node *src, unsigned int component, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_node *load; ++ ++ if (!dest) ++ return true; ++ ++ if (!(load = hlsl_add_load_component(ctx, block_to_list(instrs), src, component, loc))) ++ return false; ++ ++ if (!add_assignment(ctx, instrs, dest, ASSIGN_OP_ASSIGN, load)) ++ return false; ++ + return true; + } + +-static bool add_sample_lod_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++static bool add_getdimensions_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, ++ const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) ++{ ++ const struct hlsl_type *object_type = object->data_type; ++ bool uint_resinfo, has_uint_arg, has_float_arg; ++ struct hlsl_resource_load_params load_params; ++ struct hlsl_ir_node *sample_info, *res_info; ++ struct hlsl_ir_node *zero = NULL, *void_ret; ++ struct hlsl_type *uint_type, *float_type; ++ unsigned int i, j; ++ enum func_argument ++ { ++ ARG_MIP_LEVEL, ++ ARG_WIDTH, ++ ARG_HEIGHT, ++ ARG_ELEMENT_COUNT, ++ ARG_LEVEL_COUNT, ++ ARG_SAMPLE_COUNT, ++ ARG_MAX_ARGS, ++ }; ++ struct hlsl_ir_node *args[ARG_MAX_ARGS] = { 0 }; ++ static const struct overload ++ { ++ enum hlsl_sampler_dim sampler_dim; ++ unsigned int args_count; ++ enum func_argument args[ARG_MAX_ARGS]; ++ } ++ overloads[] = ++ { ++ { HLSL_SAMPLER_DIM_1D, 1, { ARG_WIDTH } }, ++ { HLSL_SAMPLER_DIM_1D, 3, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_LEVEL_COUNT } }, ++ { HLSL_SAMPLER_DIM_1DARRAY, 2, { ARG_WIDTH, ARG_ELEMENT_COUNT } }, ++ { HLSL_SAMPLER_DIM_1DARRAY, 4, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_ELEMENT_COUNT, ARG_LEVEL_COUNT } }, ++ { HLSL_SAMPLER_DIM_2D, 2, { ARG_WIDTH, ARG_HEIGHT } }, ++ { HLSL_SAMPLER_DIM_2D, 4, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_HEIGHT, ARG_LEVEL_COUNT } }, ++ { HLSL_SAMPLER_DIM_2DARRAY, 3, { ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT } }, ++ { HLSL_SAMPLER_DIM_2DARRAY, 5, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT, ARG_LEVEL_COUNT } }, ++ { HLSL_SAMPLER_DIM_3D, 3, { ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT } }, ++ { HLSL_SAMPLER_DIM_3D, 5, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT, ARG_LEVEL_COUNT } }, ++ { HLSL_SAMPLER_DIM_CUBE, 2, { ARG_WIDTH, ARG_HEIGHT } }, ++ { HLSL_SAMPLER_DIM_CUBE, 4, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_HEIGHT, ARG_LEVEL_COUNT } }, ++ { HLSL_SAMPLER_DIM_CUBEARRAY, 3, { ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT } }, ++ { HLSL_SAMPLER_DIM_CUBEARRAY, 5, { ARG_MIP_LEVEL, ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT, ARG_LEVEL_COUNT } }, ++ { HLSL_SAMPLER_DIM_2DMS, 3, { ARG_WIDTH, ARG_HEIGHT, ARG_SAMPLE_COUNT } }, ++ { HLSL_SAMPLER_DIM_2DMSARRAY, 4, { ARG_WIDTH, ARG_HEIGHT, ARG_ELEMENT_COUNT, ARG_SAMPLE_COUNT } }, ++ }; ++ const struct overload *o = NULL; ++ ++ if (object_type->sampler_dim > HLSL_SAMPLER_DIM_LAST_TEXTURE) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "GetDimensions() is not defined for this type."); ++ } ++ ++ uint_type = hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT); ++ float_type = hlsl_get_scalar_type(ctx, HLSL_TYPE_FLOAT); ++ has_uint_arg = has_float_arg = false; ++ for (i = 0; i < ARRAY_SIZE(overloads); ++i) ++ { ++ const struct overload *iter = &overloads[i]; ++ ++ if (iter->sampler_dim == object_type->sampler_dim && iter->args_count == params->args_count) ++ { ++ for (j = 0; j < params->args_count; ++j) ++ { ++ args[iter->args[j]] = params->args[j]; ++ ++ /* Input parameter. */ ++ if (iter->args[j] == ARG_MIP_LEVEL) ++ { ++ if (!(args[ARG_MIP_LEVEL] = add_implicit_conversion(ctx, block, args[ARG_MIP_LEVEL], ++ hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc))) ++ { ++ return false; ++ } ++ ++ continue; ++ } ++ ++ has_float_arg |= hlsl_types_are_equal(params->args[j]->data_type, float_type); ++ has_uint_arg |= hlsl_types_are_equal(params->args[j]->data_type, uint_type); ++ ++ if (params->args[j]->data_type->class != HLSL_CLASS_SCALAR) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Expected scalar arguments."); ++ break; ++ } ++ } ++ o = iter; ++ break; ++ } ++ } ++ uint_resinfo = !has_float_arg && has_uint_arg; ++ ++ if (!o) ++ { ++ struct vkd3d_string_buffer *string; ++ ++ if ((string = hlsl_type_to_string(ctx, object_type))) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, ++ "Unexpected number of arguments %u for %s.%s().", params->args_count, string->buffer, name); ++ hlsl_release_string_buffer(ctx, string); ++ } ++ } ++ ++ if (!args[ARG_MIP_LEVEL]) ++ { ++ if (!(zero = hlsl_new_uint_constant(ctx, 0, loc))) ++ return false; ++ hlsl_block_add_instr(block, zero); ++ args[ARG_MIP_LEVEL] = zero; ++ } ++ ++ memset(&load_params, 0, sizeof(load_params)); ++ load_params.type = HLSL_RESOURCE_RESINFO; ++ load_params.resource = object; ++ load_params.lod = args[ARG_MIP_LEVEL]; ++ load_params.format = hlsl_get_vector_type(ctx, uint_resinfo ? HLSL_TYPE_UINT : HLSL_TYPE_FLOAT, 4); ++ ++ if (!(res_info = hlsl_new_resource_load(ctx, &load_params, loc))) ++ return false; ++ hlsl_block_add_instr(block, res_info); ++ ++ if (!add_assignment_from_component(ctx, block, args[ARG_WIDTH], res_info, 0, loc)) ++ return false; ++ ++ if (!add_assignment_from_component(ctx, block, args[ARG_HEIGHT], res_info, 1, loc)) ++ return false; ++ ++ if (!add_assignment_from_component(ctx, block, args[ARG_ELEMENT_COUNT], res_info, ++ object_type->sampler_dim == HLSL_SAMPLER_DIM_1DARRAY ? 1 : 2, loc)) ++ { ++ return false; ++ } ++ ++ if (!add_assignment_from_component(ctx, block, args[ARG_LEVEL_COUNT], res_info, 3, loc)) ++ return false; ++ ++ if (args[ARG_SAMPLE_COUNT]) ++ { ++ memset(&load_params, 0, sizeof(load_params)); ++ load_params.type = HLSL_RESOURCE_SAMPLE_INFO; ++ load_params.resource = object; ++ load_params.format = args[ARG_SAMPLE_COUNT]->data_type; ++ if (!(sample_info = hlsl_new_resource_load(ctx, &load_params, loc))) ++ return false; ++ hlsl_block_add_instr(block, sample_info); ++ ++ if (!add_assignment(ctx, block, args[ARG_SAMPLE_COUNT], ASSIGN_OP_ASSIGN, sample_info)) ++ return false; ++ } ++ ++ if (!(void_ret = hlsl_new_void_expr(ctx, loc))) ++ return false; ++ hlsl_block_add_instr(block, void_ret); ++ ++ return true; ++} ++ ++static bool add_sample_lod_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *object_type = object->data_type; +@@ -4235,17 +4403,17 @@ static bool add_sample_lod_method_call(struct hlsl_ctx *ctx, struct list *instrs + return false; + } + +- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], ++ if (!(load_params.coords = add_implicit_conversion(ctx, block, params->args[1], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + load_params.coords = params->args[1]; + +- if (!(load_params.lod = add_implicit_conversion(ctx, instrs, params->args[2], ++ if (!(load_params.lod = add_implicit_conversion(ctx, block, params->args[2], + hlsl_get_scalar_type(ctx, HLSL_TYPE_FLOAT), loc))) + load_params.lod = params->args[2]; + + if (offset_dim && params->args_count > 3) + { +- if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[3], ++ if (!(load_params.texel_offset = add_implicit_conversion(ctx, block, params->args[3], + hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) + return false; + } +@@ -4259,11 +4427,11 @@ static bool add_sample_lod_method_call(struct hlsl_ctx *ctx, struct list *instrs + + if (!(load = hlsl_new_resource_load(ctx, &load_params, loc))) + return false; +- list_add_tail(instrs, &load->entry); ++ hlsl_block_add_instr(block, load); + return true; + } + +-static bool add_sample_grad_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++static bool add_sample_grad_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *object_type = object->data_type; +@@ -4302,21 +4470,21 @@ static bool add_sample_grad_method_call(struct hlsl_ctx *ctx, struct list *instr + return false; + } + +- if (!(load_params.coords = add_implicit_conversion(ctx, instrs, params->args[1], ++ if (!(load_params.coords = add_implicit_conversion(ctx, block, params->args[1], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + load_params.coords = params->args[1]; + +- if (!(load_params.ddx = add_implicit_conversion(ctx, instrs, params->args[2], ++ if (!(load_params.ddx = add_implicit_conversion(ctx, block, params->args[2], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + load_params.ddx = params->args[2]; + +- if (!(load_params.ddy = add_implicit_conversion(ctx, instrs, params->args[3], ++ if (!(load_params.ddy = add_implicit_conversion(ctx, block, params->args[3], + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) + load_params.ddy = params->args[3]; + + if (offset_dim && params->args_count > 4) + { +- if (!(load_params.texel_offset = add_implicit_conversion(ctx, instrs, params->args[4], ++ if (!(load_params.texel_offset = add_implicit_conversion(ctx, block, params->args[4], + hlsl_get_vector_type(ctx, HLSL_TYPE_INT, offset_dim), loc))) + return false; + } +@@ -4330,14 +4498,14 @@ static bool add_sample_grad_method_call(struct hlsl_ctx *ctx, struct list *instr + + if (!(load = hlsl_new_resource_load(ctx, &load_params, loc))) + return false; +- list_add_tail(instrs, &load->entry); ++ hlsl_block_add_instr(block, load); + return true; + } + + static const struct method_function + { + const char *name; +- bool (*handler)(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++ bool (*handler)(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc); + } + object_methods[] = +@@ -4348,6 +4516,8 @@ object_methods[] = + { "GatherGreen", add_gather_method_call }, + { "GatherRed", add_gather_method_call }, + ++ { "GetDimensions", add_getdimensions_method_call }, ++ + { "Load", add_load_method_call }, + + { "Sample", add_sample_method_call }, +@@ -4365,7 +4535,7 @@ static int object_method_function_name_compare(const void *a, const void *b) + return strcmp(a, func->name); + } + +-static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *object, ++static bool add_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *object, + const char *name, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { + const struct hlsl_type *object_type = object->data_type; +@@ -4386,7 +4556,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl + if ((method = bsearch(name, object_methods, ARRAY_SIZE(object_methods), + sizeof(*method), object_method_function_name_compare))) + { +- return method->handler(ctx, instrs, object, name, params, loc); ++ return method->handler(ctx, block, object, name, params, loc); + } + else + { +@@ -4557,10 +4727,6 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type + %token C_INTEGER + %token PRE_LINE + +-%type declaration +-%type declaration_statement +-%type primary_expr +-%type struct_declaration_without_vars + %type type_specs + %type variables_def + %type variables_def_typed +@@ -4586,6 +4752,8 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type + %type bitxor_expr + %type compound_statement + %type conditional_expr ++%type declaration ++%type declaration_statement + %type equality_expr + %type expr + %type expr_optional +@@ -4597,11 +4765,13 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type + %type loop_statement + %type mul_expr + %type postfix_expr ++%type primary_expr + %type relational_expr + %type shift_expr + %type selection_statement + %type statement + %type statement_list ++%type struct_declaration_without_vars + %type unary_expr + + %type boolean +@@ -4661,9 +4831,9 @@ hlsl_prog: + | hlsl_prog buffer_declaration buffer_body + | hlsl_prog declaration_statement + { +- if (!list_empty($2)) ++ if (!list_empty(&$2->instrs)) + hlsl_fixme(ctx, &@2, "Uniform initializer."); +- destroy_instr_list($2); ++ destroy_block($2); + } + | hlsl_prog preproc_directive + | hlsl_prog ';' +@@ -4731,7 +4901,7 @@ struct_declaration_without_vars: + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, + "Modifiers are not allowed on struct type declarations."); + +- if (!($$ = make_empty_list(ctx))) ++ if (!($$ = make_empty_block(ctx))) + YYABORT; + } + +@@ -5515,7 +5685,7 @@ declaration_statement: + | struct_declaration_without_vars + | typedef + { +- if (!($$ = make_empty_list(ctx))) ++ if (!($$ = make_empty_block(ctx))) + YYABORT; + } + +@@ -5912,9 +6082,6 @@ statement_list: + + statement: + declaration_statement +- { +- $$ = list_to_block($1); +- } + | expr_statement + | compound_statement + | jump_statement +@@ -6006,7 +6173,7 @@ loop_statement: + } + | attribute_list_optional KW_FOR '(' scope_start declaration expr_statement expr_optional ')' statement + { +- $$ = create_loop(ctx, LOOP_FOR, &$1, list_to_block($5), $6, $7, $9, &@2); ++ $$ = create_loop(ctx, LOOP_FOR, &$1, $5, $6, $7, $9, &@2); + hlsl_pop_scope(ctx); + } + +@@ -6042,7 +6209,7 @@ primary_expr: + + if (!(c = hlsl_new_float_constant(ctx, $1, &@1))) + YYABORT; +- if (!($$ = make_list(ctx, c))) ++ if (!($$ = make_block(ctx, c))) + YYABORT; + } + | C_INTEGER +@@ -6051,7 +6218,7 @@ primary_expr: + + if (!(c = hlsl_new_int_constant(ctx, $1, &@1))) + YYABORT; +- if (!($$ = make_list(ctx, c))) ++ if (!($$ = make_block(ctx, c))) + YYABORT; + } + | boolean +@@ -6060,7 +6227,7 @@ primary_expr: + + if (!(c = hlsl_new_bool_constant(ctx, $1, &@1))) + YYABORT; +- if (!($$ = make_list(ctx, c))) ++ if (!($$ = make_block(ctx, c))) + { + hlsl_free_instr(c); + YYABORT; +@@ -6078,12 +6245,12 @@ primary_expr: + } + if (!(load = hlsl_new_var_load(ctx, var, &@1))) + YYABORT; +- if (!($$ = make_list(ctx, &load->node))) ++ if (!($$ = make_block(ctx, &load->node))) + YYABORT; + } + | '(' expr ')' + { +- $$ = block_to_list($2); ++ $$ = $2; + } + | var_identifier '(' func_arguments ')' + { +@@ -6106,7 +6273,7 @@ primary_expr: + YYABORT; + if (!(load = hlsl_new_var_load(ctx, var, &@1))) + YYABORT; +- if (!($$ = make_list(ctx, &load->node))) ++ if (!($$ = make_block(ctx, &load->node))) + YYABORT; + } + else +@@ -6118,9 +6285,6 @@ primary_expr: + + postfix_expr: + primary_expr +- { +- $$ = list_to_block($1); +- } + | postfix_expr OP_INC + { + if (!add_increment(ctx, $1, false, true, &@2)) +@@ -6185,7 +6349,7 @@ postfix_expr: + hlsl_block_add_block($3, $1); + destroy_block($1); + +- if (!add_array_access(ctx, block_to_list($3), array, index, &@2)) ++ if (!add_array_access(ctx, $3, array, index, &@2)) + { + destroy_block($3); + YYABORT; +@@ -6236,7 +6400,7 @@ postfix_expr: + hlsl_block_add_block($1, $5.instrs); + vkd3d_free($5.instrs); + +- if (!add_method_call(ctx, block_to_list($1), object, $3, &$5, &@3)) ++ if (!add_method_call(ctx, $1, object, $3, &$5, &@3)) + { + destroy_block($1); + vkd3d_free($5.args); +@@ -6324,7 +6488,7 @@ unary_expr: + YYABORT; + } + +- if (!add_cast(ctx, block_to_list($6), node_from_block($6), dst_type, &@3)) ++ if (!add_cast(ctx, $6, node_from_block($6), dst_type, &@3)) + { + destroy_block($6); + YYABORT; +@@ -6455,13 +6619,13 @@ conditional_expr: + if (!(common_type = get_common_numeric_type(ctx, first, second, &@3))) + YYABORT; + +- if (!(first = add_implicit_conversion(ctx, block_to_list($1), first, common_type, &@3))) ++ if (!(first = add_implicit_conversion(ctx, $1, first, common_type, &@3))) + YYABORT; + +- if (!(second = add_implicit_conversion(ctx, block_to_list($1), second, common_type, &@5))) ++ if (!(second = add_implicit_conversion(ctx, $1, second, common_type, &@5))) + YYABORT; + +- if (!hlsl_add_conditional(ctx, block_to_list($1), cond, first, second)) ++ if (!hlsl_add_conditional(ctx, $1, cond, first, second)) + YYABORT; + $$ = $1; + } +@@ -6480,7 +6644,7 @@ assignment_expr: + } + hlsl_block_add_block($3, $1); + destroy_block($1); +- if (!add_assignment(ctx, block_to_list($3), lhs, $2, rhs)) ++ if (!add_assignment(ctx, $3, lhs, $2, rhs)) + YYABORT; + $$ = $3; + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +index 09a3ea4ca08..4f5a5b02a67 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +@@ -574,6 +574,37 @@ bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, + return progress; + } + ++typedef bool (*PFN_lower_func)(struct hlsl_ctx *, struct hlsl_ir_node *, struct hlsl_block *); ++ ++static bool call_lower_func(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++{ ++ PFN_lower_func func = context; ++ struct hlsl_block block; ++ ++ hlsl_block_init(&block); ++ if (func(ctx, instr, &block)) ++ { ++ struct hlsl_ir_node *replacement = LIST_ENTRY(list_tail(&block.instrs), struct hlsl_ir_node, entry); ++ ++ list_move_before(&instr->entry, &block.instrs); ++ hlsl_replace_node(instr, replacement); ++ return true; ++ } ++ else ++ { ++ hlsl_block_cleanup(&block); ++ return false; ++ } ++} ++ ++/* Specific form of transform_ir() for passes which convert a single instruction ++ * to a block of one or more instructions. This helper takes care of setting up ++ * the block and calling hlsl_replace_node_with_block(). */ ++static bool lower_ir(struct hlsl_ctx *ctx, PFN_lower_func func, struct hlsl_block *block) ++{ ++ return hlsl_transform_ir(ctx, call_lower_func, block, func); ++} ++ + static bool transform_instr_derefs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) + { + bool res; +@@ -2087,9 +2118,11 @@ static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *in + case HLSL_RESOURCE_GATHER_GREEN: + case HLSL_RESOURCE_GATHER_BLUE: + case HLSL_RESOURCE_GATHER_ALPHA: ++ case HLSL_RESOURCE_RESINFO: + case HLSL_RESOURCE_SAMPLE_CMP: + case HLSL_RESOURCE_SAMPLE_CMP_LZ: + case HLSL_RESOURCE_SAMPLE_GRAD: ++ case HLSL_RESOURCE_SAMPLE_INFO: + return false; + + case HLSL_RESOURCE_SAMPLE: +@@ -2356,7 +2389,7 @@ static bool lower_casts_to_bool(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr + return true; + } + +-struct hlsl_ir_node *hlsl_add_conditional(struct hlsl_ctx *ctx, struct list *instrs, ++struct hlsl_ir_node *hlsl_add_conditional(struct hlsl_ctx *ctx, struct hlsl_block *instrs, + struct hlsl_ir_node *condition, struct hlsl_ir_node *if_true, struct hlsl_ir_node *if_false) + { + struct hlsl_block then_block, else_block; +@@ -2382,18 +2415,18 @@ struct hlsl_ir_node *hlsl_add_conditional(struct hlsl_ctx *ctx, struct list *ins + + if (!(iff = hlsl_new_if(ctx, condition, &then_block, &else_block, &condition->loc))) + return NULL; +- list_add_tail(instrs, &iff->entry); ++ hlsl_block_add_instr(instrs, iff); + + if (!(load = hlsl_new_var_load(ctx, var, &condition->loc))) + return NULL; +- list_add_tail(instrs, &load->node.entry); ++ hlsl_block_add_instr(instrs, &load->node); + + return &load->node; + } + +-static bool lower_int_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++static bool lower_int_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) + { +- struct hlsl_ir_node *arg1, *arg2, *xor, *and, *abs1, *abs2, *div, *neg, *cast1, *cast2, *cast3, *cond, *high_bit; ++ struct hlsl_ir_node *arg1, *arg2, *xor, *and, *abs1, *abs2, *div, *neg, *cast1, *cast2, *cast3, *high_bit; + struct hlsl_type *type = instr->data_type, *utype; + struct hlsl_constant_value high_bit_value; + struct hlsl_ir_expr *expr; +@@ -2414,56 +2447,52 @@ static bool lower_int_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + + if (!(xor = hlsl_new_binary_expr(ctx, HLSL_OP2_BIT_XOR, arg1, arg2))) + return false; +- list_add_before(&instr->entry, &xor->entry); ++ hlsl_block_add_instr(block, xor); + + for (i = 0; i < type->dimx; ++i) + high_bit_value.u[i].u = 0x80000000; + if (!(high_bit = hlsl_new_constant(ctx, type, &high_bit_value, &instr->loc))) + return false; +- list_add_before(&instr->entry, &high_bit->entry); ++ hlsl_block_add_instr(block, high_bit); + + if (!(and = hlsl_new_binary_expr(ctx, HLSL_OP2_BIT_AND, xor, high_bit))) + return false; +- list_add_before(&instr->entry, &and->entry); ++ hlsl_block_add_instr(block, and); + + if (!(abs1 = hlsl_new_unary_expr(ctx, HLSL_OP1_ABS, arg1, &instr->loc))) + return false; +- list_add_before(&instr->entry, &abs1->entry); ++ hlsl_block_add_instr(block, abs1); + + if (!(cast1 = hlsl_new_cast(ctx, abs1, utype, &instr->loc))) + return false; +- list_add_before(&instr->entry, &cast1->entry); ++ hlsl_block_add_instr(block, cast1); + + if (!(abs2 = hlsl_new_unary_expr(ctx, HLSL_OP1_ABS, arg2, &instr->loc))) + return false; +- list_add_before(&instr->entry, &abs2->entry); ++ hlsl_block_add_instr(block, abs2); + + if (!(cast2 = hlsl_new_cast(ctx, abs2, utype, &instr->loc))) + return false; +- list_add_before(&instr->entry, &cast2->entry); ++ hlsl_block_add_instr(block, cast2); + + if (!(div = hlsl_new_binary_expr(ctx, HLSL_OP2_DIV, cast1, cast2))) + return false; +- list_add_before(&instr->entry, &div->entry); ++ hlsl_block_add_instr(block, div); + + if (!(cast3 = hlsl_new_cast(ctx, div, type, &instr->loc))) + return false; +- list_add_before(&instr->entry, &cast3->entry); ++ hlsl_block_add_instr(block, cast3); + + if (!(neg = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, cast3, &instr->loc))) + return false; +- list_add_before(&instr->entry, &neg->entry); +- +- if (!(cond = hlsl_add_conditional(ctx, &instr->entry, and, neg, cast3))) +- return false; +- hlsl_replace_node(instr, cond); ++ hlsl_block_add_instr(block, neg); + +- return true; ++ return hlsl_add_conditional(ctx, block, and, neg, cast3); + } + +-static bool lower_int_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++static bool lower_int_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) + { +- struct hlsl_ir_node *arg1, *arg2, *and, *abs1, *abs2, *div, *neg, *cast1, *cast2, *cast3, *cond, *high_bit; ++ struct hlsl_ir_node *arg1, *arg2, *and, *abs1, *abs2, *div, *neg, *cast1, *cast2, *cast3, *high_bit; + struct hlsl_type *type = instr->data_type, *utype; + struct hlsl_constant_value high_bit_value; + struct hlsl_ir_expr *expr; +@@ -2486,45 +2515,41 @@ static bool lower_int_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + high_bit_value.u[i].u = 0x80000000; + if (!(high_bit = hlsl_new_constant(ctx, type, &high_bit_value, &instr->loc))) + return false; +- list_add_before(&instr->entry, &high_bit->entry); ++ hlsl_block_add_instr(block, high_bit); + + if (!(and = hlsl_new_binary_expr(ctx, HLSL_OP2_BIT_AND, arg1, high_bit))) + return false; +- list_add_before(&instr->entry, &and->entry); ++ hlsl_block_add_instr(block, and); + + if (!(abs1 = hlsl_new_unary_expr(ctx, HLSL_OP1_ABS, arg1, &instr->loc))) + return false; +- list_add_before(&instr->entry, &abs1->entry); ++ hlsl_block_add_instr(block, abs1); + + if (!(cast1 = hlsl_new_cast(ctx, abs1, utype, &instr->loc))) + return false; +- list_add_before(&instr->entry, &cast1->entry); ++ hlsl_block_add_instr(block, cast1); + + if (!(abs2 = hlsl_new_unary_expr(ctx, HLSL_OP1_ABS, arg2, &instr->loc))) + return false; +- list_add_before(&instr->entry, &abs2->entry); ++ hlsl_block_add_instr(block, abs2); + + if (!(cast2 = hlsl_new_cast(ctx, abs2, utype, &instr->loc))) + return false; +- list_add_before(&instr->entry, &cast2->entry); ++ hlsl_block_add_instr(block, cast2); + + if (!(div = hlsl_new_binary_expr(ctx, HLSL_OP2_MOD, cast1, cast2))) + return false; +- list_add_before(&instr->entry, &div->entry); ++ hlsl_block_add_instr(block, div); + + if (!(cast3 = hlsl_new_cast(ctx, div, type, &instr->loc))) + return false; +- list_add_before(&instr->entry, &cast3->entry); ++ hlsl_block_add_instr(block, cast3); + + if (!(neg = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, cast3, &instr->loc))) + return false; +- list_add_before(&instr->entry, &neg->entry); +- +- if (!(cond = hlsl_add_conditional(ctx, &instr->entry, and, neg, cast3))) +- return false; +- hlsl_replace_node(instr, cond); ++ hlsl_block_add_instr(block, neg); + +- return true; ++ return hlsl_add_conditional(ctx, block, and, neg, cast3); + } + + static bool lower_int_abs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +@@ -2608,9 +2633,9 @@ static bool lower_int_dot(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void + return false; + } + +-static bool lower_float_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++static bool lower_float_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) + { +- struct hlsl_ir_node *arg1, *arg2, *mul1, *neg1, *ge, *neg2, *div, *mul2, *frc, *cond, *one; ++ struct hlsl_ir_node *arg1, *arg2, *mul1, *neg1, *ge, *neg2, *div, *mul2, *frc, *cond, *one, *mul3; + struct hlsl_type *type = instr->data_type, *btype; + struct hlsl_constant_value one_value; + struct hlsl_ir_expr *expr; +@@ -2631,47 +2656,45 @@ static bool lower_float_modulus(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr + + if (!(mul1 = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, arg2, arg1))) + return false; +- list_add_before(&instr->entry, &mul1->entry); ++ hlsl_block_add_instr(block, mul1); + + if (!(neg1 = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, mul1, &instr->loc))) + return false; +- list_add_before(&instr->entry, &neg1->entry); ++ hlsl_block_add_instr(block, neg1); + + if (!(ge = hlsl_new_binary_expr(ctx, HLSL_OP2_GEQUAL, mul1, neg1))) + return false; + ge->data_type = btype; +- list_add_before(&instr->entry, &ge->entry); ++ hlsl_block_add_instr(block, ge); + + if (!(neg2 = hlsl_new_unary_expr(ctx, HLSL_OP1_NEG, arg2, &instr->loc))) + return false; +- list_add_before(&instr->entry, &neg2->entry); ++ hlsl_block_add_instr(block, neg2); + +- if (!(cond = hlsl_add_conditional(ctx, &instr->entry, ge, arg2, neg2))) ++ if (!(cond = hlsl_add_conditional(ctx, block, ge, arg2, neg2))) + return false; + + for (i = 0; i < type->dimx; ++i) + one_value.u[i].f = 1.0f; + if (!(one = hlsl_new_constant(ctx, type, &one_value, &instr->loc))) + return false; +- list_add_before(&instr->entry, &one->entry); ++ hlsl_block_add_instr(block, one); + + if (!(div = hlsl_new_binary_expr(ctx, HLSL_OP2_DIV, one, cond))) + return false; +- list_add_before(&instr->entry, &div->entry); ++ hlsl_block_add_instr(block, div); + + if (!(mul2 = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, div, arg1))) + return false; +- list_add_before(&instr->entry, &mul2->entry); ++ hlsl_block_add_instr(block, mul2); + + if (!(frc = hlsl_new_unary_expr(ctx, HLSL_OP1_FRACT, mul2, &instr->loc))) + return false; +- list_add_before(&instr->entry, &frc->entry); ++ hlsl_block_add_instr(block, frc); + +- expr->op = HLSL_OP2_MUL; +- hlsl_src_remove(&expr->operands[0]); +- hlsl_src_remove(&expr->operands[1]); +- hlsl_src_from_node(&expr->operands[0], frc); +- hlsl_src_from_node(&expr->operands[1], cond); ++ if (!(mul3 = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, frc, cond))) ++ return false; ++ hlsl_block_add_instr(block, mul3); + + return true; + } +@@ -2683,8 +2706,8 @@ static bool lower_discard_neg(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + struct hlsl_type *arg_type, *cmp_type; + struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = { 0 }; + struct hlsl_ir_jump *jump; ++ struct hlsl_block block; + unsigned int i, count; +- struct list instrs; + + if (instr->type != HLSL_IR_JUMP) + return false; +@@ -2692,38 +2715,38 @@ static bool lower_discard_neg(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, + if (jump->type != HLSL_IR_JUMP_DISCARD_NEG) + return false; + +- list_init(&instrs); ++ hlsl_block_init(&block); + + arg_type = jump->condition.node->data_type; + if (!(zero = hlsl_new_constant(ctx, arg_type, &zero_value, &instr->loc))) + return false; +- list_add_tail(&instrs, &zero->entry); ++ hlsl_block_add_instr(&block, zero); + + operands[0] = jump->condition.node; + operands[1] = zero; + cmp_type = hlsl_get_numeric_type(ctx, arg_type->class, HLSL_TYPE_BOOL, arg_type->dimx, arg_type->dimy); + if (!(cmp = hlsl_new_expr(ctx, HLSL_OP2_LESS, operands, cmp_type, &instr->loc))) + return false; +- list_add_tail(&instrs, &cmp->entry); ++ hlsl_block_add_instr(&block, cmp); + + if (!(bool_false = hlsl_new_constant(ctx, hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL), &zero_value, &instr->loc))) + return false; +- list_add_tail(&instrs, &bool_false->entry); ++ hlsl_block_add_instr(&block, bool_false); + + or = bool_false; + + count = hlsl_type_component_count(cmp_type); + for (i = 0; i < count; ++i) + { +- if (!(load = hlsl_add_load_component(ctx, &instrs, cmp, i, &instr->loc))) ++ if (!(load = hlsl_add_load_component(ctx, &block.instrs, cmp, i, &instr->loc))) + return false; + + if (!(or = hlsl_new_binary_expr(ctx, HLSL_OP2_LOGIC_OR, or, load))) + return NULL; +- list_add_tail(&instrs, &or->entry); ++ hlsl_block_add_instr(&block, or); + } + +- list_move_tail(&instr->entry, &instrs); ++ list_move_tail(&instr->entry, &block.instrs); + hlsl_src_remove(&jump->condition); + hlsl_src_from_node(&jump->condition, or); + jump->type = HLSL_IR_JUMP_DISCARD_NZ; +@@ -2953,7 +2976,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + load->sampler.offset.node->last_read = last_read; + } + +- load->coords.node->last_read = last_read; ++ if (load->coords.node) ++ load->coords.node->last_read = last_read; + if (load->texel_offset.node) + load->texel_offset.node->last_read = last_read; + if (load->lod.node) +@@ -4268,10 +4292,10 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + hlsl_transform_ir(ctx, lower_narrowing_casts, body, NULL); + hlsl_transform_ir(ctx, lower_casts_to_bool, body, NULL); + hlsl_transform_ir(ctx, lower_int_dot, body, NULL); +- hlsl_transform_ir(ctx, lower_int_division, body, NULL); +- hlsl_transform_ir(ctx, lower_int_modulus, body, NULL); ++ lower_ir(ctx, lower_int_division, body); ++ lower_ir(ctx, lower_int_modulus, body); + hlsl_transform_ir(ctx, lower_int_abs, body, NULL); +- hlsl_transform_ir(ctx, lower_float_modulus, body, NULL); ++ lower_ir(ctx, lower_float_modulus, body); + hlsl_transform_ir(ctx, fold_redundant_casts, body, NULL); + do + { +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index 9eefb82c226..d74f81afc39 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -247,13 +247,13 @@ static void shader_register_init(struct vkd3d_shader_register *reg, enum vkd3d_s + reg->immconst_type = VKD3D_IMMCONST_SCALAR; + } + +-static void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode handler_idx) ++void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode handler_idx) + { + memset(ins, 0, sizeof(*ins)); + ins->handler_idx = handler_idx; + } + +-enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions) ++static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions) + { + struct hull_flattener flattener = {*src_instructions}; + struct vkd3d_shader_instruction_array *instructions; +@@ -388,7 +388,7 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p + return VKD3D_OK; + } + +-enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( ++static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( + struct vkd3d_shader_instruction_array *src_instructions, const struct shader_signature *input_signature) + { + struct vkd3d_shader_instruction_array *instructions; +@@ -999,7 +999,7 @@ static void shader_instruction_normalise_io_params(struct vkd3d_shader_instructi + shader_instruction_init(ins, VKD3DSIH_NOP); + } + +-enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_shader_instruction_array *instructions, ++static enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_shader_instruction_array *instructions, + enum vkd3d_shader_type shader_type, struct shader_signature *input_signature, + struct shader_signature *output_signature, struct shader_signature *patch_constant_signature) + { +@@ -1070,3 +1070,154 @@ enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_shader_i + *instructions = normaliser.instructions; + return VKD3D_OK; + } ++ ++struct flat_constant_def ++{ ++ enum vkd3d_shader_d3dbc_constant_register set; ++ uint32_t index; ++ uint32_t value[4]; ++}; ++ ++struct flat_constants_normaliser ++{ ++ struct vkd3d_shader_parser *parser; ++ struct flat_constant_def *defs; ++ size_t def_count, defs_capacity; ++}; ++ ++static bool get_flat_constant_register_type(const struct vkd3d_shader_register *reg, ++ enum vkd3d_shader_d3dbc_constant_register *set, uint32_t *index) ++{ ++ static const struct ++ { ++ enum vkd3d_shader_register_type type; ++ enum vkd3d_shader_d3dbc_constant_register set; ++ uint32_t offset; ++ } ++ regs[] = ++ { ++ {VKD3DSPR_CONST, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 0}, ++ {VKD3DSPR_CONST2, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 2048}, ++ {VKD3DSPR_CONST3, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 4096}, ++ {VKD3DSPR_CONST4, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 6144}, ++ {VKD3DSPR_CONSTINT, VKD3D_SHADER_D3DBC_INT_CONSTANT_REGISTER, 0}, ++ {VKD3DSPR_CONSTBOOL, VKD3D_SHADER_D3DBC_BOOL_CONSTANT_REGISTER, 0}, ++ }; ++ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(regs); ++i) ++ { ++ if (reg->type == regs[i].type) ++ { ++ if (reg->idx[0].rel_addr) ++ { ++ FIXME("Unhandled relative address.\n"); ++ return false; ++ } ++ ++ *set = regs[i].set; ++ *index = regs[i].offset + reg->idx[0].offset; ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_param *param, ++ const struct flat_constants_normaliser *normaliser) ++{ ++ enum vkd3d_shader_d3dbc_constant_register set; ++ uint32_t index; ++ size_t i, j; ++ ++ if (!get_flat_constant_register_type(¶m->reg, &set, &index)) ++ return; ++ ++ for (i = 0; i < normaliser->def_count; ++i) ++ { ++ if (normaliser->defs[i].set == set && normaliser->defs[i].index == index) ++ { ++ param->reg.type = VKD3DSPR_IMMCONST; ++ param->reg.idx_count = 0; ++ param->reg.immconst_type = VKD3D_IMMCONST_VEC4; ++ for (j = 0; j < 4; ++j) ++ param->reg.u.immconst_uint[j] = normaliser->defs[i].value[j]; ++ return; ++ } ++ } ++ ++ param->reg.type = VKD3DSPR_CONSTBUFFER; ++ param->reg.idx[0].offset = set; /* register ID */ ++ param->reg.idx[1].offset = set; /* register index */ ++ param->reg.idx[2].offset = index; /* buffer index */ ++ param->reg.idx_count = 3; ++} ++ ++static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d_shader_parser *parser) ++{ ++ struct flat_constants_normaliser normaliser = {.parser = parser}; ++ unsigned int i, j; ++ ++ for (i = 0; i < parser->instructions.count; ++i) ++ { ++ struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i]; ++ ++ if (ins->handler_idx == VKD3DSIH_DEF || ins->handler_idx == VKD3DSIH_DEFI || ins->handler_idx == VKD3DSIH_DEFB) ++ { ++ struct flat_constant_def *def; ++ ++ if (!vkd3d_array_reserve((void **)&normaliser.defs, &normaliser.defs_capacity, ++ normaliser.def_count + 1, sizeof(*normaliser.defs))) ++ { ++ vkd3d_free(normaliser.defs); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ ++ def = &normaliser.defs[normaliser.def_count++]; ++ ++ get_flat_constant_register_type((struct vkd3d_shader_register *)&ins->dst[0].reg, &def->set, &def->index); ++ for (j = 0; j < 4; ++j) ++ def->value[j] = ins->src[0].reg.u.immconst_uint[j]; ++ ++ vkd3d_shader_instruction_make_nop(ins); ++ } ++ else ++ { ++ for (j = 0; j < ins->src_count; ++j) ++ shader_register_normalise_flat_constants((struct vkd3d_shader_src_param *)&ins->src[j], &normaliser); ++ } ++ } ++ ++ vkd3d_free(normaliser.defs); ++ return VKD3D_OK; ++} ++ ++enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser) ++{ ++ struct vkd3d_shader_instruction_array *instructions = &parser->instructions; ++ enum vkd3d_result result = VKD3D_OK; ++ ++ if (parser->shader_desc.is_dxil) ++ return result; ++ ++ if (parser->shader_version.type == VKD3D_SHADER_TYPE_HULL ++ && (result = instruction_array_flatten_hull_shader_phases(instructions)) >= 0) ++ { ++ result = instruction_array_normalise_hull_shader_control_point_io(instructions, ++ &parser->shader_desc.input_signature); ++ } ++ if (result >= 0) ++ result = instruction_array_normalise_io_registers(instructions, parser->shader_version.type, ++ &parser->shader_desc.input_signature, &parser->shader_desc.output_signature, ++ &parser->shader_desc.patch_constant_signature); ++ ++ if (result >= 0) ++ result = instruction_array_normalise_flat_constants(parser); ++ ++ if (result >= 0 && TRACE_ON()) ++ vkd3d_shader_trace(instructions, &parser->shader_version); ++ ++ return result; ++} +diff --git a/libs/vkd3d/libs/vkd3d-shader/preproc.l b/libs/vkd3d/libs/vkd3d-shader/preproc.l +index 94079696280..6fb61eff6c3 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/preproc.l ++++ b/libs/vkd3d/libs/vkd3d-shader/preproc.l +@@ -30,6 +30,13 @@ + + #define YY_DECL static int preproc_lexer_lex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner) + ++static struct preproc_macro *preproc_get_top_macro(struct preproc_ctx *ctx) ++{ ++ if (!ctx->expansion_count) ++ return NULL; ++ return ctx->expansion_stack[ctx->expansion_count - 1].macro; ++} ++ + static void update_location(struct preproc_ctx *ctx); + + #define YY_USER_ACTION update_location(yyget_extra(yyscanner)); +@@ -125,7 +132,20 @@ INT_SUFFIX [uUlL]{0,2} + const char *p; + + if (!ctx->last_was_newline) +- return T_HASHSTRING; ++ { ++ struct preproc_macro *macro; ++ ++ /* Stringification is only done for function-like macro bodies. ++ * Anywhere else, we need to parse it as two separate tokens. ++ * We could use a state for this, but yyless() is easier and cheap. ++ */ ++ ++ if ((macro = preproc_get_top_macro(ctx)) && macro->arg_count) ++ return T_HASHSTRING; ++ ++ yyless(1); ++ return T_TEXT; ++ } + + for (p = yytext + 1; strchr(" \t", *p); ++p) + ; +@@ -219,13 +239,6 @@ static bool preproc_is_writing(struct preproc_ctx *ctx) + return file->if_stack[file->if_count - 1].current_true; + } + +-static struct preproc_macro *preproc_get_top_macro(struct preproc_ctx *ctx) +-{ +- if (!ctx->expansion_count) +- return NULL; +- return ctx->expansion_stack[ctx->expansion_count - 1].macro; +-} +- + /* Concatenation is not done for object-like macros, but is done for both + * function-like macro bodies and their arguments. */ + static bool should_concat(struct preproc_ctx *ctx) +@@ -334,6 +347,43 @@ static bool preproc_push_expansion(struct preproc_ctx *ctx, + return true; + } + ++static void preproc_stringify(struct preproc_ctx *ctx, struct vkd3d_string_buffer *buffer, const char *text) ++{ ++ const struct preproc_text *expansion; ++ const char *p = text + 1; ++ unsigned int i; ++ ++ while (*p == ' ' || *p == '\t') ++ ++p; ++ ++ vkd3d_string_buffer_printf(buffer, "\""); ++ if ((expansion = find_arg_expansion(ctx, p))) ++ { ++ size_t len = expansion->text.content_size; ++ size_t start = 0; ++ ++ while (len && strchr(" \t\r\n", expansion->text.buffer[len - 1])) ++ --len; ++ ++ while (start < len && strchr(" \t\r\n", expansion->text.buffer[start])) ++ ++start; ++ ++ for (i = start; i < len; ++i) ++ { ++ char c = expansion->text.buffer[i]; ++ ++ if (c == '\\' || c == '"') ++ vkd3d_string_buffer_printf(buffer, "\\"); ++ vkd3d_string_buffer_printf(buffer, "%c", c); ++ } ++ } ++ else ++ { ++ vkd3d_string_buffer_printf(buffer, "%s", p); ++ } ++ vkd3d_string_buffer_printf(buffer, "\""); ++} ++ + int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) + { + struct preproc_ctx *ctx = yyget_extra(scanner); +@@ -441,9 +491,6 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) + switch (func_state->state) + { + case STATE_NONE: +- { +- struct preproc_macro *macro; +- + if (token == T_CONCAT && should_concat(ctx)) + { + while (ctx->buffer.content_size +@@ -452,37 +499,17 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) + break; + } + +- /* Stringification, however, is only done for function-like +- * macro bodies. */ +- if (token == T_HASHSTRING && (macro = preproc_get_top_macro(ctx)) && macro->arg_count) ++ if (token == T_HASHSTRING) + { +- const struct preproc_text *expansion; +- const char *p = text + 1; +- unsigned int i; ++ struct vkd3d_string_buffer buffer; + + if (ctx->current_directive) + return return_token(token, lval, text); + +- while (*p == ' ' || *p == '\t') +- ++p; +- +- vkd3d_string_buffer_printf(&ctx->buffer, "\""); +- if ((expansion = find_arg_expansion(ctx, p))) +- { +- for (i = 0; i < expansion->text.content_size; ++i) +- { +- char c = expansion->text.buffer[i]; +- +- if (c == '\\' || c == '"') +- vkd3d_string_buffer_printf(&ctx->buffer, "\\"); +- vkd3d_string_buffer_printf(&ctx->buffer, "%c", c); +- } +- } +- else +- { +- vkd3d_string_buffer_printf(&ctx->buffer, "%s", p); +- } +- vkd3d_string_buffer_printf(&ctx->buffer, "\""); ++ vkd3d_string_buffer_init(&buffer); ++ preproc_stringify(ctx, &buffer, text); ++ vkd3d_string_buffer_printf(&ctx->buffer, "%s", buffer.buffer); ++ vkd3d_string_buffer_cleanup(&buffer); + break; + } + +@@ -586,7 +613,6 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) + else + vkd3d_string_buffer_printf(&ctx->buffer, "%s ", text); + break; +- } + + case STATE_IDENTIFIER: + if (token == '(') +@@ -628,6 +654,41 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) + + switch (token) + { ++ /* Most text gets left alone (e.g. if it contains macros, ++ * the macros should be evaluated later). ++ * Arguments are a special case, and are replaced with ++ * their values immediately. */ ++ case T_IDENTIFIER: ++ case T_IDENTIFIER_PAREN: ++ { ++ const struct preproc_text *expansion; ++ ++ if ((expansion = find_arg_expansion(ctx, text))) ++ { ++ preproc_push_expansion(ctx, expansion, NULL); ++ continue; ++ } ++ ++ if (current_arg) ++ preproc_text_add(current_arg, text); ++ break; ++ } ++ ++ /* Stringification is another special case. Unsurprisingly, ++ * we need to stringify if this is an argument. More ++ * surprisingly, we need to stringify even if it's not. */ ++ case T_HASHSTRING: ++ { ++ struct vkd3d_string_buffer buffer; ++ ++ vkd3d_string_buffer_init(&buffer); ++ preproc_stringify(ctx, &buffer, text); ++ if (current_arg) ++ preproc_text_add(current_arg, buffer.buffer); ++ vkd3d_string_buffer_cleanup(&buffer); ++ break; ++ } ++ + case T_NEWLINE: + if (current_arg) + preproc_text_add(current_arg, " "); +@@ -686,6 +747,9 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) + if (current_arg) + preproc_text_add(current_arg, text); + } ++ ++ if (current_arg) ++ preproc_text_add(current_arg, " "); + break; + } + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 9725a5c7e25..d71f0a698d9 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -199,6 +199,21 @@ enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d + } + } + ++static inline bool register_is_undef(const struct vkd3d_shader_register *reg) ++{ ++ return reg->type == VKD3DSPR_UNDEF; ++} ++ ++static inline bool register_is_constant(const struct vkd3d_shader_register *reg) ++{ ++ return (reg->type == VKD3DSPR_IMMCONST || reg->type == VKD3DSPR_IMMCONST64); ++} ++ ++static inline bool register_is_constant_or_undef(const struct vkd3d_shader_register *reg) ++{ ++ return register_is_constant(reg) || register_is_undef(reg); ++} ++ + #define VKD3D_SPIRV_VERSION 0x00010000 + #define VKD3D_SPIRV_GENERATOR_ID 18 + #define VKD3D_SPIRV_GENERATOR_VERSION 8 +@@ -1746,6 +1761,38 @@ static uint32_t vkd3d_spirv_get_type_id(struct vkd3d_spirv_builder *builder, + } + } + ++static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder *builder, ++ enum vkd3d_data_type data_type, unsigned int component_count) ++{ ++ uint32_t scalar_id; ++ ++ if (component_count == 1) ++ { ++ switch (data_type) ++ { ++ case VKD3D_DATA_FLOAT: ++ case VKD3D_DATA_SNORM: ++ case VKD3D_DATA_UNORM: ++ return vkd3d_spirv_get_op_type_float(builder, 32); ++ break; ++ case VKD3D_DATA_INT: ++ case VKD3D_DATA_UINT: ++ return vkd3d_spirv_get_op_type_int(builder, 32, data_type == VKD3D_DATA_INT); ++ break; ++ case VKD3D_DATA_DOUBLE: ++ return vkd3d_spirv_get_op_type_float(builder, 64); ++ default: ++ FIXME("Unhandled data type %#x.\n", data_type); ++ return 0; ++ } ++ } ++ else ++ { ++ scalar_id = vkd3d_spirv_get_type_id_for_data_type(builder, data_type, 1); ++ return vkd3d_spirv_get_op_type_vector(builder, scalar_id, component_count); ++ } ++} ++ + static void vkd3d_spirv_builder_init(struct vkd3d_spirv_builder *builder, const char *entry_point) + { + vkd3d_spirv_stream_init(&builder->debug_stream); +@@ -2429,13 +2476,6 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve + + compiler->shader_type = shader_version->type; + +- compiler->input_signature = shader_desc->input_signature; +- compiler->output_signature = shader_desc->output_signature; +- compiler->patch_constant_signature = shader_desc->patch_constant_signature; +- memset(&shader_desc->input_signature, 0, sizeof(shader_desc->input_signature)); +- memset(&shader_desc->output_signature, 0, sizeof(shader_desc->output_signature)); +- memset(&shader_desc->patch_constant_signature, 0, sizeof(shader_desc->patch_constant_signature)); +- + if ((shader_interface = vkd3d_find_struct(compile_info->next, INTERFACE_INFO))) + { + compiler->xfb_info = vkd3d_find_struct(compile_info->next, TRANSFORM_FEEDBACK_INFO); +@@ -2536,13 +2576,13 @@ static bool spirv_compiler_check_shader_visibility(const struct spirv_compiler * + } + + static struct vkd3d_push_constant_buffer_binding *spirv_compiler_find_push_constant_buffer( +- const struct spirv_compiler *compiler, const struct vkd3d_shader_constant_buffer *cb) ++ const struct spirv_compiler *compiler, const struct vkd3d_shader_register_range *range) + { +- unsigned int register_space = cb->range.space; +- unsigned int reg_idx = cb->range.first; ++ unsigned int register_space = range->space; ++ unsigned int reg_idx = range->first; + unsigned int i; + +- if (cb->range.first != cb->range.last) ++ if (range->first != range->last) + return NULL; + + for (i = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i) +@@ -3211,7 +3251,7 @@ static bool spirv_compiler_get_register_info(const struct spirv_compiler *compil + struct vkd3d_symbol reg_symbol, *symbol; + struct rb_entry *entry; + +- assert(reg->type != VKD3DSPR_IMMCONST && reg->type != VKD3DSPR_IMMCONST64); ++ assert(!register_is_constant_or_undef(reg)); + + if (reg->type == VKD3DSPR_TEMP) + { +@@ -3553,6 +3593,19 @@ static uint32_t spirv_compiler_emit_load_constant64(struct spirv_compiler *compi + vkd3d_component_type_from_data_type(reg->data_type), component_count, values); + } + ++static uint32_t spirv_compiler_emit_load_undef(struct spirv_compiler *compiler, ++ const struct vkd3d_shader_register *reg, DWORD write_mask) ++{ ++ unsigned int component_count = vkd3d_write_mask_component_count(write_mask); ++ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; ++ uint32_t type_id; ++ ++ assert(reg->type == VKD3DSPR_UNDEF); ++ ++ type_id = vkd3d_spirv_get_type_id_for_data_type(builder, reg->data_type, component_count); ++ return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id); ++} ++ + static uint32_t spirv_compiler_emit_load_scalar(struct spirv_compiler *compiler, + const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask, + const struct vkd3d_shader_register_info *reg_info) +@@ -3563,7 +3616,7 @@ static uint32_t spirv_compiler_emit_load_scalar(struct spirv_compiler *compiler, + enum vkd3d_shader_component_type component_type; + unsigned int skipped_component_mask; + +- assert(reg->type != VKD3DSPR_IMMCONST && reg->type != VKD3DSPR_IMMCONST64); ++ assert(!register_is_constant_or_undef(reg)); + assert(vkd3d_write_mask_component_count(write_mask) == 1); + + component_idx = vkd3d_write_mask_get_component_idx(write_mask); +@@ -3615,6 +3668,8 @@ static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler, + return spirv_compiler_emit_load_constant(compiler, reg, swizzle, write_mask); + else if (reg->type == VKD3DSPR_IMMCONST64) + return spirv_compiler_emit_load_constant64(compiler, reg, swizzle, write_mask); ++ else if (reg->type == VKD3DSPR_UNDEF) ++ return spirv_compiler_emit_load_undef(compiler, reg, write_mask); + + component_count = vkd3d_write_mask_component_count(write_mask); + component_type = vkd3d_component_type_from_data_type(reg->data_type); +@@ -3827,7 +3882,7 @@ static void spirv_compiler_emit_store_reg(struct spirv_compiler *compiler, + unsigned int src_write_mask = write_mask; + uint32_t type_id; + +- assert(reg->type != VKD3DSPR_IMMCONST && reg->type != VKD3DSPR_IMMCONST64); ++ assert(!register_is_constant_or_undef(reg)); + + if (!spirv_compiler_get_register_info(compiler, reg, ®_info)) + return; +@@ -5477,28 +5532,24 @@ static uint32_t spirv_compiler_build_descriptor_variable(struct spirv_compiler * + return var_id; + } + +-static void spirv_compiler_emit_dcl_constant_buffer(struct spirv_compiler *compiler, +- const struct vkd3d_shader_instruction *instruction) ++static void spirv_compiler_emit_constant_buffer(struct spirv_compiler *compiler, unsigned int size, ++ const struct vkd3d_shader_register_range *range, const struct vkd3d_shader_register *reg) + { +- const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t vec4_id, array_type_id, length_id, struct_id, var_id; + const SpvStorageClass storage_class = SpvStorageClassUniform; +- const struct vkd3d_shader_register *reg = &cb->src.reg; + struct vkd3d_push_constant_buffer_binding *push_cb; + struct vkd3d_descriptor_variable_info var_info; + struct vkd3d_symbol reg_symbol; + +- assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC)); +- +- if ((push_cb = spirv_compiler_find_push_constant_buffer(compiler, cb))) ++ if ((push_cb = spirv_compiler_find_push_constant_buffer(compiler, range))) + { + /* Push constant buffers are handled in + * spirv_compiler_emit_push_constant_buffers(). + */ +- unsigned int cb_size_in_bytes = cb->size * VKD3D_VEC4_SIZE * sizeof(uint32_t); ++ unsigned int cb_size_in_bytes = size * VKD3D_VEC4_SIZE * sizeof(uint32_t); + push_cb->reg = *reg; +- push_cb->size = cb->size; ++ push_cb->size = size; + if (cb_size_in_bytes > push_cb->pc.size) + { + WARN("Constant buffer size %u exceeds push constant size %u.\n", +@@ -5508,17 +5559,17 @@ static void spirv_compiler_emit_dcl_constant_buffer(struct spirv_compiler *compi + } + + vec4_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE); +- length_id = spirv_compiler_get_constant_uint(compiler, cb->size); ++ length_id = spirv_compiler_get_constant_uint(compiler, size); + array_type_id = vkd3d_spirv_build_op_type_array(builder, vec4_id, length_id); + vkd3d_spirv_build_op_decorate1(builder, array_type_id, SpvDecorationArrayStride, 16); + + struct_id = vkd3d_spirv_build_op_type_struct(builder, &array_type_id, 1); + vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0); + vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0); +- vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", cb->size); ++ vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", size); + + var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, struct_id, +- reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, false, &var_info); ++ reg, range, VKD3D_SHADER_RESOURCE_BUFFER, false, &var_info); + + vkd3d_symbol_make_register(®_symbol, reg); + vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, +@@ -5528,6 +5579,16 @@ static void spirv_compiler_emit_dcl_constant_buffer(struct spirv_compiler *compi + spirv_compiler_put_symbol(compiler, ®_symbol); + } + ++static void spirv_compiler_emit_dcl_constant_buffer(struct spirv_compiler *compiler, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb; ++ ++ assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC)); ++ ++ spirv_compiler_emit_constant_buffer(compiler, cb->size, &cb->range, &cb->src.reg); ++} ++ + static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) + { +@@ -6641,7 +6702,7 @@ static void spirv_compiler_emit_mov(struct spirv_compiler *compiler, + uint32_t components[VKD3D_VEC4_SIZE]; + unsigned int i, component_count; + +- if (src->reg.type == VKD3DSPR_IMMCONST || src->reg.type == VKD3DSPR_IMMCONST64 || dst->modifiers || src->modifiers) ++ if (register_is_constant_or_undef(&src->reg) || dst->modifiers || src->modifiers) + goto general_implementation; + + spirv_compiler_get_register_info(compiler, &dst->reg, &dst_reg_info); +@@ -9436,6 +9497,26 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, + return ret; + } + ++static void spirv_compiler_emit_sm1_constant_buffer(struct spirv_compiler *compiler, ++ const struct vkd3d_shader_desc *desc, enum vkd3d_shader_d3dbc_constant_register set, ++ enum vkd3d_data_type data_type) ++{ ++ struct vkd3d_shader_register_range range = {.space = 0, .first = set, .last = set}; ++ uint32_t count = desc->flat_constant_count[set].external; ++ struct vkd3d_shader_register reg = ++ { ++ .type = VKD3DSPR_CONSTBUFFER, ++ .idx[0].offset = set, /* register ID */ ++ .idx[1].offset = set, /* register index */ ++ .idx[2].offset = count, /* size */ ++ .idx_count = 3, ++ .data_type = data_type, ++ }; ++ ++ if (count) ++ spirv_compiler_emit_constant_buffer(compiler, count, &range, ®); ++} ++ + static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser, + struct vkd3d_shader_code *spirv) +@@ -9443,6 +9524,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, + const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info; + const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; ++ struct vkd3d_shader_desc *shader_desc = &parser->shader_desc; + struct vkd3d_shader_instruction_array instructions; + enum vkd3d_result result = VKD3D_OK; + unsigned int i; +@@ -9450,24 +9532,28 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, + if (parser->shader_desc.temp_count) + spirv_compiler_emit_temps(compiler, parser->shader_desc.temp_count); + ++ spirv_compiler_emit_sm1_constant_buffer(compiler, &parser->shader_desc, ++ VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, VKD3D_DATA_FLOAT); ++ spirv_compiler_emit_sm1_constant_buffer(compiler, &parser->shader_desc, ++ VKD3D_SHADER_D3DBC_INT_CONSTANT_REGISTER, VKD3D_DATA_INT); ++ spirv_compiler_emit_sm1_constant_buffer(compiler, &parser->shader_desc, ++ VKD3D_SHADER_D3DBC_BOOL_CONSTANT_REGISTER, VKD3D_DATA_UINT); ++ + compiler->location.column = 0; + compiler->location.line = 1; + ++ if ((result = vkd3d_shader_normalise(parser)) < 0) ++ return result; ++ + instructions = parser->instructions; + memset(&parser->instructions, 0, sizeof(parser->instructions)); + +- if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL +- && (result = instruction_array_flatten_hull_shader_phases(&instructions)) >= 0) +- { +- result = instruction_array_normalise_hull_shader_control_point_io(&instructions, +- &compiler->input_signature); +- } +- if (result >= 0) +- result = instruction_array_normalise_io_registers(&instructions, parser->shader_version.type, +- &compiler->input_signature, &compiler->output_signature, &compiler->patch_constant_signature); +- +- if (result >= 0 && TRACE_ON()) +- vkd3d_shader_trace(&instructions, &parser->shader_version); ++ compiler->input_signature = shader_desc->input_signature; ++ compiler->output_signature = shader_desc->output_signature; ++ compiler->patch_constant_signature = shader_desc->patch_constant_signature; ++ memset(&shader_desc->input_signature, 0, sizeof(shader_desc->input_signature)); ++ memset(&shader_desc->output_signature, 0, sizeof(shader_desc->output_signature)); ++ memset(&shader_desc->patch_constant_signature, 0, sizeof(shader_desc->patch_constant_signature)); + + if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) + spirv_compiler_emit_shader_signature_outputs(compiler); +diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c +index 801c688a297..351943e2e53 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c ++++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c +@@ -2627,7 +2627,8 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant + return true; + } + +-static void add_section(struct dxbc_writer *dxbc, uint32_t tag, struct vkd3d_bytecode_buffer *buffer) ++static void add_section(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, ++ uint32_t tag, struct vkd3d_bytecode_buffer *buffer) + { + /* Native D3DDisassemble() expects at least the sizes of the ISGN and OSGN + * sections to be aligned. Without this, the sections themselves will be +@@ -2635,6 +2636,9 @@ static void add_section(struct dxbc_writer *dxbc, uint32_t tag, struct vkd3d_byt + size_t size = bytecode_align(buffer); + + dxbc_writer_add_section(dxbc, tag, buffer->data, size); ++ ++ if (buffer->status < 0) ++ ctx->result = buffer->status; + } + + static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, bool output) +@@ -2742,7 +2746,7 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, + + set_u32(&buffer, count_position, i); + +- add_section(dxbc, output ? TAG_OSGN : TAG_ISGN, &buffer); ++ add_section(ctx, dxbc, output ? TAG_OSGN : TAG_ISGN, &buffer); + } + + static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type) +@@ -2830,6 +2834,22 @@ static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type) + return D3D_SVT_VERTEXSHADER; + case HLSL_TYPE_VOID: + return D3D_SVT_VOID; ++ case HLSL_TYPE_UAV: ++ switch (type->sampler_dim) ++ { ++ case HLSL_SAMPLER_DIM_1D: ++ return D3D_SVT_RWTEXTURE1D; ++ case HLSL_SAMPLER_DIM_2D: ++ return D3D_SVT_RWTEXTURE2D; ++ case HLSL_SAMPLER_DIM_3D: ++ return D3D_SVT_RWTEXTURE3D; ++ case HLSL_SAMPLER_DIM_1DARRAY: ++ return D3D_SVT_RWTEXTURE1DARRAY; ++ case HLSL_SAMPLER_DIM_2DARRAY: ++ return D3D_SVT_RWTEXTURE2DARRAY; ++ default: ++ vkd3d_unreachable(); ++ } + default: + vkd3d_unreachable(); + } +@@ -3341,7 +3361,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + creator_offset = put_string(&buffer, vkd3d_shader_get_version(NULL, NULL)); + set_u32(&buffer, creator_position, creator_offset); + +- add_section(dxbc, TAG_RDEF, &buffer); ++ add_section(ctx, dxbc, TAG_RDEF, &buffer); + + sm4_free_extern_resources(extern_resources, extern_resources_count); + } +@@ -4283,6 +4303,53 @@ static void write_sm4_sample(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer + write_sm4_instruction(buffer, &instr); + } + ++static void write_sm4_sampleinfo(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, ++ const struct hlsl_ir_resource_load *load) ++{ ++ const struct hlsl_deref *resource = &load->resource; ++ const struct hlsl_ir_node *dst = &load->node; ++ struct sm4_instruction instr; ++ ++ assert(dst->data_type->base_type == HLSL_TYPE_UINT || dst->data_type->base_type == HLSL_TYPE_FLOAT); ++ ++ memset(&instr, 0, sizeof(instr)); ++ instr.opcode = VKD3D_SM4_OP_SAMPLE_INFO; ++ if (dst->data_type->base_type == HLSL_TYPE_UINT) ++ instr.opcode |= VKD3DSI_SAMPLE_INFO_UINT << VKD3D_SM4_INSTRUCTION_FLAGS_SHIFT; ++ ++ sm4_dst_from_node(&instr.dsts[0], dst); ++ instr.dst_count = 1; ++ ++ sm4_src_from_deref(ctx, &instr.srcs[0], resource, instr.dsts[0].writemask); ++ instr.src_count = 1; ++ ++ write_sm4_instruction(buffer, &instr); ++} ++ ++static void write_sm4_resinfo(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, ++ const struct hlsl_ir_resource_load *load) ++{ ++ const struct hlsl_deref *resource = &load->resource; ++ const struct hlsl_ir_node *dst = &load->node; ++ struct sm4_instruction instr; ++ ++ assert(dst->data_type->base_type == HLSL_TYPE_UINT || dst->data_type->base_type == HLSL_TYPE_FLOAT); ++ ++ memset(&instr, 0, sizeof(instr)); ++ instr.opcode = VKD3D_SM4_OP_RESINFO; ++ if (dst->data_type->base_type == HLSL_TYPE_UINT) ++ instr.opcode |= VKD3DSI_RESINFO_UINT << VKD3D_SM4_INSTRUCTION_FLAGS_SHIFT; ++ ++ sm4_dst_from_node(&instr.dsts[0], dst); ++ instr.dst_count = 1; ++ ++ sm4_src_from_node(&instr.srcs[0], load->lod.node, VKD3DSP_WRITEMASK_ALL); ++ sm4_src_from_deref(ctx, &instr.srcs[1], resource, instr.dsts[0].writemask); ++ instr.src_count = 2; ++ ++ write_sm4_instruction(buffer, &instr); ++} ++ + static bool type_is_float(const struct hlsl_type *type) + { + return type->base_type == HLSL_TYPE_FLOAT || type->base_type == HLSL_TYPE_HALF; +@@ -5101,6 +5168,14 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, + write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, + HLSL_SWIZZLE(W, W, W, W), texel_offset); + break; ++ ++ case HLSL_RESOURCE_SAMPLE_INFO: ++ write_sm4_sampleinfo(ctx, buffer, load); ++ break; ++ ++ case HLSL_RESOURCE_RESINFO: ++ write_sm4_resinfo(ctx, buffer, load); ++ break; + } + } + +@@ -5306,7 +5381,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + + set_u32(&buffer, token_count_position, bytecode_get_size(&buffer) / sizeof(uint32_t)); + +- add_section(dxbc, TAG_SHDR, &buffer); ++ add_section(ctx, dxbc, TAG_SHDR, &buffer); + + sm4_free_extern_resources(extern_resources, extern_resources_count); + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +index 33d8c60e59a..d59cd704ceb 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +@@ -1152,6 +1152,15 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info + } + } + ++ for (i = 0; i < ARRAY_SIZE(parser->shader_desc.flat_constant_count); ++i) ++ { ++ struct vkd3d_shader_register_range range = {.space = 0, .first = i, .last = i}; ++ ++ if (parser->shader_desc.flat_constant_count[i].external) ++ vkd3d_shader_scan_add_descriptor(&context, VKD3D_SHADER_DESCRIPTOR_TYPE_CBV, ++ &range, VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0); ++ } ++ + if (!ret && signature_info) + { + if (!vkd3d_shader_signature_from_shader_signature(&signature_info->input, &parser->shader_desc.input_signature) +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index 0e93f3a556a..d35f49a63a2 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -507,6 +507,7 @@ enum vkd3d_shader_register_type + VKD3DSPR_DEPTHOUTLE, + VKD3DSPR_RASTERIZER, + VKD3DSPR_OUTSTENCILREF, ++ VKD3DSPR_UNDEF, + + VKD3DSPR_INVALID = ~0u, + }; +@@ -840,6 +841,11 @@ struct vkd3d_shader_desc + struct shader_signature patch_constant_signature; + + uint32_t temp_count; ++ ++ struct ++ { ++ uint32_t used, external; ++ } flat_constant_count[3]; + }; + + struct vkd3d_shader_register_semantic +@@ -971,6 +977,8 @@ struct vkd3d_shader_instruction + } declaration; + }; + ++void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode handler_idx); ++ + static inline bool vkd3d_shader_instruction_has_texel_offset(const struct vkd3d_shader_instruction *ins) + { + return ins->texel_offset.u || ins->texel_offset.v || ins->texel_offset.w; +@@ -1398,11 +1406,6 @@ void dxbc_writer_add_section(struct dxbc_writer *dxbc, uint32_t tag, const void + void dxbc_writer_init(struct dxbc_writer *dxbc); + int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code); + +-enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *instructions); +-enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( +- struct vkd3d_shader_instruction_array *instructions, const struct shader_signature *input_signature); +-enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_shader_instruction_array *instructions, +- enum vkd3d_shader_type shader_type, struct shader_signature *input_signature, +- struct shader_signature *output_signature, struct shader_signature *patch_constant_signature); ++enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser); + + #endif /* __VKD3D_SHADER_PRIVATE_H */ +diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c +index 53cb5d9582c..8b5f7899cf3 100644 +--- a/libs/vkd3d/libs/vkd3d/command.c ++++ b/libs/vkd3d/libs/vkd3d/command.c +@@ -454,9 +454,9 @@ static const struct d3d12_root_parameter *root_signature_get_root_descriptor( + } + + /* ID3D12Fence */ +-static struct d3d12_fence *impl_from_ID3D12Fence(ID3D12Fence *iface) ++static struct d3d12_fence *impl_from_ID3D12Fence1(ID3D12Fence1 *iface) + { +- return CONTAINING_RECORD(iface, struct d3d12_fence, ID3D12Fence_iface); ++ return CONTAINING_RECORD(iface, struct d3d12_fence, ID3D12Fence1_iface); + } + + static VkResult d3d12_fence_create_vk_fence(struct d3d12_fence *fence, VkFence *vk_fence) +@@ -900,18 +900,19 @@ static void d3d12_fence_signal_timeline_semaphore(struct d3d12_fence *fence, uin + vkd3d_mutex_unlock(&fence->mutex); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_QueryInterface(ID3D12Fence *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_fence_QueryInterface(ID3D12Fence1 *iface, + REFIID riid, void **object) + { + TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object); + +- if (IsEqualGUID(riid, &IID_ID3D12Fence) ++ if (IsEqualGUID(riid, &IID_ID3D12Fence1) ++ || IsEqualGUID(riid, &IID_ID3D12Fence) + || IsEqualGUID(riid, &IID_ID3D12Pageable) + || IsEqualGUID(riid, &IID_ID3D12DeviceChild) + || IsEqualGUID(riid, &IID_ID3D12Object) + || IsEqualGUID(riid, &IID_IUnknown)) + { +- ID3D12Fence_AddRef(iface); ++ ID3D12Fence1_AddRef(iface); + *object = iface; + return S_OK; + } +@@ -922,9 +923,9 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_QueryInterface(ID3D12Fence *iface, + return E_NOINTERFACE; + } + +-static ULONG STDMETHODCALLTYPE d3d12_fence_AddRef(ID3D12Fence *iface) ++static ULONG STDMETHODCALLTYPE d3d12_fence_AddRef(ID3D12Fence1 *iface) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + ULONG refcount = InterlockedIncrement(&fence->refcount); + + TRACE("%p increasing refcount to %u.\n", fence, refcount); +@@ -937,9 +938,9 @@ static void d3d12_fence_incref(struct d3d12_fence *fence) + InterlockedIncrement(&fence->internal_refcount); + } + +-static ULONG STDMETHODCALLTYPE d3d12_fence_Release(ID3D12Fence *iface) ++static ULONG STDMETHODCALLTYPE d3d12_fence_Release(ID3D12Fence1 *iface) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + ULONG refcount = InterlockedDecrement(&fence->refcount); + + TRACE("%p decreasing refcount to %u.\n", fence, refcount); +@@ -972,10 +973,10 @@ static void d3d12_fence_decref(struct d3d12_fence *fence) + } + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_GetPrivateData(ID3D12Fence *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_fence_GetPrivateData(ID3D12Fence1 *iface, + REFGUID guid, UINT *data_size, void *data) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + + TRACE("iface %p, guid %s, data_size %p, data %p.\n", + iface, debugstr_guid(guid), data_size, data); +@@ -983,10 +984,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_GetPrivateData(ID3D12Fence *iface, + return vkd3d_get_private_data(&fence->private_store, guid, data_size, data); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_SetPrivateData(ID3D12Fence *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_fence_SetPrivateData(ID3D12Fence1 *iface, + REFGUID guid, UINT data_size, const void *data) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + + TRACE("iface %p, guid %s, data_size %u, data %p.\n", + iface, debugstr_guid(guid), data_size, data); +@@ -994,37 +995,37 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_SetPrivateData(ID3D12Fence *iface, + return vkd3d_set_private_data(&fence->private_store, guid, data_size, data); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_SetPrivateDataInterface(ID3D12Fence *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_fence_SetPrivateDataInterface(ID3D12Fence1 *iface, + REFGUID guid, const IUnknown *data) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + + TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data); + + return vkd3d_set_private_data_interface(&fence->private_store, guid, data); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_SetName(ID3D12Fence *iface, const WCHAR *name) ++static HRESULT STDMETHODCALLTYPE d3d12_fence_SetName(ID3D12Fence1 *iface, const WCHAR *name) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + + TRACE("iface %p, name %s.\n", iface, debugstr_w(name, fence->device->wchar_size)); + + return name ? S_OK : E_INVALIDARG; + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_GetDevice(ID3D12Fence *iface, REFIID iid, void **device) ++static HRESULT STDMETHODCALLTYPE d3d12_fence_GetDevice(ID3D12Fence1 *iface, REFIID iid, void **device) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + + TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device); + + return d3d12_device_query_interface(fence->device, iid, device); + } + +-static UINT64 STDMETHODCALLTYPE d3d12_fence_GetCompletedValue(ID3D12Fence *iface) ++static UINT64 STDMETHODCALLTYPE d3d12_fence_GetCompletedValue(ID3D12Fence1 *iface) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + uint64_t completed_value; + + TRACE("iface %p.\n", iface); +@@ -1035,10 +1036,10 @@ static UINT64 STDMETHODCALLTYPE d3d12_fence_GetCompletedValue(ID3D12Fence *iface + return completed_value; + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence1 *iface, + UINT64 value, HANDLE event) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + unsigned int i; + bool latch = false; + +@@ -1106,9 +1107,9 @@ static HRESULT d3d12_fence_signal_cpu_timeline_semaphore(struct d3d12_fence *fen + return d3d12_device_flush_blocked_queues(fence->device); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_fence_Signal(ID3D12Fence *iface, UINT64 value) ++static HRESULT STDMETHODCALLTYPE d3d12_fence_Signal(ID3D12Fence1 *iface, UINT64 value) + { +- struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); + + TRACE("iface %p, value %#"PRIx64".\n", iface, value); + +@@ -1117,7 +1118,16 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_Signal(ID3D12Fence *iface, UINT64 v + return d3d12_fence_signal(fence, value, VK_NULL_HANDLE, true); + } + +-static const struct ID3D12FenceVtbl d3d12_fence_vtbl = ++static D3D12_FENCE_FLAGS STDMETHODCALLTYPE d3d12_fence_GetCreationFlags(ID3D12Fence1 *iface) ++{ ++ struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface); ++ ++ TRACE("iface %p.\n", iface); ++ ++ return fence->flags; ++} ++ ++static const struct ID3D12Fence1Vtbl d3d12_fence_vtbl = + { + /* IUnknown methods */ + d3d12_fence_QueryInterface, +@@ -1134,14 +1144,18 @@ static const struct ID3D12FenceVtbl d3d12_fence_vtbl = + d3d12_fence_GetCompletedValue, + d3d12_fence_SetEventOnCompletion, + d3d12_fence_Signal, ++ /* ID3D12Fence1 methods */ ++ d3d12_fence_GetCreationFlags, + }; + + static struct d3d12_fence *unsafe_impl_from_ID3D12Fence(ID3D12Fence *iface) + { +- if (!iface) ++ ID3D12Fence1 *iface1; ++ ++ if (!(iface1 = (ID3D12Fence1 *)iface)) + return NULL; +- assert(iface->lpVtbl == &d3d12_fence_vtbl); +- return impl_from_ID3D12Fence(iface); ++ assert(iface1->lpVtbl == &d3d12_fence_vtbl); ++ return impl_from_ID3D12Fence1(iface1); + } + + static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device *device, +@@ -1151,7 +1165,7 @@ static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device * + VkResult vr; + HRESULT hr; + +- fence->ID3D12Fence_iface.lpVtbl = &d3d12_fence_vtbl; ++ fence->ID3D12Fence1_iface.lpVtbl = &d3d12_fence_vtbl; + fence->internal_refcount = 1; + fence->refcount = 1; + +@@ -1162,7 +1176,7 @@ static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device * + + vkd3d_cond_init(&fence->null_event_cond); + +- if (flags) ++ if ((fence->flags = flags)) + FIXME("Ignoring flags %#x.\n", flags); + + fence->events = NULL; +@@ -1316,32 +1330,26 @@ static HRESULT d3d12_command_allocator_allocate_command_buffer(struct d3d12_comm + return hr; + } + +- allocator->current_command_list = list; +- +- return S_OK; +-} +- +-static void d3d12_command_allocator_free_command_buffer(struct d3d12_command_allocator *allocator, +- struct d3d12_command_list *list) +-{ +- struct d3d12_device *device = allocator->device; +- const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; +- +- TRACE("allocator %p, list %p.\n", allocator, list); +- +- if (allocator->current_command_list == list) +- allocator->current_command_list = NULL; +- + if (!vkd3d_array_reserve((void **)&allocator->command_buffers, &allocator->command_buffers_size, + allocator->command_buffer_count + 1, sizeof(*allocator->command_buffers))) + { + WARN("Failed to add command buffer.\n"); + VK_CALL(vkFreeCommandBuffers(device->vk_device, allocator->vk_command_pool, + 1, &list->vk_command_buffer)); +- return; ++ return E_OUTOFMEMORY; + } +- + allocator->command_buffers[allocator->command_buffer_count++] = list->vk_command_buffer; ++ ++ allocator->current_command_list = list; ++ ++ return S_OK; ++} ++ ++static void d3d12_command_allocator_remove_command_list(struct d3d12_command_allocator *allocator, ++ const struct d3d12_command_list *list) ++{ ++ if (allocator->current_command_list == list) ++ allocator->current_command_list = NULL; + } + + static bool d3d12_command_allocator_add_render_pass(struct d3d12_command_allocator *allocator, VkRenderPass pass) +@@ -1911,10 +1919,32 @@ HRESULT d3d12_command_allocator_create(struct d3d12_device *device, + return S_OK; + } + ++static void d3d12_command_signature_incref(struct d3d12_command_signature *signature) ++{ ++ vkd3d_atomic_increment(&signature->internal_refcount); ++} ++ ++static void d3d12_command_signature_decref(struct d3d12_command_signature *signature) ++{ ++ unsigned int refcount = vkd3d_atomic_decrement(&signature->internal_refcount); ++ ++ if (!refcount) ++ { ++ struct d3d12_device *device = signature->device; ++ ++ vkd3d_private_store_destroy(&signature->private_store); ++ ++ vkd3d_free((void *)signature->desc.pArgumentDescs); ++ vkd3d_free(signature); ++ ++ d3d12_device_release(device); ++ } ++} ++ + /* ID3D12CommandList */ +-static inline struct d3d12_command_list *impl_from_ID3D12GraphicsCommandList2(ID3D12GraphicsCommandList2 *iface) ++static inline struct d3d12_command_list *impl_from_ID3D12GraphicsCommandList3(ID3D12GraphicsCommandList3 *iface) + { +- return CONTAINING_RECORD(iface, struct d3d12_command_list, ID3D12GraphicsCommandList2_iface); ++ return CONTAINING_RECORD(iface, struct d3d12_command_list, ID3D12GraphicsCommandList3_iface); + } + + static void d3d12_command_list_invalidate_current_framebuffer(struct d3d12_command_list *list) +@@ -2260,12 +2290,13 @@ static void d3d12_command_list_track_resource_usage(struct d3d12_command_list *l + } + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_QueryInterface(ID3D12GraphicsCommandList2 *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_QueryInterface(ID3D12GraphicsCommandList3 *iface, + REFIID iid, void **object) + { + TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object); + +- if (IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList2) ++ if (IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList3) ++ || IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList2) + || IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList1) + || IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList) + || IsEqualGUID(iid, &IID_ID3D12CommandList) +@@ -2273,7 +2304,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_QueryInterface(ID3D12Graphic + || IsEqualGUID(iid, &IID_ID3D12Object) + || IsEqualGUID(iid, &IID_IUnknown)) + { +- ID3D12GraphicsCommandList2_AddRef(iface); ++ ID3D12GraphicsCommandList3_AddRef(iface); + *object = iface; + return S_OK; + } +@@ -2284,9 +2315,9 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_QueryInterface(ID3D12Graphic + return E_NOINTERFACE; + } + +-static ULONG STDMETHODCALLTYPE d3d12_command_list_AddRef(ID3D12GraphicsCommandList2 *iface) ++static ULONG STDMETHODCALLTYPE d3d12_command_list_AddRef(ID3D12GraphicsCommandList3 *iface) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + ULONG refcount = InterlockedIncrement(&list->refcount); + + TRACE("%p increasing refcount to %u.\n", list, refcount); +@@ -2299,9 +2330,9 @@ static void vkd3d_pipeline_bindings_cleanup(struct vkd3d_pipeline_bindings *bind + vkd3d_free(bindings->vk_uav_counter_views); + } + +-static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandList2 *iface) ++static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandList3 *iface) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + ULONG refcount = InterlockedDecrement(&list->refcount); + + TRACE("%p decreasing refcount to %u.\n", list, refcount); +@@ -2314,7 +2345,7 @@ static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandL + + /* When command pool is destroyed, all command buffers are implicitly freed. */ + if (list->allocator) +- d3d12_command_allocator_free_command_buffer(list->allocator, list); ++ d3d12_command_allocator_remove_command_list(list->allocator, list); + + vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COMPUTE]); + vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_GRAPHICS]); +@@ -2327,66 +2358,66 @@ static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandL + return refcount; + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_GetPrivateData(ID3D12GraphicsCommandList2 *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_GetPrivateData(ID3D12GraphicsCommandList3 *iface, + REFGUID guid, UINT *data_size, void *data) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return vkd3d_get_private_data(&list->private_store, guid, data_size, data); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetPrivateData(ID3D12GraphicsCommandList2 *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetPrivateData(ID3D12GraphicsCommandList3 *iface, + REFGUID guid, UINT data_size, const void *data) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return vkd3d_set_private_data(&list->private_store, guid, data_size, data); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetPrivateDataInterface(ID3D12GraphicsCommandList2 *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetPrivateDataInterface(ID3D12GraphicsCommandList3 *iface, + REFGUID guid, const IUnknown *data) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data); + + return vkd3d_set_private_data_interface(&list->private_store, guid, data); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetName(ID3D12GraphicsCommandList2 *iface, const WCHAR *name) ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_SetName(ID3D12GraphicsCommandList3 *iface, const WCHAR *name) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, name %s.\n", iface, debugstr_w(name, list->device->wchar_size)); + + return name ? S_OK : E_INVALIDARG; + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_GetDevice(ID3D12GraphicsCommandList2 *iface, REFIID iid, void **device) ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_GetDevice(ID3D12GraphicsCommandList3 *iface, REFIID iid, void **device) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device); + + return d3d12_device_query_interface(list->device, iid, device); + } + +-static D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE d3d12_command_list_GetType(ID3D12GraphicsCommandList2 *iface) ++static D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE d3d12_command_list_GetType(ID3D12GraphicsCommandList3 *iface) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p.\n", iface); + + return list->type; + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(ID3D12GraphicsCommandList2 *iface) ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(ID3D12GraphicsCommandList3 *iface) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + VkResult vr; + +@@ -2412,7 +2443,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(ID3D12GraphicsCommandL + + if (list->allocator) + { +- d3d12_command_allocator_free_command_buffer(list->allocator, list); ++ d3d12_command_allocator_remove_command_list(list->allocator, list); + list->allocator = NULL; + } + +@@ -2430,7 +2461,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(ID3D12GraphicsCommandL + static void d3d12_command_list_reset_state(struct d3d12_command_list *list, + ID3D12PipelineState *initial_pipeline_state) + { +- ID3D12GraphicsCommandList2 *iface = &list->ID3D12GraphicsCommandList2_iface; ++ ID3D12GraphicsCommandList3 *iface = &list->ID3D12GraphicsCommandList3_iface; + + memset(list->strides, 0, sizeof(list->strides)); + list->primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; +@@ -2466,14 +2497,14 @@ static void d3d12_command_list_reset_state(struct d3d12_command_list *list, + + list->descriptor_heap_count = 0; + +- ID3D12GraphicsCommandList2_SetPipelineState(iface, initial_pipeline_state); ++ ID3D12GraphicsCommandList3_SetPipelineState(iface, initial_pipeline_state); + } + +-static HRESULT STDMETHODCALLTYPE d3d12_command_list_Reset(ID3D12GraphicsCommandList2 *iface, ++static HRESULT STDMETHODCALLTYPE d3d12_command_list_Reset(ID3D12GraphicsCommandList3 *iface, + ID3D12CommandAllocator *allocator, ID3D12PipelineState *initial_pipeline_state) + { + struct d3d12_command_allocator *allocator_impl = unsafe_impl_from_ID3D12CommandAllocator(allocator); +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + HRESULT hr; + + TRACE("iface %p, allocator %p, initial_pipeline_state %p.\n", +@@ -2500,7 +2531,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_Reset(ID3D12GraphicsCommandL + return hr; + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ClearState(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ClearState(ID3D12GraphicsCommandList3 *iface, + ID3D12PipelineState *pipeline_state) + { + FIXME("iface %p, pipline_state %p stub!\n", iface, pipeline_state); +@@ -3186,6 +3217,20 @@ static void command_list_flush_vk_heap_updates(struct d3d12_command_list *list) + } + } + ++static void command_list_add_descriptor_heap(struct d3d12_command_list *list, struct d3d12_descriptor_heap *heap) ++{ ++ if (!contains_heap(list->descriptor_heaps, list->descriptor_heap_count, heap)) ++ { ++ if (list->descriptor_heap_count == ARRAY_SIZE(list->descriptor_heaps)) ++ { ++ /* Descriptors can be written after binding. */ ++ FIXME("Flushing descriptor updates while list %p is not closed.\n", list); ++ command_list_flush_vk_heap_updates(list); ++ } ++ list->descriptor_heaps[list->descriptor_heap_count++] = heap; ++ } ++} ++ + static void d3d12_command_list_bind_descriptor_heap(struct d3d12_command_list *list, + enum vkd3d_pipeline_bind_point bind_point, struct d3d12_descriptor_heap *heap) + { +@@ -3210,18 +3255,6 @@ static void d3d12_command_list_bind_descriptor_heap(struct d3d12_command_list *l + bindings->sampler_heap_id = heap->serial_id; + } + +- if (!contains_heap(list->descriptor_heaps, list->descriptor_heap_count, heap)) +- { +- if (list->descriptor_heap_count == ARRAY_SIZE(list->descriptor_heaps)) +- { +- /* Descriptors can be written after binding. */ +- FIXME("Flushing descriptor updates while list %p is not closed.\n", list); +- command_list_flush_vk_heap_updates(list); +- list->descriptor_heap_count = 0; +- } +- list->descriptor_heaps[list->descriptor_heap_count++] = heap; +- } +- + vkd3d_mutex_lock(&heap->vk_sets_mutex); + + for (set = 0; set < ARRAY_SIZE(heap->vk_descriptor_sets); ++set) +@@ -3354,11 +3387,11 @@ static void d3d12_command_list_check_index_buffer_strip_cut_value(struct d3d12_c + } + } + +-static void STDMETHODCALLTYPE d3d12_command_list_DrawInstanced(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_DrawInstanced(ID3D12GraphicsCommandList3 *iface, + UINT vertex_count_per_instance, UINT instance_count, UINT start_vertex_location, + UINT start_instance_location) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + + TRACE("iface %p, vertex_count_per_instance %u, instance_count %u, " +@@ -3378,11 +3411,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_DrawInstanced(ID3D12GraphicsCom + instance_count, start_vertex_location, start_instance_location)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_DrawIndexedInstanced(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_DrawIndexedInstanced(ID3D12GraphicsCommandList3 *iface, + UINT index_count_per_instance, UINT instance_count, UINT start_vertex_location, + INT base_vertex_location, UINT start_instance_location) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + + TRACE("iface %p, index_count_per_instance %u, instance_count %u, start_vertex_location %u, " +@@ -3404,10 +3437,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_DrawIndexedInstanced(ID3D12Grap + instance_count, start_vertex_location, base_vertex_location, start_instance_location)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_Dispatch(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_Dispatch(ID3D12GraphicsCommandList3 *iface, + UINT x, UINT y, UINT z) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + + TRACE("iface %p, x %u, y %u, z %u.\n", iface, x, y, z); +@@ -3423,10 +3456,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_Dispatch(ID3D12GraphicsCommandL + VK_CALL(vkCmdDispatch(list->vk_command_buffer, x, y, z)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_CopyBufferRegion(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_CopyBufferRegion(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *dst, UINT64 dst_offset, ID3D12Resource *src, UINT64 src_offset, UINT64 byte_count) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_resource *dst_resource, *src_resource; + const struct vkd3d_vk_device_procs *vk_procs; + VkBufferCopy buffer_copy; +@@ -3708,11 +3741,11 @@ static bool validate_d3d12_box(const D3D12_BOX *box) + && box->back > box->front; + } + +-static void STDMETHODCALLTYPE d3d12_command_list_CopyTextureRegion(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_CopyTextureRegion(ID3D12GraphicsCommandList3 *iface, + const D3D12_TEXTURE_COPY_LOCATION *dst, UINT dst_x, UINT dst_y, UINT dst_z, + const D3D12_TEXTURE_COPY_LOCATION *src, const D3D12_BOX *src_box) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_resource *dst_resource, *src_resource; + const struct vkd3d_format *src_format, *dst_format; + const struct vkd3d_vk_device_procs *vk_procs; +@@ -3833,10 +3866,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyTextureRegion(ID3D12Graphic + } + } + +-static void STDMETHODCALLTYPE d3d12_command_list_CopyResource(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_CopyResource(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *dst, ID3D12Resource *src) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_resource *dst_resource, *src_resource; + const struct vkd3d_format *dst_format, *src_format; + const struct vkd3d_vk_device_procs *vk_procs; +@@ -3903,7 +3936,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyResource(ID3D12GraphicsComm + } + } + +-static void STDMETHODCALLTYPE d3d12_command_list_CopyTiles(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_CopyTiles(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *tiled_resource, const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate, + const D3D12_TILE_REGION_SIZE *tile_region_size, ID3D12Resource *buffer, UINT64 buffer_offset, + D3D12_TILE_COPY_FLAGS flags) +@@ -3914,11 +3947,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyTiles(ID3D12GraphicsCommand + buffer, buffer_offset, flags); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresource(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresource(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *dst, UINT dst_sub_resource_idx, + ID3D12Resource *src, UINT src_sub_resource_idx, DXGI_FORMAT format) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_format *src_format, *dst_format, *vk_format; + struct d3d12_resource *dst_resource, *src_resource; + const struct vkd3d_vk_device_procs *vk_procs; +@@ -3981,10 +4014,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresource(ID3D12Graphi + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vk_image_resolve)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_IASetPrimitiveTopology(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_IASetPrimitiveTopology(ID3D12GraphicsCommandList3 *iface, + D3D12_PRIMITIVE_TOPOLOGY topology) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, topology %#x.\n", iface, topology); + +@@ -3995,11 +4028,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetPrimitiveTopology(ID3D12Gr + d3d12_command_list_invalidate_current_pipeline(list); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_RSSetViewports(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_RSSetViewports(ID3D12GraphicsCommandList3 *iface, + UINT viewport_count, const D3D12_VIEWPORT *viewports) + { + VkViewport vk_viewports[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + unsigned int i; + +@@ -4033,10 +4066,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_RSSetViewports(ID3D12GraphicsCo + VK_CALL(vkCmdSetViewport(list->vk_command_buffer, 0, viewport_count, vk_viewports)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_RSSetScissorRects(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_RSSetScissorRects(ID3D12GraphicsCommandList3 *iface, + UINT rect_count, const D3D12_RECT *rects) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + VkRect2D vk_rects[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + const struct vkd3d_vk_device_procs *vk_procs; + unsigned int i; +@@ -4061,10 +4094,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_RSSetScissorRects(ID3D12Graphic + VK_CALL(vkCmdSetScissor(list->vk_command_buffer, 0, rect_count, vk_rects)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_OMSetBlendFactor(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_OMSetBlendFactor(ID3D12GraphicsCommandList3 *iface, + const FLOAT blend_factor[4]) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + + TRACE("iface %p, blend_factor %p.\n", iface, blend_factor); +@@ -4073,10 +4106,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetBlendFactor(ID3D12Graphics + VK_CALL(vkCmdSetBlendConstants(list->vk_command_buffer, blend_factor)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_OMSetStencilRef(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_OMSetStencilRef(ID3D12GraphicsCommandList3 *iface, + UINT stencil_ref) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + + TRACE("iface %p, stencil_ref %u.\n", iface, stencil_ref); +@@ -4085,11 +4118,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetStencilRef(ID3D12GraphicsC + VK_CALL(vkCmdSetStencilReference(list->vk_command_buffer, VK_STENCIL_FRONT_AND_BACK, stencil_ref)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetPipelineState(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetPipelineState(ID3D12GraphicsCommandList3 *iface, + ID3D12PipelineState *pipeline_state) + { + struct d3d12_pipeline_state *state = unsafe_impl_from_ID3D12PipelineState(pipeline_state); +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, pipeline_state %p.\n", iface, pipeline_state); + +@@ -4140,10 +4173,10 @@ static unsigned int d3d12_find_ds_multiplanar_transition(const D3D12_RESOURCE_BA + return 0; + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsCommandList3 *iface, + UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + bool have_aliasing_barriers = false, have_split_barriers = false; + const struct vkd3d_vk_device_procs *vk_procs; + const struct vkd3d_vulkan_info *vk_info; +@@ -4366,13 +4399,13 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC + WARN("Issuing split barrier(s) on D3D12_RESOURCE_BARRIER_FLAG_END_ONLY.\n"); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ExecuteBundle(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ExecuteBundle(ID3D12GraphicsCommandList3 *iface, + ID3D12GraphicsCommandList *command_list) + { + FIXME("iface %p, command_list %p stub!\n", iface, command_list); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetDescriptorHeaps(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetDescriptorHeaps(ID3D12GraphicsCommandList3 *iface, + UINT heap_count, ID3D12DescriptorHeap *const *heaps) + { + TRACE("iface %p, heap_count %u, heaps %p.\n", iface, heap_count, heaps); +@@ -4398,10 +4431,10 @@ static void d3d12_command_list_set_root_signature(struct d3d12_command_list *lis + d3d12_command_list_invalidate_root_parameters(list, bind_point); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootSignature(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootSignature(ID3D12GraphicsCommandList3 *iface, + ID3D12RootSignature *root_signature) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_signature %p.\n", iface, root_signature); + +@@ -4409,10 +4442,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootSignature(ID3D12G + unsafe_impl_from_ID3D12RootSignature(root_signature)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootSignature(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootSignature(ID3D12GraphicsCommandList3 *iface, + ID3D12RootSignature *root_signature) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_signature %p.\n", iface, root_signature); + +@@ -4425,6 +4458,7 @@ static void d3d12_command_list_set_descriptor_table(struct d3d12_command_list *l + { + struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point]; + const struct d3d12_root_signature *root_signature = bindings->root_signature; ++ struct d3d12_descriptor_heap *descriptor_heap; + struct d3d12_desc *desc; + + assert(root_signature_get_descriptor_table(root_signature, index)); +@@ -4435,15 +4469,25 @@ static void d3d12_command_list_set_descriptor_table(struct d3d12_command_list *l + if (bindings->descriptor_tables[index] == desc) + return; + ++ descriptor_heap = d3d12_desc_get_descriptor_heap(desc); ++ if (!(descriptor_heap->desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) ++ { ++ /* GetGPUDescriptorHandleForHeapStart() returns a null handle in this case, ++ * but a CPU handle could be passed. */ ++ WARN("Descriptor heap %p is not shader visible.\n", descriptor_heap); ++ return; ++ } ++ command_list_add_descriptor_heap(list, descriptor_heap); ++ + bindings->descriptor_tables[index] = desc; + bindings->descriptor_table_dirty_mask |= (uint64_t)1 << index; + bindings->descriptor_table_active_mask |= (uint64_t)1 << index; + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList3 *iface, + UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64".\n", + iface, root_parameter_index, base_descriptor.ptr); +@@ -4452,10 +4496,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootDescriptorTable(I + root_parameter_index, base_descriptor); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList3 *iface, + UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64".\n", + iface, root_parameter_index, base_descriptor.ptr); +@@ -4477,10 +4521,10 @@ static void d3d12_command_list_set_root_constants(struct d3d12_command_list *lis + c->stage_flags, c->offset + offset * sizeof(uint32_t), count * sizeof(uint32_t), data)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList3 *iface, + UINT root_parameter_index, UINT data, UINT dst_offset) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, data 0x%08x, dst_offset %u.\n", + iface, root_parameter_index, data, dst_offset); +@@ -4489,10 +4533,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstant(ID3 + root_parameter_index, dst_offset, 1, &data); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList3 *iface, + UINT root_parameter_index, UINT data, UINT dst_offset) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, data 0x%08x, dst_offset %u.\n", + iface, root_parameter_index, data, dst_offset); +@@ -4501,10 +4545,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRoot32BitConstant(ID + root_parameter_index, dst_offset, 1, &data); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList3 *iface, + UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, constant_count %u, data %p, dst_offset %u.\n", + iface, root_parameter_index, constant_count, data, dst_offset); +@@ -4513,10 +4557,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRoot32BitConstants(ID + root_parameter_index, dst_offset, constant_count, data); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList3 *iface, + UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, constant_count %u, data %p, dst_offset %u.\n", + iface, root_parameter_index, constant_count, data, dst_offset); +@@ -4578,9 +4622,9 @@ static void d3d12_command_list_set_root_cbv(struct d3d12_command_list *list, + } + + static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootConstantBufferView( +- ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) ++ ID3D12GraphicsCommandList3 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n", + iface, root_parameter_index, address); +@@ -4589,9 +4633,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootConstantBufferVie + } + + static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootConstantBufferView( +- ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) ++ ID3D12GraphicsCommandList3 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n", + iface, root_parameter_index, address); +@@ -4650,9 +4694,9 @@ static void d3d12_command_list_set_root_descriptor(struct d3d12_command_list *li + } + + static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootShaderResourceView( +- ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) ++ ID3D12GraphicsCommandList3 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n", + iface, root_parameter_index, address); +@@ -4662,9 +4706,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootShaderResourceVie + } + + static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootShaderResourceView( +- ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) ++ ID3D12GraphicsCommandList3 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n", + iface, root_parameter_index, address); +@@ -4674,9 +4718,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootShaderResourceVi + } + + static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootUnorderedAccessView( +- ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) ++ ID3D12GraphicsCommandList3 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n", + iface, root_parameter_index, address); +@@ -4686,9 +4730,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootUnorderedAccessVi + } + + static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootUnorderedAccessView( +- ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) ++ ID3D12GraphicsCommandList3 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + + TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n", + iface, root_parameter_index, address); +@@ -4697,10 +4741,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootUnorderedAccessV + root_parameter_index, address); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_IASetIndexBuffer(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_IASetIndexBuffer(ID3D12GraphicsCommandList3 *iface, + const D3D12_INDEX_BUFFER_VIEW *view) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_vk_device_procs *vk_procs; + struct d3d12_resource *resource; + enum VkIndexType index_type; +@@ -4740,10 +4784,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetIndexBuffer(ID3D12Graphics + view->BufferLocation - resource->gpu_address, index_type)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_IASetVertexBuffers(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_IASetVertexBuffers(ID3D12GraphicsCommandList3 *iface, + UINT start_slot, UINT view_count, const D3D12_VERTEX_BUFFER_VIEW *views) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct vkd3d_null_resources *null_resources; + struct vkd3d_gpu_va_allocator *gpu_va_allocator; + VkDeviceSize offsets[ARRAY_SIZE(list->strides)]; +@@ -4798,10 +4842,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetVertexBuffers(ID3D12Graphi + d3d12_command_list_invalidate_current_pipeline(list); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SOSetTargets(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SOSetTargets(ID3D12GraphicsCommandList3 *iface, + UINT start_slot, UINT view_count, const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + VkDeviceSize offsets[ARRAY_SIZE(list->so_counter_buffers)]; + VkDeviceSize sizes[ARRAY_SIZE(list->so_counter_buffers)]; + VkBuffer buffers[ARRAY_SIZE(list->so_counter_buffers)]; +@@ -4863,11 +4907,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_SOSetTargets(ID3D12GraphicsComm + VK_CALL(vkCmdBindTransformFeedbackBuffersEXT(list->vk_command_buffer, first, count, buffers, offsets, sizes)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12GraphicsCommandList3 *iface, + UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, + BOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct d3d12_rtv_desc *rtv_desc; + const struct d3d12_dsv_desc *dsv_desc; + VkFormat prev_dsv_format; +@@ -5068,12 +5112,12 @@ static void d3d12_command_list_clear(struct d3d12_command_list *list, + } + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(ID3D12GraphicsCommandList3 *iface, + D3D12_CPU_DESCRIPTOR_HANDLE dsv, D3D12_CLEAR_FLAGS flags, float depth, UINT8 stencil, + UINT rect_count, const D3D12_RECT *rects) + { + const union VkClearValue clear_value = {.depthStencil = {depth, stencil}}; +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct d3d12_dsv_desc *dsv_desc = d3d12_dsv_desc_from_cpu_handle(dsv); + struct VkAttachmentDescription attachment_desc; + struct VkAttachmentReference ds_reference; +@@ -5117,10 +5161,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(ID3D12Gra + &clear_value, rect_count, rects); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(ID3D12GraphicsCommandList3 *iface, + D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4], UINT rect_count, const D3D12_RECT *rects) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const struct d3d12_rtv_desc *rtv_desc = d3d12_rtv_desc_from_cpu_handle(rtv); + struct VkAttachmentDescription attachment_desc; + struct VkAttachmentReference color_reference; +@@ -5365,11 +5409,11 @@ static const struct vkd3d_format *vkd3d_fixup_clear_uav_uint_colour(struct d3d12 + } + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList3 *iface, + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, + const UINT values[4], UINT rect_count, const D3D12_RECT *rects) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct vkd3d_view *descriptor, *uint_view = NULL; + struct d3d12_device *device = list->device; + struct vkd3d_texture_view_desc view_desc; +@@ -5431,11 +5475,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID + vkd3d_view_decref(uint_view, device); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList3 *iface, + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, + const float values[4], UINT rect_count, const D3D12_RECT *rects) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_resource *resource_impl; + VkClearColorValue colour; + struct vkd3d_view *view; +@@ -5451,16 +5495,16 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(I + d3d12_command_list_clear_uav(list, resource_impl, view, &colour, rect_count, rects); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_DiscardResource(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_DiscardResource(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *resource, const D3D12_DISCARD_REGION *region) + { + FIXME_ONCE("iface %p, resource %p, region %p stub!\n", iface, resource, region); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_BeginQuery(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_BeginQuery(ID3D12GraphicsCommandList3 *iface, + ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap); + const struct vkd3d_vk_device_procs *vk_procs; + VkQueryControlFlags flags = 0; +@@ -5487,10 +5531,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_BeginQuery(ID3D12GraphicsComman + VK_CALL(vkCmdBeginQuery(list->vk_command_buffer, query_heap->vk_query_pool, index, flags)); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_EndQuery(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_EndQuery(ID3D12GraphicsCommandList3 *iface, + ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap); + const struct vkd3d_vk_device_procs *vk_procs; + +@@ -5532,12 +5576,12 @@ static size_t get_query_stride(D3D12_QUERY_TYPE type) + return sizeof(uint64_t); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ResolveQueryData(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ResolveQueryData(ID3D12GraphicsCommandList3 *iface, + ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT start_index, UINT query_count, + ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset) + { + const struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap); +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_resource *buffer = unsafe_impl_from_ID3D12Resource(dst_buffer); + const struct vkd3d_vk_device_procs *vk_procs; + unsigned int i, first, count; +@@ -5613,10 +5657,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResolveQueryData(ID3D12Graphics + } + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetPredication(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetPredication(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *buffer, UINT64 aligned_buffer_offset, D3D12_PREDICATION_OP operation) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_resource *resource = unsafe_impl_from_ID3D12Resource(buffer); + const struct vkd3d_vulkan_info *vk_info = &list->device->vk_info; + const struct vkd3d_vk_device_procs *vk_procs; +@@ -5685,19 +5729,19 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetPredication(ID3D12GraphicsCo + } + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetMarker(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetMarker(ID3D12GraphicsCommandList3 *iface, + UINT metadata, const void *data, UINT size) + { + FIXME("iface %p, metadata %#x, data %p, size %u stub!\n", iface, metadata, data, size); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_BeginEvent(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_BeginEvent(ID3D12GraphicsCommandList3 *iface, + UINT metadata, const void *data, UINT size) + { + FIXME("iface %p, metadata %#x, data %p, size %u stub!\n", iface, metadata, data, size); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_EndEvent(ID3D12GraphicsCommandList2 *iface) ++static void STDMETHODCALLTYPE d3d12_command_list_EndEvent(ID3D12GraphicsCommandList3 *iface) + { + FIXME("iface %p stub!\n", iface); + } +@@ -5706,14 +5750,14 @@ STATIC_ASSERT(sizeof(VkDispatchIndirectCommand) == sizeof(D3D12_DISPATCH_ARGUMEN + STATIC_ASSERT(sizeof(VkDrawIndexedIndirectCommand) == sizeof(D3D12_DRAW_INDEXED_ARGUMENTS)); + STATIC_ASSERT(sizeof(VkDrawIndirectCommand) == sizeof(D3D12_DRAW_ARGUMENTS)); + +-static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(ID3D12GraphicsCommandList3 *iface, + ID3D12CommandSignature *command_signature, UINT max_command_count, ID3D12Resource *arg_buffer, + UINT64 arg_buffer_offset, ID3D12Resource *count_buffer, UINT64 count_buffer_offset) + { + struct d3d12_command_signature *sig_impl = unsafe_impl_from_ID3D12CommandSignature(command_signature); + struct d3d12_resource *count_impl = unsafe_impl_from_ID3D12Resource(count_buffer); + struct d3d12_resource *arg_impl = unsafe_impl_from_ID3D12Resource(arg_buffer); +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + const D3D12_COMMAND_SIGNATURE_DESC *signature_desc; + const struct vkd3d_vk_device_procs *vk_procs; + unsigned int i; +@@ -5731,6 +5775,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(ID3D12GraphicsC + return; + } + ++ d3d12_command_signature_incref(sig_impl); ++ + signature_desc = &sig_impl->desc; + for (i = 0; i < signature_desc->NumArgumentDescs; ++i) + { +@@ -5793,6 +5839,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(ID3D12GraphicsC + if (!d3d12_command_list_update_compute_state(list)) + { + WARN("Failed to update compute state, ignoring dispatch.\n"); ++ d3d12_command_signature_decref(sig_impl); + return; + } + +@@ -5805,9 +5852,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(ID3D12GraphicsC + break; + } + } ++ ++ d3d12_command_signature_decref(sig_impl); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *dst_buffer, UINT64 dst_offset, + ID3D12Resource *src_buffer, UINT64 src_offset, + UINT dependent_resource_count, ID3D12Resource * const *dependent_resources, +@@ -5820,7 +5869,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT(ID3D12Grap + dependent_resource_count, dependent_resources, dependent_sub_resource_ranges); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *dst_buffer, UINT64 dst_offset, + ID3D12Resource *src_buffer, UINT64 src_offset, + UINT dependent_resource_count, ID3D12Resource * const *dependent_resources, +@@ -5833,20 +5882,20 @@ static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT64(ID3D12Gr + dependent_resource_count, dependent_resources, dependent_sub_resource_ranges); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_OMSetDepthBounds(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_OMSetDepthBounds(ID3D12GraphicsCommandList3 *iface, + FLOAT min, FLOAT max) + { + FIXME("iface %p, min %.8e, max %.8e stub!\n", iface, min, max); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetSamplePositions(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_SetSamplePositions(ID3D12GraphicsCommandList3 *iface, + UINT sample_count, UINT pixel_count, D3D12_SAMPLE_POSITION *sample_positions) + { + FIXME("iface %p, sample_count %u, pixel_count %u, sample_positions %p stub!\n", + iface, sample_count, pixel_count, sample_positions); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresourceRegion(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresourceRegion(ID3D12GraphicsCommandList3 *iface, + ID3D12Resource *dst_resource, UINT dst_sub_resource_idx, UINT dst_x, UINT dst_y, + ID3D12Resource *src_resource, UINT src_sub_resource_idx, + D3D12_RECT *src_rect, DXGI_FORMAT format, D3D12_RESOLVE_MODE mode) +@@ -5858,16 +5907,16 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResolveSubresourceRegion(ID3D12 + src_resource, src_sub_resource_idx, src_rect, format, mode); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_SetViewInstanceMask(ID3D12GraphicsCommandList2 *iface, UINT mask) ++static void STDMETHODCALLTYPE d3d12_command_list_SetViewInstanceMask(ID3D12GraphicsCommandList3 *iface, UINT mask) + { + FIXME("iface %p, mask %#x stub!\n", iface, mask); + } + +-static void STDMETHODCALLTYPE d3d12_command_list_WriteBufferImmediate(ID3D12GraphicsCommandList2 *iface, ++static void STDMETHODCALLTYPE d3d12_command_list_WriteBufferImmediate(ID3D12GraphicsCommandList3 *iface, + UINT count, const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters, + const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes) + { +- struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList3(iface); + struct d3d12_resource *resource; + unsigned int i; + +@@ -5880,7 +5929,13 @@ static void STDMETHODCALLTYPE d3d12_command_list_WriteBufferImmediate(ID3D12Grap + } + } + +-static const struct ID3D12GraphicsCommandList2Vtbl d3d12_command_list_vtbl = ++static void STDMETHODCALLTYPE d3d12_command_list_SetProtectedResourceSession(ID3D12GraphicsCommandList3 *iface, ++ ID3D12ProtectedResourceSession *protected_session) ++{ ++ FIXME("iface %p, protected_session %p stub!\n", iface, protected_session); ++} ++ ++static const struct ID3D12GraphicsCommandList3Vtbl d3d12_command_list_vtbl = + { + /* IUnknown methods */ + d3d12_command_list_QueryInterface, +@@ -5956,6 +6011,8 @@ static const struct ID3D12GraphicsCommandList2Vtbl d3d12_command_list_vtbl = + d3d12_command_list_SetViewInstanceMask, + /* ID3D12GraphicsCommandList2 methods */ + d3d12_command_list_WriteBufferImmediate, ++ /* ID3D12GraphicsCommandList3 methods */ ++ d3d12_command_list_SetProtectedResourceSession, + }; + + static struct d3d12_command_list *unsafe_impl_from_ID3D12CommandList(ID3D12CommandList *iface) +@@ -5963,7 +6020,7 @@ static struct d3d12_command_list *unsafe_impl_from_ID3D12CommandList(ID3D12Comma + if (!iface) + return NULL; + assert(iface->lpVtbl == (struct ID3D12CommandListVtbl *)&d3d12_command_list_vtbl); +- return CONTAINING_RECORD(iface, struct d3d12_command_list, ID3D12GraphicsCommandList2_iface); ++ return CONTAINING_RECORD(iface, struct d3d12_command_list, ID3D12GraphicsCommandList3_iface); + } + + static HRESULT d3d12_command_list_init(struct d3d12_command_list *list, struct d3d12_device *device, +@@ -5972,7 +6029,7 @@ static HRESULT d3d12_command_list_init(struct d3d12_command_list *list, struct d + { + HRESULT hr; + +- list->ID3D12GraphicsCommandList2_iface.lpVtbl = &d3d12_command_list_vtbl; ++ list->ID3D12GraphicsCommandList3_iface.lpVtbl = &d3d12_command_list_vtbl; + list->refcount = 1; + + list->type = type; +@@ -7299,16 +7356,7 @@ static ULONG STDMETHODCALLTYPE d3d12_command_signature_Release(ID3D12CommandSign + TRACE("%p decreasing refcount to %u.\n", signature, refcount); + + if (!refcount) +- { +- struct d3d12_device *device = signature->device; +- +- vkd3d_private_store_destroy(&signature->private_store); +- +- vkd3d_free((void *)signature->desc.pArgumentDescs); +- vkd3d_free(signature); +- +- d3d12_device_release(device); +- } ++ d3d12_command_signature_decref(signature); + + return refcount; + } +@@ -7415,6 +7463,7 @@ HRESULT d3d12_command_signature_create(struct d3d12_device *device, const D3D12_ + + object->ID3D12CommandSignature_iface.lpVtbl = &d3d12_command_signature_vtbl; + object->refcount = 1; ++ object->internal_refcount = 1; + + object->desc = *desc; + if (!(object->desc.pArgumentDescs = vkd3d_calloc(desc->NumArgumentDescs, sizeof(*desc->pArgumentDescs)))) +diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c +index b9a8943cc08..a2e1f13dec3 100644 +--- a/libs/vkd3d/libs/vkd3d/device.c ++++ b/libs/vkd3d/libs/vkd3d/device.c +@@ -2657,8 +2657,8 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList(ID3D12Device *if + initial_pipeline_state, &object))) + return hr; + +- return return_interface(&object->ID3D12GraphicsCommandList2_iface, +- &IID_ID3D12GraphicsCommandList2, riid, command_list); ++ return return_interface(&object->ID3D12GraphicsCommandList3_iface, ++ &IID_ID3D12GraphicsCommandList3, riid, command_list); + } + + /* Direct3D feature levels restrict which formats can be optionally supported. */ +@@ -3414,6 +3414,7 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device *iface, + struct d3d12_device *device = impl_from_ID3D12Device(iface); + unsigned int dst_range_idx, dst_idx, src_range_idx, src_idx; + unsigned int dst_range_size, src_range_size; ++ struct d3d12_descriptor_heap *dst_heap; + const struct d3d12_desc *src; + struct d3d12_desc *dst; + +@@ -3443,13 +3444,14 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device *iface, + src_range_size = src_descriptor_range_sizes ? src_descriptor_range_sizes[src_range_idx] : 1; + + dst = d3d12_desc_from_cpu_handle(dst_descriptor_range_offsets[dst_range_idx]); ++ dst_heap = d3d12_desc_get_descriptor_heap(dst); + src = d3d12_desc_from_cpu_handle(src_descriptor_range_offsets[src_range_idx]); + + for (; dst_idx < dst_range_size && src_idx < src_range_size; ++dst_idx, ++src_idx) + { + if (dst[dst_idx].s.u.object == src[src_idx].s.u.object) + continue; +- d3d12_desc_copy(&dst[dst_idx], &src[src_idx], device); ++ d3d12_desc_copy(&dst[dst_idx], &src[src_idx], dst_heap, device); + } + + if (dst_idx >= dst_range_size) +@@ -3747,7 +3749,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateFence(ID3D12Device *iface, + if (FAILED(hr = d3d12_fence_create(device, initial_value, flags, &object))) + return hr; + +- return return_interface(&object->ID3D12Fence_iface, &IID_ID3D12Fence, riid, fence); ++ return return_interface(&object->ID3D12Fence1_iface, &IID_ID3D12Fence1, riid, fence); + } + + static HRESULT STDMETHODCALLTYPE d3d12_device_GetDeviceRemovedReason(ID3D12Device *iface) +@@ -3891,12 +3893,18 @@ static void STDMETHODCALLTYPE d3d12_device_GetResourceTiling(ID3D12Device *iface + UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling, + D3D12_SUBRESOURCE_TILING *sub_resource_tilings) + { +- FIXME("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, " ++ const struct d3d12_resource *resource_impl = impl_from_ID3D12Resource(resource); ++ struct d3d12_device *device = impl_from_ID3D12Device(iface); ++ ++ TRACE("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, " + "standard_title_shape %p, sub_resource_tiling_count %p, " +- "first_sub_resource_tiling %u, sub_resource_tilings %p stub!\n", ++ "first_sub_resource_tiling %u, sub_resource_tilings %p.\n", + iface, resource, total_tile_count, packed_mip_info, standard_tile_shape, + sub_resource_tiling_count, first_sub_resource_tiling, + sub_resource_tilings); ++ ++ d3d12_resource_get_tiling(device, resource_impl, total_tile_count, packed_mip_info, standard_tile_shape, ++ sub_resource_tiling_count, first_sub_resource_tiling, sub_resource_tilings); + } + + static LUID * STDMETHODCALLTYPE d3d12_device_GetAdapterLuid(ID3D12Device *iface, LUID *luid) +diff --git a/libs/vkd3d/libs/vkd3d/resource.c b/libs/vkd3d/libs/vkd3d/resource.c +index 4c07d326504..cd3856c2937 100644 +--- a/libs/vkd3d/libs/vkd3d/resource.c ++++ b/libs/vkd3d/libs/vkd3d/resource.c +@@ -971,6 +971,11 @@ HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device, + return hr; + } + ++static void d3d12_resource_tile_info_cleanup(struct d3d12_resource *resource) ++{ ++ vkd3d_free(resource->tiles.subresources); ++} ++ + static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12_device *device) + { + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; +@@ -986,6 +991,8 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12 + else + VK_CALL(vkDestroyImage(device->vk_device, resource->u.vk_image, NULL)); + ++ d3d12_resource_tile_info_cleanup(resource); ++ + if (resource->heap) + d3d12_heap_resource_destroyed(resource->heap); + } +@@ -1057,9 +1064,193 @@ static void d3d12_resource_get_level_box(const struct d3d12_resource *resource, + box->back = d3d12_resource_desc_get_depth(&resource->desc, level); + } + +-static void d3d12_resource_init_tiles(struct d3d12_resource *resource) ++static void compute_image_subresource_size_in_tiles(const VkExtent3D *tile_extent, ++ const struct D3D12_RESOURCE_DESC *desc, unsigned int miplevel_idx, ++ struct vkd3d_tiled_region_extent *size) ++{ ++ unsigned int width, height, depth; ++ ++ width = d3d12_resource_desc_get_width(desc, miplevel_idx); ++ height = d3d12_resource_desc_get_height(desc, miplevel_idx); ++ depth = d3d12_resource_desc_get_depth(desc, miplevel_idx); ++ size->width = (width + tile_extent->width - 1) / tile_extent->width; ++ size->height = (height + tile_extent->height - 1) / tile_extent->height; ++ size->depth = (depth + tile_extent->depth - 1) / tile_extent->depth; ++} ++ ++void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource, ++ UINT *total_tile_count, D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape, ++ UINT *subresource_tiling_count, UINT first_subresource_tiling, ++ D3D12_SUBRESOURCE_TILING *subresource_tilings) + { +- resource->tiles.subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc); ++ unsigned int i, subresource, subresource_count, miplevel_idx, count; ++ const struct vkd3d_subresource_tile_info *tile_info; ++ const VkExtent3D *tile_extent; ++ ++ tile_extent = &resource->tiles.tile_extent; ++ ++ if (packed_mip_info) ++ { ++ packed_mip_info->NumStandardMips = resource->tiles.standard_mip_count; ++ packed_mip_info->NumPackedMips = resource->desc.MipLevels - packed_mip_info->NumStandardMips; ++ packed_mip_info->NumTilesForPackedMips = !!resource->tiles.packed_mip_tile_count; /* non-zero dummy value */ ++ packed_mip_info->StartTileIndexInOverallResource = packed_mip_info->NumPackedMips ++ ? resource->tiles.subresources[resource->tiles.standard_mip_count].offset : 0; ++ } ++ ++ if (standard_tile_shape) ++ { ++ /* D3D12 docs say tile shape is cleared to zero if there is no standard mip, but drivers don't to do this. */ ++ standard_tile_shape->WidthInTexels = tile_extent->width; ++ standard_tile_shape->HeightInTexels = tile_extent->height; ++ standard_tile_shape->DepthInTexels = tile_extent->depth; ++ } ++ ++ if (total_tile_count) ++ *total_tile_count = resource->tiles.total_count; ++ ++ if (!subresource_tiling_count) ++ return; ++ ++ subresource_count = resource->tiles.subresource_count; ++ ++ count = subresource_count - min(first_subresource_tiling, subresource_count); ++ count = min(count, *subresource_tiling_count); ++ ++ for (i = 0; i < count; ++i) ++ { ++ subresource = i + first_subresource_tiling; ++ miplevel_idx = subresource % resource->desc.MipLevels; ++ if (miplevel_idx >= resource->tiles.standard_mip_count) ++ { ++ memset(&subresource_tilings[i], 0, sizeof(subresource_tilings[i])); ++ subresource_tilings[i].StartTileIndexInOverallResource = D3D12_PACKED_TILE; ++ continue; ++ } ++ ++ tile_info = &resource->tiles.subresources[subresource]; ++ subresource_tilings[i].StartTileIndexInOverallResource = tile_info->offset; ++ subresource_tilings[i].WidthInTiles = tile_info->extent.width; ++ subresource_tilings[i].HeightInTiles = tile_info->extent.height; ++ subresource_tilings[i].DepthInTiles = tile_info->extent.depth; ++ } ++ *subresource_tiling_count = i; ++} ++ ++static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3d12_device *device) ++{ ++ unsigned int i, start_idx, subresource_count, tile_count, miplevel_idx; ++ const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; ++ VkSparseImageMemoryRequirements *sparse_requirements_array; ++ VkSparseImageMemoryRequirements sparse_requirements = {0}; ++ struct vkd3d_subresource_tile_info *tile_info; ++ VkMemoryRequirements requirements; ++ const VkExtent3D *tile_extent; ++ uint32_t requirement_count; ++ ++ subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc); ++ ++ if (!(resource->tiles.subresources = vkd3d_calloc(subresource_count, sizeof(*resource->tiles.subresources)))) ++ { ++ ERR("Failed to allocate subresource info array.\n"); ++ return false; ++ } ++ ++ if (d3d12_resource_is_buffer(resource)) ++ { ++ assert(subresource_count == 1); ++ ++ VK_CALL(vkGetBufferMemoryRequirements(device->vk_device, resource->u.vk_buffer, &requirements)); ++ if (requirements.alignment > D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES) ++ FIXME("Vulkan device tile size is greater than the standard D3D12 tile size.\n"); ++ ++ tile_info = &resource->tiles.subresources[0]; ++ tile_info->offset = 0; ++ tile_info->extent.width = align(resource->desc.Width, D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES) ++ / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; ++ tile_info->extent.height = 1; ++ tile_info->extent.depth = 1; ++ tile_info->count = tile_info->extent.width; ++ ++ resource->tiles.tile_extent.width = D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; ++ resource->tiles.tile_extent.height = 1; ++ resource->tiles.tile_extent.depth = 1; ++ resource->tiles.total_count = tile_info->extent.width; ++ resource->tiles.subresource_count = 1; ++ resource->tiles.standard_mip_count = 1; ++ resource->tiles.packed_mip_tile_count = 0; ++ } ++ else ++ { ++ VK_CALL(vkGetImageMemoryRequirements(device->vk_device, resource->u.vk_image, &requirements)); ++ if (requirements.alignment > D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES) ++ FIXME("Vulkan device tile size is greater than the standard D3D12 tile size.\n"); ++ ++ requirement_count = 0; ++ VK_CALL(vkGetImageSparseMemoryRequirements(device->vk_device, resource->u.vk_image, &requirement_count, NULL)); ++ if (!(sparse_requirements_array = vkd3d_calloc(requirement_count, sizeof(*sparse_requirements_array)))) ++ { ++ ERR("Failed to allocate sparse requirements array.\n"); ++ return false; ++ } ++ VK_CALL(vkGetImageSparseMemoryRequirements(device->vk_device, resource->u.vk_image, ++ &requirement_count, sparse_requirements_array)); ++ ++ for (i = 0; i < requirement_count; ++i) ++ { ++ if (sparse_requirements_array[i].formatProperties.aspectMask & resource->format->vk_aspect_mask) ++ { ++ if (sparse_requirements.formatProperties.aspectMask) ++ { ++ WARN("Ignoring properties for aspect mask %#x.\n", ++ sparse_requirements_array[i].formatProperties.aspectMask); ++ } ++ else ++ { ++ sparse_requirements = sparse_requirements_array[i]; ++ } ++ } ++ } ++ vkd3d_free(sparse_requirements_array); ++ if (!sparse_requirements.formatProperties.aspectMask) ++ { ++ WARN("Failed to get sparse requirements.\n"); ++ return false; ++ } ++ ++ resource->tiles.tile_extent = sparse_requirements.formatProperties.imageGranularity; ++ resource->tiles.subresource_count = subresource_count; ++ resource->tiles.standard_mip_count = sparse_requirements.imageMipTailSize ++ ? sparse_requirements.imageMipTailFirstLod : resource->desc.MipLevels; ++ resource->tiles.packed_mip_tile_count = (resource->tiles.standard_mip_count < resource->desc.MipLevels) ++ ? sparse_requirements.imageMipTailSize / requirements.alignment : 0; ++ ++ for (i = 0, start_idx = 0; i < subresource_count; ++i) ++ { ++ miplevel_idx = i % resource->desc.MipLevels; ++ ++ tile_extent = &sparse_requirements.formatProperties.imageGranularity; ++ tile_info = &resource->tiles.subresources[i]; ++ compute_image_subresource_size_in_tiles(tile_extent, &resource->desc, miplevel_idx, &tile_info->extent); ++ tile_info->offset = start_idx; ++ tile_info->count = 0; ++ ++ if (miplevel_idx < resource->tiles.standard_mip_count) ++ { ++ tile_count = tile_info->extent.width * tile_info->extent.height * tile_info->extent.depth; ++ start_idx += tile_count; ++ tile_info->count = tile_count; ++ } ++ else if (miplevel_idx == resource->tiles.standard_mip_count) ++ { ++ tile_info->count = 1; /* Non-zero dummy value */ ++ start_idx += 1; ++ } ++ } ++ resource->tiles.total_count = start_idx; ++ } ++ ++ return true; + } + + /* ID3D12Resource */ +@@ -2013,7 +2204,11 @@ HRESULT d3d12_reserved_resource_create(struct d3d12_device *device, + desc, initial_state, optimized_clear_value, &object))) + return hr; + +- d3d12_resource_init_tiles(object); ++ if (!d3d12_resource_init_tiles(object, device)) ++ { ++ d3d12_resource_Release(&object->ID3D12Resource_iface); ++ return E_OUTOFMEMORY; ++ } + + TRACE("Created reserved resource %p.\n", object); + +@@ -2411,13 +2606,11 @@ void d3d12_desc_flush_vk_heap_updates_locked(struct d3d12_descriptor_heap *descr + descriptor_writes_free_object_refs(&writes, device); + } + +-static void d3d12_desc_mark_as_modified(struct d3d12_desc *dst) ++static void d3d12_desc_mark_as_modified(struct d3d12_desc *dst, struct d3d12_descriptor_heap *descriptor_heap) + { +- struct d3d12_descriptor_heap *descriptor_heap; + unsigned int i, head; + + i = dst->index; +- descriptor_heap = d3d12_desc_get_descriptor_heap(dst); + head = descriptor_heap->dirty_list_head; + + /* Only one thread can swap the value away from zero. */ +@@ -2431,14 +2624,20 @@ static void d3d12_desc_mark_as_modified(struct d3d12_desc *dst) + } + } + +-void d3d12_desc_write_atomic(struct d3d12_desc *dst, const struct d3d12_desc *src, +- struct d3d12_device *device) ++static inline void descriptor_heap_write_atomic(struct d3d12_descriptor_heap *descriptor_heap, struct d3d12_desc *dst, ++ const struct d3d12_desc *src, struct d3d12_device *device) + { + void *object = src->s.u.object; + + d3d12_desc_replace(dst, object, device); +- if (device->use_vk_heaps && object && !dst->next) +- d3d12_desc_mark_as_modified(dst); ++ if (descriptor_heap->use_vk_heaps && object && !dst->next) ++ d3d12_desc_mark_as_modified(dst, descriptor_heap); ++} ++ ++void d3d12_desc_write_atomic(struct d3d12_desc *dst, const struct d3d12_desc *src, ++ struct d3d12_device *device) ++{ ++ descriptor_heap_write_atomic(d3d12_desc_get_descriptor_heap(dst), dst, src, device); + } + + static void d3d12_desc_destroy(struct d3d12_desc *descriptor, struct d3d12_device *device) +@@ -2446,7 +2645,9 @@ static void d3d12_desc_destroy(struct d3d12_desc *descriptor, struct d3d12_devic + d3d12_desc_replace(descriptor, NULL, device); + } + +-void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src, ++/* This is a major performance bottleneck for some games, so do not load the device ++ * pointer from dst_heap. In some cases device will not be used. */ ++void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src, struct d3d12_descriptor_heap *dst_heap, + struct d3d12_device *device) + { + struct d3d12_desc tmp; +@@ -2454,7 +2655,7 @@ void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src, + assert(dst != src); + + tmp.s.u.object = d3d12_desc_get_object_ref(src, device); +- d3d12_desc_write_atomic(dst, &tmp, device); ++ descriptor_heap_write_atomic(dst_heap, dst, &tmp, device); + } + + static VkDeviceSize vkd3d_get_required_texel_buffer_alignment(const struct d3d12_device *device, +@@ -3853,7 +4054,15 @@ static D3D12_GPU_DESCRIPTOR_HANDLE * STDMETHODCALLTYPE d3d12_descriptor_heap_Get + + TRACE("iface %p, descriptor %p.\n", iface, descriptor); + +- descriptor->ptr = (uint64_t)(intptr_t)heap->descriptors; ++ if (heap->desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) ++ { ++ descriptor->ptr = (uint64_t)(intptr_t)heap->descriptors; ++ } ++ else ++ { ++ WARN("Heap %p is not shader-visible.\n", iface); ++ descriptor->ptr = 0; ++ } + + return descriptor; + } +@@ -3956,7 +4165,7 @@ static HRESULT d3d12_descriptor_heap_vk_descriptor_sets_init(struct d3d12_descri + descriptor_heap->vk_descriptor_pool = VK_NULL_HANDLE; + memset(descriptor_heap->vk_descriptor_sets, 0, sizeof(descriptor_heap->vk_descriptor_sets)); + +- if (!device->use_vk_heaps || (desc->Type != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ++ if (!descriptor_heap->use_vk_heaps || (desc->Type != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV + && desc->Type != D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)) + return S_OK; + +@@ -3987,6 +4196,7 @@ static HRESULT d3d12_descriptor_heap_init(struct d3d12_descriptor_heap *descript + if (FAILED(hr = vkd3d_private_store_init(&descriptor_heap->private_store))) + return hr; + ++ descriptor_heap->use_vk_heaps = device->use_vk_heaps && (desc->Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); + d3d12_descriptor_heap_vk_descriptor_sets_init(descriptor_heap, device, desc); + vkd3d_mutex_init(&descriptor_heap->vk_sets_mutex); + +diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h +index c5259420acf..4bd6812b16e 100644 +--- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h ++++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h +@@ -253,6 +253,11 @@ static inline void vkd3d_cond_destroy(struct vkd3d_cond *cond) + { + } + ++static inline unsigned int vkd3d_atomic_increment(unsigned int volatile *x) ++{ ++ return InterlockedIncrement((LONG volatile *)x); ++} ++ + static inline unsigned int vkd3d_atomic_decrement(unsigned int volatile *x) + { + return InterlockedDecrement((LONG volatile *)x); +@@ -387,6 +392,15 @@ static inline unsigned int vkd3d_atomic_decrement(unsigned int volatile *x) + } + # else + # error "vkd3d_atomic_decrement() not implemented for this platform" ++# endif /* HAVE_SYNC_SUB_AND_FETCH */ ++ ++# if HAVE_SYNC_ADD_AND_FETCH ++static inline unsigned int vkd3d_atomic_increment(unsigned int volatile *x) ++{ ++ return __sync_add_and_fetch(x, 1); ++} ++# else ++# error "vkd3d_atomic_increment() not implemented for this platform" + # endif /* HAVE_SYNC_ADD_AND_FETCH */ + + # if HAVE_SYNC_BOOL_COMPARE_AND_SWAP +@@ -602,10 +616,12 @@ struct vkd3d_signaled_semaphore + /* ID3D12Fence */ + struct d3d12_fence + { +- ID3D12Fence ID3D12Fence_iface; ++ ID3D12Fence1 ID3D12Fence1_iface; + LONG internal_refcount; + LONG refcount; + ++ D3D12_FENCE_FLAGS flags; ++ + uint64_t value; + uint64_t max_pending_value; + struct vkd3d_mutex mutex; +@@ -673,9 +689,28 @@ struct d3d12_heap *unsafe_impl_from_ID3D12Heap(ID3D12Heap *iface); + #define VKD3D_RESOURCE_DEDICATED_HEAP 0x00000008 + #define VKD3D_RESOURCE_LINEAR_TILING 0x00000010 + ++struct vkd3d_tiled_region_extent ++{ ++ unsigned int width; ++ unsigned int height; ++ unsigned int depth; ++}; ++ ++struct vkd3d_subresource_tile_info ++{ ++ unsigned int offset; ++ unsigned int count; ++ struct vkd3d_tiled_region_extent extent; ++}; ++ + struct d3d12_resource_tile_info + { ++ VkExtent3D tile_extent; ++ unsigned int total_count; ++ unsigned int standard_mip_count; ++ unsigned int packed_mip_tile_count; + unsigned int subresource_count; ++ struct vkd3d_subresource_tile_info *subresources; + }; + + /* ID3D12Resource */ +@@ -728,6 +763,10 @@ static inline bool d3d12_resource_is_texture(const struct d3d12_resource *resour + + bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource); + HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC *desc, struct d3d12_device *device); ++void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource, ++ UINT *total_tile_count, D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape, ++ UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling, ++ D3D12_SUBRESOURCE_TILING *sub_resource_tilings); + + HRESULT d3d12_committed_resource_create(struct d3d12_device *device, + const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, +@@ -868,8 +907,9 @@ static inline void *d3d12_desc_get_object_ref(const volatile struct d3d12_desc * + { + do + { +- view = src->s.u.object; +- } while (view && !vkd3d_view_incref(view)); ++ if (!(view = src->s.u.object)) ++ return NULL; ++ } while (!vkd3d_view_incref(view)); + + /* Check if the object is still in src to handle the case where it was + * already freed and reused elsewhere when the refcount was incremented. */ +@@ -895,7 +935,10 @@ static inline void d3d12_desc_copy_raw(struct d3d12_desc *dst, const struct d3d1 + dst->s = src->s; + } + +-void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src, struct d3d12_device *device); ++struct d3d12_descriptor_heap; ++ ++void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src, struct d3d12_descriptor_heap *dst_heap, ++ struct d3d12_device *device); + void d3d12_desc_create_cbv(struct d3d12_desc *descriptor, + struct d3d12_device *device, const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc); + void d3d12_desc_create_srv(struct d3d12_desc *descriptor, +@@ -998,6 +1041,7 @@ struct d3d12_descriptor_heap + D3D12_DESCRIPTOR_HEAP_DESC desc; + + struct d3d12_device *device; ++ bool use_vk_heaps; + + struct vkd3d_private_store private_store; + +@@ -1382,7 +1426,7 @@ enum vkd3d_pipeline_bind_point + /* ID3D12CommandList */ + struct d3d12_command_list + { +- ID3D12GraphicsCommandList2 ID3D12GraphicsCommandList2_iface; ++ ID3D12GraphicsCommandList3 ID3D12GraphicsCommandList3_iface; + LONG refcount; + + D3D12_COMMAND_LIST_TYPE type; +@@ -1575,6 +1619,7 @@ struct d3d12_command_signature + { + ID3D12CommandSignature ID3D12CommandSignature_iface; + LONG refcount; ++ unsigned int internal_refcount; + + D3D12_COMMAND_SIGNATURE_DESC desc; + +-- +2.40.1 + diff --git a/patches/vkd3d-latest/0003-Updated-vkd3d-to-d4d960cb8b4f503ce3de51d9f29267ca938.patch b/patches/vkd3d-latest/0003-Updated-vkd3d-to-d4d960cb8b4f503ce3de51d9f29267ca938.patch deleted file mode 100644 index acec92b9..00000000 --- a/patches/vkd3d-latest/0003-Updated-vkd3d-to-d4d960cb8b4f503ce3de51d9f29267ca938.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 4f0d4cfe7cfe53c49aadb4b04ed852dc66d8ea2c Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Tue, 11 Jul 2023 09:11:10 +1000 -Subject: [PATCH] Updated vkd3d to d4d960cb8b4f503ce3de51d9f29267ca938f3183. - ---- - libs/vkd3d/libs/vkd3d-shader/spirv.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c -index 5535a6503d6..9725a5c7e25 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/spirv.c -+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c -@@ -3998,6 +3998,11 @@ static void spirv_compiler_emit_interpolation_decorations(struct spirv_compiler - vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading); - vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationSample, NULL, 0); - break; -+ case VKD3DSIM_LINEAR_NOPERSPECTIVE_SAMPLE: -+ vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationNoPerspective, NULL, 0); -+ vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading); -+ vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationSample, NULL, 0); -+ break; - default: - FIXME("Unhandled interpolation mode %#x.\n", mode); - break; --- -2.40.1 - diff --git a/patches/vkd3d-latest/0004-Updated-vkd3d-to-3bafd036bb53bf211cb8b05651835aba6fb.patch b/patches/vkd3d-latest/0004-Updated-vkd3d-to-3bafd036bb53bf211cb8b05651835aba6fb.patch deleted file mode 100644 index 5dd1c800..00000000 --- a/patches/vkd3d-latest/0004-Updated-vkd3d-to-3bafd036bb53bf211cb8b05651835aba6fb.patch +++ /dev/null @@ -1,3733 +0,0 @@ -From dbc2b39e89483d17a08439c8eb2b7d415ece362b Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 22 Jul 2023 09:56:45 +1000 -Subject: [PATCH] Updated vkd3d to 3bafd036bb53bf211cb8b05651835aba6fb47ebc. - ---- - libs/vkd3d/include/private/vkd3d_common.h | 5 + - libs/vkd3d/libs/vkd3d-shader/dxil.c | 1640 +++++++++++++++-- - libs/vkd3d/libs/vkd3d-shader/hlsl.c | 102 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.h | 13 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.y | 241 ++- - libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 195 +- - libs/vkd3d/libs/vkd3d-shader/tpf.c | 335 ++-- - .../libs/vkd3d-shader/vkd3d_shader_private.h | 9 + - 8 files changed, 2120 insertions(+), 420 deletions(-) - -diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h -index da15ee23fd3..0263fc47297 100644 ---- a/libs/vkd3d/include/private/vkd3d_common.h -+++ b/libs/vkd3d/include/private/vkd3d_common.h -@@ -173,6 +173,11 @@ static inline bool vkd3d_bound_range(size_t start, size_t count, size_t limit) - #endif - } - -+static inline bool vkd3d_object_range_overflow(size_t start, size_t count, size_t size) -+{ -+ return (~(size_t)0 - start) / size < count; -+} -+ - static inline uint16_t vkd3d_make_u16(uint8_t low, uint8_t high) - { - return low | ((uint16_t)high << 8); -diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c -index 67dcd26a0e0..53a4c2da4ba 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/dxil.c -+++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c -@@ -62,6 +62,159 @@ enum bitcode_abbrev_type - ABBREV_BLOB = 5, - }; - -+enum bitcode_address_space -+{ -+ ADDRESS_SPACE_DEFAULT, -+ ADDRESS_SPACE_DEVICEMEM, -+ ADDRESS_SPACE_CBUFFER, -+ ADDRESS_SPACE_GROUPSHARED, -+}; -+ -+enum bitcode_module_code -+{ -+ MODULE_CODE_VERSION = 1, -+ MODULE_CODE_GLOBALVAR = 7, -+ MODULE_CODE_FUNCTION = 8, -+}; -+ -+enum bitcode_constant_code -+{ -+ CST_CODE_SETTYPE = 1, -+ CST_CODE_NULL = 2, -+ CST_CODE_UNDEF = 3, -+ CST_CODE_INTEGER = 4, -+ CST_CODE_FLOAT = 6, -+ CST_CODE_STRING = 8, -+ CST_CODE_CE_GEP = 12, -+ CST_CODE_CE_INBOUNDS_GEP = 20, -+ CST_CODE_DATA = 22, -+}; -+ -+enum bitcode_function_code -+{ -+ FUNC_CODE_DECLAREBLOCKS = 1, -+ FUNC_CODE_INST_BINOP = 2, -+ FUNC_CODE_INST_CAST = 3, -+ FUNC_CODE_INST_RET = 10, -+ FUNC_CODE_INST_BR = 11, -+ FUNC_CODE_INST_SWITCH = 12, -+ FUNC_CODE_INST_PHI = 16, -+ FUNC_CODE_INST_ALLOCA = 19, -+ FUNC_CODE_INST_LOAD = 20, -+ FUNC_CODE_INST_EXTRACTVAL = 26, -+ FUNC_CODE_INST_CMP2 = 28, -+ FUNC_CODE_INST_VSELECT = 29, -+ FUNC_CODE_INST_CALL = 34, -+ FUNC_CODE_INST_ATOMICRMW = 38, -+ FUNC_CODE_INST_LOADATOMIC = 41, -+ FUNC_CODE_INST_GEP = 43, -+ FUNC_CODE_INST_STORE = 44, -+ FUNC_CODE_INST_STOREATOMIC = 45, -+ FUNC_CODE_INST_CMPXCHG = 46, -+}; -+ -+enum bitcode_type_code -+{ -+ TYPE_CODE_NUMENTRY = 1, -+ TYPE_CODE_VOID = 2, -+ TYPE_CODE_FLOAT = 3, -+ TYPE_CODE_DOUBLE = 4, -+ TYPE_CODE_LABEL = 5, -+ TYPE_CODE_INTEGER = 7, -+ TYPE_CODE_POINTER = 8, -+ TYPE_CODE_HALF = 10, -+ TYPE_CODE_ARRAY = 11, -+ TYPE_CODE_VECTOR = 12, -+ TYPE_CODE_METADATA = 16, -+ TYPE_CODE_STRUCT_ANON = 18, -+ TYPE_CODE_STRUCT_NAME = 19, -+ TYPE_CODE_STRUCT_NAMED = 20, -+ TYPE_CODE_FUNCTION = 21, -+}; -+ -+enum bitcode_value_symtab_code -+{ -+ VST_CODE_ENTRY = 1, -+ VST_CODE_BBENTRY = 2, -+}; -+ -+struct sm6_pointer_info -+{ -+ const struct sm6_type *type; -+ enum bitcode_address_space addr_space; -+}; -+ -+struct sm6_struct_info -+{ -+ const char *name; -+ unsigned int elem_count; -+ const struct sm6_type *elem_types[]; -+}; -+ -+struct sm6_function_info -+{ -+ const struct sm6_type *ret_type; -+ unsigned int param_count; -+ const struct sm6_type *param_types[]; -+}; -+ -+struct sm6_array_info -+{ -+ unsigned int count; -+ const struct sm6_type *elem_type; -+}; -+ -+enum sm6_type_class -+{ -+ TYPE_CLASS_VOID, -+ TYPE_CLASS_INTEGER, -+ TYPE_CLASS_FLOAT, -+ TYPE_CLASS_POINTER, -+ TYPE_CLASS_STRUCT, -+ TYPE_CLASS_FUNCTION, -+ TYPE_CLASS_VECTOR, -+ TYPE_CLASS_ARRAY, -+ TYPE_CLASS_LABEL, -+ TYPE_CLASS_METADATA, -+}; -+ -+struct sm6_type -+{ -+ enum sm6_type_class class; -+ union -+ { -+ unsigned int width; -+ struct sm6_pointer_info pointer; -+ struct sm6_struct_info *struc; -+ struct sm6_function_info *function; -+ struct sm6_array_info array; -+ } u; -+}; -+ -+enum sm6_value_type -+{ -+ VALUE_TYPE_FUNCTION, -+ VALUE_TYPE_REG, -+}; -+ -+struct sm6_function_data -+{ -+ const char *name; -+ bool is_prototype; -+ unsigned int attribs_id; -+}; -+ -+struct sm6_value -+{ -+ const struct sm6_type *type; -+ enum sm6_value_type value_type; -+ union -+ { -+ struct sm6_function_data function; -+ struct vkd3d_shader_register reg; -+ } u; -+}; -+ - struct dxil_record - { - unsigned int code; -@@ -69,6 +222,27 @@ struct dxil_record - uint64_t operands[]; - }; - -+struct sm6_symbol -+{ -+ unsigned int id; -+ const char *name; -+}; -+ -+struct sm6_block -+{ -+ struct vkd3d_shader_instruction *instructions; -+ size_t instruction_capacity; -+ size_t instruction_count; -+}; -+ -+struct sm6_function -+{ -+ const struct sm6_value *declaration; -+ -+ struct sm6_block *blocks[1]; -+ size_t block_count; -+}; -+ - struct dxil_block - { - const struct dxil_block *parent; -@@ -106,6 +280,19 @@ struct sm6_parser - size_t abbrev_capacity; - size_t abbrev_count; - -+ struct sm6_type *types; -+ size_t type_count; -+ -+ struct sm6_symbol *global_symbols; -+ size_t global_symbol_count; -+ -+ struct sm6_function *functions; -+ size_t function_count; -+ -+ struct sm6_value *values; -+ size_t value_count; -+ size_t value_capacity; -+ - struct vkd3d_shader_parser p; - }; - -@@ -128,6 +315,12 @@ struct dxil_global_abbrev - struct dxil_abbrev abbrev; - }; - -+static size_t size_add_with_overflow_check(size_t a, size_t b) -+{ -+ size_t i = a + b; -+ return (i < a) ? SIZE_MAX : i; -+} -+ - static struct sm6_parser *sm6_parser(struct vkd3d_shader_parser *parser) - { - return CONTAINING_RECORD(parser, struct sm6_parser, p); -@@ -628,10 +821,10 @@ static enum vkd3d_result dxil_block_read(struct dxil_block *parent, struct sm6_p - return VKD3D_ERROR_INVALID_SHADER; - } - --static unsigned int sm6_parser_compute_global_abbrev_count_for_block_id(struct sm6_parser *sm6, -+static size_t sm6_parser_compute_global_abbrev_count_for_block_id(struct sm6_parser *sm6, - unsigned int block_id) - { -- unsigned int i, count; -+ size_t i, count; - - for (i = 0, count = 0; i < sm6->abbrev_count; ++i) - count += sm6->abbrevs[i]->block_id == block_id; -@@ -641,7 +834,7 @@ static unsigned int sm6_parser_compute_global_abbrev_count_for_block_id(struct s - - static void dxil_block_destroy(struct dxil_block *block) - { -- unsigned int i; -+ size_t i; - - for (i = 0; i < block->record_count; ++i) - vkd3d_free(block->records[i]); -@@ -663,7 +856,7 @@ static void dxil_block_destroy(struct dxil_block *block) - static enum vkd3d_result dxil_block_init(struct dxil_block *block, const struct dxil_block *parent, - struct sm6_parser *sm6) - { -- unsigned int i, abbrev_count = 0; -+ size_t i, abbrev_count = 0; - enum vkd3d_result ret; - - block->parent = parent; -@@ -705,159 +898,1360 @@ static enum vkd3d_result dxil_block_init(struct dxil_block *block, const struct - return ret; - } - --static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, unsigned int count) -+static size_t dxil_block_compute_function_count(const struct dxil_block *root) - { -- unsigned int i; -+ size_t i, count; -+ -+ for (i = 0, count = 0; i < root->child_block_count; ++i) -+ count += root->child_blocks[i]->id == FUNCTION_BLOCK; -+ -+ return count; -+} -+ -+static size_t dxil_block_compute_module_decl_count(const struct dxil_block *block) -+{ -+ size_t i, count; -+ -+ for (i = 0, count = 0; i < block->record_count; ++i) -+ count += block->records[i]->code == MODULE_CODE_FUNCTION; -+ return count; -+} -+ -+static size_t dxil_block_compute_constants_count(const struct dxil_block *block) -+{ -+ size_t i, count; -+ -+ for (i = 0, count = 0; i < block->record_count; ++i) -+ count += block->records[i]->code != CST_CODE_SETTYPE; -+ return count; -+} -+ -+static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, size_t count) -+{ -+ size_t i; - - for (i = 0; i < count; ++i) - vkd3d_free(abbrevs[i]); - vkd3d_free(abbrevs); - } - --static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) -+static const struct dxil_block *sm6_parser_get_level_one_block(const struct sm6_parser *sm6, -+ enum bitcode_block_id id, bool *is_unique) - { -- struct sm6_parser *sm6 = sm6_parser(parser); -+ const struct dxil_block *block, *found = NULL; -+ size_t i; - -- dxil_block_destroy(&sm6->root_block); -- dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); -- shader_instruction_array_destroy(&parser->instructions); -- free_shader_desc(&parser->shader_desc); -- vkd3d_free(sm6); -+ for (i = 0, *is_unique = true; i < sm6->root_block.child_block_count; ++i) -+ { -+ block = sm6->root_block.child_blocks[i]; -+ if (block->id != id) -+ continue; -+ -+ if (!found) -+ found = block; -+ else -+ *is_unique = false; -+ } -+ -+ return found; - } - --static const struct vkd3d_shader_parser_ops sm6_parser_ops = -+static char *dxil_record_to_string(const struct dxil_record *record, unsigned int offset) - { -- .parser_destroy = sm6_parser_destroy, --}; -+ unsigned int i; -+ char *str; - --static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t *byte_code, size_t byte_code_size, -- const char *source_name, struct vkd3d_shader_message_context *message_context) -+ assert(offset <= record->operand_count); -+ if (!(str = vkd3d_calloc(record->operand_count - offset + 1, 1))) -+ return NULL; -+ -+ for (i = offset; i < record->operand_count; ++i) -+ str[i - offset] = record->operands[i]; -+ -+ return str; -+} -+ -+static bool dxil_record_validate_operand_min_count(const struct dxil_record *record, unsigned int min_count, -+ struct sm6_parser *sm6) - { -- const struct vkd3d_shader_location location = {.source_name = source_name}; -- uint32_t version_token, dxil_version, token_count, magic; -- unsigned int count, length, chunk_offset, chunk_size; -- enum bitcode_block_abbreviation abbr; -- struct vkd3d_shader_version version; -- struct dxil_block *block; -- enum vkd3d_result ret; -+ if (record->operand_count >= min_count) -+ return true; - -- count = byte_code_size / sizeof(*byte_code); -- if (count < 6) -- { -- WARN("Invalid data size %zu.\n", byte_code_size); -- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_SIZE, -- "DXIL chunk size %zu is smaller than the DXIL header size.", byte_code_size); -- return VKD3D_ERROR_INVALID_SHADER; -- } -+ WARN("Invalid operand count %u for code %u.\n", record->operand_count, record->code); -+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, -+ "Invalid operand count %u for record code %u.", record->operand_count, record->code); -+ return false; -+} - -- version_token = byte_code[0]; -- TRACE("Compiler version: 0x%08x.\n", version_token); -- token_count = byte_code[1]; -- TRACE("Token count: %u.\n", token_count); -+static void dxil_record_validate_operand_max_count(const struct dxil_record *record, unsigned int max_count, -+ struct sm6_parser *sm6) -+{ -+ if (record->operand_count <= max_count) -+ return; - -- if (token_count < 6 || count < token_count) -+ WARN("Ignoring %u extra operands for code %u.\n", record->operand_count - max_count, record->code); -+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, -+ "Ignoring %u extra operands for record code %u.", record->operand_count - max_count, record->code); -+} -+ -+static bool dxil_record_validate_operand_count(const struct dxil_record *record, unsigned int min_count, -+ unsigned int max_count, struct sm6_parser *sm6) -+{ -+ dxil_record_validate_operand_max_count(record, max_count, sm6); -+ return dxil_record_validate_operand_min_count(record, min_count, sm6); -+} -+ -+static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) -+{ -+ const struct dxil_record *record; -+ size_t i, type_count, type_index; -+ const struct dxil_block *block; -+ char *struct_name = NULL; -+ unsigned int j, count; -+ struct sm6_type *type; -+ uint64_t type_id; -+ bool is_unique; -+ -+ sm6->p.location.line = 0; -+ sm6->p.location.column = 0; -+ -+ if (!(block = sm6_parser_get_level_one_block(sm6, TYPE_BLOCK, &is_unique))) - { -- WARN("Invalid token count %u (word count %u).\n", token_count, count); -- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, -- "DXIL chunk token count %#x is invalid (word count %u).", token_count, count); -- return VKD3D_ERROR_INVALID_SHADER; -+ WARN("No type definitions found.\n"); -+ return VKD3D_OK; - } -+ if (!is_unique) -+ WARN("Ignoring invalid extra type table(s).\n"); - -- if (byte_code[2] != TAG_DXIL) -- WARN("Unknown magic number 0x%08x.\n", byte_code[2]); -+ sm6->p.location.line = block->id; - -- dxil_version = byte_code[3]; -- if (dxil_version > 0x102) -- WARN("Unknown DXIL version: 0x%08x.\n", dxil_version); -- else -- TRACE("DXIL version: 0x%08x.\n", dxil_version); -+ type_count = 0; -+ for (i = 0; i < block->record_count; ++i) -+ type_count += block->records[i]->code != TYPE_CODE_NUMENTRY && block->records[i]->code != TYPE_CODE_STRUCT_NAME; - -- chunk_offset = byte_code[4]; -- if (chunk_offset < 16 || chunk_offset >= byte_code_size) -- { -- WARN("Invalid bitcode chunk offset %#x (data size %zu).\n", chunk_offset, byte_code_size); -- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_OFFSET, -- "DXIL bitcode chunk has invalid offset %#x (data size %#zx).", chunk_offset, byte_code_size); -- return VKD3D_ERROR_INVALID_SHADER; -- } -- chunk_size = byte_code[5]; -- if (chunk_size > byte_code_size - chunk_offset) -+ /* The type array must not be relocated. */ -+ if (!(sm6->types = vkd3d_calloc(type_count, sizeof(*sm6->types)))) - { -- WARN("Invalid bitcode chunk size %#x (data size %zu, chunk offset %#x).\n", -- chunk_size, byte_code_size, chunk_offset); -- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, -- "DXIL bitcode chunk has invalid size %#x (data size %#zx, chunk offset %#x).", -- chunk_size, byte_code_size, chunk_offset); -- return VKD3D_ERROR_INVALID_SHADER; -+ ERR("Failed to allocate type array.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; - } - -- sm6->start = (const uint32_t *)((const char*)&byte_code[2] + chunk_offset); -- if ((magic = sm6->start[0]) != BITCODE_MAGIC) -+ for (i = 0; i < block->record_count; ++i) - { -- WARN("Unknown magic number 0x%08x.\n", magic); -- vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER, -- "DXIL bitcode chunk magic number 0x%08x is not the expected 0x%08x.", magic, BITCODE_MAGIC); -- } -+ sm6->p.location.column = i; -+ record = block->records[i]; - -- sm6->end = &sm6->start[(chunk_size + sizeof(*sm6->start) - 1) / sizeof(*sm6->start)]; -+ type = &sm6->types[sm6->type_count]; -+ type_index = sm6->type_count; - -- if ((version.type = version_token >> 16) >= VKD3D_SHADER_TYPE_COUNT) -- { -- FIXME("Unknown shader type %#x.\n", version.type); -- vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE, -- "Unknown shader type %#x.", version.type); -- } -+ switch (record->code) -+ { -+ case TYPE_CODE_ARRAY: -+ case TYPE_CODE_VECTOR: -+ if (!dxil_record_validate_operand_count(record, 2, 2, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; - -- version.major = VKD3D_SM6_VERSION_MAJOR(version_token); -- version.minor = VKD3D_SM6_VERSION_MINOR(version_token); -+ type->class = record->code == TYPE_CODE_ARRAY ? TYPE_CLASS_ARRAY : TYPE_CLASS_VECTOR; - -- if ((abbr = sm6->start[1] & 3) != ENTER_SUBBLOCK) -- { -- WARN("Initial block abbreviation %u is not ENTER_SUBBLOCK.\n", abbr); -- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, -- "DXIL bitcode chunk has invalid initial block abbreviation %u.", abbr); -- return VKD3D_ERROR_INVALID_SHADER; -- } -+ if (!(type->u.array.count = record->operands[0])) -+ { -+ TRACE("Setting unbounded for type %zu.\n", type_index); -+ type->u.array.count = UINT_MAX; -+ } - -- /* Estimate instruction count to avoid reallocation in most shaders. */ -- count = max(token_count, 400) - 400; -- vkd3d_shader_parser_init(&sm6->p, message_context, source_name, &version, &sm6_parser_ops, -- (count + (count >> 2)) / 2u + 10); -- sm6->ptr = &sm6->start[1]; -- sm6->bitpos = 2; -+ if ((type_id = record->operands[1]) >= type_count) -+ { -+ WARN("Invalid contained type id %"PRIu64" for type %zu.\n", type_id, type_index); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ type->u.array.elem_type = &sm6->types[type_id]; -+ break; - -- block = &sm6->root_block; -- if ((ret = dxil_block_init(block, NULL, sm6)) < 0) -- { -- if (ret == VKD3D_ERROR_OUT_OF_MEMORY) -- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, -- "Out of memory parsing DXIL bitcode chunk."); -- else if (ret == VKD3D_ERROR_INVALID_SHADER) -- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, -- "DXIL bitcode chunk has invalid bitcode."); -- else -- vkd3d_unreachable(); -- return ret; -- } -+ case TYPE_CODE_DOUBLE: -+ dxil_record_validate_operand_max_count(record, 0, sm6); -+ type->class = TYPE_CLASS_FLOAT; -+ type->u.width = 64; -+ break; - -- dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); -- sm6->abbrevs = NULL; -- sm6->abbrev_count = 0; -+ case TYPE_CODE_FLOAT: -+ dxil_record_validate_operand_max_count(record, 0, sm6); -+ type->class = TYPE_CLASS_FLOAT; -+ type->u.width = 32; -+ break; - -- length = sm6->ptr - sm6->start - block->start; -- if (length != block->length) -- { -- WARN("Invalid block length %u; expected %u.\n", length, block->length); -- vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH, -- "Root block ends with length %u but indicated length is %u.", length, block->length); -- } -- if (sm6->ptr != sm6->end) -- { -- unsigned int expected_length = sm6->end - sm6->start; -- length = sm6->ptr - sm6->start; -- WARN("Invalid module length %u; expected %u.\n", length, expected_length); -- vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH, -- "Module ends with length %u but indicated length is %u.", length, expected_length); -+ case TYPE_CODE_FUNCTION: -+ if (!dxil_record_validate_operand_min_count(record, 2, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; -+ if (record->operands[0]) -+ FIXME("Unhandled vararg function type %zu.\n", type_index); -+ -+ type->class = TYPE_CLASS_FUNCTION; -+ -+ if ((type_id = record->operands[1]) >= type_count) -+ { -+ WARN("Invalid return type id %"PRIu64" for type %zu.\n", type_id, type_index); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ count = record->operand_count - 2; -+ if (vkd3d_object_range_overflow(sizeof(type->u.function), count, sizeof(type->u.function->param_types[0])) -+ || !(type->u.function = vkd3d_malloc(offsetof(struct sm6_function_info, param_types[count])))) -+ { -+ ERR("Failed to allocate function parameter types.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ -+ type->u.function->ret_type = &sm6->types[type_id]; -+ type->u.function->param_count = count; -+ for (j = 0; j < count; ++j) -+ { -+ if ((type_id = record->operands[j + 2]) >= type_count) -+ { -+ WARN("Invalid parameter type id %"PRIu64" for type %zu.\n", type_id, type_index); -+ vkd3d_free(type->u.function); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ type->u.function->param_types[j] = &sm6->types[type_id]; -+ } -+ break; -+ -+ case TYPE_CODE_HALF: -+ dxil_record_validate_operand_max_count(record, 0, sm6); -+ type->class = TYPE_CLASS_FLOAT; -+ type->u.width = 16; -+ break; -+ -+ case TYPE_CODE_INTEGER: -+ { -+ uint64_t width; -+ -+ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; -+ -+ type->class = TYPE_CLASS_INTEGER; -+ -+ switch ((width = record->operands[0])) -+ { -+ case 1: -+ case 8: -+ case 16: -+ case 32: -+ case 64: -+ break; -+ default: -+ WARN("Invalid integer width %"PRIu64" for type %zu.\n", width, type_index); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ type->u.width = width; -+ break; -+ } -+ -+ case TYPE_CODE_LABEL: -+ type->class = TYPE_CLASS_LABEL; -+ break; -+ -+ case TYPE_CODE_METADATA: -+ type->class = TYPE_CLASS_METADATA; -+ break; -+ -+ case TYPE_CODE_NUMENTRY: -+ continue; -+ -+ case TYPE_CODE_POINTER: -+ if (!dxil_record_validate_operand_count(record, 1, 2, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; -+ -+ type->class = TYPE_CLASS_POINTER; -+ -+ if ((type_id = record->operands[0]) >= type_count) -+ { -+ WARN("Invalid pointee type id %"PRIu64" for type %zu.\n", type_id, type_index); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ type->u.pointer.type = &sm6->types[type_id]; -+ type->u.pointer.addr_space = (record->operand_count > 1) ? record->operands[1] : ADDRESS_SPACE_DEFAULT; -+ break; -+ -+ case TYPE_CODE_STRUCT_ANON: -+ case TYPE_CODE_STRUCT_NAMED: -+ if (!dxil_record_validate_operand_min_count(record, 2, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; -+ if (record->code == TYPE_CODE_STRUCT_NAMED && !struct_name) -+ { -+ WARN("Missing struct name before struct type %zu.\n", type_index); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ type->class = TYPE_CLASS_STRUCT; -+ -+ count = record->operand_count - 1; -+ if (vkd3d_object_range_overflow(sizeof(type->u.struc), count, sizeof(type->u.struc->elem_types[0])) -+ || !(type->u.struc = vkd3d_malloc(offsetof(struct sm6_struct_info, elem_types[count])))) -+ { -+ ERR("Failed to allocate struct element types.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ -+ if (record->operands[0]) -+ FIXME("Ignoring struct packed attribute.\n"); -+ -+ type->u.struc->elem_count = count; -+ for (j = 0; j < count; ++j) -+ { -+ if ((type_id = record->operands[j + 1]) >= type_count) -+ { -+ WARN("Invalid contained type id %"PRIu64" for type %zu.\n", type_id, type_index); -+ vkd3d_free(type->u.struc); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ type->u.struc->elem_types[j] = &sm6->types[type_id]; -+ } -+ -+ if (record->code == TYPE_CODE_STRUCT_ANON) -+ { -+ type->u.struc->name = NULL; -+ break; -+ } -+ -+ type->u.struc->name = struct_name; -+ struct_name = NULL; -+ break; -+ -+ case TYPE_CODE_STRUCT_NAME: -+ if (!(struct_name = dxil_record_to_string(record, 0))) -+ { -+ ERR("Failed to allocate struct name.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ if (!struct_name[0]) -+ WARN("Struct name is empty for type %zu.\n", type_index); -+ continue; -+ -+ case TYPE_CODE_VOID: -+ dxil_record_validate_operand_max_count(record, 0, sm6); -+ type->class = TYPE_CLASS_VOID; -+ break; -+ -+ default: -+ FIXME("Unhandled type %u at index %zu.\n", record->code, type_index); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ ++sm6->type_count; -+ } -+ -+ assert(sm6->type_count == type_count); -+ -+ if (struct_name) -+ { -+ WARN("Unused struct name %s.\n", struct_name); -+ vkd3d_free(struct_name); -+ } -+ -+ return VKD3D_OK; -+} -+ -+static inline bool sm6_type_is_void(const struct sm6_type *type) -+{ -+ return type->class == TYPE_CLASS_VOID; -+} -+ -+static inline bool sm6_type_is_integer(const struct sm6_type *type) -+{ -+ return type->class == TYPE_CLASS_INTEGER; -+} -+ -+static inline bool sm6_type_is_floating_point(const struct sm6_type *type) -+{ -+ return type->class == TYPE_CLASS_FLOAT; -+} -+ -+static inline bool sm6_type_is_numeric(const struct sm6_type *type) -+{ -+ return type->class == TYPE_CLASS_INTEGER || type->class == TYPE_CLASS_FLOAT; -+} -+ -+static inline bool sm6_type_is_pointer(const struct sm6_type *type) -+{ -+ return type->class == TYPE_CLASS_POINTER; -+} -+ -+static bool sm6_type_is_numeric_aggregate(const struct sm6_type *type) -+{ -+ unsigned int i; -+ -+ switch (type->class) -+ { -+ case TYPE_CLASS_ARRAY: -+ case TYPE_CLASS_VECTOR: -+ return sm6_type_is_numeric(type->u.array.elem_type); -+ -+ case TYPE_CLASS_STRUCT: -+ /* Do not handle nested structs. Support can be added if they show up. */ -+ for (i = 0; i < type->u.struc->elem_count; ++i) -+ if (!sm6_type_is_numeric(type->u.struc->elem_types[i])) -+ return false; -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static inline bool sm6_type_is_struct(const struct sm6_type *type) -+{ -+ return type->class == TYPE_CLASS_STRUCT; -+} -+ -+static inline bool sm6_type_is_function(const struct sm6_type *type) -+{ -+ return type->class == TYPE_CLASS_FUNCTION; -+} -+ -+static inline bool sm6_type_is_function_pointer(const struct sm6_type *type) -+{ -+ return sm6_type_is_pointer(type) && sm6_type_is_function(type->u.pointer.type); -+} -+ -+static inline bool sm6_type_is_handle(const struct sm6_type *type) -+{ -+ return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.Handle"); -+} -+ -+static inline const struct sm6_type *sm6_type_get_element_type(const struct sm6_type *type) -+{ -+ return (type->class == TYPE_CLASS_ARRAY || type->class == TYPE_CLASS_VECTOR) ? type->u.array.elem_type : type; -+} -+ -+static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type *type, -+ enum bitcode_address_space addr_space, struct sm6_parser *sm6) -+{ -+ size_t i, start = type - sm6->types; -+ const struct sm6_type *pointer_type; -+ -+ /* DXC seems usually to place the pointer type immediately after its pointee. */ -+ for (i = (start + 1) % sm6->type_count; i != start; i = (i + 1) % sm6->type_count) -+ { -+ pointer_type = &sm6->types[i]; -+ if (sm6_type_is_pointer(pointer_type) && pointer_type->u.pointer.type == type -+ && pointer_type->u.pointer.addr_space == addr_space) -+ return pointer_type; -+ } -+ -+ return NULL; -+} -+ -+static const struct sm6_type *sm6_parser_get_type(struct sm6_parser *sm6, uint64_t type_id) -+{ -+ if (type_id >= sm6->type_count) -+ { -+ WARN("Invalid type index %"PRIu64" at %zu.\n", type_id, sm6->value_count); -+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID, -+ "DXIL type id %"PRIu64" is invalid.", type_id); -+ return NULL; -+ } -+ return &sm6->types[type_id]; -+} -+ -+static int global_symbol_compare(const void *a, const void *b) -+{ -+ return vkd3d_u32_compare(((const struct sm6_symbol *)a)->id, ((const struct sm6_symbol *)b)->id); -+} -+ -+static enum vkd3d_result sm6_parser_symtab_init(struct sm6_parser *sm6) -+{ -+ const struct dxil_record *record; -+ const struct dxil_block *block; -+ struct sm6_symbol *symbol; -+ size_t i, count; -+ bool is_unique; -+ -+ sm6->p.location.line = 0; -+ sm6->p.location.column = 0; -+ -+ if (!(block = sm6_parser_get_level_one_block(sm6, VALUE_SYMTAB_BLOCK, &is_unique))) -+ { -+ /* There should always be at least one symbol: the name of the entry point function. */ -+ WARN("No value symtab block found.\n"); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ if (!is_unique) -+ FIXME("Ignoring extra value symtab block(s).\n"); -+ -+ sm6->p.location.line = block->id; -+ -+ for (i = 0, count = 0; i < block->record_count; ++i) -+ count += block->records[i]->code == VST_CODE_ENTRY; -+ -+ if (!(sm6->global_symbols = vkd3d_calloc(count, sizeof(*sm6->global_symbols)))) -+ { -+ ERR("Failed to allocate global symbols.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ -+ for (i = 0; i < block->record_count; ++i) -+ { -+ sm6->p.location.column = i; -+ record = block->records[i]; -+ -+ if (record->code != VST_CODE_ENTRY) -+ { -+ FIXME("Unhandled symtab code %u.\n", record->code); -+ continue; -+ } -+ if (!dxil_record_validate_operand_min_count(record, 1, sm6)) -+ continue; -+ -+ symbol = &sm6->global_symbols[sm6->global_symbol_count]; -+ symbol->id = record->operands[0]; -+ if (!(symbol->name = dxil_record_to_string(record, 1))) -+ { -+ ERR("Failed to allocate symbol name.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ ++sm6->global_symbol_count; -+ } -+ -+ sm6->p.location.column = block->record_count; -+ -+ qsort(sm6->global_symbols, sm6->global_symbol_count, sizeof(*sm6->global_symbols), global_symbol_compare); -+ for (i = 1; i < sm6->global_symbol_count; ++i) -+ { -+ if (sm6->global_symbols[i].id == sm6->global_symbols[i - 1].id) -+ { -+ WARN("Invalid duplicate symbol id %u.\n", sm6->global_symbols[i].id); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ } -+ -+ return VKD3D_OK; -+} -+ -+static const char *sm6_parser_get_global_symbol_name(const struct sm6_parser *sm6, size_t id) -+{ -+ size_t i, start; -+ -+ /* id == array index is normally true */ -+ i = start = id % sm6->global_symbol_count; -+ do -+ { -+ if (sm6->global_symbols[i].id == id) -+ return sm6->global_symbols[i].name; -+ i = (i + 1) % sm6->global_symbol_count; -+ } while (i != start); -+ -+ return NULL; -+} -+ -+static inline bool sm6_value_is_dx_intrinsic_dcl(const struct sm6_value *fn) -+{ -+ assert(fn->value_type == VALUE_TYPE_FUNCTION); -+ return fn->u.function.is_prototype && !strncmp(fn->u.function.name, "dx.op.", 6); -+} -+ -+static inline struct sm6_value *sm6_parser_get_current_value(const struct sm6_parser *sm6) -+{ -+ assert(sm6->value_count < sm6->value_capacity); -+ return &sm6->values[sm6->value_count]; -+} -+ -+static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type *type) -+{ -+ if (type->class == TYPE_CLASS_INTEGER) -+ { -+ switch (type->u.width) -+ { -+ case 8: -+ return VKD3D_DATA_UINT8; -+ case 32: -+ return VKD3D_DATA_UINT; -+ default: -+ FIXME("Unhandled width %u.\n", type->u.width); -+ return VKD3D_DATA_UINT; -+ } -+ } -+ else if (type->class == TYPE_CLASS_FLOAT) -+ { -+ switch (type->u.width) -+ { -+ case 32: -+ return VKD3D_DATA_FLOAT; -+ case 64: -+ return VKD3D_DATA_DOUBLE; -+ default: -+ FIXME("Unhandled width %u.\n", type->u.width); -+ return VKD3D_DATA_FLOAT; -+ } -+ } -+ -+ FIXME("Unhandled type %u.\n", type->class); -+ return VKD3D_DATA_UINT; -+} -+ -+/* Recurse through the block tree while maintaining a current value count. The current -+ * count is the sum of the global count plus all declarations within the current function. -+ * Store into value_capacity the highest count seen. */ -+static size_t sm6_parser_compute_max_value_count(struct sm6_parser *sm6, -+ const struct dxil_block *block, size_t value_count) -+{ -+ size_t i, old_value_count = value_count; -+ -+ if (block->id == MODULE_BLOCK) -+ value_count = size_add_with_overflow_check(value_count, dxil_block_compute_module_decl_count(block)); -+ -+ for (i = 0; i < block->child_block_count; ++i) -+ value_count = sm6_parser_compute_max_value_count(sm6, block->child_blocks[i], value_count); -+ -+ switch (block->id) -+ { -+ case CONSTANTS_BLOCK: -+ /* Function local constants are contained in a child block of the function block. */ -+ value_count = size_add_with_overflow_check(value_count, dxil_block_compute_constants_count(block)); -+ break; -+ case FUNCTION_BLOCK: -+ /* A function must start with a block count, which emits no value. This formula is likely to -+ * overestimate the value count somewhat, but this should be no problem. */ -+ value_count = size_add_with_overflow_check(value_count, max(block->record_count, 1u) - 1); -+ sm6->value_capacity = max(sm6->value_capacity, value_count); -+ /* The value count returns to its previous value after handling a function. */ -+ if (value_count < SIZE_MAX) -+ value_count = old_value_count; -+ break; -+ default: -+ break; -+ } -+ -+ return value_count; -+} -+ -+static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxil_record *record) -+{ -+ const unsigned int max_count = 15; -+ const struct sm6_type *ret_type; -+ struct sm6_value *fn; -+ unsigned int i, j; -+ -+ if (!dxil_record_validate_operand_count(record, 8, max_count, sm6)) -+ return false; -+ -+ fn = sm6_parser_get_current_value(sm6); -+ fn->value_type = VALUE_TYPE_FUNCTION; -+ if (!(fn->u.function.name = sm6_parser_get_global_symbol_name(sm6, sm6->value_count))) -+ { -+ WARN("Missing symbol name for function %zu.\n", sm6->value_count); -+ fn->u.function.name = ""; -+ } -+ -+ if (!(fn->type = sm6_parser_get_type(sm6, record->operands[0]))) -+ return false; -+ if (!sm6_type_is_function(fn->type)) -+ { -+ WARN("Type is not a function.\n"); -+ return false; -+ } -+ ret_type = fn->type->u.function->ret_type; -+ -+ if (!(fn->type = sm6_type_get_pointer_to_type(fn->type, ADDRESS_SPACE_DEFAULT, sm6))) -+ { -+ WARN("Failed to get pointer type for type %u.\n", fn->type->class); -+ return false; -+ } -+ -+ if (record->operands[1]) -+ WARN("Ignoring calling convention %#"PRIx64".\n", record->operands[1]); -+ -+ fn->u.function.is_prototype = !!record->operands[2]; -+ -+ if (record->operands[3]) -+ WARN("Ignoring linkage %#"PRIx64".\n", record->operands[3]); -+ -+ if (record->operands[4] > UINT_MAX) -+ WARN("Invalid attributes id %#"PRIx64".\n", record->operands[4]); -+ /* 1-based index. */ -+ if ((fn->u.function.attribs_id = record->operands[4])) -+ TRACE("Ignoring function attributes.\n"); -+ -+ /* These always seem to be zero. */ -+ for (i = 5, j = 0; i < min(record->operand_count, max_count); ++i) -+ j += !!record->operands[i]; -+ if (j) -+ WARN("Ignoring %u operands.\n", j); -+ -+ if (sm6_value_is_dx_intrinsic_dcl(fn) && !sm6_type_is_void(ret_type) && !sm6_type_is_numeric(ret_type) -+ && !sm6_type_is_numeric_aggregate(ret_type) && !sm6_type_is_handle(ret_type)) -+ { -+ WARN("Unexpected return type for dx intrinsic function '%s'.\n", fn->u.function.name); -+ } -+ -+ ++sm6->value_count; -+ -+ return true; -+} -+ -+static inline uint64_t decode_rotated_signed_value(uint64_t value) -+{ -+ if (value != 1) -+ { -+ bool neg = value & 1; -+ value >>= 1; -+ return neg ? -value : value; -+ } -+ return value << 63; -+} -+ -+static inline float bitcast_uint64_to_float(uint64_t value) -+{ -+ union -+ { -+ uint32_t uint32_value; -+ float float_value; -+ } u; -+ -+ u.uint32_value = value; -+ return u.float_value; -+} -+ -+static inline double bitcast_uint64_to_double(uint64_t value) -+{ -+ union -+ { -+ uint64_t uint64_value; -+ double double_value; -+ } u; -+ -+ u.uint64_value = value; -+ return u.double_value; -+} -+ -+static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) -+{ -+ enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; -+ const struct sm6_type *type, *elem_type; -+ enum vkd3d_data_type reg_data_type; -+ const struct dxil_record *record; -+ struct sm6_value *dst; -+ size_t i, value_idx; -+ uint64_t value; -+ -+ for (i = 0, type = NULL; i < block->record_count; ++i) -+ { -+ sm6->p.location.column = i; -+ record = block->records[i]; -+ value_idx = sm6->value_count; -+ -+ if (record->code == CST_CODE_SETTYPE) -+ { -+ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; -+ -+ if (!(type = sm6_parser_get_type(sm6, record->operands[0]))) -+ return VKD3D_ERROR_INVALID_SHADER; -+ -+ elem_type = sm6_type_get_element_type(type); -+ if (sm6_type_is_numeric(elem_type)) -+ { -+ reg_data_type = vkd3d_data_type_from_sm6_type(elem_type); -+ reg_type = elem_type->u.width > 32 ? VKD3DSPR_IMMCONST64 : VKD3DSPR_IMMCONST; -+ } -+ else -+ { -+ reg_data_type = VKD3D_DATA_UNUSED; -+ reg_type = VKD3DSPR_INVALID; -+ } -+ -+ if (i == block->record_count - 1) -+ WARN("Unused SETTYPE record.\n"); -+ -+ continue; -+ } -+ -+ if (!type) -+ { -+ WARN("Constant record %zu has no type.\n", value_idx); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ dst = sm6_parser_get_current_value(sm6); -+ dst->type = type; -+ dst->value_type = VALUE_TYPE_REG; -+ dst->u.reg.type = reg_type; -+ dst->u.reg.immconst_type = VKD3D_IMMCONST_SCALAR; -+ dst->u.reg.data_type = reg_data_type; -+ -+ switch (record->code) -+ { -+ case CST_CODE_NULL: -+ /* Register constant data is already zero-filled. */ -+ break; -+ -+ case CST_CODE_INTEGER: -+ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; -+ -+ if (!sm6_type_is_integer(type)) -+ { -+ WARN("Invalid integer of non-integer type %u at constant idx %zu.\n", type->class, value_idx); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ value = decode_rotated_signed_value(record->operands[0]); -+ if (type->u.width <= 32) -+ dst->u.reg.u.immconst_uint[0] = value & ((1ull << type->u.width) - 1); -+ else -+ dst->u.reg.u.immconst_uint64[0] = value; -+ -+ break; -+ -+ case CST_CODE_FLOAT: -+ if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) -+ return VKD3D_ERROR_INVALID_SHADER; -+ -+ if (!sm6_type_is_floating_point(type)) -+ { -+ WARN("Invalid float of non-fp type %u at constant idx %zu.\n", type->class, value_idx); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ if (type->u.width == 16) -+ FIXME("Half float type is not supported yet.\n"); -+ else if (type->u.width == 32) -+ dst->u.reg.u.immconst_float[0] = bitcast_uint64_to_float(record->operands[0]); -+ else if (type->u.width == 64) -+ dst->u.reg.u.immconst_double[0] = bitcast_uint64_to_double(record->operands[0]); -+ else -+ vkd3d_unreachable(); -+ -+ break; -+ -+ case CST_CODE_DATA: -+ WARN("Unhandled constant array.\n"); -+ break; -+ -+ default: -+ FIXME("Unhandled constant code %u.\n", record->code); -+ break; -+ } -+ -+ ++sm6->value_count; -+ } -+ -+ return VKD3D_OK; -+} -+ -+static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) -+{ -+ const struct dxil_block *block = &sm6->root_block; -+ const struct dxil_record *record; -+ uint64_t version; -+ size_t i; -+ -+ sm6->p.location.line = block->id; -+ sm6->p.location.column = 0; -+ -+ for (i = 0; i < block->record_count; ++i) -+ { -+ sm6->p.location.column = i; -+ record = block->records[i]; -+ switch (record->code) -+ { -+ case MODULE_CODE_FUNCTION: -+ if (!sm6_parser_declare_function(sm6, record)) -+ { -+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL, -+ "A DXIL function declaration is invalid."); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ break; -+ -+ case MODULE_CODE_GLOBALVAR: -+ FIXME("Global variables are not implemented yet.\n"); -+ break; -+ -+ case MODULE_CODE_VERSION: -+ dxil_record_validate_operand_count(record, 1, 1, sm6); -+ 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, -+ "Bitcode format version %#"PRIx64" is unsupported.", version); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ return VKD3D_OK; -+} -+ -+static const struct sm6_value *sm6_parser_next_function_definition(struct sm6_parser *sm6) -+{ -+ size_t i, count = sm6->function_count; -+ -+ for (i = 0; i < sm6->value_count; ++i) -+ { -+ if (sm6_type_is_function_pointer(sm6->values[i].type) && !sm6->values[i].u.function.is_prototype && !count--) -+ break; -+ } -+ if (i == sm6->value_count) -+ return NULL; -+ -+ ++sm6->function_count; -+ return &sm6->values[i]; -+} -+ -+static struct sm6_block *sm6_block_create() -+{ -+ struct sm6_block *block = vkd3d_calloc(1, sizeof(*block)); -+ return block; -+} -+ -+static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record, -+ struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) -+{ -+ if (!dxil_record_validate_operand_count(record, 0, 1, sm6)) -+ return; -+ -+ if (record->operand_count) -+ FIXME("Non-void return is not implemented.\n"); -+ -+ ins->handler_idx = VKD3DSIH_NOP; -+} -+ -+static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, -+ struct sm6_function *function) -+{ -+ struct vkd3d_shader_instruction *ins; -+ const struct dxil_record *record; -+ struct sm6_block *code_block; -+ struct sm6_value *dst; -+ size_t i, block_idx; -+ bool ret_found; -+ enum -+ { -+ RESULT_VALUE, -+ RESULT_TERMINATE, -+ } result_type; -+ -+ if (sm6->function_count) -+ { -+ FIXME("Multiple functions are not supported yet.\n"); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ if (!(function->declaration = sm6_parser_next_function_definition(sm6))) -+ { -+ WARN("Failed to find definition to match function body.\n"); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ if (block->record_count < 2) -+ { -+ /* It should contain at least a block count and a RET instruction. */ -+ WARN("Invalid function block record count %zu.\n", block->record_count); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ if (block->records[0]->code != FUNC_CODE_DECLAREBLOCKS || !block->records[0]->operand_count -+ || block->records[0]->operands[0] > UINT_MAX) -+ { -+ WARN("Block count declaration not found or invalid.\n"); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ if (!(function->block_count = block->records[0]->operands[0])) -+ { -+ WARN("Function contains no blocks.\n"); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ if (function->block_count > 1) -+ { -+ FIXME("Branched shaders are not supported yet.\n"); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ if (!(function->blocks[0] = sm6_block_create())) -+ { -+ ERR("Failed to allocate code block.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ code_block = function->blocks[0]; -+ -+ for (i = 1, block_idx = 0, ret_found = false; i < block->record_count; ++i) -+ { -+ sm6->p.location.column = i; -+ -+ /* block->record_count - 1 is the instruction count, but some instructions -+ * can emit >1 IR instruction, so extra may be used. */ -+ if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity, -+ max(code_block->instruction_count + 1, block->record_count), sizeof(*code_block->instructions))) -+ { -+ ERR("Failed to allocate instructions.\n"); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ -+ ins = &code_block->instructions[code_block->instruction_count]; -+ ins->handler_idx = VKD3DSIH_INVALID; -+ -+ dst = sm6_parser_get_current_value(sm6); -+ dst->type = NULL; -+ dst->value_type = VALUE_TYPE_REG; -+ result_type = RESULT_VALUE; -+ -+ record = block->records[i]; -+ switch (record->code) -+ { -+ case FUNC_CODE_INST_RET: -+ sm6_parser_emit_ret(sm6, record, code_block, ins); -+ result_type = RESULT_TERMINATE; -+ ret_found = true; -+ break; -+ default: -+ FIXME("Unhandled dxil instruction %u.\n", record->code); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ if (result_type == RESULT_TERMINATE) -+ { -+ ++block_idx; -+ code_block = (block_idx < function->block_count) ? function->blocks[block_idx] : NULL; -+ } -+ if (code_block) -+ code_block->instruction_count += ins->handler_idx != VKD3DSIH_NOP; -+ else -+ assert(ins->handler_idx == VKD3DSIH_NOP); -+ sm6->value_count += !!dst->type; -+ } -+ -+ if (!ret_found) -+ { -+ WARN("Function contains no RET instruction.\n"); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ return VKD3D_OK; -+} -+ -+static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const struct dxil_block *block, -+ unsigned int level) -+{ -+ size_t i, old_value_count = sm6->value_count; -+ struct sm6_function *function; -+ enum vkd3d_result ret; -+ -+ for (i = 0; i < block->child_block_count; ++i) -+ { -+ if ((ret = sm6_parser_module_init(sm6, block->child_blocks[i], level + 1)) < 0) -+ return ret; -+ } -+ -+ sm6->p.location.line = block->id; -+ sm6->p.location.column = 0; -+ -+ switch (block->id) -+ { -+ case CONSTANTS_BLOCK: -+ return sm6_parser_constants_init(sm6, block); -+ -+ case FUNCTION_BLOCK: -+ function = &sm6->functions[sm6->function_count]; -+ if ((ret = sm6_parser_function_init(sm6, block, function)) < 0) -+ return ret; -+ /* The value index returns to its previous value after handling a function. It's usually nonzero -+ * at the start because of global constants/variables/function declarations. Function constants -+ * occur in a child block, so value_count is already saved before they are emitted. */ -+ memset(&sm6->values[old_value_count], 0, (sm6->value_count - old_value_count) * sizeof(*sm6->values)); -+ sm6->value_count = old_value_count; -+ break; -+ -+ case BLOCKINFO_BLOCK: -+ case MODULE_BLOCK: -+ case PARAMATTR_BLOCK: -+ case PARAMATTR_GROUP_BLOCK: -+ case VALUE_SYMTAB_BLOCK: -+ case METADATA_BLOCK: -+ case METADATA_ATTACHMENT_BLOCK: -+ case TYPE_BLOCK: -+ break; -+ -+ default: -+ FIXME("Unhandled block id %u.\n", block->id); -+ break; -+ } -+ -+ return VKD3D_OK; -+} -+ -+static void sm6_type_table_cleanup(struct sm6_type *types, size_t count) -+{ -+ size_t i; -+ -+ if (!types) -+ return; -+ -+ for (i = 0; i < count; ++i) -+ { -+ switch (types[i].class) -+ { -+ case TYPE_CLASS_STRUCT: -+ vkd3d_free((void *)types[i].u.struc->name); -+ vkd3d_free(types[i].u.struc); -+ break; -+ case TYPE_CLASS_FUNCTION: -+ vkd3d_free(types[i].u.function); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ vkd3d_free(types); -+} -+ -+static void sm6_symtab_cleanup(struct sm6_symbol *symbols, size_t count) -+{ -+ size_t i; -+ -+ for (i = 0; i < count; ++i) -+ vkd3d_free((void *)symbols[i].name); -+ vkd3d_free(symbols); -+} -+ -+static void sm6_block_destroy(struct sm6_block *block) -+{ -+ vkd3d_free(block->instructions); -+ vkd3d_free(block); -+} -+ -+static void sm6_functions_cleanup(struct sm6_function *functions, size_t count) -+{ -+ size_t i, j; -+ -+ for (i = 0; i < count; ++i) -+ { -+ for (j = 0; j < functions[i].block_count; ++j) -+ sm6_block_destroy(functions[i].blocks[j]); -+ } -+ vkd3d_free(functions); -+} -+ -+static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) -+{ -+ struct sm6_parser *sm6 = sm6_parser(parser); -+ -+ dxil_block_destroy(&sm6->root_block); -+ dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); -+ shader_instruction_array_destroy(&parser->instructions); -+ sm6_type_table_cleanup(sm6->types, sm6->type_count); -+ sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); -+ sm6_functions_cleanup(sm6->functions, sm6->function_count); -+ vkd3d_free(sm6->values); -+ free_shader_desc(&parser->shader_desc); -+ vkd3d_free(sm6); -+} -+ -+static const struct vkd3d_shader_parser_ops sm6_parser_ops = -+{ -+ .parser_destroy = sm6_parser_destroy, -+}; -+ -+static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t *byte_code, size_t byte_code_size, -+ const char *source_name, struct vkd3d_shader_message_context *message_context) -+{ -+ const struct vkd3d_shader_location location = {.source_name = source_name}; -+ uint32_t version_token, dxil_version, token_count, magic; -+ unsigned int chunk_offset, chunk_size; -+ size_t count, length, function_count; -+ enum bitcode_block_abbreviation abbr; -+ struct vkd3d_shader_version version; -+ struct dxil_block *block; -+ enum vkd3d_result ret; -+ -+ count = byte_code_size / sizeof(*byte_code); -+ if (count < 6) -+ { -+ WARN("Invalid data size %zu.\n", byte_code_size); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_SIZE, -+ "DXIL chunk size %zu is smaller than the DXIL header size.", byte_code_size); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ version_token = byte_code[0]; -+ TRACE("Compiler version: 0x%08x.\n", version_token); -+ token_count = byte_code[1]; -+ TRACE("Token count: %u.\n", token_count); -+ -+ if (token_count < 6 || count < token_count) -+ { -+ WARN("Invalid token count %u (word count %zu).\n", token_count, count); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, -+ "DXIL chunk token count %#x is invalid (word count %zu).", token_count, count); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ if (byte_code[2] != TAG_DXIL) -+ WARN("Unknown magic number 0x%08x.\n", byte_code[2]); -+ -+ dxil_version = byte_code[3]; -+ if (dxil_version > 0x102) -+ WARN("Unknown DXIL version: 0x%08x.\n", dxil_version); -+ else -+ TRACE("DXIL version: 0x%08x.\n", dxil_version); -+ -+ chunk_offset = byte_code[4]; -+ if (chunk_offset < 16 || chunk_offset >= byte_code_size) -+ { -+ WARN("Invalid bitcode chunk offset %#x (data size %zu).\n", chunk_offset, byte_code_size); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_OFFSET, -+ "DXIL bitcode chunk has invalid offset %#x (data size %#zx).", chunk_offset, byte_code_size); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ chunk_size = byte_code[5]; -+ if (chunk_size > byte_code_size - chunk_offset) -+ { -+ WARN("Invalid bitcode chunk size %#x (data size %zu, chunk offset %#x).\n", -+ chunk_size, byte_code_size, chunk_offset); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, -+ "DXIL bitcode chunk has invalid size %#x (data size %#zx, chunk offset %#x).", -+ chunk_size, byte_code_size, chunk_offset); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ sm6->start = (const uint32_t *)((const char*)&byte_code[2] + chunk_offset); -+ if ((magic = sm6->start[0]) != BITCODE_MAGIC) -+ { -+ WARN("Unknown magic number 0x%08x.\n", magic); -+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER, -+ "DXIL bitcode chunk magic number 0x%08x is not the expected 0x%08x.", magic, BITCODE_MAGIC); -+ } -+ -+ sm6->end = &sm6->start[(chunk_size + sizeof(*sm6->start) - 1) / sizeof(*sm6->start)]; -+ -+ if ((version.type = version_token >> 16) >= VKD3D_SHADER_TYPE_COUNT) -+ { -+ FIXME("Unknown shader type %#x.\n", version.type); -+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE, -+ "Unknown shader type %#x.", version.type); -+ } -+ -+ version.major = VKD3D_SM6_VERSION_MAJOR(version_token); -+ version.minor = VKD3D_SM6_VERSION_MINOR(version_token); -+ -+ if ((abbr = sm6->start[1] & 3) != ENTER_SUBBLOCK) -+ { -+ WARN("Initial block abbreviation %u is not ENTER_SUBBLOCK.\n", abbr); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, -+ "DXIL bitcode chunk has invalid initial block abbreviation %u.", abbr); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ -+ /* Estimate instruction count to avoid reallocation in most shaders. */ -+ count = max(token_count, 400) - 400; -+ vkd3d_shader_parser_init(&sm6->p, message_context, source_name, &version, &sm6_parser_ops, -+ (count + (count >> 2)) / 2u + 10); -+ sm6->ptr = &sm6->start[1]; -+ sm6->bitpos = 2; -+ -+ block = &sm6->root_block; -+ if ((ret = dxil_block_init(block, NULL, sm6)) < 0) -+ { -+ if (ret == VKD3D_ERROR_OUT_OF_MEMORY) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, -+ "Out of memory parsing DXIL bitcode chunk."); -+ else if (ret == VKD3D_ERROR_INVALID_SHADER) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, -+ "DXIL bitcode chunk has invalid bitcode."); -+ else -+ vkd3d_unreachable(); -+ return ret; -+ } -+ -+ dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); -+ sm6->abbrevs = NULL; -+ sm6->abbrev_count = 0; -+ -+ length = sm6->ptr - sm6->start - block->start; -+ if (length != block->length) -+ { -+ WARN("Invalid block length %zu; expected %u.\n", length, block->length); -+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH, -+ "Root block ends with length %zu but indicated length is %u.", length, block->length); -+ } -+ if (sm6->ptr != sm6->end) -+ { -+ size_t expected_length = sm6->end - sm6->start; -+ length = sm6->ptr - sm6->start; -+ WARN("Invalid module length %zu; expected %zu.\n", length, expected_length); -+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH, -+ "Module ends with length %zu but indicated length is %zu.", length, expected_length); -+ } -+ -+ if ((ret = sm6_parser_type_table_init(sm6)) < 0) -+ { -+ if (ret == VKD3D_ERROR_OUT_OF_MEMORY) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, -+ "Out of memory parsing DXIL type table."); -+ else if (ret == VKD3D_ERROR_INVALID_SHADER) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE, -+ "DXIL type table is invalid."); -+ else -+ vkd3d_unreachable(); -+ return ret; -+ } -+ -+ if ((ret = sm6_parser_symtab_init(sm6)) < 0) -+ { -+ if (ret == VKD3D_ERROR_OUT_OF_MEMORY) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, -+ "Out of memory parsing DXIL value symbol table."); -+ else if (ret == VKD3D_ERROR_INVALID_SHADER) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB, -+ "DXIL value symbol table is invalid."); -+ else -+ vkd3d_unreachable(); -+ return ret; -+ } -+ -+ function_count = dxil_block_compute_function_count(&sm6->root_block); -+ if (!(sm6->functions = vkd3d_calloc(function_count, sizeof(*sm6->functions)))) -+ { -+ ERR("Failed to allocate function array.\n"); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, -+ "Out of memory allocating DXIL function array."); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ -+ if (sm6_parser_compute_max_value_count(sm6, &sm6->root_block, 0) == SIZE_MAX) -+ { -+ WARN("Value array count overflowed.\n"); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, -+ "Overflow occurred in the DXIL module value count."); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } -+ if (!(sm6->values = vkd3d_calloc(sm6->value_capacity, sizeof(*sm6->values)))) -+ { -+ ERR("Failed to allocate value array.\n"); -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, -+ "Out of memory allocating DXIL value array."); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ -+ if ((ret = sm6_parser_globals_init(sm6)) < 0) -+ { -+ WARN("Failed to load global declarations.\n"); -+ return ret; -+ } -+ -+ if ((ret = sm6_parser_module_init(sm6, &sm6->root_block, 0)) < 0) -+ { -+ if (ret == VKD3D_ERROR_OUT_OF_MEMORY) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, -+ "Out of memory parsing DXIL module."); -+ else if (ret == VKD3D_ERROR_INVALID_SHADER) -+ vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, -+ "DXIL module is invalid."); -+ else -+ vkd3d_unreachable(); -+ return ret; - } - - dxil_block_destroy(&sm6->root_block); -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -index 4e9af15c1be..ab508502623 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -@@ -430,6 +430,51 @@ struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl - return type; - } - -+unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, -+ enum hlsl_regset regset, unsigned int index) -+{ -+ struct hlsl_type *next_type; -+ unsigned int offset = 0; -+ unsigned int idx; -+ -+ while (!type_is_single_component(type)) -+ { -+ next_type = type; -+ idx = traverse_path_from_component_index(ctx, &next_type, &index); -+ -+ switch (type->class) -+ { -+ case HLSL_CLASS_SCALAR: -+ case HLSL_CLASS_VECTOR: -+ case HLSL_CLASS_MATRIX: -+ if (regset == HLSL_REGSET_NUMERIC) -+ offset += idx; -+ break; -+ -+ case HLSL_CLASS_STRUCT: -+ offset += type->e.record.fields[idx].reg_offset[regset]; -+ break; -+ -+ case HLSL_CLASS_ARRAY: -+ if (regset == HLSL_REGSET_NUMERIC) -+ offset += idx * align(type->e.array.type->reg_size[regset], 4); -+ else -+ offset += idx * type->e.array.type->reg_size[regset]; -+ break; -+ -+ case HLSL_CLASS_OBJECT: -+ assert(idx == 0); -+ break; -+ -+ default: -+ vkd3d_unreachable(); -+ } -+ type = next_type; -+ } -+ -+ return offset; -+} -+ - static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_var *var, - unsigned int path_len) - { -@@ -524,7 +569,9 @@ struct hlsl_type *hlsl_deref_get_type(struct hlsl_ctx *ctx, const struct hlsl_de - unsigned int i; - - assert(deref); -- assert(!deref->offset.node); -+ -+ if (deref->offset.node) -+ return deref->data_type; - - type = deref->var->data_type; - for (i = 0; i < deref->path_len; ++i) -@@ -626,6 +673,7 @@ struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *ba - type->e.array.type = basic_type; - type->dimx = basic_type->dimx; - type->dimy = basic_type->dimy; -+ type->sampler_dim = basic_type->sampler_dim; - hlsl_type_calculate_reg_size(ctx, type); - - list_add_tail(&ctx->types, &type->entry); -@@ -992,20 +1040,31 @@ struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *tem - struct vkd3d_string_buffer *string; - struct hlsl_ir_var *var; - static LONG counter; -- const char *name; - - if (!(string = hlsl_get_string_buffer(ctx))) - return NULL; - vkd3d_string_buffer_printf(string, "<%s-%u>", template, InterlockedIncrement(&counter)); -- if (!(name = hlsl_strdup(ctx, string->buffer))) -- { -- hlsl_release_string_buffer(ctx, string); -- return NULL; -- } -- var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL); -+ var = hlsl_new_synthetic_var_named(ctx, string->buffer, type, loc, true); - hlsl_release_string_buffer(ctx, string); -+ return var; -+} -+ -+struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const char *name, -+ struct hlsl_type *type, const struct vkd3d_shader_location *loc, bool dummy_scope) -+{ -+ struct hlsl_ir_var *var; -+ const char *name_copy; -+ -+ if (!(name_copy = hlsl_strdup(ctx, name))) -+ return NULL; -+ var = hlsl_new_var(ctx, name_copy, type, loc, NULL, 0, NULL); - if (var) -- list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); -+ { -+ if (dummy_scope) -+ list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); -+ else -+ list_add_tail(&ctx->globals->vars, &var->scope_entry); -+ } - return var; - } - -@@ -2066,6 +2125,31 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru - } - } - -+struct vkd3d_string_buffer *hlsl_component_to_string(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var, -+ unsigned int index) -+{ -+ struct hlsl_type *type = var->data_type, *current_type; -+ struct vkd3d_string_buffer *buffer; -+ unsigned int element_index; -+ -+ if (!(buffer = hlsl_get_string_buffer(ctx))) -+ return NULL; -+ -+ vkd3d_string_buffer_printf(buffer, "%s", var->name); -+ -+ while (!type_is_single_component(type)) -+ { -+ current_type = type; -+ element_index = traverse_path_from_component_index(ctx, &type, &index); -+ if (current_type->class == HLSL_CLASS_STRUCT) -+ vkd3d_string_buffer_printf(buffer, ".%s", current_type->e.record.fields[element_index].name); -+ else -+ vkd3d_string_buffer_printf(buffer, "[%u]", element_index); -+ } -+ -+ return buffer; -+} -+ - const char *debug_hlsl_type(struct hlsl_ctx *ctx, const struct hlsl_type *type) - { - struct vkd3d_string_buffer *string; -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -index 17ac36a57c6..1a4b995abbf 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -@@ -422,6 +422,7 @@ struct hlsl_ir_var - uint32_t is_output_semantic : 1; - uint32_t is_uniform : 1; - uint32_t is_param : 1; -+ uint32_t is_separated_resource : 1; - }; - - /* Sized array of variables representing a function's parameters. */ -@@ -607,9 +608,11 @@ struct hlsl_deref - * components, within the pertaining regset), from the start of the variable, of the part - * referenced. - * The path is lowered to this single offset -- whose value may vary between SM1 and SM4 -- -- * before writing the bytecode. */ -+ * before writing the bytecode. -+ * Since the type information cannot longer be retrieved from the offset alone, the type is -+ * stored in the data_type field. */ - struct hlsl_src offset; -- enum hlsl_regset offset_regset; -+ struct hlsl_type *data_type; - }; - - struct hlsl_ir_load -@@ -1066,6 +1069,8 @@ const char *debug_hlsl_writemask(unsigned int writemask); - const char *debug_hlsl_swizzle(unsigned int swizzle, unsigned int count); - - struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const struct hlsl_type *type); -+struct vkd3d_string_buffer *hlsl_component_to_string(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var, -+ unsigned int index); - struct vkd3d_string_buffer *hlsl_modifiers_to_string(struct hlsl_ctx *ctx, unsigned int modifiers); - const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type); - -@@ -1169,6 +1174,8 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned in - struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc); - struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *template, - struct hlsl_type *type, const struct vkd3d_shader_location *loc); -+struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const char *name, -+ struct hlsl_type *type, const struct vkd3d_shader_location *loc, bool dummy_scope); - struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, - unsigned int sample_count); - struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format); -@@ -1200,6 +1207,8 @@ unsigned int hlsl_type_component_count(const struct hlsl_type *type); - unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type, enum hlsl_regset regset); - struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl_type *type, - unsigned int index); -+unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, -+ enum hlsl_regset regset, unsigned int index); - bool hlsl_type_is_row_major(const struct hlsl_type *type); - unsigned int hlsl_type_minor_size(const struct hlsl_type *type); - unsigned int hlsl_type_major_size(const struct hlsl_type *type); -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -index 42fa2129e40..6bf87f8f916 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -@@ -133,11 +133,6 @@ static void yyerror(YYLTYPE *loc, void *scanner, struct hlsl_ctx *ctx, const cha - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "%s", s); - } - --static struct hlsl_ir_node *node_from_list(struct list *list) --{ -- return LIST_ENTRY(list_tail(list), struct hlsl_ir_node, entry); --} -- - static struct hlsl_ir_node *node_from_block(struct hlsl_block *block) - { - return LIST_ENTRY(list_tail(&block->instrs), struct hlsl_ir_node, entry); -@@ -719,7 +714,7 @@ struct hlsl_ir_node *hlsl_add_load_component(struct hlsl_ctx *ctx, struct list * - return load; - } - --static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *record, -+static bool add_record_access(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *record, - unsigned int idx, const struct vkd3d_shader_location *loc) - { - struct hlsl_ir_node *index, *c; -@@ -728,11 +723,11 @@ static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct - - if (!(c = hlsl_new_uint_constant(ctx, idx, loc))) - return false; -- list_add_tail(instrs, &c->entry); -+ hlsl_block_add_instr(block, c); - - if (!(index = hlsl_new_index(ctx, record, c, loc))) - return false; -- list_add_tail(instrs, &index->entry); -+ hlsl_block_add_instr(block, index); - - return true; - } -@@ -1170,7 +1165,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str - return 0; - hlsl_block_add_block(&expr, block); - -- if (!add_implicit_conversion(ctx, &expr.instrs, node_from_list(&expr.instrs), -+ if (!add_implicit_conversion(ctx, &expr.instrs, node_from_block(&expr), - hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc)) - { - hlsl_block_cleanup(&expr); -@@ -1183,7 +1178,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str - progress |= hlsl_copy_propagation_execute(ctx, &expr); - } while (progress); - -- node = node_from_list(&expr.instrs); -+ node = node_from_block(&expr); - if (node->type == HLSL_IR_CONSTANT) - { - constant = hlsl_ir_constant(node); -@@ -1417,15 +1412,15 @@ static struct hlsl_ir_node *add_unary_arithmetic_expr(struct hlsl_ctx *ctx, stru - return add_expr(ctx, block_to_list(block), op, args, arg->data_type, loc); - } - --static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, -+static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) - { - check_integer_type(ctx, arg); - -- return add_unary_arithmetic_expr(ctx, list_to_block(instrs), op, arg, loc); -+ return add_unary_arithmetic_expr(ctx, block, op, arg, loc); - } - --static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, -+static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) - { - struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; -@@ -1434,10 +1429,10 @@ static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct - bool_type = hlsl_get_numeric_type(ctx, arg->data_type->class, HLSL_TYPE_BOOL, - arg->data_type->dimx, arg->data_type->dimy); - -- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg, bool_type, loc))) -+ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg, bool_type, loc))) - return NULL; - -- return add_expr(ctx, instrs, op, args, bool_type, loc); -+ return add_expr(ctx, block_to_list(block), op, args, bool_type, loc); - } - - static struct hlsl_type *get_common_numeric_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *arg1, -@@ -1471,17 +1466,17 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str - return add_expr(ctx, block_to_list(block), op, args, common_type, loc); - } - --static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, -+static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, - const struct vkd3d_shader_location *loc) - { - check_integer_type(ctx, arg1); - check_integer_type(ctx, arg2); - -- return add_binary_arithmetic_expr(ctx, list_to_block(instrs), op, arg1, arg2, loc); -+ return add_binary_arithmetic_expr(ctx, block, op, arg1, arg2, loc); - } - --static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct list *instrs, -+static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, - const struct vkd3d_shader_location *loc) - { -@@ -1497,16 +1492,16 @@ static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, str - common_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); - return_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); - -- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) -+ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) - return NULL; - -- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) -+ if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) - return NULL; - -- return add_expr(ctx, instrs, op, args, return_type, loc); -+ return add_expr(ctx, block_to_list(block), op, args, return_type, loc); - } - --static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, -+static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, - const struct vkd3d_shader_location *loc) - { -@@ -1520,16 +1515,16 @@ static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct - - common_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); - -- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) -+ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) - return NULL; - -- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) -+ if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) - return NULL; - -- return add_expr(ctx, instrs, op, args, common_type, loc); -+ return add_expr(ctx, block_to_list(block), op, args, common_type, loc); - } - --static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct list *instrs, -+static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, - const struct vkd3d_shader_location *loc) - { -@@ -1551,13 +1546,13 @@ static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct l - return_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); - integer_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_INT, dimx, dimy); - -- if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, return_type, loc))) -+ if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, return_type, loc))) - return NULL; - -- if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, integer_type, loc))) -+ if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, integer_type, loc))) - return NULL; - -- return add_expr(ctx, instrs, op, args, return_type, loc); -+ return add_expr(ctx, block_to_list(block), op, args, return_type, loc); - } - - static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct hlsl_block *instrs, -@@ -1613,13 +1608,13 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct hls - return add_expr(ctx, block_to_list(instrs), op, args, ret_type, loc); - } - --static struct list *add_binary_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, -- enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) -+static struct hlsl_block *add_binary_expr_merge(struct hlsl_ctx *ctx, struct hlsl_block *block1, -+ struct hlsl_block *block2, enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) - { -- struct hlsl_ir_node *arg1 = node_from_list(list1), *arg2 = node_from_list(list2); -+ struct hlsl_ir_node *arg1 = node_from_block(block1), *arg2 = node_from_block(block2); - -- list_move_tail(list1, list2); -- vkd3d_free(list2); -+ hlsl_block_add_block(block1, block2); -+ destroy_block(block2); - - switch (op) - { -@@ -1627,37 +1622,37 @@ static struct list *add_binary_expr_merge(struct hlsl_ctx *ctx, struct list *lis - case HLSL_OP2_DIV: - case HLSL_OP2_MOD: - case HLSL_OP2_MUL: -- add_binary_arithmetic_expr(ctx, list_to_block(list1), op, arg1, arg2, loc); -+ add_binary_arithmetic_expr(ctx, block1, op, arg1, arg2, loc); - break; - - case HLSL_OP2_BIT_AND: - case HLSL_OP2_BIT_OR: - case HLSL_OP2_BIT_XOR: -- add_binary_bitwise_expr(ctx, list1, op, arg1, arg2, loc); -+ add_binary_bitwise_expr(ctx, block1, op, arg1, arg2, loc); - break; - - case HLSL_OP2_LESS: - case HLSL_OP2_GEQUAL: - case HLSL_OP2_EQUAL: - case HLSL_OP2_NEQUAL: -- add_binary_comparison_expr(ctx, list1, op, arg1, arg2, loc); -+ add_binary_comparison_expr(ctx, block1, op, arg1, arg2, loc); - break; - - case HLSL_OP2_LOGIC_AND: - case HLSL_OP2_LOGIC_OR: -- add_binary_logical_expr(ctx, list1, op, arg1, arg2, loc); -+ add_binary_logical_expr(ctx, block1, op, arg1, arg2, loc); - break; - - case HLSL_OP2_LSHIFT: - case HLSL_OP2_RSHIFT: -- add_binary_shift_expr(ctx, list1, op, arg1, arg2, loc); -+ add_binary_shift_expr(ctx, block1, op, arg1, arg2, loc); - break; - - default: - vkd3d_unreachable(); - } - -- return list1; -+ return block1; - } - - static enum hlsl_ir_expr_op op_from_assignment(enum parse_assign_op op) -@@ -1882,10 +1877,10 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in - return copy; - } - --static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrement, bool post, -+static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool decrement, bool post, - const struct vkd3d_shader_location *loc) - { -- struct hlsl_ir_node *lhs = node_from_list(instrs); -+ struct hlsl_ir_node *lhs = node_from_block(block); - struct hlsl_ir_node *one; - - if (lhs->data_type->modifiers & HLSL_MODIFIER_CONST) -@@ -1894,9 +1889,9 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem - - if (!(one = hlsl_new_int_constant(ctx, 1, loc))) - return false; -- list_add_tail(instrs, &one->entry); -+ hlsl_block_add_instr(block, one); - -- if (!add_assignment(ctx, instrs, lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) -+ if (!add_assignment(ctx, block_to_list(block), lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) - return false; - - if (post) -@@ -1905,7 +1900,7 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem - - if (!(copy = hlsl_new_copy(ctx, lhs))) - return false; -- list_add_tail(instrs, ©->entry); -+ hlsl_block_add_instr(block, copy); - - /* Post increment/decrement expressions are considered const. */ - if (!(copy->data_type = hlsl_type_clone(ctx, copy->data_type, 0, HLSL_MODIFIER_CONST))) -@@ -2495,7 +2490,7 @@ static bool intrinsic_all(struct hlsl_ctx *ctx, - return false; - } - -- return !!add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_NEQUAL, mul, zero, loc); -+ return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, mul, zero, loc); - } - - static bool intrinsic_any(struct hlsl_ctx *ctx, -@@ -2519,7 +2514,7 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, - if (!(dot = add_binary_dot_expr(ctx, params->instrs, arg, arg, loc))) - return false; - -- return !!add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_NEQUAL, dot, zero, loc); -+ return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, dot, zero, loc); - } - else if (arg->data_type->base_type == HLSL_TYPE_BOOL) - { -@@ -2535,7 +2530,7 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, - if (!(load = hlsl_add_load_component(ctx, block_to_list(params->instrs), arg, i, loc))) - return false; - -- if (!(or = add_binary_bitwise_expr(ctx, block_to_list(params->instrs), HLSL_OP2_BIT_OR, or, load, loc))) -+ if (!(or = add_binary_bitwise_expr(ctx, params->instrs, HLSL_OP2_BIT_OR, or, load, loc))) - return false; - } - -@@ -2881,7 +2876,7 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer - if (!(neg_frac = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, frac, loc))) - return false; - -- if (!(ge = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_GEQUAL, div, zero, loc))) -+ if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, div, zero, loc))) - return false; - - if (!(select = hlsl_add_conditional(ctx, block_to_list(params->instrs), ge, frac, neg_frac))) -@@ -3035,13 +3030,13 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, - hlsl_block_add_block(params->instrs, &block); - - /* Specular component. */ -- if (!(n_h_neg = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, n_h, zero, loc))) -+ if (!(n_h_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_h, zero, loc))) - return false; - -- if (!(n_l_neg = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, n_l, zero, loc))) -+ if (!(n_l_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_l, zero, loc))) - return false; - -- if (!(specular_or = add_binary_logical_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) -+ if (!(specular_or = add_binary_logical_expr(ctx, params->instrs, HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) - return false; - - if (!(specular_pow = add_pow_expr(ctx, params->instrs, n_h, m, loc))) -@@ -3330,7 +3325,7 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, - - /* Check if 0 < arg, cast bool to int */ - -- if (!(lt = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, zero, arg, loc))) -+ if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, zero, arg, loc))) - return false; - - if (!(op1 = add_implicit_conversion(ctx, block_to_list(params->instrs), lt, int_type, loc))) -@@ -3338,7 +3333,7 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, - - /* Check if arg < 0, cast bool to int and invert (meaning true is -1) */ - -- if (!(lt = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, arg, zero, loc))) -+ if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, arg, zero, loc))) - return false; - - if (!(op2 = add_implicit_conversion(ctx, block_to_list(params->instrs), lt, int_type, loc))) -@@ -3440,7 +3435,7 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, - if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) - return false; - -- if (!(ge = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_GEQUAL, -+ if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, - params->args[1], params->args[0], loc))) - return false; - -@@ -3824,7 +3819,7 @@ fail: - return NULL; - } - --static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, -+static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, - struct parse_initializer *params, const struct vkd3d_shader_location *loc) - { - struct hlsl_ir_load *load; -@@ -3857,7 +3852,7 @@ static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type - hlsl_block_add_instr(params->instrs, &load->node); - - vkd3d_free(params->args); -- return block_to_list(params->instrs); -+ return params->instrs; - } - - static unsigned int hlsl_offset_dim_count(enum hlsl_sampler_dim dim) -@@ -4562,26 +4557,11 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type - %token C_INTEGER - %token PRE_LINE - --%type add_expr --%type assignment_expr --%type bitand_expr --%type bitor_expr --%type bitxor_expr --%type conditional_expr - %type declaration - %type declaration_statement --%type equality_expr --%type initializer_expr --%type logicand_expr --%type logicor_expr --%type mul_expr --%type postfix_expr - %type primary_expr --%type relational_expr --%type shift_expr - %type struct_declaration_without_vars - %type type_specs --%type unary_expr - %type variables_def - %type variables_def_typed - -@@ -4599,15 +4579,30 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type - %type attribute_list - %type attribute_list_optional - -+%type add_expr -+%type assignment_expr -+%type bitand_expr -+%type bitor_expr -+%type bitxor_expr - %type compound_statement -+%type conditional_expr -+%type equality_expr - %type expr - %type expr_optional - %type expr_statement -+%type initializer_expr - %type jump_statement -+%type logicand_expr -+%type logicor_expr - %type loop_statement -+%type mul_expr -+%type postfix_expr -+%type relational_expr -+%type shift_expr - %type selection_statement - %type statement - %type statement_list -+%type unary_expr - - %type boolean - -@@ -5433,7 +5428,7 @@ type_no_void: - struct hlsl_block block; - - hlsl_block_init(&block); -- list_move_tail(&block.instrs, $5); -+ hlsl_block_add_block(&block, $5); - - sample_count = evaluate_static_expression_as_uint(ctx, &block, &@5); - -@@ -5824,11 +5819,11 @@ complex_initializer: - $$.args_count = 1; - if (!($$.args = hlsl_alloc(ctx, sizeof(*$$.args)))) - { -- destroy_instr_list($1); -+ destroy_block($1); - YYABORT; - } -- $$.args[0] = node_from_list($1); -- $$.instrs = list_to_block($1); -+ $$.args[0] = node_from_block($1); -+ $$.instrs = $1; - $$.braces = false; - } - | '{' complex_initializer_list '}' -@@ -5872,11 +5867,11 @@ initializer_expr_list: - $$.args_count = 1; - if (!($$.args = hlsl_alloc(ctx, sizeof(*$$.args)))) - { -- destroy_instr_list($1); -+ destroy_block($1); - YYABORT; - } -- $$.args[0] = node_from_list($1); -- $$.instrs = list_to_block($1); -+ $$.args[0] = node_from_block($1); -+ $$.instrs = $1; - $$.braces = false; - } - | initializer_expr_list ',' initializer_expr -@@ -5887,13 +5882,13 @@ initializer_expr_list: - if (!(new_args = hlsl_realloc(ctx, $$.args, ($$.args_count + 1) * sizeof(*$$.args)))) - { - free_parse_initializer(&$$); -- destroy_instr_list($3); -+ destroy_block($3); - YYABORT; - } - $$.args = new_args; -- $$.args[$$.args_count++] = node_from_list($3); -- list_move_tail(&$$.instrs->instrs, $3); -- vkd3d_free($3); -+ $$.args[$$.args_count++] = node_from_block($3); -+ hlsl_block_add_block($$.instrs, $3); -+ destroy_block($3); - } - - boolean: -@@ -6123,11 +6118,14 @@ primary_expr: - - postfix_expr: - primary_expr -+ { -+ $$ = list_to_block($1); -+ } - | postfix_expr OP_INC - { - if (!add_increment(ctx, $1, false, true, &@2)) - { -- destroy_instr_list($1); -+ destroy_block($1); - YYABORT; - } - $$ = $1; -@@ -6136,14 +6134,14 @@ postfix_expr: - { - if (!add_increment(ctx, $1, true, true, &@2)) - { -- destroy_instr_list($1); -+ destroy_block($1); - YYABORT; - } - $$ = $1; - } - | postfix_expr '.' any_identifier - { -- struct hlsl_ir_node *node = node_from_list($1); -+ struct hlsl_ir_node *node = node_from_block($1); - - if (node->data_type->class == HLSL_CLASS_STRUCT) - { -@@ -6171,7 +6169,7 @@ postfix_expr: - hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Invalid swizzle \"%s\".", $3); - YYABORT; - } -- list_add_tail($1, &swizzle->entry); -+ hlsl_block_add_instr($1, swizzle); - $$ = $1; - } - else -@@ -6182,17 +6180,17 @@ postfix_expr: - } - | postfix_expr '[' expr ']' - { -- struct hlsl_ir_node *array = node_from_list($1), *index = node_from_block($3); -+ struct hlsl_ir_node *array = node_from_block($1), *index = node_from_block($3); - -- list_move_head($1, &$3->instrs); -- destroy_block($3); -+ hlsl_block_add_block($3, $1); -+ destroy_block($1); - -- if (!add_array_access(ctx, $1, array, index, &@2)) -+ if (!add_array_access(ctx, block_to_list($3), array, index, &@2)) - { -- destroy_instr_list($1); -+ destroy_block($3); - YYABORT; - } -- $$ = $1; -+ $$ = $3; - } - - /* var_modifiers is necessary to avoid shift/reduce conflicts. */ -@@ -6233,14 +6231,14 @@ postfix_expr: - } - | postfix_expr '.' any_identifier '(' func_arguments ')' - { -- struct hlsl_ir_node *object = node_from_list($1); -+ struct hlsl_ir_node *object = node_from_block($1); - -- list_move_tail($1, &$5.instrs->instrs); -+ hlsl_block_add_block($1, $5.instrs); - vkd3d_free($5.instrs); - -- if (!add_method_call(ctx, $1, object, $3, &$5, &@3)) -+ if (!add_method_call(ctx, block_to_list($1), object, $3, &$5, &@3)) - { -- hlsl_free_instr_list($1); -+ destroy_block($1); - vkd3d_free($5.args); - YYABORT; - } -@@ -6254,7 +6252,7 @@ unary_expr: - { - if (!add_increment(ctx, $2, false, false, &@1)) - { -- destroy_instr_list($2); -+ destroy_block($2); - YYABORT; - } - $$ = $2; -@@ -6263,7 +6261,7 @@ unary_expr: - { - if (!add_increment(ctx, $2, true, false, &@1)) - { -- destroy_instr_list($2); -+ destroy_block($2); - YYABORT; - } - $$ = $2; -@@ -6274,23 +6272,23 @@ unary_expr: - } - | '-' unary_expr - { -- add_unary_arithmetic_expr(ctx, list_to_block($2), HLSL_OP1_NEG, node_from_list($2), &@1); -+ add_unary_arithmetic_expr(ctx, $2, HLSL_OP1_NEG, node_from_block($2), &@1); - $$ = $2; - } - | '~' unary_expr - { -- add_unary_bitwise_expr(ctx, $2, HLSL_OP1_BIT_NOT, node_from_list($2), &@1); -+ add_unary_bitwise_expr(ctx, $2, HLSL_OP1_BIT_NOT, node_from_block($2), &@1); - $$ = $2; - } - | '!' unary_expr - { -- add_unary_logical_expr(ctx, $2, HLSL_OP1_LOGIC_NOT, node_from_list($2), &@1); -+ add_unary_logical_expr(ctx, $2, HLSL_OP1_LOGIC_NOT, node_from_block($2), &@1); - $$ = $2; - } - /* var_modifiers is necessary to avoid shift/reduce conflicts. */ - | '(' var_modifiers type arrays ')' unary_expr - { -- struct hlsl_type *src_type = node_from_list($6)->data_type; -+ struct hlsl_type *src_type = node_from_block($6)->data_type; - struct hlsl_type *dst_type; - unsigned int i; - -@@ -6326,9 +6324,9 @@ unary_expr: - YYABORT; - } - -- if (!add_cast(ctx, $6, node_from_list($6), dst_type, &@3)) -+ if (!add_cast(ctx, block_to_list($6), node_from_block($6), dst_type, &@3)) - { -- hlsl_free_instr_list($6); -+ destroy_block($6); - YYABORT; - } - $$ = $6; -@@ -6359,7 +6357,7 @@ add_expr: - { - struct hlsl_ir_node *neg; - -- if (!(neg = add_unary_arithmetic_expr(ctx, list_to_block($3), HLSL_OP1_NEG, node_from_list($3), &@2))) -+ if (!(neg = add_unary_arithmetic_expr(ctx, $3, HLSL_OP1_NEG, node_from_block($3), &@2))) - YYABORT; - $$ = add_binary_expr_merge(ctx, $1, $3, HLSL_OP2_ADD, &@2); - } -@@ -6444,24 +6442,26 @@ conditional_expr: - logicor_expr - | logicor_expr '?' expr ':' assignment_expr - { -- struct hlsl_ir_node *cond = node_from_list($1), *first = node_from_block($3), *second = node_from_list($5); -+ struct hlsl_ir_node *cond = node_from_block($1); -+ struct hlsl_ir_node *first = node_from_block($3); -+ struct hlsl_ir_node *second = node_from_block($5); - struct hlsl_type *common_type; - -- list_move_tail($1, &$3->instrs); -- list_move_tail($1, $5); -+ hlsl_block_add_block($1, $3); -+ hlsl_block_add_block($1, $5); - destroy_block($3); -- vkd3d_free($5); -+ destroy_block($5); - - if (!(common_type = get_common_numeric_type(ctx, first, second, &@3))) - YYABORT; - -- if (!(first = add_implicit_conversion(ctx, $1, first, common_type, &@3))) -+ if (!(first = add_implicit_conversion(ctx, block_to_list($1), first, common_type, &@3))) - YYABORT; - -- if (!(second = add_implicit_conversion(ctx, $1, second, common_type, &@5))) -+ if (!(second = add_implicit_conversion(ctx, block_to_list($1), second, common_type, &@5))) - YYABORT; - -- if (!hlsl_add_conditional(ctx, $1, cond, first, second)) -+ if (!hlsl_add_conditional(ctx, block_to_list($1), cond, first, second)) - YYABORT; - $$ = $1; - } -@@ -6471,16 +6471,16 @@ assignment_expr: - conditional_expr - | unary_expr assign_op assignment_expr - { -- struct hlsl_ir_node *lhs = node_from_list($1), *rhs = node_from_list($3); -+ struct hlsl_ir_node *lhs = node_from_block($1), *rhs = node_from_block($3); - - if (lhs->data_type->modifiers & HLSL_MODIFIER_CONST) - { - hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_MODIFIES_CONST, "Statement modifies a const expression."); - YYABORT; - } -- list_move_tail($3, $1); -- vkd3d_free($1); -- if (!add_assignment(ctx, $3, lhs, $2, rhs)) -+ hlsl_block_add_block($3, $1); -+ destroy_block($1); -+ if (!add_assignment(ctx, block_to_list($3), lhs, $2, rhs)) - YYABORT; - $$ = $3; - } -@@ -6533,12 +6533,9 @@ assign_op: - - expr: - assignment_expr -- { -- $$ = list_to_block($1); -- } - | expr ',' assignment_expr - { - $$ = $1; -- list_move_tail(&$$->instrs, $3); -- vkd3d_free($3); -+ hlsl_block_add_block($$, $3); -+ destroy_block($3); - } -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -index 8927e291183..09a3ea4ca08 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -@@ -97,6 +97,7 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str - static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, struct hlsl_block *block, - const struct hlsl_deref *deref, const struct vkd3d_shader_location *loc) - { -+ enum hlsl_regset regset = hlsl_type_get_regset(deref->data_type); - struct hlsl_ir_node *offset = NULL; - struct hlsl_type *type; - unsigned int i; -@@ -111,7 +112,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st - struct hlsl_block idx_block; - - if (!(offset = new_offset_from_path_index(ctx, &idx_block, type, offset, deref->path[i].node, -- deref->offset_regset, loc))) -+ regset, loc))) - return NULL; - - hlsl_block_add_block(block, &idx_block); -@@ -126,7 +127,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st - static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_deref *deref, - struct hlsl_ir_node *instr) - { -- const struct hlsl_type *type; -+ struct hlsl_type *type; - struct hlsl_ir_node *offset; - struct hlsl_block block; - -@@ -145,7 +146,7 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der - return true; - } - -- deref->offset_regset = hlsl_type_get_regset(type); -+ deref->data_type = type; - - if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &instr->loc))) - return false; -@@ -1689,7 +1690,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ - { - struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr); - -- if (!(load->resource.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) -+ if (!load->resource.var->is_uniform) - { - hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, - "Loaded resource must have a single uniform source."); -@@ -1704,7 +1705,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ - - if (load->sampler.var) - { -- if (!(load->sampler.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) -+ if (!load->sampler.var->is_uniform) - { - hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, - "Resource load sampler must have a single uniform source."); -@@ -1722,7 +1723,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ - { - struct hlsl_ir_resource_store *store = hlsl_ir_resource_store(instr); - -- if (!(store->resource.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) -+ if (!store->resource.var->is_uniform) - { - hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, - "Accessed resource must have a single uniform source."); -@@ -2066,6 +2067,97 @@ static bool lower_nonconstant_vector_derefs(struct hlsl_ctx *ctx, struct hlsl_ir - return false; - } - -+/* Lower combined samples and sampler variables to synthesized separated textures and samplers. -+ * That is, translate SM1-style samples in the source to SM4-style samples in the bytecode. */ -+static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) -+{ -+ struct hlsl_ir_resource_load *load; -+ struct vkd3d_string_buffer *name; -+ struct hlsl_ir_var *var; -+ unsigned int i; -+ -+ if (instr->type != HLSL_IR_RESOURCE_LOAD) -+ return false; -+ load = hlsl_ir_resource_load(instr); -+ -+ switch (load->load_type) -+ { -+ case HLSL_RESOURCE_LOAD: -+ case HLSL_RESOURCE_GATHER_RED: -+ case HLSL_RESOURCE_GATHER_GREEN: -+ case HLSL_RESOURCE_GATHER_BLUE: -+ case HLSL_RESOURCE_GATHER_ALPHA: -+ case HLSL_RESOURCE_SAMPLE_CMP: -+ case HLSL_RESOURCE_SAMPLE_CMP_LZ: -+ case HLSL_RESOURCE_SAMPLE_GRAD: -+ return false; -+ -+ case HLSL_RESOURCE_SAMPLE: -+ case HLSL_RESOURCE_SAMPLE_LOD: -+ case HLSL_RESOURCE_SAMPLE_LOD_BIAS: -+ break; -+ } -+ if (load->sampler.var) -+ return false; -+ -+ if (!hlsl_type_is_resource(load->resource.var->data_type)) -+ { -+ hlsl_fixme(ctx, &instr->loc, "Lower combined samplers within structs."); -+ return false; -+ } -+ -+ assert(hlsl_type_get_regset(load->resource.var->data_type) == HLSL_REGSET_SAMPLERS); -+ -+ if (!(name = hlsl_get_string_buffer(ctx))) -+ return false; -+ vkd3d_string_buffer_printf(name, "%s", load->resource.var->name); -+ -+ TRACE("Lowering to separate resource %s.\n", debugstr_a(name->buffer)); -+ -+ if (!(var = hlsl_get_var(ctx->globals, name->buffer))) -+ { -+ struct hlsl_type *texture_array_type = hlsl_new_texture_type(ctx, load->sampling_dim, -+ hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4), 0); -+ -+ /* Create (possibly multi-dimensional) texture array type with the same dims as the sampler array. */ -+ struct hlsl_type *arr_type = load->resource.var->data_type; -+ for (i = 0; i < load->resource.path_len; ++i) -+ { -+ assert(arr_type->class == HLSL_CLASS_ARRAY); -+ texture_array_type = hlsl_new_array_type(ctx, texture_array_type, arr_type->e.array.elements_count); -+ arr_type = arr_type->e.array.type; -+ } -+ -+ if (!(var = hlsl_new_synthetic_var_named(ctx, name->buffer, texture_array_type, &instr->loc, false))) -+ { -+ hlsl_release_string_buffer(ctx, name); -+ return false; -+ } -+ var->is_uniform = 1; -+ var->is_separated_resource = true; -+ -+ list_add_tail(&ctx->extern_vars, &var->extern_entry); -+ } -+ hlsl_release_string_buffer(ctx, name); -+ -+ if (load->sampling_dim != var->data_type->sampler_dim) -+ { -+ hlsl_error(ctx, &load->node.loc, VKD3D_SHADER_ERROR_HLSL_INCONSISTENT_SAMPLER, -+ "Cannot split combined samplers from \"%s\" if they have different usage dimensions.", -+ load->resource.var->name); -+ hlsl_note(ctx, &var->loc, VKD3D_SHADER_LOG_ERROR, "First use as combined sampler is here."); -+ return false; -+ -+ } -+ -+ hlsl_copy_deref(ctx, &load->sampler, &load->resource); -+ load->resource.var = var; -+ assert(hlsl_deref_get_type(ctx, &load->resource)->base_type == HLSL_TYPE_TEXTURE); -+ assert(hlsl_deref_get_type(ctx, &load->sampler)->base_type == HLSL_TYPE_SAMPLER); -+ -+ return true; -+} -+ - /* Lower DIV to RCP + MUL. */ - static bool lower_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) - { -@@ -3096,7 +3188,7 @@ static const char *debug_register(char class, struct hlsl_reg reg, const struct - return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask)); - } - --static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) -+static bool track_object_components_sampler_dim(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) - { - struct hlsl_ir_resource_load *load; - struct hlsl_ir_var *var; -@@ -3108,15 +3200,16 @@ static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_n - - load = hlsl_ir_resource_load(instr); - var = load->resource.var; -+ - regset = hlsl_type_get_regset(hlsl_deref_get_type(ctx, &load->resource)); -+ if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) -+ return false; - - if (regset == HLSL_REGSET_SAMPLERS) - { - enum hlsl_sampler_dim dim; - - assert(!load->sampler.var); -- if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) -- return false; - - dim = var->objects_usage[regset][index].sampler_dim; - if (dim != load->sampling_dim) -@@ -3134,25 +3227,37 @@ static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_n - return false; - } - } -- var->objects_usage[regset][index].used = true; -- var->objects_usage[regset][index].sampler_dim = load->sampling_dim; - } -- else -- { -- if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) -- return false; -+ var->objects_usage[regset][index].sampler_dim = load->sampling_dim; - -- var->objects_usage[regset][index].used = true; -- var->objects_usage[regset][index].sampler_dim = load->sampling_dim; -+ return false; -+} - -- if (load->sampler.var) -- { -- var = load->sampler.var; -- if (!hlsl_regset_index_from_deref(ctx, &load->sampler, HLSL_REGSET_SAMPLERS, &index)) -- return false; -+static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) -+{ -+ struct hlsl_ir_resource_load *load; -+ struct hlsl_ir_var *var; -+ enum hlsl_regset regset; -+ unsigned int index; - -- var->objects_usage[HLSL_REGSET_SAMPLERS][index].used = true; -- } -+ if (instr->type != HLSL_IR_RESOURCE_LOAD) -+ return false; -+ -+ load = hlsl_ir_resource_load(instr); -+ var = load->resource.var; -+ -+ regset = hlsl_type_get_regset(hlsl_deref_get_type(ctx, &load->resource)); -+ if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) -+ return false; -+ -+ var->objects_usage[regset][index].used = true; -+ if (load->sampler.var) -+ { -+ var = load->sampler.var; -+ if (!hlsl_regset_index_from_deref(ctx, &load->sampler, HLSL_REGSET_SAMPLERS, &index)) -+ return false; -+ -+ var->objects_usage[HLSL_REGSET_SAMPLERS][index].used = true; - } - - return false; -@@ -3172,9 +3277,12 @@ static void calculate_resource_register_counts(struct hlsl_ctx *ctx) - { - for (i = 0; i < type->reg_size[k]; ++i) - { -- /* Samplers are only allocated until the last used one. */ -+ bool is_separated = var->is_separated_resource; -+ -+ /* Samplers (and textures separated from them) are only allocated until the last -+ * used one. */ - if (var->objects_usage[k][i].used) -- var->regs[k].bind_count = (k == HLSL_REGSET_SAMPLERS) ? i + 1 : type->reg_size[k]; -+ var->regs[k].bind_count = (k == HLSL_REGSET_SAMPLERS || is_separated) ? i + 1 : type->reg_size[k]; - } - } - } -@@ -3568,7 +3676,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) - - LIST_FOR_EACH_ENTRY(var1, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { -- if (!var1->is_uniform || var1->data_type->class == HLSL_CLASS_OBJECT) -+ if (!var1->is_uniform || hlsl_type_is_resource(var1->data_type)) - continue; - - buffer = var1->buffer; -@@ -3579,7 +3687,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) - { - unsigned int var1_reg_size, var2_reg_size; - -- if (!var2->is_uniform || var2->data_type->class == HLSL_CLASS_OBJECT) -+ if (!var2->is_uniform || hlsl_type_is_resource(var2->data_type)) - continue; - - if (var1 == var2 || var1->buffer != var2->buffer) -@@ -3629,7 +3737,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx) - - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { -- if (var->is_uniform && var->data_type->class != HLSL_CLASS_OBJECT) -+ if (var->is_uniform && !hlsl_type_is_resource(var->data_type)) - { - if (var->is_param) - var->buffer = ctx->params_buffer; -@@ -3689,7 +3797,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx) - } - - static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum hlsl_regset regset, -- uint32_t index) -+ uint32_t index, bool allocated_only) - { - const struct hlsl_ir_var *var; - unsigned int start, count; -@@ -3703,6 +3811,9 @@ static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum - * bound there even if the reserved vars aren't used. */ - start = var->reg_reservation.reg_index; - count = var->data_type->reg_size[regset]; -+ -+ if (!var->regs[regset].allocated && allocated_only) -+ continue; - } - else if (var->regs[regset].allocated) - { -@@ -3743,6 +3854,7 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) - if (count == 0) - continue; - -+ /* The variable was already allocated if it has a reservation. */ - if (var->regs[regset].allocated) - { - const struct hlsl_ir_var *reserved_object, *last_reported = NULL; -@@ -3761,7 +3873,10 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) - { - index = var->regs[regset].id + i; - -- reserved_object = get_allocated_object(ctx, regset, index); -+ /* get_allocated_object() may return "var" itself, but we -+ * actually want that, otherwise we'll end up reporting the -+ * same conflict between the same two variables twice. */ -+ reserved_object = get_allocated_object(ctx, regset, index, true); - if (reserved_object && reserved_object != var && reserved_object != last_reported) - { - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS, -@@ -3780,7 +3895,7 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) - - while (available < count) - { -- if (get_allocated_object(ctx, regset, index)) -+ if (get_allocated_object(ctx, regset, index, false)) - available = 0; - else - ++available; -@@ -3924,6 +4039,7 @@ bool hlsl_regset_index_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref - bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, unsigned int *offset) - { - struct hlsl_ir_node *offset_node = deref->offset.node; -+ enum hlsl_regset regset; - unsigned int size; - - if (!offset_node) -@@ -3940,8 +4056,9 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref - return false; - - *offset = hlsl_ir_constant(offset_node)->value.u[0].u; -+ regset = hlsl_type_get_regset(deref->data_type); - -- size = deref->var->data_type->reg_size[deref->offset_regset]; -+ size = deref->var->data_type->reg_size[regset]; - if (*offset >= size) - { - hlsl_error(ctx, &deref->offset.node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS, -@@ -3971,7 +4088,8 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere - struct hlsl_reg ret = var->regs[HLSL_REGSET_NUMERIC]; - unsigned int offset = hlsl_offset_from_deref_safe(ctx, deref); - -- assert(deref->offset_regset == HLSL_REGSET_NUMERIC); -+ assert(deref->data_type); -+ assert(deref->data_type->class <= HLSL_CLASS_LAST_NUMERIC); - - ret.id += offset / 4; - -@@ -4169,6 +4287,12 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry - hlsl_transform_ir(ctx, lower_casts_to_bool, body, NULL); - hlsl_transform_ir(ctx, lower_int_dot, body, NULL); - -+ hlsl_transform_ir(ctx, validate_static_object_references, body, NULL); -+ hlsl_transform_ir(ctx, track_object_components_sampler_dim, body, NULL); -+ if (profile->major_version >= 4) -+ hlsl_transform_ir(ctx, lower_combined_samples, body, NULL); -+ hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); -+ - if (profile->major_version < 4) - { - hlsl_transform_ir(ctx, lower_division, body, NULL); -@@ -4182,9 +4306,6 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry - hlsl_transform_ir(ctx, lower_abs, body, NULL); - } - -- hlsl_transform_ir(ctx, validate_static_object_references, body, NULL); -- hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); -- - /* TODO: move forward, remove when no longer needed */ - transform_derefs(ctx, replace_deref_path_with_offset, body); - while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL)); -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index 290fdcb3f62..801c688a297 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -2970,47 +2970,154 @@ static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *typ - } - } - -+struct extern_resource -+{ -+ /* var is only not NULL if this resource is a whole variable, so it may be responsible for more -+ * than one component. */ -+ const struct hlsl_ir_var *var; -+ -+ char *name; -+ struct hlsl_type *data_type; -+ bool is_user_packed; -+ -+ enum hlsl_regset regset; -+ unsigned int id, bind_count; -+}; -+ - static int sm4_compare_extern_resources(const void *a, const void *b) - { -- const struct hlsl_ir_var *aa = *(const struct hlsl_ir_var **)a; -- const struct hlsl_ir_var *bb = *(const struct hlsl_ir_var **)b; -- enum hlsl_regset aa_regset, bb_regset; -+ const struct extern_resource *aa = (const struct extern_resource *)a; -+ const struct extern_resource *bb = (const struct extern_resource *)b; -+ int r; -+ -+ if ((r = vkd3d_u32_compare(aa->regset, bb->regset))) -+ return r; - -- aa_regset = hlsl_type_get_regset(aa->data_type); -- bb_regset = hlsl_type_get_regset(bb->data_type); -+ return vkd3d_u32_compare(aa->id, bb->id); -+} - -- if (aa_regset != bb_regset) -- return aa_regset - bb_regset; -+static void sm4_free_extern_resources(struct extern_resource *extern_resources, unsigned int count) -+{ -+ unsigned int i; - -- return aa->regs[aa_regset].id - bb->regs[bb_regset].id; -+ for (i = 0; i < count; ++i) -+ vkd3d_free(extern_resources[i].name); -+ vkd3d_free(extern_resources); -+} -+ -+static const char *string_skip_tag(const char *string) -+{ -+ if (!strncmp(string, "", strlen(""))) -+ return string + strlen(""); -+ return string; - } - --static const struct hlsl_ir_var **sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count) -+static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count) - { -- const struct hlsl_ir_var **extern_resources = NULL; -+ bool separate_components = ctx->profile->major_version == 5 && ctx->profile->minor_version == 0; -+ struct extern_resource *extern_resources = NULL; - const struct hlsl_ir_var *var; - enum hlsl_regset regset; - size_t capacity = 0; -+ char *name; - - *count = 0; - - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { -- if (!hlsl_type_is_resource(var->data_type)) -- continue; -- regset = hlsl_type_get_regset(var->data_type); -- if (!var->regs[regset].allocated) -- continue; -- -- if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, -- sizeof(*extern_resources)))) -+ if (separate_components) - { -- *count = 0; -- return NULL; -+ unsigned int component_count = hlsl_type_component_count(var->data_type); -+ unsigned int k, regset_offset; -+ -+ for (k = 0; k < component_count; ++k) -+ { -+ struct hlsl_type *component_type = hlsl_type_get_component_type(ctx, var->data_type, k); -+ struct vkd3d_string_buffer *name_buffer; -+ -+ if (!hlsl_type_is_resource(component_type)) -+ continue; -+ -+ regset = hlsl_type_get_regset(component_type); -+ regset_offset = hlsl_type_get_component_offset(ctx, var->data_type, regset, k); -+ -+ if (regset_offset > var->regs[regset].bind_count) -+ continue; -+ -+ if (var->objects_usage[regset][regset_offset].used) -+ { -+ if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, -+ sizeof(*extern_resources)))) -+ { -+ sm4_free_extern_resources(extern_resources, *count); -+ *count = 0; -+ return NULL; -+ } -+ -+ if (!(name_buffer = hlsl_component_to_string(ctx, var, k))) -+ { -+ sm4_free_extern_resources(extern_resources, *count); -+ *count = 0; -+ return NULL; -+ } -+ if (!(name = hlsl_strdup(ctx, string_skip_tag(name_buffer->buffer)))) -+ { -+ sm4_free_extern_resources(extern_resources, *count); -+ *count = 0; -+ hlsl_release_string_buffer(ctx, name_buffer); -+ return NULL; -+ } -+ hlsl_release_string_buffer(ctx, name_buffer); -+ -+ extern_resources[*count].var = NULL; -+ -+ extern_resources[*count].name = name; -+ extern_resources[*count].data_type = component_type; -+ extern_resources[*count].is_user_packed = false; -+ -+ extern_resources[*count].regset = regset; -+ extern_resources[*count].id = var->regs[regset].id + regset_offset; -+ extern_resources[*count].bind_count = 1; -+ -+ ++*count; -+ } -+ } - } -+ else -+ { -+ if (!hlsl_type_is_resource(var->data_type)) -+ continue; -+ regset = hlsl_type_get_regset(var->data_type); -+ if (!var->regs[regset].allocated) -+ continue; -+ -+ if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, -+ sizeof(*extern_resources)))) -+ { -+ sm4_free_extern_resources(extern_resources, *count); -+ *count = 0; -+ return NULL; -+ } - -- extern_resources[*count] = var; -- ++*count; -+ if (!(name = hlsl_strdup(ctx, string_skip_tag(var->name)))) -+ { -+ sm4_free_extern_resources(extern_resources, *count); -+ *count = 0; -+ return NULL; -+ } -+ -+ extern_resources[*count].var = var; -+ -+ extern_resources[*count].name = name; -+ extern_resources[*count].data_type = var->data_type; -+ extern_resources[*count].is_user_packed = !!var->reg_reservation.reg_type; -+ -+ extern_resources[*count].regset = regset; -+ extern_resources[*count].id = var->regs[regset].id; -+ extern_resources[*count].bind_count = var->regs[regset].bind_count; -+ -+ ++*count; -+ } - } - - qsort(extern_resources, *count, sizeof(*extern_resources), sm4_compare_extern_resources); -@@ -3023,8 +3130,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - size_t cbuffers_offset, resources_offset, creator_offset, string_offset; - size_t cbuffer_position, resource_position, creator_position; - const struct hlsl_profile_info *profile = ctx->profile; -- const struct hlsl_ir_var **extern_resources; - struct vkd3d_bytecode_buffer buffer = {0}; -+ struct extern_resource *extern_resources; - const struct hlsl_buffer *cbuffer; - const struct hlsl_ir_var *var; - -@@ -3078,18 +3185,15 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - - for (i = 0; i < extern_resources_count; ++i) - { -- enum hlsl_regset regset; -+ const struct extern_resource *resource = &extern_resources[i]; - uint32_t flags = 0; - -- var = extern_resources[i]; -- regset = hlsl_type_get_regset(var->data_type); -- -- if (var->reg_reservation.reg_type) -+ if (resource->is_user_packed) - flags |= D3D_SIF_USERPACKED; - - put_u32(&buffer, 0); /* name */ -- put_u32(&buffer, sm4_resource_type(var->data_type)); -- if (regset == HLSL_REGSET_SAMPLERS) -+ put_u32(&buffer, sm4_resource_type(resource->data_type)); -+ if (resource->regset == HLSL_REGSET_SAMPLERS) - { - put_u32(&buffer, 0); - put_u32(&buffer, 0); -@@ -3097,15 +3201,15 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - } - else - { -- unsigned int dimx = hlsl_type_get_component_type(ctx, var->data_type, 0)->e.resource_format->dimx; -+ unsigned int dimx = hlsl_type_get_component_type(ctx, resource->data_type, 0)->e.resource_format->dimx; - -- put_u32(&buffer, sm4_resource_format(var->data_type)); -- put_u32(&buffer, sm4_rdef_resource_dimension(var->data_type)); -+ put_u32(&buffer, sm4_resource_format(resource->data_type)); -+ put_u32(&buffer, sm4_rdef_resource_dimension(resource->data_type)); - put_u32(&buffer, ~0u); /* FIXME: multisample count */ - flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; - } -- put_u32(&buffer, var->regs[regset].id); -- put_u32(&buffer, var->regs[regset].bind_count); -+ put_u32(&buffer, resource->id); -+ put_u32(&buffer, resource->bind_count); - put_u32(&buffer, flags); - } - -@@ -3131,9 +3235,9 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - - for (i = 0; i < extern_resources_count; ++i) - { -- var = extern_resources[i]; -+ const struct extern_resource *resource = &extern_resources[i]; - -- string_offset = put_string(&buffer, var->name); -+ string_offset = put_string(&buffer, resource->name); - set_u32(&buffer, resources_offset + i * 8 * sizeof(uint32_t), string_offset); - } - -@@ -3239,7 +3343,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - - add_section(dxbc, TAG_RDEF, &buffer); - -- vkd3d_free(extern_resources); -+ sm4_free_extern_resources(extern_resources, extern_resources_count); - } - - static enum vkd3d_sm4_resource_type sm4_resource_dimension(const struct hlsl_type *type) -@@ -3349,8 +3453,9 @@ struct sm4_instruction - - static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *reg, - unsigned int *writemask, enum vkd3d_sm4_swizzle_type *swizzle_type, -- const struct hlsl_deref *deref, const struct hlsl_type *data_type) -+ const struct hlsl_deref *deref) - { -+ const struct hlsl_type *data_type = hlsl_deref_get_type(ctx, deref); - const struct hlsl_ir_var *var = deref->var; - - if (var->is_uniform) -@@ -3365,7 +3470,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r - *swizzle_type = VKD3D_SM4_SWIZZLE_VEC4; - reg->idx[0] = var->regs[HLSL_REGSET_TEXTURES].id; - reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); -- assert(deref->offset_regset == HLSL_REGSET_TEXTURES); -+ assert(regset == HLSL_REGSET_TEXTURES); - reg->idx_count = 1; - *writemask = VKD3DSP_WRITEMASK_ALL; - } -@@ -3377,7 +3482,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r - *swizzle_type = VKD3D_SM4_SWIZZLE_VEC4; - reg->idx[0] = var->regs[HLSL_REGSET_UAVS].id; - reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); -- assert(deref->offset_regset == HLSL_REGSET_UAVS); -+ assert(regset == HLSL_REGSET_UAVS); - reg->idx_count = 1; - *writemask = VKD3DSP_WRITEMASK_ALL; - } -@@ -3389,7 +3494,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r - *swizzle_type = VKD3D_SM4_SWIZZLE_NONE; - reg->idx[0] = var->regs[HLSL_REGSET_SAMPLERS].id; - reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); -- assert(deref->offset_regset == HLSL_REGSET_SAMPLERS); -+ assert(regset == HLSL_REGSET_SAMPLERS); - reg->idx_count = 1; - *writemask = VKD3DSP_WRITEMASK_ALL; - } -@@ -3487,11 +3592,11 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r - } - - static void sm4_src_from_deref(struct hlsl_ctx *ctx, struct sm4_src_register *src, -- const struct hlsl_deref *deref, const struct hlsl_type *data_type, unsigned int map_writemask) -+ const struct hlsl_deref *deref, unsigned int map_writemask) - { - unsigned int writemask; - -- sm4_register_from_deref(ctx, &src->reg, &writemask, &src->swizzle_type, deref, data_type); -+ sm4_register_from_deref(ctx, &src->reg, &writemask, &src->swizzle_type, deref); - if (src->swizzle_type == VKD3D_SM4_SWIZZLE_VEC4) - src->swizzle = hlsl_map_swizzle(hlsl_swizzle_from_writemask(writemask), map_writemask); - } -@@ -3692,9 +3797,11 @@ static void write_sm4_dcl_constant_buffer(struct vkd3d_bytecode_buffer *buffer, - write_sm4_instruction(buffer, &instr); - } - --static void write_sm4_dcl_samplers(struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_var *var) -+static void write_sm4_dcl_samplers(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, -+ const struct extern_resource *resource) - { -- unsigned int i, count = var->data_type->reg_size[HLSL_REGSET_SAMPLERS]; -+ struct hlsl_type *component_type; -+ unsigned int i; - struct sm4_instruction instr = - { - .opcode = VKD3D_SM4_OP_DCL_SAMPLER, -@@ -3704,38 +3811,44 @@ static void write_sm4_dcl_samplers(struct vkd3d_bytecode_buffer *buffer, const s - .dst_count = 1, - }; - -- if (var->data_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON) -+ component_type = hlsl_type_get_component_type(ctx, resource->data_type, 0); -+ -+ if (component_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON) - instr.opcode |= VKD3D_SM4_SAMPLER_COMPARISON << VKD3D_SM4_SAMPLER_MODE_SHIFT; - -- for (i = 0; i < count; ++i) -+ assert(resource->regset == HLSL_REGSET_SAMPLERS); -+ -+ for (i = 0; i < resource->bind_count; ++i) - { -- if (!var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) -+ if (resource->var && !resource->var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) - continue; - -- instr.dsts[0].reg.idx[0] = var->regs[HLSL_REGSET_SAMPLERS].id + i; -+ instr.dsts[0].reg.idx[0] = resource->id + i; - write_sm4_instruction(buffer, &instr); - } - } - - static void write_sm4_dcl_textures(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, -- const struct hlsl_ir_var *var, bool uav) -+ const struct extern_resource *resource, bool uav) - { - enum hlsl_regset regset = uav ? HLSL_REGSET_UAVS : HLSL_REGSET_TEXTURES; -- unsigned int i, count = var->data_type->reg_size[regset]; - struct hlsl_type *component_type; - struct sm4_instruction instr; -+ unsigned int i; - -- component_type = hlsl_type_get_component_type(ctx, var->data_type, 0); -+ assert(resource->regset == regset); - -- for (i = 0; i < count; ++i) -+ component_type = hlsl_type_get_component_type(ctx, resource->data_type, 0); -+ -+ for (i = 0; i < resource->bind_count; ++i) - { -- if (!var->objects_usage[regset][i].used) -+ if (resource->var && !resource->var->objects_usage[regset][i].used) - continue; - - instr = (struct sm4_instruction) - { - .dsts[0].reg.type = uav ? VKD3D_SM5_RT_UAV : VKD3D_SM4_RT_RESOURCE, -- .dsts[0].reg.idx = {var->regs[regset].id + i}, -+ .dsts[0].reg.idx = {resource->id + i}, - .dsts[0].reg.idx_count = 1, - .dst_count = 1, - -@@ -3745,11 +3858,11 @@ static void write_sm4_dcl_textures(struct hlsl_ctx *ctx, struct vkd3d_bytecode_b - - if (uav) - { -- switch (var->data_type->sampler_dim) -+ switch (resource->data_type->sampler_dim) - { - case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER: - instr.opcode = VKD3D_SM5_OP_DCL_UAV_STRUCTURED; -- instr.byte_stride = var->data_type->e.resource_format->reg_size[HLSL_REGSET_NUMERIC] * 4; -+ instr.byte_stride = resource->data_type->e.resource_format->reg_size[HLSL_REGSET_NUMERIC] * 4; - break; - default: - instr.opcode = VKD3D_SM5_OP_DCL_UAV_TYPED; -@@ -4011,11 +4124,11 @@ static void write_sm4_binary_op_with_two_destinations(struct vkd3d_bytecode_buff - } - - static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, -- const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, -- const struct hlsl_deref *resource, const struct hlsl_ir_node *coords, -- const struct hlsl_ir_node *sample_index, const struct hlsl_ir_node *texel_offset, -- enum hlsl_sampler_dim dim) -+ const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, -+ const struct hlsl_ir_node *coords, const struct hlsl_ir_node *sample_index, -+ const struct hlsl_ir_node *texel_offset, enum hlsl_sampler_dim dim) - { -+ const struct hlsl_type *resource_type = hlsl_deref_get_type(ctx, resource); - bool multisampled = resource_type->base_type == HLSL_TYPE_TEXTURE - && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); - bool uav = (hlsl_type_get_regset(resource_type) == HLSL_REGSET_UAVS); -@@ -4055,7 +4168,7 @@ static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buf - - sm4_src_from_node(&instr.srcs[0], coords, coords_writemask); - -- sm4_src_from_deref(ctx, &instr.srcs[1], resource, resource_type, instr.dsts[0].writemask); -+ sm4_src_from_deref(ctx, &instr.srcs[1], resource, instr.dsts[0].writemask); - - instr.src_count = 2; - -@@ -4092,7 +4205,6 @@ static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buf - static void write_sm4_sample(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, - const struct hlsl_ir_resource_load *load) - { -- const struct hlsl_type *resource_type = load->resource.var->data_type; - const struct hlsl_ir_node *texel_offset = load->texel_offset.node; - const struct hlsl_ir_node *coords = load->coords.node; - const struct hlsl_deref *resource = &load->resource; -@@ -4145,8 +4257,8 @@ static void write_sm4_sample(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer - instr.dst_count = 1; - - sm4_src_from_node(&instr.srcs[0], coords, VKD3DSP_WRITEMASK_ALL); -- sm4_src_from_deref(ctx, &instr.srcs[1], resource, resource_type, instr.dsts[0].writemask); -- sm4_src_from_deref(ctx, &instr.srcs[2], sampler, sampler->var->data_type, VKD3DSP_WRITEMASK_ALL); -+ sm4_src_from_deref(ctx, &instr.srcs[1], resource, instr.dsts[0].writemask); -+ sm4_src_from_deref(ctx, &instr.srcs[2], sampler, VKD3DSP_WRITEMASK_ALL); - instr.src_count = 3; - - if (load->load_type == HLSL_RESOURCE_SAMPLE_LOD -@@ -4316,7 +4428,7 @@ static void write_sm4_store_uav_typed(struct hlsl_ctx *ctx, struct vkd3d_bytecod - memset(&instr, 0, sizeof(instr)); - instr.opcode = VKD3D_SM5_OP_STORE_UAV_TYPED; - -- sm4_register_from_deref(ctx, &instr.dsts[0].reg, &instr.dsts[0].writemask, NULL, dst, dst->var->data_type); -+ sm4_register_from_deref(ctx, &instr.dsts[0].reg, &instr.dsts[0].writemask, NULL, dst); - instr.dst_count = 1; - - sm4_src_from_node(&instr.srcs[0], coords, VKD3DSP_WRITEMASK_ALL); -@@ -4856,7 +4968,7 @@ static void write_sm4_load(struct hlsl_ctx *ctx, - - instr.opcode = VKD3D_SM4_OP_MOVC; - -- sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, type, instr.dsts[0].writemask); -+ sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, instr.dsts[0].writemask); - - memset(&value, 0xff, sizeof(value)); - sm4_src_from_constant_value(&instr.srcs[1], &value, type->dimx, instr.dsts[0].writemask); -@@ -4868,7 +4980,7 @@ static void write_sm4_load(struct hlsl_ctx *ctx, - { - instr.opcode = VKD3D_SM4_OP_MOV; - -- sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, type, instr.dsts[0].writemask); -+ sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, instr.dsts[0].writemask); - instr.src_count = 1; - } - -@@ -4892,8 +5004,7 @@ static void write_sm4_loop(struct hlsl_ctx *ctx, - } - - static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, -- const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, -- const struct hlsl_deref *resource, const struct hlsl_deref *sampler, -+ const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, const struct hlsl_deref *sampler, - const struct hlsl_ir_node *coords, unsigned int swizzle, const struct hlsl_ir_node *texel_offset) - { - struct sm4_src_register *src; -@@ -4923,10 +5034,10 @@ static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer - } - } - -- sm4_src_from_deref(ctx, &instr.srcs[instr.src_count++], resource, resource_type, instr.dsts[0].writemask); -+ sm4_src_from_deref(ctx, &instr.srcs[instr.src_count++], resource, instr.dsts[0].writemask); - - src = &instr.srcs[instr.src_count++]; -- sm4_src_from_deref(ctx, src, sampler, sampler->var->data_type, VKD3DSP_WRITEMASK_ALL); -+ sm4_src_from_deref(ctx, src, sampler, VKD3DSP_WRITEMASK_ALL); - src->reg.dim = VKD3D_SM4_DIMENSION_VEC4; - src->swizzle_type = VKD3D_SM4_SWIZZLE_SCALAR; - src->swizzle = swizzle; -@@ -4937,34 +5048,16 @@ static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer - static void write_sm4_resource_load(struct hlsl_ctx *ctx, - struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_load *load) - { -- const struct hlsl_type *resource_type = load->resource.var->data_type; - const struct hlsl_ir_node *texel_offset = load->texel_offset.node; - const struct hlsl_ir_node *sample_index = load->sample_index.node; - const struct hlsl_ir_node *coords = load->coords.node; - -- if (!hlsl_type_is_resource(resource_type)) -+ if (load->sampler.var && !load->sampler.var->is_uniform) - { -- hlsl_fixme(ctx, &load->node.loc, "Separate object fields as new variables."); -+ hlsl_fixme(ctx, &load->node.loc, "Sample using non-uniform sampler variable."); - return; - } - -- if (load->sampler.var) -- { -- const struct hlsl_type *sampler_type = load->sampler.var->data_type; -- -- if (!hlsl_type_is_resource(sampler_type)) -- { -- hlsl_fixme(ctx, &load->node.loc, "Separate object fields as new variables."); -- return; -- } -- -- if (!load->sampler.var->is_uniform) -- { -- hlsl_fixme(ctx, &load->node.loc, "Sample using non-uniform sampler variable."); -- return; -- } -- } -- - if (!load->resource.var->is_uniform) - { - hlsl_fixme(ctx, &load->node.loc, "Load from non-uniform resource variable."); -@@ -4974,7 +5067,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, - switch (load->load_type) - { - case HLSL_RESOURCE_LOAD: -- write_sm4_ld(ctx, buffer, resource_type, &load->node, &load->resource, -+ write_sm4_ld(ctx, buffer, &load->node, &load->resource, - coords, sample_index, texel_offset, load->sampling_dim); - break; - -@@ -4984,32 +5077,29 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, - case HLSL_RESOURCE_SAMPLE_LOD: - case HLSL_RESOURCE_SAMPLE_LOD_BIAS: - case HLSL_RESOURCE_SAMPLE_GRAD: -- if (!load->sampler.var) -- { -- hlsl_fixme(ctx, &load->node.loc, "SM4 combined sample expression."); -- return; -- } -+ /* Combined sample expressions were lowered. */ -+ assert(load->sampler.var); - write_sm4_sample(ctx, buffer, load); - break; - - case HLSL_RESOURCE_GATHER_RED: -- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, -- &load->sampler, coords, HLSL_SWIZZLE(X, X, X, X), texel_offset); -+ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, -+ HLSL_SWIZZLE(X, X, X, X), texel_offset); - break; - - case HLSL_RESOURCE_GATHER_GREEN: -- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, -- &load->sampler, coords, HLSL_SWIZZLE(Y, Y, Y, Y), texel_offset); -+ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, -+ HLSL_SWIZZLE(Y, Y, Y, Y), texel_offset); - break; - - case HLSL_RESOURCE_GATHER_BLUE: -- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, -- &load->sampler, coords, HLSL_SWIZZLE(Z, Z, Z, Z), texel_offset); -+ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, -+ HLSL_SWIZZLE(Z, Z, Z, Z), texel_offset); - break; - - case HLSL_RESOURCE_GATHER_ALPHA: -- write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, -- &load->sampler, coords, HLSL_SWIZZLE(W, W, W, W), texel_offset); -+ write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, -+ HLSL_SWIZZLE(W, W, W, W), texel_offset); - break; - } - } -@@ -5017,13 +5107,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, - static void write_sm4_resource_store(struct hlsl_ctx *ctx, - struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_store *store) - { -- const struct hlsl_type *resource_type = store->resource.var->data_type; -- -- if (!hlsl_type_is_resource(resource_type)) -- { -- hlsl_fixme(ctx, &store->node.loc, "Separate object fields as new variables."); -- return; -- } -+ struct hlsl_type *resource_type = hlsl_deref_get_type(ctx, &store->resource); - - if (!store->resource.var->is_uniform) - { -@@ -5050,7 +5134,7 @@ static void write_sm4_store(struct hlsl_ctx *ctx, - memset(&instr, 0, sizeof(instr)); - instr.opcode = VKD3D_SM4_OP_MOV; - -- sm4_register_from_deref(ctx, &instr.dsts[0].reg, &writemask, NULL, &store->lhs, rhs->data_type); -+ sm4_register_from_deref(ctx, &instr.dsts[0].reg, &writemask, NULL, &store->lhs); - instr.dsts[0].writemask = hlsl_combine_writemasks(writemask, store->writemask); - instr.dst_count = 1; - -@@ -5161,8 +5245,8 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, - const struct hlsl_ir_function_decl *entry_func, struct dxbc_writer *dxbc) - { - const struct hlsl_profile_info *profile = ctx->profile; -- const struct hlsl_ir_var **extern_resources; - struct vkd3d_bytecode_buffer buffer = {0}; -+ struct extern_resource *extern_resources; - unsigned int extern_resources_count, i; - const struct hlsl_buffer *cbuffer; - const struct hlsl_ir_var *var; -@@ -5194,17 +5278,14 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, - - for (i = 0; i < extern_resources_count; ++i) - { -- enum hlsl_regset regset; -- -- var = extern_resources[i]; -- regset = hlsl_type_get_regset(var->data_type); -+ const struct extern_resource *resource = &extern_resources[i]; - -- if (regset == HLSL_REGSET_SAMPLERS) -- write_sm4_dcl_samplers(&buffer, var); -- else if (regset == HLSL_REGSET_TEXTURES) -- write_sm4_dcl_textures(ctx, &buffer, var, false); -- else if (regset == HLSL_REGSET_UAVS) -- write_sm4_dcl_textures(ctx, &buffer, var, true); -+ if (resource->regset == HLSL_REGSET_SAMPLERS) -+ write_sm4_dcl_samplers(ctx, &buffer, resource); -+ else if (resource->regset == HLSL_REGSET_TEXTURES) -+ write_sm4_dcl_textures(ctx, &buffer, resource, false); -+ else if (resource->regset == HLSL_REGSET_UAVS) -+ write_sm4_dcl_textures(ctx, &buffer, resource, true); - } - - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) -@@ -5227,7 +5308,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, - - add_section(dxbc, TAG_SHDR, &buffer); - -- vkd3d_free(extern_resources); -+ sm4_free_extern_resources(extern_resources, extern_resources_count); - } - - int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index 85fca964227..0e93f3a556a 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -155,11 +155,19 @@ enum vkd3d_shader_error - VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_OFFSET = 8002, - VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE = 8003, - VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE = 8004, -+ 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_INVALID_FUNCTION_DCL = 8009, -+ VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID = 8010, -+ VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE = 8011, - - VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, - VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, - VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH = 8302, - VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH = 8303, -+ VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304, - }; - - enum vkd3d_shader_opcode -@@ -529,6 +537,7 @@ enum vkd3d_data_type - VKD3D_DATA_DOUBLE, - VKD3D_DATA_CONTINUED, - VKD3D_DATA_UNUSED, -+ VKD3D_DATA_UINT8, - }; - - enum vkd3d_immconst_type --- -2.40.1 - diff --git a/patches/vkd3d-latest/definition b/patches/vkd3d-latest/definition index c330a4dd..ece8a5de 100644 --- a/patches/vkd3d-latest/definition +++ b/patches/vkd3d-latest/definition @@ -1,6 +1,6 @@ #Update vkd3d to the latest to allow testing before it's # finally be integrated into wine. -# Bugs for this patchset should be fixed in the usually place against vkd3d +# Bugs for this patchset should be filled in the usually place against vkd3d # Games used for testing # Stranded Alien Dawn - Requires dxvk