From 3695e096530ed650ce08207f8193af028ec85242 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 3 Oct 2024 12:53:56 +1000 Subject: [PATCH] updated vkd3d-latest patchset --- ...-2ac7f650a196e47a18ea1957eac5953255c.patch | 10160 ++++++++++++++++ ...-6d28cc131b0cad61c681aed6b9f6611a12b.patch | 1260 -- ...-0a6bcf5da78863cc6402756a429b21b6234.patch | 2749 ----- ...-a2aeb3a1421c5540b7f4d0e68ec3ff211e1.patch | 949 ++ ...-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch | 619 - ...-e8b14d765dbebae32d83aa5d2a7521932d9.patch | 303 + ...-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch | 485 - ...-f28d39b609036ce9bc3a4baaf6cda012fc2.patch | 1233 ++ ...-ab525f31e43a0f3c04c76b799aae88c1268.patch | 1436 --- ...-ae27fded1a039fda84b526cd9bd7b64aeb5.patch | 1977 +++ ...-4c03cda3c77123a71590b872acdc216e362.patch | 1823 --- ...-3e012c355db12ecad32d45a76058c29a407.patch | 2281 ---- ...-a1487380bb69c6ec07495c1a6eef4cfb224.patch | 1125 -- ...-32ced3bd8f52e19d184c8191f420dcb7bad.patch | 820 -- ...-2ac7f650a196e47a18ea1957eac5953255c.patch | 520 - patches/vkd3d-latest/definition | 7 - 16 files changed, 14622 insertions(+), 13125 deletions(-) create mode 100644 patches/vkd3d-latest/0001-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch delete mode 100644 patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch delete mode 100644 patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch create mode 100644 patches/vkd3d-latest/0002-Updated-vkd3d-to-a2aeb3a1421c5540b7f4d0e68ec3ff211e1.patch delete mode 100644 patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch create mode 100644 patches/vkd3d-latest/0003-Updated-vkd3d-to-e8b14d765dbebae32d83aa5d2a7521932d9.patch delete mode 100644 patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch create mode 100644 patches/vkd3d-latest/0004-Updated-vkd3d-to-f28d39b609036ce9bc3a4baaf6cda012fc2.patch delete mode 100644 patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch create mode 100644 patches/vkd3d-latest/0005-Updated-vkd3d-to-ae27fded1a039fda84b526cd9bd7b64aeb5.patch delete mode 100644 patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch delete mode 100644 patches/vkd3d-latest/0007-Updated-vkd3d-to-3e012c355db12ecad32d45a76058c29a407.patch delete mode 100644 patches/vkd3d-latest/0008-Updated-vkd3d-to-a1487380bb69c6ec07495c1a6eef4cfb224.patch delete mode 100644 patches/vkd3d-latest/0009-Updated-vkd3d-to-32ced3bd8f52e19d184c8191f420dcb7bad.patch delete mode 100644 patches/vkd3d-latest/0010-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch delete mode 100644 patches/vkd3d-latest/definition diff --git a/patches/vkd3d-latest/0001-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch b/patches/vkd3d-latest/0001-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch new file mode 100644 index 00000000..749b83f6 --- /dev/null +++ b/patches/vkd3d-latest/0001-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch @@ -0,0 +1,10160 @@ +From 8197153f5099eec17d017d9369b8e23a37963dba Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Tue, 3 Sep 2024 07:18:49 +1000 +Subject: [PATCH] Updated vkd3d to 2ac7f650a196e47a18ea1957eac5953255cf424d. + +--- + libs/vkd3d/Makefile.in | 1 + + libs/vkd3d/include/private/vkd3d_common.h | 4 +- + libs/vkd3d/include/vkd3d_shader.h | 13 +- + libs/vkd3d/libs/vkd3d-common/blob.c | 1 + + libs/vkd3d/libs/vkd3d-shader/checksum.c | 49 +- + libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 6 +- + libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 1183 ++++-------- + libs/vkd3d/libs/vkd3d-shader/dxbc.c | 19 +- + libs/vkd3d/libs/vkd3d-shader/dxil.c | 4 +- + libs/vkd3d/libs/vkd3d-shader/fx.c | 106 +- + libs/vkd3d/libs/vkd3d-shader/glsl.c | 755 +++++++- + libs/vkd3d/libs/vkd3d-shader/hlsl.c | 198 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.h | 70 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.l | 2 + + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 509 ++++-- + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 1382 +++++++++++++- + .../libs/vkd3d-shader/hlsl_constant_ops.c | 20 +- + libs/vkd3d/libs/vkd3d-shader/ir.c | 1605 +++++++++-------- + libs/vkd3d/libs/vkd3d-shader/msl.c | 275 +++ + libs/vkd3d/libs/vkd3d-shader/preproc.l | 1 + + libs/vkd3d/libs/vkd3d-shader/spirv.c | 134 +- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 554 +++++- + .../libs/vkd3d-shader/vkd3d_shader_main.c | 119 +- + .../libs/vkd3d-shader/vkd3d_shader_private.h | 53 +- + libs/vkd3d/libs/vkd3d/command.c | 50 +- + libs/vkd3d/libs/vkd3d/device.c | 1 + + libs/vkd3d/libs/vkd3d/state.c | 3 +- + libs/vkd3d/libs/vkd3d/utils.c | 3 +- + libs/vkd3d/libs/vkd3d/vkd3d_private.h | 4 +- + 29 files changed, 4987 insertions(+), 2137 deletions(-) + create mode 100644 libs/vkd3d/libs/vkd3d-shader/msl.c + +diff --git a/libs/vkd3d/Makefile.in b/libs/vkd3d/Makefile.in +index 94e4833dc9a..b073790d986 100644 +--- a/libs/vkd3d/Makefile.in ++++ b/libs/vkd3d/Makefile.in +@@ -25,6 +25,7 @@ SOURCES = \ + libs/vkd3d-shader/hlsl_codegen.c \ + libs/vkd3d-shader/hlsl_constant_ops.c \ + libs/vkd3d-shader/ir.c \ ++ libs/vkd3d-shader/msl.c \ + libs/vkd3d-shader/preproc.l \ + libs/vkd3d-shader/preproc.y \ + libs/vkd3d-shader/spirv.c \ +diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h +index 39145a97df1..fd62730f948 100644 +--- a/libs/vkd3d/include/private/vkd3d_common.h ++++ b/libs/vkd3d/include/private/vkd3d_common.h +@@ -62,6 +62,8 @@ + #define VKD3D_STRINGIFY(x) #x + #define VKD3D_EXPAND_AND_STRINGIFY(x) VKD3D_EXPAND(VKD3D_STRINGIFY(x)) + ++#define vkd3d_clamp(value, lower, upper) max(min(value, upper), lower) ++ + #define TAG_AON9 VKD3D_MAKE_TAG('A', 'o', 'n', '9') + #define TAG_DXBC VKD3D_MAKE_TAG('D', 'X', 'B', 'C') + #define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L') +@@ -273,7 +275,7 @@ static inline unsigned int vkd3d_popcount(unsigned int v) + { + #ifdef _MSC_VER + return __popcnt(v); +-#elif defined(__MINGW32__) ++#elif defined(HAVE_BUILTIN_POPCOUNT) + return __builtin_popcount(v); + #else + v -= (v >> 1) & 0x55555555; +diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h +index d9a355d3bc9..46feff35138 100644 +--- a/libs/vkd3d/include/vkd3d_shader.h ++++ b/libs/vkd3d/include/vkd3d_shader.h +@@ -1087,6 +1087,10 @@ enum vkd3d_shader_target_type + * Output is a raw FX section without container. \since 1.11 + */ + VKD3D_SHADER_TARGET_FX, ++ /** ++ * A 'Metal Shading Language' shader. \since 1.14 ++ */ ++ VKD3D_SHADER_TARGET_MSL, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TARGET_TYPE), + }; +@@ -1292,7 +1296,8 @@ typedef int (*PFN_vkd3d_shader_open_include)(const char *filename, bool local, + * vkd3d_shader_preprocess_info. + * + * \param code Contents of the included file, which were allocated by the +- * \ref pfn_open_include callback. The user must free them. ++ * vkd3d_shader_preprocess_info.pfn_open_include callback. ++ * The user must free them. + * + * \param context The user-defined pointer passed to struct + * vkd3d_shader_preprocess_info. +@@ -1319,8 +1324,8 @@ struct vkd3d_shader_preprocess_info + + /** + * Pointer to an array of predefined macros. Each macro in this array will +- * be expanded as if a corresponding #define statement were prepended to the +- * source code. ++ * be expanded as if a corresponding \#define statement were prepended to ++ * the source code. + * + * If the same macro is specified multiple times, only the last value is + * used. +@@ -2798,7 +2803,7 @@ VKD3D_SHADER_API void vkd3d_shader_free_scan_signature_info(struct vkd3d_shader_ + * \param input_signature The input signature of the second shader. + * + * \param count On output, contains the number of entries written into +- * \ref varyings. ++ * "varyings". + * + * \param varyings Pointer to an output array of varyings. + * This must point to space for N varyings, where N is the number of elements +diff --git a/libs/vkd3d/libs/vkd3d-common/blob.c b/libs/vkd3d/libs/vkd3d-common/blob.c +index f60ef7db769..c2c6ad67804 100644 +--- a/libs/vkd3d/libs/vkd3d-common/blob.c ++++ b/libs/vkd3d/libs/vkd3d-common/blob.c +@@ -20,6 +20,7 @@ + #define WIDL_C_INLINE_WRAPPERS + #endif + #define COBJMACROS ++ + #define CONST_VTABLE + #include "vkd3d.h" + #include "vkd3d_blob.h" +diff --git a/libs/vkd3d/libs/vkd3d-shader/checksum.c b/libs/vkd3d/libs/vkd3d-shader/checksum.c +index d9560628c77..45de1c92513 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/checksum.c ++++ b/libs/vkd3d/libs/vkd3d-shader/checksum.c +@@ -33,6 +33,11 @@ + * will fill a supplied 16-byte array with the digest. + */ + ++/* ++ * DXBC uses a variation of the MD5 algorithm, which only changes the way ++ * the message is padded in the final step. ++ */ ++ + #include "vkd3d_shader_private.h" + + #define DXBC_CHECKSUM_BLOCK_SIZE 64 +@@ -230,10 +235,9 @@ static void md5_update(struct md5_ctx *ctx, const unsigned char *buf, unsigned i + memcpy(ctx->in, buf, len); + } + +-static void dxbc_checksum_final(struct md5_ctx *ctx) ++static void md5_final(struct md5_ctx *ctx, enum vkd3d_md5_variant variant) + { + unsigned int padding; +- unsigned int length; + unsigned int count; + unsigned char *p; + +@@ -260,7 +264,7 @@ static void dxbc_checksum_final(struct md5_ctx *ctx) + /* Now fill the next block */ + memset(ctx->in, 0, DXBC_CHECKSUM_BLOCK_SIZE); + } +- else ++ else if (variant == VKD3D_MD5_DXBC) + { + /* Make place for bitcount at the beginning of the block */ + memmove(&ctx->in[4], ctx->in, count); +@@ -268,33 +272,44 @@ static void dxbc_checksum_final(struct md5_ctx *ctx) + /* Pad block to 60 bytes */ + memset(p + 4, 0, padding - 4); + } ++ else ++ { ++ /* Pad block to 56 bytes */ ++ memset(p, 0, padding - 8); ++ } + + /* Append length in bits and transform */ +- length = ctx->i[0]; +- memcpy(&ctx->in[0], &length, sizeof(length)); +- byte_reverse(&ctx->in[4], 14); +- length = ctx->i[0] >> 2 | 0x1; +- memcpy(&ctx->in[DXBC_CHECKSUM_BLOCK_SIZE - 4], &length, sizeof(length)); ++ if (variant == VKD3D_MD5_DXBC) ++ { ++ unsigned int length; ++ ++ length = ctx->i[0]; ++ memcpy(&ctx->in[0], &length, sizeof(length)); ++ byte_reverse(&ctx->in[4], 14); ++ length = ctx->i[0] >> 2 | 0x1; ++ memcpy(&ctx->in[DXBC_CHECKSUM_BLOCK_SIZE - 4], &length, sizeof(length)); ++ } ++ else ++ { ++ byte_reverse(ctx->in, 14); ++ ++ ((unsigned int *)ctx->in)[14] = ctx->i[0]; ++ ((unsigned int *)ctx->in)[15] = ctx->i[1]; ++ } + + md5_transform(ctx->buf, (unsigned int *)ctx->in); + byte_reverse((unsigned char *)ctx->buf, 4); + memcpy(ctx->digest, ctx->buf, 16); + } + +-#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20 +- +-void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]) ++void vkd3d_compute_md5(const void *data, size_t size, uint32_t checksum[4], enum vkd3d_md5_variant variant) + { +- const uint8_t *ptr = dxbc; ++ const uint8_t *ptr = data; + struct md5_ctx ctx; + +- VKD3D_ASSERT(size > DXBC_CHECKSUM_SKIP_BYTE_COUNT); +- ptr += DXBC_CHECKSUM_SKIP_BYTE_COUNT; +- size -= DXBC_CHECKSUM_SKIP_BYTE_COUNT; +- + md5_init(&ctx); + md5_update(&ctx, ptr, size); +- dxbc_checksum_final(&ctx); ++ md5_final(&ctx, variant); + + memcpy(checksum, ctx.digest, sizeof(ctx.digest)); + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +index 77e9711300f..cfee053d49c 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +@@ -79,7 +79,7 @@ static const char * const shader_opcode_names[] = + [VKD3DSIH_DCL_INDEXABLE_TEMP ] = "dcl_indexableTemp", + [VKD3DSIH_DCL_INPUT ] = "dcl_input", + [VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT ] = "dcl_input_control_point_count", +- [VKD3DSIH_DCL_INPUT_PRIMITIVE ] = "dcl_inputPrimitive", ++ [VKD3DSIH_DCL_INPUT_PRIMITIVE ] = "dcl_inputprimitive", + [VKD3DSIH_DCL_INPUT_PS ] = "dcl_input_ps", + [VKD3DSIH_DCL_INPUT_PS_SGV ] = "dcl_input_ps_sgv", + [VKD3DSIH_DCL_INPUT_PS_SIV ] = "dcl_input_ps_siv", +@@ -89,7 +89,7 @@ static const char * const shader_opcode_names[] = + [VKD3DSIH_DCL_OUTPUT ] = "dcl_output", + [VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT ] = "dcl_output_control_point_count", + [VKD3DSIH_DCL_OUTPUT_SIV ] = "dcl_output_siv", +- [VKD3DSIH_DCL_OUTPUT_TOPOLOGY ] = "dcl_outputTopology", ++ [VKD3DSIH_DCL_OUTPUT_TOPOLOGY ] = "dcl_outputtopology", + [VKD3DSIH_DCL_RESOURCE_RAW ] = "dcl_resource_raw", + [VKD3DSIH_DCL_RESOURCE_STRUCTURED ] = "dcl_resource_structured", + [VKD3DSIH_DCL_SAMPLER ] = "dcl_sampler", +@@ -104,7 +104,7 @@ static const char * const shader_opcode_names[] = + [VKD3DSIH_DCL_UAV_RAW ] = "dcl_uav_raw", + [VKD3DSIH_DCL_UAV_STRUCTURED ] = "dcl_uav_structured", + [VKD3DSIH_DCL_UAV_TYPED ] = "dcl_uav_typed", +- [VKD3DSIH_DCL_VERTICES_OUT ] = "dcl_maxOutputVertexCount", ++ [VKD3DSIH_DCL_VERTICES_OUT ] = "dcl_maxout", + [VKD3DSIH_DDIV ] = "ddiv", + [VKD3DSIH_DEF ] = "def", + [VKD3DSIH_DEFAULT ] = "default", +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +index d05394c3ab7..10f2e5e5e6d 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +@@ -104,6 +104,19 @@ enum vkd3d_sm1_resource_type + VKD3D_SM1_RESOURCE_TEXTURE_3D = 0x4, + }; + ++enum vkd3d_sm1_misc_register ++{ ++ VKD3D_SM1_MISC_POSITION = 0x0, ++ VKD3D_SM1_MISC_FACE = 0x1, ++}; ++ ++enum vkd3d_sm1_rastout_register ++{ ++ VKD3D_SM1_RASTOUT_POSITION = 0x0, ++ VKD3D_SM1_RASTOUT_FOG = 0x1, ++ VKD3D_SM1_RASTOUT_POINT_SIZE = 0x2, ++}; ++ + enum vkd3d_sm1_opcode + { + VKD3D_SM1_OP_NOP = 0x00, +@@ -1272,7 +1285,8 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, st + sm1->end = &code[token_count]; + + /* Estimate instruction count to avoid reallocation in most shaders. */ +- if (!vsir_program_init(program, compile_info, &version, code_size != ~(size_t)0 ? token_count / 4u + 4 : 16)) ++ if (!vsir_program_init(program, compile_info, &version, ++ code_size != ~(size_t)0 ? token_count / 4u + 4 : 16, VSIR_CF_STRUCTURED)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + vkd3d_shader_parser_init(&sm1->p, program, message_context, compile_info->source_name); +@@ -1384,22 +1398,22 @@ bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, + {"depth", true, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_DEPTHOUT}, + {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_DEPTHOUT}, + {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_COLOROUT}, +- {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, D3DSMO_POSITION}, +- {"vface", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, D3DSMO_FACE}, +- {"vpos", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, D3DSMO_POSITION}, ++ {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, VKD3D_SM1_MISC_POSITION}, ++ {"vface", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, VKD3D_SM1_MISC_FACE}, ++ {"vpos", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, VKD3D_SM1_MISC_POSITION}, + + {"color", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_ATTROUT}, +- {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_FOG}, +- {"position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, +- {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_POINT_SIZE}, +- {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, ++ {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_FOG}, ++ {"position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, ++ {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POINT_SIZE}, ++ {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, + {"texcoord", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_TEXCRDOUT}, + + {"color", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_ATTROUT}, +- {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_FOG}, +- {"position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, +- {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_POINT_SIZE}, +- {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, ++ {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_FOG}, ++ {"position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, ++ {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POINT_SIZE}, ++ {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, + {"texcoord", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_TEXCRDOUT}, + }; + +@@ -1423,32 +1437,32 @@ bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, + } + + bool hlsl_sm1_usage_from_semantic(const char *semantic_name, +- uint32_t semantic_index, D3DDECLUSAGE *usage, uint32_t *usage_idx) ++ uint32_t semantic_index, enum vkd3d_decl_usage *usage, uint32_t *usage_idx) + { + static const struct + { + const char *name; +- D3DDECLUSAGE usage; ++ enum vkd3d_decl_usage usage; + } + semantics[] = + { +- {"binormal", D3DDECLUSAGE_BINORMAL}, +- {"blendindices", D3DDECLUSAGE_BLENDINDICES}, +- {"blendweight", D3DDECLUSAGE_BLENDWEIGHT}, +- {"color", D3DDECLUSAGE_COLOR}, +- {"depth", D3DDECLUSAGE_DEPTH}, +- {"fog", D3DDECLUSAGE_FOG}, +- {"normal", D3DDECLUSAGE_NORMAL}, +- {"position", D3DDECLUSAGE_POSITION}, +- {"positiont", D3DDECLUSAGE_POSITIONT}, +- {"psize", D3DDECLUSAGE_PSIZE}, +- {"sample", D3DDECLUSAGE_SAMPLE}, +- {"sv_depth", D3DDECLUSAGE_DEPTH}, +- {"sv_position", D3DDECLUSAGE_POSITION}, +- {"sv_target", D3DDECLUSAGE_COLOR}, +- {"tangent", D3DDECLUSAGE_TANGENT}, +- {"tessfactor", D3DDECLUSAGE_TESSFACTOR}, +- {"texcoord", D3DDECLUSAGE_TEXCOORD}, ++ {"binormal", VKD3D_DECL_USAGE_BINORMAL}, ++ {"blendindices", VKD3D_DECL_USAGE_BLEND_INDICES}, ++ {"blendweight", VKD3D_DECL_USAGE_BLEND_WEIGHT}, ++ {"color", VKD3D_DECL_USAGE_COLOR}, ++ {"depth", VKD3D_DECL_USAGE_DEPTH}, ++ {"fog", VKD3D_DECL_USAGE_FOG}, ++ {"normal", VKD3D_DECL_USAGE_NORMAL}, ++ {"position", VKD3D_DECL_USAGE_POSITION}, ++ {"positiont", VKD3D_DECL_USAGE_POSITIONT}, ++ {"psize", VKD3D_DECL_USAGE_PSIZE}, ++ {"sample", VKD3D_DECL_USAGE_SAMPLE}, ++ {"sv_depth", VKD3D_DECL_USAGE_DEPTH}, ++ {"sv_position", VKD3D_DECL_USAGE_POSITION}, ++ {"sv_target", VKD3D_DECL_USAGE_COLOR}, ++ {"tangent", VKD3D_DECL_USAGE_TANGENT}, ++ {"tessfactor", VKD3D_DECL_USAGE_TESS_FACTOR}, ++ {"texcoord", VKD3D_DECL_USAGE_TEXCOORD}, + }; + + unsigned int i; +@@ -1468,21 +1482,17 @@ bool hlsl_sm1_usage_from_semantic(const char *semantic_name, + + struct d3dbc_compiler + { ++ const struct vkd3d_sm1_opcode_info *opcode_table; + struct vsir_program *program; + struct vkd3d_bytecode_buffer buffer; + struct vkd3d_shader_message_context *message_context; +- +- /* OBJECTIVE: Store all the required information in the other fields so +- * that this hlsl_ctx is no longer necessary. */ +- struct hlsl_ctx *ctx; ++ bool failed; + }; + + static uint32_t sm1_version(enum vkd3d_shader_type type, unsigned int major, unsigned int minor) + { +- if (type == VKD3D_SHADER_TYPE_VERTEX) +- return D3DVS_VERSION(major, minor); +- else +- return D3DPS_VERSION(major, minor); ++ return vkd3d_make_u32(vkd3d_make_u16(minor, major), ++ type == VKD3D_SHADER_TYPE_VERTEX ? VKD3D_SM1_VS : VKD3D_SM1_PS); + } + + D3DXPARAMETER_CLASS hlsl_sm1_class(const struct hlsl_type *type) +@@ -1860,24 +1870,24 @@ void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buff + set_u32(buffer, creator_offset, offset - ctab_start); + + ctab_end = bytecode_align(buffer); +- set_u32(buffer, size_offset, vkd3d_make_u32(D3DSIO_COMMENT, (ctab_end - ctab_offset) / sizeof(uint32_t))); ++ set_u32(buffer, size_offset, vkd3d_make_u32(VKD3D_SM1_OP_COMMENT, (ctab_end - ctab_offset) / sizeof(uint32_t))); + } + + static uint32_t sm1_encode_register_type(enum vkd3d_shader_register_type type) + { +- return ((type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) +- | ((type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2); ++ return ((type << VKD3D_SM1_REGISTER_TYPE_SHIFT) & VKD3D_SM1_REGISTER_TYPE_MASK) ++ | ((type << VKD3D_SM1_REGISTER_TYPE_SHIFT2) & VKD3D_SM1_REGISTER_TYPE_MASK2); + } + + struct sm1_instruction + { +- D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode; ++ enum vkd3d_sm1_opcode opcode; + unsigned int flags; + + struct sm1_dst_register + { + enum vkd3d_shader_register_type type; +- D3DSHADER_PARAM_DSTMOD_TYPE mod; ++ enum vkd3d_shader_dst_modifier mod; + unsigned int writemask; + uint32_t reg; + } dst; +@@ -1885,7 +1895,7 @@ struct sm1_instruction + struct sm1_src_register + { + enum vkd3d_shader_register_type type; +- D3DSHADER_PARAM_SRCMOD_TYPE mod; ++ enum vkd3d_shader_src_modifier mod; + unsigned int swizzle; + uint32_t reg; + } srcs[4]; +@@ -1900,11 +1910,11 @@ static bool is_inconsequential_instr(const struct sm1_instruction *instr) + const struct sm1_dst_register *dst = &instr->dst; + unsigned int i; + +- if (instr->opcode != D3DSIO_MOV) ++ if (instr->opcode != VKD3D_SM1_OP_MOV) + return false; +- if (dst->mod != D3DSPDM_NONE) ++ if (dst->mod != VKD3DSPDM_NONE) + return false; +- if (src->mod != D3DSPSM_NONE) ++ if (src->mod != VKD3DSPSM_NONE) + return false; + if (src->type != dst->type) + return false; +@@ -1923,13 +1933,19 @@ static bool is_inconsequential_instr(const struct sm1_instruction *instr) + static void write_sm1_dst_register(struct vkd3d_bytecode_buffer *buffer, const struct sm1_dst_register *reg) + { + VKD3D_ASSERT(reg->writemask); +- put_u32(buffer, (1u << 31) | sm1_encode_register_type(reg->type) | reg->mod | (reg->writemask << 16) | reg->reg); ++ put_u32(buffer, VKD3D_SM1_INSTRUCTION_PARAMETER ++ | sm1_encode_register_type(reg->type) ++ | (reg->mod << VKD3D_SM1_DST_MODIFIER_SHIFT) ++ | (reg->writemask << VKD3D_SM1_WRITEMASK_SHIFT) | reg->reg); + } + + static void write_sm1_src_register(struct vkd3d_bytecode_buffer *buffer, + const struct sm1_src_register *reg) + { +- put_u32(buffer, (1u << 31) | sm1_encode_register_type(reg->type) | reg->mod | (reg->swizzle << 16) | reg->reg); ++ put_u32(buffer, VKD3D_SM1_INSTRUCTION_PARAMETER ++ | sm1_encode_register_type(reg->type) ++ | (reg->mod << VKD3D_SM1_SRC_MODIFIER_SHIFT) ++ | (reg->swizzle << VKD3D_SM1_SWIZZLE_SHIFT) | reg->reg); + } + + static void d3dbc_write_instruction(struct d3dbc_compiler *d3dbc, const struct sm1_instruction *instr) +@@ -1945,7 +1961,7 @@ static void d3dbc_write_instruction(struct d3dbc_compiler *d3dbc, const struct s + token |= VKD3D_SM1_INSTRUCTION_FLAGS_MASK & (instr->flags << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT); + + if (version->major > 1) +- token |= (instr->has_dst + instr->src_count) << D3DSI_INSTLENGTH_SHIFT; ++ token |= (instr->has_dst + instr->src_count) << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; + put_u32(buffer, token); + + if (instr->has_dst) +@@ -1955,346 +1971,112 @@ static void d3dbc_write_instruction(struct d3dbc_compiler *d3dbc, const struct s + write_sm1_src_register(buffer, &instr->srcs[i]); + }; + +-static void sm1_map_src_swizzle(struct sm1_src_register *src, unsigned int map_writemask) +-{ +- src->swizzle = hlsl_map_swizzle(src->swizzle, map_writemask); +-} +- +-static void d3dbc_write_dp2add(struct d3dbc_compiler *d3dbc, const struct hlsl_reg *dst, +- const struct hlsl_reg *src1, const struct hlsl_reg *src2, const struct hlsl_reg *src3) ++static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info_from_vsir( ++ struct d3dbc_compiler *d3dbc, enum vkd3d_shader_opcode vkd3d_opcode) + { +- struct sm1_instruction instr = +- { +- .opcode = D3DSIO_DP2ADD, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.writemask = dst->writemask, +- .dst.reg = dst->id, +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), +- .srcs[0].reg = src1->id, +- .srcs[1].type = VKD3DSPR_TEMP, +- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), +- .srcs[1].reg = src2->id, +- .srcs[2].type = VKD3DSPR_TEMP, +- .srcs[2].swizzle = hlsl_swizzle_from_writemask(src3->writemask), +- .srcs[2].reg = src3->id, +- .src_count = 3, +- }; +- +- d3dbc_write_instruction(d3dbc, &instr); +-} +- +-static void d3dbc_write_ternary_op(struct d3dbc_compiler *d3dbc, +- D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, const struct hlsl_reg *dst, +- const struct hlsl_reg *src1, const struct hlsl_reg *src2, const struct hlsl_reg *src3) +-{ +- struct sm1_instruction instr = +- { +- .opcode = opcode, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.writemask = dst->writemask, +- .dst.reg = dst->id, +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), +- .srcs[0].reg = src1->id, +- .srcs[1].type = VKD3DSPR_TEMP, +- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), +- .srcs[1].reg = src2->id, +- .srcs[2].type = VKD3DSPR_TEMP, +- .srcs[2].swizzle = hlsl_swizzle_from_writemask(src3->writemask), +- .srcs[2].reg = src3->id, +- .src_count = 3, +- }; +- +- sm1_map_src_swizzle(&instr.srcs[0], instr.dst.writemask); +- sm1_map_src_swizzle(&instr.srcs[1], instr.dst.writemask); +- sm1_map_src_swizzle(&instr.srcs[2], instr.dst.writemask); +- d3dbc_write_instruction(d3dbc, &instr); +-} +- +-static void d3dbc_write_binary_op(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, +- const struct hlsl_reg *dst, const struct hlsl_reg *src1, const struct hlsl_reg *src2) +-{ +- struct sm1_instruction instr = +- { +- .opcode = opcode, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.writemask = dst->writemask, +- .dst.reg = dst->id, +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), +- .srcs[0].reg = src1->id, +- .srcs[1].type = VKD3DSPR_TEMP, +- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), +- .srcs[1].reg = src2->id, +- .src_count = 2, +- }; +- +- sm1_map_src_swizzle(&instr.srcs[0], instr.dst.writemask); +- sm1_map_src_swizzle(&instr.srcs[1], instr.dst.writemask); +- d3dbc_write_instruction(d3dbc, &instr); +-} ++ const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; ++ const struct vkd3d_sm1_opcode_info *info; ++ unsigned int i = 0; + +-static void d3dbc_write_dot(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, +- const struct hlsl_reg *dst, const struct hlsl_reg *src1, const struct hlsl_reg *src2) +-{ +- struct sm1_instruction instr = ++ for (;;) + { +- .opcode = opcode, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.writemask = dst->writemask, +- .dst.reg = dst->id, +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), +- .srcs[0].reg = src1->id, +- .srcs[1].type = VKD3DSPR_TEMP, +- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), +- .srcs[1].reg = src2->id, +- .src_count = 2, +- }; ++ info = &d3dbc->opcode_table[i++]; ++ if (info->vkd3d_opcode == VKD3DSIH_INVALID) ++ return NULL; + +- d3dbc_write_instruction(d3dbc, &instr); ++ if (vkd3d_opcode == info->vkd3d_opcode ++ && vkd3d_shader_ver_ge(version, info->min_version.major, info->min_version.minor) ++ && (vkd3d_shader_ver_le(version, info->max_version.major, info->max_version.minor) ++ || !info->max_version.major)) ++ return info; ++ } + } + +-static void d3dbc_write_unary_op(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, +- const struct hlsl_reg *dst, const struct hlsl_reg *src, +- D3DSHADER_PARAM_SRCMOD_TYPE src_mod, D3DSHADER_PARAM_DSTMOD_TYPE dst_mod) ++static uint32_t swizzle_from_vsir(uint32_t swizzle) + { +- struct sm1_instruction instr = +- { +- .opcode = opcode, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.mod = dst_mod, +- .dst.writemask = dst->writemask, +- .dst.reg = dst->id, +- .has_dst = 1, ++ uint32_t x = vsir_swizzle_get_component(swizzle, 0); ++ uint32_t y = vsir_swizzle_get_component(swizzle, 1); ++ uint32_t z = vsir_swizzle_get_component(swizzle, 2); ++ uint32_t w = vsir_swizzle_get_component(swizzle, 3); + +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src->writemask), +- .srcs[0].reg = src->id, +- .srcs[0].mod = src_mod, +- .src_count = 1, +- }; ++ if (x & ~0x3u || y & ~0x3u || z & ~0x3u || w & ~0x3u) ++ ERR("Unexpected vsir swizzle: 0x%08x.\n", swizzle); + +- sm1_map_src_swizzle(&instr.srcs[0], instr.dst.writemask); +- d3dbc_write_instruction(d3dbc, &instr); ++ return ((x & 0x3u) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(0)) ++ | ((y & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(1)) ++ | ((z & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(2)) ++ | ((w & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(3)); + } + +-static void d3dbc_write_cast(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) ++static void sm1_src_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_src_param *param, ++ struct sm1_src_register *src, const struct vkd3d_shader_location *loc) + { +- struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); +- const struct hlsl_ir_node *arg1 = expr->operands[0].node; +- const struct hlsl_type *dst_type = expr->node.data_type; +- const struct hlsl_type *src_type = arg1->data_type; +- struct hlsl_ctx *ctx = d3dbc->ctx; ++ src->mod = param->modifiers; ++ src->reg = param->reg.idx[0].offset; ++ src->type = param->reg.type; ++ src->swizzle = swizzle_from_vsir(param->swizzle); + +- /* Narrowing casts were already lowered. */ +- VKD3D_ASSERT(src_type->dimx == dst_type->dimx); +- +- switch (dst_type->e.numeric.type) ++ if (param->reg.idx[0].rel_addr) + { +- case HLSL_TYPE_HALF: +- case HLSL_TYPE_FLOAT: +- switch (src_type->e.numeric.type) +- { +- case HLSL_TYPE_INT: +- case HLSL_TYPE_UINT: +- case HLSL_TYPE_BOOL: +- /* Integrals are internally represented as floats, so no change is necessary.*/ +- case HLSL_TYPE_HALF: +- case HLSL_TYPE_FLOAT: +- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); +- break; +- +- case HLSL_TYPE_DOUBLE: +- hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to float."); +- break; +- +- default: +- vkd3d_unreachable(); +- } +- break; +- +- case HLSL_TYPE_INT: +- case HLSL_TYPE_UINT: +- switch(src_type->e.numeric.type) +- { +- case HLSL_TYPE_HALF: +- case HLSL_TYPE_FLOAT: +- /* A compilation pass turns these into FLOOR+REINTERPRET, so we should not +- * reach this case unless we are missing something. */ +- hlsl_fixme(ctx, &instr->loc, "Unlowered SM1 cast from float to integer."); +- break; +- case HLSL_TYPE_INT: +- case HLSL_TYPE_UINT: +- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); +- break; +- +- case HLSL_TYPE_BOOL: +- hlsl_fixme(ctx, &instr->loc, "SM1 cast from bool to integer."); +- break; +- +- case HLSL_TYPE_DOUBLE: +- hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to integer."); +- break; +- +- default: +- vkd3d_unreachable(); +- } +- break; +- +- case HLSL_TYPE_DOUBLE: +- hlsl_fixme(ctx, &instr->loc, "SM1 cast to double."); +- break; +- +- case HLSL_TYPE_BOOL: +- /* Casts to bool should have already been lowered. */ +- default: +- hlsl_fixme(ctx, &expr->node.loc, "SM1 cast from %s to %s.", +- debug_hlsl_type(ctx, src_type), debug_hlsl_type(ctx, dst_type)); +- break; ++ vkd3d_shader_error(d3dbc->message_context, loc, VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED, ++ "Unhandled relative addressing on source register."); ++ d3dbc->failed = true; + } + } + +-static void d3dbc_write_constant_defs(struct d3dbc_compiler *d3dbc) ++static void sm1_dst_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_dst_param *param, ++ struct sm1_dst_register *dst, const struct vkd3d_shader_location *loc) + { +- const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; +- struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; +- struct hlsl_ctx *ctx = d3dbc->ctx; +- unsigned int i, x; ++ dst->mod = param->modifiers; ++ dst->reg = param->reg.idx[0].offset; ++ dst->type = param->reg.type; ++ dst->writemask = param->write_mask; + +- for (i = 0; i < ctx->constant_defs.count; ++i) ++ if (param->reg.idx[0].rel_addr) + { +- const struct hlsl_constant_register *constant_reg = &ctx->constant_defs.regs[i]; +- uint32_t token = D3DSIO_DEF; +- const struct sm1_dst_register reg = +- { +- .type = VKD3DSPR_CONST, +- .writemask = VKD3DSP_WRITEMASK_ALL, +- .reg = constant_reg->index, +- }; +- +- if (version->major > 1) +- token |= 5 << D3DSI_INSTLENGTH_SHIFT; +- put_u32(buffer, token); +- +- write_sm1_dst_register(buffer, ®); +- for (x = 0; x < 4; ++x) +- put_f32(buffer, constant_reg->value.f[x]); ++ vkd3d_shader_error(d3dbc->message_context, loc, VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED, ++ "Unhandled relative addressing on destination register."); ++ d3dbc->failed = true; + } + } + +-static void d3dbc_write_semantic_dcl(struct d3dbc_compiler *d3dbc, +- const struct signature_element *element, bool output) ++static void d3dbc_write_vsir_def(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) + { + const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; + struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; +- struct sm1_dst_register reg = {0}; +- uint32_t token, usage_idx; +- D3DDECLUSAGE usage; +- bool ret; ++ uint32_t token; + +- if (hlsl_sm1_register_from_semantic(version, element->semantic_name, +- element->semantic_index, output, ®.type, ®.reg)) +- { +- usage = 0; +- usage_idx = 0; +- } +- else ++ const struct sm1_dst_register reg = + { +- ret = hlsl_sm1_usage_from_semantic(element->semantic_name, element->semantic_index, &usage, &usage_idx); +- VKD3D_ASSERT(ret); +- reg.type = output ? VKD3DSPR_OUTPUT : VKD3DSPR_INPUT; +- reg.reg = element->register_index; +- } ++ .type = VKD3DSPR_CONST, ++ .writemask = VKD3DSP_WRITEMASK_ALL, ++ .reg = ins->dst[0].reg.idx[0].offset, ++ }; + +- token = D3DSIO_DCL; ++ token = VKD3D_SM1_OP_DEF; + if (version->major > 1) +- token |= 2 << D3DSI_INSTLENGTH_SHIFT; ++ token |= 5 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; + put_u32(buffer, token); + +- token = (1u << 31); +- token |= usage << D3DSP_DCL_USAGE_SHIFT; +- token |= usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT; +- put_u32(buffer, token); +- +- reg.writemask = element->mask; + write_sm1_dst_register(buffer, ®); ++ for (unsigned int x = 0; x < 4; ++x) ++ put_f32(buffer, ins->src[0].reg.u.immconst_f32[x]); + } + +-static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc) +-{ +- struct vsir_program *program = d3dbc->program; +- const struct vkd3d_shader_version *version; +- bool write_in = false, write_out = false; +- +- version = &program->shader_version; +- if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major >= 2) +- write_in = true; +- else if (version->type == VKD3D_SHADER_TYPE_VERTEX && version->major == 3) +- write_in = write_out = true; +- else if (version->type == VKD3D_SHADER_TYPE_VERTEX && version->major < 3) +- write_in = true; +- +- if (write_in) +- { +- for (unsigned int i = 0; i < program->input_signature.element_count; ++i) +- d3dbc_write_semantic_dcl(d3dbc, &program->input_signature.elements[i], false); +- } +- +- if (write_out) +- { +- for (unsigned int i = 0; i < program->output_signature.element_count; ++i) +- d3dbc_write_semantic_dcl(d3dbc, &program->output_signature.elements[i], true); +- } +-} +- +-static void d3dbc_write_sampler_dcl(struct d3dbc_compiler *d3dbc, +- unsigned int reg_id, enum hlsl_sampler_dim sampler_dim) ++static void d3dbc_write_vsir_sampler_dcl(struct d3dbc_compiler *d3dbc, ++ unsigned int reg_id, enum vkd3d_sm1_resource_type res_type) + { + const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; + struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; + struct sm1_dst_register reg = {0}; +- uint32_t token, res_type = 0; ++ uint32_t token; + +- token = D3DSIO_DCL; ++ token = VKD3D_SM1_OP_DCL; + if (version->major > 1) +- token |= 2 << D3DSI_INSTLENGTH_SHIFT; ++ token |= 2 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; + put_u32(buffer, token); + +- switch (sampler_dim) +- { +- case HLSL_SAMPLER_DIM_2D: +- res_type = VKD3D_SM1_RESOURCE_TEXTURE_2D; +- break; +- +- case HLSL_SAMPLER_DIM_CUBE: +- res_type = VKD3D_SM1_RESOURCE_TEXTURE_CUBE; +- break; +- +- case HLSL_SAMPLER_DIM_3D: +- res_type = VKD3D_SM1_RESOURCE_TEXTURE_3D; +- break; +- +- default: +- vkd3d_unreachable(); +- break; +- } +- +- token = (1u << 31); ++ token = VKD3D_SM1_INSTRUCTION_PARAMETER; + token |= res_type << VKD3D_SM1_RESOURCE_TYPE_SHIFT; + put_u32(buffer, token); + +@@ -2305,618 +2087,283 @@ static void d3dbc_write_sampler_dcl(struct d3dbc_compiler *d3dbc, + write_sm1_dst_register(buffer, ®); + } + +-static void d3dbc_write_sampler_dcls(struct d3dbc_compiler *d3dbc) ++static void d3dbc_write_vsir_dcl(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) + { + const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; +- struct hlsl_ctx *ctx = d3dbc->ctx; +- enum hlsl_sampler_dim sampler_dim; +- unsigned int i, count, reg_id; +- struct hlsl_ir_var *var; ++ const struct vkd3d_shader_semantic *semantic = &ins->declaration.semantic; ++ unsigned int reg_id; + + if (version->major < 2) + return; + +- LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) +- { +- if (!var->regs[HLSL_REGSET_SAMPLERS].allocated) +- continue; +- +- count = var->bind_count[HLSL_REGSET_SAMPLERS]; ++ reg_id = semantic->resource.reg.reg.idx[0].offset; + +- for (i = 0; i < count; ++i) +- { +- if (var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) +- { +- sampler_dim = var->objects_usage[HLSL_REGSET_SAMPLERS][i].sampler_dim; +- if (sampler_dim == HLSL_SAMPLER_DIM_GENERIC) +- { +- /* These can appear in sm4-style combined sample instructions. */ +- hlsl_fixme(ctx, &var->loc, "Generic samplers need to be lowered."); +- continue; +- } +- +- reg_id = var->regs[HLSL_REGSET_SAMPLERS].index + i; +- d3dbc_write_sampler_dcl(d3dbc, reg_id, sampler_dim); +- } +- } +- } +-} +- +-static void d3dbc_write_constant(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) +-{ +- const struct hlsl_ir_constant *constant = hlsl_ir_constant(instr); +- struct sm1_instruction sm1_instr = ++ if (semantic->resource.reg.reg.type != VKD3DSPR_SAMPLER) + { +- .opcode = D3DSIO_MOV, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.reg = instr->reg.id, +- .dst.writemask = instr->reg.writemask, +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_CONST, +- .srcs[0].reg = constant->reg.id, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(constant->reg.writemask), +- .src_count = 1, +- }; +- +- VKD3D_ASSERT(instr->reg.allocated); +- VKD3D_ASSERT(constant->reg.allocated); +- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); +- d3dbc_write_instruction(d3dbc, &sm1_instr); +-} +- +-static void d3dbc_write_per_component_unary_op(struct d3dbc_compiler *d3dbc, +- const struct hlsl_ir_node *instr, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode) +-{ +- struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); +- struct hlsl_ir_node *arg1 = expr->operands[0].node; +- unsigned int i; +- +- for (i = 0; i < instr->data_type->dimx; ++i) +- { +- struct hlsl_reg src = arg1->reg, dst = instr->reg; +- +- src.writemask = hlsl_combine_writemasks(src.writemask, 1u << i); +- dst.writemask = hlsl_combine_writemasks(dst.writemask, 1u << i); +- d3dbc_write_unary_op(d3dbc, opcode, &dst, &src, 0, 0); +- } +-} +- +-static void d3dbc_write_sincos(struct d3dbc_compiler *d3dbc, enum hlsl_ir_expr_op op, +- const struct hlsl_reg *dst, const struct hlsl_reg *src) +-{ +- struct sm1_instruction instr = +- { +- .opcode = D3DSIO_SINCOS, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.writemask = dst->writemask, +- .dst.reg = dst->id, +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src->writemask), +- .srcs[0].reg = src->id, +- .src_count = 1, +- }; +- +- if (op == HLSL_OP1_COS_REDUCED) +- VKD3D_ASSERT(dst->writemask == VKD3DSP_WRITEMASK_0); +- else /* HLSL_OP1_SIN_REDUCED */ +- VKD3D_ASSERT(dst->writemask == VKD3DSP_WRITEMASK_1); +- +- if (d3dbc->ctx->profile->major_version < 3) +- { +- instr.src_count = 3; +- +- instr.srcs[1].type = VKD3DSPR_CONST; +- instr.srcs[1].swizzle = hlsl_swizzle_from_writemask(VKD3DSP_WRITEMASK_ALL); +- instr.srcs[1].reg = d3dbc->ctx->d3dsincosconst1.id; +- +- instr.srcs[2].type = VKD3DSPR_CONST; +- instr.srcs[2].swizzle = hlsl_swizzle_from_writemask(VKD3DSP_WRITEMASK_ALL); +- instr.srcs[2].reg = d3dbc->ctx->d3dsincosconst2.id; +- } +- +- d3dbc_write_instruction(d3dbc, &instr); +-} +- +-static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) +-{ +- const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; +- struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); +- struct hlsl_ir_node *arg1 = expr->operands[0].node; +- struct hlsl_ir_node *arg2 = expr->operands[1].node; +- struct hlsl_ir_node *arg3 = expr->operands[2].node; +- struct hlsl_ctx *ctx = d3dbc->ctx; +- +- VKD3D_ASSERT(instr->reg.allocated); +- +- if (expr->op == HLSL_OP1_REINTERPRET) +- { +- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); +- return; +- } +- +- if (expr->op == HLSL_OP1_CAST) +- { +- d3dbc_write_cast(d3dbc, instr); ++ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_TYPE, ++ "dcl instruction with register type %u.", semantic->resource.reg.reg.type); ++ d3dbc->failed = true; + return; + } + +- if (instr->data_type->e.numeric.type != HLSL_TYPE_FLOAT) ++ switch (semantic->resource_type) + { +- /* These need to be lowered. */ +- hlsl_fixme(ctx, &instr->loc, "SM1 non-float expression."); +- return; +- } +- +- switch (expr->op) +- { +- case HLSL_OP1_ABS: +- d3dbc_write_unary_op(d3dbc, D3DSIO_ABS, &instr->reg, &arg1->reg, 0, 0); +- break; +- +- case HLSL_OP1_DSX: +- d3dbc_write_unary_op(d3dbc, D3DSIO_DSX, &instr->reg, &arg1->reg, 0, 0); +- break; +- +- case HLSL_OP1_DSY: +- d3dbc_write_unary_op(d3dbc, D3DSIO_DSY, &instr->reg, &arg1->reg, 0, 0); +- break; +- +- case HLSL_OP1_EXP2: +- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_EXP); +- break; +- +- case HLSL_OP1_LOG2: +- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_LOG); +- break; +- +- case HLSL_OP1_NEG: +- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, D3DSPSM_NEG, 0); +- break; +- +- case HLSL_OP1_SAT: +- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, D3DSPDM_SATURATE); +- break; +- +- case HLSL_OP1_RCP: +- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_RCP); +- break; +- +- case HLSL_OP1_RSQ: +- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_RSQ); +- break; +- +- case HLSL_OP1_COS_REDUCED: +- case HLSL_OP1_SIN_REDUCED: +- d3dbc_write_sincos(d3dbc, expr->op, &instr->reg, &arg1->reg); +- break; +- +- case HLSL_OP2_ADD: +- d3dbc_write_binary_op(d3dbc, D3DSIO_ADD, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- case HLSL_OP2_MAX: +- d3dbc_write_binary_op(d3dbc, D3DSIO_MAX, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- case HLSL_OP2_MIN: +- d3dbc_write_binary_op(d3dbc, D3DSIO_MIN, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- case HLSL_OP2_MUL: +- d3dbc_write_binary_op(d3dbc, D3DSIO_MUL, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- case HLSL_OP1_FRACT: +- d3dbc_write_unary_op(d3dbc, D3DSIO_FRC, &instr->reg, &arg1->reg, D3DSPSM_NONE, 0); +- break; +- +- case HLSL_OP2_DOT: +- switch (arg1->data_type->dimx) +- { +- case 4: +- d3dbc_write_dot(d3dbc, D3DSIO_DP4, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- case 3: +- d3dbc_write_dot(d3dbc, D3DSIO_DP3, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- default: +- vkd3d_unreachable(); +- } ++ case VKD3D_SHADER_RESOURCE_TEXTURE_2D: ++ d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_2D); + break; + +- case HLSL_OP2_LOGIC_AND: +- d3dbc_write_binary_op(d3dbc, D3DSIO_MIN, &instr->reg, &arg1->reg, &arg2->reg); ++ case VKD3D_SHADER_RESOURCE_TEXTURE_CUBE: ++ d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_CUBE); + break; + +- case HLSL_OP2_LOGIC_OR: +- d3dbc_write_binary_op(d3dbc, D3DSIO_MAX, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- case HLSL_OP2_SLT: +- if (version->type == VKD3D_SHADER_TYPE_PIXEL) +- hlsl_fixme(ctx, &instr->loc, "Lower SLT instructions for pixel shaders."); +- d3dbc_write_binary_op(d3dbc, D3DSIO_SLT, &instr->reg, &arg1->reg, &arg2->reg); +- break; +- +- case HLSL_OP3_CMP: +- if (version->type == VKD3D_SHADER_TYPE_VERTEX) +- hlsl_fixme(ctx, &instr->loc, "Lower CMP instructions for vertex shaders."); +- d3dbc_write_ternary_op(d3dbc, D3DSIO_CMP, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); +- break; +- +- case HLSL_OP3_DP2ADD: +- d3dbc_write_dp2add(d3dbc, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); +- break; +- +- case HLSL_OP3_MAD: +- d3dbc_write_ternary_op(d3dbc, D3DSIO_MAD, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); ++ case VKD3D_SHADER_RESOURCE_TEXTURE_3D: ++ d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_3D); + break; + + default: +- hlsl_fixme(ctx, &instr->loc, "SM1 \"%s\" expression.", debug_hlsl_expr_op(expr->op)); +- break; ++ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_RESOURCE_TYPE, ++ "dcl instruction with resource_type %u.", semantic->resource_type); ++ d3dbc->failed = true; ++ return; + } + } + +-static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block); +- +-static void d3dbc_write_if(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) ++static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info_from_vsir_instruction( ++ struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) + { +- const struct hlsl_ir_if *iff = hlsl_ir_if(instr); +- const struct hlsl_ir_node *condition; +- struct sm1_instruction sm1_ifc, sm1_else, sm1_endif; +- +- condition = iff->condition.node; +- VKD3D_ASSERT(condition->data_type->dimx == 1 && condition->data_type->dimy == 1); +- +- sm1_ifc = (struct sm1_instruction) +- { +- .opcode = D3DSIO_IFC, +- .flags = VKD3D_SHADER_REL_OP_NE, /* Make it a "if_ne" instruction. */ +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(condition->reg.writemask), +- .srcs[0].reg = condition->reg.id, +- .srcs[0].mod = 0, +- +- .srcs[1].type = VKD3DSPR_TEMP, +- .srcs[1].swizzle = hlsl_swizzle_from_writemask(condition->reg.writemask), +- .srcs[1].reg = condition->reg.id, +- .srcs[1].mod = D3DSPSM_NEG, +- +- .src_count = 2, +- }; +- d3dbc_write_instruction(d3dbc, &sm1_ifc); +- d3dbc_write_block(d3dbc, &iff->then_block); ++ const struct vkd3d_sm1_opcode_info *info; + +- if (!list_empty(&iff->else_block.instrs)) ++ if (!(info = shader_sm1_get_opcode_info_from_vsir(d3dbc, ins->opcode))) + { +- sm1_else = (struct sm1_instruction){.opcode = D3DSIO_ELSE}; +- d3dbc_write_instruction(d3dbc, &sm1_else); +- d3dbc_write_block(d3dbc, &iff->else_block); ++ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE, ++ "Opcode %#x not supported for shader profile.", ins->opcode); ++ d3dbc->failed = true; ++ return NULL; + } + +- sm1_endif = (struct sm1_instruction){.opcode = D3DSIO_ENDIF}; +- d3dbc_write_instruction(d3dbc, &sm1_endif); +-} +- +-static void d3dbc_write_jump(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) +-{ +- const struct hlsl_ir_jump *jump = hlsl_ir_jump(instr); +- +- switch (jump->type) ++ if (ins->dst_count != info->dst_count) + { +- case HLSL_IR_JUMP_DISCARD_NEG: +- { +- struct hlsl_reg *reg = &jump->condition.node->reg; +- +- struct sm1_instruction sm1_instr = +- { +- .opcode = D3DSIO_TEXKILL, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.reg = reg->id, +- .dst.writemask = reg->writemask, +- .has_dst = 1, +- }; +- +- d3dbc_write_instruction(d3dbc, &sm1_instr); +- break; +- } +- +- default: +- hlsl_fixme(d3dbc->ctx, &jump->node.loc, "Jump type %s.", hlsl_jump_type_to_string(jump->type)); ++ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT, ++ "Invalid destination count %u for vsir instruction %#x (expected %u).", ++ ins->dst_count, ins->opcode, info->dst_count); ++ d3dbc->failed = true; ++ return NULL; + } +-} +- +-static void d3dbc_write_load(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) +-{ +- const struct hlsl_ir_load *load = hlsl_ir_load(instr); +- struct hlsl_ctx *ctx = d3dbc->ctx; +- const struct hlsl_reg reg = hlsl_reg_from_deref(ctx, &load->src); +- struct sm1_instruction sm1_instr = +- { +- .opcode = D3DSIO_MOV, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.reg = instr->reg.id, +- .dst.writemask = instr->reg.writemask, +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].reg = reg.id, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(reg.writemask), +- .src_count = 1, +- }; +- +- VKD3D_ASSERT(instr->reg.allocated); +- +- if (load->src.var->is_uniform) ++ if (ins->src_count != info->src_count) + { +- VKD3D_ASSERT(reg.allocated); +- sm1_instr.srcs[0].type = VKD3DSPR_CONST; +- } +- else if (load->src.var->is_input_semantic) +- { +- if (!hlsl_sm1_register_from_semantic(&d3dbc->program->shader_version, load->src.var->semantic.name, +- load->src.var->semantic.index, false, &sm1_instr.srcs[0].type, &sm1_instr.srcs[0].reg)) +- { +- VKD3D_ASSERT(reg.allocated); +- sm1_instr.srcs[0].type = VKD3DSPR_INPUT; +- sm1_instr.srcs[0].reg = reg.id; +- } +- else +- sm1_instr.srcs[0].swizzle = hlsl_swizzle_from_writemask((1 << load->src.var->data_type->dimx) - 1); ++ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT, ++ "Invalid source count %u for vsir instruction %#x (expected %u).", ++ ins->src_count, ins->opcode, info->src_count); ++ d3dbc->failed = true; ++ return NULL; + } + +- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); +- d3dbc_write_instruction(d3dbc, &sm1_instr); ++ return info; + } + +-static void d3dbc_write_resource_load(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) ++static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, ++ const struct vkd3d_shader_instruction *ins) + { +- const struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr); +- struct hlsl_ir_node *coords = load->coords.node; +- struct hlsl_ir_node *ddx = load->ddx.node; +- struct hlsl_ir_node *ddy = load->ddy.node; +- unsigned int sampler_offset, reg_id; +- struct hlsl_ctx *ctx = d3dbc->ctx; +- struct sm1_instruction sm1_instr; ++ struct sm1_instruction instr = {0}; ++ const struct vkd3d_sm1_opcode_info *info; + +- sampler_offset = hlsl_offset_from_deref_safe(ctx, &load->resource); +- reg_id = load->resource.var->regs[HLSL_REGSET_SAMPLERS].index + sampler_offset; ++ if (!(info = shader_sm1_get_opcode_info_from_vsir_instruction(d3dbc, ins))) ++ return; + +- sm1_instr = (struct sm1_instruction) +- { +- .dst.type = VKD3DSPR_TEMP, +- .dst.reg = instr->reg.id, +- .dst.writemask = instr->reg.writemask, +- .has_dst = 1, ++ instr.opcode = info->sm1_opcode; ++ instr.flags = ins->flags; ++ instr.has_dst = info->dst_count; ++ instr.src_count = info->src_count; + +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].reg = coords->reg.id, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(coords->reg.writemask), ++ if (instr.has_dst) ++ sm1_dst_reg_from_vsir(d3dbc, &ins->dst[0], &instr.dst, &ins->location); ++ for (unsigned int i = 0; i < instr.src_count; ++i) ++ sm1_src_reg_from_vsir(d3dbc, &ins->src[i], &instr.srcs[i], &ins->location); + +- .srcs[1].type = VKD3DSPR_COMBINED_SAMPLER, +- .srcs[1].reg = reg_id, +- .srcs[1].swizzle = hlsl_swizzle_from_writemask(VKD3DSP_WRITEMASK_ALL), ++ d3dbc_write_instruction(d3dbc, &instr); ++} + +- .src_count = 2, +- }; ++static void d3dbc_write_vsir_instruction(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) ++{ ++ uint32_t writemask; + +- switch (load->load_type) ++ switch (ins->opcode) + { +- case HLSL_RESOURCE_SAMPLE: +- sm1_instr.opcode = D3DSIO_TEX; ++ case VKD3DSIH_DEF: ++ d3dbc_write_vsir_def(d3dbc, ins); + break; + +- case HLSL_RESOURCE_SAMPLE_PROJ: +- sm1_instr.opcode = D3DSIO_TEX; +- sm1_instr.opcode |= VKD3DSI_TEXLD_PROJECT << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT; ++ case VKD3DSIH_DCL: ++ d3dbc_write_vsir_dcl(d3dbc, ins); + break; + +- case HLSL_RESOURCE_SAMPLE_LOD_BIAS: +- sm1_instr.opcode = D3DSIO_TEX; +- sm1_instr.opcode |= VKD3DSI_TEXLD_BIAS << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT; ++ case VKD3DSIH_ABS: ++ case VKD3DSIH_ADD: ++ case VKD3DSIH_CMP: ++ case VKD3DSIH_DP2ADD: ++ case VKD3DSIH_DP3: ++ case VKD3DSIH_DP4: ++ case VKD3DSIH_DSX: ++ case VKD3DSIH_DSY: ++ case VKD3DSIH_ELSE: ++ case VKD3DSIH_ENDIF: ++ case VKD3DSIH_FRC: ++ case VKD3DSIH_IFC: ++ case VKD3DSIH_MAD: ++ case VKD3DSIH_MAX: ++ case VKD3DSIH_MIN: ++ case VKD3DSIH_MOV: ++ case VKD3DSIH_MUL: ++ case VKD3DSIH_SINCOS: ++ case VKD3DSIH_SLT: ++ case VKD3DSIH_TEX: ++ case VKD3DSIH_TEXKILL: ++ case VKD3DSIH_TEXLDD: ++ d3dbc_write_vsir_simple_instruction(d3dbc, ins); + break; + +- case HLSL_RESOURCE_SAMPLE_GRAD: +- sm1_instr.opcode = D3DSIO_TEXLDD; +- +- sm1_instr.srcs[2].type = VKD3DSPR_TEMP; +- sm1_instr.srcs[2].reg = ddx->reg.id; +- sm1_instr.srcs[2].swizzle = hlsl_swizzle_from_writemask(ddx->reg.writemask); +- +- sm1_instr.srcs[3].type = VKD3DSPR_TEMP; +- sm1_instr.srcs[3].reg = ddy->reg.id; +- sm1_instr.srcs[3].swizzle = hlsl_swizzle_from_writemask(ddy->reg.writemask); +- +- sm1_instr.src_count += 2; ++ case VKD3DSIH_EXP: ++ case VKD3DSIH_LOG: ++ case VKD3DSIH_RCP: ++ case VKD3DSIH_RSQ: ++ writemask = ins->dst->write_mask; ++ if (writemask != VKD3DSP_WRITEMASK_0 && writemask != VKD3DSP_WRITEMASK_1 ++ && writemask != VKD3DSP_WRITEMASK_2 && writemask != VKD3DSP_WRITEMASK_3) ++ { ++ vkd3d_shader_error(d3dbc->message_context, &ins->location, ++ VKD3D_SHADER_ERROR_D3DBC_INVALID_WRITEMASK, ++ "writemask %#x for vsir instruction with opcode %#x is not single component.", ++ writemask, ins->opcode); ++ d3dbc->failed = true; ++ } ++ d3dbc_write_vsir_simple_instruction(d3dbc, ins); + break; + + default: +- hlsl_fixme(ctx, &instr->loc, "Resource load type %u.", load->load_type); +- return; ++ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE, ++ "vsir instruction with opcode %#x.", ins->opcode); ++ d3dbc->failed = true; ++ break; + } +- +- VKD3D_ASSERT(instr->reg.allocated); +- +- d3dbc_write_instruction(d3dbc, &sm1_instr); + } + +-static void d3dbc_write_store(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) ++static void d3dbc_write_semantic_dcl(struct d3dbc_compiler *d3dbc, ++ const struct signature_element *element, bool output) + { + const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; +- const struct hlsl_ir_store *store = hlsl_ir_store(instr); +- struct hlsl_ctx *ctx = d3dbc->ctx; +- const struct hlsl_reg reg = hlsl_reg_from_deref(ctx, &store->lhs); +- const struct hlsl_ir_node *rhs = store->rhs.node; +- struct sm1_instruction sm1_instr = +- { +- .opcode = D3DSIO_MOV, +- +- .dst.type = VKD3DSPR_TEMP, +- .dst.reg = reg.id, +- .dst.writemask = hlsl_combine_writemasks(reg.writemask, store->writemask), +- .has_dst = 1, +- +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].reg = rhs->reg.id, +- .srcs[0].swizzle = hlsl_swizzle_from_writemask(rhs->reg.writemask), +- .src_count = 1, +- }; ++ struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; ++ struct sm1_dst_register reg = {0}; ++ enum vkd3d_decl_usage usage; ++ uint32_t token, usage_idx; ++ bool ret; + +- if (store->lhs.var->is_output_semantic) ++ if (hlsl_sm1_register_from_semantic(version, element->semantic_name, ++ element->semantic_index, output, ®.type, ®.reg)) + { +- if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major == 1) +- { +- sm1_instr.dst.type = VKD3DSPR_TEMP; +- sm1_instr.dst.reg = 0; +- } +- else if (!hlsl_sm1_register_from_semantic(&d3dbc->program->shader_version, store->lhs.var->semantic.name, +- store->lhs.var->semantic.index, true, &sm1_instr.dst.type, &sm1_instr.dst.reg)) +- { +- VKD3D_ASSERT(reg.allocated); +- sm1_instr.dst.type = VKD3DSPR_OUTPUT; +- sm1_instr.dst.reg = reg.id; +- } +- else +- sm1_instr.dst.writemask = (1u << store->lhs.var->data_type->dimx) - 1; ++ usage = 0; ++ usage_idx = 0; + } + else +- VKD3D_ASSERT(reg.allocated); +- +- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); +- d3dbc_write_instruction(d3dbc, &sm1_instr); +-} +- +-static void d3dbc_write_swizzle(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) +-{ +- const struct hlsl_ir_swizzle *swizzle = hlsl_ir_swizzle(instr); +- const struct hlsl_ir_node *val = swizzle->val.node; +- struct sm1_instruction sm1_instr = + { +- .opcode = D3DSIO_MOV, ++ ret = hlsl_sm1_usage_from_semantic(element->semantic_name, element->semantic_index, &usage, &usage_idx); ++ VKD3D_ASSERT(ret); ++ reg.type = output ? VKD3DSPR_OUTPUT : VKD3DSPR_INPUT; ++ reg.reg = element->register_index; ++ } + +- .dst.type = VKD3DSPR_TEMP, +- .dst.reg = instr->reg.id, +- .dst.writemask = instr->reg.writemask, +- .has_dst = 1, ++ token = VKD3D_SM1_OP_DCL; ++ if (version->major > 1) ++ token |= 2 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; ++ put_u32(buffer, token); + +- .srcs[0].type = VKD3DSPR_TEMP, +- .srcs[0].reg = val->reg.id, +- .srcs[0].swizzle = hlsl_combine_swizzles(hlsl_swizzle_from_writemask(val->reg.writemask), +- swizzle->swizzle, instr->data_type->dimx), +- .src_count = 1, +- }; ++ token = (1u << 31); ++ token |= usage << VKD3D_SM1_DCL_USAGE_SHIFT; ++ token |= usage_idx << VKD3D_SM1_DCL_USAGE_INDEX_SHIFT; ++ put_u32(buffer, token); + +- VKD3D_ASSERT(instr->reg.allocated); +- VKD3D_ASSERT(val->reg.allocated); +- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); +- d3dbc_write_instruction(d3dbc, &sm1_instr); ++ reg.writemask = element->mask; ++ write_sm1_dst_register(buffer, ®); + } + +-static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block) ++static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc) + { +- struct hlsl_ctx *ctx = d3dbc->ctx; +- const struct hlsl_ir_node *instr; +- +- LIST_FOR_EACH_ENTRY(instr, &block->instrs, struct hlsl_ir_node, entry) +- { +- if (instr->data_type) +- { +- if (instr->data_type->class != HLSL_CLASS_SCALAR && instr->data_type->class != HLSL_CLASS_VECTOR) +- { +- hlsl_fixme(ctx, &instr->loc, "Class %#x should have been lowered or removed.", instr->data_type->class); +- break; +- } +- } +- +- switch (instr->type) +- { +- case HLSL_IR_CALL: +- vkd3d_unreachable(); +- +- case HLSL_IR_CONSTANT: +- d3dbc_write_constant(d3dbc, instr); +- break; +- +- case HLSL_IR_EXPR: +- d3dbc_write_expr(d3dbc, instr); +- break; +- +- case HLSL_IR_IF: +- if (hlsl_version_ge(ctx, 2, 1)) +- d3dbc_write_if(d3dbc, instr); +- else +- hlsl_fixme(ctx, &instr->loc, "Flatten \"if\" conditionals branches."); +- break; +- +- case HLSL_IR_JUMP: +- d3dbc_write_jump(d3dbc, instr); +- break; ++ struct vsir_program *program = d3dbc->program; ++ const struct vkd3d_shader_version *version; ++ bool write_in = false, write_out = false; + +- case HLSL_IR_LOAD: +- d3dbc_write_load(d3dbc, instr); +- break; ++ version = &program->shader_version; ++ if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major >= 2) ++ write_in = true; ++ else if (version->type == VKD3D_SHADER_TYPE_VERTEX && version->major == 3) ++ write_in = write_out = true; ++ else if (version->type == VKD3D_SHADER_TYPE_VERTEX && version->major < 3) ++ write_in = true; + +- case HLSL_IR_RESOURCE_LOAD: +- d3dbc_write_resource_load(d3dbc, instr); +- break; ++ if (write_in) ++ { ++ for (unsigned int i = 0; i < program->input_signature.element_count; ++i) ++ d3dbc_write_semantic_dcl(d3dbc, &program->input_signature.elements[i], false); ++ } + +- case HLSL_IR_STORE: +- d3dbc_write_store(d3dbc, instr); +- break; ++ if (write_out) ++ { ++ for (unsigned int i = 0; i < program->output_signature.element_count; ++i) ++ d3dbc_write_semantic_dcl(d3dbc, &program->output_signature.elements[i], true); ++ } ++} + +- case HLSL_IR_SWIZZLE: +- d3dbc_write_swizzle(d3dbc, instr); +- break; ++static void d3dbc_write_program_instructions(struct d3dbc_compiler *d3dbc) ++{ ++ struct vsir_program *program = d3dbc->program; ++ unsigned int i; + +- default: +- hlsl_fixme(ctx, &instr->loc, "Instruction type %s.", hlsl_node_type_to_string(instr->type)); +- } +- } ++ for (i = 0; i < program->instructions.count; ++i) ++ d3dbc_write_vsir_instruction(d3dbc, &program->instructions.elements[i]); + } + +-/* OBJECTIVE: Stop relying on ctx and entry_func on this function, receiving +- * data from the other parameters instead, so it can be removed as an argument +- * and be declared in vkd3d_shader_private.h and used without relying on HLSL +- * IR structs. */ + int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_code *ctab, +- struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context, +- struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) ++ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) + { + const struct vkd3d_shader_version *version = &program->shader_version; + struct d3dbc_compiler d3dbc = {0}; + struct vkd3d_bytecode_buffer *buffer = &d3dbc.buffer; ++ int result; + +- d3dbc.ctx = ctx; + d3dbc.program = program; + d3dbc.message_context = message_context; ++ switch (version->type) ++ { ++ case VKD3D_SHADER_TYPE_VERTEX: ++ d3dbc.opcode_table = vs_opcode_table; ++ break; ++ ++ case VKD3D_SHADER_TYPE_PIXEL: ++ d3dbc.opcode_table = ps_opcode_table; ++ break; ++ ++ default: ++ vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_D3DBC_INVALID_PROFILE, ++ "Invalid shader type %u.", version->type); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } + + put_u32(buffer, sm1_version(version->type, version->major, version->minor)); + + bytecode_put_bytes(buffer, ctab->code, ctab->size); + +- d3dbc_write_constant_defs(&d3dbc); + d3dbc_write_semantic_dcls(&d3dbc); +- d3dbc_write_sampler_dcls(&d3dbc); +- d3dbc_write_block(&d3dbc, &entry_func->body); ++ d3dbc_write_program_instructions(&d3dbc); + +- put_u32(buffer, D3DSIO_END); ++ put_u32(buffer, VKD3D_SM1_OP_END); + ++ result = VKD3D_OK; + if (buffer->status) +- ctx->result = buffer->status; ++ result = buffer->status; ++ if (d3dbc.failed) ++ result = VKD3D_ERROR_INVALID_SHADER; + +- if (!ctx->result) ++ if (!result) + { + out->code = buffer->data; + out->size = buffer->size; +@@ -2925,5 +2372,5 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, + { + vkd3d_free(buffer->data); + } +- return ctx->result; ++ return result; + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/dxbc.c b/libs/vkd3d/libs/vkd3d-shader/dxbc.c +index 184788dc57e..93fc993e0d1 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/dxbc.c ++++ b/libs/vkd3d/libs/vkd3d-shader/dxbc.c +@@ -20,6 +20,19 @@ + + #include "vkd3d_shader_private.h" + ++#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20 ++ ++static void compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]) ++{ ++ const uint8_t *ptr = dxbc; ++ ++ VKD3D_ASSERT(size > DXBC_CHECKSUM_SKIP_BYTE_COUNT); ++ ptr += DXBC_CHECKSUM_SKIP_BYTE_COUNT; ++ size -= DXBC_CHECKSUM_SKIP_BYTE_COUNT; ++ ++ vkd3d_compute_md5(ptr, size, checksum, VKD3D_MD5_DXBC); ++} ++ + void dxbc_writer_init(struct dxbc_writer *dxbc) + { + memset(dxbc, 0, sizeof(*dxbc)); +@@ -72,7 +85,7 @@ int vkd3d_shader_serialize_dxbc(size_t section_count, const struct vkd3d_shader_ + } + set_u32(&buffer, size_position, bytecode_get_size(&buffer)); + +- vkd3d_compute_dxbc_checksum(buffer.data, buffer.size, checksum); ++ compute_dxbc_checksum(buffer.data, buffer.size, checksum); + for (i = 0; i < 4; ++i) + set_u32(&buffer, checksum_position + i * sizeof(uint32_t), checksum[i]); + +@@ -188,7 +201,7 @@ static int parse_dxbc(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_ + checksum[3] = read_u32(&ptr); + if (!(flags & VKD3D_SHADER_PARSE_DXBC_IGNORE_CHECKSUM)) + { +- vkd3d_compute_dxbc_checksum(data, data_size, calculated_checksum); ++ compute_dxbc_checksum(data, data_size, calculated_checksum); + if (memcmp(checksum, calculated_checksum, sizeof(checksum))) + { + WARN("Checksum {0x%08x, 0x%08x, 0x%08x, 0x%08x} does not match " +@@ -1488,7 +1501,7 @@ int vkd3d_shader_serialize_root_signature(const struct vkd3d_shader_versioned_ro + dxbc->code = context.buffer.data; + dxbc->size = total_size; + +- vkd3d_compute_dxbc_checksum(dxbc->code, dxbc->size, checksum); ++ compute_dxbc_checksum(dxbc->code, dxbc->size, checksum); + for (i = 0; i < 4; ++i) + set_u32(&context.buffer, (i + 1) * sizeof(uint32_t), checksum[i]); + +diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c +index 4a17c62292b..ee78b6251f9 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c ++++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c +@@ -3888,7 +3888,7 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade + if (is_control_point) + { + if (reg_type == VKD3DSPR_OUTPUT) +- param->reg.idx[count].rel_addr = instruction_array_create_outpointid_param(&sm6->p.program->instructions); ++ param->reg.idx[count].rel_addr = vsir_program_create_outpointid_param(sm6->p.program); + param->reg.idx[count++].offset = 0; + } + +@@ -10303,7 +10303,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro + + /* Estimate instruction count to avoid reallocation in most shaders. */ + count = max(token_count, 400) - 400; +- if (!vsir_program_init(program, compile_info, &version, (count + (count >> 2)) / 2u + 10)) ++ if (!vsir_program_init(program, compile_info, &version, (count + (count >> 2)) / 2u + 10, VSIR_CF_BLOCKS)) + return VKD3D_ERROR_OUT_OF_MEMORY; + vkd3d_shader_parser_init(&sm6->p, program, message_context, compile_info->source_name); + sm6->ptr = &sm6->start[1]; +diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c +index a1d1fd6572f..1314bc09e73 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/fx.c ++++ b/libs/vkd3d/libs/vkd3d-shader/fx.c +@@ -38,6 +38,7 @@ struct type_entry + struct list entry; + const char *name; + uint32_t elements_count; ++ uint32_t modifiers; + uint32_t offset; + }; + +@@ -278,9 +279,9 @@ static void write_fx_4_state_block(struct hlsl_ir_var *var, unsigned int block_i + + static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context *fx) + { ++ unsigned int elements_count, modifiers; + const struct hlsl_type *element_type; + struct type_entry *type_entry; +- unsigned int elements_count; + const char *name; + + VKD3D_ASSERT(fx->ctx->profile->major_version >= 4); +@@ -297,6 +298,7 @@ static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context + } + + name = get_fx_4_type_name(element_type); ++ modifiers = element_type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK; + + LIST_FOR_EACH_ENTRY(type_entry, &fx->types, struct type_entry, entry) + { +@@ -306,6 +308,9 @@ static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context + if (type_entry->elements_count != elements_count) + continue; + ++ if (type_entry->modifiers != modifiers) ++ continue; ++ + return type_entry->offset; + } + +@@ -315,6 +320,7 @@ static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context + type_entry->offset = write_fx_4_type(type, fx); + type_entry->name = name; + type_entry->elements_count = elements_count; ++ type_entry->modifiers = modifiers; + + list_add_tail(&fx->types, &type_entry->entry); + +@@ -564,6 +570,9 @@ static const char * get_fx_4_type_name(const struct hlsl_type *type) + case HLSL_CLASS_VERTEX_SHADER: + return "VertexShader"; + ++ case HLSL_CLASS_GEOMETRY_SHADER: ++ return "GeometryShader"; ++ + case HLSL_CLASS_PIXEL_SHADER: + return "PixelShader"; + +@@ -575,6 +584,12 @@ static const char * get_fx_4_type_name(const struct hlsl_type *type) + } + } + ++static bool is_numeric_fx_4_type(const struct hlsl_type *type) ++{ ++ type = hlsl_get_multiarray_element_type(type); ++ return type->class == HLSL_CLASS_STRUCT || hlsl_is_numeric_type(type); ++} ++ + static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx) + { + struct field_offsets +@@ -584,43 +599,41 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co + uint32_t offset; + uint32_t type; + }; +- uint32_t name_offset, offset, total_size, packed_size, stride, numeric_desc; ++ uint32_t name_offset, offset, unpacked_size, packed_size, stride, numeric_desc; + struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + struct field_offsets *field_offsets = NULL; ++ const struct hlsl_type *element_type; + struct hlsl_ctx *ctx = fx->ctx; + uint32_t elements_count = 0; + const char *name; + size_t i; + +- /* Resolve arrays to element type and number of elements. */ + if (type->class == HLSL_CLASS_ARRAY) +- { + elements_count = hlsl_get_multiarray_size(type); +- type = hlsl_get_multiarray_element_type(type); +- } ++ element_type = hlsl_get_multiarray_element_type(type); + +- name = get_fx_4_type_name(type); ++ name = get_fx_4_type_name(element_type); + + name_offset = write_string(name, fx); +- if (type->class == HLSL_CLASS_STRUCT) ++ if (element_type->class == HLSL_CLASS_STRUCT) + { +- if (!(field_offsets = hlsl_calloc(ctx, type->e.record.field_count, sizeof(*field_offsets)))) ++ if (!(field_offsets = hlsl_calloc(ctx, element_type->e.record.field_count, sizeof(*field_offsets)))) + return 0; + +- for (i = 0; i < type->e.record.field_count; ++i) ++ for (i = 0; i < element_type->e.record.field_count; ++i) + { +- const struct hlsl_struct_field *field = &type->e.record.fields[i]; ++ const struct hlsl_struct_field *field = &element_type->e.record.fields[i]; + + field_offsets[i].name = write_string(field->name, fx); + field_offsets[i].semantic = write_string(field->semantic.raw_name, fx); +- field_offsets[i].offset = field->reg_offset[HLSL_REGSET_NUMERIC]; ++ field_offsets[i].offset = field->reg_offset[HLSL_REGSET_NUMERIC] * sizeof(float); + field_offsets[i].type = write_type(field->type, fx); + } + } + + offset = put_u32_unaligned(buffer, name_offset); + +- switch (type->class) ++ switch (element_type->class) + { + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_VECTOR: +@@ -659,32 +672,32 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co + vkd3d_unreachable(); + + case HLSL_CLASS_VOID: +- FIXME("Writing type class %u is not implemented.\n", type->class); ++ FIXME("Writing type class %u is not implemented.\n", element_type->class); + set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); + return 0; + } + + /* Structures can only contain numeric fields, this is validated during variable declaration. */ +- total_size = stride = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); ++ unpacked_size = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); ++ + packed_size = 0; +- if (type->class == HLSL_CLASS_STRUCT || hlsl_is_numeric_type(type)) +- packed_size = hlsl_type_component_count(type) * sizeof(float); ++ if (is_numeric_fx_4_type(element_type)) ++ packed_size = hlsl_type_component_count(element_type) * sizeof(float); + if (elements_count) +- { +- total_size *= elements_count; + packed_size *= elements_count; +- } ++ ++ stride = element_type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); + stride = align(stride, 4 * sizeof(float)); + + put_u32_unaligned(buffer, elements_count); +- put_u32_unaligned(buffer, total_size); ++ put_u32_unaligned(buffer, unpacked_size); + put_u32_unaligned(buffer, stride); + put_u32_unaligned(buffer, packed_size); + +- if (type->class == HLSL_CLASS_STRUCT) ++ if (element_type->class == HLSL_CLASS_STRUCT) + { +- put_u32_unaligned(buffer, type->e.record.field_count); +- for (i = 0; i < type->e.record.field_count; ++i) ++ put_u32_unaligned(buffer, element_type->e.record.field_count); ++ for (i = 0; i < element_type->e.record.field_count; ++i) + { + const struct field_offsets *field = &field_offsets[i]; + +@@ -700,7 +713,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co + put_u32_unaligned(buffer, 0); /* Interface count */ + } + } +- else if (type->class == HLSL_CLASS_TEXTURE) ++ else if (element_type->class == HLSL_CLASS_TEXTURE) + { + static const uint32_t texture_type[] = + { +@@ -716,13 +729,13 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co + [HLSL_SAMPLER_DIM_CUBEARRAY] = 23, + }; + +- put_u32_unaligned(buffer, texture_type[type->sampler_dim]); ++ put_u32_unaligned(buffer, texture_type[element_type->sampler_dim]); + } +- else if (type->class == HLSL_CLASS_SAMPLER) ++ else if (element_type->class == HLSL_CLASS_SAMPLER) + { + put_u32_unaligned(buffer, 21); + } +- else if (type->class == HLSL_CLASS_UAV) ++ else if (element_type->class == HLSL_CLASS_UAV) + { + static const uint32_t uav_type[] = + { +@@ -735,60 +748,60 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co + [HLSL_SAMPLER_DIM_STRUCTURED_BUFFER] = 40, + }; + +- put_u32_unaligned(buffer, uav_type[type->sampler_dim]); ++ put_u32_unaligned(buffer, uav_type[element_type->sampler_dim]); + } +- else if (type->class == HLSL_CLASS_DEPTH_STENCIL_VIEW) ++ else if (element_type->class == HLSL_CLASS_DEPTH_STENCIL_VIEW) + { + put_u32_unaligned(buffer, 20); + } +- else if (type->class == HLSL_CLASS_RENDER_TARGET_VIEW) ++ else if (element_type->class == HLSL_CLASS_RENDER_TARGET_VIEW) + { + put_u32_unaligned(buffer, 19); + } +- else if (type->class == HLSL_CLASS_PIXEL_SHADER) ++ else if (element_type->class == HLSL_CLASS_PIXEL_SHADER) + { + put_u32_unaligned(buffer, 5); + } +- else if (type->class == HLSL_CLASS_VERTEX_SHADER) ++ else if (element_type->class == HLSL_CLASS_VERTEX_SHADER) + { + put_u32_unaligned(buffer, 6); + } +- else if (type->class == HLSL_CLASS_RASTERIZER_STATE) ++ else if (element_type->class == HLSL_CLASS_RASTERIZER_STATE) + { + put_u32_unaligned(buffer, 4); + } +- else if (type->class == HLSL_CLASS_DEPTH_STENCIL_STATE) ++ else if (element_type->class == HLSL_CLASS_DEPTH_STENCIL_STATE) + { + put_u32_unaligned(buffer, 3); + } +- else if (type->class == HLSL_CLASS_BLEND_STATE) ++ else if (element_type->class == HLSL_CLASS_BLEND_STATE) + { + put_u32_unaligned(buffer, 2); + } +- else if (type->class == HLSL_CLASS_STRING) ++ else if (element_type->class == HLSL_CLASS_STRING) + { + put_u32_unaligned(buffer, 1); + } +- else if (hlsl_is_numeric_type(type)) ++ else if (hlsl_is_numeric_type(element_type)) + { +- numeric_desc = get_fx_4_numeric_type_description(type, fx); ++ numeric_desc = get_fx_4_numeric_type_description(element_type, fx); + put_u32_unaligned(buffer, numeric_desc); + } +- else if (type->class == HLSL_CLASS_COMPUTE_SHADER) ++ else if (element_type->class == HLSL_CLASS_COMPUTE_SHADER) + { + put_u32_unaligned(buffer, 28); + } +- else if (type->class == HLSL_CLASS_HULL_SHADER) ++ else if (element_type->class == HLSL_CLASS_HULL_SHADER) + { + put_u32_unaligned(buffer, 29); + } +- else if (type->class == HLSL_CLASS_DOMAIN_SHADER) ++ else if (element_type->class == HLSL_CLASS_DOMAIN_SHADER) + { + put_u32_unaligned(buffer, 30); + } + else + { +- FIXME("Type %u is not supported.\n", type->class); ++ FIXME("Type %u is not supported.\n", element_type->class); + set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); + } + +@@ -2126,7 +2139,7 @@ static unsigned int decompose_fx_4_state_function_call(struct hlsl_ir_var *var, + } + + /* For some states assignment sets all of the elements. This behaviour is limited to certain states of BlendState +- object, and only when fx_5_0 profile is used. */ ++ object, and only when fx_4_1 or fx_5_0 profile is used. */ + static unsigned int decompose_fx_4_state_block_expand_array(struct hlsl_ir_var *var, struct hlsl_state_block *block, + unsigned int entry_index, struct fx_write_context *fx) + { +@@ -2140,7 +2153,7 @@ static unsigned int decompose_fx_4_state_block_expand_array(struct hlsl_ir_var * + + if (type->class != HLSL_CLASS_BLEND_STATE) + return 1; +- if (ctx->profile->major_version != 5) ++ if (hlsl_version_lt(ctx, 4, 1)) + return 1; + if (entry->lhs_has_index) + return 1; +@@ -2401,6 +2414,9 @@ static void write_fx_4_buffer(struct hlsl_buffer *b, struct fx_write_context *fx + size = 0; + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { ++ if (!is_numeric_fx_4_type(var->data_type)) ++ continue; ++ + if (var->buffer != b) + continue; + +diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c +index d1f02ab568b..dd1c121d5a8 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c +@@ -38,7 +38,20 @@ struct vkd3d_glsl_generator + struct vkd3d_shader_location location; + struct vkd3d_shader_message_context *message_context; + unsigned int indent; ++ const char *prefix; + bool failed; ++ ++ struct shader_limits ++ { ++ unsigned int input_count; ++ unsigned int output_count; ++ } limits; ++ bool interstage_input; ++ bool interstage_output; ++ ++ const struct vkd3d_shader_interface_info *interface_info; ++ const struct vkd3d_shader_descriptor_offset_info *offset_info; ++ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info; + }; + + static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( +@@ -53,6 +66,27 @@ static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( + generator->failed = true; + } + ++static const char *shader_glsl_get_prefix(enum vkd3d_shader_type type) ++{ ++ switch (type) ++ { ++ case VKD3D_SHADER_TYPE_VERTEX: ++ return "vs"; ++ case VKD3D_SHADER_TYPE_HULL: ++ return "hs"; ++ case VKD3D_SHADER_TYPE_DOMAIN: ++ return "ds"; ++ case VKD3D_SHADER_TYPE_GEOMETRY: ++ return "gs"; ++ case VKD3D_SHADER_TYPE_PIXEL: ++ return "ps"; ++ case VKD3D_SHADER_TYPE_COMPUTE: ++ return "cs"; ++ default: ++ return NULL; ++ } ++} ++ + static void shader_glsl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent) + { + vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); +@@ -67,6 +101,82 @@ static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer, + vkd3d_string_buffer_printf(buffer, "r[%u]", reg->idx[0].offset); + break; + ++ case VKD3DSPR_INPUT: ++ if (reg->idx_count != 1) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled input register index count %u.", reg->idx_count); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++ break; ++ } ++ if (reg->idx[0].rel_addr) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled input register indirect addressing."); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++ break; ++ } ++ vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, reg->idx[0].offset); ++ break; ++ ++ case VKD3DSPR_OUTPUT: ++ if (reg->idx_count != 1) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled output register index count %u.", reg->idx_count); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++ break; ++ } ++ if (reg->idx[0].rel_addr) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled output register indirect addressing."); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++ break; ++ } ++ vkd3d_string_buffer_printf(buffer, "%s_out[%u]", gen->prefix, reg->idx[0].offset); ++ break; ++ ++ case VKD3DSPR_IMMCONST: ++ switch (reg->dimension) ++ { ++ case VSIR_DIMENSION_SCALAR: ++ vkd3d_string_buffer_printf(buffer, "%#xu", reg->u.immconst_u32[0]); ++ break; ++ ++ case VSIR_DIMENSION_VEC4: ++ vkd3d_string_buffer_printf(buffer, "uvec4(%#xu, %#xu, %#xu, %#xu)", ++ reg->u.immconst_u32[0], reg->u.immconst_u32[1], ++ reg->u.immconst_u32[2], reg->u.immconst_u32[3]); ++ break; ++ ++ default: ++ vkd3d_string_buffer_printf(buffer, "", reg->dimension); ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled dimension %#x.", reg->dimension); ++ break; ++ } ++ break; ++ ++ case VKD3DSPR_CONSTBUFFER: ++ if (reg->idx_count != 3) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled constant buffer register index count %u.", reg->idx_count); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++ break; ++ } ++ if (reg->idx[0].rel_addr || reg->idx[2].rel_addr) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled constant buffer register indirect addressing."); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++ break; ++ } ++ vkd3d_string_buffer_printf(buffer, "%s_cb_%u[%u]", ++ gen->prefix, reg->idx[0].offset, reg->idx[2].offset); ++ break; ++ + default: + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled register type %#x.", reg->type); +@@ -106,23 +216,109 @@ static void glsl_src_cleanup(struct glsl_src *src, struct vkd3d_string_buffer_ca + vkd3d_string_buffer_release(cache, src->str); + } + ++static void shader_glsl_print_bitcast(struct vkd3d_string_buffer *dst, struct vkd3d_glsl_generator *gen, ++ const char *src, enum vkd3d_data_type dst_data_type, enum vkd3d_data_type src_data_type, unsigned int size) ++{ ++ if (dst_data_type == VKD3D_DATA_UNORM || dst_data_type == VKD3D_DATA_SNORM) ++ dst_data_type = VKD3D_DATA_FLOAT; ++ if (src_data_type == VKD3D_DATA_UNORM || src_data_type == VKD3D_DATA_SNORM) ++ src_data_type = VKD3D_DATA_FLOAT; ++ ++ if (dst_data_type == src_data_type) ++ { ++ vkd3d_string_buffer_printf(dst, "%s", src); ++ return; ++ } ++ ++ if (src_data_type == VKD3D_DATA_FLOAT) ++ { ++ switch (dst_data_type) ++ { ++ case VKD3D_DATA_INT: ++ vkd3d_string_buffer_printf(dst, "floatBitsToInt(%s)", src); ++ return; ++ case VKD3D_DATA_UINT: ++ vkd3d_string_buffer_printf(dst, "floatBitsToUint(%s)", src); ++ return; ++ default: ++ break; ++ } ++ } ++ ++ if (src_data_type == VKD3D_DATA_UINT) ++ { ++ switch (dst_data_type) ++ { ++ case VKD3D_DATA_FLOAT: ++ vkd3d_string_buffer_printf(dst, "uintBitsToFloat(%s)", src); ++ return; ++ case VKD3D_DATA_INT: ++ if (size == 1) ++ vkd3d_string_buffer_printf(dst, "int(%s)", src); ++ else ++ vkd3d_string_buffer_printf(dst, "ivec%u(%s)", size, src); ++ return; ++ default: ++ break; ++ } ++ } ++ ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled bitcast from %#x to %#x.", ++ src_data_type, dst_data_type); ++ vkd3d_string_buffer_printf(dst, "%s", src); ++} ++ + static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) + { + const struct vkd3d_shader_register *reg = &vsir_src->reg; ++ struct vkd3d_string_buffer *register_name, *str; ++ enum vkd3d_data_type src_data_type; ++ unsigned int size; + + glsl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); ++ register_name = vkd3d_string_buffer_get(&gen->string_buffers); + + if (reg->non_uniform) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled 'non-uniform' modifier."); +- if (vsir_src->modifiers) +- vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, +- "Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers); + +- shader_glsl_print_register_name(glsl_src->str, gen, reg); ++ if (reg->type == VKD3DSPR_IMMCONST) ++ src_data_type = VKD3D_DATA_UINT; ++ else ++ src_data_type = VKD3D_DATA_FLOAT; ++ ++ shader_glsl_print_register_name(register_name, gen, reg); ++ ++ if (!vsir_src->modifiers) ++ str = glsl_src->str; ++ else ++ str = vkd3d_string_buffer_get(&gen->string_buffers); ++ ++ size = reg->dimension == VSIR_DIMENSION_VEC4 ? 4 : 1; ++ shader_glsl_print_bitcast(str, gen, register_name->buffer, reg->data_type, src_data_type, size); + if (reg->dimension == VSIR_DIMENSION_VEC4) +- shader_glsl_print_swizzle(glsl_src->str, vsir_src->swizzle, mask); ++ shader_glsl_print_swizzle(str, vsir_src->swizzle, mask); ++ ++ switch (vsir_src->modifiers) ++ { ++ case VKD3DSPSM_NONE: ++ break; ++ case VKD3DSPSM_ABS: ++ vkd3d_string_buffer_printf(glsl_src->str, "abs(%s)", str->buffer); ++ break; ++ default: ++ vkd3d_string_buffer_printf(glsl_src->str, "(%s)", ++ vsir_src->modifiers, str->buffer); ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers); ++ break; ++ } ++ ++ if (str != glsl_src->str) ++ vkd3d_string_buffer_release(&gen->string_buffers, str); ++ vkd3d_string_buffer_release(&gen->string_buffers, register_name); + } + + static void glsl_dst_cleanup(struct glsl_dst *dst, struct vkd3d_string_buffer_cache *cache) +@@ -156,6 +352,9 @@ static uint32_t glsl_dst_init(struct glsl_dst *glsl_dst, struct vkd3d_glsl_gener + static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( + struct vkd3d_glsl_generator *gen, struct glsl_dst *dst, const char *format, ...) + { ++ const struct vkd3d_shader_register *dst_reg = &dst->vsir->reg; ++ struct vkd3d_string_buffer *buffer = gen->buffer; ++ bool close = true; + va_list args; + + if (dst->vsir->shift) +@@ -165,14 +364,28 @@ static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled destination modifier(s) %#x.", dst->vsir->modifiers); + +- shader_glsl_print_indent(gen->buffer, gen->indent); +- vkd3d_string_buffer_printf(gen->buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); ++ shader_glsl_print_indent(buffer, gen->indent); ++ vkd3d_string_buffer_printf(buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); ++ ++ switch (dst_reg->data_type) ++ { ++ default: ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled destination register data type %#x.", dst_reg->data_type); ++ /* fall through */ ++ case VKD3D_DATA_FLOAT: ++ close = false; ++ break; ++ case VKD3D_DATA_UINT: ++ vkd3d_string_buffer_printf(buffer, "uintBitsToFloat("); ++ break; ++ } + + va_start(args, format); +- vkd3d_string_buffer_vprintf(gen->buffer, format, args); ++ vkd3d_string_buffer_vprintf(buffer, format, args); + va_end(args); + +- vkd3d_string_buffer_printf(gen->buffer, ";\n"); ++ vkd3d_string_buffer_printf(buffer, "%s;\n", close ? ")" : ""); + } + + static void shader_glsl_unhandled(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) +@@ -183,6 +396,48 @@ static void shader_glsl_unhandled(struct vkd3d_glsl_generator *gen, const struct + "Internal compiler error: Unhandled instruction %#x.", ins->opcode); + } + ++static void shader_glsl_binop(struct vkd3d_glsl_generator *gen, ++ const struct vkd3d_shader_instruction *ins, const char *op) ++{ ++ struct glsl_src src[2]; ++ struct glsl_dst dst; ++ uint32_t mask; ++ ++ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ glsl_src_init(&src[0], gen, &ins->src[0], mask); ++ glsl_src_init(&src[1], gen, &ins->src[1], mask); ++ ++ shader_glsl_print_assignment(gen, &dst, "%s %s %s", src[0].str->buffer, op, src[1].str->buffer); ++ ++ glsl_src_cleanup(&src[1], &gen->string_buffers); ++ glsl_src_cleanup(&src[0], &gen->string_buffers); ++ glsl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ ++static void shader_glsl_relop(struct vkd3d_glsl_generator *gen, ++ const struct vkd3d_shader_instruction *ins, const char *scalar_op, const char *vector_op) ++{ ++ unsigned int mask_size; ++ struct glsl_src src[2]; ++ struct glsl_dst dst; ++ uint32_t mask; ++ ++ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ glsl_src_init(&src[0], gen, &ins->src[0], mask); ++ glsl_src_init(&src[1], gen, &ins->src[1], mask); ++ ++ if ((mask_size = vsir_write_mask_component_count(mask)) > 1) ++ shader_glsl_print_assignment(gen, &dst, "uvec%u(%s(%s, %s)) * 0xffffffffu", ++ mask_size, vector_op, src[0].str->buffer, src[1].str->buffer); ++ else ++ shader_glsl_print_assignment(gen, &dst, "%s %s %s ? 0xffffffffu : 0u", ++ src[0].str->buffer, scalar_op, src[1].str->buffer); ++ ++ glsl_src_cleanup(&src[1], &gen->string_buffers); ++ glsl_src_cleanup(&src[0], &gen->string_buffers); ++ glsl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ + static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) + { + struct glsl_src src; +@@ -198,16 +453,138 @@ static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d + glsl_dst_cleanup(&dst, &gen->string_buffers); + } + ++static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, ++ enum vkd3d_shader_sysval_semantic sysval, unsigned int idx) ++{ ++ const struct vkd3d_shader_version *version = &gen->program->shader_version; ++ ++ switch (sysval) ++ { ++ case VKD3D_SHADER_SV_POSITION: ++ if (version->type == VKD3D_SHADER_TYPE_PIXEL || version->type == VKD3D_SHADER_TYPE_COMPUTE) ++ { ++ vkd3d_string_buffer_printf(buffer, "", sysval); ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled system value %#x.", sysval); ++ } ++ else ++ { ++ vkd3d_string_buffer_printf(buffer, "gl_Position"); ++ if (idx) ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled SV_POSITION index %u.", idx); ++ } ++ break; ++ ++ case VKD3D_SHADER_SV_TARGET: ++ if (version->type != VKD3D_SHADER_TYPE_PIXEL) ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled SV_TARGET in shader type #%x.", version->type); ++ vkd3d_string_buffer_printf(buffer, "shader_out_%u", idx); ++ break; ++ ++ default: ++ vkd3d_string_buffer_printf(buffer, "", sysval); ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled system value %#x.", sysval); ++ break; ++ } ++} ++ ++static void shader_glsl_shader_prologue(struct vkd3d_glsl_generator *gen) ++{ ++ const struct shader_signature *signature = &gen->program->input_signature; ++ struct vkd3d_string_buffer *buffer = gen->buffer; ++ const struct signature_element *e; ++ unsigned int i; ++ ++ for (i = 0; i < signature->element_count; ++i) ++ { ++ e = &signature->elements[i]; ++ ++ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) ++ continue; ++ ++ shader_glsl_print_indent(buffer, gen->indent); ++ vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, e->register_index); ++ shader_glsl_print_write_mask(buffer, e->mask); ++ if (e->sysval_semantic == VKD3D_SHADER_SV_NONE) ++ { ++ if (gen->interstage_input) ++ { ++ vkd3d_string_buffer_printf(buffer, " = shader_in.reg_%u", e->target_location); ++ if (e->target_location >= gen->limits.input_count) ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Input element %u specifies target location %u, " ++ "but only %u inputs are supported.", ++ i, e->target_location, gen->limits.input_count); ++ } ++ else ++ { ++ vkd3d_string_buffer_printf(buffer, " = shader_in_%u", i); ++ } ++ } ++ else ++ { ++ vkd3d_string_buffer_printf(buffer, " = "); ++ shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index); ++ } ++ shader_glsl_print_write_mask(buffer, e->mask); ++ vkd3d_string_buffer_printf(buffer, ";\n"); ++ } ++} ++ ++static void shader_glsl_shader_epilogue(struct vkd3d_glsl_generator *gen) ++{ ++ const struct shader_signature *signature = &gen->program->output_signature; ++ struct vkd3d_string_buffer *buffer = gen->buffer; ++ const struct signature_element *e; ++ unsigned int i; ++ ++ for (i = 0; i < signature->element_count; ++i) ++ { ++ e = &signature->elements[i]; ++ ++ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) ++ continue; ++ ++ shader_glsl_print_indent(buffer, gen->indent); ++ if (e->sysval_semantic == VKD3D_SHADER_SV_NONE) ++ { ++ if (gen->interstage_output) ++ { ++ vkd3d_string_buffer_printf(buffer, "shader_out.reg_%u", e->target_location); ++ if (e->target_location >= gen->limits.output_count) ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Output element %u specifies target location %u, " ++ "but only %u outputs are supported.", ++ i, e->target_location, gen->limits.output_count); ++ } ++ else ++ { ++ vkd3d_string_buffer_printf(buffer, "", e->target_location); ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled output."); ++ } ++ } ++ else ++ { ++ shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index); ++ } ++ shader_glsl_print_write_mask(buffer, e->mask); ++ vkd3d_string_buffer_printf(buffer, " = %s_out[%u]", gen->prefix, e->register_index); ++ shader_glsl_print_write_mask(buffer, e->mask); ++ vkd3d_string_buffer_printf(buffer, ";\n"); ++ } ++} ++ + static void shader_glsl_ret(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) + { + const struct vkd3d_shader_version *version = &gen->program->shader_version; + +- /* +- * TODO: Implement in_subroutine +- * TODO: shader_glsl_generate_shader_epilogue(generator); +- */ + if (version->major >= 4) + { ++ shader_glsl_shader_epilogue(gen); + shader_glsl_print_indent(gen->buffer, gen->indent); + vkd3d_string_buffer_printf(gen->buffer, "return;\n"); + } +@@ -220,14 +597,30 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + + switch (ins->opcode) + { ++ case VKD3DSIH_ADD: ++ shader_glsl_binop(gen, ins, "+"); ++ break; ++ case VKD3DSIH_AND: ++ shader_glsl_binop(gen, ins, "&"); ++ break; + case VKD3DSIH_DCL_INPUT: + case VKD3DSIH_DCL_OUTPUT: + case VKD3DSIH_DCL_OUTPUT_SIV: + case VKD3DSIH_NOP: + break; ++ case VKD3DSIH_INE: ++ case VKD3DSIH_NEU: ++ shader_glsl_relop(gen, ins, "!=", "notEqual"); ++ break; + case VKD3DSIH_MOV: + shader_glsl_mov(gen, ins); + break; ++ case VKD3DSIH_MUL: ++ shader_glsl_binop(gen, ins, "*"); ++ break; ++ case VKD3DSIH_OR: ++ shader_glsl_binop(gen, ins, "|"); ++ break; + case VKD3DSIH_RET: + shader_glsl_ret(gen, ins); + break; +@@ -237,13 +630,290 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + } + } + ++static bool shader_glsl_check_shader_visibility(const struct vkd3d_glsl_generator *gen, ++ enum vkd3d_shader_visibility visibility) ++{ ++ enum vkd3d_shader_type t = gen->program->shader_version.type; ++ ++ switch (visibility) ++ { ++ case VKD3D_SHADER_VISIBILITY_ALL: ++ return true; ++ case VKD3D_SHADER_VISIBILITY_VERTEX: ++ return t == VKD3D_SHADER_TYPE_VERTEX; ++ case VKD3D_SHADER_VISIBILITY_HULL: ++ return t == VKD3D_SHADER_TYPE_HULL; ++ case VKD3D_SHADER_VISIBILITY_DOMAIN: ++ return t == VKD3D_SHADER_TYPE_DOMAIN; ++ case VKD3D_SHADER_VISIBILITY_GEOMETRY: ++ return t == VKD3D_SHADER_TYPE_GEOMETRY; ++ case VKD3D_SHADER_VISIBILITY_PIXEL: ++ return t == VKD3D_SHADER_TYPE_PIXEL; ++ case VKD3D_SHADER_VISIBILITY_COMPUTE: ++ return t == VKD3D_SHADER_TYPE_COMPUTE; ++ default: ++ WARN("Invalid shader visibility %#x.\n", visibility); ++ return false; ++ } ++} ++ ++static bool shader_glsl_get_cbv_binding(const struct vkd3d_glsl_generator *gen, ++ unsigned int register_space, unsigned int register_idx, unsigned int *binding_idx) ++{ ++ const struct vkd3d_shader_interface_info *interface_info = gen->interface_info; ++ const struct vkd3d_shader_resource_binding *binding; ++ unsigned int i; ++ ++ if (!interface_info) ++ return false; ++ ++ for (i = 0; i < interface_info->binding_count; ++i) ++ { ++ binding = &interface_info->bindings[i]; ++ ++ if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_CBV) ++ continue; ++ if (binding->register_space != register_space) ++ continue; ++ if (binding->register_index != register_idx) ++ continue; ++ if (!shader_glsl_check_shader_visibility(gen, binding->shader_visibility)) ++ continue; ++ if (!(binding->flags & VKD3D_SHADER_BINDING_FLAG_BUFFER)) ++ continue; ++ *binding_idx = i; ++ return true; ++ } ++ ++ return false; ++} ++ ++static void shader_glsl_generate_cbv_declaration(struct vkd3d_glsl_generator *gen, ++ const struct vkd3d_shader_descriptor_info1 *cbv) ++{ ++ const struct vkd3d_shader_descriptor_binding *binding; ++ const struct vkd3d_shader_descriptor_offset *offset; ++ struct vkd3d_string_buffer *buffer = gen->buffer; ++ const char *prefix = gen->prefix; ++ unsigned int binding_idx; ++ size_t size; ++ ++ if (cbv->count != 1) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, ++ "Constant buffer %u has unsupported descriptor array size %u.", cbv->register_id, cbv->count); ++ return; ++ } ++ ++ if (!shader_glsl_get_cbv_binding(gen, cbv->register_space, cbv->register_index, &binding_idx)) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, ++ "No descriptor binding specified for constant buffer %u.", cbv->register_id); ++ return; ++ } ++ ++ binding = &gen->interface_info->bindings[binding_idx].binding; ++ ++ if (binding->set != 0) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, ++ "Unsupported binding set %u specified for constant buffer %u.", binding->set, cbv->register_id); ++ return; ++ } ++ ++ if (binding->count != 1) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, ++ "Unsupported binding count %u specified for constant buffer %u.", binding->count, cbv->register_id); ++ return; ++ } ++ ++ if (gen->offset_info && gen->offset_info->binding_offsets) ++ { ++ offset = &gen->offset_info->binding_offsets[binding_idx]; ++ if (offset->static_offset || offset->dynamic_offset_index != ~0u) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled descriptor offset specified for constant buffer %u.", ++ cbv->register_id); ++ return; ++ } ++ } ++ ++ size = align(cbv->buffer_size, VKD3D_VEC4_SIZE * sizeof(uint32_t)); ++ size /= VKD3D_VEC4_SIZE * sizeof(uint32_t); ++ ++ vkd3d_string_buffer_printf(buffer, ++ "layout(std140, binding = %u) uniform block_%s_cb_%u { vec4 %s_cb_%u[%zu]; };\n", ++ binding->binding, prefix, cbv->register_id, prefix, cbv->register_id, size); ++} ++ ++static void shader_glsl_generate_descriptor_declarations(struct vkd3d_glsl_generator *gen) ++{ ++ const struct vkd3d_shader_scan_descriptor_info1 *info = gen->descriptor_info; ++ const struct vkd3d_shader_descriptor_info1 *descriptor; ++ unsigned int i; ++ ++ for (i = 0; i < info->descriptor_count; ++i) ++ { ++ descriptor = &info->descriptors[i]; ++ ++ switch (descriptor->type) ++ { ++ case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: ++ shader_glsl_generate_cbv_declaration(gen, descriptor); ++ break; ++ ++ default: ++ vkd3d_string_buffer_printf(gen->buffer, "/* */\n", descriptor->type); ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled descriptor type %#x.", descriptor->type); ++ break; ++ } ++ } ++ if (info->descriptor_count) ++ vkd3d_string_buffer_printf(gen->buffer, "\n"); ++} ++ ++static void shader_glsl_generate_interface_block(struct vkd3d_string_buffer *buffer, ++ const char *type, unsigned int count) ++{ ++ unsigned int i; ++ ++ vkd3d_string_buffer_printf(buffer, "%s shader_in_out\n{\n", type); ++ for (i = 0; i < count; ++i) ++ { ++ vkd3d_string_buffer_printf(buffer, " vec4 reg_%u;\n", i); ++ } ++ vkd3d_string_buffer_printf(buffer, "} shader_%s;\n", type); ++} ++ ++static void shader_glsl_generate_input_declarations(struct vkd3d_glsl_generator *gen) ++{ ++ const struct shader_signature *signature = &gen->program->input_signature; ++ struct vkd3d_string_buffer *buffer = gen->buffer; ++ const struct signature_element *e; ++ unsigned int i; ++ ++ if (!gen->interstage_input) ++ { ++ for (i = 0; i < signature->element_count; ++i) ++ { ++ e = &signature->elements[i]; ++ ++ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) ++ continue; ++ ++ if (e->sysval_semantic) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled system value %#x.", e->sysval_semantic); ++ continue; ++ } ++ ++ if (e->component_type != VKD3D_SHADER_COMPONENT_FLOAT) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled component type %#x.", e->component_type); ++ continue; ++ } ++ ++ if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled minimum precision %#x.", e->min_precision); ++ continue; ++ } ++ ++ if (e->interpolation_mode != VKD3DSIM_NONE) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode); ++ continue; ++ } ++ ++ vkd3d_string_buffer_printf(buffer, ++ "layout(location = %u) in vec4 shader_in_%u;\n", e->target_location, i); ++ } ++ } ++ else if (gen->limits.input_count) ++ { ++ shader_glsl_generate_interface_block(buffer, "in", gen->limits.input_count); ++ } ++ vkd3d_string_buffer_printf(buffer, "\n"); ++} ++ ++static void shader_glsl_generate_output_declarations(struct vkd3d_glsl_generator *gen) ++{ ++ const struct shader_signature *signature = &gen->program->output_signature; ++ struct vkd3d_string_buffer *buffer = gen->buffer; ++ const struct signature_element *e; ++ unsigned int i; ++ ++ if (!gen->interstage_output) ++ { ++ for (i = 0; i < signature->element_count; ++i) ++ { ++ e = &signature->elements[i]; ++ ++ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) ++ continue; ++ ++ if (e->sysval_semantic != VKD3D_SHADER_SV_TARGET) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled system value %#x.", e->sysval_semantic); ++ continue; ++ } ++ ++ if (e->component_type != VKD3D_SHADER_COMPONENT_FLOAT) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled component type %#x.", e->component_type); ++ continue; ++ } ++ ++ if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled minimum precision %#x.", e->min_precision); ++ continue; ++ } ++ ++ if (e->interpolation_mode != VKD3DSIM_NONE) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode); ++ continue; ++ } ++ ++ vkd3d_string_buffer_printf(buffer, ++ "layout(location = %u) out vec4 shader_out_%u;\n", e->target_location, i); ++ } ++ } ++ else if (gen->limits.output_count) ++ { ++ shader_glsl_generate_interface_block(buffer, "out", gen->limits.output_count); ++ } ++ vkd3d_string_buffer_printf(buffer, "\n"); ++} ++ + static void shader_glsl_generate_declarations(struct vkd3d_glsl_generator *gen) + { + const struct vsir_program *program = gen->program; + struct vkd3d_string_buffer *buffer = gen->buffer; + ++ shader_glsl_generate_descriptor_declarations(gen); ++ shader_glsl_generate_input_declarations(gen); ++ shader_glsl_generate_output_declarations(gen); ++ ++ if (gen->limits.input_count) ++ vkd3d_string_buffer_printf(buffer, "vec4 %s_in[%u];\n", gen->prefix, gen->limits.input_count); ++ if (gen->limits.output_count) ++ vkd3d_string_buffer_printf(buffer, "vec4 %s_out[%u];\n", gen->prefix, gen->limits.output_count); + if (program->temp_count) +- vkd3d_string_buffer_printf(buffer, "vec4 r[%u];\n\n", program->temp_count); ++ vkd3d_string_buffer_printf(buffer, "vec4 r[%u];\n", program->temp_count); ++ vkd3d_string_buffer_printf(buffer, "\n"); + } + + static int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *gen, struct vkd3d_shader_code *out) +@@ -264,6 +934,7 @@ static int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *gen, struc + vkd3d_string_buffer_printf(buffer, "void main()\n{\n"); + + ++gen->indent; ++ shader_glsl_shader_prologue(gen); + for (i = 0; i < instructions->count; ++i) + { + vkd3d_glsl_handle_instruction(gen, &instructions->elements[i]); +@@ -294,27 +965,73 @@ static void vkd3d_glsl_generator_cleanup(struct vkd3d_glsl_generator *gen) + vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); + } + ++static void shader_glsl_init_limits(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_version *version) ++{ ++ struct shader_limits *limits = &gen->limits; ++ ++ if (version->major < 4 || version->major >= 6) ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled shader version %u.%u.", version->major, version->minor); ++ ++ switch (version->type) ++ { ++ case VKD3D_SHADER_TYPE_VERTEX: ++ limits->input_count = 32; ++ limits->output_count = 32; ++ break; ++ case VKD3D_SHADER_TYPE_PIXEL: ++ limits->input_count = 32; ++ limits->output_count = 8; ++ break; ++ default: ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled shader type %#x.", version->type); ++ limits->input_count = 0; ++ limits->output_count = 0; ++ break; ++ } ++} ++ + static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen, +- struct vsir_program *program, struct vkd3d_shader_message_context *message_context) ++ struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, ++ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, ++ struct vkd3d_shader_message_context *message_context) + { ++ enum vkd3d_shader_type type = program->shader_version.type; ++ + memset(gen, 0, sizeof(*gen)); + gen->program = program; + vkd3d_string_buffer_cache_init(&gen->string_buffers); + gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers); ++ gen->location.source_name = compile_info->source_name; + gen->message_context = message_context; ++ if (!(gen->prefix = shader_glsl_get_prefix(type))) ++ { ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled shader type %#x.", type); ++ gen->prefix = "unknown"; ++ } ++ shader_glsl_init_limits(gen, &program->shader_version); ++ gen->interstage_input = type != VKD3D_SHADER_TYPE_VERTEX; ++ gen->interstage_output = type != VKD3D_SHADER_TYPE_PIXEL; ++ ++ gen->interface_info = vkd3d_find_struct(compile_info->next, INTERFACE_INFO); ++ gen->offset_info = vkd3d_find_struct(compile_info->next, DESCRIPTOR_OFFSET_INFO); ++ gen->descriptor_info = descriptor_info; + } + + int glsl_compile(struct vsir_program *program, uint64_t config_flags, +- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, +- struct vkd3d_shader_message_context *message_context) ++ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, ++ const struct vkd3d_shader_compile_info *compile_info, ++ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) + { + struct vkd3d_glsl_generator generator; + int ret; + +- if ((ret = vsir_program_normalise(program, config_flags, compile_info, message_context)) < 0) ++ if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0) + return ret; + +- vkd3d_glsl_generator_init(&generator, program, message_context); ++ vkd3d_glsl_generator_init(&generator, program, compile_info, descriptor_info, message_context); + ret = vkd3d_glsl_generator_generate(&generator, out); + vkd3d_glsl_generator_cleanup(&generator); + +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +index bd5baacd83d..6323260eab7 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +@@ -254,6 +254,45 @@ bool hlsl_type_is_resource(const struct hlsl_type *type) + } + } + ++bool hlsl_type_is_shader(const struct hlsl_type *type) ++{ ++ switch (type->class) ++ { ++ case HLSL_CLASS_ARRAY: ++ return hlsl_type_is_shader(type->e.array.type); ++ ++ case HLSL_CLASS_COMPUTE_SHADER: ++ case HLSL_CLASS_DOMAIN_SHADER: ++ case HLSL_CLASS_GEOMETRY_SHADER: ++ case HLSL_CLASS_HULL_SHADER: ++ case HLSL_CLASS_PIXEL_SHADER: ++ case HLSL_CLASS_VERTEX_SHADER: ++ return true; ++ ++ case HLSL_CLASS_SCALAR: ++ case HLSL_CLASS_VECTOR: ++ case HLSL_CLASS_MATRIX: ++ case HLSL_CLASS_STRUCT: ++ case HLSL_CLASS_DEPTH_STENCIL_STATE: ++ case HLSL_CLASS_DEPTH_STENCIL_VIEW: ++ case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_PASS: ++ case HLSL_CLASS_RASTERIZER_STATE: ++ case HLSL_CLASS_RENDER_TARGET_VIEW: ++ case HLSL_CLASS_SAMPLER: ++ case HLSL_CLASS_STRING: ++ case HLSL_CLASS_TECHNIQUE: ++ case HLSL_CLASS_TEXTURE: ++ case HLSL_CLASS_UAV: ++ case HLSL_CLASS_CONSTANT_BUFFER: ++ case HLSL_CLASS_BLEND_STATE: ++ case HLSL_CLASS_VOID: ++ case HLSL_CLASS_NULL: ++ return false; ++ } ++ return false; ++} ++ + /* Only intended to be used for derefs (after copies have been lowered to components or vectors) or + * resources, since for both their data types span across a single regset. */ + static enum hlsl_regset type_get_regset(const struct hlsl_type *type) +@@ -930,6 +969,7 @@ static const char * get_case_insensitive_typename(const char *name) + { + "dword", + "float", ++ "geometryshader", + "matrix", + "pixelshader", + "texture", +@@ -1792,6 +1832,65 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned + return &swizzle->node; + } + ++struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, ++ const char *profile_name, struct hlsl_ir_node **args, unsigned int args_count, ++ struct hlsl_block *args_instrs, const struct vkd3d_shader_location *loc) ++{ ++ const struct hlsl_profile_info *profile_info = NULL; ++ struct hlsl_ir_compile *compile; ++ struct hlsl_type *type = NULL; ++ unsigned int i; ++ ++ switch (compile_type) ++ { ++ case HLSL_COMPILE_TYPE_COMPILE: ++ if (!(profile_info = hlsl_get_target_info(profile_name))) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Unknown profile \"%s\".", profile_name); ++ return NULL; ++ } ++ ++ if (profile_info->type == VKD3D_SHADER_TYPE_PIXEL) ++ type = hlsl_get_type(ctx->cur_scope, "PixelShader", true, true); ++ else if (profile_info->type == VKD3D_SHADER_TYPE_VERTEX) ++ type = hlsl_get_type(ctx->cur_scope, "VertexShader", true, true); ++ ++ if (!type) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile_name); ++ return NULL; ++ } ++ ++ break; ++ ++ case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: ++ type = hlsl_get_type(ctx->cur_scope, "GeometryShader", true, true); ++ break; ++ } ++ ++ if (!(compile = hlsl_alloc(ctx, sizeof(*compile)))) ++ return NULL; ++ ++ init_node(&compile->node, HLSL_IR_COMPILE, type, loc); ++ ++ compile->compile_type = compile_type; ++ compile->profile = profile_info; ++ ++ hlsl_block_init(&compile->instrs); ++ hlsl_block_add_block(&compile->instrs, args_instrs); ++ ++ compile->args_count = args_count; ++ if (!(compile->args = hlsl_alloc(ctx, sizeof(*compile->args) * args_count))) ++ { ++ vkd3d_free(compile); ++ return NULL; ++ } ++ for (i = 0; i < compile->args_count; ++i) ++ hlsl_src_from_node(&compile->args[i], args[i]); ++ ++ return &compile->node; ++} ++ + struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, + struct vkd3d_shader_location *loc) + { +@@ -2142,6 +2241,44 @@ static struct hlsl_ir_node *clone_index(struct hlsl_ctx *ctx, struct clone_instr + return dst; + } + ++static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, ++ struct clone_instr_map *map, struct hlsl_ir_compile *compile) ++{ ++ const char *profile_name = NULL; ++ struct hlsl_ir_node **args; ++ struct hlsl_ir_node *node; ++ struct hlsl_block block; ++ unsigned int i; ++ ++ if (!(clone_block(ctx, &block, &compile->instrs, map))) ++ return NULL; ++ ++ if (!(args = hlsl_alloc(ctx, sizeof(*args) * compile->args_count))) ++ { ++ hlsl_block_cleanup(&block); ++ return NULL; ++ } ++ for (i = 0; i < compile->args_count; ++i) ++ { ++ args[i] = map_instr(map, compile->args[i].node); ++ VKD3D_ASSERT(args[i]); ++ } ++ ++ if (compile->profile) ++ profile_name = compile->profile->name; ++ ++ if (!(node = hlsl_new_compile(ctx, compile->compile_type, profile_name, ++ args, compile->args_count, &block, &compile->node.loc))) ++ { ++ hlsl_block_cleanup(&block); ++ vkd3d_free(args); ++ return NULL; ++ } ++ ++ vkd3d_free(args); ++ return node; ++} ++ + static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, + struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant) + { +@@ -2284,6 +2421,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, + case HLSL_IR_SWIZZLE: + return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr)); + ++ case HLSL_IR_COMPILE: ++ return clone_compile(ctx, map, hlsl_ir_compile(instr)); ++ + case HLSL_IR_STATEBLOCK_CONSTANT: + return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); + } +@@ -2698,6 +2838,8 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) + [HLSL_IR_STORE ] = "HLSL_IR_STORE", + [HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH", + [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", ++ ++ [HLSL_IR_COMPILE] = "HLSL_IR_COMPILE", + [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", + }; + +@@ -3146,6 +3288,34 @@ static void dump_ir_index(struct vkd3d_string_buffer *buffer, const struct hlsl_ + vkd3d_string_buffer_printf(buffer, "]"); + } + ++static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, ++ const struct hlsl_ir_compile *compile) ++{ ++ unsigned int i; ++ ++ switch (compile->compile_type) ++ { ++ case HLSL_COMPILE_TYPE_COMPILE: ++ vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name); ++ break; ++ ++ case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: ++ vkd3d_string_buffer_printf(buffer, "ConstructGSWithSO {\n"); ++ break; ++ } ++ ++ dump_block(ctx, buffer, &compile->instrs); ++ ++ vkd3d_string_buffer_printf(buffer, " %10s } (", ""); ++ for (i = 0; i < compile->args_count; ++i) ++ { ++ dump_src(buffer, &compile->args[i]); ++ if (i + 1 < compile->args_count) ++ vkd3d_string_buffer_printf(buffer, ", "); ++ } ++ vkd3d_string_buffer_printf(buffer, ")"); ++} ++ + static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer, + const struct hlsl_ir_stateblock_constant *constant) + { +@@ -3245,6 +3415,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, + dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr)); + break; + ++ case HLSL_IR_COMPILE: ++ dump_ir_compile(ctx, buffer, hlsl_ir_compile(instr)); ++ break; ++ + case HLSL_IR_STATEBLOCK_CONSTANT: + dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); + break; +@@ -3308,8 +3482,8 @@ void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new) + { + struct hlsl_src *src, *next; + +- VKD3D_ASSERT(old->data_type->dimx == new->data_type->dimx); +- VKD3D_ASSERT(old->data_type->dimy == new->data_type->dimy); ++ VKD3D_ASSERT(old->data_type == new->data_type || old->data_type->dimx == new->data_type->dimx); ++ VKD3D_ASSERT(old->data_type == new->data_type || old->data_type->dimy == new->data_type->dimy); + + LIST_FOR_EACH_ENTRY_SAFE(src, next, &old->uses, struct hlsl_src, entry) + { +@@ -3459,6 +3633,17 @@ static void free_ir_index(struct hlsl_ir_index *index) + vkd3d_free(index); + } + ++static void free_ir_compile(struct hlsl_ir_compile *compile) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < compile->args_count; ++i) ++ hlsl_src_remove(&compile->args[i]); ++ ++ hlsl_block_cleanup(&compile->instrs); ++ vkd3d_free(compile); ++} ++ + static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant) + { + vkd3d_free(constant->name); +@@ -3527,6 +3712,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) + free_ir_switch(hlsl_ir_switch(node)); + break; + ++ case HLSL_IR_COMPILE: ++ free_ir_compile(hlsl_ir_compile(node)); ++ break; ++ + case HLSL_IR_STATEBLOCK_CONSTANT: + free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node)); + break; +@@ -4078,6 +4267,11 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compil + } + } + ++ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_INVALID; ++ ctx->output_control_point_count = UINT_MAX; ++ ctx->output_primitive = 0; ++ ctx->partitioning = 0; ++ + return true; + } + +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +index 22e25b23988..20a96692a48 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +@@ -22,7 +22,6 @@ + + #include "vkd3d_shader_private.h" + #include "wine/rbtree.h" +-#include "d3dcommon.h" + #include "d3dx9shader.h" + + /* The general IR structure is inspired by Mesa GLSL hir, even though the code +@@ -70,6 +69,14 @@ static inline unsigned int hlsl_swizzle_get_component(uint32_t swizzle, unsigned + return (swizzle >> HLSL_SWIZZLE_SHIFT(idx)) & HLSL_SWIZZLE_MASK; + } + ++static inline uint32_t vsir_swizzle_from_hlsl(uint32_t swizzle) ++{ ++ return vkd3d_shader_create_swizzle(hlsl_swizzle_get_component(swizzle, 0), ++ hlsl_swizzle_get_component(swizzle, 1), ++ hlsl_swizzle_get_component(swizzle, 2), ++ hlsl_swizzle_get_component(swizzle, 3)); ++} ++ + enum hlsl_type_class + { + HLSL_CLASS_SCALAR, +@@ -316,6 +323,8 @@ enum hlsl_ir_node_type + HLSL_IR_STORE, + HLSL_IR_SWIZZLE, + HLSL_IR_SWITCH, ++ ++ HLSL_IR_COMPILE, + HLSL_IR_STATEBLOCK_CONSTANT, + }; + +@@ -591,6 +600,8 @@ struct hlsl_ir_function_decl + unsigned int attr_count; + const struct hlsl_attribute *const *attrs; + ++ bool early_depth_test; ++ + /* Synthetic boolean variable marking whether a return statement has been + * executed. Needed to deal with return statements in non-uniform control + * flow, since some backends can't handle them. */ +@@ -703,7 +714,7 @@ enum hlsl_ir_expr_op + HLSL_OP2_SLT, + + /* DP2ADD(a, b, c) computes the scalar product of a.xy and b.xy, +- * then adds c. */ ++ * then adds c, where c must have dimx=1. */ + HLSL_OP3_DP2ADD, + /* TERNARY(a, b, c) returns 'b' if 'a' is true and 'c' otherwise. 'a' must always be boolean. + * CMP(a, b, c) returns 'b' if 'a' >= 0, and 'c' otherwise. It's used only for SM1-SM3 targets. */ +@@ -854,6 +865,35 @@ struct hlsl_ir_string_constant + char *string; + }; + ++/* Represents shader compilation call for effects, such as "CompileShader()". ++ * ++ * Unlike hlsl_ir_call, it is not flattened, thus, it keeps track of its ++ * arguments and maintains its own instruction block. */ ++struct hlsl_ir_compile ++{ ++ struct hlsl_ir_node node; ++ ++ enum hlsl_compile_type ++ { ++ /* A shader compilation through the CompileShader() function or the "compile" syntax. */ ++ HLSL_COMPILE_TYPE_COMPILE, ++ /* A call to ConstructGSWithSO(), which receives a geometry shader and retrieves one as well. */ ++ HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO, ++ } compile_type; ++ ++ /* Special field to store the profile argument for HLSL_COMPILE_TYPE_COMPILE. */ ++ const struct hlsl_profile_info *profile; ++ ++ /* Block containing the instructions required by the arguments of the ++ * compilation call. */ ++ struct hlsl_block instrs; ++ ++ /* Arguments to the compilation call. For HLSL_COMPILE_TYPE_COMPILE ++ * args[0] is an hlsl_ir_call to the specified function. */ ++ struct hlsl_src *args; ++ unsigned int args_count; ++}; ++ + /* Stateblock constants are undeclared values found on state blocks or technique passes descriptions, + * that do not concern regular pixel, vertex, or compute shaders, except for parsing. */ + struct hlsl_ir_stateblock_constant +@@ -1016,6 +1056,7 @@ struct hlsl_ctx + { + uint32_t index; + struct hlsl_vec4 value; ++ struct vkd3d_shader_location loc; + } *regs; + size_t count, size; + } constant_defs; +@@ -1029,6 +1070,12 @@ struct hlsl_ctx + * compute shader profiles. It is set using the numthreads() attribute in the entry point. */ + uint32_t thread_count[3]; + ++ enum vkd3d_tessellator_domain domain; ++ unsigned int output_control_point_count; ++ enum vkd3d_shader_tessellator_output_primitive output_primitive; ++ enum vkd3d_shader_tessellator_partitioning partitioning; ++ struct hlsl_ir_function_decl *patch_constant_func; ++ + /* In some cases we generate opcodes by parsing an HLSL function and then + * invoking it. If not NULL, this field is the name of the function that we + * are currently parsing, "mangled" with an internal prefix to avoid +@@ -1149,6 +1196,12 @@ static inline struct hlsl_ir_switch *hlsl_ir_switch(const struct hlsl_ir_node *n + return CONTAINING_RECORD(node, struct hlsl_ir_switch, node); + } + ++static inline struct hlsl_ir_compile *hlsl_ir_compile(const struct hlsl_ir_node *node) ++{ ++ VKD3D_ASSERT(node->type == HLSL_IR_COMPILE); ++ return CONTAINING_RECORD(node, struct hlsl_ir_compile, node); ++} ++ + static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(const struct hlsl_ir_node *node) + { + VKD3D_ASSERT(node->type == HLSL_IR_STATEBLOCK_CONSTANT); +@@ -1428,6 +1481,9 @@ bool hlsl_index_is_noncontiguous(struct hlsl_ir_index *index); + bool hlsl_index_is_resource_access(struct hlsl_ir_index *index); + bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index); + ++struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, ++ const char *profile_name, struct hlsl_ir_node **args, unsigned int args_count, ++ struct hlsl_block *args_instrs, const struct vkd3d_shader_location *loc); + struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val, + struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); + struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, +@@ -1493,6 +1549,7 @@ unsigned int hlsl_type_minor_size(const struct hlsl_type *type); + unsigned int hlsl_type_major_size(const struct hlsl_type *type); + unsigned int hlsl_type_element_count(const struct hlsl_type *type); + bool hlsl_type_is_resource(const struct hlsl_type *type); ++bool hlsl_type_is_shader(const struct hlsl_type *type); + unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset); + bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2); + +@@ -1528,16 +1585,15 @@ D3DXPARAMETER_TYPE hlsl_sm1_base_type(const struct hlsl_type *type); + bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, const char *semantic_name, + unsigned int semantic_index, bool output, enum vkd3d_shader_register_type *type, unsigned int *reg); + bool hlsl_sm1_usage_from_semantic(const char *semantic_name, +- uint32_t semantic_index, D3DDECLUSAGE *usage, uint32_t *usage_idx); ++ uint32_t semantic_index, enum vkd3d_decl_usage *usage, uint32_t *usage_idx); + + void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer); + int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_code *ctab, +- struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context, +- struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func); ++ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); + +-bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, +- const struct hlsl_semantic *semantic, bool output, D3D_NAME *usage); ++bool sysval_semantic_from_hlsl(enum vkd3d_shader_sysval_semantic *semantic, ++ struct hlsl_ctx *ctx, const struct hlsl_semantic *hlsl_semantic, bool output); + bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, + bool output, enum vkd3d_shader_register_type *type, bool *has_idx); + int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out); +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.l b/libs/vkd3d/libs/vkd3d-shader/hlsl.l +index 0c02b27817e..b7c242661e3 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.l ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.l +@@ -80,7 +80,9 @@ centroid {return KW_CENTROID; } + column_major {return KW_COLUMN_MAJOR; } + ComputeShader {return KW_COMPUTESHADER; } + compile {return KW_COMPILE; } ++CompileShader {return KW_COMPILESHADER; } + const {return KW_CONST; } ++ConstructGSWithSO {return KW_CONSTRUCTGSWITHSO; } + continue {return KW_CONTINUE; } + DepthStencilState {return KW_DEPTHSTENCILSTATE; } + DepthStencilView {return KW_DEPTHSTENCILVIEW; } +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +index 3f319dea0d8..67262c2ccfd 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +@@ -516,7 +516,7 @@ enum loop_type + LOOP_DO_WHILE + }; + +-static bool attribute_list_has_duplicates(const struct parse_attribute_list *attrs) ++static void check_attribute_list_for_duplicates(struct hlsl_ctx *ctx, const struct parse_attribute_list *attrs) + { + unsigned int i, j; + +@@ -525,11 +525,10 @@ static bool attribute_list_has_duplicates(const struct parse_attribute_list *att + for (j = i + 1; j < attrs->count; ++j) + { + if (!strcmp(attrs->attrs[i]->name, attrs->attrs[j]->name)) +- return true; ++ hlsl_error(ctx, &attrs->attrs[j]->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, ++ "Found duplicate attribute \"%s\".", attrs->attrs[j]->name); + } + } +- +- return false; + } + + static void resolve_loop_continue(struct hlsl_ctx *ctx, struct hlsl_block *block, enum loop_type type, +@@ -610,6 +609,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx + { + switch (node->type) + { ++ case HLSL_IR_COMPILE: + case HLSL_IR_CONSTANT: + case HLSL_IR_EXPR: + case HLSL_IR_STRING_CONSTANT: +@@ -697,9 +697,7 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type, + unsigned int i, unroll_limit = 0; + struct hlsl_ir_node *loop; + +- if (attribute_list_has_duplicates(attributes)) +- hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Found duplicate attribute."); +- ++ check_attribute_list_for_duplicates(ctx, attributes); + check_loop_attributes(ctx, attributes, loc); + + /* Ignore unroll(0) attribute, and any invalid attribute. */ +@@ -1227,7 +1225,8 @@ static bool add_typedef(struct hlsl_ctx *ctx, struct hlsl_type *const orig_type, + } + + static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs, +- struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src); ++ struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src, ++ bool is_default_values_initializer); + + static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters *parameters, + struct parse_parameter *param, const struct vkd3d_shader_location *loc) +@@ -1285,7 +1284,8 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters + + for (i = 0; i < param->initializer.args_count; ++i) + { +- initialize_var_components(ctx, param->initializer.instrs, var, &store_index, param->initializer.args[i]); ++ initialize_var_components(ctx, param->initializer.instrs, var, ++ &store_index, param->initializer.args[i], true); + } + + free_parse_initializer(¶m->initializer); +@@ -1673,25 +1673,36 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct hlsl_block *bl + return expr; + } + +-static void check_integer_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *instr) ++static bool type_is_integer(enum hlsl_base_type type) + { +- const struct hlsl_type *type = instr->data_type; +- struct vkd3d_string_buffer *string; +- +- switch (type->e.numeric.type) ++ switch (type) + { + case HLSL_TYPE_BOOL: + case HLSL_TYPE_INT: + case HLSL_TYPE_UINT: +- break; ++ return true; + +- default: +- if ((string = hlsl_type_to_string(ctx, type))) +- hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, +- "Expression type '%s' is not integer.", string->buffer); +- hlsl_release_string_buffer(ctx, string); +- break; ++ case HLSL_TYPE_DOUBLE: ++ case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: ++ return false; + } ++ ++ vkd3d_unreachable(); ++} ++ ++static void check_integer_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *instr) ++{ ++ const struct hlsl_type *type = instr->data_type; ++ struct vkd3d_string_buffer *string; ++ ++ if (type_is_integer(type->e.numeric.type)) ++ return; ++ ++ if ((string = hlsl_type_to_string(ctx, type))) ++ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, ++ "Expression type '%s' is not integer.", string->buffer); ++ hlsl_release_string_buffer(ctx, string); + } + + static struct hlsl_ir_node *add_unary_arithmetic_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, +@@ -2357,7 +2368,8 @@ static unsigned int get_component_index_from_default_initializer_index(struct hl + } + + static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs, +- struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src) ++ struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src, ++ bool is_default_values_initializer) + { + unsigned int src_comp_count = hlsl_type_component_count(src->data_type); + struct hlsl_deref dst_deref; +@@ -2376,23 +2388,43 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i + + dst_comp_type = hlsl_type_get_component_type(ctx, dst->data_type, *store_index); + +- if (dst->default_values) ++ if (is_default_values_initializer) + { + struct hlsl_default_value default_value = {0}; + unsigned int dst_index; + +- if (!hlsl_clone_block(ctx, &block, instrs)) +- return; +- default_value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); ++ if (hlsl_is_numeric_type(dst_comp_type)) ++ { ++ if (src->type == HLSL_IR_COMPILE) ++ { ++ /* Default values are discarded if they contain an object ++ * literal expression for a numeric component. */ ++ if (dst->default_values) ++ { ++ hlsl_warning(ctx, &src->loc, VKD3D_SHADER_WARNING_HLSL_IGNORED_DEFAULT_VALUE, ++ "Component %u in variable '%s' initializer is object literal. Default values discarded.", ++ k, dst->name); ++ vkd3d_free(dst->default_values); ++ dst->default_values = NULL; ++ } ++ } ++ else ++ { ++ if (!hlsl_clone_block(ctx, &block, instrs)) ++ return; ++ default_value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); + +- if (dst->is_param) +- dst_index = *store_index; +- else +- dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index); ++ if (dst->is_param) ++ dst_index = *store_index; ++ else ++ dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index); + +- dst->default_values[dst_index] = default_value; ++ if (dst->default_values) ++ dst->default_values[dst_index] = default_value; + +- hlsl_block_cleanup(&block); ++ hlsl_block_cleanup(&block); ++ } ++ } + } + else + { +@@ -2733,13 +2765,15 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var + + if (v->initializer.args_count) + { +- unsigned int store_index = 0; + bool is_default_values_initializer; ++ unsigned int store_index = 0; + unsigned int size, k; + + is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) + || (var->storage_modifiers & HLSL_STORAGE_UNIFORM) + || ctx->cur_scope->annotations; ++ if (hlsl_type_is_shader(type)) ++ is_default_values_initializer = false; + + if (is_default_values_initializer) + { +@@ -2780,7 +2814,8 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var + + for (k = 0; k < v->initializer.args_count; ++k) + { +- initialize_var_components(ctx, v->initializer.instrs, var, &store_index, v->initializer.args[k]); ++ initialize_var_components(ctx, v->initializer.instrs, var, ++ &store_index, v->initializer.args[k], is_default_values_initializer); + } + + if (is_default_values_initializer) +@@ -2835,28 +2870,36 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var + return initializers; + } + +-static bool func_is_compatible_match(struct hlsl_ctx *ctx, +- const struct hlsl_ir_function_decl *decl, const struct parse_initializer *args) ++static bool func_is_compatible_match(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *decl, ++ bool is_compile, const struct parse_initializer *args) + { +- unsigned int i; +- +- if (decl->parameters.count < args->args_count) +- return false; ++ unsigned int i, k; + +- for (i = 0; i < args->args_count; ++i) ++ k = 0; ++ for (i = 0; i < decl->parameters.count; ++i) + { +- if (!implicit_compatible_data_types(ctx, args->args[i]->data_type, decl->parameters.vars[i]->data_type)) ++ if (is_compile && !(decl->parameters.vars[i]->storage_modifiers & HLSL_STORAGE_UNIFORM)) ++ continue; ++ ++ if (k >= args->args_count) ++ { ++ if (!decl->parameters.vars[i]->default_values) ++ return false; ++ return true; ++ } ++ ++ if (!implicit_compatible_data_types(ctx, args->args[k]->data_type, decl->parameters.vars[i]->data_type)) + return false; +- } + +- if (args->args_count < decl->parameters.count && !decl->parameters.vars[args->args_count]->default_values) ++ ++k; ++ } ++ if (k < args->args_count) + return false; +- + return true; + } + + static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, +- const char *name, const struct parse_initializer *args, ++ const char *name, const struct parse_initializer *args, bool is_compile, + const struct vkd3d_shader_location *loc) + { + struct hlsl_ir_function_decl *decl, *compatible_match = NULL; +@@ -2869,7 +2912,7 @@ static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, + + LIST_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry) + { +- if (func_is_compatible_match(ctx, decl, args)) ++ if (func_is_compatible_match(ctx, decl, is_compile, args)) + { + if (compatible_match) + { +@@ -2890,26 +2933,35 @@ static struct hlsl_ir_node *hlsl_new_void_expr(struct hlsl_ctx *ctx, const struc + return hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc); + } + +-static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, +- const struct parse_initializer *args, const struct vkd3d_shader_location *loc) ++static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx, ++ struct hlsl_ir_function_decl *func, const struct parse_initializer *args, ++ bool is_compile, const struct vkd3d_shader_location *loc) + { + struct hlsl_ir_node *call; +- unsigned int i, j; ++ unsigned int i, j, k; + + VKD3D_ASSERT(args->args_count <= func->parameters.count); + +- for (i = 0; i < args->args_count; ++i) ++ k = 0; ++ for (i = 0; i < func->parameters.count; ++i) + { + struct hlsl_ir_var *param = func->parameters.vars[i]; +- struct hlsl_ir_node *arg = args->args[i]; ++ struct hlsl_ir_node *arg; ++ ++ if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM)) ++ continue; ++ ++ if (k >= args->args_count) ++ break; ++ arg = args->args[k]; + + if (!hlsl_types_are_equal(arg->data_type, param->data_type)) + { + struct hlsl_ir_node *cast; + + if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc))) +- return false; +- args->args[i] = cast; ++ return NULL; ++ args->args[k] = cast; + arg = cast; + } + +@@ -2918,13 +2970,15 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu + struct hlsl_ir_node *store; + + if (!(store = hlsl_new_simple_store(ctx, param, arg))) +- return false; ++ return NULL; + hlsl_block_add_instr(args->instrs, store); + } ++ ++ ++k; + } + + /* Add default values for the remaining parameters. */ +- for (i = args->args_count; i < func->parameters.count; ++i) ++ for (; i < func->parameters.count; ++i) + { + struct hlsl_ir_var *param = func->parameters.vars[i]; + unsigned int comp_count = hlsl_type_component_count(param->data_type); +@@ -2932,6 +2986,9 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu + + VKD3D_ASSERT(param->default_values); + ++ if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM)) ++ continue; ++ + hlsl_init_simple_deref_from_var(¶m_deref, param); + + for (j = 0; j < comp_count; ++j) +@@ -2945,20 +3002,23 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu + { + value.u[0] = param->default_values[j].number; + if (!(comp = hlsl_new_constant(ctx, type, &value, loc))) +- return false; ++ return NULL; + hlsl_block_add_instr(args->instrs, comp); + + if (!hlsl_new_store_component(ctx, &store_block, ¶m_deref, j, comp)) +- return false; ++ return NULL; + hlsl_block_add_block(args->instrs, &store_block); + } + } + } + + if (!(call = hlsl_new_call(ctx, func, loc))) +- return false; ++ return NULL; + hlsl_block_add_instr(args->instrs, call); + ++ if (is_compile) ++ return call; ++ + for (i = 0; i < args->args_count; ++i) + { + struct hlsl_ir_var *param = func->parameters.vars[i]; +@@ -2973,11 +3033,11 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu + "Output argument to \"%s\" is const.", func->func->name); + + if (!(load = hlsl_new_var_load(ctx, param, &arg->loc))) +- return false; ++ return NULL; + hlsl_block_add_instr(args->instrs, &load->node); + + if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &load->node)) +- return false; ++ return NULL; + } + } + +@@ -2998,7 +3058,7 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu + hlsl_block_add_instr(args->instrs, expr); + } + +- return true; ++ return call; + } + + static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, +@@ -3006,7 +3066,7 @@ static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, + { + struct hlsl_type *type = arg->data_type; + +- if (type->e.numeric.type == HLSL_TYPE_FLOAT || type->e.numeric.type == HLSL_TYPE_HALF) ++ if (!type_is_integer(type->e.numeric.type)) + return arg; + + type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); +@@ -3094,14 +3154,12 @@ static bool elementwise_intrinsic_convert_args(struct hlsl_ctx *ctx, + static bool elementwise_intrinsic_float_convert_args(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { +- enum hlsl_base_type base_type; + struct hlsl_type *type; + + if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) + return false; +- +- base_type = type->e.numeric.type == HLSL_TYPE_HALF ? HLSL_TYPE_HALF : HLSL_TYPE_FLOAT; +- type = hlsl_get_numeric_type(ctx, type->class, base_type, type->dimx, type->dimy); ++ if (type_is_integer(type->e.numeric.type)) ++ type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); + + return convert_args(ctx, params, type, loc); + } +@@ -3129,6 +3187,7 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc, bool asin_mode) + { + struct hlsl_ir_function_decl *func; ++ struct hlsl_ir_node *arg; + struct hlsl_type *type; + char *body; + +@@ -3152,8 +3211,9 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, + + const char *fn_name = asin_mode ? fn_name_asin : fn_name_acos; + +- type = params->args[0]->data_type; +- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); ++ if (!(arg = intrinsic_float_convert_arg(ctx, params, params->args[0], loc))) ++ return false; ++ type = arg->data_type; + + if (!(body = hlsl_sprintf_alloc(ctx, template, + type->name, fn_name, type->name, +@@ -3165,7 +3225,7 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_acos(struct hlsl_ctx *ctx, +@@ -3282,9 +3342,9 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx, + " : poly_approx;\n" + "}"; + +- if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) ++ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) + return false; +- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); ++ type = params->args[0]->data_type; + + if (!(buf = hlsl_get_string_buffer(ctx))) + return false; +@@ -3314,7 +3374,7 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_atan(struct hlsl_ctx *ctx, +@@ -3507,7 +3567,7 @@ static bool write_cosh_or_sinh(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_cosh(struct hlsl_ctx *ctx, +@@ -3525,9 +3585,8 @@ static bool intrinsic_cross(struct hlsl_ctx *ctx, + struct hlsl_type *cast_type; + enum hlsl_base_type base; + +- if (arg1->data_type->e.numeric.type == HLSL_TYPE_HALF && arg2->data_type->e.numeric.type == HLSL_TYPE_HALF) +- base = HLSL_TYPE_HALF; +- else ++ base = expr_common_base_type(arg1->data_type->e.numeric.type, arg2->data_type->e.numeric.type); ++ if (type_is_integer(base)) + base = HLSL_TYPE_FLOAT; + + cast_type = hlsl_get_vector_type(ctx, base, 3); +@@ -3698,15 +3757,14 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx, + return false; + } + ++ if (!(arg = intrinsic_float_convert_arg(ctx, params, arg, loc))) ++ return false; ++ + dim = min(type->dimx, type->dimy); + if (dim == 1) +- { +- if (!(arg = intrinsic_float_convert_arg(ctx, params, arg, loc))) +- return false; + return hlsl_add_load_component(ctx, params->instrs, arg, 0, loc); +- } + +- typename = type->e.numeric.type == HLSL_TYPE_HALF ? "half" : "float"; ++ typename = hlsl_get_scalar_type(ctx, arg->data_type->e.numeric.type)->name; + template = templates[dim]; + + switch (dim) +@@ -3734,7 +3792,7 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_distance(struct hlsl_ctx *ctx, +@@ -3766,6 +3824,50 @@ static bool intrinsic_dot(struct hlsl_ctx *ctx, + return !!add_binary_dot_expr(ctx, params->instrs, params->args[0], params->args[1], loc); + } + ++static bool intrinsic_dst(struct hlsl_ctx *ctx, const struct parse_initializer *params, ++ const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_function_decl *func; ++ struct hlsl_type *type, *vec4_type; ++ char *body; ++ ++ static const char template[] = ++ "%s dst(%s i0, %s i1)\n" ++ "{\n" ++ /* Scalars and vector-4s are both valid inputs, so promote scalars ++ * if necessary. */ ++ " %s src0 = i0, src1 = i1;\n" ++ " return %s(1, src0.y * src1.y, src0.z, src1.w);\n" ++ "}"; ++ ++ if (!elementwise_intrinsic_convert_args(ctx, params, loc)) ++ return false; ++ type = params->args[0]->data_type; ++ if (!(type->class == HLSL_CLASS_SCALAR ++ || (type->class == HLSL_CLASS_VECTOR && type->dimx == 4))) ++ { ++ struct vkd3d_string_buffer *string; ++ if ((string = hlsl_type_to_string(ctx, type))) ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, ++ "Wrong dimension for dst(): expected scalar or 4-dimensional vector, but got %s.", ++ string->buffer); ++ hlsl_release_string_buffer(ctx, string); ++ } ++ vec4_type = hlsl_get_vector_type(ctx, type->e.numeric.type, 4); ++ ++ if (!(body = hlsl_sprintf_alloc(ctx, template, ++ vec4_type->name, type->name, type->name, ++ vec4_type->name, ++ vec4_type->name))) ++ return false; ++ func = hlsl_compile_internal_function(ctx, "dst", body); ++ vkd3d_free(body); ++ if (!func) ++ return false; ++ ++ return !!add_user_call(ctx, func, params, false, loc); ++} ++ + static bool intrinsic_exp(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { +@@ -3809,9 +3911,9 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx, + " return dot(i, ng) < 0 ? n : -n;\n" + "}\n"; + +- if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) ++ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) + return false; +- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); ++ type = params->args[0]->data_type; + + if (!(body = hlsl_sprintf_alloc(ctx, template, + type->name, type->name, type->name, type->name))) +@@ -3821,7 +3923,7 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_f16tof32(struct hlsl_ctx *ctx, +@@ -3926,7 +4028,7 @@ static bool intrinsic_fwidth(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_ldexp(struct hlsl_ctx *ctx, +@@ -4029,7 +4131,7 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, + if (!(func = hlsl_compile_internal_function(ctx, "lit", body))) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_log(struct hlsl_ctx *ctx, +@@ -4081,6 +4183,20 @@ static bool intrinsic_log2(struct hlsl_ctx *ctx, + return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_LOG2, arg, loc); + } + ++static bool intrinsic_mad(struct hlsl_ctx *ctx, ++ const struct parse_initializer *params, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; ++ ++ if (!elementwise_intrinsic_convert_args(ctx, params, loc)) ++ return false; ++ ++ args[0] = params->args[0]; ++ args[1] = params->args[1]; ++ args[2] = params->args[2]; ++ return add_expr(ctx, params->instrs, HLSL_OP3_MAD, args, args[0]->data_type, loc); ++} ++ + static bool intrinsic_max(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { +@@ -4285,13 +4401,9 @@ static bool intrinsic_reflect(struct hlsl_ctx *ctx, + static bool intrinsic_refract(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { +- struct hlsl_type *r_type = params->args[0]->data_type; +- struct hlsl_type *n_type = params->args[1]->data_type; +- struct hlsl_type *i_type = params->args[2]->data_type; +- struct hlsl_type *res_type, *idx_type, *scal_type; +- struct parse_initializer mut_params; ++ struct hlsl_type *type, *scalar_type; + struct hlsl_ir_function_decl *func; +- enum hlsl_base_type base; ++ struct hlsl_ir_node *index; + char *body; + + static const char template[] = +@@ -4303,28 +4415,34 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx, + " return t >= 0.0 ? i.x * r - (i.x * d + sqrt(t)) * n : 0;\n" + "}"; + +- if (r_type->class == HLSL_CLASS_MATRIX +- || n_type->class == HLSL_CLASS_MATRIX +- || i_type->class == HLSL_CLASS_MATRIX) ++ if (params->args[0]->data_type->class == HLSL_CLASS_MATRIX ++ || params->args[1]->data_type->class == HLSL_CLASS_MATRIX ++ || params->args[2]->data_type->class == HLSL_CLASS_MATRIX) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Matrix arguments are not supported."); + return false; + } + +- VKD3D_ASSERT(params->args_count == 3); +- mut_params = *params; +- mut_params.args_count = 2; +- if (!(res_type = elementwise_intrinsic_get_common_type(ctx, &mut_params, loc))) ++ /* This is technically not an elementwise intrinsic, but the first two ++ * arguments are. ++ * The third argument is a scalar, but can be passed as a vector, ++ * which should generate an implicit truncation warning. ++ * Cast down to scalar explicitly, then we can just use ++ * elementwise_intrinsic_float_convert_args(). ++ * This may result in casting the scalar back to a vector, ++ * which we will only use the first component of. */ ++ ++ scalar_type = hlsl_get_scalar_type(ctx, params->args[2]->data_type->e.numeric.type); ++ if (!(index = add_implicit_conversion(ctx, params->instrs, params->args[2], scalar_type, loc))) + return false; ++ params->args[2] = index; + +- base = expr_common_base_type(res_type->e.numeric.type, i_type->e.numeric.type); +- base = base == HLSL_TYPE_HALF ? HLSL_TYPE_HALF : HLSL_TYPE_FLOAT; +- res_type = convert_numeric_type(ctx, res_type, base); +- idx_type = convert_numeric_type(ctx, i_type, base); +- scal_type = hlsl_get_scalar_type(ctx, base); ++ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) ++ return false; ++ type = params->args[0]->data_type; + +- if (!(body = hlsl_sprintf_alloc(ctx, template, res_type->name, res_type->name, +- res_type->name, idx_type->name, scal_type->name))) ++ if (!(body = hlsl_sprintf_alloc(ctx, template, type->name, type->name, ++ type->name, type->name, scalar_type->name))) + return false; + + func = hlsl_compile_internal_function(ctx, "refract", body); +@@ -4332,7 +4450,7 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_round(struct hlsl_ctx *ctx, +@@ -4415,6 +4533,35 @@ static bool intrinsic_sin(struct hlsl_ctx *ctx, + return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_SIN, arg, loc); + } + ++static bool intrinsic_sincos(struct hlsl_ctx *ctx, ++ const struct parse_initializer *params, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_function_decl *func; ++ struct hlsl_type *type; ++ char *body; ++ ++ static const char template[] = ++ "void sincos(%s f, out %s s, out %s c)\n" ++ "{\n" ++ " s = sin(f);\n" ++ " c = cos(f);\n" ++ "}"; ++ ++ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) ++ return false; ++ type = params->args[0]->data_type; ++ ++ if (!(body = hlsl_sprintf_alloc(ctx, template, ++ type->name, type->name, type->name))) ++ return false; ++ func = hlsl_compile_internal_function(ctx, "sincos", body); ++ vkd3d_free(body); ++ if (!func) ++ return false; ++ ++ return !!add_user_call(ctx, func, params, false, loc); ++} ++ + static bool intrinsic_sinh(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { +@@ -4436,9 +4583,9 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, + " return (p * p) * (3 - 2 * p);\n" + "}"; + +- if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) ++ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) + return false; +- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); ++ type = params->args[0]->data_type; + + if (!(body = hlsl_sprintf_alloc(ctx, template, type->name, type->name, type->name, type->name, type->name))) + return false; +@@ -4447,7 +4594,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_sqrt(struct hlsl_ctx *ctx, +@@ -4469,13 +4616,12 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, + + if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) + return false; ++ type = params->args[0]->data_type; + + if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, + params->args[1], params->args[0], loc))) + return false; + +- type = ge->data_type; +- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); + return !!add_implicit_conversion(ctx, params->instrs, ge, type, loc); + } + +@@ -4523,7 +4669,7 @@ static bool intrinsic_tanh(struct hlsl_ctx *ctx, + if (!func) + return false; + +- return add_user_call(ctx, func, params, loc); ++ return !!add_user_call(ctx, func, params, false, loc); + } + + static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, +@@ -4661,17 +4807,17 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * + if (!(var = hlsl_new_synthetic_var(ctx, "coords", hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 2), loc))) + return false; + +- initialize_var_components(ctx, params->instrs, var, &idx, coords); ++ initialize_var_components(ctx, params->instrs, var, &idx, coords, false); + if (hlsl_version_ge(ctx, 4, 0)) + { + if (!(half = hlsl_new_float_constant(ctx, 0.5f, loc))) + return false; + hlsl_block_add_instr(params->instrs, half); + +- initialize_var_components(ctx, params->instrs, var, &idx, half); ++ initialize_var_components(ctx, params->instrs, var, &idx, half, false); + } + else +- initialize_var_components(ctx, params->instrs, var, &idx, coords); ++ initialize_var_components(ctx, params->instrs, var, &idx, coords, false); + + if (!(load = hlsl_new_var_load(ctx, var, loc))) + return false; +@@ -4937,6 +5083,7 @@ intrinsic_functions[] = + {"determinant", 1, true, intrinsic_determinant}, + {"distance", 2, true, intrinsic_distance}, + {"dot", 2, true, intrinsic_dot}, ++ {"dst", 2, true, intrinsic_dst}, + {"exp", 1, true, intrinsic_exp}, + {"exp2", 1, true, intrinsic_exp2}, + {"f16tof32", 1, true, intrinsic_f16tof32}, +@@ -4952,6 +5099,7 @@ intrinsic_functions[] = + {"log", 1, true, intrinsic_log}, + {"log10", 1, true, intrinsic_log10}, + {"log2", 1, true, intrinsic_log2}, ++ {"mad", 3, true, intrinsic_mad}, + {"max", 2, true, intrinsic_max}, + {"min", 2, true, intrinsic_min}, + {"mul", 2, true, intrinsic_mul}, +@@ -4966,6 +5114,7 @@ intrinsic_functions[] = + {"saturate", 1, true, intrinsic_saturate}, + {"sign", 1, true, intrinsic_sign}, + {"sin", 1, true, intrinsic_sin}, ++ {"sincos", 3, true, intrinsic_sincos}, + {"sinh", 1, true, intrinsic_sinh}, + {"smoothstep", 3, true, intrinsic_smoothstep}, + {"sqrt", 1, true, intrinsic_sqrt}, +@@ -5002,9 +5151,9 @@ static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name, + struct intrinsic_function *intrinsic; + struct hlsl_ir_function_decl *decl; + +- if ((decl = find_function_call(ctx, name, args, loc))) ++ if ((decl = find_function_call(ctx, name, args, false, loc))) + { +- if (!add_user_call(ctx, decl, args, loc)) ++ if (!add_user_call(ctx, decl, args, false, loc)) + goto fail; + } + else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions), +@@ -5060,6 +5209,84 @@ fail: + return NULL; + } + ++static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const char *profile_name, ++ const char *function_name, struct parse_initializer *args, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_node *compile, *call_to_compile = NULL; ++ struct hlsl_ir_function_decl *decl; ++ ++ if (!ctx->in_state_block && ctx->cur_scope != ctx->globals) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE, ++ "Shader compilation statements must be in global scope or a state block."); ++ free_parse_initializer(args); ++ return NULL; ++ } ++ ++ if (!(decl = find_function_call(ctx, function_name, args, true, loc))) ++ { ++ if (rb_get(&ctx->functions, function_name)) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, ++ "No compatible \"%s\" declaration with %u uniform parameters found.", ++ function_name, args->args_count); ++ } ++ else ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, ++ "Function \"%s\" is not defined.", function_name); ++ } ++ free_parse_initializer(args); ++ return NULL; ++ } ++ ++ if (!(call_to_compile = add_user_call(ctx, decl, args, true, loc))) ++ { ++ free_parse_initializer(args); ++ return NULL; ++ } ++ ++ if (!(compile = hlsl_new_compile(ctx, HLSL_COMPILE_TYPE_COMPILE, ++ profile_name, &call_to_compile, 1, args->instrs, loc))) ++ { ++ free_parse_initializer(args); ++ return NULL; ++ } ++ ++ free_parse_initializer(args); ++ return make_block(ctx, compile); ++} ++ ++static struct hlsl_block *add_compile_variant(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, ++ struct parse_initializer *args, const struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_node *compile; ++ ++ switch (compile_type) ++ { ++ case HLSL_COMPILE_TYPE_COMPILE: ++ vkd3d_unreachable(); ++ ++ case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: ++ if (args->args_count != 2 && args->args_count != 6) ++ { ++ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, ++ "Wrong number of arguments to ConstructGSWithSO: expected 2 or 6, but got %u.", ++ args->args_count); ++ } ++ break; ++ } ++ ++ if (!(compile = hlsl_new_compile(ctx, compile_type, NULL, args->args, args->args_count, args->instrs, loc))) ++ { ++ free_parse_initializer(args); ++ return NULL; ++ } ++ ++ free_parse_initializer(args); ++ return make_block(ctx, compile); ++} ++ + static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, + struct parse_initializer *params, const struct vkd3d_shader_location *loc) + { +@@ -5071,7 +5298,7 @@ static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type + return NULL; + + for (i = 0; i < params->args_count; ++i) +- initialize_var_components(ctx, params->instrs, var, &idx, params->args[i]); ++ initialize_var_components(ctx, params->instrs, var, &idx, params->args[i], false); + + if (!(load = hlsl_new_var_load(ctx, var, loc))) + return NULL; +@@ -6058,8 +6285,10 @@ static bool state_block_add_entry(struct hlsl_state_block *state_block, struct h + %token KW_CENTROID + %token KW_COLUMN_MAJOR + %token KW_COMPILE ++%token KW_COMPILESHADER + %token KW_COMPUTESHADER + %token KW_CONST ++%token KW_CONSTRUCTGSWITHSO + %token KW_CONTINUE + %token KW_DEFAULT + %token KW_DEPTHSTENCILSTATE +@@ -6827,6 +7056,8 @@ func_prototype: + func_prototype_no_attrs + | attribute_list func_prototype_no_attrs + { ++ check_attribute_list_for_duplicates(ctx, &$1); ++ + if ($2.first) + { + $2.decl->attr_count = $1.count; +@@ -7619,6 +7850,11 @@ stateblock_lhs_identifier: + if (!($$ = hlsl_strdup(ctx, "vertexshader"))) + YYABORT; + } ++ | KW_GEOMETRYSHADER ++ { ++ if (!($$ = hlsl_strdup(ctx, "geometryshader"))) ++ YYABORT; ++ } + + state_block_index_opt: + %empty +@@ -8092,8 +8328,7 @@ selection_statement: + struct hlsl_ir_node *instr; + unsigned int i; + +- if (attribute_list_has_duplicates(attributes)) +- hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Found duplicate attribute."); ++ check_attribute_list_for_duplicates(ctx, attributes); + + for (i = 0; i < attributes->count; ++i) + { +@@ -8391,6 +8626,34 @@ primary_expr: + { + $$ = $2; + } ++ ++ | KW_COMPILE any_identifier var_identifier '(' func_arguments ')' ++ { ++ if (!($$ = add_shader_compilation(ctx, $2, $3, &$5, &@1))) ++ { ++ vkd3d_free($2); ++ vkd3d_free($3); ++ YYABORT; ++ } ++ vkd3d_free($2); ++ vkd3d_free($3); ++ } ++ | KW_COMPILESHADER '(' any_identifier ',' var_identifier '(' func_arguments ')' ')' ++ { ++ if (!($$ = add_shader_compilation(ctx, $3, $5, &$7, &@1))) ++ { ++ vkd3d_free($3); ++ vkd3d_free($5); ++ YYABORT; ++ } ++ vkd3d_free($3); ++ vkd3d_free($5); ++ } ++ | KW_CONSTRUCTGSWITHSO '(' func_arguments ')' ++ { ++ if (!($$ = add_compile_variant(ctx, HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO, &$3, &@1))) ++ YYABORT; ++ } + | var_identifier '(' func_arguments ')' + { + if (!($$ = add_call(ctx, $1, &$3, &@1))) +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +index 92b5c71c43f..6cae0e3b5c9 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +@@ -4050,6 +4050,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) + switch (instr->type) + { + case HLSL_IR_CONSTANT: ++ case HLSL_IR_COMPILE: + case HLSL_IR_EXPR: + case HLSL_IR_INDEX: + case HLSL_IR_LOAD: +@@ -4337,6 +4338,9 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + case HLSL_IR_CONSTANT: + case HLSL_IR_STRING_CONSTANT: + break; ++ case HLSL_IR_COMPILE: ++ /* Compile calls are skipped as they are only relevent to effects. */ ++ break; + } + } + } +@@ -4816,7 +4820,8 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, + } + } + +-static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, float f) ++static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, float f, ++ const struct vkd3d_shader_location *loc) + { + struct hlsl_constant_defs *defs = &ctx->constant_defs; + struct hlsl_constant_register *reg; +@@ -4838,6 +4843,7 @@ static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, + memset(reg, 0, sizeof(*reg)); + reg->index = component_index / 4; + reg->value.f[component_index % 4] = f; ++ reg->loc = *loc; + } + + static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, +@@ -4898,7 +4904,7 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, + vkd3d_unreachable(); + } + +- record_constant(ctx, constant->reg.id * 4 + x, f); ++ record_constant(ctx, constant->reg.id * 4 + x, f, &constant->node.loc); + } + + break; +@@ -4991,17 +4997,17 @@ static void allocate_sincos_const_registers(struct hlsl_ctx *ctx, struct hlsl_bl + + ctx->d3dsincosconst1 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type); + TRACE("Allocated D3DSINCOSCONST1 to %s.\n", debug_register('c', ctx->d3dsincosconst1, type)); +- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 0, -1.55009923e-06f); +- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 1, -2.17013894e-05f); +- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 2, 2.60416674e-03f); +- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 3, 2.60416680e-04f); ++ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 0, -1.55009923e-06f, &instr->loc); ++ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 1, -2.17013894e-05f, &instr->loc); ++ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 2, 2.60416674e-03f, &instr->loc); ++ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 3, 2.60416680e-04f, &instr->loc); + + ctx->d3dsincosconst2 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type); + TRACE("Allocated D3DSINCOSCONST2 to %s.\n", debug_register('c', ctx->d3dsincosconst2, type)); +- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 0, -2.08333340e-02f); +- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 1, -1.25000000e-01f); +- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 2, 1.00000000e+00f); +- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 3, 5.00000000e-01f); ++ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 0, -2.08333340e-02f, &instr->loc); ++ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 1, -1.25000000e-01f, &instr->loc); ++ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 2, 1.00000000e+00f, &instr->loc); ++ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 3, 5.00000000e-01f, &instr->loc); + + return; + } +@@ -5128,7 +5134,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var + if (ctx->profile->major_version < 4) + { + struct vkd3d_shader_version version; +- D3DDECLUSAGE usage; ++ enum vkd3d_decl_usage usage; + uint32_t usage_idx; + + /* ps_1_* outputs are special and go in temp register 0. */ +@@ -5152,10 +5158,10 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var + } + else + { +- D3D_NAME usage; ++ enum vkd3d_shader_sysval_semantic semantic; + bool has_idx; + +- if (!hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage)) ++ if (!sysval_semantic_from_hlsl(&semantic, ctx, &var->semantic, output)) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Invalid semantic '%s'.", var->semantic.name); +@@ -5786,6 +5792,26 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere + return ret; + } + ++static const char *get_string_argument_value(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr, unsigned int i) ++{ ++ const struct hlsl_ir_node *instr = attr->args[i].node; ++ const struct hlsl_type *type = instr->data_type; ++ ++ if (type->class != HLSL_CLASS_STRING) ++ { ++ struct vkd3d_string_buffer *string; ++ ++ if ((string = hlsl_type_to_string(ctx, type))) ++ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, ++ "Wrong type for the argument %u of [%s]: expected string, but got %s.", ++ i, attr->name, string->buffer); ++ hlsl_release_string_buffer(ctx, string); ++ return NULL; ++ } ++ ++ return hlsl_ir_string_constant(instr)->string; ++} ++ + static void parse_numthreads_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) + { + unsigned int i; +@@ -5834,6 +5860,263 @@ static void parse_numthreads_attribute(struct hlsl_ctx *ctx, const struct hlsl_a + } + } + ++static void parse_domain_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) ++{ ++ const char *value; ++ ++ if (attr->args_count != 1) ++ { ++ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, ++ "Expected 1 parameter for [domain] attribute, but got %u.", attr->args_count); ++ return; ++ } ++ ++ if (!(value = get_string_argument_value(ctx, attr, 0))) ++ return; ++ ++ if (!strcmp(value, "isoline")) ++ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_LINE; ++ else if (!strcmp(value, "tri")) ++ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_TRIANGLE; ++ else if (!strcmp(value, "quad")) ++ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_QUAD; ++ else ++ hlsl_error(ctx, &attr->args[0].node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_DOMAIN, ++ "Invalid tessellator domain \"%s\": expected \"isoline\", \"tri\", or \"quad\".", ++ value); ++} ++ ++static void parse_outputcontrolpoints_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) ++{ ++ const struct hlsl_ir_node *instr; ++ const struct hlsl_type *type; ++ const struct hlsl_ir_constant *constant; ++ ++ if (attr->args_count != 1) ++ { ++ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, ++ "Expected 1 parameter for [outputcontrolpoints] attribute, but got %u.", attr->args_count); ++ return; ++ } ++ ++ instr = attr->args[0].node; ++ type = instr->data_type; ++ ++ if (type->class != HLSL_CLASS_SCALAR ++ || (type->e.numeric.type != HLSL_TYPE_INT && type->e.numeric.type != HLSL_TYPE_UINT)) ++ { ++ struct vkd3d_string_buffer *string; ++ ++ if ((string = hlsl_type_to_string(ctx, type))) ++ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, ++ "Wrong type for argument 0 of [outputcontrolpoints]: expected int or uint, but got %s.", ++ string->buffer); ++ hlsl_release_string_buffer(ctx, string); ++ return; ++ } ++ ++ if (instr->type != HLSL_IR_CONSTANT) ++ { ++ hlsl_fixme(ctx, &instr->loc, "Non-constant expression in [outputcontrolpoints] initializer."); ++ return; ++ } ++ constant = hlsl_ir_constant(instr); ++ ++ if ((type->e.numeric.type == HLSL_TYPE_INT && constant->value.u[0].i < 0) ++ || constant->value.u[0].u > 32) ++ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT, ++ "Output control point count must be between 0 and 32."); ++ ++ ctx->output_control_point_count = constant->value.u[0].u; ++} ++ ++static void parse_outputtopology_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) ++{ ++ const char *value; ++ ++ if (attr->args_count != 1) ++ { ++ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, ++ "Expected 1 parameter for [outputtopology] attribute, but got %u.", attr->args_count); ++ return; ++ } ++ ++ if (!(value = get_string_argument_value(ctx, attr, 0))) ++ return; ++ ++ if (!strcmp(value, "point")) ++ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_POINT; ++ else if (!strcmp(value, "line")) ++ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE; ++ else if (!strcmp(value, "triangle_cw")) ++ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW; ++ else if (!strcmp(value, "triangle_ccw")) ++ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW; ++ else ++ hlsl_error(ctx, &attr->args[0].node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, ++ "Invalid tessellator output topology \"%s\": " ++ "expected \"point\", \"line\", \"triangle_cw\", or \"triangle_ccw\".", value); ++} ++ ++static void parse_partitioning_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) ++{ ++ const char *value; ++ ++ if (attr->args_count != 1) ++ { ++ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, ++ "Expected 1 parameter for [partitioning] attribute, but got %u.", attr->args_count); ++ return; ++ } ++ ++ if (!(value = get_string_argument_value(ctx, attr, 0))) ++ return; ++ ++ if (!strcmp(value, "integer")) ++ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_INTEGER; ++ else if (!strcmp(value, "pow2")) ++ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_POW2; ++ else if (!strcmp(value, "fractional_even")) ++ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN; ++ else if (!strcmp(value, "fractional_odd")) ++ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD; ++ else ++ hlsl_error(ctx, &attr->args[0].node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING, ++ "Invalid tessellator partitioning \"%s\": " ++ "expected \"integer\", \"pow2\", \"fractional_even\", or \"fractional_odd\".", value); ++} ++ ++static void parse_patchconstantfunc_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) ++{ ++ const char *name; ++ struct hlsl_ir_function *func; ++ struct hlsl_ir_function_decl *decl; ++ ++ if (attr->args_count != 1) ++ { ++ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, ++ "Expected 1 parameter for [patchconstantfunc] attribute, but got %u.", attr->args_count); ++ return; ++ } ++ ++ if (!(name = get_string_argument_value(ctx, attr, 0))) ++ return; ++ ++ ctx->patch_constant_func = NULL; ++ if ((func = hlsl_get_function(ctx, name))) ++ { ++ /* Pick the last overload with a body. */ ++ LIST_FOR_EACH_ENTRY_REV(decl, &func->overloads, struct hlsl_ir_function_decl, entry) ++ { ++ if (decl->has_body) ++ { ++ ctx->patch_constant_func = decl; ++ break; ++ } ++ } ++ } ++ ++ if (!ctx->patch_constant_func) ++ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, ++ "Patch constant function \"%s\" is not defined.", name); ++} ++ ++static void parse_entry_function_attributes(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) ++{ ++ const struct hlsl_profile_info *profile = ctx->profile; ++ unsigned int i; ++ ++ for (i = 0; i < entry_func->attr_count; ++i) ++ { ++ const struct hlsl_attribute *attr = entry_func->attrs[i]; ++ ++ if (!strcmp(attr->name, "numthreads") && profile->type == VKD3D_SHADER_TYPE_COMPUTE) ++ parse_numthreads_attribute(ctx, attr); ++ else if (!strcmp(attr->name, "domain") ++ && (profile->type == VKD3D_SHADER_TYPE_HULL || profile->type == VKD3D_SHADER_TYPE_DOMAIN)) ++ parse_domain_attribute(ctx, attr); ++ else if (!strcmp(attr->name, "outputcontrolpoints") && profile->type == VKD3D_SHADER_TYPE_HULL) ++ parse_outputcontrolpoints_attribute(ctx, attr); ++ else if (!strcmp(attr->name, "outputtopology") && profile->type == VKD3D_SHADER_TYPE_HULL) ++ parse_outputtopology_attribute(ctx, attr); ++ else if (!strcmp(attr->name, "partitioning") && profile->type == VKD3D_SHADER_TYPE_HULL) ++ parse_partitioning_attribute(ctx, attr); ++ else if (!strcmp(attr->name, "patchconstantfunc") && profile->type == VKD3D_SHADER_TYPE_HULL) ++ parse_patchconstantfunc_attribute(ctx, attr); ++ else if (!strcmp(attr->name, "earlydepthstencil") && profile->type == VKD3D_SHADER_TYPE_PIXEL) ++ entry_func->early_depth_test = true; ++ else ++ hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, ++ "Ignoring unknown attribute \"%s\".", entry_func->attrs[i]->name); ++ } ++} ++ ++static void validate_hull_shader_attributes(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *entry_func) ++{ ++ if (ctx->domain == VKD3D_TESSELLATOR_DOMAIN_INVALID) ++ { ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, ++ "Entry point \"%s\" is missing a [domain] attribute.", entry_func->func->name); ++ } ++ ++ if (ctx->output_control_point_count == UINT_MAX) ++ { ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, ++ "Entry point \"%s\" is missing a [outputcontrolpoints] attribute.", entry_func->func->name); ++ } ++ ++ if (!ctx->output_primitive) ++ { ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, ++ "Entry point \"%s\" is missing a [outputtopology] attribute.", entry_func->func->name); ++ } ++ ++ if (!ctx->partitioning) ++ { ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, ++ "Entry point \"%s\" is missing a [partitioning] attribute.", entry_func->func->name); ++ } ++ ++ if (!ctx->patch_constant_func) ++ { ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, ++ "Entry point \"%s\" is missing a [patchconstantfunc] attribute.", entry_func->func->name); ++ } ++ else if (ctx->patch_constant_func == entry_func) ++ { ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_RECURSIVE_CALL, ++ "Patch constant function cannot be the entry point function."); ++ /* Native returns E_NOTIMPL instead of E_FAIL here. */ ++ ctx->result = VKD3D_ERROR_NOT_IMPLEMENTED; ++ return; ++ } ++ ++ switch (ctx->domain) ++ { ++ case VKD3D_TESSELLATOR_DOMAIN_LINE: ++ if (ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW ++ || ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, ++ "Triangle output topologies are not available for isoline domains."); ++ break; ++ ++ case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE: ++ if (ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE) ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, ++ "Line output topologies are not available for triangle domains."); ++ break; ++ ++ case VKD3D_TESSELLATOR_DOMAIN_QUAD: ++ if (ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE) ++ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, ++ "Line output topologies are not available for quad domains."); ++ break; ++ ++ default: ++ break; ++ } ++} ++ + static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *body) + { + struct hlsl_ir_node *instr, *next; +@@ -5956,8 +6239,8 @@ static void sm1_generate_vsir_signature_entry(struct hlsl_ctx *ctx, + if (!hlsl_sm1_register_from_semantic(&program->shader_version, + var->semantic.name, var->semantic.index, output, &type, ®ister_index)) + { ++ enum vkd3d_decl_usage usage; + unsigned int usage_idx; +- D3DDECLUSAGE usage; + bool ret; + + register_index = var->regs[HLSL_REGSET_NUMERIC].id; +@@ -5969,7 +6252,7 @@ static void sm1_generate_vsir_signature_entry(struct hlsl_ctx *ctx, + * SV_Position; the closer equivalent is VPOS, which is not declared + * as a semantic. */ + if (program->shader_version.type == VKD3D_SHADER_TYPE_VERTEX +- && output && usage == D3DDECLUSAGE_POSITION) ++ && output && usage == VKD3D_DECL_USAGE_POSITION) + sysval = VKD3D_SHADER_SV_POSITION; + } + mask = (1 << var->data_type->dimx) - 1; +@@ -6006,104 +6289,1018 @@ static void sm1_generate_vsir_signature(struct hlsl_ctx *ctx, struct vsir_progra + } + } + +-/* OBJECTIVE: Translate all the information from ctx and entry_func to the +- * vsir_program and ctab blob, so they can be used as input to d3dbc_compile() +- * without relying on ctx and entry_func. */ +-static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, +- uint64_t config_flags, struct vsir_program *program, struct vkd3d_shader_code *ctab) ++static uint32_t sm1_generate_vsir_get_src_swizzle(uint32_t src_writemask, uint32_t dst_writemask) + { +- struct vkd3d_shader_version version = {0}; +- struct vkd3d_bytecode_buffer buffer = {0}; +- +- version.major = ctx->profile->major_version; +- version.minor = ctx->profile->minor_version; +- version.type = ctx->profile->type; +- if (!vsir_program_init(program, NULL, &version, 0)) +- { +- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; +- return; +- } ++ uint32_t swizzle; + +- write_sm1_uniforms(ctx, &buffer); +- if (buffer.status) +- { +- vkd3d_free(buffer.data); +- ctx->result = buffer.status; +- return; +- } +- ctab->code = buffer.data; +- ctab->size = buffer.size; +- +- sm1_generate_vsir_signature(ctx, program); ++ swizzle = hlsl_swizzle_from_writemask(src_writemask); ++ swizzle = hlsl_map_swizzle(swizzle, dst_writemask); ++ swizzle = vsir_swizzle_from_hlsl(swizzle); ++ return swizzle; + } + +-static struct hlsl_ir_jump *loop_unrolling_find_jump(struct hlsl_block *block, struct hlsl_ir_node *stop_point, +- struct hlsl_block **found_block) ++static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, struct vsir_program *program, ++ struct hlsl_block *block) + { +- struct hlsl_ir_node *node; ++ struct vkd3d_shader_instruction_array *instructions = &program->instructions; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_src_param *src_param; ++ struct vkd3d_shader_instruction *ins; ++ unsigned int i, x; + +- LIST_FOR_EACH_ENTRY(node, &block->instrs, struct hlsl_ir_node, entry) ++ for (i = 0; i < ctx->constant_defs.count; ++i) + { +- if (node == stop_point) +- return NULL; ++ const struct hlsl_constant_register *constant_reg = &ctx->constant_defs.regs[i]; + +- if (node->type == HLSL_IR_IF) ++ if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) + { +- struct hlsl_ir_if *iff = hlsl_ir_if(node); +- struct hlsl_ir_jump *jump = NULL; +- +- if ((jump = loop_unrolling_find_jump(&iff->then_block, stop_point, found_block))) +- return jump; +- if ((jump = loop_unrolling_find_jump(&iff->else_block, stop_point, found_block))) +- return jump; ++ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; ++ return; + } +- else if (node->type == HLSL_IR_JUMP) ++ ++ ins = &instructions->elements[instructions->count]; ++ if (!vsir_instruction_init_with_params(program, ins, &constant_reg->loc, VKD3DSIH_DEF, 1, 1)) + { +- struct hlsl_ir_jump *jump = hlsl_ir_jump(node); ++ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; ++ return; ++ } ++ ++instructions->count; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); ++ ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ++ ins->dst[0].reg.idx[0].offset = constant_reg->index; ++ ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; ++ ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_IMMCONST, VKD3D_DATA_FLOAT, 0); ++ src_param->reg.type = VKD3DSPR_IMMCONST; ++ src_param->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; ++ src_param->reg.non_uniform = false; ++ src_param->reg.data_type = VKD3D_DATA_FLOAT; ++ src_param->reg.dimension = VSIR_DIMENSION_VEC4; ++ for (x = 0; x < 4; ++x) ++ src_param->reg.u.immconst_f32[x] = constant_reg->value.f[x]; ++ src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ } ++} ++ ++static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx, ++ struct vsir_program *program, struct hlsl_block *block) ++{ ++ struct vkd3d_shader_instruction_array *instructions = &program->instructions; ++ enum vkd3d_shader_resource_type resource_type; ++ struct vkd3d_shader_register_range *range; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_semantic *semantic; ++ struct vkd3d_shader_instruction *ins; ++ enum hlsl_sampler_dim sampler_dim; ++ struct hlsl_ir_var *var; ++ unsigned int i, count; + +- if (jump->type == HLSL_IR_JUMP_BREAK || jump->type == HLSL_IR_JUMP_CONTINUE) ++ LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) ++ { ++ if (!var->regs[HLSL_REGSET_SAMPLERS].allocated) ++ continue; ++ ++ count = var->bind_count[HLSL_REGSET_SAMPLERS]; ++ for (i = 0; i < count; ++i) ++ { ++ if (var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) + { +- *found_block = block; +- return jump; ++ sampler_dim = var->objects_usage[HLSL_REGSET_SAMPLERS][i].sampler_dim; ++ ++ switch (sampler_dim) ++ { ++ case HLSL_SAMPLER_DIM_2D: ++ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; ++ break; ++ ++ case HLSL_SAMPLER_DIM_CUBE: ++ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_CUBE; ++ break; ++ ++ case HLSL_SAMPLER_DIM_3D: ++ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_3D; ++ break; ++ ++ case HLSL_SAMPLER_DIM_GENERIC: ++ /* These can appear in sm4-style combined sample instructions. */ ++ hlsl_fixme(ctx, &var->loc, "Generic samplers need to be lowered."); ++ continue; ++ ++ default: ++ vkd3d_unreachable(); ++ break; ++ } ++ ++ if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) ++ { ++ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; ++ return; ++ } ++ ++ ins = &instructions->elements[instructions->count]; ++ if (!vsir_instruction_init_with_params(program, ins, &var->loc, VKD3DSIH_DCL, 0, 0)) ++ { ++ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; ++ return; ++ } ++ ++instructions->count; ++ ++ semantic = &ins->declaration.semantic; ++ semantic->resource_type = resource_type; ++ ++ dst_param = &semantic->resource.reg; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_SAMPLER, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.dimension = VSIR_DIMENSION_NONE; ++ dst_param->reg.idx[0].offset = var->regs[HLSL_REGSET_SAMPLERS].index + i; ++ dst_param->write_mask = 0; ++ range = &semantic->resource.range; ++ range->space = 0; ++ range->first = range->last = dst_param->reg.idx[0].offset; + } + } + } ++} + +- return NULL; ++static struct vkd3d_shader_instruction *generate_vsir_add_program_instruction( ++ struct hlsl_ctx *ctx, struct vsir_program *program, ++ const struct vkd3d_shader_location *loc, enum vkd3d_shader_opcode opcode, ++ unsigned int dst_count, unsigned int src_count) ++{ ++ struct vkd3d_shader_instruction_array *instructions = &program->instructions; ++ struct vkd3d_shader_instruction *ins; ++ ++ if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) ++ { ++ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; ++ return NULL; ++ } ++ ins = &instructions->elements[instructions->count]; ++ if (!vsir_instruction_init_with_params(program, ins, loc, opcode, dst_count, src_count)) ++ { ++ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; ++ return NULL; ++ } ++ ++instructions->count; ++ return ins; + } + +-static unsigned int loop_unrolling_get_max_iterations(struct hlsl_ctx *ctx, struct hlsl_ir_loop *loop) ++static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, ++ struct vsir_program *program, struct hlsl_ir_constant *constant) + { +- /* Always use the explicit limit if it has been passed. */ +- if (loop->unroll_limit) +- return loop->unroll_limit; ++ struct hlsl_ir_node *instr = &constant->node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_src_param *src_param; ++ struct vkd3d_shader_instruction *ins; + +- /* All SMs will default to 1024 if [unroll] has been specified without an explicit limit. */ +- if (loop->unroll_type == HLSL_IR_LOOP_FORCE_UNROLL) +- return 1024; ++ VKD3D_ASSERT(instr->reg.allocated); ++ VKD3D_ASSERT(constant->reg.allocated); + +- /* SM4 limits implicit unrolling to 254 iterations. */ +- if (hlsl_version_ge(ctx, 4, 0)) +- return 254; ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) ++ return; + +- /* SM<3 implicitly unrolls up to 1024 iterations. */ +- return 1024; ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = constant->reg.id; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(constant->reg.writemask, instr->reg.writemask); ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = instr->reg.id; ++ dst_param->write_mask = instr->reg.writemask; + } + +-static bool loop_unrolling_unroll_loop(struct hlsl_ctx *ctx, struct hlsl_block *block, +- struct hlsl_block *loop_parent, struct hlsl_ir_loop *loop) ++/* Translate ops that can be mapped to a single vsir instruction with only one dst register. */ ++static void sm1_generate_vsir_instr_expr_single_instr_op(struct hlsl_ctx *ctx, struct vsir_program *program, ++ struct hlsl_ir_expr *expr, enum vkd3d_shader_opcode opcode, uint32_t src_mod, uint32_t dst_mod, ++ bool map_src_swizzles) + { +- unsigned int max_iterations, i; ++ struct hlsl_ir_node *instr = &expr->node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_src_param *src_param; ++ struct vkd3d_shader_instruction *ins; ++ unsigned int i, src_count = 0; + +- max_iterations = loop_unrolling_get_max_iterations(ctx, loop); ++ VKD3D_ASSERT(instr->reg.allocated); + +- for (i = 0; i < max_iterations; ++i) ++ for (i = 0; i < HLSL_MAX_OPERANDS; ++i) + { +- struct hlsl_block tmp_dst, *jump_block; +- struct hlsl_ir_jump *jump = NULL; ++ if (expr->operands[i].node) ++ src_count = i + 1; ++ } ++ VKD3D_ASSERT(!src_mod || src_count == 1); + +- if (!hlsl_clone_block(ctx, &tmp_dst, &loop->body)) +- return false; ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, src_count))) ++ return; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = instr->reg.id; ++ dst_param->write_mask = instr->reg.writemask; ++ dst_param->modifiers = dst_mod; ++ ++ for (i = 0; i < src_count; ++i) ++ { ++ struct hlsl_ir_node *operand = expr->operands[i].node; ++ ++ src_param = &ins->src[i]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = operand->reg.id; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(operand->reg.writemask, ++ map_src_swizzles ? dst_param->write_mask : VKD3DSP_WRITEMASK_ALL); ++ src_param->modifiers = src_mod; ++ } ++} ++ ++/* Translate ops that have 1 src and need one instruction for each component in ++ * the d3dbc backend. */ ++static void sm1_generate_vsir_instr_expr_per_component_instr_op(struct hlsl_ctx *ctx, ++ struct vsir_program *program, struct hlsl_ir_expr *expr, enum vkd3d_shader_opcode opcode) ++{ ++ struct hlsl_ir_node *operand = expr->operands[0].node; ++ struct hlsl_ir_node *instr = &expr->node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_src_param *src_param; ++ struct vkd3d_shader_instruction *ins; ++ uint32_t src_swizzle; ++ unsigned int i, c; ++ ++ VKD3D_ASSERT(instr->reg.allocated); ++ VKD3D_ASSERT(operand); ++ ++ src_swizzle = sm1_generate_vsir_get_src_swizzle(operand->reg.writemask, instr->reg.writemask); ++ for (i = 0; i < 4; ++i) ++ { ++ if (instr->reg.writemask & (1u << i)) ++ { ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, 1))) ++ return; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = instr->reg.id; ++ dst_param->write_mask = 1u << i; ++ ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = operand->reg.id; ++ c = vsir_swizzle_get_component(src_swizzle, i); ++ src_param->swizzle = vsir_swizzle_from_writemask(1u << c); ++ } ++ } ++} ++ ++static void sm1_generate_vsir_instr_expr_sincos(struct hlsl_ctx *ctx, struct vsir_program *program, ++ struct hlsl_ir_expr *expr) ++{ ++ struct hlsl_ir_node *operand = expr->operands[0].node; ++ struct hlsl_ir_node *instr = &expr->node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_src_param *src_param; ++ struct vkd3d_shader_instruction *ins; ++ unsigned int src_count = 0; ++ ++ VKD3D_ASSERT(instr->reg.allocated); ++ src_count = (ctx->profile->major_version < 3) ? 3 : 1; ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_SINCOS, 1, src_count))) ++ return; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = instr->reg.id; ++ dst_param->write_mask = instr->reg.writemask; ++ ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = operand->reg.id; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(operand->reg.writemask, VKD3DSP_WRITEMASK_ALL); ++ ++ if (ctx->profile->major_version < 3) ++ { ++ src_param = &ins->src[1]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = ctx->d3dsincosconst1.id; ++ src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ ++ src_param = &ins->src[1]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = ctx->d3dsincosconst2.id; ++ src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ } ++} ++ ++static bool sm1_generate_vsir_instr_expr_cast(struct hlsl_ctx *ctx, ++ struct vsir_program *program, struct hlsl_ir_expr *expr) ++{ ++ const struct hlsl_type *src_type, *dst_type; ++ const struct hlsl_ir_node *arg1, *instr; ++ ++ arg1 = expr->operands[0].node; ++ src_type = arg1->data_type; ++ instr = &expr->node; ++ dst_type = instr->data_type; ++ ++ /* Narrowing casts were already lowered. */ ++ VKD3D_ASSERT(src_type->dimx == dst_type->dimx); ++ ++ switch (dst_type->e.numeric.type) ++ { ++ case HLSL_TYPE_HALF: ++ case HLSL_TYPE_FLOAT: ++ switch (src_type->e.numeric.type) ++ { ++ case HLSL_TYPE_INT: ++ case HLSL_TYPE_UINT: ++ case HLSL_TYPE_BOOL: ++ /* Integrals are internally represented as floats, so no change is necessary.*/ ++ case HLSL_TYPE_HALF: ++ case HLSL_TYPE_FLOAT: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); ++ return true; ++ ++ case HLSL_TYPE_DOUBLE: ++ hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to float."); ++ break; ++ ++ default: ++ vkd3d_unreachable(); ++ } ++ break; ++ ++ case HLSL_TYPE_INT: ++ case HLSL_TYPE_UINT: ++ switch(src_type->e.numeric.type) ++ { ++ case HLSL_TYPE_HALF: ++ case HLSL_TYPE_FLOAT: ++ /* A compilation pass turns these into FLOOR+REINTERPRET, so we should not ++ * reach this case unless we are missing something. */ ++ hlsl_fixme(ctx, &instr->loc, "Unlowered SM1 cast from float to integer."); ++ break; ++ ++ case HLSL_TYPE_INT: ++ case HLSL_TYPE_UINT: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); ++ return true; ++ ++ case HLSL_TYPE_BOOL: ++ hlsl_fixme(ctx, &instr->loc, "SM1 cast from bool to integer."); ++ break; ++ ++ case HLSL_TYPE_DOUBLE: ++ hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to integer."); ++ break; ++ ++ default: ++ vkd3d_unreachable(); ++ } ++ break; ++ ++ case HLSL_TYPE_DOUBLE: ++ hlsl_fixme(ctx, &instr->loc, "SM1 cast to double."); ++ break; ++ ++ case HLSL_TYPE_BOOL: ++ /* Casts to bool should have already been lowered. */ ++ default: ++ hlsl_fixme(ctx, &expr->node.loc, "SM1 cast from %s to %s.", ++ debug_hlsl_type(ctx, src_type), debug_hlsl_type(ctx, dst_type)); ++ break; ++ } ++ ++ return false; ++} ++ ++static bool sm1_generate_vsir_instr_expr(struct hlsl_ctx *ctx, struct vsir_program *program, ++ struct hlsl_ir_expr *expr) ++{ ++ struct hlsl_ir_node *instr = &expr->node; ++ ++ if (expr->op != HLSL_OP1_REINTERPRET && expr->op != HLSL_OP1_CAST ++ && instr->data_type->e.numeric.type != HLSL_TYPE_FLOAT) ++ { ++ /* These need to be lowered. */ ++ hlsl_fixme(ctx, &instr->loc, "SM1 non-float expression."); ++ return false; ++ } ++ ++ switch (expr->op) ++ { ++ case HLSL_OP1_ABS: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_ABS, 0, 0, true); ++ break; ++ ++ case HLSL_OP1_CAST: ++ return sm1_generate_vsir_instr_expr_cast(ctx, program, expr); ++ ++ case HLSL_OP1_COS_REDUCED: ++ VKD3D_ASSERT(expr->node.reg.writemask == VKD3DSP_WRITEMASK_0); ++ sm1_generate_vsir_instr_expr_sincos(ctx, program, expr); ++ break; ++ ++ case HLSL_OP1_DSX: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DSX, 0, 0, true); ++ break; ++ ++ case HLSL_OP1_DSY: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DSY, 0, 0, true); ++ break; ++ ++ case HLSL_OP1_EXP2: ++ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_EXP); ++ break; ++ ++ case HLSL_OP1_LOG2: ++ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_LOG); ++ break; ++ ++ case HLSL_OP1_NEG: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, VKD3DSPSM_NEG, 0, true); ++ break; ++ ++ case HLSL_OP1_RCP: ++ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_RCP); ++ break; ++ ++ case HLSL_OP1_REINTERPRET: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); ++ break; ++ ++ case HLSL_OP1_RSQ: ++ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_RSQ); ++ break; ++ ++ case HLSL_OP1_SAT: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, VKD3DSPDM_SATURATE, true); ++ break; ++ ++ case HLSL_OP1_SIN_REDUCED: ++ VKD3D_ASSERT(expr->node.reg.writemask == VKD3DSP_WRITEMASK_1); ++ sm1_generate_vsir_instr_expr_sincos(ctx, program, expr); ++ break; ++ ++ case HLSL_OP2_ADD: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_ADD, 0, 0, true); ++ break; ++ ++ case HLSL_OP2_DOT: ++ switch (expr->operands[0].node->data_type->dimx) ++ { ++ case 3: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DP3, 0, 0, false); ++ break; ++ ++ case 4: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DP4, 0, 0, false); ++ break; ++ ++ default: ++ vkd3d_unreachable(); ++ return false; ++ } ++ break; ++ ++ case HLSL_OP2_MAX: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MAX, 0, 0, true); ++ break; ++ ++ case HLSL_OP2_MIN: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MIN, 0, 0, true); ++ break; ++ ++ case HLSL_OP2_MUL: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MUL, 0, 0, true); ++ break; ++ ++ case HLSL_OP1_FRACT: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_FRC, 0, 0, true); ++ break; ++ ++ case HLSL_OP2_LOGIC_AND: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MIN, 0, 0, true); ++ break; ++ ++ case HLSL_OP2_LOGIC_OR: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MAX, 0, 0, true); ++ break; ++ ++ case HLSL_OP2_SLT: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_SLT, 0, 0, true); ++ break; ++ ++ case HLSL_OP3_CMP: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_CMP, 0, 0, true); ++ break; ++ ++ case HLSL_OP3_DP2ADD: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DP2ADD, 0, 0, false); ++ break; ++ ++ case HLSL_OP3_MAD: ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MAD, 0, 0, true); ++ break; ++ ++ default: ++ hlsl_fixme(ctx, &instr->loc, "SM1 \"%s\" expression.", debug_hlsl_expr_op(expr->op)); ++ return false; ++ } ++ ++ return true; ++} ++ ++static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx, ++ struct vkd3d_shader_dst_param *dst_param, struct hlsl_deref *deref, ++ const struct vkd3d_shader_location *loc, unsigned int writemask) ++{ ++ enum vkd3d_shader_register_type type = VKD3DSPR_TEMP; ++ struct vkd3d_shader_version version; ++ uint32_t register_index; ++ struct hlsl_reg reg; ++ ++ reg = hlsl_reg_from_deref(ctx, deref); ++ register_index = reg.id; ++ writemask = hlsl_combine_writemasks(reg.writemask, writemask); ++ ++ if (deref->var->is_output_semantic) ++ { ++ version.major = ctx->profile->major_version; ++ version.minor = ctx->profile->minor_version; ++ version.type = ctx->profile->type; ++ ++ if (version.type == VKD3D_SHADER_TYPE_PIXEL && version.major == 1) ++ { ++ type = VKD3DSPR_TEMP; ++ register_index = 0; ++ } ++ else if (!hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name, ++ deref->var->semantic.index, true, &type, ®ister_index)) ++ { ++ VKD3D_ASSERT(reg.allocated); ++ type = VKD3DSPR_OUTPUT; ++ register_index = reg.id; ++ } ++ else ++ writemask = (1u << deref->var->data_type->dimx) - 1; ++ } ++ else ++ VKD3D_ASSERT(reg.allocated); ++ ++ vsir_register_init(&dst_param->reg, type, VKD3D_DATA_FLOAT, 1); ++ dst_param->write_mask = writemask; ++ dst_param->reg.idx[0].offset = register_index; ++ ++ if (deref->rel_offset.node) ++ hlsl_fixme(ctx, loc, "Translate relative addressing on dst register for vsir."); ++} ++ ++static void sm1_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx, ++ struct vkd3d_shader_src_param *src_param, struct hlsl_deref *deref, ++ unsigned int dst_writemask, const struct vkd3d_shader_location *loc) ++{ ++ enum vkd3d_shader_register_type type = VKD3DSPR_TEMP; ++ struct vkd3d_shader_version version; ++ uint32_t register_index; ++ unsigned int writemask; ++ struct hlsl_reg reg; ++ ++ if (hlsl_type_is_resource(deref->var->data_type)) ++ { ++ unsigned int sampler_offset; ++ ++ type = VKD3DSPR_COMBINED_SAMPLER; ++ ++ sampler_offset = hlsl_offset_from_deref_safe(ctx, deref); ++ register_index = deref->var->regs[HLSL_REGSET_SAMPLERS].index + sampler_offset; ++ writemask = VKD3DSP_WRITEMASK_ALL; ++ } ++ else if (deref->var->is_uniform) ++ { ++ type = VKD3DSPR_CONST; ++ ++ reg = hlsl_reg_from_deref(ctx, deref); ++ register_index = reg.id; ++ writemask = reg.writemask; ++ VKD3D_ASSERT(reg.allocated); ++ } ++ else if (deref->var->is_input_semantic) ++ { ++ version.major = ctx->profile->major_version; ++ version.minor = ctx->profile->minor_version; ++ version.type = ctx->profile->type; ++ if (hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name, ++ deref->var->semantic.index, false, &type, ®ister_index)) ++ { ++ writemask = (1 << deref->var->data_type->dimx) - 1; ++ } ++ else ++ { ++ type = VKD3DSPR_INPUT; ++ ++ reg = hlsl_reg_from_deref(ctx, deref); ++ register_index = reg.id; ++ writemask = reg.writemask; ++ VKD3D_ASSERT(reg.allocated); ++ } ++ } ++ else ++ { ++ type = VKD3DSPR_TEMP; ++ ++ reg = hlsl_reg_from_deref(ctx, deref); ++ register_index = reg.id; ++ writemask = reg.writemask; ++ } ++ ++ vsir_register_init(&src_param->reg, type, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = register_index; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(writemask, dst_writemask); ++ ++ if (deref->rel_offset.node) ++ hlsl_fixme(ctx, loc, "Translate relative addressing on src register for vsir."); ++} ++ ++static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_program *program, ++ struct hlsl_ir_load *load) ++{ ++ struct hlsl_ir_node *instr = &load->node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_instruction *ins; ++ ++ VKD3D_ASSERT(instr->reg.allocated); ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) ++ return; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = instr->reg.id; ++ dst_param->write_mask = instr->reg.writemask; ++ ++ sm1_generate_vsir_init_src_param_from_deref(ctx, &ins->src[0], &load->src, dst_param->write_mask, ++ &ins->location); ++} ++ ++static void sm1_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, ++ struct vsir_program *program, struct hlsl_ir_resource_load *load) ++{ ++ struct hlsl_ir_node *coords = load->coords.node; ++ struct hlsl_ir_node *ddx = load->ddx.node; ++ struct hlsl_ir_node *ddy = load->ddy.node; ++ struct hlsl_ir_node *instr = &load->node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_src_param *src_param; ++ struct vkd3d_shader_instruction *ins; ++ enum vkd3d_shader_opcode opcode; ++ unsigned int src_count = 2; ++ uint32_t flags = 0; ++ ++ VKD3D_ASSERT(instr->reg.allocated); ++ ++ switch (load->load_type) ++ { ++ case HLSL_RESOURCE_SAMPLE: ++ opcode = VKD3DSIH_TEX; ++ break; ++ ++ case HLSL_RESOURCE_SAMPLE_PROJ: ++ opcode = VKD3DSIH_TEX; ++ flags |= VKD3DSI_TEXLD_PROJECT; ++ break; ++ ++ case HLSL_RESOURCE_SAMPLE_LOD_BIAS: ++ opcode = VKD3DSIH_TEX; ++ flags |= VKD3DSI_TEXLD_BIAS; ++ break; ++ ++ case HLSL_RESOURCE_SAMPLE_GRAD: ++ opcode = VKD3DSIH_TEXLDD; ++ src_count += 2; ++ break; ++ ++ default: ++ hlsl_fixme(ctx, &instr->loc, "Resource load type %u.", load->load_type); ++ return; ++ } ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, src_count))) ++ return; ++ ins->flags = flags; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = instr->reg.id; ++ dst_param->write_mask = instr->reg.writemask; ++ ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = coords->reg.id; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(coords->reg.writemask, VKD3DSP_WRITEMASK_ALL); ++ ++ sm1_generate_vsir_init_src_param_from_deref(ctx, &ins->src[1], &load->resource, ++ VKD3DSP_WRITEMASK_ALL, &ins->location); ++ ++ if (load->load_type == HLSL_RESOURCE_SAMPLE_GRAD) ++ { ++ src_param = &ins->src[2]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = ddx->reg.id; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(ddx->reg.writemask, VKD3DSP_WRITEMASK_ALL); ++ ++ src_param = &ins->src[3]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = ddy->reg.id; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(ddy->reg.writemask, VKD3DSP_WRITEMASK_ALL); ++ } ++} ++ ++static void sm1_generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, struct vsir_program *program, ++ struct hlsl_ir_swizzle *swizzle_instr) ++{ ++ struct hlsl_ir_node *instr = &swizzle_instr->node, *val = swizzle_instr->val.node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_src_param *src_param; ++ struct vkd3d_shader_instruction *ins; ++ uint32_t swizzle; ++ ++ VKD3D_ASSERT(instr->reg.allocated); ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) ++ return; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = instr->reg.id; ++ dst_param->write_mask = instr->reg.writemask; ++ ++ swizzle = hlsl_swizzle_from_writemask(val->reg.writemask); ++ swizzle = hlsl_combine_swizzles(swizzle, swizzle_instr->swizzle, instr->data_type->dimx); ++ swizzle = hlsl_map_swizzle(swizzle, ins->dst[0].write_mask); ++ swizzle = vsir_swizzle_from_hlsl(swizzle); ++ ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = val->reg.id; ++ src_param->swizzle = swizzle; ++} ++ ++static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_program *program, ++ struct hlsl_ir_store *store) ++{ ++ struct hlsl_ir_node *rhs = store->rhs.node; ++ struct hlsl_ir_node *instr = &store->node; ++ struct vkd3d_shader_instruction *ins; ++ struct vkd3d_shader_src_param *src_param; ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) ++ return; ++ ++ sm1_generate_vsir_init_dst_param_from_deref(ctx, &ins->dst[0], &store->lhs, &ins->location, store->writemask); ++ ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = rhs->reg.id; ++ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(rhs->reg.writemask, ins->dst[0].write_mask); ++} ++ ++static void sm1_generate_vsir_instr_jump(struct hlsl_ctx *ctx, ++ struct vsir_program *program, struct hlsl_ir_jump *jump) ++{ ++ struct hlsl_ir_node *condition = jump->condition.node; ++ struct hlsl_ir_node *instr = &jump->node; ++ struct vkd3d_shader_dst_param *dst_param; ++ struct vkd3d_shader_instruction *ins; ++ ++ if (jump->type == HLSL_IR_JUMP_DISCARD_NEG) ++ { ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_TEXKILL, 1, 0))) ++ return; ++ ++ dst_param = &ins->dst[0]; ++ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ dst_param->reg.idx[0].offset = condition->reg.id; ++ dst_param->write_mask = condition->reg.writemask; ++ } ++ else ++ { ++ hlsl_fixme(ctx, &instr->loc, "Jump type %s.", hlsl_jump_type_to_string(jump->type)); ++ } ++} ++ ++static void sm1_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *block, struct vsir_program *program); ++ ++static void sm1_generate_vsir_instr_if(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_if *iff) ++{ ++ struct hlsl_ir_node *condition = iff->condition.node; ++ struct vkd3d_shader_src_param *src_param; ++ struct hlsl_ir_node *instr = &iff->node; ++ struct vkd3d_shader_instruction *ins; ++ uint32_t swizzle; ++ ++ if (hlsl_version_lt(ctx, 2, 1)) ++ { ++ hlsl_fixme(ctx, &instr->loc, "Flatten \"if\" conditionals branches."); ++ return; ++ } ++ VKD3D_ASSERT(condition->data_type->dimx == 1 && condition->data_type->dimy == 1); ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_IFC, 0, 2))) ++ return; ++ ins->flags = VKD3D_SHADER_REL_OP_NE; ++ ++ swizzle = hlsl_swizzle_from_writemask(condition->reg.writemask); ++ swizzle = vsir_swizzle_from_hlsl(swizzle); ++ ++ src_param = &ins->src[0]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = condition->reg.id; ++ src_param->swizzle = swizzle; ++ src_param->modifiers = 0; ++ ++ src_param = &ins->src[1]; ++ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src_param->reg.idx[0].offset = condition->reg.id; ++ src_param->swizzle = swizzle; ++ src_param->modifiers = VKD3DSPSM_NEG; ++ ++ sm1_generate_vsir_block(ctx, &iff->then_block, program); ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_ELSE, 0, 0))) ++ return; ++ ++ sm1_generate_vsir_block(ctx, &iff->else_block, program); ++ ++ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_ENDIF, 0, 0))) ++ return; ++} ++ ++static void sm1_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *block, struct vsir_program *program) ++{ ++ struct hlsl_ir_node *instr, *next; ++ ++ LIST_FOR_EACH_ENTRY_SAFE(instr, next, &block->instrs, struct hlsl_ir_node, entry) ++ { ++ if (instr->data_type) ++ { ++ if (instr->data_type->class != HLSL_CLASS_SCALAR && instr->data_type->class != HLSL_CLASS_VECTOR) ++ { ++ hlsl_fixme(ctx, &instr->loc, "Class %#x should have been lowered or removed.", instr->data_type->class); ++ break; ++ } ++ } ++ ++ switch (instr->type) ++ { ++ case HLSL_IR_CALL: ++ vkd3d_unreachable(); ++ ++ case HLSL_IR_CONSTANT: ++ sm1_generate_vsir_instr_constant(ctx, program, hlsl_ir_constant(instr)); ++ break; ++ ++ case HLSL_IR_EXPR: ++ sm1_generate_vsir_instr_expr(ctx, program, hlsl_ir_expr(instr)); ++ break; ++ ++ case HLSL_IR_IF: ++ sm1_generate_vsir_instr_if(ctx, program, hlsl_ir_if(instr)); ++ break; ++ ++ case HLSL_IR_JUMP: ++ sm1_generate_vsir_instr_jump(ctx, program, hlsl_ir_jump(instr)); ++ break; ++ ++ case HLSL_IR_LOAD: ++ sm1_generate_vsir_instr_load(ctx, program, hlsl_ir_load(instr)); ++ break; ++ ++ case HLSL_IR_RESOURCE_LOAD: ++ sm1_generate_vsir_instr_resource_load(ctx, program, hlsl_ir_resource_load(instr)); ++ break; ++ ++ case HLSL_IR_STORE: ++ sm1_generate_vsir_instr_store(ctx, program, hlsl_ir_store(instr)); ++ break; ++ ++ case HLSL_IR_SWIZZLE: ++ sm1_generate_vsir_instr_swizzle(ctx, program, hlsl_ir_swizzle(instr)); ++ break; ++ ++ default: ++ hlsl_fixme(ctx, &instr->loc, "Instruction type %s.", hlsl_node_type_to_string(instr->type)); ++ break; ++ } ++ } ++} ++ ++/* OBJECTIVE: Translate all the information from ctx and entry_func to the ++ * vsir_program and ctab blob, so they can be used as input to d3dbc_compile() ++ * without relying on ctx and entry_func. */ ++static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, ++ uint64_t config_flags, struct vsir_program *program, struct vkd3d_shader_code *ctab) ++{ ++ struct vkd3d_shader_version version = {0}; ++ struct vkd3d_bytecode_buffer buffer = {0}; ++ struct hlsl_block block; ++ ++ version.major = ctx->profile->major_version; ++ version.minor = ctx->profile->minor_version; ++ version.type = ctx->profile->type; ++ if (!vsir_program_init(program, NULL, &version, 0, VSIR_CF_STRUCTURED)) ++ { ++ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; ++ return; ++ } ++ ++ write_sm1_uniforms(ctx, &buffer); ++ if (buffer.status) ++ { ++ vkd3d_free(buffer.data); ++ ctx->result = buffer.status; ++ return; ++ } ++ ctab->code = buffer.data; ++ ctab->size = buffer.size; ++ ++ sm1_generate_vsir_signature(ctx, program); ++ ++ hlsl_block_init(&block); ++ sm1_generate_vsir_constant_defs(ctx, program, &block); ++ sm1_generate_vsir_sampler_dcls(ctx, program, &block); ++ list_move_head(&entry_func->body.instrs, &block.instrs); ++ ++ sm1_generate_vsir_block(ctx, &entry_func->body, program); ++} ++ ++static struct hlsl_ir_jump *loop_unrolling_find_jump(struct hlsl_block *block, struct hlsl_ir_node *stop_point, ++ struct hlsl_block **found_block) ++{ ++ struct hlsl_ir_node *node; ++ ++ LIST_FOR_EACH_ENTRY(node, &block->instrs, struct hlsl_ir_node, entry) ++ { ++ if (node == stop_point) ++ return NULL; ++ ++ if (node->type == HLSL_IR_IF) ++ { ++ struct hlsl_ir_if *iff = hlsl_ir_if(node); ++ struct hlsl_ir_jump *jump = NULL; ++ ++ if ((jump = loop_unrolling_find_jump(&iff->then_block, stop_point, found_block))) ++ return jump; ++ if ((jump = loop_unrolling_find_jump(&iff->else_block, stop_point, found_block))) ++ return jump; ++ } ++ else if (node->type == HLSL_IR_JUMP) ++ { ++ struct hlsl_ir_jump *jump = hlsl_ir_jump(node); ++ ++ if (jump->type == HLSL_IR_JUMP_BREAK || jump->type == HLSL_IR_JUMP_CONTINUE) ++ { ++ *found_block = block; ++ return jump; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++static unsigned int loop_unrolling_get_max_iterations(struct hlsl_ctx *ctx, struct hlsl_ir_loop *loop) ++{ ++ /* Always use the explicit limit if it has been passed. */ ++ if (loop->unroll_limit) ++ return loop->unroll_limit; ++ ++ /* All SMs will default to 1024 if [unroll] has been specified without an explicit limit. */ ++ if (loop->unroll_type == HLSL_IR_LOOP_FORCE_UNROLL) ++ return 1024; ++ ++ /* SM4 limits implicit unrolling to 254 iterations. */ ++ if (hlsl_version_ge(ctx, 4, 0)) ++ return 254; ++ ++ /* SM<3 implicitly unrolls up to 1024 iterations. */ ++ return 1024; ++} ++ ++static bool loop_unrolling_unroll_loop(struct hlsl_ctx *ctx, struct hlsl_block *block, ++ struct hlsl_block *loop_parent, struct hlsl_ir_loop *loop) ++{ ++ unsigned int max_iterations, i; ++ ++ max_iterations = loop_unrolling_get_max_iterations(ctx, loop); ++ ++ for (i = 0; i < max_iterations; ++i) ++ { ++ struct hlsl_block tmp_dst, *jump_block; ++ struct hlsl_ir_jump *jump = NULL; ++ ++ if (!hlsl_clone_block(ctx, &tmp_dst, &loop->body)) ++ return false; + list_move_before(&loop->node.entry, &tmp_dst.instrs); + hlsl_block_cleanup(&tmp_dst); + +@@ -6406,18 +7603,13 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + append_output_var_copy(ctx, body, entry_func->return_var); + } + +- for (i = 0; i < entry_func->attr_count; ++i) +- { +- const struct hlsl_attribute *attr = entry_func->attrs[i]; +- +- if (!strcmp(attr->name, "numthreads") && profile->type == VKD3D_SHADER_TYPE_COMPUTE) +- parse_numthreads_attribute(ctx, attr); +- else +- hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, +- "Ignoring unknown attribute \"%s\".", entry_func->attrs[i]->name); +- } ++ parse_entry_function_attributes(ctx, entry_func); ++ if (ctx->result) ++ return ctx->result; + +- if (profile->type == VKD3D_SHADER_TYPE_COMPUTE && !ctx->found_numthreads) ++ if (profile->type == VKD3D_SHADER_TYPE_HULL) ++ validate_hull_shader_attributes(ctx, entry_func); ++ else if (profile->type == VKD3D_SHADER_TYPE_COMPUTE && !ctx->found_numthreads) + hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, + "Entry point \"%s\" is missing a [numthreads] attribute.", entry_func->func->name); + +@@ -6540,7 +7732,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry + return ctx->result; + } + +- result = d3dbc_compile(&program, config_flags, NULL, &ctab, out, ctx->message_context, ctx, entry_func); ++ result = d3dbc_compile(&program, config_flags, NULL, &ctab, out, ctx->message_context); + vsir_program_cleanup(&program); + vkd3d_shader_free_shader_code(&ctab); + return result; +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c +index db4913b7c62..716adb15f08 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c +@@ -1452,11 +1452,15 @@ static bool constant_is_one(struct hlsl_ir_constant *const_arg) + + case HLSL_TYPE_UINT: + case HLSL_TYPE_INT: +- case HLSL_TYPE_BOOL: + if (const_arg->value.u[k].u != 1) + return false; + break; + ++ case HLSL_TYPE_BOOL: ++ if (const_arg->value.u[k].u != ~0) ++ return false; ++ break; ++ + default: + return false; + } +@@ -1514,6 +1518,20 @@ bool hlsl_fold_constant_identities(struct hlsl_ctx *ctx, struct hlsl_ir_node *in + res_node = mut_arg; + break; + ++ case HLSL_OP2_LOGIC_AND: ++ if (constant_is_zero(const_arg)) ++ res_node = &const_arg->node; ++ else if (constant_is_one(const_arg)) ++ res_node = mut_arg; ++ break; ++ ++ case HLSL_OP2_LOGIC_OR: ++ if (constant_is_zero(const_arg)) ++ res_node = mut_arg; ++ else if (constant_is_one(const_arg)) ++ res_node = &const_arg->node; ++ break; ++ + default: + break; + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index 747238e2fee..db9992d9715 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -19,6 +19,15 @@ + #include "vkd3d_shader_private.h" + #include "vkd3d_types.h" + ++struct vsir_transformation_context ++{ ++ enum vkd3d_result result; ++ struct vsir_program *program; ++ uint64_t config_flags; ++ const struct vkd3d_shader_compile_info *compile_info; ++ struct vkd3d_shader_message_context *message_context; ++}; ++ + static int convert_parameter_info(const struct vkd3d_shader_compile_info *compile_info, + unsigned int *ret_count, const struct vkd3d_shader_parameter1 **ret_parameters) + { +@@ -65,7 +74,7 @@ static int convert_parameter_info(const struct vkd3d_shader_compile_info *compil + } + + bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, +- const struct vkd3d_shader_version *version, unsigned int reserve) ++ const struct vkd3d_shader_version *version, unsigned int reserve, enum vsir_control_flow_type cf_type) + { + memset(program, 0, sizeof(*program)); + +@@ -87,6 +96,7 @@ bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_c + } + + program->shader_version = *version; ++ program->cf_type = cf_type; + return shader_instruction_array_init(&program->instructions, reserve); + } + +@@ -117,26 +127,137 @@ const struct vkd3d_shader_parameter1 *vsir_program_get_parameter( + return NULL; + } + ++void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type, ++ enum vkd3d_data_type data_type, unsigned int idx_count) ++{ ++ reg->type = reg_type; ++ reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; ++ reg->non_uniform = false; ++ reg->data_type = data_type; ++ reg->idx[0].offset = ~0u; ++ reg->idx[0].rel_addr = NULL; ++ reg->idx[0].is_in_bounds = false; ++ reg->idx[1].offset = ~0u; ++ reg->idx[1].rel_addr = NULL; ++ reg->idx[1].is_in_bounds = false; ++ reg->idx[2].offset = ~0u; ++ reg->idx[2].rel_addr = NULL; ++ reg->idx[2].is_in_bounds = false; ++ reg->idx_count = idx_count; ++ reg->dimension = VSIR_DIMENSION_SCALAR; ++ reg->alignment = 0; ++} ++ + static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg) + { + return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; + } + +-static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction) ++void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, ++ enum vkd3d_data_type data_type, unsigned int idx_count) + { +- enum vkd3d_shader_opcode opcode = instruction->opcode; +- return (VKD3DSIH_DCL <= opcode && opcode <= VKD3DSIH_DCL_VERTICES_OUT) +- || opcode == VKD3DSIH_HS_DECLS; ++ vsir_register_init(¶m->reg, reg_type, data_type, idx_count); ++ param->swizzle = 0; ++ param->modifiers = VKD3DSPSM_NONE; + } + +-static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins) ++static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value) + { +- struct vkd3d_shader_location location = ins->location; ++ vsir_src_param_init(src, VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0); ++ src->reg.u.immconst_u32[0] = value; ++} + +- vsir_instruction_init(ins, &location, VKD3DSIH_NOP); ++void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) ++{ ++ vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UNUSED, 1); ++ param->reg.dimension = VSIR_DIMENSION_NONE; ++ param->reg.idx[0].offset = label_id; ++} ++ ++static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type) ++{ ++ vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1); ++ src->reg.idx[0].offset = idx; ++} ++ ++static void vsir_src_param_init_resource(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx) ++{ ++ vsir_src_param_init(src, VKD3DSPR_RESOURCE, VKD3D_DATA_RESOURCE, 2); ++ src->reg.idx[0].offset = id; ++ src->reg.idx[1].offset = idx; ++ src->reg.dimension = VSIR_DIMENSION_VEC4; ++ src->swizzle = VKD3D_SHADER_NO_SWIZZLE; ++} ++ ++static void vsir_src_param_init_sampler(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx) ++{ ++ vsir_src_param_init(src, VKD3DSPR_SAMPLER, VKD3D_DATA_SAMPLER, 2); ++ src->reg.idx[0].offset = id; ++ src->reg.idx[1].offset = idx; ++ src->reg.dimension = VSIR_DIMENSION_NONE; ++} ++ ++static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx) ++{ ++ vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); ++ src->reg.idx[0].offset = idx; ++} ++ ++static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx) ++{ ++ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); ++ src->reg.idx[0].offset = idx; ++} ++ ++static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsigned int idx) ++{ ++ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src->reg.idx[0].offset = idx; ++} ++ ++static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) ++{ ++ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); ++ src->reg.idx[0].offset = idx; ++} ++ ++void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type, ++ enum vkd3d_data_type data_type, unsigned int idx_count) ++{ ++ vsir_register_init(¶m->reg, reg_type, data_type, idx_count); ++ param->write_mask = VKD3DSP_WRITEMASK_0; ++ param->modifiers = VKD3DSPDM_NONE; ++ param->shift = 0; ++} ++ ++static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) ++{ ++ vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); ++ dst->reg.idx[0].offset = idx; ++} ++ ++static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) ++{ ++ vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); ++ dst->reg.idx[0].offset = idx; ++} ++ ++static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx) ++{ ++ vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); ++ dst->reg.idx[0].offset = idx; ++ dst->write_mask = VKD3DSP_WRITEMASK_0; + } + +-static bool vsir_instruction_init_with_params(struct vsir_program *program, ++void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, ++ enum vkd3d_shader_opcode opcode) ++{ ++ memset(ins, 0, sizeof(*ins)); ++ ins->location = *location; ++ ins->opcode = opcode; ++} ++ ++bool vsir_instruction_init_with_params(struct vsir_program *program, + struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, + enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count) + { +@@ -161,6 +282,37 @@ static bool vsir_instruction_init_with_params(struct vsir_program *program, + return true; + } + ++static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, ++ const struct vkd3d_shader_location *location, unsigned int label_id, struct vsir_program *program) ++{ ++ struct vkd3d_shader_src_param *src_param; ++ ++ if (!(src_param = vsir_program_get_src_params(program, 1))) ++ return false; ++ ++ vsir_src_param_init_label(src_param, label_id); ++ ++ vsir_instruction_init(ins, location, VKD3DSIH_LABEL); ++ ins->src = src_param; ++ ins->src_count = 1; ++ ++ return true; ++} ++ ++static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction) ++{ ++ enum vkd3d_shader_opcode opcode = instruction->opcode; ++ return (VKD3DSIH_DCL <= opcode && opcode <= VKD3DSIH_DCL_VERTICES_OUT) ++ || opcode == VKD3DSIH_HS_DECLS; ++} ++ ++static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins) ++{ ++ struct vkd3d_shader_location location = ins->location; ++ ++ vsir_instruction_init(ins, &location, VKD3DSIH_NOP); ++} ++ + static bool get_opcode_from_rel_op(enum vkd3d_shader_rel_op rel_op, enum vkd3d_data_type data_type, + enum vkd3d_shader_opcode *opcode, bool *requires_swap) + { +@@ -441,10 +593,58 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog + return VKD3D_OK; + } + ++static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, struct vkd3d_shader_instruction *tex) ++{ ++ unsigned int idx = tex->src[1].reg.idx[0].offset; ++ struct vkd3d_shader_src_param *srcs; ++ ++ VKD3D_ASSERT(tex->src[1].reg.idx_count == 1); ++ VKD3D_ASSERT(!tex->src[1].reg.idx[0].rel_addr); ++ ++ if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 3))) ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ ++ srcs[0] = tex->src[0]; ++ vsir_src_param_init_resource(&srcs[1], idx, idx); ++ vsir_src_param_init_sampler(&srcs[2], idx, idx); ++ ++ tex->opcode = VKD3DSIH_SAMPLE; ++ tex->src = srcs; ++ tex->src_count = 3; ++ ++ return VKD3D_OK; ++} ++ ++static enum vkd3d_result vsir_program_lower_texldd(struct vsir_program *program, ++ struct vkd3d_shader_instruction *texldd) ++{ ++ unsigned int idx = texldd->src[1].reg.idx[0].offset; ++ struct vkd3d_shader_src_param *srcs; ++ ++ VKD3D_ASSERT(texldd->src[1].reg.idx_count == 1); ++ VKD3D_ASSERT(!texldd->src[1].reg.idx[0].rel_addr); ++ ++ if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 5))) ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ ++ srcs[0] = texldd->src[0]; ++ vsir_src_param_init_resource(&srcs[1], idx, idx); ++ vsir_src_param_init_sampler(&srcs[2], idx, idx); ++ srcs[3] = texldd->src[2]; ++ srcs[4] = texldd->src[3]; ++ ++ texldd->opcode = VKD3DSIH_SAMPLE_GRAD; ++ texldd->src = srcs; ++ texldd->src_count = 5; ++ ++ return VKD3D_OK; ++} ++ + static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context) ++ struct vsir_transformation_context *ctx) + { + struct vkd3d_shader_instruction_array *instructions = &program->instructions; ++ struct vkd3d_shader_message_context *message_context = ctx->message_context; + unsigned int tmp_idx = ~0u, i; + enum vkd3d_result ret; + +@@ -481,6 +681,38 @@ static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *pr + return ret; + break; + ++ case VKD3DSIH_TEX: ++ if ((ret = vsir_program_lower_tex(program, ins)) < 0) ++ return ret; ++ break; ++ ++ case VKD3DSIH_TEXLDD: ++ if ((ret = vsir_program_lower_texldd(program, ins)) < 0) ++ return ret; ++ break; ++ ++ case VKD3DSIH_TEXBEM: ++ case VKD3DSIH_TEXBEML: ++ case VKD3DSIH_TEXCOORD: ++ case VKD3DSIH_TEXDEPTH: ++ case VKD3DSIH_TEXDP3: ++ case VKD3DSIH_TEXDP3TEX: ++ case VKD3DSIH_TEXLDL: ++ case VKD3DSIH_TEXM3x2PAD: ++ case VKD3DSIH_TEXM3x2TEX: ++ case VKD3DSIH_TEXM3x3DIFF: ++ case VKD3DSIH_TEXM3x3PAD: ++ case VKD3DSIH_TEXM3x3SPEC: ++ case VKD3DSIH_TEXM3x3TEX: ++ case VKD3DSIH_TEXM3x3VSPEC: ++ case VKD3DSIH_TEXREG2AR: ++ case VKD3DSIH_TEXREG2GB: ++ case VKD3DSIH_TEXREG2RGB: ++ vkd3d_shader_error(ctx->message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, ++ "Aborting due to unimplemented feature: Combined sampler instruction %#x.", ++ ins->opcode); ++ return VKD3D_ERROR_NOT_IMPLEMENTED; ++ + default: + break; + } +@@ -541,9 +773,11 @@ static const struct vkd3d_shader_varying_map *find_varying_map( + } + + static enum vkd3d_result vsir_program_remap_output_signature(struct vsir_program *program, +- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) ++ struct vsir_transformation_context *ctx) + { +- const struct vkd3d_shader_location location = {.source_name = compile_info->source_name}; ++ const struct vkd3d_shader_location location = {.source_name = ctx->compile_info->source_name}; ++ struct vkd3d_shader_message_context *message_context = ctx->message_context; ++ const struct vkd3d_shader_compile_info *compile_info = ctx->compile_info; + struct shader_signature *signature = &program->output_signature; + const struct vkd3d_shader_varying_map_info *varying_map; + unsigned int i; +@@ -727,174 +961,50 @@ static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normali + return VKD3D_OK; + } + +-void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type, +- enum vkd3d_data_type data_type, unsigned int idx_count) ++static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program, ++ struct vsir_transformation_context *ctx) + { +- reg->type = reg_type; +- reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; +- reg->non_uniform = false; +- reg->data_type = data_type; +- reg->idx[0].offset = ~0u; +- reg->idx[0].rel_addr = NULL; +- reg->idx[0].is_in_bounds = false; +- reg->idx[1].offset = ~0u; +- reg->idx[1].rel_addr = NULL; +- reg->idx[1].is_in_bounds = false; +- reg->idx[2].offset = ~0u; +- reg->idx[2].rel_addr = NULL; +- reg->idx[2].is_in_bounds = false; +- reg->idx_count = idx_count; +- reg->dimension = VSIR_DIMENSION_SCALAR; +- reg->alignment = 0; ++ struct hull_flattener flattener = {program->instructions}; ++ struct vkd3d_shader_instruction_array *instructions; ++ struct shader_phase_location_array locations; ++ enum vkd3d_result result = VKD3D_OK; ++ unsigned int i; ++ ++ instructions = &flattener.instructions; ++ ++ flattener.phase = VKD3DSIH_INVALID; ++ for (i = 0, locations.count = 0; i < instructions->count; ++i) ++ flattener_eliminate_phase_related_dcls(&flattener, i, &locations); ++ ++ if ((result = flattener_flatten_phases(&flattener, &locations)) < 0) ++ return result; ++ ++ if (flattener.phase != VKD3DSIH_INVALID) ++ { ++ if (!shader_instruction_array_reserve(&flattener.instructions, flattener.instructions.count + 1)) ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ vsir_instruction_init(&instructions->elements[instructions->count++], &flattener.last_ret_location, VKD3DSIH_RET); ++ } ++ ++ program->instructions = flattener.instructions; ++ return result; + } + +-void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, +- enum vkd3d_data_type data_type, unsigned int idx_count) ++struct control_point_normaliser + { +- vsir_register_init(¶m->reg, reg_type, data_type, idx_count); +- param->swizzle = 0; +- param->modifiers = VKD3DSPSM_NONE; ++ struct vkd3d_shader_instruction_array instructions; ++ enum vkd3d_shader_opcode phase; ++ struct vkd3d_shader_src_param *outpointid_param; ++}; ++ ++static bool control_point_normaliser_is_in_control_point_phase(const struct control_point_normaliser *normaliser) ++{ ++ return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; + } + +-void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type, +- enum vkd3d_data_type data_type, unsigned int idx_count) +-{ +- vsir_register_init(¶m->reg, reg_type, data_type, idx_count); +- param->write_mask = VKD3DSP_WRITEMASK_0; +- param->modifiers = VKD3DSPDM_NONE; +- param->shift = 0; +-} +- +-void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) +-{ +- vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UNUSED, 1); +- param->reg.dimension = VSIR_DIMENSION_NONE; +- param->reg.idx[0].offset = label_id; +-} +- +-static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx) +-{ +- vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); +- src->reg.idx[0].offset = idx; +-} +- +-static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx) +-{ +- vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); +- src->reg.idx[0].offset = idx; +-} +- +-static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) +-{ +- vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); +- dst->reg.idx[0].offset = idx; +-} +- +-static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) +-{ +- vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); +- dst->reg.idx[0].offset = idx; +-} +- +-static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx) +-{ +- vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); +- dst->reg.idx[0].offset = idx; +- dst->write_mask = VKD3DSP_WRITEMASK_0; +-} +- +-static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsigned int idx) +-{ +- vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); +- src->reg.idx[0].offset = idx; +-} +- +-static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) +-{ +- vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); +- src->reg.idx[0].offset = idx; +-} +- +-static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value) +-{ +- vsir_src_param_init(src, VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0); +- src->reg.u.immconst_u32[0] = value; +-} +- +-static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type) +-{ +- vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1); +- src->reg.idx[0].offset = idx; +-} +- +-void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, +- enum vkd3d_shader_opcode opcode) +-{ +- memset(ins, 0, sizeof(*ins)); +- ins->location = *location; +- ins->opcode = opcode; +-} +- +-static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, +- const struct vkd3d_shader_location *location, unsigned int label_id, struct vsir_program *program) +-{ +- struct vkd3d_shader_src_param *src_param; +- +- if (!(src_param = vsir_program_get_src_params(program, 1))) +- return false; +- +- vsir_src_param_init_label(src_param, label_id); +- +- vsir_instruction_init(ins, location, VKD3DSIH_LABEL); +- ins->src = src_param; +- ins->src_count = 1; +- +- return true; +-} +- +-static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions) +-{ +- struct hull_flattener flattener = {*src_instructions}; +- struct vkd3d_shader_instruction_array *instructions; +- struct shader_phase_location_array locations; +- enum vkd3d_result result = VKD3D_OK; +- unsigned int i; +- +- instructions = &flattener.instructions; +- +- flattener.phase = VKD3DSIH_INVALID; +- for (i = 0, locations.count = 0; i < instructions->count; ++i) +- flattener_eliminate_phase_related_dcls(&flattener, i, &locations); +- +- if ((result = flattener_flatten_phases(&flattener, &locations)) < 0) +- return result; +- +- if (flattener.phase != VKD3DSIH_INVALID) +- { +- if (!shader_instruction_array_reserve(&flattener.instructions, flattener.instructions.count + 1)) +- return VKD3D_ERROR_OUT_OF_MEMORY; +- vsir_instruction_init(&instructions->elements[instructions->count++], &flattener.last_ret_location, VKD3DSIH_RET); +- } +- +- *src_instructions = flattener.instructions; +- return result; +-} +- +-struct control_point_normaliser +-{ +- struct vkd3d_shader_instruction_array instructions; +- enum vkd3d_shader_opcode phase; +- struct vkd3d_shader_src_param *outpointid_param; +-}; +- +-static bool control_point_normaliser_is_in_control_point_phase(const struct control_point_normaliser *normaliser) +-{ +- return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; +-} +- +-struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( +- struct vkd3d_shader_instruction_array *instructions) ++struct vkd3d_shader_src_param *vsir_program_create_outpointid_param(struct vsir_program *program) + { ++ struct vkd3d_shader_instruction_array *instructions = &program->instructions; + struct vkd3d_shader_src_param *rel_addr; + + if (instructions->outpointid_param) +@@ -991,7 +1101,7 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p + } + + static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( +- struct vkd3d_shader_instruction_array *src_instructions, const struct shader_signature *input_signature) ++ struct vsir_program *program, struct vsir_transformation_context *ctx) + { + struct vkd3d_shader_instruction_array *instructions; + struct control_point_normaliser normaliser; +@@ -1001,12 +1111,12 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i + enum vkd3d_result ret; + unsigned int i, j; + +- if (!(normaliser.outpointid_param = instruction_array_create_outpointid_param(src_instructions))) ++ if (!(normaliser.outpointid_param = vsir_program_create_outpointid_param(program))) + { + ERR("Failed to allocate src param.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } +- normaliser.instructions = *src_instructions; ++ normaliser.instructions = program->instructions; + instructions = &normaliser.instructions; + normaliser.phase = VKD3DSIH_INVALID; + +@@ -1043,22 +1153,22 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i + input_control_point_count = ins->declaration.count; + break; + case VKD3DSIH_HS_CONTROL_POINT_PHASE: +- *src_instructions = normaliser.instructions; ++ program->instructions = normaliser.instructions; + return VKD3D_OK; + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + /* ins may be relocated if the instruction array expands. */ + location = ins->location; +- ret = control_point_normaliser_emit_hs_input(&normaliser, input_signature, ++ ret = control_point_normaliser_emit_hs_input(&normaliser, &program->input_signature, + input_control_point_count, i, &location); +- *src_instructions = normaliser.instructions; ++ program->instructions = normaliser.instructions; + return ret; + default: + break; + } + } + +- *src_instructions = normaliser.instructions; ++ program->instructions = normaliser.instructions; + return VKD3D_OK; + } + +@@ -1098,8 +1208,8 @@ static bool io_normaliser_is_in_control_point_phase(const struct io_normaliser * + return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; + } + +-static unsigned int shader_signature_find_element_for_reg(const struct shader_signature *signature, +- unsigned int reg_idx, unsigned int write_mask) ++static bool shader_signature_find_element_for_reg(const struct shader_signature *signature, ++ unsigned int reg_idx, unsigned int write_mask, unsigned int *element_idx) + { + unsigned int i, base_write_mask; + +@@ -1109,7 +1219,8 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si + if (e->register_index <= reg_idx && e->register_index + e->register_count > reg_idx + && (e->mask & write_mask) == write_mask) + { +- return i; ++ *element_idx = i; ++ return true; + } + } + +@@ -1119,15 +1230,20 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si + reg_idx, write_mask); + base_write_mask = 1u << vsir_write_mask_get_component_idx(write_mask); + if (base_write_mask != write_mask) +- return shader_signature_find_element_for_reg(signature, reg_idx, base_write_mask); ++ return shader_signature_find_element_for_reg(signature, reg_idx, base_write_mask, element_idx); + +- vkd3d_unreachable(); ++ return false; + } + + 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)]; ++ unsigned int element_idx; ++ ++ if (shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) ++ return &signature->elements[element_idx]; ++ ++ return NULL; + } + + static unsigned int range_map_get_register_count(uint8_t range_map[][VKD3D_VEC4_SIZE], +@@ -1181,9 +1297,10 @@ static void io_normaliser_add_index_range(struct io_normaliser *normaliser, + { + const struct vkd3d_shader_index_range *range = &ins->declaration.index_range; + const struct vkd3d_shader_register *reg = &range->dst.reg; +- unsigned int reg_idx, write_mask, element_idx; + const struct shader_signature *signature; + uint8_t (*range_map)[VKD3D_VEC4_SIZE]; ++ struct signature_element *element; ++ unsigned int reg_idx, write_mask; + + switch (reg->type) + { +@@ -1215,9 +1332,8 @@ static void io_normaliser_add_index_range(struct io_normaliser *normaliser, + + reg_idx = reg->idx[reg->idx_count - 1].offset; + write_mask = range->dst.write_mask; +- element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); +- range_map_set_register_range(range_map, reg_idx, range->register_count, +- signature->elements[element_idx].mask, true); ++ element = vsir_signature_find_element_for_reg(signature, reg_idx, write_mask); ++ range_map_set_register_range(range_map, reg_idx, range->register_count, element->mask, true); + } + + static int signature_element_mask_compare(const void *a, const void *b) +@@ -1388,6 +1504,8 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map + else + e->interpolation_mode = f->interpolation_mode; + } ++ ++ vkd3d_free((void *)f->semantic_name); + } + } + element_count = new_count; +@@ -1415,6 +1533,12 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map + TRACE("Merging %s, base reg %u, count %u.\n", e->semantic_name, e->register_index, register_count); + e->register_count = register_count; + e->mask = signature_element_range_expand_mask(e, register_count, range_map); ++ ++ for (j = 1; j < register_count; ++j) ++ { ++ f = &elements[i + j]; ++ vkd3d_free((void *)f->semantic_name); ++ } + } + } + element_count = new_count; +@@ -1530,7 +1654,8 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par + + id_idx = reg->idx_count - 1; + write_mask = dst_param->write_mask; +- element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); ++ if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) ++ vkd3d_unreachable(); + e = &signature->elements[element_idx]; + + dst_param->write_mask >>= vsir_write_mask_get_component_idx(e->mask); +@@ -1653,7 +1778,8 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par + + id_idx = reg->idx_count - 1; + write_mask = VKD3DSP_WRITEMASK_0 << vsir_swizzle_get_component(src_param->swizzle, 0); +- element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); ++ if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) ++ vkd3d_unreachable(); + + e = &signature->elements[element_idx]; + if ((e->register_count > 1 || vsir_sysval_semantic_is_tess_factor(e->sysval_semantic))) +@@ -1751,12 +1877,12 @@ static bool use_flat_interpolation(const struct vsir_program *program, + } + + static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context) ++ struct vsir_transformation_context *ctx) + { ++ struct vkd3d_shader_message_context *message_context = ctx->message_context; + struct io_normaliser normaliser = {program->instructions}; + struct vkd3d_shader_instruction *ins; +- bool has_control_point_phase; +- unsigned int i, j; ++ unsigned int i; + + normaliser.phase = VKD3DSIH_INVALID; + normaliser.shader_type = program->shader_version.type; +@@ -1765,7 +1891,7 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program + normaliser.output_signature = &program->output_signature; + normaliser.patch_constant_signature = &program->patch_constant_signature; + +- for (i = 0, has_control_point_phase = false; i < program->instructions.count; ++i) ++ for (i = 0; i < program->instructions.count; ++i) + { + ins = &program->instructions.elements[i]; + +@@ -1779,8 +1905,6 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program + vkd3d_shader_instruction_make_nop(ins); + break; + case VKD3DSIH_HS_CONTROL_POINT_PHASE: +- has_control_point_phase = true; +- /* fall through */ + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + normaliser.phase = ins->opcode; +@@ -1790,22 +1914,6 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program + } + } + +- if (normaliser.shader_type == VKD3D_SHADER_TYPE_HULL && !has_control_point_phase) +- { +- /* Inputs and outputs must match for the default phase, so merge ranges must match too. */ +- for (i = 0; i < MAX_REG_OUTPUT; ++i) +- { +- for (j = 0; j < VKD3D_VEC4_SIZE; ++j) +- { +- if (!normaliser.input_range_map[i][j] && normaliser.output_range_map[i][j]) +- normaliser.input_range_map[i][j] = normaliser.output_range_map[i][j]; +- else if (normaliser.input_range_map[i][j] && !normaliser.output_range_map[i][j]) +- normaliser.output_range_map[i][j] = normaliser.input_range_map[i][j]; +- else VKD3D_ASSERT(normaliser.input_range_map[i][j] == normaliser.output_range_map[i][j]); +- } +- } +- } +- + if (!shader_signature_merge(&program->input_signature, normaliser.input_range_map, false) + || !shader_signature_merge(&program->output_signature, normaliser.output_range_map, false) + || !shader_signature_merge(&program->patch_constant_signature, normaliser.pc_range_map, true)) +@@ -1918,7 +2026,8 @@ static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_par + param->reg.idx_count = 3; + } + +-static enum vkd3d_result instruction_array_normalise_flat_constants(struct vsir_program *program) ++static enum vkd3d_result vsir_program_normalise_flat_constants(struct vsir_program *program, ++ struct vsir_transformation_context *ctx) + { + struct flat_constants_normaliser normaliser = {0}; + unsigned int i, j; +@@ -1957,7 +2066,8 @@ static enum vkd3d_result instruction_array_normalise_flat_constants(struct vsir_ + return VKD3D_OK; + } + +-static void remove_dead_code(struct vsir_program *program) ++static enum vkd3d_result vsir_program_remove_dead_code(struct vsir_program *program, ++ struct vsir_transformation_context *ctx) + { + size_t i, depth = 0; + bool dead = false; +@@ -2045,103 +2155,6 @@ static void remove_dead_code(struct vsir_program *program) + break; + } + } +-} +- +-static enum vkd3d_result vsir_program_normalise_combined_samplers(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context) +-{ +- unsigned int i; +- +- for (i = 0; i < program->instructions.count; ++i) +- { +- struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; +- struct vkd3d_shader_src_param *srcs; +- +- switch (ins->opcode) +- { +- case VKD3DSIH_TEX: +- if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 3))) +- return VKD3D_ERROR_OUT_OF_MEMORY; +- memset(srcs, 0, sizeof(*srcs) * 3); +- +- ins->opcode = VKD3DSIH_SAMPLE; +- +- srcs[0] = ins->src[0]; +- +- srcs[1].reg.type = VKD3DSPR_RESOURCE; +- srcs[1].reg.idx[0] = ins->src[1].reg.idx[0]; +- srcs[1].reg.idx[1] = ins->src[1].reg.idx[0]; +- srcs[1].reg.idx_count = 2; +- srcs[1].reg.data_type = VKD3D_DATA_RESOURCE; +- srcs[1].reg.dimension = VSIR_DIMENSION_VEC4; +- srcs[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; +- +- srcs[2].reg.type = VKD3DSPR_SAMPLER; +- srcs[2].reg.idx[0] = ins->src[1].reg.idx[0]; +- srcs[2].reg.idx[1] = ins->src[1].reg.idx[0]; +- srcs[2].reg.idx_count = 2; +- srcs[2].reg.data_type = VKD3D_DATA_SAMPLER; +- +- ins->src = srcs; +- ins->src_count = 3; +- break; +- +- case VKD3DSIH_TEXLDD: +- if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 5))) +- return VKD3D_ERROR_OUT_OF_MEMORY; +- memset(srcs, 0, sizeof(*srcs) * 5); +- +- ins->opcode = VKD3DSIH_SAMPLE_GRAD; +- +- srcs[0] = ins->src[0]; +- +- srcs[1].reg.type = VKD3DSPR_RESOURCE; +- srcs[1].reg.idx[0] = ins->src[1].reg.idx[0]; +- srcs[1].reg.idx[1] = ins->src[1].reg.idx[0]; +- srcs[1].reg.idx_count = 2; +- srcs[1].reg.data_type = VKD3D_DATA_RESOURCE; +- srcs[1].reg.dimension = VSIR_DIMENSION_VEC4; +- srcs[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; +- +- srcs[2].reg.type = VKD3DSPR_SAMPLER; +- srcs[2].reg.idx[0] = ins->src[1].reg.idx[0]; +- srcs[2].reg.idx[1] = ins->src[1].reg.idx[0]; +- srcs[2].reg.idx_count = 2; +- srcs[2].reg.data_type = VKD3D_DATA_SAMPLER; +- +- srcs[3] = ins->src[2]; +- srcs[4] = ins->src[3]; +- +- ins->src = srcs; +- ins->src_count = 5; +- break; +- +- case VKD3DSIH_TEXBEM: +- case VKD3DSIH_TEXBEML: +- case VKD3DSIH_TEXCOORD: +- case VKD3DSIH_TEXDEPTH: +- case VKD3DSIH_TEXDP3: +- case VKD3DSIH_TEXDP3TEX: +- case VKD3DSIH_TEXLDL: +- case VKD3DSIH_TEXM3x2PAD: +- case VKD3DSIH_TEXM3x2TEX: +- case VKD3DSIH_TEXM3x3DIFF: +- case VKD3DSIH_TEXM3x3PAD: +- case VKD3DSIH_TEXM3x3SPEC: +- case VKD3DSIH_TEXM3x3TEX: +- case VKD3DSIH_TEXM3x3VSPEC: +- case VKD3DSIH_TEXREG2AR: +- case VKD3DSIH_TEXREG2GB: +- case VKD3DSIH_TEXREG2RGB: +- vkd3d_shader_error(message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, +- "Aborting due to not yet implemented feature: " +- "Combined sampler instruction %#x.", ins->opcode); +- return VKD3D_ERROR_NOT_IMPLEMENTED; +- +- default: +- break; +- } +- } + + return VKD3D_OK; + } +@@ -2789,11 +2802,14 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte + } + + static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context) ++ struct vsir_transformation_context *ctx) + { ++ struct vkd3d_shader_message_context *message_context = ctx->message_context; + struct cf_flattener flattener = {.program = program}; + enum vkd3d_result result; + ++ VKD3D_ASSERT(program->cf_type == VSIR_CF_STRUCTURED); ++ + if ((result = cf_flattener_iterate_instruction_array(&flattener, message_context)) >= 0) + { + vkd3d_free(program->instructions.elements); +@@ -2801,6 +2817,7 @@ static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsi + program->instructions.capacity = flattener.instruction_capacity; + program->instructions.count = flattener.instruction_count; + program->block_count = flattener.block_id; ++ program->cf_type = VSIR_CF_BLOCKS; + } + else + { +@@ -2860,13 +2877,16 @@ static bool lower_switch_to_if_ladder_add_block_mapping(struct lower_switch_to_i + return true; + } + +-static enum vkd3d_result lower_switch_to_if_ladder(struct vsir_program *program) ++static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vsir_program *program, ++ struct vsir_transformation_context *ctx) + { + unsigned int block_count = program->block_count, ssa_count = program->ssa_count, current_label = 0, if_label; + size_t ins_capacity = 0, ins_count = 0, i, map_capacity = 0, map_count = 0; + struct vkd3d_shader_instruction *instructions = NULL; + struct lower_switch_to_if_ladder_block_mapping *block_map = NULL; + ++ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); ++ + if (!reserve_instructions(&instructions, &ins_capacity, program->instructions.count)) + goto fail; + +@@ -3050,7 +3070,8 @@ static void ssas_to_temps_block_info_cleanup(struct ssas_to_temps_block_info *bl + vkd3d_free(block_info); + } + +-static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps(struct vsir_program *program) ++static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps(struct vsir_program *program, ++ struct vsir_transformation_context *ctx) + { + size_t ins_capacity = 0, ins_count = 0, phi_count, incoming_count, i; + struct ssas_to_temps_block_info *info, *block_info = NULL; +@@ -3058,6 +3079,8 @@ static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps(struct vsir_ + struct ssas_to_temps_alloc alloc = {0}; + unsigned int current_label = 0; + ++ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); ++ + if (!(block_info = vkd3d_calloc(program->block_count, sizeof(*block_info)))) + { + ERR("Failed to allocate block info array.\n"); +@@ -5271,12 +5294,15 @@ out: + } + + static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context) ++ struct vsir_transformation_context *ctx) + { ++ struct vkd3d_shader_message_context *message_context = ctx->message_context; + struct vsir_cfg_emit_target target = {0}; + enum vkd3d_result ret; + size_t i; + ++ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); ++ + target.jump_target_temp_idx = program->temp_count; + target.temp_count = program->temp_count + 1; + +@@ -5324,6 +5350,7 @@ static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, + program->instructions.capacity = target.ins_capacity; + program->instructions.count = target.ins_count; + program->temp_count = target.temp_count; ++ program->cf_type = VSIR_CF_STRUCTURED; + + return VKD3D_OK; + +@@ -5451,11 +5478,14 @@ static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps_in_f + } + + static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context) ++ struct vsir_transformation_context *ctx) + { ++ struct vkd3d_shader_message_context *message_context = ctx->message_context; + enum vkd3d_result ret; + size_t i; + ++ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); ++ + for (i = 0; i < program->instructions.count;) + { + struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; +@@ -5596,8 +5626,9 @@ static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *progr + } + + static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *program, +- struct vkd3d_shader_message_context *message_context) ++ struct vsir_transformation_context *ctx) + { ++ struct vkd3d_shader_message_context *message_context = ctx->message_context; + const struct vkd3d_shader_parameter1 *func = NULL, *ref = NULL; + static const struct vkd3d_shader_location no_loc; + enum vkd3d_shader_comparison_func compare_func; +@@ -5687,12 +5718,6 @@ struct validation_context + enum vkd3d_result status; + bool dcl_temps_found; + enum vkd3d_shader_opcode phase; +- enum cf_type +- { +- CF_TYPE_UNKNOWN = 0, +- CF_TYPE_STRUCTURED, +- CF_TYPE_BLOCKS, +- } cf_type; + bool inside_block; + + struct validation_context_temp_data +@@ -5731,14 +5756,14 @@ static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *c + if (ctx->invalid_instruction_idx) + { + vkd3d_shader_error(ctx->message_context, &ctx->null_location, error, "%s", buf.buffer); +- ERR("VSIR validation error: %s\n", buf.buffer); ++ WARN("VSIR validation error: %s\n", buf.buffer); + } + else + { + const struct vkd3d_shader_instruction *ins = &ctx->program->instructions.elements[ctx->instruction_idx]; + vkd3d_shader_error(ctx->message_context, &ins->location, error, + "instruction %zu: %s", ctx->instruction_idx + 1, buf.buffer); +- ERR("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer); ++ WARN("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer); + } + + vkd3d_string_buffer_cleanup(&buf); +@@ -6105,13 +6130,13 @@ static bool vsir_validate_src_max_count(struct validation_context *ctx, + return true; + } + +-static const char *name_from_cf_type(enum cf_type type) ++static const char *name_from_cf_type(enum vsir_control_flow_type type) + { + switch (type) + { +- case CF_TYPE_STRUCTURED: ++ case VSIR_CF_STRUCTURED: + return "structured"; +- case CF_TYPE_BLOCKS: ++ case VSIR_CF_BLOCKS: + return "block-based"; + default: + vkd3d_unreachable(); +@@ -6119,437 +6144,510 @@ static const char *name_from_cf_type(enum cf_type type) + } + + static void vsir_validate_cf_type(struct validation_context *ctx, +- const struct vkd3d_shader_instruction *instruction, enum cf_type expected_type) ++ const struct vkd3d_shader_instruction *instruction, enum vsir_control_flow_type expected_type) + { +- VKD3D_ASSERT(ctx->cf_type != CF_TYPE_UNKNOWN); +- VKD3D_ASSERT(expected_type != CF_TYPE_UNKNOWN); +- if (ctx->cf_type != expected_type) ++ if (ctx->program->cf_type != expected_type) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x in %s shader.", +- instruction->opcode, name_from_cf_type(ctx->cf_type)); ++ instruction->opcode, name_from_cf_type(ctx->program->cf_type)); + } + +-static void vsir_validate_instruction(struct validation_context *ctx) ++static void vsir_validator_push_block(struct validation_context *ctx, enum vkd3d_shader_opcode opcode) + { +- const struct vkd3d_shader_version *version = &ctx->program->shader_version; +- const struct vkd3d_shader_instruction *instruction; +- size_t i; +- +- instruction = &ctx->program->instructions.elements[ctx->instruction_idx]; +- +- for (i = 0; i < instruction->dst_count; ++i) +- vsir_validate_dst_param(ctx, &instruction->dst[i]); +- +- for (i = 0; i < instruction->src_count; ++i) +- vsir_validate_src_param(ctx, &instruction->src[i]); +- +- if (instruction->opcode >= VKD3DSIH_INVALID) ++ if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) + { +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, "Invalid instruction handler %#x.", +- instruction->opcode); ++ ctx->status = VKD3D_ERROR_OUT_OF_MEMORY; ++ return; + } ++ ctx->blocks[ctx->depth++] = opcode; ++} + +- switch (instruction->opcode) +- { +- case VKD3DSIH_HS_DECLS: +- case VKD3DSIH_HS_CONTROL_POINT_PHASE: +- case VKD3DSIH_HS_FORK_PHASE: +- case VKD3DSIH_HS_JOIN_PHASE: +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- if (version->type != VKD3D_SHADER_TYPE_HULL) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, +- "Phase instruction %#x is only valid in a hull shader.", +- instruction->opcode); +- if (ctx->depth != 0) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, +- "Phase instruction %#x must appear to top level.", +- instruction->opcode); +- ctx->phase = instruction->opcode; +- ctx->dcl_temps_found = false; +- return; ++static void vsir_validate_hull_shader_phase(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (ctx->program->shader_version.type != VKD3D_SHADER_TYPE_HULL) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, ++ "Phase instruction %#x is only valid in a hull shader.", ++ instruction->opcode); ++ if (ctx->depth != 0) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "Phase instruction %#x must appear to top level.", ++ instruction->opcode); ++ ctx->phase = instruction->opcode; ++ ctx->dcl_temps_found = false; ++} + +- case VKD3DSIH_DCL_HS_MAX_TESSFACTOR: +- /* Exclude non-finite values. */ +- if (!(instruction->declaration.max_tessellation_factor >= 1.0f +- && instruction->declaration.max_tessellation_factor <= 64.0f)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Max tessellation factor %f is invalid.", +- instruction->declaration.max_tessellation_factor); +- return; ++static void vsir_validate_branch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ size_t i; + +- case VKD3DSIH_DCL_INPUT_PRIMITIVE: +- if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED +- || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS input primitive %u is invalid.", +- instruction->declaration.primitive_type.type); +- return; ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); ++ vsir_validate_dst_count(ctx, instruction, 0); + +- case VKD3DSIH_DCL_VERTICES_OUT: +- if (instruction->declaration.count > 1024) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output vertex count %u is invalid.", +- instruction->declaration.count); +- return; ++ if (!vsir_validate_src_min_count(ctx, instruction, 1)) ++ return; + +- case VKD3DSIH_DCL_OUTPUT_TOPOLOGY: +- if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED +- || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output primitive %u is invalid.", +- instruction->declaration.primitive_type.type); +- return; ++ if (vsir_register_is_label(&instruction->src[0].reg)) ++ { ++ /* Unconditional branch: parameters are jump label, ++ * optional merge label, optional continue label. */ ++ vsir_validate_src_max_count(ctx, instruction, 3); + +- case VKD3DSIH_DCL_GS_INSTANCES: +- if (!instruction->declaration.count || instruction->declaration.count > 32) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS instance count %u is invalid.", +- instruction->declaration.count); +- return; ++ for (i = 0; i < instruction->src_count; ++i) ++ { ++ if (!vsir_register_is_label(&instruction->src[i].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid register of type %#x in unconditional BRANCH instruction, expected LABEL.", ++ instruction->src[i].reg.type); ++ } ++ } ++ else ++ { ++ /* Conditional branch: parameters are condition, true ++ * jump label, false jump label, optional merge label, ++ * optional continue label. */ ++ vsir_validate_src_min_count(ctx, instruction, 3); ++ vsir_validate_src_max_count(ctx, instruction, 5); + +- case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT: +- if (!instruction->declaration.count || instruction->declaration.count > 32) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Output control point count %u is invalid.", +- instruction->declaration.count); +- return; ++ for (i = 1; i < instruction->src_count; ++i) ++ { ++ if (!vsir_register_is_label(&instruction->src[i].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid register of type %#x in conditional BRANCH instruction, expected LABEL.", ++ instruction->src[i].reg.type); ++ } ++ } + +- case VKD3DSIH_DCL_TESSELLATOR_DOMAIN: +- if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID +- || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, +- "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain); +- return; ++ ctx->inside_block = false; ++} + +- case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: +- if (!instruction->declaration.tessellator_output_primitive +- || instruction->declaration.tessellator_output_primitive > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, +- "Tessellator output primitive %#x is invalid.", instruction->declaration.tessellator_output_primitive); +- return; ++static void vsir_validate_dcl_gs_instances(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (!instruction->declaration.count || instruction->declaration.count > 32) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS instance count %u is invalid.", ++ instruction->declaration.count); ++} + +- case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING: +- if (!instruction->declaration.tessellator_partitioning +- || instruction->declaration.tessellator_partitioning > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, +- "Tessellator partitioning %#x is invalid.", instruction->declaration.tessellator_partitioning); +- return; ++static void vsir_validate_dcl_hs_max_tessfactor(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ /* Exclude non-finite values. */ ++ if (!(instruction->declaration.max_tessellation_factor >= 1.0f ++ && instruction->declaration.max_tessellation_factor <= 64.0f)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, ++ "Max tessellation factor %f is invalid.", ++ instruction->declaration.max_tessellation_factor); ++} + +- default: +- break; +- } ++static void vsir_validate_dcl_input_primitive(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED ++ || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS input primitive %u is invalid.", ++ instruction->declaration.primitive_type.type); ++} + +- /* Only DCL instructions may occur outside hull shader phases. */ +- if (!vsir_instruction_is_dcl(instruction) && version->type == VKD3D_SHADER_TYPE_HULL +- && ctx->phase == VKD3DSIH_INVALID) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, +- "Instruction %#x appear before any phase instruction in a hull shader.", +- instruction->opcode); ++static void vsir_validate_dcl_output_control_point_count(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (!instruction->declaration.count || instruction->declaration.count > 32) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, ++ "Output control point count %u is invalid.", ++ instruction->declaration.count); ++} + +- /* We support two different control flow types in shaders: +- * block-based, like DXIL and SPIR-V, and structured, like D3DBC +- * and TPF. The shader is detected as block-based when its first +- * instruction, except for DCL_* and phases, is a LABEL. Currently +- * we mandate that each shader is either purely block-based or +- * purely structured. In principle we could allow structured +- * constructs in a block, provided they are confined in a single +- * block, but need for that hasn't arisen yet, so we don't. */ +- if (ctx->cf_type == CF_TYPE_UNKNOWN && !vsir_instruction_is_dcl(instruction)) +- { +- if (instruction->opcode == VKD3DSIH_LABEL) +- ctx->cf_type = CF_TYPE_BLOCKS; +- else +- ctx->cf_type = CF_TYPE_STRUCTURED; +- } ++static void vsir_validate_dcl_output_topology(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED ++ || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output primitive %u is invalid.", ++ instruction->declaration.primitive_type.type); ++} ++ ++static void vsir_validate_dcl_temps(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (ctx->dcl_temps_found) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS, ++ "Duplicate DCL_TEMPS instruction."); ++ if (instruction->declaration.count > ctx->program->temp_count) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, ++ "Invalid DCL_TEMPS count %u, expected at most %u.", ++ instruction->declaration.count, ctx->program->temp_count); ++ ctx->dcl_temps_found = true; ++} ++ ++static void vsir_validate_dcl_tessellator_domain(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID ++ || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, ++ "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain); ++} ++ ++static void vsir_validate_dcl_tessellator_output_primitive(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (!instruction->declaration.tessellator_output_primitive ++ || instruction->declaration.tessellator_output_primitive ++ > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, ++ "Tessellator output primitive %#x is invalid.", ++ instruction->declaration.tessellator_output_primitive); ++} ++ ++static void vsir_validate_dcl_tessellator_partitioning(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (!instruction->declaration.tessellator_partitioning ++ || instruction->declaration.tessellator_partitioning ++ > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, ++ "Tessellator partitioning %#x is invalid.", ++ instruction->declaration.tessellator_partitioning); ++} + +- if (ctx->cf_type == CF_TYPE_BLOCKS && !vsir_instruction_is_dcl(instruction)) ++static void vsir_validate_dcl_vertices_out(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ if (instruction->declaration.count > 1024) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output vertex count %u is invalid.", ++ instruction->declaration.count); ++} ++ ++static void vsir_validate_else(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "ELSE instruction doesn't terminate IF block."); ++ else ++ ctx->blocks[ctx->depth - 1] = VKD3DSIH_ELSE; ++} ++ ++static void vsir_validate_endif(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ if (ctx->depth == 0 || (ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF ++ && ctx->blocks[ctx->depth - 1] != VKD3DSIH_ELSE)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "ENDIF instruction doesn't terminate IF/ELSE block."); ++ else ++ --ctx->depth; ++} ++ ++static void vsir_validate_endloop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_LOOP) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "ENDLOOP instruction doesn't terminate LOOP block."); ++ else ++ --ctx->depth; ++} ++ ++static void vsir_validate_endrep(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_REP) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "ENDREP instruction doesn't terminate REP block."); ++ else ++ --ctx->depth; ++} ++ ++static void vsir_validate_endswitch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_SWITCH) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "ENDSWITCH instruction doesn't terminate SWITCH block."); ++ else ++ --ctx->depth; ++} ++ ++static void vsir_validate_if(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ vsir_validator_push_block(ctx, VKD3DSIH_IF); ++} ++ ++static void vsir_validate_ifc(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ vsir_validator_push_block(ctx, VKD3DSIH_IF); ++} ++ ++static void vsir_validate_label(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); ++ if (instruction->src_count >= 1 && !vsir_register_is_label(&instruction->src[0].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid register of type %#x in a LABEL instruction, expected LABEL.", ++ instruction->src[0].reg.type); ++ ++ if (ctx->inside_block) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "Invalid LABEL instruction inside a block."); ++ ctx->inside_block = true; ++} ++ ++static void vsir_validate_loop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ vsir_validate_src_count(ctx, instruction, ctx->program->shader_version.major <= 3 ? 2 : 0); ++ vsir_validator_push_block(ctx, VKD3DSIH_LOOP); ++} ++ ++static void vsir_validate_nop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++} ++ ++static void vsir_validate_phi(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ unsigned int i, incoming_count; ++ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); ++ ++ vsir_validate_src_min_count(ctx, instruction, 2); ++ ++ if (instruction->src_count % 2 != 0) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, ++ "Invalid source count %u for a PHI instruction, it must be an even number.", ++ instruction->src_count); ++ incoming_count = instruction->src_count / 2; ++ ++ for (i = 0; i < incoming_count; ++i) + { +- switch (instruction->opcode) +- { +- case VKD3DSIH_LABEL: +- if (ctx->inside_block) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid LABEL instruction inside a block."); +- ctx->inside_block = true; +- break; ++ unsigned int value_idx = 2 * i; ++ unsigned int label_idx = 2 * i + 1; + +- case VKD3DSIH_RET: +- case VKD3DSIH_BRANCH: +- case VKD3DSIH_SWITCH_MONOLITHIC: +- if (!ctx->inside_block) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, +- "Invalid instruction %#x outside any block.", +- instruction->opcode); +- ctx->inside_block = false; +- break; ++ if (!register_is_constant_or_undef(&instruction->src[value_idx].reg) ++ && !register_is_ssa(&instruction->src[value_idx].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid value register for incoming %u of type %#x in PHI instruction, " ++ "expected SSA, IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); + +- default: +- if (!ctx->inside_block) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, +- "Invalid instruction %#x outside any block.", +- instruction->opcode); +- break; +- } ++ if (instruction->src[value_idx].reg.dimension != VSIR_DIMENSION_SCALAR) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, ++ "Invalid value dimension %#x for incoming %u in PHI instruction, expected scalar.", ++ instruction->src[value_idx].reg.dimension, i); ++ ++ if (!vsir_register_is_label(&instruction->src[label_idx].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid label register for case %u of type %#x in PHI instruction, " ++ "expected LABEL.", i, instruction->src[value_idx].reg.type); + } + +- switch (instruction->opcode) +- { +- case VKD3DSIH_DCL_TEMPS: +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- if (ctx->dcl_temps_found) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS, "Duplicate DCL_TEMPS instruction."); +- if (instruction->declaration.count > ctx->program->temp_count) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, +- "Invalid DCL_TEMPS count %u, expected at most %u.", +- instruction->declaration.count, ctx->program->temp_count); +- ctx->dcl_temps_found = true; +- break; ++ if (instruction->dst_count < 1) ++ return; + +- case VKD3DSIH_IF: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 1); +- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) +- return; +- ctx->blocks[ctx->depth++] = instruction->opcode; +- break; ++ if (!register_is_ssa(&instruction->dst[0].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid destination of type %#x in PHI instruction, expected SSA.", ++ instruction->dst[0].reg.type); + +- case VKD3DSIH_IFC: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 2); +- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) +- return; +- ctx->blocks[ctx->depth++] = VKD3DSIH_IF; +- break; ++ if (instruction->dst[0].reg.dimension != VSIR_DIMENSION_SCALAR) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, ++ "Invalid destination dimension %#x in PHI instruction, expected scalar.", ++ instruction->dst[0].reg.dimension); + +- case VKD3DSIH_ELSE: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ELSE instruction doesn't terminate IF block."); +- else +- ctx->blocks[ctx->depth - 1] = instruction->opcode; +- break; ++ if (instruction->dst[0].modifiers != VKD3DSPDM_NONE) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, ++ "Invalid modifiers %#x for the destination of a PHI instruction, expected none.", ++ instruction->dst[0].modifiers); + +- case VKD3DSIH_ENDIF: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- if (ctx->depth == 0 || (ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF && ctx->blocks[ctx->depth - 1] != VKD3DSIH_ELSE)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDIF instruction doesn't terminate IF/ELSE block."); +- else +- --ctx->depth; +- break; ++ if (instruction->dst[0].shift != 0) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT, ++ "Invalid shift %#x for the destination of a PHI instruction, expected none.", ++ instruction->dst[0].shift); ++} + +- case VKD3DSIH_LOOP: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, version->major <= 3 ? 2 : 0); +- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) +- return; +- ctx->blocks[ctx->depth++] = instruction->opcode; +- break; ++static void vsir_validate_rep(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ vsir_validator_push_block(ctx, VKD3DSIH_REP); ++} + +- case VKD3DSIH_ENDLOOP: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_LOOP) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDLOOP instruction doesn't terminate LOOP block."); +- else +- --ctx->depth; +- break; ++static void vsir_validate_ret(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ ctx->inside_block = false; ++} + +- case VKD3DSIH_REP: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 1); +- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) +- return; +- ctx->blocks[ctx->depth++] = instruction->opcode; +- break; ++static void vsir_validate_switch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) ++{ ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); ++ vsir_validator_push_block(ctx, VKD3DSIH_SWITCH); ++} + +- case VKD3DSIH_ENDREP: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_REP) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDREP instruction doesn't terminate REP block."); +- else +- --ctx->depth; +- break; ++static void vsir_validate_switch_monolithic(struct validation_context *ctx, ++ const struct vkd3d_shader_instruction *instruction) ++{ ++ unsigned int i, case_count; + +- case VKD3DSIH_SWITCH: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 1); +- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) +- return; +- ctx->blocks[ctx->depth++] = instruction->opcode; +- break; ++ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); + +- case VKD3DSIH_ENDSWITCH: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_SWITCH) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDSWITCH instruction doesn't terminate SWITCH block."); +- else +- --ctx->depth; +- break; ++ /* Parameters are source, default label, merge label and ++ * then pairs of constant value and case label. */ + +- case VKD3DSIH_RET: +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 0); +- break; ++ if (!vsir_validate_src_min_count(ctx, instruction, 3)) ++ return; + +- case VKD3DSIH_LABEL: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); +- vsir_validate_dst_count(ctx, instruction, 0); +- vsir_validate_src_count(ctx, instruction, 1); +- if (instruction->src_count >= 1 && !vsir_register_is_label(&instruction->src[0].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid register of type %#x in a LABEL instruction, expected LABEL.", +- instruction->src[0].reg.type); +- break; ++ if (instruction->src_count % 2 != 1) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, ++ "Invalid source count %u for a monolithic SWITCH instruction, it must be an odd number.", ++ instruction->src_count); + +- case VKD3DSIH_BRANCH: +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); +- vsir_validate_dst_count(ctx, instruction, 0); +- if (!vsir_validate_src_min_count(ctx, instruction, 1)) +- break; +- if (vsir_register_is_label(&instruction->src[0].reg)) +- { +- /* Unconditional branch: parameters are jump label, +- * optional merge label, optional continue label. */ +- vsir_validate_src_max_count(ctx, instruction, 3); ++ if (!vsir_register_is_label(&instruction->src[1].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid default label register of type %#x in monolithic SWITCH instruction, expected LABEL.", ++ instruction->src[1].reg.type); + +- for (i = 0; i < instruction->src_count; ++i) +- { +- if (!vsir_register_is_label(&instruction->src[i].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid register of type %#x in unconditional BRANCH instruction, expected LABEL.", +- instruction->src[i].reg.type); +- } +- } +- else +- { +- /* Conditional branch: parameters are condition, true +- * jump label, false jump label, optional merge label, +- * optional continue label. */ +- vsir_validate_src_min_count(ctx, instruction, 3); +- vsir_validate_src_max_count(ctx, instruction, 5); ++ if (!vsir_register_is_label(&instruction->src[2].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid merge label register of type %#x in monolithic SWITCH instruction, expected LABEL.", ++ instruction->src[2].reg.type); + +- for (i = 1; i < instruction->src_count; ++i) +- { +- if (!vsir_register_is_label(&instruction->src[i].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid register of type %#x in conditional BRANCH instruction, expected LABEL.", +- instruction->src[i].reg.type); +- } +- } +- break; ++ case_count = (instruction->src_count - 3) / 2; + +- case VKD3DSIH_SWITCH_MONOLITHIC: +- { +- unsigned int case_count; ++ for (i = 0; i < case_count; ++i) ++ { ++ unsigned int value_idx = 3 + 2 * i; ++ unsigned int label_idx = 3 + 2 * i + 1; + +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); +- vsir_validate_dst_count(ctx, instruction, 0); +- /* Parameters are source, default label, merge label and +- * then pairs of constant value and case label. */ +- if (!vsir_validate_src_min_count(ctx, instruction, 3)) +- break; +- if (instruction->src_count % 2 != 1) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, +- "Invalid source count %u for a monolithic SWITCH instruction, it must be an odd number.", +- instruction->src_count); ++ if (!register_is_constant(&instruction->src[value_idx].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid value register for case %u of type %#x in monolithic SWITCH instruction, " ++ "expected IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); + +- if (!vsir_register_is_label(&instruction->src[1].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid default label register of type %#x in monolithic SWITCH instruction, expected LABEL.", +- instruction->src[1].reg.type); ++ if (!vsir_register_is_label(&instruction->src[label_idx].reg)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid label register for case %u of type %#x in monolithic SWITCH instruction, " ++ "expected LABEL.", i, instruction->src[value_idx].reg.type); ++ } + +- if (!vsir_register_is_label(&instruction->src[2].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid merge label register of type %#x in monolithic SWITCH instruction, expected LABEL.", +- instruction->src[2].reg.type); ++ ctx->inside_block = false; ++} + +- case_count = (instruction->src_count - 3) / 2; ++struct vsir_validator_instruction_desc ++{ ++ unsigned int dst_param_count; ++ unsigned int src_param_count; ++ void (*validate)(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction); ++}; + +- for (i = 0; i < case_count; ++i) +- { +- unsigned int value_idx = 3 + 2 * i; +- unsigned int label_idx = 3 + 2 * i + 1; +- +- if (!register_is_constant(&instruction->src[value_idx].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid value register for case %zu of type %#x in monolithic SWITCH instruction, " +- "expected IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); +- +- if (!vsir_register_is_label(&instruction->src[label_idx].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid label register for case %zu of type %#x in monolithic SWITCH instruction, " +- "expected LABEL.", i, instruction->src[value_idx].reg.type); +- } +- break; ++static const struct vsir_validator_instruction_desc vsir_validator_instructions[] = ++{ ++ [VKD3DSIH_BRANCH] = {0, ~0u, vsir_validate_branch}, ++ [VKD3DSIH_HS_CONTROL_POINT_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, ++ [VKD3DSIH_HS_DECLS] = {0, 0, vsir_validate_hull_shader_phase}, ++ [VKD3DSIH_HS_FORK_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, ++ [VKD3DSIH_HS_JOIN_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, ++ [VKD3DSIH_DCL_GS_INSTANCES] = {0, 0, vsir_validate_dcl_gs_instances}, ++ [VKD3DSIH_DCL_HS_MAX_TESSFACTOR] = {0, 0, vsir_validate_dcl_hs_max_tessfactor}, ++ [VKD3DSIH_DCL_INPUT_PRIMITIVE] = {0, 0, vsir_validate_dcl_input_primitive}, ++ [VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT] = {0, 0, vsir_validate_dcl_output_control_point_count}, ++ [VKD3DSIH_DCL_OUTPUT_TOPOLOGY] = {0, 0, vsir_validate_dcl_output_topology}, ++ [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, ++ [VKD3DSIH_DCL_TESSELLATOR_DOMAIN] = {0, 0, vsir_validate_dcl_tessellator_domain}, ++ [VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE] = {0, 0, vsir_validate_dcl_tessellator_output_primitive}, ++ [VKD3DSIH_DCL_TESSELLATOR_PARTITIONING] = {0, 0, vsir_validate_dcl_tessellator_partitioning}, ++ [VKD3DSIH_DCL_VERTICES_OUT] = {0, 0, vsir_validate_dcl_vertices_out}, ++ [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, ++ [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, ++ [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, ++ [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, ++ [VKD3DSIH_ENDSWITCH] = {0, 0, vsir_validate_endswitch}, ++ [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, ++ [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, ++ [VKD3DSIH_LABEL] = {0, 1, vsir_validate_label}, ++ [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, ++ [VKD3DSIH_NOP] = {0, 0, vsir_validate_nop}, ++ [VKD3DSIH_PHI] = {1, ~0u, vsir_validate_phi}, ++ [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, ++ [VKD3DSIH_RET] = {0, 0, vsir_validate_ret}, ++ [VKD3DSIH_SWITCH] = {0, 1, vsir_validate_switch}, ++ [VKD3DSIH_SWITCH_MONOLITHIC] = {0, ~0u, vsir_validate_switch_monolithic}, ++}; ++ ++static void vsir_validate_instruction(struct validation_context *ctx) ++{ ++ const struct vkd3d_shader_version *version = &ctx->program->shader_version; ++ const struct vkd3d_shader_instruction *instruction; ++ size_t i; ++ ++ instruction = &ctx->program->instructions.elements[ctx->instruction_idx]; ++ ++ for (i = 0; i < instruction->dst_count; ++i) ++ vsir_validate_dst_param(ctx, &instruction->dst[i]); ++ ++ for (i = 0; i < instruction->src_count; ++i) ++ vsir_validate_src_param(ctx, &instruction->src[i]); ++ ++ if (instruction->opcode >= VKD3DSIH_INVALID) ++ { ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, "Invalid instruction handler %#x.", ++ instruction->opcode); ++ } ++ ++ if (version->type == VKD3D_SHADER_TYPE_HULL && ctx->phase == VKD3DSIH_INVALID) ++ { ++ switch (instruction->opcode) ++ { ++ case VKD3DSIH_NOP: ++ case VKD3DSIH_HS_DECLS: ++ case VKD3DSIH_HS_CONTROL_POINT_PHASE: ++ case VKD3DSIH_HS_FORK_PHASE: ++ case VKD3DSIH_HS_JOIN_PHASE: ++ break; ++ ++ default: ++ if (!vsir_instruction_is_dcl(instruction)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, ++ "Instruction %#x appear before any phase instruction in a hull shader.", ++ instruction->opcode); ++ break; + } ++ } + +- case VKD3DSIH_PHI: ++ if (ctx->program->cf_type == VSIR_CF_BLOCKS && !ctx->inside_block) ++ { ++ switch (instruction->opcode) + { +- unsigned int incoming_count; +- +- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); +- vsir_validate_dst_count(ctx, instruction, 1); +- vsir_validate_src_min_count(ctx, instruction, 2); +- if (instruction->src_count % 2 != 0) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, +- "Invalid source count %u for a PHI instruction, it must be an even number.", +- instruction->src_count); +- incoming_count = instruction->src_count / 2; +- +- if (!register_is_ssa(&instruction->dst[0].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid destination of type %#x in PHI instruction, expected SSA.", +- instruction->dst[0].reg.type); ++ case VKD3DSIH_NOP: ++ case VKD3DSIH_LABEL: ++ case VKD3DSIH_HS_DECLS: ++ case VKD3DSIH_HS_CONTROL_POINT_PHASE: ++ case VKD3DSIH_HS_FORK_PHASE: ++ case VKD3DSIH_HS_JOIN_PHASE: ++ break; + +- if (instruction->dst[0].reg.dimension != VSIR_DIMENSION_SCALAR) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, +- "Invalid destination dimension %#x in PHI instruction, expected scalar.", +- instruction->dst[0].reg.dimension); ++ default: ++ if (!vsir_instruction_is_dcl(instruction)) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, ++ "Invalid instruction %#x outside any block.", ++ instruction->opcode); ++ break; ++ } ++ } + +- if (instruction->dst[0].modifiers != VKD3DSPDM_NONE) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, +- "Invalid modifiers %#x for the destination of a PHI instruction, expected none.", +- instruction->dst[0].modifiers); ++ if (instruction->opcode < ARRAY_SIZE(vsir_validator_instructions)) ++ { ++ const struct vsir_validator_instruction_desc *desc; + +- if (instruction->dst[0].shift != 0) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT, +- "Invalid shift %#x for the destination of a PHI instruction, expected none.", +- instruction->dst[0].shift); ++ desc = &vsir_validator_instructions[instruction->opcode]; + +- for (i = 0; i < incoming_count; ++i) +- { +- unsigned int value_idx = 2 * i; +- unsigned int label_idx = 2 * i + 1; +- +- if (!register_is_constant_or_undef(&instruction->src[value_idx].reg) +- && !register_is_ssa(&instruction->src[value_idx].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid value register for incoming %zu of type %#x in PHI instruction, " +- "expected SSA, IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); +- +- if (instruction->src[value_idx].reg.dimension != VSIR_DIMENSION_SCALAR) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, +- "Invalid value dimension %#x for incoming %zu in PHI instruction, expected scalar.", +- instruction->src[value_idx].reg.dimension, i); +- +- if (!vsir_register_is_label(&instruction->src[label_idx].reg)) +- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, +- "Invalid label register for case %zu of type %#x in PHI instruction, " +- "expected LABEL.", i, instruction->src[value_idx].reg.type); +- } +- break; ++ if (desc->validate) ++ { ++ if (desc->dst_param_count != ~0u) ++ vsir_validate_dst_count(ctx, instruction, desc->dst_param_count); ++ if (desc->src_param_count != ~0u) ++ vsir_validate_src_count(ctx, instruction, desc->src_param_count); ++ desc->validate(ctx, instruction); + } +- +- default: +- break; + } + } + +@@ -6575,7 +6673,8 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c + if (!(ctx.ssas = vkd3d_calloc(ctx.program->ssa_count, sizeof(*ctx.ssas)))) + goto fail; + +- for (ctx.instruction_idx = 0; ctx.instruction_idx < program->instructions.count; ++ctx.instruction_idx) ++ for (ctx.instruction_idx = 0; ctx.instruction_idx < program->instructions.count ++ && ctx.status != VKD3D_ERROR_OUT_OF_MEMORY; ++ctx.instruction_idx) + vsir_validate_instruction(&ctx); + + ctx.invalid_instruction_idx = true; +@@ -6610,74 +6709,74 @@ fail: + return VKD3D_ERROR_OUT_OF_MEMORY; + } + +-enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, +- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) ++#define vsir_transform(ctx, step) vsir_transform_(ctx, #step, step) ++static void vsir_transform_( ++ struct vsir_transformation_context *ctx, const char *step_name, ++ enum vkd3d_result (*step)(struct vsir_program *program, struct vsir_transformation_context *ctx)) + { +- enum vkd3d_result result = VKD3D_OK; +- +- if ((result = vsir_program_lower_instructions(program, message_context)) < 0) +- return result; ++ if (ctx->result < 0) ++ return; + +- if (program->shader_version.major >= 6) ++ if ((ctx->result = step(ctx->program, ctx)) < 0) + { +- if ((result = vsir_program_materialise_phi_ssas_to_temps(program)) < 0) +- return result; ++ WARN("Transformation \"%s\" failed with result %d.\n", step_name, ctx->result); ++ return; ++ } + +- if ((result = lower_switch_to_if_ladder(program)) < 0) +- return result; ++ if ((ctx->result = vsir_program_validate(ctx->program, ctx->config_flags, ++ ctx->compile_info->source_name, ctx->message_context)) < 0) ++ { ++ WARN("Validation failed with result %d after transformation \"%s\".\n", ctx->result, step_name); ++ return; ++ } ++} + +- if ((result = vsir_program_structurize(program, message_context)) < 0) +- return result; ++enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t config_flags, ++ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) ++{ ++ struct vsir_transformation_context ctx = ++ { ++ .result = VKD3D_OK, ++ .program = program, ++ .config_flags = config_flags, ++ .compile_info = compile_info, ++ .message_context = message_context, ++ }; + +- if ((result = vsir_program_flatten_control_flow_constructs(program, message_context)) < 0) +- return result; ++ vsir_transform(&ctx, vsir_program_lower_instructions); + +- if ((result = vsir_program_materialize_undominated_ssas_to_temps(program, message_context)) < 0) +- return result; ++ if (program->shader_version.major >= 6) ++ { ++ vsir_transform(&ctx, vsir_program_materialise_phi_ssas_to_temps); ++ vsir_transform(&ctx, vsir_program_lower_switch_to_selection_ladder); ++ vsir_transform(&ctx, vsir_program_structurize); ++ vsir_transform(&ctx, vsir_program_flatten_control_flow_constructs); ++ vsir_transform(&ctx, vsir_program_materialize_undominated_ssas_to_temps); + } + else + { + if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL) +- { +- if ((result = vsir_program_remap_output_signature(program, compile_info, message_context)) < 0) +- return result; +- } ++ vsir_transform(&ctx, vsir_program_remap_output_signature); + + if (program->shader_version.type == VKD3D_SHADER_TYPE_HULL) + { +- if ((result = instruction_array_flatten_hull_shader_phases(&program->instructions)) < 0) +- return result; +- +- if ((result = instruction_array_normalise_hull_shader_control_point_io(&program->instructions, +- &program->input_signature)) < 0) +- return result; ++ vsir_transform(&ctx, vsir_program_flatten_hull_shader_phases); ++ vsir_transform(&ctx, instruction_array_normalise_hull_shader_control_point_io); + } + +- if ((result = vsir_program_normalise_io_registers(program, message_context)) < 0) +- return result; +- +- if ((result = instruction_array_normalise_flat_constants(program)) < 0) +- return result; +- +- remove_dead_code(program); +- +- if ((result = vsir_program_normalise_combined_samplers(program, message_context)) < 0) +- return result; ++ vsir_transform(&ctx, vsir_program_normalise_io_registers); ++ vsir_transform(&ctx, vsir_program_normalise_flat_constants); ++ vsir_transform(&ctx, vsir_program_remove_dead_code); + + if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL +- && (result = vsir_program_flatten_control_flow_constructs(program, message_context)) < 0) +- return result; ++ && compile_info->target_type != VKD3D_SHADER_TARGET_MSL) ++ vsir_transform(&ctx, vsir_program_flatten_control_flow_constructs); + } + +- if ((result = vsir_program_insert_alpha_test(program, message_context)) < 0) +- return result; ++ vsir_transform(&ctx, vsir_program_insert_alpha_test); + + if (TRACE_ON()) + vkd3d_shader_trace(program); + +- if ((result = vsir_program_validate(program, config_flags, +- compile_info->source_name, message_context)) < 0) +- return result; +- +- return result; ++ return ctx.result; + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c +new file mode 100644 +index 00000000000..7d2e713cddc +--- /dev/null ++++ b/libs/vkd3d/libs/vkd3d-shader/msl.c +@@ -0,0 +1,275 @@ ++/* ++ * Copyright 2024 Feifan He 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 ++ */ ++ ++#include "vkd3d_shader_private.h" ++ ++struct msl_src ++{ ++ struct vkd3d_string_buffer *str; ++}; ++ ++struct msl_dst ++{ ++ const struct vkd3d_shader_dst_param *vsir; ++ struct vkd3d_string_buffer *register_name; ++ struct vkd3d_string_buffer *mask; ++}; ++ ++struct msl_generator ++{ ++ struct vsir_program *program; ++ struct vkd3d_string_buffer_cache string_buffers; ++ struct vkd3d_string_buffer *buffer; ++ struct vkd3d_shader_location location; ++ struct vkd3d_shader_message_context *message_context; ++ unsigned int indent; ++}; ++ ++static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen, ++ enum vkd3d_shader_error error, const char *fmt, ...) ++{ ++ va_list args; ++ ++ va_start(args, fmt); ++ vkd3d_shader_verror(gen->message_context, &gen->location, error, fmt, args); ++ va_end(args); ++} ++ ++static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent) ++{ ++ vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); ++} ++ ++static void msl_print_register_name(struct vkd3d_string_buffer *buffer, ++ struct msl_generator *gen, const struct vkd3d_shader_register *reg) ++{ ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled register type %#x.", reg->type); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++} ++ ++static void msl_print_swizzle(struct vkd3d_string_buffer *buffer, uint32_t swizzle, uint32_t mask) ++{ ++ const char swizzle_chars[] = "xyzw"; ++ unsigned int i; ++ ++ vkd3d_string_buffer_printf(buffer, "."); ++ for (i = 0; i < VKD3D_VEC4_SIZE; ++i) ++ { ++ if (mask & (VKD3DSP_WRITEMASK_0 << i)) ++ vkd3d_string_buffer_printf(buffer, "%c", swizzle_chars[vsir_swizzle_get_component(swizzle, i)]); ++ } ++} ++ ++static void msl_print_write_mask(struct vkd3d_string_buffer *buffer, uint32_t write_mask) ++{ ++ vkd3d_string_buffer_printf(buffer, "."); ++ if (write_mask & VKD3DSP_WRITEMASK_0) ++ vkd3d_string_buffer_printf(buffer, "x"); ++ if (write_mask & VKD3DSP_WRITEMASK_1) ++ vkd3d_string_buffer_printf(buffer, "y"); ++ if (write_mask & VKD3DSP_WRITEMASK_2) ++ vkd3d_string_buffer_printf(buffer, "z"); ++ if (write_mask & VKD3DSP_WRITEMASK_3) ++ vkd3d_string_buffer_printf(buffer, "w"); ++} ++ ++static void msl_src_cleanup(struct msl_src *src, struct vkd3d_string_buffer_cache *cache) ++{ ++ vkd3d_string_buffer_release(cache, src->str); ++} ++ ++static void msl_src_init(struct msl_src *msl_src, struct msl_generator *gen, ++ const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) ++{ ++ const struct vkd3d_shader_register *reg = &vsir_src->reg; ++ ++ msl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); ++ ++ if (reg->non_uniform) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled 'non-uniform' modifier."); ++ if (vsir_src->modifiers) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers); ++ ++ msl_print_register_name(msl_src->str, gen, reg); ++ if (reg->dimension == VSIR_DIMENSION_VEC4) ++ msl_print_swizzle(msl_src->str, vsir_src->swizzle, mask); ++} ++ ++static void msl_dst_cleanup(struct msl_dst *dst, struct vkd3d_string_buffer_cache *cache) ++{ ++ vkd3d_string_buffer_release(cache, dst->mask); ++ vkd3d_string_buffer_release(cache, dst->register_name); ++} ++ ++static uint32_t msl_dst_init(struct msl_dst *msl_dst, struct msl_generator *gen, ++ const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_dst_param *vsir_dst) ++{ ++ uint32_t write_mask = vsir_dst->write_mask; ++ ++ if (ins->flags & VKD3DSI_PRECISE_XYZW) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled 'precise' modifier."); ++ if (vsir_dst->reg.non_uniform) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled 'non-uniform' modifier."); ++ ++ msl_dst->vsir = vsir_dst; ++ msl_dst->register_name = vkd3d_string_buffer_get(&gen->string_buffers); ++ msl_dst->mask = vkd3d_string_buffer_get(&gen->string_buffers); ++ ++ msl_print_register_name(msl_dst->register_name, gen, &vsir_dst->reg); ++ msl_print_write_mask(msl_dst->mask, write_mask); ++ ++ return write_mask; ++} ++ ++static void VKD3D_PRINTF_FUNC(3, 4) msl_print_assignment( ++ struct msl_generator *gen, struct msl_dst *dst, const char *format, ...) ++{ ++ va_list args; ++ ++ if (dst->vsir->shift) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled destination shift %#x.", dst->vsir->shift); ++ if (dst->vsir->modifiers) ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled destination modifier(s) %#x.", dst->vsir->modifiers); ++ ++ msl_print_indent(gen->buffer, gen->indent); ++ vkd3d_string_buffer_printf(gen->buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); ++ ++ va_start(args, format); ++ vkd3d_string_buffer_vprintf(gen->buffer, format, args); ++ va_end(args); ++ ++ vkd3d_string_buffer_printf(gen->buffer, ";\n"); ++} ++ ++static void msl_unhandled(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) ++{ ++ msl_print_indent(gen->buffer, gen->indent); ++ vkd3d_string_buffer_printf(gen->buffer, "/* */\n", ins->opcode); ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled instruction %#x.", ins->opcode); ++} ++ ++static void msl_mov(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) ++{ ++ struct msl_src src; ++ struct msl_dst dst; ++ uint32_t mask; ++ ++ mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ msl_src_init(&src, gen, &ins->src[0], mask); ++ ++ msl_print_assignment(gen, &dst, "%s", src.str->buffer); ++ ++ msl_src_cleanup(&src, &gen->string_buffers); ++ msl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ ++static void msl_ret(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) ++{ ++ msl_print_indent(gen->buffer, gen->indent); ++ vkd3d_string_buffer_printf(gen->buffer, "return;\n"); ++} ++ ++static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) ++{ ++ gen->location = ins->location; ++ ++ switch (ins->opcode) ++ { ++ case VKD3DSIH_NOP: ++ break; ++ case VKD3DSIH_MOV: ++ msl_mov(gen, ins); ++ break; ++ case VKD3DSIH_RET: ++ msl_ret(gen, ins); ++ break; ++ default: ++ msl_unhandled(gen, ins); ++ break; ++ } ++} ++ ++static void msl_generator_generate(struct msl_generator *gen) ++{ ++ const struct vkd3d_shader_instruction_array *instructions = &gen->program->instructions; ++ unsigned int i; ++ ++ MESSAGE("Generating a MSL shader. This is unsupported; you get to keep all the pieces if it breaks.\n"); ++ ++ vkd3d_string_buffer_printf(gen->buffer, "/* Generated by %s. */\n\n", vkd3d_shader_get_version(NULL, NULL)); ++ ++ vkd3d_string_buffer_printf(gen->buffer, "void shader_main()\n{\n"); ++ ++ ++gen->indent; ++ for (i = 0; i < instructions->count; ++i) ++ { ++ msl_handle_instruction(gen, &instructions->elements[i]); ++ } ++ ++ vkd3d_string_buffer_printf(gen->buffer, "}\n"); ++ ++ if (TRACE_ON()) ++ vkd3d_string_buffer_trace(gen->buffer); ++} ++ ++static void msl_generator_cleanup(struct msl_generator *gen) ++{ ++ vkd3d_string_buffer_release(&gen->string_buffers, gen->buffer); ++ vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); ++} ++ ++static int msl_generator_init(struct msl_generator *gen, struct vsir_program *program, ++ struct vkd3d_shader_message_context *message_context) ++{ ++ memset(gen, 0, sizeof(*gen)); ++ gen->program = program; ++ vkd3d_string_buffer_cache_init(&gen->string_buffers); ++ if (!(gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers))) ++ { ++ vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ } ++ gen->message_context = message_context; ++ ++ return VKD3D_OK; ++} ++ ++int msl_compile(struct vsir_program *program, uint64_t config_flags, ++ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) ++{ ++ struct msl_generator generator; ++ int ret; ++ ++ if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0) ++ return ret; ++ ++ if ((ret = msl_generator_init(&generator, program, message_context)) < 0) ++ return ret; ++ msl_generator_generate(&generator); ++ msl_generator_cleanup(&generator); ++ ++ return VKD3D_ERROR_INVALID_SHADER; ++} +diff --git a/libs/vkd3d/libs/vkd3d-shader/preproc.l b/libs/vkd3d/libs/vkd3d-shader/preproc.l +index 2b7455a5c30..7fc963192cf 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/preproc.l ++++ b/libs/vkd3d/libs/vkd3d-shader/preproc.l +@@ -20,6 +20,7 @@ + + %{ + ++#include "preproc.h" + #include "preproc.tab.h" + + #undef ERROR /* defined in wingdi.h */ +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 49979ab2491..7f1e0fea2c3 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -97,15 +97,37 @@ static enum vkd3d_result vkd3d_spirv_binary_to_text(const struct vkd3d_shader_co + if (!(spvret = spvBinaryToText(context, spirv->code, spirv->size / sizeof(uint32_t), + get_binary_to_text_options(formatting), &text, &diagnostic))) + { +- void *code = vkd3d_malloc(text->length); +- if (code) ++ const char *p, *q, *end, *pad, *truncate; ++ struct vkd3d_string_buffer buffer; ++ size_t line_len; ++ ++ vkd3d_string_buffer_init(&buffer); ++ ++ for (p = text->str, end = p + text->length; p < end; p = q) + { +- memcpy(code, text->str, text->length); +- out->size = text->length; +- out->code = code; ++ if (!(q = memchr(p, '\n', end - p))) ++ q = end; ++ else ++ ++q; ++ ++ /* FIXME: Note that when colour output is enabled, we count colour ++ * escape codes towards the line length. It's possible to fix ++ * that, but not completely trivial. */ ++ for (pad = "", line_len = 100; q - p > line_len; line_len = 100 - strlen(pad)) ++ { ++ if (!(truncate = memchr(p + line_len, ' ', q - p - line_len))) ++ break; ++ vkd3d_string_buffer_printf(&buffer, "%s%.*s\n", pad, (int)(truncate - p), p); ++ p = truncate + 1; ++ if (formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT) ++ pad = " "; ++ else ++ pad = " "; ++ } ++ vkd3d_string_buffer_printf(&buffer, "%s%.*s", pad, (int)(q - p), p); + } +- else +- result = VKD3D_ERROR_OUT_OF_MEMORY; ++ ++ vkd3d_shader_code_from_string_buffer(out, &buffer); + } + else + { +@@ -277,6 +299,16 @@ static void vkd3d_spirv_stream_free(struct vkd3d_spirv_stream *stream) + vkd3d_spirv_stream_clear(stream); + } + ++static void vkd3d_shader_code_from_spirv_stream(struct vkd3d_shader_code *code, struct vkd3d_spirv_stream *stream) ++{ ++ code->code = stream->words; ++ code->size = stream->word_count * sizeof(*stream->words); ++ ++ stream->words = NULL; ++ stream->capacity = 0; ++ stream->word_count = 0; ++} ++ + static size_t vkd3d_spirv_stream_current_location(struct vkd3d_spirv_stream *stream) + { + return stream->word_count; +@@ -1996,9 +2028,7 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, + { + uint64_t capability_mask = builder->capability_mask; + struct vkd3d_spirv_stream stream; +- uint32_t *code; + unsigned int i; +- size_t size; + + vkd3d_spirv_stream_init(&stream); + +@@ -2053,26 +2083,20 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, + if (builder->invocation_count) + vkd3d_spirv_build_op_execution_mode(&builder->execution_mode_stream, + builder->main_function_id, SpvExecutionModeInvocations, &builder->invocation_count, 1); +- vkd3d_spirv_stream_append(&stream, &builder->execution_mode_stream); +- +- vkd3d_spirv_stream_append(&stream, &builder->debug_stream); +- vkd3d_spirv_stream_append(&stream, &builder->annotation_stream); +- vkd3d_spirv_stream_append(&stream, &builder->global_stream); +- vkd3d_spirv_stream_append(&stream, &builder->function_stream); + +- if (!(code = vkd3d_calloc(stream.word_count, sizeof(*code)))) ++ if (!vkd3d_spirv_stream_append(&stream, &builder->execution_mode_stream) ++ || !vkd3d_spirv_stream_append(&stream, &builder->debug_stream) ++ || !vkd3d_spirv_stream_append(&stream, &builder->annotation_stream) ++ || !vkd3d_spirv_stream_append(&stream, &builder->global_stream) ++ || !vkd3d_spirv_stream_append(&stream, &builder->function_stream)) + { + vkd3d_spirv_stream_free(&stream); + return false; + } + +- size = stream.word_count * sizeof(*code); +- memcpy(code, stream.words, size); ++ vkd3d_shader_code_from_spirv_stream(spirv, &stream); + vkd3d_spirv_stream_free(&stream); + +- spirv->code = code; +- spirv->size = size; +- + return true; + } + +@@ -6120,12 +6144,12 @@ static void spirv_compiler_decorate_descriptor(struct spirv_compiler *compiler, + static uint32_t spirv_compiler_build_descriptor_variable(struct spirv_compiler *compiler, + SpvStorageClass storage_class, uint32_t type_id, const struct vkd3d_shader_register *reg, + const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type, +- bool is_uav, bool is_uav_counter, struct vkd3d_descriptor_variable_info *var_info) ++ const struct vkd3d_shader_descriptor_info1 *descriptor, bool is_uav_counter, ++ struct vkd3d_descriptor_variable_info *var_info) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + struct vkd3d_descriptor_binding_address binding_address; + struct vkd3d_shader_descriptor_binding binding; +- const struct vkd3d_shader_descriptor_info1 *d; + uint32_t array_type_id, ptr_type_id, var_id; + bool write_only = false, coherent = false; + struct vkd3d_symbol symbol; +@@ -6135,12 +6159,11 @@ static uint32_t spirv_compiler_build_descriptor_variable(struct spirv_compiler * + resource_type, is_uav_counter, &binding_address); + var_info->binding_base_idx = binding_address.binding_base_idx; + +- if (is_uav) ++ if (descriptor->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV && !is_uav_counter) + { +- d = spirv_compiler_get_descriptor_info(compiler, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, range); +- write_only = !(d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ); ++ write_only = !(descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ); + /* ROVs are implicitly globally coherent. */ +- coherent = d->uav_flags & (VKD3DSUF_GLOBALLY_COHERENT | VKD3DSUF_RASTERISER_ORDERED_VIEW); ++ coherent = descriptor->uav_flags & (VKD3DSUF_GLOBALLY_COHERENT | VKD3DSUF_RASTERISER_ORDERED_VIEW); + } + + if (binding.count == 1 && range->first == binding_address.binding_base_idx && range->last != ~0u +@@ -6194,11 +6217,12 @@ static uint32_t spirv_compiler_build_descriptor_variable(struct spirv_compiler * + } + + static void spirv_compiler_emit_cbv_declaration(struct spirv_compiler *compiler, +- const struct vkd3d_shader_register_range *range, unsigned int register_id, unsigned int size_in_bytes) ++ const struct vkd3d_shader_register_range *range, const struct vkd3d_shader_descriptor_info1 *descriptor) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t vec4_id, array_type_id, length_id, struct_id, var_id; + const SpvStorageClass storage_class = SpvStorageClassUniform; ++ unsigned int size_in_bytes = descriptor->buffer_size; + struct vkd3d_push_constant_buffer_binding *push_cb; + struct vkd3d_descriptor_variable_info var_info; + struct vkd3d_shader_register reg; +@@ -6206,7 +6230,7 @@ static void spirv_compiler_emit_cbv_declaration(struct spirv_compiler *compiler, + unsigned int size; + + vsir_register_init(®, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3); +- reg.idx[0].offset = register_id; ++ reg.idx[0].offset = descriptor->register_id; + reg.idx[1].offset = range->first; + reg.idx[2].offset = range->last; + +@@ -6239,7 +6263,7 @@ static void spirv_compiler_emit_cbv_declaration(struct spirv_compiler *compiler, + vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", size); + + var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, struct_id, +- ®, range, VKD3D_SHADER_RESOURCE_BUFFER, false, false, &var_info); ++ ®, range, VKD3D_SHADER_RESOURCE_BUFFER, descriptor, false, &var_info); + + vkd3d_symbol_make_register(®_symbol, ®); + vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, +@@ -6275,7 +6299,7 @@ static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compi + } + + static void spirv_compiler_emit_sampler_declaration(struct spirv_compiler *compiler, +- const struct vkd3d_shader_register_range *range, unsigned int register_id) ++ const struct vkd3d_shader_register_range *range, const struct vkd3d_shader_descriptor_info1 *descriptor) + { + const SpvStorageClass storage_class = SpvStorageClassUniformConstant; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; +@@ -6285,7 +6309,7 @@ static void spirv_compiler_emit_sampler_declaration(struct spirv_compiler *compi + uint32_t type_id, var_id; + + vsir_register_init(®, VKD3DSPR_SAMPLER, VKD3D_DATA_FLOAT, 1); +- reg.idx[0].offset = register_id; ++ reg.idx[0].offset = descriptor->register_id; + + vkd3d_symbol_make_sampler(®_symbol, ®); + reg_symbol.info.sampler.range = *range; +@@ -6295,8 +6319,8 @@ static void spirv_compiler_emit_sampler_declaration(struct spirv_compiler *compi + return; + + type_id = vkd3d_spirv_get_op_type_sampler(builder); +- var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, type_id, ®, +- range, VKD3D_SHADER_RESOURCE_NONE, false, false, &var_info); ++ var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, type_id, ++ ®, range, VKD3D_SHADER_RESOURCE_NONE, descriptor, false, &var_info); + + vkd3d_symbol_make_register(®_symbol, ®); + vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, +@@ -6461,21 +6485,24 @@ static void spirv_compiler_emit_combined_sampler_declarations(struct spirv_compi + } + + static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *compiler, +- const struct vkd3d_shader_register_range *range, unsigned int register_id, +- unsigned int sample_count, bool is_uav, enum vkd3d_shader_resource_type resource_type, +- enum vkd3d_shader_resource_data_type resource_data_type, unsigned int structure_stride, bool raw) ++ const struct vkd3d_shader_register_range *range, const struct vkd3d_shader_descriptor_info1 *descriptor) + { ++ bool raw = descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER; ++ enum vkd3d_shader_resource_type resource_type = descriptor->resource_type; + struct vkd3d_descriptor_variable_info var_info, counter_var_info = {0}; ++ bool is_uav = descriptor->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; ++ unsigned int structure_stride = descriptor->structure_stride / 4; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + SpvStorageClass storage_class = SpvStorageClassUniformConstant; + uint32_t counter_type_id, type_id, var_id, counter_var_id = 0; + const struct vkd3d_spirv_resource_type *resource_type_info; ++ unsigned int sample_count = descriptor->sample_count; + enum vkd3d_shader_component_type sampled_type; + struct vkd3d_symbol resource_symbol; + struct vkd3d_shader_register reg; + + vsir_register_init(®, is_uav ? VKD3DSPR_UAV : VKD3DSPR_RESOURCE, VKD3D_DATA_FLOAT, 1); +- reg.idx[0].offset = register_id; ++ reg.idx[0].offset = descriptor->register_id; + + if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS && sample_count == 1) + resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; +@@ -6489,7 +6516,7 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp + return; + } + +- sampled_type = vkd3d_component_type_from_resource_data_type(resource_data_type); ++ sampled_type = vkd3d_component_type_from_resource_data_type(descriptor->resource_data_type); + + if (!is_uav && spirv_compiler_has_combined_sampler_for_resource(compiler, range)) + { +@@ -6520,16 +6547,12 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp + resource_type_info, sampled_type, structure_stride || raw, 0); + } + +- var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, type_id, ®, +- range, resource_type, is_uav, false, &var_info); ++ var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, ++ type_id, ®, range, resource_type, descriptor, false, &var_info); + + if (is_uav) + { +- const struct vkd3d_shader_descriptor_info1 *d; +- +- d = spirv_compiler_get_descriptor_info(compiler, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, range); +- +- if (d->uav_flags & VKD3DSUF_RASTERISER_ORDERED_VIEW) ++ if (descriptor->uav_flags & VKD3DSUF_RASTERISER_ORDERED_VIEW) + { + if (compiler->shader_type != VKD3D_SHADER_TYPE_PIXEL) + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE, +@@ -6543,7 +6566,7 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp + compiler->use_invocation_interlock = true; + } + +- if (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER) ++ if (descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER) + { + VKD3D_ASSERT(structure_stride); /* counters are valid only for structured buffers */ + +@@ -6571,7 +6594,7 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp + } + + counter_var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, +- type_id, ®, range, resource_type, false, true, &counter_var_info); ++ type_id, ®, range, resource_type, descriptor, true, &counter_var_info); + } + } + +@@ -10564,23 +10587,16 @@ static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *c + switch (descriptor->type) + { + case VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER: +- spirv_compiler_emit_sampler_declaration(compiler, &range, descriptor->register_id); ++ spirv_compiler_emit_sampler_declaration(compiler, &range, descriptor); + break; + + case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: +- spirv_compiler_emit_cbv_declaration(compiler, &range, descriptor->register_id, descriptor->buffer_size); ++ spirv_compiler_emit_cbv_declaration(compiler, &range, descriptor); + break; + + case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV: +- spirv_compiler_emit_resource_declaration(compiler, &range, descriptor->register_id, +- descriptor->sample_count, false, descriptor->resource_type, descriptor->resource_data_type, +- descriptor->structure_stride / 4, descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER); +- break; +- + case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV: +- spirv_compiler_emit_resource_declaration(compiler, &range, descriptor->register_id, +- descriptor->sample_count, true, descriptor->resource_type, descriptor->resource_data_type, +- descriptor->structure_stride / 4, descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER); ++ spirv_compiler_emit_resource_declaration(compiler, &range, descriptor); + break; + + default: +@@ -10600,7 +10616,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct + enum vkd3d_result result = VKD3D_OK; + unsigned int i, max_element_count; + +- if ((result = vsir_program_normalise(program, compiler->config_flags, ++ if ((result = vsir_program_transform(program, compiler->config_flags, + compile_info, compiler->message_context)) < 0) + return result; + +diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c +index 84f641cc316..884a2998d5b 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c ++++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c +@@ -23,6 +23,7 @@ + + #include "hlsl.h" + #include "vkd3d_shader_private.h" ++#include "d3dcommon.h" + + #define SM4_MAX_SRC_COUNT 6 + #define SM4_MAX_DST_COUNT 2 +@@ -616,6 +617,47 @@ enum vkd3d_sm4_shader_data_type + VKD3D_SM4_SHADER_DATA_MESSAGE = 0x4, + }; + ++enum vkd3d_sm4_stat_field ++{ ++ VKD3D_STAT_UNUSED = 0, ++ VKD3D_STAT_INSTR_COUNT, ++ VKD3D_STAT_MOV, ++ VKD3D_STAT_MOVC, ++ VKD3D_STAT_CONV, ++ VKD3D_STAT_FLOAT, ++ VKD3D_STAT_INT, ++ VKD3D_STAT_UINT, ++ VKD3D_STAT_EMIT, ++ VKD3D_STAT_CUT, ++ VKD3D_STAT_SAMPLE, ++ VKD3D_STAT_SAMPLE_C, ++ VKD3D_STAT_SAMPLE_GRAD, ++ VKD3D_STAT_SAMPLE_BIAS, ++ VKD3D_STAT_LOAD, ++ VKD3D_STAT_STORE, ++ VKD3D_STAT_DCL_VERTICES_OUT, ++ VKD3D_STAT_DCL_INPUT_PRIMITIVE, ++ VKD3D_STAT_DCL_OUTPUT_TOPOLOGY, ++ VKD3D_STAT_DCL_GS_INSTANCES, ++ VKD3D_STAT_BITWISE, ++ VKD3D_STAT_ATOMIC, ++ VKD3D_STAT_TESS_DOMAIN, ++ VKD3D_STAT_TESS_PARTITIONING, ++ VKD3D_STAT_TESS_OUTPUT_PRIMITIVE, ++ VKD3D_STAT_TESS_CONTROL_POINT_COUNT, ++ VKD3D_STAT_BARRIER, ++ VKD3D_STAT_LOD, ++ VKD3D_STAT_GATHER, ++ VKD3D_STAT_TEMPS, ++ VKD3D_STAT_COUNT, ++}; ++ ++struct vkd3d_sm4_stat_field_info ++{ ++ enum vkd3d_sm4_opcode opcode; ++ enum vkd3d_sm4_stat_field field; ++}; ++ + struct sm4_index_range + { + unsigned int index; +@@ -634,6 +676,7 @@ struct vkd3d_sm4_lookup_tables + const struct vkd3d_sm4_opcode_info *opcode_info_from_sm4[VKD3D_SM4_OP_COUNT]; + const struct vkd3d_sm4_register_type_info *register_type_info_from_sm4[VKD3D_SM4_REGISTER_TYPE_COUNT]; + const struct vkd3d_sm4_register_type_info *register_type_info_from_vkd3d[VKD3DSPR_COUNT]; ++ const struct vkd3d_sm4_stat_field_info *stat_field_from_sm4[VKD3D_SM4_OP_COUNT]; + }; + + struct vkd3d_shader_sm4_parser +@@ -1115,7 +1158,18 @@ static void shader_sm4_read_dcl_input_ps(struct vkd3d_shader_instruction *ins, u + struct signature_element *e = vsir_signature_find_element_for_reg( + &priv->p.program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); + +- e->interpolation_mode = ins->flags; ++ if (!e) ++ { ++ WARN("No matching signature element for input register %u with mask %#x.\n", ++ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); ++ vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, ++ "No matching signature element for input register %u with mask %#x.\n", ++ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); ++ } ++ else ++ { ++ e->interpolation_mode = ins->flags; ++ } + } + } + +@@ -1130,7 +1184,18 @@ static void shader_sm4_read_dcl_input_ps_siv(struct vkd3d_shader_instruction *in + struct signature_element *e = vsir_signature_find_element_for_reg( + &priv->p.program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); + +- e->interpolation_mode = ins->flags; ++ if (!e) ++ { ++ WARN("No matching signature element for input register %u with mask %#x.\n", ++ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); ++ vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, ++ "No matching signature element for input register %u with mask %#x.\n", ++ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); ++ } ++ else ++ { ++ e->interpolation_mode = ins->flags; ++ } + } + ins->declaration.register_semantic.sysval_semantic = *tokens; + } +@@ -1330,11 +1395,17 @@ static const enum vkd3d_shader_register_precision register_precision_table[] = + /* VKD3D_SM4_REGISTER_PRECISION_MIN_UINT_16 */ VKD3D_SHADER_REGISTER_PRECISION_MIN_UINT_16, + }; + ++struct sm4_stat ++{ ++ uint32_t fields[VKD3D_STAT_COUNT]; ++}; ++ + struct tpf_writer + { + struct hlsl_ctx *ctx; + struct vkd3d_bytecode_buffer *buffer; + struct vkd3d_sm4_lookup_tables lookup; ++ struct sm4_stat *stat; + }; + + static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) +@@ -1662,6 +1733,161 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + {VKD3D_SM5_RT_OUTPUT_STENCIL_REF, VKD3DSPR_OUTSTENCILREF, VKD3D_SM4_SWIZZLE_VEC4}, + }; + ++ static const struct vkd3d_sm4_stat_field_info stat_field_table[] = ++ { ++ {VKD3D_SM4_OP_MOV, VKD3D_STAT_MOV}, ++ {VKD3D_SM4_OP_MOVC, VKD3D_STAT_MOVC}, ++ {VKD3D_SM5_OP_DMOV, VKD3D_STAT_MOV}, ++ {VKD3D_SM5_OP_DMOVC, VKD3D_STAT_MOVC}, ++ ++ {VKD3D_SM4_OP_ITOF, VKD3D_STAT_CONV}, ++ {VKD3D_SM4_OP_FTOI, VKD3D_STAT_CONV}, ++ {VKD3D_SM4_OP_FTOU, VKD3D_STAT_CONV}, ++ {VKD3D_SM4_OP_UTOF, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_DTOU, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_UTOD, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_DTOF, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_FTOD, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_DTOI, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_ITOD, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_F32TOF16, VKD3D_STAT_CONV}, ++ {VKD3D_SM5_OP_F16TOF32, VKD3D_STAT_CONV}, ++ ++ {VKD3D_SM4_OP_ADD, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_DIV, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_DP2, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_DP3, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_DP4, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_EQ, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_EXP, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_FRC, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_GE, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_LT, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_MAD, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_MIN, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_MAX, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_MUL, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_NE, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_ROUND_NE, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_ROUND_NI, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_ROUND_PI, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_ROUND_Z, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_RSQ, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_SQRT, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM4_OP_SINCOS, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_RCP, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DADD, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DMAX, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DMIN, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DMUL, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DEQ, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DGE, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DLT, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DNE, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DDIV, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DFMA, VKD3D_STAT_FLOAT}, ++ {VKD3D_SM5_OP_DRCP, VKD3D_STAT_FLOAT}, ++ ++ {VKD3D_SM4_OP_IADD, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_IEQ, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_IGE, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_ILT, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_IMAD, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_IMAX, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_IMIN, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_IMUL, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_INE, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_INEG, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_ISHL, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_ISHR, VKD3D_STAT_INT}, ++ {VKD3D_SM4_OP_ITOF, VKD3D_STAT_INT}, ++ ++ {VKD3D_SM4_OP_UDIV, VKD3D_STAT_UINT}, ++ {VKD3D_SM4_OP_ULT, VKD3D_STAT_UINT}, ++ {VKD3D_SM4_OP_UGE, VKD3D_STAT_UINT}, ++ {VKD3D_SM4_OP_UMUL, VKD3D_STAT_UINT}, ++ {VKD3D_SM4_OP_UMAX, VKD3D_STAT_UINT}, ++ {VKD3D_SM4_OP_UMIN, VKD3D_STAT_UINT}, ++ {VKD3D_SM4_OP_USHR, VKD3D_STAT_UINT}, ++ ++ {VKD3D_SM4_OP_EMIT, VKD3D_STAT_EMIT}, ++ {VKD3D_SM4_OP_CUT, VKD3D_STAT_CUT}, ++ {VKD3D_SM5_OP_EMIT_STREAM, VKD3D_STAT_EMIT}, ++ {VKD3D_SM5_OP_CUT_STREAM, VKD3D_STAT_CUT}, ++ ++ {VKD3D_SM4_OP_SAMPLE, VKD3D_STAT_SAMPLE}, ++ {VKD3D_SM4_OP_SAMPLE_LOD, VKD3D_STAT_SAMPLE}, ++ {VKD3D_SM5_OP_SAMPLE_LOD_S, VKD3D_STAT_SAMPLE}, ++ {VKD3D_SM5_OP_SAMPLE_CL_S, VKD3D_STAT_SAMPLE}, ++ {VKD3D_SM4_OP_SAMPLE_C, VKD3D_STAT_SAMPLE_C}, ++ {VKD3D_SM4_OP_SAMPLE_C_LZ, VKD3D_STAT_SAMPLE_C}, ++ {VKD3D_SM5_OP_SAMPLE_C_LZ_S, VKD3D_STAT_SAMPLE_C}, ++ {VKD3D_SM5_OP_SAMPLE_C_CL_S, VKD3D_STAT_SAMPLE_C}, ++ {VKD3D_SM4_OP_SAMPLE_GRAD, VKD3D_STAT_SAMPLE_GRAD}, ++ {VKD3D_SM5_OP_SAMPLE_GRAD_CL_S, VKD3D_STAT_SAMPLE_GRAD}, ++ {VKD3D_SM4_OP_SAMPLE_B, VKD3D_STAT_SAMPLE_BIAS}, ++ {VKD3D_SM4_OP_GATHER4, VKD3D_STAT_GATHER}, ++ {VKD3D_SM5_OP_GATHER4_PO, VKD3D_STAT_GATHER}, ++ {VKD3D_SM4_OP_LOD, VKD3D_STAT_LOD}, ++ ++ {VKD3D_SM4_OP_LD, VKD3D_STAT_LOAD}, ++ {VKD3D_SM4_OP_LD2DMS, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD_UAV_TYPED, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD_RAW, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD_STRUCTURED, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD_S, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD2DMS_S, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD_UAV_TYPED_S, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD_RAW_S, VKD3D_STAT_LOAD}, ++ {VKD3D_SM5_OP_LD_STRUCTURED_S, VKD3D_STAT_LOAD}, ++ ++ {VKD3D_SM5_OP_STORE_UAV_TYPED, VKD3D_STAT_STORE}, ++ {VKD3D_SM5_OP_STORE_RAW, VKD3D_STAT_STORE}, ++ {VKD3D_SM5_OP_STORE_STRUCTURED,VKD3D_STAT_STORE}, ++ ++ {VKD3D_SM4_OP_DCL_VERTICES_OUT, VKD3D_STAT_DCL_VERTICES_OUT}, ++ {VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE, VKD3D_STAT_DCL_INPUT_PRIMITIVE}, ++ {VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY, VKD3D_STAT_DCL_OUTPUT_TOPOLOGY}, ++ {VKD3D_SM5_OP_DCL_GS_INSTANCES, VKD3D_STAT_DCL_GS_INSTANCES}, ++ ++ {VKD3D_SM4_OP_AND, VKD3D_STAT_BITWISE}, ++ {VKD3D_SM4_OP_NOT, VKD3D_STAT_BITWISE}, ++ {VKD3D_SM4_OP_OR, VKD3D_STAT_BITWISE}, ++ {VKD3D_SM4_OP_XOR, VKD3D_STAT_BITWISE}, ++ ++ {VKD3D_SM5_OP_ATOMIC_AND, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_OR, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_XOR, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_CMP_STORE, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_IADD, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_IMAX, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_IMIN, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_UMAX, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_ATOMIC_UMIN, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_ALLOC, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_CONSUME, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_IADD, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_AND, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_OR, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_XOR, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_EXCH, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_CMP_EXCH, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_IMAX, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_IMIN, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_UMAX, VKD3D_STAT_ATOMIC}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_UMIN, VKD3D_STAT_ATOMIC}, ++ ++ {VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN, VKD3D_STAT_TESS_DOMAIN}, ++ {VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING, VKD3D_STAT_TESS_PARTITIONING}, ++ {VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE, VKD3D_STAT_TESS_OUTPUT_PRIMITIVE}, ++ {VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, ++ {VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, ++ ++ {VKD3D_SM5_OP_SYNC, VKD3D_STAT_BARRIER}, ++ ++ {VKD3D_SM4_OP_DCL_TEMPS, VKD3D_STAT_TEMPS}, ++ }; ++ + memset(lookup, 0, sizeof(*lookup)); + + for (i = 0; i < ARRAY_SIZE(opcode_table); ++i) +@@ -1678,12 +1904,21 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + lookup->register_type_info_from_sm4[info->sm4_type] = info; + lookup->register_type_info_from_vkd3d[info->vkd3d_type] = info; + } ++ ++ for (i = 0; i < ARRAY_SIZE(stat_field_table); ++i) ++ { ++ const struct vkd3d_sm4_stat_field_info *info = &stat_field_table[i]; ++ ++ lookup->stat_field_from_sm4[info->opcode] = info; ++ } + } + +-static void tpf_writer_init(struct tpf_writer *tpf, struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer) ++static void tpf_writer_init(struct tpf_writer *tpf, struct hlsl_ctx *ctx, struct sm4_stat *stat, ++ struct vkd3d_bytecode_buffer *buffer) + { + tpf->ctx = ctx; + tpf->buffer = buffer; ++ tpf->stat = stat; + init_sm4_lookup_tables(&tpf->lookup); + } + +@@ -1721,6 +1956,16 @@ static enum vkd3d_sm4_swizzle_type vkd3d_sm4_get_default_swizzle_type( + return register_type_info->default_src_swizzle_type; + } + ++static enum vkd3d_sm4_stat_field get_stat_field_from_sm4_opcode( ++ const struct vkd3d_sm4_lookup_tables *lookup, enum vkd3d_sm4_opcode sm4_opcode) ++{ ++ const struct vkd3d_sm4_stat_field_info *field_info; ++ ++ if (sm4_opcode >= VKD3D_SM4_OP_COUNT || !(field_info = lookup->stat_field_from_sm4[sm4_opcode])) ++ return VKD3D_STAT_UNUSED; ++ return field_info->field; ++} ++ + static enum vkd3d_data_type map_data_type(char t) + { + switch (t) +@@ -2553,7 +2798,7 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, struct vsir_pro + version.minor = VKD3D_SM4_VERSION_MINOR(version_token); + + /* Estimate instruction count to avoid reallocation in most shaders. */ +- if (!vsir_program_init(program, compile_info, &version, token_count / 7u + 20)) ++ if (!vsir_program_init(program, compile_info, &version, token_count / 7u + 20, VSIR_CF_STRUCTURED)) + return false; + vkd3d_shader_parser_init(&sm4->p, program, message_context, compile_info->source_name); + sm4->ptr = sm4->start; +@@ -2782,8 +3027,8 @@ bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_sem + return false; + } + +-bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, +- bool output, D3D_NAME *usage) ++bool sysval_semantic_from_hlsl(enum vkd3d_shader_sysval_semantic *semantic, ++ struct hlsl_ctx *ctx, const struct hlsl_semantic *hlsl_semantic, bool output) + { + unsigned int i; + +@@ -2792,7 +3037,7 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant + const char *name; + bool output; + enum vkd3d_shader_type shader_type; +- D3D_NAME usage; ++ enum vkd3d_shader_sysval_semantic semantic; + } + semantics[] = + { +@@ -2800,46 +3045,47 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant + {"sv_groupid", false, VKD3D_SHADER_TYPE_COMPUTE, ~0u}, + {"sv_groupthreadid", false, VKD3D_SHADER_TYPE_COMPUTE, ~0u}, + +- {"position", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, +- {"sv_position", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, +- {"sv_primitiveid", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_PRIMITIVE_ID}, +- +- {"position", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, +- {"sv_position", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, +- {"sv_primitiveid", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_PRIMITIVE_ID}, +- +- {"position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, +- {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, +- {"sv_primitiveid", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_PRIMITIVE_ID}, +- {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_IS_FRONT_FACE}, +- {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_RENDER_TARGET_ARRAY_INDEX}, +- {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_VIEWPORT_ARRAY_INDEX}, +- +- {"color", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET}, +- {"depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH}, +- {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET}, +- {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH}, +- {"sv_coverage", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_COVERAGE}, +- +- {"sv_position", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_UNDEFINED}, +- {"sv_vertexid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VERTEX_ID}, +- {"sv_instanceid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_INSTANCE_ID}, +- +- {"position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, +- {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, +- {"sv_rendertargetarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_RENDER_TARGET_ARRAY_INDEX}, +- {"sv_viewportarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VIEWPORT_ARRAY_INDEX}, ++ {"position", false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, ++ {"sv_position", false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, ++ {"sv_primitiveid", false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_PRIMITIVE_ID}, ++ ++ {"position", true, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, ++ {"sv_position", true, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, ++ {"sv_primitiveid", true, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_PRIMITIVE_ID}, ++ ++ {"position", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_POSITION}, ++ {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_POSITION}, ++ {"sv_primitiveid", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_PRIMITIVE_ID}, ++ {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_IS_FRONT_FACE}, ++ {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX}, ++ {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX}, ++ {"sv_sampleindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_SAMPLE_INDEX}, ++ ++ {"color", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_TARGET}, ++ {"depth", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_DEPTH}, ++ {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_TARGET}, ++ {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_DEPTH}, ++ {"sv_coverage", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_COVERAGE}, ++ ++ {"sv_position", false, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_NONE}, ++ {"sv_vertexid", false, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_VERTEX_ID}, ++ {"sv_instanceid", false, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_INSTANCE_ID}, ++ ++ {"position", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_POSITION}, ++ {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_POSITION}, ++ {"sv_rendertargetarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX}, ++ {"sv_viewportarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX}, + }; +- bool needs_compat_mapping = ascii_strncasecmp(semantic->name, "sv_", 3); ++ bool needs_compat_mapping = ascii_strncasecmp(hlsl_semantic->name, "sv_", 3); + + for (i = 0; i < ARRAY_SIZE(semantics); ++i) + { +- if (!ascii_strcasecmp(semantic->name, semantics[i].name) ++ if (!ascii_strcasecmp(hlsl_semantic->name, semantics[i].name) + && output == semantics[i].output + && (ctx->semantic_compat_mapping == needs_compat_mapping || !needs_compat_mapping) + && ctx->profile->type == semantics[i].shader_type) + { +- *usage = semantics[i].usage; ++ *semantic = semantics[i].semantic; + return true; + } + } +@@ -2847,7 +3093,7 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant + if (!needs_compat_mapping) + return false; + +- *usage = D3D_NAME_UNDEFINED; ++ *semantic = VKD3D_SHADER_SV_NONE; + return true; + } + +@@ -2880,16 +3126,16 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + unsigned int width = (1u << var->data_type->dimx) - 1, use_mask; ++ enum vkd3d_shader_sysval_semantic semantic; + uint32_t usage_idx, reg_idx; +- D3D_NAME usage; + bool has_idx; + + if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic)) + continue; + +- ret = hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage); ++ ret = sysval_semantic_from_hlsl(&semantic, ctx, &var->semantic, output); + VKD3D_ASSERT(ret); +- if (usage == ~0u) ++ if (semantic == ~0u) + continue; + usage_idx = var->semantic.index; + +@@ -2908,26 +3154,26 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, + use_mask = 0xf ^ use_mask; + + /* Special pixel shader semantics (TARGET, DEPTH, COVERAGE). */ +- if (usage >= 64) +- usage = 0; ++ if (semantic >= VKD3D_SHADER_SV_TARGET) ++ semantic = VKD3D_SHADER_SV_NONE; + + put_u32(&buffer, 0); /* name */ + put_u32(&buffer, usage_idx); +- put_u32(&buffer, usage); ++ put_u32(&buffer, semantic); + switch (var->data_type->e.numeric.type) + { + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_HALF: +- put_u32(&buffer, D3D_REGISTER_COMPONENT_FLOAT32); ++ put_u32(&buffer, VKD3D_SHADER_COMPONENT_FLOAT); + break; + + case HLSL_TYPE_INT: +- put_u32(&buffer, D3D_REGISTER_COMPONENT_SINT32); ++ put_u32(&buffer, VKD3D_SHADER_COMPONENT_INT); + break; + + case HLSL_TYPE_BOOL: + case HLSL_TYPE_UINT: +- put_u32(&buffer, D3D_REGISTER_COMPONENT_UINT32); ++ put_u32(&buffer, VKD3D_SHADER_COMPONENT_UINT); + break; + + default: +@@ -2935,7 +3181,7 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Invalid data type %s for semantic variable %s.", string->buffer, var->name); + hlsl_release_string_buffer(ctx, string); +- put_u32(&buffer, D3D_REGISTER_COMPONENT_UNKNOWN); ++ put_u32(&buffer, VKD3D_SHADER_COMPONENT_VOID); + } + put_u32(&buffer, reg_idx); + put_u32(&buffer, vkd3d_make_u16(width, use_mask)); +@@ -2944,25 +3190,25 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, + i = 0; + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +- const char *semantic = var->semantic.name; ++ enum vkd3d_shader_sysval_semantic semantic; ++ const char *name = var->semantic.name; + size_t string_offset; +- D3D_NAME usage; + + if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic)) + continue; + +- hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage); +- if (usage == ~0u) ++ sysval_semantic_from_hlsl(&semantic, ctx, &var->semantic, output); ++ if (semantic == ~0u) + continue; + +- if (usage == D3D_NAME_TARGET && !ascii_strcasecmp(semantic, "color")) ++ if (semantic == VKD3D_SHADER_SV_TARGET && !ascii_strcasecmp(name, "color")) + string_offset = put_string(&buffer, "SV_Target"); +- else if (usage == D3D_NAME_DEPTH && !ascii_strcasecmp(semantic, "depth")) ++ else if (semantic == VKD3D_SHADER_SV_DEPTH && !ascii_strcasecmp(name, "depth")) + string_offset = put_string(&buffer, "SV_Depth"); +- else if (usage == D3D_NAME_POSITION && !ascii_strcasecmp(semantic, "position")) ++ else if (semantic == VKD3D_SHADER_SV_POSITION && !ascii_strcasecmp(name, "position")) + string_offset = put_string(&buffer, "SV_Position"); + else +- string_offset = put_string(&buffer, semantic); ++ string_offset = put_string(&buffer, name); + set_u32(&buffer, (2 + i++ * 6) * sizeof(uint32_t), string_offset); + } + +@@ -3123,24 +3369,24 @@ static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type) + vkd3d_unreachable(); + } + +-static D3D_RESOURCE_RETURN_TYPE sm4_resource_format(const struct hlsl_type *type) ++static enum vkd3d_sm4_data_type sm4_data_type(const struct hlsl_type *type) + { + switch (type->e.resource.format->e.numeric.type) + { + case HLSL_TYPE_DOUBLE: +- return D3D_RETURN_TYPE_DOUBLE; ++ return VKD3D_SM4_DATA_DOUBLE; + + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_HALF: +- return D3D_RETURN_TYPE_FLOAT; ++ return VKD3D_SM4_DATA_FLOAT; + + case HLSL_TYPE_INT: +- return D3D_RETURN_TYPE_SINT; ++ return VKD3D_SM4_DATA_INT; + break; + + case HLSL_TYPE_BOOL: + case HLSL_TYPE_UINT: +- return D3D_RETURN_TYPE_UINT; ++ return VKD3D_SM4_DATA_UINT; + + default: + vkd3d_unreachable(); +@@ -3471,7 +3717,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + { + unsigned int dimx = resource->component_type->e.resource.format->dimx; + +- put_u32(&buffer, sm4_resource_format(resource->component_type)); ++ put_u32(&buffer, sm4_data_type(resource->component_type)); + put_u32(&buffer, sm4_rdef_resource_dimension(resource->component_type)); + put_u32(&buffer, ~0u); /* FIXME: multisample count */ + flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; +@@ -4182,10 +4428,55 @@ static void sm4_write_src_register(const struct tpf_writer *tpf, const struct vk + } + } + ++static void sm4_update_stat_counters(const struct tpf_writer *tpf, const struct sm4_instruction *instr) ++{ ++ enum vkd3d_shader_type shader_type = tpf->ctx->profile->type; ++ enum vkd3d_sm4_stat_field stat_field; ++ uint32_t opcode; ++ ++ ++tpf->stat->fields[VKD3D_STAT_INSTR_COUNT]; ++ ++ opcode = instr->opcode & VKD3D_SM4_OPCODE_MASK; ++ stat_field = get_stat_field_from_sm4_opcode(&tpf->lookup, opcode); ++ ++ switch (opcode) ++ { ++ case VKD3D_SM4_OP_DCL_TEMPS: ++ tpf->stat->fields[stat_field] = max(tpf->stat->fields[stat_field], instr->idx[0]); ++ break; ++ case VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY: ++ case VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE: ++ tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM4_PRIMITIVE_TYPE_MASK) ++ >> VKD3D_SM4_PRIMITIVE_TYPE_SHIFT; ++ break; ++ case VKD3D_SM4_OP_DCL_VERTICES_OUT: ++ case VKD3D_SM5_OP_DCL_GS_INSTANCES: ++ tpf->stat->fields[stat_field] = instr->idx[0]; ++ break; ++ case VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN: ++ case VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING: ++ case VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: ++ tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM5_TESSELLATOR_MASK) >> VKD3D_SM5_TESSELLATOR_SHIFT; ++ break; ++ case VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT: ++ case VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT: ++ if ((shader_type == VKD3D_SHADER_TYPE_HULL && opcode == VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT) ++ || (shader_type == VKD3D_SHADER_TYPE_DOMAIN ++ && opcode == VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT)) ++ { ++ tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM5_CONTROL_POINT_COUNT_MASK) ++ >> VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT; ++ } ++ break; ++ default: ++ ++tpf->stat->fields[stat_field]; ++ } ++} ++ + static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4_instruction *instr) + { +- struct vkd3d_bytecode_buffer *buffer = tpf->buffer; + uint32_t token = instr->opcode | instr->extra_bits; ++ struct vkd3d_bytecode_buffer *buffer = tpf->buffer; + unsigned int size, i, j; + size_t token_position; + +@@ -4218,6 +4509,8 @@ static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4 + size = (bytecode_get_size(buffer) - token_position) / sizeof(uint32_t); + token |= (size << VKD3D_SM4_INSTRUCTION_LENGTH_SHIFT); + set_u32(buffer, token_position, token); ++ ++ sm4_update_stat_counters(tpf, instr); + } + + static bool encode_texel_offset_as_aoffimmi(struct sm4_instruction *instr, +@@ -4348,7 +4641,7 @@ static void write_sm4_dcl_textures(const struct tpf_writer *tpf, const struct ex + .dsts[0].reg.idx_count = 1, + .dst_count = 1, + +- .idx[0] = sm4_resource_format(component_type) * 0x1111, ++ .idx[0] = sm4_data_type(component_type) * 0x1111, + .idx_count = 1, + }; + +@@ -4412,7 +4705,7 @@ static void write_sm4_dcl_semantic(const struct tpf_writer *tpf, const struct hl + { + const struct hlsl_profile_info *profile = tpf->ctx->profile; + const bool output = var->is_output_semantic; +- D3D_NAME usage; ++ enum vkd3d_shader_sysval_semantic semantic; + bool has_idx; + + struct sm4_instruction instr = +@@ -4445,22 +4738,23 @@ static void write_sm4_dcl_semantic(const struct tpf_writer *tpf, const struct hl + if (instr.dsts[0].reg.type == VKD3DSPR_DEPTHOUT) + instr.dsts[0].reg.dimension = VSIR_DIMENSION_SCALAR; + +- hlsl_sm4_usage_from_semantic(tpf->ctx, &var->semantic, output, &usage); +- if (usage == ~0u) +- usage = D3D_NAME_UNDEFINED; ++ sysval_semantic_from_hlsl(&semantic, tpf->ctx, &var->semantic, output); ++ if (semantic == ~0u) ++ semantic = VKD3D_SHADER_SV_NONE; + + if (var->is_input_semantic) + { +- switch (usage) ++ switch (semantic) + { +- case D3D_NAME_UNDEFINED: ++ case VKD3D_SHADER_SV_NONE: + instr.opcode = (profile->type == VKD3D_SHADER_TYPE_PIXEL) + ? VKD3D_SM4_OP_DCL_INPUT_PS : VKD3D_SM4_OP_DCL_INPUT; + break; + +- case D3D_NAME_INSTANCE_ID: +- case D3D_NAME_PRIMITIVE_ID: +- case D3D_NAME_VERTEX_ID: ++ case VKD3D_SHADER_SV_INSTANCE_ID: ++ case VKD3D_SHADER_SV_PRIMITIVE_ID: ++ case VKD3D_SHADER_SV_VERTEX_ID: ++ case VKD3D_SHADER_SV_SAMPLE_INDEX: + instr.opcode = (profile->type == VKD3D_SHADER_TYPE_PIXEL) + ? VKD3D_SM4_OP_DCL_INPUT_PS_SGV : VKD3D_SM4_OP_DCL_INPUT_SGV; + break; +@@ -4510,25 +4804,25 @@ static void write_sm4_dcl_semantic(const struct tpf_writer *tpf, const struct hl + } + else + { +- if (usage == D3D_NAME_UNDEFINED || profile->type == VKD3D_SHADER_TYPE_PIXEL) ++ if (semantic == VKD3D_SHADER_SV_NONE || profile->type == VKD3D_SHADER_TYPE_PIXEL) + instr.opcode = VKD3D_SM4_OP_DCL_OUTPUT; + else + instr.opcode = VKD3D_SM4_OP_DCL_OUTPUT_SIV; + } + +- switch (usage) ++ switch (semantic) + { +- case D3D_NAME_COVERAGE: +- case D3D_NAME_DEPTH: +- case D3D_NAME_DEPTH_GREATER_EQUAL: +- case D3D_NAME_DEPTH_LESS_EQUAL: +- case D3D_NAME_TARGET: +- case D3D_NAME_UNDEFINED: ++ 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_TARGET: ++ case VKD3D_SHADER_SV_NONE: + break; + + default: + instr.idx_count = 1; +- instr.idx[0] = usage; ++ instr.idx[0] = semantic; + break; + } + +@@ -4577,6 +4871,17 @@ static void write_sm4_dcl_thread_group(const struct tpf_writer *tpf, const uint3 + write_sm4_instruction(tpf, &instr); + } + ++static void write_sm4_dcl_global_flags(const struct tpf_writer *tpf, uint32_t flags) ++{ ++ struct sm4_instruction instr = ++ { ++ .opcode = VKD3D_SM4_OP_DCL_GLOBAL_FLAGS, ++ .extra_bits = flags << VKD3D_SM4_GLOBAL_FLAGS_SHIFT, ++ }; ++ ++ write_sm4_instruction(tpf, &instr); ++} ++ + static void write_sm4_ret(const struct tpf_writer *tpf) + { + struct sm4_instruction instr = +@@ -5578,6 +5883,23 @@ static void write_sm4_expr(const struct tpf_writer *tpf, const struct hlsl_ir_ex + write_sm4_ternary_op(tpf, VKD3D_SM4_OP_MOVC, &expr->node, arg1, arg2, arg3); + break; + ++ case HLSL_OP3_MAD: ++ switch (dst_type->e.numeric.type) ++ { ++ case HLSL_TYPE_FLOAT: ++ write_sm4_ternary_op(tpf, VKD3D_SM4_OP_MAD, &expr->node, arg1, arg2, arg3); ++ break; ++ ++ case HLSL_TYPE_INT: ++ case HLSL_TYPE_UINT: ++ write_sm4_ternary_op(tpf, VKD3D_SM4_OP_IMAD, &expr->node, arg1, arg2, arg3); ++ break; ++ ++ default: ++ hlsl_fixme(tpf->ctx, &expr->node.loc, "SM4 %s negation expression.", dst_type_string->buffer); ++ } ++ break; ++ + default: + hlsl_fixme(tpf->ctx, &expr->node.loc, "SM4 %s expression.", debug_hlsl_expr_op(expr->op)); + } +@@ -5998,8 +6320,8 @@ static void write_sm4_block(const struct tpf_writer *tpf, const struct hlsl_bloc + } + } + +-static void write_sm4_shdr(struct hlsl_ctx *ctx, +- const struct hlsl_ir_function_decl *entry_func, struct dxbc_writer *dxbc) ++static void write_sm4_shdr(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *entry_func, ++ struct sm4_stat *stat, struct dxbc_writer *dxbc) + { + const struct hlsl_profile_info *profile = ctx->profile; + struct vkd3d_bytecode_buffer buffer = {0}; +@@ -6024,7 +6346,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + VKD3D_SM4_LIB, + }; + +- tpf_writer_init(&tpf, ctx, &buffer); ++ tpf_writer_init(&tpf, ctx, stat, &buffer); + + extern_resources = sm4_get_extern_resources(ctx, &extern_resources_count); + +@@ -6049,6 +6371,9 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, + write_sm4_dcl_textures(&tpf, resource, true); + } + ++ if (entry_func->early_depth_test && profile->major_version >= 5) ++ write_sm4_dcl_global_flags(&tpf, VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL); ++ + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if ((var->is_input_semantic && var->last_read) || (var->is_output_semantic && var->first_write)) +@@ -6110,14 +6435,64 @@ static void write_sm4_sfi0(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + /* FIXME: We also emit code that should require UAVS_AT_EVERY_STAGE, + * STENCIL_REF, and TYPED_UAV_LOAD_ADDITIONAL_FORMATS. */ + +- if (flags) ++ if (*flags) + dxbc_writer_add_section(dxbc, TAG_SFI0, flags, sizeof(*flags)); + else + vkd3d_free(flags); + } + ++static void write_sm4_stat(struct hlsl_ctx *ctx, const struct sm4_stat *stat, struct dxbc_writer *dxbc) ++{ ++ struct vkd3d_bytecode_buffer buffer = {0}; ++ ++ put_u32(&buffer, stat->fields[VKD3D_STAT_INSTR_COUNT]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_TEMPS]); ++ put_u32(&buffer, 0); /* Def count */ ++ put_u32(&buffer, 0); /* DCL count */ ++ put_u32(&buffer, stat->fields[VKD3D_STAT_FLOAT]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_INT]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_UINT]); ++ put_u32(&buffer, 0); /* Static flow control count */ ++ put_u32(&buffer, 0); /* Dynamic flow control count */ ++ put_u32(&buffer, 0); /* Macro instruction count */ ++ put_u32(&buffer, 0); /* Temp array count */ ++ put_u32(&buffer, 0); /* Array instr count */ ++ put_u32(&buffer, stat->fields[VKD3D_STAT_CUT]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_EMIT]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_LOAD]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE_C]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE_BIAS]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE_GRAD]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_MOV]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_MOVC]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_CONV]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_BITWISE]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_INPUT_PRIMITIVE]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_OUTPUT_TOPOLOGY]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_VERTICES_OUT]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_GATHER]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_LOD]); ++ put_u32(&buffer, 0); /* Sample frequency */ ++ ++ if (hlsl_version_ge(ctx, 5, 0)) ++ { ++ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_GS_INSTANCES]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_CONTROL_POINT_COUNT]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_OUTPUT_PRIMITIVE]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_PARTITIONING]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_DOMAIN]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_BARRIER]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_ATOMIC]); ++ put_u32(&buffer, stat->fields[VKD3D_STAT_STORE]); ++ } ++ ++ add_section(ctx, dxbc, TAG_STAT, &buffer); ++} ++ + int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) + { ++ struct sm4_stat stat = {0}; + struct dxbc_writer dxbc; + size_t i; + int ret; +@@ -6127,8 +6502,9 @@ int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun + write_sm4_signature(ctx, &dxbc, false); + write_sm4_signature(ctx, &dxbc, true); + write_sm4_rdef(ctx, &dxbc); +- write_sm4_shdr(ctx, entry_func, &dxbc); ++ write_sm4_shdr(ctx, entry_func, &stat, &dxbc); + write_sm4_sfi0(ctx, &dxbc); ++ write_sm4_stat(ctx, &stat, &dxbc); + + if (!(ret = ctx->result)) + ret = dxbc_writer_write(&dxbc, out); +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +index 306c1ca0dd8..fc217860403 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +@@ -23,6 +23,8 @@ + #include + #include + ++/* VKD3D_DEBUG_ENV_NAME("VKD3D_SHADER_DEBUG"); */ ++ + static inline int char_to_int(char c) + { + if ('0' <= c && c <= '9') +@@ -443,20 +445,47 @@ void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char + bytecode_set_bytes(buffer, offset, string, length); + } + +-static void vkd3d_shader_dump_blob(const char *path, const char *profile, +- const char *suffix, const void *data, size_t size) ++struct shader_dump_data ++{ ++ uint8_t checksum[16]; ++ const char *path; ++ const char *profile; ++ const char *source_suffix; ++ const char *target_suffix; ++}; ++ ++static void vkd3d_shader_dump_shader(const struct shader_dump_data *dump_data, ++ const void *data, size_t size, bool source) + { +- static unsigned int shader_id = 0; ++ static const char hexadecimal_digits[] = "0123456789abcdef"; ++ const uint8_t *checksum = dump_data->checksum; ++ char str_checksum[33]; ++ unsigned int pos = 0; + char filename[1024]; +- unsigned int id; ++ unsigned int i; + FILE *f; + +- id = vkd3d_atomic_increment_u32(&shader_id) - 1; ++ if (!dump_data->path) ++ return; ++ ++ for (i = 0; i < ARRAY_SIZE(dump_data->checksum); ++i) ++ { ++ str_checksum[2 * i] = hexadecimal_digits[checksum[i] >> 4]; ++ str_checksum[2 * i + 1] = hexadecimal_digits[checksum[i] & 0xf]; ++ } ++ str_checksum[32] = '\0'; + +- if (profile) +- snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u-%s.%s", path, id, profile, suffix); ++ pos = snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%s", dump_data->path, str_checksum); ++ ++ if (dump_data->profile) ++ pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-%s", dump_data->profile); ++ ++ if (source) ++ pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-source.%s", dump_data->source_suffix); + else +- snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u.%s", path, id, suffix); ++ pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-target.%s", dump_data->target_suffix); ++ ++ TRACE("Dumping shader to \"%s\".\n", filename); + if ((f = fopen(filename, "wb"))) + { + if (fwrite(data, 1, size, f) != size) +@@ -488,37 +517,61 @@ static const char *shader_get_source_type_suffix(enum vkd3d_shader_source_type t + } + } + +-void vkd3d_shader_dump_shader(const struct vkd3d_shader_compile_info *compile_info) ++static const char *shader_get_target_type_suffix(enum vkd3d_shader_target_type type) ++{ ++ switch (type) ++ { ++ case VKD3D_SHADER_TARGET_SPIRV_BINARY: ++ return "spv"; ++ case VKD3D_SHADER_TARGET_SPIRV_TEXT: ++ return "spv.s"; ++ case VKD3D_SHADER_TARGET_D3D_ASM: ++ return "d3d.s"; ++ case VKD3D_SHADER_TARGET_D3D_BYTECODE: ++ return "d3dbc"; ++ case VKD3D_SHADER_TARGET_DXBC_TPF: ++ return "dxbc"; ++ case VKD3D_SHADER_TARGET_GLSL: ++ return "glsl"; ++ case VKD3D_SHADER_TARGET_FX: ++ return "fx"; ++ case VKD3D_SHADER_TARGET_MSL: ++ return "msl"; ++ default: ++ FIXME("Unhandled target type %#x.\n", type); ++ return "bin"; ++ } ++} ++ ++static void fill_shader_dump_data(const struct vkd3d_shader_compile_info *compile_info, ++ struct shader_dump_data *data) + { +- 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; ++ ++ data->path = NULL; + + if (!enabled) + return; + +- if (!(path = getenv("VKD3D_SHADER_DUMP_PATH"))) ++ if (!(data->path = getenv("VKD3D_SHADER_DUMP_PATH"))) + { + enabled = false; + return; + } + ++ data->profile = NULL; + if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL) + { +- if (!(hlsl_source_info = vkd3d_find_struct(compile_info->next, HLSL_SOURCE_INFO))) +- return; ++ const struct vkd3d_shader_hlsl_source_info *hlsl_source_info; + +- if (!(profile = hlsl_get_target_info(hlsl_source_info->profile))) +- return; +- +- profile_name = profile->name; ++ if ((hlsl_source_info = vkd3d_find_struct(compile_info->next, HLSL_SOURCE_INFO))) ++ data->profile = hlsl_source_info->profile; + } + +- vkd3d_shader_dump_blob(path, profile_name, shader_get_source_type_suffix(compile_info->source_type), +- shader->code, shader->size); ++ vkd3d_compute_md5(compile_info->source.code, compile_info->source.size, ++ (uint32_t *)data->checksum, VKD3D_MD5_STANDARD); ++ data->source_suffix = shader_get_source_type_suffix(compile_info->source_type); ++ data->target_suffix = shader_get_target_type_suffix(compile_info->target_type); + } + + static void init_scan_signature_info(const struct vkd3d_shader_compile_info *info) +@@ -1497,6 +1550,7 @@ static int vsir_program_scan(struct vsir_program *program, const struct vkd3d_sh + int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char **messages) + { + struct vkd3d_shader_message_context message_context; ++ struct shader_dump_data dump_data; + int ret; + + TRACE("compile_info %p, messages %p.\n", compile_info, messages); +@@ -1511,7 +1565,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); ++ fill_shader_dump_data(compile_info, &dump_data); ++ vkd3d_shader_dump_shader(&dump_data, compile_info->source.code, compile_info->source.size, true); + + if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL) + { +@@ -1580,7 +1635,8 @@ int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, + case VKD3D_SHADER_TARGET_GLSL: + if ((ret = vsir_program_scan(program, &scan_info, message_context, &scan_descriptor_info)) < 0) + return ret; +- ret = glsl_compile(program, config_flags, compile_info, out, message_context); ++ ret = glsl_compile(program, config_flags, &scan_descriptor_info, ++ compile_info, out, message_context); + vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); + break; + +@@ -1593,6 +1649,10 @@ int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, + vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); + break; + ++ case VKD3D_SHADER_TARGET_MSL: ++ ret = msl_compile(program, config_flags, compile_info, message_context); ++ break; ++ + default: + /* Validation should prevent us from reaching this. */ + vkd3d_unreachable(); +@@ -1620,6 +1680,7 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, char **messages) + { + struct vkd3d_shader_message_context message_context; ++ struct shader_dump_data dump_data; + int ret; + + TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages); +@@ -1634,7 +1695,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); ++ fill_shader_dump_data(compile_info, &dump_data); ++ vkd3d_shader_dump_shader(&dump_data, compile_info->source.code, compile_info->source.size, true); + + if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL) + { +@@ -1676,6 +1738,8 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, + } + } + ++ vkd3d_shader_dump_shader(&dump_data, out->code, out->size, false); ++ + vkd3d_shader_message_context_trace_messages(&message_context); + if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) + ret = VKD3D_ERROR_OUT_OF_MEMORY; +@@ -1888,6 +1952,9 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( + VKD3D_SHADER_TARGET_D3D_ASM, + #ifdef VKD3D_SHADER_UNSUPPORTED_GLSL + VKD3D_SHADER_TARGET_GLSL, ++#endif ++#ifdef VKD3D_SHADER_UNSUPPORTED_MSL ++ VKD3D_SHADER_TARGET_MSL, + #endif + }; + +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index ef66a8ca07a..447210449da 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -80,6 +80,7 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_TPF_INVALID_CASE_VALUE = 1007, + VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION = 1008, + VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE = 1009, ++ VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL = 1010, + + VKD3D_SHADER_WARNING_TPF_MASK_NOT_CONTIGUOUS = 1300, + VKD3D_SHADER_WARNING_TPF_UNHANDLED_INDEX_RANGE_MASK = 1301, +@@ -152,6 +153,12 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_HLSL_UNKNOWN_MODIFIER = 5030, + VKD3D_SHADER_ERROR_HLSL_INVALID_STATE_BLOCK_ENTRY = 5031, + VKD3D_SHADER_ERROR_HLSL_FAILED_FORCED_UNROLL = 5032, ++ VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE = 5033, ++ VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE = 5034, ++ VKD3D_SHADER_ERROR_HLSL_INVALID_DOMAIN = 5035, ++ VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT = 5036, ++ VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE = 5037, ++ VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING = 5038, + + VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, + VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, +@@ -159,8 +166,10 @@ enum vkd3d_shader_error + VKD3D_SHADER_WARNING_HLSL_IMAGINARY_NUMERIC_RESULT = 5303, + VKD3D_SHADER_WARNING_HLSL_NON_FINITE_RESULT = 5304, + VKD3D_SHADER_WARNING_HLSL_IGNORED_ATTRIBUTE = 5305, ++ VKD3D_SHADER_WARNING_HLSL_IGNORED_DEFAULT_VALUE = 5306, + + VKD3D_SHADER_ERROR_GLSL_INTERNAL = 6000, ++ VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND = 6001, + + VKD3D_SHADER_ERROR_D3DBC_UNEXPECTED_EOF = 7000, + VKD3D_SHADER_ERROR_D3DBC_INVALID_VERSION_TOKEN = 7001, +@@ -169,6 +178,11 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY = 7004, + VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_INDEX = 7005, + VKD3D_SHADER_ERROR_D3DBC_UNDECLARED_SEMANTIC = 7006, ++ VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_TYPE = 7007, ++ VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT = 7008, ++ VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED = 7009, ++ VKD3D_SHADER_ERROR_D3DBC_INVALID_PROFILE = 7010, ++ VKD3D_SHADER_ERROR_D3DBC_INVALID_WRITEMASK = 7011, + + VKD3D_SHADER_WARNING_D3DBC_IGNORED_INSTRUCTION_FLAGS= 7300, + +@@ -227,6 +241,8 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_VSIR_INVALID_GS = 9019, + + VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300, ++ ++ VKD3D_SHADER_ERROR_MSL_INTERNAL = 10000, + }; + + enum vkd3d_shader_opcode +@@ -1344,8 +1360,6 @@ bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *ins + struct vkd3d_shader_immediate_constant_buffer *icb); + bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, + unsigned int dst, unsigned int src); +-struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( +- struct vkd3d_shader_instruction_array *instructions); + void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions); + + enum vkd3d_shader_config_flags +@@ -1353,6 +1367,12 @@ enum vkd3d_shader_config_flags + VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION = 0x00000001, + }; + ++enum vsir_control_flow_type ++{ ++ VSIR_CF_STRUCTURED, ++ VSIR_CF_BLOCKS, ++}; ++ + struct vsir_program + { + struct vkd3d_shader_version shader_version; +@@ -1372,6 +1392,7 @@ struct vsir_program + unsigned int temp_count; + unsigned int ssa_count; + bool use_vocp; ++ enum vsir_control_flow_type cf_type; + + const char **block_names; + size_t block_name_count; +@@ -1384,11 +1405,16 @@ int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_parameter1 *vsir_program_get_parameter( + const struct vsir_program *program, enum vkd3d_shader_parameter_name name); + bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, +- const struct vkd3d_shader_version *version, unsigned int reserve); +-enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, ++ const struct vkd3d_shader_version *version, unsigned int reserve, enum vsir_control_flow_type cf_type); ++enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); + enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, + const char *source_name, struct vkd3d_shader_message_context *message_context); ++struct vkd3d_shader_src_param *vsir_program_create_outpointid_param( ++ struct vsir_program *program); ++bool vsir_instruction_init_with_params(struct vsir_program *program, ++ struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, ++ enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count); + + static inline struct vkd3d_shader_dst_param *vsir_program_get_dst_params( + struct vsir_program *program, unsigned int count) +@@ -1549,7 +1575,6 @@ void vkd3d_shader_warning(struct vkd3d_shader_message_context *context, const st + 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(const struct vkd3d_shader_compile_info *compile_info); + uint64_t vkd3d_shader_init_config_flags(void); + void vkd3d_shader_trace_text_(const char *text, size_t size, const char *function); + #define vkd3d_shader_trace_text(text, size) \ +@@ -1570,8 +1595,9 @@ int shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, + struct vkd3d_shader_message_context *message_context, struct shader_signature *signature); + + int glsl_compile(struct vsir_program *program, uint64_t config_flags, +- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, +- struct vkd3d_shader_message_context *message_context); ++ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, ++ const struct vkd3d_shader_compile_info *compile_info, ++ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); + + #define SPIRV_MAX_SRC_COUNT 6 + +@@ -1580,7 +1606,16 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); + +-void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]); ++int msl_compile(struct vsir_program *program, uint64_t config_flags, ++ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); ++ ++enum vkd3d_md5_variant ++{ ++ VKD3D_MD5_STANDARD, ++ VKD3D_MD5_DXBC, ++}; ++ ++void vkd3d_compute_md5(const void *dxbc, size_t size, uint32_t checksum[4], enum vkd3d_md5_variant variant); + + int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); +@@ -1853,7 +1888,7 @@ static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain, + #define VKD3D_DXBC_HEADER_SIZE (8 * sizeof(uint32_t)) + #define VKD3D_DXBC_CHUNK_ALIGNMENT sizeof(uint32_t) + +-#define DXBC_MAX_SECTION_COUNT 5 ++#define DXBC_MAX_SECTION_COUNT 6 + + struct dxbc_writer + { +diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c +index dcc7690876f..eab0436bebd 100644 +--- a/libs/vkd3d/libs/vkd3d/command.c ++++ b/libs/vkd3d/libs/vkd3d/command.c +@@ -19,6 +19,7 @@ + */ + + #include "vkd3d_private.h" ++#include + + static void d3d12_fence_incref(struct d3d12_fence *fence); + static void d3d12_fence_decref(struct d3d12_fence *fence); +@@ -2451,6 +2452,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(ID3D12GraphicsCommandL + } + + list->is_recording = false; ++ list->has_depth_bounds = false; + + if (!list->is_valid) + { +@@ -2479,7 +2481,7 @@ static void d3d12_command_list_reset_state(struct d3d12_command_list *list, + list->fb_layer_count = 0; + + list->xfb_enabled = false; +- ++ list->has_depth_bounds = false; + list->is_predicated = false; + + list->current_framebuffer = VK_NULL_HANDLE; +@@ -3078,7 +3080,7 @@ done: + vkd3d_free(vk_descriptor_writes); + } + +-static void d3d12_command_list_update_descriptors(struct d3d12_command_list *list, ++static void d3d12_command_list_update_virtual_descriptors(struct d3d12_command_list *list, + enum vkd3d_pipeline_bind_point bind_point) + { + struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point]; +@@ -3210,6 +3212,9 @@ static void command_list_flush_vk_heap_updates(struct d3d12_command_list *list) + + static void command_list_add_descriptor_heap(struct d3d12_command_list *list, struct d3d12_descriptor_heap *heap) + { ++ if (!list->device->use_vk_heaps) ++ return; ++ + if (!contains_heap(list->descriptor_heaps, list->descriptor_heap_count, heap)) + { + if (list->descriptor_heap_count == ARRAY_SIZE(list->descriptor_heaps)) +@@ -3296,6 +3301,15 @@ static void d3d12_command_list_update_heap_descriptors(struct d3d12_command_list + d3d12_command_list_bind_descriptor_heap(list, bind_point, sampler_heap); + } + ++static void d3d12_command_list_update_descriptors(struct d3d12_command_list *list, ++ enum vkd3d_pipeline_bind_point bind_point) ++{ ++ if (list->device->use_vk_heaps) ++ d3d12_command_list_update_heap_descriptors(list, bind_point); ++ else ++ d3d12_command_list_update_virtual_descriptors(list, bind_point); ++} ++ + static bool d3d12_command_list_update_compute_state(struct d3d12_command_list *list) + { + d3d12_command_list_end_current_render_pass(list); +@@ -3303,7 +3317,7 @@ static bool d3d12_command_list_update_compute_state(struct d3d12_command_list *l + if (!d3d12_command_list_update_compute_pipeline(list)) + return false; + +- list->update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE); ++ d3d12_command_list_update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE); + + return true; + } +@@ -3320,7 +3334,7 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list + if (!d3d12_command_list_update_current_framebuffer(list)) + return false; + +- list->update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_GRAPHICS); ++ d3d12_command_list_update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_GRAPHICS); + + if (list->current_render_pass != VK_NULL_HANDLE) + return true; +@@ -3351,6 +3365,12 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list + list->xfb_enabled = true; + } + ++ if (graphics->ds_desc.depthBoundsTestEnable && !list->has_depth_bounds) ++ { ++ list->has_depth_bounds = true; ++ VK_CALL(vkCmdSetDepthBounds(list->vk_command_buffer, 0.0f, 1.0f)); ++ } ++ + return true; + } + +@@ -5939,7 +5959,25 @@ static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT64(ID3D12Gr + static void STDMETHODCALLTYPE d3d12_command_list_OMSetDepthBounds(ID3D12GraphicsCommandList6 *iface, + FLOAT min, FLOAT max) + { +- FIXME("iface %p, min %.8e, max %.8e stub!\n", iface, min, max); ++ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList6(iface); ++ const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; ++ ++ TRACE("iface %p, min %.8e, max %.8e.\n", iface, min, max); ++ ++ if (isnan(max)) ++ max = 0.0f; ++ if (isnan(min)) ++ min = 0.0f; ++ ++ if (!list->device->vk_info.EXT_depth_range_unrestricted && (min < 0.0f || min > 1.0f || max < 0.0f || max > 1.0f)) ++ { ++ WARN("VK_EXT_depth_range_unrestricted was not found, clamping depth bounds to 0.0 and 1.0.\n"); ++ max = vkd3d_clamp(max, 0.0f, 1.0f); ++ min = vkd3d_clamp(min, 0.0f, 1.0f); ++ } ++ ++ list->has_depth_bounds = true; ++ VK_CALL(vkCmdSetDepthBounds(list->vk_command_buffer, min, max)); + } + + static void STDMETHODCALLTYPE d3d12_command_list_SetSamplePositions(ID3D12GraphicsCommandList6 *iface, +@@ -6189,8 +6227,6 @@ static HRESULT d3d12_command_list_init(struct d3d12_command_list *list, struct d + + list->allocator = allocator; + +- list->update_descriptors = device->use_vk_heaps ? d3d12_command_list_update_heap_descriptors +- : d3d12_command_list_update_descriptors; + list->descriptor_heap_count = 0; + + if (SUCCEEDED(hr = d3d12_command_allocator_allocate_command_buffer(allocator, list))) +diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c +index 01841c89692..65339c7ba5d 100644 +--- a/libs/vkd3d/libs/vkd3d/device.c ++++ b/libs/vkd3d/libs/vkd3d/device.c +@@ -102,6 +102,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = + VK_EXTENSION(EXT_CALIBRATED_TIMESTAMPS, EXT_calibrated_timestamps), + VK_EXTENSION(EXT_CONDITIONAL_RENDERING, EXT_conditional_rendering), + VK_DEBUG_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker), ++ VK_EXTENSION(EXT_DEPTH_RANGE_UNRESTRICTED, EXT_depth_range_unrestricted), + VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable), + VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing), + VK_EXTENSION(EXT_FRAGMENT_SHADER_INTERLOCK, EXT_fragment_shader_interlock), +diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c +index 682d488faa8..ea7d8f040b5 100644 +--- a/libs/vkd3d/libs/vkd3d/state.c ++++ b/libs/vkd3d/libs/vkd3d/state.c +@@ -738,7 +738,7 @@ static bool vkd3d_validate_descriptor_set_count(struct d3d12_device *device, uns + if (set_count > max_count) + { + /* NOTE: If maxBoundDescriptorSets is < 9, try VKD3D_CONFIG=virtual_heaps */ +- ERR("Required descriptor set count exceeds maximum allowed count of %u.\n", max_count); ++ WARN("Required descriptor set count exceeds maximum allowed count of %u.\n", max_count); + return false; + } + +@@ -3867,6 +3867,7 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_BLEND_CONSTANTS, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, ++ VK_DYNAMIC_STATE_DEPTH_BOUNDS, + }; + static const VkPipelineDynamicStateCreateInfo dynamic_desc = + { +diff --git a/libs/vkd3d/libs/vkd3d/utils.c b/libs/vkd3d/libs/vkd3d/utils.c +index 831dc07af56..839bb173854 100644 +--- a/libs/vkd3d/libs/vkd3d/utils.c ++++ b/libs/vkd3d/libs/vkd3d/utils.c +@@ -703,7 +703,7 @@ const char *debug_vk_extent_3d(VkExtent3D extent) + + const char *debug_vk_queue_flags(VkQueueFlags flags) + { +- char buffer[159]; ++ char buffer[191]; + + buffer[0] = '\0'; + #define FLAG_TO_STR(f) if (flags & f) { strcat(buffer, " | "#f); flags &= ~f; } +@@ -715,6 +715,7 @@ const char *debug_vk_queue_flags(VkQueueFlags flags) + #undef FLAG_TO_STR + #define FLAG_TO_STR(f, n) if (flags & f) { strcat(buffer, " | "#n); flags &= ~f; } + FLAG_TO_STR(0x20, VK_QUEUE_VIDEO_DECODE_BIT_KHR) ++ FLAG_TO_STR(0x40, VK_QUEUE_VIDEO_ENCODE_BIT_KHR) + #undef FLAG_TO_STR + if (flags) + FIXME("Unrecognized flag(s) %#x.\n", flags); +diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h +index ba4e2e8488d..e6d477a5c12 100644 +--- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h ++++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h +@@ -131,6 +131,7 @@ struct vkd3d_vulkan_info + bool EXT_calibrated_timestamps; + bool EXT_conditional_rendering; + bool EXT_debug_marker; ++ bool EXT_depth_range_unrestricted; + bool EXT_depth_clip_enable; + bool EXT_descriptor_indexing; + bool EXT_fragment_shader_interlock; +@@ -1254,7 +1255,7 @@ struct d3d12_command_list + VkFormat dsv_format; + + bool xfb_enabled; +- ++ bool has_depth_bounds; + bool is_predicated; + + VkFramebuffer current_framebuffer; +@@ -1271,7 +1272,6 @@ struct d3d12_command_list + VkBuffer so_counter_buffers[D3D12_SO_BUFFER_SLOT_COUNT]; + VkDeviceSize so_counter_buffer_offsets[D3D12_SO_BUFFER_SLOT_COUNT]; + +- void (*update_descriptors)(struct d3d12_command_list *list, enum vkd3d_pipeline_bind_point bind_point); + struct d3d12_descriptor_heap *descriptor_heaps[64]; + unsigned int descriptor_heap_count; + +-- +2.45.2 + diff --git a/patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch b/patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch deleted file mode 100644 index 987d86ee..00000000 --- a/patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch +++ /dev/null @@ -1,1260 +0,0 @@ -From 2fef300f9d8c19f4344a90d842c109ad35d4b593 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Tue, 3 Sep 2024 07:18:49 +1000 -Subject: [PATCH] Updated vkd3d to 6d28cc131b0cad61c681aed6b9f6611a12b352d1. - ---- - libs/vkd3d/include/private/vkd3d_common.h | 2 +- - libs/vkd3d/libs/vkd3d-common/blob.c | 1 + - libs/vkd3d/libs/vkd3d-shader/checksum.c | 49 ++++--- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 40 +++--- - libs/vkd3d/libs/vkd3d-shader/dxbc.c | 19 ++- - libs/vkd3d/libs/vkd3d-shader/fx.c | 95 ++++++------ - libs/vkd3d/libs/vkd3d-shader/hlsl.h | 6 +- - libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 10 +- - libs/vkd3d/libs/vkd3d-shader/preproc.l | 1 + - libs/vkd3d/libs/vkd3d-shader/spirv.c | 66 ++++----- - libs/vkd3d/libs/vkd3d-shader/tpf.c | 136 +++++++++--------- - .../libs/vkd3d-shader/vkd3d_shader_main.c | 107 ++++++++++---- - .../libs/vkd3d-shader/vkd3d_shader_private.h | 9 +- - 13 files changed, 316 insertions(+), 225 deletions(-) - -diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h -index 39145a97df1..c62dc00415f 100644 ---- a/libs/vkd3d/include/private/vkd3d_common.h -+++ b/libs/vkd3d/include/private/vkd3d_common.h -@@ -273,7 +273,7 @@ static inline unsigned int vkd3d_popcount(unsigned int v) - { - #ifdef _MSC_VER - return __popcnt(v); --#elif defined(__MINGW32__) -+#elif defined(HAVE_BUILTIN_POPCOUNT) - return __builtin_popcount(v); - #else - v -= (v >> 1) & 0x55555555; -diff --git a/libs/vkd3d/libs/vkd3d-common/blob.c b/libs/vkd3d/libs/vkd3d-common/blob.c -index f60ef7db769..c2c6ad67804 100644 ---- a/libs/vkd3d/libs/vkd3d-common/blob.c -+++ b/libs/vkd3d/libs/vkd3d-common/blob.c -@@ -20,6 +20,7 @@ - #define WIDL_C_INLINE_WRAPPERS - #endif - #define COBJMACROS -+ - #define CONST_VTABLE - #include "vkd3d.h" - #include "vkd3d_blob.h" -diff --git a/libs/vkd3d/libs/vkd3d-shader/checksum.c b/libs/vkd3d/libs/vkd3d-shader/checksum.c -index d9560628c77..45de1c92513 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/checksum.c -+++ b/libs/vkd3d/libs/vkd3d-shader/checksum.c -@@ -33,6 +33,11 @@ - * will fill a supplied 16-byte array with the digest. - */ - -+/* -+ * DXBC uses a variation of the MD5 algorithm, which only changes the way -+ * the message is padded in the final step. -+ */ -+ - #include "vkd3d_shader_private.h" - - #define DXBC_CHECKSUM_BLOCK_SIZE 64 -@@ -230,10 +235,9 @@ static void md5_update(struct md5_ctx *ctx, const unsigned char *buf, unsigned i - memcpy(ctx->in, buf, len); - } - --static void dxbc_checksum_final(struct md5_ctx *ctx) -+static void md5_final(struct md5_ctx *ctx, enum vkd3d_md5_variant variant) - { - unsigned int padding; -- unsigned int length; - unsigned int count; - unsigned char *p; - -@@ -260,7 +264,7 @@ static void dxbc_checksum_final(struct md5_ctx *ctx) - /* Now fill the next block */ - memset(ctx->in, 0, DXBC_CHECKSUM_BLOCK_SIZE); - } -- else -+ else if (variant == VKD3D_MD5_DXBC) - { - /* Make place for bitcount at the beginning of the block */ - memmove(&ctx->in[4], ctx->in, count); -@@ -268,33 +272,44 @@ static void dxbc_checksum_final(struct md5_ctx *ctx) - /* Pad block to 60 bytes */ - memset(p + 4, 0, padding - 4); - } -+ else -+ { -+ /* Pad block to 56 bytes */ -+ memset(p, 0, padding - 8); -+ } - - /* Append length in bits and transform */ -- length = ctx->i[0]; -- memcpy(&ctx->in[0], &length, sizeof(length)); -- byte_reverse(&ctx->in[4], 14); -- length = ctx->i[0] >> 2 | 0x1; -- memcpy(&ctx->in[DXBC_CHECKSUM_BLOCK_SIZE - 4], &length, sizeof(length)); -+ if (variant == VKD3D_MD5_DXBC) -+ { -+ unsigned int length; -+ -+ length = ctx->i[0]; -+ memcpy(&ctx->in[0], &length, sizeof(length)); -+ byte_reverse(&ctx->in[4], 14); -+ length = ctx->i[0] >> 2 | 0x1; -+ memcpy(&ctx->in[DXBC_CHECKSUM_BLOCK_SIZE - 4], &length, sizeof(length)); -+ } -+ else -+ { -+ byte_reverse(ctx->in, 14); -+ -+ ((unsigned int *)ctx->in)[14] = ctx->i[0]; -+ ((unsigned int *)ctx->in)[15] = ctx->i[1]; -+ } - - md5_transform(ctx->buf, (unsigned int *)ctx->in); - byte_reverse((unsigned char *)ctx->buf, 4); - memcpy(ctx->digest, ctx->buf, 16); - } - --#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20 -- --void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]) -+void vkd3d_compute_md5(const void *data, size_t size, uint32_t checksum[4], enum vkd3d_md5_variant variant) - { -- const uint8_t *ptr = dxbc; -+ const uint8_t *ptr = data; - struct md5_ctx ctx; - -- VKD3D_ASSERT(size > DXBC_CHECKSUM_SKIP_BYTE_COUNT); -- ptr += DXBC_CHECKSUM_SKIP_BYTE_COUNT; -- size -= DXBC_CHECKSUM_SKIP_BYTE_COUNT; -- - md5_init(&ctx); - md5_update(&ctx, ptr, size); -- dxbc_checksum_final(&ctx); -+ md5_final(&ctx, variant); - - memcpy(checksum, ctx.digest, sizeof(ctx.digest)); - } -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index d05394c3ab7..1145a91f3e6 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -1423,32 +1423,32 @@ bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, - } - - bool hlsl_sm1_usage_from_semantic(const char *semantic_name, -- uint32_t semantic_index, D3DDECLUSAGE *usage, uint32_t *usage_idx) -+ uint32_t semantic_index, enum vkd3d_decl_usage *usage, uint32_t *usage_idx) - { - static const struct - { - const char *name; -- D3DDECLUSAGE usage; -+ enum vkd3d_decl_usage usage; - } - semantics[] = - { -- {"binormal", D3DDECLUSAGE_BINORMAL}, -- {"blendindices", D3DDECLUSAGE_BLENDINDICES}, -- {"blendweight", D3DDECLUSAGE_BLENDWEIGHT}, -- {"color", D3DDECLUSAGE_COLOR}, -- {"depth", D3DDECLUSAGE_DEPTH}, -- {"fog", D3DDECLUSAGE_FOG}, -- {"normal", D3DDECLUSAGE_NORMAL}, -- {"position", D3DDECLUSAGE_POSITION}, -- {"positiont", D3DDECLUSAGE_POSITIONT}, -- {"psize", D3DDECLUSAGE_PSIZE}, -- {"sample", D3DDECLUSAGE_SAMPLE}, -- {"sv_depth", D3DDECLUSAGE_DEPTH}, -- {"sv_position", D3DDECLUSAGE_POSITION}, -- {"sv_target", D3DDECLUSAGE_COLOR}, -- {"tangent", D3DDECLUSAGE_TANGENT}, -- {"tessfactor", D3DDECLUSAGE_TESSFACTOR}, -- {"texcoord", D3DDECLUSAGE_TEXCOORD}, -+ {"binormal", VKD3D_DECL_USAGE_BINORMAL}, -+ {"blendindices", VKD3D_DECL_USAGE_BLEND_INDICES}, -+ {"blendweight", VKD3D_DECL_USAGE_BLEND_WEIGHT}, -+ {"color", VKD3D_DECL_USAGE_COLOR}, -+ {"depth", VKD3D_DECL_USAGE_DEPTH}, -+ {"fog", VKD3D_DECL_USAGE_FOG}, -+ {"normal", VKD3D_DECL_USAGE_NORMAL}, -+ {"position", VKD3D_DECL_USAGE_POSITION}, -+ {"positiont", VKD3D_DECL_USAGE_POSITIONT}, -+ {"psize", VKD3D_DECL_USAGE_PSIZE}, -+ {"sample", VKD3D_DECL_USAGE_SAMPLE}, -+ {"sv_depth", VKD3D_DECL_USAGE_DEPTH}, -+ {"sv_position", VKD3D_DECL_USAGE_POSITION}, -+ {"sv_target", VKD3D_DECL_USAGE_COLOR}, -+ {"tangent", VKD3D_DECL_USAGE_TANGENT}, -+ {"tessfactor", VKD3D_DECL_USAGE_TESS_FACTOR}, -+ {"texcoord", VKD3D_DECL_USAGE_TEXCOORD}, - }; - - unsigned int i; -@@ -2203,8 +2203,8 @@ static void d3dbc_write_semantic_dcl(struct d3dbc_compiler *d3dbc, - const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; - struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; - struct sm1_dst_register reg = {0}; -+ enum vkd3d_decl_usage usage; - uint32_t token, usage_idx; -- D3DDECLUSAGE usage; - bool ret; - - if (hlsl_sm1_register_from_semantic(version, element->semantic_name, -diff --git a/libs/vkd3d/libs/vkd3d-shader/dxbc.c b/libs/vkd3d/libs/vkd3d-shader/dxbc.c -index 184788dc57e..93fc993e0d1 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/dxbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/dxbc.c -@@ -20,6 +20,19 @@ - - #include "vkd3d_shader_private.h" - -+#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20 -+ -+static void compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]) -+{ -+ const uint8_t *ptr = dxbc; -+ -+ VKD3D_ASSERT(size > DXBC_CHECKSUM_SKIP_BYTE_COUNT); -+ ptr += DXBC_CHECKSUM_SKIP_BYTE_COUNT; -+ size -= DXBC_CHECKSUM_SKIP_BYTE_COUNT; -+ -+ vkd3d_compute_md5(ptr, size, checksum, VKD3D_MD5_DXBC); -+} -+ - void dxbc_writer_init(struct dxbc_writer *dxbc) - { - memset(dxbc, 0, sizeof(*dxbc)); -@@ -72,7 +85,7 @@ int vkd3d_shader_serialize_dxbc(size_t section_count, const struct vkd3d_shader_ - } - set_u32(&buffer, size_position, bytecode_get_size(&buffer)); - -- vkd3d_compute_dxbc_checksum(buffer.data, buffer.size, checksum); -+ compute_dxbc_checksum(buffer.data, buffer.size, checksum); - for (i = 0; i < 4; ++i) - set_u32(&buffer, checksum_position + i * sizeof(uint32_t), checksum[i]); - -@@ -188,7 +201,7 @@ static int parse_dxbc(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_ - checksum[3] = read_u32(&ptr); - if (!(flags & VKD3D_SHADER_PARSE_DXBC_IGNORE_CHECKSUM)) - { -- vkd3d_compute_dxbc_checksum(data, data_size, calculated_checksum); -+ compute_dxbc_checksum(data, data_size, calculated_checksum); - if (memcmp(checksum, calculated_checksum, sizeof(checksum))) - { - WARN("Checksum {0x%08x, 0x%08x, 0x%08x, 0x%08x} does not match " -@@ -1488,7 +1501,7 @@ int vkd3d_shader_serialize_root_signature(const struct vkd3d_shader_versioned_ro - dxbc->code = context.buffer.data; - dxbc->size = total_size; - -- vkd3d_compute_dxbc_checksum(dxbc->code, dxbc->size, checksum); -+ compute_dxbc_checksum(dxbc->code, dxbc->size, checksum); - for (i = 0; i < 4; ++i) - set_u32(&context.buffer, (i + 1) * sizeof(uint32_t), checksum[i]); - -diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c -index a1d1fd6572f..e3ab71fb386 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/fx.c -+++ b/libs/vkd3d/libs/vkd3d-shader/fx.c -@@ -575,6 +575,12 @@ static const char * get_fx_4_type_name(const struct hlsl_type *type) - } - } - -+static bool is_numeric_fx_4_type(const struct hlsl_type *type) -+{ -+ type = hlsl_get_multiarray_element_type(type); -+ return type->class == HLSL_CLASS_STRUCT || hlsl_is_numeric_type(type); -+} -+ - static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx) - { - struct field_offsets -@@ -584,43 +590,41 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co - uint32_t offset; - uint32_t type; - }; -- uint32_t name_offset, offset, total_size, packed_size, stride, numeric_desc; -+ uint32_t name_offset, offset, unpacked_size, packed_size, stride, numeric_desc; - struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; - struct field_offsets *field_offsets = NULL; -+ const struct hlsl_type *element_type; - struct hlsl_ctx *ctx = fx->ctx; - uint32_t elements_count = 0; - const char *name; - size_t i; - -- /* Resolve arrays to element type and number of elements. */ - if (type->class == HLSL_CLASS_ARRAY) -- { - elements_count = hlsl_get_multiarray_size(type); -- type = hlsl_get_multiarray_element_type(type); -- } -+ element_type = hlsl_get_multiarray_element_type(type); - -- name = get_fx_4_type_name(type); -+ name = get_fx_4_type_name(element_type); - - name_offset = write_string(name, fx); -- if (type->class == HLSL_CLASS_STRUCT) -+ if (element_type->class == HLSL_CLASS_STRUCT) - { -- if (!(field_offsets = hlsl_calloc(ctx, type->e.record.field_count, sizeof(*field_offsets)))) -+ if (!(field_offsets = hlsl_calloc(ctx, element_type->e.record.field_count, sizeof(*field_offsets)))) - return 0; - -- for (i = 0; i < type->e.record.field_count; ++i) -+ for (i = 0; i < element_type->e.record.field_count; ++i) - { -- const struct hlsl_struct_field *field = &type->e.record.fields[i]; -+ const struct hlsl_struct_field *field = &element_type->e.record.fields[i]; - - field_offsets[i].name = write_string(field->name, fx); - field_offsets[i].semantic = write_string(field->semantic.raw_name, fx); -- field_offsets[i].offset = field->reg_offset[HLSL_REGSET_NUMERIC]; -+ field_offsets[i].offset = field->reg_offset[HLSL_REGSET_NUMERIC] * sizeof(float); - field_offsets[i].type = write_type(field->type, fx); - } - } - - offset = put_u32_unaligned(buffer, name_offset); - -- switch (type->class) -+ switch (element_type->class) - { - case HLSL_CLASS_SCALAR: - case HLSL_CLASS_VECTOR: -@@ -659,32 +663,32 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co - vkd3d_unreachable(); - - case HLSL_CLASS_VOID: -- FIXME("Writing type class %u is not implemented.\n", type->class); -+ FIXME("Writing type class %u is not implemented.\n", element_type->class); - set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); - return 0; - } - - /* Structures can only contain numeric fields, this is validated during variable declaration. */ -- total_size = stride = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); -+ unpacked_size = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); -+ - packed_size = 0; -- if (type->class == HLSL_CLASS_STRUCT || hlsl_is_numeric_type(type)) -- packed_size = hlsl_type_component_count(type) * sizeof(float); -+ if (is_numeric_fx_4_type(element_type)) -+ packed_size = hlsl_type_component_count(element_type) * sizeof(float); - if (elements_count) -- { -- total_size *= elements_count; - packed_size *= elements_count; -- } -+ -+ stride = element_type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); - stride = align(stride, 4 * sizeof(float)); - - put_u32_unaligned(buffer, elements_count); -- put_u32_unaligned(buffer, total_size); -+ put_u32_unaligned(buffer, unpacked_size); - put_u32_unaligned(buffer, stride); - put_u32_unaligned(buffer, packed_size); - -- if (type->class == HLSL_CLASS_STRUCT) -+ if (element_type->class == HLSL_CLASS_STRUCT) - { -- put_u32_unaligned(buffer, type->e.record.field_count); -- for (i = 0; i < type->e.record.field_count; ++i) -+ put_u32_unaligned(buffer, element_type->e.record.field_count); -+ for (i = 0; i < element_type->e.record.field_count; ++i) - { - const struct field_offsets *field = &field_offsets[i]; - -@@ -700,7 +704,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co - put_u32_unaligned(buffer, 0); /* Interface count */ - } - } -- else if (type->class == HLSL_CLASS_TEXTURE) -+ else if (element_type->class == HLSL_CLASS_TEXTURE) - { - static const uint32_t texture_type[] = - { -@@ -716,13 +720,13 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co - [HLSL_SAMPLER_DIM_CUBEARRAY] = 23, - }; - -- put_u32_unaligned(buffer, texture_type[type->sampler_dim]); -+ put_u32_unaligned(buffer, texture_type[element_type->sampler_dim]); - } -- else if (type->class == HLSL_CLASS_SAMPLER) -+ else if (element_type->class == HLSL_CLASS_SAMPLER) - { - put_u32_unaligned(buffer, 21); - } -- else if (type->class == HLSL_CLASS_UAV) -+ else if (element_type->class == HLSL_CLASS_UAV) - { - static const uint32_t uav_type[] = - { -@@ -735,60 +739,60 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co - [HLSL_SAMPLER_DIM_STRUCTURED_BUFFER] = 40, - }; - -- put_u32_unaligned(buffer, uav_type[type->sampler_dim]); -+ put_u32_unaligned(buffer, uav_type[element_type->sampler_dim]); - } -- else if (type->class == HLSL_CLASS_DEPTH_STENCIL_VIEW) -+ else if (element_type->class == HLSL_CLASS_DEPTH_STENCIL_VIEW) - { - put_u32_unaligned(buffer, 20); - } -- else if (type->class == HLSL_CLASS_RENDER_TARGET_VIEW) -+ else if (element_type->class == HLSL_CLASS_RENDER_TARGET_VIEW) - { - put_u32_unaligned(buffer, 19); - } -- else if (type->class == HLSL_CLASS_PIXEL_SHADER) -+ else if (element_type->class == HLSL_CLASS_PIXEL_SHADER) - { - put_u32_unaligned(buffer, 5); - } -- else if (type->class == HLSL_CLASS_VERTEX_SHADER) -+ else if (element_type->class == HLSL_CLASS_VERTEX_SHADER) - { - put_u32_unaligned(buffer, 6); - } -- else if (type->class == HLSL_CLASS_RASTERIZER_STATE) -+ else if (element_type->class == HLSL_CLASS_RASTERIZER_STATE) - { - put_u32_unaligned(buffer, 4); - } -- else if (type->class == HLSL_CLASS_DEPTH_STENCIL_STATE) -+ else if (element_type->class == HLSL_CLASS_DEPTH_STENCIL_STATE) - { - put_u32_unaligned(buffer, 3); - } -- else if (type->class == HLSL_CLASS_BLEND_STATE) -+ else if (element_type->class == HLSL_CLASS_BLEND_STATE) - { - put_u32_unaligned(buffer, 2); - } -- else if (type->class == HLSL_CLASS_STRING) -+ else if (element_type->class == HLSL_CLASS_STRING) - { - put_u32_unaligned(buffer, 1); - } -- else if (hlsl_is_numeric_type(type)) -+ else if (hlsl_is_numeric_type(element_type)) - { -- numeric_desc = get_fx_4_numeric_type_description(type, fx); -+ numeric_desc = get_fx_4_numeric_type_description(element_type, fx); - put_u32_unaligned(buffer, numeric_desc); - } -- else if (type->class == HLSL_CLASS_COMPUTE_SHADER) -+ else if (element_type->class == HLSL_CLASS_COMPUTE_SHADER) - { - put_u32_unaligned(buffer, 28); - } -- else if (type->class == HLSL_CLASS_HULL_SHADER) -+ else if (element_type->class == HLSL_CLASS_HULL_SHADER) - { - put_u32_unaligned(buffer, 29); - } -- else if (type->class == HLSL_CLASS_DOMAIN_SHADER) -+ else if (element_type->class == HLSL_CLASS_DOMAIN_SHADER) - { - put_u32_unaligned(buffer, 30); - } - else - { -- FIXME("Type %u is not supported.\n", type->class); -+ FIXME("Type %u is not supported.\n", element_type->class); - set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED); - } - -@@ -2126,7 +2130,7 @@ static unsigned int decompose_fx_4_state_function_call(struct hlsl_ir_var *var, - } - - /* For some states assignment sets all of the elements. This behaviour is limited to certain states of BlendState -- object, and only when fx_5_0 profile is used. */ -+ object, and only when fx_4_1 or fx_5_0 profile is used. */ - static unsigned int decompose_fx_4_state_block_expand_array(struct hlsl_ir_var *var, struct hlsl_state_block *block, - unsigned int entry_index, struct fx_write_context *fx) - { -@@ -2140,7 +2144,7 @@ static unsigned int decompose_fx_4_state_block_expand_array(struct hlsl_ir_var * - - if (type->class != HLSL_CLASS_BLEND_STATE) - return 1; -- if (ctx->profile->major_version != 5) -+ if (hlsl_version_lt(ctx, 4, 1)) - return 1; - if (entry->lhs_has_index) - return 1; -@@ -2401,6 +2405,9 @@ static void write_fx_4_buffer(struct hlsl_buffer *b, struct fx_write_context *fx - size = 0; - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { -+ if (!is_numeric_fx_4_type(var->data_type)) -+ continue; -+ - if (var->buffer != b) - continue; - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -index 22e25b23988..bf38c0cd945 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -@@ -1528,7 +1528,7 @@ D3DXPARAMETER_TYPE hlsl_sm1_base_type(const struct hlsl_type *type); - bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, const char *semantic_name, - unsigned int semantic_index, bool output, enum vkd3d_shader_register_type *type, unsigned int *reg); - bool hlsl_sm1_usage_from_semantic(const char *semantic_name, -- uint32_t semantic_index, D3DDECLUSAGE *usage, uint32_t *usage_idx); -+ uint32_t semantic_index, enum vkd3d_decl_usage *usage, uint32_t *usage_idx); - - void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer); - int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, -@@ -1536,8 +1536,8 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, - struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context, - struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func); - --bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, -- const struct hlsl_semantic *semantic, bool output, D3D_NAME *usage); -+bool sysval_semantic_from_hlsl(enum vkd3d_shader_sysval_semantic *semantic, -+ struct hlsl_ctx *ctx, const struct hlsl_semantic *hlsl_semantic, bool output); - bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, - bool output, enum vkd3d_shader_register_type *type, bool *has_idx); - int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out); -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -index 92b5c71c43f..154328a64c3 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -@@ -5128,7 +5128,7 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var - if (ctx->profile->major_version < 4) - { - struct vkd3d_shader_version version; -- D3DDECLUSAGE usage; -+ enum vkd3d_decl_usage usage; - uint32_t usage_idx; - - /* ps_1_* outputs are special and go in temp register 0. */ -@@ -5152,10 +5152,10 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var - } - else - { -- D3D_NAME usage; -+ enum vkd3d_shader_sysval_semantic semantic; - bool has_idx; - -- if (!hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage)) -+ if (!sysval_semantic_from_hlsl(&semantic, ctx, &var->semantic, output)) - { - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, - "Invalid semantic '%s'.", var->semantic.name); -@@ -5956,8 +5956,8 @@ static void sm1_generate_vsir_signature_entry(struct hlsl_ctx *ctx, - if (!hlsl_sm1_register_from_semantic(&program->shader_version, - var->semantic.name, var->semantic.index, output, &type, ®ister_index)) - { -+ enum vkd3d_decl_usage usage; - unsigned int usage_idx; -- D3DDECLUSAGE usage; - bool ret; - - register_index = var->regs[HLSL_REGSET_NUMERIC].id; -@@ -5969,7 +5969,7 @@ static void sm1_generate_vsir_signature_entry(struct hlsl_ctx *ctx, - * SV_Position; the closer equivalent is VPOS, which is not declared - * as a semantic. */ - if (program->shader_version.type == VKD3D_SHADER_TYPE_VERTEX -- && output && usage == D3DDECLUSAGE_POSITION) -+ && output && usage == VKD3D_DECL_USAGE_POSITION) - sysval = VKD3D_SHADER_SV_POSITION; - } - mask = (1 << var->data_type->dimx) - 1; -diff --git a/libs/vkd3d/libs/vkd3d-shader/preproc.l b/libs/vkd3d/libs/vkd3d-shader/preproc.l -index 2b7455a5c30..7fc963192cf 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/preproc.l -+++ b/libs/vkd3d/libs/vkd3d-shader/preproc.l -@@ -20,6 +20,7 @@ - - %{ - -+#include "preproc.h" - #include "preproc.tab.h" - - #undef ERROR /* defined in wingdi.h */ -diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c -index 49979ab2491..8052e951704 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/spirv.c -+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c -@@ -6120,12 +6120,12 @@ static void spirv_compiler_decorate_descriptor(struct spirv_compiler *compiler, - static uint32_t spirv_compiler_build_descriptor_variable(struct spirv_compiler *compiler, - SpvStorageClass storage_class, uint32_t type_id, const struct vkd3d_shader_register *reg, - const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type, -- bool is_uav, bool is_uav_counter, struct vkd3d_descriptor_variable_info *var_info) -+ const struct vkd3d_shader_descriptor_info1 *descriptor, bool is_uav_counter, -+ struct vkd3d_descriptor_variable_info *var_info) - { - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - struct vkd3d_descriptor_binding_address binding_address; - struct vkd3d_shader_descriptor_binding binding; -- const struct vkd3d_shader_descriptor_info1 *d; - uint32_t array_type_id, ptr_type_id, var_id; - bool write_only = false, coherent = false; - struct vkd3d_symbol symbol; -@@ -6135,12 +6135,11 @@ static uint32_t spirv_compiler_build_descriptor_variable(struct spirv_compiler * - resource_type, is_uav_counter, &binding_address); - var_info->binding_base_idx = binding_address.binding_base_idx; - -- if (is_uav) -+ if (descriptor->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV && !is_uav_counter) - { -- d = spirv_compiler_get_descriptor_info(compiler, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, range); -- write_only = !(d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ); -+ write_only = !(descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ); - /* ROVs are implicitly globally coherent. */ -- coherent = d->uav_flags & (VKD3DSUF_GLOBALLY_COHERENT | VKD3DSUF_RASTERISER_ORDERED_VIEW); -+ coherent = descriptor->uav_flags & (VKD3DSUF_GLOBALLY_COHERENT | VKD3DSUF_RASTERISER_ORDERED_VIEW); - } - - if (binding.count == 1 && range->first == binding_address.binding_base_idx && range->last != ~0u -@@ -6194,11 +6193,12 @@ static uint32_t spirv_compiler_build_descriptor_variable(struct spirv_compiler * - } - - static void spirv_compiler_emit_cbv_declaration(struct spirv_compiler *compiler, -- const struct vkd3d_shader_register_range *range, unsigned int register_id, unsigned int size_in_bytes) -+ const struct vkd3d_shader_register_range *range, const struct vkd3d_shader_descriptor_info1 *descriptor) - { - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t vec4_id, array_type_id, length_id, struct_id, var_id; - const SpvStorageClass storage_class = SpvStorageClassUniform; -+ unsigned int size_in_bytes = descriptor->buffer_size; - struct vkd3d_push_constant_buffer_binding *push_cb; - struct vkd3d_descriptor_variable_info var_info; - struct vkd3d_shader_register reg; -@@ -6206,7 +6206,7 @@ static void spirv_compiler_emit_cbv_declaration(struct spirv_compiler *compiler, - unsigned int size; - - vsir_register_init(®, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3); -- reg.idx[0].offset = register_id; -+ reg.idx[0].offset = descriptor->register_id; - reg.idx[1].offset = range->first; - reg.idx[2].offset = range->last; - -@@ -6239,7 +6239,7 @@ static void spirv_compiler_emit_cbv_declaration(struct spirv_compiler *compiler, - vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", size); - - var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, struct_id, -- ®, range, VKD3D_SHADER_RESOURCE_BUFFER, false, false, &var_info); -+ ®, range, VKD3D_SHADER_RESOURCE_BUFFER, descriptor, false, &var_info); - - vkd3d_symbol_make_register(®_symbol, ®); - vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, -@@ -6275,7 +6275,7 @@ static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compi - } - - static void spirv_compiler_emit_sampler_declaration(struct spirv_compiler *compiler, -- const struct vkd3d_shader_register_range *range, unsigned int register_id) -+ const struct vkd3d_shader_register_range *range, const struct vkd3d_shader_descriptor_info1 *descriptor) - { - const SpvStorageClass storage_class = SpvStorageClassUniformConstant; - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; -@@ -6285,7 +6285,7 @@ static void spirv_compiler_emit_sampler_declaration(struct spirv_compiler *compi - uint32_t type_id, var_id; - - vsir_register_init(®, VKD3DSPR_SAMPLER, VKD3D_DATA_FLOAT, 1); -- reg.idx[0].offset = register_id; -+ reg.idx[0].offset = descriptor->register_id; - - vkd3d_symbol_make_sampler(®_symbol, ®); - reg_symbol.info.sampler.range = *range; -@@ -6295,8 +6295,8 @@ static void spirv_compiler_emit_sampler_declaration(struct spirv_compiler *compi - return; - - type_id = vkd3d_spirv_get_op_type_sampler(builder); -- var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, type_id, ®, -- range, VKD3D_SHADER_RESOURCE_NONE, false, false, &var_info); -+ var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, type_id, -+ ®, range, VKD3D_SHADER_RESOURCE_NONE, descriptor, false, &var_info); - - vkd3d_symbol_make_register(®_symbol, ®); - vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, -@@ -6461,21 +6461,24 @@ static void spirv_compiler_emit_combined_sampler_declarations(struct spirv_compi - } - - static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *compiler, -- const struct vkd3d_shader_register_range *range, unsigned int register_id, -- unsigned int sample_count, bool is_uav, enum vkd3d_shader_resource_type resource_type, -- enum vkd3d_shader_resource_data_type resource_data_type, unsigned int structure_stride, bool raw) -+ const struct vkd3d_shader_register_range *range, const struct vkd3d_shader_descriptor_info1 *descriptor) - { -+ bool raw = descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER; -+ enum vkd3d_shader_resource_type resource_type = descriptor->resource_type; - struct vkd3d_descriptor_variable_info var_info, counter_var_info = {0}; -+ bool is_uav = descriptor->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; -+ unsigned int structure_stride = descriptor->structure_stride / 4; - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - SpvStorageClass storage_class = SpvStorageClassUniformConstant; - uint32_t counter_type_id, type_id, var_id, counter_var_id = 0; - const struct vkd3d_spirv_resource_type *resource_type_info; -+ unsigned int sample_count = descriptor->sample_count; - enum vkd3d_shader_component_type sampled_type; - struct vkd3d_symbol resource_symbol; - struct vkd3d_shader_register reg; - - vsir_register_init(®, is_uav ? VKD3DSPR_UAV : VKD3DSPR_RESOURCE, VKD3D_DATA_FLOAT, 1); -- reg.idx[0].offset = register_id; -+ reg.idx[0].offset = descriptor->register_id; - - if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS && sample_count == 1) - resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; -@@ -6489,7 +6492,7 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp - return; - } - -- sampled_type = vkd3d_component_type_from_resource_data_type(resource_data_type); -+ sampled_type = vkd3d_component_type_from_resource_data_type(descriptor->resource_data_type); - - if (!is_uav && spirv_compiler_has_combined_sampler_for_resource(compiler, range)) - { -@@ -6520,16 +6523,12 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp - resource_type_info, sampled_type, structure_stride || raw, 0); - } - -- var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, type_id, ®, -- range, resource_type, is_uav, false, &var_info); -+ var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, -+ type_id, ®, range, resource_type, descriptor, false, &var_info); - - if (is_uav) - { -- const struct vkd3d_shader_descriptor_info1 *d; -- -- d = spirv_compiler_get_descriptor_info(compiler, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, range); -- -- if (d->uav_flags & VKD3DSUF_RASTERISER_ORDERED_VIEW) -+ if (descriptor->uav_flags & VKD3DSUF_RASTERISER_ORDERED_VIEW) - { - if (compiler->shader_type != VKD3D_SHADER_TYPE_PIXEL) - spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE, -@@ -6543,7 +6542,7 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp - compiler->use_invocation_interlock = true; - } - -- if (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER) -+ if (descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER) - { - VKD3D_ASSERT(structure_stride); /* counters are valid only for structured buffers */ - -@@ -6571,7 +6570,7 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp - } - - counter_var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, -- type_id, ®, range, resource_type, false, true, &counter_var_info); -+ type_id, ®, range, resource_type, descriptor, true, &counter_var_info); - } - } - -@@ -10564,23 +10563,16 @@ static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *c - switch (descriptor->type) - { - case VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER: -- spirv_compiler_emit_sampler_declaration(compiler, &range, descriptor->register_id); -+ spirv_compiler_emit_sampler_declaration(compiler, &range, descriptor); - break; - - case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: -- spirv_compiler_emit_cbv_declaration(compiler, &range, descriptor->register_id, descriptor->buffer_size); -+ spirv_compiler_emit_cbv_declaration(compiler, &range, descriptor); - break; - - case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV: -- spirv_compiler_emit_resource_declaration(compiler, &range, descriptor->register_id, -- descriptor->sample_count, false, descriptor->resource_type, descriptor->resource_data_type, -- descriptor->structure_stride / 4, descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER); -- break; -- - case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV: -- spirv_compiler_emit_resource_declaration(compiler, &range, descriptor->register_id, -- descriptor->sample_count, true, descriptor->resource_type, descriptor->resource_data_type, -- descriptor->structure_stride / 4, descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER); -+ spirv_compiler_emit_resource_declaration(compiler, &range, descriptor); - break; - - default: -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index 84f641cc316..497a4c3b335 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -2782,8 +2782,8 @@ bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_sem - return false; - } - --bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, -- bool output, D3D_NAME *usage) -+bool sysval_semantic_from_hlsl(enum vkd3d_shader_sysval_semantic *semantic, -+ struct hlsl_ctx *ctx, const struct hlsl_semantic *hlsl_semantic, bool output) - { - unsigned int i; - -@@ -2792,7 +2792,7 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant - const char *name; - bool output; - enum vkd3d_shader_type shader_type; -- D3D_NAME usage; -+ enum vkd3d_shader_sysval_semantic semantic; - } - semantics[] = - { -@@ -2800,46 +2800,46 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant - {"sv_groupid", false, VKD3D_SHADER_TYPE_COMPUTE, ~0u}, - {"sv_groupthreadid", false, VKD3D_SHADER_TYPE_COMPUTE, ~0u}, - -- {"position", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, -- {"sv_position", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, -- {"sv_primitiveid", false, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_PRIMITIVE_ID}, -- -- {"position", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, -- {"sv_position", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_POSITION}, -- {"sv_primitiveid", true, VKD3D_SHADER_TYPE_GEOMETRY, D3D_NAME_PRIMITIVE_ID}, -- -- {"position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, -- {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, -- {"sv_primitiveid", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_PRIMITIVE_ID}, -- {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_IS_FRONT_FACE}, -- {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_RENDER_TARGET_ARRAY_INDEX}, -- {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_VIEWPORT_ARRAY_INDEX}, -- -- {"color", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET}, -- {"depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH}, -- {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET}, -- {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH}, -- {"sv_coverage", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_COVERAGE}, -- -- {"sv_position", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_UNDEFINED}, -- {"sv_vertexid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VERTEX_ID}, -- {"sv_instanceid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_INSTANCE_ID}, -- -- {"position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, -- {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, -- {"sv_rendertargetarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_RENDER_TARGET_ARRAY_INDEX}, -- {"sv_viewportarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VIEWPORT_ARRAY_INDEX}, -+ {"position", false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, -+ {"sv_position", false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, -+ {"sv_primitiveid", false, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_PRIMITIVE_ID}, -+ -+ {"position", true, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, -+ {"sv_position", true, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_POSITION}, -+ {"sv_primitiveid", true, VKD3D_SHADER_TYPE_GEOMETRY, VKD3D_SHADER_SV_PRIMITIVE_ID}, -+ -+ {"position", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_POSITION}, -+ {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_POSITION}, -+ {"sv_primitiveid", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_PRIMITIVE_ID}, -+ {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_IS_FRONT_FACE}, -+ {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX}, -+ {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX}, -+ -+ {"color", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_TARGET}, -+ {"depth", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_DEPTH}, -+ {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_TARGET}, -+ {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_DEPTH}, -+ {"sv_coverage", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_COVERAGE}, -+ -+ {"sv_position", false, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_NONE}, -+ {"sv_vertexid", false, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_VERTEX_ID}, -+ {"sv_instanceid", false, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_INSTANCE_ID}, -+ -+ {"position", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_POSITION}, -+ {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_POSITION}, -+ {"sv_rendertargetarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX}, -+ {"sv_viewportarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX}, - }; -- bool needs_compat_mapping = ascii_strncasecmp(semantic->name, "sv_", 3); -+ bool needs_compat_mapping = ascii_strncasecmp(hlsl_semantic->name, "sv_", 3); - - for (i = 0; i < ARRAY_SIZE(semantics); ++i) - { -- if (!ascii_strcasecmp(semantic->name, semantics[i].name) -+ if (!ascii_strcasecmp(hlsl_semantic->name, semantics[i].name) - && output == semantics[i].output - && (ctx->semantic_compat_mapping == needs_compat_mapping || !needs_compat_mapping) - && ctx->profile->type == semantics[i].shader_type) - { -- *usage = semantics[i].usage; -+ *semantic = semantics[i].semantic; - return true; - } - } -@@ -2847,7 +2847,7 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant - if (!needs_compat_mapping) - return false; - -- *usage = D3D_NAME_UNDEFINED; -+ *semantic = VKD3D_SHADER_SV_NONE; - return true; - } - -@@ -2880,16 +2880,16 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { - unsigned int width = (1u << var->data_type->dimx) - 1, use_mask; -+ enum vkd3d_shader_sysval_semantic semantic; - uint32_t usage_idx, reg_idx; -- D3D_NAME usage; - bool has_idx; - - if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic)) - continue; - -- ret = hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage); -+ ret = sysval_semantic_from_hlsl(&semantic, ctx, &var->semantic, output); - VKD3D_ASSERT(ret); -- if (usage == ~0u) -+ if (semantic == ~0u) - continue; - usage_idx = var->semantic.index; - -@@ -2908,12 +2908,12 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, - use_mask = 0xf ^ use_mask; - - /* Special pixel shader semantics (TARGET, DEPTH, COVERAGE). */ -- if (usage >= 64) -- usage = 0; -+ if (semantic >= VKD3D_SHADER_SV_TARGET) -+ semantic = VKD3D_SHADER_SV_NONE; - - put_u32(&buffer, 0); /* name */ - put_u32(&buffer, usage_idx); -- put_u32(&buffer, usage); -+ put_u32(&buffer, semantic); - switch (var->data_type->e.numeric.type) - { - case HLSL_TYPE_FLOAT: -@@ -2944,25 +2944,25 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, - i = 0; - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { -- const char *semantic = var->semantic.name; -+ enum vkd3d_shader_sysval_semantic semantic; -+ const char *name = var->semantic.name; - size_t string_offset; -- D3D_NAME usage; - - if ((output && !var->is_output_semantic) || (!output && !var->is_input_semantic)) - continue; - -- hlsl_sm4_usage_from_semantic(ctx, &var->semantic, output, &usage); -- if (usage == ~0u) -+ sysval_semantic_from_hlsl(&semantic, ctx, &var->semantic, output); -+ if (semantic == ~0u) - continue; - -- if (usage == D3D_NAME_TARGET && !ascii_strcasecmp(semantic, "color")) -+ if (semantic == VKD3D_SHADER_SV_TARGET && !ascii_strcasecmp(name, "color")) - string_offset = put_string(&buffer, "SV_Target"); -- else if (usage == D3D_NAME_DEPTH && !ascii_strcasecmp(semantic, "depth")) -+ else if (semantic == VKD3D_SHADER_SV_DEPTH && !ascii_strcasecmp(name, "depth")) - string_offset = put_string(&buffer, "SV_Depth"); -- else if (usage == D3D_NAME_POSITION && !ascii_strcasecmp(semantic, "position")) -+ else if (semantic == VKD3D_SHADER_SV_POSITION && !ascii_strcasecmp(name, "position")) - string_offset = put_string(&buffer, "SV_Position"); - else -- string_offset = put_string(&buffer, semantic); -+ string_offset = put_string(&buffer, name); - set_u32(&buffer, (2 + i++ * 6) * sizeof(uint32_t), string_offset); - } - -@@ -4412,7 +4412,7 @@ static void write_sm4_dcl_semantic(const struct tpf_writer *tpf, const struct hl - { - const struct hlsl_profile_info *profile = tpf->ctx->profile; - const bool output = var->is_output_semantic; -- D3D_NAME usage; -+ enum vkd3d_shader_sysval_semantic semantic; - bool has_idx; - - struct sm4_instruction instr = -@@ -4445,22 +4445,22 @@ static void write_sm4_dcl_semantic(const struct tpf_writer *tpf, const struct hl - if (instr.dsts[0].reg.type == VKD3DSPR_DEPTHOUT) - instr.dsts[0].reg.dimension = VSIR_DIMENSION_SCALAR; - -- hlsl_sm4_usage_from_semantic(tpf->ctx, &var->semantic, output, &usage); -- if (usage == ~0u) -- usage = D3D_NAME_UNDEFINED; -+ sysval_semantic_from_hlsl(&semantic, tpf->ctx, &var->semantic, output); -+ if (semantic == ~0u) -+ semantic = VKD3D_SHADER_SV_NONE; - - if (var->is_input_semantic) - { -- switch (usage) -+ switch (semantic) - { -- case D3D_NAME_UNDEFINED: -+ case VKD3D_SHADER_SV_NONE: - instr.opcode = (profile->type == VKD3D_SHADER_TYPE_PIXEL) - ? VKD3D_SM4_OP_DCL_INPUT_PS : VKD3D_SM4_OP_DCL_INPUT; - break; - -- case D3D_NAME_INSTANCE_ID: -- case D3D_NAME_PRIMITIVE_ID: -- case D3D_NAME_VERTEX_ID: -+ case VKD3D_SHADER_SV_INSTANCE_ID: -+ case VKD3D_SHADER_SV_PRIMITIVE_ID: -+ case VKD3D_SHADER_SV_VERTEX_ID: - instr.opcode = (profile->type == VKD3D_SHADER_TYPE_PIXEL) - ? VKD3D_SM4_OP_DCL_INPUT_PS_SGV : VKD3D_SM4_OP_DCL_INPUT_SGV; - break; -@@ -4510,25 +4510,25 @@ static void write_sm4_dcl_semantic(const struct tpf_writer *tpf, const struct hl - } - else - { -- if (usage == D3D_NAME_UNDEFINED || profile->type == VKD3D_SHADER_TYPE_PIXEL) -+ if (semantic == VKD3D_SHADER_SV_NONE || profile->type == VKD3D_SHADER_TYPE_PIXEL) - instr.opcode = VKD3D_SM4_OP_DCL_OUTPUT; - else - instr.opcode = VKD3D_SM4_OP_DCL_OUTPUT_SIV; - } - -- switch (usage) -+ switch (semantic) - { -- case D3D_NAME_COVERAGE: -- case D3D_NAME_DEPTH: -- case D3D_NAME_DEPTH_GREATER_EQUAL: -- case D3D_NAME_DEPTH_LESS_EQUAL: -- case D3D_NAME_TARGET: -- case D3D_NAME_UNDEFINED: -+ 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_TARGET: -+ case VKD3D_SHADER_SV_NONE: - break; - - default: - instr.idx_count = 1; -- instr.idx[0] = usage; -+ instr.idx[0] = semantic; - break; - } - -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -index 306c1ca0dd8..60be996ae24 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -@@ -23,6 +23,8 @@ - #include - #include - -+/* VKD3D_DEBUG_ENV_NAME("VKD3D_SHADER_DEBUG"); */ -+ - static inline int char_to_int(char c) - { - if ('0' <= c && c <= '9') -@@ -443,20 +445,47 @@ void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char - bytecode_set_bytes(buffer, offset, string, length); - } - --static void vkd3d_shader_dump_blob(const char *path, const char *profile, -- const char *suffix, const void *data, size_t size) -+struct shader_dump_data -+{ -+ uint8_t checksum[16]; -+ const char *path; -+ const char *profile; -+ const char *source_suffix; -+ const char *target_suffix; -+}; -+ -+static void vkd3d_shader_dump_shader(const struct shader_dump_data *dump_data, -+ const void *data, size_t size, bool source) - { -- static unsigned int shader_id = 0; -+ static const char hexadecimal_digits[] = "0123456789abcdef"; -+ const uint8_t *checksum = dump_data->checksum; -+ char str_checksum[33]; -+ unsigned int pos = 0; - char filename[1024]; -- unsigned int id; -+ unsigned int i; - FILE *f; - -- id = vkd3d_atomic_increment_u32(&shader_id) - 1; -+ if (!dump_data->path) -+ return; - -- if (profile) -- snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u-%s.%s", path, id, profile, suffix); -+ for (i = 0; i < ARRAY_SIZE(dump_data->checksum); ++i) -+ { -+ str_checksum[2 * i] = hexadecimal_digits[checksum[i] >> 4]; -+ str_checksum[2 * i + 1] = hexadecimal_digits[checksum[i] & 0xf]; -+ } -+ str_checksum[32] = '\0'; -+ -+ pos = snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%s", dump_data->path, str_checksum); -+ -+ if (dump_data->profile) -+ pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-%s", dump_data->profile); -+ -+ if (source) -+ pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-source.%s", dump_data->source_suffix); - else -- snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u.%s", path, id, suffix); -+ pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-target.%s", dump_data->target_suffix); -+ -+ TRACE("Dumping shader to \"%s\".\n", filename); - if ((f = fopen(filename, "wb"))) - { - if (fwrite(data, 1, size, f) != size) -@@ -488,37 +517,59 @@ static const char *shader_get_source_type_suffix(enum vkd3d_shader_source_type t - } - } - --void vkd3d_shader_dump_shader(const struct vkd3d_shader_compile_info *compile_info) -+static const char *shader_get_target_type_suffix(enum vkd3d_shader_target_type type) -+{ -+ switch (type) -+ { -+ case VKD3D_SHADER_TARGET_SPIRV_BINARY: -+ return "spv"; -+ case VKD3D_SHADER_TARGET_SPIRV_TEXT: -+ return "spv.s"; -+ case VKD3D_SHADER_TARGET_D3D_ASM: -+ return "d3d.s"; -+ case VKD3D_SHADER_TARGET_D3D_BYTECODE: -+ return "d3dbc"; -+ case VKD3D_SHADER_TARGET_DXBC_TPF: -+ return "dxbc"; -+ case VKD3D_SHADER_TARGET_GLSL: -+ return "glsl"; -+ case VKD3D_SHADER_TARGET_FX: -+ return "fx"; -+ default: -+ FIXME("Unhandled target type %#x.\n", type); -+ return "bin"; -+ } -+} -+ -+static void fill_shader_dump_data(const struct vkd3d_shader_compile_info *compile_info, -+ struct shader_dump_data *data) - { -- 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; -+ -+ data->path = NULL; - - if (!enabled) - return; - -- if (!(path = getenv("VKD3D_SHADER_DUMP_PATH"))) -+ if (!(data->path = getenv("VKD3D_SHADER_DUMP_PATH"))) - { - enabled = false; - return; - } - -+ data->profile = NULL; - 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; -+ const struct vkd3d_shader_hlsl_source_info *hlsl_source_info; - -- profile_name = profile->name; -+ if ((hlsl_source_info = vkd3d_find_struct(compile_info->next, HLSL_SOURCE_INFO))) -+ data->profile = hlsl_source_info->profile; - } - -- vkd3d_shader_dump_blob(path, profile_name, shader_get_source_type_suffix(compile_info->source_type), -- shader->code, shader->size); -+ vkd3d_compute_md5(compile_info->source.code, compile_info->source.size, -+ (uint32_t *)data->checksum, VKD3D_MD5_STANDARD); -+ data->source_suffix = shader_get_source_type_suffix(compile_info->source_type); -+ data->target_suffix = shader_get_target_type_suffix(compile_info->target_type); - } - - static void init_scan_signature_info(const struct vkd3d_shader_compile_info *info) -@@ -1497,6 +1548,7 @@ static int vsir_program_scan(struct vsir_program *program, const struct vkd3d_sh - int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char **messages) - { - struct vkd3d_shader_message_context message_context; -+ struct shader_dump_data dump_data; - int ret; - - TRACE("compile_info %p, messages %p.\n", compile_info, messages); -@@ -1511,7 +1563,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); -+ fill_shader_dump_data(compile_info, &dump_data); -+ vkd3d_shader_dump_shader(&dump_data, compile_info->source.code, compile_info->source.size, true); - - if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL) - { -@@ -1620,6 +1673,7 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, char **messages) - { - struct vkd3d_shader_message_context message_context; -+ struct shader_dump_data dump_data; - int ret; - - TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages); -@@ -1634,7 +1688,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); -+ fill_shader_dump_data(compile_info, &dump_data); -+ vkd3d_shader_dump_shader(&dump_data, compile_info->source.code, compile_info->source.size, true); - - if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL) - { -@@ -1676,6 +1731,8 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, - } - } - -+ vkd3d_shader_dump_shader(&dump_data, out->code, out->size, false); -+ - vkd3d_shader_message_context_trace_messages(&message_context); - if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) - ret = VKD3D_ERROR_OUT_OF_MEMORY; -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index ef66a8ca07a..442885f53b4 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -1549,7 +1549,6 @@ void vkd3d_shader_warning(struct vkd3d_shader_message_context *context, const st - 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(const struct vkd3d_shader_compile_info *compile_info); - uint64_t vkd3d_shader_init_config_flags(void); - void vkd3d_shader_trace_text_(const char *text, size_t size, const char *function); - #define vkd3d_shader_trace_text(text, size) \ -@@ -1580,7 +1579,13 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); - --void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]); -+enum vkd3d_md5_variant -+{ -+ VKD3D_MD5_STANDARD, -+ VKD3D_MD5_DXBC, -+}; -+ -+void vkd3d_compute_md5(const void *dxbc, size_t size, uint32_t checksum[4], enum vkd3d_md5_variant variant); - - int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); --- -2.45.2 - diff --git a/patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch b/patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch deleted file mode 100644 index 25935a4b..00000000 --- a/patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch +++ /dev/null @@ -1,2749 +0,0 @@ -From f04037713b67a027bb91fdb4c5424e629b189daa Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Thu, 5 Sep 2024 06:59:11 +1000 -Subject: [PATCH] Updated vkd3d to 0a6bcf5da78863cc6402756a429b21b623400790. - ---- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 495 ++++++----- - libs/vkd3d/libs/vkd3d-shader/hlsl.c | 205 ++++- - libs/vkd3d/libs/vkd3d-shader/hlsl.h | 69 ++ - libs/vkd3d/libs/vkd3d-shader/hlsl.l | 1 + - libs/vkd3d/libs/vkd3d-shader/hlsl.y | 274 +++++-- - libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 767 +++++++++++++++++- - .../libs/vkd3d-shader/hlsl_constant_ops.c | 20 +- - libs/vkd3d/libs/vkd3d-shader/ir.c | 2 +- - libs/vkd3d/libs/vkd3d-shader/spirv.c | 36 +- - libs/vkd3d/libs/vkd3d-shader/tpf.c | 24 +- - .../libs/vkd3d-shader/vkd3d_shader_private.h | 13 + - 11 files changed, 1555 insertions(+), 351 deletions(-) - -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index 1145a91f3e6..3b9ec98448d 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -1468,9 +1468,11 @@ bool hlsl_sm1_usage_from_semantic(const char *semantic_name, - - struct d3dbc_compiler - { -+ const struct vkd3d_sm1_opcode_info *opcode_table; - struct vsir_program *program; - struct vkd3d_bytecode_buffer buffer; - struct vkd3d_shader_message_context *message_context; -+ bool failed; - - /* OBJECTIVE: Store all the required information in the other fields so - * that this hlsl_ctx is no longer necessary. */ -@@ -2169,31 +2171,221 @@ static void d3dbc_write_cast(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - } - } - --static void d3dbc_write_constant_defs(struct d3dbc_compiler *d3dbc) -+static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info_from_vsir( -+ struct d3dbc_compiler *d3dbc, enum vkd3d_shader_opcode vkd3d_opcode) -+{ -+ const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; -+ const struct vkd3d_sm1_opcode_info *info; -+ unsigned int i = 0; -+ -+ for (;;) -+ { -+ info = &d3dbc->opcode_table[i++]; -+ if (info->vkd3d_opcode == VKD3DSIH_INVALID) -+ return NULL; -+ -+ if (vkd3d_opcode == info->vkd3d_opcode -+ && vkd3d_shader_ver_ge(version, info->min_version.major, info->min_version.minor) -+ && (vkd3d_shader_ver_le(version, info->max_version.major, info->max_version.minor) -+ || !info->max_version.major)) -+ return info; -+ } -+} -+ -+static uint32_t swizzle_from_vsir(uint32_t swizzle) -+{ -+ uint32_t x = vsir_swizzle_get_component(swizzle, 0); -+ uint32_t y = vsir_swizzle_get_component(swizzle, 1); -+ uint32_t z = vsir_swizzle_get_component(swizzle, 2); -+ uint32_t w = vsir_swizzle_get_component(swizzle, 3); -+ -+ if (x & ~0x3u || y & ~0x3u || z & ~0x3u || w & ~0x3u) -+ ERR("Unexpected vsir swizzle: 0x%08x.\n", swizzle); -+ -+ return ((x & 0x3u) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(0)) -+ | ((y & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(1)) -+ | ((z & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(2)) -+ | ((w & 0x3) << VKD3D_SM1_SWIZZLE_COMPONENT_SHIFT(3)); -+} -+ -+static void sm1_src_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_src_param *param, -+ struct sm1_src_register *src, const struct vkd3d_shader_location *loc) -+{ -+ src->mod = (uint32_t)param->modifiers << VKD3D_SM1_SRC_MODIFIER_SHIFT; -+ src->reg = param->reg.idx[0].offset; -+ src->type = param->reg.type; -+ src->swizzle = swizzle_from_vsir(param->swizzle); -+ -+ if (param->reg.idx[0].rel_addr) -+ { -+ vkd3d_shader_error(d3dbc->message_context, loc, VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED, -+ "Unhandled relative addressing on source register."); -+ d3dbc->failed = true; -+ } -+} -+ -+static void sm1_dst_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_dst_param *param, -+ struct sm1_dst_register *dst, const struct vkd3d_shader_location *loc) -+{ -+ dst->mod = (uint32_t)param->modifiers << VKD3D_SM1_DST_MODIFIER_SHIFT; -+ dst->reg = param->reg.idx[0].offset; -+ dst->type = param->reg.type; -+ dst->writemask = param->write_mask; -+ -+ if (param->reg.idx[0].rel_addr) -+ { -+ vkd3d_shader_error(d3dbc->message_context, loc, VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED, -+ "Unhandled relative addressing on destination register."); -+ d3dbc->failed = true; -+ } -+} -+ -+static void d3dbc_write_vsir_def(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) - { - const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; - struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; -- struct hlsl_ctx *ctx = d3dbc->ctx; -- unsigned int i, x; -+ uint32_t token; - -- for (i = 0; i < ctx->constant_defs.count; ++i) -+ const struct sm1_dst_register reg = - { -- const struct hlsl_constant_register *constant_reg = &ctx->constant_defs.regs[i]; -- uint32_t token = D3DSIO_DEF; -- const struct sm1_dst_register reg = -- { -- .type = VKD3DSPR_CONST, -- .writemask = VKD3DSP_WRITEMASK_ALL, -- .reg = constant_reg->index, -- }; -+ .type = VKD3DSPR_CONST, -+ .writemask = VKD3DSP_WRITEMASK_ALL, -+ .reg = ins->dst[0].reg.idx[0].offset, -+ }; -+ -+ token = VKD3D_SM1_OP_DEF; -+ if (version->major > 1) -+ token |= 5 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; -+ put_u32(buffer, token); - -- if (version->major > 1) -- token |= 5 << D3DSI_INSTLENGTH_SHIFT; -- put_u32(buffer, token); -+ write_sm1_dst_register(buffer, ®); -+ for (unsigned int x = 0; x < 4; ++x) -+ put_f32(buffer, ins->src[0].reg.u.immconst_f32[x]); -+} -+ -+static void d3dbc_write_vsir_sampler_dcl(struct d3dbc_compiler *d3dbc, -+ unsigned int reg_id, enum vkd3d_sm1_resource_type res_type) -+{ -+ const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; -+ struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; -+ struct sm1_dst_register reg = {0}; -+ uint32_t token; -+ -+ token = VKD3D_SM1_OP_DCL; -+ if (version->major > 1) -+ token |= 2 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; -+ put_u32(buffer, token); -+ -+ token = VKD3D_SM1_INSTRUCTION_PARAMETER; -+ token |= res_type << VKD3D_SM1_RESOURCE_TYPE_SHIFT; -+ put_u32(buffer, token); -+ -+ reg.type = VKD3DSPR_COMBINED_SAMPLER; -+ reg.writemask = VKD3DSP_WRITEMASK_ALL; -+ reg.reg = reg_id; -+ -+ write_sm1_dst_register(buffer, ®); -+} -+ -+static void d3dbc_write_vsir_dcl(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) -+{ -+ const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; -+ const struct vkd3d_shader_semantic *semantic = &ins->declaration.semantic; -+ unsigned int reg_id; - -- write_sm1_dst_register(buffer, ®); -- for (x = 0; x < 4; ++x) -- put_f32(buffer, constant_reg->value.f[x]); -+ if (version->major < 2) -+ return; -+ -+ reg_id = semantic->resource.reg.reg.idx[0].offset; -+ -+ if (semantic->resource.reg.reg.type != VKD3DSPR_SAMPLER) -+ { -+ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_TYPE, -+ "dcl instruction with register type %u.", semantic->resource.reg.reg.type); -+ d3dbc->failed = true; -+ return; -+ } -+ -+ switch (semantic->resource_type) -+ { -+ case VKD3D_SHADER_RESOURCE_TEXTURE_2D: -+ d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_2D); -+ break; -+ -+ case VKD3D_SHADER_RESOURCE_TEXTURE_CUBE: -+ d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_CUBE); -+ break; -+ -+ case VKD3D_SHADER_RESOURCE_TEXTURE_3D: -+ d3dbc_write_vsir_sampler_dcl(d3dbc, reg_id, VKD3D_SM1_RESOURCE_TEXTURE_3D); -+ break; -+ -+ default: -+ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_RESOURCE_TYPE, -+ "dcl instruction with resource_type %u.", semantic->resource_type); -+ d3dbc->failed = true; -+ return; -+ } -+} -+ -+static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, -+ const struct vkd3d_shader_instruction *ins) -+{ -+ const struct vkd3d_sm1_opcode_info *info; -+ struct sm1_instruction instr = {0}; -+ -+ info = shader_sm1_get_opcode_info_from_vsir(d3dbc, ins->opcode); -+ -+ if (ins->dst_count != info->dst_count) -+ { -+ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT, -+ "Invalid destination count %u for vsir instruction %#x (expected %u).", -+ ins->dst_count, ins->opcode, info->dst_count); -+ d3dbc->failed = true; -+ return; -+ } -+ if (ins->src_count != info->src_count) -+ { -+ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT, -+ "Invalid source count %u for vsir instruction %#x (expected %u).", -+ ins->src_count, ins->opcode, info->src_count); -+ d3dbc->failed = true; -+ return; -+ } -+ -+ instr.opcode = (D3DSHADER_INSTRUCTION_OPCODE_TYPE)info->sm1_opcode; -+ instr.has_dst = info->dst_count; -+ instr.src_count = info->src_count; -+ -+ if (instr.has_dst) -+ sm1_dst_reg_from_vsir(d3dbc, &ins->dst[0], &instr.dst, &ins->location); -+ for (unsigned int i = 0; i < instr.src_count; ++i) -+ sm1_src_reg_from_vsir(d3dbc, &ins->src[i], &instr.srcs[i], &ins->location); -+ -+ d3dbc_write_instruction(d3dbc, &instr); -+} -+ -+static void d3dbc_write_vsir_instruction(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) -+{ -+ switch (ins->opcode) -+ { -+ case VKD3DSIH_DEF: -+ d3dbc_write_vsir_def(d3dbc, ins); -+ break; -+ -+ case VKD3DSIH_DCL: -+ d3dbc_write_vsir_dcl(d3dbc, ins); -+ break; -+ -+ case VKD3DSIH_MOV: -+ d3dbc_write_vsir_simple_instruction(d3dbc, ins); -+ break; -+ -+ default: -+ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE, -+ "vsir instruction with opcode %#x.", ins->opcode); -+ d3dbc->failed = true; -+ break; - } - } - -@@ -2262,110 +2454,6 @@ static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc) - } - } - --static void d3dbc_write_sampler_dcl(struct d3dbc_compiler *d3dbc, -- unsigned int reg_id, enum hlsl_sampler_dim sampler_dim) --{ -- const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; -- struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; -- struct sm1_dst_register reg = {0}; -- uint32_t token, res_type = 0; -- -- token = D3DSIO_DCL; -- if (version->major > 1) -- token |= 2 << D3DSI_INSTLENGTH_SHIFT; -- put_u32(buffer, token); -- -- switch (sampler_dim) -- { -- case HLSL_SAMPLER_DIM_2D: -- res_type = VKD3D_SM1_RESOURCE_TEXTURE_2D; -- break; -- -- case HLSL_SAMPLER_DIM_CUBE: -- res_type = VKD3D_SM1_RESOURCE_TEXTURE_CUBE; -- break; -- -- case HLSL_SAMPLER_DIM_3D: -- res_type = VKD3D_SM1_RESOURCE_TEXTURE_3D; -- break; -- -- default: -- vkd3d_unreachable(); -- break; -- } -- -- token = (1u << 31); -- token |= res_type << VKD3D_SM1_RESOURCE_TYPE_SHIFT; -- put_u32(buffer, token); -- -- reg.type = VKD3DSPR_COMBINED_SAMPLER; -- reg.writemask = VKD3DSP_WRITEMASK_ALL; -- reg.reg = reg_id; -- -- write_sm1_dst_register(buffer, ®); --} -- --static void d3dbc_write_sampler_dcls(struct d3dbc_compiler *d3dbc) --{ -- const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; -- struct hlsl_ctx *ctx = d3dbc->ctx; -- enum hlsl_sampler_dim sampler_dim; -- unsigned int i, count, reg_id; -- struct hlsl_ir_var *var; -- -- if (version->major < 2) -- return; -- -- LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) -- { -- if (!var->regs[HLSL_REGSET_SAMPLERS].allocated) -- continue; -- -- count = var->bind_count[HLSL_REGSET_SAMPLERS]; -- -- for (i = 0; i < count; ++i) -- { -- if (var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) -- { -- sampler_dim = var->objects_usage[HLSL_REGSET_SAMPLERS][i].sampler_dim; -- if (sampler_dim == HLSL_SAMPLER_DIM_GENERIC) -- { -- /* These can appear in sm4-style combined sample instructions. */ -- hlsl_fixme(ctx, &var->loc, "Generic samplers need to be lowered."); -- continue; -- } -- -- reg_id = var->regs[HLSL_REGSET_SAMPLERS].index + i; -- d3dbc_write_sampler_dcl(d3dbc, reg_id, sampler_dim); -- } -- } -- } --} -- --static void d3dbc_write_constant(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- const struct hlsl_ir_constant *constant = hlsl_ir_constant(instr); -- struct sm1_instruction sm1_instr = -- { -- .opcode = D3DSIO_MOV, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.reg = instr->reg.id, -- .dst.writemask = instr->reg.writemask, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_CONST, -- .srcs[0].reg = constant->reg.id, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(constant->reg.writemask), -- .src_count = 1, -- }; -- -- VKD3D_ASSERT(instr->reg.allocated); -- VKD3D_ASSERT(constant->reg.allocated); -- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); -- d3dbc_write_instruction(d3dbc, &sm1_instr); --} -- - static void d3dbc_write_per_component_unary_op(struct d3dbc_compiler *d3dbc, - const struct hlsl_ir_node *instr, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode) - { -@@ -2636,50 +2724,6 @@ static void d3dbc_write_jump(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - } - } - --static void d3dbc_write_load(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- const struct hlsl_ir_load *load = hlsl_ir_load(instr); -- struct hlsl_ctx *ctx = d3dbc->ctx; -- const struct hlsl_reg reg = hlsl_reg_from_deref(ctx, &load->src); -- struct sm1_instruction sm1_instr = -- { -- .opcode = D3DSIO_MOV, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.reg = instr->reg.id, -- .dst.writemask = instr->reg.writemask, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].reg = reg.id, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(reg.writemask), -- .src_count = 1, -- }; -- -- VKD3D_ASSERT(instr->reg.allocated); -- -- if (load->src.var->is_uniform) -- { -- VKD3D_ASSERT(reg.allocated); -- sm1_instr.srcs[0].type = VKD3DSPR_CONST; -- } -- else if (load->src.var->is_input_semantic) -- { -- if (!hlsl_sm1_register_from_semantic(&d3dbc->program->shader_version, load->src.var->semantic.name, -- load->src.var->semantic.index, false, &sm1_instr.srcs[0].type, &sm1_instr.srcs[0].reg)) -- { -- VKD3D_ASSERT(reg.allocated); -- sm1_instr.srcs[0].type = VKD3DSPR_INPUT; -- sm1_instr.srcs[0].reg = reg.id; -- } -- else -- sm1_instr.srcs[0].swizzle = hlsl_swizzle_from_writemask((1 << load->src.var->data_type->dimx) - 1); -- } -- -- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); -- d3dbc_write_instruction(d3dbc, &sm1_instr); --} -- - static void d3dbc_write_resource_load(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) - { - const struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr); -@@ -2751,82 +2795,12 @@ static void d3dbc_write_resource_load(struct d3dbc_compiler *d3dbc, const struct - d3dbc_write_instruction(d3dbc, &sm1_instr); - } - --static void d3dbc_write_store(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; -- const struct hlsl_ir_store *store = hlsl_ir_store(instr); -- struct hlsl_ctx *ctx = d3dbc->ctx; -- const struct hlsl_reg reg = hlsl_reg_from_deref(ctx, &store->lhs); -- const struct hlsl_ir_node *rhs = store->rhs.node; -- struct sm1_instruction sm1_instr = -- { -- .opcode = D3DSIO_MOV, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.reg = reg.id, -- .dst.writemask = hlsl_combine_writemasks(reg.writemask, store->writemask), -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].reg = rhs->reg.id, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(rhs->reg.writemask), -- .src_count = 1, -- }; -- -- if (store->lhs.var->is_output_semantic) -- { -- if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major == 1) -- { -- sm1_instr.dst.type = VKD3DSPR_TEMP; -- sm1_instr.dst.reg = 0; -- } -- else if (!hlsl_sm1_register_from_semantic(&d3dbc->program->shader_version, store->lhs.var->semantic.name, -- store->lhs.var->semantic.index, true, &sm1_instr.dst.type, &sm1_instr.dst.reg)) -- { -- VKD3D_ASSERT(reg.allocated); -- sm1_instr.dst.type = VKD3DSPR_OUTPUT; -- sm1_instr.dst.reg = reg.id; -- } -- else -- sm1_instr.dst.writemask = (1u << store->lhs.var->data_type->dimx) - 1; -- } -- else -- VKD3D_ASSERT(reg.allocated); -- -- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); -- d3dbc_write_instruction(d3dbc, &sm1_instr); --} -- --static void d3dbc_write_swizzle(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- const struct hlsl_ir_swizzle *swizzle = hlsl_ir_swizzle(instr); -- const struct hlsl_ir_node *val = swizzle->val.node; -- struct sm1_instruction sm1_instr = -- { -- .opcode = D3DSIO_MOV, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.reg = instr->reg.id, -- .dst.writemask = instr->reg.writemask, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].reg = val->reg.id, -- .srcs[0].swizzle = hlsl_combine_swizzles(hlsl_swizzle_from_writemask(val->reg.writemask), -- swizzle->swizzle, instr->data_type->dimx), -- .src_count = 1, -- }; -- -- VKD3D_ASSERT(instr->reg.allocated); -- VKD3D_ASSERT(val->reg.allocated); -- sm1_map_src_swizzle(&sm1_instr.srcs[0], sm1_instr.dst.writemask); -- d3dbc_write_instruction(d3dbc, &sm1_instr); --} -- - static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block) - { -+ struct vkd3d_shader_instruction *vsir_instr; - struct hlsl_ctx *ctx = d3dbc->ctx; - const struct hlsl_ir_node *instr; -+ unsigned int vsir_instr_idx; - - LIST_FOR_EACH_ENTRY(instr, &block->instrs, struct hlsl_ir_node, entry) - { -@@ -2844,10 +2818,6 @@ static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_bl - case HLSL_IR_CALL: - vkd3d_unreachable(); - -- case HLSL_IR_CONSTANT: -- d3dbc_write_constant(d3dbc, instr); -- break; -- - case HLSL_IR_EXPR: - d3dbc_write_expr(d3dbc, instr); - break; -@@ -2863,20 +2833,14 @@ static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_bl - d3dbc_write_jump(d3dbc, instr); - break; - -- case HLSL_IR_LOAD: -- d3dbc_write_load(d3dbc, instr); -- break; -- - case HLSL_IR_RESOURCE_LOAD: - d3dbc_write_resource_load(d3dbc, instr); - break; - -- case HLSL_IR_STORE: -- d3dbc_write_store(d3dbc, instr); -- break; -- -- case HLSL_IR_SWIZZLE: -- d3dbc_write_swizzle(d3dbc, instr); -+ case HLSL_IR_VSIR_INSTRUCTION_REF: -+ vsir_instr_idx = hlsl_ir_vsir_instruction_ref(instr)->vsir_instr_idx; -+ vsir_instr = &d3dbc->program->instructions.elements[vsir_instr_idx]; -+ d3dbc_write_vsir_instruction(d3dbc, vsir_instr); - break; - - default: -@@ -2897,26 +2861,43 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_version *version = &program->shader_version; - struct d3dbc_compiler d3dbc = {0}; - struct vkd3d_bytecode_buffer *buffer = &d3dbc.buffer; -+ int result; - - d3dbc.ctx = ctx; - d3dbc.program = program; - d3dbc.message_context = message_context; -+ switch (version->type) -+ { -+ case VKD3D_SHADER_TYPE_VERTEX: -+ d3dbc.opcode_table = vs_opcode_table; -+ break; -+ -+ case VKD3D_SHADER_TYPE_PIXEL: -+ d3dbc.opcode_table = ps_opcode_table; -+ break; -+ -+ default: -+ vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_D3DBC_INVALID_PROFILE, -+ "Invalid shader type %u.", version->type); -+ return VKD3D_ERROR_INVALID_SHADER; -+ } - - put_u32(buffer, sm1_version(version->type, version->major, version->minor)); - - bytecode_put_bytes(buffer, ctab->code, ctab->size); - -- d3dbc_write_constant_defs(&d3dbc); - d3dbc_write_semantic_dcls(&d3dbc); -- d3dbc_write_sampler_dcls(&d3dbc); - d3dbc_write_block(&d3dbc, &entry_func->body); - - put_u32(buffer, D3DSIO_END); - -+ result = ctx->result; - if (buffer->status) -- ctx->result = buffer->status; -+ result = buffer->status; -+ if (d3dbc.failed) -+ result = VKD3D_ERROR_INVALID_SHADER; - -- if (!ctx->result) -+ if (!result) - { - out->code = buffer->data; - out->size = buffer->size; -@@ -2925,5 +2906,5 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, - { - vkd3d_free(buffer->data); - } -- return ctx->result; -+ return result; - } -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -index bd5baacd83d..6f737be2e2a 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -@@ -254,6 +254,45 @@ bool hlsl_type_is_resource(const struct hlsl_type *type) - } - } - -+bool hlsl_type_is_shader(const struct hlsl_type *type) -+{ -+ switch (type->class) -+ { -+ case HLSL_CLASS_ARRAY: -+ return hlsl_type_is_shader(type->e.array.type); -+ -+ case HLSL_CLASS_COMPUTE_SHADER: -+ case HLSL_CLASS_DOMAIN_SHADER: -+ case HLSL_CLASS_GEOMETRY_SHADER: -+ case HLSL_CLASS_HULL_SHADER: -+ case HLSL_CLASS_PIXEL_SHADER: -+ case HLSL_CLASS_VERTEX_SHADER: -+ return true; -+ -+ case HLSL_CLASS_SCALAR: -+ case HLSL_CLASS_VECTOR: -+ case HLSL_CLASS_MATRIX: -+ case HLSL_CLASS_STRUCT: -+ case HLSL_CLASS_DEPTH_STENCIL_STATE: -+ case HLSL_CLASS_DEPTH_STENCIL_VIEW: -+ case HLSL_CLASS_EFFECT_GROUP: -+ case HLSL_CLASS_PASS: -+ case HLSL_CLASS_RASTERIZER_STATE: -+ case HLSL_CLASS_RENDER_TARGET_VIEW: -+ case HLSL_CLASS_SAMPLER: -+ case HLSL_CLASS_STRING: -+ case HLSL_CLASS_TECHNIQUE: -+ case HLSL_CLASS_TEXTURE: -+ case HLSL_CLASS_UAV: -+ case HLSL_CLASS_CONSTANT_BUFFER: -+ case HLSL_CLASS_BLEND_STATE: -+ case HLSL_CLASS_VOID: -+ case HLSL_CLASS_NULL: -+ return false; -+ } -+ return false; -+} -+ - /* Only intended to be used for derefs (after copies have been lowered to components or vectors) or - * resources, since for both their data types span across a single regset. */ - static enum hlsl_regset type_get_regset(const struct hlsl_type *type) -@@ -1640,6 +1679,22 @@ struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node * - return &s->node; - } - -+struct hlsl_ir_node *hlsl_new_vsir_instruction_ref(struct hlsl_ctx *ctx, unsigned int vsir_instr_idx, -+ struct hlsl_type *type, const struct hlsl_reg *reg, const struct vkd3d_shader_location *loc) -+{ -+ struct hlsl_ir_vsir_instruction_ref *vsir_instr; -+ -+ if (!(vsir_instr = hlsl_alloc(ctx, sizeof(*vsir_instr)))) -+ return NULL; -+ init_node(&vsir_instr->node, HLSL_IR_VSIR_INSTRUCTION_REF, type, loc); -+ vsir_instr->vsir_instr_idx = vsir_instr_idx; -+ -+ if (reg) -+ vsir_instr->node.reg = *reg; -+ -+ return &vsir_instr->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) - { -@@ -1792,6 +1847,54 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned - return &swizzle->node; - } - -+struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name, -+ struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs, -+ const struct vkd3d_shader_location *loc) -+{ -+ const struct hlsl_profile_info *profile_info = NULL; -+ struct hlsl_ir_compile *compile; -+ struct hlsl_type *type = NULL; -+ unsigned int i; -+ -+ if (!(profile_info = hlsl_get_target_info(profile_name))) -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Unknown profile \"%s\".", profile_name); -+ return NULL; -+ } -+ -+ if (profile_info->type == VKD3D_SHADER_TYPE_PIXEL) -+ type = hlsl_get_type(ctx->cur_scope, "PixelShader", true, true); -+ else if (profile_info->type == VKD3D_SHADER_TYPE_VERTEX) -+ type = hlsl_get_type(ctx->cur_scope, "VertexShader", true, true); -+ -+ if (!type) -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile_name); -+ return NULL; -+ } -+ -+ if (!(compile = hlsl_alloc(ctx, sizeof(*compile)))) -+ return NULL; -+ -+ init_node(&compile->node, HLSL_IR_COMPILE, type, loc); -+ -+ compile->profile = profile_info; -+ -+ hlsl_block_init(&compile->instrs); -+ hlsl_block_add_block(&compile->instrs, args_instrs); -+ -+ compile->args_count = args_count; -+ if (!(compile->args = hlsl_alloc(ctx, sizeof(*compile->args) * args_count))) -+ { -+ vkd3d_free(compile); -+ return NULL; -+ } -+ for (i = 0; i < compile->args_count; ++i) -+ hlsl_src_from_node(&compile->args[i], args[i]); -+ -+ return &compile->node; -+} -+ - struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, - struct vkd3d_shader_location *loc) - { -@@ -2142,6 +2245,43 @@ static struct hlsl_ir_node *clone_index(struct hlsl_ctx *ctx, struct clone_instr - return dst; - } - -+static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, -+ struct clone_instr_map *map, struct hlsl_ir_compile *compile) -+{ -+ const char *profile_name = NULL; -+ struct hlsl_ir_node **args; -+ struct hlsl_ir_node *node; -+ struct hlsl_block block; -+ unsigned int i; -+ -+ if (!(clone_block(ctx, &block, &compile->instrs, map))) -+ return NULL; -+ -+ if (!(args = hlsl_alloc(ctx, sizeof(*args) * compile->args_count))) -+ { -+ hlsl_block_cleanup(&block); -+ return NULL; -+ } -+ for (i = 0; i < compile->args_count; ++i) -+ { -+ args[i] = map_instr(map, compile->args[i].node); -+ VKD3D_ASSERT(args[i]); -+ } -+ -+ if (compile->profile) -+ profile_name = compile->profile->name; -+ -+ if (!(node = hlsl_new_compile(ctx, profile_name, args, compile->args_count, &block, &compile->node.loc))) -+ { -+ hlsl_block_cleanup(&block); -+ vkd3d_free(args); -+ return NULL; -+ } -+ -+ vkd3d_free(args); -+ return node; -+} -+ - static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, - struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant) - { -@@ -2284,8 +2424,14 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, - case HLSL_IR_SWIZZLE: - return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr)); - -+ case HLSL_IR_COMPILE: -+ return clone_compile(ctx, map, hlsl_ir_compile(instr)); -+ - case HLSL_IR_STATEBLOCK_CONSTANT: - return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); -+ -+ case HLSL_IR_VSIR_INSTRUCTION_REF: -+ vkd3d_unreachable(); - } - - vkd3d_unreachable(); -@@ -2698,7 +2844,10 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) - [HLSL_IR_STORE ] = "HLSL_IR_STORE", - [HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH", - [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", -+ -+ [HLSL_IR_COMPILE] = "HLSL_IR_COMPILE", - [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", -+ [HLSL_IR_VSIR_INSTRUCTION_REF] = "HLSL_IR_VSIR_INSTRUCTION_REF", - }; - - if (type >= ARRAY_SIZE(names)) -@@ -3146,6 +3295,25 @@ static void dump_ir_index(struct vkd3d_string_buffer *buffer, const struct hlsl_ - vkd3d_string_buffer_printf(buffer, "]"); - } - -+static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, -+ const struct hlsl_ir_compile *compile) -+{ -+ unsigned int i; -+ -+ vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name); -+ -+ dump_block(ctx, buffer, &compile->instrs); -+ -+ vkd3d_string_buffer_printf(buffer, " %10s } (", ""); -+ for (i = 0; i < compile->args_count; ++i) -+ { -+ dump_src(buffer, &compile->args[i]); -+ if (i + 1 < compile->args_count) -+ vkd3d_string_buffer_printf(buffer, ", "); -+ } -+ vkd3d_string_buffer_printf(buffer, ")"); -+} -+ - static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer, - const struct hlsl_ir_stateblock_constant *constant) - { -@@ -3245,9 +3413,18 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, - dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr)); - break; - -+ case HLSL_IR_COMPILE: -+ dump_ir_compile(ctx, buffer, hlsl_ir_compile(instr)); -+ break; -+ - case HLSL_IR_STATEBLOCK_CONSTANT: - dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); - break; -+ -+ case HLSL_IR_VSIR_INSTRUCTION_REF: -+ vkd3d_string_buffer_printf(buffer, "vsir_program instruction %u", -+ hlsl_ir_vsir_instruction_ref(instr)->vsir_instr_idx); -+ break; - } - } - -@@ -3308,8 +3485,8 @@ void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new) - { - struct hlsl_src *src, *next; - -- VKD3D_ASSERT(old->data_type->dimx == new->data_type->dimx); -- VKD3D_ASSERT(old->data_type->dimy == new->data_type->dimy); -+ VKD3D_ASSERT(old->data_type == new->data_type || old->data_type->dimx == new->data_type->dimx); -+ VKD3D_ASSERT(old->data_type == new->data_type || old->data_type->dimy == new->data_type->dimy); - - LIST_FOR_EACH_ENTRY_SAFE(src, next, &old->uses, struct hlsl_src, entry) - { -@@ -3459,6 +3636,17 @@ static void free_ir_index(struct hlsl_ir_index *index) - vkd3d_free(index); - } - -+static void free_ir_compile(struct hlsl_ir_compile *compile) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < compile->args_count; ++i) -+ hlsl_src_remove(&compile->args[i]); -+ -+ hlsl_block_cleanup(&compile->instrs); -+ vkd3d_free(compile); -+} -+ - static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant) - { - vkd3d_free(constant->name); -@@ -3527,9 +3715,17 @@ void hlsl_free_instr(struct hlsl_ir_node *node) - free_ir_switch(hlsl_ir_switch(node)); - break; - -+ case HLSL_IR_COMPILE: -+ free_ir_compile(hlsl_ir_compile(node)); -+ break; -+ - case HLSL_IR_STATEBLOCK_CONSTANT: - free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node)); - break; -+ -+ case HLSL_IR_VSIR_INSTRUCTION_REF: -+ vkd3d_free(hlsl_ir_vsir_instruction_ref(node)); -+ break; - } - } - -@@ -4078,6 +4274,11 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compil - } - } - -+ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_INVALID; -+ ctx->output_control_point_count = UINT_MAX; -+ ctx->output_primitive = 0; -+ ctx->partitioning = 0; -+ - return true; - } - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -index bf38c0cd945..9bcba99efff 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -@@ -70,6 +70,14 @@ static inline unsigned int hlsl_swizzle_get_component(uint32_t swizzle, unsigned - return (swizzle >> HLSL_SWIZZLE_SHIFT(idx)) & HLSL_SWIZZLE_MASK; - } - -+static inline uint32_t vsir_swizzle_from_hlsl(uint32_t swizzle) -+{ -+ return vkd3d_shader_create_swizzle(hlsl_swizzle_get_component(swizzle, 0), -+ hlsl_swizzle_get_component(swizzle, 1), -+ hlsl_swizzle_get_component(swizzle, 2), -+ hlsl_swizzle_get_component(swizzle, 3)); -+} -+ - enum hlsl_type_class - { - HLSL_CLASS_SCALAR, -@@ -316,7 +324,11 @@ enum hlsl_ir_node_type - HLSL_IR_STORE, - HLSL_IR_SWIZZLE, - HLSL_IR_SWITCH, -+ -+ HLSL_IR_COMPILE, - HLSL_IR_STATEBLOCK_CONSTANT, -+ -+ HLSL_IR_VSIR_INSTRUCTION_REF, - }; - - /* Common data for every type of IR instruction node. */ -@@ -854,6 +866,27 @@ struct hlsl_ir_string_constant - char *string; - }; - -+/* Represents shader compilation call for effects, such as "CompileShader()". -+ * -+ * Unlike hlsl_ir_call, it is not flattened, thus, it keeps track of its -+ * arguments and maintains its own instruction block. */ -+struct hlsl_ir_compile -+{ -+ struct hlsl_ir_node node; -+ -+ /* Special field to store the profile argument. */ -+ const struct hlsl_profile_info *profile; -+ -+ /* Block containing the instructions required by the arguments of the -+ * compilation call. */ -+ struct hlsl_block instrs; -+ -+ /* Arguments to the compilation call. For a "compile" or "CompileShader()" -+ * args[0] is an hlsl_ir_call to the specified function. */ -+ struct hlsl_src *args; -+ unsigned int args_count; -+}; -+ - /* Stateblock constants are undeclared values found on state blocks or technique passes descriptions, - * that do not concern regular pixel, vertex, or compute shaders, except for parsing. */ - struct hlsl_ir_stateblock_constant -@@ -862,6 +895,16 @@ struct hlsl_ir_stateblock_constant - char *name; - }; - -+/* A vkd3d_shader_instruction that can be inserted in a hlsl_block. -+ * Only used for the HLSL IR to vsir translation, might be removed once this translation is complete. */ -+struct hlsl_ir_vsir_instruction_ref -+{ -+ struct hlsl_ir_node node; -+ -+ /* Index to a vkd3d_shader_instruction within a vkd3d_shader_instruction_array in a vsir_program. */ -+ unsigned int vsir_instr_idx; -+}; -+ - struct hlsl_scope - { - /* Item entry for hlsl_ctx.scopes. */ -@@ -1016,6 +1059,7 @@ struct hlsl_ctx - { - uint32_t index; - struct hlsl_vec4 value; -+ struct vkd3d_shader_location loc; - } *regs; - size_t count, size; - } constant_defs; -@@ -1029,6 +1073,12 @@ struct hlsl_ctx - * compute shader profiles. It is set using the numthreads() attribute in the entry point. */ - uint32_t thread_count[3]; - -+ enum vkd3d_tessellator_domain domain; -+ unsigned int output_control_point_count; -+ enum vkd3d_shader_tessellator_output_primitive output_primitive; -+ enum vkd3d_shader_tessellator_partitioning partitioning; -+ struct hlsl_ir_function_decl *patch_constant_func; -+ - /* In some cases we generate opcodes by parsing an HLSL function and then - * invoking it. If not NULL, this field is the name of the function that we - * are currently parsing, "mangled" with an internal prefix to avoid -@@ -1149,12 +1199,24 @@ static inline struct hlsl_ir_switch *hlsl_ir_switch(const struct hlsl_ir_node *n - return CONTAINING_RECORD(node, struct hlsl_ir_switch, node); - } - -+static inline struct hlsl_ir_compile *hlsl_ir_compile(const struct hlsl_ir_node *node) -+{ -+ VKD3D_ASSERT(node->type == HLSL_IR_COMPILE); -+ return CONTAINING_RECORD(node, struct hlsl_ir_compile, node); -+} -+ - static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(const struct hlsl_ir_node *node) - { - VKD3D_ASSERT(node->type == HLSL_IR_STATEBLOCK_CONSTANT); - return CONTAINING_RECORD(node, struct hlsl_ir_stateblock_constant, node); - } - -+static inline struct hlsl_ir_vsir_instruction_ref *hlsl_ir_vsir_instruction_ref(const struct hlsl_ir_node *node) -+{ -+ VKD3D_ASSERT(node->type == HLSL_IR_VSIR_INSTRUCTION_REF); -+ return CONTAINING_RECORD(node, struct hlsl_ir_vsir_instruction_ref, node); -+} -+ - static inline void hlsl_block_init(struct hlsl_block *block) - { - list_init(&block->instrs); -@@ -1428,6 +1490,9 @@ bool hlsl_index_is_noncontiguous(struct hlsl_ir_index *index); - bool hlsl_index_is_resource_access(struct hlsl_ir_index *index); - bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index); - -+struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name, -+ struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs, -+ const struct vkd3d_shader_location *loc); - struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val, - struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); - struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, -@@ -1466,6 +1531,9 @@ struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned - 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_node *hlsl_new_vsir_instruction_ref(struct hlsl_ctx *ctx, unsigned int vsir_instr_idx, -+ struct hlsl_type *type, const struct hlsl_reg *reg, 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); - void hlsl_fixme(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc, -@@ -1493,6 +1561,7 @@ unsigned int hlsl_type_minor_size(const struct hlsl_type *type); - unsigned int hlsl_type_major_size(const struct hlsl_type *type); - unsigned int hlsl_type_element_count(const struct hlsl_type *type); - bool hlsl_type_is_resource(const struct hlsl_type *type); -+bool hlsl_type_is_shader(const struct hlsl_type *type); - unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset); - bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2); - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.l b/libs/vkd3d/libs/vkd3d-shader/hlsl.l -index 0c02b27817e..e5472709a8c 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.l -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.l -@@ -80,6 +80,7 @@ centroid {return KW_CENTROID; } - column_major {return KW_COLUMN_MAJOR; } - ComputeShader {return KW_COMPUTESHADER; } - compile {return KW_COMPILE; } -+CompileShader {return KW_COMPILESHADER; } - const {return KW_CONST; } - continue {return KW_CONTINUE; } - DepthStencilState {return KW_DEPTHSTENCILSTATE; } -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -index 3f319dea0d8..816d992afa8 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -@@ -516,7 +516,7 @@ enum loop_type - LOOP_DO_WHILE - }; - --static bool attribute_list_has_duplicates(const struct parse_attribute_list *attrs) -+static void check_attribute_list_for_duplicates(struct hlsl_ctx *ctx, const struct parse_attribute_list *attrs) - { - unsigned int i, j; - -@@ -525,11 +525,10 @@ static bool attribute_list_has_duplicates(const struct parse_attribute_list *att - for (j = i + 1; j < attrs->count; ++j) - { - if (!strcmp(attrs->attrs[i]->name, attrs->attrs[j]->name)) -- return true; -+ hlsl_error(ctx, &attrs->attrs[j]->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, -+ "Found duplicate attribute \"%s\".", attrs->attrs[j]->name); - } - } -- -- return false; - } - - static void resolve_loop_continue(struct hlsl_ctx *ctx, struct hlsl_block *block, enum loop_type type, -@@ -628,10 +627,13 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx - case HLSL_IR_RESOURCE_LOAD: - case HLSL_IR_RESOURCE_STORE: - case HLSL_IR_SWITCH: -+ case HLSL_IR_COMPILE: - case HLSL_IR_STATEBLOCK_CONSTANT: - hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, - "Expected literal expression."); - break; -+ case HLSL_IR_VSIR_INSTRUCTION_REF: -+ vkd3d_unreachable(); - } - } - -@@ -697,9 +699,7 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type, - unsigned int i, unroll_limit = 0; - struct hlsl_ir_node *loop; - -- if (attribute_list_has_duplicates(attributes)) -- hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Found duplicate attribute."); -- -+ check_attribute_list_for_duplicates(ctx, attributes); - check_loop_attributes(ctx, attributes, loc); - - /* Ignore unroll(0) attribute, and any invalid attribute. */ -@@ -2733,13 +2733,15 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var - - if (v->initializer.args_count) - { -- unsigned int store_index = 0; - bool is_default_values_initializer; -+ unsigned int store_index = 0; - unsigned int size, k; - - is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) - || (var->storage_modifiers & HLSL_STORAGE_UNIFORM) - || ctx->cur_scope->annotations; -+ if (hlsl_type_is_shader(type)) -+ is_default_values_initializer = false; - - if (is_default_values_initializer) - { -@@ -2835,28 +2837,36 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var - return initializers; - } - --static bool func_is_compatible_match(struct hlsl_ctx *ctx, -- const struct hlsl_ir_function_decl *decl, const struct parse_initializer *args) -+static bool func_is_compatible_match(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *decl, -+ bool is_compile, const struct parse_initializer *args) - { -- unsigned int i; -- -- if (decl->parameters.count < args->args_count) -- return false; -+ unsigned int i, k; - -- for (i = 0; i < args->args_count; ++i) -+ k = 0; -+ for (i = 0; i < decl->parameters.count; ++i) - { -- if (!implicit_compatible_data_types(ctx, args->args[i]->data_type, decl->parameters.vars[i]->data_type)) -+ if (is_compile && !(decl->parameters.vars[i]->storage_modifiers & HLSL_STORAGE_UNIFORM)) -+ continue; -+ -+ if (k >= args->args_count) -+ { -+ if (!decl->parameters.vars[i]->default_values) -+ return false; -+ return true; -+ } -+ -+ if (!implicit_compatible_data_types(ctx, args->args[k]->data_type, decl->parameters.vars[i]->data_type)) - return false; -- } - -- if (args->args_count < decl->parameters.count && !decl->parameters.vars[args->args_count]->default_values) -+ ++k; -+ } -+ if (k < args->args_count) - return false; -- - return true; - } - - static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, -- const char *name, const struct parse_initializer *args, -+ const char *name, const struct parse_initializer *args, bool is_compile, - const struct vkd3d_shader_location *loc) - { - struct hlsl_ir_function_decl *decl, *compatible_match = NULL; -@@ -2869,7 +2879,7 @@ static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, - - LIST_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry) - { -- if (func_is_compatible_match(ctx, decl, args)) -+ if (func_is_compatible_match(ctx, decl, is_compile, args)) - { - if (compatible_match) - { -@@ -2890,26 +2900,35 @@ static struct hlsl_ir_node *hlsl_new_void_expr(struct hlsl_ctx *ctx, const struc - return hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc); - } - --static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, -- const struct parse_initializer *args, const struct vkd3d_shader_location *loc) -+static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx, -+ struct hlsl_ir_function_decl *func, const struct parse_initializer *args, -+ bool is_compile, const struct vkd3d_shader_location *loc) - { - struct hlsl_ir_node *call; -- unsigned int i, j; -+ unsigned int i, j, k; - - VKD3D_ASSERT(args->args_count <= func->parameters.count); - -- for (i = 0; i < args->args_count; ++i) -+ k = 0; -+ for (i = 0; i < func->parameters.count; ++i) - { - struct hlsl_ir_var *param = func->parameters.vars[i]; -- struct hlsl_ir_node *arg = args->args[i]; -+ struct hlsl_ir_node *arg; -+ -+ if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM)) -+ continue; -+ -+ if (k >= args->args_count) -+ break; -+ arg = args->args[k]; - - if (!hlsl_types_are_equal(arg->data_type, param->data_type)) - { - struct hlsl_ir_node *cast; - - if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc))) -- return false; -- args->args[i] = cast; -+ return NULL; -+ args->args[k] = cast; - arg = cast; - } - -@@ -2918,13 +2937,15 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu - struct hlsl_ir_node *store; - - if (!(store = hlsl_new_simple_store(ctx, param, arg))) -- return false; -+ return NULL; - hlsl_block_add_instr(args->instrs, store); - } -+ -+ ++k; - } - - /* Add default values for the remaining parameters. */ -- for (i = args->args_count; i < func->parameters.count; ++i) -+ for (; i < func->parameters.count; ++i) - { - struct hlsl_ir_var *param = func->parameters.vars[i]; - unsigned int comp_count = hlsl_type_component_count(param->data_type); -@@ -2932,6 +2953,9 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu - - VKD3D_ASSERT(param->default_values); - -+ if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM)) -+ continue; -+ - hlsl_init_simple_deref_from_var(¶m_deref, param); - - for (j = 0; j < comp_count; ++j) -@@ -2945,20 +2969,23 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu - { - value.u[0] = param->default_values[j].number; - if (!(comp = hlsl_new_constant(ctx, type, &value, loc))) -- return false; -+ return NULL; - hlsl_block_add_instr(args->instrs, comp); - - if (!hlsl_new_store_component(ctx, &store_block, ¶m_deref, j, comp)) -- return false; -+ return NULL; - hlsl_block_add_block(args->instrs, &store_block); - } - } - } - - if (!(call = hlsl_new_call(ctx, func, loc))) -- return false; -+ return NULL; - hlsl_block_add_instr(args->instrs, call); - -+ if (is_compile) -+ return call; -+ - for (i = 0; i < args->args_count; ++i) - { - struct hlsl_ir_var *param = func->parameters.vars[i]; -@@ -2973,11 +3000,11 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu - "Output argument to \"%s\" is const.", func->func->name); - - if (!(load = hlsl_new_var_load(ctx, param, &arg->loc))) -- return false; -+ return NULL; - hlsl_block_add_instr(args->instrs, &load->node); - - if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &load->node)) -- return false; -+ return NULL; - } - } - -@@ -2998,7 +3025,7 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu - hlsl_block_add_instr(args->instrs, expr); - } - -- return true; -+ return call; - } - - static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, -@@ -3165,7 +3192,7 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_acos(struct hlsl_ctx *ctx, -@@ -3314,7 +3341,7 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_atan(struct hlsl_ctx *ctx, -@@ -3507,7 +3534,7 @@ static bool write_cosh_or_sinh(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_cosh(struct hlsl_ctx *ctx, -@@ -3734,7 +3761,7 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_distance(struct hlsl_ctx *ctx, -@@ -3766,6 +3793,50 @@ static bool intrinsic_dot(struct hlsl_ctx *ctx, - return !!add_binary_dot_expr(ctx, params->instrs, params->args[0], params->args[1], loc); - } - -+static bool intrinsic_dst(struct hlsl_ctx *ctx, const struct parse_initializer *params, -+ const struct vkd3d_shader_location *loc) -+{ -+ struct hlsl_ir_function_decl *func; -+ struct hlsl_type *type, *vec4_type; -+ char *body; -+ -+ static const char template[] = -+ "%s dst(%s i0, %s i1)\n" -+ "{\n" -+ /* Scalars and vector-4s are both valid inputs, so promote scalars -+ * if necessary. */ -+ " %s src0 = i0, src1 = i1;\n" -+ " return %s(1, src0.y * src1.y, src0.z, src1.w);\n" -+ "}"; -+ -+ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) -+ return false; -+ type = params->args[0]->data_type; -+ if (!(type->class == HLSL_CLASS_SCALAR -+ || (type->class == HLSL_CLASS_VECTOR && type->dimx == 4))) -+ { -+ struct vkd3d_string_buffer *string; -+ if ((string = hlsl_type_to_string(ctx, type))) -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, -+ "Wrong dimension for dst(): expected scalar or 4-dimensional vector, but got %s.", -+ string->buffer); -+ hlsl_release_string_buffer(ctx, string); -+ } -+ vec4_type = hlsl_get_vector_type(ctx, type->e.numeric.type, 4); -+ -+ if (!(body = hlsl_sprintf_alloc(ctx, template, -+ vec4_type->name, type->name, type->name, -+ vec4_type->name, -+ vec4_type->name))) -+ return false; -+ func = hlsl_compile_internal_function(ctx, "dst", body); -+ vkd3d_free(body); -+ if (!func) -+ return false; -+ -+ return !!add_user_call(ctx, func, params, false, loc); -+} -+ - static bool intrinsic_exp(struct hlsl_ctx *ctx, - const struct parse_initializer *params, const struct vkd3d_shader_location *loc) - { -@@ -3821,7 +3892,7 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_f16tof32(struct hlsl_ctx *ctx, -@@ -3926,7 +3997,7 @@ static bool intrinsic_fwidth(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_ldexp(struct hlsl_ctx *ctx, -@@ -4029,7 +4100,7 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, - if (!(func = hlsl_compile_internal_function(ctx, "lit", body))) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_log(struct hlsl_ctx *ctx, -@@ -4332,7 +4403,7 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_round(struct hlsl_ctx *ctx, -@@ -4415,6 +4486,35 @@ static bool intrinsic_sin(struct hlsl_ctx *ctx, - return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_SIN, arg, loc); - } - -+static bool intrinsic_sincos(struct hlsl_ctx *ctx, -+ const struct parse_initializer *params, const struct vkd3d_shader_location *loc) -+{ -+ struct hlsl_ir_function_decl *func; -+ struct hlsl_type *type; -+ char *body; -+ -+ static const char template[] = -+ "void sincos(%s f, out %s s, out %s c)\n" -+ "{\n" -+ " s = sin(f);\n" -+ " c = cos(f);\n" -+ "}"; -+ -+ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) -+ return false; -+ type = params->args[0]->data_type; -+ -+ if (!(body = hlsl_sprintf_alloc(ctx, template, -+ type->name, type->name, type->name))) -+ return false; -+ func = hlsl_compile_internal_function(ctx, "sincos", body); -+ vkd3d_free(body); -+ if (!func) -+ return false; -+ -+ return !!add_user_call(ctx, func, params, false, loc); -+} -+ - static bool intrinsic_sinh(struct hlsl_ctx *ctx, - const struct parse_initializer *params, const struct vkd3d_shader_location *loc) - { -@@ -4447,7 +4547,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_sqrt(struct hlsl_ctx *ctx, -@@ -4523,7 +4623,7 @@ static bool intrinsic_tanh(struct hlsl_ctx *ctx, - if (!func) - return false; - -- return add_user_call(ctx, func, params, loc); -+ return !!add_user_call(ctx, func, params, false, loc); - } - - static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, -@@ -4937,6 +5037,7 @@ intrinsic_functions[] = - {"determinant", 1, true, intrinsic_determinant}, - {"distance", 2, true, intrinsic_distance}, - {"dot", 2, true, intrinsic_dot}, -+ {"dst", 2, true, intrinsic_dst}, - {"exp", 1, true, intrinsic_exp}, - {"exp2", 1, true, intrinsic_exp2}, - {"f16tof32", 1, true, intrinsic_f16tof32}, -@@ -4966,6 +5067,7 @@ intrinsic_functions[] = - {"saturate", 1, true, intrinsic_saturate}, - {"sign", 1, true, intrinsic_sign}, - {"sin", 1, true, intrinsic_sin}, -+ {"sincos", 3, true, intrinsic_sincos}, - {"sinh", 1, true, intrinsic_sinh}, - {"smoothstep", 3, true, intrinsic_smoothstep}, - {"sqrt", 1, true, intrinsic_sqrt}, -@@ -5002,9 +5104,9 @@ static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name, - struct intrinsic_function *intrinsic; - struct hlsl_ir_function_decl *decl; - -- if ((decl = find_function_call(ctx, name, args, loc))) -+ if ((decl = find_function_call(ctx, name, args, false, loc))) - { -- if (!add_user_call(ctx, decl, args, loc)) -+ if (!add_user_call(ctx, decl, args, false, loc)) - goto fail; - } - else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions), -@@ -5060,6 +5162,53 @@ fail: - return NULL; - } - -+static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const char *profile_name, -+ const char *function_name, struct parse_initializer *args, const struct vkd3d_shader_location *loc) -+{ -+ struct hlsl_ir_node *compile, *call_to_compile = NULL; -+ struct hlsl_ir_function_decl *decl; -+ -+ if (!ctx->in_state_block && ctx->cur_scope != ctx->globals) -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE, -+ "Shader compilation statements must be in global scope or a state block."); -+ free_parse_initializer(args); -+ return NULL; -+ } -+ -+ if (!(decl = find_function_call(ctx, function_name, args, true, loc))) -+ { -+ if (rb_get(&ctx->functions, function_name)) -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, -+ "No compatible \"%s\" declaration with %u uniform parameters found.", -+ function_name, args->args_count); -+ } -+ else -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, -+ "Function \"%s\" is not defined.", function_name); -+ } -+ free_parse_initializer(args); -+ return NULL; -+ } -+ -+ if (!(call_to_compile = add_user_call(ctx, decl, args, true, loc))) -+ { -+ free_parse_initializer(args); -+ return NULL; -+ } -+ -+ if (!(compile = hlsl_new_compile(ctx, profile_name, &call_to_compile, 1, args->instrs, loc))) -+ { -+ free_parse_initializer(args); -+ return NULL; -+ } -+ -+ free_parse_initializer(args); -+ return make_block(ctx, compile); -+} -+ - static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, - struct parse_initializer *params, const struct vkd3d_shader_location *loc) - { -@@ -6058,6 +6207,7 @@ static bool state_block_add_entry(struct hlsl_state_block *state_block, struct h - %token KW_CENTROID - %token KW_COLUMN_MAJOR - %token KW_COMPILE -+%token KW_COMPILESHADER - %token KW_COMPUTESHADER - %token KW_CONST - %token KW_CONTINUE -@@ -6827,6 +6977,8 @@ func_prototype: - func_prototype_no_attrs - | attribute_list func_prototype_no_attrs - { -+ check_attribute_list_for_duplicates(ctx, &$1); -+ - if ($2.first) - { - $2.decl->attr_count = $1.count; -@@ -8092,8 +8244,7 @@ selection_statement: - struct hlsl_ir_node *instr; - unsigned int i; - -- if (attribute_list_has_duplicates(attributes)) -- hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Found duplicate attribute."); -+ check_attribute_list_for_duplicates(ctx, attributes); - - for (i = 0; i < attributes->count; ++i) - { -@@ -8391,6 +8542,29 @@ primary_expr: - { - $$ = $2; - } -+ -+ | KW_COMPILE any_identifier var_identifier '(' func_arguments ')' -+ { -+ if (!($$ = add_shader_compilation(ctx, $2, $3, &$5, &@1))) -+ { -+ vkd3d_free($2); -+ vkd3d_free($3); -+ YYABORT; -+ } -+ vkd3d_free($2); -+ vkd3d_free($3); -+ } -+ | KW_COMPILESHADER '(' any_identifier ',' var_identifier '(' func_arguments ')' ')' -+ { -+ if (!($$ = add_shader_compilation(ctx, $3, $5, &$7, &@1))) -+ { -+ vkd3d_free($3); -+ vkd3d_free($5); -+ YYABORT; -+ } -+ vkd3d_free($3); -+ vkd3d_free($5); -+ } - | var_identifier '(' func_arguments ')' - { - if (!($$ = add_call(ctx, $1, &$3, &@1))) -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -index 154328a64c3..e470115f191 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -@@ -4050,6 +4050,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) - switch (instr->type) - { - case HLSL_IR_CONSTANT: -+ case HLSL_IR_COMPILE: - case HLSL_IR_EXPR: - case HLSL_IR_INDEX: - case HLSL_IR_LOAD: -@@ -4088,6 +4089,9 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) - case HLSL_IR_STATEBLOCK_CONSTANT: - /* Stateblock constants should not appear in the shader program. */ - vkd3d_unreachable(); -+ case HLSL_IR_VSIR_INSTRUCTION_REF: -+ /* HLSL IR nodes are not translated to hlsl_ir_vsir_instruction_ref at this point. */ -+ vkd3d_unreachable(); - } - - return false; -@@ -4213,6 +4217,9 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop - case HLSL_IR_STATEBLOCK_CONSTANT: - /* Stateblock constants should not appear in the shader program. */ - vkd3d_unreachable(); -+ case HLSL_IR_VSIR_INSTRUCTION_REF: -+ /* HLSL IR nodes are not translated to hlsl_ir_vsir_instruction_ref at this point. */ -+ vkd3d_unreachable(); - - case HLSL_IR_STORE: - { -@@ -4337,6 +4344,9 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop - case HLSL_IR_CONSTANT: - case HLSL_IR_STRING_CONSTANT: - break; -+ case HLSL_IR_COMPILE: -+ /* Compile calls are skipped as they are only relevent to effects. */ -+ break; - } - } - } -@@ -4816,7 +4826,8 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, - } - } - --static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, float f) -+static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, float f, -+ const struct vkd3d_shader_location *loc) - { - struct hlsl_constant_defs *defs = &ctx->constant_defs; - struct hlsl_constant_register *reg; -@@ -4838,6 +4849,7 @@ static void record_constant(struct hlsl_ctx *ctx, unsigned int component_index, - memset(reg, 0, sizeof(*reg)); - reg->index = component_index / 4; - reg->value.f[component_index % 4] = f; -+ reg->loc = *loc; - } - - static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, -@@ -4898,7 +4910,7 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, - vkd3d_unreachable(); - } - -- record_constant(ctx, constant->reg.id * 4 + x, f); -+ record_constant(ctx, constant->reg.id * 4 + x, f, &constant->node.loc); - } - - break; -@@ -4991,17 +5003,17 @@ static void allocate_sincos_const_registers(struct hlsl_ctx *ctx, struct hlsl_bl - - ctx->d3dsincosconst1 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type); - TRACE("Allocated D3DSINCOSCONST1 to %s.\n", debug_register('c', ctx->d3dsincosconst1, type)); -- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 0, -1.55009923e-06f); -- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 1, -2.17013894e-05f); -- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 2, 2.60416674e-03f); -- record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 3, 2.60416680e-04f); -+ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 0, -1.55009923e-06f, &instr->loc); -+ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 1, -2.17013894e-05f, &instr->loc); -+ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 2, 2.60416674e-03f, &instr->loc); -+ record_constant(ctx, ctx->d3dsincosconst1.id * 4 + 3, 2.60416680e-04f, &instr->loc); - - ctx->d3dsincosconst2 = allocate_numeric_registers_for_type(ctx, allocator, 1, UINT_MAX, type); - TRACE("Allocated D3DSINCOSCONST2 to %s.\n", debug_register('c', ctx->d3dsincosconst2, type)); -- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 0, -2.08333340e-02f); -- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 1, -1.25000000e-01f); -- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 2, 1.00000000e+00f); -- record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 3, 5.00000000e-01f); -+ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 0, -2.08333340e-02f, &instr->loc); -+ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 1, -1.25000000e-01f, &instr->loc); -+ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 2, 1.00000000e+00f, &instr->loc); -+ record_constant(ctx, ctx->d3dsincosconst2.id * 4 + 3, 5.00000000e-01f, &instr->loc); - - return; - } -@@ -5786,6 +5798,26 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere - return ret; - } - -+static const char *get_string_argument_value(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr, unsigned int i) -+{ -+ const struct hlsl_ir_node *instr = attr->args[i].node; -+ const struct hlsl_type *type = instr->data_type; -+ -+ if (type->class != HLSL_CLASS_STRING) -+ { -+ struct vkd3d_string_buffer *string; -+ -+ if ((string = hlsl_type_to_string(ctx, type))) -+ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, -+ "Wrong type for the argument %u of [%s]: expected string, but got %s.", -+ i, attr->name, string->buffer); -+ hlsl_release_string_buffer(ctx, string); -+ return NULL; -+ } -+ -+ return hlsl_ir_string_constant(instr)->string; -+} -+ - static void parse_numthreads_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) - { - unsigned int i; -@@ -5834,6 +5866,261 @@ static void parse_numthreads_attribute(struct hlsl_ctx *ctx, const struct hlsl_a - } - } - -+static void parse_domain_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) -+{ -+ const char *value; -+ -+ if (attr->args_count != 1) -+ { -+ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, -+ "Expected 1 parameter for [domain] attribute, but got %u.", attr->args_count); -+ return; -+ } -+ -+ if (!(value = get_string_argument_value(ctx, attr, 0))) -+ return; -+ -+ if (!strcmp(value, "isoline")) -+ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_LINE; -+ else if (!strcmp(value, "tri")) -+ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_TRIANGLE; -+ else if (!strcmp(value, "quad")) -+ ctx->domain = VKD3D_TESSELLATOR_DOMAIN_QUAD; -+ else -+ hlsl_error(ctx, &attr->args[0].node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_DOMAIN, -+ "Invalid tessellator domain \"%s\": expected \"isoline\", \"tri\", or \"quad\".", -+ value); -+} -+ -+static void parse_outputcontrolpoints_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) -+{ -+ const struct hlsl_ir_node *instr; -+ const struct hlsl_type *type; -+ const struct hlsl_ir_constant *constant; -+ -+ if (attr->args_count != 1) -+ { -+ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, -+ "Expected 1 parameter for [outputcontrolpoints] attribute, but got %u.", attr->args_count); -+ return; -+ } -+ -+ instr = attr->args[0].node; -+ type = instr->data_type; -+ -+ if (type->class != HLSL_CLASS_SCALAR -+ || (type->e.numeric.type != HLSL_TYPE_INT && type->e.numeric.type != HLSL_TYPE_UINT)) -+ { -+ struct vkd3d_string_buffer *string; -+ -+ if ((string = hlsl_type_to_string(ctx, type))) -+ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, -+ "Wrong type for argument 0 of [outputcontrolpoints]: expected int or uint, but got %s.", -+ string->buffer); -+ hlsl_release_string_buffer(ctx, string); -+ return; -+ } -+ -+ if (instr->type != HLSL_IR_CONSTANT) -+ { -+ hlsl_fixme(ctx, &instr->loc, "Non-constant expression in [outputcontrolpoints] initializer."); -+ return; -+ } -+ constant = hlsl_ir_constant(instr); -+ -+ if ((type->e.numeric.type == HLSL_TYPE_INT && constant->value.u[0].i < 0) -+ || constant->value.u[0].u > 32) -+ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT, -+ "Output control point count must be between 0 and 32."); -+ -+ ctx->output_control_point_count = constant->value.u[0].u; -+} -+ -+static void parse_outputtopology_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) -+{ -+ const char *value; -+ -+ if (attr->args_count != 1) -+ { -+ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, -+ "Expected 1 parameter for [outputtopology] attribute, but got %u.", attr->args_count); -+ return; -+ } -+ -+ if (!(value = get_string_argument_value(ctx, attr, 0))) -+ return; -+ -+ if (!strcmp(value, "point")) -+ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_POINT; -+ else if (!strcmp(value, "line")) -+ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE; -+ else if (!strcmp(value, "triangle_cw")) -+ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW; -+ else if (!strcmp(value, "triangle_ccw")) -+ ctx->output_primitive = VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW; -+ else -+ hlsl_error(ctx, &attr->args[0].node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, -+ "Invalid tessellator output topology \"%s\": " -+ "expected \"point\", \"line\", \"triangle_cw\", or \"triangle_ccw\".", value); -+} -+ -+static void parse_partitioning_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) -+{ -+ const char *value; -+ -+ if (attr->args_count != 1) -+ { -+ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, -+ "Expected 1 parameter for [partitioning] attribute, but got %u.", attr->args_count); -+ return; -+ } -+ -+ if (!(value = get_string_argument_value(ctx, attr, 0))) -+ return; -+ -+ if (!strcmp(value, "integer")) -+ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_INTEGER; -+ else if (!strcmp(value, "pow2")) -+ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_POW2; -+ else if (!strcmp(value, "fractional_even")) -+ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN; -+ else if (!strcmp(value, "fractional_odd")) -+ ctx->partitioning = VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD; -+ else -+ hlsl_error(ctx, &attr->args[0].node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING, -+ "Invalid tessellator partitioning \"%s\": " -+ "expected \"integer\", \"pow2\", \"fractional_even\", or \"fractional_odd\".", value); -+} -+ -+static void parse_patchconstantfunc_attribute(struct hlsl_ctx *ctx, const struct hlsl_attribute *attr) -+{ -+ const char *name; -+ struct hlsl_ir_function *func; -+ struct hlsl_ir_function_decl *decl; -+ -+ if (attr->args_count != 1) -+ { -+ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, -+ "Expected 1 parameter for [patchconstantfunc] attribute, but got %u.", attr->args_count); -+ return; -+ } -+ -+ if (!(name = get_string_argument_value(ctx, attr, 0))) -+ return; -+ -+ ctx->patch_constant_func = NULL; -+ if ((func = hlsl_get_function(ctx, name))) -+ { -+ /* Pick the last overload with a body. */ -+ LIST_FOR_EACH_ENTRY_REV(decl, &func->overloads, struct hlsl_ir_function_decl, entry) -+ { -+ if (decl->has_body) -+ { -+ ctx->patch_constant_func = decl; -+ break; -+ } -+ } -+ } -+ -+ if (!ctx->patch_constant_func) -+ hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, -+ "Patch constant function \"%s\" is not defined.", name); -+} -+ -+static void parse_entry_function_attributes(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *entry_func) -+{ -+ const struct hlsl_profile_info *profile = ctx->profile; -+ unsigned int i; -+ -+ for (i = 0; i < entry_func->attr_count; ++i) -+ { -+ const struct hlsl_attribute *attr = entry_func->attrs[i]; -+ -+ if (!strcmp(attr->name, "numthreads") && profile->type == VKD3D_SHADER_TYPE_COMPUTE) -+ parse_numthreads_attribute(ctx, attr); -+ else if (!strcmp(attr->name, "domain") -+ && (profile->type == VKD3D_SHADER_TYPE_HULL || profile->type == VKD3D_SHADER_TYPE_DOMAIN)) -+ parse_domain_attribute(ctx, attr); -+ else if (!strcmp(attr->name, "outputcontrolpoints") && profile->type == VKD3D_SHADER_TYPE_HULL) -+ parse_outputcontrolpoints_attribute(ctx, attr); -+ else if (!strcmp(attr->name, "outputtopology") && profile->type == VKD3D_SHADER_TYPE_HULL) -+ parse_outputtopology_attribute(ctx, attr); -+ else if (!strcmp(attr->name, "partitioning") && profile->type == VKD3D_SHADER_TYPE_HULL) -+ parse_partitioning_attribute(ctx, attr); -+ else if (!strcmp(attr->name, "patchconstantfunc") && profile->type == VKD3D_SHADER_TYPE_HULL) -+ parse_patchconstantfunc_attribute(ctx, attr); -+ else -+ hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, -+ "Ignoring unknown attribute \"%s\".", entry_func->attrs[i]->name); -+ } -+} -+ -+static void validate_hull_shader_attributes(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *entry_func) -+{ -+ if (ctx->domain == VKD3D_TESSELLATOR_DOMAIN_INVALID) -+ { -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, -+ "Entry point \"%s\" is missing a [domain] attribute.", entry_func->func->name); -+ } -+ -+ if (ctx->output_control_point_count == UINT_MAX) -+ { -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, -+ "Entry point \"%s\" is missing a [outputcontrolpoints] attribute.", entry_func->func->name); -+ } -+ -+ if (!ctx->output_primitive) -+ { -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, -+ "Entry point \"%s\" is missing a [outputtopology] attribute.", entry_func->func->name); -+ } -+ -+ if (!ctx->partitioning) -+ { -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, -+ "Entry point \"%s\" is missing a [partitioning] attribute.", entry_func->func->name); -+ } -+ -+ if (!ctx->patch_constant_func) -+ { -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, -+ "Entry point \"%s\" is missing a [patchconstantfunc] attribute.", entry_func->func->name); -+ } -+ else if (ctx->patch_constant_func == entry_func) -+ { -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_RECURSIVE_CALL, -+ "Patch constant function cannot be the entry point function."); -+ /* Native returns E_NOTIMPL instead of E_FAIL here. */ -+ ctx->result = VKD3D_ERROR_NOT_IMPLEMENTED; -+ return; -+ } -+ -+ switch (ctx->domain) -+ { -+ case VKD3D_TESSELLATOR_DOMAIN_LINE: -+ if (ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CW -+ || ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, -+ "Triangle output topologies are not available for isoline domains."); -+ break; -+ -+ case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE: -+ if (ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE) -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, -+ "Line output topologies are not available for triangle domains."); -+ break; -+ -+ case VKD3D_TESSELLATOR_DOMAIN_QUAD: -+ if (ctx->output_primitive == VKD3D_SHADER_TESSELLATOR_OUTPUT_LINE) -+ hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE, -+ "Line output topologies are not available for quad domains."); -+ break; -+ -+ default: -+ break; -+ } -+} -+ - static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *body) - { - struct hlsl_ir_node *instr, *next; -@@ -6006,6 +6293,441 @@ static void sm1_generate_vsir_signature(struct hlsl_ctx *ctx, struct vsir_progra - } - } - -+static uint32_t sm1_generate_vsir_get_src_swizzle(uint32_t src_writemask, uint32_t dst_writemask) -+{ -+ uint32_t swizzle; -+ -+ swizzle = hlsl_swizzle_from_writemask(src_writemask); -+ swizzle = hlsl_map_swizzle(swizzle, dst_writemask); -+ swizzle = vsir_swizzle_from_hlsl(swizzle); -+ return swizzle; -+} -+ -+static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, struct vsir_program *program, -+ struct hlsl_block *block) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_src_param *src_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ unsigned int i, x; -+ -+ for (i = 0; i < ctx->constant_defs.count; ++i) -+ { -+ const struct hlsl_constant_register *constant_reg = &ctx->constant_defs.regs[i]; -+ -+ if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ ins = &instructions->elements[instructions->count]; -+ if (!vsir_instruction_init_with_params(program, ins, &constant_reg->loc, VKD3DSIH_DEF, 1, 1)) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ ++instructions->count; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); -+ ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; -+ ins->dst[0].reg.idx[0].offset = constant_reg->index; -+ ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_IMMCONST, VKD3D_DATA_FLOAT, 0); -+ src_param->reg.type = VKD3DSPR_IMMCONST; -+ src_param->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; -+ src_param->reg.non_uniform = false; -+ src_param->reg.data_type = VKD3D_DATA_FLOAT; -+ src_param->reg.dimension = VSIR_DIMENSION_VEC4; -+ for (x = 0; x < 4; ++x) -+ src_param->reg.u.immconst_f32[x] = constant_reg->value.f[x]; -+ src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, NULL, -+ &constant_reg->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ hlsl_block_add_instr(block, vsir_instr); -+ } -+} -+ -+static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx, -+ struct vsir_program *program, struct hlsl_block *block) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ enum vkd3d_shader_resource_type resource_type; -+ struct vkd3d_shader_register_range *range; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_semantic *semantic; -+ struct vkd3d_shader_instruction *ins; -+ enum hlsl_sampler_dim sampler_dim; -+ struct hlsl_ir_node *vsir_instr; -+ struct hlsl_ir_var *var; -+ unsigned int i, count; -+ -+ LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) -+ { -+ if (!var->regs[HLSL_REGSET_SAMPLERS].allocated) -+ continue; -+ -+ count = var->bind_count[HLSL_REGSET_SAMPLERS]; -+ for (i = 0; i < count; ++i) -+ { -+ if (var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) -+ { -+ sampler_dim = var->objects_usage[HLSL_REGSET_SAMPLERS][i].sampler_dim; -+ -+ switch (sampler_dim) -+ { -+ case HLSL_SAMPLER_DIM_2D: -+ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; -+ break; -+ -+ case HLSL_SAMPLER_DIM_CUBE: -+ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_CUBE; -+ break; -+ -+ case HLSL_SAMPLER_DIM_3D: -+ resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_3D; -+ break; -+ -+ case HLSL_SAMPLER_DIM_GENERIC: -+ /* These can appear in sm4-style combined sample instructions. */ -+ hlsl_fixme(ctx, &var->loc, "Generic samplers need to be lowered."); -+ continue; -+ -+ default: -+ vkd3d_unreachable(); -+ break; -+ } -+ -+ if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ ins = &instructions->elements[instructions->count]; -+ if (!vsir_instruction_init_with_params(program, ins, &var->loc, VKD3DSIH_DCL, 0, 0)) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ ++instructions->count; -+ -+ semantic = &ins->declaration.semantic; -+ semantic->resource_type = resource_type; -+ -+ dst_param = &semantic->resource.reg; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_SAMPLER, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.dimension = VSIR_DIMENSION_NONE; -+ dst_param->reg.idx[0].offset = var->regs[HLSL_REGSET_SAMPLERS].index + i; -+ dst_param->write_mask = 0; -+ range = &semantic->resource.range; -+ range->space = 0; -+ range->first = range->last = dst_param->reg.idx[0].offset; -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, -+ NULL, &var->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ hlsl_block_add_instr(block, vsir_instr); -+ } -+ } -+ } -+} -+ -+static struct vkd3d_shader_instruction *generate_vsir_add_program_instruction( -+ struct hlsl_ctx *ctx, struct vsir_program *program, -+ const struct vkd3d_shader_location *loc, enum vkd3d_shader_opcode opcode, -+ unsigned int dst_count, unsigned int src_count) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct vkd3d_shader_instruction *ins; -+ -+ if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return NULL; -+ } -+ ins = &instructions->elements[instructions->count]; -+ if (!vsir_instruction_init_with_params(program, ins, loc, opcode, dst_count, src_count)) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return NULL; -+ } -+ ++instructions->count; -+ return ins; -+} -+ -+static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, -+ struct vsir_program *program, struct hlsl_ir_constant *constant) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *instr = &constant->node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_src_param *src_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ -+ VKD3D_ASSERT(instr->reg.allocated); -+ VKD3D_ASSERT(constant->reg.allocated); -+ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) -+ return; -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = constant->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(constant->reg.writemask, instr->reg.writemask); -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = instr->reg.writemask; -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, -+ instr->data_type, &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ -+static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx, -+ struct vkd3d_shader_dst_param *dst_param, struct hlsl_deref *deref, -+ const struct vkd3d_shader_location *loc, unsigned int writemask) -+{ -+ enum vkd3d_shader_register_type type = VKD3DSPR_TEMP; -+ struct vkd3d_shader_version version; -+ uint32_t register_index; -+ struct hlsl_reg reg; -+ -+ reg = hlsl_reg_from_deref(ctx, deref); -+ register_index = reg.id; -+ writemask = hlsl_combine_writemasks(reg.writemask, writemask); -+ -+ if (deref->var->is_output_semantic) -+ { -+ version.major = ctx->profile->major_version; -+ version.minor = ctx->profile->minor_version; -+ version.type = ctx->profile->type; -+ -+ if (version.type == VKD3D_SHADER_TYPE_PIXEL && version.major == 1) -+ { -+ type = VKD3DSPR_TEMP; -+ register_index = 0; -+ } -+ else if (!hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name, -+ deref->var->semantic.index, true, &type, ®ister_index)) -+ { -+ VKD3D_ASSERT(reg.allocated); -+ type = VKD3DSPR_OUTPUT; -+ register_index = reg.id; -+ } -+ else -+ writemask = (1u << deref->var->data_type->dimx) - 1; -+ } -+ else -+ VKD3D_ASSERT(reg.allocated); -+ -+ vsir_register_init(&dst_param->reg, type, VKD3D_DATA_FLOAT, 1); -+ dst_param->write_mask = writemask; -+ dst_param->reg.idx[0].offset = register_index; -+ -+ if (deref->rel_offset.node) -+ hlsl_fixme(ctx, loc, "Translate relative addressing on dst register for vsir."); -+} -+ -+static void sm1_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx, -+ struct vkd3d_shader_src_param *src_param, struct hlsl_deref *deref, -+ unsigned int dst_writemask, const struct vkd3d_shader_location *loc) -+{ -+ enum vkd3d_shader_register_type type = VKD3DSPR_TEMP; -+ struct vkd3d_shader_version version; -+ uint32_t register_index; -+ unsigned int writemask; -+ struct hlsl_reg reg; -+ -+ reg = hlsl_reg_from_deref(ctx, deref); -+ register_index = reg.id; -+ writemask = reg.writemask; -+ -+ if (deref->var->is_uniform) -+ { -+ VKD3D_ASSERT(reg.allocated); -+ type = VKD3DSPR_CONST; -+ } -+ else if (deref->var->is_input_semantic) -+ { -+ version.major = ctx->profile->major_version; -+ version.minor = ctx->profile->minor_version; -+ version.type = ctx->profile->type; -+ if (!hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name, -+ deref->var->semantic.index, false, &type, ®ister_index)) -+ { -+ VKD3D_ASSERT(reg.allocated); -+ type = VKD3DSPR_INPUT; -+ register_index = reg.id; -+ } -+ else -+ writemask = (1 << deref->var->data_type->dimx) - 1; -+ } -+ -+ vsir_register_init(&src_param->reg, type, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = register_index; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(writemask, dst_writemask); -+ -+ if (deref->rel_offset.node) -+ hlsl_fixme(ctx, loc, "Translate relative addressing on src register for vsir."); -+} -+ -+static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_program *program, -+ struct hlsl_ir_load *load) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *instr = &load->node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ -+ VKD3D_ASSERT(instr->reg.allocated); -+ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) -+ return; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = instr->reg.writemask; -+ -+ sm1_generate_vsir_init_src_param_from_deref(ctx, &ins->src[0], &load->src, dst_param->write_mask, -+ &ins->location); -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -+ &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ -+static void sm1_generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, struct vsir_program *program, -+ struct hlsl_ir_swizzle *swizzle_instr) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *instr = &swizzle_instr->node, *val = swizzle_instr->val.node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_src_param *src_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ uint32_t swizzle; -+ -+ VKD3D_ASSERT(instr->reg.allocated); -+ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) -+ return; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = instr->reg.writemask; -+ -+ swizzle = hlsl_swizzle_from_writemask(val->reg.writemask); -+ swizzle = hlsl_combine_swizzles(swizzle, swizzle_instr->swizzle, instr->data_type->dimx); -+ swizzle = hlsl_map_swizzle(swizzle, ins->dst[0].write_mask); -+ swizzle = vsir_swizzle_from_hlsl(swizzle); -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = val->reg.id; -+ src_param->swizzle = swizzle; -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -+ &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ -+static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_program *program, -+ struct hlsl_ir_store *store) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *rhs = store->rhs.node; -+ struct hlsl_ir_node *instr = &store->node; -+ struct vkd3d_shader_instruction *ins; -+ struct vkd3d_shader_src_param *src_param; -+ struct hlsl_ir_node *vsir_instr; -+ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) -+ return; -+ -+ sm1_generate_vsir_init_dst_param_from_deref(ctx, &ins->dst[0], &store->lhs, &ins->location, store->writemask); -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = rhs->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(rhs->reg.writemask, ins->dst[0].write_mask); -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, NULL, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ -+static bool sm1_generate_vsir_instr(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) -+{ -+ struct vsir_program *program = context; -+ -+ switch (instr->type) -+ { -+ case HLSL_IR_CONSTANT: -+ sm1_generate_vsir_instr_constant(ctx, program, hlsl_ir_constant(instr)); -+ return true; -+ -+ case HLSL_IR_LOAD: -+ sm1_generate_vsir_instr_load(ctx, program, hlsl_ir_load(instr)); -+ return true; -+ -+ case HLSL_IR_STORE: -+ sm1_generate_vsir_instr_store(ctx, program, hlsl_ir_store(instr)); -+ return true; -+ -+ case HLSL_IR_SWIZZLE: -+ sm1_generate_vsir_instr_swizzle(ctx, program, hlsl_ir_swizzle(instr)); -+ return true; -+ -+ default: -+ break; -+ } -+ -+ return false; -+} -+ - /* OBJECTIVE: Translate all the information from ctx and entry_func to the - * vsir_program and ctab blob, so they can be used as input to d3dbc_compile() - * without relying on ctx and entry_func. */ -@@ -6014,6 +6736,7 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl - { - struct vkd3d_shader_version version = {0}; - struct vkd3d_bytecode_buffer buffer = {0}; -+ struct hlsl_block block; - - version.major = ctx->profile->major_version; - version.minor = ctx->profile->minor_version; -@@ -6035,6 +6758,13 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl - ctab->size = buffer.size; - - sm1_generate_vsir_signature(ctx, program); -+ -+ hlsl_block_init(&block); -+ sm1_generate_vsir_constant_defs(ctx, program, &block); -+ sm1_generate_vsir_sampler_dcls(ctx, program, &block); -+ list_move_head(&entry_func->body.instrs, &block.instrs); -+ -+ hlsl_transform_ir(ctx, sm1_generate_vsir_instr, &entry_func->body, program); - } - - static struct hlsl_ir_jump *loop_unrolling_find_jump(struct hlsl_block *block, struct hlsl_ir_node *stop_point, -@@ -6406,18 +7136,13 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry - append_output_var_copy(ctx, body, entry_func->return_var); - } - -- for (i = 0; i < entry_func->attr_count; ++i) -- { -- const struct hlsl_attribute *attr = entry_func->attrs[i]; -- -- if (!strcmp(attr->name, "numthreads") && profile->type == VKD3D_SHADER_TYPE_COMPUTE) -- parse_numthreads_attribute(ctx, attr); -- else -- hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, -- "Ignoring unknown attribute \"%s\".", entry_func->attrs[i]->name); -- } -+ parse_entry_function_attributes(ctx, entry_func); -+ if (ctx->result) -+ return ctx->result; - -- if (profile->type == VKD3D_SHADER_TYPE_COMPUTE && !ctx->found_numthreads) -+ if (profile->type == VKD3D_SHADER_TYPE_HULL) -+ validate_hull_shader_attributes(ctx, entry_func); -+ else if (profile->type == VKD3D_SHADER_TYPE_COMPUTE && !ctx->found_numthreads) - hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, - "Entry point \"%s\" is missing a [numthreads] attribute.", entry_func->func->name); - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c -index db4913b7c62..716adb15f08 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c -@@ -1452,11 +1452,15 @@ static bool constant_is_one(struct hlsl_ir_constant *const_arg) - - case HLSL_TYPE_UINT: - case HLSL_TYPE_INT: -- case HLSL_TYPE_BOOL: - if (const_arg->value.u[k].u != 1) - return false; - break; - -+ case HLSL_TYPE_BOOL: -+ if (const_arg->value.u[k].u != ~0) -+ return false; -+ break; -+ - default: - return false; - } -@@ -1514,6 +1518,20 @@ bool hlsl_fold_constant_identities(struct hlsl_ctx *ctx, struct hlsl_ir_node *in - res_node = mut_arg; - break; - -+ case HLSL_OP2_LOGIC_AND: -+ if (constant_is_zero(const_arg)) -+ res_node = &const_arg->node; -+ else if (constant_is_one(const_arg)) -+ res_node = mut_arg; -+ break; -+ -+ case HLSL_OP2_LOGIC_OR: -+ if (constant_is_zero(const_arg)) -+ res_node = mut_arg; -+ else if (constant_is_one(const_arg)) -+ res_node = &const_arg->node; -+ break; -+ - default: - break; - } -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index 747238e2fee..d765abc938b 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -136,7 +136,7 @@ static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *i - vsir_instruction_init(ins, &location, VKD3DSIH_NOP); - } - --static bool vsir_instruction_init_with_params(struct vsir_program *program, -+bool vsir_instruction_init_with_params(struct vsir_program *program, - struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, - enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count) - { -diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c -index 8052e951704..c1fd07a533a 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/spirv.c -+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c -@@ -97,15 +97,37 @@ static enum vkd3d_result vkd3d_spirv_binary_to_text(const struct vkd3d_shader_co - if (!(spvret = spvBinaryToText(context, spirv->code, spirv->size / sizeof(uint32_t), - get_binary_to_text_options(formatting), &text, &diagnostic))) - { -- void *code = vkd3d_malloc(text->length); -- if (code) -+ const char *p, *q, *end, *pad, *truncate; -+ struct vkd3d_string_buffer buffer; -+ size_t line_len; -+ -+ vkd3d_string_buffer_init(&buffer); -+ -+ for (p = text->str, end = p + text->length; p < end; p = q) - { -- memcpy(code, text->str, text->length); -- out->size = text->length; -- out->code = code; -+ if (!(q = memchr(p, '\n', end - p))) -+ q = end; -+ else -+ ++q; -+ -+ /* FIXME: Note that when colour output is enabled, we count colour -+ * escape codes towards the line length. It's possible to fix -+ * that, but not completely trivial. */ -+ for (pad = "", line_len = 100; q - p > line_len; line_len = 100 - strlen(pad)) -+ { -+ if (!(truncate = memchr(p + line_len, ' ', q - p - line_len))) -+ break; -+ vkd3d_string_buffer_printf(&buffer, "%s%.*s\n", pad, (int)(truncate - p), p); -+ p = truncate + 1; -+ if (formatting & VKD3D_SHADER_COMPILE_OPTION_FORMATTING_INDENT) -+ pad = " "; -+ else -+ pad = " "; -+ } -+ vkd3d_string_buffer_printf(&buffer, "%s%.*s", pad, (int)(q - p), p); - } -- else -- result = VKD3D_ERROR_OUT_OF_MEMORY; -+ -+ vkd3d_shader_code_from_string_buffer(out, &buffer); - } - else - { -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index 497a4c3b335..c61086419a6 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -2918,16 +2918,16 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, - { - case HLSL_TYPE_FLOAT: - case HLSL_TYPE_HALF: -- put_u32(&buffer, D3D_REGISTER_COMPONENT_FLOAT32); -+ put_u32(&buffer, VKD3D_SHADER_COMPONENT_FLOAT); - break; - - case HLSL_TYPE_INT: -- put_u32(&buffer, D3D_REGISTER_COMPONENT_SINT32); -+ put_u32(&buffer, VKD3D_SHADER_COMPONENT_INT); - break; - - case HLSL_TYPE_BOOL: - case HLSL_TYPE_UINT: -- put_u32(&buffer, D3D_REGISTER_COMPONENT_UINT32); -+ put_u32(&buffer, VKD3D_SHADER_COMPONENT_UINT); - break; - - default: -@@ -2935,7 +2935,7 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "Invalid data type %s for semantic variable %s.", string->buffer, var->name); - hlsl_release_string_buffer(ctx, string); -- put_u32(&buffer, D3D_REGISTER_COMPONENT_UNKNOWN); -+ put_u32(&buffer, VKD3D_SHADER_COMPONENT_VOID); - } - put_u32(&buffer, reg_idx); - put_u32(&buffer, vkd3d_make_u16(width, use_mask)); -@@ -3123,24 +3123,24 @@ static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type) - vkd3d_unreachable(); - } - --static D3D_RESOURCE_RETURN_TYPE sm4_resource_format(const struct hlsl_type *type) -+static enum vkd3d_sm4_data_type sm4_data_type(const struct hlsl_type *type) - { - switch (type->e.resource.format->e.numeric.type) - { - case HLSL_TYPE_DOUBLE: -- return D3D_RETURN_TYPE_DOUBLE; -+ return VKD3D_SM4_DATA_DOUBLE; - - case HLSL_TYPE_FLOAT: - case HLSL_TYPE_HALF: -- return D3D_RETURN_TYPE_FLOAT; -+ return VKD3D_SM4_DATA_FLOAT; - - case HLSL_TYPE_INT: -- return D3D_RETURN_TYPE_SINT; -+ return VKD3D_SM4_DATA_INT; - break; - - case HLSL_TYPE_BOOL: - case HLSL_TYPE_UINT: -- return D3D_RETURN_TYPE_UINT; -+ return VKD3D_SM4_DATA_UINT; - - default: - vkd3d_unreachable(); -@@ -3471,7 +3471,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - { - unsigned int dimx = resource->component_type->e.resource.format->dimx; - -- put_u32(&buffer, sm4_resource_format(resource->component_type)); -+ put_u32(&buffer, sm4_data_type(resource->component_type)); - put_u32(&buffer, sm4_rdef_resource_dimension(resource->component_type)); - put_u32(&buffer, ~0u); /* FIXME: multisample count */ - flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; -@@ -4348,7 +4348,7 @@ static void write_sm4_dcl_textures(const struct tpf_writer *tpf, const struct ex - .dsts[0].reg.idx_count = 1, - .dst_count = 1, - -- .idx[0] = sm4_resource_format(component_type) * 0x1111, -+ .idx[0] = sm4_data_type(component_type) * 0x1111, - .idx_count = 1, - }; - -@@ -6110,7 +6110,7 @@ static void write_sm4_sfi0(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - /* FIXME: We also emit code that should require UAVS_AT_EVERY_STAGE, - * STENCIL_REF, and TYPED_UAV_LOAD_ADDITIONAL_FORMATS. */ - -- if (flags) -+ if (*flags) - dxbc_writer_add_section(dxbc, TAG_SFI0, flags, sizeof(*flags)); - else - vkd3d_free(flags); -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index 442885f53b4..327461371a4 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -152,6 +152,12 @@ enum vkd3d_shader_error - VKD3D_SHADER_ERROR_HLSL_UNKNOWN_MODIFIER = 5030, - VKD3D_SHADER_ERROR_HLSL_INVALID_STATE_BLOCK_ENTRY = 5031, - VKD3D_SHADER_ERROR_HLSL_FAILED_FORCED_UNROLL = 5032, -+ VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE = 5033, -+ VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE = 5034, -+ VKD3D_SHADER_ERROR_HLSL_INVALID_DOMAIN = 5035, -+ VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT = 5036, -+ VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE = 5037, -+ VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING = 5038, - - VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, - VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, -@@ -169,6 +175,10 @@ enum vkd3d_shader_error - VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY = 7004, - VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_INDEX = 7005, - VKD3D_SHADER_ERROR_D3DBC_UNDECLARED_SEMANTIC = 7006, -+ VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_TYPE = 7007, -+ VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT = 7008, -+ VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED = 7009, -+ VKD3D_SHADER_ERROR_D3DBC_INVALID_PROFILE = 7010, - - VKD3D_SHADER_WARNING_D3DBC_IGNORED_INSTRUCTION_FLAGS= 7300, - -@@ -1389,6 +1399,9 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); - enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, - const char *source_name, struct vkd3d_shader_message_context *message_context); -+bool vsir_instruction_init_with_params(struct vsir_program *program, -+ struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, -+ enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count); - - static inline struct vkd3d_shader_dst_param *vsir_program_get_dst_params( - struct vsir_program *program, unsigned int count) --- -2.45.2 - diff --git a/patches/vkd3d-latest/0002-Updated-vkd3d-to-a2aeb3a1421c5540b7f4d0e68ec3ff211e1.patch b/patches/vkd3d-latest/0002-Updated-vkd3d-to-a2aeb3a1421c5540b7f4d0e68ec3ff211e1.patch new file mode 100644 index 00000000..b98184e5 --- /dev/null +++ b/patches/vkd3d-latest/0002-Updated-vkd3d-to-a2aeb3a1421c5540b7f4d0e68ec3ff211e1.patch @@ -0,0 +1,949 @@ +From f7442f283e45fca56616dc6dbbd9db472bebef3a Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Tue, 24 Sep 2024 08:29:40 +1000 +Subject: [PATCH] Updated vkd3d to a2aeb3a1421c5540b7f4d0e68ec3ff211e15f646. + +--- + libs/vkd3d/include/vkd3d_shader.h | 11 +++ + libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 13 ++- + libs/vkd3d/libs/vkd3d-shader/fx.c | 2 + + libs/vkd3d/libs/vkd3d-shader/glsl.c | 56 +++++++++++ + libs/vkd3d/libs/vkd3d-shader/hlsl.c | 39 ++++++-- + libs/vkd3d/libs/vkd3d-shader/hlsl.h | 13 +++ + libs/vkd3d/libs/vkd3d-shader/hlsl.l | 1 - + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 93 ++++++++++--------- + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 36 ++++++- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 64 +++++-------- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 1 + + .../libs/vkd3d-shader/vkd3d_shader_private.h | 2 + + libs/vkd3d/libs/vkd3d/state.c | 4 +- + 13 files changed, 234 insertions(+), 101 deletions(-) + +diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h +index 46feff35138..115bb21b932 100644 +--- a/libs/vkd3d/include/vkd3d_shader.h ++++ b/libs/vkd3d/include/vkd3d_shader.h +@@ -190,6 +190,17 @@ enum vkd3d_shader_compile_option_backward_compatibility + * - DEPTH to SV_Depth for pixel shader outputs. + */ + VKD3D_SHADER_COMPILE_OPTION_BACKCOMPAT_MAP_SEMANTIC_NAMES = 0x00000001, ++ /** ++ * Causes 'double' to behave as an alias for 'float'. This option only ++ * applies to HLSL sources with shader model 1-3 target profiles. Without ++ * this option using the 'double' type produces compilation errors in ++ * these target profiles. ++ * ++ * This option is disabled by default. ++ * ++ * \since 1.14 ++ */ ++ VKD3D_SHADER_COMPILE_OPTION_DOUBLE_AS_FLOAT_ALIAS = 0x00000002, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_BACKWARD_COMPATIBILITY), + }; +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +index 10f2e5e5e6d..34752a1ab89 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +@@ -1522,6 +1522,7 @@ D3DXPARAMETER_CLASS hlsl_sm1_class(const struct hlsl_type *type) + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_RASTERIZER_STATE: + case HLSL_CLASS_RENDER_TARGET_VIEW: +@@ -1627,6 +1628,7 @@ D3DXPARAMETER_TYPE hlsl_sm1_base_type(const struct hlsl_type *type) + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_RASTERIZER_STATE: + case HLSL_CLASS_RENDER_TARGET_VIEW: +@@ -1719,7 +1721,7 @@ static void sm1_sort_externs(struct hlsl_ctx *ctx) + + void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer) + { +- size_t ctab_offset, ctab_start, ctab_end, vars_start, size_offset, creator_offset, offset; ++ size_t ctab_offset, ctab_start, ctab_end, vars_offset, vars_start, size_offset, creator_offset, offset; + unsigned int uniform_count = 0; + struct hlsl_ir_var *var; + +@@ -1755,11 +1757,12 @@ void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buff + creator_offset = put_u32(buffer, 0); + put_u32(buffer, sm1_version(ctx->profile->type, ctx->profile->major_version, ctx->profile->minor_version)); + put_u32(buffer, uniform_count); +- put_u32(buffer, sizeof(D3DXSHADER_CONSTANTTABLE)); /* offset of constants */ ++ vars_offset = put_u32(buffer, 0); + put_u32(buffer, 0); /* FIXME: flags */ + put_u32(buffer, 0); /* FIXME: target string */ + + vars_start = bytecode_align(buffer); ++ set_u32(buffer, vars_offset, vars_start - ctab_start); + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { +@@ -1835,8 +1838,10 @@ void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buff + switch (comp_type->e.numeric.type) + { + case HLSL_TYPE_DOUBLE: +- hlsl_fixme(ctx, &var->loc, "Write double default values."); +- uni.u = 0; ++ if (ctx->double_as_float_alias) ++ uni.u = var->default_values[k].number.u; ++ else ++ uni.u = 0; + break; + + case HLSL_TYPE_INT: +diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c +index 1314bc09e73..7d4a9d2e2ff 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/fx.c ++++ b/libs/vkd3d/libs/vkd3d-shader/fx.c +@@ -665,6 +665,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co + + case HLSL_CLASS_ARRAY: + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_TECHNIQUE: + case HLSL_CLASS_CONSTANT_BUFFER: +@@ -1117,6 +1118,7 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type + return false; + + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_TECHNIQUE: + case HLSL_CLASS_CONSTANT_BUFFER: +diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c +index dd1c121d5a8..b29f13f2b19 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c +@@ -305,6 +305,9 @@ static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator + { + case VKD3DSPSM_NONE: + break; ++ case VKD3DSPSM_NEG: ++ vkd3d_string_buffer_printf(glsl_src->str, "-%s", str->buffer); ++ break; + case VKD3DSPSM_ABS: + vkd3d_string_buffer_printf(glsl_src->str, "abs(%s)", str->buffer); + break; +@@ -414,6 +417,22 @@ static void shader_glsl_binop(struct vkd3d_glsl_generator *gen, + glsl_dst_cleanup(&dst, &gen->string_buffers); + } + ++static void shader_glsl_intrinsic(struct vkd3d_glsl_generator *gen, ++ const struct vkd3d_shader_instruction *ins, const char *op) ++{ ++ struct glsl_src src; ++ struct glsl_dst dst; ++ uint32_t mask; ++ ++ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ glsl_src_init(&src, gen, &ins->src[0], mask); ++ ++ shader_glsl_print_assignment(gen, &dst, "%s(%s)", op, src.str->buffer); ++ ++ glsl_src_cleanup(&src, &gen->string_buffers); ++ glsl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ + static void shader_glsl_relop(struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_instruction *ins, const char *scalar_op, const char *vector_op) + { +@@ -453,6 +472,31 @@ static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d + glsl_dst_cleanup(&dst, &gen->string_buffers); + } + ++static void shader_glsl_movc(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) ++{ ++ unsigned int component_count; ++ struct glsl_src src[3]; ++ struct glsl_dst dst; ++ uint32_t mask; ++ ++ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ glsl_src_init(&src[0], gen, &ins->src[0], mask); ++ glsl_src_init(&src[1], gen, &ins->src[1], mask); ++ glsl_src_init(&src[2], gen, &ins->src[2], mask); ++ ++ if ((component_count = vsir_write_mask_component_count(mask)) > 1) ++ shader_glsl_print_assignment(gen, &dst, "mix(%s, %s, bvec%u(%s))", ++ src[2].str->buffer, src[1].str->buffer, component_count, src[0].str->buffer); ++ else ++ shader_glsl_print_assignment(gen, &dst, "mix(%s, %s, bool(%s))", ++ src[2].str->buffer, src[1].str->buffer, src[0].str->buffer); ++ ++ glsl_src_cleanup(&src[2], &gen->string_buffers); ++ glsl_src_cleanup(&src[1], &gen->string_buffers); ++ glsl_src_cleanup(&src[0], &gen->string_buffers); ++ glsl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ + static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, + enum vkd3d_shader_sysval_semantic sysval, unsigned int idx) + { +@@ -608,6 +652,15 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_DCL_OUTPUT_SIV: + case VKD3DSIH_NOP: + break; ++ case VKD3DSIH_DIV: ++ shader_glsl_binop(gen, ins, "/"); ++ break; ++ case VKD3DSIH_FRC: ++ shader_glsl_intrinsic(gen, ins, "fract"); ++ break; ++ case VKD3DSIH_GEO: ++ shader_glsl_relop(gen, ins, ">=", "greaterThanEqual"); ++ break; + case VKD3DSIH_INE: + case VKD3DSIH_NEU: + shader_glsl_relop(gen, ins, "!=", "notEqual"); +@@ -615,6 +668,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_MOV: + shader_glsl_mov(gen, ins); + break; ++ case VKD3DSIH_MOVC: ++ shader_glsl_movc(gen, ins); ++ break; + case VKD3DSIH_MUL: + shader_glsl_binop(gen, ins, "*"); + break; +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +index 6323260eab7..f4401bc5d89 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +@@ -276,6 +276,7 @@ bool hlsl_type_is_shader(const struct hlsl_type *type) + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_RASTERIZER_STATE: + case HLSL_CLASS_RENDER_TARGET_VIEW: +@@ -418,6 +419,7 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_RASTERIZER_STATE: +@@ -494,6 +496,7 @@ static bool type_is_single_component(const struct hlsl_type *type) + { + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_SAMPLER: +@@ -670,6 +673,7 @@ unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_ty + break; + + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_TECHNIQUE: + case HLSL_CLASS_VOID: +@@ -1061,6 +1065,7 @@ unsigned int hlsl_type_component_count(const struct hlsl_type *type) + + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_RASTERIZER_STATE: + case HLSL_CLASS_RENDER_TARGET_VIEW: +@@ -1155,6 +1160,7 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2 + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_PASS: + case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_RASTERIZER_STATE: +@@ -1629,6 +1635,16 @@ struct hlsl_ir_node *hlsl_new_ternary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_ex + return hlsl_new_expr(ctx, op, operands, arg1->data_type, &arg1->loc); + } + ++static struct hlsl_ir_node *hlsl_new_error_expr(struct hlsl_ctx *ctx) ++{ ++ static const struct vkd3d_shader_location loc = {.source_name = ""}; ++ struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS] = {0}; ++ ++ /* Use a dummy location; we should never report any messages related to ++ * this expression. */ ++ return hlsl_new_expr(ctx, HLSL_OP0_ERROR, operands, ctx->builtin_types.error, &loc); ++} ++ + struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condition, + struct hlsl_block *then_block, struct hlsl_block *else_block, const struct vkd3d_shader_location *loc) + { +@@ -2710,6 +2726,10 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru + } + return string; + ++ case HLSL_CLASS_ERROR: ++ vkd3d_string_buffer_printf(string, ""); ++ return string; ++ + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: +@@ -3049,6 +3069,7 @@ const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op) + { + static const char *const op_names[] = + { ++ [HLSL_OP0_ERROR] = "error", + [HLSL_OP0_VOID] = "void", + [HLSL_OP0_RASTERIZER_SAMPLE_COUNT] = "GetRenderTargetSampleCount", + +@@ -3990,12 +4011,12 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) + + static const char * const names[] = + { +- "float", +- "half", +- "double", +- "int", +- "uint", +- "bool", ++ [HLSL_TYPE_FLOAT] = "float", ++ [HLSL_TYPE_HALF] = "half", ++ [HLSL_TYPE_DOUBLE] = "double", ++ [HLSL_TYPE_INT] = "int", ++ [HLSL_TYPE_UINT] = "uint", ++ [HLSL_TYPE_BOOL] = "bool", + }; + + static const char *const variants_float[] = {"min10float", "min16float"}; +@@ -4146,6 +4167,7 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) + ctx->builtin_types.Void = hlsl_new_simple_type(ctx, "void", HLSL_CLASS_VOID); + ctx->builtin_types.null = hlsl_new_type(ctx, "NULL", HLSL_CLASS_NULL, HLSL_TYPE_UINT, 1, 1); + ctx->builtin_types.string = hlsl_new_simple_type(ctx, "string", HLSL_CLASS_STRING); ++ ctx->builtin_types.error = hlsl_new_simple_type(ctx, "", HLSL_CLASS_ERROR); + hlsl_scope_add_type(ctx->globals, ctx->builtin_types.string); + hlsl_scope_add_type(ctx->globals, hlsl_new_simple_type(ctx, "DepthStencilView", HLSL_CLASS_DEPTH_STENCIL_VIEW)); + hlsl_scope_add_type(ctx->globals, hlsl_new_simple_type(ctx, "DepthStencilState", HLSL_CLASS_DEPTH_STENCIL_STATE)); +@@ -4248,6 +4270,7 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compil + + case VKD3D_SHADER_COMPILE_OPTION_BACKWARD_COMPATIBILITY: + ctx->semantic_compat_mapping = option->value & VKD3D_SHADER_COMPILE_OPTION_BACKCOMPAT_MAP_SEMANTIC_NAMES; ++ ctx->double_as_float_alias = option->value & VKD3D_SHADER_COMPILE_OPTION_DOUBLE_AS_FLOAT_ALIAS; + break; + + case VKD3D_SHADER_COMPILE_OPTION_CHILD_EFFECT: +@@ -4267,6 +4290,10 @@ static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compil + } + } + ++ if (!(ctx->error_instr = hlsl_new_error_expr(ctx))) ++ return false; ++ hlsl_block_add_instr(&ctx->static_initializers, ctx->error_instr); ++ + ctx->domain = VKD3D_TESSELLATOR_DOMAIN_INVALID; + ctx->output_control_point_count = UINT_MAX; + ctx->output_primitive = 0; +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +index 20a96692a48..b8678962f67 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +@@ -106,6 +106,7 @@ enum hlsl_type_class + HLSL_CLASS_BLEND_STATE, + HLSL_CLASS_VOID, + HLSL_CLASS_NULL, ++ HLSL_CLASS_ERROR, + }; + + enum hlsl_base_type +@@ -361,6 +362,9 @@ struct hlsl_block + { + /* List containing instruction nodes; linked by the hlsl_ir_node.entry fields. */ + struct list instrs; ++ /* Instruction representing the "value" of this block, if applicable. ++ * This may point to an instruction outside of this block! */ ++ struct hlsl_ir_node *value; + }; + + /* A reference to an instruction node (struct hlsl_ir_node), usable as a field in other structs. +@@ -657,6 +661,7 @@ struct hlsl_ir_switch + + enum hlsl_ir_expr_op + { ++ HLSL_OP0_ERROR, + HLSL_OP0_VOID, + HLSL_OP0_RASTERIZER_SAMPLE_COUNT, + +@@ -1043,8 +1048,12 @@ struct hlsl_ctx + struct hlsl_type *string; + struct hlsl_type *Void; + struct hlsl_type *null; ++ struct hlsl_type *error; + } builtin_types; + ++ /* Pre-allocated "error" expression. */ ++ struct hlsl_ir_node *error_instr; ++ + /* List of the instruction nodes for initializing static variables. */ + struct hlsl_block static_initializers; + +@@ -1091,6 +1100,7 @@ struct hlsl_ctx + bool child_effect; + bool include_empty_buffers; + bool warn_implicit_truncation; ++ bool double_as_float_alias; + }; + + static inline bool hlsl_version_ge(const struct hlsl_ctx *ctx, unsigned int major, unsigned int minor) +@@ -1211,16 +1221,19 @@ static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(co + static inline void hlsl_block_init(struct hlsl_block *block) + { + list_init(&block->instrs); ++ block->value = NULL; + } + + static inline void hlsl_block_add_instr(struct hlsl_block *block, struct hlsl_ir_node *instr) + { + list_add_tail(&block->instrs, &instr->entry); ++ block->value = (instr->data_type ? instr : NULL); + } + + static inline void hlsl_block_add_block(struct hlsl_block *block, struct hlsl_block *add) + { + list_move_tail(&block->instrs, &add->instrs); ++ block->value = add->value; + } + + static inline void hlsl_src_from_node(struct hlsl_src *src, struct hlsl_ir_node *node) +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.l b/libs/vkd3d/libs/vkd3d-shader/hlsl.l +index b7c242661e3..97d8b13772b 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.l ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.l +@@ -90,7 +90,6 @@ default {return KW_DEFAULT; } + discard {return KW_DISCARD; } + DomainShader {return KW_DOMAINSHADER; } + do {return KW_DO; } +-double {return KW_DOUBLE; } + else {return KW_ELSE; } + export {return KW_EXPORT; } + extern {return KW_EXTERN; } +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +index 67262c2ccfd..c39f2020ef7 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +@@ -147,7 +147,7 @@ static void yyerror(YYLTYPE *loc, void *scanner, struct hlsl_ctx *ctx, const cha + + static struct hlsl_ir_node *node_from_block(struct hlsl_block *block) + { +- return LIST_ENTRY(list_tail(&block->instrs), struct hlsl_ir_node, entry); ++ return block->value; + } + + static struct hlsl_block *make_empty_block(struct hlsl_ctx *ctx) +@@ -489,9 +489,10 @@ static bool append_conditional_break(struct hlsl_ctx *ctx, struct hlsl_block *co + check_condition_type(ctx, condition); + + bool_type = hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL); +- if (!(cast = hlsl_new_cast(ctx, condition, bool_type, &condition->loc))) ++ /* We already checked for a 1-component numeric type, so ++ * add_implicit_conversion() is equivalent to add_cast() here. */ ++ if (!(cast = add_cast(ctx, cond_block, condition, bool_type, &condition->loc))) + return false; +- hlsl_block_add_instr(cond_block, cast); + + if (!(not = hlsl_new_unary_expr(ctx, HLSL_OP1_LOGIC_NOT, cast, &condition->loc))) + return false; +@@ -639,14 +640,14 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx + return ret; + hlsl_block_add_block(&expr, block); + +- if (!add_implicit_conversion(ctx, &expr, node_from_block(&expr), dst_type, loc)) ++ if (!(node = add_implicit_conversion(ctx, &expr, node_from_block(&expr), dst_type, loc))) + { + hlsl_block_cleanup(&expr); + return ret; + } + + /* Wrap the node into a src to allow the reference to survive the multiple const passes. */ +- hlsl_src_from_node(&src, node_from_block(&expr)); ++ hlsl_src_from_node(&src, node); + hlsl_run_const_passes(ctx, &expr); + node = src.node; + hlsl_src_remove(&src); +@@ -1710,12 +1711,18 @@ static struct hlsl_ir_node *add_unary_arithmetic_expr(struct hlsl_ctx *ctx, stru + { + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {arg}; + ++ if (arg->data_type->class == HLSL_CLASS_ERROR) ++ return arg; ++ + return add_expr(ctx, block, op, args, arg->data_type, loc); + } + + static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, + enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) + { ++ if (arg->data_type->class == HLSL_CLASS_ERROR) ++ return arg; ++ + check_integer_type(ctx, arg); + + return add_unary_arithmetic_expr(ctx, block, op, arg, loc); +@@ -1727,6 +1734,9 @@ static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; + struct hlsl_type *bool_type; + ++ if (arg->data_type->class == HLSL_CLASS_ERROR) ++ return arg; ++ + bool_type = hlsl_get_numeric_type(ctx, arg->data_type->class, HLSL_TYPE_BOOL, + arg->data_type->dimx, arg->data_type->dimy); + +@@ -1756,7 +1766,11 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str + struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; + struct hlsl_type *common_type; + +- common_type = get_common_numeric_type(ctx, arg1, arg2, loc); ++ if (!(common_type = get_common_numeric_type(ctx, arg1, arg2, loc))) ++ { ++ block->value = ctx->error_instr; ++ return block->value; ++ } + + if (!(args[0] = add_implicit_conversion(ctx, block, arg1, common_type, loc))) + return NULL; +@@ -2059,18 +2073,17 @@ static bool invert_swizzle_matrix(uint32_t *swizzle, unsigned int *writemask, un + return true; + } + +-static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *lhs, ++static bool add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *lhs, + enum parse_assign_op assign_op, struct hlsl_ir_node *rhs) + { + struct hlsl_type *lhs_type = lhs->data_type; +- struct hlsl_ir_node *copy; + unsigned int writemask = 0, width = 0; + bool matrix_writemask = false; + + if (assign_op == ASSIGN_OP_SUB) + { + if (!(rhs = add_unary_arithmetic_expr(ctx, block, HLSL_OP1_NEG, rhs, &rhs->loc))) +- return NULL; ++ return false; + assign_op = ASSIGN_OP_ADD; + } + if (assign_op != ASSIGN_OP_ASSIGN) +@@ -2079,7 +2092,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + + VKD3D_ASSERT(op); + if (!(rhs = add_binary_expr(ctx, block, op, lhs, rhs, &rhs->loc))) +- return NULL; ++ return false; + } + + if (hlsl_is_numeric_type(lhs_type)) +@@ -2089,14 +2102,14 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + } + + if (!(rhs = add_implicit_conversion(ctx, block, rhs, lhs_type, &rhs->loc))) +- return NULL; ++ return false; + + while (lhs->type != HLSL_IR_LOAD && lhs->type != HLSL_IR_INDEX) + { + if (lhs->type == HLSL_IR_EXPR && hlsl_ir_expr(lhs)->op == HLSL_OP1_CAST) + { + hlsl_fixme(ctx, &lhs->loc, "Cast on the LHS."); +- return NULL; ++ return false; + } + else if (lhs->type == HLSL_IR_SWIZZLE) + { +@@ -2111,25 +2124,23 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + if (swizzle->val.node->type != HLSL_IR_LOAD && swizzle->val.node->type != HLSL_IR_INDEX) + { + hlsl_fixme(ctx, &lhs->loc, "Unhandled source of matrix swizzle."); +- return NULL; ++ return false; + } + if (!invert_swizzle_matrix(&s, &writemask, &width)) + { + hlsl_error(ctx, &lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_WRITEMASK, "Invalid writemask for matrix."); +- return NULL; ++ return false; + } + matrix_writemask = true; + } + else if (!invert_swizzle(&s, &writemask, &width)) + { + hlsl_error(ctx, &lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_WRITEMASK, "Invalid writemask."); +- return NULL; ++ return false; + } + + if (!(new_swizzle = hlsl_new_swizzle(ctx, s, width, rhs, &swizzle->node.loc))) +- { +- return NULL; +- } ++ return false; + hlsl_block_add_instr(block, new_swizzle); + + lhs = swizzle->val.node; +@@ -2138,7 +2149,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + else + { + hlsl_error(ctx, &lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_LVALUE, "Invalid lvalue."); +- return NULL; ++ return false; + } + } + +@@ -2153,11 +2164,11 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + if (!hlsl_index_is_resource_access(hlsl_ir_index(lhs))) + { + hlsl_fixme(ctx, &lhs->loc, "Non-direct structured resource store."); +- return NULL; ++ return false; + } + + if (!hlsl_init_deref_from_index_chain(ctx, &resource_deref, hlsl_ir_index(lhs)->val.node)) +- return NULL; ++ return false; + + resource_type = hlsl_deref_get_type(ctx, &resource_deref); + VKD3D_ASSERT(resource_type->class == HLSL_CLASS_TEXTURE || resource_type->class == HLSL_CLASS_UAV); +@@ -2179,7 +2190,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + if (!(store = hlsl_new_resource_store(ctx, &resource_deref, coords, rhs, &lhs->loc))) + { + hlsl_cleanup_deref(&resource_deref); +- return NULL; ++ return false; + } + hlsl_block_add_instr(block, store); + hlsl_cleanup_deref(&resource_deref); +@@ -2206,13 +2217,13 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + if (!(load = hlsl_add_load_component(ctx, block, rhs, k++, &rhs->loc))) + { + hlsl_cleanup_deref(&deref); +- return NULL; ++ return false; + } + + if (!hlsl_new_store_component(ctx, &store_block, &deref, component, load)) + { + hlsl_cleanup_deref(&deref); +- return NULL; ++ return false; + } + hlsl_block_add_block(block, &store_block); + } +@@ -2237,23 +2248,23 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + continue; + + if (!(c = hlsl_new_uint_constant(ctx, i, &lhs->loc))) +- return NULL; ++ return false; + hlsl_block_add_instr(block, c); + + if (!(cell = hlsl_new_index(ctx, &row->node, c, &lhs->loc))) +- return NULL; ++ return false; + hlsl_block_add_instr(block, cell); + + if (!(load = hlsl_add_load_component(ctx, block, rhs, k++, &rhs->loc))) +- return NULL; ++ return false; + + if (!hlsl_init_deref_from_index_chain(ctx, &deref, cell)) +- return NULL; ++ return false; + + if (!(store = hlsl_new_store_index(ctx, &deref, NULL, load, 0, &rhs->loc))) + { + hlsl_cleanup_deref(&deref); +- return NULL; ++ return false; + } + hlsl_block_add_instr(block, store); + hlsl_cleanup_deref(&deref); +@@ -2265,24 +2276,19 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo + struct hlsl_deref deref; + + if (!hlsl_init_deref_from_index_chain(ctx, &deref, lhs)) +- return NULL; ++ return false; + + if (!(store = hlsl_new_store_index(ctx, &deref, NULL, rhs, writemask, &rhs->loc))) + { + hlsl_cleanup_deref(&deref); +- return NULL; ++ return false; + } + hlsl_block_add_instr(block, store); + hlsl_cleanup_deref(&deref); + } + +- /* Don't use the instruction itself as a source, as this makes structure +- * splitting easier. Instead copy it here. Since we retrieve sources from +- * the last instruction in the list, we do need to copy. */ +- if (!(copy = hlsl_new_copy(ctx, rhs))) +- return NULL; +- hlsl_block_add_instr(block, copy); +- return copy; ++ block->value = rhs; ++ return true; + } + + static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool decrement, bool post, +@@ -5340,11 +5346,6 @@ static bool add_ternary(struct hlsl_ctx *ctx, struct hlsl_block *block, + } + else + { +- cond_type = hlsl_get_numeric_type(ctx, cond_type->class, HLSL_TYPE_BOOL, +- cond_type->dimx, cond_type->dimy); +- if (!(cond = add_implicit_conversion(ctx, block, cond, cond_type, &cond->loc))) +- return false; +- + if (common_type->dimx == 1 && common_type->dimy == 1) + { + common_type = hlsl_get_numeric_type(ctx, cond_type->class, +@@ -5366,6 +5367,11 @@ static bool add_ternary(struct hlsl_ctx *ctx, struct hlsl_block *block, + hlsl_release_string_buffer(ctx, cond_string); + hlsl_release_string_buffer(ctx, value_string); + } ++ ++ cond_type = hlsl_get_numeric_type(ctx, common_type->class, HLSL_TYPE_BOOL, ++ common_type->dimx, common_type->dimy); ++ if (!(cond = add_implicit_conversion(ctx, block, cond, cond_type, &cond->loc))) ++ return false; + } + + if (!(first = add_implicit_conversion(ctx, block, first, common_type, &first->loc))) +@@ -6296,7 +6302,6 @@ static bool state_block_add_entry(struct hlsl_state_block *state_block, struct h + %token KW_DISCARD + %token KW_DO + %token KW_DOMAINSHADER +-%token KW_DOUBLE + %token KW_ELSE + %token KW_EXPORT + %token KW_EXTERN +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +index 6cae0e3b5c9..feab6cf06c1 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +@@ -1655,11 +1655,16 @@ static bool copy_propagation_transform_load(struct hlsl_ctx *ctx, + case HLSL_CLASS_MATRIX: + case HLSL_CLASS_ARRAY: + case HLSL_CLASS_STRUCT: +- case HLSL_CLASS_CONSTANT_BUFFER: +- /* FIXME: Actually we shouldn't even get here, but we don't split +- * matrices yet. */ ++ /* We can't handle complex types here. ++ * They should have been already split anyway by earlier passes, ++ * but they may not have been deleted yet. We can't rely on DCE to ++ * solve that problem for us, since we may be called on a partial ++ * block, but DCE deletes dead stores, so it needs to be able to ++ * see the whole program. */ ++ case HLSL_CLASS_ERROR: + return false; + ++ case HLSL_CLASS_CONSTANT_BUFFER: + case HLSL_CLASS_EFFECT_GROUP: + case HLSL_CLASS_PASS: + case HLSL_CLASS_TECHNIQUE: +@@ -6622,7 +6627,13 @@ static bool sm1_generate_vsir_instr_expr_cast(struct hlsl_ctx *ctx, + return true; + + case HLSL_TYPE_DOUBLE: +- hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to float."); ++ if (ctx->double_as_float_alias) ++ { ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); ++ return true; ++ } ++ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, ++ "The 'double' type is not supported for the %s profile.", ctx->profile->name); + break; + + default: +@@ -6660,7 +6671,22 @@ static bool sm1_generate_vsir_instr_expr_cast(struct hlsl_ctx *ctx, + break; + + case HLSL_TYPE_DOUBLE: +- hlsl_fixme(ctx, &instr->loc, "SM1 cast to double."); ++ switch (src_type->e.numeric.type) ++ { ++ case HLSL_TYPE_FLOAT: ++ if (ctx->double_as_float_alias) ++ { ++ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); ++ return true; ++ } ++ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, ++ "The 'double' type is not supported for the %s profile.", ctx->profile->name); ++ break; ++ ++ default: ++ hlsl_fixme(ctx, &instr->loc, "SM1 cast to double."); ++ break; ++ } + break; + + case HLSL_TYPE_BOOL: +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 7f1e0fea2c3..1876ad38653 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -394,6 +394,7 @@ struct vkd3d_spirv_builder + uint32_t type_bool_id; + uint32_t type_void_id; + uint32_t scope_subgroup_id; ++ uint32_t numeric_type_ids[VKD3D_SHADER_COMPONENT_TYPE_COUNT][VKD3D_VEC4_SIZE]; + + struct vkd3d_spirv_stream debug_stream; /* debug instructions */ + struct vkd3d_spirv_stream annotation_stream; /* decoration instructions */ +@@ -1902,29 +1903,37 @@ static uint32_t vkd3d_spirv_build_op_glsl_std450_nclamp(struct vkd3d_spirv_build + static uint32_t vkd3d_spirv_get_type_id(struct vkd3d_spirv_builder *builder, + enum vkd3d_shader_component_type component_type, unsigned int component_count) + { +- uint32_t scalar_id; ++ uint32_t scalar_id, type_id; ++ ++ VKD3D_ASSERT(component_type < VKD3D_SHADER_COMPONENT_TYPE_COUNT); ++ VKD3D_ASSERT(1 <= component_count && component_count <= VKD3D_VEC4_SIZE); ++ ++ if ((type_id = builder->numeric_type_ids[component_type][component_count - 1])) ++ return type_id; + + if (component_count == 1) + { + switch (component_type) + { + case VKD3D_SHADER_COMPONENT_VOID: +- return vkd3d_spirv_get_op_type_void(builder); ++ type_id = vkd3d_spirv_get_op_type_void(builder); + break; + case VKD3D_SHADER_COMPONENT_FLOAT: +- return vkd3d_spirv_get_op_type_float(builder, 32); ++ type_id = vkd3d_spirv_get_op_type_float(builder, 32); + break; + case VKD3D_SHADER_COMPONENT_INT: + case VKD3D_SHADER_COMPONENT_UINT: +- return vkd3d_spirv_get_op_type_int(builder, 32, component_type == VKD3D_SHADER_COMPONENT_INT); ++ type_id = vkd3d_spirv_get_op_type_int(builder, 32, component_type == VKD3D_SHADER_COMPONENT_INT); + break; + case VKD3D_SHADER_COMPONENT_BOOL: +- return vkd3d_spirv_get_op_type_bool(builder); ++ type_id = vkd3d_spirv_get_op_type_bool(builder); + break; + case VKD3D_SHADER_COMPONENT_DOUBLE: +- return vkd3d_spirv_get_op_type_float(builder, 64); ++ type_id = vkd3d_spirv_get_op_type_float(builder, 64); ++ break; + case VKD3D_SHADER_COMPONENT_UINT64: +- return vkd3d_spirv_get_op_type_int(builder, 64, 0); ++ type_id = vkd3d_spirv_get_op_type_int(builder, 64, 0); ++ break; + default: + FIXME("Unhandled component type %#x.\n", component_type); + return 0; +@@ -1934,46 +1943,21 @@ static uint32_t vkd3d_spirv_get_type_id(struct vkd3d_spirv_builder *builder, + { + VKD3D_ASSERT(component_type != VKD3D_SHADER_COMPONENT_VOID); + scalar_id = vkd3d_spirv_get_type_id(builder, component_type, 1); +- return vkd3d_spirv_get_op_type_vector(builder, scalar_id, component_count); ++ type_id = vkd3d_spirv_get_op_type_vector(builder, scalar_id, component_count); + } ++ ++ builder->numeric_type_ids[component_type][component_count - 1] = type_id; ++ ++ return type_id; + } + + static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder *builder, + enum vkd3d_data_type data_type, unsigned int component_count) + { +- uint32_t scalar_id; ++ enum vkd3d_shader_component_type component_type; + +- if (component_count == 1) +- { +- switch (data_type) +- { +- case VKD3D_DATA_HALF: /* Minimum precision. TODO: native 16-bit */ +- case VKD3D_DATA_FLOAT: +- case VKD3D_DATA_SNORM: +- case VKD3D_DATA_UNORM: +- return vkd3d_spirv_get_op_type_float(builder, 32); +- break; +- case VKD3D_DATA_INT: +- case VKD3D_DATA_UINT: +- case VKD3D_DATA_UINT16: /* Minimum precision. TODO: native 16-bit */ +- return vkd3d_spirv_get_op_type_int(builder, 32, data_type == VKD3D_DATA_INT); +- break; +- case VKD3D_DATA_DOUBLE: +- return vkd3d_spirv_get_op_type_float(builder, 64); +- case VKD3D_DATA_UINT64: +- return vkd3d_spirv_get_op_type_int(builder, 64, 0); +- case VKD3D_DATA_BOOL: +- return vkd3d_spirv_get_op_type_bool(builder); +- default: +- FIXME("Unhandled data type %#x.\n", data_type); +- return 0; +- } +- } +- else +- { +- scalar_id = vkd3d_spirv_get_type_id_for_data_type(builder, data_type, 1); +- return vkd3d_spirv_get_op_type_vector(builder, scalar_id, component_count); +- } ++ component_type = vkd3d_component_type_from_data_type(data_type); ++ return vkd3d_spirv_get_type_id(builder, component_type, component_count); + } + + static void vkd3d_spirv_builder_init(struct vkd3d_spirv_builder *builder, const char *entry_point) +diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c +index 884a2998d5b..ab9f4cf2b57 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c ++++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c +@@ -3236,6 +3236,7 @@ static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type) + case HLSL_CLASS_DEPTH_STENCIL_STATE: + case HLSL_CLASS_DEPTH_STENCIL_VIEW: + case HLSL_CLASS_EFFECT_GROUP: ++ case HLSL_CLASS_ERROR: + case HLSL_CLASS_STRUCT: + case HLSL_CLASS_PASS: + case HLSL_CLASS_PIXEL_SHADER: +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index 447210449da..7ac86e35227 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -59,6 +59,8 @@ + #define VKD3D_VEC4_SIZE 4 + #define VKD3D_DVEC2_SIZE 2 + ++#define VKD3D_SHADER_COMPONENT_TYPE_COUNT (VKD3D_SHADER_COMPONENT_UINT64 + 1) ++ + enum vkd3d_shader_error + { + VKD3D_SHADER_ERROR_DXBC_INVALID_SIZE = 1, +diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c +index ea7d8f040b5..fb377177403 100644 +--- a/libs/vkd3d/libs/vkd3d/state.c ++++ b/libs/vkd3d/libs/vkd3d/state.c +@@ -1107,7 +1107,9 @@ static int compare_descriptor_range(const void *a, const void *b) + if ((ret = vkd3d_u32_compare(range_a->offset, range_b->offset))) + return ret; + +- return (range_a->descriptor_count == UINT_MAX) - (range_b->descriptor_count == UINT_MAX); ++ /* Place bounded ranges after unbounded ones of equal offset, ++ * so the bounded range can be mapped to the unbounded one. */ ++ return (range_b->descriptor_count == UINT_MAX) - (range_a->descriptor_count == UINT_MAX); + } + + static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_root_signature *root_signature, +-- +2.45.2 + diff --git a/patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch b/patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch deleted file mode 100644 index 0e162ac8..00000000 --- a/patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch +++ /dev/null @@ -1,619 +0,0 @@ -From e48d811509a661939136b1567d165fc400a38784 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Fri, 6 Sep 2024 08:13:50 +1000 -Subject: [PATCH] Updated vkd3d to bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a3282c1f9. - ---- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 98 +++++++++++----------- - libs/vkd3d/libs/vkd3d-shader/ir.c | 121 ++++++++++++++++----------- - 2 files changed, 121 insertions(+), 98 deletions(-) - -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index 3b9ec98448d..de5f28c1815 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -1862,7 +1862,7 @@ void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buff - set_u32(buffer, creator_offset, offset - ctab_start); - - ctab_end = bytecode_align(buffer); -- set_u32(buffer, size_offset, vkd3d_make_u32(D3DSIO_COMMENT, (ctab_end - ctab_offset) / sizeof(uint32_t))); -+ set_u32(buffer, size_offset, vkd3d_make_u32(VKD3D_SM1_OP_COMMENT, (ctab_end - ctab_offset) / sizeof(uint32_t))); - } - - static uint32_t sm1_encode_register_type(enum vkd3d_shader_register_type type) -@@ -1873,7 +1873,7 @@ static uint32_t sm1_encode_register_type(enum vkd3d_shader_register_type type) - - struct sm1_instruction - { -- D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode; -+ enum vkd3d_sm1_opcode opcode; - unsigned int flags; - - struct sm1_dst_register -@@ -1902,7 +1902,7 @@ static bool is_inconsequential_instr(const struct sm1_instruction *instr) - const struct sm1_dst_register *dst = &instr->dst; - unsigned int i; - -- if (instr->opcode != D3DSIO_MOV) -+ if (instr->opcode != VKD3D_SM1_OP_MOV) - return false; - if (dst->mod != D3DSPDM_NONE) - return false; -@@ -1947,7 +1947,7 @@ static void d3dbc_write_instruction(struct d3dbc_compiler *d3dbc, const struct s - token |= VKD3D_SM1_INSTRUCTION_FLAGS_MASK & (instr->flags << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT); - - if (version->major > 1) -- token |= (instr->has_dst + instr->src_count) << D3DSI_INSTLENGTH_SHIFT; -+ token |= (instr->has_dst + instr->src_count) << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; - put_u32(buffer, token); - - if (instr->has_dst) -@@ -1967,7 +1967,7 @@ static void d3dbc_write_dp2add(struct d3dbc_compiler *d3dbc, const struct hlsl_r - { - struct sm1_instruction instr = - { -- .opcode = D3DSIO_DP2ADD, -+ .opcode = VKD3D_SM1_OP_DP2ADD, - - .dst.type = VKD3DSPR_TEMP, - .dst.writemask = dst->writemask, -@@ -1989,9 +1989,9 @@ static void d3dbc_write_dp2add(struct d3dbc_compiler *d3dbc, const struct hlsl_r - d3dbc_write_instruction(d3dbc, &instr); - } - --static void d3dbc_write_ternary_op(struct d3dbc_compiler *d3dbc, -- D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, const struct hlsl_reg *dst, -- const struct hlsl_reg *src1, const struct hlsl_reg *src2, const struct hlsl_reg *src3) -+static void d3dbc_write_ternary_op(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, -+ const struct hlsl_reg *dst, const struct hlsl_reg *src1, -+ const struct hlsl_reg *src2, const struct hlsl_reg *src3) - { - struct sm1_instruction instr = - { -@@ -2020,7 +2020,7 @@ static void d3dbc_write_ternary_op(struct d3dbc_compiler *d3dbc, - d3dbc_write_instruction(d3dbc, &instr); - } - --static void d3dbc_write_binary_op(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, -+static void d3dbc_write_binary_op(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, - const struct hlsl_reg *dst, const struct hlsl_reg *src1, const struct hlsl_reg *src2) - { - struct sm1_instruction instr = -@@ -2046,7 +2046,7 @@ static void d3dbc_write_binary_op(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRU - d3dbc_write_instruction(d3dbc, &instr); - } - --static void d3dbc_write_dot(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, -+static void d3dbc_write_dot(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, - const struct hlsl_reg *dst, const struct hlsl_reg *src1, const struct hlsl_reg *src2) - { - struct sm1_instruction instr = -@@ -2070,7 +2070,7 @@ static void d3dbc_write_dot(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRUCTION_ - d3dbc_write_instruction(d3dbc, &instr); - } - --static void d3dbc_write_unary_op(struct d3dbc_compiler *d3dbc, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode, -+static void d3dbc_write_unary_op(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, - const struct hlsl_reg *dst, const struct hlsl_reg *src, - D3DSHADER_PARAM_SRCMOD_TYPE src_mod, D3DSHADER_PARAM_DSTMOD_TYPE dst_mod) - { -@@ -2118,7 +2118,7 @@ static void d3dbc_write_cast(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - /* Integrals are internally represented as floats, so no change is necessary.*/ - case HLSL_TYPE_HALF: - case HLSL_TYPE_FLOAT: -- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, 0); - break; - - case HLSL_TYPE_DOUBLE: -@@ -2142,7 +2142,7 @@ static void d3dbc_write_cast(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - break; - case HLSL_TYPE_INT: - case HLSL_TYPE_UINT: -- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, 0); - break; - - case HLSL_TYPE_BOOL: -@@ -2353,7 +2353,7 @@ static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, - return; - } - -- instr.opcode = (D3DSHADER_INSTRUCTION_OPCODE_TYPE)info->sm1_opcode; -+ instr.opcode = info->sm1_opcode; - instr.has_dst = info->dst_count; - instr.src_count = info->src_count; - -@@ -2413,9 +2413,9 @@ static void d3dbc_write_semantic_dcl(struct d3dbc_compiler *d3dbc, - reg.reg = element->register_index; - } - -- token = D3DSIO_DCL; -+ token = VKD3D_SM1_OP_DCL; - if (version->major > 1) -- token |= 2 << D3DSI_INSTLENGTH_SHIFT; -+ token |= 2 << VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; - put_u32(buffer, token); - - token = (1u << 31); -@@ -2455,7 +2455,7 @@ static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc) - } - - static void d3dbc_write_per_component_unary_op(struct d3dbc_compiler *d3dbc, -- const struct hlsl_ir_node *instr, D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode) -+ const struct hlsl_ir_node *instr, enum vkd3d_sm1_opcode opcode) - { - struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); - struct hlsl_ir_node *arg1 = expr->operands[0].node; -@@ -2476,7 +2476,7 @@ static void d3dbc_write_sincos(struct d3dbc_compiler *d3dbc, enum hlsl_ir_expr_o - { - struct sm1_instruction instr = - { -- .opcode = D3DSIO_SINCOS, -+ .opcode = VKD3D_SM1_OP_SINCOS, - - .dst.type = VKD3DSPR_TEMP, - .dst.writemask = dst->writemask, -@@ -2523,7 +2523,7 @@ static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - - if (expr->op == HLSL_OP1_REINTERPRET) - { -- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, 0); - return; - } - -@@ -2543,39 +2543,39 @@ static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - switch (expr->op) - { - case HLSL_OP1_ABS: -- d3dbc_write_unary_op(d3dbc, D3DSIO_ABS, &instr->reg, &arg1->reg, 0, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_ABS, &instr->reg, &arg1->reg, 0, 0); - break; - - case HLSL_OP1_DSX: -- d3dbc_write_unary_op(d3dbc, D3DSIO_DSX, &instr->reg, &arg1->reg, 0, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_DSX, &instr->reg, &arg1->reg, 0, 0); - break; - - case HLSL_OP1_DSY: -- d3dbc_write_unary_op(d3dbc, D3DSIO_DSY, &instr->reg, &arg1->reg, 0, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_DSY, &instr->reg, &arg1->reg, 0, 0); - break; - - case HLSL_OP1_EXP2: -- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_EXP); -+ d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_EXP); - break; - - case HLSL_OP1_LOG2: -- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_LOG); -+ d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_LOG); - break; - - case HLSL_OP1_NEG: -- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, D3DSPSM_NEG, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, D3DSPSM_NEG, 0); - break; - - case HLSL_OP1_SAT: -- d3dbc_write_unary_op(d3dbc, D3DSIO_MOV, &instr->reg, &arg1->reg, 0, D3DSPDM_SATURATE); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, D3DSPDM_SATURATE); - break; - - case HLSL_OP1_RCP: -- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_RCP); -+ d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_RCP); - break; - - case HLSL_OP1_RSQ: -- d3dbc_write_per_component_unary_op(d3dbc, instr, D3DSIO_RSQ); -+ d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_RSQ); - break; - - case HLSL_OP1_COS_REDUCED: -@@ -2584,34 +2584,34 @@ static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - break; - - case HLSL_OP2_ADD: -- d3dbc_write_binary_op(d3dbc, D3DSIO_ADD, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_ADD, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case HLSL_OP2_MAX: -- d3dbc_write_binary_op(d3dbc, D3DSIO_MAX, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MAX, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case HLSL_OP2_MIN: -- d3dbc_write_binary_op(d3dbc, D3DSIO_MIN, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MIN, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case HLSL_OP2_MUL: -- d3dbc_write_binary_op(d3dbc, D3DSIO_MUL, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MUL, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case HLSL_OP1_FRACT: -- d3dbc_write_unary_op(d3dbc, D3DSIO_FRC, &instr->reg, &arg1->reg, D3DSPSM_NONE, 0); -+ d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_FRC, &instr->reg, &arg1->reg, D3DSPSM_NONE, 0); - break; - - case HLSL_OP2_DOT: - switch (arg1->data_type->dimx) - { - case 4: -- d3dbc_write_dot(d3dbc, D3DSIO_DP4, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_dot(d3dbc, VKD3D_SM1_OP_DP4, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case 3: -- d3dbc_write_dot(d3dbc, D3DSIO_DP3, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_dot(d3dbc, VKD3D_SM1_OP_DP3, &instr->reg, &arg1->reg, &arg2->reg); - break; - - default: -@@ -2620,23 +2620,23 @@ static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - break; - - case HLSL_OP2_LOGIC_AND: -- d3dbc_write_binary_op(d3dbc, D3DSIO_MIN, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MIN, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case HLSL_OP2_LOGIC_OR: -- d3dbc_write_binary_op(d3dbc, D3DSIO_MAX, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MAX, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case HLSL_OP2_SLT: - if (version->type == VKD3D_SHADER_TYPE_PIXEL) - hlsl_fixme(ctx, &instr->loc, "Lower SLT instructions for pixel shaders."); -- d3dbc_write_binary_op(d3dbc, D3DSIO_SLT, &instr->reg, &arg1->reg, &arg2->reg); -+ d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_SLT, &instr->reg, &arg1->reg, &arg2->reg); - break; - - case HLSL_OP3_CMP: - if (version->type == VKD3D_SHADER_TYPE_VERTEX) - hlsl_fixme(ctx, &instr->loc, "Lower CMP instructions for vertex shaders."); -- d3dbc_write_ternary_op(d3dbc, D3DSIO_CMP, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); -+ d3dbc_write_ternary_op(d3dbc, VKD3D_SM1_OP_CMP, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); - break; - - case HLSL_OP3_DP2ADD: -@@ -2644,7 +2644,7 @@ static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - break; - - case HLSL_OP3_MAD: -- d3dbc_write_ternary_op(d3dbc, D3DSIO_MAD, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); -+ d3dbc_write_ternary_op(d3dbc, VKD3D_SM1_OP_MAD, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); - break; - - default: -@@ -2666,7 +2666,7 @@ static void d3dbc_write_if(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_no - - sm1_ifc = (struct sm1_instruction) - { -- .opcode = D3DSIO_IFC, -+ .opcode = VKD3D_SM1_OP_IFC, - .flags = VKD3D_SHADER_REL_OP_NE, /* Make it a "if_ne" instruction. */ - - .srcs[0].type = VKD3DSPR_TEMP, -@@ -2686,12 +2686,12 @@ static void d3dbc_write_if(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_no - - if (!list_empty(&iff->else_block.instrs)) - { -- sm1_else = (struct sm1_instruction){.opcode = D3DSIO_ELSE}; -+ sm1_else = (struct sm1_instruction){.opcode = VKD3D_SM1_OP_ELSE}; - d3dbc_write_instruction(d3dbc, &sm1_else); - d3dbc_write_block(d3dbc, &iff->else_block); - } - -- sm1_endif = (struct sm1_instruction){.opcode = D3DSIO_ENDIF}; -+ sm1_endif = (struct sm1_instruction){.opcode = VKD3D_SM1_OP_ENDIF}; - d3dbc_write_instruction(d3dbc, &sm1_endif); - } - -@@ -2707,7 +2707,7 @@ static void d3dbc_write_jump(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - - struct sm1_instruction sm1_instr = - { -- .opcode = D3DSIO_TEXKILL, -+ .opcode = VKD3D_SM1_OP_TEXKILL, - - .dst.type = VKD3DSPR_TEMP, - .dst.reg = reg->id, -@@ -2758,21 +2758,21 @@ static void d3dbc_write_resource_load(struct d3dbc_compiler *d3dbc, const struct - switch (load->load_type) - { - case HLSL_RESOURCE_SAMPLE: -- sm1_instr.opcode = D3DSIO_TEX; -+ sm1_instr.opcode = VKD3D_SM1_OP_TEX; - break; - - case HLSL_RESOURCE_SAMPLE_PROJ: -- sm1_instr.opcode = D3DSIO_TEX; -+ sm1_instr.opcode = VKD3D_SM1_OP_TEX; - sm1_instr.opcode |= VKD3DSI_TEXLD_PROJECT << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT; - break; - - case HLSL_RESOURCE_SAMPLE_LOD_BIAS: -- sm1_instr.opcode = D3DSIO_TEX; -+ sm1_instr.opcode = VKD3D_SM1_OP_TEX; - sm1_instr.opcode |= VKD3DSI_TEXLD_BIAS << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT; - break; - - case HLSL_RESOURCE_SAMPLE_GRAD: -- sm1_instr.opcode = D3DSIO_TEXLDD; -+ sm1_instr.opcode = VKD3D_SM1_OP_TEXLDD; - - sm1_instr.srcs[2].type = VKD3DSPR_TEMP; - sm1_instr.srcs[2].reg = ddx->reg.id; -@@ -2889,7 +2889,7 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, - d3dbc_write_semantic_dcls(&d3dbc); - d3dbc_write_block(&d3dbc, &entry_func->body); - -- put_u32(buffer, D3DSIO_END); -+ put_u32(buffer, VKD3D_SM1_OP_END); - - result = ctx->result; - if (buffer->status) -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index d765abc938b..a483c25f3ad 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -19,6 +19,15 @@ - #include "vkd3d_shader_private.h" - #include "vkd3d_types.h" - -+struct vsir_normalisation_context -+{ -+ enum vkd3d_result result; -+ struct vsir_program *program; -+ uint64_t config_flags; -+ const struct vkd3d_shader_compile_info *compile_info; -+ struct vkd3d_shader_message_context *message_context; -+}; -+ - static int convert_parameter_info(const struct vkd3d_shader_compile_info *compile_info, - unsigned int *ret_count, const struct vkd3d_shader_parameter1 **ret_parameters) - { -@@ -442,9 +451,10 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog - } - - static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *program, -- struct vkd3d_shader_message_context *message_context) -+ struct vsir_normalisation_context *ctx) - { - struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct vkd3d_shader_message_context *message_context = ctx->message_context; - unsigned int tmp_idx = ~0u, i; - enum vkd3d_result ret; - -@@ -1755,8 +1765,7 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program - { - struct io_normaliser normaliser = {program->instructions}; - struct vkd3d_shader_instruction *ins; -- bool has_control_point_phase; -- unsigned int i, j; -+ unsigned int i; - - normaliser.phase = VKD3DSIH_INVALID; - normaliser.shader_type = program->shader_version.type; -@@ -1765,7 +1774,7 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program - normaliser.output_signature = &program->output_signature; - normaliser.patch_constant_signature = &program->patch_constant_signature; - -- for (i = 0, has_control_point_phase = false; i < program->instructions.count; ++i) -+ for (i = 0; i < program->instructions.count; ++i) - { - ins = &program->instructions.elements[i]; - -@@ -1779,8 +1788,6 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program - vkd3d_shader_instruction_make_nop(ins); - break; - case VKD3DSIH_HS_CONTROL_POINT_PHASE: -- has_control_point_phase = true; -- /* fall through */ - case VKD3DSIH_HS_FORK_PHASE: - case VKD3DSIH_HS_JOIN_PHASE: - normaliser.phase = ins->opcode; -@@ -1790,22 +1797,6 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program - } - } - -- if (normaliser.shader_type == VKD3D_SHADER_TYPE_HULL && !has_control_point_phase) -- { -- /* Inputs and outputs must match for the default phase, so merge ranges must match too. */ -- for (i = 0; i < MAX_REG_OUTPUT; ++i) -- { -- for (j = 0; j < VKD3D_VEC4_SIZE; ++j) -- { -- if (!normaliser.input_range_map[i][j] && normaliser.output_range_map[i][j]) -- normaliser.input_range_map[i][j] = normaliser.output_range_map[i][j]; -- else if (normaliser.input_range_map[i][j] && !normaliser.output_range_map[i][j]) -- normaliser.output_range_map[i][j] = normaliser.input_range_map[i][j]; -- else VKD3D_ASSERT(normaliser.input_range_map[i][j] == normaliser.output_range_map[i][j]); -- } -- } -- } -- - if (!shader_signature_merge(&program->input_signature, normaliser.input_range_map, false) - || !shader_signature_merge(&program->output_signature, normaliser.output_range_map, false) - || !shader_signature_merge(&program->patch_constant_signature, normaliser.pc_range_map, true)) -@@ -2789,8 +2780,9 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte - } - - static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsir_program *program, -- struct vkd3d_shader_message_context *message_context) -+ struct vsir_normalisation_context *ctx) - { -+ struct vkd3d_shader_message_context *message_context = ctx->message_context; - struct cf_flattener flattener = {.program = program}; - enum vkd3d_result result; - -@@ -2860,7 +2852,8 @@ static bool lower_switch_to_if_ladder_add_block_mapping(struct lower_switch_to_i - return true; - } - --static enum vkd3d_result lower_switch_to_if_ladder(struct vsir_program *program) -+static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vsir_program *program, -+ struct vsir_normalisation_context *ctx) - { - unsigned int block_count = program->block_count, ssa_count = program->ssa_count, current_label = 0, if_label; - size_t ins_capacity = 0, ins_count = 0, i, map_capacity = 0, map_count = 0; -@@ -3050,7 +3043,8 @@ static void ssas_to_temps_block_info_cleanup(struct ssas_to_temps_block_info *bl - vkd3d_free(block_info); - } - --static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps(struct vsir_program *program) -+static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps(struct vsir_program *program, -+ struct vsir_normalisation_context *ctx) - { - size_t ins_capacity = 0, ins_count = 0, phi_count, incoming_count, i; - struct ssas_to_temps_block_info *info, *block_info = NULL; -@@ -5271,8 +5265,9 @@ out: - } - - static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, -- struct vkd3d_shader_message_context *message_context) -+ struct vsir_normalisation_context *ctx) - { -+ struct vkd3d_shader_message_context *message_context = ctx->message_context; - struct vsir_cfg_emit_target target = {0}; - enum vkd3d_result ret; - size_t i; -@@ -5451,8 +5446,9 @@ static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps_in_f - } - - static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps(struct vsir_program *program, -- struct vkd3d_shader_message_context *message_context) -+ struct vsir_normalisation_context *ctx) - { -+ struct vkd3d_shader_message_context *message_context = ctx->message_context; - enum vkd3d_result ret; - size_t i; - -@@ -5731,14 +5727,14 @@ static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *c - if (ctx->invalid_instruction_idx) - { - vkd3d_shader_error(ctx->message_context, &ctx->null_location, error, "%s", buf.buffer); -- ERR("VSIR validation error: %s\n", buf.buffer); -+ WARN("VSIR validation error: %s\n", buf.buffer); - } - else - { - const struct vkd3d_shader_instruction *ins = &ctx->program->instructions.elements[ctx->instruction_idx]; - vkd3d_shader_error(ctx->message_context, &ins->location, error, - "instruction %zu: %s", ctx->instruction_idx + 1, buf.buffer); -- ERR("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer); -+ WARN("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer); - } - - vkd3d_string_buffer_cleanup(&buf); -@@ -6243,12 +6239,13 @@ static void vsir_validate_instruction(struct validation_context *ctx) - /* We support two different control flow types in shaders: - * block-based, like DXIL and SPIR-V, and structured, like D3DBC - * and TPF. The shader is detected as block-based when its first -- * instruction, except for DCL_* and phases, is a LABEL. Currently -- * we mandate that each shader is either purely block-based or -+ * instruction, except for NOP, DCL_* and phases, is a LABEL. -+ * Currently we mandate that each shader is either purely block-based or - * purely structured. In principle we could allow structured - * constructs in a block, provided they are confined in a single - * block, but need for that hasn't arisen yet, so we don't. */ -- if (ctx->cf_type == CF_TYPE_UNKNOWN && !vsir_instruction_is_dcl(instruction)) -+ if (ctx->cf_type == CF_TYPE_UNKNOWN && instruction->opcode != VKD3DSIH_NOP -+ && !vsir_instruction_is_dcl(instruction)) - { - if (instruction->opcode == VKD3DSIH_LABEL) - ctx->cf_type = CF_TYPE_BLOCKS; -@@ -6610,33 +6607,59 @@ fail: - return VKD3D_ERROR_OUT_OF_MEMORY; - } - --enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, -- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) -+#define vsir_transform(ctx, step) vsir_transform_(ctx, #step, step) -+static void vsir_transform_( -+ struct vsir_normalisation_context *ctx, const char *step_name, -+ enum vkd3d_result (*step)(struct vsir_program *program, struct vsir_normalisation_context *ctx)) - { -- enum vkd3d_result result = VKD3D_OK; -+ if (ctx->result < 0) -+ return; - -- if ((result = vsir_program_lower_instructions(program, message_context)) < 0) -- return result; -+ if ((ctx->result = step(ctx->program, ctx)) < 0) -+ { -+ WARN("Transformation \"%s\" failed with result %u.\n", step_name, ctx->result); -+ return; -+ } - -- if (program->shader_version.major >= 6) -+ if ((ctx->result = vsir_program_validate(ctx->program, ctx->config_flags, -+ ctx->compile_info->source_name, ctx->message_context)) < 0) - { -- if ((result = vsir_program_materialise_phi_ssas_to_temps(program)) < 0) -- return result; -+ WARN("Validation failed with result %u after transformation \"%s\".\n", ctx->result, step_name); -+ return; -+ } -+} - -- if ((result = lower_switch_to_if_ladder(program)) < 0) -- return result; -+enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, -+ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) -+{ -+ struct vsir_normalisation_context ctx = -+ { -+ .result = VKD3D_OK, -+ .program = program, -+ .config_flags = config_flags, -+ .compile_info = compile_info, -+ .message_context = message_context, -+ }; -+ enum vkd3d_result result; - -- if ((result = vsir_program_structurize(program, message_context)) < 0) -- return result; -+ vsir_transform(&ctx, vsir_program_lower_instructions); - -- if ((result = vsir_program_flatten_control_flow_constructs(program, message_context)) < 0) -- return result; -+ if (program->shader_version.major >= 6) -+ { -+ vsir_transform(&ctx, vsir_program_materialise_phi_ssas_to_temps); -+ vsir_transform(&ctx, vsir_program_lower_switch_to_selection_ladder); -+ vsir_transform(&ctx, vsir_program_structurize); -+ vsir_transform(&ctx, vsir_program_flatten_control_flow_constructs); -+ vsir_transform(&ctx, vsir_program_materialize_undominated_ssas_to_temps); - -- if ((result = vsir_program_materialize_undominated_ssas_to_temps(program, message_context)) < 0) -- return result; -+ if (ctx.result < 0) -+ return ctx.result; - } - else - { -+ if (ctx.result < 0) -+ return ctx.result; -+ - if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL) - { - if ((result = vsir_program_remap_output_signature(program, compile_info, message_context)) < 0) -@@ -6665,7 +6688,7 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t - return result; - - if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL -- && (result = vsir_program_flatten_control_flow_constructs(program, message_context)) < 0) -+ && (result = vsir_program_flatten_control_flow_constructs(program, &ctx)) < 0) - return result; - } - --- -2.45.2 - diff --git a/patches/vkd3d-latest/0003-Updated-vkd3d-to-e8b14d765dbebae32d83aa5d2a7521932d9.patch b/patches/vkd3d-latest/0003-Updated-vkd3d-to-e8b14d765dbebae32d83aa5d2a7521932d9.patch new file mode 100644 index 00000000..aa8c10cb --- /dev/null +++ b/patches/vkd3d-latest/0003-Updated-vkd3d-to-e8b14d765dbebae32d83aa5d2a7521932d9.patch @@ -0,0 +1,303 @@ +From 06ac76ef4dafe44bc7c05d3ccea10f773f6dfc47 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Wed, 25 Sep 2024 07:29:36 +1000 +Subject: [PATCH] Updated vkd3d to e8b14d765dbebae32d83aa5d2a7521932d9943f9. + +--- + libs/vkd3d/libs/vkd3d-shader/glsl.c | 38 ++++++++++++++++++++ + libs/vkd3d/libs/vkd3d-shader/ir.c | 5 +-- + libs/vkd3d/libs/vkd3d-shader/msl.c | 50 ++++++++++++++++++++++++-- + libs/vkd3d/libs/vkd3d-shader/preproc.l | 2 +- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 25 ++++--------- + libs/vkd3d/libs/vkd3d/vkd3d_main.c | 1 + + 6 files changed, 96 insertions(+), 25 deletions(-) + +diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c +index b29f13f2b19..a8cc6d87c40 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c +@@ -379,6 +379,9 @@ static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( + case VKD3D_DATA_FLOAT: + close = false; + break; ++ case VKD3D_DATA_INT: ++ vkd3d_string_buffer_printf(buffer, "intBitsToFloat("); ++ break; + case VKD3D_DATA_UINT: + vkd3d_string_buffer_printf(buffer, "uintBitsToFloat("); + break; +@@ -457,6 +460,28 @@ static void shader_glsl_relop(struct vkd3d_glsl_generator *gen, + glsl_dst_cleanup(&dst, &gen->string_buffers); + } + ++static void shader_glsl_cast(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins, ++ const char *scalar_constructor, const char *vector_constructor) ++{ ++ unsigned int component_count; ++ struct glsl_src src; ++ struct glsl_dst dst; ++ uint32_t mask; ++ ++ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ glsl_src_init(&src, gen, &ins->src[0], mask); ++ ++ if ((component_count = vsir_write_mask_component_count(mask)) > 1) ++ shader_glsl_print_assignment(gen, &dst, "%s%u(%s)", ++ vector_constructor, component_count, src.str->buffer); ++ else ++ shader_glsl_print_assignment(gen, &dst, "%s(%s)", ++ scalar_constructor, src.str->buffer); ++ ++ glsl_src_cleanup(&src, &gen->string_buffers); ++ glsl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ + static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) + { + struct glsl_src src; +@@ -658,6 +683,12 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_FRC: + shader_glsl_intrinsic(gen, ins, "fract"); + break; ++ case VKD3DSIH_FTOI: ++ shader_glsl_cast(gen, ins, "int", "ivec"); ++ break; ++ case VKD3DSIH_FTOU: ++ shader_glsl_cast(gen, ins, "uint", "uvec"); ++ break; + case VKD3DSIH_GEO: + shader_glsl_relop(gen, ins, ">=", "greaterThanEqual"); + break; +@@ -665,6 +696,10 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_NEU: + shader_glsl_relop(gen, ins, "!=", "notEqual"); + break; ++ case VKD3DSIH_ITOF: ++ case VKD3DSIH_UTOF: ++ shader_glsl_cast(gen, ins, "float", "vec"); ++ break; + case VKD3DSIH_MOV: + shader_glsl_mov(gen, ins); + break; +@@ -680,6 +715,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_RET: + shader_glsl_ret(gen, ins); + break; ++ case VKD3DSIH_ROUND_PI: ++ shader_glsl_intrinsic(gen, ins, "ceil"); ++ break; + default: + shader_glsl_unhandled(gen, ins); + break; +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index db9992d9715..0bbe13ad7d8 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -1211,12 +1211,13 @@ static bool io_normaliser_is_in_control_point_phase(const struct io_normaliser * + static bool shader_signature_find_element_for_reg(const struct shader_signature *signature, + unsigned int reg_idx, unsigned int write_mask, unsigned int *element_idx) + { ++ const struct signature_element *e; + unsigned int i, base_write_mask; + + for (i = 0; i < signature->element_count; ++i) + { +- struct signature_element *e = &signature->elements[i]; +- if (e->register_index <= reg_idx && e->register_index + e->register_count > reg_idx ++ e = &signature->elements[i]; ++ if (e->register_index <= reg_idx && e->register_count > reg_idx - e->register_index + && (e->mask & write_mask) == write_mask) + { + *element_idx = i; +diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c +index 7d2e713cddc..6b41363d60e 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/msl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/msl.c +@@ -55,12 +55,44 @@ static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int in + vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); + } + ++static void msl_print_register_datatype(struct vkd3d_string_buffer *buffer, ++ struct msl_generator *gen, const struct vkd3d_shader_register *reg) ++{ ++ vkd3d_string_buffer_printf(buffer, "."); ++ switch (reg->data_type) ++ { ++ case VKD3D_DATA_FLOAT: ++ vkd3d_string_buffer_printf(buffer, "f"); ++ break; ++ case VKD3D_DATA_INT: ++ vkd3d_string_buffer_printf(buffer, "i"); ++ break; ++ case VKD3D_DATA_UINT: ++ vkd3d_string_buffer_printf(buffer, "u"); ++ break; ++ default: ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled register datatype %#x.", reg->data_type); ++ vkd3d_string_buffer_printf(buffer, "", reg->data_type); ++ break; ++ } ++} ++ + static void msl_print_register_name(struct vkd3d_string_buffer *buffer, + struct msl_generator *gen, const struct vkd3d_shader_register *reg) + { +- msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, +- "Internal compiler error: Unhandled register type %#x.", reg->type); +- vkd3d_string_buffer_printf(buffer, "", reg->type); ++ switch (reg->type) ++ { ++ case VKD3DSPR_TEMP: ++ vkd3d_string_buffer_printf(buffer, "r[%u]", reg->idx[0].offset); ++ msl_print_register_datatype(buffer, gen, reg); ++ break; ++ default: ++ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, ++ "Internal compiler error: Unhandled register type %#x.", reg->type); ++ vkd3d_string_buffer_printf(buffer, "", reg->type); ++ break; ++ } + } + + static void msl_print_swizzle(struct vkd3d_string_buffer *buffer, uint32_t swizzle, uint32_t mask) +@@ -221,9 +253,21 @@ static void msl_generator_generate(struct msl_generator *gen) + + vkd3d_string_buffer_printf(gen->buffer, "/* Generated by %s. */\n\n", vkd3d_shader_get_version(NULL, NULL)); + ++ vkd3d_string_buffer_printf(gen->buffer, "union vkd3d_vec4\n{\n"); ++ vkd3d_string_buffer_printf(gen->buffer, " uint4 u;\n"); ++ vkd3d_string_buffer_printf(gen->buffer, " int4 i;\n"); ++ vkd3d_string_buffer_printf(gen->buffer, " float4 f;\n};\n\n"); ++ + vkd3d_string_buffer_printf(gen->buffer, "void shader_main()\n{\n"); + + ++gen->indent; ++ ++ if (gen->program->temp_count) ++ { ++ msl_print_indent(gen->buffer, gen->indent); ++ vkd3d_string_buffer_printf(gen->buffer, "vkd3d_vec4 r[%u];\n\n", gen->program->temp_count); ++ } ++ + for (i = 0; i < instructions->count; ++i) + { + msl_handle_instruction(gen, &instructions->elements[i]); +diff --git a/libs/vkd3d/libs/vkd3d-shader/preproc.l b/libs/vkd3d/libs/vkd3d-shader/preproc.l +index 7fc963192cf..41c21cca1f5 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/preproc.l ++++ b/libs/vkd3d/libs/vkd3d-shader/preproc.l +@@ -67,7 +67,7 @@ static void update_location(struct preproc_ctx *ctx); + + NEWLINE \r?\n + WS [ \t\r] +-IDENTIFIER [A-Za-z_][A-Za-z0-9_]* ++IDENTIFIER (::)?[A-Za-z_]((::)?[A-Za-z0-9_]+)* + INT_SUFFIX [uUlL]{0,2} + + %% +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 1876ad38653..0278a6ca232 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -6354,7 +6354,7 @@ static SpvImageFormat image_format_for_image_read(enum vkd3d_shader_component_ty + static uint32_t spirv_compiler_get_image_type_id(struct spirv_compiler *compiler, + const struct vkd3d_shader_register *reg, const struct vkd3d_shader_register_range *range, + const struct vkd3d_spirv_resource_type *resource_type_info, enum vkd3d_shader_component_type data_type, +- bool raw_structured, uint32_t depth) ++ bool raw_structured) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_descriptor_info1 *d; +@@ -6377,7 +6377,7 @@ static uint32_t spirv_compiler_get_image_type_id(struct spirv_compiler *compiler + + sampled_type_id = vkd3d_spirv_get_type_id(builder, data_type, 1); + return vkd3d_spirv_get_op_type_image(builder, sampled_type_id, resource_type_info->dim, +- depth, resource_type_info->arrayed, resource_type_info->ms, ++ 2, resource_type_info->arrayed, resource_type_info->ms, + reg->type == VKD3DSPR_UAV ? 2 : 1, format); + } + +@@ -6392,18 +6392,14 @@ static void spirv_compiler_emit_combined_sampler_declarations(struct spirv_compi + const struct vkd3d_shader_combined_resource_sampler *current; + uint32_t image_type_id, type_id, ptr_type_id, var_id; + enum vkd3d_shader_binding_flag resource_type_flag; +- const struct vkd3d_shader_descriptor_info1 *d; + struct vkd3d_symbol symbol; + unsigned int i; +- bool depth; + + resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER + ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE; + + for (i = 0; i < shader_interface->combined_sampler_count; ++i) + { +- struct vkd3d_shader_register_range sampler_range; +- + current = &shader_interface->combined_samplers[i]; + + if (current->resource_space != resource_range->space || current->resource_index != resource_range->first) +@@ -6425,16 +6421,8 @@ static void spirv_compiler_emit_combined_sampler_declarations(struct spirv_compi + current->sampler_space, current->binding.count); + } + +- sampler_range.space = current->sampler_space; +- sampler_range.first = current->sampler_index; +- sampler_range.last = current->sampler_index; +- d = spirv_compiler_get_descriptor_info(compiler, +- VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, &sampler_range); +- depth = current->sampler_index != VKD3D_SHADER_DUMMY_SAMPLER_INDEX +- && (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE); +- + image_type_id = spirv_compiler_get_image_type_id(compiler, resource, resource_range, +- resource_type_info, sampled_type, structure_stride || raw, depth); ++ resource_type_info, sampled_type, structure_stride || raw); + type_id = vkd3d_spirv_get_op_type_sampled_image(builder, image_type_id); + + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id); +@@ -6528,7 +6516,7 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp + else + { + type_id = spirv_compiler_get_image_type_id(compiler, ®, range, +- resource_type_info, sampled_type, structure_stride || raw, 0); ++ resource_type_info, sampled_type, structure_stride || raw); + } + + var_id = spirv_compiler_build_descriptor_variable(compiler, storage_class, +@@ -8440,11 +8428,10 @@ static void spirv_compiler_prepare_image(struct spirv_compiler *compiler, + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t sampler_var_id, sampler_id, sampled_image_type_id; + const struct vkd3d_symbol *symbol = NULL; +- bool load, sampled, depth_comparison; ++ bool load, sampled; + + load = !(flags & VKD3D_IMAGE_FLAG_NO_LOAD); + sampled = flags & VKD3D_IMAGE_FLAG_SAMPLED; +- depth_comparison = flags & VKD3D_IMAGE_FLAG_DEPTH; + + if (resource_reg->type == VKD3DSPR_RESOURCE) + symbol = spirv_compiler_find_combined_sampler(compiler, resource_reg, sampler_reg); +@@ -8498,7 +8485,7 @@ static void spirv_compiler_prepare_image(struct spirv_compiler *compiler, + + image->image_type_id = spirv_compiler_get_image_type_id(compiler, resource_reg, + &symbol->info.resource.range, image->resource_type_info, +- image->sampled_type, image->structure_stride || image->raw, depth_comparison); ++ image->sampled_type, image->structure_stride || image->raw); + + if (sampled) + { +diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_main.c b/libs/vkd3d/libs/vkd3d/vkd3d_main.c +index 9eccec111c7..5215cf8ef86 100644 +--- a/libs/vkd3d/libs/vkd3d/vkd3d_main.c ++++ b/libs/vkd3d/libs/vkd3d/vkd3d_main.c +@@ -415,6 +415,7 @@ HRESULT vkd3d_create_versioned_root_signature_deserializer(const void *data, SIZ + if (FAILED(hr = d3d12_versioned_root_signature_deserializer_init(object, &dxbc))) + { + vkd3d_free(object); ++ *deserializer = NULL; + return hr; + } + +-- +2.45.2 + diff --git a/patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch b/patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch deleted file mode 100644 index 729a2cfa..00000000 --- a/patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch +++ /dev/null @@ -1,485 +0,0 @@ -From 974ebb67f03cda95a36c014378acd627f913f47b Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Wed, 11 Sep 2024 07:14:31 +1000 -Subject: [PATCH] Updated vkd3d to 3b4e0ce8e94cd4091b9f2fe80d86588b64c88111. - ---- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 10 ++- - libs/vkd3d/libs/vkd3d-shader/dxil.c | 2 +- - libs/vkd3d/libs/vkd3d-shader/fx.c | 8 ++- - libs/vkd3d/libs/vkd3d-shader/hlsl.y | 15 ++++ - libs/vkd3d/libs/vkd3d-shader/ir.c | 69 ++++++++++--------- - libs/vkd3d/libs/vkd3d-shader/tpf.c | 19 +++++ - .../libs/vkd3d-shader/vkd3d_shader_private.h | 4 +- - libs/vkd3d/libs/vkd3d/command.c | 20 ++++-- - libs/vkd3d/libs/vkd3d/state.c | 2 +- - libs/vkd3d/libs/vkd3d/vkd3d_private.h | 1 - - 10 files changed, 100 insertions(+), 50 deletions(-) - -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index de5f28c1815..a41182e1f4a 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -1481,10 +1481,8 @@ struct d3dbc_compiler - - static uint32_t sm1_version(enum vkd3d_shader_type type, unsigned int major, unsigned int minor) - { -- if (type == VKD3D_SHADER_TYPE_VERTEX) -- return D3DVS_VERSION(major, minor); -- else -- return D3DPS_VERSION(major, minor); -+ return vkd3d_make_u32(vkd3d_make_u16(minor, major), -+ type == VKD3D_SHADER_TYPE_VERTEX ? VKD3D_SM1_VS : VKD3D_SM1_PS); - } - - D3DXPARAMETER_CLASS hlsl_sm1_class(const struct hlsl_type *type) -@@ -1867,8 +1865,8 @@ void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buff - - static uint32_t sm1_encode_register_type(enum vkd3d_shader_register_type type) - { -- return ((type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) -- | ((type << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2); -+ return ((type << VKD3D_SM1_REGISTER_TYPE_SHIFT) & VKD3D_SM1_REGISTER_TYPE_MASK) -+ | ((type << VKD3D_SM1_REGISTER_TYPE_SHIFT2) & VKD3D_SM1_REGISTER_TYPE_MASK2); - } - - struct sm1_instruction -diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c -index 4a17c62292b..1c62a305d30 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/dxil.c -+++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c -@@ -3888,7 +3888,7 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade - if (is_control_point) - { - if (reg_type == VKD3DSPR_OUTPUT) -- param->reg.idx[count].rel_addr = instruction_array_create_outpointid_param(&sm6->p.program->instructions); -+ param->reg.idx[count].rel_addr = vsir_program_create_outpointid_param(sm6->p.program); - param->reg.idx[count++].offset = 0; - } - -diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c -index e3ab71fb386..2c2e486aa0e 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/fx.c -+++ b/libs/vkd3d/libs/vkd3d-shader/fx.c -@@ -38,6 +38,7 @@ struct type_entry - struct list entry; - const char *name; - uint32_t elements_count; -+ uint32_t modifiers; - uint32_t offset; - }; - -@@ -278,9 +279,9 @@ static void write_fx_4_state_block(struct hlsl_ir_var *var, unsigned int block_i - - static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context *fx) - { -+ unsigned int elements_count, modifiers; - const struct hlsl_type *element_type; - struct type_entry *type_entry; -- unsigned int elements_count; - const char *name; - - VKD3D_ASSERT(fx->ctx->profile->major_version >= 4); -@@ -297,6 +298,7 @@ static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context - } - - name = get_fx_4_type_name(element_type); -+ modifiers = element_type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK; - - LIST_FOR_EACH_ENTRY(type_entry, &fx->types, struct type_entry, entry) - { -@@ -306,6 +308,9 @@ static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context - if (type_entry->elements_count != elements_count) - continue; - -+ if (type_entry->modifiers != modifiers) -+ continue; -+ - return type_entry->offset; - } - -@@ -315,6 +320,7 @@ static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context - type_entry->offset = write_fx_4_type(type, fx); - type_entry->name = name; - type_entry->elements_count = elements_count; -+ type_entry->modifiers = modifiers; - - list_add_tail(&fx->types, &type_entry->entry); - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -index 816d992afa8..38642025b52 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -@@ -4152,6 +4152,20 @@ static bool intrinsic_log2(struct hlsl_ctx *ctx, - return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_LOG2, arg, loc); - } - -+static bool intrinsic_mad(struct hlsl_ctx *ctx, -+ const struct parse_initializer *params, const struct vkd3d_shader_location *loc) -+{ -+ struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; -+ -+ if (!elementwise_intrinsic_convert_args(ctx, params, loc)) -+ return false; -+ -+ args[0] = params->args[0]; -+ args[1] = params->args[1]; -+ args[2] = params->args[2]; -+ return add_expr(ctx, params->instrs, HLSL_OP3_MAD, args, args[0]->data_type, loc); -+} -+ - static bool intrinsic_max(struct hlsl_ctx *ctx, - const struct parse_initializer *params, const struct vkd3d_shader_location *loc) - { -@@ -5053,6 +5067,7 @@ intrinsic_functions[] = - {"log", 1, true, intrinsic_log}, - {"log10", 1, true, intrinsic_log10}, - {"log2", 1, true, intrinsic_log2}, -+ {"mad", 3, true, intrinsic_mad}, - {"max", 2, true, intrinsic_max}, - {"min", 2, true, intrinsic_min}, - {"mul", 2, true, intrinsic_mul}, -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index a483c25f3ad..68f2e2f795e 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -551,9 +551,11 @@ static const struct vkd3d_shader_varying_map *find_varying_map( - } - - static enum vkd3d_result vsir_program_remap_output_signature(struct vsir_program *program, -- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) -+ struct vsir_normalisation_context *ctx) - { -- const struct vkd3d_shader_location location = {.source_name = compile_info->source_name}; -+ const struct vkd3d_shader_location location = {.source_name = ctx->compile_info->source_name}; -+ struct vkd3d_shader_message_context *message_context = ctx->message_context; -+ const struct vkd3d_shader_compile_info *compile_info = ctx->compile_info; - struct shader_signature *signature = &program->output_signature; - const struct vkd3d_shader_varying_map_info *varying_map; - unsigned int i; -@@ -862,9 +864,10 @@ static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, - return true; - } - --static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions) -+static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program, -+ struct vsir_normalisation_context *ctx) - { -- struct hull_flattener flattener = {*src_instructions}; -+ struct hull_flattener flattener = {program->instructions}; - struct vkd3d_shader_instruction_array *instructions; - struct shader_phase_location_array locations; - enum vkd3d_result result = VKD3D_OK; -@@ -886,7 +889,7 @@ static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd - vsir_instruction_init(&instructions->elements[instructions->count++], &flattener.last_ret_location, VKD3DSIH_RET); - } - -- *src_instructions = flattener.instructions; -+ program->instructions = flattener.instructions; - return result; - } - -@@ -902,9 +905,9 @@ static bool control_point_normaliser_is_in_control_point_phase(const struct cont - return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; - } - --struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( -- struct vkd3d_shader_instruction_array *instructions) -+struct vkd3d_shader_src_param *vsir_program_create_outpointid_param(struct vsir_program *program) - { -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct vkd3d_shader_src_param *rel_addr; - - if (instructions->outpointid_param) -@@ -1001,7 +1004,7 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p - } - - static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( -- struct vkd3d_shader_instruction_array *src_instructions, const struct shader_signature *input_signature) -+ struct vsir_program *program, struct vsir_normalisation_context *ctx) - { - struct vkd3d_shader_instruction_array *instructions; - struct control_point_normaliser normaliser; -@@ -1011,12 +1014,12 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i - enum vkd3d_result ret; - unsigned int i, j; - -- if (!(normaliser.outpointid_param = instruction_array_create_outpointid_param(src_instructions))) -+ if (!(normaliser.outpointid_param = vsir_program_create_outpointid_param(program))) - { - ERR("Failed to allocate src param.\n"); - return VKD3D_ERROR_OUT_OF_MEMORY; - } -- normaliser.instructions = *src_instructions; -+ normaliser.instructions = program->instructions; - instructions = &normaliser.instructions; - normaliser.phase = VKD3DSIH_INVALID; - -@@ -1053,22 +1056,22 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i - input_control_point_count = ins->declaration.count; - break; - case VKD3DSIH_HS_CONTROL_POINT_PHASE: -- *src_instructions = normaliser.instructions; -+ program->instructions = normaliser.instructions; - return VKD3D_OK; - case VKD3DSIH_HS_FORK_PHASE: - case VKD3DSIH_HS_JOIN_PHASE: - /* ins may be relocated if the instruction array expands. */ - location = ins->location; -- ret = control_point_normaliser_emit_hs_input(&normaliser, input_signature, -+ ret = control_point_normaliser_emit_hs_input(&normaliser, &program->input_signature, - input_control_point_count, i, &location); -- *src_instructions = normaliser.instructions; -+ program->instructions = normaliser.instructions; - return ret; - default: - break; - } - } - -- *src_instructions = normaliser.instructions; -+ program->instructions = normaliser.instructions; - return VKD3D_OK; - } - -@@ -1398,6 +1401,8 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map - else - e->interpolation_mode = f->interpolation_mode; - } -+ -+ vkd3d_free((void *)f->semantic_name); - } - } - element_count = new_count; -@@ -1425,6 +1430,12 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map - TRACE("Merging %s, base reg %u, count %u.\n", e->semantic_name, e->register_index, register_count); - e->register_count = register_count; - e->mask = signature_element_range_expand_mask(e, register_count, range_map); -+ -+ for (j = 1; j < register_count; ++j) -+ { -+ f = &elements[i + j]; -+ vkd3d_free((void *)f->semantic_name); -+ } - } - } - element_count = new_count; -@@ -1761,8 +1772,9 @@ static bool use_flat_interpolation(const struct vsir_program *program, - } - - static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program *program, -- struct vkd3d_shader_message_context *message_context) -+ struct vsir_normalisation_context *ctx) - { -+ struct vkd3d_shader_message_context *message_context = ctx->message_context; - struct io_normaliser normaliser = {program->instructions}; - struct vkd3d_shader_instruction *ins; - unsigned int i; -@@ -1909,7 +1921,8 @@ static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_par - param->reg.idx_count = 3; - } - --static enum vkd3d_result instruction_array_normalise_flat_constants(struct vsir_program *program) -+static enum vkd3d_result vsir_program_normalise_flat_constants(struct vsir_program *program, -+ struct vsir_normalisation_context *ctx) - { - struct flat_constants_normaliser normaliser = {0}; - unsigned int i, j; -@@ -6657,30 +6670,20 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t - } - else - { -- if (ctx.result < 0) -- return ctx.result; -- - if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL) -- { -- if ((result = vsir_program_remap_output_signature(program, compile_info, message_context)) < 0) -- return result; -- } -+ vsir_transform(&ctx, vsir_program_remap_output_signature); - - if (program->shader_version.type == VKD3D_SHADER_TYPE_HULL) - { -- if ((result = instruction_array_flatten_hull_shader_phases(&program->instructions)) < 0) -- return result; -- -- if ((result = instruction_array_normalise_hull_shader_control_point_io(&program->instructions, -- &program->input_signature)) < 0) -- return result; -+ vsir_transform(&ctx, vsir_program_flatten_hull_shader_phases); -+ vsir_transform(&ctx, instruction_array_normalise_hull_shader_control_point_io); - } - -- if ((result = vsir_program_normalise_io_registers(program, message_context)) < 0) -- return result; -+ vsir_transform(&ctx, vsir_program_normalise_io_registers); -+ vsir_transform(&ctx, vsir_program_normalise_flat_constants); - -- if ((result = instruction_array_normalise_flat_constants(program)) < 0) -- return result; -+ if (ctx.result < 0) -+ return ctx.result; - - remove_dead_code(program); - -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index c61086419a6..b76a596bb60 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -2814,6 +2814,7 @@ bool sysval_semantic_from_hlsl(enum vkd3d_shader_sysval_semantic *semantic, - {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_IS_FRONT_FACE}, - {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX}, - {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX}, -+ {"sv_sampleindex", false, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_SAMPLE_INDEX}, - - {"color", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_TARGET}, - {"depth", true, VKD3D_SHADER_TYPE_PIXEL, VKD3D_SHADER_SV_DEPTH}, -@@ -4461,6 +4462,7 @@ static void write_sm4_dcl_semantic(const struct tpf_writer *tpf, const struct hl - case VKD3D_SHADER_SV_INSTANCE_ID: - case VKD3D_SHADER_SV_PRIMITIVE_ID: - case VKD3D_SHADER_SV_VERTEX_ID: -+ case VKD3D_SHADER_SV_SAMPLE_INDEX: - instr.opcode = (profile->type == VKD3D_SHADER_TYPE_PIXEL) - ? VKD3D_SM4_OP_DCL_INPUT_PS_SGV : VKD3D_SM4_OP_DCL_INPUT_SGV; - break; -@@ -5578,6 +5580,23 @@ static void write_sm4_expr(const struct tpf_writer *tpf, const struct hlsl_ir_ex - write_sm4_ternary_op(tpf, VKD3D_SM4_OP_MOVC, &expr->node, arg1, arg2, arg3); - break; - -+ case HLSL_OP3_MAD: -+ switch (dst_type->e.numeric.type) -+ { -+ case HLSL_TYPE_FLOAT: -+ write_sm4_ternary_op(tpf, VKD3D_SM4_OP_MAD, &expr->node, arg1, arg2, arg3); -+ break; -+ -+ case HLSL_TYPE_INT: -+ case HLSL_TYPE_UINT: -+ write_sm4_ternary_op(tpf, VKD3D_SM4_OP_IMAD, &expr->node, arg1, arg2, arg3); -+ break; -+ -+ default: -+ hlsl_fixme(tpf->ctx, &expr->node.loc, "SM4 %s negation expression.", dst_type_string->buffer); -+ } -+ break; -+ - default: - hlsl_fixme(tpf->ctx, &expr->node.loc, "SM4 %s expression.", debug_hlsl_expr_op(expr->op)); - } -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index 327461371a4..ffec48daa17 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -1354,8 +1354,6 @@ bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *ins - struct vkd3d_shader_immediate_constant_buffer *icb); - bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, - unsigned int dst, unsigned int src); --struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( -- struct vkd3d_shader_instruction_array *instructions); - void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions); - - enum vkd3d_shader_config_flags -@@ -1399,6 +1397,8 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); - enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, - const char *source_name, struct vkd3d_shader_message_context *message_context); -+struct vkd3d_shader_src_param *vsir_program_create_outpointid_param( -+ struct vsir_program *program); - bool vsir_instruction_init_with_params(struct vsir_program *program, - struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, - enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count); -diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c -index dcc7690876f..188162f9e6e 100644 ---- a/libs/vkd3d/libs/vkd3d/command.c -+++ b/libs/vkd3d/libs/vkd3d/command.c -@@ -3078,7 +3078,7 @@ done: - vkd3d_free(vk_descriptor_writes); - } - --static void d3d12_command_list_update_descriptors(struct d3d12_command_list *list, -+static void d3d12_command_list_update_virtual_descriptors(struct d3d12_command_list *list, - enum vkd3d_pipeline_bind_point bind_point) - { - struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point]; -@@ -3210,6 +3210,9 @@ static void command_list_flush_vk_heap_updates(struct d3d12_command_list *list) - - static void command_list_add_descriptor_heap(struct d3d12_command_list *list, struct d3d12_descriptor_heap *heap) - { -+ if (!list->device->use_vk_heaps) -+ return; -+ - if (!contains_heap(list->descriptor_heaps, list->descriptor_heap_count, heap)) - { - if (list->descriptor_heap_count == ARRAY_SIZE(list->descriptor_heaps)) -@@ -3296,6 +3299,15 @@ static void d3d12_command_list_update_heap_descriptors(struct d3d12_command_list - d3d12_command_list_bind_descriptor_heap(list, bind_point, sampler_heap); - } - -+static void d3d12_command_list_update_descriptors(struct d3d12_command_list *list, -+ enum vkd3d_pipeline_bind_point bind_point) -+{ -+ if (list->device->use_vk_heaps) -+ d3d12_command_list_update_heap_descriptors(list, bind_point); -+ else -+ d3d12_command_list_update_virtual_descriptors(list, bind_point); -+} -+ - static bool d3d12_command_list_update_compute_state(struct d3d12_command_list *list) - { - d3d12_command_list_end_current_render_pass(list); -@@ -3303,7 +3315,7 @@ static bool d3d12_command_list_update_compute_state(struct d3d12_command_list *l - if (!d3d12_command_list_update_compute_pipeline(list)) - return false; - -- list->update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE); -+ d3d12_command_list_update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE); - - return true; - } -@@ -3320,7 +3332,7 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list - if (!d3d12_command_list_update_current_framebuffer(list)) - return false; - -- list->update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_GRAPHICS); -+ d3d12_command_list_update_descriptors(list, VKD3D_PIPELINE_BIND_POINT_GRAPHICS); - - if (list->current_render_pass != VK_NULL_HANDLE) - return true; -@@ -6189,8 +6201,6 @@ static HRESULT d3d12_command_list_init(struct d3d12_command_list *list, struct d - - list->allocator = allocator; - -- list->update_descriptors = device->use_vk_heaps ? d3d12_command_list_update_heap_descriptors -- : d3d12_command_list_update_descriptors; - list->descriptor_heap_count = 0; - - if (SUCCEEDED(hr = d3d12_command_allocator_allocate_command_buffer(allocator, list))) -diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c -index 682d488faa8..bc887fa2f33 100644 ---- a/libs/vkd3d/libs/vkd3d/state.c -+++ b/libs/vkd3d/libs/vkd3d/state.c -@@ -738,7 +738,7 @@ static bool vkd3d_validate_descriptor_set_count(struct d3d12_device *device, uns - if (set_count > max_count) - { - /* NOTE: If maxBoundDescriptorSets is < 9, try VKD3D_CONFIG=virtual_heaps */ -- ERR("Required descriptor set count exceeds maximum allowed count of %u.\n", max_count); -+ WARN("Required descriptor set count exceeds maximum allowed count of %u.\n", max_count); - return false; - } - -diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h -index ba4e2e8488d..729b1baee18 100644 ---- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h -+++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h -@@ -1271,7 +1271,6 @@ struct d3d12_command_list - VkBuffer so_counter_buffers[D3D12_SO_BUFFER_SLOT_COUNT]; - VkDeviceSize so_counter_buffer_offsets[D3D12_SO_BUFFER_SLOT_COUNT]; - -- void (*update_descriptors)(struct d3d12_command_list *list, enum vkd3d_pipeline_bind_point bind_point); - struct d3d12_descriptor_heap *descriptor_heaps[64]; - unsigned int descriptor_heap_count; - --- -2.45.2 - diff --git a/patches/vkd3d-latest/0004-Updated-vkd3d-to-f28d39b609036ce9bc3a4baaf6cda012fc2.patch b/patches/vkd3d-latest/0004-Updated-vkd3d-to-f28d39b609036ce9bc3a4baaf6cda012fc2.patch new file mode 100644 index 00000000..ca2dee9e --- /dev/null +++ b/patches/vkd3d-latest/0004-Updated-vkd3d-to-f28d39b609036ce9bc3a4baaf6cda012fc2.patch @@ -0,0 +1,1233 @@ +From 1a7fe5c66183d5193808f6280e25a4b6ccd15a04 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Tue, 1 Oct 2024 21:50:23 +1000 +Subject: [PATCH] Updated vkd3d to f28d39b609036ce9bc3a4baaf6cda012fc2e3002. + +--- + libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 29 +++- + libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 16 +- + libs/vkd3d/libs/vkd3d-shader/dxil.c | 79 +++++---- + libs/vkd3d/libs/vkd3d-shader/fx.c | 157 ++++++++++++------ + libs/vkd3d/libs/vkd3d-shader/glsl.c | 107 ++++++++++++ + libs/vkd3d/libs/vkd3d-shader/ir.c | 71 +++++++- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 150 +++++++++-------- + .../libs/vkd3d-shader/vkd3d_shader_private.h | 4 +- + 8 files changed, 444 insertions(+), 169 deletions(-) + +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +index cfee053d49c..9fe4b74486a 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +@@ -675,9 +675,6 @@ static void shader_dump_data_type(struct vkd3d_d3d_asm_compiler *compiler, enum + { + [VKD3D_DATA_FLOAT ] = "float", + [VKD3D_DATA_INT ] = "int", +- [VKD3D_DATA_RESOURCE ] = "resource", +- [VKD3D_DATA_SAMPLER ] = "sampler", +- [VKD3D_DATA_UAV ] = "uav", + [VKD3D_DATA_UINT ] = "uint", + [VKD3D_DATA_UNORM ] = "unorm", + [VKD3D_DATA_SNORM ] = "snorm", +@@ -1229,8 +1226,6 @@ static void shader_print_register(struct vkd3d_d3d_asm_compiler *compiler, const + case VKD3D_DATA_INT: + shader_print_int_literal(compiler, "", reg->u.immconst_u32[0], ""); + break; +- case VKD3D_DATA_RESOURCE: +- case VKD3D_DATA_SAMPLER: + case VKD3D_DATA_UINT: + shader_print_uint_literal(compiler, "", reg->u.immconst_u32[0], ""); + break; +@@ -1266,8 +1261,6 @@ static void shader_print_register(struct vkd3d_d3d_asm_compiler *compiler, const + shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[2], ""); + shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[3], ""); + break; +- case VKD3D_DATA_RESOURCE: +- case VKD3D_DATA_SAMPLER: + case VKD3D_DATA_UINT: + shader_print_uint_literal(compiler, "", reg->u.immconst_u32[0], ""); + shader_print_uint_literal(compiler, ", ", reg->u.immconst_u32[1], ""); +@@ -1319,6 +1312,23 @@ static void shader_print_register(struct vkd3d_d3d_asm_compiler *compiler, const + } + vkd3d_string_buffer_printf(buffer, ")"); + } ++ else if (compiler->flags & VSIR_ASM_FLAG_DUMP_ALL_INDICES) ++ { ++ unsigned int i = 0; ++ ++ if (reg->idx_count == 0 || reg->idx[0].rel_addr) ++ { ++ vkd3d_string_buffer_printf(buffer, "%s", compiler->colours.reset); ++ } ++ else ++ { ++ vkd3d_string_buffer_printf(buffer, "%u%s", offset, compiler->colours.reset); ++ i = 1; ++ } ++ ++ for (; i < reg->idx_count; ++i) ++ shader_print_subscript(compiler, reg->idx[i].offset, reg->idx[i].rel_addr); ++ } + else if (reg->type != VKD3DSPR_RASTOUT + && reg->type != VKD3DSPR_MISCTYPE + && reg->type != VKD3DSPR_NULL +@@ -2491,10 +2501,11 @@ enum vkd3d_result d3d_asm_compile(const struct vsir_program *program, + + void vkd3d_shader_trace(const struct vsir_program *program) + { +- const char *p, *q, *end; ++ const unsigned int flags = VSIR_ASM_FLAG_DUMP_TYPES | VSIR_ASM_FLAG_DUMP_ALL_INDICES; + struct vkd3d_shader_code code; ++ const char *p, *q, *end; + +- if (d3d_asm_compile(program, NULL, &code, VSIR_ASM_FLAG_DUMP_TYPES) != VKD3D_OK) ++ if (d3d_asm_compile(program, NULL, &code, flags) != VKD3D_OK) + return; + + end = (const char *)code.code + code.size; +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +index 34752a1ab89..763d52e1b62 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +@@ -1352,9 +1352,6 @@ int d3dbc_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t c + for (i = 0; i < ARRAY_SIZE(program->flat_constant_count); ++i) + program->flat_constant_count[i] = get_external_constant_count(&sm1, i); + +- if (!sm1.p.failed) +- ret = vkd3d_shader_parser_validate(&sm1.p, config_flags); +- + if (sm1.p.failed && ret >= 0) + ret = VKD3D_ERROR_INVALID_SHADER; + +@@ -1365,7 +1362,18 @@ int d3dbc_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t c + return ret; + } + +- return ret; ++ if ((ret = vkd3d_shader_parser_validate(&sm1.p, config_flags)) < 0) ++ { ++ WARN("Failed to validate shader after parsing, ret %d.\n", ret); ++ ++ if (TRACE_ON()) ++ vkd3d_shader_trace(program); ++ ++ vsir_program_cleanup(program); ++ return ret; ++ } ++ ++ return VKD3D_OK; + } + + bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, const char *semantic_name, +diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c +index ee78b6251f9..165ab222fca 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c ++++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c +@@ -4161,8 +4161,7 @@ static void sm6_parser_emit_atomicrmw(struct sm6_parser *sm6, const struct dxil_ + dst_param_init(&dst_params[0]); + + dst_params[1].reg = ptr->u.reg; +- /* The groupshared register has data type UAV when accessed. */ +- dst_params[1].reg.data_type = VKD3D_DATA_UAV; ++ dst_params[1].reg.data_type = VKD3D_DATA_UNUSED; + dst_params[1].reg.idx[1].rel_addr = NULL; + dst_params[1].reg.idx[1].offset = ~0u; + dst_params[1].reg.idx_count = 1; +@@ -6861,7 +6860,6 @@ static void sm6_parser_emit_cmpxchg(struct sm6_parser *sm6, const struct dxil_re + struct vkd3d_shader_dst_param *dst_params; + struct vkd3d_shader_src_param *src_params; + const struct sm6_value *ptr, *cmp, *new; +- const struct sm6_type *type; + unsigned int i = 0; + bool is_volatile; + uint64_t code; +@@ -6887,9 +6885,10 @@ static void sm6_parser_emit_cmpxchg(struct sm6_parser *sm6, const struct dxil_re + return; + } + +- type = ptr->type->u.pointer.type; +- cmp = sm6_parser_get_value_by_ref(sm6, record, type, &i); +- new = sm6_parser_get_value_by_ref(sm6, record, type, &i); ++ /* Forward-referenced comparands are stored as value/type pairs, even ++ * though in principle we could use the destination type. */ ++ cmp = sm6_parser_get_value_by_ref(sm6, record, NULL, &i); ++ new = sm6_parser_get_value_by_ref(sm6, record, ptr->type->u.pointer.type, &i); + if (!cmp || !new) + return; + +@@ -7287,7 +7286,6 @@ static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_reco + unsigned int i = 0, alignment, operand_count; + struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_dst_param *dst_param; +- const struct sm6_type *pointee_type; + const struct sm6_value *ptr, *src; + uint64_t alignment_code; + +@@ -7299,13 +7297,14 @@ static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_reco + return; + } + +- pointee_type = ptr->type->u.pointer.type; +- if (!(src = sm6_parser_get_value_by_ref(sm6, record, pointee_type, &i))) ++ /* Forward-referenced sources are stored as value/type pairs, even ++ * though in principle we could use the destination type. */ ++ if (!(src = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + return; + if (!sm6_value_validate_is_numeric(src, sm6)) + return; + +- if (pointee_type != src->type) ++ if (ptr->type->u.pointer.type != src->type) + { + WARN("Type mismatch.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, +@@ -8908,7 +8907,7 @@ static enum vkd3d_result sm6_parser_resources_load_srv(struct sm6_parser *sm6, + d->resource_type = ins->resource_type; + d->kind = kind; + d->reg_type = VKD3DSPR_RESOURCE; +- d->reg_data_type = (ins->resource_type == VKD3D_SHADER_RESOURCE_BUFFER) ? VKD3D_DATA_UINT : VKD3D_DATA_RESOURCE; ++ d->reg_data_type = VKD3D_DATA_UNUSED; + d->resource_data_type = (ins->opcode == VKD3DSIH_DCL) + ? ins->declaration.semantic.resource_data_type[0] : VKD3D_DATA_UNUSED; + +@@ -8982,7 +8981,7 @@ static enum vkd3d_result sm6_parser_resources_load_uav(struct sm6_parser *sm6, + d->resource_type = ins->resource_type; + d->kind = values[0]; + d->reg_type = VKD3DSPR_UAV; +- d->reg_data_type = (ins->resource_type == VKD3D_SHADER_RESOURCE_BUFFER) ? VKD3D_DATA_UINT : VKD3D_DATA_UAV; ++ d->reg_data_type = VKD3D_DATA_UNUSED; + d->resource_data_type = (ins->opcode == VKD3DSIH_DCL_UAV_TYPED) + ? ins->declaration.semantic.resource_data_type[0] : VKD3D_DATA_UNUSED; + +@@ -9346,7 +9345,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Signature element is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element is not a metadata node."); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + + element_node = m->u.node; +@@ -9355,7 +9354,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Invalid operand count %u.\n", element_node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Invalid signature element operand count %u.", element_node->operand_count); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + if (element_node->operand_count > 11) + { +@@ -9374,7 +9373,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Failed to load uint value at index %u.\n", j); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element value at index %u is not an integer.", j); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + } + +@@ -9385,7 +9384,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + FIXME("Unsupported element id %u not equal to its index %u.\n", values[0], i); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "A non-sequential and non-zero-based element id is not supported."); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + + if (!sm6_metadata_value_is_string(element_node->operands[1])) +@@ -9393,7 +9392,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Element name is not a string.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element name is not a metadata string."); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + e->semantic_name = element_node->operands[1]->u.string_value; + +@@ -9407,7 +9406,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Unhandled semantic kind %u.\n", j); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "DXIL semantic kind %u is unhandled.", j); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + + if ((e->interpolation_mode = values[5]) >= VKD3DSIM_COUNT) +@@ -9415,7 +9414,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Unhandled interpolation mode %u.\n", e->interpolation_mode); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Interpolation mode %u is unhandled.", e->interpolation_mode); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + + e->register_count = values[6]; +@@ -9430,7 +9429,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Unhandled I/O register semantic kind %u.\n", j); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "DXIL semantic kind %u is unhandled for an I/O register.", j); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + } + else if (e->register_index > MAX_REG_OUTPUT || e->register_count > MAX_REG_OUTPUT - e->register_index) +@@ -9439,7 +9438,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "A signature element starting row of %u with count %u is invalid.", + e->register_index, e->register_count); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + + index = values[9]; +@@ -9448,7 +9447,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Invalid column start %u with count %u.\n", index, column_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "A signature element starting column %u with count %u is invalid.", index, column_count); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + + e->mask = vkd3d_write_mask_from_component_count(column_count); +@@ -9471,7 +9470,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + WARN("Semantic index list is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + "Signature element semantic index list is not a metadata node."); +- return VKD3D_ERROR_INVALID_SHADER; ++ goto invalid; + } + + element_node = m->u.node; +@@ -9516,6 +9515,10 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const + s->element_count = operand_count; + + return VKD3D_OK; ++ ++invalid: ++ vkd3d_free(elements); ++ return VKD3D_ERROR_INVALID_SHADER; + } + + static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, const struct sm6_metadata_value *m, +@@ -10526,9 +10529,16 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro + + dxil_block_destroy(&sm6->root_block); + ++ if (sm6->p.failed) ++ { ++ ret = VKD3D_ERROR_INVALID_SHADER; ++ goto fail; ++ } ++ + return VKD3D_OK; + + fail: ++ sm6_parser_cleanup(sm6); + vsir_program_cleanup(program); + return ret; + } +@@ -10570,18 +10580,25 @@ int dxil_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t co + free_dxbc_shader_desc(&dxbc_desc); + vkd3d_free(byte_code); + +- if (!sm6.p.failed && ret >= 0) +- ret = vkd3d_shader_parser_validate(&sm6.p, config_flags); +- +- if (sm6.p.failed && ret >= 0) +- ret = VKD3D_ERROR_INVALID_SHADER; +- +- sm6_parser_cleanup(&sm6); + if (ret < 0) + { + WARN("Failed to parse shader.\n"); + return ret; + } + +- return ret; ++ if ((ret = vkd3d_shader_parser_validate(&sm6.p, config_flags)) < 0) ++ { ++ WARN("Failed to validate shader after parsing, ret %d.\n", ret); ++ ++ if (TRACE_ON()) ++ vkd3d_shader_trace(program); ++ ++ sm6_parser_cleanup(&sm6); ++ vsir_program_cleanup(program); ++ return ret; ++ } ++ ++ sm6_parser_cleanup(&sm6); ++ ++ return VKD3D_OK; + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c +index 7d4a9d2e2ff..84e827e7943 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/fx.c ++++ b/libs/vkd3d/libs/vkd3d-shader/fx.c +@@ -224,11 +224,6 @@ static void set_status(struct fx_write_context *fx, int status) + fx->status = status; + } + +-static bool has_annotations(const struct hlsl_ir_var *var) +-{ +- return var->annotations && !list_empty(&var->annotations->vars); +-} +- + static uint32_t write_string(const char *string, struct fx_write_context *fx) + { + return fx->ops->write_string(string, fx); +@@ -435,17 +430,26 @@ static void write_fx_4_pass(struct hlsl_ir_var *var, struct fx_write_context *fx + write_fx_4_state_block(var, 0, count_offset, fx); + } + ++static void write_fx_2_annotations(struct hlsl_ir_var *var, uint32_t count_offset, struct fx_write_context *fx) ++{ ++ struct vkd3d_bytecode_buffer *buffer = &fx->structured; ++ uint32_t count; ++ ++ count = write_annotations(var->annotations, fx); ++ set_u32(buffer, count_offset, count); ++} ++ + static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx) + { + struct vkd3d_bytecode_buffer *buffer = &fx->structured; +- uint32_t name_offset; ++ uint32_t name_offset, annotation_count_offset; + + name_offset = write_string(var->name, fx); + put_u32(buffer, name_offset); +- put_u32(buffer, 0); /* Annotation count. */ ++ annotation_count_offset = put_u32(buffer, 0); + put_u32(buffer, 0); /* Assignment count. */ + +- /* TODO: annotations */ ++ write_fx_2_annotations(var, annotation_count_offset, fx); + /* TODO: assignments */ + + if (var->state_block_count && var->state_blocks[0]->count) +@@ -467,6 +471,7 @@ static uint32_t get_fx_4_type_size(const struct hlsl_type *type) + + static const uint32_t fx_4_numeric_base_type[] = + { ++ [HLSL_TYPE_HALF] = 1, + [HLSL_TYPE_FLOAT] = 1, + [HLSL_TYPE_INT ] = 2, + [HLSL_TYPE_UINT ] = 3, +@@ -503,6 +508,7 @@ static uint32_t get_fx_4_numeric_type_description(const struct hlsl_type *type, + switch (type->e.numeric.type) + { + case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: + case HLSL_TYPE_INT: + case HLSL_TYPE_UINT: + case HLSL_TYPE_BOOL: +@@ -579,6 +585,12 @@ static const char * get_fx_4_type_name(const struct hlsl_type *type) + case HLSL_CLASS_STRING: + return "String"; + ++ case HLSL_CLASS_SCALAR: ++ case HLSL_CLASS_VECTOR: ++ case HLSL_CLASS_MATRIX: ++ if (type->e.numeric.type == HLSL_TYPE_HALF) ++ return "float"; ++ /* fall-through */ + default: + return type->name; + } +@@ -977,16 +989,16 @@ static uint32_t write_fx_2_parameter(const struct hlsl_type *type, const char *n + + static void write_fx_2_technique(struct hlsl_ir_var *var, struct fx_write_context *fx) + { ++ uint32_t name_offset, pass_count_offset, annotation_count_offset, count = 0; + struct vkd3d_bytecode_buffer *buffer = &fx->structured; +- uint32_t name_offset, count_offset, count = 0; + struct hlsl_ir_var *pass; + + name_offset = write_string(var->name, fx); + put_u32(buffer, name_offset); +- put_u32(buffer, 0); /* Annotation count. */ +- count_offset = put_u32(buffer, 0); /* Pass count. */ ++ annotation_count_offset = put_u32(buffer, 0); ++ pass_count_offset = put_u32(buffer, 0); + +- /* FIXME: annotations */ ++ write_fx_2_annotations(var, annotation_count_offset, fx); + + LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry) + { +@@ -994,41 +1006,78 @@ static void write_fx_2_technique(struct hlsl_ir_var *var, struct fx_write_contex + ++count; + } + +- set_u32(buffer, count_offset, count); ++ set_u32(buffer, pass_count_offset, count); + } + +-static uint32_t get_fx_2_type_size(const struct hlsl_type *type) ++static uint32_t write_fx_2_default_value(struct hlsl_type *value_type, struct hlsl_default_value *value, ++ struct fx_write_context *fx) + { +- uint32_t size = 0, elements_count; +- size_t i; ++ const struct hlsl_type *type = hlsl_get_multiarray_element_type(value_type); ++ uint32_t elements_count = hlsl_get_multiarray_size(value_type), i, j; ++ struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; ++ struct hlsl_ctx *ctx = fx->ctx; ++ uint32_t offset = buffer->size; ++ unsigned int comp_count; + +- if (type->class == HLSL_CLASS_ARRAY) +- { +- elements_count = hlsl_get_multiarray_size(type); +- type = hlsl_get_multiarray_element_type(type); +- return get_fx_2_type_size(type) * elements_count; +- } +- else if (type->class == HLSL_CLASS_STRUCT) ++ if (!value) ++ return 0; ++ ++ comp_count = hlsl_type_component_count(type); ++ ++ for (i = 0; i < elements_count; ++i) + { +- for (i = 0; i < type->e.record.field_count; ++i) ++ switch (type->class) + { +- const struct hlsl_struct_field *field = &type->e.record.fields[i]; +- size += get_fx_2_type_size(field->type); +- } ++ case HLSL_CLASS_SCALAR: ++ case HLSL_CLASS_VECTOR: ++ case HLSL_CLASS_MATRIX: ++ { ++ switch (type->e.numeric.type) ++ { ++ case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: ++ case HLSL_TYPE_INT: ++ case HLSL_TYPE_UINT: ++ case HLSL_TYPE_BOOL: ++ ++ for (j = 0; j < comp_count; ++j) ++ { ++ put_u32(buffer, value->number.u); ++ value++; ++ } ++ break; ++ default: ++ hlsl_fixme(ctx, &ctx->location, "Writing default values for numeric type %u is not implemented.", ++ type->e.numeric.type); ++ } + +- return size; ++ break; ++ } ++ case HLSL_CLASS_STRUCT: ++ { ++ struct hlsl_struct_field *fields = type->e.record.fields; ++ ++ for (j = 0; j < type->e.record.field_count; ++j) ++ { ++ write_fx_2_default_value(fields[i].type, value, fx); ++ value += hlsl_type_component_count(fields[i].type); ++ } ++ break; ++ } ++ default: ++ hlsl_fixme(ctx, &ctx->location, "Writing default values for class %u is not implemented.", type->class); ++ } + } + +- return type->dimx * type->dimy * sizeof(float); ++ return offset; + } + + static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct fx_write_context *fx) + { + struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + const struct hlsl_type *type = var->data_type; +- uint32_t offset, size, elements_count = 1; +- +- size = get_fx_2_type_size(type); ++ uint32_t offset, elements_count = 1; ++ struct hlsl_ctx *ctx = fx->ctx; + + if (type->class == HLSL_CLASS_ARRAY) + { +@@ -1044,16 +1093,17 @@ static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct f + case HLSL_CLASS_VECTOR: + case HLSL_CLASS_MATRIX: + case HLSL_CLASS_STRUCT: +- /* FIXME: write actual initial value */ +- if (var->default_values) +- hlsl_fixme(fx->ctx, &var->loc, "Write default values.\n"); +- +- offset = put_u32(buffer, 0); +- +- for (uint32_t i = 1; i < size / sizeof(uint32_t); ++i) +- put_u32(buffer, 0); ++ offset = write_fx_2_default_value(var->data_type, var->default_values, fx); + break; + ++ case HLSL_CLASS_TEXTURE: ++ case HLSL_CLASS_PIXEL_SHADER: ++ case HLSL_CLASS_SAMPLER: ++ case HLSL_CLASS_STRING: ++ case HLSL_CLASS_VERTEX_SHADER: ++ hlsl_fixme(ctx, &var->loc, "Write fx 2.0 object initializer."); ++ /* fallthrough */ ++ + default: + /* Objects are given sequential ids. */ + offset = put_u32(buffer, fx->object_variable_count++); +@@ -1132,8 +1182,8 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type + + static void write_fx_2_parameters(struct fx_write_context *fx) + { ++ uint32_t desc_offset, value_offset, flags, annotation_count_offset; + struct vkd3d_bytecode_buffer *buffer = &fx->structured; +- uint32_t desc_offset, value_offset, flags; + struct hlsl_ctx *ctx = fx->ctx; + struct hlsl_ir_var *var; + enum fx_2_parameter_flags +@@ -1153,23 +1203,35 @@ static void write_fx_2_parameters(struct fx_write_context *fx) + if (var->storage_modifiers & HLSL_STORAGE_SHARED) + flags |= IS_SHARED; + +- put_u32(buffer, desc_offset); /* Parameter description */ +- put_u32(buffer, value_offset); /* Value */ +- put_u32(buffer, flags); /* Flags */ ++ put_u32(buffer, desc_offset); ++ put_u32(buffer, value_offset); ++ put_u32(buffer, flags); + +- put_u32(buffer, 0); /* Annotations count */ +- if (has_annotations(var)) +- hlsl_fixme(ctx, &ctx->location, "Writing annotations for parameters is not implemented."); ++ annotation_count_offset = put_u32(buffer, 0); ++ write_fx_2_annotations(var, annotation_count_offset, fx); + + ++fx->parameter_count; + } + } + ++static void write_fx_2_annotation(struct hlsl_ir_var *var, struct fx_write_context *fx) ++{ ++ struct vkd3d_bytecode_buffer *buffer = &fx->structured; ++ uint32_t desc_offset, value_offset; ++ ++ desc_offset = write_fx_2_parameter(var->data_type, var->name, &var->semantic, fx); ++ value_offset = write_fx_2_initial_value(var, fx); ++ ++ put_u32(buffer, desc_offset); ++ put_u32(buffer, value_offset); ++} ++ + static const struct fx_write_context_ops fx_2_ops = + { + .write_string = write_fx_2_string, + .write_technique = write_fx_2_technique, + .write_pass = write_fx_2_pass, ++ .write_annotation = write_fx_2_annotation, + }; + + static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) +@@ -1267,6 +1329,7 @@ static uint32_t write_fx_4_default_value(struct hlsl_type *value_type, struct hl + switch (type->e.numeric.type) + { + case HLSL_TYPE_FLOAT: ++ case HLSL_TYPE_HALF: + case HLSL_TYPE_INT: + case HLSL_TYPE_UINT: + case HLSL_TYPE_BOOL: +diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c +index a8cc6d87c40..26fd4818970 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c +@@ -137,6 +137,14 @@ static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer, + vkd3d_string_buffer_printf(buffer, "%s_out[%u]", gen->prefix, reg->idx[0].offset); + break; + ++ case VKD3DSPR_DEPTHOUT: ++ if (gen->program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL) ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled depth output in shader type #%x.", ++ gen->program->shader_version.type); ++ vkd3d_string_buffer_printf(buffer, "gl_FragDepth"); ++ break; ++ + case VKD3DSPR_IMMCONST: + switch (reg->dimension) + { +@@ -420,6 +428,30 @@ static void shader_glsl_binop(struct vkd3d_glsl_generator *gen, + glsl_dst_cleanup(&dst, &gen->string_buffers); + } + ++static void shader_glsl_dot(struct vkd3d_glsl_generator *gen, ++ const struct vkd3d_shader_instruction *ins, uint32_t src_mask) ++{ ++ unsigned int component_count; ++ struct glsl_src src[2]; ++ struct glsl_dst dst; ++ uint32_t dst_mask; ++ ++ dst_mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ glsl_src_init(&src[0], gen, &ins->src[0], src_mask); ++ glsl_src_init(&src[1], gen, &ins->src[1], src_mask); ++ ++ if ((component_count = vsir_write_mask_component_count(dst_mask)) > 1) ++ shader_glsl_print_assignment(gen, &dst, "vec%d(dot(%s, %s))", ++ component_count, src[0].str->buffer, src[1].str->buffer); ++ else ++ shader_glsl_print_assignment(gen, &dst, "dot(%s, %s)", ++ src[0].str->buffer, src[1].str->buffer); ++ ++ glsl_src_cleanup(&src[1], &gen->string_buffers); ++ glsl_src_cleanup(&src[0], &gen->string_buffers); ++ glsl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ + static void shader_glsl_intrinsic(struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_instruction *ins, const char *op) + { +@@ -482,6 +514,31 @@ static void shader_glsl_cast(struct vkd3d_glsl_generator *gen, const struct vkd3 + glsl_dst_cleanup(&dst, &gen->string_buffers); + } + ++static void shader_glsl_if(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) ++{ ++ const char *condition; ++ struct glsl_src src; ++ ++ glsl_src_init(&src, gen, &ins->src[0], VKD3DSP_WRITEMASK_0); ++ ++ shader_glsl_print_indent(gen->buffer, gen->indent); ++ condition = ins->flags == VKD3D_SHADER_CONDITIONAL_OP_NZ ? "bool" : "!bool"; ++ vkd3d_string_buffer_printf(gen->buffer, "if (%s(%s))\n", condition, src.str->buffer); ++ ++ glsl_src_cleanup(&src, &gen->string_buffers); ++ ++ shader_glsl_print_indent(gen->buffer, gen->indent); ++ vkd3d_string_buffer_printf(gen->buffer, "{\n"); ++ ++gen->indent; ++} ++ ++static void shader_glsl_endif(struct vkd3d_glsl_generator *gen) ++{ ++ --gen->indent; ++ shader_glsl_print_indent(gen->buffer, gen->indent); ++ vkd3d_string_buffer_printf(gen->buffer, "}\n"); ++} ++ + static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) + { + struct glsl_src src; +@@ -545,6 +602,15 @@ static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, st + } + break; + ++ case VKD3D_SHADER_SV_IS_FRONT_FACE: ++ if (version->type != VKD3D_SHADER_TYPE_PIXEL) ++ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, ++ "Internal compiler error: Unhandled SV_IS_FRONT_FACE in shader type #%x.", version->type); ++ vkd3d_string_buffer_printf(buffer, ++ "uintBitsToFloat(uvec4(gl_FrontFacing ? 0xffffffffu : 0u, 0u, 0u, 0u))"); ++ ++ break; ++ + case VKD3D_SHADER_SV_TARGET: + if (version->type != VKD3D_SHADER_TYPE_PIXEL) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, +@@ -673,6 +739,8 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + shader_glsl_binop(gen, ins, "&"); + break; + case VKD3DSIH_DCL_INPUT: ++ case VKD3DSIH_DCL_INPUT_PS: ++ case VKD3DSIH_DCL_INPUT_PS_SIV: + case VKD3DSIH_DCL_OUTPUT: + case VKD3DSIH_DCL_OUTPUT_SIV: + case VKD3DSIH_NOP: +@@ -680,6 +748,24 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_DIV: + shader_glsl_binop(gen, ins, "/"); + break; ++ case VKD3DSIH_DP2: ++ shader_glsl_dot(gen, ins, vkd3d_write_mask_from_component_count(2)); ++ break; ++ case VKD3DSIH_DP3: ++ shader_glsl_dot(gen, ins, vkd3d_write_mask_from_component_count(3)); ++ break; ++ case VKD3DSIH_DP4: ++ shader_glsl_dot(gen, ins, VKD3DSP_WRITEMASK_ALL); ++ break; ++ case VKD3DSIH_ENDIF: ++ shader_glsl_endif(gen); ++ break; ++ case VKD3DSIH_IEQ: ++ shader_glsl_relop(gen, ins, "==", "equal"); ++ break; ++ case VKD3DSIH_EXP: ++ shader_glsl_intrinsic(gen, ins, "exp2"); ++ break; + case VKD3DSIH_FRC: + shader_glsl_intrinsic(gen, ins, "fract"); + break; +@@ -692,6 +778,12 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_GEO: + shader_glsl_relop(gen, ins, ">=", "greaterThanEqual"); + break; ++ case VKD3DSIH_IF: ++ shader_glsl_if(gen, ins); ++ break; ++ case VKD3DSIH_LTO: ++ shader_glsl_relop(gen, ins, "<", "lessThan"); ++ break; + case VKD3DSIH_INE: + case VKD3DSIH_NEU: + shader_glsl_relop(gen, ins, "!=", "notEqual"); +@@ -700,6 +792,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_UTOF: + shader_glsl_cast(gen, ins, "float", "vec"); + break; ++ case VKD3DSIH_LOG: ++ shader_glsl_intrinsic(gen, ins, "log2"); ++ break; + case VKD3DSIH_MOV: + shader_glsl_mov(gen, ins); + break; +@@ -715,9 +810,21 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_RET: + shader_glsl_ret(gen, ins); + break; ++ case VKD3DSIH_ROUND_NE: ++ shader_glsl_intrinsic(gen, ins, "roundEven"); ++ break; ++ case VKD3DSIH_ROUND_NI: ++ shader_glsl_intrinsic(gen, ins, "floor"); ++ break; + case VKD3DSIH_ROUND_PI: + shader_glsl_intrinsic(gen, ins, "ceil"); + break; ++ case VKD3DSIH_ROUND_Z: ++ shader_glsl_intrinsic(gen, ins, "trunc"); ++ break; ++ case VKD3DSIH_SQRT: ++ shader_glsl_intrinsic(gen, ins, "sqrt"); ++ break; + default: + shader_glsl_unhandled(gen, ins); + break; +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index 0bbe13ad7d8..88650a97068 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -182,7 +182,7 @@ static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_ + + static void vsir_src_param_init_resource(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx) + { +- vsir_src_param_init(src, VKD3DSPR_RESOURCE, VKD3D_DATA_RESOURCE, 2); ++ vsir_src_param_init(src, VKD3DSPR_RESOURCE, VKD3D_DATA_UNUSED, 2); + src->reg.idx[0].offset = id; + src->reg.idx[1].offset = idx; + src->reg.dimension = VSIR_DIMENSION_VEC4; +@@ -191,7 +191,7 @@ static void vsir_src_param_init_resource(struct vkd3d_shader_src_param *src, uns + + static void vsir_src_param_init_sampler(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx) + { +- vsir_src_param_init(src, VKD3DSPR_SAMPLER, VKD3D_DATA_SAMPLER, 2); ++ vsir_src_param_init(src, VKD3DSPR_SAMPLER, VKD3D_DATA_UNUSED, 2); + src->reg.idx[0].offset = id; + src->reg.idx[1].offset = idx; + src->reg.dimension = VSIR_DIMENSION_NONE; +@@ -5960,6 +5960,58 @@ static void vsir_validate_register(struct validation_context *ctx, + reg->idx_count); + break; + ++ case VKD3DSPR_SAMPLER: ++ if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, ++ "Invalid precision %#x for a SAMPLER register.", ++ reg->precision); ++ ++ if (reg->data_type != VKD3D_DATA_UNUSED) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, ++ "Invalid data type %#x for a SAMPLER register.", ++ reg->data_type); ++ ++ /* VEC4 is allowed in gather operations. */ ++ if (reg->dimension == VSIR_DIMENSION_SCALAR) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, ++ "Invalid dimension SCALAR for a SAMPLER register."); ++ break; ++ ++ case VKD3DSPR_RESOURCE: ++ if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, ++ "Invalid precision %#x for a RESOURCE register.", ++ reg->precision); ++ ++ if (reg->data_type != VKD3D_DATA_UNUSED) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, ++ "Invalid data type %#x for a RESOURCE register.", ++ reg->data_type); ++ ++ if (reg->dimension != VSIR_DIMENSION_VEC4) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, ++ "Invalid dimension %#x for a RESOURCE register.", ++ reg->dimension); ++ break; ++ ++ case VKD3DSPR_UAV: ++ if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, ++ "Invalid precision %#x for a UAV register.", ++ reg->precision); ++ ++ if (reg->data_type != VKD3D_DATA_UNUSED) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, ++ "Invalid data type %#x for a UAV register.", ++ reg->data_type); ++ ++ /* NONE is allowed in counter operations. */ ++ if (reg->dimension == VSIR_DIMENSION_SCALAR) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, ++ "Invalid dimension %#x for a UAV register.", ++ reg->dimension); ++ break; ++ + default: + break; + } +@@ -6045,6 +6097,16 @@ static void vsir_validate_dst_param(struct validation_context *ctx, + "Invalid IMMCONST64 register used as destination parameter."); + break; + ++ case VKD3DSPR_SAMPLER: ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid SAMPLER register used as destination parameter."); ++ break; ++ ++ case VKD3DSPR_RESOURCE: ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid RESOURCE register used as destination parameter."); ++ break; ++ + default: + break; + } +@@ -6080,6 +6142,11 @@ static void vsir_validate_src_param(struct validation_context *ctx, + } + break; + ++ case VKD3DSPR_NULL: ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, ++ "Invalid NULL register used as source parameter."); ++ break; ++ + default: + break; + } +diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c +index ab9f4cf2b57..389946e2c2f 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c ++++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c +@@ -896,7 +896,7 @@ static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins, u + >> VKD3D_SM4_RESOURCE_SAMPLE_COUNT_SHIFT; + } + +- reg_data_type = opcode == VKD3D_SM4_OP_DCL_RESOURCE ? VKD3D_DATA_RESOURCE : VKD3D_DATA_UAV; ++ reg_data_type = VKD3D_DATA_UNUSED; + shader_sm4_read_dst_param(priv, &tokens, end, reg_data_type, &semantic->resource.reg); + shader_sm4_set_descriptor_register_range(priv, &semantic->resource.reg.reg, &semantic->resource.range); + +@@ -916,7 +916,7 @@ static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins, u + } + } + +- if (reg_data_type == VKD3D_DATA_UAV) ++ if (opcode != VKD3D_SM4_OP_DCL_RESOURCE) + ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT; + + shader_sm4_read_register_space(priv, &tokens, end, &semantic->resource.range.space); +@@ -958,7 +958,7 @@ static void shader_sm4_read_dcl_sampler(struct vkd3d_shader_instruction *ins, ui + ins->flags = (opcode_token & VKD3D_SM4_SAMPLER_MODE_MASK) >> VKD3D_SM4_SAMPLER_MODE_SHIFT; + if (ins->flags & ~VKD3D_SM4_SAMPLER_COMPARISON) + FIXME("Unhandled sampler mode %#x.\n", ins->flags); +- shader_sm4_read_src_param(priv, &tokens, end, VKD3D_DATA_SAMPLER, &ins->declaration.sampler.src); ++ shader_sm4_read_src_param(priv, &tokens, end, VKD3D_DATA_UNUSED, &ins->declaration.sampler.src); + shader_sm4_set_descriptor_register_range(priv, &ins->declaration.sampler.src.reg, &ins->declaration.sampler.range); + shader_sm4_read_register_space(priv, &tokens, end, &ins->declaration.sampler.range.space); + } +@@ -1302,7 +1302,7 @@ static void shader_sm5_read_dcl_uav_raw(struct vkd3d_shader_instruction *ins, ui + struct vkd3d_shader_raw_resource *resource = &ins->declaration.raw_resource; + const uint32_t *end = &tokens[token_count]; + +- shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UAV, &resource->resource.reg); ++ shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); + ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT; + shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.range.space); +@@ -1314,7 +1314,7 @@ static void shader_sm5_read_dcl_uav_structured(struct vkd3d_shader_instruction * + struct vkd3d_shader_structured_resource *resource = &ins->declaration.structured_resource; + const uint32_t *end = &tokens[token_count]; + +- shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UAV, &resource->resource.reg); ++ shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); + ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT; + resource->byte_stride = *tokens++; +@@ -1351,7 +1351,7 @@ static void shader_sm5_read_dcl_resource_structured(struct vkd3d_shader_instruct + struct vkd3d_shader_structured_resource *resource = &ins->declaration.structured_resource; + const uint32_t *end = &tokens[token_count]; + +- shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_RESOURCE, &resource->resource.reg); ++ shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); + resource->byte_stride = *tokens++; + if (resource->byte_stride % 4) +@@ -1365,7 +1365,7 @@ static void shader_sm5_read_dcl_resource_raw(struct vkd3d_shader_instruction *in + struct vkd3d_shader_raw_resource *resource = &ins->declaration.raw_resource; + const uint32_t *end = &tokens[token_count]; + +- shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_RESOURCE, &resource->resource.reg); ++ shader_sm4_read_dst_param(priv, &tokens, end, VKD3D_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); + shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.range.space); + } +@@ -1471,8 +1471,8 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + {VKD3D_SM4_OP_ISHR, VKD3DSIH_ISHR, "i", "ii"}, + {VKD3D_SM4_OP_ITOF, VKD3DSIH_ITOF, "f", "i"}, + {VKD3D_SM4_OP_LABEL, VKD3DSIH_LABEL, "", "O"}, +- {VKD3D_SM4_OP_LD, VKD3DSIH_LD, "u", "iR"}, +- {VKD3D_SM4_OP_LD2DMS, VKD3DSIH_LD2DMS, "u", "iRi"}, ++ {VKD3D_SM4_OP_LD, VKD3DSIH_LD, "u", "i*"}, ++ {VKD3D_SM4_OP_LD2DMS, VKD3DSIH_LD2DMS, "u", "i*i"}, + {VKD3D_SM4_OP_LOG, VKD3DSIH_LOG, "f", "f"}, + {VKD3D_SM4_OP_LOOP, VKD3DSIH_LOOP, "", ""}, + {VKD3D_SM4_OP_LT, VKD3DSIH_LTO, "u", "ff"}, +@@ -1488,7 +1488,7 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + {VKD3D_SM4_OP_NOP, VKD3DSIH_NOP, "", ""}, + {VKD3D_SM4_OP_NOT, VKD3DSIH_NOT, "u", "u"}, + {VKD3D_SM4_OP_OR, VKD3DSIH_OR, "u", "uu"}, +- {VKD3D_SM4_OP_RESINFO, VKD3DSIH_RESINFO, "f", "iR"}, ++ {VKD3D_SM4_OP_RESINFO, VKD3DSIH_RESINFO, "f", "i*"}, + {VKD3D_SM4_OP_RET, VKD3DSIH_RET, "", ""}, + {VKD3D_SM4_OP_RETC, VKD3DSIH_RETP, "", "u", + shader_sm4_read_conditional_op}, +@@ -1497,12 +1497,12 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + {VKD3D_SM4_OP_ROUND_PI, VKD3DSIH_ROUND_PI, "f", "f"}, + {VKD3D_SM4_OP_ROUND_Z, VKD3DSIH_ROUND_Z, "f", "f"}, + {VKD3D_SM4_OP_RSQ, VKD3DSIH_RSQ, "f", "f"}, +- {VKD3D_SM4_OP_SAMPLE, VKD3DSIH_SAMPLE, "u", "fRS"}, +- {VKD3D_SM4_OP_SAMPLE_C, VKD3DSIH_SAMPLE_C, "f", "fRSf"}, +- {VKD3D_SM4_OP_SAMPLE_C_LZ, VKD3DSIH_SAMPLE_C_LZ, "f", "fRSf"}, +- {VKD3D_SM4_OP_SAMPLE_LOD, VKD3DSIH_SAMPLE_LOD, "u", "fRSf"}, +- {VKD3D_SM4_OP_SAMPLE_GRAD, VKD3DSIH_SAMPLE_GRAD, "u", "fRSff"}, +- {VKD3D_SM4_OP_SAMPLE_B, VKD3DSIH_SAMPLE_B, "u", "fRSf"}, ++ {VKD3D_SM4_OP_SAMPLE, VKD3DSIH_SAMPLE, "u", "f**"}, ++ {VKD3D_SM4_OP_SAMPLE_C, VKD3DSIH_SAMPLE_C, "f", "f**f"}, ++ {VKD3D_SM4_OP_SAMPLE_C_LZ, VKD3DSIH_SAMPLE_C_LZ, "f", "f**f"}, ++ {VKD3D_SM4_OP_SAMPLE_LOD, VKD3DSIH_SAMPLE_LOD, "u", "f**f"}, ++ {VKD3D_SM4_OP_SAMPLE_GRAD, VKD3DSIH_SAMPLE_GRAD, "u", "f**ff"}, ++ {VKD3D_SM4_OP_SAMPLE_B, VKD3DSIH_SAMPLE_B, "u", "f**f"}, + {VKD3D_SM4_OP_SQRT, VKD3DSIH_SQRT, "f", "f"}, + {VKD3D_SM4_OP_SWITCH, VKD3DSIH_SWITCH, "", "i"}, + {VKD3D_SM4_OP_SINCOS, VKD3DSIH_SINCOS, "ff", "f"}, +@@ -1551,10 +1551,10 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + shader_sm4_read_dcl_indexable_temp}, + {VKD3D_SM4_OP_DCL_GLOBAL_FLAGS, VKD3DSIH_DCL_GLOBAL_FLAGS, "", "", + shader_sm4_read_dcl_global_flags}, +- {VKD3D_SM4_OP_LOD, VKD3DSIH_LOD, "f", "fRS"}, +- {VKD3D_SM4_OP_GATHER4, VKD3DSIH_GATHER4, "u", "fRS"}, +- {VKD3D_SM4_OP_SAMPLE_POS, VKD3DSIH_SAMPLE_POS, "f", "Ru"}, +- {VKD3D_SM4_OP_SAMPLE_INFO, VKD3DSIH_SAMPLE_INFO, "f", "R"}, ++ {VKD3D_SM4_OP_LOD, VKD3DSIH_LOD, "f", "f**"}, ++ {VKD3D_SM4_OP_GATHER4, VKD3DSIH_GATHER4, "u", "f**"}, ++ {VKD3D_SM4_OP_SAMPLE_POS, VKD3DSIH_SAMPLE_POS, "f", "*u"}, ++ {VKD3D_SM4_OP_SAMPLE_INFO, VKD3DSIH_SAMPLE_INFO, "f", "*"}, + {VKD3D_SM5_OP_HS_DECLS, VKD3DSIH_HS_DECLS, "", ""}, + {VKD3D_SM5_OP_HS_CONTROL_POINT_PHASE, VKD3DSIH_HS_CONTROL_POINT_PHASE, "", ""}, + {VKD3D_SM5_OP_HS_FORK_PHASE, VKD3DSIH_HS_FORK_PHASE, "", ""}, +@@ -1563,14 +1563,14 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + {VKD3D_SM5_OP_CUT_STREAM, VKD3DSIH_CUT_STREAM, "", "f"}, + {VKD3D_SM5_OP_FCALL, VKD3DSIH_FCALL, "", "O", + shader_sm5_read_fcall}, +- {VKD3D_SM5_OP_BUFINFO, VKD3DSIH_BUFINFO, "i", "U"}, ++ {VKD3D_SM5_OP_BUFINFO, VKD3DSIH_BUFINFO, "i", "*"}, + {VKD3D_SM5_OP_DERIV_RTX_COARSE, VKD3DSIH_DSX_COARSE, "f", "f"}, + {VKD3D_SM5_OP_DERIV_RTX_FINE, VKD3DSIH_DSX_FINE, "f", "f"}, + {VKD3D_SM5_OP_DERIV_RTY_COARSE, VKD3DSIH_DSY_COARSE, "f", "f"}, + {VKD3D_SM5_OP_DERIV_RTY_FINE, VKD3DSIH_DSY_FINE, "f", "f"}, +- {VKD3D_SM5_OP_GATHER4_C, VKD3DSIH_GATHER4_C, "f", "fRSf"}, +- {VKD3D_SM5_OP_GATHER4_PO, VKD3DSIH_GATHER4_PO, "f", "fiRS"}, +- {VKD3D_SM5_OP_GATHER4_PO_C, VKD3DSIH_GATHER4_PO_C, "f", "fiRSf"}, ++ {VKD3D_SM5_OP_GATHER4_C, VKD3DSIH_GATHER4_C, "f", "f**f"}, ++ {VKD3D_SM5_OP_GATHER4_PO, VKD3DSIH_GATHER4_PO, "f", "fi**"}, ++ {VKD3D_SM5_OP_GATHER4_PO_C, VKD3DSIH_GATHER4_PO_C, "f", "fi**f"}, + {VKD3D_SM5_OP_RCP, VKD3DSIH_RCP, "f", "f"}, + {VKD3D_SM5_OP_F32TOF16, VKD3DSIH_F32TOF16, "u", "f"}, + {VKD3D_SM5_OP_F16TOF32, VKD3DSIH_F16TOF32, "f", "u"}, +@@ -1622,33 +1622,33 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + shader_sm5_read_dcl_resource_raw}, + {VKD3D_SM5_OP_DCL_RESOURCE_STRUCTURED, VKD3DSIH_DCL_RESOURCE_STRUCTURED, "", "", + shader_sm5_read_dcl_resource_structured}, +- {VKD3D_SM5_OP_LD_UAV_TYPED, VKD3DSIH_LD_UAV_TYPED, "u", "iU"}, +- {VKD3D_SM5_OP_STORE_UAV_TYPED, VKD3DSIH_STORE_UAV_TYPED, "U", "iu"}, +- {VKD3D_SM5_OP_LD_RAW, VKD3DSIH_LD_RAW, "u", "iU"}, +- {VKD3D_SM5_OP_STORE_RAW, VKD3DSIH_STORE_RAW, "U", "uu"}, +- {VKD3D_SM5_OP_LD_STRUCTURED, VKD3DSIH_LD_STRUCTURED, "u", "iiR"}, +- {VKD3D_SM5_OP_STORE_STRUCTURED, VKD3DSIH_STORE_STRUCTURED, "U", "iiu"}, +- {VKD3D_SM5_OP_ATOMIC_AND, VKD3DSIH_ATOMIC_AND, "U", "iu"}, +- {VKD3D_SM5_OP_ATOMIC_OR, VKD3DSIH_ATOMIC_OR, "U", "iu"}, +- {VKD3D_SM5_OP_ATOMIC_XOR, VKD3DSIH_ATOMIC_XOR, "U", "iu"}, +- {VKD3D_SM5_OP_ATOMIC_CMP_STORE, VKD3DSIH_ATOMIC_CMP_STORE, "U", "iuu"}, +- {VKD3D_SM5_OP_ATOMIC_IADD, VKD3DSIH_ATOMIC_IADD, "U", "ii"}, +- {VKD3D_SM5_OP_ATOMIC_IMAX, VKD3DSIH_ATOMIC_IMAX, "U", "ii"}, +- {VKD3D_SM5_OP_ATOMIC_IMIN, VKD3DSIH_ATOMIC_IMIN, "U", "ii"}, +- {VKD3D_SM5_OP_ATOMIC_UMAX, VKD3DSIH_ATOMIC_UMAX, "U", "iu"}, +- {VKD3D_SM5_OP_ATOMIC_UMIN, VKD3DSIH_ATOMIC_UMIN, "U", "iu"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_ALLOC, VKD3DSIH_IMM_ATOMIC_ALLOC, "u", "U"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_CONSUME, VKD3DSIH_IMM_ATOMIC_CONSUME, "u", "U"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_IADD, VKD3DSIH_IMM_ATOMIC_IADD, "uU", "ii"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_AND, VKD3DSIH_IMM_ATOMIC_AND, "uU", "iu"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_OR, VKD3DSIH_IMM_ATOMIC_OR, "uU", "iu"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_XOR, VKD3DSIH_IMM_ATOMIC_XOR, "uU", "iu"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_EXCH, VKD3DSIH_IMM_ATOMIC_EXCH, "uU", "iu"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_CMP_EXCH, VKD3DSIH_IMM_ATOMIC_CMP_EXCH, "uU", "iuu"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_IMAX, VKD3DSIH_IMM_ATOMIC_IMAX, "iU", "ii"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_IMIN, VKD3DSIH_IMM_ATOMIC_IMIN, "iU", "ii"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_UMAX, VKD3DSIH_IMM_ATOMIC_UMAX, "uU", "iu"}, +- {VKD3D_SM5_OP_IMM_ATOMIC_UMIN, VKD3DSIH_IMM_ATOMIC_UMIN, "uU", "iu"}, ++ {VKD3D_SM5_OP_LD_UAV_TYPED, VKD3DSIH_LD_UAV_TYPED, "u", "i*"}, ++ {VKD3D_SM5_OP_STORE_UAV_TYPED, VKD3DSIH_STORE_UAV_TYPED, "*", "iu"}, ++ {VKD3D_SM5_OP_LD_RAW, VKD3DSIH_LD_RAW, "u", "i*"}, ++ {VKD3D_SM5_OP_STORE_RAW, VKD3DSIH_STORE_RAW, "*", "uu"}, ++ {VKD3D_SM5_OP_LD_STRUCTURED, VKD3DSIH_LD_STRUCTURED, "u", "ii*"}, ++ {VKD3D_SM5_OP_STORE_STRUCTURED, VKD3DSIH_STORE_STRUCTURED, "*", "iiu"}, ++ {VKD3D_SM5_OP_ATOMIC_AND, VKD3DSIH_ATOMIC_AND, "*", "iu"}, ++ {VKD3D_SM5_OP_ATOMIC_OR, VKD3DSIH_ATOMIC_OR, "*", "iu"}, ++ {VKD3D_SM5_OP_ATOMIC_XOR, VKD3DSIH_ATOMIC_XOR, "*", "iu"}, ++ {VKD3D_SM5_OP_ATOMIC_CMP_STORE, VKD3DSIH_ATOMIC_CMP_STORE, "*", "iuu"}, ++ {VKD3D_SM5_OP_ATOMIC_IADD, VKD3DSIH_ATOMIC_IADD, "*", "ii"}, ++ {VKD3D_SM5_OP_ATOMIC_IMAX, VKD3DSIH_ATOMIC_IMAX, "*", "ii"}, ++ {VKD3D_SM5_OP_ATOMIC_IMIN, VKD3DSIH_ATOMIC_IMIN, "*", "ii"}, ++ {VKD3D_SM5_OP_ATOMIC_UMAX, VKD3DSIH_ATOMIC_UMAX, "*", "iu"}, ++ {VKD3D_SM5_OP_ATOMIC_UMIN, VKD3DSIH_ATOMIC_UMIN, "*", "iu"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_ALLOC, VKD3DSIH_IMM_ATOMIC_ALLOC, "u", "*"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_CONSUME, VKD3DSIH_IMM_ATOMIC_CONSUME, "u", "*"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_IADD, VKD3DSIH_IMM_ATOMIC_IADD, "u*", "ii"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_AND, VKD3DSIH_IMM_ATOMIC_AND, "u*", "iu"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_OR, VKD3DSIH_IMM_ATOMIC_OR, "u*", "iu"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_XOR, VKD3DSIH_IMM_ATOMIC_XOR, "u*", "iu"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_EXCH, VKD3DSIH_IMM_ATOMIC_EXCH, "u*", "iu"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_CMP_EXCH, VKD3DSIH_IMM_ATOMIC_CMP_EXCH, "u*", "iuu"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_IMAX, VKD3DSIH_IMM_ATOMIC_IMAX, "i*", "ii"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_IMIN, VKD3DSIH_IMM_ATOMIC_IMIN, "i*", "ii"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_UMAX, VKD3DSIH_IMM_ATOMIC_UMAX, "u*", "iu"}, ++ {VKD3D_SM5_OP_IMM_ATOMIC_UMIN, VKD3DSIH_IMM_ATOMIC_UMIN, "u*", "iu"}, + {VKD3D_SM5_OP_SYNC, VKD3DSIH_SYNC, "", "", + shader_sm5_read_sync}, + {VKD3D_SM5_OP_DADD, VKD3DSIH_DADD, "d", "dd"}, +@@ -1675,21 +1675,21 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) + {VKD3D_SM5_OP_DTOU, VKD3DSIH_DTOU, "u", "d"}, + {VKD3D_SM5_OP_ITOD, VKD3DSIH_ITOD, "d", "i"}, + {VKD3D_SM5_OP_UTOD, VKD3DSIH_UTOD, "d", "u"}, +- {VKD3D_SM5_OP_GATHER4_S, VKD3DSIH_GATHER4_S, "uu", "fRS"}, +- {VKD3D_SM5_OP_GATHER4_C_S, VKD3DSIH_GATHER4_C_S, "fu", "fRSf"}, +- {VKD3D_SM5_OP_GATHER4_PO_S, VKD3DSIH_GATHER4_PO_S, "fu", "fiRS"}, +- {VKD3D_SM5_OP_GATHER4_PO_C_S, VKD3DSIH_GATHER4_PO_C_S, "fu", "fiRSf"}, +- {VKD3D_SM5_OP_LD_S, VKD3DSIH_LD_S, "uu", "iR"}, +- {VKD3D_SM5_OP_LD2DMS_S, VKD3DSIH_LD2DMS_S, "uu", "iRi"}, ++ {VKD3D_SM5_OP_GATHER4_S, VKD3DSIH_GATHER4_S, "uu", "f**"}, ++ {VKD3D_SM5_OP_GATHER4_C_S, VKD3DSIH_GATHER4_C_S, "fu", "f**f"}, ++ {VKD3D_SM5_OP_GATHER4_PO_S, VKD3DSIH_GATHER4_PO_S, "fu", "fi**"}, ++ {VKD3D_SM5_OP_GATHER4_PO_C_S, VKD3DSIH_GATHER4_PO_C_S, "fu", "fi**f"}, ++ {VKD3D_SM5_OP_LD_S, VKD3DSIH_LD_S, "uu", "i*"}, ++ {VKD3D_SM5_OP_LD2DMS_S, VKD3DSIH_LD2DMS_S, "uu", "i*i"}, + {VKD3D_SM5_OP_LD_UAV_TYPED_S, VKD3DSIH_LD_UAV_TYPED_S, "uu", "iU"}, + {VKD3D_SM5_OP_LD_RAW_S, VKD3DSIH_LD_RAW_S, "uu", "iU"}, +- {VKD3D_SM5_OP_LD_STRUCTURED_S, VKD3DSIH_LD_STRUCTURED_S, "uu", "iiR"}, +- {VKD3D_SM5_OP_SAMPLE_LOD_S, VKD3DSIH_SAMPLE_LOD_S, "uu", "fRSf"}, +- {VKD3D_SM5_OP_SAMPLE_C_LZ_S, VKD3DSIH_SAMPLE_C_LZ_S, "fu", "fRSf"}, +- {VKD3D_SM5_OP_SAMPLE_CL_S, VKD3DSIH_SAMPLE_CL_S, "uu", "fRSf"}, +- {VKD3D_SM5_OP_SAMPLE_B_CL_S, VKD3DSIH_SAMPLE_B_CL_S, "uu", "fRSff"}, +- {VKD3D_SM5_OP_SAMPLE_GRAD_CL_S, VKD3DSIH_SAMPLE_GRAD_CL_S, "uu", "fRSfff"}, +- {VKD3D_SM5_OP_SAMPLE_C_CL_S, VKD3DSIH_SAMPLE_C_CL_S, "fu", "fRSff"}, ++ {VKD3D_SM5_OP_LD_STRUCTURED_S, VKD3DSIH_LD_STRUCTURED_S, "uu", "ii*"}, ++ {VKD3D_SM5_OP_SAMPLE_LOD_S, VKD3DSIH_SAMPLE_LOD_S, "uu", "f**f"}, ++ {VKD3D_SM5_OP_SAMPLE_C_LZ_S, VKD3DSIH_SAMPLE_C_LZ_S, "fu", "f**f"}, ++ {VKD3D_SM5_OP_SAMPLE_CL_S, VKD3DSIH_SAMPLE_CL_S, "uu", "f**f"}, ++ {VKD3D_SM5_OP_SAMPLE_B_CL_S, VKD3DSIH_SAMPLE_B_CL_S, "uu", "f**ff"}, ++ {VKD3D_SM5_OP_SAMPLE_GRAD_CL_S, VKD3DSIH_SAMPLE_GRAD_CL_S, "uu", "f**fff"}, ++ {VKD3D_SM5_OP_SAMPLE_C_CL_S, VKD3DSIH_SAMPLE_C_CL_S, "fu", "f**ff"}, + {VKD3D_SM5_OP_CHECK_ACCESS_FULLY_MAPPED, VKD3DSIH_CHECK_ACCESS_FULLY_MAPPED, "u", "u"}, + }; + +@@ -1980,12 +1980,8 @@ static enum vkd3d_data_type map_data_type(char t) + return VKD3D_DATA_UINT; + case 'O': + return VKD3D_DATA_OPAQUE; +- case 'R': +- return VKD3D_DATA_RESOURCE; +- case 'S': +- return VKD3D_DATA_SAMPLER; +- case 'U': +- return VKD3D_DATA_UAV; ++ case '*': ++ return VKD3D_DATA_UNUSED; + default: + ERR("Invalid data type '%c'.\n", t); + return VKD3D_DATA_FLOAT; +@@ -2951,9 +2947,6 @@ int tpf_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t con + && !sm4.has_control_point_phase && !sm4.p.failed) + shader_sm4_validate_default_phase_index_ranges(&sm4); + +- if (!sm4.p.failed) +- vkd3d_shader_parser_validate(&sm4.p, config_flags); +- + if (sm4.p.failed) + { + WARN("Failed to parse shader.\n"); +@@ -2961,6 +2954,17 @@ int tpf_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t con + return VKD3D_ERROR_INVALID_SHADER; + } + ++ if ((ret = vkd3d_shader_parser_validate(&sm4.p, config_flags)) < 0) ++ { ++ WARN("Failed to validate shader after parsing, ret %d.\n", ret); ++ ++ if (TRACE_ON()) ++ vkd3d_shader_trace(program); ++ ++ vsir_program_cleanup(program); ++ return ret; ++ } ++ + return VKD3D_OK; + } + +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index 7ac86e35227..112bdc4da7f 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -660,9 +660,6 @@ enum vkd3d_data_type + { + VKD3D_DATA_FLOAT, + VKD3D_DATA_INT, +- VKD3D_DATA_RESOURCE, +- VKD3D_DATA_SAMPLER, +- VKD3D_DATA_UAV, + VKD3D_DATA_UINT, + VKD3D_DATA_UNORM, + VKD3D_DATA_SNORM, +@@ -1493,6 +1490,7 @@ enum vsir_asm_flags + { + VSIR_ASM_FLAG_NONE = 0, + VSIR_ASM_FLAG_DUMP_TYPES = 0x1, ++ VSIR_ASM_FLAG_DUMP_ALL_INDICES = 0x2, + }; + + enum vkd3d_result d3d_asm_compile(const struct vsir_program *program, +-- +2.45.2 + diff --git a/patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch b/patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch deleted file mode 100644 index f67cceb8..00000000 --- a/patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch +++ /dev/null @@ -1,1436 +0,0 @@ -From 7158e5d2ecb970eb54299a2358f74ddae1248bc4 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Thu, 12 Sep 2024 08:58:41 +1000 -Subject: [PATCH] Updated vkd3d to ab525f31e43a0f3c04c76b799aae88c12684b110. - ---- - libs/vkd3d/include/private/vkd3d_common.h | 2 + - libs/vkd3d/include/vkd3d_shader.h | 9 +- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 368 ++++-------------- - libs/vkd3d/libs/vkd3d-shader/glsl.c | 2 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.h | 2 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.y | 59 +-- - libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 300 ++++++++++++++ - libs/vkd3d/libs/vkd3d-shader/ir.c | 77 ++-- - libs/vkd3d/libs/vkd3d-shader/spirv.c | 2 +- - .../libs/vkd3d-shader/vkd3d_shader_private.h | 3 +- - libs/vkd3d/libs/vkd3d/command.c | 30 +- - libs/vkd3d/libs/vkd3d/device.c | 1 + - libs/vkd3d/libs/vkd3d/state.c | 1 + - libs/vkd3d/libs/vkd3d/vkd3d_private.h | 3 +- - 14 files changed, 481 insertions(+), 378 deletions(-) - -diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h -index c62dc00415f..fd62730f948 100644 ---- a/libs/vkd3d/include/private/vkd3d_common.h -+++ b/libs/vkd3d/include/private/vkd3d_common.h -@@ -62,6 +62,8 @@ - #define VKD3D_STRINGIFY(x) #x - #define VKD3D_EXPAND_AND_STRINGIFY(x) VKD3D_EXPAND(VKD3D_STRINGIFY(x)) - -+#define vkd3d_clamp(value, lower, upper) max(min(value, upper), lower) -+ - #define TAG_AON9 VKD3D_MAKE_TAG('A', 'o', 'n', '9') - #define TAG_DXBC VKD3D_MAKE_TAG('D', 'X', 'B', 'C') - #define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L') -diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h -index d9a355d3bc9..5737d27c0e9 100644 ---- a/libs/vkd3d/include/vkd3d_shader.h -+++ b/libs/vkd3d/include/vkd3d_shader.h -@@ -1292,7 +1292,8 @@ typedef int (*PFN_vkd3d_shader_open_include)(const char *filename, bool local, - * vkd3d_shader_preprocess_info. - * - * \param code Contents of the included file, which were allocated by the -- * \ref pfn_open_include callback. The user must free them. -+ * vkd3d_shader_preprocess_info.pfn_open_include callback. -+ * The user must free them. - * - * \param context The user-defined pointer passed to struct - * vkd3d_shader_preprocess_info. -@@ -1319,8 +1320,8 @@ struct vkd3d_shader_preprocess_info - - /** - * Pointer to an array of predefined macros. Each macro in this array will -- * be expanded as if a corresponding #define statement were prepended to the -- * source code. -+ * be expanded as if a corresponding \#define statement were prepended to -+ * the source code. - * - * If the same macro is specified multiple times, only the last value is - * used. -@@ -2798,7 +2799,7 @@ VKD3D_SHADER_API void vkd3d_shader_free_scan_signature_info(struct vkd3d_shader_ - * \param input_signature The input signature of the second shader. - * - * \param count On output, contains the number of entries written into -- * \ref varyings. -+ * "varyings". - * - * \param varyings Pointer to an output array of varyings. - * This must point to space for N varyings, where N is the number of elements -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index a41182e1f4a..e7d1d2420c6 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -1877,7 +1877,7 @@ struct sm1_instruction - struct sm1_dst_register - { - enum vkd3d_shader_register_type type; -- D3DSHADER_PARAM_DSTMOD_TYPE mod; -+ enum vkd3d_shader_dst_modifier mod; - unsigned int writemask; - uint32_t reg; - } dst; -@@ -1885,7 +1885,7 @@ struct sm1_instruction - struct sm1_src_register - { - enum vkd3d_shader_register_type type; -- D3DSHADER_PARAM_SRCMOD_TYPE mod; -+ enum vkd3d_shader_src_modifier mod; - unsigned int swizzle; - uint32_t reg; - } srcs[4]; -@@ -1902,9 +1902,9 @@ static bool is_inconsequential_instr(const struct sm1_instruction *instr) - - if (instr->opcode != VKD3D_SM1_OP_MOV) - return false; -- if (dst->mod != D3DSPDM_NONE) -+ if (dst->mod != VKD3DSPDM_NONE) - return false; -- if (src->mod != D3DSPSM_NONE) -+ if (src->mod != VKD3DSPSM_NONE) - return false; - if (src->type != dst->type) - return false; -@@ -1923,13 +1923,19 @@ static bool is_inconsequential_instr(const struct sm1_instruction *instr) - static void write_sm1_dst_register(struct vkd3d_bytecode_buffer *buffer, const struct sm1_dst_register *reg) - { - VKD3D_ASSERT(reg->writemask); -- put_u32(buffer, (1u << 31) | sm1_encode_register_type(reg->type) | reg->mod | (reg->writemask << 16) | reg->reg); -+ put_u32(buffer, VKD3D_SM1_INSTRUCTION_PARAMETER -+ | sm1_encode_register_type(reg->type) -+ | (reg->mod << VKD3D_SM1_DST_MODIFIER_SHIFT) -+ | (reg->writemask << VKD3D_SM1_WRITEMASK_SHIFT) | reg->reg); - } - - static void write_sm1_src_register(struct vkd3d_bytecode_buffer *buffer, - const struct sm1_src_register *reg) - { -- put_u32(buffer, (1u << 31) | sm1_encode_register_type(reg->type) | reg->mod | (reg->swizzle << 16) | reg->reg); -+ put_u32(buffer, VKD3D_SM1_INSTRUCTION_PARAMETER -+ | sm1_encode_register_type(reg->type) -+ | (reg->mod << VKD3D_SM1_SRC_MODIFIER_SHIFT) -+ | (reg->swizzle << VKD3D_SM1_SWIZZLE_SHIFT) | reg->reg); - } - - static void d3dbc_write_instruction(struct d3dbc_compiler *d3dbc, const struct sm1_instruction *instr) -@@ -1960,117 +1966,9 @@ static void sm1_map_src_swizzle(struct sm1_src_register *src, unsigned int map_w - src->swizzle = hlsl_map_swizzle(src->swizzle, map_writemask); - } - --static void d3dbc_write_dp2add(struct d3dbc_compiler *d3dbc, const struct hlsl_reg *dst, -- const struct hlsl_reg *src1, const struct hlsl_reg *src2, const struct hlsl_reg *src3) --{ -- struct sm1_instruction instr = -- { -- .opcode = VKD3D_SM1_OP_DP2ADD, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.writemask = dst->writemask, -- .dst.reg = dst->id, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), -- .srcs[0].reg = src1->id, -- .srcs[1].type = VKD3DSPR_TEMP, -- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), -- .srcs[1].reg = src2->id, -- .srcs[2].type = VKD3DSPR_TEMP, -- .srcs[2].swizzle = hlsl_swizzle_from_writemask(src3->writemask), -- .srcs[2].reg = src3->id, -- .src_count = 3, -- }; -- -- d3dbc_write_instruction(d3dbc, &instr); --} -- --static void d3dbc_write_ternary_op(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, -- const struct hlsl_reg *dst, const struct hlsl_reg *src1, -- const struct hlsl_reg *src2, const struct hlsl_reg *src3) --{ -- struct sm1_instruction instr = -- { -- .opcode = opcode, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.writemask = dst->writemask, -- .dst.reg = dst->id, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), -- .srcs[0].reg = src1->id, -- .srcs[1].type = VKD3DSPR_TEMP, -- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), -- .srcs[1].reg = src2->id, -- .srcs[2].type = VKD3DSPR_TEMP, -- .srcs[2].swizzle = hlsl_swizzle_from_writemask(src3->writemask), -- .srcs[2].reg = src3->id, -- .src_count = 3, -- }; -- -- sm1_map_src_swizzle(&instr.srcs[0], instr.dst.writemask); -- sm1_map_src_swizzle(&instr.srcs[1], instr.dst.writemask); -- sm1_map_src_swizzle(&instr.srcs[2], instr.dst.writemask); -- d3dbc_write_instruction(d3dbc, &instr); --} -- --static void d3dbc_write_binary_op(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, -- const struct hlsl_reg *dst, const struct hlsl_reg *src1, const struct hlsl_reg *src2) --{ -- struct sm1_instruction instr = -- { -- .opcode = opcode, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.writemask = dst->writemask, -- .dst.reg = dst->id, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), -- .srcs[0].reg = src1->id, -- .srcs[1].type = VKD3DSPR_TEMP, -- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), -- .srcs[1].reg = src2->id, -- .src_count = 2, -- }; -- -- sm1_map_src_swizzle(&instr.srcs[0], instr.dst.writemask); -- sm1_map_src_swizzle(&instr.srcs[1], instr.dst.writemask); -- d3dbc_write_instruction(d3dbc, &instr); --} -- --static void d3dbc_write_dot(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, -- const struct hlsl_reg *dst, const struct hlsl_reg *src1, const struct hlsl_reg *src2) --{ -- struct sm1_instruction instr = -- { -- .opcode = opcode, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.writemask = dst->writemask, -- .dst.reg = dst->id, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src1->writemask), -- .srcs[0].reg = src1->id, -- .srcs[1].type = VKD3DSPR_TEMP, -- .srcs[1].swizzle = hlsl_swizzle_from_writemask(src2->writemask), -- .srcs[1].reg = src2->id, -- .src_count = 2, -- }; -- -- d3dbc_write_instruction(d3dbc, &instr); --} -- - static void d3dbc_write_unary_op(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, - const struct hlsl_reg *dst, const struct hlsl_reg *src, -- D3DSHADER_PARAM_SRCMOD_TYPE src_mod, D3DSHADER_PARAM_DSTMOD_TYPE dst_mod) -+ enum vkd3d_shader_src_modifier src_mod, enum vkd3d_shader_dst_modifier dst_mod) - { - struct sm1_instruction instr = - { -@@ -2209,7 +2107,7 @@ static uint32_t swizzle_from_vsir(uint32_t swizzle) - static void sm1_src_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_src_param *param, - struct sm1_src_register *src, const struct vkd3d_shader_location *loc) - { -- src->mod = (uint32_t)param->modifiers << VKD3D_SM1_SRC_MODIFIER_SHIFT; -+ src->mod = param->modifiers; - src->reg = param->reg.idx[0].offset; - src->type = param->reg.type; - src->swizzle = swizzle_from_vsir(param->swizzle); -@@ -2225,7 +2123,7 @@ static void sm1_src_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd - static void sm1_dst_reg_from_vsir(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_dst_param *param, - struct sm1_dst_register *dst, const struct vkd3d_shader_location *loc) - { -- dst->mod = (uint32_t)param->modifiers << VKD3D_SM1_DST_MODIFIER_SHIFT; -+ dst->mod = param->modifiers; - dst->reg = param->reg.idx[0].offset; - dst->type = param->reg.type; - dst->writemask = param->write_mask; -@@ -2326,13 +2224,18 @@ static void d3dbc_write_vsir_dcl(struct d3dbc_compiler *d3dbc, const struct vkd3 - } - } - --static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, -- const struct vkd3d_shader_instruction *ins) -+static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info_from_vsir_instruction( -+ struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) - { - const struct vkd3d_sm1_opcode_info *info; -- struct sm1_instruction instr = {0}; - -- info = shader_sm1_get_opcode_info_from_vsir(d3dbc, ins->opcode); -+ if (!(info = shader_sm1_get_opcode_info_from_vsir(d3dbc, ins->opcode))) -+ { -+ vkd3d_shader_error(d3dbc->message_context, &ins->location, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE, -+ "Opcode %#x not supported for shader profile.", ins->opcode); -+ d3dbc->failed = true; -+ return NULL; -+ } - - if (ins->dst_count != info->dst_count) - { -@@ -2340,7 +2243,7 @@ static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, - "Invalid destination count %u for vsir instruction %#x (expected %u).", - ins->dst_count, ins->opcode, info->dst_count); - d3dbc->failed = true; -- return; -+ return NULL; - } - if (ins->src_count != info->src_count) - { -@@ -2348,9 +2251,21 @@ static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, - "Invalid source count %u for vsir instruction %#x (expected %u).", - ins->src_count, ins->opcode, info->src_count); - d3dbc->failed = true; -- return; -+ return NULL; - } - -+ return info; -+} -+ -+static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, -+ const struct vkd3d_shader_instruction *ins) -+{ -+ struct sm1_instruction instr = {0}; -+ const struct vkd3d_sm1_opcode_info *info; -+ -+ if (!(info = shader_sm1_get_opcode_info_from_vsir_instruction(d3dbc, ins))) -+ return; -+ - instr.opcode = info->sm1_opcode; - instr.has_dst = info->dst_count; - instr.src_count = info->src_count; -@@ -2365,6 +2280,8 @@ static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, - - static void d3dbc_write_vsir_instruction(struct d3dbc_compiler *d3dbc, const struct vkd3d_shader_instruction *ins) - { -+ uint32_t writemask; -+ - switch (ins->opcode) - { - case VKD3DSIH_DEF: -@@ -2375,7 +2292,39 @@ static void d3dbc_write_vsir_instruction(struct d3dbc_compiler *d3dbc, const str - d3dbc_write_vsir_dcl(d3dbc, ins); - break; - -+ case VKD3DSIH_ABS: -+ case VKD3DSIH_ADD: -+ case VKD3DSIH_CMP: -+ case VKD3DSIH_DP2ADD: -+ case VKD3DSIH_DP3: -+ case VKD3DSIH_DP4: -+ case VKD3DSIH_DSX: -+ case VKD3DSIH_DSY: -+ case VKD3DSIH_FRC: -+ case VKD3DSIH_MAD: -+ case VKD3DSIH_MAX: -+ case VKD3DSIH_MIN: - case VKD3DSIH_MOV: -+ case VKD3DSIH_MUL: -+ case VKD3DSIH_SINCOS: -+ case VKD3DSIH_SLT: -+ d3dbc_write_vsir_simple_instruction(d3dbc, ins); -+ break; -+ -+ case VKD3DSIH_EXP: -+ case VKD3DSIH_LOG: -+ case VKD3DSIH_RCP: -+ case VKD3DSIH_RSQ: -+ writemask = ins->dst->write_mask; -+ if (writemask != VKD3DSP_WRITEMASK_0 && writemask != VKD3DSP_WRITEMASK_1 -+ && writemask != VKD3DSP_WRITEMASK_2 && writemask != VKD3DSP_WRITEMASK_3) -+ { -+ vkd3d_shader_error(d3dbc->message_context, &ins->location, -+ VKD3D_SHADER_ERROR_D3DBC_INVALID_WRITEMASK, -+ "writemask %#x for vsir instruction with opcode %#x is not single component.", -+ writemask, ins->opcode); -+ d3dbc->failed = true; -+ } - d3dbc_write_vsir_simple_instruction(d3dbc, ins); - break; - -@@ -2452,69 +2401,10 @@ static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc) - } - } - --static void d3dbc_write_per_component_unary_op(struct d3dbc_compiler *d3dbc, -- const struct hlsl_ir_node *instr, enum vkd3d_sm1_opcode opcode) --{ -- struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); -- struct hlsl_ir_node *arg1 = expr->operands[0].node; -- unsigned int i; -- -- for (i = 0; i < instr->data_type->dimx; ++i) -- { -- struct hlsl_reg src = arg1->reg, dst = instr->reg; -- -- src.writemask = hlsl_combine_writemasks(src.writemask, 1u << i); -- dst.writemask = hlsl_combine_writemasks(dst.writemask, 1u << i); -- d3dbc_write_unary_op(d3dbc, opcode, &dst, &src, 0, 0); -- } --} -- --static void d3dbc_write_sincos(struct d3dbc_compiler *d3dbc, enum hlsl_ir_expr_op op, -- const struct hlsl_reg *dst, const struct hlsl_reg *src) --{ -- struct sm1_instruction instr = -- { -- .opcode = VKD3D_SM1_OP_SINCOS, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.writemask = dst->writemask, -- .dst.reg = dst->id, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src->writemask), -- .srcs[0].reg = src->id, -- .src_count = 1, -- }; -- -- if (op == HLSL_OP1_COS_REDUCED) -- VKD3D_ASSERT(dst->writemask == VKD3DSP_WRITEMASK_0); -- else /* HLSL_OP1_SIN_REDUCED */ -- VKD3D_ASSERT(dst->writemask == VKD3DSP_WRITEMASK_1); -- -- if (d3dbc->ctx->profile->major_version < 3) -- { -- instr.src_count = 3; -- -- instr.srcs[1].type = VKD3DSPR_CONST; -- instr.srcs[1].swizzle = hlsl_swizzle_from_writemask(VKD3DSP_WRITEMASK_ALL); -- instr.srcs[1].reg = d3dbc->ctx->d3dsincosconst1.id; -- -- instr.srcs[2].type = VKD3DSPR_CONST; -- instr.srcs[2].swizzle = hlsl_swizzle_from_writemask(VKD3DSP_WRITEMASK_ALL); -- instr.srcs[2].reg = d3dbc->ctx->d3dsincosconst2.id; -- } -- -- d3dbc_write_instruction(d3dbc, &instr); --} -- - static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) - { -- const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; - struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); - struct hlsl_ir_node *arg1 = expr->operands[0].node; -- struct hlsl_ir_node *arg2 = expr->operands[1].node; -- struct hlsl_ir_node *arg3 = expr->operands[2].node; - struct hlsl_ctx *ctx = d3dbc->ctx; - - VKD3D_ASSERT(instr->reg.allocated); -@@ -2538,117 +2428,7 @@ static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_ - return; - } - -- switch (expr->op) -- { -- case HLSL_OP1_ABS: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_ABS, &instr->reg, &arg1->reg, 0, 0); -- break; -- -- case HLSL_OP1_DSX: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_DSX, &instr->reg, &arg1->reg, 0, 0); -- break; -- -- case HLSL_OP1_DSY: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_DSY, &instr->reg, &arg1->reg, 0, 0); -- break; -- -- case HLSL_OP1_EXP2: -- d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_EXP); -- break; -- -- case HLSL_OP1_LOG2: -- d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_LOG); -- break; -- -- case HLSL_OP1_NEG: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, D3DSPSM_NEG, 0); -- break; -- -- case HLSL_OP1_SAT: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, D3DSPDM_SATURATE); -- break; -- -- case HLSL_OP1_RCP: -- d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_RCP); -- break; -- -- case HLSL_OP1_RSQ: -- d3dbc_write_per_component_unary_op(d3dbc, instr, VKD3D_SM1_OP_RSQ); -- break; -- -- case HLSL_OP1_COS_REDUCED: -- case HLSL_OP1_SIN_REDUCED: -- d3dbc_write_sincos(d3dbc, expr->op, &instr->reg, &arg1->reg); -- break; -- -- case HLSL_OP2_ADD: -- d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_ADD, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case HLSL_OP2_MAX: -- d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MAX, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case HLSL_OP2_MIN: -- d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MIN, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case HLSL_OP2_MUL: -- d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MUL, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case HLSL_OP1_FRACT: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_FRC, &instr->reg, &arg1->reg, D3DSPSM_NONE, 0); -- break; -- -- case HLSL_OP2_DOT: -- switch (arg1->data_type->dimx) -- { -- case 4: -- d3dbc_write_dot(d3dbc, VKD3D_SM1_OP_DP4, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case 3: -- d3dbc_write_dot(d3dbc, VKD3D_SM1_OP_DP3, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- default: -- vkd3d_unreachable(); -- } -- break; -- -- case HLSL_OP2_LOGIC_AND: -- d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MIN, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case HLSL_OP2_LOGIC_OR: -- d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_MAX, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case HLSL_OP2_SLT: -- if (version->type == VKD3D_SHADER_TYPE_PIXEL) -- hlsl_fixme(ctx, &instr->loc, "Lower SLT instructions for pixel shaders."); -- d3dbc_write_binary_op(d3dbc, VKD3D_SM1_OP_SLT, &instr->reg, &arg1->reg, &arg2->reg); -- break; -- -- case HLSL_OP3_CMP: -- if (version->type == VKD3D_SHADER_TYPE_VERTEX) -- hlsl_fixme(ctx, &instr->loc, "Lower CMP instructions for vertex shaders."); -- d3dbc_write_ternary_op(d3dbc, VKD3D_SM1_OP_CMP, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); -- break; -- -- case HLSL_OP3_DP2ADD: -- d3dbc_write_dp2add(d3dbc, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); -- break; -- -- case HLSL_OP3_MAD: -- d3dbc_write_ternary_op(d3dbc, VKD3D_SM1_OP_MAD, &instr->reg, &arg1->reg, &arg2->reg, &arg3->reg); -- break; -- -- default: -- hlsl_fixme(ctx, &instr->loc, "SM1 \"%s\" expression.", debug_hlsl_expr_op(expr->op)); -- break; -- } -+ hlsl_fixme(ctx, &instr->loc, "SM1 \"%s\" expression.", debug_hlsl_expr_op(expr->op)); - } - - static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block); -@@ -2675,7 +2455,7 @@ static void d3dbc_write_if(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_no - .srcs[1].type = VKD3DSPR_TEMP, - .srcs[1].swizzle = hlsl_swizzle_from_writemask(condition->reg.writemask), - .srcs[1].reg = condition->reg.id, -- .srcs[1].mod = D3DSPSM_NEG, -+ .srcs[1].mod = VKD3DSPSM_NEG, - - .src_count = 2, - }; -diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c -index d1f02ab568b..b0aacdfef65 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/glsl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c -@@ -311,7 +311,7 @@ int glsl_compile(struct vsir_program *program, uint64_t config_flags, - struct vkd3d_glsl_generator generator; - int ret; - -- if ((ret = vsir_program_normalise(program, config_flags, compile_info, message_context)) < 0) -+ if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0) - return ret; - - vkd3d_glsl_generator_init(&generator, program, message_context); -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -index 9bcba99efff..bdd0e401770 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -@@ -715,7 +715,7 @@ enum hlsl_ir_expr_op - HLSL_OP2_SLT, - - /* DP2ADD(a, b, c) computes the scalar product of a.xy and b.xy, -- * then adds c. */ -+ * then adds c, where c must have dimx=1. */ - HLSL_OP3_DP2ADD, - /* TERNARY(a, b, c) returns 'b' if 'a' is true and 'c' otherwise. 'a' must always be boolean. - * CMP(a, b, c) returns 'b' if 'a' >= 0, and 'c' otherwise. It's used only for SM1-SM3 targets. */ -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -index 38642025b52..eabf072befb 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -@@ -3309,9 +3309,9 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx, - " : poly_approx;\n" - "}"; - -- if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) -+ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) - return false; -- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); -+ type = params->args[0]->data_type; - - if (!(buf = hlsl_get_string_buffer(ctx))) - return false; -@@ -3809,7 +3809,7 @@ static bool intrinsic_dst(struct hlsl_ctx *ctx, const struct parse_initializer * - " return %s(1, src0.y * src1.y, src0.z, src1.w);\n" - "}"; - -- if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) -+ if (!elementwise_intrinsic_convert_args(ctx, params, loc)) - return false; - type = params->args[0]->data_type; - if (!(type->class == HLSL_CLASS_SCALAR -@@ -3880,9 +3880,9 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx, - " return dot(i, ng) < 0 ? n : -n;\n" - "}\n"; - -- if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) -+ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) - return false; -- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); -+ type = params->args[0]->data_type; - - if (!(body = hlsl_sprintf_alloc(ctx, template, - type->name, type->name, type->name, type->name))) -@@ -4370,13 +4370,9 @@ static bool intrinsic_reflect(struct hlsl_ctx *ctx, - static bool intrinsic_refract(struct hlsl_ctx *ctx, - const struct parse_initializer *params, const struct vkd3d_shader_location *loc) - { -- struct hlsl_type *r_type = params->args[0]->data_type; -- struct hlsl_type *n_type = params->args[1]->data_type; -- struct hlsl_type *i_type = params->args[2]->data_type; -- struct hlsl_type *res_type, *idx_type, *scal_type; -- struct parse_initializer mut_params; -+ struct hlsl_type *type, *scalar_type; - struct hlsl_ir_function_decl *func; -- enum hlsl_base_type base; -+ struct hlsl_ir_node *index; - char *body; - - static const char template[] = -@@ -4388,28 +4384,34 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx, - " return t >= 0.0 ? i.x * r - (i.x * d + sqrt(t)) * n : 0;\n" - "}"; - -- if (r_type->class == HLSL_CLASS_MATRIX -- || n_type->class == HLSL_CLASS_MATRIX -- || i_type->class == HLSL_CLASS_MATRIX) -+ if (params->args[0]->data_type->class == HLSL_CLASS_MATRIX -+ || params->args[1]->data_type->class == HLSL_CLASS_MATRIX -+ || params->args[2]->data_type->class == HLSL_CLASS_MATRIX) - { - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Matrix arguments are not supported."); - return false; - } - -- VKD3D_ASSERT(params->args_count == 3); -- mut_params = *params; -- mut_params.args_count = 2; -- if (!(res_type = elementwise_intrinsic_get_common_type(ctx, &mut_params, loc))) -+ /* This is technically not an elementwise intrinsic, but the first two -+ * arguments are. -+ * The third argument is a scalar, but can be passed as a vector, -+ * which should generate an implicit truncation warning. -+ * Cast down to scalar explicitly, then we can just use -+ * elementwise_intrinsic_float_convert_args(). -+ * This may result in casting the scalar back to a vector, -+ * which we will only use the first component of. */ -+ -+ scalar_type = hlsl_get_scalar_type(ctx, params->args[2]->data_type->e.numeric.type); -+ if (!(index = add_implicit_conversion(ctx, params->instrs, params->args[2], scalar_type, loc))) - return false; -+ params->args[2] = index; - -- base = expr_common_base_type(res_type->e.numeric.type, i_type->e.numeric.type); -- base = base == HLSL_TYPE_HALF ? HLSL_TYPE_HALF : HLSL_TYPE_FLOAT; -- res_type = convert_numeric_type(ctx, res_type, base); -- idx_type = convert_numeric_type(ctx, i_type, base); -- scal_type = hlsl_get_scalar_type(ctx, base); -+ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) -+ return false; -+ type = params->args[0]->data_type; - -- if (!(body = hlsl_sprintf_alloc(ctx, template, res_type->name, res_type->name, -- res_type->name, idx_type->name, scal_type->name))) -+ if (!(body = hlsl_sprintf_alloc(ctx, template, type->name, type->name, -+ type->name, type->name, scalar_type->name))) - return false; - - func = hlsl_compile_internal_function(ctx, "refract", body); -@@ -4550,9 +4552,9 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, - " return (p * p) * (3 - 2 * p);\n" - "}"; - -- if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) -+ if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) - return false; -- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); -+ type = params->args[0]->data_type; - - if (!(body = hlsl_sprintf_alloc(ctx, template, type->name, type->name, type->name, type->name, type->name))) - return false; -@@ -4583,13 +4585,12 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, - - if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) - return false; -+ type = params->args[0]->data_type; - - if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, - params->args[1], params->args[0], loc))) - return false; - -- type = ge->data_type; -- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); - return !!add_implicit_conversion(ctx, params->instrs, ge, type, loc); - } - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -index e470115f191..2d80b524913 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -@@ -6506,6 +6506,303 @@ static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, - hlsl_replace_node(instr, vsir_instr); - } - -+/* Translate ops that can be mapped to a single vsir instruction with only one dst register. */ -+static void sm1_generate_vsir_instr_expr_single_instr_op(struct hlsl_ctx *ctx, struct vsir_program *program, -+ struct hlsl_ir_expr *expr, enum vkd3d_shader_opcode opcode, uint32_t src_mod, uint32_t dst_mod, -+ bool map_src_swizzles) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *instr = &expr->node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_src_param *src_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ unsigned int i, src_count = 0; -+ -+ VKD3D_ASSERT(instr->reg.allocated); -+ -+ for (i = 0; i < HLSL_MAX_OPERANDS; ++i) -+ { -+ if (expr->operands[i].node) -+ src_count = i + 1; -+ } -+ VKD3D_ASSERT(!src_mod || src_count == 1); -+ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, src_count))) -+ return; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = instr->reg.writemask; -+ dst_param->modifiers = dst_mod; -+ -+ for (i = 0; i < src_count; ++i) -+ { -+ struct hlsl_ir_node *operand = expr->operands[i].node; -+ -+ src_param = &ins->src[i]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = operand->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(operand->reg.writemask, -+ map_src_swizzles ? dst_param->write_mask : VKD3DSP_WRITEMASK_ALL); -+ src_param->modifiers = src_mod; -+ } -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -+ &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ -+/* Translate ops that have 1 src and need one instruction for each component in -+ * the d3dbc backend. */ -+static void sm1_generate_vsir_instr_expr_per_component_instr_op(struct hlsl_ctx *ctx, -+ struct vsir_program *program, struct hlsl_ir_expr *expr, enum vkd3d_shader_opcode opcode) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *operand = expr->operands[0].node; -+ struct hlsl_ir_node *instr = &expr->node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_src_param *src_param; -+ struct hlsl_ir_node *vsir_instr = NULL; -+ struct vkd3d_shader_instruction *ins; -+ uint32_t src_swizzle; -+ unsigned int i, c; -+ -+ VKD3D_ASSERT(instr->reg.allocated); -+ VKD3D_ASSERT(operand); -+ -+ src_swizzle = sm1_generate_vsir_get_src_swizzle(operand->reg.writemask, instr->reg.writemask); -+ for (i = 0; i < 4; ++i) -+ { -+ if (instr->reg.writemask & (1u << i)) -+ { -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, 1))) -+ return; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = 1u << i; -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = operand->reg.id; -+ c = vsir_swizzle_get_component(src_swizzle, i); -+ src_param->swizzle = vsir_swizzle_from_writemask(1u << c); -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, -+ hlsl_get_scalar_type(ctx, instr->data_type->e.numeric.type), -+ &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ } -+ } -+ -+ /* Replace expr with a no-op move. For the other instructions that reference it. */ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) -+ return; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = instr->reg.writemask; -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = instr->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(instr->reg.writemask, dst_param->write_mask); -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -+ &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ -+static void sm1_generate_vsir_instr_expr_sincos(struct hlsl_ctx *ctx, struct vsir_program *program, -+ struct hlsl_ir_expr *expr) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *operand = expr->operands[0].node; -+ struct hlsl_ir_node *instr = &expr->node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_src_param *src_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ unsigned int src_count = 0; -+ -+ VKD3D_ASSERT(instr->reg.allocated); -+ src_count = (ctx->profile->major_version < 3) ? 3 : 1; -+ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_SINCOS, 1, src_count))) -+ return; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = instr->reg.writemask; -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = operand->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(operand->reg.writemask, VKD3DSP_WRITEMASK_ALL); -+ -+ if (ctx->profile->major_version < 3) -+ { -+ src_param = &ins->src[1]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = ctx->d3dsincosconst1.id; -+ src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; -+ -+ src_param = &ins->src[1]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = ctx->d3dsincosconst2.id; -+ src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; -+ } -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -+ &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ -+static bool sm1_generate_vsir_instr_expr(struct hlsl_ctx *ctx, struct vsir_program *program, -+ struct hlsl_ir_expr *expr) -+{ -+ switch (expr->op) -+ { -+ case HLSL_OP1_ABS: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_ABS, 0, 0, true); -+ break; -+ -+ case HLSL_OP1_COS_REDUCED: -+ VKD3D_ASSERT(expr->node.reg.writemask == VKD3DSP_WRITEMASK_0); -+ sm1_generate_vsir_instr_expr_sincos(ctx, program, expr); -+ break; -+ -+ case HLSL_OP1_DSX: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DSX, 0, 0, true); -+ break; -+ -+ case HLSL_OP1_DSY: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DSY, 0, 0, true); -+ break; -+ -+ case HLSL_OP1_EXP2: -+ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_EXP); -+ break; -+ -+ case HLSL_OP1_LOG2: -+ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_LOG); -+ break; -+ -+ case HLSL_OP1_NEG: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, VKD3DSPSM_NEG, 0, true); -+ break; -+ -+ case HLSL_OP1_RCP: -+ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_RCP); -+ break; -+ -+ case HLSL_OP1_RSQ: -+ sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_RSQ); -+ break; -+ -+ case HLSL_OP1_SAT: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, VKD3DSPDM_SATURATE, true); -+ break; -+ -+ case HLSL_OP1_SIN_REDUCED: -+ VKD3D_ASSERT(expr->node.reg.writemask == VKD3DSP_WRITEMASK_1); -+ sm1_generate_vsir_instr_expr_sincos(ctx, program, expr); -+ break; -+ -+ case HLSL_OP2_ADD: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_ADD, 0, 0, true); -+ break; -+ -+ case HLSL_OP2_DOT: -+ switch (expr->operands[0].node->data_type->dimx) -+ { -+ case 3: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DP3, 0, 0, false); -+ break; -+ -+ case 4: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DP4, 0, 0, false); -+ break; -+ -+ default: -+ vkd3d_unreachable(); -+ return false; -+ } -+ break; -+ -+ case HLSL_OP2_MAX: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MAX, 0, 0, true); -+ break; -+ -+ case HLSL_OP2_MIN: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MIN, 0, 0, true); -+ break; -+ -+ case HLSL_OP2_MUL: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MUL, 0, 0, true); -+ break; -+ -+ case HLSL_OP1_FRACT: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_FRC, 0, 0, true); -+ break; -+ -+ case HLSL_OP2_LOGIC_AND: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MIN, 0, 0, true); -+ break; -+ -+ case HLSL_OP2_LOGIC_OR: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MAX, 0, 0, true); -+ break; -+ -+ case HLSL_OP2_SLT: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_SLT, 0, 0, true); -+ break; -+ -+ case HLSL_OP3_CMP: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_CMP, 0, 0, true); -+ break; -+ -+ case HLSL_OP3_DP2ADD: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_DP2ADD, 0, 0, false); -+ break; -+ -+ case HLSL_OP3_MAD: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MAD, 0, 0, true); -+ break; -+ -+ default: -+ return false; -+ } -+ -+ return true; -+} -+ - static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx, - struct vkd3d_shader_dst_param *dst_param, struct hlsl_deref *deref, - const struct vkd3d_shader_location *loc, unsigned int writemask) -@@ -6709,6 +7006,9 @@ static bool sm1_generate_vsir_instr(struct hlsl_ctx *ctx, struct hlsl_ir_node *i - sm1_generate_vsir_instr_constant(ctx, program, hlsl_ir_constant(instr)); - return true; - -+ case HLSL_IR_EXPR: -+ return sm1_generate_vsir_instr_expr(ctx, program, hlsl_ir_expr(instr)); -+ - case HLSL_IR_LOAD: - sm1_generate_vsir_instr_load(ctx, program, hlsl_ir_load(instr)); - return true; -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index 68f2e2f795e..6cef85fdc84 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -19,7 +19,7 @@ - #include "vkd3d_shader_private.h" - #include "vkd3d_types.h" - --struct vsir_normalisation_context -+struct vsir_transformation_context - { - enum vkd3d_result result; - struct vsir_program *program; -@@ -451,7 +451,7 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog - } - - static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct vkd3d_shader_message_context *message_context = ctx->message_context; -@@ -551,7 +551,7 @@ static const struct vkd3d_shader_varying_map *find_varying_map( - } - - static enum vkd3d_result vsir_program_remap_output_signature(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - const struct vkd3d_shader_location location = {.source_name = ctx->compile_info->source_name}; - struct vkd3d_shader_message_context *message_context = ctx->message_context; -@@ -865,7 +865,7 @@ static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, - } - - static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - struct hull_flattener flattener = {program->instructions}; - struct vkd3d_shader_instruction_array *instructions; -@@ -1004,7 +1004,7 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p - } - - static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_io( -- struct vsir_program *program, struct vsir_normalisation_context *ctx) -+ struct vsir_program *program, struct vsir_transformation_context *ctx) - { - struct vkd3d_shader_instruction_array *instructions; - struct control_point_normaliser normaliser; -@@ -1772,7 +1772,7 @@ static bool use_flat_interpolation(const struct vsir_program *program, - } - - static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - struct vkd3d_shader_message_context *message_context = ctx->message_context; - struct io_normaliser normaliser = {program->instructions}; -@@ -1922,7 +1922,7 @@ static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_par - } - - static enum vkd3d_result vsir_program_normalise_flat_constants(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - struct flat_constants_normaliser normaliser = {0}; - unsigned int i, j; -@@ -1961,7 +1961,8 @@ static enum vkd3d_result vsir_program_normalise_flat_constants(struct vsir_progr - return VKD3D_OK; - } - --static void remove_dead_code(struct vsir_program *program) -+static enum vkd3d_result vsir_program_remove_dead_code(struct vsir_program *program, -+ struct vsir_transformation_context *ctx) - { - size_t i, depth = 0; - bool dead = false; -@@ -2049,10 +2050,12 @@ static void remove_dead_code(struct vsir_program *program) - break; - } - } -+ -+ return VKD3D_OK; - } - - static enum vkd3d_result vsir_program_normalise_combined_samplers(struct vsir_program *program, -- struct vkd3d_shader_message_context *message_context) -+ struct vsir_transformation_context *ctx) - { - unsigned int i; - -@@ -2137,7 +2140,8 @@ static enum vkd3d_result vsir_program_normalise_combined_samplers(struct vsir_pr - case VKD3DSIH_TEXREG2AR: - case VKD3DSIH_TEXREG2GB: - case VKD3DSIH_TEXREG2RGB: -- vkd3d_shader_error(message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, -+ vkd3d_shader_error(ctx->message_context, &ins->location, -+ VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, - "Aborting due to not yet implemented feature: " - "Combined sampler instruction %#x.", ins->opcode); - return VKD3D_ERROR_NOT_IMPLEMENTED; -@@ -2793,7 +2797,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte - } - - static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - struct vkd3d_shader_message_context *message_context = ctx->message_context; - struct cf_flattener flattener = {.program = program}; -@@ -2866,7 +2870,7 @@ static bool lower_switch_to_if_ladder_add_block_mapping(struct lower_switch_to_i - } - - static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - unsigned int block_count = program->block_count, ssa_count = program->ssa_count, current_label = 0, if_label; - size_t ins_capacity = 0, ins_count = 0, i, map_capacity = 0, map_count = 0; -@@ -3057,7 +3061,7 @@ static void ssas_to_temps_block_info_cleanup(struct ssas_to_temps_block_info *bl - } - - static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - size_t ins_capacity = 0, ins_count = 0, phi_count, incoming_count, i; - struct ssas_to_temps_block_info *info, *block_info = NULL; -@@ -5278,7 +5282,7 @@ out: - } - - static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - struct vkd3d_shader_message_context *message_context = ctx->message_context; - struct vsir_cfg_emit_target target = {0}; -@@ -5459,7 +5463,7 @@ static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps_in_f - } - - static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps(struct vsir_program *program, -- struct vsir_normalisation_context *ctx) -+ struct vsir_transformation_context *ctx) - { - struct vkd3d_shader_message_context *message_context = ctx->message_context; - enum vkd3d_result ret; -@@ -5605,8 +5609,9 @@ static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *progr - } - - static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *program, -- struct vkd3d_shader_message_context *message_context) -+ struct vsir_transformation_context *ctx) - { -+ struct vkd3d_shader_message_context *message_context = ctx->message_context; - const struct vkd3d_shader_parameter1 *func = NULL, *ref = NULL; - static const struct vkd3d_shader_location no_loc; - enum vkd3d_shader_comparison_func compare_func; -@@ -6622,30 +6627,30 @@ fail: - - #define vsir_transform(ctx, step) vsir_transform_(ctx, #step, step) - static void vsir_transform_( -- struct vsir_normalisation_context *ctx, const char *step_name, -- enum vkd3d_result (*step)(struct vsir_program *program, struct vsir_normalisation_context *ctx)) -+ struct vsir_transformation_context *ctx, const char *step_name, -+ enum vkd3d_result (*step)(struct vsir_program *program, struct vsir_transformation_context *ctx)) - { - if (ctx->result < 0) - return; - - if ((ctx->result = step(ctx->program, ctx)) < 0) - { -- WARN("Transformation \"%s\" failed with result %u.\n", step_name, ctx->result); -+ WARN("Transformation \"%s\" failed with result %d.\n", step_name, ctx->result); - return; - } - - if ((ctx->result = vsir_program_validate(ctx->program, ctx->config_flags, - ctx->compile_info->source_name, ctx->message_context)) < 0) - { -- WARN("Validation failed with result %u after transformation \"%s\".\n", ctx->result, step_name); -+ WARN("Validation failed with result %d after transformation \"%s\".\n", ctx->result, step_name); - return; - } - } - --enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, -+enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) - { -- struct vsir_normalisation_context ctx = -+ struct vsir_transformation_context ctx = - { - .result = VKD3D_OK, - .program = program, -@@ -6653,7 +6658,6 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t - .compile_info = compile_info, - .message_context = message_context, - }; -- enum vkd3d_result result; - - vsir_transform(&ctx, vsir_program_lower_instructions); - -@@ -6664,9 +6668,6 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t - vsir_transform(&ctx, vsir_program_structurize); - vsir_transform(&ctx, vsir_program_flatten_control_flow_constructs); - vsir_transform(&ctx, vsir_program_materialize_undominated_ssas_to_temps); -- -- if (ctx.result < 0) -- return ctx.result; - } - else - { -@@ -6681,29 +6682,17 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t - - vsir_transform(&ctx, vsir_program_normalise_io_registers); - vsir_transform(&ctx, vsir_program_normalise_flat_constants); -+ vsir_transform(&ctx, vsir_program_remove_dead_code); -+ vsir_transform(&ctx, vsir_program_normalise_combined_samplers); - -- if (ctx.result < 0) -- return ctx.result; -- -- remove_dead_code(program); -- -- if ((result = vsir_program_normalise_combined_samplers(program, message_context)) < 0) -- return result; -- -- if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL -- && (result = vsir_program_flatten_control_flow_constructs(program, &ctx)) < 0) -- return result; -+ if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL) -+ vsir_transform(&ctx, vsir_program_flatten_control_flow_constructs); - } - -- if ((result = vsir_program_insert_alpha_test(program, message_context)) < 0) -- return result; -+ vsir_transform(&ctx, vsir_program_insert_alpha_test); - - if (TRACE_ON()) - vkd3d_shader_trace(program); - -- if ((result = vsir_program_validate(program, config_flags, -- compile_info->source_name, message_context)) < 0) -- return result; -- -- return result; -+ return ctx.result; - } -diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c -index c1fd07a533a..a3e121f8687 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/spirv.c -+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c -@@ -10614,7 +10614,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct - enum vkd3d_result result = VKD3D_OK; - unsigned int i, max_element_count; - -- if ((result = vsir_program_normalise(program, compiler->config_flags, -+ if ((result = vsir_program_transform(program, compiler->config_flags, - compile_info, compiler->message_context)) < 0) - return result; - -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index ffec48daa17..bc369ec6866 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -179,6 +179,7 @@ enum vkd3d_shader_error - VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_COUNT = 7008, - VKD3D_SHADER_ERROR_D3DBC_NOT_IMPLEMENTED = 7009, - VKD3D_SHADER_ERROR_D3DBC_INVALID_PROFILE = 7010, -+ VKD3D_SHADER_ERROR_D3DBC_INVALID_WRITEMASK = 7011, - - VKD3D_SHADER_WARNING_D3DBC_IGNORED_INSTRUCTION_FLAGS= 7300, - -@@ -1393,7 +1394,7 @@ const struct vkd3d_shader_parameter1 *vsir_program_get_parameter( - const struct vsir_program *program, enum vkd3d_shader_parameter_name name); - bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, - const struct vkd3d_shader_version *version, unsigned int reserve); --enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, -+enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); - enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, - const char *source_name, struct vkd3d_shader_message_context *message_context); -diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c -index 188162f9e6e..eab0436bebd 100644 ---- a/libs/vkd3d/libs/vkd3d/command.c -+++ b/libs/vkd3d/libs/vkd3d/command.c -@@ -19,6 +19,7 @@ - */ - - #include "vkd3d_private.h" -+#include - - static void d3d12_fence_incref(struct d3d12_fence *fence); - static void d3d12_fence_decref(struct d3d12_fence *fence); -@@ -2451,6 +2452,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(ID3D12GraphicsCommandL - } - - list->is_recording = false; -+ list->has_depth_bounds = false; - - if (!list->is_valid) - { -@@ -2479,7 +2481,7 @@ static void d3d12_command_list_reset_state(struct d3d12_command_list *list, - list->fb_layer_count = 0; - - list->xfb_enabled = false; -- -+ list->has_depth_bounds = false; - list->is_predicated = false; - - list->current_framebuffer = VK_NULL_HANDLE; -@@ -3363,6 +3365,12 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list - list->xfb_enabled = true; - } - -+ if (graphics->ds_desc.depthBoundsTestEnable && !list->has_depth_bounds) -+ { -+ list->has_depth_bounds = true; -+ VK_CALL(vkCmdSetDepthBounds(list->vk_command_buffer, 0.0f, 1.0f)); -+ } -+ - return true; - } - -@@ -5951,7 +5959,25 @@ static void STDMETHODCALLTYPE d3d12_command_list_AtomicCopyBufferUINT64(ID3D12Gr - static void STDMETHODCALLTYPE d3d12_command_list_OMSetDepthBounds(ID3D12GraphicsCommandList6 *iface, - FLOAT min, FLOAT max) - { -- FIXME("iface %p, min %.8e, max %.8e stub!\n", iface, min, max); -+ struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList6(iface); -+ const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; -+ -+ TRACE("iface %p, min %.8e, max %.8e.\n", iface, min, max); -+ -+ if (isnan(max)) -+ max = 0.0f; -+ if (isnan(min)) -+ min = 0.0f; -+ -+ if (!list->device->vk_info.EXT_depth_range_unrestricted && (min < 0.0f || min > 1.0f || max < 0.0f || max > 1.0f)) -+ { -+ WARN("VK_EXT_depth_range_unrestricted was not found, clamping depth bounds to 0.0 and 1.0.\n"); -+ max = vkd3d_clamp(max, 0.0f, 1.0f); -+ min = vkd3d_clamp(min, 0.0f, 1.0f); -+ } -+ -+ list->has_depth_bounds = true; -+ VK_CALL(vkCmdSetDepthBounds(list->vk_command_buffer, min, max)); - } - - static void STDMETHODCALLTYPE d3d12_command_list_SetSamplePositions(ID3D12GraphicsCommandList6 *iface, -diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c -index 01841c89692..65339c7ba5d 100644 ---- a/libs/vkd3d/libs/vkd3d/device.c -+++ b/libs/vkd3d/libs/vkd3d/device.c -@@ -102,6 +102,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = - VK_EXTENSION(EXT_CALIBRATED_TIMESTAMPS, EXT_calibrated_timestamps), - VK_EXTENSION(EXT_CONDITIONAL_RENDERING, EXT_conditional_rendering), - VK_DEBUG_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker), -+ VK_EXTENSION(EXT_DEPTH_RANGE_UNRESTRICTED, EXT_depth_range_unrestricted), - VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable), - VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing), - VK_EXTENSION(EXT_FRAGMENT_SHADER_INTERLOCK, EXT_fragment_shader_interlock), -diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c -index bc887fa2f33..ea7d8f040b5 100644 ---- a/libs/vkd3d/libs/vkd3d/state.c -+++ b/libs/vkd3d/libs/vkd3d/state.c -@@ -3867,6 +3867,7 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_BLEND_CONSTANTS, - VK_DYNAMIC_STATE_STENCIL_REFERENCE, -+ VK_DYNAMIC_STATE_DEPTH_BOUNDS, - }; - static const VkPipelineDynamicStateCreateInfo dynamic_desc = - { -diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h -index 729b1baee18..e6d477a5c12 100644 ---- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h -+++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h -@@ -131,6 +131,7 @@ struct vkd3d_vulkan_info - bool EXT_calibrated_timestamps; - bool EXT_conditional_rendering; - bool EXT_debug_marker; -+ bool EXT_depth_range_unrestricted; - bool EXT_depth_clip_enable; - bool EXT_descriptor_indexing; - bool EXT_fragment_shader_interlock; -@@ -1254,7 +1255,7 @@ struct d3d12_command_list - VkFormat dsv_format; - - bool xfb_enabled; -- -+ bool has_depth_bounds; - bool is_predicated; - - VkFramebuffer current_framebuffer; --- -2.45.2 - diff --git a/patches/vkd3d-latest/0005-Updated-vkd3d-to-ae27fded1a039fda84b526cd9bd7b64aeb5.patch b/patches/vkd3d-latest/0005-Updated-vkd3d-to-ae27fded1a039fda84b526cd9bd7b64aeb5.patch new file mode 100644 index 00000000..3c2cd368 --- /dev/null +++ b/patches/vkd3d-latest/0005-Updated-vkd3d-to-ae27fded1a039fda84b526cd9bd7b64aeb5.patch @@ -0,0 +1,1977 @@ +From 10e8e5d62381bc132ac64fd9a5a7f1e39b3c843b Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 3 Oct 2024 10:05:51 +1000 +Subject: [PATCH] Updated vkd3d to ae27fded1a039fda84b526cd9bd7b64aeb5573b5. + +--- + libs/vkd3d/include/vkd3d_shader.h | 78 ++++- + libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 37 ++- + libs/vkd3d/libs/vkd3d-shader/fx.c | 172 ++++++++--- + libs/vkd3d/libs/vkd3d-shader/glsl.c | 75 ++++- + libs/vkd3d/libs/vkd3d-shader/hlsl.c | 106 ++++++- + libs/vkd3d/libs/vkd3d-shader/hlsl.h | 24 +- + libs/vkd3d/libs/vkd3d-shader/hlsl.y | 146 +++++---- + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 32 +- + libs/vkd3d/libs/vkd3d-shader/ir.c | 281 +++++++++++++++++- + libs/vkd3d/libs/vkd3d-shader/spirv.c | 131 +++++--- + libs/vkd3d/libs/vkd3d-shader/tpf.c | 47 ++- + .../libs/vkd3d-shader/vkd3d_shader_private.h | 3 + + 12 files changed, 945 insertions(+), 187 deletions(-) + +diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h +index 115bb21b932..d08ee74a3a0 100644 +--- a/libs/vkd3d/include/vkd3d_shader.h ++++ b/libs/vkd3d/include/vkd3d_shader.h +@@ -480,8 +480,8 @@ enum vkd3d_shader_parameter_type + /** The parameter value is embedded directly in the shader. */ + VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT, + /** +- * The parameter value is provided to the shader via a specialization +- * constant. This value is only supported for the SPIR-V target type. ++ * The parameter value is provided to the shader via specialization ++ * constants. This value is only supported for the SPIR-V target type. + */ + VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT, + /** +@@ -506,6 +506,13 @@ enum vkd3d_shader_parameter_data_type + VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32, + /** The parameter is provided as a 32-bit float. \since 1.13 */ + VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32, ++ /** ++ * The parameter is provided as a 4-dimensional vector of 32-bit floats. ++ * This parameter must be used with struct vkd3d_shader_parameter1; ++ * it cannot be used with struct vkd3d_shader_parameter. ++ * \since 1.14 ++ */ ++ VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_DATA_TYPE), + }; +@@ -589,6 +596,58 @@ enum vkd3d_shader_parameter_name + * \since 1.13 + */ + VKD3D_SHADER_PARAMETER_NAME_FLAT_INTERPOLATION, ++ /** ++ * A mask of enabled clip planes. ++ * ++ * When this parameter is provided to a vertex shader, for each nonzero bit ++ * of this mask, a user clip distance will be generated from vertex position ++ * in clip space, and the clip plane defined by the indexed vector, taken ++ * from the VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_# parameter. ++ * ++ * Regardless of the specific clip planes which are enabled, the clip ++ * distances which are output are a contiguous array starting from clip ++ * distance 0. This affects the interface of OpenGL. For example, if only ++ * clip planes 1 and 3 are enabled (and so the value of the mask is 0xa), ++ * the user should enable only GL_CLIP_DISTANCE0 and GL_CLIP_DISTANCE1. ++ * ++ * The default value is zero, i.e. do not enable any clip planes. ++ * ++ * The data type for this parameter must be ++ * VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32. ++ * ++ * Only VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT is supported in this ++ * version of vkd3d-shader. ++ * ++ * If the source shader writes clip distances and this parameter is nonzero, ++ * compilation fails. ++ * ++ * \since 1.14 ++ */ ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK, ++ /** ++ * Clip plane values. ++ * See VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK for documentation of ++ * clip planes. ++ * ++ * These enum values are contiguous and arithmetic may safely be performed ++ * on them. That is, VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_[n] is ++ * VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0 plus n. ++ * ++ * The data type for each parameter must be ++ * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4. ++ * ++ * The default value for each plane is a (0, 0, 0, 0) vector. ++ * ++ * \since 1.14 ++ */ ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0, ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_1, ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_2, ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_3, ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_4, ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_5, ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_6, ++ VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_7, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME), + }; +@@ -636,6 +695,13 @@ struct vkd3d_shader_parameter_immediate_constant1 + * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32. + */ + float f32; ++ /** ++ * A pointer to the value if the parameter's data type is ++ * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4. ++ * ++ * \since 1.14 ++ */ ++ float f32_vec4[4]; + void *_pointer_pad; + uint32_t _pad[4]; + } u; +@@ -647,7 +713,13 @@ struct vkd3d_shader_parameter_immediate_constant1 + */ + struct vkd3d_shader_parameter_specialization_constant + { +- /** The ID of the specialization constant. */ ++ /** ++ * The ID of the specialization constant. ++ * If the type comprises more than one constant, such as ++ * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4, then a contiguous ++ * array of specialization constants should be used, one for each component, ++ * and this ID should point to the first component. ++ */ + uint32_t id; + }; + +diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +index 763d52e1b62..267cf410cbe 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c ++++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +@@ -457,17 +457,36 @@ static uint32_t swizzle_from_sm1(uint32_t swizzle) + shader_sm1_get_swizzle_component(swizzle, 3)); + } + ++/* D3DBC doesn't have the concept of index count. All registers implicitly have ++ * exactly one index. However for some register types the index doesn't make ++ * sense, so we remove it. */ ++static unsigned int idx_count_from_reg_type(enum vkd3d_shader_register_type reg_type) ++{ ++ switch (reg_type) ++ { ++ case VKD3DSPR_DEPTHOUT: ++ return 0; ++ ++ default: ++ return 1; ++ } ++} ++ + static void shader_sm1_parse_src_param(uint32_t param, struct vkd3d_shader_src_param *rel_addr, + struct vkd3d_shader_src_param *src) + { + enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT) + | ((param & VKD3D_SM1_REGISTER_TYPE_MASK2) >> VKD3D_SM1_REGISTER_TYPE_SHIFT2); ++ unsigned int idx_count = idx_count_from_reg_type(reg_type); + +- vsir_register_init(&src->reg, reg_type, VKD3D_DATA_FLOAT, 1); ++ vsir_register_init(&src->reg, reg_type, VKD3D_DATA_FLOAT, idx_count); + src->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; + src->reg.non_uniform = false; +- src->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; +- src->reg.idx[0].rel_addr = rel_addr; ++ if (idx_count == 1) ++ { ++ src->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; ++ src->reg.idx[0].rel_addr = rel_addr; ++ } + if (src->reg.type == VKD3DSPR_SAMPLER) + src->reg.dimension = VSIR_DIMENSION_NONE; + else if (src->reg.type == VKD3DSPR_DEPTHOUT) +@@ -483,12 +502,16 @@ static void shader_sm1_parse_dst_param(uint32_t param, struct vkd3d_shader_src_p + { + enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT) + | ((param & VKD3D_SM1_REGISTER_TYPE_MASK2) >> VKD3D_SM1_REGISTER_TYPE_SHIFT2); ++ unsigned int idx_count = idx_count_from_reg_type(reg_type); + +- vsir_register_init(&dst->reg, reg_type, VKD3D_DATA_FLOAT, 1); ++ vsir_register_init(&dst->reg, reg_type, VKD3D_DATA_FLOAT, idx_count); + dst->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; + dst->reg.non_uniform = false; +- dst->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; +- dst->reg.idx[0].rel_addr = rel_addr; ++ if (idx_count == 1) ++ { ++ dst->reg.idx[0].offset = param & VKD3D_SM1_REGISTER_NUMBER_MASK; ++ dst->reg.idx[0].rel_addr = rel_addr; ++ } + if (dst->reg.type == VKD3DSPR_SAMPLER) + dst->reg.dimension = VSIR_DIMENSION_NONE; + else if (dst->reg.type == VKD3DSPR_DEPTHOUT) +@@ -614,7 +637,7 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser * + const struct vkd3d_shader_register *reg, bool is_dcl, unsigned int mask) + { + const struct vkd3d_shader_version *version = &sm1->p.program->shader_version; +- unsigned int register_index = reg->idx[0].offset; ++ unsigned int register_index = reg->idx_count > 0 ? reg->idx[0].offset : 0; + + switch (reg->type) + { +diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c +index 84e827e7943..cc18857a010 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/fx.c ++++ b/libs/vkd3d/libs/vkd3d-shader/fx.c +@@ -182,6 +182,7 @@ struct fx_write_context + + struct vkd3d_bytecode_buffer unstructured; + struct vkd3d_bytecode_buffer structured; ++ struct vkd3d_bytecode_buffer objects; + + struct rb_tree strings; + struct list types; +@@ -1072,19 +1073,63 @@ static uint32_t write_fx_2_default_value(struct hlsl_type *value_type, struct hl + return offset; + } + +-static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct fx_write_context *fx) ++static uint32_t write_fx_2_object_initializer(const struct hlsl_ir_var *var, struct fx_write_context *fx) + { +- struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; +- const struct hlsl_type *type = var->data_type; +- uint32_t offset, elements_count = 1; ++ const struct hlsl_type *type = hlsl_get_multiarray_element_type(var->data_type); ++ unsigned int i, elements_count = hlsl_get_multiarray_size(var->data_type); ++ struct vkd3d_bytecode_buffer *buffer = &fx->objects; ++ uint32_t offset = fx->unstructured.size, id, size; + struct hlsl_ctx *ctx = fx->ctx; ++ const void *data; + +- if (type->class == HLSL_CLASS_ARRAY) ++ for (i = 0; i < elements_count; ++i) + { +- elements_count = hlsl_get_multiarray_size(type); +- type = hlsl_get_multiarray_element_type(type); ++ if (type->class == HLSL_CLASS_SAMPLER) ++ { ++ hlsl_fixme(ctx, &var->loc, "Writing fx_2_0 sampler objects initializers is not implemented."); ++ } ++ else ++ { ++ switch (type->class) ++ { ++ case HLSL_CLASS_STRING: ++ { ++ const char *string = var->default_values[i].string ? var->default_values[i].string : ""; ++ size = strlen(string) + 1; ++ data = string; ++ break; ++ } ++ case HLSL_CLASS_TEXTURE: ++ size = 0; ++ break; ++ case HLSL_CLASS_PIXEL_SHADER: ++ case HLSL_CLASS_VERTEX_SHADER: ++ size = 0; ++ hlsl_fixme(ctx, &var->loc, "Writing fx_2_0 shader objects initializers is not implemented."); ++ break; ++ default: ++ vkd3d_unreachable(); ++ } ++ id = fx->object_variable_count++; ++ ++ put_u32(&fx->unstructured, id); ++ ++ put_u32(buffer, id); ++ put_u32(buffer, size); ++ if (size) ++ bytecode_put_bytes(buffer, data, size); ++ } + } + ++ return offset; ++} ++ ++static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct fx_write_context *fx) ++{ ++ const struct hlsl_type *type = hlsl_get_multiarray_element_type(var->data_type); ++ struct hlsl_ctx *ctx = fx->ctx; ++ uint32_t offset; ++ + /* Note that struct fields must all be numeric; + * this was validated in check_invalid_object_fields(). */ + switch (type->class) +@@ -1096,19 +1141,17 @@ static uint32_t write_fx_2_initial_value(const struct hlsl_ir_var *var, struct f + offset = write_fx_2_default_value(var->data_type, var->default_values, fx); + break; + +- case HLSL_CLASS_TEXTURE: +- case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_SAMPLER: ++ case HLSL_CLASS_TEXTURE: + case HLSL_CLASS_STRING: ++ case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_VERTEX_SHADER: +- hlsl_fixme(ctx, &var->loc, "Write fx 2.0 object initializer."); +- /* fallthrough */ ++ offset = write_fx_2_object_initializer(var, fx); ++ break; + + default: +- /* Objects are given sequential ids. */ +- offset = put_u32(buffer, fx->object_variable_count++); +- for (uint32_t i = 1; i < elements_count; ++i) +- put_u32(buffer, fx->object_variable_count++); ++ offset = 0; ++ hlsl_fixme(ctx, &var->loc, "Writing initializer not implemented for parameter class %#x.", type->class); + break; + } + +@@ -1134,6 +1177,7 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type + return is_type_supported_fx_2(ctx, type->e.array.type, loc); + + case HLSL_CLASS_TEXTURE: ++ case HLSL_CLASS_SAMPLER: + switch (type->sampler_dim) + { + case HLSL_SAMPLER_DIM_1D: +@@ -1147,9 +1191,10 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type + } + break; + +- case HLSL_CLASS_PIXEL_SHADER: +- case HLSL_CLASS_SAMPLER: + case HLSL_CLASS_STRING: ++ return true; ++ ++ case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_VERTEX_SHADER: + hlsl_fixme(ctx, loc, "Write fx 2.0 parameter class %#x.", type->class); + return false; +@@ -1257,19 +1302,18 @@ static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) + object_count = put_u32(structured, 0); + + write_fx_2_parameters(&fx); +- set_u32(structured, parameter_count, fx.parameter_count); +- set_u32(structured, object_count, fx.object_variable_count); +- + write_techniques(ctx->globals, &fx); +- set_u32(structured, technique_count, fx.technique_count); +- set_u32(structured, shader_count, fx.shader_count); +- +- put_u32(structured, 0); /* String count */ ++ put_u32(structured, fx.object_variable_count - 1); + put_u32(structured, 0); /* Resource count */ + +- /* TODO: strings */ ++ bytecode_put_bytes(structured, fx.objects.data, fx.objects.size); + /* TODO: resources */ + ++ set_u32(structured, parameter_count, fx.parameter_count); ++ set_u32(structured, object_count, fx.object_variable_count); ++ set_u32(structured, technique_count, fx.technique_count); ++ set_u32(structured, shader_count, fx.shader_count); ++ + size = align(fx.unstructured.size, 4); + set_u32(&buffer, offset, size); + +@@ -1278,6 +1322,7 @@ static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) + + vkd3d_free(fx.unstructured.data); + vkd3d_free(fx.structured.data); ++ vkd3d_free(fx.objects.data); + + if (!fx.technique_count) + hlsl_error(ctx, &ctx->location, VKD3D_SHADER_ERROR_HLSL_MISSING_TECHNIQUE, "No techniques found."); +@@ -1516,11 +1561,14 @@ static uint32_t write_fx_4_state_numeric_value(struct hlsl_ir_constant *value, s + static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hlsl_state_block_entry *entry, + struct fx_write_context *fx) + { +- uint32_t value_offset = 0, assignment_type = 0, rhs_offset; +- uint32_t type_offset; ++ uint32_t value_offset = 0, assignment_type = 0, rhs_offset, type_offset, offset; ++ struct vkd3d_bytecode_buffer *unstructured = &fx->unstructured; + struct vkd3d_bytecode_buffer *buffer = &fx->structured; +- struct hlsl_ctx *ctx = fx->ctx; + struct hlsl_ir_node *value = entry->args->node; ++ struct hlsl_ctx *ctx = fx->ctx; ++ struct hlsl_ir_var *index_var; ++ struct hlsl_ir_constant *c; ++ struct hlsl_ir_load *load; + + put_u32(buffer, entry->name_id); + put_u32(buffer, entry->lhs_index); +@@ -1531,7 +1579,7 @@ static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hl + { + case HLSL_IR_CONSTANT: + { +- struct hlsl_ir_constant *c = hlsl_ir_constant(value); ++ c = hlsl_ir_constant(value); + + value_offset = write_fx_4_state_numeric_value(c, fx); + assignment_type = 1; +@@ -1539,15 +1587,71 @@ static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hl + } + case HLSL_IR_LOAD: + { +- struct hlsl_ir_load *l = hlsl_ir_load(value); ++ load = hlsl_ir_load(value); + +- if (l->src.path_len) ++ if (load->src.path_len) + hlsl_fixme(ctx, &var->loc, "Indexed access in RHS values is not implemented."); + +- value_offset = write_fx_4_string(l->src.var->name, fx); ++ value_offset = write_fx_4_string(load->src.var->name, fx); + assignment_type = 2; + break; + } ++ case HLSL_IR_INDEX: ++ { ++ struct hlsl_ir_index *index = hlsl_ir_index(value); ++ struct hlsl_ir_node *val = index->val.node; ++ struct hlsl_ir_node *idx = index->idx.node; ++ struct hlsl_type *type; ++ ++ if (val->type != HLSL_IR_LOAD) ++ { ++ hlsl_fixme(ctx, &var->loc, "Unexpected indexed RHS value type."); ++ break; ++ } ++ ++ load = hlsl_ir_load(val); ++ value_offset = write_fx_4_string(load->src.var->name, fx); ++ type = load->src.var->data_type; ++ ++ switch (idx->type) ++ { ++ case HLSL_IR_CONSTANT: ++ { ++ c = hlsl_ir_constant(idx); ++ value_offset = put_u32(unstructured, value_offset); ++ put_u32(unstructured, c->value.u[0].u); ++ assignment_type = 3; ++ ++ if (c->value.u[0].u >= type->e.array.elements_count) ++ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS, ++ "Array index %u exceeds array size %u.", c->value.u[0].u, type->e.array.elements_count); ++ break; ++ } ++ ++ case HLSL_IR_LOAD: ++ { ++ load = hlsl_ir_load(idx); ++ index_var = load->src.var; ++ ++ /* Special case for uint index variables, for anything more complex use an expression. */ ++ if (hlsl_types_are_equal(index_var->data_type, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT)) ++ && !load->src.path_len) ++ { ++ offset = write_fx_4_string(index_var->name, fx); ++ ++ value_offset = put_u32(unstructured, value_offset); ++ put_u32(unstructured, offset); ++ assignment_type = 4; ++ break; ++ } ++ } ++ /* fall through */ ++ ++ default: ++ hlsl_fixme(ctx, &var->loc, "Complex array index expressions in RHS values are not implemented."); ++ } ++ break; ++ } + default: + hlsl_fixme(ctx, &var->loc, "Unsupported assignment type for state %s.", entry->name); + } +@@ -2196,7 +2300,7 @@ static unsigned int decompose_fx_4_state_function_call(struct hlsl_ir_var *var, + const struct function_component *comp = &components[i]; + unsigned int arg_index = (i + 1) % entry->args_count; + block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, comp->name, +- comp->lhs_has_index, comp->lhs_index, arg_index); ++ comp->lhs_has_index, comp->lhs_index, true, arg_index); + } + hlsl_free_state_block_entry(entry); + +@@ -2242,7 +2346,7 @@ static unsigned int decompose_fx_4_state_block_expand_array(struct hlsl_ir_var * + for (i = 1; i < array_size; ++i) + { + block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, +- entry->name, true, i, 0); ++ entry->name, true, i, true, 0); + } + + return array_size; +diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c +index 26fd4818970..e2bcca56f05 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c +@@ -365,18 +365,21 @@ static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( + { + const struct vkd3d_shader_register *dst_reg = &dst->vsir->reg; + struct vkd3d_string_buffer *buffer = gen->buffer; ++ uint32_t modifiers = dst->vsir->modifiers; + bool close = true; + va_list args; + + if (dst->vsir->shift) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled destination shift %#x.", dst->vsir->shift); +- if (dst->vsir->modifiers) ++ if (modifiers & ~VKD3DSPDM_SATURATE) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, +- "Internal compiler error: Unhandled destination modifier(s) %#x.", dst->vsir->modifiers); ++ "Internal compiler error: Unhandled destination modifier(s) %#x.", modifiers); + + shader_glsl_print_indent(buffer, gen->indent); + vkd3d_string_buffer_printf(buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); ++ if (modifiers & VKD3DSPDM_SATURATE) ++ vkd3d_string_buffer_printf(buffer, "clamp("); + + switch (dst_reg->data_type) + { +@@ -399,7 +402,11 @@ static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( + vkd3d_string_buffer_vprintf(buffer, format, args); + va_end(args); + +- vkd3d_string_buffer_printf(buffer, "%s;\n", close ? ")" : ""); ++ if (close) ++ vkd3d_string_buffer_printf(buffer, ")"); ++ if (modifiers & VKD3DSPDM_SATURATE) ++ vkd3d_string_buffer_printf(buffer, ", 0.0, 1.0)"); ++ vkd3d_string_buffer_printf(buffer, ";\n"); + } + + static void shader_glsl_unhandled(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) +@@ -455,16 +462,24 @@ static void shader_glsl_dot(struct vkd3d_glsl_generator *gen, + static void shader_glsl_intrinsic(struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_instruction *ins, const char *op) + { ++ struct vkd3d_string_buffer *args; + struct glsl_src src; + struct glsl_dst dst; ++ unsigned int i; + uint32_t mask; + + mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); +- glsl_src_init(&src, gen, &ins->src[0], mask); ++ args = vkd3d_string_buffer_get(&gen->string_buffers); + +- shader_glsl_print_assignment(gen, &dst, "%s(%s)", op, src.str->buffer); ++ for (i = 0; i < ins->src_count; ++i) ++ { ++ glsl_src_init(&src, gen, &ins->src[i], mask); ++ vkd3d_string_buffer_printf(args, "%s%s", i ? ", " : "", src.str->buffer); ++ glsl_src_cleanup(&src, &gen->string_buffers); ++ } ++ shader_glsl_print_assignment(gen, &dst, "%s(%s)", op, args->buffer); + +- glsl_src_cleanup(&src, &gen->string_buffers); ++ vkd3d_string_buffer_release(&gen->string_buffers, args); + glsl_dst_cleanup(&dst, &gen->string_buffers); + } + +@@ -532,6 +547,13 @@ static void shader_glsl_if(struct vkd3d_glsl_generator *gen, const struct vkd3d_ + ++gen->indent; + } + ++static void shader_glsl_else(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) ++{ ++ unsigned int i = 4 * (gen->indent - 1); ++ ++ vkd3d_string_buffer_printf(gen->buffer, "%*s}\n%*selse\n%*s{\n", i, "", i, "", i, ""); ++} ++ + static void shader_glsl_endif(struct vkd3d_glsl_generator *gen) + { + --gen->indent; +@@ -539,6 +561,22 @@ static void shader_glsl_endif(struct vkd3d_glsl_generator *gen) + vkd3d_string_buffer_printf(gen->buffer, "}\n"); + } + ++static void shader_glsl_unary_op(struct vkd3d_glsl_generator *gen, ++ const struct vkd3d_shader_instruction *ins, const char *op) ++{ ++ struct glsl_src src; ++ struct glsl_dst dst; ++ uint32_t mask; ++ ++ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); ++ glsl_src_init(&src, gen, &ins->src[0], mask); ++ ++ shader_glsl_print_assignment(gen, &dst, "%s%s", op, src.str->buffer); ++ ++ glsl_src_cleanup(&src, &gen->string_buffers); ++ glsl_dst_cleanup(&dst, &gen->string_buffers); ++} ++ + static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) + { + struct glsl_src src; +@@ -757,6 +795,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_DP4: + shader_glsl_dot(gen, ins, VKD3DSP_WRITEMASK_ALL); + break; ++ case VKD3DSIH_ELSE: ++ shader_glsl_else(gen, ins); ++ break; + case VKD3DSIH_ENDIF: + shader_glsl_endif(gen); + break; +@@ -781,9 +822,25 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_IF: + shader_glsl_if(gen, ins); + break; ++ case VKD3DSIH_MAD: ++ shader_glsl_intrinsic(gen, ins, "fma"); ++ break; ++ case VKD3DSIH_ISHL: ++ shader_glsl_binop(gen, ins, "<<"); ++ break; ++ case VKD3DSIH_ISHR: ++ case VKD3DSIH_USHR: ++ shader_glsl_binop(gen, ins, ">>"); ++ break; + case VKD3DSIH_LTO: + shader_glsl_relop(gen, ins, "<", "lessThan"); + break; ++ case VKD3DSIH_MAX: ++ shader_glsl_intrinsic(gen, ins, "max"); ++ break; ++ case VKD3DSIH_MIN: ++ shader_glsl_intrinsic(gen, ins, "min"); ++ break; + case VKD3DSIH_INE: + case VKD3DSIH_NEU: + shader_glsl_relop(gen, ins, "!=", "notEqual"); +@@ -804,6 +861,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_MUL: + shader_glsl_binop(gen, ins, "*"); + break; ++ case VKD3DSIH_NOT: ++ shader_glsl_unary_op(gen, ins, "~"); ++ break; + case VKD3DSIH_OR: + shader_glsl_binop(gen, ins, "|"); + break; +@@ -822,6 +882,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, + case VKD3DSIH_ROUND_Z: + shader_glsl_intrinsic(gen, ins, "trunc"); + break; ++ case VKD3DSIH_RSQ: ++ shader_glsl_intrinsic(gen, ins, "inversesqrt"); ++ break; + case VKD3DSIH_SQRT: + shader_glsl_intrinsic(gen, ins, "sqrt"); + break; +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +index f4401bc5d89..ce3dd91f04f 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c +@@ -1907,6 +1907,59 @@ struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_ty + return &compile->node; + } + ++bool hlsl_state_block_add_entry(struct hlsl_state_block *state_block, ++ struct hlsl_state_block_entry *entry) ++{ ++ if (!vkd3d_array_reserve((void **)&state_block->entries, ++ &state_block->capacity, state_block->count + 1, ++ sizeof(*state_block->entries))) ++ return false; ++ ++ state_block->entries[state_block->count++] = entry; ++ return true; ++} ++ ++struct hlsl_ir_node *hlsl_new_sampler_state(struct hlsl_ctx *ctx, ++ const struct hlsl_state_block *state_block, struct vkd3d_shader_location *loc) ++{ ++ struct hlsl_ir_sampler_state *sampler_state; ++ struct hlsl_type *type = ctx->builtin_types.sampler[HLSL_SAMPLER_DIM_GENERIC]; ++ ++ if (!(sampler_state = hlsl_alloc(ctx, sizeof(*sampler_state)))) ++ return NULL; ++ ++ init_node(&sampler_state->node, HLSL_IR_SAMPLER_STATE, type, loc); ++ ++ if (!(sampler_state->state_block = hlsl_alloc(ctx, sizeof(*sampler_state->state_block)))) ++ { ++ vkd3d_free(sampler_state); ++ return NULL; ++ } ++ ++ if (state_block) ++ { ++ for (unsigned int i = 0; i < state_block->count; ++i) ++ { ++ const struct hlsl_state_block_entry *src = state_block->entries[i]; ++ struct hlsl_state_block_entry *entry; ++ ++ if (!(entry = clone_stateblock_entry(ctx, src, src->name, src->lhs_has_index, src->lhs_index, false, 0))) ++ { ++ hlsl_free_instr(&sampler_state->node); ++ return NULL; ++ } ++ ++ if (!hlsl_state_block_add_entry(sampler_state->state_block, entry)) ++ { ++ hlsl_free_instr(&sampler_state->node); ++ return NULL; ++ } ++ } ++ } ++ ++ return &sampler_state->node; ++} ++ + struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, + struct vkd3d_shader_location *loc) + { +@@ -2295,6 +2348,13 @@ static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, + return node; + } + ++static struct hlsl_ir_node *clone_sampler_state(struct hlsl_ctx *ctx, ++ struct clone_instr_map *map, struct hlsl_ir_sampler_state *sampler_state) ++{ ++ return hlsl_new_sampler_state(ctx, sampler_state->state_block, ++ &sampler_state->node.loc); ++} ++ + static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, + struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant) + { +@@ -2302,8 +2362,8 @@ static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, + } + + struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, +- struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, +- unsigned int lhs_index, unsigned int arg_index) ++ const struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, ++ unsigned int lhs_index, bool single_arg, unsigned int arg_index) + { + struct hlsl_state_block_entry *entry; + struct clone_instr_map map = { 0 }; +@@ -2319,7 +2379,11 @@ struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, + return NULL; + } + +- entry->args_count = 1; ++ if (single_arg) ++ entry->args_count = 1; ++ else ++ entry->args_count = src->args_count; ++ + if (!(entry->args = hlsl_alloc(ctx, sizeof(*entry->args) * entry->args_count))) + { + hlsl_free_state_block_entry(entry); +@@ -2332,7 +2396,16 @@ struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, + hlsl_free_state_block_entry(entry); + return NULL; + } +- clone_src(&map, entry->args, &src->args[arg_index]); ++ ++ if (single_arg) ++ { ++ clone_src(&map, entry->args, &src->args[arg_index]); ++ } ++ else ++ { ++ for (unsigned int i = 0; i < src->args_count; ++i) ++ clone_src(&map, &entry->args[i], &src->args[i]); ++ } + vkd3d_free(map.instrs); + + return entry; +@@ -2440,6 +2513,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, + case HLSL_IR_COMPILE: + return clone_compile(ctx, map, hlsl_ir_compile(instr)); + ++ case HLSL_IR_SAMPLER_STATE: ++ return clone_sampler_state(ctx, map, hlsl_ir_sampler_state(instr)); ++ + case HLSL_IR_STATEBLOCK_CONSTANT: + return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); + } +@@ -2860,6 +2936,7 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) + [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", + + [HLSL_IR_COMPILE] = "HLSL_IR_COMPILE", ++ [HLSL_IR_SAMPLER_STATE] = "HLSL_IR_SAMPLER_STATE", + [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", + }; + +@@ -3337,6 +3414,12 @@ static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *bu + vkd3d_string_buffer_printf(buffer, ")"); + } + ++static void dump_ir_sampler_state(struct vkd3d_string_buffer *buffer, ++ const struct hlsl_ir_sampler_state *sampler_state) ++{ ++ vkd3d_string_buffer_printf(buffer, "sampler_state {...}"); ++} ++ + static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer, + const struct hlsl_ir_stateblock_constant *constant) + { +@@ -3440,6 +3523,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, + dump_ir_compile(ctx, buffer, hlsl_ir_compile(instr)); + break; + ++ case HLSL_IR_SAMPLER_STATE: ++ dump_ir_sampler_state(buffer, hlsl_ir_sampler_state(instr)); ++ break; ++ + case HLSL_IR_STATEBLOCK_CONSTANT: + dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); + break; +@@ -3665,6 +3752,13 @@ static void free_ir_compile(struct hlsl_ir_compile *compile) + vkd3d_free(compile); + } + ++static void free_ir_sampler_state(struct hlsl_ir_sampler_state *sampler_state) ++{ ++ if (sampler_state->state_block) ++ hlsl_free_state_block(sampler_state->state_block); ++ vkd3d_free(sampler_state); ++} ++ + static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant) + { + vkd3d_free(constant->name); +@@ -3737,6 +3831,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) + free_ir_compile(hlsl_ir_compile(node)); + break; + ++ case HLSL_IR_SAMPLER_STATE: ++ free_ir_sampler_state(hlsl_ir_sampler_state(node)); ++ break; ++ + case HLSL_IR_STATEBLOCK_CONSTANT: + free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node)); + break; +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +index b8678962f67..4082b14fe04 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h +@@ -326,6 +326,7 @@ enum hlsl_ir_node_type + HLSL_IR_SWITCH, + + HLSL_IR_COMPILE, ++ HLSL_IR_SAMPLER_STATE, + HLSL_IR_STATEBLOCK_CONSTANT, + }; + +@@ -899,6 +900,14 @@ struct hlsl_ir_compile + unsigned int args_count; + }; + ++/* Represents a state block initialized with the "sampler_state" keyword. */ ++struct hlsl_ir_sampler_state ++{ ++ struct hlsl_ir_node node; ++ ++ struct hlsl_state_block *state_block; ++}; ++ + /* Stateblock constants are undeclared values found on state blocks or technique passes descriptions, + * that do not concern regular pixel, vertex, or compute shaders, except for parsing. */ + struct hlsl_ir_stateblock_constant +@@ -1212,6 +1221,12 @@ static inline struct hlsl_ir_compile *hlsl_ir_compile(const struct hlsl_ir_node + return CONTAINING_RECORD(node, struct hlsl_ir_compile, node); + } + ++static inline struct hlsl_ir_sampler_state *hlsl_ir_sampler_state(const struct hlsl_ir_node *node) ++{ ++ VKD3D_ASSERT(node->type == HLSL_IR_SAMPLER_STATE); ++ return CONTAINING_RECORD(node, struct hlsl_ir_sampler_state, node); ++}; ++ + static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(const struct hlsl_ir_node *node) + { + VKD3D_ASSERT(node->type == HLSL_IR_STATEBLOCK_CONSTANT); +@@ -1396,12 +1411,15 @@ bool hlsl_clone_block(struct hlsl_ctx *ctx, struct hlsl_block *dst_block, const + void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *func); + void hlsl_dump_var_default_values(const struct hlsl_ir_var *var); + ++bool hlsl_state_block_add_entry(struct hlsl_state_block *state_block, ++ struct hlsl_state_block_entry *entry); + bool hlsl_validate_state_block_entry(struct hlsl_ctx *ctx, struct hlsl_state_block_entry *entry, + const struct vkd3d_shader_location *loc); + struct hlsl_state_block_entry *clone_stateblock_entry(struct hlsl_ctx *ctx, +- struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, +- unsigned int lhs_index, unsigned int arg_index); ++ const struct hlsl_state_block_entry *src, const char *name, bool lhs_has_index, ++ unsigned int lhs_index, bool single_arg, unsigned int arg_index); + ++void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *body); + void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body); + 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); +@@ -1509,6 +1527,8 @@ struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, + struct hlsl_struct_field *fields, size_t field_count); + struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned int components, + struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc); ++struct hlsl_ir_node *hlsl_new_sampler_state(struct hlsl_ctx *ctx, ++ const struct hlsl_state_block *state_block, struct vkd3d_shader_location *loc); + struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, + struct vkd3d_shader_location *loc); + struct hlsl_ir_node *hlsl_new_string_constant(struct hlsl_ctx *ctx, const char *str, +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +index c39f2020ef7..b4d9f0988b0 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y +@@ -437,6 +437,9 @@ static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct + if (hlsl_types_are_equal(src_type, dst_type)) + return node; + ++ if (node->type == HLSL_IR_SAMPLER_STATE && dst_type->class == HLSL_CLASS_SAMPLER) ++ return node; ++ + if (!implicit_compatible_data_types(ctx, src_type, dst_type)) + { + struct vkd3d_string_buffer *src_string, *dst_string; +@@ -613,6 +616,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx + case HLSL_IR_COMPILE: + case HLSL_IR_CONSTANT: + case HLSL_IR_EXPR: ++ case HLSL_IR_SAMPLER_STATE: + case HLSL_IR_STRING_CONSTANT: + case HLSL_IR_SWIZZLE: + case HLSL_IR_LOAD: +@@ -648,6 +652,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx + + /* Wrap the node into a src to allow the reference to survive the multiple const passes. */ + hlsl_src_from_node(&src, node); ++ hlsl_lower_index_loads(ctx, &expr); + hlsl_run_const_passes(ctx, &expr); + node = src.node; + hlsl_src_remove(&src); +@@ -2324,55 +2329,6 @@ static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool d + return true; + } + +-/* For some reason, for matrices, values from default value initializers end up in different +- * components than from regular initializers. Default value initializers fill the matrix in +- * vertical reading order (left-to-right top-to-bottom) instead of regular reading order +- * (top-to-bottom left-to-right), so they have to be adjusted. +- * An exception is that the order of matrix initializers for function parameters are row-major +- * (top-to-bottom left-to-right). */ +-static unsigned int get_component_index_from_default_initializer_index(struct hlsl_ctx *ctx, +- struct hlsl_type *type, unsigned int index) +-{ +- unsigned int element_comp_count, element, x, y, i; +- unsigned int base = 0; +- +- if (ctx->profile->major_version < 4) +- return index; +- +- if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT) +- return index; +- +- switch (type->class) +- { +- case HLSL_CLASS_MATRIX: +- x = index / type->dimy; +- y = index % type->dimy; +- return y * type->dimx + x; +- +- case HLSL_CLASS_ARRAY: +- element_comp_count = hlsl_type_component_count(type->e.array.type); +- element = index / element_comp_count; +- base = element * element_comp_count; +- return base + get_component_index_from_default_initializer_index(ctx, type->e.array.type, index - base); +- +- case HLSL_CLASS_STRUCT: +- for (i = 0; i < type->e.record.field_count; ++i) +- { +- struct hlsl_type *field_type = type->e.record.fields[i].type; +- +- element_comp_count = hlsl_type_component_count(field_type); +- if (index - base < element_comp_count) +- return base + get_component_index_from_default_initializer_index(ctx, field_type, index - base); +- base += element_comp_count; +- } +- break; +- +- default: +- return index; +- } +- vkd3d_unreachable(); +-} +- + static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs, + struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src, + bool is_default_values_initializer) +@@ -2397,11 +2353,10 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i + if (is_default_values_initializer) + { + struct hlsl_default_value default_value = {0}; +- unsigned int dst_index; + + if (hlsl_is_numeric_type(dst_comp_type)) + { +- if (src->type == HLSL_IR_COMPILE) ++ if (src->type == HLSL_IR_COMPILE || src->type == HLSL_IR_SAMPLER_STATE) + { + /* Default values are discarded if they contain an object + * literal expression for a numeric component. */ +@@ -2420,13 +2375,8 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i + return; + default_value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); + +- if (dst->is_param) +- dst_index = *store_index; +- else +- dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index); +- + if (dst->default_values) +- dst->default_values[dst_index] = default_value; ++ dst->default_values[*store_index] = default_value; + + hlsl_block_cleanup(&block); + } +@@ -2434,12 +2384,41 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i + } + else + { +- if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) +- return; ++ if (src->type == HLSL_IR_SAMPLER_STATE) ++ { ++ /* Sampler states end up in the variable's state_blocks instead of ++ * being used to initialize its value. */ ++ struct hlsl_ir_sampler_state *sampler_state = hlsl_ir_sampler_state(src); ++ ++ if (dst_comp_type->class != HLSL_CLASS_SAMPLER) ++ { ++ struct vkd3d_string_buffer *dst_string; ++ ++ dst_string = hlsl_type_to_string(ctx, dst_comp_type); ++ if (dst_string) ++ hlsl_error(ctx, &src->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, ++ "Cannot assign sampler_state to %s.", dst_string->buffer); ++ hlsl_release_string_buffer(ctx, dst_string); ++ return; ++ } + +- if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) +- return; +- hlsl_block_add_block(instrs, &block); ++ if (!hlsl_array_reserve(ctx, (void **)&dst->state_blocks, &dst->state_block_capacity, ++ dst->state_block_count + 1, sizeof(*dst->state_blocks))) ++ return; ++ ++ dst->state_blocks[dst->state_block_count] = sampler_state->state_block; ++ sampler_state->state_block = NULL; ++ ++dst->state_block_count; ++ } ++ else ++ { ++ if (!(conv = add_implicit_conversion(ctx, instrs, load, dst_comp_type, &src->loc))) ++ return; ++ ++ if (!hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv)) ++ return; ++ hlsl_block_add_block(instrs, &block); ++ } + } + + ++*store_index; +@@ -2778,6 +2757,8 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var + is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) + || (var->storage_modifiers & HLSL_STORAGE_UNIFORM) + || ctx->cur_scope->annotations; ++ if (hlsl_get_multiarray_element_type(type)->class == HLSL_CLASS_SAMPLER) ++ is_default_values_initializer = false; + if (hlsl_type_is_shader(type)) + is_default_values_initializer = false; + +@@ -2836,6 +2817,9 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var + { + hlsl_block_add_block(initializers, v->initializer.instrs); + } ++ ++ if (var->state_blocks) ++ TRACE("Variable %s has %u state blocks.\n", var->name, var->state_block_count); + } + else if (var->storage_modifiers & HLSL_STORAGE_STATIC) + { +@@ -6228,16 +6212,6 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, + hlsl_release_string_buffer(ctx, string); + } + +-static bool state_block_add_entry(struct hlsl_state_block *state_block, struct hlsl_state_block_entry *entry) +-{ +- if (!vkd3d_array_reserve((void **)&state_block->entries, &state_block->capacity, state_block->count + 1, +- sizeof(*state_block->entries))) +- return false; +- +- state_block->entries[state_block->count++] = entry; +- return true; +-} +- + } + + %locations +@@ -7850,6 +7824,11 @@ stateblock_lhs_identifier: + if (!($$ = hlsl_strdup(ctx, "pixelshader"))) + YYABORT; + } ++ | KW_TEXTURE ++ { ++ if (!($$ = hlsl_strdup(ctx, "texture"))) ++ YYABORT; ++ } + | KW_VERTEXSHADER + { + if (!($$ = hlsl_strdup(ctx, "vertexshader"))) +@@ -7907,7 +7886,7 @@ state_block: + vkd3d_free($5.args); + + $$ = $1; +- state_block_add_entry($$, entry); ++ hlsl_state_block_add_entry($$, entry); + } + | state_block any_identifier '(' func_arguments ')' ';' + { +@@ -7935,7 +7914,7 @@ state_block: + hlsl_validate_state_block_entry(ctx, entry, &@4); + + $$ = $1; +- state_block_add_entry($$, entry); ++ hlsl_state_block_add_entry($$, entry); + } + + state_block_list: +@@ -8668,6 +8647,25 @@ primary_expr: + } + vkd3d_free($1); + } ++ | KW_SAMPLER_STATE '{' state_block_start state_block '}' ++ { ++ struct hlsl_ir_node *sampler_state; ++ ctx->in_state_block = 0; ++ ++ if (!ctx->in_state_block && ctx->cur_scope != ctx->globals) ++ hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE, ++ "sampler_state must be in global scope or a state block."); ++ ++ if (!(sampler_state = hlsl_new_sampler_state(ctx, $4, &@1))) ++ { ++ hlsl_free_state_block($4); ++ YYABORT; ++ } ++ hlsl_free_state_block($4); ++ ++ if (!($$ = make_block(ctx, sampler_state))) ++ YYABORT; ++ } + | NEW_IDENTIFIER + { + if (ctx->in_state_block) +diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +index feab6cf06c1..c5dd5e71e02 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c ++++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +@@ -4062,6 +4062,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) + case HLSL_IR_RESOURCE_LOAD: + case HLSL_IR_STRING_CONSTANT: + case HLSL_IR_SWIZZLE: ++ case HLSL_IR_SAMPLER_STATE: + if (list_empty(&instr->uses)) + { + list_remove(&instr->entry); +@@ -4344,7 +4345,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop + case HLSL_IR_STRING_CONSTANT: + break; + case HLSL_IR_COMPILE: +- /* Compile calls are skipped as they are only relevent to effects. */ ++ case HLSL_IR_SAMPLER_STATE: ++ /* These types are skipped as they are only relevant to effects. */ + break; + } + } +@@ -5206,7 +5208,8 @@ static void allocate_semantic_registers(struct hlsl_ctx *ctx) + } + } + +-static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint32_t space, uint32_t index) ++static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, ++ uint32_t space, uint32_t index, bool allocated_only) + { + const struct hlsl_buffer *buffer; + +@@ -5214,7 +5217,12 @@ static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint3 + { + if (buffer->reservation.reg_type == 'b' + && buffer->reservation.reg_space == space && buffer->reservation.reg_index == index) ++ { ++ if (allocated_only && !buffer->reg.allocated) ++ continue; ++ + return buffer; ++ } + } + return NULL; + } +@@ -5397,8 +5405,8 @@ static void allocate_buffers(struct hlsl_ctx *ctx) + + if (reservation->reg_type == 'b') + { +- const struct hlsl_buffer *reserved_buffer = get_reserved_buffer(ctx, +- reservation->reg_space, reservation->reg_index); ++ const struct hlsl_buffer *allocated_buffer = get_reserved_buffer(ctx, ++ reservation->reg_space, reservation->reg_index, true); + unsigned int max_index = get_max_cbuffer_reg_index(ctx); + + if (buffer->reservation.reg_index > max_index) +@@ -5406,14 +5414,14 @@ static void allocate_buffers(struct hlsl_ctx *ctx) + "Buffer reservation cb%u exceeds target's maximum (cb%u).", + buffer->reservation.reg_index, max_index); + +- if (reserved_buffer && reserved_buffer != buffer) ++ if (allocated_buffer && allocated_buffer != buffer) + { + hlsl_error(ctx, &buffer->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS, + "Multiple buffers bound to space %u, index %u.", + reservation->reg_space, reservation->reg_index); +- hlsl_note(ctx, &reserved_buffer->loc, VKD3D_SHADER_LOG_ERROR, ++ hlsl_note(ctx, &allocated_buffer->loc, VKD3D_SHADER_LOG_ERROR, + "Buffer %s is already bound to space %u, index %u.", +- reserved_buffer->name, reservation->reg_space, reservation->reg_index); ++ allocated_buffer->name, reservation->reg_space, reservation->reg_index); + } + + buffer->reg.space = reservation->reg_space; +@@ -5430,12 +5438,12 @@ static void allocate_buffers(struct hlsl_ctx *ctx) + else if (!reservation->reg_type) + { + unsigned int max_index = get_max_cbuffer_reg_index(ctx); +- while (get_reserved_buffer(ctx, 0, index)) ++ while (get_reserved_buffer(ctx, 0, index, false)) + ++index; + + if (index > max_index) + hlsl_error(ctx, &buffer->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, +- "Too many buffers allocated, target's maximum is %u.", max_index); ++ "Too many buffers reserved, target's maximum is %u.", max_index); + + buffer->reg.space = 0; + buffer->reg.index = index; +@@ -6178,12 +6186,16 @@ static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *bod + } + } + ++void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *body) ++{ ++ lower_ir(ctx, lower_index_loads, body); ++} ++ + void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body) + { + bool progress; + + lower_ir(ctx, lower_matrix_swizzles, body); +- lower_ir(ctx, lower_index_loads, body); + + lower_ir(ctx, lower_broadcasts, body); + while (hlsl_transform_ir(ctx, fold_redundant_casts, body, NULL)); +diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c +index 88650a97068..2fe5472167f 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/ir.c ++++ b/libs/vkd3d/libs/vkd3d-shader/ir.c +@@ -215,6 +215,14 @@ static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsign + src->reg.idx[0].offset = idx; + } + ++static void src_param_init_temp_float4(struct vkd3d_shader_src_param *src, unsigned int idx) ++{ ++ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); ++ src->reg.dimension = VSIR_DIMENSION_VEC4; ++ src->swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ src->reg.idx[0].offset = idx; ++} ++ + static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) + { + vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); +@@ -1864,13 +1872,13 @@ static bool use_flat_interpolation(const struct vsir_program *program, + if (parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + { + vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, +- "Unsupported flat interpolation parameter type %#x.\n", parameter->type); ++ "Unsupported flat interpolation parameter type %#x.", parameter->type); + return false; + } + if (parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) + { + vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid flat interpolation parameter data type %#x.\n", parameter->data_type); ++ "Invalid flat interpolation parameter data type %#x.", parameter->data_type); + return false; + } + +@@ -5539,9 +5547,11 @@ static bool find_colour_signature_idx(const struct shader_signature *signature, + + static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *program, + const struct vkd3d_shader_instruction *ret, enum vkd3d_shader_comparison_func compare_func, +- const struct vkd3d_shader_parameter1 *ref, uint32_t colour_signature_idx, uint32_t colour_temp, size_t *ret_pos) ++ const struct vkd3d_shader_parameter1 *ref, uint32_t colour_signature_idx, ++ uint32_t colour_temp, size_t *ret_pos, struct vkd3d_shader_message_context *message_context) + { + struct vkd3d_shader_instruction_array *instructions = &program->instructions; ++ static const struct vkd3d_shader_location no_loc; + size_t pos = ret - instructions->elements; + struct vkd3d_shader_instruction *ins; + +@@ -5596,6 +5606,11 @@ static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *progr + VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, VKD3D_DATA_UINT); + break; + ++ case VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4: ++ vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER, ++ "Alpha test reference data type must be a single component."); ++ return VKD3D_ERROR_INVALID_ARGUMENT; ++ + default: + FIXME("Unhandled parameter data type %#x.\n", ref->data_type); + return VKD3D_ERROR_NOT_IMPLEMENTED; +@@ -5652,13 +5667,13 @@ static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *pro + if (func->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + { + vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, +- "Unsupported alpha test function parameter type %#x.\n", func->type); ++ "Unsupported alpha test function parameter type %#x.", func->type); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + if (func->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) + { + vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, +- "Invalid alpha test function parameter data type %#x.\n", func->data_type); ++ "Invalid alpha test function parameter data type %#x.", func->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + compare_func = func->u.immediate_constant.u.u32; +@@ -5682,7 +5697,7 @@ static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *pro + if (ins->opcode == VKD3DSIH_RET) + { + if ((ret = insert_alpha_test_before_ret(program, ins, compare_func, +- ref, colour_signature_idx, colour_temp, &new_pos)) < 0) ++ ref, colour_signature_idx, colour_temp, &new_pos, message_context)) < 0) + return ret; + i = new_pos; + continue; +@@ -5709,6 +5724,202 @@ static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *pro + return VKD3D_OK; + } + ++static enum vkd3d_result insert_clip_planes_before_ret(struct vsir_program *program, ++ const struct vkd3d_shader_instruction *ret, uint32_t mask, uint32_t position_signature_idx, ++ uint32_t position_temp, uint32_t low_signature_idx, uint32_t high_signature_idx, size_t *ret_pos) ++{ ++ struct vkd3d_shader_instruction_array *instructions = &program->instructions; ++ size_t pos = ret - instructions->elements; ++ struct vkd3d_shader_instruction *ins; ++ unsigned int output_idx = 0; ++ ++ if (!shader_instruction_array_insert_at(&program->instructions, pos, vkd3d_popcount(mask) + 1)) ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ ++ ins = &program->instructions.elements[pos]; ++ ++ for (unsigned int i = 0; i < 8; ++i) ++ { ++ if (!(mask & (1u << i))) ++ continue; ++ ++ vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_DP4, 1, 2); ++ src_param_init_temp_float4(&ins->src[0], position_temp); ++ src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0 + i, VKD3D_DATA_FLOAT); ++ ins->src[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; ++ ++ vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VKD3D_DATA_FLOAT, 1); ++ if (output_idx < 4) ++ ins->dst[0].reg.idx[0].offset = low_signature_idx; ++ else ++ ins->dst[0].reg.idx[0].offset = high_signature_idx; ++ ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ++ ins->dst[0].write_mask = (1u << (output_idx % 4)); ++ ++output_idx; ++ ++ ++ins; ++ } ++ ++ vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_MOV, 1, 1); ++ vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VKD3D_DATA_FLOAT, 1); ++ ins->dst[0].reg.idx[0].offset = position_signature_idx; ++ ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ++ ins->dst[0].write_mask = program->output_signature.elements[position_signature_idx].mask; ++ src_param_init_temp_float(&ins->src[0], position_temp); ++ ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ++ ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; ++ ++ *ret_pos = pos + vkd3d_popcount(mask) + 1; ++ return VKD3D_OK; ++} ++ ++static bool find_position_signature_idx(const struct shader_signature *signature, uint32_t *idx) ++{ ++ for (unsigned int i = 0; i < signature->element_count; ++i) ++ { ++ if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_POSITION) ++ { ++ *idx = i; ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *program, ++ struct vsir_transformation_context *ctx) ++{ ++ struct shader_signature *signature = &program->output_signature; ++ unsigned int low_signature_idx = ~0u, high_signature_idx = ~0u; ++ const struct vkd3d_shader_parameter1 *mask_parameter = NULL; ++ struct signature_element *new_elements, *clip_element; ++ uint32_t position_signature_idx, position_temp, mask; ++ static const struct vkd3d_shader_location no_loc; ++ struct vkd3d_shader_instruction *ins; ++ unsigned int plane_count; ++ size_t new_pos; ++ int ret; ++ ++ if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX) ++ return VKD3D_OK; ++ ++ for (unsigned int i = 0; i < program->parameter_count; ++i) ++ { ++ const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i]; ++ ++ if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK) ++ mask_parameter = parameter; ++ } ++ ++ if (!mask_parameter) ++ return VKD3D_OK; ++ ++ if (mask_parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) ++ { ++ vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, ++ "Unsupported clip plane mask parameter type %#x.", mask_parameter->type); ++ return VKD3D_ERROR_NOT_IMPLEMENTED; ++ } ++ if (mask_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) ++ { ++ vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, ++ "Invalid clip plane mask parameter data type %#x.", mask_parameter->data_type); ++ return VKD3D_ERROR_INVALID_ARGUMENT; ++ } ++ mask = mask_parameter->u.immediate_constant.u.u32; ++ ++ if (!mask) ++ return VKD3D_OK; ++ ++ for (unsigned int i = 0; i < signature->element_count; ++i) ++ { ++ if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE) ++ { ++ vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER, ++ "Clip planes cannot be used if the shader writes clip distance."); ++ return VKD3D_ERROR_INVALID_ARGUMENT; ++ } ++ } ++ ++ if (!find_position_signature_idx(signature, &position_signature_idx)) ++ { ++ vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC, ++ "Shader does not write position."); ++ return VKD3D_ERROR_INVALID_SHADER; ++ } ++ ++ /* Append the clip plane signature indices. */ ++ ++ plane_count = vkd3d_popcount(mask); ++ ++ if (!(new_elements = vkd3d_realloc(signature->elements, ++ (signature->element_count + 2) * sizeof(*signature->elements)))) ++ return VKD3D_ERROR_OUT_OF_MEMORY; ++ signature->elements = new_elements; ++ ++ low_signature_idx = signature->element_count; ++ clip_element = &signature->elements[signature->element_count++]; ++ memset(clip_element, 0, sizeof(*clip_element)); ++ clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; ++ clip_element->component_type = VKD3D_SHADER_COMPONENT_FLOAT; ++ clip_element->register_count = 1; ++ clip_element->mask = vkd3d_write_mask_from_component_count(min(plane_count, 4)); ++ clip_element->used_mask = clip_element->mask; ++ clip_element->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE; ++ ++ if (plane_count > 4) ++ { ++ high_signature_idx = signature->element_count; ++ clip_element = &signature->elements[signature->element_count++]; ++ memset(clip_element, 0, sizeof(*clip_element)); ++ clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; ++ clip_element->semantic_index = 1; ++ clip_element->component_type = VKD3D_SHADER_COMPONENT_FLOAT; ++ clip_element->register_count = 1; ++ clip_element->mask = vkd3d_write_mask_from_component_count(plane_count - 4); ++ clip_element->used_mask = clip_element->mask; ++ clip_element->min_precision = VKD3D_SHADER_MINIMUM_PRECISION_NONE; ++ } ++ ++ /* We're going to be reading from the output position, so we need to go ++ * through the whole shader and convert it to a temp. */ ++ ++ position_temp = program->temp_count++; ++ ++ for (size_t i = 0; i < program->instructions.count; ++i) ++ { ++ ins = &program->instructions.elements[i]; ++ ++ if (vsir_instruction_is_dcl(ins)) ++ continue; ++ ++ if (ins->opcode == VKD3DSIH_RET) ++ { ++ if ((ret = insert_clip_planes_before_ret(program, ins, mask, position_signature_idx, ++ position_temp, low_signature_idx, high_signature_idx, &new_pos)) < 0) ++ return ret; ++ i = new_pos; ++ continue; ++ } ++ ++ for (size_t j = 0; j < ins->dst_count; ++j) ++ { ++ struct vkd3d_shader_dst_param *dst = &ins->dst[j]; ++ ++ /* Note we run after I/O normalization. */ ++ if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == position_signature_idx) ++ { ++ dst->reg.type = VKD3DSPR_TEMP; ++ dst->reg.idx[0].offset = position_temp; ++ } ++ } ++ } ++ ++ return VKD3D_OK; ++} ++ + struct validation_context + { + struct vkd3d_shader_message_context *message_context; +@@ -6012,6 +6223,63 @@ static void vsir_validate_register(struct validation_context *ctx, + reg->dimension); + break; + ++ case VKD3DSPR_DEPTHOUT: ++ if (reg->idx_count != 0) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, ++ "Invalid index count %u for a DEPTHOUT register.", ++ reg->idx_count); ++ break; ++ ++ case VKD3DSPR_DEPTHOUTGE: ++ if (reg->idx_count != 0) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, ++ "Invalid index count %u for a DEPTHOUTGE register.", ++ reg->idx_count); ++ break; ++ ++ case VKD3DSPR_DEPTHOUTLE: ++ if (reg->idx_count != 0) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, ++ "Invalid index count %u for a DEPTHOUTLE register.", ++ reg->idx_count); ++ break; ++ ++ case VKD3DSPR_RASTOUT: ++ if (reg->idx_count != 1) ++ { ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, ++ "Invalid index count %u for a RASTOUT register.", ++ reg->idx_count); ++ break; ++ } ++ ++ if (reg->idx[0].rel_addr) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, ++ "Non-NULL relative address for a RASTOUT register."); ++ ++ if (reg->idx[0].offset >= 3) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, ++ "Invalid offset for a RASTOUT register."); ++ break; ++ ++ case VKD3DSPR_MISCTYPE: ++ if (reg->idx_count != 1) ++ { ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, ++ "Invalid index count %u for a MISCTYPE register.", ++ reg->idx_count); ++ break; ++ } ++ ++ if (reg->idx[0].rel_addr) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, ++ "Non-NULL relative address for a MISCTYPE register."); ++ ++ if (reg->idx[0].offset >= 2) ++ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, ++ "Invalid offset for a MISCTYPE register."); ++ break; ++ + default: + break; + } +@@ -6842,6 +7110,7 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t + } + + vsir_transform(&ctx, vsir_program_insert_alpha_test); ++ vsir_transform(&ctx, vsir_program_insert_clip_planes); + + if (TRACE_ON()) + vkd3d_shader_trace(program); +diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c +index 0278a6ca232..11c054a28f5 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c ++++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c +@@ -1228,6 +1228,13 @@ static uint32_t vkd3d_spirv_build_op_constant_composite(struct vkd3d_spirv_build + SpvOpConstantComposite, result_type, constituents, constituent_count); + } + ++static uint32_t vkd3d_spirv_build_op_spec_constant_composite(struct vkd3d_spirv_builder *builder, ++ uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count) ++{ ++ return vkd3d_spirv_build_op_trv(builder, &builder->global_stream, ++ SpvOpSpecConstantComposite, result_type, constituents, constituent_count); ++} ++ + static uint32_t vkd3d_spirv_get_op_constant_composite(struct vkd3d_spirv_builder *builder, + uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count) + { +@@ -3324,8 +3331,10 @@ static const struct vkd3d_spec_constant_info *get_spec_constant_info(enum vkd3d_ + return NULL; + } + +-static uint32_t spirv_compiler_alloc_spec_constant_id(struct spirv_compiler *compiler) ++static uint32_t spirv_compiler_alloc_spec_constant_id(struct spirv_compiler *compiler, unsigned int count) + { ++ uint32_t ret; ++ + if (!compiler->current_spec_constant_id) + { + unsigned int i, id = 0; +@@ -3335,28 +3344,52 @@ static uint32_t spirv_compiler_alloc_spec_constant_id(struct spirv_compiler *com + const struct vkd3d_shader_parameter1 *current = &compiler->program->parameters[i]; + + if (current->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT) +- id = max(current->u.specialization_constant.id + 1, id); ++ { ++ switch (current->data_type) ++ { ++ case VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4: ++ id = max(current->u.specialization_constant.id + 4, id); ++ break; ++ ++ default: ++ id = max(current->u.specialization_constant.id + 1, id); ++ break; ++ } ++ } + } + + compiler->current_spec_constant_id = id; + } + +- return compiler->current_spec_constant_id++; ++ ret = compiler->current_spec_constant_id; ++ compiler->current_spec_constant_id += count; ++ return ret; + } + + static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compiler, +- enum vkd3d_shader_parameter_name name, uint32_t spec_id, enum vkd3d_data_type type) ++ enum vkd3d_shader_parameter_name name, uint32_t spec_id, ++ enum vkd3d_data_type type, unsigned int component_count) + { ++ uint32_t scalar_type_id, vector_type_id, id, default_value, components[4]; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_spec_constant_info *info; +- uint32_t type_id, id, default_value; + + info = get_spec_constant_info(name); + default_value = info ? info->default_value : 0; + +- type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); +- id = vkd3d_spirv_build_op_spec_constant(builder, type_id, default_value); +- vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationSpecId, spec_id); ++ scalar_type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); ++ vector_type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), component_count); ++ ++ for (unsigned int i = 0; i < component_count; ++i) ++ { ++ components[i] = vkd3d_spirv_build_op_spec_constant(builder, scalar_type_id, default_value); ++ vkd3d_spirv_build_op_decorate1(builder, components[i], SpvDecorationSpecId, spec_id + i); ++ } ++ ++ if (component_count == 1) ++ id = components[0]; ++ else ++ id = vkd3d_spirv_build_op_spec_constant_composite(builder, vector_type_id, components, component_count); + + if (info) + vkd3d_spirv_build_op_name(builder, id, "%s", info->debug_name); +@@ -3373,7 +3406,8 @@ static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compile + } + + static uint32_t spirv_compiler_get_spec_constant(struct spirv_compiler *compiler, +- enum vkd3d_shader_parameter_name name, uint32_t spec_id, enum vkd3d_data_type type) ++ enum vkd3d_shader_parameter_name name, uint32_t spec_id, ++ enum vkd3d_data_type type, unsigned int component_count) + { + unsigned int i; + +@@ -3383,17 +3417,17 @@ static uint32_t spirv_compiler_get_spec_constant(struct spirv_compiler *compiler + return compiler->spec_constants[i].id; + } + +- return spirv_compiler_emit_spec_constant(compiler, name, spec_id, type); ++ return spirv_compiler_emit_spec_constant(compiler, name, spec_id, type, component_count); + } + + static uint32_t spirv_compiler_get_buffer_parameter(struct spirv_compiler *compiler, +- const struct vkd3d_shader_parameter1 *parameter, enum vkd3d_data_type type) ++ const struct vkd3d_shader_parameter1 *parameter, enum vkd3d_data_type type, unsigned int component_count) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + unsigned int index = parameter - compiler->program->parameters; + uint32_t type_id, ptr_id, ptr_type_id; + +- type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1); ++ type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), component_count); + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, type_id); + ptr_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, + compiler->spirv_parameter_info[index].buffer_id, +@@ -3401,48 +3435,49 @@ static uint32_t spirv_compiler_get_buffer_parameter(struct spirv_compiler *compi + return vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone); + } + ++static const struct ++{ ++ enum vkd3d_data_type type; ++ unsigned int component_count; ++} ++parameter_data_type_map[] = ++{ ++ [VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32] = {VKD3D_DATA_FLOAT, 1}, ++ [VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32] = {VKD3D_DATA_UINT, 1}, ++ [VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4] = {VKD3D_DATA_FLOAT, 4}, ++}; ++ + static uint32_t spirv_compiler_emit_shader_parameter(struct spirv_compiler *compiler, +- enum vkd3d_shader_parameter_name name, enum vkd3d_data_type type) ++ enum vkd3d_shader_parameter_name name, enum vkd3d_data_type type, unsigned int component_count) + { + const struct vkd3d_shader_parameter1 *parameter; + +- static const struct +- { +- enum vkd3d_data_type type; +- } +- type_map[] = +- { +- [VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32] = {VKD3D_DATA_FLOAT}, +- [VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32] = {VKD3D_DATA_UINT}, +- }; +- + if (!(parameter = vsir_program_get_parameter(compiler->program, name))) + { + WARN("Unresolved shader parameter %#x.\n", name); + goto default_parameter; + } + +- if (type_map[parameter->data_type].type != type) +- ERR("Expected data type %#x for parameter %#x, got %#x.\n", type, name, parameter->data_type); ++ if (parameter_data_type_map[parameter->data_type].type != type ++ || parameter_data_type_map[parameter->data_type].component_count != component_count) ++ ERR("Expected type %#x, count %u for parameter %#x, got %#x.\n", ++ type, component_count, name, parameter->data_type); + + if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) +- { +- if (parameter->data_type == VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32) +- return spirv_compiler_get_constant_float(compiler, parameter->u.immediate_constant.u.f32); +- else +- return spirv_compiler_get_constant_uint(compiler, parameter->u.immediate_constant.u.u32); +- } ++ return spirv_compiler_get_constant(compiler, vkd3d_component_type_from_data_type(type), ++ component_count, (const uint32_t *)¶meter->u.immediate_constant); + + if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_SPECIALIZATION_CONSTANT) +- return spirv_compiler_get_spec_constant(compiler, name, parameter->u.specialization_constant.id, type); ++ return spirv_compiler_get_spec_constant(compiler, name, ++ parameter->u.specialization_constant.id, type, component_count); + if (parameter->type == VKD3D_SHADER_PARAMETER_TYPE_BUFFER) +- return spirv_compiler_get_buffer_parameter(compiler, parameter, type); ++ return spirv_compiler_get_buffer_parameter(compiler, parameter, type, component_count); + + FIXME("Unhandled parameter type %#x.\n", parameter->type); + + default_parameter: + return spirv_compiler_get_spec_constant(compiler, +- name, spirv_compiler_alloc_spec_constant_id(compiler), type); ++ name, spirv_compiler_alloc_spec_constant_id(compiler, component_count), type, component_count); + } + + static uint32_t spirv_compiler_emit_construct_vector(struct spirv_compiler *compiler, +@@ -4218,7 +4253,8 @@ static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler, + else if (reg->type == VKD3DSPR_UNDEF) + return spirv_compiler_emit_load_undef(compiler, reg, write_mask); + else if (reg->type == VKD3DSPR_PARAMETER) +- return spirv_compiler_emit_shader_parameter(compiler, reg->idx[0].offset, reg->data_type); ++ return spirv_compiler_emit_shader_parameter(compiler, reg->idx[0].offset, ++ reg->data_type, reg->dimension == VSIR_DIMENSION_VEC4 ? 4 : 1); + + component_count = vsir_write_mask_component_count(write_mask); + component_type = vkd3d_component_type_from_data_type(reg->data_type); +@@ -4508,9 +4544,24 @@ static uint32_t spirv_compiler_emit_sat(struct spirv_compiler *compiler, + static void spirv_compiler_emit_store_dst(struct spirv_compiler *compiler, + const struct vkd3d_shader_dst_param *dst, uint32_t val_id) + { +- VKD3D_ASSERT(!(dst->modifiers & ~VKD3DSPDM_SATURATE)); +- if (dst->modifiers & VKD3DSPDM_SATURATE) ++ uint32_t modifiers = dst->modifiers; ++ ++ /* It is always legitimate to ignore _pp. */ ++ modifiers &= ~VKD3DSPDM_PARTIALPRECISION; ++ ++ if (modifiers & VKD3DSPDM_SATURATE) ++ { + val_id = spirv_compiler_emit_sat(compiler, &dst->reg, dst->write_mask, val_id); ++ modifiers &= ~VKD3DSPDM_SATURATE; ++ } ++ ++ if (dst->modifiers & VKD3DSPDM_MSAMPCENTROID) ++ { ++ FIXME("Ignoring _centroid modifier.\n"); ++ modifiers &= ~VKD3DSPDM_MSAMPCENTROID; ++ } ++ ++ VKD3D_ASSERT(!modifiers); + + spirv_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id); + } +@@ -9563,7 +9614,7 @@ static uint32_t spirv_compiler_emit_query_sample_count(struct spirv_compiler *co + if (src->reg.type == VKD3DSPR_RASTERIZER) + { + val_id = spirv_compiler_emit_shader_parameter(compiler, +- VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, VKD3D_DATA_UINT); ++ VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, VKD3D_DATA_UINT, 1); + } + else + { +@@ -10611,7 +10662,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct + { + uint32_t type_id, struct_id, ptr_type_id, var_id; + +- type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); ++ type_id = vkd3d_spirv_get_type_id(builder, ++ vkd3d_component_type_from_data_type(parameter_data_type_map[parameter->data_type].type), ++ parameter_data_type_map[parameter->data_type].component_count); + + struct_id = vkd3d_spirv_build_op_type_struct(builder, &type_id, 1); + vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0); +diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c +index 389946e2c2f..00a525c9ac3 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c ++++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c +@@ -3649,6 +3649,48 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un + return extern_resources; + } + ++/* For some reason, for matrices, values from default value initializers end up in different ++ * components than from regular initializers. Default value initializers fill the matrix in ++ * vertical reading order (left-to-right top-to-bottom) instead of regular reading order ++ * (top-to-bottom left-to-right), so they have to be adjusted. ++ * An exception is that the order of matrix initializers for function parameters are row-major ++ * (top-to-bottom left-to-right). */ ++static unsigned int get_component_index_from_default_initializer_index(struct hlsl_type *type, unsigned int index) ++{ ++ unsigned int element_comp_count, element, x, y, i; ++ unsigned int base = 0; ++ ++ switch (type->class) ++ { ++ case HLSL_CLASS_MATRIX: ++ x = index / type->dimy; ++ y = index % type->dimy; ++ return y * type->dimx + x; ++ ++ case HLSL_CLASS_ARRAY: ++ element_comp_count = hlsl_type_component_count(type->e.array.type); ++ element = index / element_comp_count; ++ base = element * element_comp_count; ++ return base + get_component_index_from_default_initializer_index(type->e.array.type, index - base); ++ ++ case HLSL_CLASS_STRUCT: ++ for (i = 0; i < type->e.record.field_count; ++i) ++ { ++ struct hlsl_type *field_type = type->e.record.fields[i].type; ++ ++ element_comp_count = hlsl_type_component_count(field_type); ++ if (index - base < element_comp_count) ++ return base + get_component_index_from_default_initializer_index(field_type, index - base); ++ base += element_comp_count; ++ } ++ break; ++ ++ default: ++ return index; ++ } ++ vkd3d_unreachable(); ++} ++ + static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + { + uint32_t binding_desc_size = (hlsl_version_ge(ctx, 5, 1) ? 10 : 8) * sizeof(uint32_t); +@@ -3849,7 +3891,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + for (k = 0; k < comp_count; ++k) + { + struct hlsl_type *comp_type = hlsl_type_get_component_type(ctx, var->data_type, k); +- unsigned int comp_offset; ++ unsigned int comp_offset, comp_index; + enum hlsl_regset regset; + + if (comp_type->class == HLSL_CLASS_STRING) +@@ -3859,7 +3901,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) + continue; + } + +- comp_offset = hlsl_type_get_component_offset(ctx, var->data_type, k, ®set); ++ comp_index = get_component_index_from_default_initializer_index(var->data_type, k); ++ comp_offset = hlsl_type_get_component_offset(ctx, var->data_type, comp_index, ®set); + if (regset == HLSL_REGSET_NUMERIC) + { + if (comp_type->e.numeric.type == HLSL_TYPE_DOUBLE) +diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +index 112bdc4da7f..d9d5b4a405e 100644 +--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h ++++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +@@ -161,6 +161,7 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_HLSL_INVALID_CONTROL_POINT_COUNT = 5036, + VKD3D_SHADER_ERROR_HLSL_INVALID_OUTPUT_PRIMITIVE = 5037, + VKD3D_SHADER_ERROR_HLSL_INVALID_PARTITIONING = 5038, ++ VKD3D_SHADER_ERROR_HLSL_MISPLACED_SAMPLER_STATE = 5039, + + VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, + VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, +@@ -241,6 +242,8 @@ enum vkd3d_shader_error + VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE = 9017, + VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION = 9018, + VKD3D_SHADER_ERROR_VSIR_INVALID_GS = 9019, ++ VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER = 9020, ++ VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC = 9021, + + VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300, + +-- +2.45.2 + diff --git a/patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch b/patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch deleted file mode 100644 index f8d4c257..00000000 --- a/patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch +++ /dev/null @@ -1,1823 +0,0 @@ -From c55e0d0e093a7c99c0a45f7084d81b7477a5e025 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 14 Sep 2024 10:18:09 +1000 -Subject: [PATCH] Updated vkd3d to 4c03cda3c77123a71590b872acdc216e3625c109. - ---- - libs/vkd3d/Makefile.in | 1 + - libs/vkd3d/include/vkd3d_shader.h | 4 + - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 258 +--------------- - libs/vkd3d/libs/vkd3d-shader/dxil.c | 2 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.h | 3 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.y | 63 ++-- - libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 275 ++++++++++++++++- - libs/vkd3d/libs/vkd3d-shader/ir.c | 282 ++++++++++-------- - libs/vkd3d/libs/vkd3d-shader/tpf.c | 251 +++++++++++++++- - .../libs/vkd3d-shader/vkd3d_shader_main.c | 9 + - .../libs/vkd3d-shader/vkd3d_shader_private.h | 16 +- - 11 files changed, 738 insertions(+), 426 deletions(-) - -diff --git a/libs/vkd3d/Makefile.in b/libs/vkd3d/Makefile.in -index 94e4833dc9a..b073790d986 100644 ---- a/libs/vkd3d/Makefile.in -+++ b/libs/vkd3d/Makefile.in -@@ -25,6 +25,7 @@ SOURCES = \ - libs/vkd3d-shader/hlsl_codegen.c \ - libs/vkd3d-shader/hlsl_constant_ops.c \ - libs/vkd3d-shader/ir.c \ -+ libs/vkd3d-shader/msl.c \ - libs/vkd3d-shader/preproc.l \ - libs/vkd3d-shader/preproc.y \ - libs/vkd3d-shader/spirv.c \ -diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h -index 5737d27c0e9..46feff35138 100644 ---- a/libs/vkd3d/include/vkd3d_shader.h -+++ b/libs/vkd3d/include/vkd3d_shader.h -@@ -1087,6 +1087,10 @@ enum vkd3d_shader_target_type - * Output is a raw FX section without container. \since 1.11 - */ - VKD3D_SHADER_TARGET_FX, -+ /** -+ * A 'Metal Shading Language' shader. \since 1.14 -+ */ -+ VKD3D_SHADER_TARGET_MSL, - - VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TARGET_TYPE), - }; -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index e7d1d2420c6..b69b70c6304 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -1272,7 +1272,8 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, st - sm1->end = &code[token_count]; - - /* Estimate instruction count to avoid reallocation in most shaders. */ -- if (!vsir_program_init(program, compile_info, &version, code_size != ~(size_t)0 ? token_count / 4u + 4 : 16)) -+ if (!vsir_program_init(program, compile_info, &version, -+ code_size != ~(size_t)0 ? token_count / 4u + 4 : 16, VSIR_CF_STRUCTURED)) - return VKD3D_ERROR_OUT_OF_MEMORY; - - vkd3d_shader_parser_init(&sm1->p, program, message_context, compile_info->source_name); -@@ -1961,112 +1962,6 @@ static void d3dbc_write_instruction(struct d3dbc_compiler *d3dbc, const struct s - write_sm1_src_register(buffer, &instr->srcs[i]); - }; - --static void sm1_map_src_swizzle(struct sm1_src_register *src, unsigned int map_writemask) --{ -- src->swizzle = hlsl_map_swizzle(src->swizzle, map_writemask); --} -- --static void d3dbc_write_unary_op(struct d3dbc_compiler *d3dbc, enum vkd3d_sm1_opcode opcode, -- const struct hlsl_reg *dst, const struct hlsl_reg *src, -- enum vkd3d_shader_src_modifier src_mod, enum vkd3d_shader_dst_modifier dst_mod) --{ -- struct sm1_instruction instr = -- { -- .opcode = opcode, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.mod = dst_mod, -- .dst.writemask = dst->writemask, -- .dst.reg = dst->id, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(src->writemask), -- .srcs[0].reg = src->id, -- .srcs[0].mod = src_mod, -- .src_count = 1, -- }; -- -- sm1_map_src_swizzle(&instr.srcs[0], instr.dst.writemask); -- d3dbc_write_instruction(d3dbc, &instr); --} -- --static void d3dbc_write_cast(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); -- const struct hlsl_ir_node *arg1 = expr->operands[0].node; -- const struct hlsl_type *dst_type = expr->node.data_type; -- const struct hlsl_type *src_type = arg1->data_type; -- struct hlsl_ctx *ctx = d3dbc->ctx; -- -- /* Narrowing casts were already lowered. */ -- VKD3D_ASSERT(src_type->dimx == dst_type->dimx); -- -- switch (dst_type->e.numeric.type) -- { -- case HLSL_TYPE_HALF: -- case HLSL_TYPE_FLOAT: -- switch (src_type->e.numeric.type) -- { -- case HLSL_TYPE_INT: -- case HLSL_TYPE_UINT: -- case HLSL_TYPE_BOOL: -- /* Integrals are internally represented as floats, so no change is necessary.*/ -- case HLSL_TYPE_HALF: -- case HLSL_TYPE_FLOAT: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, 0); -- break; -- -- case HLSL_TYPE_DOUBLE: -- hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to float."); -- break; -- -- default: -- vkd3d_unreachable(); -- } -- break; -- -- case HLSL_TYPE_INT: -- case HLSL_TYPE_UINT: -- switch(src_type->e.numeric.type) -- { -- case HLSL_TYPE_HALF: -- case HLSL_TYPE_FLOAT: -- /* A compilation pass turns these into FLOOR+REINTERPRET, so we should not -- * reach this case unless we are missing something. */ -- hlsl_fixme(ctx, &instr->loc, "Unlowered SM1 cast from float to integer."); -- break; -- case HLSL_TYPE_INT: -- case HLSL_TYPE_UINT: -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, 0); -- break; -- -- case HLSL_TYPE_BOOL: -- hlsl_fixme(ctx, &instr->loc, "SM1 cast from bool to integer."); -- break; -- -- case HLSL_TYPE_DOUBLE: -- hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to integer."); -- break; -- -- default: -- vkd3d_unreachable(); -- } -- break; -- -- case HLSL_TYPE_DOUBLE: -- hlsl_fixme(ctx, &instr->loc, "SM1 cast to double."); -- break; -- -- case HLSL_TYPE_BOOL: -- /* Casts to bool should have already been lowered. */ -- default: -- hlsl_fixme(ctx, &expr->node.loc, "SM1 cast from %s to %s.", -- debug_hlsl_type(ctx, src_type), debug_hlsl_type(ctx, dst_type)); -- break; -- } --} -- - static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info_from_vsir( - struct d3dbc_compiler *d3dbc, enum vkd3d_shader_opcode vkd3d_opcode) - { -@@ -2308,6 +2203,9 @@ static void d3dbc_write_vsir_instruction(struct d3dbc_compiler *d3dbc, const str - case VKD3DSIH_MUL: - case VKD3DSIH_SINCOS: - case VKD3DSIH_SLT: -+ case VKD3DSIH_TEX: -+ case VKD3DSIH_TEXKILL: -+ case VKD3DSIH_TEXLDD: - d3dbc_write_vsir_simple_instruction(d3dbc, ins); - break; - -@@ -2366,8 +2264,8 @@ static void d3dbc_write_semantic_dcl(struct d3dbc_compiler *d3dbc, - put_u32(buffer, token); - - token = (1u << 31); -- token |= usage << D3DSP_DCL_USAGE_SHIFT; -- token |= usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT; -+ token |= usage << VKD3D_SM1_DCL_USAGE_SHIFT; -+ token |= usage_idx << VKD3D_SM1_DCL_USAGE_INDEX_SHIFT; - put_u32(buffer, token); - - reg.writemask = element->mask; -@@ -2401,36 +2299,6 @@ static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc) - } - } - --static void d3dbc_write_expr(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); -- struct hlsl_ir_node *arg1 = expr->operands[0].node; -- struct hlsl_ctx *ctx = d3dbc->ctx; -- -- VKD3D_ASSERT(instr->reg.allocated); -- -- if (expr->op == HLSL_OP1_REINTERPRET) -- { -- d3dbc_write_unary_op(d3dbc, VKD3D_SM1_OP_MOV, &instr->reg, &arg1->reg, 0, 0); -- return; -- } -- -- if (expr->op == HLSL_OP1_CAST) -- { -- d3dbc_write_cast(d3dbc, instr); -- return; -- } -- -- if (instr->data_type->e.numeric.type != HLSL_TYPE_FLOAT) -- { -- /* These need to be lowered. */ -- hlsl_fixme(ctx, &instr->loc, "SM1 non-float expression."); -- return; -- } -- -- hlsl_fixme(ctx, &instr->loc, "SM1 \"%s\" expression.", debug_hlsl_expr_op(expr->op)); --} -- - static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block); - - static void d3dbc_write_if(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) -@@ -2473,106 +2341,6 @@ static void d3dbc_write_if(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_no - d3dbc_write_instruction(d3dbc, &sm1_endif); - } - --static void d3dbc_write_jump(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- const struct hlsl_ir_jump *jump = hlsl_ir_jump(instr); -- -- switch (jump->type) -- { -- case HLSL_IR_JUMP_DISCARD_NEG: -- { -- struct hlsl_reg *reg = &jump->condition.node->reg; -- -- struct sm1_instruction sm1_instr = -- { -- .opcode = VKD3D_SM1_OP_TEXKILL, -- -- .dst.type = VKD3DSPR_TEMP, -- .dst.reg = reg->id, -- .dst.writemask = reg->writemask, -- .has_dst = 1, -- }; -- -- d3dbc_write_instruction(d3dbc, &sm1_instr); -- break; -- } -- -- default: -- hlsl_fixme(d3dbc->ctx, &jump->node.loc, "Jump type %s.", hlsl_jump_type_to_string(jump->type)); -- } --} -- --static void d3dbc_write_resource_load(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- const struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr); -- struct hlsl_ir_node *coords = load->coords.node; -- struct hlsl_ir_node *ddx = load->ddx.node; -- struct hlsl_ir_node *ddy = load->ddy.node; -- unsigned int sampler_offset, reg_id; -- struct hlsl_ctx *ctx = d3dbc->ctx; -- struct sm1_instruction sm1_instr; -- -- sampler_offset = hlsl_offset_from_deref_safe(ctx, &load->resource); -- reg_id = load->resource.var->regs[HLSL_REGSET_SAMPLERS].index + sampler_offset; -- -- sm1_instr = (struct sm1_instruction) -- { -- .dst.type = VKD3DSPR_TEMP, -- .dst.reg = instr->reg.id, -- .dst.writemask = instr->reg.writemask, -- .has_dst = 1, -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].reg = coords->reg.id, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(coords->reg.writemask), -- -- .srcs[1].type = VKD3DSPR_COMBINED_SAMPLER, -- .srcs[1].reg = reg_id, -- .srcs[1].swizzle = hlsl_swizzle_from_writemask(VKD3DSP_WRITEMASK_ALL), -- -- .src_count = 2, -- }; -- -- switch (load->load_type) -- { -- case HLSL_RESOURCE_SAMPLE: -- sm1_instr.opcode = VKD3D_SM1_OP_TEX; -- break; -- -- case HLSL_RESOURCE_SAMPLE_PROJ: -- sm1_instr.opcode = VKD3D_SM1_OP_TEX; -- sm1_instr.opcode |= VKD3DSI_TEXLD_PROJECT << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT; -- break; -- -- case HLSL_RESOURCE_SAMPLE_LOD_BIAS: -- sm1_instr.opcode = VKD3D_SM1_OP_TEX; -- sm1_instr.opcode |= VKD3DSI_TEXLD_BIAS << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT; -- break; -- -- case HLSL_RESOURCE_SAMPLE_GRAD: -- sm1_instr.opcode = VKD3D_SM1_OP_TEXLDD; -- -- sm1_instr.srcs[2].type = VKD3DSPR_TEMP; -- sm1_instr.srcs[2].reg = ddx->reg.id; -- sm1_instr.srcs[2].swizzle = hlsl_swizzle_from_writemask(ddx->reg.writemask); -- -- sm1_instr.srcs[3].type = VKD3DSPR_TEMP; -- sm1_instr.srcs[3].reg = ddy->reg.id; -- sm1_instr.srcs[3].swizzle = hlsl_swizzle_from_writemask(ddy->reg.writemask); -- -- sm1_instr.src_count += 2; -- break; -- -- default: -- hlsl_fixme(ctx, &instr->loc, "Resource load type %u.", load->load_type); -- return; -- } -- -- VKD3D_ASSERT(instr->reg.allocated); -- -- d3dbc_write_instruction(d3dbc, &sm1_instr); --} -- - static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block) - { - struct vkd3d_shader_instruction *vsir_instr; -@@ -2596,10 +2364,6 @@ static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_bl - case HLSL_IR_CALL: - vkd3d_unreachable(); - -- case HLSL_IR_EXPR: -- d3dbc_write_expr(d3dbc, instr); -- break; -- - case HLSL_IR_IF: - if (hlsl_version_ge(ctx, 2, 1)) - d3dbc_write_if(d3dbc, instr); -@@ -2607,14 +2371,6 @@ static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_bl - hlsl_fixme(ctx, &instr->loc, "Flatten \"if\" conditionals branches."); - break; - -- case HLSL_IR_JUMP: -- d3dbc_write_jump(d3dbc, instr); -- break; -- -- case HLSL_IR_RESOURCE_LOAD: -- d3dbc_write_resource_load(d3dbc, instr); -- break; -- - case HLSL_IR_VSIR_INSTRUCTION_REF: - vsir_instr_idx = hlsl_ir_vsir_instruction_ref(instr)->vsir_instr_idx; - vsir_instr = &d3dbc->program->instructions.elements[vsir_instr_idx]; -diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c -index 1c62a305d30..ee78b6251f9 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/dxil.c -+++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c -@@ -10303,7 +10303,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro - - /* Estimate instruction count to avoid reallocation in most shaders. */ - count = max(token_count, 400) - 400; -- if (!vsir_program_init(program, compile_info, &version, (count + (count >> 2)) / 2u + 10)) -+ if (!vsir_program_init(program, compile_info, &version, (count + (count >> 2)) / 2u + 10, VSIR_CF_BLOCKS)) - return VKD3D_ERROR_OUT_OF_MEMORY; - vkd3d_shader_parser_init(&sm6->p, program, message_context, compile_info->source_name); - sm6->ptr = &sm6->start[1]; -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -index bdd0e401770..eece693b48c 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -@@ -22,7 +22,6 @@ - - #include "vkd3d_shader_private.h" - #include "wine/rbtree.h" --#include "d3dcommon.h" - #include "d3dx9shader.h" - - /* The general IR structure is inspired by Mesa GLSL hir, even though the code -@@ -603,6 +602,8 @@ struct hlsl_ir_function_decl - unsigned int attr_count; - const struct hlsl_attribute *const *attrs; - -+ bool early_depth_test; -+ - /* Synthetic boolean variable marking whether a return statement has been - * executed. Needed to deal with return statements in non-uniform control - * flow, since some backends can't handle them. */ -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -index eabf072befb..60e196c63cc 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -@@ -1673,25 +1673,36 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct hlsl_block *bl - return expr; - } - --static void check_integer_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *instr) -+static bool type_is_integer(enum hlsl_base_type type) - { -- const struct hlsl_type *type = instr->data_type; -- struct vkd3d_string_buffer *string; -- -- switch (type->e.numeric.type) -+ switch (type) - { - case HLSL_TYPE_BOOL: - case HLSL_TYPE_INT: - case HLSL_TYPE_UINT: -- break; -+ return true; - -- default: -- if ((string = hlsl_type_to_string(ctx, type))) -- hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, -- "Expression type '%s' is not integer.", string->buffer); -- hlsl_release_string_buffer(ctx, string); -- break; -+ case HLSL_TYPE_DOUBLE: -+ case HLSL_TYPE_FLOAT: -+ case HLSL_TYPE_HALF: -+ return false; - } -+ -+ vkd3d_unreachable(); -+} -+ -+static void check_integer_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *instr) -+{ -+ const struct hlsl_type *type = instr->data_type; -+ struct vkd3d_string_buffer *string; -+ -+ if (type_is_integer(type->e.numeric.type)) -+ return; -+ -+ if ((string = hlsl_type_to_string(ctx, type))) -+ hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, -+ "Expression type '%s' is not integer.", string->buffer); -+ hlsl_release_string_buffer(ctx, string); - } - - static struct hlsl_ir_node *add_unary_arithmetic_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, -@@ -3033,7 +3044,7 @@ static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, - { - struct hlsl_type *type = arg->data_type; - -- if (type->e.numeric.type == HLSL_TYPE_FLOAT || type->e.numeric.type == HLSL_TYPE_HALF) -+ if (!type_is_integer(type->e.numeric.type)) - return arg; - - type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); -@@ -3121,14 +3132,12 @@ static bool elementwise_intrinsic_convert_args(struct hlsl_ctx *ctx, - static bool elementwise_intrinsic_float_convert_args(struct hlsl_ctx *ctx, - const struct parse_initializer *params, const struct vkd3d_shader_location *loc) - { -- enum hlsl_base_type base_type; - struct hlsl_type *type; - - if (!(type = elementwise_intrinsic_get_common_type(ctx, params, loc))) - return false; -- -- base_type = type->e.numeric.type == HLSL_TYPE_HALF ? HLSL_TYPE_HALF : HLSL_TYPE_FLOAT; -- type = hlsl_get_numeric_type(ctx, type->class, base_type, type->dimx, type->dimy); -+ if (type_is_integer(type->e.numeric.type)) -+ type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); - - return convert_args(ctx, params, type, loc); - } -@@ -3156,6 +3165,7 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, - const struct parse_initializer *params, const struct vkd3d_shader_location *loc, bool asin_mode) - { - struct hlsl_ir_function_decl *func; -+ struct hlsl_ir_node *arg; - struct hlsl_type *type; - char *body; - -@@ -3179,8 +3189,9 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, - - const char *fn_name = asin_mode ? fn_name_asin : fn_name_acos; - -- type = params->args[0]->data_type; -- type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->dimx, type->dimy); -+ if (!(arg = intrinsic_float_convert_arg(ctx, params, params->args[0], loc))) -+ return false; -+ type = arg->data_type; - - if (!(body = hlsl_sprintf_alloc(ctx, template, - type->name, fn_name, type->name, -@@ -3552,9 +3563,8 @@ static bool intrinsic_cross(struct hlsl_ctx *ctx, - struct hlsl_type *cast_type; - enum hlsl_base_type base; - -- if (arg1->data_type->e.numeric.type == HLSL_TYPE_HALF && arg2->data_type->e.numeric.type == HLSL_TYPE_HALF) -- base = HLSL_TYPE_HALF; -- else -+ base = expr_common_base_type(arg1->data_type->e.numeric.type, arg2->data_type->e.numeric.type); -+ if (type_is_integer(base)) - base = HLSL_TYPE_FLOAT; - - cast_type = hlsl_get_vector_type(ctx, base, 3); -@@ -3725,15 +3735,14 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx, - return false; - } - -+ if (!(arg = intrinsic_float_convert_arg(ctx, params, arg, loc))) -+ return false; -+ - dim = min(type->dimx, type->dimy); - if (dim == 1) -- { -- if (!(arg = intrinsic_float_convert_arg(ctx, params, arg, loc))) -- return false; - return hlsl_add_load_component(ctx, params->instrs, arg, 0, loc); -- } - -- typename = type->e.numeric.type == HLSL_TYPE_HALF ? "half" : "float"; -+ typename = hlsl_get_scalar_type(ctx, arg->data_type->e.numeric.type)->name; - template = templates[dim]; - - switch (dim) -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -index 2d80b524913..93f19360953 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -@@ -6027,7 +6027,7 @@ static void parse_patchconstantfunc_attribute(struct hlsl_ctx *ctx, const struct - "Patch constant function \"%s\" is not defined.", name); - } - --static void parse_entry_function_attributes(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *entry_func) -+static void parse_entry_function_attributes(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) - { - const struct hlsl_profile_info *profile = ctx->profile; - unsigned int i; -@@ -6049,6 +6049,8 @@ static void parse_entry_function_attributes(struct hlsl_ctx *ctx, const struct h - parse_partitioning_attribute(ctx, attr); - else if (!strcmp(attr->name, "patchconstantfunc") && profile->type == VKD3D_SHADER_TYPE_HULL) - parse_patchconstantfunc_attribute(ctx, attr); -+ else if (!strcmp(attr->name, "earlydepthstencil") && profile->type == VKD3D_SHADER_TYPE_PIXEL) -+ entry_func->early_depth_test = true; - else - hlsl_warning(ctx, &entry_func->attrs[i]->loc, VKD3D_SHADER_WARNING_HLSL_UNKNOWN_ATTRIBUTE, - "Ignoring unknown attribute \"%s\".", entry_func->attrs[i]->name); -@@ -6684,15 +6686,110 @@ static void sm1_generate_vsir_instr_expr_sincos(struct hlsl_ctx *ctx, struct vsi - hlsl_replace_node(instr, vsir_instr); - } - -+static bool sm1_generate_vsir_instr_expr_cast(struct hlsl_ctx *ctx, -+ struct vsir_program *program, struct hlsl_ir_expr *expr) -+{ -+ const struct hlsl_type *src_type, *dst_type; -+ const struct hlsl_ir_node *arg1, *instr; -+ -+ arg1 = expr->operands[0].node; -+ src_type = arg1->data_type; -+ instr = &expr->node; -+ dst_type = instr->data_type; -+ -+ /* Narrowing casts were already lowered. */ -+ VKD3D_ASSERT(src_type->dimx == dst_type->dimx); -+ -+ switch (dst_type->e.numeric.type) -+ { -+ case HLSL_TYPE_HALF: -+ case HLSL_TYPE_FLOAT: -+ switch (src_type->e.numeric.type) -+ { -+ case HLSL_TYPE_INT: -+ case HLSL_TYPE_UINT: -+ case HLSL_TYPE_BOOL: -+ /* Integrals are internally represented as floats, so no change is necessary.*/ -+ case HLSL_TYPE_HALF: -+ case HLSL_TYPE_FLOAT: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); -+ return true; -+ -+ case HLSL_TYPE_DOUBLE: -+ hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to float."); -+ break; -+ -+ default: -+ vkd3d_unreachable(); -+ } -+ break; -+ -+ case HLSL_TYPE_INT: -+ case HLSL_TYPE_UINT: -+ switch(src_type->e.numeric.type) -+ { -+ case HLSL_TYPE_HALF: -+ case HLSL_TYPE_FLOAT: -+ /* A compilation pass turns these into FLOOR+REINTERPRET, so we should not -+ * reach this case unless we are missing something. */ -+ hlsl_fixme(ctx, &instr->loc, "Unlowered SM1 cast from float to integer."); -+ break; -+ -+ case HLSL_TYPE_INT: -+ case HLSL_TYPE_UINT: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); -+ return true; -+ -+ case HLSL_TYPE_BOOL: -+ hlsl_fixme(ctx, &instr->loc, "SM1 cast from bool to integer."); -+ break; -+ -+ case HLSL_TYPE_DOUBLE: -+ hlsl_fixme(ctx, &instr->loc, "SM1 cast from double to integer."); -+ break; -+ -+ default: -+ vkd3d_unreachable(); -+ } -+ break; -+ -+ case HLSL_TYPE_DOUBLE: -+ hlsl_fixme(ctx, &instr->loc, "SM1 cast to double."); -+ break; -+ -+ case HLSL_TYPE_BOOL: -+ /* Casts to bool should have already been lowered. */ -+ default: -+ hlsl_fixme(ctx, &expr->node.loc, "SM1 cast from %s to %s.", -+ debug_hlsl_type(ctx, src_type), debug_hlsl_type(ctx, dst_type)); -+ break; -+ } -+ -+ return false; -+} -+ - static bool sm1_generate_vsir_instr_expr(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_ir_expr *expr) - { -+ struct hlsl_ir_node *instr = &expr->node; -+ -+ if (expr->op != HLSL_OP1_REINTERPRET && expr->op != HLSL_OP1_CAST -+ && instr->data_type->e.numeric.type != HLSL_TYPE_FLOAT) -+ { -+ /* These need to be lowered. */ -+ hlsl_fixme(ctx, &instr->loc, "SM1 non-float expression."); -+ return false; -+ } -+ - switch (expr->op) - { - case HLSL_OP1_ABS: - sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_ABS, 0, 0, true); - break; - -+ case HLSL_OP1_CAST: -+ return sm1_generate_vsir_instr_expr_cast(ctx, program, expr); -+ - case HLSL_OP1_COS_REDUCED: - VKD3D_ASSERT(expr->node.reg.writemask == VKD3DSP_WRITEMASK_0); - sm1_generate_vsir_instr_expr_sincos(ctx, program, expr); -@@ -6722,6 +6819,10 @@ static bool sm1_generate_vsir_instr_expr(struct hlsl_ctx *ctx, struct vsir_progr - sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_RCP); - break; - -+ case HLSL_OP1_REINTERPRET: -+ sm1_generate_vsir_instr_expr_single_instr_op(ctx, program, expr, VKD3DSIH_MOV, 0, 0, true); -+ break; -+ - case HLSL_OP1_RSQ: - sm1_generate_vsir_instr_expr_per_component_instr_op(ctx, program, expr, VKD3DSIH_RSQ); - break; -@@ -6858,29 +6959,52 @@ static void sm1_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx, - unsigned int writemask; - struct hlsl_reg reg; - -- reg = hlsl_reg_from_deref(ctx, deref); -- register_index = reg.id; -- writemask = reg.writemask; -+ if (hlsl_type_is_resource(deref->var->data_type)) -+ { -+ unsigned int sampler_offset; -+ -+ type = VKD3DSPR_COMBINED_SAMPLER; - -- if (deref->var->is_uniform) -+ sampler_offset = hlsl_offset_from_deref_safe(ctx, deref); -+ register_index = deref->var->regs[HLSL_REGSET_SAMPLERS].index + sampler_offset; -+ writemask = VKD3DSP_WRITEMASK_ALL; -+ } -+ else if (deref->var->is_uniform) - { -- VKD3D_ASSERT(reg.allocated); - type = VKD3DSPR_CONST; -+ -+ reg = hlsl_reg_from_deref(ctx, deref); -+ register_index = reg.id; -+ writemask = reg.writemask; -+ VKD3D_ASSERT(reg.allocated); - } - else if (deref->var->is_input_semantic) - { - version.major = ctx->profile->major_version; - version.minor = ctx->profile->minor_version; - version.type = ctx->profile->type; -- if (!hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name, -+ if (hlsl_sm1_register_from_semantic(&version, deref->var->semantic.name, - deref->var->semantic.index, false, &type, ®ister_index)) - { -- VKD3D_ASSERT(reg.allocated); -+ writemask = (1 << deref->var->data_type->dimx) - 1; -+ } -+ else -+ { - type = VKD3DSPR_INPUT; -+ -+ reg = hlsl_reg_from_deref(ctx, deref); - register_index = reg.id; -+ writemask = reg.writemask; -+ VKD3D_ASSERT(reg.allocated); - } -- else -- writemask = (1 << deref->var->data_type->dimx) - 1; -+ } -+ else -+ { -+ type = VKD3DSPR_TEMP; -+ -+ reg = hlsl_reg_from_deref(ctx, deref); -+ register_index = reg.id; -+ writemask = reg.writemask; - } - - vsir_register_init(&src_param->reg, type, VKD3D_DATA_FLOAT, 1); -@@ -6924,6 +7048,91 @@ static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_progr - hlsl_replace_node(instr, vsir_instr); - } - -+static void sm1_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, -+ struct vsir_program *program, struct hlsl_ir_resource_load *load) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *coords = load->coords.node; -+ struct hlsl_ir_node *ddx = load->ddx.node; -+ struct hlsl_ir_node *ddy = load->ddy.node; -+ struct hlsl_ir_node *instr = &load->node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_src_param *src_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ enum vkd3d_shader_opcode opcode; -+ unsigned int src_count = 2; -+ uint32_t flags = 0; -+ -+ VKD3D_ASSERT(instr->reg.allocated); -+ -+ switch (load->load_type) -+ { -+ case HLSL_RESOURCE_SAMPLE: -+ opcode = VKD3DSIH_TEX; -+ break; -+ -+ case HLSL_RESOURCE_SAMPLE_PROJ: -+ opcode = VKD3DSIH_TEX; -+ flags |= VKD3DSI_TEXLD_PROJECT; -+ break; -+ -+ case HLSL_RESOURCE_SAMPLE_LOD_BIAS: -+ opcode = VKD3DSIH_TEX; -+ flags |= VKD3DSI_TEXLD_BIAS; -+ break; -+ -+ case HLSL_RESOURCE_SAMPLE_GRAD: -+ opcode = VKD3DSIH_TEXLDD; -+ src_count += 2; -+ break; -+ -+ default: -+ hlsl_fixme(ctx, &instr->loc, "Resource load type %u.", load->load_type); -+ return; -+ } -+ -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, src_count))) -+ return; -+ ins->flags = flags; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = instr->reg.id; -+ dst_param->write_mask = instr->reg.writemask; -+ -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = coords->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(coords->reg.writemask, VKD3DSP_WRITEMASK_ALL); -+ -+ sm1_generate_vsir_init_src_param_from_deref(ctx, &ins->src[1], &load->resource, -+ VKD3DSP_WRITEMASK_ALL, &ins->location); -+ -+ if (load->load_type == HLSL_RESOURCE_SAMPLE_GRAD) -+ { -+ src_param = &ins->src[2]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = ddx->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(ddx->reg.writemask, VKD3DSP_WRITEMASK_ALL); -+ -+ src_param = &ins->src[3]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = ddy->reg.id; -+ src_param->swizzle = sm1_generate_vsir_get_src_swizzle(ddy->reg.writemask, VKD3DSP_WRITEMASK_ALL); -+ } -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -+ &instr->reg, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+} -+ - static void sm1_generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_ir_swizzle *swizzle_instr) - { -@@ -6996,6 +7205,42 @@ static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_prog - hlsl_replace_node(instr, vsir_instr); - } - -+static void sm1_generate_vsir_instr_jump(struct hlsl_ctx *ctx, -+ struct vsir_program *program, struct hlsl_ir_jump *jump) -+{ -+ struct vkd3d_shader_instruction_array *instructions = &program->instructions; -+ struct hlsl_ir_node *condition = jump->condition.node; -+ struct hlsl_ir_node *instr = &jump->node; -+ struct vkd3d_shader_dst_param *dst_param; -+ struct vkd3d_shader_instruction *ins; -+ struct hlsl_ir_node *vsir_instr; -+ -+ if (jump->type == HLSL_IR_JUMP_DISCARD_NEG) -+ { -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_TEXKILL, 1, 0))) -+ return; -+ -+ dst_param = &ins->dst[0]; -+ vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ dst_param->reg.idx[0].offset = condition->reg.id; -+ dst_param->write_mask = condition->reg.writemask; -+ -+ if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, -+ instructions->count - 1, instr->data_type, NULL, &instr->loc))) -+ { -+ ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ -+ list_add_before(&instr->entry, &vsir_instr->entry); -+ hlsl_replace_node(instr, vsir_instr); -+ } -+ else -+ { -+ hlsl_fixme(ctx, &instr->loc, "Jump type %s.", hlsl_jump_type_to_string(jump->type)); -+ } -+} -+ - static bool sm1_generate_vsir_instr(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) - { - struct vsir_program *program = context; -@@ -7009,10 +7254,18 @@ static bool sm1_generate_vsir_instr(struct hlsl_ctx *ctx, struct hlsl_ir_node *i - case HLSL_IR_EXPR: - return sm1_generate_vsir_instr_expr(ctx, program, hlsl_ir_expr(instr)); - -+ case HLSL_IR_JUMP: -+ sm1_generate_vsir_instr_jump(ctx, program, hlsl_ir_jump(instr)); -+ return true; -+ - case HLSL_IR_LOAD: - sm1_generate_vsir_instr_load(ctx, program, hlsl_ir_load(instr)); - return true; - -+ case HLSL_IR_RESOURCE_LOAD: -+ sm1_generate_vsir_instr_resource_load(ctx, program, hlsl_ir_resource_load(instr)); -+ return true; -+ - case HLSL_IR_STORE: - sm1_generate_vsir_instr_store(ctx, program, hlsl_ir_store(instr)); - return true; -@@ -7041,7 +7294,7 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl - version.major = ctx->profile->major_version; - version.minor = ctx->profile->minor_version; - version.type = ctx->profile->type; -- if (!vsir_program_init(program, NULL, &version, 0)) -+ if (!vsir_program_init(program, NULL, &version, 0, VSIR_CF_STRUCTURED)) - { - ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; - return; -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index 6cef85fdc84..4b79a058b6f 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -74,7 +74,7 @@ static int convert_parameter_info(const struct vkd3d_shader_compile_info *compil - } - - bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, -- const struct vkd3d_shader_version *version, unsigned int reserve) -+ const struct vkd3d_shader_version *version, unsigned int reserve, enum vsir_control_flow_type cf_type) - { - memset(program, 0, sizeof(*program)); - -@@ -96,6 +96,7 @@ bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_c - } - - program->shader_version = *version; -+ program->cf_type = cf_type; - return shader_instruction_array_init(&program->instructions, reserve); - } - -@@ -2803,6 +2804,8 @@ static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsi - struct cf_flattener flattener = {.program = program}; - enum vkd3d_result result; - -+ VKD3D_ASSERT(program->cf_type == VSIR_CF_STRUCTURED); -+ - if ((result = cf_flattener_iterate_instruction_array(&flattener, message_context)) >= 0) - { - vkd3d_free(program->instructions.elements); -@@ -2810,6 +2813,7 @@ static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsi - program->instructions.capacity = flattener.instruction_capacity; - program->instructions.count = flattener.instruction_count; - program->block_count = flattener.block_id; -+ program->cf_type = VSIR_CF_BLOCKS; - } - else - { -@@ -2877,6 +2881,8 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs - struct vkd3d_shader_instruction *instructions = NULL; - struct lower_switch_to_if_ladder_block_mapping *block_map = NULL; - -+ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); -+ - if (!reserve_instructions(&instructions, &ins_capacity, program->instructions.count)) - goto fail; - -@@ -3069,6 +3075,8 @@ static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps(struct vsir_ - struct ssas_to_temps_alloc alloc = {0}; - unsigned int current_label = 0; - -+ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); -+ - if (!(block_info = vkd3d_calloc(program->block_count, sizeof(*block_info)))) - { - ERR("Failed to allocate block info array.\n"); -@@ -5289,6 +5297,8 @@ static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, - enum vkd3d_result ret; - size_t i; - -+ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); -+ - target.jump_target_temp_idx = program->temp_count; - target.temp_count = program->temp_count + 1; - -@@ -5336,6 +5346,7 @@ static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, - program->instructions.capacity = target.ins_capacity; - program->instructions.count = target.ins_count; - program->temp_count = target.temp_count; -+ program->cf_type = VSIR_CF_STRUCTURED; - - return VKD3D_OK; - -@@ -5469,6 +5480,8 @@ static enum vkd3d_result vsir_program_materialize_undominated_ssas_to_temps(stru - enum vkd3d_result ret; - size_t i; - -+ VKD3D_ASSERT(program->cf_type == VSIR_CF_BLOCKS); -+ - for (i = 0; i < program->instructions.count;) - { - struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; -@@ -5701,12 +5714,6 @@ struct validation_context - enum vkd3d_result status; - bool dcl_temps_found; - enum vkd3d_shader_opcode phase; -- enum cf_type -- { -- CF_TYPE_UNKNOWN = 0, -- CF_TYPE_STRUCTURED, -- CF_TYPE_BLOCKS, -- } cf_type; - bool inside_block; - - struct validation_context_temp_data -@@ -6119,13 +6126,13 @@ static bool vsir_validate_src_max_count(struct validation_context *ctx, - return true; - } - --static const char *name_from_cf_type(enum cf_type type) -+static const char *name_from_cf_type(enum vsir_control_flow_type type) - { - switch (type) - { -- case CF_TYPE_STRUCTURED: -+ case VSIR_CF_STRUCTURED: - return "structured"; -- case CF_TYPE_BLOCKS: -+ case VSIR_CF_BLOCKS: - return "block-based"; - default: - vkd3d_unreachable(); -@@ -6133,15 +6140,122 @@ static const char *name_from_cf_type(enum cf_type type) - } - - static void vsir_validate_cf_type(struct validation_context *ctx, -- const struct vkd3d_shader_instruction *instruction, enum cf_type expected_type) -+ const struct vkd3d_shader_instruction *instruction, enum vsir_control_flow_type expected_type) - { -- VKD3D_ASSERT(ctx->cf_type != CF_TYPE_UNKNOWN); -- VKD3D_ASSERT(expected_type != CF_TYPE_UNKNOWN); -- if (ctx->cf_type != expected_type) -+ if (ctx->program->cf_type != expected_type) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x in %s shader.", -- instruction->opcode, name_from_cf_type(ctx->cf_type)); -+ instruction->opcode, name_from_cf_type(ctx->program->cf_type)); -+} -+ -+static void vsir_validator_push_block(struct validation_context *ctx, enum vkd3d_shader_opcode opcode) -+{ -+ if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) -+ { -+ ctx->status = VKD3D_ERROR_OUT_OF_MEMORY; -+ return; -+ } -+ ctx->blocks[ctx->depth++] = opcode; -+} -+ -+static void vsir_validate_dcl_temps(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (ctx->dcl_temps_found) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS, -+ "Duplicate DCL_TEMPS instruction."); -+ if (instruction->declaration.count > ctx->program->temp_count) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, -+ "Invalid DCL_TEMPS count %u, expected at most %u.", -+ instruction->declaration.count, ctx->program->temp_count); -+ ctx->dcl_temps_found = true; -+} -+ -+static void vsir_validate_else(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -+ "ELSE instruction doesn't terminate IF block."); -+ else -+ ctx->blocks[ctx->depth - 1] = VKD3DSIH_ELSE; -+} -+ -+static void vsir_validate_endif(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ if (ctx->depth == 0 || (ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF -+ && ctx->blocks[ctx->depth - 1] != VKD3DSIH_ELSE)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -+ "ENDIF instruction doesn't terminate IF/ELSE block."); -+ else -+ --ctx->depth; -+} -+ -+static void vsir_validate_endloop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_LOOP) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -+ "ENDLOOP instruction doesn't terminate LOOP block."); -+ else -+ --ctx->depth; -+} -+ -+static void vsir_validate_endrep(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_REP) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -+ "ENDREP instruction doesn't terminate REP block."); -+ else -+ --ctx->depth; -+} -+ -+static void vsir_validate_if(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ vsir_validator_push_block(ctx, VKD3DSIH_IF); -+} -+ -+static void vsir_validate_ifc(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ vsir_validator_push_block(ctx, VKD3DSIH_IF); -+} -+ -+static void vsir_validate_loop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ vsir_validate_src_count(ctx, instruction, ctx->program->shader_version.major <= 3 ? 2 : 0); -+ vsir_validator_push_block(ctx, VKD3DSIH_LOOP); - } - -+static void vsir_validate_rep(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ vsir_validator_push_block(ctx, VKD3DSIH_REP); -+} -+ -+struct vsir_validator_instruction_desc -+{ -+ unsigned int dst_param_count; -+ unsigned int src_param_count; -+ void (*validate)(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction); -+}; -+ -+static const struct vsir_validator_instruction_desc vsir_validator_instructions[] = -+{ -+ [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, -+ [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, -+ [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, -+ [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, -+ [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, -+ [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, -+ [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, -+ [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, -+ [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, -+}; -+ - static void vsir_validate_instruction(struct validation_context *ctx) - { - const struct vkd3d_shader_version *version = &ctx->program->shader_version; -@@ -6254,24 +6368,8 @@ static void vsir_validate_instruction(struct validation_context *ctx) - "Instruction %#x appear before any phase instruction in a hull shader.", - instruction->opcode); - -- /* We support two different control flow types in shaders: -- * block-based, like DXIL and SPIR-V, and structured, like D3DBC -- * and TPF. The shader is detected as block-based when its first -- * instruction, except for NOP, DCL_* and phases, is a LABEL. -- * Currently we mandate that each shader is either purely block-based or -- * purely structured. In principle we could allow structured -- * constructs in a block, provided they are confined in a single -- * block, but need for that hasn't arisen yet, so we don't. */ -- if (ctx->cf_type == CF_TYPE_UNKNOWN && instruction->opcode != VKD3DSIH_NOP -- && !vsir_instruction_is_dcl(instruction)) -- { -- if (instruction->opcode == VKD3DSIH_LABEL) -- ctx->cf_type = CF_TYPE_BLOCKS; -- else -- ctx->cf_type = CF_TYPE_STRUCTURED; -- } -- -- if (ctx->cf_type == CF_TYPE_BLOCKS && !vsir_instruction_is_dcl(instruction)) -+ if (ctx->program->cf_type == VSIR_CF_BLOCKS && !vsir_instruction_is_dcl(instruction) -+ && instruction->opcode != VKD3DSIH_NOP) - { - switch (instruction->opcode) - { -@@ -6300,98 +6398,26 @@ static void vsir_validate_instruction(struct validation_context *ctx) - } - } - -- switch (instruction->opcode) -+ if (instruction->opcode < ARRAY_SIZE(vsir_validator_instructions)) - { -- case VKD3DSIH_DCL_TEMPS: -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- if (ctx->dcl_temps_found) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS, "Duplicate DCL_TEMPS instruction."); -- if (instruction->declaration.count > ctx->program->temp_count) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, -- "Invalid DCL_TEMPS count %u, expected at most %u.", -- instruction->declaration.count, ctx->program->temp_count); -- ctx->dcl_temps_found = true; -- break; -- -- case VKD3DSIH_IF: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 1); -- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) -- return; -- ctx->blocks[ctx->depth++] = instruction->opcode; -- break; -+ const struct vsir_validator_instruction_desc *desc; - -- case VKD3DSIH_IFC: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 2); -- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) -- return; -- ctx->blocks[ctx->depth++] = VKD3DSIH_IF; -- break; -+ desc = &vsir_validator_instructions[instruction->opcode]; - -- case VKD3DSIH_ELSE: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ELSE instruction doesn't terminate IF block."); -- else -- ctx->blocks[ctx->depth - 1] = instruction->opcode; -- break; -- -- case VKD3DSIH_ENDIF: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- if (ctx->depth == 0 || (ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF && ctx->blocks[ctx->depth - 1] != VKD3DSIH_ELSE)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDIF instruction doesn't terminate IF/ELSE block."); -- else -- --ctx->depth; -- break; -- -- case VKD3DSIH_LOOP: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, version->major <= 3 ? 2 : 0); -- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) -- return; -- ctx->blocks[ctx->depth++] = instruction->opcode; -- break; -- -- case VKD3DSIH_ENDLOOP: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_LOOP) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDLOOP instruction doesn't terminate LOOP block."); -- else -- --ctx->depth; -- break; -- -- case VKD3DSIH_REP: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 1); -- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) -- return; -- ctx->blocks[ctx->depth++] = instruction->opcode; -- break; -- -- case VKD3DSIH_ENDREP: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_REP) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDREP instruction doesn't terminate REP block."); -- else -- --ctx->depth; -- break; -+ if (desc->validate) -+ { -+ if (desc->dst_param_count != ~0u) -+ vsir_validate_dst_count(ctx, instruction, desc->dst_param_count); -+ if (desc->src_param_count != ~0u) -+ vsir_validate_src_count(ctx, instruction, desc->src_param_count); -+ desc->validate(ctx, instruction); -+ } -+ } - -+ switch (instruction->opcode) -+ { - case VKD3DSIH_SWITCH: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); - vsir_validate_dst_count(ctx, instruction, 0); - vsir_validate_src_count(ctx, instruction, 1); - if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) -@@ -6400,7 +6426,7 @@ static void vsir_validate_instruction(struct validation_context *ctx) - break; - - case VKD3DSIH_ENDSWITCH: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); - vsir_validate_dst_count(ctx, instruction, 0); - vsir_validate_src_count(ctx, instruction, 0); - if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_SWITCH) -@@ -6415,7 +6441,7 @@ static void vsir_validate_instruction(struct validation_context *ctx) - break; - - case VKD3DSIH_LABEL: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); - vsir_validate_dst_count(ctx, instruction, 0); - vsir_validate_src_count(ctx, instruction, 1); - if (instruction->src_count >= 1 && !vsir_register_is_label(&instruction->src[0].reg)) -@@ -6425,7 +6451,7 @@ static void vsir_validate_instruction(struct validation_context *ctx) - break; - - case VKD3DSIH_BRANCH: -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); - vsir_validate_dst_count(ctx, instruction, 0); - if (!vsir_validate_src_min_count(ctx, instruction, 1)) - break; -@@ -6465,7 +6491,7 @@ static void vsir_validate_instruction(struct validation_context *ctx) - { - unsigned int case_count; - -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); - vsir_validate_dst_count(ctx, instruction, 0); - /* Parameters are source, default label, merge label and - * then pairs of constant value and case label. */ -@@ -6510,7 +6536,7 @@ static void vsir_validate_instruction(struct validation_context *ctx) - { - unsigned int incoming_count; - -- vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); - vsir_validate_dst_count(ctx, instruction, 1); - vsir_validate_src_min_count(ctx, instruction, 2); - if (instruction->src_count % 2 != 0) -@@ -6590,7 +6616,8 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c - if (!(ctx.ssas = vkd3d_calloc(ctx.program->ssa_count, sizeof(*ctx.ssas)))) - goto fail; - -- for (ctx.instruction_idx = 0; ctx.instruction_idx < program->instructions.count; ++ctx.instruction_idx) -+ for (ctx.instruction_idx = 0; ctx.instruction_idx < program->instructions.count -+ && ctx.status != VKD3D_ERROR_OUT_OF_MEMORY; ++ctx.instruction_idx) - vsir_validate_instruction(&ctx); - - ctx.invalid_instruction_idx = true; -@@ -6685,7 +6712,8 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t - vsir_transform(&ctx, vsir_program_remove_dead_code); - vsir_transform(&ctx, vsir_program_normalise_combined_samplers); - -- if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL) -+ if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL -+ && compile_info->target_type != VKD3D_SHADER_TARGET_MSL) - vsir_transform(&ctx, vsir_program_flatten_control_flow_constructs); - } - -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index b76a596bb60..a9d6c9e7c13 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -23,6 +23,7 @@ - - #include "hlsl.h" - #include "vkd3d_shader_private.h" -+#include "d3dcommon.h" - - #define SM4_MAX_SRC_COUNT 6 - #define SM4_MAX_DST_COUNT 2 -@@ -616,6 +617,33 @@ enum vkd3d_sm4_shader_data_type - VKD3D_SM4_SHADER_DATA_MESSAGE = 0x4, - }; - -+enum vkd3d_sm4_stat_field -+{ -+ VKD3D_STAT_UNUSED = 0, -+ VKD3D_STAT_INSTR_COUNT, -+ VKD3D_STAT_MOV, -+ VKD3D_STAT_MOVC, -+ VKD3D_STAT_CONV, -+ VKD3D_STAT_FLOAT, -+ VKD3D_STAT_INT, -+ VKD3D_STAT_UINT, -+ VKD3D_STAT_EMIT, -+ VKD3D_STAT_CUT, -+ VKD3D_STAT_SAMPLE, -+ VKD3D_STAT_SAMPLE_C, -+ VKD3D_STAT_SAMPLE_GRAD, -+ VKD3D_STAT_SAMPLE_BIAS, -+ VKD3D_STAT_LOAD, -+ VKD3D_STAT_STORE, -+ VKD3D_STAT_COUNT, -+}; -+ -+struct vkd3d_sm4_stat_field_info -+{ -+ enum vkd3d_sm4_opcode opcode; -+ enum vkd3d_sm4_stat_field field; -+}; -+ - struct sm4_index_range - { - unsigned int index; -@@ -634,6 +662,7 @@ struct vkd3d_sm4_lookup_tables - const struct vkd3d_sm4_opcode_info *opcode_info_from_sm4[VKD3D_SM4_OP_COUNT]; - const struct vkd3d_sm4_register_type_info *register_type_info_from_sm4[VKD3D_SM4_REGISTER_TYPE_COUNT]; - const struct vkd3d_sm4_register_type_info *register_type_info_from_vkd3d[VKD3DSPR_COUNT]; -+ const struct vkd3d_sm4_stat_field_info *stat_field_from_sm4[VKD3D_SM4_OP_COUNT]; - }; - - struct vkd3d_shader_sm4_parser -@@ -1330,11 +1359,17 @@ static const enum vkd3d_shader_register_precision register_precision_table[] = - /* VKD3D_SM4_REGISTER_PRECISION_MIN_UINT_16 */ VKD3D_SHADER_REGISTER_PRECISION_MIN_UINT_16, - }; - -+struct sm4_stat -+{ -+ uint32_t fields[VKD3D_STAT_COUNT]; -+}; -+ - struct tpf_writer - { - struct hlsl_ctx *ctx; - struct vkd3d_bytecode_buffer *buffer; - struct vkd3d_sm4_lookup_tables lookup; -+ struct sm4_stat *stat; - }; - - static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) -@@ -1662,6 +1697,120 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) - {VKD3D_SM5_RT_OUTPUT_STENCIL_REF, VKD3DSPR_OUTSTENCILREF, VKD3D_SM4_SWIZZLE_VEC4}, - }; - -+ static const struct vkd3d_sm4_stat_field_info stat_field_table[] = -+ { -+ {VKD3D_SM4_OP_MOV, VKD3D_STAT_MOV}, -+ {VKD3D_SM4_OP_MOVC, VKD3D_STAT_MOVC}, -+ {VKD3D_SM5_OP_DMOV, VKD3D_STAT_MOV}, -+ {VKD3D_SM5_OP_DMOVC, VKD3D_STAT_MOVC}, -+ -+ {VKD3D_SM4_OP_ITOF, VKD3D_STAT_CONV}, -+ {VKD3D_SM4_OP_FTOI, VKD3D_STAT_CONV}, -+ {VKD3D_SM4_OP_FTOU, VKD3D_STAT_CONV}, -+ {VKD3D_SM4_OP_UTOF, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_DTOU, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_UTOD, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_DTOF, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_FTOD, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_DTOI, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_ITOD, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_F32TOF16, VKD3D_STAT_CONV}, -+ {VKD3D_SM5_OP_F16TOF32, VKD3D_STAT_CONV}, -+ -+ {VKD3D_SM4_OP_ADD, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_DIV, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_DP2, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_DP3, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_DP4, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_EQ, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_EXP, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_FRC, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_GE, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_LT, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_MAD, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_MIN, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_MAX, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_MUL, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_NE, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_ROUND_NE, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_ROUND_NI, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_ROUND_PI, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_ROUND_Z, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_RSQ, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_SQRT, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM4_OP_SINCOS, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_RCP, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DADD, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DMAX, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DMIN, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DMUL, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DEQ, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DGE, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DLT, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DNE, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DDIV, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DFMA, VKD3D_STAT_FLOAT}, -+ {VKD3D_SM5_OP_DRCP, VKD3D_STAT_FLOAT}, -+ -+ {VKD3D_SM4_OP_IADD, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_IEQ, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_IGE, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_ILT, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_IMAD, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_IMAX, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_IMIN, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_IMUL, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_INE, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_INEG, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_ISHL, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_ISHR, VKD3D_STAT_INT}, -+ {VKD3D_SM4_OP_ITOF, VKD3D_STAT_INT}, -+ -+ {VKD3D_SM4_OP_UDIV, VKD3D_STAT_UINT}, -+ {VKD3D_SM4_OP_ULT, VKD3D_STAT_UINT}, -+ {VKD3D_SM4_OP_UGE, VKD3D_STAT_UINT}, -+ {VKD3D_SM4_OP_UMUL, VKD3D_STAT_UINT}, -+ {VKD3D_SM4_OP_UMAX, VKD3D_STAT_UINT}, -+ {VKD3D_SM4_OP_UMIN, VKD3D_STAT_UINT}, -+ {VKD3D_SM4_OP_USHR, VKD3D_STAT_UINT}, -+ -+ {VKD3D_SM4_OP_EMIT, VKD3D_STAT_EMIT}, -+ {VKD3D_SM4_OP_CUT, VKD3D_STAT_CUT}, -+ {VKD3D_SM5_OP_EMIT_STREAM, VKD3D_STAT_EMIT}, -+ {VKD3D_SM5_OP_CUT_STREAM, VKD3D_STAT_CUT}, -+ -+ {VKD3D_SM4_OP_SAMPLE, VKD3D_STAT_SAMPLE}, -+ {VKD3D_SM4_OP_SAMPLE_LOD, VKD3D_STAT_SAMPLE}, -+ {VKD3D_SM5_OP_SAMPLE_LOD_S, VKD3D_STAT_SAMPLE}, -+ {VKD3D_SM5_OP_SAMPLE_CL_S, VKD3D_STAT_SAMPLE}, -+ {VKD3D_SM4_OP_GATHER4, VKD3D_STAT_SAMPLE}, -+ {VKD3D_SM5_OP_GATHER4_PO, VKD3D_STAT_SAMPLE}, -+ {VKD3D_SM4_OP_SAMPLE_C, VKD3D_STAT_SAMPLE_C}, -+ {VKD3D_SM4_OP_SAMPLE_C_LZ, VKD3D_STAT_SAMPLE_C}, -+ {VKD3D_SM5_OP_SAMPLE_C_LZ_S, VKD3D_STAT_SAMPLE_C}, -+ {VKD3D_SM5_OP_SAMPLE_C_CL_S, VKD3D_STAT_SAMPLE_C}, -+ {VKD3D_SM5_OP_GATHER4_C, VKD3D_STAT_SAMPLE_C}, -+ {VKD3D_SM5_OP_GATHER4_PO_C, VKD3D_STAT_SAMPLE_C}, -+ {VKD3D_SM4_OP_SAMPLE_GRAD, VKD3D_STAT_SAMPLE_GRAD}, -+ {VKD3D_SM5_OP_SAMPLE_GRAD_CL_S, VKD3D_STAT_SAMPLE_GRAD}, -+ {VKD3D_SM4_OP_SAMPLE_B, VKD3D_STAT_SAMPLE_BIAS}, -+ -+ {VKD3D_SM4_OP_LD, VKD3D_STAT_LOAD}, -+ {VKD3D_SM4_OP_LD2DMS, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD_UAV_TYPED, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD_RAW, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD_STRUCTURED, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD_S, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD2DMS_S, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD_UAV_TYPED_S, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD_RAW_S, VKD3D_STAT_LOAD}, -+ {VKD3D_SM5_OP_LD_STRUCTURED_S, VKD3D_STAT_LOAD}, -+ -+ {VKD3D_SM5_OP_STORE_UAV_TYPED, VKD3D_STAT_STORE}, -+ {VKD3D_SM5_OP_STORE_RAW, VKD3D_STAT_STORE}, -+ {VKD3D_SM5_OP_STORE_STRUCTURED,VKD3D_STAT_STORE}, -+ }; -+ - memset(lookup, 0, sizeof(*lookup)); - - for (i = 0; i < ARRAY_SIZE(opcode_table); ++i) -@@ -1678,12 +1827,21 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) - lookup->register_type_info_from_sm4[info->sm4_type] = info; - lookup->register_type_info_from_vkd3d[info->vkd3d_type] = info; - } -+ -+ for (i = 0; i < ARRAY_SIZE(stat_field_table); ++i) -+ { -+ const struct vkd3d_sm4_stat_field_info *info = &stat_field_table[i]; -+ -+ lookup->stat_field_from_sm4[info->opcode] = info; -+ } - } - --static void tpf_writer_init(struct tpf_writer *tpf, struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer) -+static void tpf_writer_init(struct tpf_writer *tpf, struct hlsl_ctx *ctx, struct sm4_stat *stat, -+ struct vkd3d_bytecode_buffer *buffer) - { - tpf->ctx = ctx; - tpf->buffer = buffer; -+ tpf->stat = stat; - init_sm4_lookup_tables(&tpf->lookup); - } - -@@ -1721,6 +1879,16 @@ static enum vkd3d_sm4_swizzle_type vkd3d_sm4_get_default_swizzle_type( - return register_type_info->default_src_swizzle_type; - } - -+static enum vkd3d_sm4_stat_field get_stat_field_from_sm4_opcode( -+ const struct vkd3d_sm4_lookup_tables *lookup, enum vkd3d_sm4_opcode sm4_opcode) -+{ -+ const struct vkd3d_sm4_stat_field_info *field_info; -+ -+ if (sm4_opcode >= VKD3D_SM4_OP_COUNT || !(field_info = lookup->stat_field_from_sm4[sm4_opcode])) -+ return VKD3D_STAT_UNUSED; -+ return field_info->field; -+} -+ - static enum vkd3d_data_type map_data_type(char t) - { - switch (t) -@@ -2553,7 +2721,7 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, struct vsir_pro - version.minor = VKD3D_SM4_VERSION_MINOR(version_token); - - /* Estimate instruction count to avoid reallocation in most shaders. */ -- if (!vsir_program_init(program, compile_info, &version, token_count / 7u + 20)) -+ if (!vsir_program_init(program, compile_info, &version, token_count / 7u + 20, VSIR_CF_STRUCTURED)) - return false; - vkd3d_shader_parser_init(&sm4->p, program, message_context, compile_info->source_name); - sm4->ptr = sm4->start; -@@ -4187,6 +4355,7 @@ static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4 - { - struct vkd3d_bytecode_buffer *buffer = tpf->buffer; - uint32_t token = instr->opcode | instr->extra_bits; -+ enum vkd3d_sm4_stat_field stat_field; - unsigned int size, i, j; - size_t token_position; - -@@ -4219,6 +4388,11 @@ static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4 - size = (bytecode_get_size(buffer) - token_position) / sizeof(uint32_t); - token |= (size << VKD3D_SM4_INSTRUCTION_LENGTH_SHIFT); - set_u32(buffer, token_position, token); -+ -+ ++tpf->stat->fields[VKD3D_STAT_INSTR_COUNT]; -+ -+ stat_field = get_stat_field_from_sm4_opcode(&tpf->lookup, instr->opcode & VKD3D_SM4_OPCODE_MASK); -+ ++tpf->stat->fields[stat_field]; - } - - static bool encode_texel_offset_as_aoffimmi(struct sm4_instruction *instr, -@@ -4579,6 +4753,17 @@ static void write_sm4_dcl_thread_group(const struct tpf_writer *tpf, const uint3 - write_sm4_instruction(tpf, &instr); - } - -+static void write_sm4_dcl_global_flags(const struct tpf_writer *tpf, uint32_t flags) -+{ -+ struct sm4_instruction instr = -+ { -+ .opcode = VKD3D_SM4_OP_DCL_GLOBAL_FLAGS, -+ .extra_bits = flags << VKD3D_SM4_GLOBAL_FLAGS_SHIFT, -+ }; -+ -+ write_sm4_instruction(tpf, &instr); -+} -+ - static void write_sm4_ret(const struct tpf_writer *tpf) - { - struct sm4_instruction instr = -@@ -6017,8 +6202,8 @@ static void write_sm4_block(const struct tpf_writer *tpf, const struct hlsl_bloc - } - } - --static void write_sm4_shdr(struct hlsl_ctx *ctx, -- const struct hlsl_ir_function_decl *entry_func, struct dxbc_writer *dxbc) -+static void write_sm4_shdr(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *entry_func, -+ struct sm4_stat *stat, struct dxbc_writer *dxbc) - { - const struct hlsl_profile_info *profile = ctx->profile; - struct vkd3d_bytecode_buffer buffer = {0}; -@@ -6043,7 +6228,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, - VKD3D_SM4_LIB, - }; - -- tpf_writer_init(&tpf, ctx, &buffer); -+ tpf_writer_init(&tpf, ctx, stat, &buffer); - - extern_resources = sm4_get_extern_resources(ctx, &extern_resources_count); - -@@ -6068,6 +6253,9 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, - write_sm4_dcl_textures(&tpf, resource, true); - } - -+ if (entry_func->early_depth_test && profile->major_version >= 5) -+ write_sm4_dcl_global_flags(&tpf, VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL); -+ - LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) - { - if ((var->is_input_semantic && var->last_read) || (var->is_output_semantic && var->first_write)) -@@ -6135,8 +6323,58 @@ static void write_sm4_sfi0(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) - vkd3d_free(flags); - } - -+static void write_sm4_stat(struct hlsl_ctx *ctx, const struct sm4_stat *stat, struct dxbc_writer *dxbc) -+{ -+ struct vkd3d_bytecode_buffer buffer = {0}; -+ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_INSTR_COUNT]); -+ put_u32(&buffer, 0); /* Temp count */ -+ put_u32(&buffer, 0); /* Def count */ -+ put_u32(&buffer, 0); /* DCL count */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_FLOAT]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_INT]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_UINT]); -+ put_u32(&buffer, 0); /* Static flow control count */ -+ put_u32(&buffer, 0); /* Dynamic flow control count */ -+ put_u32(&buffer, 0); /* Macro instruction count */ -+ put_u32(&buffer, 0); /* Temp array count */ -+ put_u32(&buffer, 0); /* Array instr count */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_CUT]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_EMIT]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_LOAD]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE_C]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE_BIAS]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_SAMPLE_GRAD]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_MOV]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_MOVC]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_CONV]); -+ put_u32(&buffer, 0); /* Bitwise instructions */ -+ put_u32(&buffer, 0); /* Input primitive */ -+ put_u32(&buffer, 0); /* GS output topology */ -+ put_u32(&buffer, 0); /* GS max output vertex count */ -+ put_u32(&buffer, 0); /* Unknown */ -+ put_u32(&buffer, 0); /* Unknown */ -+ put_u32(&buffer, 0); /* Sample frequency */ -+ -+ if (hlsl_version_ge(ctx, 5, 0)) -+ { -+ put_u32(&buffer, 0); /* GS instance count */ -+ put_u32(&buffer, 0); /* Control point count */ -+ put_u32(&buffer, 0); /* HS output primitive */ -+ put_u32(&buffer, 0); /* HS partitioning */ -+ put_u32(&buffer, 0); /* Tessellator domain */ -+ put_u32(&buffer, 0); /* Barrier instructions */ -+ put_u32(&buffer, 0); /* Interlocked instructions */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_STORE]); -+ } -+ -+ add_section(ctx, dxbc, TAG_STAT, &buffer); -+} -+ - int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) - { -+ struct sm4_stat stat = {0}; - struct dxbc_writer dxbc; - size_t i; - int ret; -@@ -6146,8 +6384,9 @@ int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun - write_sm4_signature(ctx, &dxbc, false); - write_sm4_signature(ctx, &dxbc, true); - write_sm4_rdef(ctx, &dxbc); -- write_sm4_shdr(ctx, entry_func, &dxbc); -+ write_sm4_shdr(ctx, entry_func, &stat, &dxbc); - write_sm4_sfi0(ctx, &dxbc); -+ write_sm4_stat(ctx, &stat, &dxbc); - - if (!(ret = ctx->result)) - ret = dxbc_writer_write(&dxbc, out); -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -index 60be996ae24..ee98a504a5b 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -@@ -535,6 +535,8 @@ static const char *shader_get_target_type_suffix(enum vkd3d_shader_target_type t - return "glsl"; - case VKD3D_SHADER_TARGET_FX: - return "fx"; -+ case VKD3D_SHADER_TARGET_MSL: -+ return "msl"; - default: - FIXME("Unhandled target type %#x.\n", type); - return "bin"; -@@ -1646,6 +1648,10 @@ int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, - vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); - break; - -+ case VKD3D_SHADER_TARGET_MSL: -+ ret = msl_compile(program, config_flags, compile_info, message_context); -+ break; -+ - default: - /* Validation should prevent us from reaching this. */ - vkd3d_unreachable(); -@@ -1945,6 +1951,9 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( - VKD3D_SHADER_TARGET_D3D_ASM, - #ifdef VKD3D_SHADER_UNSUPPORTED_GLSL - VKD3D_SHADER_TARGET_GLSL, -+#endif -+#ifdef VKD3D_SHADER_UNSUPPORTED_MSL -+ VKD3D_SHADER_TARGET_MSL, - #endif - }; - -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index bc369ec6866..8866780132e 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -238,6 +238,8 @@ enum vkd3d_shader_error - VKD3D_SHADER_ERROR_VSIR_INVALID_GS = 9019, - - VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300, -+ -+ VKD3D_SHADER_ERROR_MSL_INTERNAL = 10000, - }; - - enum vkd3d_shader_opcode -@@ -1362,6 +1364,12 @@ enum vkd3d_shader_config_flags - VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION = 0x00000001, - }; - -+enum vsir_control_flow_type -+{ -+ VSIR_CF_STRUCTURED, -+ VSIR_CF_BLOCKS, -+}; -+ - struct vsir_program - { - struct vkd3d_shader_version shader_version; -@@ -1381,6 +1389,7 @@ struct vsir_program - unsigned int temp_count; - unsigned int ssa_count; - bool use_vocp; -+ enum vsir_control_flow_type cf_type; - - const char **block_names; - size_t block_name_count; -@@ -1393,7 +1402,7 @@ int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_parameter1 *vsir_program_get_parameter( - const struct vsir_program *program, enum vkd3d_shader_parameter_name name); - bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, -- const struct vkd3d_shader_version *version, unsigned int reserve); -+ const struct vkd3d_shader_version *version, unsigned int reserve, enum vsir_control_flow_type cf_type); - enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); - enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, -@@ -1593,6 +1602,9 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); - -+int msl_compile(struct vsir_program *program, uint64_t config_flags, -+ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); -+ - enum vkd3d_md5_variant - { - VKD3D_MD5_STANDARD, -@@ -1872,7 +1884,7 @@ static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain, - #define VKD3D_DXBC_HEADER_SIZE (8 * sizeof(uint32_t)) - #define VKD3D_DXBC_CHUNK_ALIGNMENT sizeof(uint32_t) - --#define DXBC_MAX_SECTION_COUNT 5 -+#define DXBC_MAX_SECTION_COUNT 6 - - struct dxbc_writer - { --- -2.45.2 - diff --git a/patches/vkd3d-latest/0007-Updated-vkd3d-to-3e012c355db12ecad32d45a76058c29a407.patch b/patches/vkd3d-latest/0007-Updated-vkd3d-to-3e012c355db12ecad32d45a76058c29a407.patch deleted file mode 100644 index 79605d32..00000000 --- a/patches/vkd3d-latest/0007-Updated-vkd3d-to-3e012c355db12ecad32d45a76058c29a407.patch +++ /dev/null @@ -1,2281 +0,0 @@ -From 40af188e9e7e710643821bf227369b58db3a2eb5 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sun, 15 Sep 2024 07:56:38 +1000 -Subject: [PATCH] Updated vkd3d to 3e012c355db12ecad32d45a76058c29a407ac9e4. - ---- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 105 +- - libs/vkd3d/libs/vkd3d-shader/fx.c | 3 + - libs/vkd3d/libs/vkd3d-shader/hlsl.c | 85 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.h | 42 +- - libs/vkd3d/libs/vkd3d-shader/hlsl.l | 1 + - libs/vkd3d/libs/vkd3d-shader/hlsl.y | 108 +- - libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 278 ++---- - libs/vkd3d/libs/vkd3d-shader/ir.c | 936 +++++++++--------- - .../libs/vkd3d-shader/vkd3d_shader_private.h | 1 + - 9 files changed, 723 insertions(+), 836 deletions(-) - -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index b69b70c6304..9c7be1f08bb 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -1474,10 +1474,6 @@ struct d3dbc_compiler - struct vkd3d_bytecode_buffer buffer; - struct vkd3d_shader_message_context *message_context; - bool failed; -- -- /* OBJECTIVE: Store all the required information in the other fields so -- * that this hlsl_ctx is no longer necessary. */ -- struct hlsl_ctx *ctx; - }; - - static uint32_t sm1_version(enum vkd3d_shader_type type, unsigned int major, unsigned int minor) -@@ -2162,6 +2158,7 @@ static void d3dbc_write_vsir_simple_instruction(struct d3dbc_compiler *d3dbc, - return; - - instr.opcode = info->sm1_opcode; -+ instr.flags = ins->flags; - instr.has_dst = info->dst_count; - instr.src_count = info->src_count; - -@@ -2195,7 +2192,10 @@ static void d3dbc_write_vsir_instruction(struct d3dbc_compiler *d3dbc, const str - case VKD3DSIH_DP4: - case VKD3DSIH_DSX: - case VKD3DSIH_DSY: -+ case VKD3DSIH_ELSE: -+ case VKD3DSIH_ENDIF: - case VKD3DSIH_FRC: -+ case VKD3DSIH_IFC: - case VKD3DSIH_MAD: - case VKD3DSIH_MAX: - case VKD3DSIH_MIN: -@@ -2299,105 +2299,24 @@ static void d3dbc_write_semantic_dcls(struct d3dbc_compiler *d3dbc) - } - } - --static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block); -- --static void d3dbc_write_if(struct d3dbc_compiler *d3dbc, const struct hlsl_ir_node *instr) --{ -- const struct hlsl_ir_if *iff = hlsl_ir_if(instr); -- const struct hlsl_ir_node *condition; -- struct sm1_instruction sm1_ifc, sm1_else, sm1_endif; -- -- condition = iff->condition.node; -- VKD3D_ASSERT(condition->data_type->dimx == 1 && condition->data_type->dimy == 1); -- -- sm1_ifc = (struct sm1_instruction) -- { -- .opcode = VKD3D_SM1_OP_IFC, -- .flags = VKD3D_SHADER_REL_OP_NE, /* Make it a "if_ne" instruction. */ -- -- .srcs[0].type = VKD3DSPR_TEMP, -- .srcs[0].swizzle = hlsl_swizzle_from_writemask(condition->reg.writemask), -- .srcs[0].reg = condition->reg.id, -- .srcs[0].mod = 0, -- -- .srcs[1].type = VKD3DSPR_TEMP, -- .srcs[1].swizzle = hlsl_swizzle_from_writemask(condition->reg.writemask), -- .srcs[1].reg = condition->reg.id, -- .srcs[1].mod = VKD3DSPSM_NEG, -- -- .src_count = 2, -- }; -- d3dbc_write_instruction(d3dbc, &sm1_ifc); -- d3dbc_write_block(d3dbc, &iff->then_block); -- -- if (!list_empty(&iff->else_block.instrs)) -- { -- sm1_else = (struct sm1_instruction){.opcode = VKD3D_SM1_OP_ELSE}; -- d3dbc_write_instruction(d3dbc, &sm1_else); -- d3dbc_write_block(d3dbc, &iff->else_block); -- } -- -- sm1_endif = (struct sm1_instruction){.opcode = VKD3D_SM1_OP_ENDIF}; -- d3dbc_write_instruction(d3dbc, &sm1_endif); --} -- --static void d3dbc_write_block(struct d3dbc_compiler *d3dbc, const struct hlsl_block *block) -+static void d3dbc_write_program_instructions(struct d3dbc_compiler *d3dbc) - { -- struct vkd3d_shader_instruction *vsir_instr; -- struct hlsl_ctx *ctx = d3dbc->ctx; -- const struct hlsl_ir_node *instr; -- unsigned int vsir_instr_idx; -- -- LIST_FOR_EACH_ENTRY(instr, &block->instrs, struct hlsl_ir_node, entry) -- { -- if (instr->data_type) -- { -- if (instr->data_type->class != HLSL_CLASS_SCALAR && instr->data_type->class != HLSL_CLASS_VECTOR) -- { -- hlsl_fixme(ctx, &instr->loc, "Class %#x should have been lowered or removed.", instr->data_type->class); -- break; -- } -- } -- -- switch (instr->type) -- { -- case HLSL_IR_CALL: -- vkd3d_unreachable(); -- -- case HLSL_IR_IF: -- if (hlsl_version_ge(ctx, 2, 1)) -- d3dbc_write_if(d3dbc, instr); -- else -- hlsl_fixme(ctx, &instr->loc, "Flatten \"if\" conditionals branches."); -- break; -- -- case HLSL_IR_VSIR_INSTRUCTION_REF: -- vsir_instr_idx = hlsl_ir_vsir_instruction_ref(instr)->vsir_instr_idx; -- vsir_instr = &d3dbc->program->instructions.elements[vsir_instr_idx]; -- d3dbc_write_vsir_instruction(d3dbc, vsir_instr); -- break; -+ struct vsir_program *program = d3dbc->program; -+ unsigned int i; - -- default: -- hlsl_fixme(ctx, &instr->loc, "Instruction type %s.", hlsl_node_type_to_string(instr->type)); -- } -- } -+ for (i = 0; i < program->instructions.count; ++i) -+ d3dbc_write_vsir_instruction(d3dbc, &program->instructions.elements[i]); - } - --/* OBJECTIVE: Stop relying on ctx and entry_func on this function, receiving -- * data from the other parameters instead, so it can be removed as an argument -- * and be declared in vkd3d_shader_private.h and used without relying on HLSL -- * IR structs. */ - int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_code *ctab, -- struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context, -- struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) -+ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) - { - const struct vkd3d_shader_version *version = &program->shader_version; - struct d3dbc_compiler d3dbc = {0}; - struct vkd3d_bytecode_buffer *buffer = &d3dbc.buffer; - int result; - -- d3dbc.ctx = ctx; - d3dbc.program = program; - d3dbc.message_context = message_context; - switch (version->type) -@@ -2421,11 +2340,11 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, - bytecode_put_bytes(buffer, ctab->code, ctab->size); - - d3dbc_write_semantic_dcls(&d3dbc); -- d3dbc_write_block(&d3dbc, &entry_func->body); -+ d3dbc_write_program_instructions(&d3dbc); - - put_u32(buffer, VKD3D_SM1_OP_END); - -- result = ctx->result; -+ result = VKD3D_OK; - if (buffer->status) - result = buffer->status; - if (d3dbc.failed) -diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c -index 2c2e486aa0e..1314bc09e73 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/fx.c -+++ b/libs/vkd3d/libs/vkd3d-shader/fx.c -@@ -570,6 +570,9 @@ static const char * get_fx_4_type_name(const struct hlsl_type *type) - case HLSL_CLASS_VERTEX_SHADER: - return "VertexShader"; - -+ case HLSL_CLASS_GEOMETRY_SHADER: -+ return "GeometryShader"; -+ - case HLSL_CLASS_PIXEL_SHADER: - return "PixelShader"; - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -index 6f737be2e2a..6323260eab7 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c -@@ -969,6 +969,7 @@ static const char * get_case_insensitive_typename(const char *name) - { - "dword", - "float", -+ "geometryshader", - "matrix", - "pixelshader", - "texture", -@@ -1679,22 +1680,6 @@ struct hlsl_ir_node *hlsl_new_switch(struct hlsl_ctx *ctx, struct hlsl_ir_node * - return &s->node; - } - --struct hlsl_ir_node *hlsl_new_vsir_instruction_ref(struct hlsl_ctx *ctx, unsigned int vsir_instr_idx, -- struct hlsl_type *type, const struct hlsl_reg *reg, const struct vkd3d_shader_location *loc) --{ -- struct hlsl_ir_vsir_instruction_ref *vsir_instr; -- -- if (!(vsir_instr = hlsl_alloc(ctx, sizeof(*vsir_instr)))) -- return NULL; -- init_node(&vsir_instr->node, HLSL_IR_VSIR_INSTRUCTION_REF, type, loc); -- vsir_instr->vsir_instr_idx = vsir_instr_idx; -- -- if (reg) -- vsir_instr->node.reg = *reg; -- -- return &vsir_instr->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) - { -@@ -1847,30 +1832,40 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned - return &swizzle->node; - } - --struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name, -- struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs, -- const struct vkd3d_shader_location *loc) -+struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, -+ const char *profile_name, struct hlsl_ir_node **args, unsigned int args_count, -+ struct hlsl_block *args_instrs, const struct vkd3d_shader_location *loc) - { - const struct hlsl_profile_info *profile_info = NULL; - struct hlsl_ir_compile *compile; - struct hlsl_type *type = NULL; - unsigned int i; - -- if (!(profile_info = hlsl_get_target_info(profile_name))) -+ switch (compile_type) - { -- hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Unknown profile \"%s\".", profile_name); -- return NULL; -- } -+ case HLSL_COMPILE_TYPE_COMPILE: -+ if (!(profile_info = hlsl_get_target_info(profile_name))) -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Unknown profile \"%s\".", profile_name); -+ return NULL; -+ } - -- if (profile_info->type == VKD3D_SHADER_TYPE_PIXEL) -- type = hlsl_get_type(ctx->cur_scope, "PixelShader", true, true); -- else if (profile_info->type == VKD3D_SHADER_TYPE_VERTEX) -- type = hlsl_get_type(ctx->cur_scope, "VertexShader", true, true); -+ if (profile_info->type == VKD3D_SHADER_TYPE_PIXEL) -+ type = hlsl_get_type(ctx->cur_scope, "PixelShader", true, true); -+ else if (profile_info->type == VKD3D_SHADER_TYPE_VERTEX) -+ type = hlsl_get_type(ctx->cur_scope, "VertexShader", true, true); - -- if (!type) -- { -- hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile_name); -- return NULL; -+ if (!type) -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile_name); -+ return NULL; -+ } -+ -+ break; -+ -+ case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: -+ type = hlsl_get_type(ctx->cur_scope, "GeometryShader", true, true); -+ break; - } - - if (!(compile = hlsl_alloc(ctx, sizeof(*compile)))) -@@ -1878,6 +1873,7 @@ struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_ - - init_node(&compile->node, HLSL_IR_COMPILE, type, loc); - -+ compile->compile_type = compile_type; - compile->profile = profile_info; - - hlsl_block_init(&compile->instrs); -@@ -2271,7 +2267,8 @@ static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, - if (compile->profile) - profile_name = compile->profile->name; - -- if (!(node = hlsl_new_compile(ctx, profile_name, args, compile->args_count, &block, &compile->node.loc))) -+ if (!(node = hlsl_new_compile(ctx, compile->compile_type, profile_name, -+ args, compile->args_count, &block, &compile->node.loc))) - { - hlsl_block_cleanup(&block); - vkd3d_free(args); -@@ -2429,9 +2426,6 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, - - case HLSL_IR_STATEBLOCK_CONSTANT: - return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); -- -- case HLSL_IR_VSIR_INSTRUCTION_REF: -- vkd3d_unreachable(); - } - - vkd3d_unreachable(); -@@ -2847,7 +2841,6 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) - - [HLSL_IR_COMPILE] = "HLSL_IR_COMPILE", - [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", -- [HLSL_IR_VSIR_INSTRUCTION_REF] = "HLSL_IR_VSIR_INSTRUCTION_REF", - }; - - if (type >= ARRAY_SIZE(names)) -@@ -3300,7 +3293,16 @@ static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *bu - { - unsigned int i; - -- vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name); -+ switch (compile->compile_type) -+ { -+ case HLSL_COMPILE_TYPE_COMPILE: -+ vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name); -+ break; -+ -+ case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: -+ vkd3d_string_buffer_printf(buffer, "ConstructGSWithSO {\n"); -+ break; -+ } - - dump_block(ctx, buffer, &compile->instrs); - -@@ -3420,11 +3422,6 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, - case HLSL_IR_STATEBLOCK_CONSTANT: - dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); - break; -- -- case HLSL_IR_VSIR_INSTRUCTION_REF: -- vkd3d_string_buffer_printf(buffer, "vsir_program instruction %u", -- hlsl_ir_vsir_instruction_ref(instr)->vsir_instr_idx); -- break; - } - } - -@@ -3722,10 +3719,6 @@ void hlsl_free_instr(struct hlsl_ir_node *node) - case HLSL_IR_STATEBLOCK_CONSTANT: - free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node)); - break; -- -- case HLSL_IR_VSIR_INSTRUCTION_REF: -- vkd3d_free(hlsl_ir_vsir_instruction_ref(node)); -- break; - } - } - -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -index eece693b48c..20a96692a48 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h -@@ -326,8 +326,6 @@ enum hlsl_ir_node_type - - HLSL_IR_COMPILE, - HLSL_IR_STATEBLOCK_CONSTANT, -- -- HLSL_IR_VSIR_INSTRUCTION_REF, - }; - - /* Common data for every type of IR instruction node. */ -@@ -875,14 +873,22 @@ struct hlsl_ir_compile - { - struct hlsl_ir_node node; - -- /* Special field to store the profile argument. */ -+ enum hlsl_compile_type -+ { -+ /* A shader compilation through the CompileShader() function or the "compile" syntax. */ -+ HLSL_COMPILE_TYPE_COMPILE, -+ /* A call to ConstructGSWithSO(), which receives a geometry shader and retrieves one as well. */ -+ HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO, -+ } compile_type; -+ -+ /* Special field to store the profile argument for HLSL_COMPILE_TYPE_COMPILE. */ - const struct hlsl_profile_info *profile; - - /* Block containing the instructions required by the arguments of the - * compilation call. */ - struct hlsl_block instrs; - -- /* Arguments to the compilation call. For a "compile" or "CompileShader()" -+ /* Arguments to the compilation call. For HLSL_COMPILE_TYPE_COMPILE - * args[0] is an hlsl_ir_call to the specified function. */ - struct hlsl_src *args; - unsigned int args_count; -@@ -896,16 +902,6 @@ struct hlsl_ir_stateblock_constant - char *name; - }; - --/* A vkd3d_shader_instruction that can be inserted in a hlsl_block. -- * Only used for the HLSL IR to vsir translation, might be removed once this translation is complete. */ --struct hlsl_ir_vsir_instruction_ref --{ -- struct hlsl_ir_node node; -- -- /* Index to a vkd3d_shader_instruction within a vkd3d_shader_instruction_array in a vsir_program. */ -- unsigned int vsir_instr_idx; --}; -- - struct hlsl_scope - { - /* Item entry for hlsl_ctx.scopes. */ -@@ -1212,12 +1208,6 @@ static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(co - return CONTAINING_RECORD(node, struct hlsl_ir_stateblock_constant, node); - } - --static inline struct hlsl_ir_vsir_instruction_ref *hlsl_ir_vsir_instruction_ref(const struct hlsl_ir_node *node) --{ -- VKD3D_ASSERT(node->type == HLSL_IR_VSIR_INSTRUCTION_REF); -- return CONTAINING_RECORD(node, struct hlsl_ir_vsir_instruction_ref, node); --} -- - static inline void hlsl_block_init(struct hlsl_block *block) - { - list_init(&block->instrs); -@@ -1491,9 +1481,9 @@ bool hlsl_index_is_noncontiguous(struct hlsl_ir_index *index); - bool hlsl_index_is_resource_access(struct hlsl_ir_index *index); - bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index); - --struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name, -- struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs, -- const struct vkd3d_shader_location *loc); -+struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, -+ const char *profile_name, struct hlsl_ir_node **args, unsigned int args_count, -+ struct hlsl_block *args_instrs, const struct vkd3d_shader_location *loc); - struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val, - struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); - struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, -@@ -1532,9 +1522,6 @@ struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned - 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_node *hlsl_new_vsir_instruction_ref(struct hlsl_ctx *ctx, unsigned int vsir_instr_idx, -- struct hlsl_type *type, const struct hlsl_reg *reg, 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); - void hlsl_fixme(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc, -@@ -1603,8 +1590,7 @@ bool hlsl_sm1_usage_from_semantic(const char *semantic_name, - void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer); - int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, - const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_code *ctab, -- struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context, -- struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func); -+ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); - - bool sysval_semantic_from_hlsl(enum vkd3d_shader_sysval_semantic *semantic, - struct hlsl_ctx *ctx, const struct hlsl_semantic *hlsl_semantic, bool output); -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.l b/libs/vkd3d/libs/vkd3d-shader/hlsl.l -index e5472709a8c..b7c242661e3 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.l -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.l -@@ -82,6 +82,7 @@ ComputeShader {return KW_COMPUTESHADER; } - compile {return KW_COMPILE; } - CompileShader {return KW_COMPILESHADER; } - const {return KW_CONST; } -+ConstructGSWithSO {return KW_CONSTRUCTGSWITHSO; } - continue {return KW_CONTINUE; } - DepthStencilState {return KW_DEPTHSTENCILSTATE; } - DepthStencilView {return KW_DEPTHSTENCILVIEW; } -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -index 60e196c63cc..67262c2ccfd 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y -@@ -609,6 +609,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx - { - switch (node->type) - { -+ case HLSL_IR_COMPILE: - case HLSL_IR_CONSTANT: - case HLSL_IR_EXPR: - case HLSL_IR_STRING_CONSTANT: -@@ -627,13 +628,10 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx - case HLSL_IR_RESOURCE_LOAD: - case HLSL_IR_RESOURCE_STORE: - case HLSL_IR_SWITCH: -- case HLSL_IR_COMPILE: - case HLSL_IR_STATEBLOCK_CONSTANT: - hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, - "Expected literal expression."); - break; -- case HLSL_IR_VSIR_INSTRUCTION_REF: -- vkd3d_unreachable(); - } - } - -@@ -1227,7 +1225,8 @@ static bool add_typedef(struct hlsl_ctx *ctx, struct hlsl_type *const orig_type, - } - - static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs, -- struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src); -+ struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src, -+ bool is_default_values_initializer); - - static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters *parameters, - struct parse_parameter *param, const struct vkd3d_shader_location *loc) -@@ -1285,7 +1284,8 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters - - for (i = 0; i < param->initializer.args_count; ++i) - { -- initialize_var_components(ctx, param->initializer.instrs, var, &store_index, param->initializer.args[i]); -+ initialize_var_components(ctx, param->initializer.instrs, var, -+ &store_index, param->initializer.args[i], true); - } - - free_parse_initializer(¶m->initializer); -@@ -2368,7 +2368,8 @@ static unsigned int get_component_index_from_default_initializer_index(struct hl - } - - static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *instrs, -- struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src) -+ struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src, -+ bool is_default_values_initializer) - { - unsigned int src_comp_count = hlsl_type_component_count(src->data_type); - struct hlsl_deref dst_deref; -@@ -2387,23 +2388,43 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i - - dst_comp_type = hlsl_type_get_component_type(ctx, dst->data_type, *store_index); - -- if (dst->default_values) -+ if (is_default_values_initializer) - { - struct hlsl_default_value default_value = {0}; - unsigned int dst_index; - -- if (!hlsl_clone_block(ctx, &block, instrs)) -- return; -- default_value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); -+ if (hlsl_is_numeric_type(dst_comp_type)) -+ { -+ if (src->type == HLSL_IR_COMPILE) -+ { -+ /* Default values are discarded if they contain an object -+ * literal expression for a numeric component. */ -+ if (dst->default_values) -+ { -+ hlsl_warning(ctx, &src->loc, VKD3D_SHADER_WARNING_HLSL_IGNORED_DEFAULT_VALUE, -+ "Component %u in variable '%s' initializer is object literal. Default values discarded.", -+ k, dst->name); -+ vkd3d_free(dst->default_values); -+ dst->default_values = NULL; -+ } -+ } -+ else -+ { -+ if (!hlsl_clone_block(ctx, &block, instrs)) -+ return; -+ default_value = evaluate_static_expression(ctx, &block, dst_comp_type, &src->loc); - -- if (dst->is_param) -- dst_index = *store_index; -- else -- dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index); -+ if (dst->is_param) -+ dst_index = *store_index; -+ else -+ dst_index = get_component_index_from_default_initializer_index(ctx, dst->data_type, *store_index); - -- dst->default_values[dst_index] = default_value; -+ if (dst->default_values) -+ dst->default_values[dst_index] = default_value; - -- hlsl_block_cleanup(&block); -+ hlsl_block_cleanup(&block); -+ } -+ } - } - else - { -@@ -2793,7 +2814,8 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var - - for (k = 0; k < v->initializer.args_count; ++k) - { -- initialize_var_components(ctx, v->initializer.instrs, var, &store_index, v->initializer.args[k]); -+ initialize_var_components(ctx, v->initializer.instrs, var, -+ &store_index, v->initializer.args[k], is_default_values_initializer); - } - - if (is_default_values_initializer) -@@ -4785,17 +4807,17 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer * - if (!(var = hlsl_new_synthetic_var(ctx, "coords", hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 2), loc))) - return false; - -- initialize_var_components(ctx, params->instrs, var, &idx, coords); -+ initialize_var_components(ctx, params->instrs, var, &idx, coords, false); - if (hlsl_version_ge(ctx, 4, 0)) - { - if (!(half = hlsl_new_float_constant(ctx, 0.5f, loc))) - return false; - hlsl_block_add_instr(params->instrs, half); - -- initialize_var_components(ctx, params->instrs, var, &idx, half); -+ initialize_var_components(ctx, params->instrs, var, &idx, half, false); - } - else -- initialize_var_components(ctx, params->instrs, var, &idx, coords); -+ initialize_var_components(ctx, params->instrs, var, &idx, coords, false); - - if (!(load = hlsl_new_var_load(ctx, var, loc))) - return false; -@@ -5224,7 +5246,38 @@ static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const cha - return NULL; - } - -- if (!(compile = hlsl_new_compile(ctx, profile_name, &call_to_compile, 1, args->instrs, loc))) -+ if (!(compile = hlsl_new_compile(ctx, HLSL_COMPILE_TYPE_COMPILE, -+ profile_name, &call_to_compile, 1, args->instrs, loc))) -+ { -+ free_parse_initializer(args); -+ return NULL; -+ } -+ -+ free_parse_initializer(args); -+ return make_block(ctx, compile); -+} -+ -+static struct hlsl_block *add_compile_variant(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, -+ struct parse_initializer *args, const struct vkd3d_shader_location *loc) -+{ -+ struct hlsl_ir_node *compile; -+ -+ switch (compile_type) -+ { -+ case HLSL_COMPILE_TYPE_COMPILE: -+ vkd3d_unreachable(); -+ -+ case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: -+ if (args->args_count != 2 && args->args_count != 6) -+ { -+ hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_WRONG_PARAMETER_COUNT, -+ "Wrong number of arguments to ConstructGSWithSO: expected 2 or 6, but got %u.", -+ args->args_count); -+ } -+ break; -+ } -+ -+ if (!(compile = hlsl_new_compile(ctx, compile_type, NULL, args->args, args->args_count, args->instrs, loc))) - { - free_parse_initializer(args); - return NULL; -@@ -5245,7 +5298,7 @@ static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type - return NULL; - - for (i = 0; i < params->args_count; ++i) -- initialize_var_components(ctx, params->instrs, var, &idx, params->args[i]); -+ initialize_var_components(ctx, params->instrs, var, &idx, params->args[i], false); - - if (!(load = hlsl_new_var_load(ctx, var, loc))) - return NULL; -@@ -6235,6 +6288,7 @@ static bool state_block_add_entry(struct hlsl_state_block *state_block, struct h - %token KW_COMPILESHADER - %token KW_COMPUTESHADER - %token KW_CONST -+%token KW_CONSTRUCTGSWITHSO - %token KW_CONTINUE - %token KW_DEFAULT - %token KW_DEPTHSTENCILSTATE -@@ -7796,6 +7850,11 @@ stateblock_lhs_identifier: - if (!($$ = hlsl_strdup(ctx, "vertexshader"))) - YYABORT; - } -+ | KW_GEOMETRYSHADER -+ { -+ if (!($$ = hlsl_strdup(ctx, "geometryshader"))) -+ YYABORT; -+ } - - state_block_index_opt: - %empty -@@ -8590,6 +8649,11 @@ primary_expr: - vkd3d_free($3); - vkd3d_free($5); - } -+ | KW_CONSTRUCTGSWITHSO '(' func_arguments ')' -+ { -+ if (!($$ = add_compile_variant(ctx, HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO, &$3, &@1))) -+ YYABORT; -+ } - | var_identifier '(' func_arguments ')' - { - if (!($$ = add_call(ctx, $1, &$3, &@1))) -diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -index 93f19360953..6cae0e3b5c9 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c -@@ -4089,9 +4089,6 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) - case HLSL_IR_STATEBLOCK_CONSTANT: - /* Stateblock constants should not appear in the shader program. */ - vkd3d_unreachable(); -- case HLSL_IR_VSIR_INSTRUCTION_REF: -- /* HLSL IR nodes are not translated to hlsl_ir_vsir_instruction_ref at this point. */ -- vkd3d_unreachable(); - } - - return false; -@@ -4217,9 +4214,6 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop - case HLSL_IR_STATEBLOCK_CONSTANT: - /* Stateblock constants should not appear in the shader program. */ - vkd3d_unreachable(); -- case HLSL_IR_VSIR_INSTRUCTION_REF: -- /* HLSL IR nodes are not translated to hlsl_ir_vsir_instruction_ref at this point. */ -- vkd3d_unreachable(); - - case HLSL_IR_STORE: - { -@@ -6312,7 +6306,6 @@ static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, struct vsir_pr - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - unsigned int i, x; - - for (i = 0; i < ctx->constant_defs.count; ++i) -@@ -6349,14 +6342,6 @@ static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, struct vsir_pr - for (x = 0; x < 4; ++x) - src_param->reg.u.immconst_f32[x] = constant_reg->value.f[x]; - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, NULL, -- &constant_reg->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- hlsl_block_add_instr(block, vsir_instr); - } - } - -@@ -6370,7 +6355,6 @@ static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx, - struct vkd3d_shader_semantic *semantic; - struct vkd3d_shader_instruction *ins; - enum hlsl_sampler_dim sampler_dim; -- struct hlsl_ir_node *vsir_instr; - struct hlsl_ir_var *var; - unsigned int i, count; - -@@ -6435,14 +6419,6 @@ static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx, - range = &semantic->resource.range; - range->space = 0; - range->first = range->last = dst_param->reg.idx[0].offset; -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, -- NULL, &var->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- hlsl_block_add_instr(block, vsir_instr); - } - } - } -@@ -6474,12 +6450,10 @@ static struct vkd3d_shader_instruction *generate_vsir_add_program_instruction( - static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, - struct vsir_program *program, struct hlsl_ir_constant *constant) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *instr = &constant->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - - VKD3D_ASSERT(instr->reg.allocated); - VKD3D_ASSERT(constant->reg.allocated); -@@ -6496,16 +6470,6 @@ static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, - vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); - dst_param->reg.idx[0].offset = instr->reg.id; - dst_param->write_mask = instr->reg.writemask; -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, -- instr->data_type, &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - /* Translate ops that can be mapped to a single vsir instruction with only one dst register. */ -@@ -6513,12 +6477,10 @@ static void sm1_generate_vsir_instr_expr_single_instr_op(struct hlsl_ctx *ctx, s - struct hlsl_ir_expr *expr, enum vkd3d_shader_opcode opcode, uint32_t src_mod, uint32_t dst_mod, - bool map_src_swizzles) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - unsigned int i, src_count = 0; - - VKD3D_ASSERT(instr->reg.allocated); -@@ -6550,16 +6512,6 @@ static void sm1_generate_vsir_instr_expr_single_instr_op(struct hlsl_ctx *ctx, s - map_src_swizzles ? dst_param->write_mask : VKD3DSP_WRITEMASK_ALL); - src_param->modifiers = src_mod; - } -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -- &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - /* Translate ops that have 1 src and need one instruction for each component in -@@ -6567,12 +6519,10 @@ static void sm1_generate_vsir_instr_expr_single_instr_op(struct hlsl_ctx *ctx, s - static void sm1_generate_vsir_instr_expr_per_component_instr_op(struct hlsl_ctx *ctx, - struct vsir_program *program, struct hlsl_ir_expr *expr, enum vkd3d_shader_opcode opcode) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *operand = expr->operands[0].node; - struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; -- struct hlsl_ir_node *vsir_instr = NULL; - struct vkd3d_shader_instruction *ins; - uint32_t src_swizzle; - unsigned int i, c; -@@ -6598,52 +6548,18 @@ static void sm1_generate_vsir_instr_expr_per_component_instr_op(struct hlsl_ctx - src_param->reg.idx[0].offset = operand->reg.id; - c = vsir_swizzle_get_component(src_swizzle, i); - src_param->swizzle = vsir_swizzle_from_writemask(1u << c); -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, -- hlsl_get_scalar_type(ctx, instr->data_type->e.numeric.type), -- &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- list_add_before(&instr->entry, &vsir_instr->entry); - } - } -- -- /* Replace expr with a no-op move. For the other instructions that reference it. */ -- if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) -- return; -- -- dst_param = &ins->dst[0]; -- vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -- dst_param->reg.idx[0].offset = instr->reg.id; -- dst_param->write_mask = instr->reg.writemask; -- -- src_param = &ins->src[0]; -- vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -- src_param->reg.idx[0].offset = instr->reg.id; -- src_param->swizzle = sm1_generate_vsir_get_src_swizzle(instr->reg.writemask, dst_param->write_mask); -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -- &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - static void sm1_generate_vsir_instr_expr_sincos(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_ir_expr *expr) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *operand = expr->operands[0].node; - struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - unsigned int src_count = 0; - - VKD3D_ASSERT(instr->reg.allocated); -@@ -6674,16 +6590,6 @@ static void sm1_generate_vsir_instr_expr_sincos(struct hlsl_ctx *ctx, struct vsi - src_param->reg.idx[0].offset = ctx->d3dsincosconst2.id; - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; - } -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -- &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - static bool sm1_generate_vsir_instr_expr_cast(struct hlsl_ctx *ctx, -@@ -6898,6 +6804,7 @@ static bool sm1_generate_vsir_instr_expr(struct hlsl_ctx *ctx, struct vsir_progr - break; - - default: -+ hlsl_fixme(ctx, &instr->loc, "SM1 \"%s\" expression.", debug_hlsl_expr_op(expr->op)); - return false; - } - -@@ -7018,11 +6925,9 @@ static void sm1_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx, - static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_ir_load *load) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *instr = &load->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - - VKD3D_ASSERT(instr->reg.allocated); - -@@ -7036,22 +6941,11 @@ static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_progr - - sm1_generate_vsir_init_src_param_from_deref(ctx, &ins->src[0], &load->src, dst_param->write_mask, - &ins->location); -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -- &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - static void sm1_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, - struct vsir_program *program, struct hlsl_ir_resource_load *load) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *coords = load->coords.node; - struct hlsl_ir_node *ddx = load->ddx.node; - struct hlsl_ir_node *ddy = load->ddy.node; -@@ -7059,7 +6953,6 @@ static void sm1_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - enum vkd3d_shader_opcode opcode; - unsigned int src_count = 2; - uint32_t flags = 0; -@@ -7121,27 +7014,15 @@ static void sm1_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, - src_param->reg.idx[0].offset = ddy->reg.id; - src_param->swizzle = sm1_generate_vsir_get_src_swizzle(ddy->reg.writemask, VKD3DSP_WRITEMASK_ALL); - } -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -- &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - static void sm1_generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_ir_swizzle *swizzle_instr) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *instr = &swizzle_instr->node, *val = swizzle_instr->val.node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - uint32_t swizzle; - - VKD3D_ASSERT(instr->reg.allocated); -@@ -7163,27 +7044,15 @@ static void sm1_generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, struct vsir_pr - vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); - src_param->reg.idx[0].offset = val->reg.id; - src_param->swizzle = swizzle; -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, instr->data_type, -- &instr->reg, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_ir_store *store) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *rhs = store->rhs.node; - struct hlsl_ir_node *instr = &store->node; - struct vkd3d_shader_instruction *ins; - struct vkd3d_shader_src_param *src_param; -- struct hlsl_ir_node *vsir_instr; - - if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_MOV, 1, 1))) - return; -@@ -7194,26 +7063,15 @@ static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_prog - vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); - src_param->reg.idx[0].offset = rhs->reg.id; - src_param->swizzle = sm1_generate_vsir_get_src_swizzle(rhs->reg.writemask, ins->dst[0].write_mask); -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, instructions->count - 1, NULL, NULL, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - - static void sm1_generate_vsir_instr_jump(struct hlsl_ctx *ctx, - struct vsir_program *program, struct hlsl_ir_jump *jump) - { -- struct vkd3d_shader_instruction_array *instructions = &program->instructions; - struct hlsl_ir_node *condition = jump->condition.node; - struct hlsl_ir_node *instr = &jump->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_instruction *ins; -- struct hlsl_ir_node *vsir_instr; - - if (jump->type == HLSL_IR_JUMP_DISCARD_NEG) - { -@@ -7224,16 +7082,6 @@ static void sm1_generate_vsir_instr_jump(struct hlsl_ctx *ctx, - vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); - dst_param->reg.idx[0].offset = condition->reg.id; - dst_param->write_mask = condition->reg.writemask; -- -- if (!(vsir_instr = hlsl_new_vsir_instruction_ref(ctx, -- instructions->count - 1, instr->data_type, NULL, &instr->loc))) -- { -- ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; -- return; -- } -- -- list_add_before(&instr->entry, &vsir_instr->entry); -- hlsl_replace_node(instr, vsir_instr); - } - else - { -@@ -7241,44 +7089,110 @@ static void sm1_generate_vsir_instr_jump(struct hlsl_ctx *ctx, - } - } - --static bool sm1_generate_vsir_instr(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) -+static void sm1_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *block, struct vsir_program *program); -+ -+static void sm1_generate_vsir_instr_if(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_if *iff) - { -- struct vsir_program *program = context; -+ struct hlsl_ir_node *condition = iff->condition.node; -+ struct vkd3d_shader_src_param *src_param; -+ struct hlsl_ir_node *instr = &iff->node; -+ struct vkd3d_shader_instruction *ins; -+ uint32_t swizzle; - -- switch (instr->type) -+ if (hlsl_version_lt(ctx, 2, 1)) - { -- case HLSL_IR_CONSTANT: -- sm1_generate_vsir_instr_constant(ctx, program, hlsl_ir_constant(instr)); -- return true; -+ hlsl_fixme(ctx, &instr->loc, "Flatten \"if\" conditionals branches."); -+ return; -+ } -+ VKD3D_ASSERT(condition->data_type->dimx == 1 && condition->data_type->dimy == 1); - -- case HLSL_IR_EXPR: -- return sm1_generate_vsir_instr_expr(ctx, program, hlsl_ir_expr(instr)); -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_IFC, 0, 2))) -+ return; -+ ins->flags = VKD3D_SHADER_REL_OP_NE; - -- case HLSL_IR_JUMP: -- sm1_generate_vsir_instr_jump(ctx, program, hlsl_ir_jump(instr)); -- return true; -+ swizzle = hlsl_swizzle_from_writemask(condition->reg.writemask); -+ swizzle = vsir_swizzle_from_hlsl(swizzle); - -- case HLSL_IR_LOAD: -- sm1_generate_vsir_instr_load(ctx, program, hlsl_ir_load(instr)); -- return true; -+ src_param = &ins->src[0]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = condition->reg.id; -+ src_param->swizzle = swizzle; -+ src_param->modifiers = 0; - -- case HLSL_IR_RESOURCE_LOAD: -- sm1_generate_vsir_instr_resource_load(ctx, program, hlsl_ir_resource_load(instr)); -- return true; -+ src_param = &ins->src[1]; -+ vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src_param->reg.idx[0].offset = condition->reg.id; -+ src_param->swizzle = swizzle; -+ src_param->modifiers = VKD3DSPSM_NEG; - -- case HLSL_IR_STORE: -- sm1_generate_vsir_instr_store(ctx, program, hlsl_ir_store(instr)); -- return true; -+ sm1_generate_vsir_block(ctx, &iff->then_block, program); - -- case HLSL_IR_SWIZZLE: -- sm1_generate_vsir_instr_swizzle(ctx, program, hlsl_ir_swizzle(instr)); -- return true; -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_ELSE, 0, 0))) -+ return; - -- default: -- break; -- } -+ sm1_generate_vsir_block(ctx, &iff->else_block, program); - -- return false; -+ if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VKD3DSIH_ENDIF, 0, 0))) -+ return; -+} -+ -+static void sm1_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *block, struct vsir_program *program) -+{ -+ struct hlsl_ir_node *instr, *next; -+ -+ LIST_FOR_EACH_ENTRY_SAFE(instr, next, &block->instrs, struct hlsl_ir_node, entry) -+ { -+ if (instr->data_type) -+ { -+ if (instr->data_type->class != HLSL_CLASS_SCALAR && instr->data_type->class != HLSL_CLASS_VECTOR) -+ { -+ hlsl_fixme(ctx, &instr->loc, "Class %#x should have been lowered or removed.", instr->data_type->class); -+ break; -+ } -+ } -+ -+ switch (instr->type) -+ { -+ case HLSL_IR_CALL: -+ vkd3d_unreachable(); -+ -+ case HLSL_IR_CONSTANT: -+ sm1_generate_vsir_instr_constant(ctx, program, hlsl_ir_constant(instr)); -+ break; -+ -+ case HLSL_IR_EXPR: -+ sm1_generate_vsir_instr_expr(ctx, program, hlsl_ir_expr(instr)); -+ break; -+ -+ case HLSL_IR_IF: -+ sm1_generate_vsir_instr_if(ctx, program, hlsl_ir_if(instr)); -+ break; -+ -+ case HLSL_IR_JUMP: -+ sm1_generate_vsir_instr_jump(ctx, program, hlsl_ir_jump(instr)); -+ break; -+ -+ case HLSL_IR_LOAD: -+ sm1_generate_vsir_instr_load(ctx, program, hlsl_ir_load(instr)); -+ break; -+ -+ case HLSL_IR_RESOURCE_LOAD: -+ sm1_generate_vsir_instr_resource_load(ctx, program, hlsl_ir_resource_load(instr)); -+ break; -+ -+ case HLSL_IR_STORE: -+ sm1_generate_vsir_instr_store(ctx, program, hlsl_ir_store(instr)); -+ break; -+ -+ case HLSL_IR_SWIZZLE: -+ sm1_generate_vsir_instr_swizzle(ctx, program, hlsl_ir_swizzle(instr)); -+ break; -+ -+ default: -+ hlsl_fixme(ctx, &instr->loc, "Instruction type %s.", hlsl_node_type_to_string(instr->type)); -+ break; -+ } -+ } - } - - /* OBJECTIVE: Translate all the information from ctx and entry_func to the -@@ -7317,7 +7231,7 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl - sm1_generate_vsir_sampler_dcls(ctx, program, &block); - list_move_head(&entry_func->body.instrs, &block.instrs); - -- hlsl_transform_ir(ctx, sm1_generate_vsir_instr, &entry_func->body, program); -+ sm1_generate_vsir_block(ctx, &entry_func->body, program); - } - - static struct hlsl_ir_jump *loop_unrolling_find_jump(struct hlsl_block *block, struct hlsl_ir_node *stop_point, -@@ -7818,7 +7732,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry - return ctx->result; - } - -- result = d3dbc_compile(&program, config_flags, NULL, &ctab, out, ctx->message_context, ctx, entry_func); -+ result = d3dbc_compile(&program, config_flags, NULL, &ctab, out, ctx->message_context); - vsir_program_cleanup(&program); - vkd3d_shader_free_shader_code(&ctab); - return result; -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index 4b79a058b6f..1efb7106e71 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -127,23 +127,134 @@ const struct vkd3d_shader_parameter1 *vsir_program_get_parameter( - return NULL; - } - -+void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type, -+ enum vkd3d_data_type data_type, unsigned int idx_count) -+{ -+ reg->type = reg_type; -+ reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; -+ reg->non_uniform = false; -+ reg->data_type = data_type; -+ reg->idx[0].offset = ~0u; -+ reg->idx[0].rel_addr = NULL; -+ reg->idx[0].is_in_bounds = false; -+ reg->idx[1].offset = ~0u; -+ reg->idx[1].rel_addr = NULL; -+ reg->idx[1].is_in_bounds = false; -+ reg->idx[2].offset = ~0u; -+ reg->idx[2].rel_addr = NULL; -+ reg->idx[2].is_in_bounds = false; -+ reg->idx_count = idx_count; -+ reg->dimension = VSIR_DIMENSION_SCALAR; -+ reg->alignment = 0; -+} -+ - static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg) - { - return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; - } - --static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction) -+void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, -+ enum vkd3d_data_type data_type, unsigned int idx_count) - { -- enum vkd3d_shader_opcode opcode = instruction->opcode; -- return (VKD3DSIH_DCL <= opcode && opcode <= VKD3DSIH_DCL_VERTICES_OUT) -- || opcode == VKD3DSIH_HS_DECLS; -+ vsir_register_init(¶m->reg, reg_type, data_type, idx_count); -+ param->swizzle = 0; -+ param->modifiers = VKD3DSPSM_NONE; - } - --static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins) -+static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value) - { -- struct vkd3d_shader_location location = ins->location; -+ vsir_src_param_init(src, VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0); -+ src->reg.u.immconst_u32[0] = value; -+} - -- vsir_instruction_init(ins, &location, VKD3DSIH_NOP); -+void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) -+{ -+ vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UNUSED, 1); -+ param->reg.dimension = VSIR_DIMENSION_NONE; -+ param->reg.idx[0].offset = label_id; -+} -+ -+static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type) -+{ -+ vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1); -+ src->reg.idx[0].offset = idx; -+} -+ -+static void vsir_src_param_init_resource(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx) -+{ -+ vsir_src_param_init(src, VKD3DSPR_RESOURCE, VKD3D_DATA_RESOURCE, 2); -+ src->reg.idx[0].offset = id; -+ src->reg.idx[1].offset = idx; -+ src->reg.dimension = VSIR_DIMENSION_VEC4; -+ src->swizzle = VKD3D_SHADER_NO_SWIZZLE; -+} -+ -+static void vsir_src_param_init_sampler(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx) -+{ -+ vsir_src_param_init(src, VKD3DSPR_SAMPLER, VKD3D_DATA_SAMPLER, 2); -+ src->reg.idx[0].offset = id; -+ src->reg.idx[1].offset = idx; -+ src->reg.dimension = VSIR_DIMENSION_NONE; -+} -+ -+static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx) -+{ -+ vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); -+ src->reg.idx[0].offset = idx; -+} -+ -+static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx) -+{ -+ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); -+ src->reg.idx[0].offset = idx; -+} -+ -+static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsigned int idx) -+{ -+ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -+ src->reg.idx[0].offset = idx; -+} -+ -+static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) -+{ -+ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); -+ src->reg.idx[0].offset = idx; -+} -+ -+void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type, -+ enum vkd3d_data_type data_type, unsigned int idx_count) -+{ -+ vsir_register_init(¶m->reg, reg_type, data_type, idx_count); -+ param->write_mask = VKD3DSP_WRITEMASK_0; -+ param->modifiers = VKD3DSPDM_NONE; -+ param->shift = 0; -+} -+ -+static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) -+{ -+ vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); -+ dst->reg.idx[0].offset = idx; -+} -+ -+static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) -+{ -+ vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); -+ dst->reg.idx[0].offset = idx; -+} -+ -+static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx) -+{ -+ vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); -+ dst->reg.idx[0].offset = idx; -+ dst->write_mask = VKD3DSP_WRITEMASK_0; -+} -+ -+void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, -+ enum vkd3d_shader_opcode opcode) -+{ -+ memset(ins, 0, sizeof(*ins)); -+ ins->location = *location; -+ ins->opcode = opcode; - } - - bool vsir_instruction_init_with_params(struct vsir_program *program, -@@ -171,6 +282,37 @@ bool vsir_instruction_init_with_params(struct vsir_program *program, - return true; - } - -+static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, -+ const struct vkd3d_shader_location *location, unsigned int label_id, struct vsir_program *program) -+{ -+ struct vkd3d_shader_src_param *src_param; -+ -+ if (!(src_param = vsir_program_get_src_params(program, 1))) -+ return false; -+ -+ vsir_src_param_init_label(src_param, label_id); -+ -+ vsir_instruction_init(ins, location, VKD3DSIH_LABEL); -+ ins->src = src_param; -+ ins->src_count = 1; -+ -+ return true; -+} -+ -+static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction) -+{ -+ enum vkd3d_shader_opcode opcode = instruction->opcode; -+ return (VKD3DSIH_DCL <= opcode && opcode <= VKD3DSIH_DCL_VERTICES_OUT) -+ || opcode == VKD3DSIH_HS_DECLS; -+} -+ -+static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins) -+{ -+ struct vkd3d_shader_location location = ins->location; -+ -+ vsir_instruction_init(ins, &location, VKD3DSIH_NOP); -+} -+ - static bool get_opcode_from_rel_op(enum vkd3d_shader_rel_op rel_op, enum vkd3d_data_type data_type, - enum vkd3d_shader_opcode *opcode, bool *requires_swap) - { -@@ -451,6 +593,53 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog - return VKD3D_OK; - } - -+static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, struct vkd3d_shader_instruction *tex) -+{ -+ unsigned int idx = tex->src[1].reg.idx[0].offset; -+ struct vkd3d_shader_src_param *srcs; -+ -+ VKD3D_ASSERT(tex->src[1].reg.idx_count == 1); -+ VKD3D_ASSERT(!tex->src[1].reg.idx[0].rel_addr); -+ -+ if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 3))) -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ -+ srcs[0] = tex->src[0]; -+ vsir_src_param_init_resource(&srcs[1], idx, idx); -+ vsir_src_param_init_sampler(&srcs[2], idx, idx); -+ -+ tex->opcode = VKD3DSIH_SAMPLE; -+ tex->src = srcs; -+ tex->src_count = 3; -+ -+ return VKD3D_OK; -+} -+ -+static enum vkd3d_result vsir_program_lower_texldd(struct vsir_program *program, -+ struct vkd3d_shader_instruction *texldd) -+{ -+ unsigned int idx = texldd->src[1].reg.idx[0].offset; -+ struct vkd3d_shader_src_param *srcs; -+ -+ VKD3D_ASSERT(texldd->src[1].reg.idx_count == 1); -+ VKD3D_ASSERT(!texldd->src[1].reg.idx[0].rel_addr); -+ -+ if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 5))) -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ -+ srcs[0] = texldd->src[0]; -+ vsir_src_param_init_resource(&srcs[1], idx, idx); -+ vsir_src_param_init_sampler(&srcs[2], idx, idx); -+ srcs[3] = texldd->src[2]; -+ srcs[4] = texldd->src[3]; -+ -+ texldd->opcode = VKD3DSIH_SAMPLE_GRAD; -+ texldd->src = srcs; -+ texldd->src_count = 5; -+ -+ return VKD3D_OK; -+} -+ - static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *program, - struct vsir_transformation_context *ctx) - { -@@ -492,6 +681,38 @@ static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *pr - return ret; - break; - -+ case VKD3DSIH_TEX: -+ if ((ret = vsir_program_lower_tex(program, ins)) < 0) -+ return ret; -+ break; -+ -+ case VKD3DSIH_TEXLDD: -+ if ((ret = vsir_program_lower_texldd(program, ins)) < 0) -+ return ret; -+ break; -+ -+ case VKD3DSIH_TEXBEM: -+ case VKD3DSIH_TEXBEML: -+ case VKD3DSIH_TEXCOORD: -+ case VKD3DSIH_TEXDEPTH: -+ case VKD3DSIH_TEXDP3: -+ case VKD3DSIH_TEXDP3TEX: -+ case VKD3DSIH_TEXLDL: -+ case VKD3DSIH_TEXM3x2PAD: -+ case VKD3DSIH_TEXM3x2TEX: -+ case VKD3DSIH_TEXM3x3DIFF: -+ case VKD3DSIH_TEXM3x3PAD: -+ case VKD3DSIH_TEXM3x3SPEC: -+ case VKD3DSIH_TEXM3x3TEX: -+ case VKD3DSIH_TEXM3x3VSPEC: -+ case VKD3DSIH_TEXREG2AR: -+ case VKD3DSIH_TEXREG2GB: -+ case VKD3DSIH_TEXREG2RGB: -+ vkd3d_shader_error(ctx->message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, -+ "Aborting due to unimplemented feature: Combined sampler instruction %#x.", -+ ins->opcode); -+ return VKD3D_ERROR_NOT_IMPLEMENTED; -+ - default: - break; - } -@@ -689,180 +910,55 @@ static void flattener_eliminate_phase_related_dcls(struct hull_flattener *normal - loc->instruction_count = index - normaliser->phase_body_idx; - } - } -- --static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normaliser, -- struct shader_phase_location_array *locations) --{ -- struct shader_phase_location *loc; -- unsigned int i, j, k, end, count; -- -- for (i = 0, count = 0; i < locations->count; ++i) -- count += (locations->locations[i].instance_count - 1) * locations->locations[i].instruction_count; -- -- if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + count)) -- return VKD3D_ERROR_OUT_OF_MEMORY; -- end = normaliser->instructions.count; -- normaliser->instructions.count += count; -- -- for (i = locations->count; i > 0; --i) -- { -- loc = &locations->locations[i - 1]; -- j = loc->index + loc->instruction_count; -- memmove(&normaliser->instructions.elements[j + count], &normaliser->instructions.elements[j], -- (end - j) * sizeof(*normaliser->instructions.elements)); -- end = j; -- count -= (loc->instance_count - 1) * loc->instruction_count; -- loc->index += count; -- } -- -- for (i = 0, count = 0; i < locations->count; ++i) -- { -- loc = &locations->locations[i]; -- /* Make a copy of the non-dcl instructions for each instance. */ -- for (j = 1; j < loc->instance_count; ++j) -- { -- for (k = 0; k < loc->instruction_count; ++k) -- { -- if (!shader_instruction_array_clone_instruction(&normaliser->instructions, -- loc->index + loc->instruction_count * j + k, loc->index + k)) -- return VKD3D_ERROR_OUT_OF_MEMORY; -- } -- } -- /* Replace each reference to the instance id with a constant instance id. */ -- for (j = 0; j < loc->instance_count; ++j) -- { -- for (k = 0; k < loc->instruction_count; ++k) -- shader_instruction_eliminate_phase_instance_id( -- &normaliser->instructions.elements[loc->index + loc->instruction_count * j + k], j); -- } -- } -- -- return VKD3D_OK; --} -- --void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_register_type reg_type, -- enum vkd3d_data_type data_type, unsigned int idx_count) --{ -- reg->type = reg_type; -- reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; -- reg->non_uniform = false; -- reg->data_type = data_type; -- reg->idx[0].offset = ~0u; -- reg->idx[0].rel_addr = NULL; -- reg->idx[0].is_in_bounds = false; -- reg->idx[1].offset = ~0u; -- reg->idx[1].rel_addr = NULL; -- reg->idx[1].is_in_bounds = false; -- reg->idx[2].offset = ~0u; -- reg->idx[2].rel_addr = NULL; -- reg->idx[2].is_in_bounds = false; -- reg->idx_count = idx_count; -- reg->dimension = VSIR_DIMENSION_SCALAR; -- reg->alignment = 0; --} -- --void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, -- enum vkd3d_data_type data_type, unsigned int idx_count) --{ -- vsir_register_init(¶m->reg, reg_type, data_type, idx_count); -- param->swizzle = 0; -- param->modifiers = VKD3DSPSM_NONE; --} -- --void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type, -- enum vkd3d_data_type data_type, unsigned int idx_count) --{ -- vsir_register_init(¶m->reg, reg_type, data_type, idx_count); -- param->write_mask = VKD3DSP_WRITEMASK_0; -- param->modifiers = VKD3DSPDM_NONE; -- param->shift = 0; --} -- --void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) --{ -- vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UNUSED, 1); -- param->reg.dimension = VSIR_DIMENSION_NONE; -- param->reg.idx[0].offset = label_id; --} -- --static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx) --{ -- vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); -- src->reg.idx[0].offset = idx; --} -- --static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx) --{ -- vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); -- src->reg.idx[0].offset = idx; --} -- --static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) --{ -- vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1); -- dst->reg.idx[0].offset = idx; --} -- --static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) --{ -- vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); -- dst->reg.idx[0].offset = idx; --} -- --static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx) --{ -- vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); -- dst->reg.idx[0].offset = idx; -- dst->write_mask = VKD3DSP_WRITEMASK_0; --} -- --static void src_param_init_temp_float(struct vkd3d_shader_src_param *src, unsigned int idx) --{ -- vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_FLOAT, 1); -- src->reg.idx[0].offset = idx; --} -- --static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) --{ -- vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); -- src->reg.idx[0].offset = idx; --} -- --static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value) --{ -- vsir_src_param_init(src, VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0); -- src->reg.u.immconst_u32[0] = value; --} -- --static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type) --{ -- vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1); -- src->reg.idx[0].offset = idx; --} -- --void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, -- enum vkd3d_shader_opcode opcode) --{ -- memset(ins, 0, sizeof(*ins)); -- ins->location = *location; -- ins->opcode = opcode; --} -- --static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, -- const struct vkd3d_shader_location *location, unsigned int label_id, struct vsir_program *program) -+ -+static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normaliser, -+ struct shader_phase_location_array *locations) - { -- struct vkd3d_shader_src_param *src_param; -+ struct shader_phase_location *loc; -+ unsigned int i, j, k, end, count; - -- if (!(src_param = vsir_program_get_src_params(program, 1))) -- return false; -+ for (i = 0, count = 0; i < locations->count; ++i) -+ count += (locations->locations[i].instance_count - 1) * locations->locations[i].instruction_count; - -- vsir_src_param_init_label(src_param, label_id); -+ if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + count)) -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ end = normaliser->instructions.count; -+ normaliser->instructions.count += count; - -- vsir_instruction_init(ins, location, VKD3DSIH_LABEL); -- ins->src = src_param; -- ins->src_count = 1; -+ for (i = locations->count; i > 0; --i) -+ { -+ loc = &locations->locations[i - 1]; -+ j = loc->index + loc->instruction_count; -+ memmove(&normaliser->instructions.elements[j + count], &normaliser->instructions.elements[j], -+ (end - j) * sizeof(*normaliser->instructions.elements)); -+ end = j; -+ count -= (loc->instance_count - 1) * loc->instruction_count; -+ loc->index += count; -+ } - -- return true; -+ for (i = 0, count = 0; i < locations->count; ++i) -+ { -+ loc = &locations->locations[i]; -+ /* Make a copy of the non-dcl instructions for each instance. */ -+ for (j = 1; j < loc->instance_count; ++j) -+ { -+ for (k = 0; k < loc->instruction_count; ++k) -+ { -+ if (!shader_instruction_array_clone_instruction(&normaliser->instructions, -+ loc->index + loc->instruction_count * j + k, loc->index + k)) -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ } -+ /* Replace each reference to the instance id with a constant instance id. */ -+ for (j = 0; j < loc->instance_count; ++j) -+ { -+ for (k = 0; k < loc->instruction_count; ++k) -+ shader_instruction_eliminate_phase_instance_id( -+ &normaliser->instructions.elements[loc->index + loc->instruction_count * j + k], j); -+ } -+ } -+ -+ return VKD3D_OK; - } - - static enum vkd3d_result vsir_program_flatten_hull_shader_phases(struct vsir_program *program, -@@ -2055,106 +2151,6 @@ static enum vkd3d_result vsir_program_remove_dead_code(struct vsir_program *prog - return VKD3D_OK; - } - --static enum vkd3d_result vsir_program_normalise_combined_samplers(struct vsir_program *program, -- struct vsir_transformation_context *ctx) --{ -- unsigned int i; -- -- for (i = 0; i < program->instructions.count; ++i) -- { -- struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; -- struct vkd3d_shader_src_param *srcs; -- -- switch (ins->opcode) -- { -- case VKD3DSIH_TEX: -- if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 3))) -- return VKD3D_ERROR_OUT_OF_MEMORY; -- memset(srcs, 0, sizeof(*srcs) * 3); -- -- ins->opcode = VKD3DSIH_SAMPLE; -- -- srcs[0] = ins->src[0]; -- -- srcs[1].reg.type = VKD3DSPR_RESOURCE; -- srcs[1].reg.idx[0] = ins->src[1].reg.idx[0]; -- srcs[1].reg.idx[1] = ins->src[1].reg.idx[0]; -- srcs[1].reg.idx_count = 2; -- srcs[1].reg.data_type = VKD3D_DATA_RESOURCE; -- srcs[1].reg.dimension = VSIR_DIMENSION_VEC4; -- srcs[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; -- -- srcs[2].reg.type = VKD3DSPR_SAMPLER; -- srcs[2].reg.idx[0] = ins->src[1].reg.idx[0]; -- srcs[2].reg.idx[1] = ins->src[1].reg.idx[0]; -- srcs[2].reg.idx_count = 2; -- srcs[2].reg.data_type = VKD3D_DATA_SAMPLER; -- -- ins->src = srcs; -- ins->src_count = 3; -- break; -- -- case VKD3DSIH_TEXLDD: -- if (!(srcs = shader_src_param_allocator_get(&program->instructions.src_params, 5))) -- return VKD3D_ERROR_OUT_OF_MEMORY; -- memset(srcs, 0, sizeof(*srcs) * 5); -- -- ins->opcode = VKD3DSIH_SAMPLE_GRAD; -- -- srcs[0] = ins->src[0]; -- -- srcs[1].reg.type = VKD3DSPR_RESOURCE; -- srcs[1].reg.idx[0] = ins->src[1].reg.idx[0]; -- srcs[1].reg.idx[1] = ins->src[1].reg.idx[0]; -- srcs[1].reg.idx_count = 2; -- srcs[1].reg.data_type = VKD3D_DATA_RESOURCE; -- srcs[1].reg.dimension = VSIR_DIMENSION_VEC4; -- srcs[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; -- -- srcs[2].reg.type = VKD3DSPR_SAMPLER; -- srcs[2].reg.idx[0] = ins->src[1].reg.idx[0]; -- srcs[2].reg.idx[1] = ins->src[1].reg.idx[0]; -- srcs[2].reg.idx_count = 2; -- srcs[2].reg.data_type = VKD3D_DATA_SAMPLER; -- -- srcs[3] = ins->src[2]; -- srcs[4] = ins->src[3]; -- -- ins->src = srcs; -- ins->src_count = 5; -- break; -- -- case VKD3DSIH_TEXBEM: -- case VKD3DSIH_TEXBEML: -- case VKD3DSIH_TEXCOORD: -- case VKD3DSIH_TEXDEPTH: -- case VKD3DSIH_TEXDP3: -- case VKD3DSIH_TEXDP3TEX: -- case VKD3DSIH_TEXLDL: -- case VKD3DSIH_TEXM3x2PAD: -- case VKD3DSIH_TEXM3x2TEX: -- case VKD3DSIH_TEXM3x3DIFF: -- case VKD3DSIH_TEXM3x3PAD: -- case VKD3DSIH_TEXM3x3SPEC: -- case VKD3DSIH_TEXM3x3TEX: -- case VKD3DSIH_TEXM3x3VSPEC: -- case VKD3DSIH_TEXREG2AR: -- case VKD3DSIH_TEXREG2GB: -- case VKD3DSIH_TEXREG2RGB: -- vkd3d_shader_error(ctx->message_context, &ins->location, -- VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, -- "Aborting due to not yet implemented feature: " -- "Combined sampler instruction %#x.", ins->opcode); -- return VKD3D_ERROR_NOT_IMPLEMENTED; -- -- default: -- break; -- } -- } -- -- return VKD3D_OK; --} -- - struct cf_flattener_if_info - { - struct vkd3d_shader_src_param *false_param; -@@ -6157,6 +6153,48 @@ static void vsir_validator_push_block(struct validation_context *ctx, enum vkd3d - ctx->blocks[ctx->depth++] = opcode; - } - -+static void vsir_validate_branch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ size_t i; -+ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -+ vsir_validate_dst_count(ctx, instruction, 0); -+ -+ if (!vsir_validate_src_min_count(ctx, instruction, 1)) -+ return; -+ -+ if (vsir_register_is_label(&instruction->src[0].reg)) -+ { -+ /* Unconditional branch: parameters are jump label, -+ * optional merge label, optional continue label. */ -+ vsir_validate_src_max_count(ctx, instruction, 3); -+ -+ for (i = 0; i < instruction->src_count; ++i) -+ { -+ if (!vsir_register_is_label(&instruction->src[i].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid register of type %#x in unconditional BRANCH instruction, expected LABEL.", -+ instruction->src[i].reg.type); -+ } -+ } -+ else -+ { -+ /* Conditional branch: parameters are condition, true -+ * jump label, false jump label, optional merge label, -+ * optional continue label. */ -+ vsir_validate_src_min_count(ctx, instruction, 3); -+ vsir_validate_src_max_count(ctx, instruction, 5); -+ -+ for (i = 1; i < instruction->src_count; ++i) -+ { -+ if (!vsir_register_is_label(&instruction->src[i].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid register of type %#x in conditional BRANCH instruction, expected LABEL.", -+ instruction->src[i].reg.type); -+ } -+ } -+} -+ - static void vsir_validate_dcl_temps(struct validation_context *ctx, - const struct vkd3d_shader_instruction *instruction) - { -@@ -6211,6 +6249,16 @@ static void vsir_validate_endrep(struct validation_context *ctx, const struct vk - --ctx->depth; - } - -+static void vsir_validate_endswitch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_SWITCH) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -+ "ENDSWITCH instruction doesn't terminate SWITCH block."); -+ else -+ --ctx->depth; -+} -+ - static void vsir_validate_if(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) - { - vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -@@ -6223,6 +6271,15 @@ static void vsir_validate_ifc(struct validation_context *ctx, const struct vkd3d - vsir_validator_push_block(ctx, VKD3DSIH_IF); - } - -+static void vsir_validate_label(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -+ if (instruction->src_count >= 1 && !vsir_register_is_label(&instruction->src[0].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid register of type %#x in a LABEL instruction, expected LABEL.", -+ instruction->src[0].reg.type); -+} -+ - static void vsir_validate_loop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) - { - vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -@@ -6230,12 +6287,133 @@ static void vsir_validate_loop(struct validation_context *ctx, const struct vkd3 - vsir_validator_push_block(ctx, VKD3DSIH_LOOP); - } - -+static void vsir_validate_nop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+} -+ -+static void vsir_validate_phi(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ unsigned int i, incoming_count; -+ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -+ -+ vsir_validate_src_min_count(ctx, instruction, 2); -+ -+ if (instruction->src_count % 2 != 0) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, -+ "Invalid source count %u for a PHI instruction, it must be an even number.", -+ instruction->src_count); -+ incoming_count = instruction->src_count / 2; -+ -+ for (i = 0; i < incoming_count; ++i) -+ { -+ unsigned int value_idx = 2 * i; -+ unsigned int label_idx = 2 * i + 1; -+ -+ if (!register_is_constant_or_undef(&instruction->src[value_idx].reg) -+ && !register_is_ssa(&instruction->src[value_idx].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid value register for incoming %u of type %#x in PHI instruction, " -+ "expected SSA, IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); -+ -+ if (instruction->src[value_idx].reg.dimension != VSIR_DIMENSION_SCALAR) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, -+ "Invalid value dimension %#x for incoming %u in PHI instruction, expected scalar.", -+ instruction->src[value_idx].reg.dimension, i); -+ -+ if (!vsir_register_is_label(&instruction->src[label_idx].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid label register for case %u of type %#x in PHI instruction, " -+ "expected LABEL.", i, instruction->src[value_idx].reg.type); -+ } -+ -+ if (instruction->dst_count < 1) -+ return; -+ -+ if (!register_is_ssa(&instruction->dst[0].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid destination of type %#x in PHI instruction, expected SSA.", -+ instruction->dst[0].reg.type); -+ -+ if (instruction->dst[0].reg.dimension != VSIR_DIMENSION_SCALAR) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, -+ "Invalid destination dimension %#x in PHI instruction, expected scalar.", -+ instruction->dst[0].reg.dimension); -+ -+ if (instruction->dst[0].modifiers != VKD3DSPDM_NONE) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, -+ "Invalid modifiers %#x for the destination of a PHI instruction, expected none.", -+ instruction->dst[0].modifiers); -+ -+ if (instruction->dst[0].shift != 0) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT, -+ "Invalid shift %#x for the destination of a PHI instruction, expected none.", -+ instruction->dst[0].shift); -+} -+ - static void vsir_validate_rep(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) - { - vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); - vsir_validator_push_block(ctx, VKD3DSIH_REP); - } - -+static void vsir_validate_ret(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+} -+ -+static void vsir_validate_switch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -+{ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -+ vsir_validator_push_block(ctx, VKD3DSIH_SWITCH); -+} -+ -+static void vsir_validate_switch_monolithic(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ unsigned int i, case_count; -+ -+ vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -+ -+ /* Parameters are source, default label, merge label and -+ * then pairs of constant value and case label. */ -+ -+ if (!vsir_validate_src_min_count(ctx, instruction, 3)) -+ return; -+ -+ if (instruction->src_count % 2 != 1) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, -+ "Invalid source count %u for a monolithic SWITCH instruction, it must be an odd number.", -+ instruction->src_count); -+ -+ if (!vsir_register_is_label(&instruction->src[1].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid default label register of type %#x in monolithic SWITCH instruction, expected LABEL.", -+ instruction->src[1].reg.type); -+ -+ if (!vsir_register_is_label(&instruction->src[2].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid merge label register of type %#x in monolithic SWITCH instruction, expected LABEL.", -+ instruction->src[2].reg.type); -+ -+ case_count = (instruction->src_count - 3) / 2; -+ -+ for (i = 0; i < case_count; ++i) -+ { -+ unsigned int value_idx = 3 + 2 * i; -+ unsigned int label_idx = 3 + 2 * i + 1; -+ -+ if (!register_is_constant(&instruction->src[value_idx].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid value register for case %u of type %#x in monolithic SWITCH instruction, " -+ "expected IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); -+ -+ if (!vsir_register_is_label(&instruction->src[label_idx].reg)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -+ "Invalid label register for case %u of type %#x in monolithic SWITCH instruction, " -+ "expected LABEL.", i, instruction->src[value_idx].reg.type); -+ } -+} -+ - struct vsir_validator_instruction_desc - { - unsigned int dst_param_count; -@@ -6245,15 +6423,23 @@ struct vsir_validator_instruction_desc - - static const struct vsir_validator_instruction_desc vsir_validator_instructions[] = - { -- [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, -- [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, -- [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, -- [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, -- [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, -- [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, -- [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, -- [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, -- [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, -+ [VKD3DSIH_BRANCH] = {0, ~0u, vsir_validate_branch}, -+ [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, -+ [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, -+ [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, -+ [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, -+ [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, -+ [VKD3DSIH_ENDSWITCH] = {0, 0, vsir_validate_endswitch}, -+ [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, -+ [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, -+ [VKD3DSIH_LABEL] = {0, 1, vsir_validate_label}, -+ [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, -+ [VKD3DSIH_NOP] = {0, 0, vsir_validate_nop}, -+ [VKD3DSIH_PHI] = {1, ~0u, vsir_validate_phi}, -+ [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, -+ [VKD3DSIH_RET] = {0, 0, vsir_validate_ret}, -+ [VKD3DSIH_SWITCH] = {0, 1, vsir_validate_switch}, -+ [VKD3DSIH_SWITCH_MONOLITHIC] = {0, ~0u, vsir_validate_switch_monolithic}, - }; - - static void vsir_validate_instruction(struct validation_context *ctx) -@@ -6413,185 +6599,6 @@ static void vsir_validate_instruction(struct validation_context *ctx) - desc->validate(ctx, instruction); - } - } -- -- switch (instruction->opcode) -- { -- case VKD3DSIH_SWITCH: -- vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 1); -- if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) -- return; -- ctx->blocks[ctx->depth++] = instruction->opcode; -- break; -- -- case VKD3DSIH_ENDSWITCH: -- vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_SWITCH) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDSWITCH instruction doesn't terminate SWITCH block."); -- else -- --ctx->depth; -- break; -- -- case VKD3DSIH_RET: -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- break; -- -- case VKD3DSIH_LABEL: -- vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 1); -- if (instruction->src_count >= 1 && !vsir_register_is_label(&instruction->src[0].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid register of type %#x in a LABEL instruction, expected LABEL.", -- instruction->src[0].reg.type); -- break; -- -- case VKD3DSIH_BRANCH: -- vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -- vsir_validate_dst_count(ctx, instruction, 0); -- if (!vsir_validate_src_min_count(ctx, instruction, 1)) -- break; -- if (vsir_register_is_label(&instruction->src[0].reg)) -- { -- /* Unconditional branch: parameters are jump label, -- * optional merge label, optional continue label. */ -- vsir_validate_src_max_count(ctx, instruction, 3); -- -- for (i = 0; i < instruction->src_count; ++i) -- { -- if (!vsir_register_is_label(&instruction->src[i].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid register of type %#x in unconditional BRANCH instruction, expected LABEL.", -- instruction->src[i].reg.type); -- } -- } -- else -- { -- /* Conditional branch: parameters are condition, true -- * jump label, false jump label, optional merge label, -- * optional continue label. */ -- vsir_validate_src_min_count(ctx, instruction, 3); -- vsir_validate_src_max_count(ctx, instruction, 5); -- -- for (i = 1; i < instruction->src_count; ++i) -- { -- if (!vsir_register_is_label(&instruction->src[i].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid register of type %#x in conditional BRANCH instruction, expected LABEL.", -- instruction->src[i].reg.type); -- } -- } -- break; -- -- case VKD3DSIH_SWITCH_MONOLITHIC: -- { -- unsigned int case_count; -- -- vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -- vsir_validate_dst_count(ctx, instruction, 0); -- /* Parameters are source, default label, merge label and -- * then pairs of constant value and case label. */ -- if (!vsir_validate_src_min_count(ctx, instruction, 3)) -- break; -- if (instruction->src_count % 2 != 1) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, -- "Invalid source count %u for a monolithic SWITCH instruction, it must be an odd number.", -- instruction->src_count); -- -- if (!vsir_register_is_label(&instruction->src[1].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid default label register of type %#x in monolithic SWITCH instruction, expected LABEL.", -- instruction->src[1].reg.type); -- -- if (!vsir_register_is_label(&instruction->src[2].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid merge label register of type %#x in monolithic SWITCH instruction, expected LABEL.", -- instruction->src[2].reg.type); -- -- case_count = (instruction->src_count - 3) / 2; -- -- for (i = 0; i < case_count; ++i) -- { -- unsigned int value_idx = 3 + 2 * i; -- unsigned int label_idx = 3 + 2 * i + 1; -- -- if (!register_is_constant(&instruction->src[value_idx].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid value register for case %zu of type %#x in monolithic SWITCH instruction, " -- "expected IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); -- -- if (!vsir_register_is_label(&instruction->src[label_idx].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid label register for case %zu of type %#x in monolithic SWITCH instruction, " -- "expected LABEL.", i, instruction->src[value_idx].reg.type); -- } -- break; -- } -- -- case VKD3DSIH_PHI: -- { -- unsigned int incoming_count; -- -- vsir_validate_cf_type(ctx, instruction, VSIR_CF_BLOCKS); -- vsir_validate_dst_count(ctx, instruction, 1); -- vsir_validate_src_min_count(ctx, instruction, 2); -- if (instruction->src_count % 2 != 0) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, -- "Invalid source count %u for a PHI instruction, it must be an even number.", -- instruction->src_count); -- incoming_count = instruction->src_count / 2; -- -- if (!register_is_ssa(&instruction->dst[0].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid destination of type %#x in PHI instruction, expected SSA.", -- instruction->dst[0].reg.type); -- -- if (instruction->dst[0].reg.dimension != VSIR_DIMENSION_SCALAR) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, -- "Invalid destination dimension %#x in PHI instruction, expected scalar.", -- instruction->dst[0].reg.dimension); -- -- if (instruction->dst[0].modifiers != VKD3DSPDM_NONE) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, -- "Invalid modifiers %#x for the destination of a PHI instruction, expected none.", -- instruction->dst[0].modifiers); -- -- if (instruction->dst[0].shift != 0) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT, -- "Invalid shift %#x for the destination of a PHI instruction, expected none.", -- instruction->dst[0].shift); -- -- for (i = 0; i < incoming_count; ++i) -- { -- unsigned int value_idx = 2 * i; -- unsigned int label_idx = 2 * i + 1; -- -- if (!register_is_constant_or_undef(&instruction->src[value_idx].reg) -- && !register_is_ssa(&instruction->src[value_idx].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid value register for incoming %zu of type %#x in PHI instruction, " -- "expected SSA, IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); -- -- if (instruction->src[value_idx].reg.dimension != VSIR_DIMENSION_SCALAR) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, -- "Invalid value dimension %#x for incoming %zu in PHI instruction, expected scalar.", -- instruction->src[value_idx].reg.dimension, i); -- -- if (!vsir_register_is_label(&instruction->src[label_idx].reg)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, -- "Invalid label register for case %zu of type %#x in PHI instruction, " -- "expected LABEL.", i, instruction->src[value_idx].reg.type); -- } -- break; -- } -- -- default: -- break; -- } - } - - enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, -@@ -6710,7 +6717,6 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t - vsir_transform(&ctx, vsir_program_normalise_io_registers); - vsir_transform(&ctx, vsir_program_normalise_flat_constants); - vsir_transform(&ctx, vsir_program_remove_dead_code); -- vsir_transform(&ctx, vsir_program_normalise_combined_samplers); - - if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL - && compile_info->target_type != VKD3D_SHADER_TARGET_MSL) -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index 8866780132e..8146a393a4c 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -165,6 +165,7 @@ enum vkd3d_shader_error - VKD3D_SHADER_WARNING_HLSL_IMAGINARY_NUMERIC_RESULT = 5303, - VKD3D_SHADER_WARNING_HLSL_NON_FINITE_RESULT = 5304, - VKD3D_SHADER_WARNING_HLSL_IGNORED_ATTRIBUTE = 5305, -+ VKD3D_SHADER_WARNING_HLSL_IGNORED_DEFAULT_VALUE = 5306, - - VKD3D_SHADER_ERROR_GLSL_INTERNAL = 6000, - --- -2.45.2 - diff --git a/patches/vkd3d-latest/0008-Updated-vkd3d-to-a1487380bb69c6ec07495c1a6eef4cfb224.patch b/patches/vkd3d-latest/0008-Updated-vkd3d-to-a1487380bb69c6ec07495c1a6eef4cfb224.patch deleted file mode 100644 index f3dc5e1e..00000000 --- a/patches/vkd3d-latest/0008-Updated-vkd3d-to-a1487380bb69c6ec07495c1a6eef4cfb224.patch +++ /dev/null @@ -1,1125 +0,0 @@ -From 62c15c901fbc5afb9211dd1ae6b88b0a212021a9 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Wed, 18 Sep 2024 11:57:45 +1000 -Subject: [PATCH] Updated vkd3d to a1487380bb69c6ec07495c1a6eef4cfb224710cb. - ---- - libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 6 +- - libs/vkd3d/libs/vkd3d-shader/glsl.c | 360 ++++++++++++++++++++++++- - libs/vkd3d/libs/vkd3d-shader/ir.c | 284 ++++++++++--------- - libs/vkd3d/libs/vkd3d-shader/msl.c | 129 +++++++++ - libs/vkd3d/libs/vkd3d-shader/tpf.c | 106 +++++++- - 5 files changed, 743 insertions(+), 142 deletions(-) - create mode 100644 libs/vkd3d/libs/vkd3d-shader/msl.c - -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c -index 77e9711300f..cfee053d49c 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c -@@ -79,7 +79,7 @@ static const char * const shader_opcode_names[] = - [VKD3DSIH_DCL_INDEXABLE_TEMP ] = "dcl_indexableTemp", - [VKD3DSIH_DCL_INPUT ] = "dcl_input", - [VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT ] = "dcl_input_control_point_count", -- [VKD3DSIH_DCL_INPUT_PRIMITIVE ] = "dcl_inputPrimitive", -+ [VKD3DSIH_DCL_INPUT_PRIMITIVE ] = "dcl_inputprimitive", - [VKD3DSIH_DCL_INPUT_PS ] = "dcl_input_ps", - [VKD3DSIH_DCL_INPUT_PS_SGV ] = "dcl_input_ps_sgv", - [VKD3DSIH_DCL_INPUT_PS_SIV ] = "dcl_input_ps_siv", -@@ -89,7 +89,7 @@ static const char * const shader_opcode_names[] = - [VKD3DSIH_DCL_OUTPUT ] = "dcl_output", - [VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT ] = "dcl_output_control_point_count", - [VKD3DSIH_DCL_OUTPUT_SIV ] = "dcl_output_siv", -- [VKD3DSIH_DCL_OUTPUT_TOPOLOGY ] = "dcl_outputTopology", -+ [VKD3DSIH_DCL_OUTPUT_TOPOLOGY ] = "dcl_outputtopology", - [VKD3DSIH_DCL_RESOURCE_RAW ] = "dcl_resource_raw", - [VKD3DSIH_DCL_RESOURCE_STRUCTURED ] = "dcl_resource_structured", - [VKD3DSIH_DCL_SAMPLER ] = "dcl_sampler", -@@ -104,7 +104,7 @@ static const char * const shader_opcode_names[] = - [VKD3DSIH_DCL_UAV_RAW ] = "dcl_uav_raw", - [VKD3DSIH_DCL_UAV_STRUCTURED ] = "dcl_uav_structured", - [VKD3DSIH_DCL_UAV_TYPED ] = "dcl_uav_typed", -- [VKD3DSIH_DCL_VERTICES_OUT ] = "dcl_maxOutputVertexCount", -+ [VKD3DSIH_DCL_VERTICES_OUT ] = "dcl_maxout", - [VKD3DSIH_DDIV ] = "ddiv", - [VKD3DSIH_DEF ] = "def", - [VKD3DSIH_DEFAULT ] = "default", -diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c -index b0aacdfef65..f8fec6ac2bc 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/glsl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c -@@ -38,7 +38,16 @@ struct vkd3d_glsl_generator - struct vkd3d_shader_location location; - struct vkd3d_shader_message_context *message_context; - unsigned int indent; -+ const char *prefix; - bool failed; -+ -+ struct shader_limits -+ { -+ unsigned int input_count; -+ unsigned int output_count; -+ } limits; -+ bool interstage_input; -+ bool interstage_output; - }; - - static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( -@@ -53,6 +62,27 @@ static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( - generator->failed = true; - } - -+static const char *shader_glsl_get_prefix(enum vkd3d_shader_type type) -+{ -+ switch (type) -+ { -+ case VKD3D_SHADER_TYPE_VERTEX: -+ return "vs"; -+ case VKD3D_SHADER_TYPE_HULL: -+ return "hs"; -+ case VKD3D_SHADER_TYPE_DOMAIN: -+ return "ds"; -+ case VKD3D_SHADER_TYPE_GEOMETRY: -+ return "gs"; -+ case VKD3D_SHADER_TYPE_PIXEL: -+ return "ps"; -+ case VKD3D_SHADER_TYPE_COMPUTE: -+ return "cs"; -+ default: -+ return NULL; -+ } -+} -+ - static void shader_glsl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent) - { - vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); -@@ -67,6 +97,42 @@ static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer, - vkd3d_string_buffer_printf(buffer, "r[%u]", reg->idx[0].offset); - break; - -+ case VKD3DSPR_INPUT: -+ if (reg->idx_count != 1) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled input register index count %u.", reg->idx_count); -+ vkd3d_string_buffer_printf(buffer, "", reg->type); -+ break; -+ } -+ if (reg->idx[0].rel_addr) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled input register indirect addressing."); -+ vkd3d_string_buffer_printf(buffer, "", reg->type); -+ break; -+ } -+ vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, reg->idx[0].offset); -+ break; -+ -+ case VKD3DSPR_OUTPUT: -+ if (reg->idx_count != 1) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled output register index count %u.", reg->idx_count); -+ vkd3d_string_buffer_printf(buffer, "", reg->type); -+ break; -+ } -+ if (reg->idx[0].rel_addr) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled output register indirect addressing."); -+ vkd3d_string_buffer_printf(buffer, "", reg->type); -+ break; -+ } -+ vkd3d_string_buffer_printf(buffer, "%s_out[%u]", gen->prefix, reg->idx[0].offset); -+ break; -+ - default: - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, - "Internal compiler error: Unhandled register type %#x.", reg->type); -@@ -198,16 +264,130 @@ static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d - glsl_dst_cleanup(&dst, &gen->string_buffers); - } - -+static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, -+ enum vkd3d_shader_sysval_semantic sysval, unsigned int idx) -+{ -+ switch (sysval) -+ { -+ case VKD3D_SHADER_SV_POSITION: -+ if (gen->program->shader_version.type == VKD3D_SHADER_TYPE_PIXEL -+ || gen->program->shader_version.type == VKD3D_SHADER_TYPE_COMPUTE) -+ { -+ vkd3d_string_buffer_printf(buffer, "", sysval); -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled system value %#x.", sysval); -+ } -+ else -+ { -+ vkd3d_string_buffer_printf(buffer, "gl_Position"); -+ if (idx) -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled SV_POSITION index %u.", idx); -+ } -+ break; -+ -+ default: -+ vkd3d_string_buffer_printf(buffer, "", sysval); -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled system value %#x.", sysval); -+ break; -+ } -+} -+ -+static void shader_glsl_shader_prologue(struct vkd3d_glsl_generator *gen) -+{ -+ const struct shader_signature *signature = &gen->program->input_signature; -+ struct vkd3d_string_buffer *buffer = gen->buffer; -+ const struct signature_element *e; -+ unsigned int i; -+ -+ for (i = 0; i < signature->element_count; ++i) -+ { -+ e = &signature->elements[i]; -+ -+ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) -+ continue; -+ -+ shader_glsl_print_indent(buffer, gen->indent); -+ vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, e->register_index); -+ shader_glsl_print_write_mask(buffer, e->mask); -+ if (e->sysval_semantic == VKD3D_SHADER_SV_NONE) -+ { -+ if (gen->interstage_input) -+ { -+ vkd3d_string_buffer_printf(buffer, " = shader_in.reg_%u", e->target_location); -+ if (e->target_location >= gen->limits.input_count) -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Input element %u specifies target location %u, " -+ "but only %u inputs are supported.", -+ i, e->target_location, gen->limits.input_count); -+ } -+ else -+ { -+ vkd3d_string_buffer_printf(buffer, " = shader_in_%u", i); -+ } -+ } -+ else -+ { -+ vkd3d_string_buffer_printf(buffer, " = "); -+ shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index); -+ } -+ shader_glsl_print_write_mask(buffer, e->mask); -+ vkd3d_string_buffer_printf(buffer, ";\n"); -+ } -+} -+ -+static void shader_glsl_shader_epilogue(struct vkd3d_glsl_generator *gen) -+{ -+ const struct shader_signature *signature = &gen->program->output_signature; -+ struct vkd3d_string_buffer *buffer = gen->buffer; -+ const struct signature_element *e; -+ unsigned int i; -+ -+ for (i = 0; i < signature->element_count; ++i) -+ { -+ e = &signature->elements[i]; -+ -+ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) -+ continue; -+ -+ shader_glsl_print_indent(buffer, gen->indent); -+ if (e->sysval_semantic == VKD3D_SHADER_SV_NONE) -+ { -+ if (gen->interstage_output) -+ { -+ vkd3d_string_buffer_printf(buffer, "shader_out.reg_%u", e->target_location); -+ if (e->target_location >= gen->limits.output_count) -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Output element %u specifies target location %u, " -+ "but only %u outputs are supported.", -+ i, e->target_location, gen->limits.output_count); -+ } -+ else -+ { -+ vkd3d_string_buffer_printf(buffer, "", e->target_location); -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled output."); -+ } -+ } -+ else -+ { -+ shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index); -+ } -+ shader_glsl_print_write_mask(buffer, e->mask); -+ vkd3d_string_buffer_printf(buffer, " = %s_out[%u]", gen->prefix, e->register_index); -+ shader_glsl_print_write_mask(buffer, e->mask); -+ vkd3d_string_buffer_printf(buffer, ";\n"); -+ } -+} -+ - static void shader_glsl_ret(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) - { - const struct vkd3d_shader_version *version = &gen->program->shader_version; - -- /* -- * TODO: Implement in_subroutine -- * TODO: shader_glsl_generate_shader_epilogue(generator); -- */ - if (version->major >= 4) - { -+ shader_glsl_shader_epilogue(gen); - shader_glsl_print_indent(gen->buffer, gen->indent); - vkd3d_string_buffer_printf(gen->buffer, "return;\n"); - } -@@ -237,13 +417,144 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, - } - } - -+static void shader_glsl_generate_interface_block(struct vkd3d_string_buffer *buffer, -+ const char *type, unsigned int count) -+{ -+ unsigned int i; -+ -+ vkd3d_string_buffer_printf(buffer, "%s shader_in_out\n{\n", type); -+ for (i = 0; i < count; ++i) -+ { -+ vkd3d_string_buffer_printf(buffer, " vec4 reg_%u;\n", i); -+ } -+ vkd3d_string_buffer_printf(buffer, "} shader_%s;\n", type); -+} -+ -+static void shader_glsl_generate_input_declarations(struct vkd3d_glsl_generator *gen) -+{ -+ const struct shader_signature *signature = &gen->program->input_signature; -+ struct vkd3d_string_buffer *buffer = gen->buffer; -+ const struct signature_element *e; -+ unsigned int i; -+ -+ if (!gen->interstage_input) -+ { -+ for (i = 0; i < signature->element_count; ++i) -+ { -+ e = &signature->elements[i]; -+ -+ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) -+ continue; -+ -+ if (e->sysval_semantic) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled system value %#x.", e->sysval_semantic); -+ continue; -+ } -+ -+ if (e->component_type != VKD3D_SHADER_COMPONENT_FLOAT) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled component type %#x.", e->component_type); -+ continue; -+ } -+ -+ if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled minimum precision %#x.", e->min_precision); -+ continue; -+ } -+ -+ if (e->interpolation_mode != VKD3DSIM_NONE) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode); -+ continue; -+ } -+ -+ vkd3d_string_buffer_printf(buffer, -+ "layout(location = %u) in vec4 shader_in_%u;\n", e->target_location, i); -+ } -+ } -+ else if (gen->limits.input_count) -+ { -+ shader_glsl_generate_interface_block(buffer, "in", gen->limits.input_count); -+ } -+ vkd3d_string_buffer_printf(buffer, "\n"); -+} -+ -+static void shader_glsl_generate_output_declarations(struct vkd3d_glsl_generator *gen) -+{ -+ const struct shader_signature *signature = &gen->program->output_signature; -+ struct vkd3d_string_buffer *buffer = gen->buffer; -+ const struct signature_element *e; -+ unsigned int i; -+ -+ if (!gen->interstage_output) -+ { -+ for (i = 0; i < signature->element_count; ++i) -+ { -+ e = &signature->elements[i]; -+ -+ if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) -+ continue; -+ -+ if (e->sysval_semantic != VKD3D_SHADER_SV_TARGET) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled system value %#x.", e->sysval_semantic); -+ continue; -+ } -+ -+ if (e->component_type != VKD3D_SHADER_COMPONENT_FLOAT) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled component type %#x.", e->component_type); -+ continue; -+ } -+ -+ if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled minimum precision %#x.", e->min_precision); -+ continue; -+ } -+ -+ if (e->interpolation_mode != VKD3DSIM_NONE) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode); -+ continue; -+ } -+ -+ vkd3d_string_buffer_printf(buffer, -+ "layout(location = %u) out vec4 shader_out_%u;\n", e->target_location, i); -+ } -+ } -+ else if (gen->limits.output_count) -+ { -+ shader_glsl_generate_interface_block(buffer, "out", gen->limits.output_count); -+ } -+ vkd3d_string_buffer_printf(buffer, "\n"); -+} -+ - static void shader_glsl_generate_declarations(struct vkd3d_glsl_generator *gen) - { - const struct vsir_program *program = gen->program; - struct vkd3d_string_buffer *buffer = gen->buffer; - -+ shader_glsl_generate_input_declarations(gen); -+ shader_glsl_generate_output_declarations(gen); -+ -+ if (gen->limits.input_count) -+ vkd3d_string_buffer_printf(buffer, "vec4 %s_in[%u];\n", gen->prefix, gen->limits.input_count); -+ if (gen->limits.output_count) -+ vkd3d_string_buffer_printf(buffer, "vec4 %s_out[%u];\n", gen->prefix, gen->limits.output_count); - if (program->temp_count) -- vkd3d_string_buffer_printf(buffer, "vec4 r[%u];\n\n", program->temp_count); -+ vkd3d_string_buffer_printf(buffer, "vec4 r[%u];\n", program->temp_count); -+ vkd3d_string_buffer_printf(buffer, "\n"); - } - - static int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *gen, struct vkd3d_shader_code *out) -@@ -264,6 +575,7 @@ static int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *gen, struc - vkd3d_string_buffer_printf(buffer, "void main()\n{\n"); - - ++gen->indent; -+ shader_glsl_shader_prologue(gen); - for (i = 0; i < instructions->count; ++i) - { - vkd3d_glsl_handle_instruction(gen, &instructions->elements[i]); -@@ -294,14 +606,52 @@ static void vkd3d_glsl_generator_cleanup(struct vkd3d_glsl_generator *gen) - vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); - } - -+static void shader_glsl_init_limits(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_version *version) -+{ -+ struct shader_limits *limits = &gen->limits; -+ -+ if (version->major < 4 || version->major >= 6) -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled shader version %u.%u.", version->major, version->minor); -+ -+ switch (version->type) -+ { -+ case VKD3D_SHADER_TYPE_VERTEX: -+ limits->input_count = 32; -+ limits->output_count = 32; -+ break; -+ case VKD3D_SHADER_TYPE_PIXEL: -+ limits->input_count = 32; -+ limits->output_count = 8; -+ break; -+ default: -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled shader type %#x.", version->type); -+ limits->input_count = 0; -+ limits->output_count = 0; -+ break; -+ } -+} -+ - static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen, - struct vsir_program *program, struct vkd3d_shader_message_context *message_context) - { -+ enum vkd3d_shader_type type = program->shader_version.type; -+ - memset(gen, 0, sizeof(*gen)); - gen->program = program; - vkd3d_string_buffer_cache_init(&gen->string_buffers); - gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers); - gen->message_context = message_context; -+ if (!(gen->prefix = shader_glsl_get_prefix(type))) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled shader type %#x.", type); -+ gen->prefix = "unknown"; -+ } -+ shader_glsl_init_limits(gen, &program->shader_version); -+ gen->interstage_input = type != VKD3D_SHADER_TYPE_VERTEX; -+ gen->interstage_output = type != VKD3D_SHADER_TYPE_PIXEL; - } - - int glsl_compile(struct vsir_program *program, uint64_t config_flags, -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index 1efb7106e71..9e06b94e2eb 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -6153,6 +6153,21 @@ static void vsir_validator_push_block(struct validation_context *ctx, enum vkd3d - ctx->blocks[ctx->depth++] = opcode; - } - -+static void vsir_validate_hull_shader_phase(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (ctx->program->shader_version.type != VKD3D_SHADER_TYPE_HULL) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, -+ "Phase instruction %#x is only valid in a hull shader.", -+ instruction->opcode); -+ if (ctx->depth != 0) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -+ "Phase instruction %#x must appear to top level.", -+ instruction->opcode); -+ ctx->phase = instruction->opcode; -+ ctx->dcl_temps_found = false; -+} -+ - static void vsir_validate_branch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) - { - size_t i; -@@ -6193,6 +6208,54 @@ static void vsir_validate_branch(struct validation_context *ctx, const struct vk - instruction->src[i].reg.type); - } - } -+ -+ ctx->inside_block = false; -+} -+ -+static void vsir_validate_dcl_gs_instances(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (!instruction->declaration.count || instruction->declaration.count > 32) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS instance count %u is invalid.", -+ instruction->declaration.count); -+} -+ -+static void vsir_validate_dcl_hs_max_tessfactor(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ /* Exclude non-finite values. */ -+ if (!(instruction->declaration.max_tessellation_factor >= 1.0f -+ && instruction->declaration.max_tessellation_factor <= 64.0f)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -+ "Max tessellation factor %f is invalid.", -+ instruction->declaration.max_tessellation_factor); -+} -+ -+static void vsir_validate_dcl_input_primitive(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED -+ || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS input primitive %u is invalid.", -+ instruction->declaration.primitive_type.type); -+} -+ -+static void vsir_validate_dcl_output_control_point_count(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (!instruction->declaration.count || instruction->declaration.count > 32) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -+ "Output control point count %u is invalid.", -+ instruction->declaration.count); -+} -+ -+static void vsir_validate_dcl_output_topology(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED -+ || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output primitive %u is invalid.", -+ instruction->declaration.primitive_type.type); - } - - static void vsir_validate_dcl_temps(struct validation_context *ctx, -@@ -6208,6 +6271,45 @@ static void vsir_validate_dcl_temps(struct validation_context *ctx, - ctx->dcl_temps_found = true; - } - -+static void vsir_validate_dcl_tessellator_domain(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID -+ || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -+ "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain); -+} -+ -+static void vsir_validate_dcl_tessellator_output_primitive(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (!instruction->declaration.tessellator_output_primitive -+ || instruction->declaration.tessellator_output_primitive -+ > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -+ "Tessellator output primitive %#x is invalid.", -+ instruction->declaration.tessellator_output_primitive); -+} -+ -+static void vsir_validate_dcl_tessellator_partitioning(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (!instruction->declaration.tessellator_partitioning -+ || instruction->declaration.tessellator_partitioning -+ > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -+ "Tessellator partitioning %#x is invalid.", -+ instruction->declaration.tessellator_partitioning); -+} -+ -+static void vsir_validate_dcl_vertices_out(struct validation_context *ctx, -+ const struct vkd3d_shader_instruction *instruction) -+{ -+ if (instruction->declaration.count > 1024) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output vertex count %u is invalid.", -+ instruction->declaration.count); -+} -+ - static void vsir_validate_else(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) - { - vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); -@@ -6278,6 +6380,11 @@ static void vsir_validate_label(struct validation_context *ctx, const struct vkd - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, - "Invalid register of type %#x in a LABEL instruction, expected LABEL.", - instruction->src[0].reg.type); -+ -+ if (ctx->inside_block) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -+ "Invalid LABEL instruction inside a block."); -+ ctx->inside_block = true; - } - - static void vsir_validate_loop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -@@ -6359,6 +6466,7 @@ static void vsir_validate_rep(struct validation_context *ctx, const struct vkd3d - - static void vsir_validate_ret(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) - { -+ ctx->inside_block = false; - } - - static void vsir_validate_switch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) -@@ -6412,6 +6520,8 @@ static void vsir_validate_switch_monolithic(struct validation_context *ctx, - "Invalid label register for case %u of type %#x in monolithic SWITCH instruction, " - "expected LABEL.", i, instruction->src[value_idx].reg.type); - } -+ -+ ctx->inside_block = false; - } - - struct vsir_validator_instruction_desc -@@ -6423,23 +6533,36 @@ struct vsir_validator_instruction_desc - - static const struct vsir_validator_instruction_desc vsir_validator_instructions[] = - { -- [VKD3DSIH_BRANCH] = {0, ~0u, vsir_validate_branch}, -- [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, -- [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, -- [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, -- [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, -- [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, -- [VKD3DSIH_ENDSWITCH] = {0, 0, vsir_validate_endswitch}, -- [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, -- [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, -- [VKD3DSIH_LABEL] = {0, 1, vsir_validate_label}, -- [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, -- [VKD3DSIH_NOP] = {0, 0, vsir_validate_nop}, -- [VKD3DSIH_PHI] = {1, ~0u, vsir_validate_phi}, -- [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, -- [VKD3DSIH_RET] = {0, 0, vsir_validate_ret}, -- [VKD3DSIH_SWITCH] = {0, 1, vsir_validate_switch}, -- [VKD3DSIH_SWITCH_MONOLITHIC] = {0, ~0u, vsir_validate_switch_monolithic}, -+ [VKD3DSIH_BRANCH] = {0, ~0u, vsir_validate_branch}, -+ [VKD3DSIH_HS_CONTROL_POINT_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, -+ [VKD3DSIH_HS_DECLS] = {0, 0, vsir_validate_hull_shader_phase}, -+ [VKD3DSIH_HS_FORK_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, -+ [VKD3DSIH_HS_JOIN_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, -+ [VKD3DSIH_DCL_GS_INSTANCES] = {0, 0, vsir_validate_dcl_gs_instances}, -+ [VKD3DSIH_DCL_HS_MAX_TESSFACTOR] = {0, 0, vsir_validate_dcl_hs_max_tessfactor}, -+ [VKD3DSIH_DCL_INPUT_PRIMITIVE] = {0, 0, vsir_validate_dcl_input_primitive}, -+ [VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT] = {0, 0, vsir_validate_dcl_output_control_point_count}, -+ [VKD3DSIH_DCL_OUTPUT_TOPOLOGY] = {0, 0, vsir_validate_dcl_output_topology}, -+ [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, -+ [VKD3DSIH_DCL_TESSELLATOR_DOMAIN] = {0, 0, vsir_validate_dcl_tessellator_domain}, -+ [VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE] = {0, 0, vsir_validate_dcl_tessellator_output_primitive}, -+ [VKD3DSIH_DCL_TESSELLATOR_PARTITIONING] = {0, 0, vsir_validate_dcl_tessellator_partitioning}, -+ [VKD3DSIH_DCL_VERTICES_OUT] = {0, 0, vsir_validate_dcl_vertices_out}, -+ [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, -+ [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, -+ [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, -+ [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, -+ [VKD3DSIH_ENDSWITCH] = {0, 0, vsir_validate_endswitch}, -+ [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, -+ [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, -+ [VKD3DSIH_LABEL] = {0, 1, vsir_validate_label}, -+ [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, -+ [VKD3DSIH_NOP] = {0, 0, vsir_validate_nop}, -+ [VKD3DSIH_PHI] = {1, ~0u, vsir_validate_phi}, -+ [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, -+ [VKD3DSIH_RET] = {0, 0, vsir_validate_ret}, -+ [VKD3DSIH_SWITCH] = {0, 1, vsir_validate_switch}, -+ [VKD3DSIH_SWITCH_MONOLITHIC] = {0, ~0u, vsir_validate_switch_monolithic}, - }; - - static void vsir_validate_instruction(struct validation_context *ctx) -@@ -6462,121 +6585,40 @@ static void vsir_validate_instruction(struct validation_context *ctx) - instruction->opcode); - } - -- switch (instruction->opcode) -+ if (version->type == VKD3D_SHADER_TYPE_HULL && ctx->phase == VKD3DSIH_INVALID) - { -- case VKD3DSIH_HS_DECLS: -- case VKD3DSIH_HS_CONTROL_POINT_PHASE: -- case VKD3DSIH_HS_FORK_PHASE: -- case VKD3DSIH_HS_JOIN_PHASE: -- vsir_validate_dst_count(ctx, instruction, 0); -- vsir_validate_src_count(ctx, instruction, 0); -- if (version->type != VKD3D_SHADER_TYPE_HULL) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, -- "Phase instruction %#x is only valid in a hull shader.", -- instruction->opcode); -- if (ctx->depth != 0) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -- "Phase instruction %#x must appear to top level.", -- instruction->opcode); -- ctx->phase = instruction->opcode; -- ctx->dcl_temps_found = false; -- return; -- -- case VKD3DSIH_DCL_HS_MAX_TESSFACTOR: -- /* Exclude non-finite values. */ -- if (!(instruction->declaration.max_tessellation_factor >= 1.0f -- && instruction->declaration.max_tessellation_factor <= 64.0f)) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Max tessellation factor %f is invalid.", -- instruction->declaration.max_tessellation_factor); -- return; -- -- case VKD3DSIH_DCL_INPUT_PRIMITIVE: -- if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED -- || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS input primitive %u is invalid.", -- instruction->declaration.primitive_type.type); -- return; -- -- case VKD3DSIH_DCL_VERTICES_OUT: -- if (instruction->declaration.count > 1024) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output vertex count %u is invalid.", -- instruction->declaration.count); -- return; -- -- case VKD3DSIH_DCL_OUTPUT_TOPOLOGY: -- if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED -- || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output primitive %u is invalid.", -- instruction->declaration.primitive_type.type); -- return; -- -- case VKD3DSIH_DCL_GS_INSTANCES: -- if (!instruction->declaration.count || instruction->declaration.count > 32) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS instance count %u is invalid.", -- instruction->declaration.count); -- return; -- -- case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT: -- if (!instruction->declaration.count || instruction->declaration.count > 32) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Output control point count %u is invalid.", -- instruction->declaration.count); -- return; -- -- case VKD3DSIH_DCL_TESSELLATOR_DOMAIN: -- if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID -- || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -- "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain); -- return; -- -- case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: -- if (!instruction->declaration.tessellator_output_primitive -- || instruction->declaration.tessellator_output_primitive > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -- "Tessellator output primitive %#x is invalid.", instruction->declaration.tessellator_output_primitive); -- return; -- -- case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING: -- if (!instruction->declaration.tessellator_partitioning -- || instruction->declaration.tessellator_partitioning > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, -- "Tessellator partitioning %#x is invalid.", instruction->declaration.tessellator_partitioning); -- return; -+ switch (instruction->opcode) -+ { -+ case VKD3DSIH_NOP: -+ case VKD3DSIH_HS_DECLS: -+ case VKD3DSIH_HS_CONTROL_POINT_PHASE: -+ case VKD3DSIH_HS_FORK_PHASE: -+ case VKD3DSIH_HS_JOIN_PHASE: -+ break; - -- default: -- break; -+ default: -+ if (!vsir_instruction_is_dcl(instruction)) -+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, -+ "Instruction %#x appear before any phase instruction in a hull shader.", -+ instruction->opcode); -+ break; -+ } - } - -- /* Only DCL instructions may occur outside hull shader phases. */ -- if (!vsir_instruction_is_dcl(instruction) && version->type == VKD3D_SHADER_TYPE_HULL -- && ctx->phase == VKD3DSIH_INVALID) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, -- "Instruction %#x appear before any phase instruction in a hull shader.", -- instruction->opcode); -- -- if (ctx->program->cf_type == VSIR_CF_BLOCKS && !vsir_instruction_is_dcl(instruction) -- && instruction->opcode != VKD3DSIH_NOP) -+ if (ctx->program->cf_type == VSIR_CF_BLOCKS && !ctx->inside_block) - { - switch (instruction->opcode) - { -+ case VKD3DSIH_NOP: - case VKD3DSIH_LABEL: -- if (ctx->inside_block) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid LABEL instruction inside a block."); -- ctx->inside_block = true; -- break; -- -- case VKD3DSIH_RET: -- case VKD3DSIH_BRANCH: -- case VKD3DSIH_SWITCH_MONOLITHIC: -- if (!ctx->inside_block) -- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, -- "Invalid instruction %#x outside any block.", -- instruction->opcode); -- ctx->inside_block = false; -+ case VKD3DSIH_HS_DECLS: -+ case VKD3DSIH_HS_CONTROL_POINT_PHASE: -+ case VKD3DSIH_HS_FORK_PHASE: -+ case VKD3DSIH_HS_JOIN_PHASE: - break; - - default: -- if (!ctx->inside_block) -+ if (!vsir_instruction_is_dcl(instruction)) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, - "Invalid instruction %#x outside any block.", - instruction->opcode); -diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c -new file mode 100644 -index 00000000000..2923494feed ---- /dev/null -+++ b/libs/vkd3d/libs/vkd3d-shader/msl.c -@@ -0,0 +1,129 @@ -+/* -+ * Copyright 2024 Feifan He 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 -+ */ -+ -+#include "vkd3d_shader_private.h" -+ -+struct msl_generator -+{ -+ struct vsir_program *program; -+ struct vkd3d_string_buffer_cache string_buffers; -+ struct vkd3d_string_buffer *buffer; -+ struct vkd3d_shader_location location; -+ struct vkd3d_shader_message_context *message_context; -+ unsigned int indent; -+}; -+ -+static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen, -+ enum vkd3d_shader_error error, const char *fmt, ...) -+{ -+ va_list args; -+ -+ va_start(args, fmt); -+ vkd3d_shader_verror(gen->message_context, &gen->location, error, fmt, args); -+ va_end(args); -+} -+ -+static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent) -+{ -+ vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); -+} -+ -+ -+static void msl_unhandled(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) -+{ -+ msl_print_indent(gen->buffer, gen->indent); -+ vkd3d_string_buffer_printf(gen->buffer, "/* */\n", ins->opcode); -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled instruction %#x.", ins->opcode); -+} -+ -+static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) -+{ -+ gen->location = ins->location; -+ -+ switch (ins->opcode) -+ { -+ case VKD3DSIH_NOP: -+ break; -+ default: -+ msl_unhandled(gen, ins); -+ break; -+ } -+} -+ -+static void msl_generator_generate(struct msl_generator *gen) -+{ -+ const struct vkd3d_shader_instruction_array *instructions = &gen->program->instructions; -+ unsigned int i; -+ -+ MESSAGE("Generating a MSL shader. This is unsupported; you get to keep all the pieces if it breaks.\n"); -+ -+ vkd3d_string_buffer_printf(gen->buffer, "/* Generated by %s. */\n\n", vkd3d_shader_get_version(NULL, NULL)); -+ -+ vkd3d_string_buffer_printf(gen->buffer, "void shader_main()\n{\n"); -+ -+ ++gen->indent; -+ for (i = 0; i < instructions->count; ++i) -+ { -+ msl_handle_instruction(gen, &instructions->elements[i]); -+ } -+ -+ vkd3d_string_buffer_printf(gen->buffer, "}\n"); -+ -+ if (TRACE_ON()) -+ vkd3d_string_buffer_trace(gen->buffer); -+} -+ -+static void msl_generator_cleanup(struct msl_generator *gen) -+{ -+ vkd3d_string_buffer_release(&gen->string_buffers, gen->buffer); -+ vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); -+} -+ -+static int msl_generator_init(struct msl_generator *gen, struct vsir_program *program, -+ struct vkd3d_shader_message_context *message_context) -+{ -+ memset(gen, 0, sizeof(*gen)); -+ gen->program = program; -+ vkd3d_string_buffer_cache_init(&gen->string_buffers); -+ if (!(gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers))) -+ { -+ vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); -+ return VKD3D_ERROR_OUT_OF_MEMORY; -+ } -+ gen->message_context = message_context; -+ -+ return VKD3D_OK; -+} -+ -+int msl_compile(struct vsir_program *program, uint64_t config_flags, -+ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) -+{ -+ struct msl_generator generator; -+ int ret; -+ -+ if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0) -+ return ret; -+ -+ if ((ret = msl_generator_init(&generator, program, message_context)) < 0) -+ return ret; -+ msl_generator_generate(&generator); -+ msl_generator_cleanup(&generator); -+ -+ return VKD3D_ERROR_INVALID_SHADER; -+} -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index a9d6c9e7c13..48efe1e2d72 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -635,6 +635,16 @@ enum vkd3d_sm4_stat_field - VKD3D_STAT_SAMPLE_BIAS, - VKD3D_STAT_LOAD, - VKD3D_STAT_STORE, -+ VKD3D_STAT_DCL_VERTICES_OUT, -+ VKD3D_STAT_DCL_INPUT_PRIMITIVE, -+ VKD3D_STAT_DCL_OUTPUT_TOPOLOGY, -+ VKD3D_STAT_DCL_GS_INSTANCES, -+ VKD3D_STAT_BITWISE, -+ VKD3D_STAT_ATOMIC, -+ VKD3D_STAT_TESS_DOMAIN, -+ VKD3D_STAT_TESS_PARTITIONING, -+ VKD3D_STAT_TESS_OUTPUT_PRIMITIVE, -+ VKD3D_STAT_TESS_CONTROL_POINT_COUNT, - VKD3D_STAT_COUNT, - }; - -@@ -1809,6 +1819,44 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) - {VKD3D_SM5_OP_STORE_UAV_TYPED, VKD3D_STAT_STORE}, - {VKD3D_SM5_OP_STORE_RAW, VKD3D_STAT_STORE}, - {VKD3D_SM5_OP_STORE_STRUCTURED,VKD3D_STAT_STORE}, -+ -+ {VKD3D_SM4_OP_DCL_VERTICES_OUT, VKD3D_STAT_DCL_VERTICES_OUT}, -+ {VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE, VKD3D_STAT_DCL_INPUT_PRIMITIVE}, -+ {VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY, VKD3D_STAT_DCL_OUTPUT_TOPOLOGY}, -+ {VKD3D_SM5_OP_DCL_GS_INSTANCES, VKD3D_STAT_DCL_GS_INSTANCES}, -+ -+ {VKD3D_SM4_OP_AND, VKD3D_STAT_BITWISE}, -+ {VKD3D_SM4_OP_NOT, VKD3D_STAT_BITWISE}, -+ {VKD3D_SM4_OP_OR, VKD3D_STAT_BITWISE}, -+ {VKD3D_SM4_OP_XOR, VKD3D_STAT_BITWISE}, -+ -+ {VKD3D_SM5_OP_ATOMIC_AND, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_OR, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_XOR, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_CMP_STORE, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_IADD, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_IMAX, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_IMIN, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_UMAX, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_ATOMIC_UMIN, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_ALLOC, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_CONSUME, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_IADD, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_AND, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_OR, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_XOR, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_EXCH, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_CMP_EXCH, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_IMAX, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_IMIN, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_UMAX, VKD3D_STAT_ATOMIC}, -+ {VKD3D_SM5_OP_IMM_ATOMIC_UMIN, VKD3D_STAT_ATOMIC}, -+ -+ {VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN, VKD3D_STAT_TESS_DOMAIN}, -+ {VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING, VKD3D_STAT_TESS_PARTITIONING}, -+ {VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE, VKD3D_STAT_TESS_OUTPUT_PRIMITIVE}, -+ {VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, -+ {VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, - }; - - memset(lookup, 0, sizeof(*lookup)); -@@ -4353,8 +4401,9 @@ static void sm4_write_src_register(const struct tpf_writer *tpf, const struct vk - - static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4_instruction *instr) - { -+ enum vkd3d_shader_type shader_type = tpf->ctx->profile->type; -+ uint32_t token = instr->opcode | instr->extra_bits, opcode; - struct vkd3d_bytecode_buffer *buffer = tpf->buffer; -- uint32_t token = instr->opcode | instr->extra_bits; - enum vkd3d_sm4_stat_field stat_field; - unsigned int size, i, j; - size_t token_position; -@@ -4391,8 +4440,39 @@ static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4 - - ++tpf->stat->fields[VKD3D_STAT_INSTR_COUNT]; - -- stat_field = get_stat_field_from_sm4_opcode(&tpf->lookup, instr->opcode & VKD3D_SM4_OPCODE_MASK); -- ++tpf->stat->fields[stat_field]; -+ opcode = instr->opcode & VKD3D_SM4_OPCODE_MASK; -+ stat_field = get_stat_field_from_sm4_opcode(&tpf->lookup, opcode); -+ -+ switch (opcode) -+ { -+ case VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY: -+ case VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE: -+ tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM4_PRIMITIVE_TYPE_MASK) -+ >> VKD3D_SM4_PRIMITIVE_TYPE_SHIFT; -+ break; -+ case VKD3D_SM4_OP_DCL_VERTICES_OUT: -+ case VKD3D_SM5_OP_DCL_GS_INSTANCES: -+ tpf->stat->fields[stat_field] = instr->idx[0]; -+ break; -+ case VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN: -+ case VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING: -+ case VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: -+ tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM5_TESSELLATOR_MASK) >> VKD3D_SM5_TESSELLATOR_SHIFT; -+ break; -+ case VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT: -+ case VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT: -+ if ((shader_type == VKD3D_SHADER_TYPE_HULL && opcode == VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT) -+ || (shader_type == VKD3D_SHADER_TYPE_DOMAIN -+ && opcode == VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT)) -+ { -+ tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM5_CONTROL_POINT_COUNT_MASK) -+ >> VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT; -+ } -+ break; -+ default: -+ ++tpf->stat->fields[stat_field]; -+ } -+ - } - - static bool encode_texel_offset_as_aoffimmi(struct sm4_instruction *instr, -@@ -6349,23 +6429,23 @@ static void write_sm4_stat(struct hlsl_ctx *ctx, const struct sm4_stat *stat, st - put_u32(&buffer, stat->fields[VKD3D_STAT_MOV]); - put_u32(&buffer, stat->fields[VKD3D_STAT_MOVC]); - put_u32(&buffer, stat->fields[VKD3D_STAT_CONV]); -- put_u32(&buffer, 0); /* Bitwise instructions */ -- put_u32(&buffer, 0); /* Input primitive */ -- put_u32(&buffer, 0); /* GS output topology */ -- put_u32(&buffer, 0); /* GS max output vertex count */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_BITWISE]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_INPUT_PRIMITIVE]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_OUTPUT_TOPOLOGY]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_VERTICES_OUT]); - put_u32(&buffer, 0); /* Unknown */ - put_u32(&buffer, 0); /* Unknown */ - put_u32(&buffer, 0); /* Sample frequency */ - - if (hlsl_version_ge(ctx, 5, 0)) - { -- put_u32(&buffer, 0); /* GS instance count */ -- put_u32(&buffer, 0); /* Control point count */ -- put_u32(&buffer, 0); /* HS output primitive */ -- put_u32(&buffer, 0); /* HS partitioning */ -- put_u32(&buffer, 0); /* Tessellator domain */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_GS_INSTANCES]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_CONTROL_POINT_COUNT]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_OUTPUT_PRIMITIVE]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_PARTITIONING]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_DOMAIN]); - put_u32(&buffer, 0); /* Barrier instructions */ -- put_u32(&buffer, 0); /* Interlocked instructions */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_ATOMIC]); - put_u32(&buffer, stat->fields[VKD3D_STAT_STORE]); - } - --- -2.45.2 - diff --git a/patches/vkd3d-latest/0009-Updated-vkd3d-to-32ced3bd8f52e19d184c8191f420dcb7bad.patch b/patches/vkd3d-latest/0009-Updated-vkd3d-to-32ced3bd8f52e19d184c8191f420dcb7bad.patch deleted file mode 100644 index c28f3080..00000000 --- a/patches/vkd3d-latest/0009-Updated-vkd3d-to-32ced3bd8f52e19d184c8191f420dcb7bad.patch +++ /dev/null @@ -1,820 +0,0 @@ -From 72a24faa48be8d8a3b396a94fb8e028b7eaf6898 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Fri, 20 Sep 2024 07:31:45 +1000 -Subject: [PATCH] Updated vkd3d to 32ced3bd8f52e19d184c8191f420dcb7badbbad2. - ---- - libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 35 +- - libs/vkd3d/libs/vkd3d-shader/glsl.c | 334 +++++++++++++++++- - libs/vkd3d/libs/vkd3d-shader/msl.c | 146 ++++++++ - libs/vkd3d/libs/vkd3d-shader/tpf.c | 18 +- - .../libs/vkd3d-shader/vkd3d_shader_main.c | 3 +- - .../libs/vkd3d-shader/vkd3d_shader_private.h | 6 +- - 6 files changed, 506 insertions(+), 36 deletions(-) - -diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -index 9c7be1f08bb..10f2e5e5e6d 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c -@@ -104,6 +104,19 @@ enum vkd3d_sm1_resource_type - VKD3D_SM1_RESOURCE_TEXTURE_3D = 0x4, - }; - -+enum vkd3d_sm1_misc_register -+{ -+ VKD3D_SM1_MISC_POSITION = 0x0, -+ VKD3D_SM1_MISC_FACE = 0x1, -+}; -+ -+enum vkd3d_sm1_rastout_register -+{ -+ VKD3D_SM1_RASTOUT_POSITION = 0x0, -+ VKD3D_SM1_RASTOUT_FOG = 0x1, -+ VKD3D_SM1_RASTOUT_POINT_SIZE = 0x2, -+}; -+ - enum vkd3d_sm1_opcode - { - VKD3D_SM1_OP_NOP = 0x00, -@@ -1385,22 +1398,22 @@ bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, - {"depth", true, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_DEPTHOUT}, - {"sv_depth", true, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_DEPTHOUT}, - {"sv_target", true, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_COLOROUT}, -- {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, D3DSMO_POSITION}, -- {"vface", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, D3DSMO_FACE}, -- {"vpos", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, D3DSMO_POSITION}, -+ {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, VKD3D_SM1_MISC_POSITION}, -+ {"vface", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, VKD3D_SM1_MISC_FACE}, -+ {"vpos", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, VKD3D_SM1_MISC_POSITION}, - - {"color", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_ATTROUT}, -- {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_FOG}, -- {"position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, -- {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_POINT_SIZE}, -- {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, -+ {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_FOG}, -+ {"position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, -+ {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POINT_SIZE}, -+ {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, - {"texcoord", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_TEXCRDOUT}, - - {"color", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_ATTROUT}, -- {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_FOG}, -- {"position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, -- {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_POINT_SIZE}, -- {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, D3DSRO_POSITION}, -+ {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_FOG}, -+ {"position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, -+ {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POINT_SIZE}, -+ {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, - {"texcoord", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_TEXCRDOUT}, - }; - -diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c -index f8fec6ac2bc..ac101d44214 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/glsl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c -@@ -48,6 +48,10 @@ struct vkd3d_glsl_generator - } limits; - bool interstage_input; - bool interstage_output; -+ -+ const struct vkd3d_shader_interface_info *interface_info; -+ const struct vkd3d_shader_descriptor_offset_info *offset_info; -+ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info; - }; - - static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( -@@ -133,6 +137,40 @@ static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer, - vkd3d_string_buffer_printf(buffer, "%s_out[%u]", gen->prefix, reg->idx[0].offset); - break; - -+ case VKD3DSPR_IMMCONST: -+ switch (reg->dimension) -+ { -+ case VSIR_DIMENSION_SCALAR: -+ vkd3d_string_buffer_printf(buffer, "%#xu", reg->u.immconst_u32[0]); -+ break; -+ -+ default: -+ vkd3d_string_buffer_printf(buffer, "", reg->dimension); -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled dimension %#x.", reg->dimension); -+ break; -+ } -+ break; -+ -+ case VKD3DSPR_CONSTBUFFER: -+ if (reg->idx_count != 3) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled constant buffer register index count %u.", reg->idx_count); -+ vkd3d_string_buffer_printf(buffer, "", reg->type); -+ break; -+ } -+ if (reg->idx[0].rel_addr || reg->idx[2].rel_addr) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled constant buffer register indirect addressing."); -+ vkd3d_string_buffer_printf(buffer, "", reg->type); -+ break; -+ } -+ vkd3d_string_buffer_printf(buffer, "%s_cb_%u[%u]", -+ gen->prefix, reg->idx[0].offset, reg->idx[2].offset); -+ break; -+ - default: - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, - "Internal compiler error: Unhandled register type %#x.", reg->type); -@@ -172,23 +210,86 @@ static void glsl_src_cleanup(struct glsl_src *src, struct vkd3d_string_buffer_ca - vkd3d_string_buffer_release(cache, src->str); - } - -+static void shader_glsl_print_bitcast(struct vkd3d_string_buffer *dst, struct vkd3d_glsl_generator *gen, -+ const char *src, enum vkd3d_data_type dst_data_type, enum vkd3d_data_type src_data_type) -+{ -+ if (dst_data_type == VKD3D_DATA_UNORM || dst_data_type == VKD3D_DATA_SNORM) -+ dst_data_type = VKD3D_DATA_FLOAT; -+ if (src_data_type == VKD3D_DATA_UNORM || src_data_type == VKD3D_DATA_SNORM) -+ src_data_type = VKD3D_DATA_FLOAT; -+ -+ if (dst_data_type == src_data_type) -+ { -+ vkd3d_string_buffer_printf(dst, "%s", src); -+ return; -+ } -+ -+ if (src_data_type == VKD3D_DATA_FLOAT && dst_data_type == VKD3D_DATA_UINT) -+ { -+ vkd3d_string_buffer_printf(dst, "floatBitsToUint(%s)", src); -+ return; -+ } -+ -+ if (src_data_type == VKD3D_DATA_UINT && dst_data_type == VKD3D_DATA_FLOAT) -+ { -+ vkd3d_string_buffer_printf(dst, "uintBitsToFloat(%s)", src); -+ return; -+ } -+ -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled bitcast from %#x to %#x.", -+ src_data_type, dst_data_type); -+ vkd3d_string_buffer_printf(dst, "%s", src); -+} -+ - static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) - { - const struct vkd3d_shader_register *reg = &vsir_src->reg; -+ struct vkd3d_string_buffer *register_name, *str; -+ enum vkd3d_data_type src_data_type; - - glsl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); -+ register_name = vkd3d_string_buffer_get(&gen->string_buffers); - - if (reg->non_uniform) - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, - "Internal compiler error: Unhandled 'non-uniform' modifier."); -- if (vsir_src->modifiers) -- vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -- "Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers); - -- shader_glsl_print_register_name(glsl_src->str, gen, reg); -+ if (reg->type == VKD3DSPR_IMMCONST) -+ src_data_type = VKD3D_DATA_UINT; -+ else -+ src_data_type = VKD3D_DATA_FLOAT; -+ -+ shader_glsl_print_register_name(register_name, gen, reg); -+ -+ if (!vsir_src->modifiers) -+ str = glsl_src->str; -+ else -+ str = vkd3d_string_buffer_get(&gen->string_buffers); -+ -+ shader_glsl_print_bitcast(str, gen, register_name->buffer, reg->data_type, src_data_type); - if (reg->dimension == VSIR_DIMENSION_VEC4) -- shader_glsl_print_swizzle(glsl_src->str, vsir_src->swizzle, mask); -+ shader_glsl_print_swizzle(str, vsir_src->swizzle, mask); -+ -+ switch (vsir_src->modifiers) -+ { -+ case VKD3DSPSM_NONE: -+ break; -+ case VKD3DSPSM_ABS: -+ vkd3d_string_buffer_printf(glsl_src->str, "abs(%s)", str->buffer); -+ break; -+ default: -+ vkd3d_string_buffer_printf(glsl_src->str, "(%s)", -+ vsir_src->modifiers, str->buffer); -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers); -+ break; -+ } -+ -+ if (str != glsl_src->str) -+ vkd3d_string_buffer_release(&gen->string_buffers, str); -+ vkd3d_string_buffer_release(&gen->string_buffers, register_name); - } - - static void glsl_dst_cleanup(struct glsl_dst *dst, struct vkd3d_string_buffer_cache *cache) -@@ -222,6 +323,9 @@ static uint32_t glsl_dst_init(struct glsl_dst *glsl_dst, struct vkd3d_glsl_gener - static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( - struct vkd3d_glsl_generator *gen, struct glsl_dst *dst, const char *format, ...) - { -+ const struct vkd3d_shader_register *dst_reg = &dst->vsir->reg; -+ struct vkd3d_string_buffer *buffer = gen->buffer; -+ bool close = true; - va_list args; - - if (dst->vsir->shift) -@@ -231,14 +335,28 @@ static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment( - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, - "Internal compiler error: Unhandled destination modifier(s) %#x.", dst->vsir->modifiers); - -- shader_glsl_print_indent(gen->buffer, gen->indent); -- vkd3d_string_buffer_printf(gen->buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); -+ shader_glsl_print_indent(buffer, gen->indent); -+ vkd3d_string_buffer_printf(buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); -+ -+ switch (dst_reg->data_type) -+ { -+ default: -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled destination register data type %#x.", dst_reg->data_type); -+ /* fall through */ -+ case VKD3D_DATA_FLOAT: -+ close = false; -+ break; -+ case VKD3D_DATA_UINT: -+ vkd3d_string_buffer_printf(buffer, "uintBitsToFloat("); -+ break; -+ } - - va_start(args, format); -- vkd3d_string_buffer_vprintf(gen->buffer, format, args); -+ vkd3d_string_buffer_vprintf(buffer, format, args); - va_end(args); - -- vkd3d_string_buffer_printf(gen->buffer, ";\n"); -+ vkd3d_string_buffer_printf(buffer, "%s;\n", close ? ")" : ""); - } - - static void shader_glsl_unhandled(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) -@@ -249,6 +367,24 @@ static void shader_glsl_unhandled(struct vkd3d_glsl_generator *gen, const struct - "Internal compiler error: Unhandled instruction %#x.", ins->opcode); - } - -+static void shader_glsl_binop(struct vkd3d_glsl_generator *gen, -+ const struct vkd3d_shader_instruction *ins, const char *op) -+{ -+ struct glsl_src src[2]; -+ struct glsl_dst dst; -+ uint32_t mask; -+ -+ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); -+ glsl_src_init(&src[0], gen, &ins->src[0], mask); -+ glsl_src_init(&src[1], gen, &ins->src[1], mask); -+ -+ shader_glsl_print_assignment(gen, &dst, "%s %s %s", src[0].str->buffer, op, src[1].str->buffer); -+ -+ glsl_src_cleanup(&src[1], &gen->string_buffers); -+ glsl_src_cleanup(&src[0], &gen->string_buffers); -+ glsl_dst_cleanup(&dst, &gen->string_buffers); -+} -+ - static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) - { - struct glsl_src src; -@@ -267,11 +403,12 @@ static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d - static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, - enum vkd3d_shader_sysval_semantic sysval, unsigned int idx) - { -+ const struct vkd3d_shader_version *version = &gen->program->shader_version; -+ - switch (sysval) - { - case VKD3D_SHADER_SV_POSITION: -- if (gen->program->shader_version.type == VKD3D_SHADER_TYPE_PIXEL -- || gen->program->shader_version.type == VKD3D_SHADER_TYPE_COMPUTE) -+ if (version->type == VKD3D_SHADER_TYPE_PIXEL || version->type == VKD3D_SHADER_TYPE_COMPUTE) - { - vkd3d_string_buffer_printf(buffer, "", sysval); - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -@@ -286,6 +423,13 @@ static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, st - } - break; - -+ case VKD3D_SHADER_SV_TARGET: -+ if (version->type != VKD3D_SHADER_TYPE_PIXEL) -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled SV_TARGET in shader type #%x.", version->type); -+ vkd3d_string_buffer_printf(buffer, "shader_out_%u", idx); -+ break; -+ - default: - vkd3d_string_buffer_printf(buffer, "", sysval); - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -@@ -400,6 +544,12 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, - - switch (ins->opcode) - { -+ case VKD3DSIH_ADD: -+ shader_glsl_binop(gen, ins, "+"); -+ break; -+ case VKD3DSIH_AND: -+ shader_glsl_binop(gen, ins, "&"); -+ break; - case VKD3DSIH_DCL_INPUT: - case VKD3DSIH_DCL_OUTPUT: - case VKD3DSIH_DCL_OUTPUT_SIV: -@@ -417,6 +567,151 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, - } - } - -+static bool shader_glsl_check_shader_visibility(const struct vkd3d_glsl_generator *gen, -+ enum vkd3d_shader_visibility visibility) -+{ -+ enum vkd3d_shader_type t = gen->program->shader_version.type; -+ -+ switch (visibility) -+ { -+ case VKD3D_SHADER_VISIBILITY_ALL: -+ return true; -+ case VKD3D_SHADER_VISIBILITY_VERTEX: -+ return t == VKD3D_SHADER_TYPE_VERTEX; -+ case VKD3D_SHADER_VISIBILITY_HULL: -+ return t == VKD3D_SHADER_TYPE_HULL; -+ case VKD3D_SHADER_VISIBILITY_DOMAIN: -+ return t == VKD3D_SHADER_TYPE_DOMAIN; -+ case VKD3D_SHADER_VISIBILITY_GEOMETRY: -+ return t == VKD3D_SHADER_TYPE_GEOMETRY; -+ case VKD3D_SHADER_VISIBILITY_PIXEL: -+ return t == VKD3D_SHADER_TYPE_PIXEL; -+ case VKD3D_SHADER_VISIBILITY_COMPUTE: -+ return t == VKD3D_SHADER_TYPE_COMPUTE; -+ default: -+ WARN("Invalid shader visibility %#x.\n", visibility); -+ return false; -+ } -+} -+ -+static bool shader_glsl_get_cbv_binding(const struct vkd3d_glsl_generator *gen, -+ unsigned int register_space, unsigned int register_idx, unsigned int *binding_idx) -+{ -+ const struct vkd3d_shader_interface_info *interface_info = gen->interface_info; -+ const struct vkd3d_shader_resource_binding *binding; -+ unsigned int i; -+ -+ if (!interface_info) -+ return false; -+ -+ for (i = 0; i < interface_info->binding_count; ++i) -+ { -+ binding = &interface_info->bindings[i]; -+ -+ if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_CBV) -+ continue; -+ if (binding->register_space != register_space) -+ continue; -+ if (binding->register_index != register_idx) -+ continue; -+ if (!shader_glsl_check_shader_visibility(gen, binding->shader_visibility)) -+ continue; -+ if (!(binding->flags & VKD3D_SHADER_BINDING_FLAG_BUFFER)) -+ continue; -+ *binding_idx = i; -+ return true; -+ } -+ -+ return false; -+} -+ -+static void shader_glsl_generate_cbv_declaration(struct vkd3d_glsl_generator *gen, -+ const struct vkd3d_shader_descriptor_info1 *cbv) -+{ -+ const struct vkd3d_shader_descriptor_binding *binding; -+ const struct vkd3d_shader_descriptor_offset *offset; -+ struct vkd3d_string_buffer *buffer = gen->buffer; -+ const char *prefix = gen->prefix; -+ unsigned int binding_idx; -+ size_t size; -+ -+ if (cbv->count != 1) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, -+ "Constant buffer %u has unsupported descriptor array size %u.", cbv->register_id, cbv->count); -+ return; -+ } -+ -+ if (!shader_glsl_get_cbv_binding(gen, cbv->register_space, cbv->register_index, &binding_idx)) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, -+ "No descriptor binding specified for constant buffer %u.", cbv->register_id); -+ return; -+ } -+ -+ binding = &gen->interface_info->bindings[binding_idx].binding; -+ -+ if (binding->set != 0) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, -+ "Unsupported binding set %u specified for constant buffer %u.", binding->set, cbv->register_id); -+ return; -+ } -+ -+ if (binding->count != 1) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, -+ "Unsupported binding count %u specified for constant buffer %u.", binding->count, cbv->register_id); -+ return; -+ } -+ -+ if (gen->offset_info && gen->offset_info->binding_offsets) -+ { -+ offset = &gen->offset_info->binding_offsets[binding_idx]; -+ if (offset->static_offset || offset->dynamic_offset_index != ~0u) -+ { -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled descriptor offset specified for constant buffer %u.", -+ cbv->register_id); -+ return; -+ } -+ } -+ -+ size = align(cbv->buffer_size, VKD3D_VEC4_SIZE * sizeof(uint32_t)); -+ size /= VKD3D_VEC4_SIZE * sizeof(uint32_t); -+ -+ vkd3d_string_buffer_printf(buffer, -+ "layout(std140, binding = %u) uniform block_%s_cb_%u { vec4 %s_cb_%u[%zu]; };\n", -+ binding->binding, prefix, cbv->register_id, prefix, cbv->register_id, size); -+} -+ -+static void shader_glsl_generate_descriptor_declarations(struct vkd3d_glsl_generator *gen) -+{ -+ const struct vkd3d_shader_scan_descriptor_info1 *info = gen->descriptor_info; -+ const struct vkd3d_shader_descriptor_info1 *descriptor; -+ unsigned int i; -+ -+ for (i = 0; i < info->descriptor_count; ++i) -+ { -+ descriptor = &info->descriptors[i]; -+ -+ switch (descriptor->type) -+ { -+ case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: -+ shader_glsl_generate_cbv_declaration(gen, descriptor); -+ break; -+ -+ default: -+ vkd3d_string_buffer_printf(gen->buffer, "/* */\n", descriptor->type); -+ vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -+ "Internal compiler error: Unhandled descriptor type %#x.", descriptor->type); -+ break; -+ } -+ } -+ if (info->descriptor_count) -+ vkd3d_string_buffer_printf(gen->buffer, "\n"); -+} -+ - static void shader_glsl_generate_interface_block(struct vkd3d_string_buffer *buffer, - const char *type, unsigned int count) - { -@@ -545,6 +840,7 @@ static void shader_glsl_generate_declarations(struct vkd3d_glsl_generator *gen) - const struct vsir_program *program = gen->program; - struct vkd3d_string_buffer *buffer = gen->buffer; - -+ shader_glsl_generate_descriptor_declarations(gen); - shader_glsl_generate_input_declarations(gen); - shader_glsl_generate_output_declarations(gen); - -@@ -634,7 +930,9 @@ static void shader_glsl_init_limits(struct vkd3d_glsl_generator *gen, const stru - } - - static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen, -- struct vsir_program *program, struct vkd3d_shader_message_context *message_context) -+ struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, -+ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, -+ struct vkd3d_shader_message_context *message_context) - { - enum vkd3d_shader_type type = program->shader_version.type; - -@@ -642,6 +940,7 @@ static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen, - gen->program = program; - vkd3d_string_buffer_cache_init(&gen->string_buffers); - gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers); -+ gen->location.source_name = compile_info->source_name; - gen->message_context = message_context; - if (!(gen->prefix = shader_glsl_get_prefix(type))) - { -@@ -652,11 +951,16 @@ static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen, - shader_glsl_init_limits(gen, &program->shader_version); - gen->interstage_input = type != VKD3D_SHADER_TYPE_VERTEX; - gen->interstage_output = type != VKD3D_SHADER_TYPE_PIXEL; -+ -+ gen->interface_info = vkd3d_find_struct(compile_info->next, INTERFACE_INFO); -+ gen->offset_info = vkd3d_find_struct(compile_info->next, DESCRIPTOR_OFFSET_INFO); -+ gen->descriptor_info = descriptor_info; - } - - int glsl_compile(struct vsir_program *program, uint64_t config_flags, -- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, -- struct vkd3d_shader_message_context *message_context) -+ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, -+ const struct vkd3d_shader_compile_info *compile_info, -+ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) - { - struct vkd3d_glsl_generator generator; - int ret; -@@ -664,7 +968,7 @@ int glsl_compile(struct vsir_program *program, uint64_t config_flags, - if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0) - return ret; - -- vkd3d_glsl_generator_init(&generator, program, message_context); -+ vkd3d_glsl_generator_init(&generator, program, compile_info, descriptor_info, message_context); - ret = vkd3d_glsl_generator_generate(&generator, out); - vkd3d_glsl_generator_cleanup(&generator); - -diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c -index 2923494feed..7d2e713cddc 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/msl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/msl.c -@@ -18,6 +18,18 @@ - - #include "vkd3d_shader_private.h" - -+struct msl_src -+{ -+ struct vkd3d_string_buffer *str; -+}; -+ -+struct msl_dst -+{ -+ const struct vkd3d_shader_dst_param *vsir; -+ struct vkd3d_string_buffer *register_name; -+ struct vkd3d_string_buffer *mask; -+}; -+ - struct msl_generator - { - struct vsir_program *program; -@@ -43,6 +55,113 @@ static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int in - vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); - } - -+static void msl_print_register_name(struct vkd3d_string_buffer *buffer, -+ struct msl_generator *gen, const struct vkd3d_shader_register *reg) -+{ -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled register type %#x.", reg->type); -+ vkd3d_string_buffer_printf(buffer, "", reg->type); -+} -+ -+static void msl_print_swizzle(struct vkd3d_string_buffer *buffer, uint32_t swizzle, uint32_t mask) -+{ -+ const char swizzle_chars[] = "xyzw"; -+ unsigned int i; -+ -+ vkd3d_string_buffer_printf(buffer, "."); -+ for (i = 0; i < VKD3D_VEC4_SIZE; ++i) -+ { -+ if (mask & (VKD3DSP_WRITEMASK_0 << i)) -+ vkd3d_string_buffer_printf(buffer, "%c", swizzle_chars[vsir_swizzle_get_component(swizzle, i)]); -+ } -+} -+ -+static void msl_print_write_mask(struct vkd3d_string_buffer *buffer, uint32_t write_mask) -+{ -+ vkd3d_string_buffer_printf(buffer, "."); -+ if (write_mask & VKD3DSP_WRITEMASK_0) -+ vkd3d_string_buffer_printf(buffer, "x"); -+ if (write_mask & VKD3DSP_WRITEMASK_1) -+ vkd3d_string_buffer_printf(buffer, "y"); -+ if (write_mask & VKD3DSP_WRITEMASK_2) -+ vkd3d_string_buffer_printf(buffer, "z"); -+ if (write_mask & VKD3DSP_WRITEMASK_3) -+ vkd3d_string_buffer_printf(buffer, "w"); -+} -+ -+static void msl_src_cleanup(struct msl_src *src, struct vkd3d_string_buffer_cache *cache) -+{ -+ vkd3d_string_buffer_release(cache, src->str); -+} -+ -+static void msl_src_init(struct msl_src *msl_src, struct msl_generator *gen, -+ const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) -+{ -+ const struct vkd3d_shader_register *reg = &vsir_src->reg; -+ -+ msl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); -+ -+ if (reg->non_uniform) -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled 'non-uniform' modifier."); -+ if (vsir_src->modifiers) -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers); -+ -+ msl_print_register_name(msl_src->str, gen, reg); -+ if (reg->dimension == VSIR_DIMENSION_VEC4) -+ msl_print_swizzle(msl_src->str, vsir_src->swizzle, mask); -+} -+ -+static void msl_dst_cleanup(struct msl_dst *dst, struct vkd3d_string_buffer_cache *cache) -+{ -+ vkd3d_string_buffer_release(cache, dst->mask); -+ vkd3d_string_buffer_release(cache, dst->register_name); -+} -+ -+static uint32_t msl_dst_init(struct msl_dst *msl_dst, struct msl_generator *gen, -+ const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_dst_param *vsir_dst) -+{ -+ uint32_t write_mask = vsir_dst->write_mask; -+ -+ if (ins->flags & VKD3DSI_PRECISE_XYZW) -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled 'precise' modifier."); -+ if (vsir_dst->reg.non_uniform) -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled 'non-uniform' modifier."); -+ -+ msl_dst->vsir = vsir_dst; -+ msl_dst->register_name = vkd3d_string_buffer_get(&gen->string_buffers); -+ msl_dst->mask = vkd3d_string_buffer_get(&gen->string_buffers); -+ -+ msl_print_register_name(msl_dst->register_name, gen, &vsir_dst->reg); -+ msl_print_write_mask(msl_dst->mask, write_mask); -+ -+ return write_mask; -+} -+ -+static void VKD3D_PRINTF_FUNC(3, 4) msl_print_assignment( -+ struct msl_generator *gen, struct msl_dst *dst, const char *format, ...) -+{ -+ va_list args; -+ -+ if (dst->vsir->shift) -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled destination shift %#x.", dst->vsir->shift); -+ if (dst->vsir->modifiers) -+ msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, -+ "Internal compiler error: Unhandled destination modifier(s) %#x.", dst->vsir->modifiers); -+ -+ msl_print_indent(gen->buffer, gen->indent); -+ vkd3d_string_buffer_printf(gen->buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer); -+ -+ va_start(args, format); -+ vkd3d_string_buffer_vprintf(gen->buffer, format, args); -+ va_end(args); -+ -+ vkd3d_string_buffer_printf(gen->buffer, ";\n"); -+} - - static void msl_unhandled(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) - { -@@ -52,6 +171,27 @@ static void msl_unhandled(struct msl_generator *gen, const struct vkd3d_shader_i - "Internal compiler error: Unhandled instruction %#x.", ins->opcode); - } - -+static void msl_mov(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) -+{ -+ struct msl_src src; -+ struct msl_dst dst; -+ uint32_t mask; -+ -+ mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]); -+ msl_src_init(&src, gen, &ins->src[0], mask); -+ -+ msl_print_assignment(gen, &dst, "%s", src.str->buffer); -+ -+ msl_src_cleanup(&src, &gen->string_buffers); -+ msl_dst_cleanup(&dst, &gen->string_buffers); -+} -+ -+static void msl_ret(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) -+{ -+ msl_print_indent(gen->buffer, gen->indent); -+ vkd3d_string_buffer_printf(gen->buffer, "return;\n"); -+} -+ - static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) - { - gen->location = ins->location; -@@ -60,6 +200,12 @@ static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d - { - case VKD3DSIH_NOP: - break; -+ case VKD3DSIH_MOV: -+ msl_mov(gen, ins); -+ break; -+ case VKD3DSIH_RET: -+ msl_ret(gen, ins); -+ break; - default: - msl_unhandled(gen, ins); - break; -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index 48efe1e2d72..cbf28f5ec50 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -645,6 +645,9 @@ enum vkd3d_sm4_stat_field - VKD3D_STAT_TESS_PARTITIONING, - VKD3D_STAT_TESS_OUTPUT_PRIMITIVE, - VKD3D_STAT_TESS_CONTROL_POINT_COUNT, -+ VKD3D_STAT_BARRIER, -+ VKD3D_STAT_LOD, -+ VKD3D_STAT_GATHER, - VKD3D_STAT_COUNT, - }; - -@@ -1793,17 +1796,16 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) - {VKD3D_SM4_OP_SAMPLE_LOD, VKD3D_STAT_SAMPLE}, - {VKD3D_SM5_OP_SAMPLE_LOD_S, VKD3D_STAT_SAMPLE}, - {VKD3D_SM5_OP_SAMPLE_CL_S, VKD3D_STAT_SAMPLE}, -- {VKD3D_SM4_OP_GATHER4, VKD3D_STAT_SAMPLE}, -- {VKD3D_SM5_OP_GATHER4_PO, VKD3D_STAT_SAMPLE}, - {VKD3D_SM4_OP_SAMPLE_C, VKD3D_STAT_SAMPLE_C}, - {VKD3D_SM4_OP_SAMPLE_C_LZ, VKD3D_STAT_SAMPLE_C}, - {VKD3D_SM5_OP_SAMPLE_C_LZ_S, VKD3D_STAT_SAMPLE_C}, - {VKD3D_SM5_OP_SAMPLE_C_CL_S, VKD3D_STAT_SAMPLE_C}, -- {VKD3D_SM5_OP_GATHER4_C, VKD3D_STAT_SAMPLE_C}, -- {VKD3D_SM5_OP_GATHER4_PO_C, VKD3D_STAT_SAMPLE_C}, - {VKD3D_SM4_OP_SAMPLE_GRAD, VKD3D_STAT_SAMPLE_GRAD}, - {VKD3D_SM5_OP_SAMPLE_GRAD_CL_S, VKD3D_STAT_SAMPLE_GRAD}, - {VKD3D_SM4_OP_SAMPLE_B, VKD3D_STAT_SAMPLE_BIAS}, -+ {VKD3D_SM4_OP_GATHER4, VKD3D_STAT_GATHER}, -+ {VKD3D_SM5_OP_GATHER4_PO, VKD3D_STAT_GATHER}, -+ {VKD3D_SM4_OP_LOD, VKD3D_STAT_LOD}, - - {VKD3D_SM4_OP_LD, VKD3D_STAT_LOAD}, - {VKD3D_SM4_OP_LD2DMS, VKD3D_STAT_LOAD}, -@@ -1857,6 +1859,8 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) - {VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE, VKD3D_STAT_TESS_OUTPUT_PRIMITIVE}, - {VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, - {VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, -+ -+ {VKD3D_SM5_OP_SYNC, VKD3D_STAT_BARRIER}, - }; - - memset(lookup, 0, sizeof(*lookup)); -@@ -6433,8 +6437,8 @@ static void write_sm4_stat(struct hlsl_ctx *ctx, const struct sm4_stat *stat, st - put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_INPUT_PRIMITIVE]); - put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_OUTPUT_TOPOLOGY]); - put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_VERTICES_OUT]); -- put_u32(&buffer, 0); /* Unknown */ -- put_u32(&buffer, 0); /* Unknown */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_GATHER]); -+ put_u32(&buffer, stat->fields[VKD3D_STAT_LOD]); - put_u32(&buffer, 0); /* Sample frequency */ - - if (hlsl_version_ge(ctx, 5, 0)) -@@ -6444,7 +6448,7 @@ static void write_sm4_stat(struct hlsl_ctx *ctx, const struct sm4_stat *stat, st - put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_OUTPUT_PRIMITIVE]); - put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_PARTITIONING]); - put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_DOMAIN]); -- put_u32(&buffer, 0); /* Barrier instructions */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_BARRIER]); - put_u32(&buffer, stat->fields[VKD3D_STAT_ATOMIC]); - put_u32(&buffer, stat->fields[VKD3D_STAT_STORE]); - } -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -index ee98a504a5b..fc217860403 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c -@@ -1635,7 +1635,8 @@ int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, - case VKD3D_SHADER_TARGET_GLSL: - if ((ret = vsir_program_scan(program, &scan_info, message_context, &scan_descriptor_info)) < 0) - return ret; -- ret = glsl_compile(program, config_flags, compile_info, out, message_context); -+ ret = glsl_compile(program, config_flags, &scan_descriptor_info, -+ compile_info, out, message_context); - vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); - break; - -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index 8146a393a4c..a5d869172d3 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -168,6 +168,7 @@ enum vkd3d_shader_error - VKD3D_SHADER_WARNING_HLSL_IGNORED_DEFAULT_VALUE = 5306, - - VKD3D_SHADER_ERROR_GLSL_INTERNAL = 6000, -+ VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND = 6001, - - VKD3D_SHADER_ERROR_D3DBC_UNEXPECTED_EOF = 7000, - VKD3D_SHADER_ERROR_D3DBC_INVALID_VERSION_TOKEN = 7001, -@@ -1593,8 +1594,9 @@ int shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, - struct vkd3d_shader_message_context *message_context, struct shader_signature *signature); - - int glsl_compile(struct vsir_program *program, uint64_t config_flags, -- const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, -- struct vkd3d_shader_message_context *message_context); -+ const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, -+ const struct vkd3d_shader_compile_info *compile_info, -+ struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); - - #define SPIRV_MAX_SRC_COUNT 6 - --- -2.45.2 - diff --git a/patches/vkd3d-latest/0010-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch b/patches/vkd3d-latest/0010-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch deleted file mode 100644 index e0582ceb..00000000 --- a/patches/vkd3d-latest/0010-Updated-vkd3d-to-2ac7f650a196e47a18ea1957eac5953255c.patch +++ /dev/null @@ -1,520 +0,0 @@ -From 50e1fdcf167b4e3a8284fe5ac5c797cc780adb73 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 21 Sep 2024 09:40:50 +1000 -Subject: [PATCH] Updated vkd3d to 2ac7f650a196e47a18ea1957eac5953255cf424d. - ---- - libs/vkd3d/libs/vkd3d-shader/glsl.c | 79 +++++++++++-- - libs/vkd3d/libs/vkd3d-shader/ir.c | 32 +++-- - libs/vkd3d/libs/vkd3d-shader/spirv.c | 30 ++--- - libs/vkd3d/libs/vkd3d-shader/tpf.c | 110 ++++++++++++------ - .../libs/vkd3d-shader/vkd3d_shader_private.h | 1 + - libs/vkd3d/libs/vkd3d/utils.c | 3 +- - 6 files changed, 182 insertions(+), 73 deletions(-) - -diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c -index ac101d44214..dd1c121d5a8 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/glsl.c -+++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c -@@ -144,6 +144,12 @@ static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer, - vkd3d_string_buffer_printf(buffer, "%#xu", reg->u.immconst_u32[0]); - break; - -+ case VSIR_DIMENSION_VEC4: -+ vkd3d_string_buffer_printf(buffer, "uvec4(%#xu, %#xu, %#xu, %#xu)", -+ reg->u.immconst_u32[0], reg->u.immconst_u32[1], -+ reg->u.immconst_u32[2], reg->u.immconst_u32[3]); -+ break; -+ - default: - vkd3d_string_buffer_printf(buffer, "", reg->dimension); - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -@@ -211,7 +217,7 @@ static void glsl_src_cleanup(struct glsl_src *src, struct vkd3d_string_buffer_ca - } - - static void shader_glsl_print_bitcast(struct vkd3d_string_buffer *dst, struct vkd3d_glsl_generator *gen, -- const char *src, enum vkd3d_data_type dst_data_type, enum vkd3d_data_type src_data_type) -+ const char *src, enum vkd3d_data_type dst_data_type, enum vkd3d_data_type src_data_type, unsigned int size) - { - if (dst_data_type == VKD3D_DATA_UNORM || dst_data_type == VKD3D_DATA_SNORM) - dst_data_type = VKD3D_DATA_FLOAT; -@@ -224,16 +230,37 @@ static void shader_glsl_print_bitcast(struct vkd3d_string_buffer *dst, struct vk - return; - } - -- if (src_data_type == VKD3D_DATA_FLOAT && dst_data_type == VKD3D_DATA_UINT) -+ if (src_data_type == VKD3D_DATA_FLOAT) - { -- vkd3d_string_buffer_printf(dst, "floatBitsToUint(%s)", src); -- return; -+ switch (dst_data_type) -+ { -+ case VKD3D_DATA_INT: -+ vkd3d_string_buffer_printf(dst, "floatBitsToInt(%s)", src); -+ return; -+ case VKD3D_DATA_UINT: -+ vkd3d_string_buffer_printf(dst, "floatBitsToUint(%s)", src); -+ return; -+ default: -+ break; -+ } - } - -- if (src_data_type == VKD3D_DATA_UINT && dst_data_type == VKD3D_DATA_FLOAT) -+ if (src_data_type == VKD3D_DATA_UINT) - { -- vkd3d_string_buffer_printf(dst, "uintBitsToFloat(%s)", src); -- return; -+ switch (dst_data_type) -+ { -+ case VKD3D_DATA_FLOAT: -+ vkd3d_string_buffer_printf(dst, "uintBitsToFloat(%s)", src); -+ return; -+ case VKD3D_DATA_INT: -+ if (size == 1) -+ vkd3d_string_buffer_printf(dst, "int(%s)", src); -+ else -+ vkd3d_string_buffer_printf(dst, "ivec%u(%s)", size, src); -+ return; -+ default: -+ break; -+ } - } - - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, -@@ -248,6 +275,7 @@ static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator - const struct vkd3d_shader_register *reg = &vsir_src->reg; - struct vkd3d_string_buffer *register_name, *str; - enum vkd3d_data_type src_data_type; -+ unsigned int size; - - glsl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); - register_name = vkd3d_string_buffer_get(&gen->string_buffers); -@@ -268,7 +296,8 @@ static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator - else - str = vkd3d_string_buffer_get(&gen->string_buffers); - -- shader_glsl_print_bitcast(str, gen, register_name->buffer, reg->data_type, src_data_type); -+ size = reg->dimension == VSIR_DIMENSION_VEC4 ? 4 : 1; -+ shader_glsl_print_bitcast(str, gen, register_name->buffer, reg->data_type, src_data_type, size); - if (reg->dimension == VSIR_DIMENSION_VEC4) - shader_glsl_print_swizzle(str, vsir_src->swizzle, mask); - -@@ -385,6 +414,30 @@ static void shader_glsl_binop(struct vkd3d_glsl_generator *gen, - glsl_dst_cleanup(&dst, &gen->string_buffers); - } - -+static void shader_glsl_relop(struct vkd3d_glsl_generator *gen, -+ const struct vkd3d_shader_instruction *ins, const char *scalar_op, const char *vector_op) -+{ -+ unsigned int mask_size; -+ struct glsl_src src[2]; -+ struct glsl_dst dst; -+ uint32_t mask; -+ -+ mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]); -+ glsl_src_init(&src[0], gen, &ins->src[0], mask); -+ glsl_src_init(&src[1], gen, &ins->src[1], mask); -+ -+ if ((mask_size = vsir_write_mask_component_count(mask)) > 1) -+ shader_glsl_print_assignment(gen, &dst, "uvec%u(%s(%s, %s)) * 0xffffffffu", -+ mask_size, vector_op, src[0].str->buffer, src[1].str->buffer); -+ else -+ shader_glsl_print_assignment(gen, &dst, "%s %s %s ? 0xffffffffu : 0u", -+ src[0].str->buffer, scalar_op, src[1].str->buffer); -+ -+ glsl_src_cleanup(&src[1], &gen->string_buffers); -+ glsl_src_cleanup(&src[0], &gen->string_buffers); -+ glsl_dst_cleanup(&dst, &gen->string_buffers); -+} -+ - static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) - { - struct glsl_src src; -@@ -555,9 +608,19 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, - case VKD3DSIH_DCL_OUTPUT_SIV: - case VKD3DSIH_NOP: - break; -+ case VKD3DSIH_INE: -+ case VKD3DSIH_NEU: -+ shader_glsl_relop(gen, ins, "!=", "notEqual"); -+ break; - case VKD3DSIH_MOV: - shader_glsl_mov(gen, ins); - break; -+ case VKD3DSIH_MUL: -+ shader_glsl_binop(gen, ins, "*"); -+ break; -+ case VKD3DSIH_OR: -+ shader_glsl_binop(gen, ins, "|"); -+ break; - case VKD3DSIH_RET: - shader_glsl_ret(gen, ins); - break; -diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c -index 9e06b94e2eb..db9992d9715 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/ir.c -+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c -@@ -1208,8 +1208,8 @@ static bool io_normaliser_is_in_control_point_phase(const struct io_normaliser * - return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; - } - --static unsigned int shader_signature_find_element_for_reg(const struct shader_signature *signature, -- unsigned int reg_idx, unsigned int write_mask) -+static bool shader_signature_find_element_for_reg(const struct shader_signature *signature, -+ unsigned int reg_idx, unsigned int write_mask, unsigned int *element_idx) - { - unsigned int i, base_write_mask; - -@@ -1219,7 +1219,8 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si - if (e->register_index <= reg_idx && e->register_index + e->register_count > reg_idx - && (e->mask & write_mask) == write_mask) - { -- return i; -+ *element_idx = i; -+ return true; - } - } - -@@ -1229,15 +1230,20 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si - reg_idx, write_mask); - base_write_mask = 1u << vsir_write_mask_get_component_idx(write_mask); - if (base_write_mask != write_mask) -- return shader_signature_find_element_for_reg(signature, reg_idx, base_write_mask); -+ return shader_signature_find_element_for_reg(signature, reg_idx, base_write_mask, element_idx); - -- vkd3d_unreachable(); -+ return false; - } - - 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)]; -+ unsigned int element_idx; -+ -+ if (shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) -+ return &signature->elements[element_idx]; -+ -+ return NULL; - } - - static unsigned int range_map_get_register_count(uint8_t range_map[][VKD3D_VEC4_SIZE], -@@ -1291,9 +1297,10 @@ static void io_normaliser_add_index_range(struct io_normaliser *normaliser, - { - const struct vkd3d_shader_index_range *range = &ins->declaration.index_range; - const struct vkd3d_shader_register *reg = &range->dst.reg; -- unsigned int reg_idx, write_mask, element_idx; - const struct shader_signature *signature; - uint8_t (*range_map)[VKD3D_VEC4_SIZE]; -+ struct signature_element *element; -+ unsigned int reg_idx, write_mask; - - switch (reg->type) - { -@@ -1325,9 +1332,8 @@ static void io_normaliser_add_index_range(struct io_normaliser *normaliser, - - reg_idx = reg->idx[reg->idx_count - 1].offset; - write_mask = range->dst.write_mask; -- element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); -- range_map_set_register_range(range_map, reg_idx, range->register_count, -- signature->elements[element_idx].mask, true); -+ element = vsir_signature_find_element_for_reg(signature, reg_idx, write_mask); -+ range_map_set_register_range(range_map, reg_idx, range->register_count, element->mask, true); - } - - static int signature_element_mask_compare(const void *a, const void *b) -@@ -1648,7 +1654,8 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par - - id_idx = reg->idx_count - 1; - write_mask = dst_param->write_mask; -- element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); -+ if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) -+ vkd3d_unreachable(); - e = &signature->elements[element_idx]; - - dst_param->write_mask >>= vsir_write_mask_get_component_idx(e->mask); -@@ -1771,7 +1778,8 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par - - id_idx = reg->idx_count - 1; - write_mask = VKD3DSP_WRITEMASK_0 << vsir_swizzle_get_component(src_param->swizzle, 0); -- element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask); -+ if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) -+ vkd3d_unreachable(); - - e = &signature->elements[element_idx]; - if ((e->register_count > 1 || vsir_sysval_semantic_is_tess_factor(e->sysval_semantic))) -diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c -index a3e121f8687..7f1e0fea2c3 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/spirv.c -+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c -@@ -299,6 +299,16 @@ static void vkd3d_spirv_stream_free(struct vkd3d_spirv_stream *stream) - vkd3d_spirv_stream_clear(stream); - } - -+static void vkd3d_shader_code_from_spirv_stream(struct vkd3d_shader_code *code, struct vkd3d_spirv_stream *stream) -+{ -+ code->code = stream->words; -+ code->size = stream->word_count * sizeof(*stream->words); -+ -+ stream->words = NULL; -+ stream->capacity = 0; -+ stream->word_count = 0; -+} -+ - static size_t vkd3d_spirv_stream_current_location(struct vkd3d_spirv_stream *stream) - { - return stream->word_count; -@@ -2018,9 +2028,7 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, - { - uint64_t capability_mask = builder->capability_mask; - struct vkd3d_spirv_stream stream; -- uint32_t *code; - unsigned int i; -- size_t size; - - vkd3d_spirv_stream_init(&stream); - -@@ -2075,26 +2083,20 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, - if (builder->invocation_count) - vkd3d_spirv_build_op_execution_mode(&builder->execution_mode_stream, - builder->main_function_id, SpvExecutionModeInvocations, &builder->invocation_count, 1); -- vkd3d_spirv_stream_append(&stream, &builder->execution_mode_stream); -- -- vkd3d_spirv_stream_append(&stream, &builder->debug_stream); -- vkd3d_spirv_stream_append(&stream, &builder->annotation_stream); -- vkd3d_spirv_stream_append(&stream, &builder->global_stream); -- vkd3d_spirv_stream_append(&stream, &builder->function_stream); - -- if (!(code = vkd3d_calloc(stream.word_count, sizeof(*code)))) -+ if (!vkd3d_spirv_stream_append(&stream, &builder->execution_mode_stream) -+ || !vkd3d_spirv_stream_append(&stream, &builder->debug_stream) -+ || !vkd3d_spirv_stream_append(&stream, &builder->annotation_stream) -+ || !vkd3d_spirv_stream_append(&stream, &builder->global_stream) -+ || !vkd3d_spirv_stream_append(&stream, &builder->function_stream)) - { - vkd3d_spirv_stream_free(&stream); - return false; - } - -- size = stream.word_count * sizeof(*code); -- memcpy(code, stream.words, size); -+ vkd3d_shader_code_from_spirv_stream(spirv, &stream); - vkd3d_spirv_stream_free(&stream); - -- spirv->code = code; -- spirv->size = size; -- - return true; - } - -diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c -index cbf28f5ec50..884a2998d5b 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/tpf.c -+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c -@@ -648,6 +648,7 @@ enum vkd3d_sm4_stat_field - VKD3D_STAT_BARRIER, - VKD3D_STAT_LOD, - VKD3D_STAT_GATHER, -+ VKD3D_STAT_TEMPS, - VKD3D_STAT_COUNT, - }; - -@@ -1157,7 +1158,18 @@ static void shader_sm4_read_dcl_input_ps(struct vkd3d_shader_instruction *ins, u - struct signature_element *e = vsir_signature_find_element_for_reg( - &priv->p.program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - -- e->interpolation_mode = ins->flags; -+ if (!e) -+ { -+ WARN("No matching signature element for input register %u with mask %#x.\n", -+ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); -+ vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, -+ "No matching signature element for input register %u with mask %#x.\n", -+ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); -+ } -+ else -+ { -+ e->interpolation_mode = ins->flags; -+ } - } - } - -@@ -1172,7 +1184,18 @@ static void shader_sm4_read_dcl_input_ps_siv(struct vkd3d_shader_instruction *in - struct signature_element *e = vsir_signature_find_element_for_reg( - &priv->p.program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - -- e->interpolation_mode = ins->flags; -+ if (!e) -+ { -+ WARN("No matching signature element for input register %u with mask %#x.\n", -+ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); -+ vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, -+ "No matching signature element for input register %u with mask %#x.\n", -+ dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); -+ } -+ else -+ { -+ e->interpolation_mode = ins->flags; -+ } - } - ins->declaration.register_semantic.sysval_semantic = *tokens; - } -@@ -1861,6 +1884,8 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) - {VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, - - {VKD3D_SM5_OP_SYNC, VKD3D_STAT_BARRIER}, -+ -+ {VKD3D_SM4_OP_DCL_TEMPS, VKD3D_STAT_TEMPS}, - }; - - memset(lookup, 0, sizeof(*lookup)); -@@ -4403,44 +4428,11 @@ static void sm4_write_src_register(const struct tpf_writer *tpf, const struct vk - } - } - --static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4_instruction *instr) -+static void sm4_update_stat_counters(const struct tpf_writer *tpf, const struct sm4_instruction *instr) - { - enum vkd3d_shader_type shader_type = tpf->ctx->profile->type; -- uint32_t token = instr->opcode | instr->extra_bits, opcode; -- struct vkd3d_bytecode_buffer *buffer = tpf->buffer; - enum vkd3d_sm4_stat_field stat_field; -- unsigned int size, i, j; -- size_t token_position; -- -- if (instr->modifier_count > 0) -- token |= VKD3D_SM4_INSTRUCTION_MODIFIER; -- -- token_position = put_u32(buffer, 0); -- -- for (i = 0; i < instr->modifier_count; ++i) -- { -- uint32_t modifier_token = sm4_encode_instruction_modifier(&instr->modifiers[i]); -- -- if (instr->modifier_count > i + 1) -- modifier_token |= VKD3D_SM4_INSTRUCTION_MODIFIER; -- put_u32(buffer, modifier_token); -- } -- -- for (i = 0; i < instr->dst_count; ++i) -- sm4_write_dst_register(tpf, &instr->dsts[i]); -- -- for (i = 0; i < instr->src_count; ++i) -- sm4_write_src_register(tpf, &instr->srcs[i]); -- -- if (instr->byte_stride) -- put_u32(buffer, instr->byte_stride); -- -- for (j = 0; j < instr->idx_count; ++j) -- put_u32(buffer, instr->idx[j]); -- -- size = (bytecode_get_size(buffer) - token_position) / sizeof(uint32_t); -- token |= (size << VKD3D_SM4_INSTRUCTION_LENGTH_SHIFT); -- set_u32(buffer, token_position, token); -+ uint32_t opcode; - - ++tpf->stat->fields[VKD3D_STAT_INSTR_COUNT]; - -@@ -4449,6 +4441,9 @@ static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4 - - switch (opcode) - { -+ case VKD3D_SM4_OP_DCL_TEMPS: -+ tpf->stat->fields[stat_field] = max(tpf->stat->fields[stat_field], instr->idx[0]); -+ break; - case VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY: - case VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE: - tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM4_PRIMITIVE_TYPE_MASK) -@@ -4476,7 +4471,46 @@ static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4 - default: - ++tpf->stat->fields[stat_field]; - } -+} -+ -+static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4_instruction *instr) -+{ -+ uint32_t token = instr->opcode | instr->extra_bits; -+ struct vkd3d_bytecode_buffer *buffer = tpf->buffer; -+ unsigned int size, i, j; -+ size_t token_position; -+ -+ if (instr->modifier_count > 0) -+ token |= VKD3D_SM4_INSTRUCTION_MODIFIER; -+ -+ token_position = put_u32(buffer, 0); -+ -+ for (i = 0; i < instr->modifier_count; ++i) -+ { -+ uint32_t modifier_token = sm4_encode_instruction_modifier(&instr->modifiers[i]); -+ -+ if (instr->modifier_count > i + 1) -+ modifier_token |= VKD3D_SM4_INSTRUCTION_MODIFIER; -+ put_u32(buffer, modifier_token); -+ } -+ -+ for (i = 0; i < instr->dst_count; ++i) -+ sm4_write_dst_register(tpf, &instr->dsts[i]); -+ -+ for (i = 0; i < instr->src_count; ++i) -+ sm4_write_src_register(tpf, &instr->srcs[i]); -+ -+ if (instr->byte_stride) -+ put_u32(buffer, instr->byte_stride); -+ -+ for (j = 0; j < instr->idx_count; ++j) -+ put_u32(buffer, instr->idx[j]); -+ -+ size = (bytecode_get_size(buffer) - token_position) / sizeof(uint32_t); -+ token |= (size << VKD3D_SM4_INSTRUCTION_LENGTH_SHIFT); -+ set_u32(buffer, token_position, token); - -+ sm4_update_stat_counters(tpf, instr); - } - - static bool encode_texel_offset_as_aoffimmi(struct sm4_instruction *instr, -@@ -6412,7 +6446,7 @@ static void write_sm4_stat(struct hlsl_ctx *ctx, const struct sm4_stat *stat, st - struct vkd3d_bytecode_buffer buffer = {0}; - - put_u32(&buffer, stat->fields[VKD3D_STAT_INSTR_COUNT]); -- put_u32(&buffer, 0); /* Temp count */ -+ put_u32(&buffer, stat->fields[VKD3D_STAT_TEMPS]); - put_u32(&buffer, 0); /* Def count */ - put_u32(&buffer, 0); /* DCL count */ - put_u32(&buffer, stat->fields[VKD3D_STAT_FLOAT]); -diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -index a5d869172d3..447210449da 100644 ---- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h -@@ -80,6 +80,7 @@ enum vkd3d_shader_error - VKD3D_SHADER_ERROR_TPF_INVALID_CASE_VALUE = 1007, - VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION = 1008, - VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE = 1009, -+ VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL = 1010, - - VKD3D_SHADER_WARNING_TPF_MASK_NOT_CONTIGUOUS = 1300, - VKD3D_SHADER_WARNING_TPF_UNHANDLED_INDEX_RANGE_MASK = 1301, -diff --git a/libs/vkd3d/libs/vkd3d/utils.c b/libs/vkd3d/libs/vkd3d/utils.c -index 831dc07af56..839bb173854 100644 ---- a/libs/vkd3d/libs/vkd3d/utils.c -+++ b/libs/vkd3d/libs/vkd3d/utils.c -@@ -703,7 +703,7 @@ const char *debug_vk_extent_3d(VkExtent3D extent) - - const char *debug_vk_queue_flags(VkQueueFlags flags) - { -- char buffer[159]; -+ char buffer[191]; - - buffer[0] = '\0'; - #define FLAG_TO_STR(f) if (flags & f) { strcat(buffer, " | "#f); flags &= ~f; } -@@ -715,6 +715,7 @@ const char *debug_vk_queue_flags(VkQueueFlags flags) - #undef FLAG_TO_STR - #define FLAG_TO_STR(f, n) if (flags & f) { strcat(buffer, " | "#n); flags &= ~f; } - FLAG_TO_STR(0x20, VK_QUEUE_VIDEO_DECODE_BIT_KHR) -+ FLAG_TO_STR(0x40, VK_QUEUE_VIDEO_ENCODE_BIT_KHR) - #undef FLAG_TO_STR - if (flags) - FIXME("Unrecognized flag(s) %#x.\n", flags); --- -2.45.2 - diff --git a/patches/vkd3d-latest/definition b/patches/vkd3d-latest/definition deleted file mode 100644 index ece8a5de..00000000 --- a/patches/vkd3d-latest/definition +++ /dev/null @@ -1,7 +0,0 @@ -#Update vkd3d to the latest to allow testing before it's -# finally be integrated into wine. -# Bugs for this patchset should be filled in the usually place against vkd3d - -# Games used for testing -# Stranded Alien Dawn - Requires dxvk -# DOOM Eternal