From e26a92bace0fa31d9f570b88b5311cc9701b9280 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Tue, 7 Nov 2023 16:14:23 +1100 Subject: [PATCH] Updated vkd3d-latest patchset --- ...-6a942581db3093a2e5b5a76334601868e21.patch | 4 +- ...-f75bdd6e217863840cc5fb3251a171ca0ab.patch | 4 +- ...-a03e78bf6285d4344f5d7774729b4b64175.patch | 4911 +++++++++++++++++ 3 files changed, 4915 insertions(+), 4 deletions(-) create mode 100644 patches/vkd3d-latest/0003-Updated-vkd3d-to-a03e78bf6285d4344f5d7774729b4b64175.patch diff --git a/patches/vkd3d-latest/0001-Updated-vkd3d-to-6a942581db3093a2e5b5a76334601868e21.patch b/patches/vkd3d-latest/0001-Updated-vkd3d-to-6a942581db3093a2e5b5a76334601868e21.patch index 7f77aa9a..ca324b46 100644 --- a/patches/vkd3d-latest/0001-Updated-vkd3d-to-6a942581db3093a2e5b5a76334601868e21.patch +++ b/patches/vkd3d-latest/0001-Updated-vkd3d-to-6a942581db3093a2e5b5a76334601868e21.patch @@ -1,7 +1,7 @@ -From bd12bfc20c592fba43050f99c0e6fe547f49f08c Mon Sep 17 00:00:00 2001 +From 5c791faf91ed25e6528b0c3dce8d9c6ac6760726 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 17 May 2023 08:35:40 +1000 -Subject: [PATCH 1/2] Updated vkd3d to +Subject: [PATCH 1/3] Updated vkd3d to 6a942581db3093a2e5b5a76334601868e217a60d. --- diff --git a/patches/vkd3d-latest/0002-Updated-vkd3d-to-f75bdd6e217863840cc5fb3251a171ca0ab.patch b/patches/vkd3d-latest/0002-Updated-vkd3d-to-f75bdd6e217863840cc5fb3251a171ca0ab.patch index dd85b52f..0eace298 100644 --- a/patches/vkd3d-latest/0002-Updated-vkd3d-to-f75bdd6e217863840cc5fb3251a171ca0ab.patch +++ b/patches/vkd3d-latest/0002-Updated-vkd3d-to-f75bdd6e217863840cc5fb3251a171ca0ab.patch @@ -1,7 +1,7 @@ -From 41c22358dd02076d0756a2c40f6caf0f87d36802 Mon Sep 17 00:00:00 2001 +From f645194ed42238be7ec3bb0a25db0a19fe0493bd Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Mon, 30 Oct 2023 06:37:46 +1100 -Subject: [PATCH 2/2] Updated vkd3d to +Subject: [PATCH 2/3] Updated vkd3d to f75bdd6e217863840cc5fb3251a171ca0abe729b. --- diff --git a/patches/vkd3d-latest/0003-Updated-vkd3d-to-a03e78bf6285d4344f5d7774729b4b64175.patch b/patches/vkd3d-latest/0003-Updated-vkd3d-to-a03e78bf6285d4344f5d7774729b4b64175.patch new file mode 100644 index 00000000..260e8624 --- /dev/null +++ b/patches/vkd3d-latest/0003-Updated-vkd3d-to-a03e78bf6285d4344f5d7774729b4b64175.patch @@ -0,0 +1,4911 @@ +From fa8f1a271d256c8f90e4907a739005c498d10d05 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Tue, 7 Nov 2023 12:20:58 +1100 +Subject: [PATCH 3/3] Updated vkd3d to + a03e78bf6285d4344f5d7774729b4b64175422a7. + +--- + libs/vkd3d/include/vkd3d_d3dcompiler.h | 23 +- + libs/vkd3d/include/vkd3d_d3dcompiler_types.h | 45 ++ + libs/vkd3d/include/vkd3d_utils.h | 4 +- + libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 23 +- + libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 21 +- + libs/vkd3d/libs/vkd3d-shader/dxil.c | 586 +++++++++++++++++- + libs/vkd3d/libs/vkd3d-shader/hlsl.c | 200 +++++- + libs/vkd3d/libs/vkd3d-shader/hlsl.h | 58 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.l | 34 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 273 +++++++- + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 483 +++++++++++++-- + libs/vkd3d/libs/vkd3d-shader/ir.c | 118 +++- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 200 +++--- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 114 +++- + .../libs/vkd3d-shader/vkd3d_shader_main.c | 50 +- + .../libs/vkd3d-shader/vkd3d_shader_private.h | 45 +- + libs/vkd3d/libs/vkd3d/state.c | 48 +- + libs/vkd3d/libs/vkd3d/vkd3d_shaders.h | 568 ++++++----------- + 18 files changed, 2152 insertions(+), 741 deletions(-) + create mode 100644 libs/vkd3d/include/vkd3d_d3dcompiler_types.h + +diff --git a/libs/vkd3d/include/vkd3d_d3dcompiler.h b/libs/vkd3d/include/vkd3d_d3dcompiler.h +index 78d52948310..c78cf25b955 100644 +--- a/libs/vkd3d/include/vkd3d_d3dcompiler.h ++++ b/libs/vkd3d/include/vkd3d_d3dcompiler.h +@@ -20,6 +20,8 @@ + #define __VKD3D_D3DCOMPILER_H + #ifndef __D3DCOMPILER_H__ + ++#include ++ + #define D3DCOMPILE_DEBUG 0x00000001 + #define D3DCOMPILE_SKIP_VALIDATION 0x00000002 + #define D3DCOMPILE_SKIP_OPTIMIZATION 0x00000004 +@@ -58,27 +60,6 @@ + #define D3DCOMPILE_SECDATA_PRESERVE_TEMPLATE_SLOTS 0x00000002 + #define D3DCOMPILE_SECDATA_REQUIRE_TEMPLATE_MATCH 0x00000004 + +-typedef enum D3D_BLOB_PART +-{ +- D3D_BLOB_INPUT_SIGNATURE_BLOB, +- D3D_BLOB_OUTPUT_SIGNATURE_BLOB, +- D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, +- D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB, +- D3D_BLOB_ALL_SIGNATURE_BLOB, +- D3D_BLOB_DEBUG_INFO, +- D3D_BLOB_LEGACY_SHADER, +- D3D_BLOB_XNA_PREPASS_SHADER, +- D3D_BLOB_XNA_SHADER, +- D3D_BLOB_PDB, +- D3D_BLOB_PRIVATE_DATA, +- D3D_BLOB_ROOT_SIGNATURE, +- D3D_BLOB_DEBUG_NAME, +- D3D_BLOB_TEST_ALTERNATE_SHADER = 0x8000, +- D3D_BLOB_TEST_COMPILE_DETAILS, +- D3D_BLOB_TEST_COMPILE_PERF, +- D3D_BLOB_TEST_COMPILE_REPORT +-} D3D_BLOB_PART; +- + typedef enum D3DCOMPILER_STRIP_FLAGS + { + D3DCOMPILER_STRIP_REFLECTION_DATA = 0x00000001, +diff --git a/libs/vkd3d/include/vkd3d_d3dcompiler_types.h b/libs/vkd3d/include/vkd3d_d3dcompiler_types.h +new file mode 100644 +index 00000000000..b3a47cdd912 +--- /dev/null ++++ b/libs/vkd3d/include/vkd3d_d3dcompiler_types.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright 2010 Matteo Bruni for CodeWeavers ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#ifndef __VKD3D_D3DCOMPILER_TYPES_H ++#define __VKD3D_D3DCOMPILER_TYPES_H ++#ifndef __D3DCOMPILER_H__ ++ ++typedef enum D3D_BLOB_PART ++{ ++ D3D_BLOB_INPUT_SIGNATURE_BLOB, ++ D3D_BLOB_OUTPUT_SIGNATURE_BLOB, ++ D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, ++ D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB, ++ D3D_BLOB_ALL_SIGNATURE_BLOB, ++ D3D_BLOB_DEBUG_INFO, ++ D3D_BLOB_LEGACY_SHADER, ++ D3D_BLOB_XNA_PREPASS_SHADER, ++ D3D_BLOB_XNA_SHADER, ++ D3D_BLOB_PDB, ++ D3D_BLOB_PRIVATE_DATA, ++ D3D_BLOB_ROOT_SIGNATURE, ++ D3D_BLOB_DEBUG_NAME, ++ D3D_BLOB_TEST_ALTERNATE_SHADER = 0x8000, ++ D3D_BLOB_TEST_COMPILE_DETAILS, ++ D3D_BLOB_TEST_COMPILE_PERF, ++ D3D_BLOB_TEST_COMPILE_REPORT ++} D3D_BLOB_PART; ++ ++#endif /* __D3DCOMPILER_H__ */ ++#endif /* __VKD3D_D3DCOMPILER_TYPES_H */ +diff --git a/libs/vkd3d/include/vkd3d_utils.h b/libs/vkd3d/include/vkd3d_utils.h +index b5ec7981356..686ddf386e7 100644 +--- a/libs/vkd3d/include/vkd3d_utils.h ++++ b/libs/vkd3d/include/vkd3d_utils.h +@@ -20,6 +20,7 @@ + #define __VKD3D_UTILS_H + + #include ++#include + + #ifndef VKD3D_UTILS_API_VERSION + #define VKD3D_UTILS_API_VERSION VKD3D_API_VERSION_1_0 +@@ -51,9 +52,6 @@ extern "C" { + # define VKD3D_UTILS_API VKD3D_IMPORT + #endif + +-/** \since 1.10 */ +-typedef enum D3D_BLOB_PART D3D_BLOB_PART; +- + /* 1.0 */ + VKD3D_UTILS_API HANDLE vkd3d_create_event(void); + VKD3D_UTILS_API HRESULT vkd3d_signal_event(HANDLE event); +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +index 40daa5354d8..5cea0c0c260 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +@@ -152,6 +152,7 @@ static const char * const shader_opcode_names[] = + [VKD3DSIH_FIRSTBIT_LO ] = "firstbit_lo", + [VKD3DSIH_FIRSTBIT_SHI ] = "firstbit_shi", + [VKD3DSIH_FRC ] = "frc", ++ [VKD3DSIH_FREM ] = "frem", + [VKD3DSIH_FTOD ] = "ftod", + [VKD3DSIH_FTOI ] = "ftoi", + [VKD3DSIH_FTOU ] = "ftou", +@@ -170,6 +171,7 @@ static const char * const shader_opcode_names[] = + [VKD3DSIH_HS_JOIN_PHASE ] = "hs_join_phase", + [VKD3DSIH_IADD ] = "iadd", + [VKD3DSIH_IBFE ] = "ibfe", ++ [VKD3DSIH_IDIV ] = "idiv", + [VKD3DSIH_IEQ ] = "ieq", + [VKD3DSIH_IF ] = "if", + [VKD3DSIH_IFC ] = "ifc", +@@ -358,11 +360,6 @@ struct vkd3d_d3d_asm_compiler + struct vkd3d_d3d_asm_colours colours; + }; + +-static int shader_ver_ge(const struct vkd3d_shader_version *v, int major, int minor) +-{ +- return v->major > major || (v->major == major && v->minor >= minor); +-} +- + static int VKD3D_PRINTF_FUNC(2, 3) shader_addline(struct vkd3d_string_buffer *buffer, const char *format, ...) + { + va_list args; +@@ -424,7 +421,7 @@ static void shader_dump_global_flags(struct vkd3d_d3d_asm_compiler *compiler, + } + + if (global_flags) +- vkd3d_string_buffer_printf(&compiler->buffer, "unknown_flags(%#"PRIx64")", global_flags); ++ vkd3d_string_buffer_printf(&compiler->buffer, "unknown_flags(%#"PRIx64")", (uint64_t)global_flags); + } + + static void shader_dump_sync_flags(struct vkd3d_d3d_asm_compiler *compiler, uint32_t sync_flags) +@@ -684,7 +681,7 @@ static void shader_dump_decl_usage(struct vkd3d_d3d_asm_compiler *compiler, + else + { + /* Pixel shaders 3.0 don't have usage semantics. */ +- if (!shader_ver_ge(&compiler->shader_version, 3, 0) ++ if (!vkd3d_shader_ver_ge(&compiler->shader_version, 3, 0) + && compiler->shader_version.type == VKD3D_SHADER_TYPE_PIXEL) + return; + else +@@ -908,7 +905,7 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const + case VKD3DSPR_TEXCRDOUT: + /* Vertex shaders >= 3.0 use general purpose output registers + * (VKD3DSPR_OUTPUT), which can include an address token. */ +- if (shader_ver_ge(&compiler->shader_version, 3, 0)) ++ if (vkd3d_shader_ver_ge(&compiler->shader_version, 3, 0)) + shader_addline(buffer, "o"); + else + shader_addline(buffer, "oT"); +@@ -1174,7 +1171,7 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const + { + if (offset != ~0u) + { +- bool is_sm_5_1 = shader_ver_ge(&compiler->shader_version, 5, 1); ++ bool is_sm_5_1 = vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1); + + if (reg->idx[0].rel_addr || reg->type == VKD3DSPR_IMMCONSTBUFFER + || reg->type == VKD3DSPR_INCONTROLPOINT || (reg->type == VKD3DSPR_INPUT +@@ -1570,7 +1567,7 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile + break; + + case VKD3DSIH_TEX: +- if (shader_ver_ge(&compiler->shader_version, 2, 0) && (ins->flags & VKD3DSI_TEXLD_PROJECT)) ++ if (vkd3d_shader_ver_ge(&compiler->shader_version, 2, 0) && (ins->flags & VKD3DSI_TEXLD_PROJECT)) + shader_addline(buffer, "p"); + break; + +@@ -1582,7 +1579,7 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile + + static void shader_dump_register_space(struct vkd3d_d3d_asm_compiler *compiler, unsigned int register_space) + { +- if (shader_ver_ge(&compiler->shader_version, 5, 1)) ++ if (vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1)) + shader_print_uint_literal(compiler, ", space=", register_space, ""); + } + +@@ -1626,9 +1623,9 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, + case VKD3DSIH_DCL_CONSTANT_BUFFER: + vkd3d_string_buffer_printf(buffer, " "); + shader_dump_register(compiler, &ins->declaration.cb.src.reg, true); +- if (shader_ver_ge(&compiler->shader_version, 6, 0)) ++ if (vkd3d_shader_ver_ge(&compiler->shader_version, 6, 0)) + shader_print_subscript(compiler, ins->declaration.cb.size, NULL); +- else if (shader_ver_ge(&compiler->shader_version, 5, 1)) ++ else if (vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1)) + shader_print_subscript(compiler, ins->declaration.cb.size / VKD3D_VEC4_SIZE / sizeof(float), NULL); + shader_addline(buffer, ", %s", + ins->flags & VKD3DSI_INDEXED_DYNAMIC ? "dynamicIndexed" : "immediateIndexed"); +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +index 67fa32710fd..b1e2dc91d94 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +@@ -402,16 +402,6 @@ static uint32_t read_u32(const uint32_t **ptr) + return *(*ptr)++; + } + +-static bool shader_ver_ge(const struct vkd3d_shader_version *v, unsigned int major, unsigned int minor) +-{ +- return v->major > major || (v->major == major && v->minor >= minor); +-} +- +-static bool shader_ver_le(const struct vkd3d_shader_version *v, unsigned int major, unsigned int minor) +-{ +- return v->major < major || (v->major == major && v->minor <= minor); +-} +- + static bool has_relative_address(uint32_t param) + { + enum vkd3d_sm1_address_mode_type address_mode; +@@ -434,8 +424,8 @@ static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info( + return NULL; + + if (opcode == info->sm1_opcode +- && shader_ver_ge(&sm1->p.shader_version, info->min_version.major, info->min_version.minor) +- && (shader_ver_le(&sm1->p.shader_version, info->max_version.major, info->max_version.minor) ++ && vkd3d_shader_ver_ge(&sm1->p.shader_version, info->min_version.major, info->min_version.minor) ++ && (vkd3d_shader_ver_le(&sm1->p.shader_version, info->max_version.major, info->max_version.minor) + || !info->max_version.major)) + return info; + } +@@ -555,9 +545,9 @@ static bool add_signature_element(struct vkd3d_shader_sm1_parser *sm1, bool outp + return false; + element = &signature->elements[signature->element_count++]; + ++ memset(element, 0, sizeof(*element)); + element->semantic_name = name; + element->semantic_index = index; +- element->stream_index = 0; + element->sysval_semantic = sysval; + element->component_type = VKD3D_SHADER_COMPONENT_FLOAT; + element->register_index = register_index; +@@ -565,7 +555,8 @@ static bool add_signature_element(struct vkd3d_shader_sm1_parser *sm1, bool outp + element->register_count = 1; + element->mask = mask; + element->used_mask = is_dcl ? 0 : mask; +- element->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE; ++ if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && !output) ++ element->interpolation_mode = VKD3DSIM_LINEAR; + + return true; + } +@@ -1262,7 +1253,7 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, + return VKD3D_ERROR_INVALID_SHADER; + } + +- if (!shader_ver_le(&version, 3, 0)) ++ if (!vkd3d_shader_ver_le(&version, 3, 0)) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_D3DBC_INVALID_VERSION_TOKEN, + "Invalid shader version %u.%u (token 0x%08x).", version.major, version.minor, code[0]); +diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c +index 19ce2936acb..e0e242cb788 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c ++++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c +@@ -242,10 +242,51 @@ enum dxil_shader_properties_tag + SHADER_PROPERTIES_ENTRY_ROOT_SIG = 12, + }; + ++enum dxil_binop_code ++{ ++ BINOP_ADD = 0, ++ BINOP_SUB = 1, ++ BINOP_MUL = 2, ++ BINOP_UDIV = 3, ++ BINOP_SDIV = 4, ++ BINOP_UREM = 5, ++ BINOP_SREM = 6, ++ BINOP_SHL = 7, ++ BINOP_LSHR = 8, ++ BINOP_ASHR = 9, ++ BINOP_AND = 10, ++ BINOP_OR = 11, ++ BINOP_XOR = 12 ++}; ++ ++enum dxil_fast_fp_flags ++{ ++ FP_ALLOW_UNSAFE_ALGEBRA = 0x1, ++ FP_NO_NAN = 0x2, ++ FP_NO_INF = 0x4, ++ FP_NO_SIGNED_ZEROS = 0x8, ++ FP_ALLOW_RECIPROCAL = 0x10, ++}; ++ ++enum dxil_overflowing_binop_flags ++{ ++ /* Operation is known to never overflow. */ ++ OB_NO_UNSIGNED_WRAP = 0x1, ++ OB_NO_SIGNED_WRAP = 0x2, ++}; ++ ++enum dxil_possibly_exact_binop_flags ++{ ++ /* "A udiv or sdiv instruction, which can be marked as "exact", indicating that no bits are destroyed." */ ++ PEB_EXACT = 0x1, ++}; ++ + enum dx_intrinsic_opcode + { + DX_LOAD_INPUT = 4, + DX_STORE_OUTPUT = 5, ++ DX_CREATE_HANDLE = 57, ++ DX_CBUFFER_LOAD_LEGACY = 59, + }; + + struct sm6_pointer_info +@@ -305,6 +346,7 @@ enum sm6_value_type + { + VALUE_TYPE_FUNCTION, + VALUE_TYPE_REG, ++ VALUE_TYPE_HANDLE, + }; + + struct sm6_function_data +@@ -314,6 +356,12 @@ struct sm6_function_data + unsigned int attribs_id; + }; + ++struct sm6_handle_data ++{ ++ const struct sm6_descriptor_info *d; ++ struct vkd3d_shader_register reg; ++}; ++ + struct sm6_value + { + const struct sm6_type *type; +@@ -323,6 +371,7 @@ struct sm6_value + { + struct sm6_function_data function; + struct vkd3d_shader_register reg; ++ struct sm6_handle_data handle; + } u; + }; + +@@ -427,6 +476,13 @@ struct sm6_named_metadata + struct sm6_metadata_value value; + }; + ++struct sm6_descriptor_info ++{ ++ enum vkd3d_shader_descriptor_type type; ++ unsigned int id; ++ struct vkd3d_shader_register_range range; ++}; ++ + struct sm6_parser + { + const uint32_t *ptr, *start, *end; +@@ -442,6 +498,7 @@ struct sm6_parser + struct sm6_type *types; + size_t type_count; + struct sm6_type *metadata_type; ++ struct sm6_type *handle_type; + + struct sm6_symbol *global_symbols; + size_t global_symbol_count; +@@ -458,6 +515,10 @@ struct sm6_parser + struct sm6_named_metadata *named_metadata; + unsigned int named_metadata_count; + ++ struct sm6_descriptor_info *descriptors; ++ size_t descriptor_capacity; ++ size_t descriptor_count; ++ + struct sm6_value *values; + size_t value_count; + size_t value_capacity; +@@ -1352,7 +1413,7 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) + + case TYPE_CODE_STRUCT_ANON: + case TYPE_CODE_STRUCT_NAMED: +- if (!dxil_record_validate_operand_min_count(record, 2, sm6)) ++ if (!dxil_record_validate_operand_min_count(record, 1, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + if (record->code == TYPE_CODE_STRUCT_NAMED && !struct_name) + { +@@ -1391,6 +1452,9 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) + break; + } + ++ if (!ascii_strcasecmp(struct_name, "dx.types.Handle")) ++ sm6->handle_type = type; ++ + type->u.struc->name = struct_name; + struct_name = NULL; + break; +@@ -1438,6 +1502,16 @@ static inline bool sm6_type_is_integer(const struct sm6_type *type) + return type->class == TYPE_CLASS_INTEGER; + } + ++static bool sm6_type_is_bool_i16_i32_i64(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_INTEGER && (type->u.width == 1 || type->u.width >= 16); ++} ++ ++static bool sm6_type_is_bool(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_INTEGER && type->u.width == 1; ++} ++ + static inline bool sm6_type_is_i8(const struct sm6_type *type) + { + return type->class == TYPE_CLASS_INTEGER && type->u.width == 8; +@@ -1453,6 +1527,11 @@ static inline bool sm6_type_is_floating_point(const struct sm6_type *type) + return type->class == TYPE_CLASS_FLOAT; + } + ++static bool sm6_type_is_scalar(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_INTEGER || type->class == TYPE_CLASS_FLOAT || type->class == TYPE_CLASS_POINTER; ++} ++ + static inline bool sm6_type_is_numeric(const struct sm6_type *type) + { + return type->class == TYPE_CLASS_INTEGER || type->class == TYPE_CLASS_FLOAT; +@@ -1463,6 +1542,11 @@ static inline bool sm6_type_is_pointer(const struct sm6_type *type) + return type->class == TYPE_CLASS_POINTER; + } + ++static bool sm6_type_is_aggregate(const struct sm6_type *type) ++{ ++ return type->class == TYPE_CLASS_STRUCT || type->class == TYPE_CLASS_VECTOR || type->class == TYPE_CLASS_ARRAY; ++} ++ + static bool sm6_type_is_numeric_aggregate(const struct sm6_type *type) + { + unsigned int i; +@@ -1533,6 +1617,27 @@ static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type + return NULL; + } + ++/* Call for aggregate types only. */ ++static const struct sm6_type *sm6_type_get_element_type_at_index(const struct sm6_type *type, uint64_t elem_idx) ++{ ++ switch (type->class) ++ { ++ case TYPE_CLASS_ARRAY: ++ case TYPE_CLASS_VECTOR: ++ if (elem_idx >= type->u.array.count) ++ return NULL; ++ return type->u.array.elem_type; ++ ++ case TYPE_CLASS_STRUCT: ++ if (elem_idx >= type->u.struc->elem_count) ++ return NULL; ++ return type->u.struc->elem_types[elem_idx]; ++ ++ default: ++ vkd3d_unreachable(); ++ } ++} ++ + /* Never returns null for elem_idx 0. */ + static const struct sm6_type *sm6_type_get_scalar_type(const struct sm6_type *type, unsigned int elem_idx) + { +@@ -1557,6 +1662,11 @@ static const struct sm6_type *sm6_type_get_scalar_type(const struct sm6_type *ty + } + } + ++static unsigned int sm6_type_max_vector_size(const struct sm6_type *type) ++{ ++ return min((VKD3D_VEC4_SIZE * sizeof(uint32_t) * CHAR_BIT) / type->u.width, VKD3D_VEC4_SIZE); ++} ++ + static const struct sm6_type *sm6_parser_get_type(struct sm6_parser *sm6, uint64_t type_id) + { + if (type_id >= sm6->type_count) +@@ -1661,7 +1771,7 @@ static const char *sm6_parser_get_global_symbol_name(const struct sm6_parser *sm + + static unsigned int register_get_uint_value(const struct vkd3d_shader_register *reg) + { +- if (!register_is_constant(reg) || !data_type_is_integer(reg->data_type)) ++ if (!register_is_constant(reg) || (!data_type_is_integer(reg->data_type) && !data_type_is_bool(reg->data_type))) + return UINT_MAX; + + if (reg->dimension == VSIR_DIMENSION_VEC4) +@@ -1710,6 +1820,11 @@ static inline bool sm6_value_is_register(const struct sm6_value *value) + return value->value_type == VALUE_TYPE_REG; + } + ++static bool sm6_value_is_handle(const struct sm6_value *value) ++{ ++ return value->value_type == VALUE_TYPE_HANDLE; ++} ++ + static inline bool sm6_value_is_constant(const struct sm6_value *value) + { + return sm6_value_is_register(value) && register_is_constant(&value->u.reg); +@@ -1782,6 +1897,8 @@ static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type + { + switch (type->u.width) + { ++ case 1: ++ return VKD3D_DATA_BOOL; + case 8: + return VKD3D_DATA_UINT8; + case 32: +@@ -1811,8 +1928,8 @@ static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type + return VKD3D_DATA_UINT; + } + +-static void register_init_ssa_scalar(struct vkd3d_shader_register *reg, const struct sm6_type *type, +- struct sm6_parser *sm6) ++static void register_init_ssa_vector(struct vkd3d_shader_register *reg, const struct sm6_type *type, ++ unsigned int component_count, struct sm6_parser *sm6) + { + enum vkd3d_data_type data_type; + unsigned int id; +@@ -1820,6 +1937,13 @@ static void register_init_ssa_scalar(struct vkd3d_shader_register *reg, const st + id = sm6_parser_alloc_ssa_id(sm6); + data_type = vkd3d_data_type_from_sm6_type(sm6_type_get_scalar_type(type, 0)); + register_init_with_id(reg, VKD3DSPR_SSA, data_type, id); ++ reg->dimension = component_count > 1 ? VSIR_DIMENSION_VEC4 : VSIR_DIMENSION_SCALAR; ++} ++ ++static void register_init_ssa_scalar(struct vkd3d_shader_register *reg, const struct sm6_type *type, ++ struct sm6_parser *sm6) ++{ ++ register_init_ssa_vector(reg, type, 1, sm6); + } + + static void dst_param_init(struct vkd3d_shader_dst_param *param) +@@ -1836,6 +1960,13 @@ static inline void dst_param_init_scalar(struct vkd3d_shader_dst_param *param, u + param->shift = 0; + } + ++static void dst_param_init_vector(struct vkd3d_shader_dst_param *param, unsigned int component_count) ++{ ++ param->write_mask = (1u << component_count) - 1; ++ param->modifiers = 0; ++ param->shift = 0; ++} ++ + static void dst_param_init_ssa_scalar(struct vkd3d_shader_dst_param *param, const struct sm6_type *type, + struct sm6_parser *sm6) + { +@@ -1861,25 +1992,32 @@ static void src_param_init_from_value(struct vkd3d_shader_src_param *param, cons + param->reg = src->u.reg; + } + +-static void register_address_init(struct vkd3d_shader_register *reg, const struct sm6_value *address, +- unsigned int idx, struct sm6_parser *sm6) ++static void src_param_init_vector_from_reg(struct vkd3d_shader_src_param *param, ++ const struct vkd3d_shader_register *reg) ++{ ++ param->swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ param->modifiers = VKD3DSPSM_NONE; ++ param->reg = *reg; ++} ++ ++static void register_index_address_init(struct vkd3d_shader_register_index *idx, const struct sm6_value *address, ++ struct sm6_parser *sm6) + { +- assert(idx < ARRAY_SIZE(reg->idx)); + if (sm6_value_is_constant(address)) + { +- reg->idx[idx].offset = sm6_value_get_constant_uint(address); ++ idx->offset = sm6_value_get_constant_uint(address); + } + else if (sm6_value_is_undef(address)) + { +- reg->idx[idx].offset = 0; ++ idx->offset = 0; + } + else + { + struct vkd3d_shader_src_param *rel_addr = shader_parser_get_src_params(&sm6->p, 1); + if (rel_addr) + src_param_init_from_value(rel_addr, address); +- reg->idx[idx].offset = 0; +- reg->idx[idx].rel_addr = rel_addr; ++ idx->offset = 0; ++ idx->rel_addr = rel_addr; + } + } + +@@ -1893,6 +2031,17 @@ static void instruction_dst_param_init_ssa_scalar(struct vkd3d_shader_instructio + dst->u.reg = param->reg; + } + ++static void instruction_dst_param_init_ssa_vector(struct vkd3d_shader_instruction *ins, ++ unsigned int component_count, struct sm6_parser *sm6) ++{ ++ struct vkd3d_shader_dst_param *param = instruction_dst_params_alloc(ins, 1, sm6); ++ struct sm6_value *dst = sm6_parser_get_current_value(sm6); ++ ++ dst_param_init_vector(param, component_count); ++ register_init_ssa_vector(¶m->reg, sm6_type_get_scalar_type(dst->type, 0), component_count, sm6); ++ dst->u.reg = param->reg; ++} ++ + /* 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. */ +@@ -1957,6 +2106,18 @@ static size_t sm6_parser_get_value_index(struct sm6_parser *sm6, uint64_t idx) + return i; + } + ++static bool sm6_value_validate_is_handle(const struct sm6_value *value, struct sm6_parser *sm6) ++{ ++ if (!sm6_value_is_handle(value)) ++ { ++ WARN("Handle parameter of type %u is not a handle.\n", value->value_type); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCE_HANDLE, ++ "A handle parameter passed to a DX intrinsic function is not a handle."); ++ return false; ++ } ++ return true; ++} ++ + static const struct sm6_value *sm6_parser_get_value_safe(struct sm6_parser *sm6, unsigned int idx) + { + if (idx < sm6->value_count) +@@ -2230,9 +2391,7 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const + 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.dimension = VSIR_DIMENSION_SCALAR; +- dst->u.reg.data_type = reg_data_type; ++ vsir_register_init(&dst->u.reg, reg_type, reg_data_type, 0); + + switch (record->code) + { +@@ -2519,6 +2678,273 @@ static struct sm6_block *sm6_block_create() + return block; + } + ++static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_type *type_a, ++ const struct sm6_type *type_b, struct sm6_parser *sm6) ++{ ++ bool is_int = sm6_type_is_bool_i16_i32_i64(type_a); ++ bool is_bool = sm6_type_is_bool(type_a); ++ enum vkd3d_shader_opcode op; ++ bool is_valid; ++ ++ if (!is_int && !sm6_type_is_floating_point(type_a)) ++ { ++ WARN("Argument type %u is not bool, int16/32/64 or floating point.\n", type_a->class); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, ++ "An argument to a binary operation is not bool, int16/32/64 or floating point."); ++ return VKD3DSIH_INVALID; ++ } ++ if (type_a != type_b) ++ { ++ WARN("Type mismatch, type %u width %u vs type %u width %u.\n", type_a->class, ++ type_a->u.width, type_b->class, type_b->u.width); ++ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, ++ "Type mismatch in binary operation arguments."); ++ } ++ ++ switch (code) ++ { ++ case BINOP_ADD: ++ case BINOP_SUB: ++ /* NEG is applied later for subtraction. */ ++ op = is_int ? VKD3DSIH_IADD : VKD3DSIH_ADD; ++ is_valid = !is_bool; ++ break; ++ case BINOP_AND: ++ op = VKD3DSIH_AND; ++ is_valid = is_int; ++ break; ++ case BINOP_ASHR: ++ op = VKD3DSIH_ISHR; ++ is_valid = is_int && !is_bool; ++ break; ++ case BINOP_LSHR: ++ op = VKD3DSIH_USHR; ++ is_valid = is_int && !is_bool; ++ break; ++ case BINOP_MUL: ++ op = is_int ? VKD3DSIH_UMUL : VKD3DSIH_MUL; ++ is_valid = !is_bool; ++ break; ++ case BINOP_OR: ++ op = VKD3DSIH_OR; ++ is_valid = is_int; ++ break; ++ case BINOP_SDIV: ++ op = is_int ? VKD3DSIH_IDIV : VKD3DSIH_DIV; ++ is_valid = !is_bool; ++ break; ++ case BINOP_SREM: ++ op = is_int ? VKD3DSIH_IDIV : VKD3DSIH_FREM; ++ is_valid = !is_bool; ++ break; ++ case BINOP_SHL: ++ op = VKD3DSIH_ISHL; ++ is_valid = is_int && !is_bool; ++ break; ++ case BINOP_UDIV: ++ case BINOP_UREM: ++ op = VKD3DSIH_UDIV; ++ is_valid = is_int && !is_bool; ++ break; ++ case BINOP_XOR: ++ op = VKD3DSIH_XOR; ++ is_valid = is_int; ++ break; ++ default: ++ FIXME("Unhandled binary op %#"PRIx64".\n", code); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, ++ "Binary operation %#"PRIx64" is unhandled.", code); ++ return VKD3DSIH_INVALID; ++ } ++ ++ if (!is_valid) ++ { ++ WARN("Invalid operation %u for type %u, width %u.\n", op, type_a->class, type_a->u.width); ++ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION, ++ "Binary operation %u is invalid on type class %u, width %u.", op, type_a->class, type_a->u.width); ++ } ++ ++ return op; ++} ++ ++static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_record *record, ++ struct vkd3d_shader_instruction *ins, struct sm6_value *dst) ++{ ++ struct vkd3d_shader_src_param *src_params; ++ enum vkd3d_shader_opcode handler_idx; ++ const struct sm6_value *a, *b; ++ unsigned int i = 0; ++ uint64_t code; ++ ++ a = sm6_parser_get_value_by_ref(sm6, record, NULL, &i); ++ b = sm6_parser_get_value_by_ref(sm6, record, a->type, &i); ++ if (!a || !b) ++ return; ++ ++ if (!dxil_record_validate_operand_count(record, i + 1, i + 2, sm6)) ++ return; ++ ++ code = record->operands[i++]; ++ if ((handler_idx = map_binary_op(code, a->type, b->type, sm6)) == VKD3DSIH_INVALID) ++ return; ++ ++ vsir_instruction_init(ins, &sm6->p.location, handler_idx); ++ ++ if (record->operand_count > i && record->operands[i]) ++ { ++ uint64_t flags = record->operands[i]; ++ bool silence_warning = false; ++ ++ switch (handler_idx) ++ { ++ case VKD3DSIH_ADD: ++ case VKD3DSIH_MUL: ++ case VKD3DSIH_DIV: ++ case VKD3DSIH_FREM: ++ if (!(flags & FP_ALLOW_UNSAFE_ALGEBRA)) ++ ins->flags |= VKD3DSI_PRECISE_X; ++ flags &= ~FP_ALLOW_UNSAFE_ALGEBRA; ++ /* SPIR-V FPFastMathMode is only available in the Kernel executon model. */ ++ silence_warning = !(flags & ~(FP_NO_NAN | FP_NO_INF | FP_NO_SIGNED_ZEROS | FP_ALLOW_RECIPROCAL)); ++ break; ++ case VKD3DSIH_IADD: ++ case VKD3DSIH_UMUL: ++ case VKD3DSIH_ISHL: ++ silence_warning = !(flags & ~(OB_NO_UNSIGNED_WRAP | OB_NO_SIGNED_WRAP)); ++ break; ++ case VKD3DSIH_ISHR: ++ case VKD3DSIH_USHR: ++ case VKD3DSIH_IDIV: ++ case VKD3DSIH_UDIV: ++ silence_warning = !(flags & ~PEB_EXACT); ++ break; ++ default: ++ break; ++ } ++ /* The above flags are very common and cause warning spam. */ ++ if (flags && silence_warning) ++ { ++ TRACE("Ignoring flags %#"PRIx64".\n", flags); ++ } ++ else if (flags) ++ { ++ WARN("Ignoring flags %#"PRIx64".\n", flags); ++ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, ++ "Ignoring flags %#"PRIx64" for a binary operation.", flags); ++ } ++ } ++ ++ src_params = instruction_src_params_alloc(ins, 2, sm6); ++ src_param_init_from_value(&src_params[0], a); ++ src_param_init_from_value(&src_params[1], b); ++ if (code == BINOP_SUB) ++ src_params[1].modifiers = VKD3DSPSM_NEG; ++ ++ dst->type = a->type; ++ ++ if (handler_idx == VKD3DSIH_UMUL || handler_idx == VKD3DSIH_UDIV || handler_idx == VKD3DSIH_IDIV) ++ { ++ struct vkd3d_shader_dst_param *dst_params = instruction_dst_params_alloc(ins, 2, sm6); ++ unsigned int index = code != BINOP_UDIV && code != BINOP_SDIV; ++ ++ dst_param_init(&dst_params[0]); ++ dst_param_init(&dst_params[1]); ++ register_init_ssa_scalar(&dst_params[index].reg, a->type, sm6); ++ vsir_register_init(&dst_params[index ^ 1].reg, VKD3DSPR_NULL, VKD3D_DATA_UNUSED, 0); ++ dst->u.reg = dst_params[index].reg; ++ } ++ else ++ { ++ instruction_dst_param_init_ssa_scalar(ins, sm6); ++ } ++} ++ ++static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, struct sm6_block *code_block, ++ enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) ++{ ++ struct sm6_value *dst = sm6_parser_get_current_value(sm6); ++ struct vkd3d_shader_src_param *src_param; ++ const struct sm6_value *buffer; ++ const struct sm6_type *type; ++ ++ buffer = operands[0]; ++ if (!sm6_value_validate_is_handle(buffer, sm6)) ++ return; ++ ++ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV); ++ ++ src_param = instruction_src_params_alloc(ins, 1, sm6); ++ src_param_init_vector_from_reg(src_param, &buffer->u.handle.reg); ++ register_index_address_init(&src_param->reg.idx[2], operands[1], sm6); ++ assert(src_param->reg.idx_count == 3); ++ ++ type = sm6_type_get_scalar_type(dst->type, 0); ++ assert(type); ++ src_param->reg.data_type = vkd3d_data_type_from_sm6_type(type); ++ ++ instruction_dst_param_init_ssa_vector(ins, sm6_type_max_vector_size(type), sm6); ++} ++ ++static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_parser *sm6, ++ enum vkd3d_shader_descriptor_type type, unsigned int id, const struct sm6_value *address) ++{ ++ const struct sm6_descriptor_info *d; ++ unsigned int register_index; ++ size_t i; ++ ++ for (i = 0; i < sm6->descriptor_count; ++i) ++ { ++ d = &sm6->descriptors[i]; ++ ++ if (d->type != type || d->id != id) ++ continue; ++ ++ if (!sm6_value_is_constant(address)) ++ return d; ++ ++ register_index = sm6_value_get_constant_uint(address); ++ if (register_index >= d->range.first && register_index <= d->range.last) ++ return d; ++ } ++ ++ return NULL; ++} ++ ++static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_block *code_block, ++ enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) ++{ ++ enum vkd3d_shader_descriptor_type type; ++ const struct sm6_descriptor_info *d; ++ struct vkd3d_shader_register *reg; ++ struct sm6_value *dst; ++ unsigned int id; ++ ++ type = sm6_value_get_constant_uint(operands[0]); ++ id = sm6_value_get_constant_uint(operands[1]); ++ if (!(d = sm6_parser_get_descriptor(sm6, type, id, operands[2]))) ++ { ++ WARN("Failed to find resource type %#x, id %#x.\n", type, id); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, ++ "Descriptor for resource type %#x, id %#x was not found.", type, id); ++ return; ++ } ++ ++ dst = sm6_parser_get_current_value(sm6); ++ dst->value_type = VALUE_TYPE_HANDLE; ++ dst->u.handle.d = d; ++ ++ reg = &dst->u.handle.reg; ++ /* Set idx_count to 3 for use with load instructions. ++ * TODO: set register type from resource type when other types are supported. */ ++ vsir_register_init(reg, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3); ++ reg->idx[0].offset = id; ++ register_index_address_init(®->idx[1], operands[2], sm6); ++ reg->non_uniform = !!sm6_value_get_constant_uint(operands[3]); ++ ++ /* NOP is used to flag no instruction emitted. */ ++ ins->handler_idx = VKD3DSIH_NOP; ++} ++ + static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_block *code_block, + enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) + { +@@ -2546,7 +2972,7 @@ static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_blo + src_param->reg = sm6->input_params[row_index].reg; + src_param_init_scalar(src_param, column_index); + if (e->register_count > 1) +- register_address_init(&src_param->reg, operands[1], 0, sm6); ++ register_index_address_init(&src_param->reg.idx[0], operands[1], sm6); + + instruction_dst_param_init_ssa_scalar(ins, sm6); + } +@@ -2598,7 +3024,7 @@ static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, struct sm6_b + dst_param_init_scalar(dst_param, column_index); + dst_param->reg = sm6->output_params[row_index].reg; + if (e->register_count > 1) +- register_address_init(&dst_param->reg, operands[1], 0, sm6); ++ register_index_address_init(&dst_param->reg.idx[0], operands[1], sm6); + + if ((src_param = instruction_src_params_alloc(ins, 1, sm6))) + src_param_init_from_value(src_param, value); +@@ -2614,18 +3040,29 @@ struct sm6_dx_opcode_info + + /* + 8 -> int8 ++ b -> constant int1 ++ c -> constant int8/16/32 + i -> int32 ++ H -> handle + v -> void + o -> overloaded + */ + static const struct sm6_dx_opcode_info sm6_dx_op_table[] = + { ++ [DX_CBUFFER_LOAD_LEGACY ] = {'o', "Hi", sm6_parser_emit_dx_cbuffer_load}, ++ [DX_CREATE_HANDLE ] = {'H', "ccib", sm6_parser_emit_dx_create_handle}, + [DX_LOAD_INPUT ] = {'o', "ii8i", sm6_parser_emit_dx_load_input}, + [DX_STORE_OUTPUT ] = {'v', "ii8o", sm6_parser_emit_dx_store_output}, + }; + +-static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_type *type, char info_type) ++static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_value *value, char info_type, ++ bool is_return) + { ++ const struct sm6_type *type = value->type; ++ ++ if (info_type != 'H' && !sm6_value_is_register(value)) ++ return false; ++ + switch (info_type) + { + case 0: +@@ -2633,8 +3070,15 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc + return false; + case '8': + return sm6_type_is_i8(type); ++ case 'b': ++ return sm6_value_is_constant(value) && sm6_type_is_bool(type); ++ case 'c': ++ return sm6_value_is_constant(value) && sm6_type_is_integer(type) && type->u.width >= 8 ++ && type->u.width <= 32; + case 'i': + return sm6_type_is_i32(type); ++ case 'H': ++ return (is_return || sm6_value_is_handle(value)) && type == sm6->handle_type; + case 'v': + return !type; + case 'o': +@@ -2654,7 +3098,7 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_ + + info = &sm6_dx_op_table[op]; + +- if (!sm6_parser_validate_operand_type(sm6, dst->type, info->ret_type)) ++ if (!sm6_parser_validate_operand_type(sm6, dst, info->ret_type, true)) + { + WARN("Failed to validate return type for dx intrinsic id %u, '%s'.\n", op, name); + /* Return type validation failure is not so critical. We only need to set +@@ -2664,7 +3108,7 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_ + for (i = 0; i < operand_count; ++i) + { + const struct sm6_value *value = operands[i]; +- if (!sm6_value_is_register(value) || !sm6_parser_validate_operand_type(sm6, value->type, info->operand_info[i])) ++ if (!sm6_parser_validate_operand_type(sm6, value, info->operand_info[i], false)) + { + WARN("Failed to validate operand %u for dx intrinsic id %u, '%s'.\n", i + 1, op, name); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, +@@ -2804,6 +3248,64 @@ static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_recor + fn_value->u.function.name, &operands[1], operand_count - 1, ins, dst); + } + ++static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil_record *record, ++ struct vkd3d_shader_instruction *ins, struct sm6_value *dst) ++{ ++ struct vkd3d_shader_src_param *src_param; ++ const struct sm6_type *type; ++ const struct sm6_value *src; ++ unsigned int i = 0; ++ uint64_t elem_idx; ++ ++ if (!(src = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) ++ return; ++ ++ if (!dxil_record_validate_operand_min_count(record, i + 1, sm6)) ++ return; ++ ++ if (record->operand_count > i + 1) ++ { ++ FIXME("Unhandled multiple indices.\n"); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, ++ "Multiple extractval indices are not supported."); ++ return; ++ } ++ ++ type = src->type; ++ if (!sm6_type_is_aggregate(type)) ++ { ++ WARN("Invalid extraction from non-aggregate.\n"); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, ++ "Source type of an extractval instruction is not an aggregate."); ++ return; ++ } ++ ++ elem_idx = record->operands[i]; ++ if (!(type = sm6_type_get_element_type_at_index(type, elem_idx))) ++ { ++ WARN("Invalid element index %"PRIu64".\n", elem_idx); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, ++ "Element index %"PRIu64" for an extractval instruction is out of bounds.", elem_idx); ++ return; ++ } ++ if (!sm6_type_is_scalar(type)) ++ { ++ FIXME("Nested extraction is not supported.\n"); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, ++ "Extraction from nested aggregates is not supported."); ++ return; ++ } ++ dst->type = type; ++ ++ ins->handler_idx = VKD3DSIH_MOV; ++ ++ src_param = instruction_src_params_alloc(ins, 1, sm6); ++ src_param_init_from_value(src_param, src); ++ src_param->swizzle = vkd3d_shader_create_swizzle(elem_idx, elem_idx, elem_idx, elem_idx); ++ ++ instruction_dst_param_init_ssa_scalar(ins, sm6); ++} ++ + 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) + { +@@ -2956,9 +3458,15 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const + record = block->records[i]; + switch (record->code) + { ++ case FUNC_CODE_INST_BINOP: ++ sm6_parser_emit_binop(sm6, record, ins, dst); ++ break; + case FUNC_CODE_INST_CALL: + sm6_parser_emit_call(sm6, record, code_block, ins, dst); + break; ++ case FUNC_CODE_INST_EXTRACTVAL: ++ sm6_parser_emit_extractval(sm6, record, ins, dst); ++ break; + case FUNC_CODE_INST_RET: + sm6_parser_emit_ret(sm6, record, code_block, ins); + is_terminator = true; +@@ -3423,8 +3931,7 @@ static bool sm6_parser_resources_load_register_range(struct sm6_parser *sm6, + } + + static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6, +- const struct sm6_metadata_node *node, const struct vkd3d_shader_register_range *range, +- unsigned int register_id, struct vkd3d_shader_instruction *ins) ++ const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins) + { + struct vkd3d_shader_register *reg; + unsigned int buffer_size; +@@ -3459,11 +3966,11 @@ static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6, + + reg = &ins->declaration.cb.src.reg; + vsir_register_init(reg, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3); +- reg->idx[0].offset = register_id; +- reg->idx[1].offset = range->first; +- reg->idx[2].offset = range->last; ++ reg->idx[0].offset = d->id; ++ reg->idx[1].offset = d->range.first; ++ reg->idx[2].offset = d->range.last; + +- ins->declaration.cb.range = *range; ++ ins->declaration.cb.range = d->range; + + return VKD3D_OK; + } +@@ -3471,12 +3978,12 @@ static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6, + static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, + enum vkd3d_shader_descriptor_type type, const struct sm6_metadata_node *descriptor_node) + { +- struct vkd3d_shader_register_range range; + struct vkd3d_shader_instruction *ins; + const struct sm6_metadata_node *node; + const struct sm6_metadata_value *m; +- unsigned int i, register_id; ++ struct sm6_descriptor_info *d; + enum vkd3d_result ret; ++ unsigned int i; + + for (i = 0; i < descriptor_node->operand_count; ++i) + { +@@ -3498,7 +4005,18 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, + return VKD3D_ERROR_INVALID_SHADER; + } + +- if (!sm6_metadata_get_uint_value(sm6, node->operands[0], ®ister_id)) ++ if (!vkd3d_array_reserve((void **)&sm6->descriptors, &sm6->descriptor_capacity, ++ sm6->descriptor_count + 1, sizeof(*sm6->descriptors))) ++ { ++ ERR("Failed to allocate descriptor array.\n"); ++ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, ++ "Out of memory allocating the descriptor array."); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ d = &sm6->descriptors[sm6->descriptor_count]; ++ d->type = type; ++ ++ if (!sm6_metadata_get_uint_value(sm6, node->operands[0], &d->id)) + { + WARN("Failed to load resource id.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, +@@ -3506,7 +4024,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, + return VKD3D_ERROR_INVALID_SHADER; + } + +- if (!sm6_parser_resources_load_register_range(sm6, node, &range)) ++ if (!sm6_parser_resources_load_register_range(sm6, node, &d->range)) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource register range is invalid."); +@@ -3522,7 +4040,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, + switch (type) + { + case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: +- if ((ret = sm6_parser_resources_load_cbv(sm6, node, &range, register_id, ins)) < 0) ++ if ((ret = sm6_parser_resources_load_cbv(sm6, node, d, ins)) < 0) + return ret; + break; + default: +@@ -3532,6 +4050,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, + return VKD3D_ERROR_INVALID_SHADER; + } + ++ ++sm6->descriptor_count; + ++sm6->p.instructions.count; + } + +@@ -3779,10 +4298,12 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + return VKD3D_ERROR_INVALID_SHADER; + } + +- e->mask = vkd3d_write_mask_from_component_count(column_count) << index; ++ e->mask = vkd3d_write_mask_from_component_count(column_count); + e->used_mask = e->mask; ++ e->mask <<= index; + + signature_element_read_additional_element_values(e, element_node, sm6); ++ e->used_mask <<= index; + + m = element_node->operands[4]; + if (!sm6_metadata_value_is_node(m)) +@@ -3857,7 +4378,7 @@ static void sm6_parser_emit_global_flags(struct sm6_parser *sm6, const struct sm + enum vkd3d_shader_global_flags global_flags, mask, rotated_flags; + struct vkd3d_shader_instruction *ins; + +- if (!sm6_metadata_get_uint64_value(sm6, m, &global_flags)) ++ if (!sm6_metadata_get_uint64_value(sm6, m, (uint64_t*)&global_flags)) + { + WARN("Failed to load global flags.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, +@@ -4132,6 +4653,7 @@ static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) + sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); + sm6_functions_cleanup(sm6->functions, sm6->function_count); + sm6_parser_metadata_cleanup(sm6); ++ vkd3d_free(sm6->descriptors); + vkd3d_free(sm6->values); + free_shader_desc(&parser->shader_desc); + vkd3d_free(sm6); +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +index 2d383bc2fb5..1d3fd0f7d83 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +@@ -249,14 +249,7 @@ static enum hlsl_regset type_get_regset(const struct hlsl_type *type) + + enum hlsl_regset hlsl_deref_get_regset(struct hlsl_ctx *ctx, const struct hlsl_deref *deref) + { +- struct hlsl_type *type; +- +- if (deref->data_type) +- type = deref->data_type; +- else +- type = hlsl_deref_get_type(ctx, deref); +- +- return type_get_regset(type); ++ return type_get_regset(hlsl_deref_get_type(ctx, deref)); + } + + unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset) +@@ -519,7 +512,9 @@ static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hl + { + deref->var = var; + deref->path_len = path_len; +- deref->offset.node = NULL; ++ deref->rel_offset.node = NULL; ++ deref->const_offset = 0; ++ deref->data_type = NULL; + + if (path_len == 0) + { +@@ -546,7 +541,8 @@ bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *d + + deref->path = NULL; + deref->path_len = 0; +- deref->offset.node = NULL; ++ deref->rel_offset.node = NULL; ++ deref->const_offset = 0; + + assert(chain); + if (chain->type == HLSL_IR_INDEX) +@@ -609,7 +605,7 @@ struct hlsl_type *hlsl_deref_get_type(struct hlsl_ctx *ctx, const struct hlsl_de + + assert(deref); + +- if (deref->offset.node) ++ if (hlsl_deref_is_lowered(deref)) + return deref->data_type; + + type = deref->var->data_type; +@@ -763,7 +759,7 @@ struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim + { + struct hlsl_type *type; + +- if (!(type = vkd3d_calloc(1, sizeof(*type)))) ++ if (!(type = hlsl_alloc(ctx, sizeof(*type)))) + return NULL; + type->class = HLSL_CLASS_OBJECT; + type->base_type = HLSL_TYPE_UAV; +@@ -1120,7 +1116,7 @@ bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struc + if (!other) + return true; + +- assert(!other->offset.node); ++ assert(!hlsl_deref_is_lowered(other)); + + if (!init_deref(ctx, deref, other->var, other->path_len)) + return false; +@@ -1142,7 +1138,8 @@ void hlsl_cleanup_deref(struct hlsl_deref *deref) + deref->path = NULL; + deref->path_len = 0; + +- hlsl_src_remove(&deref->offset); ++ hlsl_src_remove(&deref->rel_offset); ++ deref->const_offset = 0; + } + + /* Initializes a simple variable dereference, so that it can be passed to load/store functions. */ +@@ -1177,7 +1174,7 @@ struct hlsl_ir_node *hlsl_new_store_index(struct hlsl_ctx *ctx, const struct hls + unsigned int i; + + assert(lhs); +- assert(!lhs->offset.node); ++ assert(!hlsl_deref_is_lowered(lhs)); + + if (!(store = hlsl_alloc(ctx, sizeof(*store)))) + return NULL; +@@ -1343,6 +1340,40 @@ struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *cond + return &iff->node; + } + ++struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned int value, ++ bool is_default, struct hlsl_block *body, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_switch_case *c; ++ ++ if (!(c = hlsl_alloc(ctx, sizeof(*c)))) ++ return NULL; ++ ++ c->value = value; ++ c->is_default = is_default; ++ hlsl_block_init(&c->body); ++ if (body) ++ hlsl_block_add_block(&c->body, body); ++ c->loc = *loc; ++ ++ return c; ++} ++ ++struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node *selector, ++ struct list *cases, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_switch *s; ++ ++ if (!(s = hlsl_alloc(ctx, sizeof(*s)))) ++ return NULL; ++ init_node(&s->node, HLSL_IR_SWITCH, NULL, loc); ++ hlsl_src_from_node(&s->selector, selector); ++ list_init(&s->cases); ++ if (cases) ++ list_move_head(&s->cases, cases); ++ ++ return &s->node; ++} ++ + struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, + struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc) + { +@@ -1350,7 +1381,7 @@ struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl + struct hlsl_type *type; + unsigned int i; + +- assert(!deref->offset.node); ++ assert(!hlsl_deref_is_lowered(deref)); + + type = hlsl_deref_get_type(ctx, deref); + if (idx) +@@ -1586,7 +1617,7 @@ static bool clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block, + + if (!list_empty(&src->uses)) + { +- if (!vkd3d_array_reserve((void **)&map->instrs, &map->capacity, map->count + 1, sizeof(*map->instrs))) ++ if (!hlsl_array_reserve(ctx, (void **)&map->instrs, &map->capacity, map->count + 1, sizeof(*map->instrs))) + { + hlsl_block_cleanup(dst_block); + return false; +@@ -1623,7 +1654,7 @@ static bool clone_deref(struct hlsl_ctx *ctx, struct clone_instr_map *map, + { + unsigned int i; + +- assert(!src->offset.node); ++ assert(!hlsl_deref_is_lowered(src)); + + if (!init_deref(ctx, dst, src->var, src->path_len)) + return false; +@@ -1805,6 +1836,58 @@ static struct hlsl_ir_node *clone_index(struct hlsl_ctx *ctx, struct clone_instr + return dst; + } + ++void hlsl_free_ir_switch_case(struct hlsl_ir_switch_case *c) ++{ ++ hlsl_block_cleanup(&c->body); ++ list_remove(&c->entry); ++ vkd3d_free(c); ++} ++ ++void hlsl_cleanup_ir_switch_cases(struct list *cases) ++{ ++ struct hlsl_ir_switch_case *c, *next; ++ ++ LIST_FOR_EACH_ENTRY_SAFE(c, next, cases, struct hlsl_ir_switch_case, entry) ++ { ++ hlsl_free_ir_switch_case(c); ++ } ++} ++ ++static struct hlsl_ir_node *clone_switch(struct hlsl_ctx *ctx, ++ struct clone_instr_map *map, struct hlsl_ir_switch *s) ++{ ++ struct hlsl_ir_switch_case *c, *d; ++ struct hlsl_ir_node *ret; ++ struct hlsl_block body; ++ struct list cases; ++ ++ list_init(&cases); ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ if (!(clone_block(ctx, &body, &c->body, map))) ++ { ++ hlsl_cleanup_ir_switch_cases(&cases); ++ return NULL; ++ } ++ ++ d = hlsl_new_switch_case(ctx, c->value, c->is_default, &body, &c->loc); ++ hlsl_block_cleanup(&body); ++ if (!d) ++ { ++ hlsl_cleanup_ir_switch_cases(&cases); ++ return NULL; ++ } ++ ++ list_add_tail(&cases, &d->entry); ++ } ++ ++ ret = hlsl_new_switch(ctx, map_instr(map, s->selector.node), &cases, &s->node.loc); ++ hlsl_cleanup_ir_switch_cases(&cases); ++ ++ return ret; ++} ++ + static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, + struct clone_instr_map *map, const struct hlsl_ir_node *instr) + { +@@ -1843,6 +1926,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, + case HLSL_IR_STORE: + return clone_store(ctx, map, hlsl_ir_store(instr)); + ++ case HLSL_IR_SWITCH: ++ return clone_switch(ctx, map, hlsl_ir_switch(instr)); ++ + case HLSL_IR_SWIZZLE: + return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr)); + } +@@ -2261,6 +2347,7 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) + [HLSL_IR_RESOURCE_LOAD ] = "HLSL_IR_RESOURCE_LOAD", + [HLSL_IR_RESOURCE_STORE] = "HLSL_IR_RESOURCE_STORE", + [HLSL_IR_STORE ] = "HLSL_IR_STORE", ++ [HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH", + [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", + }; + +@@ -2327,21 +2414,34 @@ static void dump_deref(struct vkd3d_string_buffer *buffer, const struct hlsl_der + if (deref->var) + { + vkd3d_string_buffer_printf(buffer, "%s", deref->var->name); +- if (deref->path_len) ++ if (!hlsl_deref_is_lowered(deref)) + { +- vkd3d_string_buffer_printf(buffer, "["); +- for (i = 0; i < deref->path_len; ++i) ++ if (deref->path_len) + { + vkd3d_string_buffer_printf(buffer, "["); +- dump_src(buffer, &deref->path[i]); ++ for (i = 0; i < deref->path_len; ++i) ++ { ++ vkd3d_string_buffer_printf(buffer, "["); ++ dump_src(buffer, &deref->path[i]); ++ vkd3d_string_buffer_printf(buffer, "]"); ++ } + vkd3d_string_buffer_printf(buffer, "]"); + } +- vkd3d_string_buffer_printf(buffer, "]"); + } +- else if (deref->offset.node) ++ else + { ++ bool show_rel, show_const; ++ ++ show_rel = deref->rel_offset.node; ++ show_const = deref->const_offset != 0 || !show_rel; ++ + vkd3d_string_buffer_printf(buffer, "["); +- dump_src(buffer, &deref->offset); ++ if (show_rel) ++ dump_src(buffer, &deref->rel_offset); ++ if (show_rel && show_const) ++ vkd3d_string_buffer_printf(buffer, " + "); ++ if (show_const) ++ vkd3d_string_buffer_printf(buffer, "%uc", deref->const_offset); + vkd3d_string_buffer_printf(buffer, "]"); + } + } +@@ -2685,6 +2785,32 @@ static void dump_ir_index(struct vkd3d_string_buffer *buffer, const struct hlsl_ + vkd3d_string_buffer_printf(buffer, "]"); + } + ++static void dump_ir_switch(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_switch *s) ++{ ++ struct hlsl_ir_switch_case *c; ++ ++ vkd3d_string_buffer_printf(buffer, "switch ("); ++ dump_src(buffer, &s->selector); ++ vkd3d_string_buffer_printf(buffer, ") {\n"); ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ if (c->is_default) ++ { ++ vkd3d_string_buffer_printf(buffer, " %10s default: {\n", ""); ++ } ++ else ++ { ++ vkd3d_string_buffer_printf(buffer, " %10s case %u : {\n", "", c->value); ++ } ++ ++ dump_block(ctx, buffer, &c->body); ++ vkd3d_string_buffer_printf(buffer, " %10s }\n", ""); ++ } ++ ++ vkd3d_string_buffer_printf(buffer, " %10s }", ""); ++} ++ + static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_node *instr) + { + if (instr->index) +@@ -2740,6 +2866,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, + dump_ir_store(buffer, hlsl_ir_store(instr)); + break; + ++ case HLSL_IR_SWITCH: ++ dump_ir_switch(ctx, buffer, hlsl_ir_switch(instr)); ++ break; ++ + case HLSL_IR_SWIZZLE: + dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr)); + break; +@@ -2881,7 +3011,7 @@ static void free_ir_resource_load(struct hlsl_ir_resource_load *load) + + static void free_ir_resource_store(struct hlsl_ir_resource_store *store) + { +- hlsl_src_remove(&store->resource.offset); ++ hlsl_src_remove(&store->resource.rel_offset); + hlsl_src_remove(&store->coords); + hlsl_src_remove(&store->value); + vkd3d_free(store); +@@ -2900,6 +3030,14 @@ static void free_ir_swizzle(struct hlsl_ir_swizzle *swizzle) + vkd3d_free(swizzle); + } + ++static void free_ir_switch(struct hlsl_ir_switch *s) ++{ ++ hlsl_src_remove(&s->selector); ++ hlsl_cleanup_ir_switch_cases(&s->cases); ++ ++ vkd3d_free(s); ++} ++ + static void free_ir_index(struct hlsl_ir_index *index) + { + hlsl_src_remove(&index->val); +@@ -2960,6 +3098,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) + case HLSL_IR_SWIZZLE: + free_ir_swizzle(hlsl_ir_swizzle(node)); + break; ++ ++ case HLSL_IR_SWITCH: ++ free_ir_switch(hlsl_ir_switch(node)); ++ break; + } + } + +@@ -3118,7 +3260,7 @@ unsigned int hlsl_combine_swizzles(unsigned int first, unsigned int second, unsi + return ret; + } + +-static const struct hlsl_profile_info *get_target_info(const char *target) ++const struct hlsl_profile_info *hlsl_get_target_info(const char *target) + { + unsigned int i; + +@@ -3485,14 +3627,12 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d + } + entry_point = hlsl_source_info->entry_point ? hlsl_source_info->entry_point : "main"; + +- if (!(profile = get_target_info(hlsl_source_info->profile))) ++ if (!(profile = hlsl_get_target_info(hlsl_source_info->profile))) + { + FIXME("Unknown compilation target %s.\n", debugstr_a(hlsl_source_info->profile)); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + +- vkd3d_shader_dump_shader(compile_info->source_type, profile->type, &compile_info->source); +- + if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_BYTECODE && profile->major_version > 3) + { + vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE, +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +index ea2117e5128..3d8f5aed174 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +@@ -281,6 +281,7 @@ enum hlsl_ir_node_type + HLSL_IR_RESOURCE_STORE, + HLSL_IR_STORE, + HLSL_IR_SWIZZLE, ++ HLSL_IR_SWITCH, + }; + + /* Common data for every type of IR instruction node. */ +@@ -424,6 +425,9 @@ struct hlsl_ir_var + * It may be less than the allocation size, e.g. for texture arrays. */ + unsigned int bind_count[HLSL_REGSET_LAST_OBJECT + 1]; + ++ /* Whether the shader performs dereferences with non-constant offsets in the variable. */ ++ bool indexable; ++ + uint32_t is_input_semantic : 1; + uint32_t is_output_semantic : 1; + uint32_t is_uniform : 1; +@@ -499,6 +503,22 @@ struct hlsl_ir_loop + unsigned int next_index; /* liveness index of the end of the loop */ + }; + ++struct hlsl_ir_switch_case ++{ ++ unsigned int value; ++ bool is_default; ++ struct hlsl_block body; ++ struct list entry; ++ struct vkd3d_shader_location loc; ++}; ++ ++struct hlsl_ir_switch ++{ ++ struct hlsl_ir_node node; ++ struct hlsl_src selector; ++ struct list cases; ++}; ++ + enum hlsl_ir_expr_op + { + HLSL_OP0_VOID, +@@ -621,17 +641,25 @@ struct hlsl_deref + unsigned int path_len; + struct hlsl_src *path; + +- /* Single instruction node of data type uint used to represent the register offset (in register +- * 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, deref paths are lowered into an offset (within the pertaining ++ * regset) from the start of the variable, to the part of the variable that is referenced. ++ * This offset is stored using two fields, one for a variable part and other for a constant ++ * part, which are added together: ++ * - rel_offset: An offset given by an instruction node, in whole registers. ++ * - const_offset: A constant number of register components. + * 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; ++ * stored in the data_type field, which remains NULL if the deref hasn't been lowered yet. */ ++ struct hlsl_src rel_offset; ++ unsigned int const_offset; + struct hlsl_type *data_type; + }; + ++/* Whether the path has been lowered to an offset or not. */ ++static inline bool hlsl_deref_is_lowered(const struct hlsl_deref *deref) ++{ ++ return !!deref->data_type; ++} ++ + struct hlsl_ir_load + { + struct hlsl_ir_node node; +@@ -710,6 +738,8 @@ struct hlsl_scope + struct hlsl_scope *upper; + /* The scope was created for the loop statement. */ + bool loop; ++ /* The scope was created for the switch statement. */ ++ bool _switch; + }; + + struct hlsl_profile_info +@@ -947,6 +977,12 @@ static inline struct hlsl_ir_index *hlsl_ir_index(const struct hlsl_ir_node *nod + return CONTAINING_RECORD(node, struct hlsl_ir_index, node); + } + ++static inline struct hlsl_ir_switch *hlsl_ir_switch(const struct hlsl_ir_node *node) ++{ ++ assert(node->type == HLSL_IR_SWITCH); ++ return CONTAINING_RECORD(node, struct hlsl_ir_switch, node); ++} ++ + static inline void hlsl_block_init(struct hlsl_block *block) + { + list_init(&block->instrs); +@@ -1120,6 +1156,9 @@ bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struc + void hlsl_cleanup_deref(struct hlsl_deref *deref); + void hlsl_cleanup_semantic(struct hlsl_semantic *semantic); + ++void hlsl_cleanup_ir_switch_cases(struct list *cases); ++void hlsl_free_ir_switch_case(struct hlsl_ir_switch_case *c); ++ + void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new); + + void hlsl_free_attribute(struct hlsl_attribute *attr); +@@ -1130,6 +1169,7 @@ void hlsl_free_var(struct hlsl_ir_var *decl); + + struct hlsl_ir_function *hlsl_get_function(struct hlsl_ctx *ctx, const char *name); + struct hlsl_ir_function_decl *hlsl_get_func_decl(struct hlsl_ctx *ctx, const char *name); ++const struct hlsl_profile_info *hlsl_get_target_info(const char *target); + struct hlsl_type *hlsl_get_type(struct hlsl_scope *scope, const char *name, bool recursive, bool case_insensitive); + struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name); + +@@ -1213,6 +1253,10 @@ struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr + struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type, + const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, unsigned int modifiers, + const struct hlsl_reg_reservation *reg_reservation); ++struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned int value, bool is_default, ++ struct hlsl_block *body, const struct vkd3d_shader_location *loc); ++struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node *selector, ++ struct list *cases, const struct vkd3d_shader_location *loc); + + void hlsl_error(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc, + enum vkd3d_shader_error error, const char *fmt, ...) VKD3D_PRINTF_FUNC(4, 5); +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.l b/libs/vkd3d/libs/vkd3d-shader/hlsl.l +index b3d4aeee839..0e5f2bb6134 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.l ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.l +@@ -46,14 +46,13 @@ static void update_location(struct hlsl_ctx *ctx, YYLTYPE *loc); + + %x pp pp_line pp_pragma pp_ignore + +-RESERVED1 auto|case|catch|char|class|const_cast|default|delete|dynamic_cast|enum ++RESERVED1 auto|catch|char|class|const_cast|delete|dynamic_cast|enum + RESERVED2 explicit|friend|goto|long|mutable|new|operator|private|protected|public + RESERVED3 reinterpret_cast|short|signed|sizeof|static_cast|template|this|throw|try + RESERVED4 typename|union|unsigned|using|virtual + + WS [ \t] + NEWLINE (\n)|(\r\n) +-DOUBLESLASHCOMMENT "//"[^\n]* + STRING \"[^\"]*\" + IDENTIFIER [A-Za-z_][A-Za-z0-9_]* + +@@ -73,13 +72,16 @@ ANY (.) + BlendState {return KW_BLENDSTATE; } + break {return KW_BREAK; } + Buffer {return KW_BUFFER; } ++case {return KW_CASE; } + cbuffer {return KW_CBUFFER; } + centroid {return KW_CENTROID; } ++column_major {return KW_COLUMN_MAJOR; } + compile {return KW_COMPILE; } + const {return KW_CONST; } + continue {return KW_CONTINUE; } + DepthStencilState {return KW_DEPTHSTENCILSTATE; } + DepthStencilView {return KW_DEPTHSTENCILVIEW; } ++default {return KW_DEFAULT; } + discard {return KW_DISCARD; } + do {return KW_DO; } + double {return KW_DOUBLE; } +@@ -103,9 +105,10 @@ pass {return KW_PASS; } + PixelShader {return KW_PIXELSHADER; } + precise {return KW_PRECISE; } + RasterizerState {return KW_RASTERIZERSTATE; } ++register {return KW_REGISTER; } + RenderTargetView {return KW_RENDERTARGETVIEW; } + return {return KW_RETURN; } +-register {return KW_REGISTER; } ++row_major {return KW_ROW_MAJOR; } + RWBuffer {return KW_RWBUFFER; } + RWStructuredBuffer {return KW_RWSTRUCTUREDBUFFER; } + RWTexture1D {return KW_RWTEXTURE1D; } +@@ -117,10 +120,10 @@ sampler {return KW_SAMPLER; } + sampler1D {return KW_SAMPLER1D; } + sampler2D {return KW_SAMPLER2D; } + sampler3D {return KW_SAMPLER3D; } +-samplerCUBE {return KW_SAMPLERCUBE; } +-sampler_state {return KW_SAMPLER_STATE; } + SamplerComparisonState {return KW_SAMPLERCOMPARISONSTATE;} ++samplerCUBE {return KW_SAMPLERCUBE; } + SamplerState {return KW_SAMPLER; } ++sampler_state {return KW_SAMPLER_STATE; } + shared {return KW_SHARED; } + stateblock {return KW_STATEBLOCK; } + stateblock_state {return KW_STATEBLOCK_STATE; } +@@ -129,21 +132,22 @@ string {return KW_STRING; } + struct {return KW_STRUCT; } + switch {return KW_SWITCH; } + tbuffer {return KW_TBUFFER; } +-technique {return KW_TECHNIQUE; } ++(?i:technique) {return KW_TECHNIQUE; } + technique10 {return KW_TECHNIQUE10; } ++technique11 {return KW_TECHNIQUE11; } + texture {return KW_TEXTURE; } +-texture1D {return KW_TEXTURE1D; } + Texture1D {return KW_TEXTURE1D; } ++texture1D {return KW_TEXTURE1D; } + Texture1DArray {return KW_TEXTURE1DARRAY; } +-texture2D {return KW_TEXTURE2D; } + Texture2D {return KW_TEXTURE2D; } ++texture2D {return KW_TEXTURE2D; } + Texture2DArray {return KW_TEXTURE2DARRAY; } + Texture2DMS {return KW_TEXTURE2DMS; } + Texture2DMSArray {return KW_TEXTURE2DMSARRAY; } +-texture3D {return KW_TEXTURE3D; } + Texture3D {return KW_TEXTURE3D; } +-textureCUBE {return KW_TEXTURECUBE; } ++texture3D {return KW_TEXTURE3D; } + TextureCube {return KW_TEXTURECUBE; } ++textureCUBE {return KW_TEXTURECUBE; } + TextureCubeArray {return KW_TEXTURECUBEARRAY; } + true {return KW_TRUE; } + typedef {return KW_TYPEDEF; } +@@ -163,7 +167,6 @@ while {return KW_WHILE; } + \<\<= {return OP_LEFTSHIFTASSIGN; } + \>\> {return OP_RIGHTSHIFT; } + \>\>= {return OP_RIGHTSHIFTASSIGN; } +-\.\.\. {return OP_ELLIPSIS; } + \<= {return OP_LE; } + \>= {return OP_GE; } + != {return OP_NE; } +@@ -175,13 +178,6 @@ while {return KW_WHILE; } + &= {return OP_ANDASSIGN; } + \|= {return OP_ORASSIGN; } + ^= {return OP_XORASSIGN; } +-## {return OP_UNKNOWN1; } +-#@ {return OP_UNKNOWN2; } +-:: {return OP_UNKNOWN3; } +-\-\> {return OP_UNKNOWN4; } +- +-column_major {return KW_COLUMN_MAJOR; } +-row_major {return KW_ROW_MAJOR; } + + {IDENTIFIER} { + struct hlsl_ctx *ctx = yyget_extra(yyscanner); +@@ -220,8 +216,6 @@ row_major {return KW_ROW_MAJOR; } + return C_INTEGER; + } + +-{DOUBLESLASHCOMMENT} {} +- + {WS}+ {} + {NEWLINE} { + struct hlsl_ctx *ctx = yyget_extra(yyscanner); +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +index e58574f7560..0e72a539e3f 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +@@ -162,6 +162,12 @@ static void destroy_block(struct hlsl_block *block) + vkd3d_free(block); + } + ++static void destroy_switch_cases(struct list *cases) ++{ ++ hlsl_cleanup_ir_switch_cases(cases); ++ vkd3d_free(cases); ++} ++ + static bool hlsl_types_are_componentwise_compatible(struct hlsl_ctx *ctx, struct hlsl_type *src, + struct hlsl_type *dst) + { +@@ -508,6 +514,28 @@ static void resolve_loop_continue(struct hlsl_ctx *ctx, struct hlsl_block *block + } + } + ++static void check_loop_attributes(struct hlsl_ctx *ctx, const struct parse_attribute_list *attributes, ++ const struct vkd3d_shader_location *loc) ++{ ++ bool has_unroll = false, has_loop = false, has_fastopt = false; ++ unsigned int i; ++ ++ for (i = 0; i < attributes->count; ++i) ++ { ++ const char *name = attributes->attrs[i]->name; ++ ++ has_loop |= !strcmp(name, "loop"); ++ has_unroll |= !strcmp(name, "unroll"); ++ has_fastopt |= !strcmp(name, "fastopt"); ++ } ++ ++ if (has_unroll && has_loop) ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Unroll attribute can't be used with 'loop' attribute."); ++ ++ if (has_unroll && has_fastopt) ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Unroll attribute can't be used with 'fastopt' attribute."); ++} ++ + static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type, + const struct parse_attribute_list *attributes, struct hlsl_block *init, struct hlsl_block *cond, + struct hlsl_block *iter, struct hlsl_block *body, const struct vkd3d_shader_location *loc) +@@ -518,6 +546,8 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type, + if (attribute_list_has_duplicates(attributes)) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Found duplicate attribute."); + ++ check_loop_attributes(ctx, attributes, loc); ++ + /* Ignore unroll(0) attribute, and any invalid attribute. */ + for (i = 0; i < attributes->count; ++i) + { +@@ -533,8 +563,11 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type, + hlsl_warning(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_IMPLEMENTED, "Loop unrolling is not implemented."); + } + } +- else if (!strcmp(attr->name, "loop") +- || !strcmp(attr->name, "fastopt") ++ else if (!strcmp(attr->name, "loop")) ++ { ++ /* TODO: this attribute will be used to disable unrolling, once it's implememented. */ ++ } ++ else if (!strcmp(attr->name, "fastopt") + || !strcmp(attr->name, "allow_uav_condition")) + { + hlsl_fixme(ctx, loc, "Unhandled attribute '%s'.", attr->name); +@@ -1180,6 +1213,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str + case HLSL_IR_RESOURCE_LOAD: + case HLSL_IR_RESOURCE_STORE: + case HLSL_IR_STORE: ++ case HLSL_IR_SWITCH: + hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, + "Expected literal expression."); + } +@@ -4633,12 +4667,64 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type + } + } + +-static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) ++static bool check_continue(struct hlsl_ctx *ctx, const struct hlsl_scope *scope, const struct vkd3d_shader_location *loc) + { ++ if (scope->_switch) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, ++ "The 'continue' statement is not allowed in 'switch' statements."); ++ return false; ++ } ++ + if (scope->loop) +- return scope; ++ return true; ++ ++ if (scope->upper) ++ return check_continue(ctx, scope->upper, loc); ++ ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'continue' statement is only allowed in loops."); ++ return false; ++} ++ ++static bool is_break_allowed(const struct hlsl_scope *scope) ++{ ++ if (scope->loop || scope->_switch) ++ return true; ++ ++ return scope->upper ? is_break_allowed(scope->upper) : false; ++} ++ ++static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hlsl_ir_switch_case *check, struct list *cases) ++{ ++ struct hlsl_ir_switch_case *c; ++ bool found_duplicate = false; + +- return scope->upper ? get_loop_scope(scope->upper) : NULL; ++ LIST_FOR_EACH_ENTRY(c, cases, struct hlsl_ir_switch_case, entry) ++ { ++ if (check->is_default) ++ { ++ if ((found_duplicate = c->is_default)) ++ { ++ hlsl_error(ctx, &check->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_SWITCH_CASE, ++ "Found multiple 'default' statements."); ++ hlsl_note(ctx, &c->loc, VKD3D_SHADER_LOG_ERROR, "The 'default' statement was previously found here."); ++ } ++ } ++ else ++ { ++ if (c->is_default) continue; ++ if ((found_duplicate = (c->value == check->value))) ++ { ++ hlsl_error(ctx, &check->loc, VKD3D_SHADER_ERROR_HLSL_DUPLICATE_SWITCH_CASE, ++ "Found duplicate 'case' statement."); ++ hlsl_note(ctx, &c->loc, VKD3D_SHADER_LOG_ERROR, "The same 'case %d' statement was previously found here.", ++ c->value); ++ } ++ } ++ ++ if (found_duplicate) ++ break; ++ } + } + + } +@@ -4679,17 +4765,20 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + enum hlsl_sampler_dim sampler_dim; + struct hlsl_attribute *attr; + struct parse_attribute_list attr_list; ++ struct hlsl_ir_switch_case *switch_case; + } + + %token KW_BLENDSTATE + %token KW_BREAK + %token KW_BUFFER ++%token KW_CASE + %token KW_CBUFFER + %token KW_CENTROID + %token KW_COLUMN_MAJOR + %token KW_COMPILE + %token KW_CONST + %token KW_CONTINUE ++%token KW_DEFAULT + %token KW_DEPTHSTENCILSTATE + %token KW_DEPTHSTENCILVIEW + %token KW_DISCARD +@@ -4743,6 +4832,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + %token KW_TBUFFER + %token KW_TECHNIQUE + %token KW_TECHNIQUE10 ++%token KW_TECHNIQUE11 + %token KW_TEXTURE + %token KW_TEXTURE1D + %token KW_TEXTURE1DARRAY +@@ -4771,7 +4861,6 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + %token OP_LEFTSHIFTASSIGN + %token OP_RIGHTSHIFT + %token OP_RIGHTSHIFTASSIGN +-%token OP_ELLIPSIS + %token OP_LE + %token OP_GE + %token OP_NE +@@ -4783,10 +4872,6 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + %token OP_ANDASSIGN + %token OP_ORASSIGN + %token OP_XORASSIGN +-%token OP_UNKNOWN1 +-%token OP_UNKNOWN2 +-%token OP_UNKNOWN3 +-%token OP_UNKNOWN4 + + %token C_FLOAT + +@@ -4796,6 +4881,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + %type type_specs + %type variables_def + %type variables_def_typed ++%type switch_cases + + %token VAR_IDENTIFIER + %token NEW_IDENTIFIER +@@ -4838,6 +4924,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + %type statement + %type statement_list + %type struct_declaration_without_vars ++%type switch_statement + %type unary_expr + + %type boolean +@@ -4863,6 +4950,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + + %type any_identifier + %type var_identifier ++%type technique_name + + %type parameter + +@@ -4876,6 +4964,8 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) + + %type semantic + ++%type switch_case ++ + %type field_type + %type named_struct_spec + %type unnamed_struct_spec +@@ -4902,8 +4992,50 @@ hlsl_prog: + destroy_block($2); + } + | hlsl_prog preproc_directive ++ | hlsl_prog technique + | hlsl_prog ';' + ++technique_name: ++ %empty ++ { ++ $$ = NULL; ++ } ++ | any_identifier ++ ++pass_list: ++ %empty ++ ++technique9: ++ KW_TECHNIQUE technique_name '{' pass_list '}' ++ { ++ hlsl_fixme(ctx, &@$, "Unsupported \'technique\' declaration."); ++ } ++ ++technique10: ++ KW_TECHNIQUE10 technique_name '{' pass_list '}' ++ { ++ if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2) ++ hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, ++ "The 'technique10' keyword is invalid for this profile."); ++ ++ hlsl_fixme(ctx, &@$, "Unsupported \'technique10\' declaration."); ++ } ++ ++technique11: ++ KW_TECHNIQUE11 technique_name '{' pass_list '}' ++ { ++ if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2) ++ hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, ++ "The 'technique11' keyword is invalid for this profile."); ++ ++ hlsl_fixme(ctx, &@$, "Unsupported \'technique11\' declaration."); ++ } ++ ++technique: ++ technique9 ++ | technique10 ++ | technique11 ++ + buffer_declaration: + buffer_type any_identifier colon_attribute + { +@@ -5357,6 +5489,13 @@ loop_scope_start: + ctx->cur_scope->loop = true; + } + ++switch_scope_start: ++ %empty ++ { ++ hlsl_push_scope(ctx); ++ ctx->cur_scope->_switch = true; ++ } ++ + var_identifier: + VAR_IDENTIFIER + | NEW_IDENTIFIER +@@ -6185,18 +6324,17 @@ statement: + | jump_statement + | selection_statement + | loop_statement ++ | switch_statement + + jump_statement: + KW_BREAK ';' + { + struct hlsl_ir_node *jump; + +- /* TODO: allow 'break' in the 'switch' statements. */ +- +- if (!get_loop_scope(ctx->cur_scope)) ++ if (!is_break_allowed(ctx->cur_scope)) + { + hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, +- "The 'break' statement must be used inside of a loop."); ++ "The 'break' statement must be used inside of a loop or a switch."); + } + + if (!($$ = make_empty_block(ctx))) +@@ -6208,13 +6346,8 @@ jump_statement: + | KW_CONTINUE ';' + { + struct hlsl_ir_node *jump; +- struct hlsl_scope *scope; + +- if (!(scope = get_loop_scope(ctx->cur_scope))) +- { +- hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, +- "The 'continue' statement must be used inside of a loop."); +- } ++ check_continue(ctx, ctx->cur_scope, &@1); + + if (!($$ = make_empty_block(ctx))) + YYABORT; +@@ -6333,6 +6466,106 @@ loop_statement: + hlsl_pop_scope(ctx); + } + ++switch_statement: ++ attribute_list_optional switch_scope_start KW_SWITCH '(' expr ')' '{' switch_cases '}' ++ { ++ struct hlsl_ir_node *selector = node_from_block($5); ++ struct hlsl_ir_node *s; ++ ++ if (!(selector = add_implicit_conversion(ctx, $5, selector, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), &@5))) ++ { ++ destroy_switch_cases($8); ++ destroy_block($5); ++ YYABORT; ++ } ++ ++ s = hlsl_new_switch(ctx, selector, $8, &@3); ++ ++ destroy_switch_cases($8); ++ ++ if (!s) ++ { ++ destroy_block($5); ++ YYABORT; ++ } ++ ++ $$ = $5; ++ hlsl_block_add_instr($$, s); ++ ++ hlsl_pop_scope(ctx); ++ } ++ ++switch_case: ++ KW_CASE expr ':' statement_list ++ { ++ struct hlsl_ir_switch_case *c; ++ unsigned int value; ++ ++ value = evaluate_static_expression_as_uint(ctx, $2, &@2); ++ ++ c = hlsl_new_switch_case(ctx, value, false, $4, &@2); ++ ++ destroy_block($2); ++ destroy_block($4); ++ ++ if (!c) ++ YYABORT; ++ $$ = c; ++ } ++ | KW_CASE expr ':' ++ { ++ struct hlsl_ir_switch_case *c; ++ unsigned int value; ++ ++ value = evaluate_static_expression_as_uint(ctx, $2, &@2); ++ ++ c = hlsl_new_switch_case(ctx, value, false, NULL, &@2); ++ ++ destroy_block($2); ++ ++ if (!c) ++ YYABORT; ++ $$ = c; ++ } ++ | KW_DEFAULT ':' statement_list ++ { ++ struct hlsl_ir_switch_case *c; ++ ++ c = hlsl_new_switch_case(ctx, 0, true, $3, &@1); ++ ++ destroy_block($3); ++ ++ if (!c) ++ YYABORT; ++ $$ = c; ++ } ++ | KW_DEFAULT ':' ++ { ++ struct hlsl_ir_switch_case *c; ++ ++ if (!(c = hlsl_new_switch_case(ctx, 0, true, NULL, &@1))) ++ YYABORT; ++ $$ = c; ++ } ++ ++switch_cases: ++ switch_case ++ { ++ struct hlsl_ir_switch_case *c = LIST_ENTRY($1, struct hlsl_ir_switch_case, entry); ++ if (!($$ = make_empty_list(ctx))) ++ { ++ hlsl_free_ir_switch_case(c); ++ YYABORT; ++ } ++ list_add_head($$, &$1->entry); ++ } ++ | switch_cases switch_case ++ { ++ $$ = $1; ++ check_duplicated_switch_cases(ctx, $2, $$); ++ list_add_tail($$, &$2->entry); ++ } ++ + expr_optional: + %empty + { +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +index 7d17ca8cec6..6eac5d490c3 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +@@ -23,30 +23,21 @@ + + /* TODO: remove when no longer needed, only used for new_offset_instr_from_deref() */ + static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, struct hlsl_block *block, +- struct hlsl_type *type, struct hlsl_ir_node *offset, struct hlsl_ir_node *idx, +- enum hlsl_regset regset, const struct vkd3d_shader_location *loc) ++ struct hlsl_type *type, struct hlsl_ir_node *base_offset, struct hlsl_ir_node *idx, ++ enum hlsl_regset regset, unsigned int *offset_component, const struct vkd3d_shader_location *loc) + { + struct hlsl_ir_node *idx_offset = NULL; + struct hlsl_ir_node *c; + +- hlsl_block_init(block); +- + switch (type->class) + { + case HLSL_CLASS_VECTOR: +- idx_offset = idx; ++ *offset_component += hlsl_ir_constant(idx)->value.u[0].u; + break; + + case HLSL_CLASS_MATRIX: + { +- if (!(c = hlsl_new_uint_constant(ctx, 4, loc))) +- return NULL; +- hlsl_block_add_instr(block, c); +- +- if (!(idx_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, c, idx))) +- return NULL; +- hlsl_block_add_instr(block, idx_offset); +- ++ idx_offset = idx; + break; + } + +@@ -54,6 +45,12 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str + { + unsigned int size = hlsl_type_get_array_element_reg_size(type->e.array.type, regset); + ++ if (regset == HLSL_REGSET_NUMERIC) ++ { ++ assert(size % 4 == 0); ++ size /= 4; ++ } ++ + if (!(c = hlsl_new_uint_constant(ctx, size, loc))) + return NULL; + hlsl_block_add_instr(block, c); +@@ -69,8 +66,16 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str + { + unsigned int field_idx = hlsl_ir_constant(idx)->value.u[0].u; + struct hlsl_struct_field *field = &type->e.record.fields[field_idx]; ++ unsigned int field_offset = field->reg_offset[regset]; ++ ++ if (regset == HLSL_REGSET_NUMERIC) ++ { ++ assert(*offset_component == 0); ++ *offset_component = field_offset % 4; ++ field_offset /= 4; ++ } + +- if (!(c = hlsl_new_uint_constant(ctx, field->reg_offset[regset], loc))) ++ if (!(c = hlsl_new_uint_constant(ctx, field_offset, loc))) + return NULL; + hlsl_block_add_instr(block, c); + +@@ -83,27 +88,33 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str + vkd3d_unreachable(); + } + +- if (offset) ++ if (idx_offset) + { +- if (!(idx_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, offset, idx_offset))) ++ if (!(base_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, base_offset, idx_offset))) + return NULL; +- hlsl_block_add_instr(block, idx_offset); ++ hlsl_block_add_instr(block, base_offset); + } + +- return idx_offset; ++ return base_offset; + } + + /* TODO: remove when no longer needed, only used for replace_deref_path_with_offset() */ + 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) ++ const struct hlsl_deref *deref, unsigned int *offset_component, const struct vkd3d_shader_location *loc) + { + enum hlsl_regset regset = hlsl_deref_get_regset(ctx, deref); +- struct hlsl_ir_node *offset = NULL; ++ struct hlsl_ir_node *offset; + struct hlsl_type *type; + unsigned int i; + ++ *offset_component = 0; ++ + hlsl_block_init(block); + ++ if (!(offset = hlsl_new_uint_constant(ctx, 0, loc))) ++ return NULL; ++ hlsl_block_add_instr(block, offset); ++ + assert(deref->var); + type = deref->var->data_type; + +@@ -111,9 +122,14 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st + { + struct hlsl_block idx_block; + ++ hlsl_block_init(&idx_block); ++ + if (!(offset = new_offset_from_path_index(ctx, &idx_block, type, offset, deref->path[i].node, +- regset, loc))) ++ regset, offset_component, loc))) ++ { ++ hlsl_block_cleanup(&idx_block); + return NULL; ++ } + + hlsl_block_add_block(block, &idx_block); + +@@ -127,14 +143,13 @@ 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) + { +- struct hlsl_type *type; ++ unsigned int offset_component; + struct hlsl_ir_node *offset; + struct hlsl_block block; ++ struct hlsl_type *type; + + assert(deref->var); +- +- /* register offsets shouldn't be used before this point is reached. */ +- assert(!deref->offset.node); ++ assert(!hlsl_deref_is_lowered(deref)); + + type = hlsl_deref_get_type(ctx, deref); + +@@ -148,16 +163,35 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der + + deref->data_type = type; + +- if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &instr->loc))) ++ if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &offset_component, &instr->loc))) + return false; + list_move_before(&instr->entry, &block.instrs); + + hlsl_cleanup_deref(deref); +- hlsl_src_from_node(&deref->offset, offset); ++ hlsl_src_from_node(&deref->rel_offset, offset); ++ deref->const_offset = offset_component; + + return true; + } + ++static bool clean_constant_deref_offset_srcs(struct hlsl_ctx *ctx, struct hlsl_deref *deref, ++ struct hlsl_ir_node *instr) ++{ ++ if (deref->rel_offset.node && deref->rel_offset.node->type == HLSL_IR_CONSTANT) ++ { ++ enum hlsl_regset regset = hlsl_deref_get_regset(ctx, deref); ++ ++ if (regset == HLSL_REGSET_NUMERIC) ++ deref->const_offset += 4 * hlsl_ir_constant(deref->rel_offset.node)->value.u[0].u; ++ else ++ deref->const_offset += hlsl_ir_constant(deref->rel_offset.node)->value.u[0].u; ++ hlsl_src_remove(&deref->rel_offset); ++ return true; ++ } ++ return false; ++} ++ ++ + /* Split uniforms into two variables representing the constant and temp + * registers, and copy the former to the latter, so that writes to uniforms + * work. */ +@@ -575,7 +609,19 @@ bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, + progress |= hlsl_transform_ir(ctx, func, &iff->else_block, context); + } + else if (instr->type == HLSL_IR_LOOP) ++ { + progress |= hlsl_transform_ir(ctx, func, &hlsl_ir_loop(instr)->body, context); ++ } ++ else if (instr->type == HLSL_IR_SWITCH) ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ progress |= hlsl_transform_ir(ctx, func, &c->body, context); ++ } ++ } + + progress |= func(ctx, instr, context); + } +@@ -835,6 +881,30 @@ static bool lower_return(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fun + } + } + } ++ else if (instr->type == HLSL_IR_SWITCH) ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ has_early_return |= lower_return(ctx, func, &c->body, true); ++ } ++ ++ if (has_early_return) ++ { ++ if (in_loop) ++ { ++ /* For a 'switch' nested in a loop append a break after the 'switch'. */ ++ insert_early_return_break(ctx, func, instr); ++ } ++ else ++ { ++ cf_instr = instr; ++ break; ++ } ++ } ++ } + } + + if (return_instr) +@@ -1639,6 +1709,19 @@ static void copy_propagation_invalidate_from_block(struct hlsl_ctx *ctx, struct + break; + } + ++ case HLSL_IR_SWITCH: ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ copy_propagation_invalidate_from_block(ctx, state, &c->body); ++ } ++ ++ break; ++ } ++ + default: + break; + } +@@ -1687,6 +1770,28 @@ static bool copy_propagation_process_loop(struct hlsl_ctx *ctx, struct hlsl_ir_l + return progress; + } + ++static bool copy_propagation_process_switch(struct hlsl_ctx *ctx, struct hlsl_ir_switch *s, ++ struct copy_propagation_state *state) ++{ ++ struct copy_propagation_state inner_state; ++ struct hlsl_ir_switch_case *c; ++ bool progress = false; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ copy_propagation_state_init(ctx, &inner_state, state); ++ progress |= copy_propagation_transform_block(ctx, &c->body, &inner_state); ++ copy_propagation_state_destroy(&inner_state); ++ } ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ copy_propagation_invalidate_from_block(ctx, state, &c->body); ++ } ++ ++ return progress; ++} ++ + static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_block *block, + struct copy_propagation_state *state) + { +@@ -1725,6 +1830,10 @@ static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_b + progress |= copy_propagation_process_loop(ctx, hlsl_ir_loop(instr), state); + break; + ++ case HLSL_IR_SWITCH: ++ progress |= copy_propagation_process_switch(ctx, hlsl_ir_switch(instr), state); ++ break; ++ + default: + break; + } +@@ -2094,6 +2203,118 @@ static bool remove_trivial_conditional_branches(struct hlsl_ctx *ctx, struct hls + return true; + } + ++static bool normalize_switch_cases(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) ++{ ++ struct hlsl_ir_switch_case *c, *def = NULL; ++ bool missing_terminal_break = false; ++ struct hlsl_ir_node *node; ++ struct hlsl_ir_jump *jump; ++ struct hlsl_ir_switch *s; ++ ++ if (instr->type != HLSL_IR_SWITCH) ++ return false; ++ s = hlsl_ir_switch(instr); ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ bool terminal_break = false; ++ ++ if (list_empty(&c->body.instrs)) ++ { ++ terminal_break = !!list_next(&s->cases, &c->entry); ++ } ++ else ++ { ++ node = LIST_ENTRY(list_tail(&c->body.instrs), struct hlsl_ir_node, entry); ++ if (node->type == HLSL_IR_JUMP) ++ { ++ jump = hlsl_ir_jump(node); ++ terminal_break = jump->type == HLSL_IR_JUMP_BREAK; ++ } ++ } ++ ++ missing_terminal_break |= !terminal_break; ++ ++ if (!terminal_break) ++ { ++ if (c->is_default) ++ { ++ hlsl_error(ctx, &c->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, ++ "The 'default' case block is not terminated with 'break' or 'return'."); ++ } ++ else ++ { ++ hlsl_error(ctx, &c->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, ++ "Switch case block '%u' is not terminated with 'break' or 'return'.", c->value); ++ } ++ } ++ } ++ ++ if (missing_terminal_break) ++ return true; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ if (c->is_default) ++ { ++ def = c; ++ ++ /* Remove preceding empty cases. */ ++ while (list_prev(&s->cases, &def->entry)) ++ { ++ c = LIST_ENTRY(list_prev(&s->cases, &def->entry), struct hlsl_ir_switch_case, entry); ++ if (!list_empty(&c->body.instrs)) ++ break; ++ hlsl_free_ir_switch_case(c); ++ } ++ ++ if (list_empty(&def->body.instrs)) ++ { ++ /* Remove following empty cases. */ ++ while (list_next(&s->cases, &def->entry)) ++ { ++ c = LIST_ENTRY(list_next(&s->cases, &def->entry), struct hlsl_ir_switch_case, entry); ++ if (!list_empty(&c->body.instrs)) ++ break; ++ hlsl_free_ir_switch_case(c); ++ } ++ ++ /* Merge with the next case. */ ++ if (list_next(&s->cases, &def->entry)) ++ { ++ c = LIST_ENTRY(list_next(&s->cases, &def->entry), struct hlsl_ir_switch_case, entry); ++ c->is_default = true; ++ hlsl_free_ir_switch_case(def); ++ def = c; ++ } ++ } ++ ++ break; ++ } ++ } ++ ++ if (def) ++ { ++ list_remove(&def->entry); ++ } ++ else ++ { ++ struct hlsl_ir_node *jump; ++ ++ if (!(def = hlsl_new_switch_case(ctx, 0, true, NULL, &s->node.loc))) ++ return true; ++ if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_BREAK, NULL, &s->node.loc))) ++ { ++ hlsl_free_ir_switch_case(def); ++ return true; ++ } ++ hlsl_block_add_instr(&def->body, jump); ++ } ++ list_add_tail(&s->cases, &def->entry); ++ ++ return true; ++} ++ + static bool lower_nonconstant_vector_derefs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) + { + struct hlsl_ir_node *idx; +@@ -2929,6 +3150,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) + case HLSL_IR_JUMP: + case HLSL_IR_LOOP: + case HLSL_IR_RESOURCE_STORE: ++ case HLSL_IR_SWITCH: + break; + } + +@@ -2956,6 +3178,16 @@ static unsigned int index_instructions(struct hlsl_block *block, unsigned int in + index = index_instructions(&hlsl_ir_loop(instr)->body, index); + hlsl_ir_loop(instr)->next_index = index; + } ++ else if (instr->type == HLSL_IR_SWITCH) ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ index = index_instructions(&c->body, index); ++ } ++ } + } + + return index; +@@ -2978,6 +3210,19 @@ static void dump_function(struct rb_entry *entry, void *context) + rb_for_each_entry(&func->overloads, dump_function_decl, ctx); + } + ++static bool mark_indexable_vars(struct hlsl_ctx *ctx, struct hlsl_deref *deref, ++ struct hlsl_ir_node *instr) ++{ ++ if (!deref->rel_offset.node) ++ return false; ++ ++ assert(deref->var); ++ assert(deref->rel_offset.node->type != HLSL_IR_CONSTANT); ++ deref->var->indexable = true; ++ ++ return true; ++} ++ + static char get_regset_name(enum hlsl_regset regset) + { + switch (regset) +@@ -3066,8 +3311,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + if (!var->first_write) + var->first_write = loop_first ? min(instr->index, loop_first) : instr->index; + store->rhs.node->last_read = last_read; +- if (store->lhs.offset.node) +- store->lhs.offset.node->last_read = last_read; ++ if (store->lhs.rel_offset.node) ++ store->lhs.rel_offset.node->last_read = last_read; + break; + } + case HLSL_IR_EXPR: +@@ -3094,8 +3339,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + + var = load->src.var; + var->last_read = max(var->last_read, last_read); +- if (load->src.offset.node) +- load->src.offset.node->last_read = last_read; ++ if (load->src.rel_offset.node) ++ load->src.rel_offset.node->last_read = last_read; + break; + } + case HLSL_IR_LOOP: +@@ -3112,14 +3357,14 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + + var = load->resource.var; + var->last_read = max(var->last_read, last_read); +- if (load->resource.offset.node) +- load->resource.offset.node->last_read = last_read; ++ if (load->resource.rel_offset.node) ++ load->resource.rel_offset.node->last_read = last_read; + + if ((var = load->sampler.var)) + { + var->last_read = max(var->last_read, last_read); +- if (load->sampler.offset.node) +- load->sampler.offset.node->last_read = last_read; ++ if (load->sampler.rel_offset.node) ++ load->sampler.rel_offset.node->last_read = last_read; + } + + if (load->coords.node) +@@ -3144,8 +3389,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + + var = store->resource.var; + var->last_read = max(var->last_read, last_read); +- if (store->resource.offset.node) +- store->resource.offset.node->last_read = last_read; ++ if (store->resource.rel_offset.node) ++ store->resource.rel_offset.node->last_read = last_read; + store->coords.node->last_read = last_read; + store->value.node->last_read = last_read; + break; +@@ -3173,6 +3418,16 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + jump->condition.node->last_read = last_read; + break; + } ++ case HLSL_IR_SWITCH: ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ compute_liveness_recurse(&c->body, loop_first, loop_last); ++ s->selector.node->last_read = last_read; ++ break; ++ } + case HLSL_IR_CONSTANT: + break; + } +@@ -3206,18 +3461,20 @@ static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl + + struct register_allocator + { +- size_t count, capacity; +- +- /* Highest register index that has been allocated. +- * Used to declare sm4 temp count. */ +- uint32_t max_reg; +- + struct allocation + { + uint32_t reg; + unsigned int writemask; + unsigned int first_write, last_read; + } *allocations; ++ size_t count, capacity; ++ ++ /* Indexable temps are allocated separately and always keep their index regardless of their ++ * lifetime. */ ++ size_t indexable_count; ++ ++ /* Total number of registers allocated so far. Used to declare sm4 temp count. */ ++ uint32_t reg_count; + }; + + static unsigned int get_available_writemask(const struct register_allocator *allocator, +@@ -3260,7 +3517,7 @@ static void record_allocation(struct hlsl_ctx *ctx, struct register_allocator *a + allocation->first_write = first_write; + allocation->last_read = last_read; + +- allocator->max_reg = max(allocator->max_reg, reg_idx); ++ allocator->reg_count = max(allocator->reg_count, reg_idx + 1); + } + + /* reg_size is the number of register components to be reserved, while component_count is the number +@@ -3464,11 +3721,23 @@ static void allocate_variable_temp_register(struct hlsl_ctx *ctx, + + if (!var->regs[HLSL_REGSET_NUMERIC].allocated && var->last_read) + { +- var->regs[HLSL_REGSET_NUMERIC] = allocate_numeric_registers_for_type(ctx, allocator, +- var->first_write, var->last_read, var->data_type); ++ if (var->indexable) ++ { ++ var->regs[HLSL_REGSET_NUMERIC].id = allocator->indexable_count++; ++ var->regs[HLSL_REGSET_NUMERIC].allocation_size = 1; ++ var->regs[HLSL_REGSET_NUMERIC].writemask = 0; ++ var->regs[HLSL_REGSET_NUMERIC].allocated = true; + +- TRACE("Allocated %s to %s (liveness %u-%u).\n", var->name, debug_register('r', +- var->regs[HLSL_REGSET_NUMERIC], var->data_type), var->first_write, var->last_read); ++ TRACE("Allocated %s to x%u[].\n", var->name, var->regs[HLSL_REGSET_NUMERIC].id); ++ } ++ else ++ { ++ var->regs[HLSL_REGSET_NUMERIC] = allocate_numeric_registers_for_type(ctx, allocator, ++ var->first_write, var->last_read, var->data_type); ++ ++ TRACE("Allocated %s to %s (liveness %u-%u).\n", var->name, debug_register('r', ++ var->regs[HLSL_REGSET_NUMERIC], var->data_type), var->first_write, var->last_read); ++ } + } + } + +@@ -3524,6 +3793,18 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, + break; + } + ++ case HLSL_IR_SWITCH: ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ allocate_temp_registers_recurse(ctx, &c->body, allocator); ++ } ++ break; ++ } ++ + default: + break; + } +@@ -3633,6 +3914,18 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, + break; + } + ++ case HLSL_IR_SWITCH: ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ allocate_const_registers_recurse(ctx, &c->body, allocator); ++ } ++ break; ++ } ++ + default: + break; + } +@@ -3691,7 +3984,7 @@ static void allocate_temp_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functio + } + + allocate_temp_registers_recurse(ctx, &entry_func->body, &allocator); +- ctx->temp_count = allocator.max_reg + 1; ++ ctx->temp_count = allocator.reg_count; + vkd3d_free(allocator.allocations); + } + +@@ -4206,30 +4499,25 @@ 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; ++ enum hlsl_regset regset = hlsl_deref_get_regset(ctx, deref); ++ struct hlsl_ir_node *offset_node = deref->rel_offset.node; + unsigned int size; + +- if (!offset_node) +- { +- *offset = 0; +- return true; +- } +- +- /* We should always have generated a cast to UINT. */ +- assert(offset_node->data_type->class == HLSL_CLASS_SCALAR +- && offset_node->data_type->base_type == HLSL_TYPE_UINT); ++ *offset = deref->const_offset; + +- if (offset_node->type != HLSL_IR_CONSTANT) ++ if (offset_node) ++ { ++ /* We should always have generated a cast to UINT. */ ++ assert(offset_node->data_type->class == HLSL_CLASS_SCALAR ++ && offset_node->data_type->base_type == HLSL_TYPE_UINT); ++ assert(offset_node->type != HLSL_IR_CONSTANT); + return false; +- +- *offset = hlsl_ir_constant(offset_node)->value.u[0].u; +- regset = hlsl_deref_get_regset(ctx, deref); ++ } + + 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, ++ hlsl_error(ctx, &offset_node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS, + "Dereference is out of bounds. %u/%u", *offset, size); + return false; + } +@@ -4244,8 +4532,8 @@ unsigned int hlsl_offset_from_deref_safe(struct hlsl_ctx *ctx, const struct hlsl + if (hlsl_offset_from_deref(ctx, deref, &offset)) + return offset; + +- hlsl_fixme(ctx, &deref->offset.node->loc, "Dereference with non-constant offset of type %s.", +- hlsl_node_type_to_string(deref->offset.node->type)); ++ hlsl_fixme(ctx, &deref->rel_offset.node->loc, "Dereference with non-constant offset of type %s.", ++ hlsl_node_type_to_string(deref->rel_offset.node->type)); + + return 0; + } +@@ -4335,6 +4623,62 @@ static bool type_has_object_components(struct hlsl_type *type) + return false; + } + ++static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *body) ++{ ++ struct hlsl_ir_node *instr, *next; ++ struct hlsl_block block; ++ struct list *start; ++ ++ LIST_FOR_EACH_ENTRY_SAFE(instr, next, &body->instrs, struct hlsl_ir_node, entry) ++ { ++ if (instr->type == HLSL_IR_IF) ++ { ++ struct hlsl_ir_if *iff = hlsl_ir_if(instr); ++ ++ remove_unreachable_code(ctx, &iff->then_block); ++ remove_unreachable_code(ctx, &iff->else_block); ++ } ++ else if (instr->type == HLSL_IR_LOOP) ++ { ++ struct hlsl_ir_loop *loop = hlsl_ir_loop(instr); ++ ++ remove_unreachable_code(ctx, &loop->body); ++ } ++ else if (instr->type == HLSL_IR_SWITCH) ++ { ++ struct hlsl_ir_switch *s = hlsl_ir_switch(instr); ++ struct hlsl_ir_switch_case *c; ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ remove_unreachable_code(ctx, &c->body); ++ } ++ } ++ } ++ ++ /* Remove instructions past unconditional jumps. */ ++ LIST_FOR_EACH_ENTRY(instr, &body->instrs, struct hlsl_ir_node, entry) ++ { ++ struct hlsl_ir_jump *jump; ++ ++ if (instr->type != HLSL_IR_JUMP) ++ continue; ++ ++ jump = hlsl_ir_jump(instr); ++ if (jump->type != HLSL_IR_JUMP_BREAK && jump->type != HLSL_IR_JUMP_CONTINUE) ++ continue; ++ ++ if (!(start = list_next(&body->instrs, &instr->entry))) ++ break; ++ ++ hlsl_block_init(&block); ++ list_move_slice_tail(&block.instrs, start, list_tail(&body->instrs)); ++ hlsl_block_cleanup(&block); ++ ++ break; ++ } ++} ++ + int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, + enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out) + { +@@ -4452,6 +4796,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + progress |= hlsl_transform_ir(ctx, remove_trivial_conditional_branches, body, NULL); + } + while (progress); ++ remove_unreachable_code(ctx, body); ++ hlsl_transform_ir(ctx, normalize_switch_cases, body, NULL); + + lower_ir(ctx, lower_nonconstant_vector_derefs, body); + lower_ir(ctx, lower_casts_to_bool, body); +@@ -4482,6 +4828,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + /* 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)); ++ transform_derefs(ctx, clean_constant_deref_offset_srcs, body); + + do + compute_liveness(ctx, entry_func); +@@ -4492,6 +4839,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + if (TRACE_ON()) + rb_for_each_entry(&ctx->functions, dump_function, ctx); + ++ transform_derefs(ctx, mark_indexable_vars, body); ++ + calculate_resource_register_counts(ctx); + + allocate_register_reservations(ctx); +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index 511b0e8faf9..758b594b330 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -550,6 +550,8 @@ struct io_normaliser + uint8_t input_range_map[MAX_REG_OUTPUT][VKD3D_VEC4_SIZE]; + uint8_t output_range_map[MAX_REG_OUTPUT][VKD3D_VEC4_SIZE]; + uint8_t pc_range_map[MAX_REG_OUTPUT][VKD3D_VEC4_SIZE]; ++ ++ bool use_vocp; + }; + + static bool io_normaliser_is_in_fork_or_join_phase(const struct io_normaliser *normaliser) +@@ -581,6 +583,12 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si + vkd3d_unreachable(); + } + ++struct signature_element *vsir_signature_find_element_for_reg(const struct shader_signature *signature, ++ unsigned int reg_idx, unsigned int write_mask) ++{ ++ return &signature->elements[shader_signature_find_element_for_reg(signature, reg_idx, write_mask)]; ++} ++ + static unsigned int range_map_get_register_count(uint8_t range_map[][VKD3D_VEC4_SIZE], + unsigned int register_idx, unsigned int write_mask) + { +@@ -1025,6 +1033,10 @@ static void shader_instruction_normalise_io_params(struct vkd3d_shader_instructi + if (normaliser->shader_type == VKD3D_SHADER_TYPE_HULL) + { + reg = &ins->declaration.dst.reg; ++ ++ if (reg->type == VKD3DSPR_OUTCONTROLPOINT) ++ normaliser->use_vocp = true; ++ + /* We don't need to keep OUTCONTROLPOINT or PATCHCONST input declarations since their + * equivalents were declared earlier, but INCONTROLPOINT may be the first occurrence. */ + if (reg->type == VKD3DSPR_OUTCONTROLPOINT || reg->type == VKD3DSPR_PATCHCONST) +@@ -1065,24 +1077,22 @@ static void shader_instruction_normalise_io_params(struct vkd3d_shader_instructi + } + } + +-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) ++static enum vkd3d_result shader_normalise_io_registers(struct vkd3d_shader_parser *parser) + { +- struct io_normaliser normaliser = {*instructions}; ++ struct io_normaliser normaliser = {parser->instructions}; + struct vkd3d_shader_instruction *ins; + bool has_control_point_phase; + unsigned int i, j; + + normaliser.phase = VKD3DSIH_INVALID; +- normaliser.shader_type = shader_type; +- normaliser.input_signature = input_signature; +- normaliser.output_signature = output_signature; +- normaliser.patch_constant_signature = patch_constant_signature; ++ normaliser.shader_type = parser->shader_version.type; ++ normaliser.input_signature = &parser->shader_desc.input_signature; ++ normaliser.output_signature = &parser->shader_desc.output_signature; ++ normaliser.patch_constant_signature = &parser->shader_desc.patch_constant_signature; + +- for (i = 0, has_control_point_phase = false; i < instructions->count; ++i) ++ for (i = 0, has_control_point_phase = false; i < parser->instructions.count; ++i) + { +- ins = &instructions->elements[i]; ++ ins = &parser->instructions.elements[i]; + + switch (ins->handler_idx) + { +@@ -1121,11 +1131,11 @@ static enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_s + } + } + +- if (!shader_signature_merge(input_signature, normaliser.input_range_map, false) +- || !shader_signature_merge(output_signature, normaliser.output_range_map, false) +- || !shader_signature_merge(patch_constant_signature, normaliser.pc_range_map, true)) ++ if (!shader_signature_merge(&parser->shader_desc.input_signature, normaliser.input_range_map, false) ++ || !shader_signature_merge(&parser->shader_desc.output_signature, normaliser.output_range_map, false) ++ || !shader_signature_merge(&parser->shader_desc.patch_constant_signature, normaliser.pc_range_map, true)) + { +- *instructions = normaliser.instructions; ++ parser->instructions = normaliser.instructions; + return VKD3D_ERROR_OUT_OF_MEMORY; + } + +@@ -1133,7 +1143,8 @@ static enum vkd3d_result instruction_array_normalise_io_registers(struct vkd3d_s + for (i = 0; i < normaliser.instructions.count; ++i) + shader_instruction_normalise_io_params(&normaliser.instructions.elements[i], &normaliser); + +- *instructions = normaliser.instructions; ++ parser->instructions = normaliser.instructions; ++ parser->shader_desc.use_vocp = normaliser.use_vocp; + return VKD3D_OK; + } + +@@ -1438,9 +1449,7 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, + &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); ++ result = shader_normalise_io_registers(parser); + + if (result >= 0) + result = instruction_array_normalise_flat_constants(parser); +@@ -1467,6 +1476,7 @@ struct validation_context + { + struct vkd3d_shader_parser *parser; + size_t instruction_idx; ++ bool dcl_temps_found; + }; + + static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *ctx, +@@ -1492,6 +1502,41 @@ static void vsir_validate_register(struct validation_context *ctx, + if (reg->type >= VKD3DSPR_COUNT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, "Invalid register type %#x.", + reg->type); ++ ++ if (reg->precision >= VKD3D_SHADER_REGISTER_PRECISION_COUNT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, "Invalid register precision %#x.", ++ reg->precision); ++ ++ if (reg->data_type >= VKD3D_DATA_COUNT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, "Invalid register data type %#x.", ++ reg->data_type); ++ ++ if (reg->dimension >= VSIR_DIMENSION_COUNT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid register dimension %#x.", ++ reg->dimension); ++ ++ if (reg->idx_count > ARRAY_SIZE(reg->idx)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid register index count %u.", ++ reg->idx_count); ++ ++ switch (reg->type) ++ { ++ case VKD3DSPR_TEMP: ++ if (reg->idx_count != 1) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a TEMP register.", ++ reg->idx_count); ++ ++ if (reg->idx_count >= 1 && reg->idx[0].rel_addr) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a TEMP register."); ++ ++ if (reg->idx_count >= 1 && reg->idx[0].offset >= ctx->parser->shader_desc.temp_count) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "TEMP register index %u exceeds the declared count %u.", ++ reg->idx[0].offset, ctx->parser->shader_desc.temp_count); ++ break; ++ ++ default: ++ break; ++ } + } + + static void vsir_validate_dst_param(struct validation_context *ctx, +@@ -1538,6 +1583,24 @@ static void vsir_validate_src_param(struct validation_context *ctx, + src->modifiers); + } + ++static void vsir_validate_dst_count(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction, unsigned int count) ++{ ++ if (instruction->dst_count != count) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DEST_COUNT, ++ "Invalid destination count %u for an instruction of type %#x, expected %u.", ++ instruction->dst_count, instruction->handler_idx, count); ++} ++ ++static void vsir_validate_src_count(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction, unsigned int count) ++{ ++ if (instruction->src_count != count) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, ++ "Invalid source count %u for an instruction of type %#x, expected %u.", ++ instruction->src_count, instruction->handler_idx, count); ++} ++ + static void vsir_validate_instruction(struct validation_context *ctx) + { + const struct vkd3d_shader_instruction *instruction = &ctx->parser->instructions.elements[ctx->instruction_idx]; +@@ -1556,6 +1619,25 @@ static void vsir_validate_instruction(struct validation_context *ctx) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, "Invalid instruction handler %#x.", + instruction->handler_idx); + } ++ ++ switch (instruction->handler_idx) ++ { ++ case VKD3DSIH_DCL_TEMPS: ++ vsir_validate_dst_count(ctx, instruction, 0); ++ vsir_validate_src_count(ctx, instruction, 0); ++ /* TODO Check that each phase in a hull shader has at most ++ * one occurrence. */ ++ if (ctx->dcl_temps_found && ctx->parser->shader_version.type != VKD3D_SHADER_TYPE_HULL) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS, "Duplicate DCL_TEMPS instruction."); ++ ctx->dcl_temps_found = true; ++ if (instruction->declaration.count != ctx->parser->shader_desc.temp_count) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, "Invalid DCL_TEMPS count %u, expected %u.", ++ instruction->declaration.count, ctx->parser->shader_desc.temp_count); ++ break; ++ ++ default: ++ break; ++ } + } + + void vsir_validate(struct vkd3d_shader_parser *parser) +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 2dab97ccbb3..a25edb64491 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -173,7 +173,13 @@ enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d + { + switch (sysval) + { ++ case VKD3D_SHADER_SV_COVERAGE: ++ case VKD3D_SHADER_SV_DEPTH: ++ case VKD3D_SHADER_SV_DEPTH_GREATER_EQUAL: ++ case VKD3D_SHADER_SV_DEPTH_LESS_EQUAL: + case VKD3D_SHADER_SV_NONE: ++ case VKD3D_SHADER_SV_STENCIL_REF: ++ case VKD3D_SHADER_SV_TARGET: + return VKD3D_SIV_NONE; + case VKD3D_SHADER_SV_POSITION: + return VKD3D_SIV_POSITION; +@@ -181,6 +187,16 @@ enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d + return VKD3D_SIV_CLIP_DISTANCE; + case VKD3D_SHADER_SV_CULL_DISTANCE: + return VKD3D_SIV_CULL_DISTANCE; ++ case VKD3D_SHADER_SV_INSTANCE_ID: ++ return VKD3D_SIV_INSTANCE_ID; ++ case VKD3D_SHADER_SV_IS_FRONT_FACE: ++ return VKD3D_SIV_IS_FRONT_FACE; ++ case VKD3D_SHADER_SV_PRIMITIVE_ID: ++ return VKD3D_SIV_PRIMITIVE_ID; ++ case VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX: ++ return VKD3D_SIV_RENDER_TARGET_ARRAY_INDEX; ++ case VKD3D_SHADER_SV_SAMPLE_INDEX: ++ return VKD3D_SIV_SAMPLE_INDEX; + case VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE: + return VKD3D_SIV_QUAD_U0_TESS_FACTOR + index; + case VKD3D_SHADER_SV_TESS_FACTOR_QUADINT: +@@ -193,6 +209,10 @@ enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d + return VKD3D_SIV_LINE_DETAIL_TESS_FACTOR; + case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: + return VKD3D_SIV_LINE_DENSITY_TESS_FACTOR; ++ case VKD3D_SHADER_SV_VERTEX_ID: ++ return VKD3D_SIV_VERTEX_ID; ++ case VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX: ++ return VKD3D_SIV_VIEWPORT_ARRAY_INDEX; + default: + FIXME("Unhandled sysval %#x, index %u.\n", sysval, index); + return VKD3D_SIV_NONE; +@@ -1411,13 +1431,6 @@ static uint32_t vkd3d_spirv_build_op_udiv(struct vkd3d_spirv_builder *builder, + SpvOpUDiv, result_type, operand0, operand1); + } + +-static uint32_t vkd3d_spirv_build_op_umod(struct vkd3d_spirv_builder *builder, +- uint32_t result_type, uint32_t operand0, uint32_t operand1) +-{ +- return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, +- SpvOpUMod, result_type, operand0, operand1); +-} +- + static uint32_t vkd3d_spirv_build_op_isub(struct vkd3d_spirv_builder *builder, + uint32_t result_type, uint32_t operand0, uint32_t operand1) + { +@@ -3523,6 +3536,14 @@ static bool vkd3d_swizzle_is_equal(unsigned int dst_write_mask, + return vkd3d_compact_swizzle(VKD3D_SHADER_NO_SWIZZLE, dst_write_mask) == vkd3d_compact_swizzle(swizzle, write_mask); + } + ++static bool vkd3d_swizzle_is_scalar(unsigned int swizzle) ++{ ++ unsigned int component_idx = vkd3d_swizzle_get_component(swizzle, 0); ++ return vkd3d_swizzle_get_component(swizzle, 1) == component_idx ++ && vkd3d_swizzle_get_component(swizzle, 2) == component_idx ++ && vkd3d_swizzle_get_component(swizzle, 3) == component_idx; ++} ++ + static uint32_t spirv_compiler_emit_swizzle(struct spirv_compiler *compiler, + uint32_t val_id, unsigned int val_write_mask, enum vkd3d_shader_component_type component_type, + unsigned int swizzle, unsigned int write_mask) +@@ -3725,6 +3746,26 @@ static void spirv_compiler_set_ssa_register_id(const struct spirv_compiler *comp + compiler->ssa_register_ids[i] = val_id; + } + ++static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler, ++ const struct vkd3d_shader_register *reg, enum vkd3d_shader_component_type component_type, ++ unsigned int swizzle) ++{ ++ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; ++ unsigned int component_idx; ++ uint32_t type_id, val_id; ++ ++ val_id = spirv_compiler_get_ssa_register_id(compiler, reg); ++ assert(val_id); ++ assert(vkd3d_swizzle_is_scalar(swizzle)); ++ ++ if (reg->dimension == VSIR_DIMENSION_SCALAR) ++ return val_id; ++ ++ type_id = vkd3d_spirv_get_type_id(builder, component_type, 1); ++ component_idx = vkd3d_swizzle_get_component(swizzle, 0); ++ return vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx); ++} ++ + static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler, + const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask) + { +@@ -3746,7 +3787,7 @@ static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler, + component_type = vkd3d_component_type_from_data_type(reg->data_type); + + if (reg->type == VKD3DSPR_SSA) +- return spirv_compiler_get_ssa_register_id(compiler, reg); ++ return spirv_compiler_emit_load_ssa_reg(compiler, reg, component_type, swizzle); + + if (!spirv_compiler_get_register_info(compiler, reg, ®_info)) + { +@@ -3824,7 +3865,7 @@ static uint32_t spirv_compiler_emit_neg(struct spirv_compiler *compiler, + type_id = spirv_compiler_get_type_id_for_reg(compiler, reg, write_mask); + if (reg->data_type == VKD3D_DATA_FLOAT || reg->data_type == VKD3D_DATA_DOUBLE) + return vkd3d_spirv_build_op_fnegate(builder, type_id, val_id); +- else if (reg->data_type == VKD3D_DATA_INT) ++ else if (reg->data_type == VKD3D_DATA_INT || reg->data_type == VKD3D_DATA_UINT) + return vkd3d_spirv_build_op_snegate(builder, type_id, val_id); + + FIXME("Unhandled data type %#x.\n", reg->data_type); +@@ -4592,8 +4633,7 @@ static unsigned int shader_register_get_io_indices(const struct vkd3d_shader_reg + } + + static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, +- const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval, +- enum vkd3d_shader_interpolation_mode interpolation_mode) ++ const struct vkd3d_shader_dst_param *dst) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_register *reg = &dst->reg; +@@ -4601,18 +4641,18 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, + const struct signature_element *signature_element; + const struct shader_signature *shader_signature; + enum vkd3d_shader_component_type component_type; +- uint32_t type_id, ptr_type_id, float_type_id; ++ enum vkd3d_shader_input_sysval_semantic sysval; + const struct vkd3d_spirv_builtin *builtin; + unsigned int write_mask, reg_write_mask; + struct vkd3d_symbol *symbol = NULL; + uint32_t val_id, input_id, var_id; ++ uint32_t type_id, float_type_id; + struct vkd3d_symbol reg_symbol; + SpvStorageClass storage_class; + struct rb_entry *entry = NULL; + bool use_private_var = false; + unsigned int array_sizes[2]; + unsigned int element_idx; +- uint32_t i, index; + + assert(!reg->idx_count || !reg->idx[0].rel_addr); + assert(reg->idx_count < 2 || !reg->idx[1].rel_addr); +@@ -4622,10 +4662,12 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, + + element_idx = shader_register_get_io_indices(reg, array_sizes); + signature_element = &shader_signature->elements[element_idx]; +- +- if ((compiler->shader_type == VKD3D_SHADER_TYPE_HULL || compiler->shader_type == VKD3D_SHADER_TYPE_GEOMETRY) +- && !sysval && signature_element->sysval_semantic) +- sysval = vkd3d_siv_from_sysval(signature_element->sysval_semantic); ++ sysval = vkd3d_siv_from_sysval(signature_element->sysval_semantic); ++ /* The Vulkan spec does not explicitly forbid passing varyings from the ++ * TCS to the TES via builtins. However, Mesa doesn't seem to handle it ++ * well, and we don't actually need them to be in builtins. */ ++ if (compiler->shader_type == VKD3D_SHADER_TYPE_DOMAIN && reg->type != VKD3DSPR_PATCHCONST) ++ sysval = VKD3D_SIV_NONE; + + builtin = get_spirv_builtin_for_sysval(compiler, sysval); + +@@ -4693,7 +4735,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, + if (component_idx) + vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationComponent, component_idx); + +- spirv_compiler_emit_interpolation_decorations(compiler, input_id, interpolation_mode); ++ spirv_compiler_emit_interpolation_decorations(compiler, input_id, signature_element->interpolation_mode); + } + + var_id = input_id; +@@ -4715,47 +4757,27 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler, + + if (use_private_var) + { ++ struct vkd3d_shader_register dst_reg = *reg; ++ dst_reg.data_type = VKD3D_DATA_FLOAT; ++ + type_id = vkd3d_spirv_get_type_id(builder, component_type, input_component_count); +- for (i = 0; i < max(array_sizes[0], 1); ++i) +- { +- struct vkd3d_shader_register dst_reg = *reg; +- dst_reg.data_type = VKD3D_DATA_FLOAT; + +- val_id = input_id; +- if (array_sizes[0]) +- { +- ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, type_id); +- index = spirv_compiler_get_constant_uint(compiler, i); +- val_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, input_id, index); +- dst_reg.idx[0].offset = i; +- } +- else if (builtin && builtin->spirv_array_size) +- { +- /* The D3D builtin is not an array, but the SPIR-V builtin is, +- * so we'll need to index into the SPIR-V builtin when loading +- * it. This happens when reading TessLevel in domain shaders. */ +- ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassInput, type_id); +- index = spirv_compiler_get_constant_uint(compiler, builtin->member_idx); +- val_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, input_id, index); +- dst_reg.idx[0].offset = element_idx + i; +- } +- val_id = vkd3d_spirv_build_op_load(builder, type_id, val_id, SpvMemoryAccessMaskNone); ++ val_id = vkd3d_spirv_build_op_load(builder, type_id, input_id, SpvMemoryAccessMaskNone); + +- if (builtin && builtin->fixup_pfn) +- val_id = builtin->fixup_pfn(compiler, val_id); ++ if (builtin && builtin->fixup_pfn) ++ val_id = builtin->fixup_pfn(compiler, val_id); + +- if (component_type != VKD3D_SHADER_COMPONENT_FLOAT) +- { +- float_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, input_component_count); +- val_id = vkd3d_spirv_build_op_bitcast(builder, float_type_id, val_id); +- } ++ if (component_type != VKD3D_SHADER_COMPONENT_FLOAT) ++ { ++ float_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, input_component_count); ++ val_id = vkd3d_spirv_build_op_bitcast(builder, float_type_id, val_id); ++ } + +- val_id = spirv_compiler_emit_swizzle(compiler, val_id, +- vkd3d_write_mask_from_component_count(input_component_count), +- VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_SHADER_NO_SWIZZLE, dst->write_mask >> component_idx); ++ val_id = spirv_compiler_emit_swizzle(compiler, val_id, ++ vkd3d_write_mask_from_component_count(input_component_count), ++ VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_SHADER_NO_SWIZZLE, dst->write_mask >> component_idx); + +- spirv_compiler_emit_store_reg(compiler, &dst_reg, dst->write_mask, val_id); +- } ++ spirv_compiler_emit_store_reg(compiler, &dst_reg, dst->write_mask, val_id); + } + + return input_id; +@@ -4806,13 +4828,12 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil + case VKD3DSPR_INPUT: + case VKD3DSPR_INCONTROLPOINT: + case VKD3DSPR_PATCHCONST: +- spirv_compiler_emit_input(compiler, dst, VKD3D_SIV_NONE, VKD3DSIM_NONE); ++ spirv_compiler_emit_input(compiler, dst); + return; + case VKD3DSPR_PRIMID: + spirv_compiler_emit_input_register(compiler, dst); + return; + case VKD3DSPR_OUTPOINTID: /* Emitted in spirv_compiler_emit_initial_declarations(). */ +- case VKD3DSPR_OUTCONTROLPOINT: /* See spirv_compiler_leave_shader_phase(). */ + return; + default: + FIXME("Unhandled shader phase input register %#x.\n", reg->type); +@@ -4977,8 +4998,7 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c + return id; + } + +-static void spirv_compiler_emit_output(struct spirv_compiler *compiler, +- const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval) ++static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_register *reg = &dst->reg; +@@ -4986,6 +5006,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, + const struct signature_element *signature_element; + enum vkd3d_shader_component_type component_type; + const struct shader_signature *shader_signature; ++ enum vkd3d_shader_input_sysval_semantic sysval; + const struct vkd3d_spirv_builtin *builtin; + unsigned int write_mask, reg_write_mask; + bool use_private_variable = false; +@@ -5002,6 +5023,10 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, + + element_idx = shader_register_get_io_indices(reg, array_sizes); + signature_element = &shader_signature->elements[element_idx]; ++ sysval = vkd3d_siv_from_sysval(signature_element->sysval_semantic); ++ /* Don't use builtins for TCS -> TES varyings. See spirv_compiler_emit_input(). */ ++ if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && !is_patch_constant) ++ sysval = VKD3D_SIV_NONE; + + builtin = vkd3d_get_spirv_builtin(compiler, dst->reg.type, sysval); + +@@ -5393,9 +5418,9 @@ static void spirv_compiler_emit_dcl_global_flags(struct spirv_compiler *compiler + } + + if (flags & ~(VKD3DSGF_REFACTORING_ALLOWED | VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS)) +- FIXME("Unhandled global flags %#"PRIx64".\n", flags); ++ FIXME("Unhandled global flags %#"PRIx64".\n", (uint64_t)flags); + else +- WARN("Unhandled global flags %#"PRIx64".\n", flags); ++ WARN("Unhandled global flags %#"PRIx64".\n", (uint64_t)flags); + } + + static void spirv_compiler_emit_temps(struct spirv_compiler *compiler, uint32_t count) +@@ -6089,33 +6114,15 @@ static void spirv_compiler_emit_dcl_input(struct spirv_compiler *compiler, + if (spirv_compiler_get_current_shader_phase(compiler)) + spirv_compiler_emit_shader_phase_input(compiler, dst); + else if (vkd3d_shader_register_is_input(&dst->reg) || dst->reg.type == VKD3DSPR_PATCHCONST) +- spirv_compiler_emit_input(compiler, dst, VKD3D_SIV_NONE, VKD3DSIM_NONE); ++ spirv_compiler_emit_input(compiler, dst); + else + spirv_compiler_emit_input_register(compiler, dst); +- +- if (dst->reg.type == VKD3DSPR_OUTCONTROLPOINT) +- compiler->use_vocp = true; +-} +- +-static void spirv_compiler_emit_dcl_input_ps(struct spirv_compiler *compiler, +- const struct vkd3d_shader_instruction *instruction) +-{ +- spirv_compiler_emit_input(compiler, &instruction->declaration.dst, VKD3D_SIV_NONE, instruction->flags); +-} +- +-static void spirv_compiler_emit_dcl_input_ps_sysval(struct spirv_compiler *compiler, +- const struct vkd3d_shader_instruction *instruction) +-{ +- const struct vkd3d_shader_register_semantic *semantic = &instruction->declaration.register_semantic; +- +- spirv_compiler_emit_input(compiler, &semantic->reg, semantic->sysval_semantic, instruction->flags); + } + + static void spirv_compiler_emit_dcl_input_sysval(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) + { +- spirv_compiler_emit_input(compiler, &instruction->declaration.register_semantic.reg, +- instruction->declaration.register_semantic.sysval_semantic, VKD3DSIM_NONE); ++ spirv_compiler_emit_input(compiler, &instruction->declaration.register_semantic.reg); + } + + static void spirv_compiler_emit_dcl_output(struct spirv_compiler *compiler, +@@ -6125,7 +6132,7 @@ static void spirv_compiler_emit_dcl_output(struct spirv_compiler *compiler, + + if (vkd3d_shader_register_is_output(&dst->reg) + || (is_in_fork_or_join_phase(compiler) && vkd3d_shader_register_is_patch_constant(&dst->reg))) +- spirv_compiler_emit_output(compiler, dst, VKD3D_SIV_NONE); ++ spirv_compiler_emit_output(compiler, dst); + else + spirv_compiler_emit_output_register(compiler, dst); + } +@@ -6133,13 +6140,7 @@ static void spirv_compiler_emit_dcl_output(struct spirv_compiler *compiler, + static void spirv_compiler_emit_dcl_output_siv(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) + { +- enum vkd3d_shader_input_sysval_semantic sysval; +- const struct vkd3d_shader_dst_param *dst; +- +- dst = &instruction->declaration.register_semantic.reg; +- sysval = instruction->declaration.register_semantic.sysval_semantic; +- +- spirv_compiler_emit_output(compiler, dst, sysval); ++ spirv_compiler_emit_output(compiler, &instruction->declaration.register_semantic.reg); + } + + static void spirv_compiler_emit_dcl_stream(struct spirv_compiler *compiler, +@@ -6569,6 +6570,7 @@ static SpvOp spirv_compiler_map_alu_instruction(const struct vkd3d_shader_instru + {VKD3DSIH_DTOF, SpvOpFConvert}, + {VKD3DSIH_DTOI, SpvOpConvertFToS}, + {VKD3DSIH_DTOU, SpvOpConvertFToU}, ++ {VKD3DSIH_FREM, SpvOpFRem}, + {VKD3DSIH_FTOD, SpvOpFConvert}, + {VKD3DSIH_IADD, SpvOpIAdd}, + {VKD3DSIH_INEG, SpvOpSNegate}, +@@ -6947,7 +6949,7 @@ static void spirv_compiler_emit_imul(struct spirv_compiler *compiler, + uint32_t type_id, val_id, src0_id, src1_id; + + if (dst[0].reg.type != VKD3DSPR_NULL) +- FIXME("Extended multiplies not implemented.\n"); /* SpvOpSMulExtended */ ++ FIXME("Extended multiplies not implemented.\n"); /* SpvOpSMulExtended/SpvOpUMulExtended */ + + if (dst[1].reg.type == VKD3DSPR_NULL) + return; +@@ -6983,7 +6985,7 @@ static void spirv_compiler_emit_imad(struct spirv_compiler *compiler, + spirv_compiler_emit_store_dst(compiler, dst, val_id); + } + +-static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, ++static void spirv_compiler_emit_int_div(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) + { + uint32_t type_id, val_id, src0_id, src1_id, condition_id, uint_max_id; +@@ -6991,6 +6993,10 @@ static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, + const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vkd3d_shader_src_param *src = instruction->src; + unsigned int component_count = 0; ++ SpvOp div_op, mod_op; ++ ++ div_op = instruction->handler_idx == VKD3DSIH_IDIV ? SpvOpSDiv : SpvOpUDiv; ++ mod_op = instruction->handler_idx == VKD3DSIH_IDIV ? SpvOpSRem : SpvOpUMod; + + if (dst[0].reg.type != VKD3DSPR_NULL) + { +@@ -7005,7 +7011,7 @@ static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, + uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, + 0xffffffff, component_count); + +- val_id = vkd3d_spirv_build_op_udiv(builder, type_id, src0_id, src1_id); ++ val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, div_op, type_id, src0_id, src1_id); + /* The SPIR-V spec says: "The resulting value is undefined if Operand 2 is 0." */ + val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, uint_max_id); + +@@ -7028,7 +7034,7 @@ static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, + 0xffffffff, component_count); + } + +- val_id = vkd3d_spirv_build_op_umod(builder, type_id, src0_id, src1_id); ++ val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, mod_op, type_id, src0_id, src1_id); + /* The SPIR-V spec says: "The resulting value is undefined if Operand 2 is 0." */ + val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, uint_max_id); + +@@ -9301,16 +9307,12 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, + case VKD3DSIH_DCL_TGSM_STRUCTURED: + spirv_compiler_emit_dcl_tgsm_structured(compiler, instruction); + break; ++ case VKD3DSIH_DCL_INPUT_PS: + case VKD3DSIH_DCL_INPUT: + spirv_compiler_emit_dcl_input(compiler, instruction); + break; +- case VKD3DSIH_DCL_INPUT_PS: +- spirv_compiler_emit_dcl_input_ps(compiler, instruction); +- break; + case VKD3DSIH_DCL_INPUT_PS_SGV: + case VKD3DSIH_DCL_INPUT_PS_SIV: +- spirv_compiler_emit_dcl_input_ps_sysval(compiler, instruction); +- break; + case VKD3DSIH_DCL_INPUT_SGV: + case VKD3DSIH_DCL_INPUT_SIV: + spirv_compiler_emit_dcl_input_sysval(compiler, instruction); +@@ -9384,6 +9386,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, + case VKD3DSIH_DTOF: + case VKD3DSIH_DTOI: + case VKD3DSIH_DTOU: ++ case VKD3DSIH_FREM: + case VKD3DSIH_FTOD: + case VKD3DSIH_IADD: + case VKD3DSIH_INEG: +@@ -9437,13 +9440,15 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, + spirv_compiler_emit_sincos(compiler, instruction); + break; + case VKD3DSIH_IMUL: ++ case VKD3DSIH_UMUL: + spirv_compiler_emit_imul(compiler, instruction); + break; + case VKD3DSIH_IMAD: + spirv_compiler_emit_imad(compiler, instruction); + break; ++ case VKD3DSIH_IDIV: + case VKD3DSIH_UDIV: +- spirv_compiler_emit_udiv(compiler, instruction); ++ spirv_compiler_emit_int_div(compiler, instruction); + break; + case VKD3DSIH_FTOI: + spirv_compiler_emit_ftoi(compiler, instruction); +@@ -9693,6 +9698,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, + 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)); ++ compiler->use_vocp = parser->shader_desc.use_vocp; + + 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 0ea5a682fa4..fbc04f61fe9 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c ++++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c +@@ -549,6 +549,8 @@ static enum vkd3d_sm4_dimension sm4_dimension_from_vsir_dimension(enum vsir_dime + return VKD3D_SM4_DIMENSION_SCALAR; + case VSIR_DIMENSION_VEC4: + return VKD3D_SM4_DIMENSION_VEC4; ++ case VSIR_DIMENSION_COUNT: ++ vkd3d_unreachable(); + } + vkd3d_unreachable(); + } +@@ -1070,16 +1072,31 @@ static void shader_sm4_read_declaration_register_semantic(struct vkd3d_shader_in + static void shader_sm4_read_dcl_input_ps(struct vkd3d_shader_instruction *ins, uint32_t opcode, + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + { ++ struct vkd3d_shader_dst_param *dst = &ins->declaration.dst; ++ + ins->flags = (opcode_token & VKD3D_SM4_INTERPOLATION_MODE_MASK) >> VKD3D_SM4_INTERPOLATION_MODE_SHIFT; +- shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT, &ins->declaration.dst); ++ if (shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT, dst)) ++ { ++ struct signature_element *e = vsir_signature_find_element_for_reg( ++ &priv->p.shader_desc.input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); ++ ++ e->interpolation_mode = ins->flags; ++ } + } + + static void shader_sm4_read_dcl_input_ps_siv(struct vkd3d_shader_instruction *ins, uint32_t opcode, + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + { ++ struct vkd3d_shader_dst_param *dst = &ins->declaration.register_semantic.reg; ++ + ins->flags = (opcode_token & VKD3D_SM4_INTERPOLATION_MODE_MASK) >> VKD3D_SM4_INTERPOLATION_MODE_SHIFT; +- shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT, +- &ins->declaration.register_semantic.reg); ++ if (shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_FLOAT, dst)) ++ { ++ struct signature_element *e = vsir_signature_find_element_for_reg( ++ &priv->p.shader_desc.input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); ++ ++ e->interpolation_mode = ins->flags; ++ } + ins->declaration.register_semantic.sysval_semantic = *tokens; + } + +@@ -3443,7 +3460,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +- if (var->is_uniform && var->buffer == cbuffer) ++ if (var->is_uniform && var->buffer == cbuffer ++ && var->data_type->class != HLSL_CLASS_OBJECT) + ++var_count; + } + +@@ -3477,7 +3495,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +- if (var->is_uniform && var->buffer == cbuffer) ++ if (var->is_uniform && var->buffer == cbuffer ++ && var->data_type->class != HLSL_CLASS_OBJECT) + { + uint32_t flags = 0; + +@@ -3504,7 +3523,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + j = 0; + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +- if (var->is_uniform && var->buffer == cbuffer) ++ if (var->is_uniform && var->buffer == cbuffer ++ && var->data_type->class != HLSL_CLASS_OBJECT) + { + const unsigned int var_size = (profile->major_version >= 5 ? 10 : 6); + size_t var_offset = vars_start + j * var_size * sizeof(uint32_t); +@@ -3732,7 +3752,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct vkd3d_shader_re + struct hlsl_reg hlsl_reg = hlsl_reg_from_deref(ctx, deref); + + assert(hlsl_reg.allocated); +- reg->type = VKD3DSPR_TEMP; ++ reg->type = deref->var->indexable ? VKD3DSPR_IDXTEMP : VKD3DSPR_TEMP; + reg->dimension = VSIR_DIMENSION_VEC4; + reg->idx[0].offset = hlsl_reg.id; + reg->idx_count = 1; +@@ -3773,7 +3793,7 @@ static void sm4_dst_from_node(struct vkd3d_shader_dst_param *dst, const struct h + static void sm4_src_from_constant_value(struct vkd3d_shader_src_param *src, + const struct hlsl_constant_value *value, unsigned int width, unsigned int map_writemask) + { +- src->swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ src->swizzle = 0; + src->reg.type = VKD3DSPR_IMMCONST; + if (width == 1) + { +@@ -4251,6 +4271,20 @@ static void write_sm4_dcl_temps(const struct tpf_writer *tpf, uint32_t temp_coun + write_sm4_instruction(tpf, &instr); + } + ++static void write_sm4_dcl_indexable_temp(const struct tpf_writer *tpf, uint32_t idx, ++ uint32_t size, uint32_t comp_count) ++{ ++ struct sm4_instruction instr = ++ { ++ .opcode = VKD3D_SM4_OP_DCL_INDEXABLE_TEMP, ++ ++ .idx = {idx, size, comp_count}, ++ .idx_count = 3, ++ }; ++ ++ write_sm4_instruction(tpf, &instr); ++} ++ + static void write_sm4_dcl_thread_group(const struct tpf_writer *tpf, const uint32_t thread_count[3]) + { + struct sm4_instruction instr = +@@ -5467,6 +5501,46 @@ static void write_sm4_store(const struct tpf_writer *tpf, const struct hlsl_ir_s + write_sm4_instruction(tpf, &instr); + } + ++static void write_sm4_switch(const struct tpf_writer *tpf, const struct hlsl_ir_switch *s) ++{ ++ const struct hlsl_ir_node *selector = s->selector.node; ++ struct hlsl_ir_switch_case *c; ++ struct sm4_instruction instr; ++ ++ memset(&instr, 0, sizeof(instr)); ++ instr.opcode = VKD3D_SM4_OP_SWITCH; ++ ++ sm4_src_from_node(tpf, &instr.srcs[0], selector, VKD3DSP_WRITEMASK_ALL); ++ instr.src_count = 1; ++ ++ write_sm4_instruction(tpf, &instr); ++ ++ LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) ++ { ++ memset(&instr, 0, sizeof(instr)); ++ if (c->is_default) ++ { ++ instr.opcode = VKD3D_SM4_OP_DEFAULT; ++ } ++ else ++ { ++ struct hlsl_constant_value value = { .u[0].u = c->value }; ++ ++ instr.opcode = VKD3D_SM4_OP_CASE; ++ sm4_src_from_constant_value(&instr.srcs[0], &value, 1, VKD3DSP_WRITEMASK_ALL); ++ instr.src_count = 1; ++ } ++ ++ write_sm4_instruction(tpf, &instr); ++ write_sm4_block(tpf, &c->body); ++ } ++ ++ memset(&instr, 0, sizeof(instr)); ++ instr.opcode = VKD3D_SM4_OP_ENDSWITCH; ++ ++ write_sm4_instruction(tpf, &instr); ++} ++ + static void write_sm4_swizzle(const struct tpf_writer *tpf, const struct hlsl_ir_swizzle *swizzle) + { + unsigned int hlsl_swizzle; +@@ -5554,6 +5628,10 @@ static void write_sm4_block(const struct tpf_writer *tpf, const struct hlsl_bloc + write_sm4_store(tpf, hlsl_ir_store(instr)); + break; + ++ case HLSL_IR_SWITCH: ++ write_sm4_switch(tpf, hlsl_ir_switch(instr)); ++ break; ++ + case HLSL_IR_SWIZZLE: + write_sm4_swizzle(tpf, hlsl_ir_swizzle(instr)); + break; +@@ -5572,6 +5650,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + struct extern_resource *extern_resources; + unsigned int extern_resources_count, i; + const struct hlsl_buffer *cbuffer; ++ const struct hlsl_scope *scope; + const struct hlsl_ir_var *var; + size_t token_count_position; + struct tpf_writer tpf; +@@ -5626,6 +5705,25 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + if (ctx->temp_count) + write_sm4_dcl_temps(&tpf, ctx->temp_count); + ++ LIST_FOR_EACH_ENTRY(scope, &ctx->scopes, struct hlsl_scope, entry) ++ { ++ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry) ++ { ++ if (var->is_uniform || var->is_input_semantic || var->is_output_semantic) ++ continue; ++ if (!var->regs[HLSL_REGSET_NUMERIC].allocated) ++ continue; ++ ++ if (var->indexable) ++ { ++ unsigned int id = var->regs[HLSL_REGSET_NUMERIC].id; ++ unsigned int size = align(var->data_type->reg_size[HLSL_REGSET_NUMERIC], 4) / 4; ++ ++ write_sm4_dcl_indexable_temp(&tpf, id, size, 4); ++ } ++ } ++ } ++ + write_sm4_block(&tpf, &entry_func->body); + + write_sm4_ret(&tpf); +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +index 4ce1c9daf90..ce51186e26b 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +@@ -18,6 +18,7 @@ + + #include "vkd3d_shader_private.h" + #include "vkd3d_version.h" ++#include "hlsl.h" + + #include + #include +@@ -381,7 +382,7 @@ void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value + memcpy(buffer->data + offset, &value, sizeof(value)); + } + +-static void vkd3d_shader_dump_blob(const char *path, const char *prefix, ++static void vkd3d_shader_dump_blob(const char *path, const char *profile, + const char *suffix, const void *data, size_t size) + { + static LONG shader_id = 0; +@@ -391,7 +392,10 @@ static void vkd3d_shader_dump_blob(const char *path, const char *prefix, + + id = InterlockedIncrement(&shader_id) - 1; + +- snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%s-%u.%s", path, prefix, id, suffix); ++ if (profile) ++ snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u-%s.%s", path, id, profile, suffix); ++ else ++ snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u.%s", path, id, suffix); + if ((f = fopen(filename, "wb"))) + { + if (fwrite(data, 1, size, f) != size) +@@ -423,9 +427,12 @@ static const char *shader_get_source_type_suffix(enum vkd3d_shader_source_type t + } + } + +-void vkd3d_shader_dump_shader(enum vkd3d_shader_source_type source_type, +- enum vkd3d_shader_type shader_type, const struct vkd3d_shader_code *shader) ++void vkd3d_shader_dump_shader(const struct vkd3d_shader_compile_info *compile_info) + { ++ const struct vkd3d_shader_code *shader = &compile_info->source; ++ const struct vkd3d_shader_hlsl_source_info *hlsl_source_info; ++ const struct hlsl_profile_info *profile; ++ const char *profile_name = NULL; + static bool enabled = true; + const char *path; + +@@ -438,8 +445,19 @@ void vkd3d_shader_dump_shader(enum vkd3d_shader_source_type source_type, + return; + } + +- vkd3d_shader_dump_blob(path, shader_get_type_prefix(shader_type), +- shader_get_source_type_suffix(source_type), shader->code, shader->size); ++ if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL) ++ { ++ if (!(hlsl_source_info = vkd3d_find_struct(compile_info->next, HLSL_SOURCE_INFO))) ++ return; ++ ++ if (!(profile = hlsl_get_target_info(hlsl_source_info->profile))) ++ return; ++ ++ profile_name = profile->name; ++ } ++ ++ vkd3d_shader_dump_blob(path, profile_name, shader_get_source_type_suffix(compile_info->source_type), ++ shader->code, shader->size); + } + + static void init_scan_signature_info(const struct vkd3d_shader_compile_info *info) +@@ -784,6 +802,9 @@ static struct vkd3d_shader_descriptor_info1 *vkd3d_shader_scan_add_descriptor(st + struct vkd3d_shader_scan_descriptor_info1 *info = context->scan_descriptor_info; + struct vkd3d_shader_descriptor_info1 *d; + ++ if (!info) ++ return NULL; ++ + if (!vkd3d_array_reserve((void **)&info->descriptors, &context->descriptors_size, + info->descriptor_count + 1, sizeof(*info->descriptors))) + { +@@ -811,9 +832,6 @@ static void vkd3d_shader_scan_constant_buffer_declaration(struct vkd3d_shader_sc + const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb; + struct vkd3d_shader_descriptor_info1 *d; + +- if (!context->scan_descriptor_info) +- return; +- + if (!(d = vkd3d_shader_scan_add_descriptor(context, VKD3D_SHADER_DESCRIPTOR_TYPE_CBV, + &cb->src.reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT))) + return; +@@ -826,9 +844,6 @@ static void vkd3d_shader_scan_sampler_declaration(struct vkd3d_shader_scan_conte + const struct vkd3d_shader_sampler *sampler = &instruction->declaration.sampler; + struct vkd3d_shader_descriptor_info1 *d; + +- if (!context->scan_descriptor_info) +- return; +- + if (!(d = vkd3d_shader_scan_add_descriptor(context, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, + &sampler->src.reg, &sampler->range, VKD3D_SHADER_RESOURCE_NONE, VKD3D_SHADER_RESOURCE_DATA_UINT))) + return; +@@ -854,9 +869,6 @@ static void vkd3d_shader_scan_resource_declaration(struct vkd3d_shader_scan_cont + struct vkd3d_shader_descriptor_info1 *d; + enum vkd3d_shader_descriptor_type type; + +- if (!context->scan_descriptor_info) +- return; +- + if (resource->reg.reg.type == VKD3DSPR_UAV) + type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; + else +@@ -1313,6 +1325,8 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char + + vkd3d_shader_message_context_init(&message_context, compile_info->log_level); + ++ vkd3d_shader_dump_shader(compile_info); ++ + switch (compile_info->source_type) + { + case VKD3D_SHADER_SOURCE_DXBC_TPF: +@@ -1354,8 +1368,6 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, + struct vkd3d_shader_compile_info scan_info; + int ret; + +- vkd3d_shader_dump_shader(compile_info->source_type, parser->shader_version.type, &compile_info->source); +- + scan_info = *compile_info; + + if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0) +@@ -1439,8 +1451,6 @@ static int compile_d3d_bytecode(const struct vkd3d_shader_compile_info *compile_ + return ret; + } + +- vkd3d_shader_dump_shader(compile_info->source_type, parser->shader_version.type, &compile_info->source); +- + if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_ASM) + { + ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out); +@@ -1487,6 +1497,8 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, + + vkd3d_shader_message_context_init(&message_context, compile_info->log_level); + ++ vkd3d_shader_dump_shader(compile_info); ++ + switch (compile_info->source_type) + { + case VKD3D_SHADER_SOURCE_DXBC_TPF: +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index c9d2dec8b89..ab7300115dc 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -142,6 +142,7 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_HLSL_RECURSIVE_CALL = 5025, + VKD3D_SHADER_ERROR_HLSL_INCONSISTENT_SAMPLER = 5026, + VKD3D_SHADER_ERROR_HLSL_NON_FINITE_RESULT = 5027, ++ VKD3D_SHADER_ERROR_HLSL_DUPLICATE_SWITCH_CASE = 5028, + + VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, + VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, +@@ -181,6 +182,7 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE = 8016, + VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES = 8017, + VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES = 8018, ++ VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCE_HANDLE = 8019, + + VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, + VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, +@@ -190,6 +192,7 @@ enum vkd3d_shader_error + VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH = 8305, + VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH = 8306, + VKD3D_SHADER_WARNING_DXIL_INVALID_MASK = 8307, ++ VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION = 8308, + + VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000, + VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER = 9001, +@@ -198,6 +201,15 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS = 9004, + VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT = 9005, + VKD3D_SHADER_ERROR_VSIR_INVALID_SWIZZLE = 9006, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION = 9007, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE = 9008, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION = 9009, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT = 9010, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_DEST_COUNT = 9011, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT = 9012, ++ VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS = 9013, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS = 9014, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX = 9015, + }; + + enum vkd3d_shader_opcode +@@ -325,6 +337,7 @@ enum vkd3d_shader_opcode + VKD3DSIH_FIRSTBIT_LO, + VKD3DSIH_FIRSTBIT_SHI, + VKD3DSIH_FRC, ++ VKD3DSIH_FREM, + VKD3DSIH_FTOD, + VKD3DSIH_FTOI, + VKD3DSIH_FTOU, +@@ -343,6 +356,7 @@ enum vkd3d_shader_opcode + VKD3DSIH_HS_JOIN_PHASE, + VKD3DSIH_IADD, + VKD3DSIH_IBFE, ++ VKD3DSIH_IDIV, + VKD3DSIH_IEQ, + VKD3DSIH_IF, + VKD3DSIH_IFC, +@@ -554,6 +568,8 @@ enum vkd3d_shader_register_precision + VKD3D_SHADER_REGISTER_PRECISION_MIN_INT_16, + VKD3D_SHADER_REGISTER_PRECISION_MIN_UINT_16, + ++ VKD3D_SHADER_REGISTER_PRECISION_COUNT, ++ + VKD3D_SHADER_REGISTER_PRECISION_INVALID = ~0u, + }; + +@@ -574,6 +590,9 @@ enum vkd3d_data_type + VKD3D_DATA_UNUSED, + VKD3D_DATA_UINT8, + VKD3D_DATA_UINT64, ++ VKD3D_DATA_BOOL, ++ ++ VKD3D_DATA_COUNT, + }; + + static inline bool data_type_is_integer(enum vkd3d_data_type data_type) +@@ -582,11 +601,18 @@ static inline bool data_type_is_integer(enum vkd3d_data_type data_type) + || data_type == VKD3D_DATA_UINT64; + } + ++static inline bool data_type_is_bool(enum vkd3d_data_type data_type) ++{ ++ return data_type == VKD3D_DATA_BOOL; ++} ++ + enum vsir_dimension + { + VSIR_DIMENSION_NONE, + VSIR_DIMENSION_SCALAR, + VSIR_DIMENSION_VEC4, ++ ++ VSIR_DIMENSION_COUNT, + }; + + enum vkd3d_shader_src_modifier +@@ -915,6 +941,8 @@ struct shader_signature + unsigned int element_count; + }; + ++struct signature_element *vsir_signature_find_element_for_reg(const struct shader_signature *signature, ++ unsigned int reg_idx, unsigned int write_mask); + void shader_signature_cleanup(struct shader_signature *signature); + + struct vkd3d_shader_desc +@@ -933,6 +961,8 @@ struct vkd3d_shader_desc + { + uint32_t used, external; + } flat_constant_count[3]; ++ ++ bool use_vocp; + }; + + struct vkd3d_shader_register_semantic +@@ -1072,6 +1102,16 @@ struct vkd3d_shader_instruction + } declaration; + }; + ++static inline bool vkd3d_shader_ver_ge(const struct vkd3d_shader_version *v, unsigned int major, unsigned int minor) ++{ ++ return v->major > major || (v->major == major && v->minor >= minor); ++} ++ ++static inline bool vkd3d_shader_ver_le(const struct vkd3d_shader_version *v, unsigned int major, unsigned int minor) ++{ ++ return v->major < major || (v->major == major && v->minor <= minor); ++} ++ + void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, + enum vkd3d_shader_opcode handler_idx); + +@@ -1082,7 +1122,7 @@ static inline bool vkd3d_shader_instruction_has_texel_offset(const struct vkd3d_ + + static inline bool vkd3d_shader_register_is_input(const struct vkd3d_shader_register *reg) + { +- return reg->type == VKD3DSPR_INPUT || reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_OUTCONTROLPOINT; ++ return reg->type == VKD3DSPR_INPUT || reg->type == VKD3DSPR_INCONTROLPOINT; + } + + static inline bool vkd3d_shader_register_is_output(const struct vkd3d_shader_register *reg) +@@ -1314,8 +1354,7 @@ void vkd3d_shader_vnote(struct vkd3d_shader_message_context *context, const stru + void vkd3d_shader_vwarning(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location, + enum vkd3d_shader_error error, const char *format, va_list args); + +-void vkd3d_shader_dump_shader(enum vkd3d_shader_source_type source_type, +- enum vkd3d_shader_type shader_type, const struct vkd3d_shader_code *shader); ++void vkd3d_shader_dump_shader(const struct vkd3d_shader_compile_info *compile_info); + void vkd3d_shader_trace_text_(const char *text, size_t size, const char *function); + #define vkd3d_shader_trace_text(text, size) \ + vkd3d_shader_trace_text_(text, size, __FUNCTION__) +diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c +index 0b92cffcde3..2545c0f0433 100644 +--- a/libs/vkd3d/libs/vkd3d/state.c ++++ b/libs/vkd3d/libs/vkd3d/state.c +@@ -3605,6 +3605,36 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta + return vk_pipeline; + } + ++static int compile_hlsl_cs(const struct vkd3d_shader_code *hlsl, struct vkd3d_shader_code *dxbc) ++{ ++ struct vkd3d_shader_hlsl_source_info hlsl_info; ++ struct vkd3d_shader_compile_info info; ++ ++ static const struct vkd3d_shader_compile_option options[] = ++ { ++ {VKD3D_SHADER_COMPILE_OPTION_API_VERSION, VKD3D_SHADER_API_VERSION_1_9}, ++ }; ++ ++ info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO; ++ info.next = &hlsl_info; ++ info.source = *hlsl; ++ info.source_type = VKD3D_SHADER_SOURCE_HLSL; ++ info.target_type = VKD3D_SHADER_TARGET_DXBC_TPF; ++ info.options = options; ++ info.option_count = ARRAY_SIZE(options); ++ info.log_level = VKD3D_SHADER_LOG_NONE; ++ info.source_name = NULL; ++ ++ hlsl_info.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO; ++ hlsl_info.next = NULL; ++ hlsl_info.entry_point = "main"; ++ hlsl_info.secondary_code.code = NULL; ++ hlsl_info.secondary_code.size = 0; ++ hlsl_info.profile = "cs_5_0"; ++ ++ return vkd3d_shader_compile(&info, dxbc, NULL); ++} ++ + static void vkd3d_uav_clear_pipelines_cleanup(struct vkd3d_uav_clear_pipelines *pipelines, + struct d3d12_device *device) + { +@@ -3658,7 +3688,7 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d + { + VkPipeline *pipeline; + VkPipelineLayout *pipeline_layout; +- D3D12_SHADER_BYTECODE code; ++ struct vkd3d_shader_code code; + } + pipelines[] = + { +@@ -3748,13 +3778,25 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d + + for (i = 0; i < ARRAY_SIZE(pipelines); ++i) + { ++ struct vkd3d_shader_code dxbc; ++ int ret; ++ ++ if ((ret = compile_hlsl_cs(&pipelines[i].code, &dxbc))) ++ { ++ ERR("Failed to compile HLSL compute shader %u, ret %d.\n", i, ret); ++ hr = hresult_from_vk_result(ret); ++ goto fail; ++ } ++ + if (pipelines[i].pipeline_layout == &state->vk_pipeline_layout_buffer) + binding.flags = VKD3D_SHADER_BINDING_FLAG_BUFFER; + else + binding.flags = VKD3D_SHADER_BINDING_FLAG_IMAGE; + +- if (FAILED(hr = vkd3d_create_compute_pipeline(device, &pipelines[i].code, &shader_interface, +- *pipelines[i].pipeline_layout, pipelines[i].pipeline))) ++ hr = vkd3d_create_compute_pipeline(device, &(D3D12_SHADER_BYTECODE){dxbc.code, dxbc.size}, ++ &shader_interface, *pipelines[i].pipeline_layout, pipelines[i].pipeline); ++ vkd3d_shader_free_shader_code(&dxbc); ++ if (FAILED(hr)) + { + ERR("Failed to create compute pipeline %u, hr %#x.\n", i, hr); + goto fail; +diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_shaders.h b/libs/vkd3d/libs/vkd3d/vkd3d_shaders.h +index b2a90cdbf3c..3fefe0da849 100644 +--- a/libs/vkd3d/libs/vkd3d/vkd3d_shaders.h ++++ b/libs/vkd3d/libs/vkd3d/vkd3d_shaders.h +@@ -19,370 +19,208 @@ + #ifndef __VKD3D_SHADERS_H + #define __VKD3D_SHADERS_H + +-static const uint32_t cs_uav_clear_buffer_float_code[] = +-{ +-#if 0 +- RWBuffer dst; +- +- struct +- { +- float4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(128, 1, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (thread_id.x < u_info.dst_extent.x) +- dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0xe114ba61, 0xff6a0d0b, 0x7b25c8f4, 0xfcf7cf22, 0x00000001, 0x0000010c, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400089c, 0x0011e000, 0x00000000, 0x00005555, +- 0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000080, 0x00000001, 0x00000001, +- 0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f, +- 0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000, +- 0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000, +- 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_buffer_uint_code[] = +-{ +-#if 0 +- RWBuffer dst; +- +- struct +- { +- uint4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(128, 1, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (thread_id.x < u_info.dst_extent.x) +- dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x3afd0cfd, 0x5145c166, 0x5b9f76b8, 0xa73775cd, 0x00000001, 0x0000010c, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400089c, 0x0011e000, 0x00000000, 0x00004444, +- 0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000080, 0x00000001, 0x00000001, +- 0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f, +- 0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000, +- 0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000, +- 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_1d_array_float_code[] = +-{ +-#if 0 +- RWTexture1DArray dst; +- +- struct +- { +- float4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(64, 1, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (thread_id.x < u_info.dst_extent.x) +- dst[int2(u_info.dst_offset.x + thread_id.x, thread_id.y)] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x3d73bc2d, 0x2b635f3d, 0x6bf98e92, 0xbe0aa5d9, 0x00000001, 0x0000011c, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000c8, 0x00050050, 0x00000032, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400389c, 0x0011e000, 0x00000000, 0x00005555, +- 0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001, +- 0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f, +- 0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000, +- 0x00000001, 0x04000036, 0x001000e2, 0x00000000, 0x00020556, 0x080000a4, 0x0011e0f2, 0x00000000, +- 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_1d_array_uint_code[] = +-{ +-#if 0 +- RWTexture1DArray dst; +- +- struct +- { +- uint4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(64, 1, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (thread_id.x < u_info.dst_extent.x) +- dst[int2(u_info.dst_offset.x + thread_id.x, thread_id.y)] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x2f0ca457, 0x72068b34, 0xd9dadc2b, 0xd3178c3e, 0x00000001, 0x0000011c, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000c8, 0x00050050, 0x00000032, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400389c, 0x0011e000, 0x00000000, 0x00004444, +- 0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001, +- 0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f, +- 0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000, +- 0x00000001, 0x04000036, 0x001000e2, 0x00000000, 0x00020556, 0x080000a4, 0x0011e0f2, 0x00000000, +- 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_1d_float_code[] = +-{ +-#if 0 +- RWTexture1D dst; +- +- struct +- { +- float4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(64, 1, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (thread_id.x < u_info.dst_extent.x) +- dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x05266503, 0x4b97006f, 0x01a5cc63, 0xe617d0a1, 0x00000001, 0x0000010c, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400109c, 0x0011e000, 0x00000000, 0x00005555, +- 0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001, +- 0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f, +- 0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000, +- 0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000, +- 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_1d_uint_code[] = +-{ +-#if 0 +- RWTexture1D dst; +- +- struct +- { +- uint4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(64, 1, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (thread_id.x < u_info.dst_extent.x) +- dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x19d5c8f2, 0x3ca4ac24, 0x9e258499, 0xf0463fd6, 0x00000001, 0x0000010c, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000b8, 0x00050050, 0x0000002e, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400109c, 0x0011e000, 0x00000000, 0x00004444, +- 0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, 0x00000040, 0x00000001, 0x00000001, +- 0x07000022, 0x00100012, 0x00000000, 0x0002000a, 0x0020802a, 0x00000000, 0x00000001, 0x0304001f, +- 0x0010000a, 0x00000000, 0x0700001e, 0x00100012, 0x00000000, 0x0002000a, 0x0020800a, 0x00000000, +- 0x00000001, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100006, 0x00000000, 0x00208e46, 0x00000000, +- 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_2d_array_float_code[] = +-{ +-#if 0 +- RWTexture2DArray dst; +- +- struct +- { +- float4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(8, 8, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (all(thread_id.xy < u_info.dst_extent.xy)) +- dst[int3(u_info.dst_offset.xy + thread_id.xy, thread_id.z)] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x924d2d2c, 0xb9166376, 0x99f83871, 0x8ef65025, 0x00000001, 0x00000138, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400409c, 0x0011e000, 0x00000000, 0x00005555, +- 0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001, +- 0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001, +- 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, +- 0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001, +- 0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, +- 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_2d_array_uint_code[] = +-{ +-#if 0 +- RWTexture2DArray dst; +- +- struct +- { +- uint4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(8, 8, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (all(thread_id.xy < u_info.dst_extent.xy)) +- dst[int3(u_info.dst_offset.xy + thread_id.xy, thread_id.z)] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0xa92219d4, 0xa2c5e47d, 0x0d308500, 0xf32197b4, 0x00000001, 0x00000138, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400409c, 0x0011e000, 0x00000000, 0x00004444, +- 0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001, +- 0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001, +- 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, +- 0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001, +- 0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, +- 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_2d_float_code[] = +-{ +-#if 0 +- RWTexture2D dst; +- +- struct +- { +- float4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(8, 8, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (all(thread_id.xy < u_info.dst_extent.xy)) +- dst[u_info.dst_offset.xy + thread_id.xy] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x6e735b3f, 0x7348c4fa, 0xb3634e42, 0x50e2d99b, 0x00000001, 0x00000128, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000d4, 0x00050050, 0x00000035, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400189c, 0x0011e000, 0x00000000, 0x00005555, +- 0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001, +- 0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001, +- 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, +- 0x00000000, 0x0700001e, 0x001000f2, 0x00000000, 0x00020546, 0x00208546, 0x00000000, 0x00000001, +- 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, +- 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_2d_uint_code[] = +-{ +-#if 0 +- RWTexture2D dst; +- +- struct +- { +- uint4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(8, 8, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (all(thread_id.xy < u_info.dst_extent.xy)) +- dst[u_info.dst_offset.xy + thread_id.xy] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0xf01db5dd, 0xc7dc5e55, 0xb017c1a8, 0x55abd52d, 0x00000001, 0x00000128, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000d4, 0x00050050, 0x00000035, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400189c, 0x0011e000, 0x00000000, 0x00004444, +- 0x0200005f, 0x00020032, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001, +- 0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001, +- 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, +- 0x00000000, 0x0700001e, 0x001000f2, 0x00000000, 0x00020546, 0x00208546, 0x00000000, 0x00000001, +- 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, +- 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_3d_float_code[] = +-{ +-#if 0 +- RWTexture3D dst; +- +- struct +- { +- float4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(8, 8, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (all(thread_id.xy < u_info.dst_extent.xy)) +- dst[int3(u_info.dst_offset.xy, 0) + thread_id.xyz] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x5d8f36a0, 0x30fa86a5, 0xfec7f2ef, 0xdfd76cbb, 0x00000001, 0x00000138, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400289c, 0x0011e000, 0x00000000, 0x00005555, +- 0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001, +- 0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001, +- 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, +- 0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001, +- 0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, +- 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e, +-}; +- +-static const uint32_t cs_uav_clear_3d_uint_code[] = +-{ +-#if 0 +- RWTexture3D dst; +- +- struct +- { +- uint4 clear_value; +- int2 dst_offset; +- int2 dst_extent; +- } u_info; +- +- [numthreads(8, 8, 1)] +- void main(int3 thread_id : SV_DispatchThreadID) +- { +- if (all(thread_id.xy < u_info.dst_extent.xy)) +- dst[int3(u_info.dst_offset.xy, 0) + thread_id.xyz] = u_info.clear_value; +- } +-#endif +- 0x43425844, 0x5b9c95b1, 0xc9bde4e3, 0x9aaff806, 0x24a1d264, 0x00000001, 0x00000138, 0x00000003, +- 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, +- 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000000e4, 0x00050050, 0x00000039, 0x0100086a, +- 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0400289c, 0x0011e000, 0x00000000, 0x00004444, +- 0x0200005f, 0x00020072, 0x02000068, 0x00000001, 0x0400009b, 0x00000008, 0x00000008, 0x00000001, +- 0x07000022, 0x00100032, 0x00000000, 0x00020046, 0x00208ae6, 0x00000000, 0x00000001, 0x07000001, +- 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, +- 0x00000000, 0x0700001e, 0x00100032, 0x00000000, 0x00020046, 0x00208046, 0x00000000, 0x00000001, +- 0x04000036, 0x001000c2, 0x00000000, 0x00020aa6, 0x080000a4, 0x0011e0f2, 0x00000000, 0x00100e46, +- 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x01000015, 0x0100003e, +-}; ++static const char cs_uav_clear_buffer_float_code[] = ++ "RWBuffer dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " float4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(128, 1, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (thread_id.x < u_info.dst_extent.x)\n" ++ " dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_buffer_uint_code[] = ++ "RWBuffer dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " uint4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(128, 1, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (thread_id.x < u_info.dst_extent.x)\n" ++ " dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_1d_array_float_code[] = ++ "RWTexture1DArray dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " float4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(64, 1, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (thread_id.x < u_info.dst_extent.x)\n" ++ " dst[int2(u_info.dst_offset.x + thread_id.x, thread_id.y)] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_1d_array_uint_code[] = ++ "RWTexture1DArray dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " uint4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(64, 1, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (thread_id.x < u_info.dst_extent.x)\n" ++ " dst[int2(u_info.dst_offset.x + thread_id.x, thread_id.y)] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_1d_float_code[] = ++ "RWTexture1D dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " float4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(64, 1, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (thread_id.x < u_info.dst_extent.x)\n" ++ " dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_1d_uint_code[] = ++ "RWTexture1D dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " uint4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(64, 1, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (thread_id.x < u_info.dst_extent.x)\n" ++ " dst[u_info.dst_offset.x + thread_id.x] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_2d_array_float_code[] = ++ "RWTexture2DArray dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " float4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(8, 8, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (all(thread_id.xy < u_info.dst_extent.xy))\n" ++ " dst[int3(u_info.dst_offset.xy + thread_id.xy, thread_id.z)] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_2d_array_uint_code[] = ++ "RWTexture2DArray dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " uint4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(8, 8, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (all(thread_id.xy < u_info.dst_extent.xy))\n" ++ " dst[int3(u_info.dst_offset.xy + thread_id.xy, thread_id.z)] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_2d_float_code[] = ++ "RWTexture2D dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " float4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(8, 8, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (all(thread_id.xy < u_info.dst_extent.xy))\n" ++ " dst[u_info.dst_offset.xy + thread_id.xy] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_2d_uint_code[] = ++ "RWTexture2D dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " uint4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(8, 8, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (all(thread_id.xy < u_info.dst_extent.xy))\n" ++ " dst[u_info.dst_offset.xy + thread_id.xy] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_3d_float_code[] = ++ "RWTexture3D dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " float4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(8, 8, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (all(thread_id.xy < u_info.dst_extent.xy))\n" ++ " dst[int3(u_info.dst_offset.xy, 0) + thread_id.xyz] = u_info.clear_value;\n" ++ "}\n"; ++ ++static const char cs_uav_clear_3d_uint_code[] = ++ "RWTexture3D dst;\n" ++ "\n" ++ "struct\n" ++ "{\n" ++ " uint4 clear_value;\n" ++ " int2 dst_offset;\n" ++ " int2 dst_extent;\n" ++ "} u_info;\n" ++ "\n" ++ "[numthreads(8, 8, 1)]\n" ++ "void main(int3 thread_id : SV_DispatchThreadID)\n" ++ "{\n" ++ " if (all(thread_id.xy < u_info.dst_extent.xy))\n" ++ " dst[int3(u_info.dst_offset.xy, 0) + thread_id.xyz] = u_info.clear_value;\n" ++ "}\n"; + + #endif /* __VKD3D_SHADERS_H */ +-- +2.42.0 +