From 2e768aee87d168d7a5004c5f8f6c7dba6264bc19 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 18 Sep 2024 11:58:56 +1000 Subject: [PATCH] Updated vkd3d-latest patchset --- ...-6d28cc131b0cad61c681aed6b9f6611a12b.patch | 2 +- ...-0a6bcf5da78863cc6402756a429b21b6234.patch | 2 +- ...-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch | 2 +- ...-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch | 2 +- ...-ab525f31e43a0f3c04c76b799aae88c1268.patch | 2 +- ...-4c03cda3c77123a71590b872acdc216e362.patch | 1823 +++++++++++++ ...-3e012c355db12ecad32d45a76058c29a407.patch | 2281 +++++++++++++++++ ...-a1487380bb69c6ec07495c1a6eef4cfb224.patch | 1125 ++++++++ 8 files changed, 5234 insertions(+), 5 deletions(-) create mode 100644 patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch create mode 100644 patches/vkd3d-latest/0007-Updated-vkd3d-to-3e012c355db12ecad32d45a76058c29a407.patch create mode 100644 patches/vkd3d-latest/0008-Updated-vkd3d-to-a1487380bb69c6ec07495c1a6eef4cfb224.patch diff --git a/patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch b/patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch index 8af80b2b..f281c731 100644 --- a/patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch +++ b/patches/vkd3d-latest/0001-Updated-vkd3d-to-6d28cc131b0cad61c681aed6b9f6611a12b.patch @@ -1,4 +1,4 @@ -From a06e686911b112c201fd718c16b842cd60f09d14 Mon Sep 17 00:00:00 2001 +From 06cbe6c7a5b6966c8e743aa08552e84190b16b09 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. diff --git a/patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch b/patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch index b2d69089..b402af28 100644 --- a/patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch +++ b/patches/vkd3d-latest/0002-Updated-vkd3d-to-0a6bcf5da78863cc6402756a429b21b6234.patch @@ -1,4 +1,4 @@ -From e27f5fd72130c55446cc0cdb3f53953abe57b3a0 Mon Sep 17 00:00:00 2001 +From 26c5311f916ee0706827fbcba5277ddc03705e00 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. diff --git a/patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch b/patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch index 4118b17b..15b50a79 100644 --- a/patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch +++ b/patches/vkd3d-latest/0003-Updated-vkd3d-to-bfd1fc9cd6cf9cf4e9c23b4ffad2ba8a328.patch @@ -1,4 +1,4 @@ -From cf61e3754eee65d04a65b541344d4ce5abe94f84 Mon Sep 17 00:00:00 2001 +From f94b61242d9d37d25ce9718dfbd56aa9673b8dad 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. diff --git a/patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch b/patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch index cd67a417..f6c05ea3 100644 --- a/patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch +++ b/patches/vkd3d-latest/0004-Updated-vkd3d-to-3b4e0ce8e94cd4091b9f2fe80d86588b64c.patch @@ -1,4 +1,4 @@ -From 7b363c5a2fe58d6d88ee577c17673aa4dd7fe8ce Mon Sep 17 00:00:00 2001 +From ae553edec2cdb5797a836135c652d39752b92769 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. diff --git a/patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch b/patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch index 399928af..11703212 100644 --- a/patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch +++ b/patches/vkd3d-latest/0005-Updated-vkd3d-to-ab525f31e43a0f3c04c76b799aae88c1268.patch @@ -1,4 +1,4 @@ -From c3cf140e1c002d936cfda0d80790c96417070cb4 Mon Sep 17 00:00:00 2001 +From b7d12942df2ec5feca52e60c07dffb2811c48fca 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. diff --git a/patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch b/patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch new file mode 100644 index 00000000..f5baea54 --- /dev/null +++ b/patches/vkd3d-latest/0006-Updated-vkd3d-to-4c03cda3c77123a71590b872acdc216e362.patch @@ -0,0 +1,1823 @@ +From 62f59bbc3c1c3c92deae4e3f9b1fe37b19bbbe87 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 new file mode 100644 index 00000000..d59f747b --- /dev/null +++ b/patches/vkd3d-latest/0007-Updated-vkd3d-to-3e012c355db12ecad32d45a76058c29a407.patch @@ -0,0 +1,2281 @@ +From fb1a6e5e456e870d6305bedb415028cd51c1b316 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 new file mode 100644 index 00000000..7022657e --- /dev/null +++ b/patches/vkd3d-latest/0008-Updated-vkd3d-to-a1487380bb69c6ec07495c1a6eef4cfb224.patch @@ -0,0 +1,1125 @@ +From 5456ac4fb585e584018d3d2a75d359f9cccb4eab 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 +