[PATCH 0/1] MR10141: vkd3d: Import upstream release 1.19.
From: Alexandre Julliard <julliard@winehq.org> --- dlls/d3dcompiler_43/tests/hlsl_d3d9.c | 15 +- libs/vkd3d/AUTHORS | 1 + libs/vkd3d/COPYING | 2 +- libs/vkd3d/config.h | 4 +- libs/vkd3d/include/private/vkd3d_common.h | 2 +- libs/vkd3d/include/vkd3d.h | 1 + libs/vkd3d/include/vkd3d_shader.h | 20 + libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 94 +- libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 192 +- libs/vkd3d/libs/vkd3d-shader/dxbc.c | 20 +- libs/vkd3d/libs/vkd3d-shader/dxil.c | 3519 +++++++++++------ libs/vkd3d/libs/vkd3d-shader/fx.c | 451 ++- libs/vkd3d/libs/vkd3d-shader/glsl.c | 24 +- libs/vkd3d/libs/vkd3d-shader/hlsl.c | 252 +- libs/vkd3d/libs/vkd3d-shader/hlsl.h | 82 +- libs/vkd3d/libs/vkd3d-shader/hlsl.l | 10 +- libs/vkd3d/libs/vkd3d-shader/hlsl.y | 607 ++- libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 1622 +++++--- .../libs/vkd3d-shader/hlsl_constant_ops.c | 8 +- libs/vkd3d/libs/vkd3d-shader/ir.c | 2892 +++++++++++--- libs/vkd3d/libs/vkd3d-shader/msl.c | 20 +- libs/vkd3d/libs/vkd3d-shader/preproc.l | 33 +- libs/vkd3d/libs/vkd3d-shader/spirv.c | 499 +-- libs/vkd3d/libs/vkd3d-shader/tpf.c | 408 +- .../libs/vkd3d-shader/vkd3d_shader_main.c | 109 +- .../libs/vkd3d-shader/vkd3d_shader_private.h | 190 +- libs/vkd3d/libs/vkd3d/command.c | 151 +- libs/vkd3d/libs/vkd3d/device.c | 56 +- libs/vkd3d/libs/vkd3d/resource.c | 38 +- libs/vkd3d/libs/vkd3d/state.c | 24 +- libs/vkd3d/libs/vkd3d/vkd3d_private.h | 25 +- 31 files changed, 7519 insertions(+), 3852 deletions(-) diff --git a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c index d9d050c3f99..a0cc1367424 100644 --- a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c +++ b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c @@ -813,17 +813,14 @@ static void test_array_dimensions(void) if (!init_test_context(&test_context)) return; - todo_wine ps_code = compile_shader(shader, "ps_2_0", 0); - if (ps_code) - { - draw_quad(test_context.device, ps_code); + ps_code = compile_shader(shader, "ps_2_0", 0); + draw_quad(test_context.device, ps_code); - v = get_color_vec4(test_context.device, 0, 0); - ok(compare_vec4(&v, 0.1f, 0.1f, 0.2f, 0.4f, 0), - "Got unexpected value {%.8e, %.8e, %.8e, %.8e}.\n", v.x, v.y, v.z, v.w); + v = get_color_vec4(test_context.device, 0, 0); + ok(compare_vec4(&v, 0.1f, 0.1f, 0.2f, 0.4f, 0), + "Got unexpected value {%.8e, %.8e, %.8e, %.8e}.\n", v.x, v.y, v.z, v.w); - ID3D10Blob_Release(ps_code); - } + ID3D10Blob_Release(ps_code); release_test_context(&test_context); } diff --git a/libs/vkd3d/AUTHORS b/libs/vkd3d/AUTHORS index 70a2fb8bc11..a42d303410e 100644 --- a/libs/vkd3d/AUTHORS +++ b/libs/vkd3d/AUTHORS @@ -36,6 +36,7 @@ Petrichor Park Philip Rebohle Rémi Bernon Robin Kertels +Santino Mazza Shaun Ren Stefan Dösinger Sven Hesse diff --git a/libs/vkd3d/COPYING b/libs/vkd3d/COPYING index 383003017aa..52b82f73b7f 100644 --- a/libs/vkd3d/COPYING +++ b/libs/vkd3d/COPYING @@ -1,4 +1,4 @@ -Copyright 2016-2025 the Vkd3d project authors (see the file AUTHORS for a +Copyright 2016-2026 the vkd3d project authors (see the file AUTHORS for a complete list) Vkd3d is free software; you can redistribute it and/or modify it under diff --git a/libs/vkd3d/config.h b/libs/vkd3d/config.h index 08647a3f943..0d6b8b14536 100644 --- a/libs/vkd3d/config.h +++ b/libs/vkd3d/config.h @@ -1,5 +1,5 @@ #define PACKAGE_NAME "vkd3d" -#define PACKAGE_STRING "vkd3d 1.18" -#define PACKAGE_VERSION "1.18" +#define PACKAGE_STRING "vkd3d 1.19" +#define PACKAGE_VERSION "1.19" #define PATH_MAX 1024 #define SONAME_LIBVULKAN "vulkan-1.dll" diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h index 7ee11b54396..196ab307d0c 100644 --- a/libs/vkd3d/include/private/vkd3d_common.h +++ b/libs/vkd3d/include/private/vkd3d_common.h @@ -43,7 +43,7 @@ #include <intrin.h> #endif -#define VKD3D_SHADER_API_VERSION_CURRENT VKD3D_SHADER_API_VERSION_1_18 +#define VKD3D_SHADER_API_VERSION_CURRENT VKD3D_SHADER_API_VERSION_1_19 #ifndef ARRAY_SIZE # define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) diff --git a/libs/vkd3d/include/vkd3d.h b/libs/vkd3d/include/vkd3d.h index 38b3c82d515..da4362c1e6f 100644 --- a/libs/vkd3d/include/vkd3d.h +++ b/libs/vkd3d/include/vkd3d.h @@ -103,6 +103,7 @@ enum vkd3d_api_version VKD3D_API_VERSION_1_16, VKD3D_API_VERSION_1_17, VKD3D_API_VERSION_1_18, + VKD3D_API_VERSION_1_19, VKD3D_FORCE_32_BIT_ENUM(VKD3D_API_VERSION), }; diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h index 352c222f27d..dd2a8a8afee 100644 --- a/libs/vkd3d/include/vkd3d_shader.h +++ b/libs/vkd3d/include/vkd3d_shader.h @@ -61,6 +61,7 @@ enum vkd3d_shader_api_version VKD3D_SHADER_API_VERSION_1_16, VKD3D_SHADER_API_VERSION_1_17, VKD3D_SHADER_API_VERSION_1_18, + VKD3D_SHADER_API_VERSION_1_19, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_API_VERSION), }; @@ -1039,6 +1040,25 @@ enum vkd3d_shader_parameter_name VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_3, VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_4, VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_5, + /** + * A mask of projected textures. + * + * When this parameter is provided to a shader model 1.0-1.3 pixel shader, + * for each nonzero bit of this mask, the corresponding texture will be + * projected. That is, it will have its coordinates divided by their W + * component before sampling. + * + * The default value is zero, i.e. no textures are projected. + * + * The data type for this parameter must be + * VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32. + * + * Only VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT is supported in this + * version of vkd3d-shader. + * + * \since 1.19 + */ + VKD3D_SHADER_PARAMETER_NAME_PROJECTED_TEXTURE_MASK, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME), }; diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c index b316f6c8830..f06870718ec 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c @@ -489,7 +489,7 @@ static void shader_print_dcl_usage(struct vkd3d_d3d_asm_compiler *compiler, return; } - /* Pixel shaders 3.0 don't have usage semantics. */ + /* Pixel shaders before 3.0 don't have usage semantics. */ if (!vkd3d_shader_ver_ge(&compiler->shader_version, 3, 0) && compiler->shader_version.type == VKD3D_SHADER_TYPE_PIXEL) return; @@ -563,8 +563,8 @@ static void shader_print_dcl_usage(struct vkd3d_d3d_asm_compiler *compiler, vkd3d_string_buffer_printf(buffer, "%s%s%s", prefix, usage, suffix); } -static void shader_print_src_param(struct vkd3d_d3d_asm_compiler *compiler, - const char *prefix, const struct vkd3d_shader_src_param *param, const char *suffix); +static void shader_print_src_operand(struct vkd3d_d3d_asm_compiler *compiler, + const char *prefix, const struct vsir_src_operand *src, const char *suffix); static void shader_print_float_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, float f, const char *suffix) @@ -672,10 +672,10 @@ static void shader_print_untyped_literal(struct vkd3d_d3d_asm_compiler *compiler } static void shader_print_subscript(struct vkd3d_d3d_asm_compiler *compiler, - unsigned int offset, const struct vkd3d_shader_src_param *rel_addr) + unsigned int offset, const struct vsir_src_operand *rel_addr) { if (rel_addr) - shader_print_src_param(compiler, "[", rel_addr, " + "); + shader_print_src_operand(compiler, "[", rel_addr, " + "); shader_print_uint_literal(compiler, rel_addr ? "" : "[", offset, "]"); } @@ -1041,32 +1041,32 @@ static void shader_print_write_mask(struct vkd3d_d3d_asm_compiler *compiler, compiler->colours.write_mask, buffer, compiler->colours.reset, suffix); } -static void shader_print_dst_param(struct vkd3d_d3d_asm_compiler *compiler, - const char *prefix, const struct vkd3d_shader_dst_param *param, bool is_declaration, const char *suffix) +static void shader_print_dst_operand(struct vkd3d_d3d_asm_compiler *compiler, + const char *prefix, const struct vsir_dst_operand *dst, bool is_declaration, const char *suffix) { - uint32_t write_mask = param->write_mask; + uint32_t write_mask = dst->write_mask; - shader_print_register(compiler, prefix, ¶m->reg, is_declaration, ""); + shader_print_register(compiler, prefix, &dst->reg, is_declaration, ""); - if (write_mask && param->reg.dimension == VSIR_DIMENSION_VEC4) + if (write_mask && dst->reg.dimension == VSIR_DIMENSION_VEC4) { - if (data_type_is_64_bit(param->reg.data_type)) + if (data_type_is_64_bit(dst->reg.data_type)) write_mask = vsir_write_mask_32_from_64(write_mask); shader_print_write_mask(compiler, "", write_mask, ""); } - shader_print_precision(compiler, ¶m->reg); - shader_print_non_uniform(compiler, ¶m->reg); - shader_print_reg_type(compiler, "", ¶m->reg, suffix); + shader_print_precision(compiler, &dst->reg); + shader_print_non_uniform(compiler, &dst->reg); + shader_print_reg_type(compiler, "", &dst->reg, suffix); } -static void shader_print_src_param(struct vkd3d_d3d_asm_compiler *compiler, - const char *prefix, const struct vkd3d_shader_src_param *param, const char *suffix) +static void shader_print_src_operand(struct vkd3d_d3d_asm_compiler *compiler, + const char *prefix, const struct vsir_src_operand *src, const char *suffix) { - enum vkd3d_shader_src_modifier src_modifier = param->modifiers; + enum vkd3d_shader_src_modifier src_modifier = src->modifiers; struct vkd3d_string_buffer *buffer = &compiler->buffer; - uint32_t swizzle = param->swizzle; + uint32_t swizzle = src->swizzle; const char *modifier = ""; bool is_abs = false; @@ -1085,7 +1085,7 @@ static void shader_print_src_param(struct vkd3d_d3d_asm_compiler *compiler, if (src_modifier == VKD3DSPSM_ABS || src_modifier == VKD3DSPSM_ABSNEG) is_abs = true; - shader_print_register(compiler, is_abs ? "|" : "", ¶m->reg, false, ""); + shader_print_register(compiler, is_abs ? "|" : "", &src->reg, false, ""); switch (src_modifier) { @@ -1120,14 +1120,14 @@ static void shader_print_src_param(struct vkd3d_d3d_asm_compiler *compiler, break; } - if (param->reg.type != VKD3DSPR_IMMCONST && param->reg.type != VKD3DSPR_IMMCONST64 - && param->reg.dimension == VSIR_DIMENSION_VEC4) + if (src->reg.type != VKD3DSPR_IMMCONST && src->reg.type != VKD3DSPR_IMMCONST64 + && src->reg.dimension == VSIR_DIMENSION_VEC4) { static const char swizzle_chars[] = "xyzw"; unsigned int swizzle_x, swizzle_y, swizzle_z, swizzle_w; - if (data_type_is_64_bit(param->reg.data_type)) + if (data_type_is_64_bit(src->reg.data_type)) swizzle = vsir_swizzle_32_from_64(swizzle); swizzle_x = vsir_swizzle_get_component(swizzle, 0); @@ -1147,13 +1147,13 @@ static void shader_print_src_param(struct vkd3d_d3d_asm_compiler *compiler, if (is_abs) vkd3d_string_buffer_printf(buffer, "|"); - shader_print_precision(compiler, ¶m->reg); - shader_print_non_uniform(compiler, ¶m->reg); - shader_print_reg_type(compiler, "", ¶m->reg, suffix); + shader_print_precision(compiler, &src->reg); + shader_print_non_uniform(compiler, &src->reg); + shader_print_reg_type(compiler, "", &src->reg, suffix); } static void shader_dump_ins_modifiers(struct vkd3d_d3d_asm_compiler *compiler, - const struct vkd3d_shader_dst_param *dst) + const struct vsir_dst_operand *dst) { struct vkd3d_string_buffer *buffer = &compiler->buffer; uint32_t mmask = dst->modifiers; @@ -1508,7 +1508,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, compiler->current = ins; if (ins->predicate) - shader_print_src_param(compiler, "(", ins->predicate, ") "); + shader_print_src_operand(compiler, "(", ins->predicate, ") "); /* PixWin marks instructions with the coissue flag with a '+' */ if (ins->coissue) @@ -1561,7 +1561,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, break; case VSIR_OP_DCL_INDEX_RANGE: - shader_print_dst_param(compiler, " ", &ins->declaration.index_range.dst, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.index_range.dst, true, ""); shader_print_uint_literal(compiler, " ", ins->declaration.index_range.register_count, ""); break; @@ -1579,7 +1579,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, case VSIR_OP_DCL_INPUT_PS: shader_print_interpolation_mode(compiler, " ", ins->flags, ""); - shader_print_dst_param(compiler, " ", &ins->declaration.dst, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.dst, true, ""); break; case VSIR_OP_DCL_INPUT_PS_SGV: @@ -1587,19 +1587,19 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, case VSIR_OP_DCL_INPUT_SIV: case VSIR_OP_DCL_OUTPUT_SGV: case VSIR_OP_DCL_OUTPUT_SIV: - shader_print_dst_param(compiler, " ", &ins->declaration.register_semantic.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.register_semantic.reg, true, ""); shader_print_input_sysval_semantic(compiler, ", ", ins->declaration.register_semantic.sysval_semantic, ""); break; case VSIR_OP_DCL_INPUT_PS_SIV: shader_print_interpolation_mode(compiler, " ", ins->flags, ""); - shader_print_dst_param(compiler, " ", &ins->declaration.register_semantic.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.register_semantic.reg, true, ""); shader_print_input_sysval_semantic(compiler, ", ", ins->declaration.register_semantic.sysval_semantic, ""); break; case VSIR_OP_DCL_INPUT: case VSIR_OP_DCL_OUTPUT: - shader_print_dst_param(compiler, " ", &ins->declaration.dst, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.dst, true, ""); break; case VSIR_OP_DCL_INPUT_PRIMITIVE: @@ -1615,12 +1615,12 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, break; case VSIR_OP_DCL_RESOURCE_RAW: - shader_print_dst_param(compiler, " ", &ins->declaration.raw_resource.resource.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.raw_resource.resource.reg, true, ""); shader_dump_register_space(compiler, ins->declaration.raw_resource.resource.range.space); break; case VSIR_OP_DCL_RESOURCE_STRUCTURED: - shader_print_dst_param(compiler, " ", &ins->declaration.structured_resource.resource.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.structured_resource.resource.reg, true, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.structured_resource.byte_stride, ""); shader_dump_register_space(compiler, ins->declaration.structured_resource.resource.range.space); break; @@ -1654,12 +1654,12 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, break; case VSIR_OP_DCL_TGSM_RAW: - shader_print_dst_param(compiler, " ", &ins->declaration.tgsm_raw.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.tgsm_raw.reg, true, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.tgsm_raw.byte_count, ""); break; case VSIR_OP_DCL_TGSM_STRUCTURED: - shader_print_dst_param(compiler, " ", &ins->declaration.tgsm_structured.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.tgsm_structured.reg, true, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.tgsm_structured.byte_stride, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.tgsm_structured.structure_count, ""); break; @@ -1672,13 +1672,13 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, case VSIR_OP_DCL_UAV_RAW: shader_dump_uav_flags(compiler, ins->flags); - shader_print_dst_param(compiler, " ", &ins->declaration.raw_resource.resource.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.raw_resource.resource.reg, true, ""); shader_dump_register_space(compiler, ins->declaration.raw_resource.resource.range.space); break; case VSIR_OP_DCL_UAV_STRUCTURED: shader_dump_uav_flags(compiler, ins->flags); - shader_print_dst_param(compiler, " ", &ins->declaration.structured_resource.resource.reg, true, ""); + shader_print_dst_operand(compiler, " ", &ins->declaration.structured_resource.resource.reg, true, ""); shader_print_uint_literal(compiler, ", ", ins->declaration.structured_resource.byte_stride, ""); shader_dump_register_space(compiler, ins->declaration.structured_resource.resource.range.space); break; @@ -1744,13 +1744,13 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, for (i = 0; i < ins->dst_count; ++i) { shader_dump_ins_modifiers(compiler, &ins->dst[i]); - shader_print_dst_param(compiler, !i ? " " : ", ", &ins->dst[i], false, ""); + shader_print_dst_operand(compiler, !i ? " " : ", ", &ins->dst[i], false, ""); } /* Other source tokens */ for (i = ins->dst_count; i < (ins->dst_count + ins->src_count); ++i) { - shader_print_src_param(compiler, !i ? " " : ", ", &ins->src[i - ins->dst_count], ""); + shader_print_src_operand(compiler, !i ? " " : ", ", &ins->src[i - ins->dst_count], ""); } break; } @@ -2088,6 +2088,12 @@ enum vkd3d_result d3d_asm_compile(struct vsir_program *program, const struct vkd shader_get_type_prefix(shader_version->type), shader_version->major, shader_version->minor, compiler.colours.reset); + if (compiler.flags & VSIR_ASM_FLAG_DUMP_DENORM_MODES) + vkd3d_string_buffer_printf(buffer, ".denorm %s, %s, %s\n", + vsir_denorm_mode_get_name(program->f16_denorm_mode, "??"), + vsir_denorm_mode_get_name(program->f32_denorm_mode, "??"), + vsir_denorm_mode_get_name(program->f64_denorm_mode, "??")); + if (compiler.flags & VSIR_ASM_FLAG_DUMP_SIGNATURES && (result = dump_dxbc_signatures(&compiler, program)) < 0) { @@ -2098,7 +2104,8 @@ enum vkd3d_result d3d_asm_compile(struct vsir_program *program, const struct vkd if (compiler.flags & VSIR_ASM_FLAG_DUMP_DESCRIPTORS) shader_print_descriptors(&compiler, &program->descriptors); - if (compiler.flags & (VSIR_ASM_FLAG_DUMP_SIGNATURES | VSIR_ASM_FLAG_DUMP_DESCRIPTORS)) + if (compiler.flags & (VSIR_ASM_FLAG_DUMP_SIGNATURES | VSIR_ASM_FLAG_DUMP_DESCRIPTORS + | VSIR_ASM_FLAG_DUMP_DENORM_MODES)) vkd3d_string_buffer_printf(buffer, "%s.text%s\n", compiler.colours.opcode, compiler.colours.reset); indent = 0; @@ -2111,6 +2118,7 @@ enum vkd3d_result d3d_asm_compile(struct vsir_program *program, const struct vkd case VSIR_OP_ELSE: case VSIR_OP_ENDIF: case VSIR_OP_ENDLOOP: + case VSIR_OP_ENDREP: case VSIR_OP_ENDSWITCH: if (indent) --indent; @@ -2141,6 +2149,7 @@ enum vkd3d_result d3d_asm_compile(struct vsir_program *program, const struct vkd case VSIR_OP_IF: case VSIR_OP_IFC: case VSIR_OP_LOOP: + case VSIR_OP_REP: case VSIR_OP_SWITCH: case VSIR_OP_LABEL: ++indent; @@ -2299,7 +2308,8 @@ static void trace_io_declarations(const struct vsir_program *program) void vsir_program_trace(struct vsir_program *program) { const unsigned int flags = VSIR_ASM_FLAG_DUMP_TYPES | VSIR_ASM_FLAG_DUMP_ALL_INDICES - | VSIR_ASM_FLAG_DUMP_SIGNATURES | VSIR_ASM_FLAG_DUMP_DESCRIPTORS; + | VSIR_ASM_FLAG_DUMP_SIGNATURES | VSIR_ASM_FLAG_DUMP_DESCRIPTORS + | VSIR_ASM_FLAG_DUMP_DENORM_MODES; struct vkd3d_shader_message_context message_context; struct vkd3d_shader_code code; const char *p, *q, *end; diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c index 87a7d48acca..8784ea69e97 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c @@ -561,7 +561,7 @@ static enum vkd3d_shader_register_type parse_register_type( } static void d3dbc_parse_register(struct vkd3d_shader_sm1_parser *d3dbc, - struct vkd3d_shader_register *reg, uint32_t param, struct vkd3d_shader_src_param *rel_addr) + struct vkd3d_shader_register *reg, uint32_t param, struct vsir_src_operand *rel_addr) { enum vkd3d_shader_register_type reg_type; unsigned int index_offset, idx_count; @@ -582,20 +582,25 @@ static void d3dbc_parse_register(struct vkd3d_shader_sm1_parser *d3dbc, reg->dimension = VSIR_DIMENSION_SCALAR; else reg->dimension = VSIR_DIMENSION_VEC4; + + if (reg->type == VKD3DSPR_CONSTINT) + reg->data_type = VSIR_DATA_U32; + else if (reg->type == VKD3DSPR_CONSTBOOL) + reg->data_type = VSIR_DATA_BOOL; } -static void shader_sm1_parse_src_param(struct vkd3d_shader_sm1_parser *sm1, uint32_t param, - struct vkd3d_shader_src_param *rel_addr, struct vkd3d_shader_src_param *src) +static void d3dbc_parse_src_operand(struct vkd3d_shader_sm1_parser *d3dbc, + uint32_t param, struct vsir_src_operand *rel_addr, struct vsir_src_operand *src) { - d3dbc_parse_register(sm1, &src->reg, param, rel_addr); + d3dbc_parse_register(d3dbc, &src->reg, param, rel_addr); src->swizzle = swizzle_from_sm1((param & VKD3D_SM1_SWIZZLE_MASK) >> VKD3D_SM1_SWIZZLE_SHIFT); src->modifiers = (param & VKD3D_SM1_SRC_MODIFIER_MASK) >> VKD3D_SM1_SRC_MODIFIER_SHIFT; } -static void shader_sm1_parse_dst_param(struct vkd3d_shader_sm1_parser *sm1, uint32_t param, - struct vkd3d_shader_src_param *rel_addr, struct vkd3d_shader_dst_param *dst) +static void d3dbc_parse_dst_operand(struct vkd3d_shader_sm1_parser *d3dbc, + uint32_t param, struct vsir_src_operand *rel_addr, struct vsir_dst_operand *dst) { - d3dbc_parse_register(sm1, &dst->reg, param, rel_addr); + d3dbc_parse_register(d3dbc, &dst->reg, param, rel_addr); dst->modifiers = (param & VKD3D_SM1_DST_MODIFIER_MASK) >> VKD3D_SM1_DST_MODIFIER_SHIFT; dst->shift = (param & VKD3D_SM1_DSTSHIFT_MASK) >> VKD3D_SM1_DSTSHIFT_SHIFT; @@ -757,6 +762,7 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser * { const struct vkd3d_shader_version *version = &sm1->program->shader_version; unsigned int register_index = reg->idx_count > 0 ? reg->idx[0].offset : 0; + struct signature_element *e; switch (reg->type) { @@ -769,13 +775,23 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser * case VKD3DSPR_INPUT: /* For vertex shaders or sm3 pixel shaders, we should have already * had a DCL instruction. Otherwise, this is a colour input. */ - if (version->type == VKD3D_SHADER_TYPE_VERTEX || version->major == 3) + if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major < 3) + return add_signature_element(sm1, false, "COLOR", register_index, + VKD3D_SHADER_SV_NONE, SM1_COLOR_REGISTER_OFFSET + register_index, is_dcl, mask, dst_modifiers); + + if (reg->idx_count > 0 && reg->idx[0].rel_addr) { - add_signature_mask(sm1, false, register_index, mask); + WARN("Indirect addressing detected, adding used_mask %#x to all input elements.\n", mask); + for (unsigned int i = 0; i < sm1->program->input_signature.element_count; ++i) + { + e = &sm1->program->input_signature.elements[i]; + e->used_mask |= mask & e->mask; + } return true; } - return add_signature_element(sm1, false, "COLOR", register_index, - VKD3D_SHADER_SV_NONE, SM1_COLOR_REGISTER_OFFSET + register_index, is_dcl, mask, dst_modifiers); + + add_signature_mask(sm1, false, register_index, mask); + return true; case VKD3DSPR_TEXTURE: return add_signature_element(sm1, false, "TEXCOORD", register_index, @@ -1039,51 +1055,51 @@ static void shader_sm1_skip_opcode(const struct vkd3d_shader_sm1_parser *sm1, co *ptr += (opcode_info->dst_count + opcode_info->src_count); } -static void shader_sm1_read_src_param(struct vkd3d_shader_sm1_parser *sm1, const uint32_t **ptr, - struct vkd3d_shader_src_param *src_param) +static void d3dbc_read_src_operand(struct vkd3d_shader_sm1_parser *d3dbc, + const uint32_t **ptr, struct vsir_src_operand *src) { - struct vkd3d_shader_src_param *src_rel_addr = NULL; + struct vsir_src_operand *src_rel_addr = NULL; uint32_t token, addr_token; - shader_sm1_read_param(sm1, ptr, &token, &addr_token); + shader_sm1_read_param(d3dbc, ptr, &token, &addr_token); if (has_relative_address(token)) { - if (!(src_rel_addr = vsir_program_get_src_params(sm1->program, 1))) + if (!(src_rel_addr = vsir_program_get_src_operands(d3dbc->program, 1))) { - vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, + vkd3d_shader_parser_error(&d3dbc->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Out of memory."); - sm1->abort = true; + d3dbc->abort = true; return; } - shader_sm1_parse_src_param(sm1, addr_token, NULL, src_rel_addr); + d3dbc_parse_src_operand(d3dbc, addr_token, NULL, src_rel_addr); } - shader_sm1_parse_src_param(sm1, token, src_rel_addr, src_param); + d3dbc_parse_src_operand(d3dbc, token, src_rel_addr, src); } -static void shader_sm1_read_dst_param(struct vkd3d_shader_sm1_parser *sm1, const uint32_t **ptr, - struct vkd3d_shader_dst_param *dst_param) +static void d3dbc_read_dst_operand(struct vkd3d_shader_sm1_parser *d3dbc, + const uint32_t **ptr, struct vsir_dst_operand *dst) { - struct vkd3d_shader_src_param *dst_rel_addr = NULL; + struct vsir_src_operand *dst_rel_addr = NULL; uint32_t token, addr_token; - shader_sm1_read_param(sm1, ptr, &token, &addr_token); + shader_sm1_read_param(d3dbc, ptr, &token, &addr_token); if (has_relative_address(token)) { - if (!(dst_rel_addr = vsir_program_get_src_params(sm1->program, 1))) + if (!(dst_rel_addr = vsir_program_get_src_operands(d3dbc->program, 1))) { - vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, + vkd3d_shader_parser_error(&d3dbc->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Out of memory."); - sm1->abort = true; + d3dbc->abort = true; return; } - shader_sm1_parse_src_param(sm1, addr_token, NULL, dst_rel_addr); + d3dbc_parse_src_operand(d3dbc, addr_token, NULL, dst_rel_addr); } - shader_sm1_parse_dst_param(sm1, token, dst_rel_addr, dst_param); + d3dbc_parse_dst_operand(d3dbc, token, dst_rel_addr, dst); - if (dst_param->reg.type == VKD3DSPR_RASTOUT && dst_param->reg.idx[0].offset == VSIR_RASTOUT_POINT_SIZE) - sm1->program->has_point_size = true; - if (dst_param->reg.type == VKD3DSPR_RASTOUT && dst_param->reg.idx[0].offset == VSIR_RASTOUT_FOG) - sm1->program->has_fog = true; + if (dst->reg.type == VKD3DSPR_RASTOUT && dst->reg.idx[0].offset == VSIR_RASTOUT_POINT_SIZE) + d3dbc->program->has_point_size = true; + if (dst->reg.type == VKD3DSPR_RASTOUT && dst->reg.idx[0].offset == VSIR_RASTOUT_FOG) + d3dbc->program->has_fog = true; } static void shader_sm1_read_semantic(struct vkd3d_shader_sm1_parser *sm1, @@ -1121,7 +1137,7 @@ static void shader_sm1_read_semantic(struct vkd3d_shader_sm1_parser *sm1, semantic->resource_data_type[1] = VSIR_DATA_F32; semantic->resource_data_type[2] = VSIR_DATA_F32; semantic->resource_data_type[3] = VSIR_DATA_F32; - shader_sm1_parse_dst_param(sm1, dst_token, NULL, &semantic->resource.reg); + d3dbc_parse_dst_operand(sm1, dst_token, NULL, &semantic->resource.reg); range = &semantic->resource.range; range->space = 0; range->first = range->last = semantic->resource.reg.reg.idx[0].offset; @@ -1135,7 +1151,7 @@ static void shader_sm1_read_semantic(struct vkd3d_shader_sm1_parser *sm1, } static void shader_sm1_read_immconst(struct vkd3d_shader_sm1_parser *sm1, const uint32_t **ptr, - struct vkd3d_shader_src_param *src_param, enum vsir_dimension dimension, enum vsir_data_type data_type) + struct vsir_src_operand *src, enum vsir_dimension dimension, enum vsir_data_type data_type) { unsigned int count = dimension == VSIR_DIMENSION_VEC4 ? 4 : 1; @@ -1148,21 +1164,10 @@ static void shader_sm1_read_immconst(struct vkd3d_shader_sm1_parser *sm1, const return; } - src_param->reg.type = VKD3DSPR_IMMCONST; - src_param->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; - src_param->reg.non_uniform = false; - src_param->reg.data_type = data_type; - src_param->reg.idx[0].offset = ~0u; - src_param->reg.idx[0].rel_addr = NULL; - src_param->reg.idx[1].offset = ~0u; - src_param->reg.idx[1].rel_addr = NULL; - src_param->reg.idx[2].offset = ~0u; - src_param->reg.idx[2].rel_addr = NULL; - src_param->reg.idx_count = 0; - src_param->reg.dimension = dimension; - memcpy(src_param->reg.u.immconst_u32, *ptr, count * sizeof(uint32_t)); - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; - src_param->modifiers = 0; + vsir_src_operand_init(src, VKD3DSPR_IMMCONST, data_type, 0); + src->reg.dimension = dimension; + memcpy(src->reg.u.immconst_u32, *ptr, count * sizeof(uint32_t)); + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; *ptr += count; } @@ -1283,12 +1288,12 @@ static unsigned int mask_from_swizzle(uint32_t swizzle) static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, struct vkd3d_shader_instruction *ins) { - struct vkd3d_shader_src_param *src_params, *predicate; const struct vkd3d_sm1_opcode_info *opcode_info; struct vsir_program *program = sm1->program; unsigned int vsir_dst_count, vsir_src_count; - struct vkd3d_shader_dst_param *dst_param; + struct vsir_src_operand *src, *predicate; const uint32_t **ptr = &sm1->ptr; + struct vsir_dst_operand *dst; uint32_t opcode_token; const uint32_t *p; bool predicated; @@ -1330,12 +1335,12 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str ins->raw = false; ins->structured = false; predicated = !!(opcode_token & VKD3D_SM1_INSTRUCTION_PREDICATED); - ins->predicate = predicate = predicated ? vsir_program_get_src_params(program, 1) : NULL; + ins->predicate = predicate = predicated ? vsir_program_get_src_operands(program, 1) : NULL; ins->dst_count = vsir_dst_count; - ins->dst = dst_param = vsir_program_get_dst_params(program, ins->dst_count); + ins->dst = dst = vsir_program_get_dst_operands(program, ins->dst_count); ins->src_count = vsir_src_count; - ins->src = src_params = vsir_program_get_src_params(program, ins->src_count); - if ((!predicate && predicated) || (!src_params && ins->src_count) || (!dst_param && ins->dst_count)) + ins->src = src = vsir_program_get_src_operands(program, ins->src_count); + if ((!predicate && predicated) || (!src && ins->src_count) || (!dst && ins->dst_count)) { vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Out of memory."); goto fail; @@ -1365,21 +1370,21 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str } else if (ins->opcode == VSIR_OP_DEF) { - shader_sm1_read_dst_param(sm1, &p, dst_param); - shader_sm1_read_immconst(sm1, &p, &src_params[0], VSIR_DIMENSION_VEC4, VSIR_DATA_F32); - shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); + d3dbc_read_dst_operand(sm1, &p, dst); + shader_sm1_read_immconst(sm1, &p, &src[0], VSIR_DIMENSION_VEC4, VSIR_DATA_F32); + shader_sm1_scan_register(sm1, &dst->reg, dst->write_mask, true); } else if (ins->opcode == VSIR_OP_DEFB) { - shader_sm1_read_dst_param(sm1, &p, dst_param); - shader_sm1_read_immconst(sm1, &p, &src_params[0], VSIR_DIMENSION_SCALAR, VSIR_DATA_U32); - shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); + d3dbc_read_dst_operand(sm1, &p, dst); + shader_sm1_read_immconst(sm1, &p, &src[0], VSIR_DIMENSION_SCALAR, VSIR_DATA_U32); + shader_sm1_scan_register(sm1, &dst->reg, dst->write_mask, true); } else if (ins->opcode == VSIR_OP_DEFI) { - shader_sm1_read_dst_param(sm1, &p, dst_param); - shader_sm1_read_immconst(sm1, &p, &src_params[0], VSIR_DIMENSION_VEC4, VSIR_DATA_I32); - shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); + d3dbc_read_dst_operand(sm1, &p, dst); + shader_sm1_read_immconst(sm1, &p, &src[0], VSIR_DIMENSION_VEC4, VSIR_DATA_I32); + shader_sm1_scan_register(sm1, &dst->reg, dst->write_mask, true); } else if (ins->opcode == VSIR_OP_TEXKILL) { @@ -1387,37 +1392,37 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str * semantically a source. Since we have multiple passes which operate * generically on sources or destinations, normalize that. */ const struct vkd3d_shader_register *reg; - struct vkd3d_shader_dst_param tmp_dst; + struct vsir_dst_operand tmp_dst; reg = &tmp_dst.reg; - shader_sm1_read_dst_param(sm1, &p, &tmp_dst); + d3dbc_read_dst_operand(sm1, &p, &tmp_dst); shader_sm1_scan_register(sm1, reg, tmp_dst.write_mask, false); - vsir_src_param_init(&src_params[0], reg->type, reg->data_type, reg->idx_count); - src_params[0].reg = *reg; - src_params[0].swizzle = vsir_swizzle_from_writemask(tmp_dst.write_mask); + vsir_src_operand_init(&src[0], reg->type, reg->data_type, reg->idx_count); + src[0].reg = *reg; + src[0].swizzle = vsir_swizzle_from_writemask(tmp_dst.write_mask); if (ins->predicate) - shader_sm1_read_src_param(sm1, &p, predicate); + d3dbc_read_src_operand(sm1, &p, predicate); } else { /* Destination token */ if (ins->dst_count) { - shader_sm1_read_dst_param(sm1, &p, dst_param); - shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, false); + d3dbc_read_dst_operand(sm1, &p, dst); + shader_sm1_scan_register(sm1, &dst->reg, dst->write_mask, false); } /* Predication token */ if (ins->predicate) - shader_sm1_read_src_param(sm1, &p, predicate); + d3dbc_read_src_operand(sm1, &p, predicate); /* Other source tokens */ for (i = 0; i < ins->src_count; ++i) { - shader_sm1_read_src_param(sm1, &p, &src_params[i]); - shader_sm1_scan_register(sm1, &src_params[i].reg, mask_from_swizzle(src_params[i].swizzle), false); + d3dbc_read_src_operand(sm1, &p, &src[i]); + shader_sm1_scan_register(sm1, &src[i].reg, mask_from_swizzle(src[i].swizzle), false); } } @@ -1522,6 +1527,8 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, st code_size != ~(size_t)0 ? token_count / 4u + 4 : 16, VSIR_CF_STRUCTURED, normalisation_level)) return VKD3D_ERROR_OUT_OF_MEMORY; + program->f32_denorm_mode = VSIR_DENORM_FLUSH_TO_ZERO; + vkd3d_shader_parser_init(&sm1->p, message_context, compile_info->source_name); sm1->program = program; sm1->ptr = sm1->start; @@ -1595,7 +1602,7 @@ int d3dbc_parse(const struct vkd3d_shader_compile_info *compile_info, uint64_t c } } - program->has_descriptor_info = true; + program->normalisation_flags.has_descriptor_info = true; if (TRACE_ON()) vsir_program_trace(program); @@ -1863,8 +1870,8 @@ static uint32_t swizzle_from_vsir(uint32_t swizzle) static bool is_inconsequential_instr(const struct vkd3d_shader_instruction *ins) { - const struct vkd3d_shader_dst_param *dst = &ins->dst[0]; - const struct vkd3d_shader_src_param *src = &ins->src[0]; + const struct vsir_src_operand *src = &ins->src[0]; + const struct vsir_dst_operand *dst = &ins->dst[0]; unsigned int i; if (ins->opcode != VSIR_OP_MOV) @@ -1887,7 +1894,7 @@ static bool is_inconsequential_instr(const struct vkd3d_shader_instruction *ins) return true; } -static void write_sm1_dst_register(struct vkd3d_bytecode_buffer *buffer, const struct vkd3d_shader_dst_param *reg) +static void write_sm1_dst_register(struct vkd3d_bytecode_buffer *buffer, const struct vsir_dst_operand *reg) { uint32_t offset = reg->reg.idx_count ? reg->reg.idx[0].offset : 0; @@ -1899,7 +1906,7 @@ static void write_sm1_dst_register(struct vkd3d_bytecode_buffer *buffer, const s | (offset & VKD3D_SM1_REGISTER_NUMBER_MASK)); } -static void write_sm1_src_register(struct vkd3d_bytecode_buffer *buffer, const struct vkd3d_shader_src_param *reg) +static void write_sm1_src_register(struct vkd3d_bytecode_buffer *buffer, const struct vsir_src_operand *reg) { uint32_t address_mode = VKD3D_SM1_ADDRESS_MODE_ABSOLUTE, offset = 0; @@ -1922,8 +1929,8 @@ static void d3dbc_write_instruction(struct d3dbc_compiler *d3dbc, const struct v { const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; - const struct vkd3d_shader_src_param *src; const struct vkd3d_sm1_opcode_info *info; + const struct vsir_src_operand *src; size_t size, token_position; unsigned int i; uint32_t token; @@ -1971,12 +1978,12 @@ static void d3dbc_write_texkill(struct d3dbc_compiler *d3dbc, const struct vkd3d { const struct vkd3d_shader_register *reg = &ins->src[0].reg; struct vkd3d_shader_instruction tmp; - struct vkd3d_shader_dst_param dst; + struct vsir_dst_operand dst; /* TEXKILL, uniquely, encodes its argument as a destination, when it is * semantically a source. We store it as a source in vsir, so convert it. */ - vsir_dst_param_init(&dst, reg->type, reg->data_type, reg->idx_count); + vsir_dst_operand_init(&dst, reg->type, reg->data_type, reg->idx_count); dst.reg = *reg; dst.write_mask = mask_from_swizzle(ins->src[0].swizzle); @@ -1994,7 +2001,7 @@ static void d3dbc_write_vsir_def(struct d3dbc_compiler *d3dbc, const struct vkd3 struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; uint32_t token; - const struct vkd3d_shader_dst_param reg = + const struct vsir_dst_operand reg = { .reg.type = VKD3DSPR_CONST, .write_mask = VKD3DSP_WRITEMASK_ALL, @@ -2017,7 +2024,7 @@ static void d3dbc_write_vsir_sampler_dcl(struct d3dbc_compiler *d3dbc, { const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; - struct vkd3d_shader_dst_param reg = {0}; + struct vsir_dst_operand reg = {0}; uint32_t token; token = VKD3D_SM1_OP_DCL; @@ -2156,7 +2163,7 @@ static void d3dbc_write_semantic_dcl(struct d3dbc_compiler *d3dbc, { const struct vkd3d_shader_version *version = &d3dbc->program->shader_version; struct vkd3d_bytecode_buffer *buffer = &d3dbc->buffer; - struct vkd3d_shader_dst_param reg = {0}; + struct vsir_dst_operand reg = {0}; enum vkd3d_decl_usage usage; uint32_t token, usage_idx; bool ret; @@ -2284,13 +2291,8 @@ int d3dbc_compile(struct vsir_program *program, uint64_t config_flags, result = VKD3D_ERROR_INVALID_SHADER; if (!result) - { - out->code = buffer->data; - out->size = buffer->size; - } - else - { - vkd3d_free(buffer->data); - } + vkd3d_shader_code_from_bytecode_buffer(out, buffer); + vkd3d_bytecode_buffer_cleanup(buffer); + return result; } diff --git a/libs/vkd3d/libs/vkd3d-shader/dxbc.c b/libs/vkd3d/libs/vkd3d-shader/dxbc.c index 45a45c3ad4a..52448e89e37 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxbc.c @@ -90,10 +90,9 @@ int vkd3d_shader_serialize_dxbc(size_t section_count, const struct vkd3d_shader_ set_u32(&buffer, checksum_position + i * sizeof(uint32_t), checksum[i]); if (!buffer.status) - { - dxbc->code = buffer.data; - dxbc->size = buffer.size; - } + vkd3d_shader_code_from_bytecode_buffer(dxbc, &buffer); + vkd3d_bytecode_buffer_cleanup(&buffer); + return buffer.status; } @@ -340,11 +339,7 @@ int vkd3d_shader_parse_dxbc(const struct vkd3d_shader_code *dxbc, ret = parse_dxbc(dxbc, &message_context, NULL, flags, desc); vkd3d_shader_message_context_trace_messages(&message_context); - if (!vkd3d_shader_message_context_copy_messages(&message_context, messages) && ret >= 0) - { - vkd3d_shader_free_dxbc(desc); - ret = VKD3D_ERROR_OUT_OF_MEMORY; - } + vkd3d_shader_string_from_message_context(messages, &message_context); vkd3d_shader_message_context_cleanup(&message_context); if (ret < 0) @@ -1106,9 +1101,7 @@ int vkd3d_shader_parse_root_signature(const struct vkd3d_shader_code *dxbc, ret = for_each_dxbc_section(dxbc, &message_context, NULL, rts0_handler, root_signature); vkd3d_shader_message_context_trace_messages(&message_context); - if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) - ret = VKD3D_ERROR_OUT_OF_MEMORY; - + vkd3d_shader_string_from_message_context(messages, &message_context); vkd3d_shader_message_context_cleanup(&message_context); if (ret < 0) vkd3d_shader_free_root_signature(root_signature); @@ -1558,8 +1551,7 @@ int vkd3d_shader_serialize_root_signature(const struct vkd3d_shader_versioned_ro done: vkd3d_shader_message_context_trace_messages(&context.message_context); - if (!vkd3d_shader_message_context_copy_messages(&context.message_context, messages)) - ret = VKD3D_ERROR_OUT_OF_MEMORY; + vkd3d_shader_string_from_message_context(messages, &context.message_context); vkd3d_shader_message_context_cleanup(&context.message_context); return ret; } diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c index 9f25ae8334b..8e6c91f9cd7 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -33,7 +33,6 @@ static const uint64_t ALLOCA_FLAG_IN_ALLOCA = 0x20; static const uint64_t ALLOCA_FLAG_EXPLICIT_TYPE = 0x40; static const uint64_t ALLOCA_ALIGNMENT_MASK = 0x1f; static const unsigned int SHADER_DESCRIPTOR_TYPE_COUNT = 4; -static const size_t MAX_IR_INSTRUCTIONS_PER_DXIL_INSTRUCTION = 11; static const unsigned int dx_max_thread_group_size[3] = {1024, 1024, 64}; @@ -108,6 +107,7 @@ enum bitcode_constant_code CST_CODE_UNDEF = 3, CST_CODE_INTEGER = 4, CST_CODE_FLOAT = 6, + CST_CODE_AGGREGATE = 7, CST_CODE_STRING = 8, CST_CODE_CE_CAST = 11, CST_CODE_CE_GEP = 12, @@ -176,6 +176,16 @@ enum bitcode_value_symtab_code VST_CODE_BBENTRY = 2, }; +enum bitcode_paramattr_code +{ + PARAMATTR_CODE_ENTRY = 2, +}; + +enum bitcode_paramattr_group_code +{ + PARAMATTR_GRP_CODE_ENTRY = 3, +}; + enum bitcode_linkage { LINKAGE_EXTERNAL = 0, @@ -596,10 +606,33 @@ struct sm6_pointer_info enum bitcode_address_space addr_space; }; +enum dxil_well_known_structs +{ + WELL_KNOWN_NONE = 0, + WELL_KNOWN_HANDLE, + WELL_KNOWN_DIMENSIONS, + WELL_KNOWN_SAMPLEPOS, + WELL_KNOWN_SPLITDOUBLE, + WELL_KNOWN_FOURI32, + WELL_KNOWN_RESBIND, + WELL_KNOWN_RESOURCE_PROPERTIES, + WELL_KNOWN_RESRET_F16, + WELL_KNOWN_RESRET_F32, + WELL_KNOWN_RESRET_I16, + WELL_KNOWN_RESRET_I32, + WELL_KNOWN_CBUFRET_F16, + WELL_KNOWN_CBUFRET_F32, + WELL_KNOWN_CBUFRET_F64, + WELL_KNOWN_CBUFRET_I16, + WELL_KNOWN_CBUFRET_I32, + WELL_KNOWN_CBUFRET_I64, +}; + struct sm6_struct_info { const char *name; unsigned int elem_count; + enum dxil_well_known_structs well_known; const struct sm6_type *elem_types[]; }; @@ -748,67 +781,15 @@ struct sm6_symbol struct incoming_value { - const struct sm6_block *block; - struct vkd3d_shader_register reg; -}; - -struct sm6_phi -{ - struct sm6_value value; - struct incoming_value *incoming; - size_t incoming_capacity; - size_t incoming_count; -}; - -enum sm6_block_terminator_type -{ - TERMINATOR_UNCOND_BR, - TERMINATOR_COND_BR, - TERMINATOR_SWITCH, - TERMINATOR_RET, -}; - -struct terminator_case -{ - const struct sm6_block *block; - uint64_t value; - bool is_default; -}; - -struct sm6_block_terminator -{ - struct vkd3d_shader_register conditional_reg; - enum sm6_block_terminator_type type; - const struct sm6_block *true_block; - const struct sm6_block *false_block; - struct terminator_case *cases; - unsigned int case_count; -}; - -struct sm6_block -{ - struct vkd3d_shader_instruction *instructions; - size_t instruction_capacity; - size_t instruction_count; - - /* A nonzero id. */ - unsigned int id; - - struct sm6_phi *phi; - size_t phi_capacity; - size_t phi_count; - - struct sm6_block_terminator terminator; + unsigned int block_idx; + const struct sm6_value *src; }; struct sm6_function { const struct sm6_value *declaration; - - struct sm6_block **blocks; - size_t block_capacity; + struct vkd3d_shader_instruction_array instructions; size_t block_count; - size_t value_count; }; @@ -888,11 +869,46 @@ struct sm6_descriptor_info enum vkd3d_shader_descriptor_type type; unsigned int id; struct vkd3d_shader_register_range range; - enum vkd3d_shader_resource_type resource_type; enum dxil_resource_kind kind; enum vsir_data_type resource_data_type; - enum vkd3d_shader_register_type reg_type; - enum vsir_data_type reg_data_type; +}; + +struct dxil_parameter_attribute +{ + uint64_t *groups; + size_t group_count; +}; + +enum dxil_attribute_kind +{ + ATTRIBUTE_WELL_KNOWN = 0, + ATTRIBUTE_WELL_KNOWN_WITH_INTEGER_VALUE = 1, + ATTRIBUTE_STRING = 3, + ATTRIBUTE_STRING_WITH_STRING_VALUE = 4, +}; + +struct dxil_attribute +{ + enum dxil_attribute_kind kind; + union + { + uint64_t well_known; + const char *string; + } key; + union + { + uint64_t numeric; + const char *string; + } value; +}; + +struct dxil_attribute_group +{ + unsigned int group_id; + unsigned int parameter_idx; + struct dxil_attribute *attributes; + size_t attribute_count; + size_t attribute_capacity; }; struct sm6_parser @@ -921,11 +937,11 @@ struct sm6_parser const char *entry_point; const char *patch_constant_function; - struct vkd3d_shader_dst_param *output_params; - struct vkd3d_shader_dst_param *input_params; - struct vkd3d_shader_dst_param *patch_constant_params; + struct vsir_dst_operand *output_params; + struct vsir_dst_operand *input_params; + struct vsir_dst_operand *patch_constant_params; uint32_t io_regs_declared[VKD3D_BITMAP_SIZE(VKD3DSPR_COUNT)]; - struct vkd3d_shader_src_param *outpointid_param; + struct vsir_src_operand *outpointid_param; struct sm6_function *functions; size_t function_count; @@ -948,6 +964,12 @@ struct sm6_parser size_t cur_max_value; unsigned int ssa_next_id; + struct dxil_parameter_attribute *parameter_attributes; + size_t parameter_attribute_count; + + struct dxil_attribute_group *attribute_groups; + size_t attribute_group_count; + struct vkd3d_shader_parser p; }; @@ -1630,6 +1652,50 @@ static char *dxil_record_to_string(const struct dxil_record *record, unsigned in return str; } +static char *dxil_record_to_zero_terminated_string(const struct dxil_record *record, + unsigned int *offset, struct sm6_parser *dxil) +{ + size_t str_len = 0, str_capacity = 0; + char *str = NULL; + unsigned int i; + + VKD3D_ASSERT(*offset < record->operand_count); + + for (i = *offset; i < record->operand_count; ++i) + { + if (record->operands[i] > UCHAR_MAX) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_STRING, + "Operand value %"PRIu64" is not a valid string character.", record->operands[i]); + vkd3d_free(str); + return NULL; + } + + if (!vkd3d_array_reserve((void **)&str, &str_capacity, str_len + 1, sizeof(*str))) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating a string of length %zu.", str_len + 1); + vkd3d_free(str); + return NULL; + } + + if (!(str[str_len++] = record->operands[i])) + break; + } + + if (i == record->operand_count) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_STRING, + "String is not zero-terminated."); + vkd3d_free(str); + return NULL; + } + + *offset = i + 1; + + return str; +} + static bool dxil_record_validate_operand_min_count(const struct dxil_record *record, unsigned int min_count, struct sm6_parser *sm6) { @@ -1660,6 +1726,8 @@ static bool dxil_record_validate_operand_count(const struct dxil_record *record, return dxil_record_validate_operand_min_count(record, min_count, sm6); } +static void dxil_recognise_well_known_struct(struct sm6_parser *dxil, struct sm6_struct_info *info); + static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) { const struct dxil_record *record; @@ -1727,6 +1795,7 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) break; case TYPE_CODE_DOUBLE: + sm6->program->f64_denorm_mode = VSIR_DENORM_PRESERVE; dxil_record_validate_operand_max_count(record, 0, sm6); type->class = TYPE_CLASS_FLOAT; type->u.width = 64; @@ -1875,11 +1944,14 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) break; } - if (!strcmp(struct_name, "dx.types.Handle")) - sm6->handle_type = type; - type->u.struc->name = struct_name; struct_name = NULL; + + dxil_recognise_well_known_struct(sm6, type->u.struc); + + if (type->u.struc->well_known == WELL_KNOWN_HANDLE) + sm6->handle_type = type; + break; case TYPE_CODE_STRUCT_NAME: @@ -1945,11 +2017,26 @@ static inline bool sm6_type_is_i8(const struct sm6_type *type) return type->class == TYPE_CLASS_INTEGER && type->u.width == 8; } +static inline bool sm6_type_is_i16(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_INTEGER && type->u.width == 16; +} + static inline bool sm6_type_is_i32(const struct sm6_type *type) { return type->class == TYPE_CLASS_INTEGER && type->u.width == 32; } +static inline bool sm6_type_is_i64(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_INTEGER && type->u.width == 64; +} + +static bool sm6_type_is_f16(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_FLOAT && type->u.width == 16; +} + static bool sm6_type_is_float(const struct sm6_type *type) { return type->class == TYPE_CLASS_FLOAT && type->u.width == 32; @@ -2034,7 +2121,7 @@ static inline bool sm6_type_is_function_pointer(const struct sm6_type *type) static inline bool sm6_type_is_handle(const struct sm6_type *type) { - return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.Handle"); + return sm6_type_is_struct(type) && type->u.struc->well_known == WELL_KNOWN_HANDLE; } static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type *type, @@ -2055,6 +2142,236 @@ static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type return NULL; } +static void dxil_recognise_well_known_struct(struct sm6_parser *dxil, struct sm6_struct_info *info) +{ + static const char cbufret_prefix[] = "dx.types.CBufRet."; + static const char resret_prefix[] = "dx.types.ResRet."; + static const char prefix[] = "dx.types."; + unsigned int i; + + info->well_known = WELL_KNOWN_NONE; + + if (!info->name) + return; + + if (strncmp(info->name, prefix, ARRAY_SIZE(prefix) - 1)) + return; + + if (!strcmp(info->name, "dx.types.Dimensions")) + { + if (info->elem_count != 4) + goto error; + for (i = 0; i < 4; ++i) + { + if (!sm6_type_is_i32(info->elem_types[i])) + goto error; + } + info->well_known = WELL_KNOWN_DIMENSIONS; + + return; + } + + if (!strcmp(info->name, "dx.types.fouri32")) + { + if (info->elem_count != 4) + goto error; + for (i = 0; i < 4; ++i) + { + if (!sm6_type_is_i32(info->elem_types[i])) + goto error; + } + info->well_known = WELL_KNOWN_FOURI32; + + return; + } + + if (!strcmp(info->name, "dx.types.Handle")) + { + if (info->elem_count != 1) + goto error; + if (!sm6_type_is_pointer(info->elem_types[0])) + goto error; + if (!sm6_type_is_i8(info->elem_types[0]->u.pointer.type)) + goto error; + if (info->elem_types[0]->u.pointer.addr_space != ADDRESS_SPACE_DEFAULT) + goto error; + info->well_known = WELL_KNOWN_HANDLE; + + return; + } + + if (!strcmp(info->name, "dx.types.ResourceProperties")) + { + if (info->elem_count != 2) + goto error; + for (i = 0; i < 2; ++i) + { + if (!sm6_type_is_i32(info->elem_types[i])) + goto error; + } + info->well_known = WELL_KNOWN_RESOURCE_PROPERTIES; + + return; + } + + if (!strcmp(info->name, "dx.types.ResBind")) + { + if (info->elem_count != 4) + goto error; + for (i = 0; i < 3; ++i) + { + if (!sm6_type_is_i32(info->elem_types[i])) + goto error; + } + if (!sm6_type_is_i8(info->elem_types[3])) + goto error; + info->well_known = WELL_KNOWN_RESBIND; + + return; + } + + if (!strcmp(info->name, "dx.types.SamplePos")) + { + if (info->elem_count != 2) + goto error; + for (i = 0; i < 2; ++i) + { + if (!sm6_type_is_float(info->elem_types[i])) + goto error; + } + info->well_known = WELL_KNOWN_SAMPLEPOS; + + return; + } + + if (!strcmp(info->name, "dx.types.splitdouble")) + { + if (info->elem_count != 2) + goto error; + for (i = 0; i < 2; ++i) + { + if (!sm6_type_is_i32(info->elem_types[i])) + goto error; + } + info->well_known = WELL_KNOWN_SPLITDOUBLE; + + return; + } + + if (!strncmp(info->name, resret_prefix, ARRAY_SIZE(resret_prefix) - 1)) + { + enum dxil_well_known_structs target_well_known = WELL_KNOWN_NONE; + bool (*field_checker)(const struct sm6_type *) = NULL; + const char *suffix; + + suffix = &info->name[ARRAY_SIZE(resret_prefix) - 1]; + if (!strcmp(suffix, "f16")) + { + target_well_known = WELL_KNOWN_RESRET_F16; + field_checker = sm6_type_is_f16; + } + else if (!strcmp(suffix, "f32")) + { + target_well_known = WELL_KNOWN_RESRET_F32; + field_checker = sm6_type_is_float; + } + else if (!strcmp(suffix, "i16")) + { + target_well_known = WELL_KNOWN_RESRET_I16; + field_checker = sm6_type_is_i16; + } + else if (!strcmp(suffix, "i32")) + { + target_well_known = WELL_KNOWN_RESRET_I32; + field_checker = sm6_type_is_i32; + } + + if (target_well_known != WELL_KNOWN_NONE) + { + if (info->elem_count != 5) + goto error; + for (i = 0; i < 4; ++i) + { + if (!field_checker(info->elem_types[i])) + goto error; + } + if (!sm6_type_is_i32(info->elem_types[4])) + goto error; + info->well_known = target_well_known; + + return; + } + } + + if (!strncmp(info->name, cbufret_prefix, ARRAY_SIZE(cbufret_prefix) - 1)) + { + enum dxil_well_known_structs target_well_known = WELL_KNOWN_NONE; + bool (*field_checker)(const struct sm6_type *) = NULL; + unsigned int field_count = 0; + const char *suffix; + + suffix = &info->name[ARRAY_SIZE(cbufret_prefix) - 1]; + if (!strcmp(suffix, "f16")) + { + target_well_known = WELL_KNOWN_CBUFRET_F16; + field_checker = sm6_type_is_f16; + field_count = 4; + } + else if (!strcmp(suffix, "f32")) + { + target_well_known = WELL_KNOWN_CBUFRET_F32; + field_checker = sm6_type_is_float; + field_count = 4; + } + else if (!strcmp(suffix, "f64")) + { + target_well_known = WELL_KNOWN_CBUFRET_F64; + field_checker = sm6_type_is_double; + field_count = 2; + } + else if (!strcmp(suffix, "i16")) + { + target_well_known = WELL_KNOWN_CBUFRET_I16; + field_checker = sm6_type_is_i16; + field_count = 4; + } + else if (!strcmp(suffix, "i32")) + { + target_well_known = WELL_KNOWN_CBUFRET_I32; + field_checker = sm6_type_is_i32; + field_count = 4; + } + else if (!strcmp(suffix, "i64")) + { + target_well_known = WELL_KNOWN_CBUFRET_I64; + field_checker = sm6_type_is_i64; + field_count = 2; + } + + if (target_well_known != WELL_KNOWN_NONE) + { + if (info->elem_count != field_count) + goto error; + for (i = 0; i < field_count; ++i) + { + if (!field_checker(info->elem_types[i])) + goto error; + } + info->well_known = target_well_known; + + return; + } + } + + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_TYPE, + "Encountered unrecognised structure type `%s'.", info->name); + return; + +error: + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Structure type `%s' has unexpected fields.", info->name); +} + static const struct sm6_type *sm6_type_get_cmpxchg_result_struct(struct sm6_parser *sm6) { const struct sm6_type *type; @@ -2141,11 +2458,27 @@ static bool resource_kind_is_texture(enum dxil_resource_kind kind) return kind >= RESOURCE_KIND_TEXTURE1D && kind <= RESOURCE_KIND_TEXTURECUBEARRAY; } +static bool resource_kind_is_buffer(enum dxil_resource_kind kind) +{ + return kind >= RESOURCE_KIND_TYPEDBUFFER && kind <= RESOURCE_KIND_STRUCTUREDBUFFER; +} + static bool resource_kind_is_multisampled(enum dxil_resource_kind kind) { return kind == RESOURCE_KIND_TEXTURE2DMS || kind == RESOURCE_KIND_TEXTURE2DMSARRAY; } +static enum vkd3d_shader_resource_type shader_resource_type_from_dxil_resource_kind(enum dxil_resource_kind kind) +{ + if (resource_kind_is_texture(kind)) + return kind + 1; + + if (resource_kind_is_buffer(kind)) + return VKD3D_SHADER_RESOURCE_BUFFER; + + return VKD3D_SHADER_RESOURCE_NONE; +} + static int global_symbol_compare(const void *a, const void *b) { return vkd3d_u32_compare(((const struct sm6_symbol *)a)->id, ((const struct sm6_symbol *)b)->id); @@ -2438,18 +2771,20 @@ static unsigned int sm6_parser_alloc_ssa_id(struct sm6_parser *sm6) static void instruction_init_with_resource(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode opcode, const struct sm6_value *resource, struct sm6_parser *dxil) { + enum dxil_resource_kind kind = resource->u.handle.d->kind; + vsir_instruction_init(ins, &dxil->p.location, opcode); - ins->resource_type = resource->u.handle.d->resource_type; - ins->raw = resource->u.handle.d->kind == RESOURCE_KIND_RAWBUFFER; - ins->structured = resource->u.handle.d->kind == RESOURCE_KIND_STRUCTUREDBUFFER; + ins->resource_type = shader_resource_type_from_dxil_resource_kind(kind); + ins->raw = kind == RESOURCE_KIND_RAWBUFFER; + ins->structured = kind == RESOURCE_KIND_STRUCTUREDBUFFER; } -static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins, +static struct vsir_src_operand *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins, unsigned int count, struct sm6_parser *sm6) { - struct vkd3d_shader_src_param *params; + struct vsir_src_operand *params; - if (!(params = vsir_program_get_src_params(sm6->program, count))) + if (!(params = vsir_program_get_src_operands(sm6->program, count))) { ERR("Failed to allocate src params.\n"); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, @@ -2461,21 +2796,21 @@ static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_ return params; } -static struct vkd3d_shader_dst_param *instruction_dst_params_alloc(struct vkd3d_shader_instruction *ins, +static struct vsir_dst_operand *instruction_dst_params_alloc(struct vkd3d_shader_instruction *ins, unsigned int count, struct sm6_parser *sm6) { - struct vkd3d_shader_dst_param *params; + struct vsir_dst_operand *dst; - if (!(params = vsir_program_get_dst_params(sm6->program, count))) + if (!(dst = vsir_program_get_dst_operands(sm6->program, count))) { - ERR("Failed to allocate dst params.\n"); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, - "Out of memory allocating instruction dst parameters."); + "Out of memory allocating instruction destination operands."); return NULL; } - ins->dst = params; + ins->dst = dst; ins->dst_count = count; - return params; + + return dst; } static void register_init_with_id(struct vkd3d_shader_register *reg, @@ -2630,8 +2965,9 @@ static void vsir_register_from_dxil_value(struct vkd3d_shader_register *reg, switch (value->value_type) { case VALUE_TYPE_SSA: + VKD3D_ASSERT(sm6_type_is_numeric(value->type) || sm6_type_is_struct(value->type)); register_init_with_id(reg, VKD3DSPR_SSA, data_type, value->u.ssa.id); - reg->dimension = sm6_type_is_scalar(value->type) ? VSIR_DIMENSION_SCALAR : VSIR_DIMENSION_VEC4; + reg->dimension = sm6_type_is_numeric(value->type) ? VSIR_DIMENSION_SCALAR : VSIR_DIMENSION_VEC4; break; case VALUE_TYPE_ICB: @@ -2656,8 +2992,10 @@ static void vsir_register_from_dxil_value(struct vkd3d_shader_register *reg, break; case VALUE_TYPE_CONSTANT: + VKD3D_ASSERT(sm6_type_is_numeric(value->type) || sm6_type_is_struct(value->type)); vsir_register_init(reg, scalar_type->u.width == 64 ? VKD3DSPR_IMMCONST64 : VKD3DSPR_IMMCONST, data_type, 0); + reg->dimension = sm6_type_is_numeric(value->type) ? VSIR_DIMENSION_SCALAR : VSIR_DIMENSION_VEC4; reg->u = value->u.constant.immconst; break; @@ -2692,6 +3030,10 @@ static void sm6_parser_init_ssa_value(struct sm6_parser *sm6, struct sm6_value * value->value_type = VALUE_TYPE_SSA; value->u.ssa.id = id; + + if (!sm6_type_is_numeric(value->type) && !sm6_type_is_struct(value->type)) + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE, + "The type of SSA value %u is neither numeric nor a structure.", id); } static void register_make_constant_uint(struct vkd3d_shader_register *reg, unsigned int value) @@ -2700,41 +3042,41 @@ static void register_make_constant_uint(struct vkd3d_shader_register *reg, unsig reg->u.immconst_u32[0] = value; } -static void dst_param_init(struct vkd3d_shader_dst_param *param) +static void dst_param_init(struct vsir_dst_operand *param) { param->write_mask = VKD3DSP_WRITEMASK_0; param->modifiers = 0; param->shift = 0; } -static void dst_param_init_with_mask(struct vkd3d_shader_dst_param *param, unsigned int mask) +static void dst_param_init_with_mask(struct vsir_dst_operand *param, unsigned int mask) { param->write_mask = mask; param->modifiers = 0; param->shift = 0; } -static inline void dst_param_init_scalar(struct vkd3d_shader_dst_param *param, unsigned int component_idx) +static inline void dst_param_init_scalar(struct vsir_dst_operand *param, unsigned int component_idx) { param->write_mask = 1u << component_idx; param->modifiers = 0; param->shift = 0; } -static void dst_param_init_vector(struct vkd3d_shader_dst_param *param, unsigned int component_count) +static void dst_param_init_vector(struct vsir_dst_operand *param, unsigned int component_count) { param->write_mask = (1u << component_count) - 1; param->modifiers = 0; param->shift = 0; } -static inline void src_param_init(struct vkd3d_shader_src_param *param) +static inline void src_param_init(struct vsir_src_operand *param) { param->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); param->modifiers = VKD3DSPSM_NONE; } -static void src_param_init_scalar(struct vkd3d_shader_src_param *param, unsigned int component_idx) +static void src_param_init_scalar(struct vsir_src_operand *param, unsigned int component_idx) { param->swizzle = vkd3d_shader_create_swizzle(component_idx, component_idx, component_idx, component_idx); if (data_type_is_64_bit(param->reg.data_type)) @@ -2742,20 +3084,20 @@ static void src_param_init_scalar(struct vkd3d_shader_src_param *param, unsigned param->modifiers = VKD3DSPSM_NONE; } -static void src_param_init_vector(struct vkd3d_shader_src_param *param, unsigned int component_count) +static void src_param_init_vector(struct vsir_src_operand *param, unsigned int component_count) { param->swizzle = VKD3D_SHADER_NO_SWIZZLE & ((1ull << VKD3D_SHADER_SWIZZLE_SHIFT(component_count)) - 1); param->modifiers = VKD3DSPSM_NONE; } -static void src_param_init_from_value(struct vkd3d_shader_src_param *param, +static void src_param_init_from_value(struct vsir_src_operand *param, const struct sm6_value *src, uint32_t type_flags, struct sm6_parser *dxil) { src_param_init(param); vsir_register_from_dxil_value(¶m->reg, src, type_flags, dxil); } -static void src_param_init_vector_from_reg(struct vkd3d_shader_src_param *param, +static void src_param_init_vector_from_reg(struct vsir_src_operand *param, const struct vkd3d_shader_register *reg) { param->swizzle = (reg->dimension == VSIR_DIMENSION_VEC4) ? VKD3D_SHADER_NO_SWIZZLE : VKD3D_SHADER_SWIZZLE(X, X, X, X); @@ -2763,15 +3105,17 @@ static void src_param_init_vector_from_reg(struct vkd3d_shader_src_param *param, param->reg = *reg; } -static void src_param_make_constant_uint(struct vkd3d_shader_src_param *param, unsigned int value) +static void src_param_make_constant_uint(struct vsir_src_operand *param, unsigned int value) { src_param_init(param); register_make_constant_uint(¶m->reg, value); } -static void register_index_address_init(struct vkd3d_shader_register_index *idx, const struct sm6_value *address, - struct sm6_parser *sm6) +static void register_index_address_init(struct vkd3d_shader_register_index *idx, + const struct sm6_value *address, struct sm6_parser *sm6) { + struct vsir_src_operand *rel_addr; + if (address && sm6_value_is_constant(address)) { idx->offset = sm6_value_get_constant_uint(address, sm6); @@ -2784,8 +3128,7 @@ static void register_index_address_init(struct vkd3d_shader_register_index *idx, } else { - struct vkd3d_shader_src_param *rel_addr = vsir_program_get_src_params(sm6->program, 1); - if (rel_addr) + if ((rel_addr = vsir_program_get_src_operands(sm6->program, 1))) src_param_init_from_value(rel_addr, address, 0, sm6); idx->offset = 0; idx->rel_addr = rel_addr; @@ -2795,7 +3138,36 @@ static void register_index_address_init(struct vkd3d_shader_register_index *idx, static void sm6_register_from_handle(struct sm6_parser *sm6, const struct sm6_handle_data *handle, struct vkd3d_shader_register *reg) { - vsir_register_init(reg, handle->d->reg_type, handle->d->reg_data_type, 2); + enum vkd3d_shader_register_type reg_type; + enum vsir_data_type data_type; + + switch (handle->d->type) + { + case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV: + reg_type = VKD3DSPR_RESOURCE; + data_type = VSIR_DATA_UNUSED; + break; + + case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV: + reg_type = VKD3DSPR_UAV; + data_type = VSIR_DATA_UNUSED; + break; + + case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: + reg_type = VKD3DSPR_CONSTBUFFER; + data_type = VSIR_DATA_F32; + break; + + case VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER: + reg_type = VKD3DSPR_SAMPLER; + data_type = VSIR_DATA_UNUSED; + break; + + default: + vkd3d_unreachable(); + } + + vsir_register_init(reg, reg_type, data_type, 2); reg->dimension = VSIR_DIMENSION_VEC4; reg->idx[0].offset = handle->d->id; register_index_address_init(®->idx[1], handle->index, sm6); @@ -2803,7 +3175,7 @@ static void sm6_register_from_handle(struct sm6_parser *sm6, } static void src_param_init_vector_from_handle(struct sm6_parser *sm6, - struct vkd3d_shader_src_param *param, const struct sm6_handle_data *handle) + struct vsir_src_operand *param, const struct sm6_handle_data *handle) { struct vkd3d_shader_register reg; @@ -2815,7 +3187,7 @@ static bool instruction_dst_param_init_ssa_scalar(struct vkd3d_shader_instructio uint32_t type_flags, struct sm6_parser *dxil) { struct sm6_value *dst = sm6_parser_get_current_value(dxil); - struct vkd3d_shader_dst_param *param; + struct vsir_dst_operand *param; if (!(param = instruction_dst_params_alloc(ins, 1, dxil))) return false; @@ -2827,28 +3199,33 @@ static bool instruction_dst_param_init_ssa_scalar(struct vkd3d_shader_instructio return true; } -static void instruction_dst_param_init_ssa_vector(struct vkd3d_shader_instruction *ins, - unsigned int component_count, struct sm6_parser *sm6) +static bool instruction_dst_param_init_ssa_vector(struct vkd3d_shader_instruction *ins, + unsigned int component_count, struct sm6_parser *dxil) { - struct vkd3d_shader_dst_param *param = instruction_dst_params_alloc(ins, 1, sm6); - struct sm6_value *dst = sm6_parser_get_current_value(sm6); + struct sm6_value *dxil_dst = sm6_parser_get_current_value(dxil); + struct vsir_dst_operand *vsir_dst; - dst_param_init_vector(param, component_count); - sm6_parser_init_ssa_value(sm6, dst); - vsir_register_from_dxil_value(¶m->reg, dst, 0, sm6); + if (!(vsir_dst = instruction_dst_params_alloc(ins, 1, dxil))) + return false; + + dst_param_init_vector(vsir_dst, component_count); + sm6_parser_init_ssa_value(dxil, dxil_dst); + vsir_register_from_dxil_value(&vsir_dst->reg, dxil_dst, 0, dxil); + + return true; } static bool instruction_dst_param_init_uint_temp_vector(struct vkd3d_shader_instruction *ins, struct sm6_parser *sm6) { - struct vkd3d_shader_dst_param *param; + struct vsir_dst_operand *dst; - if (!(param = instruction_dst_params_alloc(ins, 1, sm6))) + if (!(dst = instruction_dst_params_alloc(ins, 1, sm6))) return false; - vsir_dst_param_init(param, VKD3DSPR_TEMP, VSIR_DATA_U32, 1); - param->write_mask = VKD3DSP_WRITEMASK_ALL; - param->reg.idx[0].offset = 0; - param->reg.dimension = VSIR_DIMENSION_VEC4; + vsir_dst_operand_init(dst, VKD3DSPR_TEMP, VSIR_DATA_U32, 1); + dst->write_mask = VKD3DSP_WRITEMASK_ALL; + dst->reg.idx[0].offset = 0; + dst->reg.dimension = VSIR_DIMENSION_VEC4; return true; } @@ -2890,27 +3267,24 @@ static size_t sm6_parser_compute_max_value_count(struct sm6_parser *sm6, return value_count; } -static size_t sm6_parser_get_value_index(struct sm6_parser *sm6, uint64_t idx) +static size_t sm6_parser_get_value_index(struct sm6_parser *dxil, uint32_t idx) { size_t i; - /* The value relative index is 32 bits. */ - if (idx > UINT32_MAX) - WARN("Ignoring upper 32 bits of relative index.\n"); - i = (uint32_t)sm6->value_count - (uint32_t)idx; + i = (uint32_t)dxil->value_count - idx; - /* This may underflow to produce a forward reference, but it must not exceed the final value count. */ - if (i >= sm6->cur_max_value) + /* This may underflow to produce a forward reference, but it must not + * exceed the final value count. */ + if (i >= dxil->cur_max_value) { - WARN("Invalid value index %"PRIx64" at %zu.\n", idx, sm6->value_count); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, - "Invalid value relative index %u.", (unsigned int)idx); + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value relative index %u.", idx); return SIZE_MAX; } - if (i == sm6->value_count) + + if (i == dxil->value_count) { - WARN("Invalid value self-reference at %zu.\n", sm6->value_count); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid value self-reference."); + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid value self-reference."); return SIZE_MAX; } @@ -2950,7 +3324,7 @@ static bool sm6_value_validate_is_texture_handle(const struct sm6_value *value, return false; kind = value->u.handle.d->kind; - if (kind < RESOURCE_KIND_TEXTURE1D || kind > RESOURCE_KIND_TEXTURECUBEARRAY) + if (!resource_kind_is_texture(kind)) { WARN("Resource kind %u for op %u is not a texture.\n", kind, op); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCE_HANDLE, @@ -3084,10 +3458,38 @@ static struct sm6_value *sm6_parser_get_value_safe(struct sm6_parser *sm6, unsig return NULL; } +static void sm6_parser_pre_init_or_validate_referenced_value(struct sm6_parser *dxil, + size_t operand, const struct sm6_type *fwd_type) +{ + struct sm6_value *value; + + value = &dxil->values[operand]; + + /* If the value has a type, validate that it matches the expected type, + * otherwise it is a forward reference and we must set the type and + * initialise the value's register to SSA so it can be consumed by an + * instruction. */ + if (value->type) + { + if (value->type != fwd_type) + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "The type of a source value does not match the predefined type."); + } + else + { + value->type = fwd_type; + value->value_type = VALUE_TYPE_SSA; + value->u.ssa.id = sm6_parser_alloc_ssa_id(dxil); + + if (!sm6_type_is_numeric(value->type) && !sm6_type_is_struct(value->type)) + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE, + "The type of SSA value %u is neither numeric nor a structure.", value->u.ssa.id); + } +} + static size_t sm6_parser_get_value_idx_by_ref(struct sm6_parser *sm6, const struct dxil_record *record, const struct sm6_type *fwd_type, unsigned int *rec_idx) { - struct sm6_value *value; unsigned int idx; uint64_t val_ref; size_t operand; @@ -3097,6 +3499,11 @@ static size_t sm6_parser_get_value_idx_by_ref(struct sm6_parser *sm6, const stru return SIZE_MAX; val_ref = record->operands[idx++]; + /* Normally only the lower 32 bits are set in the value relative index. */ + if (val_ref > UINT32_MAX) + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring upper 32 bits of DXIL SSA value relative index %"PRIx64".", val_ref); + operand = sm6_parser_get_value_index(sm6, val_ref); if (operand == SIZE_MAX) return SIZE_MAX; @@ -3113,28 +3520,42 @@ static size_t sm6_parser_get_value_idx_by_ref(struct sm6_parser *sm6, const stru *rec_idx = idx; if (fwd_type) - { - value = &sm6->values[operand]; - if (value->type) - { - if (value->type != fwd_type) - { - WARN("Value already has a mismatching type.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, - "The type of a source value does not match the predefined type."); - } - } - else - { - value->type = fwd_type; - value->value_type = VALUE_TYPE_SSA; - value->u.ssa.id = sm6_parser_alloc_ssa_id(sm6); - } - } + sm6_parser_pre_init_or_validate_referenced_value(sm6, operand, fwd_type); return operand; } +static uint64_t decode_rotated_signed_value(uint64_t value) +{ + if (value != 1) + { + bool neg = value & 1; + value >>= 1; + return neg ? -value : value; + } + + return value << 63; +} + +static const struct sm6_value *sm6_parser_get_value_by_rotated_signed_idx(struct sm6_parser *dxil, + uint64_t idx, const struct sm6_type *fwd_type) +{ + int64_t rotated_idx; + size_t operand; + + rotated_idx = decode_rotated_signed_value(idx); + if (rotated_idx > INT32_MAX || rotated_idx < INT32_MIN) + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring upper 32 bits of DXIL SSA value signed relative index %"PRIx64".", rotated_idx); + + if ((operand = sm6_parser_get_value_index(dxil, rotated_idx)) == SIZE_MAX) + return NULL; + + sm6_parser_pre_init_or_validate_referenced_value(dxil, operand, fwd_type); + + return &dxil->values[operand]; +} + static const struct sm6_value *sm6_parser_get_value_by_ref(struct sm6_parser *sm6, const struct dxil_record *record, const struct sm6_type *type, unsigned int *rec_idx) { @@ -3186,8 +3607,7 @@ static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxi if (record->operands[4] > UINT_MAX) WARN("Invalid attributes id %#"PRIx64".\n", record->operands[4]); /* 1-based index. */ - if ((fn->u.function.attribs_id = record->operands[4])) - TRACE("Ignoring function attributes.\n"); + fn->u.function.attribs_id = record->operands[4]; /* These always seem to be zero. */ for (i = 5, j = 0; i < min(record->operand_count, max_count); ++i) @@ -3206,17 +3626,6 @@ static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxi return true; } -static inline uint64_t decode_rotated_signed_value(uint64_t value) -{ - if (value != 1) - { - bool neg = value & 1; - value >>= 1; - return neg ? -value : value; - } - return value << 63; -} - static struct sm6_index *sm6_get_value_index(struct sm6_parser *sm6, struct sm6_value *value) { switch (value->value_type) @@ -3361,7 +3770,7 @@ static enum vkd3d_result sm6_parser_init_constexpr_gep(struct sm6_parser *sm6, c static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) { const struct sm6_type *type, *ptr_type; - size_t i, base_value_idx, value_idx; + size_t i, j, base_value_idx, value_idx; const struct dxil_record *record; const struct sm6_value *src; enum vkd3d_result ret; @@ -3406,11 +3815,49 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const dst->value_type = VALUE_TYPE_CONSTANT_ARRAY; dst->u.constant_array.elements = NULL; } - else + else if (sm6_type_is_numeric(type)) { dst->value_type = VALUE_TYPE_CONSTANT; memset(&dst->u.constant, 0, sizeof(dst->u.constant)); } + else if (sm6_type_is_struct(type)) + { + if (type->u.struc->elem_count > VKD3D_VEC4_SIZE) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_CONSTANT, + "The type of a null constant is a structure type with %u fields, " + "while at most %u are allowed.", type->u.struc->elem_count, VKD3D_VEC4_SIZE); + return VKD3D_ERROR_INVALID_SHADER; + } + + dst->value_type = VALUE_TYPE_CONSTANT; + memset(&dst->u.constant.immconst, 0, sizeof(dst->u.constant.immconst)); + + for (j = 0; j < record->operand_count; ++j) + { + const struct sm6_type *elem_type = type->u.struc->elem_types[j]; + + if (!sm6_type_is_integer(elem_type) || elem_type->u.width > 32) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The type of a structure element is not an integer of width <= 32 bits."); + return VKD3D_ERROR_INVALID_SHADER; + } + dst->u.constant.immconst.immconst_u32[j] = sm6_value_get_constant_uint( + &sm6->values[record->operands[j]], sm6); + } + } + else + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE, + "The type of a null constant is not numeric, structure or array."); + return VKD3D_ERROR_INVALID_SHADER; + } + break; + + case CST_CODE_UNDEF: + dxil_record_validate_operand_max_count(record, 0, sm6); + dst->value_type = VALUE_TYPE_UNDEFINED; break; case CST_CODE_INTEGER: @@ -3453,26 +3900,41 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const break; - case CST_CODE_DATA: - if (!sm6_type_is_array(type)) + case CST_CODE_AGGREGATE: + if (!sm6_type_is_struct(type)) { - WARN("Invalid type %u for data constant idx %zu.\n", type->class, value_idx); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, - "The type of a constant array is not an array type."); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE, + "The type of a constant aggregate is not a structure type."); return VKD3D_ERROR_INVALID_SHADER; } - if (!dxil_record_validate_operand_count(record, type->u.array.count, type->u.array.count, sm6)) + + if (type->u.struc->elem_count > VKD3D_VEC4_SIZE) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_CONSTANT, + "The type of a constant aggregate is a structure type with %u fields, " + "while at most %u are allowed.", type->u.struc->elem_count, VKD3D_VEC4_SIZE); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!dxil_record_validate_operand_count(record, + type->u.struc->elem_count, type->u.struc->elem_count, sm6)) return VKD3D_ERROR_INVALID_SHADER; - dst->value_type = VALUE_TYPE_CONSTANT_ARRAY; - dst->u.constant_array.elements = record->operands; + dst->value_type = VALUE_TYPE_CONSTANT; - break; + for (j = 0; j < record->operand_count; ++j) + { + const struct sm6_type *elem_type = type->u.struc->elem_types[j]; - case CST_CODE_CE_GEP: - case CST_CODE_CE_INBOUNDS_GEP: - if ((ret = sm6_parser_init_constexpr_gep(sm6, record, dst)) < 0) - return ret; + if (!sm6_type_is_integer(elem_type) || elem_type->u.width > 32) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The type of a structure element is not an integer of width <= 32 bits."); + return VKD3D_ERROR_INVALID_SHADER; + } + dst->u.constant.immconst.immconst_u32[j] = sm6_value_get_constant_uint( + &sm6->values[record->operands[j]], sm6); + } break; case CST_CODE_CE_CAST: @@ -3481,9 +3943,25 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const dst->value_type = VALUE_TYPE_INVALID; break; - case CST_CODE_UNDEF: - dxil_record_validate_operand_max_count(record, 0, sm6); - dst->value_type = VALUE_TYPE_UNDEFINED; + case CST_CODE_CE_GEP: + case CST_CODE_CE_INBOUNDS_GEP: + if ((ret = sm6_parser_init_constexpr_gep(sm6, record, dst)) < 0) + return ret; + break; + + case CST_CODE_DATA: + if (!sm6_type_is_array(type)) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The type of a constant array is not an array type."); + return VKD3D_ERROR_INVALID_SHADER; + } + if (!dxil_record_validate_operand_count(record, type->u.array.count, type->u.array.count, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + dst->value_type = VALUE_TYPE_CONSTANT_ARRAY; + dst->u.constant_array.elements = record->operands; + break; default: @@ -4107,7 +4585,7 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) return VKD3D_OK; } -static void dst_param_io_init(struct vkd3d_shader_dst_param *param, const struct signature_element *e, +static void dst_param_io_init(struct vsir_dst_operand *param, const struct signature_element *e, enum vkd3d_shader_register_type reg_type, enum vsir_dimension dimension) { enum vkd3d_shader_component_type component_type; @@ -4121,7 +4599,7 @@ static void dst_param_io_init(struct vkd3d_shader_dst_param *param, const struct param->reg.dimension = dimension; } -static void src_params_init_from_operands(struct vkd3d_shader_src_param *src_params, +static void src_params_init_from_operands(struct vsir_src_operand *src_params, const struct sm6_value **operands, unsigned int count, struct sm6_parser *sm6) { unsigned int i; @@ -4164,13 +4642,13 @@ static enum vkd3d_shader_register_type register_type_from_dxil_semantic_kind( } static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shader_signature *s, - bool is_input, enum vkd3d_shader_register_type reg_type, struct vkd3d_shader_dst_param *params) + bool is_input, enum vkd3d_shader_register_type reg_type, struct vsir_dst_operand *params) { enum vkd3d_shader_type shader_type = sm6->program->shader_version.type; enum vkd3d_shader_register_type io_reg_type; bool is_patch_constant, is_control_point; - struct vkd3d_shader_dst_param *param; const struct signature_element *e; + struct vsir_dst_operand *param; unsigned int i, count; is_patch_constant = reg_type == VKD3DSPR_PATCHCONST; @@ -4234,7 +4712,7 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade static int sm6_parser_init_output_signature(struct sm6_parser *sm6, const struct shader_signature *output_signature) { - if (!(sm6->output_params = vsir_program_get_dst_params(sm6->program, output_signature->element_count))) + if (!(sm6->output_params = vsir_program_get_dst_operands(sm6->program, output_signature->element_count))) { vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, "Failed to allocate output parameters."); @@ -4248,7 +4726,7 @@ static int sm6_parser_init_output_signature(struct sm6_parser *sm6, const struct static int sm6_parser_init_input_signature(struct sm6_parser *sm6, const struct shader_signature *input_signature) { - if (!(sm6->input_params = vsir_program_get_dst_params(sm6->program, input_signature->element_count))) + if (!(sm6->input_params = vsir_program_get_dst_operands(sm6->program, input_signature->element_count))) { vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, "Failed to allocate input parameters."); @@ -4265,7 +4743,7 @@ static int sm6_parser_init_patch_constant_signature(struct sm6_parser *sm6, { bool is_input = sm6->program->shader_version.type == VKD3D_SHADER_TYPE_DOMAIN; - if (!(sm6->patch_constant_params = vsir_program_get_dst_params(sm6->program, + if (!(sm6->patch_constant_params = vsir_program_get_dst_operands(sm6->program, patch_constant_signature->element_count))) { vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, @@ -4295,47 +4773,36 @@ static const struct sm6_value *sm6_parser_next_function_definition(struct sm6_pa return &sm6->values[i]; } -static struct sm6_block *sm6_block_create() +struct function_emission_state { - struct sm6_block *block = vkd3d_calloc(1, sizeof(*block)); - return block; -} + struct sm6_function *function; + const struct dxil_record *record; + unsigned int temp_idx; +}; -static struct sm6_phi *sm6_block_phi_require_space(struct sm6_block *block, struct sm6_parser *sm6) +static struct vkd3d_shader_instruction *sm6_parser_add_function_instruction(struct sm6_parser *sm6, + struct function_emission_state *state) { - struct sm6_phi *phi; + struct sm6_function *function = state->function; + struct vkd3d_shader_instruction *ins; - if (!vkd3d_array_reserve((void **)&block->phi, &block->phi_capacity, block->phi_count + 1, sizeof(*block->phi))) - { - ERR("Failed to allocate phi array.\n"); + if (!(ins = shader_instruction_array_append(&function->instructions))) vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, - "Out of memory allocating a phi instruction."); - return NULL; - } - phi = &block->phi[block->phi_count++]; - - phi->incoming = NULL; - phi->incoming_capacity = 0; - phi->incoming_count = 0; + "Out of memory allocating instruction."); - return phi; + return ins; } -struct function_emission_state -{ - struct sm6_block *code_block; - struct vkd3d_shader_instruction *ins; - unsigned int temp_idx; -}; - static bool sm6_parser_emit_reg_composite_construct(struct sm6_parser *sm6, const struct vkd3d_shader_register *operand_regs, unsigned int component_count, struct function_emission_state *state, struct vkd3d_shader_register *reg); -static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_alloca(struct sm6_parser *sm6, struct function_emission_state *state) { + struct sm6_value *dst = sm6_parser_get_current_value(sm6); + const struct dxil_record *record = state->record; const struct sm6_type *type[2], *elem_type; + struct vkd3d_shader_instruction *ins; const struct sm6_value *size; unsigned int i, alignment; uint64_t packed_operands; @@ -4402,6 +4869,9 @@ static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_rec if (packed_operands) WARN("Ignoring flags %#"PRIx64".\n", packed_operands); + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + sm6_parser_declare_indexable_temp(sm6, elem_type, type[0]->u.array.count, alignment, true, 0, ins, dst); } @@ -4433,13 +4903,14 @@ static enum vkd3d_shader_opcode map_dx_atomicrmw_op(uint64_t code) } } -static void sm6_parser_emit_atomicrmw(struct sm6_parser *sm6, const struct dxil_record *record, - struct function_emission_state *state, struct sm6_value *dst) +static void sm6_parser_emit_atomicrmw(struct sm6_parser *sm6, struct function_emission_state *state) { - struct vkd3d_shader_dst_param *dst_params; - struct vkd3d_shader_src_param *src_params; + struct sm6_value *dst = sm6_parser_get_current_value(sm6); + const struct dxil_record *record = state->record; struct vkd3d_shader_register regs[2], reg; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_params; struct vkd3d_shader_register coord; const struct sm6_value *ptr, *src; enum vkd3d_shader_opcode op; @@ -4499,12 +4970,17 @@ static void sm6_parser_emit_atomicrmw(struct sm6_parser *sm6, const struct dxil_ return; } - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, op); ins->flags = is_volatile ? VKD3DARF_VOLATILE : 0; if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } if (ptr->structure_stride) src_param_init_vector_from_reg(&src_params[0], &coord); else @@ -4513,7 +4989,11 @@ static void sm6_parser_emit_atomicrmw(struct sm6_parser *sm6, const struct dxil_ sm6_parser_init_ssa_value(sm6, dst); - dst_params = instruction_dst_params_alloc(ins, 2, sm6); + if (!(dst_params = instruction_dst_params_alloc(ins, 2, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } vsir_register_from_dxil_value(&dst_params[0].reg, dst, 0, sm6); dst_param_init(&dst_params[0]); @@ -4622,12 +5102,14 @@ static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_ty return op; } -static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_record *record, - struct sm6_block *code_block, struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_binop(struct sm6_parser *sm6, struct function_emission_state *state) { + struct sm6_value *dst = sm6_parser_get_current_value(sm6); + const struct dxil_record *record = state->record; enum vkd3d_shader_opcode opcode, aux_opcode; - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_dst_param *dst_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_params; uint32_t type_flags = 0, aux_id = 0; const struct sm6_value *a, *b; uint64_t code, flags; @@ -4650,11 +5132,17 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco if (aux_opcode != VSIR_OP_NOP) { + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, aux_opcode); if (!(dst_params = instruction_dst_params_alloc(ins, 1, sm6)) || !(src_params = instruction_src_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } aux_id = sm6_parser_alloc_ssa_id(sm6); @@ -4662,11 +5150,11 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco dst_param_init(&dst_params[0]); register_init_with_id(&dst_params[0].reg, VKD3DSPR_SSA, src_params[0].reg.data_type, aux_id); - - ++ins; - ++code_block->instruction_count; } + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, opcode); flags = (record->operand_count > i) ? record->operands[i] : 0; @@ -4715,7 +5203,10 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco } if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } src_param_init_from_value(&src_params[0], a, type_flags, sm6); @@ -4738,71 +5229,97 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco * do. */ ins->flags |= VKD3DSI_SHIFT_UNMASKED; } - instruction_dst_param_init_ssa_scalar(ins, type_flags, sm6); + + if (!instruction_dst_param_init_ssa_scalar(ins, type_flags, sm6)) + vkd3d_shader_instruction_make_nop(ins); } -static const struct sm6_block *sm6_function_get_block(const struct sm6_function *function, uint64_t index, - struct sm6_parser *sm6) +static bool sm6_function_validate_block_index(const struct sm6_function *function, + uint64_t index, struct sm6_parser *dxil) { if (index >= function->block_count) { - WARN("Invalid code block index %#"PRIx64".\n", index); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, "Invalid code block index %#"PRIx64" for a control flow instruction.", index); - return NULL; + return false; } - return function->blocks[index]; + + return true; } -static void sm6_parser_emit_br(struct sm6_parser *sm6, const struct dxil_record *record, - struct sm6_function *function, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) +static void sm6_parser_emit_br(struct sm6_parser *dxil, struct function_emission_state *state) { + const struct dxil_record *record = state->record; + struct sm6_function *function = state->function; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; const struct sm6_value *value; unsigned int i = 2; if (record->operand_count != 1 && record->operand_count < 3) { - WARN("Invalid operand count %u.\n", record->operand_count); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, "Invalid operand count %u for a branch instruction.", record->operand_count); return; } if (record->operand_count == 1) { - code_block->terminator.type = TERMINATOR_UNCOND_BR; - code_block->terminator.true_block = sm6_function_get_block(function, record->operands[0], sm6); + if (!sm6_function_validate_block_index(function, record->operands[0], dxil)) + return; + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_BRANCH); + if (!(src_params = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + /* Label id is 1-based. */ + vsir_src_operand_init_label(&src_params[0], record->operands[0] + 1); } else { - if (!sm6->bool_type) + if (!dxil->bool_type) { - WARN("Bool type not found.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, "Module does not define a boolean type for conditions."); return; } - if (!(value = sm6_parser_get_value_by_ref(sm6, record, sm6->bool_type, &i)) - || !sm6_value_validate_is_bool(value, sm6)) + if (!(value = sm6_parser_get_value_by_ref(dxil, record, dxil->bool_type, &i)) + || !sm6_value_validate_is_bool(value, dxil)) return; - dxil_record_validate_operand_max_count(record, i, sm6); + dxil_record_validate_operand_max_count(record, i, dxil); - code_block->terminator.type = TERMINATOR_COND_BR; - vsir_register_from_dxil_value(&code_block->terminator.conditional_reg, value, 0, sm6); - code_block->terminator.true_block = sm6_function_get_block(function, record->operands[0], sm6); - code_block->terminator.false_block = sm6_function_get_block(function, record->operands[1], sm6); - } + if (!sm6_function_validate_block_index(function, record->operands[0], dxil) + || !sm6_function_validate_block_index(function, record->operands[1], dxil)) + return; + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - ins->opcode = VSIR_OP_NOP; + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_BRANCH); + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + src_param_init_from_value(&src_params[0], value, 0, dxil); + /* Label id is 1-based. */ + vsir_src_operand_init_label(&src_params[1], record->operands[0] + 1); + vsir_src_operand_init_label(&src_params[2], record->operands[1] + 1); + } } static bool sm6_parser_emit_reg_composite_construct(struct sm6_parser *sm6, const struct vkd3d_shader_register *operand_regs, unsigned int component_count, struct function_emission_state *state, struct vkd3d_shader_register *reg) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_dst_param *dst_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_param; bool all_constant = true; unsigned int i; @@ -4829,27 +5346,31 @@ static bool sm6_parser_emit_reg_composite_construct(struct sm6_parser *sm6, register_init_with_id(reg, VKD3DSPR_TEMP, operand_regs[0].data_type, state->temp_idx++); reg->dimension = VSIR_DIMENSION_VEC4; - for (i = 0; i < component_count; ++i, ++ins) + for (i = 0; i < component_count; ++i) { + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return false; + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) - return false; + goto error; src_param_init(&src_params[0]); src_params[0].reg = operand_regs[i]; if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) - return false; + goto error; dst_param_init_scalar(dst_param, i); dst_param->reg = *reg; } - state->ins = ins; - state->code_block->instruction_count += component_count; - return true; + +error: + vkd3d_shader_instruction_make_nop(ins); + return false; } static bool sm6_parser_emit_composite_construct(struct sm6_parser *sm6, const struct sm6_value **operands, @@ -4897,12 +5418,18 @@ static enum vkd3d_shader_opcode sm6_dx_map_void_op(enum dx_intrinsic_opcode op) } } -static void sm6_parser_emit_dx_void(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_void(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - vsir_instruction_init(ins, &sm6->p.location, sm6_dx_map_void_op(op)); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + struct vkd3d_shader_instruction *ins; + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, sm6_dx_map_void_op(op)); + + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static enum vkd3d_shader_opcode map_dx_unary_op(enum dx_intrinsic_opcode op) @@ -4990,18 +5517,25 @@ static enum vkd3d_shader_opcode map_dx_unary_op(enum dx_intrinsic_opcode op) } } -static void sm6_parser_emit_dx_unary(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_unary(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - vsir_instruction_init(ins, &sm6->p.location, map_dx_unary_op(op)); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, map_dx_unary_op(op)); + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(src_param, operands[0], 0, sm6); + } + src_param_init_from_value(src_param, operands[0], 0, dxil); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static enum vkd3d_shader_opcode map_dx_binary_op(enum dx_intrinsic_opcode op, @@ -5034,20 +5568,29 @@ static enum vkd3d_shader_opcode map_dx_binary_op(enum dx_intrinsic_opcode op, } } -static void sm6_parser_emit_dx_binary(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_binary(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; uint32_t type_flags; - vsir_instruction_init(ins, &sm6->p.location, map_dx_binary_op(op, operands[0]->type, &type_flags)); - if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, map_dx_binary_op(op, operands[0]->type, &type_flags)); + + if (!(src_params = instruction_src_params_alloc(ins, 2, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(&src_params[0], operands[0], type_flags, sm6); - src_param_init_from_value(&src_params[1], operands[1], type_flags, sm6); + } - instruction_dst_param_init_ssa_scalar(ins, type_flags, sm6); + src_param_init_from_value(&src_params[0], operands[0], type_flags, dxil); + src_param_init_from_value(&src_params[1], operands[1], type_flags, dxil); + + if (!instruction_dst_param_init_ssa_scalar(ins, type_flags, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static enum vkd3d_shader_opcode map_dx_atomic_binop(const struct sm6_value *operand, struct sm6_parser *sm6) @@ -5086,15 +5629,15 @@ static void sm6_parser_emit_dx_atomic_binop(struct sm6_parser *sm6, enum dx_intr const struct sm6_value **operands, struct function_emission_state *state) { struct sm6_value *dst = sm6_parser_get_current_value(sm6); - enum vkd3d_shader_resource_type resource_type; bool is_cmp_xchg = op == DX_ATOMIC_CMP_XCHG; unsigned int i, coord_idx, coord_count = 1; - struct vkd3d_shader_dst_param *dst_params; - struct vkd3d_shader_src_param *src_params; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_params; const struct sm6_value *resource; struct vkd3d_shader_register reg; enum vkd3d_shader_opcode opcode; + enum dxil_resource_kind kind; resource = operands[0]; if (!sm6_value_validate_is_handle(resource, sm6)) @@ -5106,10 +5649,10 @@ static void sm6_parser_emit_dx_atomic_binop(struct sm6_parser *sm6, enum dx_intr return; coord_idx = 2 - is_cmp_xchg; - resource_type = resource->u.handle.d->resource_type; - if (resource_type != VKD3D_SHADER_RESOURCE_BUFFER || resource->u.handle.d->kind == RESOURCE_KIND_STRUCTUREDBUFFER) + kind = resource->u.handle.d->kind; + if (resource_kind_is_texture(kind) || kind == RESOURCE_KIND_STRUCTUREDBUFFER) { - coord_count = 2 + (resource_type != VKD3D_SHADER_RESOURCE_BUFFER); + coord_count = 2 + resource_kind_is_texture(kind); if (!sm6_parser_emit_coordinate_construct(sm6, &operands[coord_idx], coord_count, NULL, state, ®)) return; } @@ -5129,11 +5672,17 @@ static void sm6_parser_emit_dx_atomic_binop(struct sm6_parser *sm6, enum dx_intr } } - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, opcode); if (!(src_params = instruction_src_params_alloc(ins, 2 + is_cmp_xchg, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_reg(&src_params[0], ®); if (is_cmp_xchg) src_param_init_from_value(&src_params[1], operands[4], 0, sm6); @@ -5141,39 +5690,44 @@ static void sm6_parser_emit_dx_atomic_binop(struct sm6_parser *sm6, enum dx_intr sm6_parser_init_ssa_value(sm6, dst); - dst_params = instruction_dst_params_alloc(ins, 2, sm6); + if (!(dst_params = instruction_dst_params_alloc(ins, 2, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + dst_param_init(&dst_params[0]); vsir_register_from_dxil_value(&dst_params[0].reg, dst, 0, sm6); dst_param_init(&dst_params[1]); sm6_register_from_handle(sm6, &resource->u.handle, &dst_params[1].reg); } -static void sm6_parser_emit_dx_barrier(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_barrier(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; + struct vkd3d_shader_instruction *ins; enum dxil_sync_flags flags; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_SYNC); - flags = sm6_value_get_constant_uint(operands[0], sm6); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_SYNC); + flags = sm6_value_get_constant_uint(operands[0], dxil); ins->flags = flags & (SYNC_THREAD_GROUP | SYNC_THREAD_GROUP_UAV); if (flags & SYNC_GLOBAL_UAV) ins->flags |= VKD3DSSF_GLOBAL_UAV; if (flags & SYNC_GROUP_SHARED_MEMORY) ins->flags |= VKD3DSSF_GROUP_SHARED_MEMORY; if (flags &= ~(SYNC_THREAD_GROUP | SYNC_GLOBAL_UAV | SYNC_THREAD_GROUP_UAV | SYNC_GROUP_SHARED_MEMORY)) - { - FIXME("Unhandled flags %#x.\n", flags); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, "Barrier flags %#x are unhandled.", flags); - } } static void sm6_parser_emit_dx_buffer_update_counter(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; const struct sm6_value *resource; unsigned int i; int8_t inc; @@ -5190,27 +5744,33 @@ static void sm6_parser_emit_dx_buffer_update_counter(struct sm6_parser *sm6, enu } i = sm6_value_get_constant_uint(operands[1], sm6); if (i != 1 && i != 255) - { - WARN("Unexpected update value %#x.\n", i); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, "Update value %#x for a UAV counter operation is not supported.", i); - } inc = i; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, (inc < 0) ? VSIR_OP_IMM_ATOMIC_CONSUME : VSIR_OP_IMM_ATOMIC_ALLOC); + if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_handle(sm6, &src_params[0], &resource->u.handle); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, sm6)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_calculate_lod(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { const struct sm6_value *resource, *sampler; - struct vkd3d_shader_src_param *src_params; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; struct vkd3d_shader_register coord; unsigned int clamp; @@ -5218,33 +5778,39 @@ static void sm6_parser_emit_dx_calculate_lod(struct sm6_parser *sm6, enum dx_int sampler = operands[1]; if (!sm6_value_validate_is_texture_handle(resource, op, sm6) || !sm6_value_validate_is_sampler_handle(sampler, op, sm6)) - { return; - } if (!sm6_parser_emit_coordinate_construct(sm6, &operands[2], 3, NULL, state, &coord)) return; clamp = sm6_value_get_constant_uint(operands[5], sm6); - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_LOD); + if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_reg(&src_params[0], &coord); sm6_register_from_handle(sm6, &resource->u.handle, &src_params[1].reg); src_param_init_scalar(&src_params[1], !clamp); src_param_init_vector_from_handle(sm6, &src_params[2], &sampler->u.handle); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, sm6)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { struct sm6_value *dst = sm6_parser_get_current_value(sm6); - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; const struct sm6_value *buffer; const struct sm6_type *type; @@ -5252,10 +5818,17 @@ static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, enum dx_intr if (!sm6_value_validate_is_handle(buffer, sm6)) return; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_handle(sm6, src_param, &buffer->u.handle); /* Differently from other descriptors, constant buffers require an * additional index, used to index within the constant buffer itself. */ @@ -5270,14 +5843,15 @@ static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, enum dx_intr else register_convert_to_minimum_precision(&src_param->reg); - instruction_dst_param_init_ssa_vector(ins, sm6_type_max_vector_size(type), sm6); + if (!instruction_dst_param_init_ssa_vector(ins, sm6_type_max_vector_size(type), sm6)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_dcl_register_builtin(struct sm6_parser *dxil, enum vkd3d_shader_opcode opcode, enum vkd3d_shader_register_type reg_type, enum vsir_data_type data_type, unsigned int component_count) { - struct vkd3d_shader_dst_param *dst_param; struct vkd3d_shader_instruction *ins; + struct vsir_dst_operand *dst_param; if (!bitmap_is_set(dxil->io_regs_declared, reg_type)) { @@ -5290,28 +5864,37 @@ static void sm6_parser_dcl_register_builtin(struct sm6_parser *dxil, enum vkd3d_ } } -static void sm6_parser_emit_dx_input_register_mov(struct sm6_parser *sm6, struct vkd3d_shader_instruction *ins, +static void sm6_parser_emit_dx_input_register_mov(struct sm6_parser *dxil, struct function_emission_state *state, enum vkd3d_shader_register_type reg_type, enum vsir_data_type data_type, bool scalar) { - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - sm6_parser_dcl_register_builtin(sm6, VSIR_OP_DCL_INPUT, reg_type, data_type, 1); + } + + sm6_parser_dcl_register_builtin(dxil, VSIR_OP_DCL_INPUT, reg_type, data_type, 1); vsir_register_init(&src_param->reg, reg_type, data_type, 0); if (!scalar) src_param->reg.dimension = VSIR_DIMENSION_VEC4; src_param_init(src_param); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_coverage(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_coverage(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - sm6_parser_emit_dx_input_register_mov(sm6, state->ins, VKD3DSPR_COVERAGE, VSIR_DATA_U32, false); + sm6_parser_emit_dx_input_register_mov(dxil, state, VKD3DSPR_COVERAGE, VSIR_DATA_U32, false); } static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_parser *sm6, @@ -5342,7 +5925,6 @@ static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_pa static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; enum vkd3d_shader_descriptor_type type; const struct sm6_descriptor_info *d; struct sm6_value *dst; @@ -5352,7 +5934,6 @@ static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, enum dx_int id = sm6_value_get_constant_uint(operands[1], sm6); if (!(d = sm6_parser_get_descriptor(sm6, type, id, operands[2]))) { - WARN("Failed to find resource type %#x, id %#x.\n", type, id); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Descriptor for resource type %#x, id %#x was not found.", type, id); return; @@ -5363,87 +5944,98 @@ static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, enum dx_int dst->u.handle.d = d; dst->u.handle.index = operands[2]; dst->u.handle.non_uniform = !!sm6_value_get_constant_uint(operands[3], sm6); - - /* NOP is used to flag no instruction emitted. */ - ins->opcode = VSIR_OP_NOP; } -static void sm6_parser_emit_dx_stream(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_stream(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; unsigned int i; - vsir_instruction_init(ins, &sm6->p.location, (op == DX_CUT_STREAM) ? VSIR_OP_CUT_STREAM : VSIR_OP_EMIT_STREAM); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, (op == DX_CUT_STREAM) ? VSIR_OP_CUT_STREAM : VSIR_OP_EMIT_STREAM); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } - i = sm6_value_get_constant_uint(operands[0], sm6); + i = sm6_value_get_constant_uint(operands[0], dxil); if (i >= MAX_GS_OUTPUT_STREAMS) - { - WARN("Invalid stream index %u.\n", i); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Output stream index %u is invalid.", i); - } register_init_with_id(&src_param->reg, VKD3DSPR_STREAM, VSIR_DATA_UNUSED, i); src_param_init(src_param); if (op == DX_EMIT_THEN_CUT_STREAM) - { - ++state->ins; - ++state->code_block->instruction_count; - sm6_parser_emit_dx_stream(sm6, DX_CUT_STREAM, operands, state); - } + sm6_parser_emit_dx_stream(dxil, DX_CUT_STREAM, operands, state); } -static void sm6_parser_emit_dx_discard(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_discard(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_DISCARD); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if ((src_param = instruction_src_params_alloc(ins, 1, sm6))) - src_param_init_from_value(src_param, operands[0], 0, sm6); + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_DISCARD); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + + src_param_init_from_value(src_param, operands[0], 0, dxil); } -static void sm6_parser_emit_dx_domain_location(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_domain_location(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; unsigned int component_idx; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if ((component_idx = sm6_value_get_constant_uint(operands[0], sm6)) >= 3) + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if ((component_idx = sm6_value_get_constant_uint(operands[0], dxil)) >= 3) { - WARN("Invalid component index %u.\n", component_idx); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid domain location component index %u.", component_idx); component_idx = 0; } - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - sm6_parser_dcl_register_builtin(sm6, VSIR_OP_DCL_INPUT, VKD3DSPR_TESSCOORD, VSIR_DATA_F32, 3); + } + + sm6_parser_dcl_register_builtin(dxil, VSIR_OP_DCL_INPUT, VKD3DSPR_TESSCOORD, VSIR_DATA_F32, 3); vsir_register_init(&src_param->reg, VKD3DSPR_TESSCOORD, VSIR_DATA_F32, 0); src_param->reg.dimension = VSIR_DIMENSION_VEC4; src_param_init_scalar(src_param, component_idx); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_dot(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_dot(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_src_param *src_params; struct vkd3d_shader_instruction *ins; struct vkd3d_shader_register regs[2]; + struct vsir_src_operand *src_params; enum vkd3d_shader_opcode opcode; unsigned int component_count; @@ -5465,28 +6057,36 @@ static void sm6_parser_emit_dx_dot(struct sm6_parser *sm6, enum dx_intrinsic_opc vkd3d_unreachable(); } - if (!sm6_parser_emit_composite_construct(sm6, &operands[0], component_count, state, ®s[0])) + if (!sm6_parser_emit_composite_construct(dxil, &operands[0], component_count, state, ®s[0])) return; - if (!sm6_parser_emit_composite_construct(sm6, &operands[component_count], component_count, state, ®s[1])) + if (!sm6_parser_emit_composite_construct(dxil, &operands[component_count], component_count, state, ®s[1])) return; - ins = state->ins; - vsir_instruction_init(ins, &sm6->p.location, opcode); - if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, opcode); + + if (!(src_params = instruction_src_params_alloc(ins, 2, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_reg(&src_params[0], ®s[0]); src_param_init_vector_from_reg(&src_params[1], ®s[1]); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_eval_attrib(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; const struct shader_signature *signature; + struct vkd3d_shader_instruction *ins; unsigned int row_index, column_index; + struct vsir_src_operand *src_params; const struct signature_element *e; row_index = sm6_value_get_constant_uint(operands[0], sm6); @@ -5495,7 +6095,6 @@ static void sm6_parser_emit_dx_eval_attrib(struct sm6_parser *sm6, enum dx_intri signature = &sm6->program->input_signature; if (row_index >= signature->element_count) { - WARN("Invalid row index %u.\n", row_index); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid input row index %u for an attribute evaluation.", row_index); return; @@ -5504,17 +6103,22 @@ static void sm6_parser_emit_dx_eval_attrib(struct sm6_parser *sm6, enum dx_intri e = &signature->elements[row_index]; if (column_index >= VKD3D_VEC4_SIZE || !(e->mask & (1 << column_index))) { - WARN("Invalid column index %u.\n", column_index); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid input column index %u for an attribute evaluation.", column_index); return; } + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, (op == DX_EVAL_CENTROID) ? VSIR_OP_EVAL_CENTROID : VSIR_OP_EVAL_SAMPLE_INDEX); if (!(src_params = instruction_src_params_alloc(ins, 1 + (op == DX_EVAL_SAMPLE_INDEX), sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } src_params[0].reg = sm6->input_params[row_index].reg; src_param_init_scalar(&src_params[0], column_index); @@ -5524,30 +6128,40 @@ static void sm6_parser_emit_dx_eval_attrib(struct sm6_parser *sm6, enum dx_intri if (op == DX_EVAL_SAMPLE_INDEX) src_param_init_from_value(&src_params[1], operands[3], 0, sm6); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, sm6)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_fabs(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_fabs(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_ABS); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) return; - src_param_init_from_value(src_param, operands[0], 0, sm6); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_ABS); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + + src_param_init_from_value(src_param, operands[0], 0, dxil); + + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_compute_builtin(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_compute_builtin(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { unsigned int component_count = 3, component_idx = 0; - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; enum vkd3d_shader_register_type reg_type; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; switch (op) { @@ -5568,17 +6182,27 @@ static void sm6_parser_emit_dx_compute_builtin(struct sm6_parser *sm6, enum dx_i vkd3d_unreachable(); } - sm6_parser_dcl_register_builtin(sm6, VSIR_OP_DCL_INPUT, reg_type, VSIR_DATA_U32, component_count); - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + sm6_parser_dcl_register_builtin(dxil, VSIR_OP_DCL_INPUT, reg_type, VSIR_DATA_U32, component_count); + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + vsir_register_init(&src_param->reg, reg_type, VSIR_DATA_U32, 0); src_param->reg.dimension = VSIR_DIMENSION_VEC4; if (component_count > 1) - component_idx = sm6_value_get_constant_uint(operands[0], sm6); + component_idx = sm6_value_get_constant_uint(operands[0], dxil); src_param_init_scalar(src_param, component_idx); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static enum vkd3d_shader_opcode sm6_dx_map_ma_op(enum dx_intrinsic_opcode op, const struct sm6_type *type) @@ -5597,44 +6221,60 @@ static enum vkd3d_shader_opcode sm6_dx_map_ma_op(enum dx_intrinsic_opcode op, co } } -static void sm6_parser_emit_dx_ma(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_ma(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; unsigned int i; - vsir_instruction_init(ins, &sm6->p.location, sm6_dx_map_ma_op(op, operands[0]->type)); - if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) return; + + vsir_instruction_init(ins, &dxil->p.location, sm6_dx_map_ma_op(op, operands[0]->type)); + + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + for (i = 0; i < 3; ++i) { - src_param_init_from_value(&src_params[i], operands[i], 0, sm6); + src_param_init_from_value(&src_params[i], operands[i], 0, dxil); } - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_get_dimensions(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; unsigned int is_texture, component_count; enum dxil_resource_kind resource_kind; - struct vkd3d_shader_dst_param *dst; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; const struct sm6_value *resource; + struct vsir_dst_operand *dst; resource = operands[0]; if (!sm6_value_validate_is_handle(resource, sm6)) return; - is_texture = resource->u.handle.d->resource_type != VKD3D_SHADER_RESOURCE_BUFFER; resource_kind = resource->u.handle.d->kind; + is_texture = resource_kind_is_texture(resource_kind); + + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; instruction_init_with_resource(ins, is_texture ? VSIR_OP_RESINFO : VSIR_OP_BUFINFO, resource, sm6); if (!(src_params = instruction_src_params_alloc(ins, 1 + is_texture, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_handle(sm6, &src_params[is_texture], &resource->u.handle); if (is_texture) @@ -5645,48 +6285,66 @@ static void sm6_parser_emit_dx_get_dimensions(struct sm6_parser *sm6, enum dx_in if (resource_kind_is_multisampled(resource_kind)) { - instruction_dst_param_init_uint_temp_vector(ins++, sm6); + if (!instruction_dst_param_init_uint_temp_vector(ins, sm6)) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + state->temp_idx = 1; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + /* DXIL does not have an intrinsic for sample info, and resinfo is expected to return * the sample count in .w for MS textures. The result is always a struct of 4 x uint32. */ vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_SAMPLE_INFO); ins->flags = VKD3DSI_SAMPLE_INFO_UINT; if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_handle(sm6, &src_params[0], &resource->u.handle); src_params[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); if (!instruction_dst_param_init_uint_temp_vector(ins, sm6)) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + dst = ins->dst; dst->write_mask = VKD3DSP_WRITEMASK_3; /* Move the result to an SSA in case another instruction overwrites r0 before * the components are extracted for use. */ - ++ins; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); + if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_vector_from_reg(&src_params[0], &dst->reg); + } - state->ins = ins; - state->code_block->instruction_count += 2; + src_param_init_vector_from_reg(&src_params[0], &dst->reg); } } else { if (operands[1]->value_type != VALUE_TYPE_UNDEFINED) - { - WARN("Ignoring unexpected operand.\n"); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, "Ignoring an unexpected defined LOD value for buffer GetDimensions."); - } component_count = 1 + (resource_kind == RESOURCE_KIND_STRUCTUREDBUFFER); } - instruction_dst_param_init_ssa_vector(ins, component_count, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, component_count, sm6)) + vkd3d_shader_instruction_make_nop(ins); } static enum vkd3d_shader_opcode sm6_dx_map_tertiary_op(enum dx_intrinsic_opcode op) @@ -5702,22 +6360,31 @@ static enum vkd3d_shader_opcode sm6_dx_map_tertiary_op(enum dx_intrinsic_opcode } } -static void sm6_parser_emit_dx_tertiary(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_tertiary(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; unsigned int i; - vsir_instruction_init(ins, &sm6->p.location, sm6_dx_map_tertiary_op(op)); - if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, sm6_dx_map_tertiary_op(op)); + + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + for (i = 0; i < 3; ++i) { - src_param_init_from_value(&src_params[i], operands[i], 0, sm6); + src_param_init_from_value(&src_params[i], operands[i], 0, dxil); } - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, @@ -5725,26 +6392,21 @@ static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, enum dx_intrin { bool is_control_point = op == DX_LOAD_OUTPUT_CONTROL_POINT; bool is_patch_constant = op == DX_LOAD_PATCH_CONSTANT; - struct vkd3d_shader_instruction *ins = state->ins; struct vsir_program *program = sm6->program; unsigned int count, row_index, column_index; - const struct vkd3d_shader_dst_param *params; - struct vkd3d_shader_src_param *src_param; const struct shader_signature *signature; + const struct vsir_dst_operand *params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; const struct signature_element *e; row_index = sm6_value_get_constant_uint(operands[0], sm6); column_index = sm6_value_get_constant_uint(operands[2], sm6); if (is_control_point && operands[3]->value_type == VALUE_TYPE_UNDEFINED) - { /* dxcompiler will compile source which does this, so let it pass. */ - WARN("Control point id is undefined.\n"); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNDEFINED_OPERAND, "The index for a control point load is undefined."); - } - - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); if (is_patch_constant) { @@ -5763,15 +6425,23 @@ static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, enum dx_intrin } if (row_index >= signature->element_count) { - WARN("Invalid row index %u.\n", row_index); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid input row index %u.", row_index); return; } e = &signature->elements[row_index]; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); + if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param->reg = params[row_index].reg; src_param_init_scalar(src_param, column_index); count = 0; @@ -5785,39 +6455,48 @@ static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, enum dx_intrin register_index_address_init(&src_param->reg.idx[count], operands[3], sm6); } - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, sm6)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_make_double(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_make_double(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_src_param *src_params; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; struct vkd3d_shader_register reg; - if (!sm6_parser_emit_composite_construct(sm6, &operands[0], 2, state, ®)) + if (!sm6_parser_emit_composite_construct(dxil, &operands[0], 2, state, ®)) return; - ins = state->ins; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); - if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if (!(src_params = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_params[0].reg = reg; src_param_init_vector(&src_params[0], 2); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_output_control_point_id(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_output_control_point_id(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - sm6_parser_emit_dx_input_register_mov(sm6, state->ins, VKD3DSPR_OUTPOINTID, VSIR_DATA_U32, true); + sm6_parser_emit_dx_input_register_mov(dxil, state, VKD3DSPR_OUTPOINTID, VSIR_DATA_U32, true); } -static void sm6_parser_emit_dx_primitive_id(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_primitive_id(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - sm6_parser_emit_dx_input_register_mov(sm6, state->ins, VKD3DSPR_PRIMID, VSIR_DATA_U32, true); + sm6_parser_emit_dx_input_register_mov(dxil, state, VKD3DSPR_PRIMID, VSIR_DATA_U32, true); } static enum vkd3d_shader_opcode dx_map_quad_op(enum dxil_quad_op_kind op) @@ -5835,38 +6514,45 @@ static enum vkd3d_shader_opcode dx_map_quad_op(enum dxil_quad_op_kind op) } } -static void sm6_parser_emit_dx_quad_op(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_quad_op(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; enum vkd3d_shader_opcode opcode; enum dxil_quad_op_kind quad_op; - quad_op = sm6_value_get_constant_uint(operands[1], sm6); + quad_op = sm6_value_get_constant_uint(operands[1], dxil); if ((opcode = dx_map_quad_op(quad_op)) == VSIR_OP_INVALID) { - FIXME("Unhandled quad op kind %u.\n", quad_op); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_UNHANDLED_INTRINSIC, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_UNHANDLED_INTRINSIC, "Quad op kind %u is unhandled.", quad_op); return; } - vsir_instruction_init(ins, &sm6->p.location, opcode); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + vsir_instruction_init(ins, &dxil->p.location, opcode); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(src_param, operands[0], 0, sm6); + } - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + src_param_init_from_value(src_param, operands[0], 0, dxil); + + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_raw_buffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { unsigned int operand_count, write_mask, component_count = VKD3D_VEC4_SIZE; - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; const struct sm6_value *resource; bool raw; @@ -5880,37 +6566,44 @@ static void sm6_parser_emit_dx_raw_buffer_load(struct sm6_parser *sm6, enum dx_i write_mask = sm6_value_get_constant_uint(operands[3], sm6); if (!write_mask || write_mask > VKD3DSP_WRITEMASK_ALL) { - WARN("Invalid write mask %#x.\n", write_mask); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a raw/structured buffer load operation is invalid.", write_mask); return; } else if (write_mask & (write_mask + 1)) { - FIXME("Unhandled write mask %#x.\n", write_mask); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a raw/structured buffer load operation is unhandled.", write_mask); } component_count = vsir_write_mask_component_count(write_mask); } + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + instruction_init_with_resource(ins, raw ? VSIR_OP_LD_RAW : VSIR_OP_LD_STRUCTURED, resource, sm6); operand_count = 2 + !raw; + if (!(src_params = instruction_src_params_alloc(ins, operand_count, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_params_init_from_operands(src_params, &operands[1], operand_count - 1, sm6); src_param_init_vector_from_handle(sm6, &src_params[operand_count - 1], &resource->u.handle); - instruction_dst_param_init_ssa_vector(ins, component_count, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, component_count, sm6)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_raw_buffer_store(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { unsigned int write_mask, component_count, alignment = 0, operand_count; - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_dst_param *dst_param; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_param; struct vkd3d_shader_register data; const struct sm6_value *resource; bool raw; @@ -5923,52 +6616,55 @@ static void sm6_parser_emit_dx_raw_buffer_store(struct sm6_parser *sm6, enum dx_ write_mask = sm6_value_get_constant_uint(operands[7], sm6); if (!write_mask || write_mask > VKD3DSP_WRITEMASK_ALL) { - WARN("Invalid write mask %#x.\n", write_mask); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a raw/structured buffer store operation is invalid.", write_mask); return; } - else if (write_mask & (write_mask + 1)) - { - /* In this case, it is unclear which source operands will be defined unless we encounter it in a shader. */ - FIXME("Unhandled write mask %#x.\n", write_mask); + + /* In this case, it is unclear which source operands will be defined + * unless we encounter it in a shader. */ + if (write_mask & (write_mask + 1)) vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a raw/structured buffer store operation is unhandled.", write_mask); - } component_count = vsir_write_mask_component_count(write_mask); if (op == DX_RAW_BUFFER_STORE) { if (!raw && resource->u.handle.d->kind != RESOURCE_KIND_STRUCTUREDBUFFER) - { - WARN("Resource is not a raw or structured buffer.\n"); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION, "Resource for a raw buffer store is not a raw or structured buffer."); - } alignment = sm6_value_get_constant_uint(operands[8], sm6); if (alignment & (alignment - 1)) - { - FIXME("Invalid alignment %#x.\n", alignment); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Alignment %#x for a raw/structured buffer store operation is invalid.", alignment); - } } if (!sm6_parser_emit_composite_construct(sm6, &operands[3], component_count, state, &data)) return; - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, raw ? VSIR_OP_STORE_RAW : VSIR_OP_STORE_STRUCTURED); operand_count = 2 + !raw; if (!(src_params = instruction_src_params_alloc(ins, operand_count, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_params_init_from_operands(src_params, &operands[1], operand_count - 1, sm6); data.data_type = VSIR_DATA_U32; src_param_init_vector_from_reg(&src_params[operand_count - 1], &data); - dst_param = instruction_dst_params_alloc(ins, 1, sm6); + if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + dst_param_init_with_mask(dst_param, write_mask); sm6_register_from_handle(sm6, &resource->u.handle, &dst_param->reg); dst_param->reg.alignment = alignment; @@ -5977,8 +6673,8 @@ static void sm6_parser_emit_dx_raw_buffer_store(struct sm6_parser *sm6, enum dx_ static void sm6_parser_emit_dx_buffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; const struct sm6_value *resource; resource = operands[0]; @@ -5987,43 +6683,44 @@ static void sm6_parser_emit_dx_buffer_load(struct sm6_parser *sm6, enum dx_intri if (resource->u.handle.d->kind == RESOURCE_KIND_RAWBUFFER || resource->u.handle.d->kind == RESOURCE_KIND_STRUCTUREDBUFFER) - { return sm6_parser_emit_dx_raw_buffer_load(sm6, op, operands, state); - } if (resource->u.handle.d->kind != RESOURCE_KIND_TYPEDBUFFER) - { - WARN("Resource is not a typed buffer.\n"); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION, "Resource for a typed buffer load is not a typed buffer."); - } + + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; instruction_init_with_resource(ins, (resource->u.handle.d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) ? VSIR_OP_LD_UAV_TYPED : VSIR_OP_LD, resource, sm6); if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_from_value(&src_params[0], operands[1], 0, sm6); + /* Constant zero would be ok, but is not worth checking for unless it + * shows up. */ if (!sm6_value_is_undef(operands[2])) - { - /* Constant zero would be ok, but is not worth checking for unless it shows up. */ - WARN("Ignoring structure offset.\n"); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, "Ignoring structure offset for a typed buffer load."); - } src_param_init_vector_from_handle(sm6, &src_params[1], &resource->u.handle); - instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6)) + vkd3d_shader_instruction_make_nop(ins); } static void sm6_parser_emit_dx_buffer_store(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_dst_param *dst_param; unsigned int write_mask, component_count; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; struct vkd3d_shader_register texel; + struct vsir_dst_operand *dst_param; const struct sm6_value *resource; resource = operands[0]; @@ -6032,29 +6729,23 @@ static void sm6_parser_emit_dx_buffer_store(struct sm6_parser *sm6, enum dx_intr if (resource->u.handle.d->kind == RESOURCE_KIND_RAWBUFFER || resource->u.handle.d->kind == RESOURCE_KIND_STRUCTUREDBUFFER) - { return sm6_parser_emit_dx_raw_buffer_store(sm6, op, operands, state); - } if (resource->u.handle.d->kind != RESOURCE_KIND_TYPEDBUFFER) - { - WARN("Resource is not a typed buffer.\n"); vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION, "Resource for a typed buffer store is not a typed buffer."); - } write_mask = sm6_value_get_constant_uint(operands[7], sm6); if (!write_mask || write_mask > VKD3DSP_WRITEMASK_ALL) { - WARN("Invalid write mask %#x.\n", write_mask); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a typed buffer store operation is invalid.", write_mask); return; } else if (write_mask & (write_mask + 1)) { - /* In this case, it is unclear which source operands will be defined unless we encounter it in a shader. */ - FIXME("Unhandled write mask %#x.\n", write_mask); + /* In this case, it is unclear which source operands will be defined + * unless we encounter it in a shader. */ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a typed buffer store operation is unhandled.", write_mask); } @@ -6063,77 +6754,106 @@ static void sm6_parser_emit_dx_buffer_store(struct sm6_parser *sm6, enum dx_intr if (!sm6_parser_emit_composite_construct(sm6, &operands[3], component_count, state, &texel)) return; - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(sm6, state))) + return; + vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_STORE_UAV_TYPED); if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_from_value(&src_params[0], operands[1], 0, sm6); if (!sm6_value_is_undef(operands[2])) - { - /* Constant zero would have no effect, but is not worth checking for unless it shows up. */ - WARN("Ignoring structure offset.\n"); + /* Constant zero would have no effect, but is not worth checking for + * unless it shows up. */ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, "Ignoring structure offset for a typed buffer store."); - } src_param_init_vector_from_reg(&src_params[1], &texel); - dst_param = instruction_dst_params_alloc(ins, 1, sm6); + if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + dst_param_init_with_mask(dst_param, write_mask); sm6_register_from_handle(sm6, &resource->u.handle, &dst_param->reg); } -static void sm6_parser_emit_dx_get_sample_count(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_get_sample_count(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_SAMPLE_INFO); + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_SAMPLE_INFO); ins->flags = VKD3DSI_SAMPLE_INFO_UINT; - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + vsir_register_init(&src_param->reg, VKD3DSPR_RASTERIZER, VSIR_DATA_F32, 0); src_param->reg.dimension = VSIR_DIMENSION_VEC4; src_param_init(src_param); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + ins->dst->reg.data_type = VSIR_DATA_U32; } -static void sm6_parser_emit_dx_get_sample_pos(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_get_sample_pos(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_params; const struct sm6_value *resource = NULL; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; if (op == DX_TEX2DMS_GET_SAMPLE_POS) { resource = operands[0]; - if (!sm6_value_validate_is_texture_2dms_handle(resource, op, sm6)) + if (!sm6_value_validate_is_texture_2dms_handle(resource, op, dxil)) return; } - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_SAMPLE_POS); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_SAMPLE_POS); + + if (!(src_params = instruction_src_params_alloc(ins, 2, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + if (op == DX_TEX2DMS_GET_SAMPLE_POS) { - src_param_init_vector_from_handle(sm6, &src_params[0], &resource->u.handle); - src_param_init_from_value(&src_params[1], operands[1], 0, sm6); + src_param_init_vector_from_handle(dxil, &src_params[0], &resource->u.handle); + src_param_init_from_value(&src_params[1], operands[1], 0, dxil); } else { src_param_init_vector(&src_params[0], 2); vsir_register_init(&src_params[0].reg, VKD3DSPR_RASTERIZER, VSIR_DATA_F32, 0); src_params[0].reg.dimension = VSIR_DIMENSION_VEC4; - src_param_init_from_value(&src_params[1], operands[0], 0, sm6); + src_param_init_from_value(&src_params[1], operands[0], 0, dxil); } - instruction_dst_param_init_ssa_vector(ins, 2, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, 2, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static unsigned int sm6_value_get_texel_offset(const struct sm6_value *value, struct sm6_parser *sm6) @@ -6152,167 +6872,216 @@ static void instruction_set_texel_offset(struct vkd3d_shader_instruction *ins, ins->texel_offset.w = 0; } -static void sm6_parser_emit_dx_sample(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_sample(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { unsigned int clamp_idx = 0, component_count = VKD3D_VEC4_SIZE; struct vkd3d_shader_register coord, ddx, ddy; const struct sm6_value *resource, *sampler; - struct vkd3d_shader_src_param *src_params; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; resource = operands[0]; sampler = operands[1]; - if (!sm6_value_validate_is_texture_handle(resource, op, sm6) - || !sm6_value_validate_is_sampler_handle(sampler, op, sm6)) + if (!sm6_value_validate_is_texture_handle(resource, op, dxil) + || !sm6_value_validate_is_sampler_handle(sampler, op, dxil)) { return; } - if (!sm6_parser_emit_coordinate_construct(sm6, &operands[2], VKD3D_VEC4_SIZE, NULL, state, &coord)) + if (!sm6_parser_emit_coordinate_construct(dxil, &operands[2], VKD3D_VEC4_SIZE, NULL, state, &coord)) return; if (op == DX_SAMPLE_GRAD) { - if (!sm6_parser_emit_coordinate_construct(sm6, &operands[9], 3, NULL, state, &ddx)) + if (!sm6_parser_emit_coordinate_construct(dxil, &operands[9], 3, NULL, state, &ddx)) return; - if (!sm6_parser_emit_coordinate_construct(sm6, &operands[12], 3, NULL, state, &ddy)) + if (!sm6_parser_emit_coordinate_construct(dxil, &operands[12], 3, NULL, state, &ddy)) return; } - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + switch (op) { case DX_SAMPLE: - instruction_init_with_resource(ins, VSIR_OP_SAMPLE, resource, sm6); - src_params = instruction_src_params_alloc(ins, 3, sm6); + instruction_init_with_resource(ins, VSIR_OP_SAMPLE, resource, dxil); + + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + clamp_idx = 9; break; + case DX_SAMPLE_B: clamp_idx = 10; /* fall through */ case DX_SAMPLE_LOD: instruction_init_with_resource(ins, (op == DX_SAMPLE_B) ? VSIR_OP_SAMPLE_B : VSIR_OP_SAMPLE_LOD, - resource, sm6); - src_params = instruction_src_params_alloc(ins, 4, sm6); - src_param_init_from_value(&src_params[3], operands[9], 0, sm6); + resource, dxil); + + if (!(src_params = instruction_src_params_alloc(ins, 4, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + + src_param_init_from_value(&src_params[3], operands[9], 0, dxil); break; + case DX_SAMPLE_C: clamp_idx = 10; /* fall through */ case DX_SAMPLE_C_LZ: instruction_init_with_resource(ins, (op == DX_SAMPLE_C_LZ) ? VSIR_OP_SAMPLE_C_LZ : VSIR_OP_SAMPLE_C, - resource, sm6); - src_params = instruction_src_params_alloc(ins, 4, sm6); - src_param_init_from_value(&src_params[3], operands[9], 0, sm6); + resource, dxil); + + if (!(src_params = instruction_src_params_alloc(ins, 4, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + + src_param_init_from_value(&src_params[3], operands[9], 0, dxil); component_count = 1; break; + case DX_SAMPLE_GRAD: - instruction_init_with_resource(ins, VSIR_OP_SAMPLE_GRAD, resource, sm6); - src_params = instruction_src_params_alloc(ins, 5, sm6); + instruction_init_with_resource(ins, VSIR_OP_SAMPLE_GRAD, resource, dxil); + + if (!(src_params = instruction_src_params_alloc(ins, 5, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + src_param_init_vector_from_reg(&src_params[3], &ddx); src_param_init_vector_from_reg(&src_params[4], &ddy); clamp_idx = 15; break; + default: vkd3d_unreachable(); } - if (!src_params) - return; - if (clamp_idx && !sm6_value_is_undef(operands[clamp_idx])) - { - FIXME("Ignoring LOD clamp value.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, "Ignoring LOD clamp value for a sample operation."); - } src_param_init_vector_from_reg(&src_params[0], &coord); - src_param_init_vector_from_handle(sm6, &src_params[1], &resource->u.handle); - src_param_init_vector_from_handle(sm6, &src_params[2], &sampler->u.handle); - instruction_set_texel_offset(ins, &operands[6], 3, sm6); + src_param_init_vector_from_handle(dxil, &src_params[1], &resource->u.handle); + src_param_init_vector_from_handle(dxil, &src_params[2], &sampler->u.handle); + instruction_set_texel_offset(ins, &operands[6], 3, dxil); - instruction_dst_param_init_ssa_vector(ins, component_count, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, component_count, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_sample_index(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_sample_index(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - const struct shader_signature *signature = &sm6->program->input_signature; - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + const struct shader_signature *signature = &dxil->program->input_signature; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; unsigned int element_idx; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); - /* SV_SampleIndex is identified in VSIR by its signature element index, * but the index is not supplied as a parameter to the DXIL intrinsic. */ if (!vsir_signature_find_sysval(signature, VKD3D_SHADER_SV_SAMPLE_INDEX, 0, &element_idx)) { - WARN("Sample index is not in the signature.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_SIGNATURE, "Sample index signature element for a sample index operation is missing."); return; } - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param->reg = sm6->input_params[element_idx].reg; + } + + src_param->reg = dxil->input_params[element_idx].reg; src_param_init(src_param); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_saturate(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_saturate(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_SATURATE); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) return; - src_param_init_from_value(src_param, operands[0], 0, sm6); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_SATURATE); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + + src_param_init_from_value(src_param, operands[0], 0, dxil); + + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_split_double(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_split_double(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(src_param, operands[0], 0, sm6); + } + + src_param_init_from_value(src_param, operands[0], 0, dxil); - instruction_dst_param_init_ssa_vector(ins, 2, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, 2, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_store_output(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { bool is_patch_constant = op == DX_STORE_PATCH_CONSTANT; - struct vkd3d_shader_instruction *ins = state->ins; - struct vsir_program *program = sm6->program; - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_dst_param *dst_param; + struct vsir_program *program = dxil->program; const struct shader_signature *signature; + struct vkd3d_shader_instruction *ins; unsigned int row_index, column_index; + struct vsir_src_operand *src_param; + struct vsir_dst_operand *dst_param; const struct signature_element *e; const struct sm6_value *value; - row_index = sm6_value_get_constant_uint(operands[0], sm6); - column_index = sm6_value_get_constant_uint(operands[2], sm6); + row_index = sm6_value_get_constant_uint(operands[0], dxil); + column_index = sm6_value_get_constant_uint(operands[2], dxil); signature = is_patch_constant ? &program->patch_constant_signature : &program->output_signature; if (row_index >= signature->element_count) { - WARN("Invalid row index %u.\n", row_index); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid output row index %u.", row_index); return; } @@ -6321,8 +7090,7 @@ static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intr if (column_index >= VKD3D_VEC4_SIZE) { - WARN("Invalid column index %u.\n", column_index); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid output column index %u.", column_index); return; } @@ -6330,204 +7098,241 @@ static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intr value = operands[3]; if (!sm6_value_is_register(value)) { - WARN("Source value is not a register.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Expected store operation source to be a register."); return; } - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if (!(dst_param = instruction_dst_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + dst_param_init_scalar(dst_param, column_index); - dst_param->reg = is_patch_constant ? sm6->patch_constant_params[row_index].reg : sm6->output_params[row_index].reg; + dst_param->reg = is_patch_constant ? dxil->patch_constant_params[row_index].reg + : dxil->output_params[row_index].reg; if (e->register_count > 1) - register_index_address_init(&dst_param->reg.idx[0], operands[1], sm6); + register_index_address_init(&dst_param->reg.idx[0], operands[1], dxil); if (e->register_index == UINT_MAX) - { - sm6_parser_dcl_register_builtin(sm6, VSIR_OP_DCL_OUTPUT, dst_param->reg.type, + sm6_parser_dcl_register_builtin(dxil, VSIR_OP_DCL_OUTPUT, dst_param->reg.type, dst_param->reg.data_type, vsir_write_mask_component_count(e->mask)); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; } - if ((src_param = instruction_src_params_alloc(ins, 1, sm6))) - src_param_init_from_value(src_param, value, 0, sm6); + src_param_init_from_value(src_param, value, 0, dxil); } -static void sm6_parser_emit_dx_texture_gather(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_texture_gather(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { struct vkd3d_shader_register coord, offset; const struct sm6_value *resource, *sampler; - struct vkd3d_shader_src_param *src_params; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; unsigned int swizzle; bool extended_offset; resource = operands[0]; sampler = operands[1]; - if (!sm6_value_validate_is_texture_handle(resource, op, sm6) - || !sm6_value_validate_is_sampler_handle(sampler, op, sm6)) - { + if (!sm6_value_validate_is_texture_handle(resource, op, dxil) + || !sm6_value_validate_is_sampler_handle(sampler, op, dxil)) return; - } - if (!sm6_parser_emit_coordinate_construct(sm6, &operands[2], VKD3D_VEC4_SIZE, NULL, state, &coord)) + if (!sm6_parser_emit_coordinate_construct(dxil, &operands[2], VKD3D_VEC4_SIZE, NULL, state, &coord)) return; if ((extended_offset = !sm6_value_vector_is_constant_or_undef(&operands[6], 2)) - && !sm6_parser_emit_coordinate_construct(sm6, &operands[6], 2, NULL, state, &offset)) - { + && !sm6_parser_emit_coordinate_construct(dxil, &operands[6], 2, NULL, state, &offset)) return; - } /* DXIL doesn't know about signedness, but vsir expects the offset to be signed. */ if (extended_offset) offset.data_type = VSIR_DATA_I32; - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + if (op == DX_TEXTURE_GATHER) { - instruction_init_with_resource(ins, extended_offset ? VSIR_OP_GATHER4_PO : VSIR_OP_GATHER4, resource, sm6); - if (!(src_params = instruction_src_params_alloc(ins, 3 + extended_offset, sm6))) + instruction_init_with_resource(ins, extended_offset ? VSIR_OP_GATHER4_PO : VSIR_OP_GATHER4, resource, dxil); + + if (!(src_params = instruction_src_params_alloc(ins, 3 + extended_offset, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } } else { - instruction_init_with_resource(ins, extended_offset ? VSIR_OP_GATHER4_PO_C : VSIR_OP_GATHER4_C, resource, sm6); - if (!(src_params = instruction_src_params_alloc(ins, 4 + extended_offset, sm6))) + instruction_init_with_resource(ins, extended_offset ? VSIR_OP_GATHER4_PO_C : VSIR_OP_GATHER4_C, resource, dxil); + + if (!(src_params = instruction_src_params_alloc(ins, 4 + extended_offset, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(&src_params[3 + extended_offset], operands[9], 0, sm6); + } + + src_param_init_from_value(&src_params[3 + extended_offset], operands[9], 0, dxil); } src_param_init_vector_from_reg(&src_params[0], &coord); if (extended_offset) src_param_init_vector_from_reg(&src_params[1], &offset); else - instruction_set_texel_offset(ins, &operands[6], 2, sm6); - src_param_init_vector_from_handle(sm6, &src_params[1 + extended_offset], &resource->u.handle); - src_param_init_vector_from_handle(sm6, &src_params[2 + extended_offset], &sampler->u.handle); + instruction_set_texel_offset(ins, &operands[6], 2, dxil); + src_param_init_vector_from_handle(dxil, &src_params[1 + extended_offset], &resource->u.handle); + src_param_init_vector_from_handle(dxil, &src_params[2 + extended_offset], &sampler->u.handle); /* Swizzle stored in the sampler parameter is the scalar component index to be gathered. */ - swizzle = sm6_value_get_constant_uint(operands[8], sm6); + swizzle = sm6_value_get_constant_uint(operands[8], dxil); if (swizzle >= VKD3D_VEC4_SIZE) - { - WARN("Invalid swizzle %#x.\n", swizzle); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Swizzle %#x for a texture gather operation is invalid.", swizzle); - } src_params[2 + extended_offset].swizzle = swizzle; - instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_texture_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_texture_load(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { const struct sm6_value *resource, *mip_level_or_sample_count; - enum vkd3d_shader_resource_type resource_type; - struct vkd3d_shader_src_param *src_params; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; struct vkd3d_shader_register coord; + enum dxil_resource_kind kind; bool is_multisample, is_uav; unsigned int i; resource = operands[0]; - if (!sm6_value_validate_is_texture_handle(resource, op, sm6)) + if (!sm6_value_validate_is_texture_handle(resource, op, dxil)) return; - resource_type = resource->u.handle.d->resource_type; - is_multisample = resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS - || resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY; + kind = resource->u.handle.d->kind; + is_multisample = resource_kind_is_multisampled(kind); is_uav = resource->u.handle.d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; - mip_level_or_sample_count = (resource_type != VKD3D_SHADER_RESOURCE_BUFFER) ? operands[1] : NULL; - if (!sm6_parser_emit_coordinate_construct(sm6, &operands[2], 3, + mip_level_or_sample_count = resource_kind_is_texture(kind) ? operands[1] : NULL; + if (!sm6_parser_emit_coordinate_construct(dxil, &operands[2], 3, is_multisample ? NULL : mip_level_or_sample_count, state, &coord)) - { return; - } - ins = state->ins; + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + instruction_init_with_resource(ins, is_uav ? VSIR_OP_LD_UAV_TYPED - : is_multisample ? VSIR_OP_LD2DMS : VSIR_OP_LD, resource, sm6); - instruction_set_texel_offset(ins, &operands[5], 3, sm6); + : is_multisample ? VSIR_OP_LD2DMS : VSIR_OP_LD, resource, dxil); + instruction_set_texel_offset(ins, &operands[5], 3, dxil); for (i = 0; i < VKD3D_VEC4_SIZE; ++i) ins->resource_data_type[i] = resource->u.handle.d->resource_data_type; - if (!(src_params = instruction_src_params_alloc(ins, 2 + is_multisample, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, 2 + is_multisample, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_reg(&src_params[0], &coord); - src_param_init_vector_from_handle(sm6, &src_params[1], &resource->u.handle); + src_param_init_vector_from_handle(dxil, &src_params[1], &resource->u.handle); if (is_multisample) - src_param_init_from_value(&src_params[2], mip_level_or_sample_count, 0, sm6); + src_param_init_from_value(&src_params[2], mip_level_or_sample_count, 0, dxil); - instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6); + if (!instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_texture_store(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_texture_store(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { struct vkd3d_shader_register coord, texel; - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_dst_param *dst_param; unsigned int write_mask, component_count; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_param; const struct sm6_value *resource; resource = operands[0]; - if (!sm6_value_validate_is_texture_handle(resource, op, sm6)) + if (!sm6_value_validate_is_texture_handle(resource, op, dxil)) return; - if (!sm6_parser_emit_coordinate_construct(sm6, &operands[1], 3, NULL, state, &coord)) + if (!sm6_parser_emit_coordinate_construct(dxil, &operands[1], 3, NULL, state, &coord)) return; - write_mask = sm6_value_get_constant_uint(operands[8], sm6); + write_mask = sm6_value_get_constant_uint(operands[8], dxil); if (!write_mask || write_mask > VKD3DSP_WRITEMASK_ALL) { - WARN("Invalid write mask %#x.\n", write_mask); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a texture store operation is invalid.", write_mask); return; } - else if (write_mask & (write_mask + 1)) - { - /* In this case, it is unclear which source operands will be defined unless we encounter it in a shader. */ - FIXME("Unhandled write mask %#x.\n", write_mask); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + + /* In this case, it is unclear which source operands will be defined + * unless we encounter it in a shader. */ + if (write_mask & (write_mask + 1)) + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Write mask %#x for a texture store operation is unhandled.", write_mask); - } component_count = vsir_write_mask_component_count(write_mask); - if (!sm6_parser_emit_composite_construct(sm6, &operands[4], component_count, state, &texel)) + if (!sm6_parser_emit_composite_construct(dxil, &operands[4], component_count, state, &texel)) return; - ins = state->ins; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_STORE_UAV_TYPED); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_STORE_UAV_TYPED); + + if (!(src_params = instruction_src_params_alloc(ins, 2, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_init_vector_from_reg(&src_params[0], &coord); src_param_init_vector_from_reg(&src_params[1], &texel); - dst_param = instruction_dst_params_alloc(ins, 1, sm6); - sm6_register_from_handle(sm6, &resource->u.handle, &dst_param->reg); + if (!(dst_param = instruction_dst_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + + sm6_register_from_handle(dxil, &resource->u.handle, &dst_param->reg); dst_param_init_with_mask(dst_param, write_mask); } -static void sm6_parser_emit_dx_wave_active_ballot(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_wave_active_ballot(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_WAVE_ACTIVE_BALLOT); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_WAVE_ACTIVE_BALLOT); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(src_param, operands[0], 0, sm6); + } - instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6); + src_param_init_from_value(src_param, operands[0], 0, dxil); + + if (!instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static enum vkd3d_shader_opcode sm6_dx_map_wave_bit_op(enum dxil_wave_bit_op_kind op, @@ -6549,25 +7354,34 @@ static enum vkd3d_shader_opcode sm6_dx_map_wave_bit_op(enum dxil_wave_bit_op_kin } } -static void sm6_parser_emit_dx_wave_active_bit(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_wave_active_bit(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; enum dxil_wave_bit_op_kind wave_op; + struct vsir_src_operand *src_param; enum vkd3d_shader_opcode opcode; - wave_op = sm6_value_get_constant_uint(operands[1], sm6); + wave_op = sm6_value_get_constant_uint(operands[1], dxil); - if ((opcode = sm6_dx_map_wave_bit_op(wave_op, sm6)) == VSIR_OP_INVALID) + if ((opcode = sm6_dx_map_wave_bit_op(wave_op, dxil)) == VSIR_OP_INVALID) return; - vsir_instruction_init(ins, &sm6->p.location, opcode); - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, opcode); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(src_param, operands[0], 0, sm6); + } + + src_param_init_from_value(src_param, operands[0], 0, dxil); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static enum vkd3d_shader_opcode sm6_dx_map_wave_op(enum dxil_wave_op_kind op, bool is_signed, bool is_float, @@ -6595,33 +7409,41 @@ static enum vkd3d_shader_opcode sm6_dx_map_wave_op(enum dxil_wave_op_kind op, bo } } -static void sm6_parser_emit_dx_wave_op(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_wave_op(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { - struct vkd3d_shader_instruction *ins = state->ins; - struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; enum vkd3d_shader_opcode opcode; enum dxil_wave_op_kind wave_op; bool is_signed; - wave_op = sm6_value_get_constant_uint(operands[1], sm6); - is_signed = !sm6_value_get_constant_uint(operands[2], sm6); - opcode = sm6_dx_map_wave_op(wave_op, is_signed, sm6_type_is_floating_point(operands[0]->type), sm6); + wave_op = sm6_value_get_constant_uint(operands[1], dxil); + is_signed = !sm6_value_get_constant_uint(operands[2], dxil); + opcode = sm6_dx_map_wave_op(wave_op, is_signed, sm6_type_is_floating_point(operands[0]->type), dxil); if (opcode == VSIR_OP_INVALID) return; - vsir_instruction_init(ins, &sm6->p.location, opcode); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, opcode); ins->flags = (op == DX_WAVE_PREFIX_OP) ? VKD3DSI_WAVE_PREFIX : 0; - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(src_param, operands[0], 0, sm6); + } + + src_param_init_from_value(src_param, operands[0], 0, dxil); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_dx_wave_builtin(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, +static void sm6_parser_emit_dx_wave_builtin(struct sm6_parser *dxil, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { enum vkd3d_shader_register_type type; @@ -6638,7 +7460,7 @@ static void sm6_parser_emit_dx_wave_builtin(struct sm6_parser *sm6, enum dx_intr vkd3d_unreachable(); } - sm6_parser_emit_dx_input_register_mov(sm6, state->ins, type, VSIR_DATA_U32, true); + sm6_parser_emit_dx_input_register_mov(dxil, state, type, VSIR_DATA_U32, true); } struct sm6_dx_opcode_info @@ -6828,13 +7650,13 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc case 'g': return sm6_type_is_floating_point(type); case 'H': - return sm6_value_is_handle(value) && type == sm6->handle_type; + return sm6_value_is_handle(value) && type->u.struc->well_known == WELL_KNOWN_HANDLE; case 'D': - return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.Dimensions"); + return sm6_type_is_struct(type) && type->u.struc->well_known == WELL_KNOWN_DIMENSIONS; case 'S': - return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.splitdouble"); + return sm6_type_is_struct(type) && type->u.struc->well_known == WELL_KNOWN_SPLITDOUBLE; case 'V': - return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.fouri32"); + return sm6_type_is_struct(type) && type->u.struc->well_known == WELL_KNOWN_FOURI32; case 'v': return sm6_value_is_invalid(value) && !type; case 'o': @@ -6878,35 +7700,19 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_ return true; } -static void sm6_parser_emit_unhandled(struct sm6_parser *sm6, struct vkd3d_shader_instruction *ins, - struct sm6_value *dst) -{ - ins->opcode = VSIR_OP_NOP; - - if (!dst->type) - return; - - dst->value_type = VALUE_TYPE_INVALID; -} - static void sm6_parser_decode_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const char *name, const struct sm6_value **operands, unsigned int operand_count, struct function_emission_state *state, struct sm6_value *dst) { if (op >= ARRAY_SIZE(sm6_dx_op_table) || !sm6_dx_op_table[op].operand_info) { - FIXME("Unhandled dx intrinsic function id %u, '%s'.\n", op, name); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_UNHANDLED_INTRINSIC, "Call to intrinsic function %s is unhandled.", name); - sm6_parser_emit_unhandled(sm6, state->ins, dst); return; } if (!sm6_parser_validate_dx_op(sm6, op, name, operands, operand_count, dst)) - { - sm6_parser_emit_unhandled(sm6, state->ins, dst); return; - } sm6_dx_op_table[op].handler(sm6, op, operands, state); @@ -6920,10 +7726,11 @@ static void sm6_parser_decode_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_op } } -static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_record *record, - struct function_emission_state *state, struct sm6_value *dst) +static void sm6_parser_emit_call(struct sm6_parser *sm6, struct function_emission_state *state) { + struct sm6_value *dst = sm6_parser_get_current_value(sm6); const struct sm6_value *operands[DXIL_OP_MAX_OPERANDS]; + const struct dxil_record *record = state->record; const struct sm6_value *fn_value, *op_value; unsigned int i = 1, j, operand_count; const struct sm6_type *type = NULL; @@ -7114,15 +7921,17 @@ static enum vkd3d_shader_opcode dxil_map_cast_op(uint64_t code, const struct sm6 to_width = 32; if (from->class == to->class && from_width == to_width) - op = VSIR_OP_NOP; + op = VSIR_OP_MOV; return op; } -static void sm6_parser_emit_cast(struct sm6_parser *dxil, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_cast(struct sm6_parser *dxil, struct function_emission_state *state) { - struct vkd3d_shader_src_param *src_param; + struct sm6_value *dst = sm6_parser_get_current_value(dxil); + const struct dxil_record *record = state->record; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; const struct sm6_value *value; enum vkd3d_shader_opcode op; const struct sm6_type *type; @@ -7144,27 +7953,30 @@ static void sm6_parser_emit_cast(struct sm6_parser *dxil, const struct dxil_reco { *dst = *value; dst->type = type; - ins->opcode = VSIR_OP_NOP; return; } if ((op = dxil_map_cast_op(record->operands[i], value->type, &src_type_flags, type, dxil)) == VSIR_OP_INVALID) return; + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + vsir_instruction_init(ins, &dxil->p.location, op); - if (op == VSIR_OP_NOP) + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) { - *dst = *value; - dst->type = type; + vkd3d_shader_instruction_make_nop(ins); return; } - if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) - return; src_param_init_from_value(src_param, value, src_type_flags, dxil); - instruction_dst_param_init_ssa_scalar(ins, 0, dxil); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } /* VSIR bitcasts are represented by source registers with types different * from the types they were written with, rather than with different types @@ -7216,33 +8028,32 @@ static const struct sm6_cmp_info *sm6_map_cmp2_op(uint64_t code) return (code < ARRAY_SIZE(cmp_op_table)) ? &cmp_op_table[code] : NULL; } -static void sm6_parser_emit_cmp2(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_cmp2(struct sm6_parser *dxil, struct function_emission_state *state) { - struct vkd3d_shader_src_param *src_params; + struct sm6_value *dst = sm6_parser_get_current_value(dxil); + const struct dxil_record *record = state->record; const struct sm6_type *type_a, *type_b; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; bool is_int, is_fp, silence_warning; const struct sm6_cmp_info *cmp; const struct sm6_value *a, *b; uint64_t code, flags; unsigned int i = 0; - if (!(dst->type = sm6->bool_type)) + if (!(dst->type = dxil->bool_type)) { - WARN("Bool type not found.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, "Module does not define a boolean type for comparison results."); return; } - a = sm6_parser_get_value_by_ref(sm6, record, NULL, &i); - if (!a) + if (!(a = sm6_parser_get_value_by_ref(dxil, record, NULL, &i))) return; - b = sm6_parser_get_value_by_ref(sm6, record, a->type, &i); - if (!b) + if (!(b = sm6_parser_get_value_by_ref(dxil, record, a->type, &i))) return; - if (!dxil_record_validate_operand_count(record, i + 1, i + 2, sm6)) + if (!dxil_record_validate_operand_count(record, i + 1, i + 2, dxil)) return; type_a = a->type; @@ -7256,36 +8067,32 @@ static void sm6_parser_emit_cmp2(struct sm6_parser *sm6, const struct dxil_recor * do not otherwise occur, so deleting these avoids the need for backend support. */ if (sm6_type_is_bool(type_a) && code == ICMP_NE && sm6_value_is_constant_zero(b)) { - ins->opcode = VSIR_OP_NOP; *dst = *a; return; } if ((!is_int && !is_fp) || is_int != (code >= ICMP_EQ)) { - FIXME("Invalid operation %"PRIu64" on type class %u.\n", code, type_a->class); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Comparison operation %"PRIu64" on type class %u is invalid.", code, type_a->class); return; } if (type_a != type_b) - { - WARN("Type mismatch, type %u width %u vs type %u width %u.\n", type_a->class, - type_a->u.width, type_b->class, type_b->u.width); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, "Type mismatch in comparison operation arguments."); - } if (!(cmp = sm6_map_cmp2_op(code)) || !cmp->opcode || cmp->opcode == VSIR_OP_INVALID) { - FIXME("Unhandled operation %"PRIu64".\n", code); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Comparison operation %"PRIu64" is unhandled.", code); return; } - vsir_instruction_init(ins, &sm6->p.location, cmp->opcode); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, cmp->opcode); flags = (record->operand_count > i) ? record->operands[i] : 0; silence_warning = false; @@ -7299,72 +8106,70 @@ static void sm6_parser_emit_cmp2(struct sm6_parser *sm6, const struct dxil_recor silence_warning = !(flags & ~(FP_NO_NAN | FP_NO_INF | FP_NO_SIGNED_ZEROS | FP_ALLOW_RECIPROCAL)); } if (flags && silence_warning) - { TRACE("Ignoring fast FP modifier %#"PRIx64".\n", flags); - } else if (flags) - { - WARN("Ignoring flags %#"PRIx64".\n", flags); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, "Ignoring flags %#"PRIx64" for a comparison operation.", flags); - } - if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, 2, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - src_param_init_from_value(&src_params[0 ^ cmp->src_swap], a, cmp->type_flags, sm6); - src_param_init_from_value(&src_params[1 ^ cmp->src_swap], b, cmp->type_flags, sm6); + } + + src_param_init_from_value(&src_params[0 ^ cmp->src_swap], a, cmp->type_flags, dxil); + src_param_init_from_value(&src_params[1 ^ cmp->src_swap], b, cmp->type_flags, dxil); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_cmpxchg(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_cmpxchg(struct sm6_parser *dxil, struct function_emission_state *state) { + struct sm6_value *dst = sm6_parser_get_current_value(dxil); + const struct dxil_record *record = state->record; uint64_t success_ordering, failure_ordering; - struct vkd3d_shader_dst_param *dst_params; - struct vkd3d_shader_src_param *src_params; const struct sm6_value *ptr, *cmp, *new; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_params; struct vkd3d_shader_register reg; unsigned int i = 0; bool is_volatile; uint64_t code; - if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) - || !sm6_value_validate_is_pointer_to_i32(ptr, sm6) - || !sm6_value_validate_is_backward_ref(ptr, sm6)) + if (!(ptr = sm6_parser_get_value_by_ref(dxil, record, NULL, &i)) + || !sm6_value_validate_is_pointer_to_i32(ptr, dxil) + || !sm6_value_validate_is_backward_ref(ptr, dxil)) return; - vsir_register_from_dxil_value(®, ptr, 0, sm6); + vsir_register_from_dxil_value(®, ptr, 0, dxil); if (reg.type != VKD3DSPR_GROUPSHAREDMEM) { - WARN("Register is not groupshared.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "The destination register for a cmpxchg instruction is not groupshared memory."); return; } - if (!(dst->type = sm6_type_get_cmpxchg_result_struct(sm6))) + if (!(dst->type = sm6_type_get_cmpxchg_result_struct(dxil))) { - WARN("Failed to find result struct.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, "Module does not define a result struct type for a cmpxchg instruction."); return; } /* Forward-referenced comparands are stored as value/type pairs, even * though in principle we could use the destination type. */ - cmp = sm6_parser_get_value_by_ref(sm6, record, NULL, &i); - new = sm6_parser_get_value_by_ref(sm6, record, ptr->type->u.pointer.type, &i); + cmp = sm6_parser_get_value_by_ref(dxil, record, NULL, &i); + new = sm6_parser_get_value_by_ref(dxil, record, ptr->type->u.pointer.type, &i); if (!cmp || !new) return; - if (!sm6_value_validate_is_i32(cmp, sm6) - || !sm6_value_validate_is_i32(new, sm6) - || !dxil_record_validate_operand_count(record, i + 3, i + 5, sm6)) - { + if (!sm6_value_validate_is_i32(cmp, dxil) + || !sm6_value_validate_is_i32(new, dxil) + || !dxil_record_validate_operand_count(record, i + 3, i + 5, dxil)) return; - } is_volatile = record->operands[i++]; success_ordering = record->operands[i++]; @@ -7385,44 +8190,56 @@ static void sm6_parser_emit_cmpxchg(struct sm6_parser *sm6, const struct dxil_re if (record->operand_count > i && record->operands[i]) FIXME("Ignoring weak cmpxchg.\n"); - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_IMM_ATOMIC_CMP_EXCH); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_IMM_ATOMIC_CMP_EXCH); ins->flags = is_volatile ? VKD3DARF_VOLATILE : 0; - if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + src_param_make_constant_uint(&src_params[0], 0); - src_param_init_from_value(&src_params[1], cmp, 0, sm6); - src_param_init_from_value(&src_params[2], new, 0, sm6); + src_param_init_from_value(&src_params[1], cmp, 0, dxil); + src_param_init_from_value(&src_params[2], new, 0, dxil); - sm6_parser_init_ssa_value(sm6, dst); + sm6_parser_init_ssa_value(dxil, dst); - if (!(dst_params = instruction_dst_params_alloc(ins, 2, sm6))) + if (!(dst_params = instruction_dst_params_alloc(ins, 2, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - vsir_register_from_dxil_value(&dst_params[0].reg, dst, 0, sm6); + } + + vsir_register_from_dxil_value(&dst_params[0].reg, dst, 0, dxil); dst_param_init(&dst_params[0]); dst_params[1].reg = reg; dst_param_init(&dst_params[1]); } -static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_extractval(struct sm6_parser *dxil, struct function_emission_state *state) { - struct vkd3d_shader_src_param *src_param; + struct sm6_value *dst = sm6_parser_get_current_value(dxil); + const struct dxil_record *record = state->record; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; const struct sm6_type *type; const struct sm6_value *src; unsigned int i = 0; uint64_t elem_idx; - if (!(src = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + if (!(src = sm6_parser_get_value_by_ref(dxil, record, NULL, &i))) return; - if (!dxil_record_validate_operand_min_count(record, i + 1, sm6)) + if (!dxil_record_validate_operand_min_count(record, i + 1, dxil)) return; if (record->operand_count > i + 1) { - FIXME("Unhandled multiple indices.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Multiple extractval indices are not supported."); return; } @@ -7430,8 +8247,7 @@ static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil type = src->type; if (!sm6_type_is_aggregate(type)) { - WARN("Invalid extraction from non-aggregate.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Source type of an extractval instruction is not an aggregate."); return; } @@ -7439,33 +8255,40 @@ static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil elem_idx = record->operands[i]; if (!(type = sm6_type_get_element_type_at_index(type, elem_idx))) { - WARN("Invalid element index %"PRIu64".\n", elem_idx); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Element index %"PRIu64" for an extractval instruction is out of bounds.", elem_idx); return; } if (!sm6_type_is_scalar(type)) { - FIXME("Nested extraction is not supported.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Extraction from nested aggregates is not supported."); return; } dst->type = type; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOV); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOV); + + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; - vsir_register_from_dxil_value(&src_param->reg, src, 0, sm6); + } + + vsir_register_from_dxil_value(&src_param->reg, src, 0, dxil); src_param_init_scalar(src_param, elem_idx); - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } -static void sm6_parser_emit_gep(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_gep(struct sm6_parser *dxil, struct function_emission_state *state) { + struct sm6_value *dst = sm6_parser_get_current_value(dxil); + const struct dxil_record *record = state->record; const struct sm6_type *type, *pointee_type; unsigned int elem_idx, operand_idx = 2; enum bitcode_address_space addr_space; @@ -7473,130 +8296,113 @@ static void sm6_parser_emit_gep(struct sm6_parser *sm6, const struct dxil_record const struct sm6_value *src; struct sm6_index *index; - if (!dxil_record_validate_operand_min_count(record, 5, sm6) - || !(type = sm6_parser_get_type(sm6, record->operands[1])) - || !(src = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx)) - || !sm6_value_validate_is_register(src, sm6) - || !sm6_value_validate_is_pointer(src, sm6) - || !dxil_record_validate_operand_min_count(record, operand_idx + 2, sm6)) - { + if (!dxil_record_validate_operand_min_count(record, 5, dxil) + || !(type = sm6_parser_get_type(dxil, record->operands[1])) + || !(src = sm6_parser_get_value_by_ref(dxil, record, NULL, &operand_idx)) + || !sm6_value_validate_is_register(src, dxil) + || !sm6_value_validate_is_pointer(src, dxil) + || !dxil_record_validate_operand_min_count(record, operand_idx + 2, dxil)) return; - } *dst = *src; - index = sm6_get_value_index(sm6, dst); + index = sm6_get_value_index(dxil, dst); if (!index) return; if (index->index) { - WARN("Unsupported stacked GEP.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "A GEP instruction on the result of a previous GEP is unsupported."); return; } if ((pointee_type = src->type->u.pointer.type) != type) - { - WARN("Type mismatch, type %u width %u vs type %u width %u.\n", type->class, - type->u.width, pointee_type->class, pointee_type->u.width); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, "Type mismatch in GEP operation arguments."); - } addr_space = src->type->u.pointer.addr_space; - if (!(elem_value = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx))) + if (!(elem_value = sm6_parser_get_value_by_ref(dxil, record, NULL, &operand_idx))) return; /* The first index is always zero, to form a simple pointer dereference. */ - if (sm6_value_get_constant_uint(elem_value, sm6)) + if (sm6_value_get_constant_uint(elem_value, dxil)) { - WARN("Expected constant zero.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "The pointer dereference index for a GEP instruction is not constant zero."); return; } if (!sm6_type_is_array(pointee_type)) { - WARN("Invalid GEP on type class %u.\n", pointee_type->class); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Source type for index 1 of a GEP instruction is not an array."); return; } - if (!(elem_value = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx))) + if (!(elem_value = sm6_parser_get_value_by_ref(dxil, record, NULL, &operand_idx))) return; /* If indexing is dynamic, just get the type at offset zero. */ - elem_idx = sm6_value_is_constant(elem_value) ? sm6_value_get_constant_uint(elem_value, sm6) : 0; + elem_idx = sm6_value_is_constant(elem_value) ? sm6_value_get_constant_uint(elem_value, dxil) : 0; type = sm6_type_get_element_type_at_index(pointee_type, elem_idx); if (!type) { - WARN("Invalid element index %u.\n", elem_idx); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Element index %u for a GEP instruction is out of bounds.", elem_idx); return; } if (operand_idx < record->operand_count) { - FIXME("Multiple element indices are not implemented.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Multi-dimensional addressing in GEP instructions is not supported."); return; } - if (!(dst->type = sm6_type_get_pointer_to_type(type, addr_space, sm6))) + if (!(dst->type = sm6_type_get_pointer_to_type(type, addr_space, dxil))) { - WARN("Failed to get pointer type for type %u.\n", type->class); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, "Module does not define a pointer type for a GEP instruction."); return; } index->index = elem_value; index->is_in_bounds = record->operands[0]; - - ins->opcode = VSIR_OP_NOP; } -static void sm6_parser_emit_load(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_load(struct sm6_parser *dxil, struct function_emission_state *state) { + struct sm6_value *dst = sm6_parser_get_current_value(dxil); const struct sm6_type *elem_type = NULL, *pointee_type; + const struct dxil_record *record = state->record; unsigned int alignment, operand_count, i = 0; - struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; struct vkd3d_shader_register reg; const struct sm6_value *ptr; uint64_t alignment_code; - if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + if (!(ptr = sm6_parser_get_value_by_ref(dxil, record, NULL, &i))) return; - if (!sm6_value_validate_is_register(ptr, sm6) - || !sm6_value_validate_is_pointer(ptr, sm6) - || !sm6_value_validate_is_backward_ref(ptr, sm6) - || !dxil_record_validate_operand_count(record, i + 2, i + 3, sm6)) + if (!sm6_value_validate_is_register(ptr, dxil) + || !sm6_value_validate_is_pointer(ptr, dxil) + || !sm6_value_validate_is_backward_ref(ptr, dxil) + || !dxil_record_validate_operand_count(record, i + 2, i + 3, dxil)) return; - if (record->operand_count > i + 2 && !(elem_type = sm6_parser_get_type(sm6, record->operands[i++]))) + if (record->operand_count > i + 2 && !(elem_type = sm6_parser_get_type(dxil, record->operands[i++]))) return; if (!elem_type) - { elem_type = ptr->type->u.pointer.type; - } else if (elem_type != (pointee_type = ptr->type->u.pointer.type)) - { - WARN("Type mismatch.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, "Type mismatch in pointer load arguments."); - } dst->type = elem_type; - if (!sm6_value_validate_is_numeric(dst, sm6)) + if (!sm6_value_validate_is_numeric(dst, dxil)) return; alignment_code = record->operands[i++]; @@ -7606,22 +8412,29 @@ static void sm6_parser_emit_load(struct sm6_parser *sm6, const struct dxil_recor if (record->operands[i]) WARN("Ignoring volatile modifier.\n"); - vsir_register_from_dxil_value(®, ptr, 0, sm6); + vsir_register_from_dxil_value(®, ptr, 0, dxil); + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; if (ptr->structure_stride) { VKD3D_ASSERT(reg.type == VKD3DSPR_GROUPSHAREDMEM); - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_LD_STRUCTURED); + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_LD_STRUCTURED); - if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + if (reg.idx[1].rel_addr) src_params[0] = *reg.idx[1].rel_addr; else src_param_make_constant_uint(&src_params[0], reg.idx[1].offset); /* Struct offset is always zero as there is no struct, just an array. */ src_param_make_constant_uint(&src_params[1], 0); - src_param_init_from_value(&src_params[2], ptr, 0, sm6); + src_param_init_from_value(&src_params[2], ptr, 0, dxil); src_params[2].reg.alignment = alignment; /* The offset is already in src_params[0]. */ src_params[2].reg.idx_count = 1; @@ -7629,161 +8442,187 @@ static void sm6_parser_emit_load(struct sm6_parser *sm6, const struct dxil_recor else { operand_count = 1 + (reg.type == VKD3DSPR_GROUPSHAREDMEM); - vsir_instruction_init(ins, &sm6->p.location, (operand_count > 1) ? VSIR_OP_LD_RAW : VSIR_OP_MOV); + vsir_instruction_init(ins, &dxil->p.location, (operand_count > 1) ? VSIR_OP_LD_RAW : VSIR_OP_MOV); - if (!(src_params = instruction_src_params_alloc(ins, operand_count, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, operand_count, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + if (operand_count > 1) src_param_make_constant_uint(&src_params[0], 0); - src_param_init_from_value(&src_params[operand_count - 1], ptr, 0, sm6); + src_param_init_from_value(&src_params[operand_count - 1], ptr, 0, dxil); src_params[operand_count - 1].reg.alignment = alignment; } - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static int phi_incoming_compare(const void *a, const void *b) { const struct incoming_value *incoming_a = a, *incoming_b = b; - return (incoming_a->block > incoming_b->block) - (incoming_a->block < incoming_b->block); + return vkd3d_u32_compare(incoming_a->block_idx, incoming_b->block_idx); } -static void sm6_parser_emit_phi(struct sm6_parser *sm6, const struct dxil_record *record, - struct sm6_function *function, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins, - struct sm6_value *dst) +static void sm6_parser_emit_phi(struct sm6_parser *dxil, struct function_emission_state *state) { + struct sm6_value *dst = sm6_parser_get_current_value(dxil); + const struct dxil_record *record = state->record; + struct sm6_function *function = state->function; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + unsigned int i, j, incoming_count; struct incoming_value *incoming; + const struct sm6_value *src; const struct sm6_type *type; - struct sm6_phi *phi; - unsigned int i, j; - uint64_t src_idx; if (!(record->operand_count & 1)) { - WARN("Invalid operand count %u.\n", record->operand_count); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, "Invalid operand count %u for phi instruction.", record->operand_count); return; } - if (!(type = sm6_parser_get_type(sm6, record->operands[0]))) + if (!(type = sm6_parser_get_type(dxil, record->operands[0]))) return; if (!sm6_type_is_numeric(type)) { /* dxc doesn't seem to use buffer/resource read return types here. */ - FIXME("Only scalar numeric types are supported.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, "Result type class %u of a phi instruction is not scalar numeric.", type->class); return; } dst->type = type; - sm6_parser_init_ssa_value(sm6, dst); - - if (!(phi = sm6_block_phi_require_space(code_block, sm6))) - return; - phi->incoming_count = record->operand_count / 2u; - if (!vkd3d_array_reserve((void **)&phi->incoming, &phi->incoming_capacity, phi->incoming_count, - sizeof(*phi->incoming))) + incoming_count = record->operand_count / 2u; + if (!(incoming = vkd3d_calloc(incoming_count, sizeof(*incoming)))) { - ERR("Failed to allocate phi incoming array.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, "Out of memory allocating a phi incoming array."); return; } - incoming = phi->incoming; for (i = 1; i < record->operand_count; i += 2) { - src_idx = sm6->value_count - decode_rotated_signed_value(record->operands[i]); - /* May be a forward reference. */ - if (src_idx >= sm6->cur_max_value) + /* Phi forward references are handled by the same mechanism as all + * others. Constant and undefined values are never forward references, + * and the only other valid incoming is an SSA value, which will be + * initialised if necessary. */ + if (!(src = sm6_parser_get_value_by_rotated_signed_idx(dxil, record->operands[i], type))) + goto done; + + if (!sm6_value_is_constant(src) && !sm6_value_is_undef(src) && !sm6_value_is_ssa(src)) { - WARN("Invalid value index %"PRIu64".\n", src_idx); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, - "Invalid value index %"PRIu64" for a phi incoming value.", src_idx); - return; + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "A PHI incoming value is not a constant or SSA register."); + goto done; } + if (src->type != type) + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "The type of a phi incoming value does not match the result type."); + + if (!sm6_function_validate_block_index(function, record->operands[i + 1], dxil)) + goto done; + j = i / 2u; - /* Store the value index in the register for later resolution. */ - incoming[j].reg.idx[0].offset = src_idx; - incoming[j].block = sm6_function_get_block(function, record->operands[i + 1], sm6); + incoming[j].src = src; + incoming[j].block_idx = record->operands[i + 1]; } - ins->opcode = VSIR_OP_NOP; - - qsort(incoming, phi->incoming_count, sizeof(*incoming), phi_incoming_compare); + qsort(incoming, incoming_count, sizeof(*incoming), phi_incoming_compare); - for (i = 1, j = 1; i < phi->incoming_count; ++i) + /* Deduplicate incomings. DXIL phi instructions can contain duplicates. */ + for (i = 1, j = 1; i < incoming_count; ++i) { - if (incoming[i].block != incoming[i - 1].block) + if (incoming[i].block_idx != incoming[i - 1].block_idx) { incoming[j++] = incoming[i]; continue; } - if (incoming[i].reg.idx[0].offset != incoming[i - 1].reg.idx[0].offset) - { - WARN("PHI conflict.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + if (incoming[i].src != incoming[i - 1].src) + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Two phi incomings have the same block but different values."); - } } - /* if (j == 1) we should be able to set dst->u.reg to incoming[0].reg, but structurisation - * may potentially add new incomings. */ - phi->incoming_count = j; + incoming_count = j; + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; + + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_PHI); + + if (!(src_params = instruction_src_params_alloc(ins, incoming_count * 2u, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + goto done; + } + + for (i = 0; i < incoming_count; ++i) + { + j = i * 2u; + src_param_init_from_value(&src_params[j], incoming[i].src, 0, dxil); + vsir_src_operand_init_label(&src_params[j + 1], incoming[i].block_idx + 1); + } + + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); + +done: + vkd3d_free(incoming); } -static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record, - struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) +static void sm6_parser_emit_ret(struct sm6_parser *dxil, struct function_emission_state *state) { - if (!dxil_record_validate_operand_count(record, 0, 1, sm6)) + const struct dxil_record *record = state->record; + struct vkd3d_shader_instruction *ins; + + if (!dxil_record_validate_operand_count(record, 0, 1, dxil)) return; if (record->operand_count) - FIXME("Non-void return is not implemented.\n"); + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Non-void return is not implemented."); - code_block->terminator.type = TERMINATOR_RET; + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - ins->opcode = VSIR_OP_NOP; + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_RET); } -static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_store(struct sm6_parser *dxil, struct function_emission_state *state) { + const struct dxil_record *record = state->record; unsigned int i = 0, alignment, operand_count; - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_dst_param *dst_param; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; + struct vsir_dst_operand *dst_param; const struct sm6_value *ptr, *src; struct vkd3d_shader_register reg; uint64_t alignment_code; - if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) - || !sm6_value_validate_is_register(ptr, sm6) - || !sm6_value_validate_is_pointer(ptr, sm6) - || !sm6_value_validate_is_backward_ref(ptr, sm6)) - { + if (!(ptr = sm6_parser_get_value_by_ref(dxil, record, NULL, &i)) + || !sm6_value_validate_is_register(ptr, dxil) + || !sm6_value_validate_is_pointer(ptr, dxil) + || !sm6_value_validate_is_backward_ref(ptr, dxil)) return; - } /* Forward-referenced sources are stored as value/type pairs, even * though in principle we could use the destination type. */ - if (!(src = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + if (!(src = sm6_parser_get_value_by_ref(dxil, record, NULL, &i))) return; - if (!sm6_value_validate_is_numeric(src, sm6)) + if (!sm6_value_validate_is_numeric(src, dxil)) return; if (ptr->type->u.pointer.type != src->type) - { - WARN("Type mismatch.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, "Type mismatch in pointer store arguments."); - } - if (!dxil_record_validate_operand_count(record, i + 2, i + 2, sm6)) + if (!dxil_record_validate_operand_count(record, i + 2, i + 2, dxil)) return; alignment_code = record->operands[i++]; @@ -7793,36 +8632,52 @@ static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_reco if (record->operands[i]) WARN("Ignoring volatile modifier.\n"); - vsir_register_from_dxil_value(®, ptr, 0, sm6); + vsir_register_from_dxil_value(®, ptr, 0, dxil); + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; if (ptr->structure_stride) { VKD3D_ASSERT(reg.type == VKD3DSPR_GROUPSHAREDMEM); - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_STORE_STRUCTURED); + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_STORE_STRUCTURED); - if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + if (reg.idx[1].rel_addr) src_params[0] = *reg.idx[1].rel_addr; else src_param_make_constant_uint(&src_params[0], reg.idx[1].offset); /* Struct offset is always zero as there is no struct, just an array. */ src_param_make_constant_uint(&src_params[1], 0); - src_param_init_from_value(&src_params[2], src, 0, sm6); + src_param_init_from_value(&src_params[2], src, 0, dxil); } else { operand_count = 1 + (reg.type == VKD3DSPR_GROUPSHAREDMEM); - vsir_instruction_init(ins, &sm6->p.location, (operand_count > 1) ? VSIR_OP_STORE_RAW : VSIR_OP_MOV); + vsir_instruction_init(ins, &dxil->p.location, (operand_count > 1) ? VSIR_OP_STORE_RAW : VSIR_OP_MOV); - if (!(src_params = instruction_src_params_alloc(ins, operand_count, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, operand_count, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + if (operand_count > 1) src_param_make_constant_uint(&src_params[0], 0); - src_param_init_from_value(&src_params[operand_count - 1], src, 0, sm6); + src_param_init_from_value(&src_params[operand_count - 1], src, 0, dxil); + } + + if (!(dst_param = instruction_dst_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; } - dst_param = instruction_dst_params_alloc(ins, 1, sm6); dst_param_init(dst_param); dst_param->reg = reg; dst_param->reg.alignment = alignment; @@ -7831,125 +8686,151 @@ static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_reco dst_param->reg.idx_count = 1; } -static void sm6_parser_emit_switch(struct sm6_parser *sm6, const struct dxil_record *record, - struct sm6_function *function, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) +static void sm6_parser_emit_switch(struct sm6_parser *dxil, struct function_emission_state *state) { - struct sm6_block_terminator *terminator = &code_block->terminator; + const struct dxil_record *record = state->record; + struct sm6_function *function = state->function; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; const struct sm6_type *type; const struct sm6_value *src; - unsigned int i = 1, j; + uint64_t case_value; + unsigned int i = 1; if (record->operand_count < 3 || !(record->operand_count & 1)) { - WARN("Invalid operand count %u.\n", record->operand_count); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, "Invalid operand count %u for a switch instruction.", record->operand_count); return; } - if (!(type = sm6_parser_get_type(sm6, record->operands[0]))) + if (!(type = sm6_parser_get_type(dxil, record->operands[0]))) return; - if (!(src = sm6_parser_get_value_by_ref(sm6, record, type, &i)) - || !sm6_value_validate_is_register(src, sm6)) + if (!(src = sm6_parser_get_value_by_ref(dxil, record, type, &i)) + || !sm6_value_validate_is_register(src, dxil)) return; VKD3D_ASSERT(i == 2); if (src->type != type) - { - WARN("Type mismatch.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, "The type of a switch selector value does not match the selector type."); - } + if (!sm6_type_is_integer(type)) { - WARN("Selector is not scalar integer.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Selector type class %u of a switch instruction is not scalar integer.", type->class); return; } - vsir_register_from_dxil_value(&terminator->conditional_reg, src, 0, sm6); - terminator->type = TERMINATOR_SWITCH; + if (!sm6_function_validate_block_index(function, record->operands[2], dxil)) + return; - terminator->case_count = record->operand_count / 2u; - if (!(terminator->cases = vkd3d_calloc(terminator->case_count, sizeof(*terminator->cases)))) - { - ERR("Failed to allocate case array.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, - "Out of memory allocating a switch case array."); + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) return; - } - /* Executes 'operand_count / 2' times because operand_count is uneven. */ - for (; i < record->operand_count; i += 2) + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_SWITCH_MONOLITHIC); + + if (!(src_params = instruction_src_params_alloc(ins, record->operand_count, dxil))) { - j = i / 2u - 1; - terminator->cases[j].block = sm6_function_get_block(function, record->operands[i], sm6); - /* For structurisation it is convenient to store the default in the case array. */ - terminator->cases[j].is_default = !j; + vkd3d_shader_instruction_make_nop(ins); + return; } + src_param_init_from_value(&src_params[0], src, 0, dxil); + /* Set the default block label id, 1-based. */ + vsir_src_operand_init_label(&src_params[1], record->operands[2] + 1); + /* Set a zero merge block label id as a placeholder until it is set during + * the structurisation pass. */ + vsir_src_operand_init_label(&src_params[2], 0); + for (i = 3; i < record->operand_count; i += 2) { - if (!(src = sm6_parser_get_value_safe(sm6, record->operands[i]))) + if (!(src = sm6_parser_get_value_safe(dxil, record->operands[i]))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } if (src->type != type) - { - WARN("Type mismatch.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, "The type of a switch case value does not match the selector type."); - } if (!sm6_value_is_constant(src)) - { - WARN("Case value is not a constant.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "A switch case value is not a constant."); + + case_value = sm6_value_get_constant_uint64(src, dxil); + + /* Set the case constant value. 64-bit values are supported. */ + if (src_params[0].reg.data_type == VSIR_DATA_U64) + { + vsir_src_operand_init(&src_params[i], VKD3DSPR_IMMCONST64, VSIR_DATA_U64, 0); + src_params[i].reg.u.immconst_u64[0] = case_value; + } + else + { + if (case_value > UINT_MAX) + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Truncating 64-bit switch case value %"PRIx64" to 32 bits.", case_value); + vsir_src_operand_init(&src_params[i], VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); + src_params[i].reg.u.immconst_u32[0] = case_value; } - terminator->cases[i / 2u].value = sm6_value_get_constant_uint64(src, sm6); + if (!sm6_function_validate_block_index(function, record->operands[i + 1], dxil)) + { + vkd3d_shader_instruction_make_nop(ins); + return; + } + /* Set the case block label id, 1-based. */ + vsir_src_operand_init_label(&src_params[i + 1], record->operands[i + 1] + 1); } - - ins->opcode = VSIR_OP_NOP; } -static void sm6_parser_emit_vselect(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +static void sm6_parser_emit_vselect(struct sm6_parser *dxil, struct function_emission_state *state) { - struct vkd3d_shader_src_param *src_params; + struct sm6_value *dst = sm6_parser_get_current_value(dxil); + const struct dxil_record *record = state->record; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_params; const struct sm6_value *src[3]; unsigned int i = 0; - if (!(src[1] = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) - || !(src[2] = sm6_parser_get_value_by_ref(sm6, record, src[1]->type, &i)) - || !(src[0] = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) - { + if (!(src[1] = sm6_parser_get_value_by_ref(dxil, record, NULL, &i)) + || !(src[2] = sm6_parser_get_value_by_ref(dxil, record, src[1]->type, &i)) + || !(src[0] = sm6_parser_get_value_by_ref(dxil, record, NULL, &i))) return; - } - dxil_record_validate_operand_max_count(record, i, sm6); + + dxil_record_validate_operand_max_count(record, i, dxil); for (i = 0; i < 3; ++i) { - if (!sm6_value_validate_is_register(src[i], sm6)) + if (!sm6_value_validate_is_register(src[i], dxil)) return; } dst->type = src[1]->type; - if (!sm6_value_validate_is_bool(src[0], sm6)) + if (!sm6_value_validate_is_bool(src[0], dxil)) + return; + + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) return; - vsir_instruction_init(ins, &sm6->p.location, VSIR_OP_MOVC); + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_MOVC); - if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + if (!(src_params = instruction_src_params_alloc(ins, 3, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); return; + } + for (i = 0; i < 3; ++i) { - src_param_init_from_value(&src_params[i], src[i], 0, sm6); + src_param_init_from_value(&src_params[i], src[i], 0, dxil); } - instruction_dst_param_init_ssa_scalar(ins, 0, sm6); + if (!instruction_dst_param_init_ssa_scalar(ins, 0, dxil)) + vkd3d_shader_instruction_make_nop(ins); } static bool sm6_metadata_value_is_node(const struct sm6_metadata_value *m) @@ -8141,7 +9022,7 @@ static bool metadata_node_get_unary_uint(const struct sm6_metadata_node *node, u } static void metadata_attachment_record_apply(const struct dxil_record *record, enum bitcode_function_code func_code, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst, struct sm6_parser *sm6) + struct vsir_program_iterator *it, struct sm6_value *dst, struct sm6_parser *dxil) { static const char *ignored_names[] = { @@ -8159,29 +9040,24 @@ static void metadata_attachment_record_apply(const struct dxil_record *record, e const char *name; if (record->attachment) - { - WARN("Ignoring nested metadata attachment.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, "Ignoring a nested metadata attachment."); - } VKD3D_ASSERT(record->operand_count & 1); for (i = 1; i < record->operand_count; i += 2) { - if (!(m = sm6_parser_find_metadata_kind(sm6, record->operands[i]))) + if (!(m = sm6_parser_find_metadata_kind(dxil, record->operands[i]))) { - WARN("Failed to find metadata kind %"PRIx64".\n", record->operands[i]); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, "Failed to find metadata kind %"PRIx64" for an attachment.", record->operands[i]); continue; } name = m->u.kind.name; - m = sm6_parser_metadata_get_value(sm6, record->operands[i + 1]); + m = sm6_parser_metadata_get_value(dxil, record->operands[i + 1]); if (!m || !sm6_metadata_value_is_node(m)) { - WARN("Failed to retrieve metadata attachment node.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, "Failed to retrieve a metadata attachment node."); continue; } @@ -8191,123 +9067,79 @@ static void metadata_attachment_record_apply(const struct dxil_record *record, e { if (!sm6_value_is_register(dst)) { - WARN("Precise value is not a register.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, "A value marked as precise is not a register."); } - else if (metadata_node_get_unary_uint(node, &operand, sm6) && operand) + else if (metadata_node_get_unary_uint(node, &operand, dxil) && operand) { - ins->flags |= sm6_type_is_scalar(dst->type) ? VKD3DSI_PRECISE_X : VKD3DSI_PRECISE_XYZW; + /* The iterator is set to the last vsir instruction before those + * that were inserted by the current DXIL instruction. */ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_next(it); + + for (; ins; ins = vsir_program_iterator_next(it)) + { + ins->flags |= sm6_type_is_scalar(dst->type) ? VKD3DSI_PRECISE_X : VKD3DSI_PRECISE_XYZW; + } } } else if (!strcmp(name, "dx.nonuniform")) { if (!sm6_value_is_register(dst)) - { - WARN("Non-uniform value is not a register.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, "A value marked as non-uniform is not a register."); - } - else if (metadata_node_get_unary_uint(node, &operand, sm6)) - { + else if (metadata_node_get_unary_uint(node, &operand, dxil)) dst->non_uniform = !!operand; - } } else { for (j = 0; j < ARRAY_SIZE(ignored_names); ++j) + { if (!strcmp(name, ignored_names[j])) break; + } if (j == ARRAY_SIZE(ignored_names)) - { - WARN("Ignoring metadata attachment '%s'.\n", name); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT, "Ignoring a metadata attachment named '%s'.", name); - } ignored = true; } - if (func_code != FUNC_CODE_INST_CALL && !ignored) - WARN("Metadata attachment target is not a function call.\n"); - } -} - -static bool sm6_function_blocks_reserve(struct sm6_function *function, unsigned int reserve) -{ - if (!vkd3d_array_reserve((void **)&function->blocks, &function->block_capacity, - reserve, sizeof(*function->blocks))) - { - ERR("Failed to allocate code block array.\n"); - return false; - } - return true; -} - -static struct sm6_block *sm6_function_create_block(struct sm6_function *function) -{ - struct sm6_block *block; - - if (!(block = sm6_block_create())) - return NULL; - - function->blocks[function->block_count++] = block; - /* Set the id to the array index + 1. */ - block->id = function->block_count; - - return block; + if (func_code != FUNC_CODE_INST_CALL && !ignored) + WARN("Metadata attachment target is not a function call.\n"); + } } -static enum vkd3d_result sm6_function_resolve_phi_incomings(const struct sm6_function *function, - struct sm6_parser *sm6) +static void dxil_emit_function_label(struct sm6_parser *dxil, + struct function_emission_state *state, unsigned int label_id) { - const struct sm6_block *block; - size_t i, j, block_idx; - - for (block_idx = 0; block_idx < function->block_count; ++block_idx) - { - block = function->blocks[block_idx]; + struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src_param; - for (i = 0; i < block->phi_count; ++i) - { - struct sm6_phi *phi = &block->phi[i]; - const struct sm6_value *src; + if (!(ins = sm6_parser_add_function_instruction(dxil, state))) + return; - for (j = 0; j < phi->incoming_count; ++j) - { - src = &sm6->values[phi->incoming[j].reg.idx[0].offset]; - if (!sm6_value_is_constant(src) && !sm6_value_is_undef(src) && !sm6_value_is_ssa(src)) - { - FIXME("PHI incoming value is not a constant or SSA register.\n"); - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, - "A PHI incoming value is not a constant or SSA register."); - return VKD3D_ERROR_INVALID_SHADER; - } - if (src->type != phi->value.type) - { - WARN("Type mismatch.\n"); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, - "The type of a phi incoming value does not match the result type."); - } - vsir_register_from_dxil_value(&phi->incoming[j].reg, src, 0, sm6); - } - } + vsir_instruction_init(ins, &dxil->p.location, VSIR_OP_LABEL); + if (!(src_param = instruction_src_params_alloc(ins, 1, dxil))) + { + vkd3d_shader_instruction_make_nop(ins); + return; } - - return VKD3D_OK; + vsir_src_operand_init_label(src_param, label_id); } -static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, - struct sm6_function *function) +static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, + const struct dxil_block *block, struct sm6_function *function) { struct vsir_program *program = sm6->program; - struct vkd3d_shader_instruction *ins; size_t i, block_idx, block_count; const struct dxil_record *record; + struct vsir_program_iterator it; const struct sm6_type *fwd_type; bool ret_found, is_terminator; - struct sm6_block *code_block; + bool emitted_label = false; struct sm6_value *dst; + it = vsir_program_iterator(&function->instructions); + if (!(function->declaration = sm6_parser_next_function_definition(sm6))) { WARN("Failed to find definition to match function body.\n"); @@ -8333,46 +9165,35 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const return VKD3D_ERROR_INVALID_SHADER; } - if (!sm6_function_blocks_reserve(function, block_count)) - return VKD3D_ERROR_OUT_OF_MEMORY; - - /* Pre-allocate all blocks to simplify instruction parsing. */ - for (i = 0; i < block_count; ++i) - { - if (!sm6_function_create_block(function)) - { - ERR("Failed to allocate code block.\n"); - return VKD3D_ERROR_OUT_OF_MEMORY; - } - } function->block_count = block_count; - code_block = function->blocks[0]; sm6->cur_max_value = function->value_count; for (i = 1, block_idx = 0, ret_found = false; i < block->record_count; ++i) { + struct function_emission_state state = {0}; + sm6->p.location.column = i; - if (!code_block) + if (block_idx >= function->block_count) { - WARN("Invalid block count %zu.\n", function->block_count); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, "Invalid block count %zu.", function->block_count); return VKD3D_ERROR_INVALID_SHADER; } - /* Some instructions can emit >1 IR instruction, so extra may be used. */ - if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity, - code_block->instruction_count + MAX_IR_INSTRUCTIONS_PER_DXIL_INSTRUCTION, - sizeof(*code_block->instructions))) + state.function = function; + state.record = block->records[i]; + + if (!emitted_label) { - ERR("Failed to allocate instructions.\n"); - return VKD3D_ERROR_OUT_OF_MEMORY; + /* Label id is 1-based. Do not emit a label until it is known that + * instructions will follow. */ + dxil_emit_function_label(sm6, &state, block_idx + 1); + emitted_label = true; } - ins = &code_block->instructions[code_block->instruction_count]; - ins->opcode = VSIR_OP_INVALID; + vsir_program_iterator_tail(&it); dst = sm6_parser_get_current_value(sm6); fwd_type = dst->type; @@ -8384,87 +9205,75 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const switch (record->code) { case FUNC_CODE_INST_ALLOCA: - sm6_parser_emit_alloca(sm6, record, ins, dst); + sm6_parser_emit_alloca(sm6, &state); break; case FUNC_CODE_INST_ATOMICRMW: - { - struct function_emission_state state = {code_block, ins}; - sm6_parser_emit_atomicrmw(sm6, record, &state, dst); - program->temp_count = max(program->temp_count, state.temp_idx); + sm6_parser_emit_atomicrmw(sm6, &state); break; - } case FUNC_CODE_INST_BINOP: - sm6_parser_emit_binop(sm6, record, code_block, ins, dst); + sm6_parser_emit_binop(sm6, &state); break; case FUNC_CODE_INST_BR: - sm6_parser_emit_br(sm6, record, function, code_block, ins); + sm6_parser_emit_br(sm6, &state); is_terminator = true; break; case FUNC_CODE_INST_CALL: - { - struct function_emission_state state = {code_block, ins}; - sm6_parser_emit_call(sm6, record, &state, dst); - program->temp_count = max(program->temp_count, state.temp_idx); + sm6_parser_emit_call(sm6, &state); break; - } case FUNC_CODE_INST_CAST: - sm6_parser_emit_cast(sm6, record, ins, dst); + sm6_parser_emit_cast(sm6, &state); break; case FUNC_CODE_INST_CMP2: - sm6_parser_emit_cmp2(sm6, record, ins, dst); + sm6_parser_emit_cmp2(sm6, &state); break; case FUNC_CODE_INST_CMPXCHG: - sm6_parser_emit_cmpxchg(sm6, record, ins, dst); + sm6_parser_emit_cmpxchg(sm6, &state); break; case FUNC_CODE_INST_EXTRACTVAL: - sm6_parser_emit_extractval(sm6, record, ins, dst); + sm6_parser_emit_extractval(sm6, &state); break; case FUNC_CODE_INST_GEP: - sm6_parser_emit_gep(sm6, record, ins, dst); + sm6_parser_emit_gep(sm6, &state); break; case FUNC_CODE_INST_LOAD: - sm6_parser_emit_load(sm6, record, ins, dst); + sm6_parser_emit_load(sm6, &state); break; case FUNC_CODE_INST_PHI: - sm6_parser_emit_phi(sm6, record, function, code_block, ins, dst); + sm6_parser_emit_phi(sm6, &state); break; case FUNC_CODE_INST_RET: - sm6_parser_emit_ret(sm6, record, code_block, ins); + sm6_parser_emit_ret(sm6, &state); is_terminator = true; ret_found = true; break; case FUNC_CODE_INST_STORE: - sm6_parser_emit_store(sm6, record, ins, dst); + sm6_parser_emit_store(sm6, &state); break; case FUNC_CODE_INST_SWITCH: - sm6_parser_emit_switch(sm6, record, function, code_block, ins); + sm6_parser_emit_switch(sm6, &state); is_terminator = true; break; case FUNC_CODE_INST_VSELECT: - sm6_parser_emit_vselect(sm6, record, ins, dst); + sm6_parser_emit_vselect(sm6, &state); break; default: FIXME("Unhandled dxil instruction %u.\n", record->code); return VKD3D_ERROR_INVALID_SHADER; } + program->temp_count = max(program->temp_count, state.temp_idx); + if (sm6->p.status < 0) return sm6->p.status; if (record->attachment) - metadata_attachment_record_apply(record->attachment, record->code, ins, dst, sm6); - - /* This is specific for PHI nodes, but must happen after attachments have been applied. */ - if (record->code == FUNC_CODE_INST_PHI) - code_block->phi[code_block->phi_count - 1].value = *dst; + metadata_attachment_record_apply(record->attachment, record->code, &it, dst, sm6); if (is_terminator) { ++block_idx; - code_block = (block_idx < function->block_count) ? function->blocks[block_idx] : NULL; + emitted_label = false; } - if (code_block) - code_block->instruction_count += ins->opcode != VSIR_OP_NOP; if (dst->type && fwd_type && dst->type != fwd_type) { @@ -8482,148 +9291,191 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const return VKD3D_ERROR_INVALID_SHADER; } - return sm6_function_resolve_phi_incomings(function, sm6); + return VKD3D_OK; } -static void sm6_block_emit_terminator(const struct sm6_block *block, struct sm6_parser *sm6) +static void sm6_parser_init_parameter_attributes(struct sm6_parser *dxil, const struct dxil_block *block) { - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_instruction *ins; - unsigned int i, count; + size_t i; - switch (block->terminator.type) + if (dxil->parameter_attributes) { - case TERMINATOR_UNCOND_BR: - if (!block->terminator.true_block) - return; - if (!(ins = sm6_parser_add_instruction(sm6, VSIR_OP_BRANCH))) - return; - if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) - { - vkd3d_shader_instruction_make_nop(ins); - return; - } - vsir_src_param_init_label(&src_params[0], block->terminator.true_block->id); - break; + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_DUPLICATED_BLOCK, + "Duplicated PARAMATTR block."); + return; + } - case TERMINATOR_COND_BR: - if (!block->terminator.true_block || !block->terminator.false_block) - return; - if (!(ins = sm6_parser_add_instruction(sm6, VSIR_OP_BRANCH))) - return; - if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) - { - vkd3d_shader_instruction_make_nop(ins); - return; - } - src_param_init(&src_params[0]); - src_params[0].reg = block->terminator.conditional_reg; - vsir_src_param_init_label(&src_params[1], block->terminator.true_block->id); - vsir_src_param_init_label(&src_params[2], block->terminator.false_block->id); - break; + dxil->parameter_attribute_count = block->record_count; - case TERMINATOR_SWITCH: - if (!(ins = sm6_parser_add_instruction(sm6, VSIR_OP_SWITCH_MONOLITHIC))) - return; - if (!(src_params = instruction_src_params_alloc(ins, block->terminator.case_count * 2u + 1, sm6))) - { - vkd3d_shader_instruction_make_nop(ins); - return; - } - src_param_init(&src_params[0]); - src_params[0].reg = block->terminator.conditional_reg; - /* TODO: emit the merge block id. */ - vsir_src_param_init_label(&src_params[2], 0); + if (!(dxil->parameter_attributes = vkd3d_calloc(block->record_count, sizeof(*dxil->parameter_attributes)))) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory while allocating the parameter attributes array."); + dxil->parameter_attribute_count = 0; + return; + } - for (i = 0, count = 3; i < block->terminator.case_count; ++i) - { - const struct terminator_case *switch_case; - const struct sm6_block *case_block; + for (i = 0; i < block->record_count; ++i) + { + struct dxil_parameter_attribute *attribute = &dxil->parameter_attributes[i]; + struct dxil_record *record = block->records[i]; - switch_case = &block->terminator.cases[i]; - if (!(case_block = switch_case->block)) - { - VKD3D_ASSERT(sm6->p.status < 0); - continue; - } - if (switch_case->is_default) - { - vsir_src_param_init_label(&src_params[1], case_block->id); - continue; - } + if (record->code != PARAMATTR_CODE_ENTRY) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_NOT_IMPLEMENTED, + "PARAMATTR record code %u is not implemented.", record->code); + return; + } - if (src_params[0].reg.data_type == VSIR_DATA_U64) - { - vsir_src_param_init(&src_params[count], VKD3DSPR_IMMCONST64, VSIR_DATA_U64, 0); - src_params[count++].reg.u.immconst_u64[0] = switch_case->value; - } - else - { - if (switch_case->value > UINT_MAX) - { - WARN("Truncating 64-bit constant %"PRIx64".\n", switch_case->value); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, - "Truncating 64-bit switch case value %"PRIx64" to 32 bits.", switch_case->value); - } - vsir_src_param_init(&src_params[count], VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); - src_params[count++].reg.u.immconst_u32[0] = switch_case->value; - } - vsir_src_param_init_label(&src_params[count++], case_block->id); - } + if (!(attribute->groups = vkd3d_calloc(record->operand_count, sizeof(*attribute->groups)))) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory while allocating the groups array."); + return; + } - break; + memcpy(attribute->groups, record->operands, record->operand_count * sizeof(*attribute->groups)); + attribute->group_count = record->operand_count; + } +} - case TERMINATOR_RET: - sm6_parser_add_instruction(sm6, VSIR_OP_RET); - break; +static void dxil_attribute_group_cleanup(struct dxil_attribute_group *group) +{ + struct dxil_attribute *attribute; + size_t i; - default: - vkd3d_unreachable(); + for (i = 0; i < group->attribute_count; ++i) + { + attribute = &group->attributes[i]; + + switch (attribute->kind) + { + case ATTRIBUTE_WELL_KNOWN: + case ATTRIBUTE_WELL_KNOWN_WITH_INTEGER_VALUE: + break; + + case ATTRIBUTE_STRING: + vkd3d_free((void *)attribute->key.string); + break; + + case ATTRIBUTE_STRING_WITH_STRING_VALUE: + vkd3d_free((void *)attribute->key.string); + vkd3d_free((void *)attribute->value.string); + break; + } } + vkd3d_free(group->attributes); } -static void sm6_block_emit_phi(const struct sm6_block *block, struct sm6_parser *sm6) +static void sm6_parser_init_attribute_groups(struct sm6_parser *dxil, const struct dxil_block *block) { - struct vkd3d_shader_instruction *ins; - unsigned int i, j, incoming_count; - const struct sm6_phi *src_phi; + size_t i, j; - for (i = 0; i < block->phi_count; ++i) + if (dxil->attribute_groups) { - struct vkd3d_shader_src_param *src_params; - struct vkd3d_shader_dst_param *dst_param; + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_DUPLICATED_BLOCK, + "Duplicated PARAMATTR_GROUP block."); + return; + } - src_phi = &block->phi[i]; - incoming_count = src_phi->incoming_count; + dxil->attribute_group_count = block->record_count; - if (!(ins = sm6_parser_add_instruction(sm6, VSIR_OP_PHI))) - return; - if (!(src_params = instruction_src_params_alloc(ins, incoming_count * 2u, sm6))) - { - vkd3d_shader_instruction_make_nop(ins); - return; - } - if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) + if (!(dxil->attribute_groups = vkd3d_calloc(block->record_count, sizeof(*dxil->attribute_groups)))) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory while allocating the parameter attribute groups array."); + dxil->attribute_group_count = 0; + return; + } + + for (i = 0, j = 0; i < block->record_count; ++i) + { + struct dxil_attribute_group *group = &dxil->attribute_groups[j]; + struct dxil_record *record = block->records[i]; + bool failed = false; + unsigned int k; + + if (record->code != PARAMATTR_GRP_CODE_ENTRY) { - vkd3d_shader_instruction_make_nop(ins); - return; + vkd3d_shader_parser_warning(&dxil->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_RECORD, + "Ignoring PARAMATTR_GROUP record code %u.", record->code); + continue; } - for (j = 0; j < incoming_count; ++j) + if (!dxil_record_validate_operand_min_count(record, 2, dxil)) + continue; + + if (record->operands[0] > UINT_MAX || record->operands[0] == 0) + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_CONSTANT, + "PARAMATTR_GROUP group id %"PRIu64" is invalid.", record->operands[0]); + + if (record->operands[1] > UINT_MAX) + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_CONSTANT, + "PARAMATTR_GROUP parameter index %"PRIu64" is invalid.", record->operands[1]); + + group->group_id = record->operands[0]; + group->parameter_idx = record->operands[1]; + + for (k = 2; k < record->operand_count && !failed;) { - const struct sm6_block *incoming_block = src_phi->incoming[j].block; - unsigned int index = j * 2; + uint64_t kind = record->operands[k++]; + struct dxil_attribute *attribute; + + if (!vkd3d_array_reserve((void **)&group->attributes, &group->attribute_capacity, + group->attribute_count + 1, sizeof(*group->attributes))) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating the attribute array."); + break; + } + + attribute = &group->attributes[group->attribute_count++]; + memset(attribute, 0, sizeof(*attribute)); + attribute->kind = kind; + + switch (kind) + { + case ATTRIBUTE_WELL_KNOWN: + if (!dxil_record_validate_operand_min_count(record, k + 1, dxil)) + { + failed = true; + break; + } + + attribute->key.well_known = record->operands[k++]; + break; + + case ATTRIBUTE_WELL_KNOWN_WITH_INTEGER_VALUE: + if (!dxil_record_validate_operand_min_count(record, k + 2, dxil)) + { + failed = true; + break; + } + + attribute->key.well_known = record->operands[k++]; + attribute->value.numeric = record->operands[k++]; + break; + + case ATTRIBUTE_STRING: + if (!(attribute->key.string = dxil_record_to_zero_terminated_string(record, &k, dxil))) + failed = true; + break; + + case ATTRIBUTE_STRING_WITH_STRING_VALUE: + if (!(attribute->key.string = dxil_record_to_zero_terminated_string(record, &k, dxil)) + || !(attribute->value.string = dxil_record_to_zero_terminated_string(record, &k, dxil))) + failed = true; + break; - src_param_init(&src_params[index]); - src_params[index].reg = src_phi->incoming[j].reg; - if (incoming_block) - vsir_src_param_init_label(&src_params[index + 1], incoming_block->id); - else - VKD3D_ASSERT(sm6->p.status < 0); + default: + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE_KIND, + "Unrecognised PARAMATTR_GROUP attribute kind %"PRIu64".", kind); + failed = true; + break; + } } - dst_param_init(dst_param); - vsir_register_from_dxil_value(&dst_param->reg, &src_phi->value, 0, sm6); + ++j; } } @@ -8647,6 +9499,16 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st switch (block->id) { + case PARAMATTR_BLOCK: + sm6_parser_init_parameter_attributes(sm6, block); + if (sm6->p.status < 0) + return sm6->p.status; + break; + + case PARAMATTR_GROUP_BLOCK: + sm6_parser_init_attribute_groups(sm6, block); + break; + case CONSTANTS_BLOCK: /* Level 1 (global) constants are already done in sm6_parser_globals_init(). */ if (level < 2) @@ -8668,8 +9530,6 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st case BLOCKINFO_BLOCK: case MODULE_BLOCK: - case PARAMATTR_BLOCK: - case PARAMATTR_GROUP_BLOCK: case VALUE_SYMTAB_BLOCK: case METADATA_BLOCK: case METADATA_ATTACHMENT_BLOCK: @@ -8681,53 +9541,29 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st break; } - return VKD3D_OK; -} - -static void sm6_parser_emit_label(struct sm6_parser *sm6, unsigned int label_id) -{ - struct vkd3d_shader_src_param *src_param; - struct vkd3d_shader_instruction *ins; - - if (!(ins = sm6_parser_add_instruction(sm6, VSIR_OP_LABEL))) - return; - if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) - { - vkd3d_shader_instruction_make_nop(ins); - return; - } - vsir_src_param_init_label(src_param, label_id); + return sm6->p.status; } -static enum vkd3d_result sm6_function_emit_blocks(const struct sm6_function *function, struct sm6_parser *sm6) +static enum vkd3d_result sm6_function_emit_instructions(struct sm6_function *function, struct sm6_parser *dxil) { - struct vsir_program *program = sm6->program; - struct vkd3d_shader_instruction *ins; - unsigned int i, j; + struct vsir_program_iterator it = vsir_program_iterator(&function->instructions); + struct vsir_program *program = dxil->program; + struct vkd3d_shader_instruction *dst, *src; program->block_count = max(program->block_count, function->block_count); - for (i = 0; i < function->block_count; ++i) + for (src = vsir_program_iterator_head(&it); src; src = vsir_program_iterator_next(&it)) { - const struct sm6_block *block = function->blocks[i]; - - sm6_parser_emit_label(sm6, block->id); - sm6_block_emit_phi(block, sm6); - - for (j = 0; j < block->instruction_count; ++j) + if (!(dst = vsir_program_append(program))) { - if (!(ins = vsir_program_append(program))) - { - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, - "Out of memory emitting block instructions."); - return sm6->p.status; - } - *ins = block->instructions[j]; + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory while emitting instructions."); + return dxil->p.status; } - sm6_block_emit_terminator(block, sm6); + *dst = *src; } - return sm6->p.status; + return dxil->p.status; } static bool sm6_parser_allocate_named_metadata(struct sm6_parser *sm6) @@ -9145,22 +9981,6 @@ static bool sm6_parser_resources_load_register_range(struct sm6_parser *sm6, return true; } -static enum vkd3d_shader_resource_type shader_resource_type_from_dxil_resource_kind(enum dxil_resource_kind kind) -{ - if (resource_kind_is_texture(kind)) - return kind + 1; - - switch (kind) - { - case RESOURCE_KIND_TYPEDBUFFER: - case RESOURCE_KIND_RAWBUFFER: - case RESOURCE_KIND_STRUCTUREDBUFFER: - return VKD3D_SHADER_RESOURCE_BUFFER; - default: - return VKD3D_SHADER_RESOURCE_NONE; - } -} - static const enum vsir_data_type data_type_table[] = { [COMPONENT_TYPE_INVALID] = VSIR_DATA_UNUSED, @@ -9372,7 +10192,7 @@ static void init_resource_declaration(struct vkd3d_shader_resource *resource, enum vkd3d_shader_register_type reg_type, enum vsir_data_type data_type, unsigned int id, const struct vkd3d_shader_register_range *range) { - struct vkd3d_shader_dst_param *param = &resource->reg; + struct vsir_dst_operand *param = &resource->reg; param->modifiers = 0; param->shift = 0; @@ -9420,14 +10240,11 @@ static enum vkd3d_result sm6_parser_resources_load_srv(struct sm6_parser *sm6, return VKD3D_ERROR_INVALID_SHADER; } - d->resource_type = ins->resource_type; d->kind = kind; - d->reg_type = VKD3DSPR_RESOURCE; - d->reg_data_type = VSIR_DATA_UNUSED; d->resource_data_type = (ins->opcode == VSIR_OP_DCL) ? ins->declaration.semantic.resource_data_type[0] : VSIR_DATA_UNUSED; - init_resource_declaration(resource, VKD3DSPR_RESOURCE, d->reg_data_type, d->id, &d->range); + init_resource_declaration(resource, VKD3DSPR_RESOURCE, VSIR_DATA_UNUSED, d->id, &d->range); if (resource_kind_is_multisampled(kind)) { @@ -9494,14 +10311,11 @@ static enum vkd3d_result sm6_parser_resources_load_uav(struct sm6_parser *sm6, return VKD3D_ERROR_INVALID_SHADER; } - d->resource_type = ins->resource_type; d->kind = values[0]; - d->reg_type = VKD3DSPR_UAV; - d->reg_data_type = VSIR_DATA_UNUSED; d->resource_data_type = (ins->opcode == VSIR_OP_DCL_UAV_TYPED) ? ins->declaration.semantic.resource_data_type[0] : VSIR_DATA_UNUSED; - init_resource_declaration(resource, VKD3DSPR_UAV, d->reg_data_type, d->id, &d->range); + init_resource_declaration(resource, VKD3DSPR_UAV, VSIR_DATA_UNUSED, d->id, &d->range); return VKD3D_OK; } @@ -9548,8 +10362,6 @@ static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6, ins->declaration.cb.range = d->range; - d->reg_type = VKD3DSPR_CONSTBUFFER; - d->reg_data_type = VSIR_DATA_F32; d->resource_data_type = VSIR_DATA_F32; return VKD3D_OK; @@ -9610,10 +10422,7 @@ static enum vkd3d_result sm6_parser_resources_load_sampler(struct sm6_parser *sm ins->declaration.sampler.range = d->range; - d->resource_type = ins->resource_type; d->kind = RESOURCE_KIND_SAMPLER; - d->reg_type = VKD3DSPR_SAMPLER; - d->reg_data_type = VSIR_DATA_UNUSED; d->resource_data_type = VSIR_DATA_UNUSED; return VKD3D_OK; @@ -10024,7 +10833,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const "Failed to allocate signature element semantic name."); for (j = 0; j < i; ++j) { - vkd3d_free((void *)elements[j].semantic_name); + vsir_signature_element_cleanup(&elements[j]); } vkd3d_free(elements); return VKD3D_ERROR_OUT_OF_MEMORY; @@ -10706,34 +11515,41 @@ static void sm6_symtab_cleanup(struct sm6_symbol *symbols, size_t count) vkd3d_free(symbols); } -static void sm6_phi_destroy(struct sm6_phi *phi) +static void sm6_functions_cleanup(struct sm6_function *functions, size_t count) { - vkd3d_free(phi->incoming); + size_t i; + + for (i = 0; i < count; ++i) + { + shader_instruction_array_cleanup(&functions[i].instructions); + } + vkd3d_free(functions); } -static void sm6_block_destroy(struct sm6_block *block) +static void sm6_parser_cleanup_parameter_attributes(struct sm6_parser *sm6) { - unsigned int i; + size_t i; + + for (i = 0; i < sm6->parameter_attribute_count; ++i) + { + struct dxil_parameter_attribute *attribute = &sm6->parameter_attributes[i]; + + vkd3d_free(attribute->groups); + } - vkd3d_free(block->instructions); - for (i = 0; i < block->phi_count; ++i) - sm6_phi_destroy(&block->phi[i]); - vkd3d_free(block->phi); - vkd3d_free(block->terminator.cases); - vkd3d_free(block); + vkd3d_free(sm6->parameter_attributes); } -static void sm6_functions_cleanup(struct sm6_function *functions, size_t count) +static void sm6_parser_cleanup_attribute_groups(struct sm6_parser *dxil) { - size_t i, j; + size_t i; - for (i = 0; i < count; ++i) + for (i = 0; i < dxil->attribute_group_count; ++i) { - for (j = 0; j < functions[i].block_count; ++j) - sm6_block_destroy(functions[i].blocks[j]); - vkd3d_free(functions[i].blocks); + dxil_attribute_group_cleanup(&dxil->attribute_groups[i]); } - vkd3d_free(functions); + + vkd3d_free(dxil->attribute_groups); } static void sm6_parser_cleanup(struct sm6_parser *sm6) @@ -10743,11 +11559,69 @@ static void sm6_parser_cleanup(struct sm6_parser *sm6) sm6_type_table_cleanup(sm6->types, sm6->type_count); sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); sm6_functions_cleanup(sm6->functions, sm6->function_count); + sm6_parser_cleanup_parameter_attributes(sm6); + sm6_parser_cleanup_attribute_groups(sm6); sm6_parser_metadata_cleanup(sm6); vkd3d_free(sm6->descriptors); vkd3d_free(sm6->values); } +static enum vsir_denorm_mode sm6_function_get_denorm_mode(const struct sm6_function *function, + struct sm6_parser *dxil) +{ + unsigned int attribs_id = function->declaration->u.function.attribs_id; + const struct dxil_parameter_attribute *parameter_attribute; + size_t i, j, k; + + if (!attribs_id) + return VSIR_DENORM_FLUSH_TO_ZERO; + + if (attribs_id > dxil->parameter_attribute_count) + { + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE, + "Invalid attribute id %u.", attribs_id); + return VSIR_DENORM_FLUSH_TO_ZERO; + } + + parameter_attribute = &dxil->parameter_attributes[attribs_id - 1]; + + for (i = 0; i < parameter_attribute->group_count; ++i) + { + for (j = 0; j < dxil->attribute_group_count; ++j) + { + struct dxil_attribute_group *attribute_group = &dxil->attribute_groups[j]; + + if (attribute_group->group_id != parameter_attribute->groups[i] + || attribute_group->parameter_idx != ~0u) + continue; + + for (k = 0; k < attribute_group->attribute_count; ++k) + { + struct dxil_attribute *attribute = &attribute_group->attributes[k]; + + if (attribute->kind != ATTRIBUTE_STRING_WITH_STRING_VALUE + || strcmp(attribute->key.string, "fp32-denorm-mode")) + continue; + + if (!strcmp(attribute->value.string, "preserve")) + return VSIR_DENORM_PRESERVE; + + if (!strcmp(attribute->value.string, "ftz")) + return VSIR_DENORM_FLUSH_TO_ZERO; + + if (!strcmp(attribute->value.string, "any")) + return VSIR_DENORM_ANY; + + vkd3d_shader_parser_error(&dxil->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE, + "Invalid value for attribute `fp32-denorm-mode'."); + return VSIR_DENORM_FLUSH_TO_ZERO; + } + } + } + + return VSIR_DENORM_FLUSH_TO_ZERO; +} + static struct sm6_function *sm6_parser_get_function(const struct sm6_parser *sm6, const char *name) { size_t i; @@ -11028,11 +11902,15 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro goto fail; } + program->f32_denorm_mode = sm6_function_get_denorm_mode(fn, sm6); + if (version.type == VKD3D_SHADER_TYPE_HULL) { + enum vsir_denorm_mode cp_denorm_mode; + sm6_parser_add_instruction(sm6, VSIR_OP_HS_CONTROL_POINT_PHASE); - if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) + if ((ret = sm6_function_emit_instructions(fn, sm6)) < 0) goto fail; if (!(fn = sm6_parser_get_function(sm6, sm6->patch_constant_function))) @@ -11045,15 +11923,24 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, struct vsir_pro goto fail; } + cp_denorm_mode = sm6_function_get_denorm_mode(fn, sm6); + + if (sm6->p.status >= 0 && program->f32_denorm_mode != cp_denorm_mode) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE, + "Patch constant denorm mode %u doesn't match control point denorm mode %u.", + program->f32_denorm_mode, cp_denorm_mode); + } + sm6_parser_add_instruction(sm6, VSIR_OP_HS_FORK_PHASE); - if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) + if ((ret = sm6_function_emit_instructions(fn, sm6)) < 0) goto fail; expected_function_count = 2; } else { - if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) + if ((ret = sm6_function_emit_instructions(fn, sm6)) < 0) goto fail; expected_function_count = 1; } diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c index 4848c531ced..1eb8d8d44b2 100644 --- a/libs/vkd3d/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d/libs/vkd3d-shader/fx.c @@ -107,6 +107,14 @@ struct fx_5_shader uint32_t iface_bindings; }; +enum fx_shader_type +{ + FX_SHADER_NONE, + FX4_SHADER, + FX4_SHADER_SO, + FX5_SHADER +}; + struct string_entry { struct rb_entry entry; @@ -119,9 +127,12 @@ struct type_entry { struct list entry; const char *name; + const struct hlsl_type *element_type; uint32_t elements_count; + uint32_t unpacked_size; uint32_t modifiers; uint32_t offset; + enum fx_shader_type shader_type; }; static int string_storage_compare(const void *key, const struct rb_entry *entry) @@ -293,6 +304,7 @@ struct fx_write_context uint32_t rasterizer_state_count; uint32_t blend_state_count; uint32_t string_count; + uint32_t inline_shader_count; int status; bool child_effect; @@ -360,64 +372,125 @@ static void write_fx_4_annotations(struct hlsl_scope *scope, struct fx_write_con set_u32(buffer, count_offset, count); } -static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx); +static uint32_t write_fx_4_type(const struct type_entry *type, struct fx_write_context *fx); static const char * get_fx_4_type_name(const struct hlsl_type *type); static void write_fx_4_annotation(struct hlsl_ir_var *var, struct fx_write_context *fx); -static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context *fx) +static uint32_t write_type(const struct type_entry *type, struct fx_write_context *fx) { - unsigned int elements_count, modifiers; - const struct hlsl_type *element_type; struct type_entry *type_entry; - const char *name; - - VKD3D_ASSERT(fx->ctx->profile->major_version >= 4); - - if (type->class == HLSL_CLASS_ARRAY) - { - elements_count = hlsl_get_multiarray_size(type); - element_type = hlsl_get_multiarray_element_type(type); - } - else - { - elements_count = 0; - element_type = type; - } - - name = get_fx_4_type_name(element_type); - modifiers = element_type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK; + uint32_t offset; /* We don't try to reuse nameless types; they will get the same * "<unnamed>" name, but are not available for the type cache. */ - if (name) + if (type->name) { LIST_FOR_EACH_ENTRY(type_entry, &fx->types, struct type_entry, entry) { - if (strcmp(type_entry->name, name)) + if (strcmp(type_entry->name, type->name)) + continue; + + if (type_entry->elements_count != type->elements_count) continue; - if (type_entry->elements_count != elements_count) + if (type_entry->modifiers != type->modifiers) continue; - if (type_entry->modifiers != modifiers) + if (type_entry->shader_type != type->shader_type) continue; return type_entry->offset; } } + offset = write_fx_4_type(type, fx); + + if (!type->name) + return offset; + if (!(type_entry = hlsl_alloc(fx->ctx, sizeof(*type_entry)))) - return 0; + return offset; + + *type_entry = *type; + type_entry->offset = offset; + list_add_tail(&fx->types, &type_entry->entry); + + return offset; +} - type_entry->offset = write_fx_4_type(type, fx); - type_entry->name = name; - type_entry->elements_count = elements_count; - type_entry->modifiers = modifiers; +static void type_entry_from_type(struct type_entry *e, const struct hlsl_type *type, const struct fx_write_context *fx) +{ + const struct hlsl_type *element_type = hlsl_get_multiarray_element_type(type); - if (name) - list_add_tail(&fx->types, &type_entry->entry); + VKD3D_ASSERT(fx->ctx->profile->major_version >= 4); - return type_entry->offset; + *e = (struct type_entry) + { + .elements_count = type->class == HLSL_CLASS_ARRAY ? hlsl_get_multiarray_size(type) : 0, + /* Structures can only contain numeric fields, this is validated + * during variable declaration. */ + .unpacked_size = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float), + .modifiers = element_type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK, + .name = get_fx_4_type_name(element_type), + .element_type = element_type, + }; +} + +static enum fx_shader_type get_shader_type(struct hlsl_ir_var *shader, struct fx_write_context *fx) +{ + const struct hlsl_type *type = hlsl_get_multiarray_element_type(shader->data_type); + uint32_t elements_count = hlsl_get_multiarray_size(shader->data_type); + enum fx_shader_type shader_type = FX4_SHADER; + struct hlsl_ctx *ctx = fx->ctx; + + switch (type->class) + { + case HLSL_CLASS_PIXEL_SHADER: + case HLSL_CLASS_VERTEX_SHADER: + return FX4_SHADER; + + case HLSL_CLASS_HULL_SHADER: + case HLSL_CLASS_COMPUTE_SHADER: + case HLSL_CLASS_DOMAIN_SHADER: + return FX5_SHADER; + + case HLSL_CLASS_GEOMETRY_SHADER: + break; + + default: + return FX_SHADER_NONE; + } + + for (size_t i = 0; i < elements_count; ++i) + { + struct hlsl_ir_compile *compile; + + if (!shader->default_values || !(compile = shader->default_values[i].shader) || !compile->output.count) + continue; + + if (compile->output.count > 1) + { + shader_type = FX5_SHADER; + break; + } + shader_type = FX4_SHADER_SO; + } + + if (shader_type == FX5_SHADER && hlsl_version_lt(ctx, 5, 0)) + hlsl_error(ctx, &shader->loc, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE, + "Multi-stream output is not supported by the fx_4_0 profile."); + + return shader_type; +} + +static uint32_t write_var_type(struct hlsl_ir_var *var, struct fx_write_context *fx) +{ + struct type_entry entry; + + type_entry_from_type(&entry, var->data_type, fx); + + entry.shader_type = get_shader_type(var, fx); + return write_type(&entry, fx); } static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_context_ops *ops, @@ -1078,6 +1151,7 @@ enum fx_4_type_constants FX_4_OBJECT_TYPE_RTV = 0x13, FX_4_OBJECT_TYPE_DSV = 0x14, FX_4_OBJECT_TYPE_SAMPLER_STATE = 0x15, + FX_4_OBJECT_TYPE_BUFFER = 0x16, FX_4_OBJECT_TYPE_TEXTURE_CUBEARRAY = 0x17, FX_5_OBJECT_TYPE_GEOMETRY_SHADER = 0x1b, @@ -1172,16 +1246,19 @@ static const char * get_fx_4_type_name(const struct hlsl_type *type) { static const char * const texture_type_names[] = { - [HLSL_SAMPLER_DIM_GENERIC] = "texture", - [HLSL_SAMPLER_DIM_1D] = "Texture1D", - [HLSL_SAMPLER_DIM_1DARRAY] = "Texture1DArray", - [HLSL_SAMPLER_DIM_2D] = "Texture2D", - [HLSL_SAMPLER_DIM_2DARRAY] = "Texture2DArray", - [HLSL_SAMPLER_DIM_2DMS] = "Texture2DMS", - [HLSL_SAMPLER_DIM_2DMSARRAY] = "Texture2DMSArray", - [HLSL_SAMPLER_DIM_3D] = "Texture3D", - [HLSL_SAMPLER_DIM_CUBE] = "TextureCube", - [HLSL_SAMPLER_DIM_CUBEARRAY] = "TextureCubeArray", + [HLSL_SAMPLER_DIM_GENERIC] = "texture", + [HLSL_SAMPLER_DIM_1D] = "Texture1D", + [HLSL_SAMPLER_DIM_1DARRAY] = "Texture1DArray", + [HLSL_SAMPLER_DIM_2D] = "Texture2D", + [HLSL_SAMPLER_DIM_2DARRAY] = "Texture2DArray", + [HLSL_SAMPLER_DIM_2DMS] = "Texture2DMS", + [HLSL_SAMPLER_DIM_2DMSARRAY] = "Texture2DMSArray", + [HLSL_SAMPLER_DIM_3D] = "Texture3D", + [HLSL_SAMPLER_DIM_CUBE] = "TextureCube", + [HLSL_SAMPLER_DIM_CUBEARRAY] = "TextureCubeArray", + [HLSL_SAMPLER_DIM_BUFFER] = "Buffer", + [HLSL_SAMPLER_DIM_STRUCTURED_BUFFER] = "StructuredBuffer", + [HLSL_SAMPLER_DIM_RAW_BUFFER] = "ByteAddressBuffer", }; static const char * const uav_type_names[] = { @@ -1201,9 +1278,11 @@ static const char * get_fx_4_type_name(const struct hlsl_type *type) return "SamplerState"; case HLSL_CLASS_TEXTURE: + VKD3D_ASSERT(type->sampler_dim < ARRAY_SIZE(texture_type_names)); return texture_type_names[type->sampler_dim]; case HLSL_CLASS_UAV: + VKD3D_ASSERT(type->sampler_dim < ARRAY_SIZE(uav_type_names)); return uav_type_names[type->sampler_dim]; case HLSL_CLASS_DEPTH_STENCIL_STATE: @@ -1244,7 +1323,7 @@ static bool is_numeric_fx_4_type(const struct hlsl_type *type) return type->class == HLSL_CLASS_STRUCT || hlsl_is_numeric_type(type); } -static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx) +static uint32_t write_fx_4_type(const struct type_entry *type, struct fx_write_context *fx) { struct field_offsets { @@ -1253,21 +1332,16 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co uint32_t offset; uint32_t type; }; - uint32_t name_offset, offset, unpacked_size, packed_size, stride, numeric_desc; + uint32_t name_offset, offset, packed_size, stride, numeric_desc; + const struct hlsl_type *element_type = type->element_type; struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + uint32_t elements_count = type->elements_count; + uint32_t unpacked_size = type->unpacked_size; struct field_offsets *field_offsets = NULL; - const struct hlsl_type *element_type; struct hlsl_ctx *ctx = fx->ctx; - uint32_t elements_count = 0; - const char *name; + const char *name = type->name; size_t i; - if (type->class == HLSL_CLASS_ARRAY) - elements_count = hlsl_get_multiarray_size(type); - element_type = hlsl_get_multiarray_element_type(type); - - name = get_fx_4_type_name(element_type); - name_offset = write_string(name ? name : "<unnamed>", fx); if (element_type->class == HLSL_CLASS_STRUCT) { @@ -1277,11 +1351,13 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co for (i = 0; i < element_type->e.record.field_count; ++i) { const struct hlsl_struct_field *field = &element_type->e.record.fields[i]; + struct type_entry entry; + type_entry_from_type(&entry, field->type, fx); field_offsets[i].name = write_string(field->name, fx); field_offsets[i].semantic = write_string(field->semantic.raw_name, fx); field_offsets[i].offset = field->reg_offset[HLSL_REGSET_NUMERIC] * sizeof(float); - field_offsets[i].type = write_type(field->type, fx); + field_offsets[i].type = write_type(&entry, fx); } } @@ -1333,9 +1409,6 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co return 0; } - /* Structures can only contain numeric fields, this is validated during variable declaration. */ - unpacked_size = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float); - packed_size = 0; if (is_numeric_fx_4_type(element_type)) packed_size = hlsl_type_component_count(element_type) * sizeof(float); @@ -1373,18 +1446,22 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co { static const uint32_t texture_type[] = { - [HLSL_SAMPLER_DIM_GENERIC] = FX_4_OBJECT_TYPE_TEXTURE, - [HLSL_SAMPLER_DIM_1D] = FX_4_OBJECT_TYPE_TEXTURE_1D, - [HLSL_SAMPLER_DIM_1DARRAY] = FX_4_OBJECT_TYPE_TEXTURE_1DARRAY, - [HLSL_SAMPLER_DIM_2D] = FX_4_OBJECT_TYPE_TEXTURE_2D, - [HLSL_SAMPLER_DIM_2DARRAY] = FX_4_OBJECT_TYPE_TEXTURE_2DARRAY, - [HLSL_SAMPLER_DIM_2DMS] = FX_4_OBJECT_TYPE_TEXTURE_2DMS, - [HLSL_SAMPLER_DIM_2DMSARRAY] = FX_4_OBJECT_TYPE_TEXTURE_2DMSARRAY, - [HLSL_SAMPLER_DIM_3D] = FX_4_OBJECT_TYPE_TEXTURE_3D, - [HLSL_SAMPLER_DIM_CUBE] = FX_4_OBJECT_TYPE_TEXTURE_CUBE, - [HLSL_SAMPLER_DIM_CUBEARRAY] = FX_4_OBJECT_TYPE_TEXTURE_CUBEARRAY, + [HLSL_SAMPLER_DIM_GENERIC] = FX_4_OBJECT_TYPE_TEXTURE, + [HLSL_SAMPLER_DIM_1D] = FX_4_OBJECT_TYPE_TEXTURE_1D, + [HLSL_SAMPLER_DIM_1DARRAY] = FX_4_OBJECT_TYPE_TEXTURE_1DARRAY, + [HLSL_SAMPLER_DIM_2D] = FX_4_OBJECT_TYPE_TEXTURE_2D, + [HLSL_SAMPLER_DIM_2DARRAY] = FX_4_OBJECT_TYPE_TEXTURE_2DARRAY, + [HLSL_SAMPLER_DIM_2DMS] = FX_4_OBJECT_TYPE_TEXTURE_2DMS, + [HLSL_SAMPLER_DIM_2DMSARRAY] = FX_4_OBJECT_TYPE_TEXTURE_2DMSARRAY, + [HLSL_SAMPLER_DIM_3D] = FX_4_OBJECT_TYPE_TEXTURE_3D, + [HLSL_SAMPLER_DIM_CUBE] = FX_4_OBJECT_TYPE_TEXTURE_CUBE, + [HLSL_SAMPLER_DIM_CUBEARRAY] = FX_4_OBJECT_TYPE_TEXTURE_CUBEARRAY, + [HLSL_SAMPLER_DIM_BUFFER] = FX_4_OBJECT_TYPE_BUFFER, + [HLSL_SAMPLER_DIM_STRUCTURED_BUFFER] = FX_5_OBJECT_TYPE_SRV_STRUCTURED_BUFFER, + [HLSL_SAMPLER_DIM_RAW_BUFFER] = FX_5_OBJECT_TYPE_SRV_RAW_BUFFER, }; + VKD3D_ASSERT(element_type->sampler_dim < ARRAY_SIZE(texture_type)); put_u32_unaligned(buffer, texture_type[element_type->sampler_dim]); } else if (element_type->class == HLSL_CLASS_SAMPLER) @@ -1405,6 +1482,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co [HLSL_SAMPLER_DIM_RAW_BUFFER] = FX_5_OBJECT_TYPE_UAV_RAW_BUFFER, }; + VKD3D_ASSERT(element_type->sampler_dim < ARRAY_SIZE(uav_type)); put_u32_unaligned(buffer, uav_type[element_type->sampler_dim]); } else if (element_type->class == HLSL_CLASS_DEPTH_STENCIL_VIEW) @@ -1423,6 +1501,23 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co { put_u32_unaligned(buffer, FX_4_OBJECT_TYPE_VERTEX_SHADER); } + else if (element_type->class == HLSL_CLASS_GEOMETRY_SHADER) + { + switch (type->shader_type) + { + case FX4_SHADER: + put_u32_unaligned(buffer, FX_4_OBJECT_TYPE_GEOMETRY_SHADER); + break; + case FX4_SHADER_SO: + put_u32_unaligned(buffer, FX_4_OBJECT_TYPE_GEOMETRY_SHADER_SO); + break; + case FX5_SHADER: + put_u32_unaligned(buffer, FX_5_OBJECT_TYPE_GEOMETRY_SHADER); + break; + case FX_SHADER_NONE: + vkd3d_unreachable(); + } + } else if (element_type->class == HLSL_CLASS_RASTERIZER_STATE) { put_u32_unaligned(buffer, FX_4_OBJECT_TYPE_RASTERIZER_STATE); @@ -2067,10 +2162,8 @@ static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) ctx->result = fx.status; if (!ctx->result) - { - out->code = buffer.data; - out->size = buffer.size; - } + vkd3d_shader_code_from_bytecode_buffer(out, &buffer); + vkd3d_bytecode_buffer_cleanup(&buffer); return fx_write_context_cleanup(&fx); } @@ -2181,7 +2274,7 @@ static void write_fx_4_numeric_variable(struct hlsl_ir_var *var, bool shared, st if (var->has_explicit_bind_point) flags |= FX_4_HAS_EXPLICIT_BIND_POINT; - type_offset = write_type(var->data_type, fx); + type_offset = write_var_type(var, fx); name_offset = write_string(var->name, fx); semantic_offset = write_string(var->semantic.raw_name, fx); @@ -2216,7 +2309,7 @@ static void write_fx_4_annotation(struct hlsl_ir_var *var, struct fx_write_conte struct hlsl_ctx *ctx = fx->ctx; name_offset = write_string(var->name, fx); - type_offset = write_type(var->data_type, fx); + type_offset = write_var_type(var, fx); put_u32(buffer, name_offset); put_u32(buffer, type_offset); @@ -2285,6 +2378,107 @@ static uint32_t write_fx_4_state_numeric_value(struct hlsl_ir_constant *value, s return offset; } +static uint32_t write_shader_blob(const struct hlsl_ir_compile *compile, struct fx_write_context *fx) +{ + struct vkd3d_bytecode_buffer *buffer = &fx->unstructured; + struct vkd3d_shader_code source = {0}, rdef = {0}; + const struct hlsl_profile_info *profile; + struct vkd3d_shader_version version; + struct hlsl_ctx *ctx = fx->ctx; + struct vsir_program program; + uint32_t offset; + int ret = 0; + + static const struct vkd3d_shader_compile_option version_option = + { + .name = VKD3D_SHADER_COMPILE_OPTION_API_VERSION, + .value = VKD3D_SHADER_API_VERSION_CURRENT, + }; + static const struct vkd3d_shader_compile_info compile_info = + { + .type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO, + .target_type = VKD3D_SHADER_TARGET_DXBC_TPF, + .options = &version_option, + .option_count = 1, + }; + + version = (struct vkd3d_shader_version) + { + .type = compile->profile->type, + .major = compile->profile->major_version, + .minor = compile->profile->minor_version, + }; + + if (!vsir_program_init(&program, &compile_info, &version, 0, VSIR_CF_STRUCTURED, VSIR_NORMALISED_SM4)) + return 0; + + profile = ctx->profile; + ctx->profile = compile->profile; + ret = hlsl_emit_vsir(ctx, &compile_info, compile->decl, &compile->initializers, &program, &rdef); + ctx->profile = profile; + if (ret < 0) + return 0; + + ret = vsir_program_compile(&program, &rdef, vkd3d_shader_init_config_flags(), + &compile_info, &source, ctx->message_context); + + vkd3d_shader_free_shader_code(&rdef); + vsir_program_cleanup(&program); + if (ret < 0) + return 0; + + offset = put_u32(buffer, source.size); + bytecode_put_bytes_unaligned(buffer, source.code, source.size); + + vkd3d_shader_free_shader_code(&source); + + return offset; +} + +static uint32_t write_fx_shader(enum fx_shader_type type, const struct hlsl_ir_compile *compile, + struct vkd3d_bytecode_buffer *buffer, struct fx_write_context *fx) +{ + struct fx_5_shader shader = {0}; + uint32_t ret; + + if (compile) + { + shader = (struct fx_5_shader) + { + .offset = write_shader_blob(compile, fx), + .sodecl_count = compile->output.count > 1 ? 4 : 0, + .rast_stream = compile->output.stream, + }; + + for (size_t i = 0; i < compile->output.count; ++i) + { + shader.sodecl[i] = write_string(compile->output.decls[i], fx); + } + } + + switch (type) + { + case FX4_SHADER: + ret = put_u32(buffer, shader.offset); + break; + + case FX4_SHADER_SO: + ret = put_u32(buffer, shader.offset); + put_u32(buffer, shader.sodecl[0]); + break; + + case FX5_SHADER: + ret = bytecode_put_bytes(buffer, &shader, sizeof(shader)); + break; + + default: + ret = 0; + break; + } + + return ret; +} + static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hlsl_state_block_entry *entry, struct fx_write_context *fx) { @@ -2379,6 +2573,26 @@ static void write_fx_4_state_assignment(const struct hlsl_ir_var *var, struct hl } break; } + case HLSL_IR_COMPILE: + { + enum fx_shader_type shader_type; + + if (hlsl_version_lt(ctx, 5, 0)) + { + assignment_type = FX_4_ASSIGNMENT_INLINE_SHADER; + shader_type = FX4_SHADER_SO; + } + else + { + assignment_type = FX_5_ASSIGNMENT_INLINE_SHADER; + shader_type = FX5_SHADER; + } + + value_offset = write_fx_shader(shader_type, hlsl_ir_compile(value), unstructured, fx); + ++fx->inline_shader_count; + ++fx->shader_count; + break; + } default: hlsl_fixme(ctx, &var->loc, "Unsupported assignment type for state %s.", entry->name); } @@ -2515,6 +2729,8 @@ static inline enum hlsl_type_class hlsl_type_class_from_fx_type(enum state_prope return HLSL_CLASS_VERTEX_SHADER; case FX_PIXELSHADER: return HLSL_CLASS_PIXEL_SHADER; + case FX_GEOMETRYSHADER: + return HLSL_CLASS_GEOMETRY_SHADER; default: vkd3d_unreachable(); } @@ -2926,6 +3142,9 @@ static void resolve_fx_state_block_values(struct hlsl_ir_var *var, break; } + case HLSL_IR_COMPILE: + case HLSL_IR_INDEX: + break; default: hlsl_fixme(ctx, &ctx->location, "Unhandled node type for object-typed field."); } @@ -3009,7 +3228,7 @@ static unsigned int decompose_fx_4_state_function_call(struct hlsl_ir_var *var, const struct state_block_function_info *info; struct function_component components[9]; struct hlsl_ctx *ctx = fx->ctx; - unsigned int i; + unsigned int i, count; if (!entry->is_function_call) return 1; @@ -3037,16 +3256,16 @@ static unsigned int decompose_fx_4_state_function_call(struct hlsl_ir_var *var, get_state_block_function_components(info, components, entry->args_count); - for (i = 0; i < entry->args_count; ++i) + for (i = 0, count = entry->args_count; i < count; ++i) { const struct function_component *comp = &components[i]; - unsigned int arg_index = (i + 1) % entry->args_count; + unsigned int arg_index = (i + 1) % count; block->entries[entry_index + i] = clone_stateblock_entry(ctx, entry, comp->name, comp->lhs_has_index, comp->lhs_index, true, arg_index); } hlsl_free_state_block_entry(entry); - return entry->args_count; + return count; } /* For some states assignment sets all of the elements. This behaviour is limited to certain states of BlendState @@ -3177,35 +3396,14 @@ static void write_fx_4_state_object_initializer(struct hlsl_ir_var *var, struct } } -static void write_fx_4_shader_initializer(struct hlsl_ir_var *var, struct fx_write_context *fx) +static void write_fx_shader_initializer(struct hlsl_ir_var *var, struct fx_write_context *fx) { - struct vkd3d_bytecode_buffer *buffer = &fx->structured; uint32_t elements_count = hlsl_get_multiarray_size(var->data_type); - unsigned int i; + enum fx_shader_type shader_type = get_shader_type(var, fx); - /* FIXME: write shader blobs, once parser support works. */ - for (i = 0; i < elements_count; ++i) - put_u32(buffer, 0); -} - -static void write_fx_5_shader_initializer(struct hlsl_ir_var *var, struct fx_write_context *fx) -{ - struct vkd3d_bytecode_buffer *buffer = &fx->structured; - uint32_t elements_count = hlsl_get_multiarray_size(var->data_type); - unsigned int i; - - /* FIXME: write shader blobs, once parser support works. */ - for (i = 0; i < elements_count; ++i) + for (size_t i = 0; i < elements_count; ++i) { - put_u32(buffer, 0); /* Blob offset */ - put_u32(buffer, 0); /* SODecl[0] offset */ - put_u32(buffer, 0); /* SODecl[1] offset */ - put_u32(buffer, 0); /* SODecl[2] offset */ - put_u32(buffer, 0); /* SODecl[3] offset */ - put_u32(buffer, 0); /* SODecl count */ - put_u32(buffer, 0); /* Rasterizer stream */ - put_u32(buffer, 0); /* Interface bindings count */ - put_u32(buffer, 0); /* Interface initializer offset */ + write_fx_shader(shader_type, var->default_values ? var->default_values[i].shader : NULL, &fx->structured, fx); } } @@ -3221,7 +3419,7 @@ static void write_fx_4_object_variable(struct hlsl_ir_var *var, struct fx_write_ if (var->reg_reservation.reg_type) bind_point = var->reg_reservation.reg_index; - type_offset = write_type(var->data_type, fx); + type_offset = write_var_type(var, fx); name_offset = write_string(var->name, fx); semantic_offset = write_string(var->semantic.raw_name, fx); @@ -3252,14 +3450,11 @@ static void write_fx_4_object_variable(struct hlsl_ir_var *var, struct fx_write_ case HLSL_CLASS_PIXEL_SHADER: case HLSL_CLASS_VERTEX_SHADER: - write_fx_4_shader_initializer(var, fx); - fx->shader_count += elements_count; - break; - case HLSL_CLASS_HULL_SHADER: case HLSL_CLASS_COMPUTE_SHADER: case HLSL_CLASS_DOMAIN_SHADER: - write_fx_5_shader_initializer(var, fx); + case HLSL_CLASS_GEOMETRY_SHADER: + write_fx_shader_initializer(var, fx); fx->shader_count += elements_count; break; @@ -3399,9 +3594,9 @@ static bool is_supported_object_variable(const struct hlsl_ctx *ctx, const struc case HLSL_CLASS_RASTERIZER_STATE: case HLSL_CLASS_RENDER_TARGET_VIEW: case HLSL_CLASS_SAMPLER: - case HLSL_CLASS_TEXTURE: case HLSL_CLASS_BLEND_STATE: case HLSL_CLASS_VERTEX_SHADER: + case HLSL_CLASS_GEOMETRY_SHADER: case HLSL_CLASS_STRING: return true; case HLSL_CLASS_COMPUTE_SHADER: @@ -3410,6 +3605,13 @@ static bool is_supported_object_variable(const struct hlsl_ctx *ctx, const struc if (ctx->profile->major_version < 5) return false; return true; + case HLSL_CLASS_TEXTURE: + if (ctx->profile->major_version >= 5) + return true; + if (type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER + || type->sampler_dim == HLSL_SAMPLER_DIM_RAW_BUFFER) + return false; + return true; case HLSL_CLASS_UAV: if (ctx->profile->major_version < 5) return false; @@ -3477,7 +3679,7 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) put_u32(&buffer, fx.rtv_count); put_u32(&buffer, fx.dsv_count); put_u32(&buffer, fx.shader_count); - put_u32(&buffer, 0); /* Inline shader count. */ + put_u32(&buffer, fx.inline_shader_count); set_u32(&buffer, size_offset, fx.unstructured.size); @@ -3493,10 +3695,8 @@ static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) ctx->result = fx.status; if (!ctx->result) - { - out->code = buffer.data; - out->size = buffer.size; - } + vkd3d_shader_code_from_bytecode_buffer(out, &buffer); + vkd3d_bytecode_buffer_cleanup(&buffer); return fx_write_context_cleanup(&fx); } @@ -3535,7 +3735,7 @@ static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) put_u32(&buffer, fx.rtv_count); put_u32(&buffer, fx.dsv_count); put_u32(&buffer, fx.shader_count); - put_u32(&buffer, 0); /* Inline shader count. */ + put_u32(&buffer, fx.inline_shader_count); put_u32(&buffer, fx.group_count); /* Group count. */ put_u32(&buffer, fx.uav_count); put_u32(&buffer, 0); /* Interface variables count. */ @@ -3556,10 +3756,8 @@ static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) ctx->result = fx.status; if (!ctx->result) - { - out->code = buffer.data; - out->size = buffer.size; - } + vkd3d_shader_code_from_bytecode_buffer(out, &buffer); + vkd3d_bytecode_buffer_cleanup(&buffer); return fx_write_context_cleanup(&fx); } @@ -5270,7 +5468,13 @@ static void fx_4_parse_fxlvm_expression(struct fx_parser *parser, uint32_t offse static void fx_4_parse_state_object_initializer(struct fx_parser *parser, uint32_t count, enum hlsl_type_class type_class) { + const struct rhs_named_value *named_value; + struct fx_5_shader shader = { 0 }; + const struct fx_state *state; + unsigned int shader_type = 0; + struct fx_state_table table; struct fx_assignment entry; + uint32_t i, j, comp_count; struct { uint32_t name; @@ -5285,6 +5489,7 @@ static void fx_4_parse_state_object_initializer(struct fx_parser *parser, uint32 float f; }; } value; + static const char *const value_types[FX_COMPONENT_TYPE_COUNT] = { [FX_BOOL] = "bool", @@ -5292,12 +5497,6 @@ static void fx_4_parse_state_object_initializer(struct fx_parser *parser, uint32 [FX_UINT] = "uint", [FX_UINT8] = "byte", }; - const struct rhs_named_value *named_value; - struct fx_5_shader shader = { 0 }; - struct fx_state_table table; - unsigned int shader_type = 0; - uint32_t i, j, comp_count; - struct fx_state *state; table = fx_get_state_table(type_class, parser->version.major, parser->version.minor); diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c index 4d7505d8740..96c64a0e4c4 100644 --- a/libs/vkd3d/libs/vkd3d-shader/glsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c @@ -38,7 +38,7 @@ struct glsl_src struct glsl_dst { - const struct vkd3d_shader_dst_param *vsir; + const struct vsir_dst_operand *vsir; struct vkd3d_string_buffer *register_name; struct vkd3d_string_buffer *mask; }; @@ -67,8 +67,8 @@ struct vkd3d_glsl_generator const struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info; }; -static void shader_glsl_print_subscript(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_src_param *rel_addr, unsigned int offset); +static void shader_glsl_print_subscript(struct vkd3d_string_buffer *buffer, + struct vkd3d_glsl_generator *gen, const struct vsir_src_operand *rel_addr, unsigned int offset); static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( struct vkd3d_glsl_generator *generator, @@ -389,7 +389,7 @@ static void shader_glsl_print_bitcast(struct vkd3d_string_buffer *dst, struct vk } static void shader_glsl_print_src(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_src_param *vsir_src, uint32_t mask, enum vsir_data_type data_type) + const struct vsir_src_operand *vsir_src, uint32_t mask, enum vsir_data_type data_type) { const struct vkd3d_shader_register *reg = &vsir_src->reg; struct vkd3d_string_buffer *register_name; @@ -418,7 +418,7 @@ static void shader_glsl_print_src(struct vkd3d_string_buffer *buffer, struct vkd } static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) + const struct vsir_src_operand *vsir_src, uint32_t mask) { glsl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); shader_glsl_print_src(glsl_src->str, gen, vsir_src, mask, vsir_src->reg.data_type); @@ -431,7 +431,7 @@ static void glsl_dst_cleanup(struct glsl_dst *dst, struct vkd3d_string_buffer_ca } static uint32_t glsl_dst_init(struct glsl_dst *glsl_dst, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_dst_param *vsir_dst) + const struct vkd3d_shader_instruction *ins, const struct vsir_dst_operand *vsir_dst) { uint32_t write_mask = vsir_dst->write_mask; @@ -452,8 +452,8 @@ static uint32_t glsl_dst_init(struct glsl_dst *glsl_dst, struct vkd3d_glsl_gener return write_mask; } -static void shader_glsl_print_subscript(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_src_param *rel_addr, unsigned int offset) +static void shader_glsl_print_subscript(struct vkd3d_string_buffer *buffer, + struct vkd3d_glsl_generator *gen, const struct vsir_src_operand *rel_addr, unsigned int offset) { struct glsl_src r; @@ -862,7 +862,7 @@ static void shader_glsl_ld(struct vkd3d_glsl_generator *gen, const struct vkd3d_ } static void shader_glsl_print_shadow_coord(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_src_param *coord, const struct vkd3d_shader_src_param *ref, unsigned int coord_size) + const struct vsir_src_operand *coord, const struct vsir_src_operand *ref, unsigned int coord_size) { uint32_t coord_mask = vkd3d_write_mask_from_component_count(coord_size); @@ -896,9 +896,9 @@ static void shader_glsl_sample(struct vkd3d_glsl_generator *gen, const struct vk { bool shadow_sampler, array, bias, dynamic_offset, gather, grad, lod, lod_zero, offset, shadow; const struct glsl_resource_type_info *resource_type_info; - const struct vkd3d_shader_src_param *resource, *sampler; unsigned int resource_id, resource_idx, resource_space; unsigned int sampler_id, sampler_idx, sampler_space; + const struct vsir_src_operand *resource, *sampler; const struct vkd3d_shader_descriptor_info1 *d; enum vkd3d_shader_resource_type resource_type; unsigned int component_idx, coord_size; @@ -2481,8 +2481,8 @@ int glsl_compile(struct vsir_program *program, uint64_t config_flags, return ret; VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6); - VKD3D_ASSERT(program->has_descriptor_info); - VKD3D_ASSERT(program->has_no_modifiers); + VKD3D_ASSERT(program->normalisation_flags.has_descriptor_info); + VKD3D_ASSERT(program->normalisation_flags.has_no_modifiers); vkd3d_glsl_generator_init(&generator, program, compile_info, combined_sampler_info, message_context); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c index 6bca2e1d1b2..c5c723be913 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c @@ -156,6 +156,8 @@ void hlsl_free_state_block(struct hlsl_state_block *state_block) void hlsl_free_default_value(struct hlsl_default_value *value) { vkd3d_free((void *)value->string); + if (value->shader) + hlsl_free_instr(&value->shader->node); } void hlsl_free_default_values(struct hlsl_ir_var *decl) @@ -459,6 +461,11 @@ static enum hlsl_regset type_get_regset(const struct hlsl_type *type) enum hlsl_regset hlsl_deref_get_regset(struct hlsl_ctx *ctx, const struct hlsl_deref *deref) { + if (deref->var->is_tgsm) + { + /* We should have already validated that TGSM variables are numeric. */ + return HLSL_REGSET_NUMERIC; + } return type_get_regset(hlsl_deref_get_type(ctx, deref)); } @@ -607,6 +614,7 @@ static struct hlsl_type *hlsl_new_simple_type(struct hlsl_ctx *ctx, const char * hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; return type; } @@ -632,6 +640,7 @@ static struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, e hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; return type; } @@ -1036,6 +1045,7 @@ struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *ba hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; return type; } @@ -1053,6 +1063,7 @@ struct hlsl_type *hlsl_new_stream_output_type(struct hlsl_ctx *ctx, hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; return type; } @@ -1071,6 +1082,7 @@ struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; return type; } @@ -1088,6 +1100,8 @@ struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_ type->sample_count = sample_count; hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; + return type; } @@ -1104,6 +1118,8 @@ struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim type->e.resource.rasteriser_ordered = rasteriser_ordered; hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; + return type; } @@ -1117,6 +1133,8 @@ struct hlsl_type *hlsl_new_cb_type(struct hlsl_ctx *ctx, struct hlsl_type *forma type->e.resource.format = format; hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; + return type; } @@ -1444,6 +1462,8 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); + type->type_id = ctx->type_count++; + return type; } @@ -2207,18 +2227,22 @@ struct hlsl_ir_node *hlsl_block_add_resource_load(struct hlsl_ctx *ctx, struct h return ctx->error_instr; } - if (load->sampling_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) + if (load->sampling_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER || load->resource.var->is_tgsm) hlsl_src_from_node(&load->byte_offset, hlsl_block_add_uint_constant(ctx, block, 0, loc)); return append_new_instr(ctx, block, &load->node); } -static struct hlsl_ir_node *hlsl_new_resource_store(struct hlsl_ctx *ctx, - enum hlsl_resource_store_type type, const struct hlsl_deref *resource, struct hlsl_ir_node *coords, +static struct hlsl_ir_node *hlsl_new_resource_store(struct hlsl_ctx *ctx, enum hlsl_resource_store_type type, + const struct hlsl_deref *resource, struct hlsl_ir_node *byte_offset, struct hlsl_ir_node *coords, struct hlsl_ir_node *value, uint32_t writemask, const struct vkd3d_shader_location *loc) { struct hlsl_ir_resource_store *store; + if (type != HLSL_RESOURCE_STORE + || hlsl_deref_get_type(ctx, resource)->sampler_dim != HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) + VKD3D_ASSERT(!byte_offset); + if (!(store = hlsl_alloc(ctx, sizeof(*store)))) return NULL; init_node(&store->node, HLSL_IR_RESOURCE_STORE, NULL, loc); @@ -2226,16 +2250,19 @@ static struct hlsl_ir_node *hlsl_new_resource_store(struct hlsl_ctx *ctx, store->writemask = writemask; hlsl_copy_deref(ctx, &store->resource, resource); + hlsl_src_from_node(&store->byte_offset, byte_offset); hlsl_src_from_node(&store->coords, coords); hlsl_src_from_node(&store->value, value); return &store->node; } struct hlsl_ir_node *hlsl_block_add_resource_store(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_resource_store_type type, const struct hlsl_deref *resource, struct hlsl_ir_node *coords, - struct hlsl_ir_node *value, uint32_t writemask, const struct vkd3d_shader_location *loc) + enum hlsl_resource_store_type type, const struct hlsl_deref *resource, + struct hlsl_ir_node *byte_offset, struct hlsl_ir_node *coords, struct hlsl_ir_node *value, + uint32_t writemask, const struct vkd3d_shader_location *loc) { - return append_new_instr(ctx, block, hlsl_new_resource_store(ctx, type, resource, coords, value, writemask, loc)); + return append_new_instr(ctx, block, hlsl_new_resource_store(ctx, type, + resource, byte_offset, coords, value, writemask, loc)); } struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned int component_count, @@ -2289,61 +2316,91 @@ struct hlsl_ir_node *hlsl_new_matrix_swizzle(struct hlsl_ctx *ctx, struct hlsl_m return &swizzle->node; } -struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, - const char *profile_name, struct hlsl_ir_node **args, unsigned int args_count, - struct hlsl_block *args_instrs, const struct vkd3d_shader_location *loc) +static struct hlsl_ir_compile *new_compile(struct hlsl_ctx *ctx, const struct hlsl_profile_info *profile, + struct hlsl_ir_function_decl *decl, struct hlsl_block *initializer, struct hlsl_type *type, + uint32_t stream, size_t count, const char *output_decls[4], const struct vkd3d_shader_location *loc) { - const struct hlsl_profile_info *profile_info = NULL; struct hlsl_ir_compile *compile; - struct hlsl_type *type = NULL; - unsigned int i; - switch (compile_type) + if (!(compile = hlsl_alloc(ctx, sizeof(*compile)))) + return NULL; + + init_node(&compile->node, HLSL_IR_COMPILE, type, loc); + hlsl_block_init(&compile->initializers); + hlsl_block_add_block(&compile->initializers, initializer); + + compile->profile = profile; + compile->decl = decl; + compile->output.stream = stream; + compile->output.count = count; + + for (size_t i = 0; i < count; ++i) { - 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 (output_decls[i]) + compile->output.decls[i] = hlsl_strdup(ctx, output_decls[i]); + } - 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); + return compile; +} - if (!type) - { - hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile_name); - return NULL; - } +struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const struct hlsl_profile_info *profile, + struct hlsl_ir_function_decl *decl, struct hlsl_block *initializer, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_compile *compile; + struct hlsl_type *type = NULL; + + switch (profile->type) + { + case VKD3D_SHADER_TYPE_PIXEL: + type = hlsl_get_type(ctx->cur_scope, "PixelShader", true, true); + break; + case VKD3D_SHADER_TYPE_VERTEX: + type = hlsl_get_type(ctx->cur_scope, "VertexShader", true, true); break; - case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: + case VKD3D_SHADER_TYPE_GEOMETRY: type = hlsl_get_type(ctx->cur_scope, "GeometryShader", true, true); break; + + default: + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile->name); + return NULL; } - if (!(compile = hlsl_alloc(ctx, sizeof(*compile)))) + if (!(compile = new_compile(ctx, profile, decl, initializer, type, 0, 0, NULL, loc))) return NULL; - init_node(&compile->node, HLSL_IR_COMPILE, type, loc); + return &compile->node; +} + +struct hlsl_ir_node *hlsl_new_compile_with_so(struct hlsl_ctx *ctx, struct hlsl_ir_compile *shader, + uint32_t stream, size_t count, const char *output_decls[4], const struct vkd3d_shader_location *loc) +{ + struct hlsl_type *type = hlsl_get_type(ctx->cur_scope, "GeometryShader", true, true); + const struct hlsl_profile_info *profile = NULL; + struct hlsl_ir_function_decl *decl = NULL; + struct hlsl_ir_compile *compile; + struct hlsl_block initializers; - compile->compile_type = compile_type; - compile->profile = profile_info; + hlsl_block_init(&initializers); - hlsl_block_init(&compile->instrs); - hlsl_block_add_block(&compile->instrs, args_instrs); + /* non-fx profiles allow ConstructGSWithSO() but do not use nor type-check + * its arguments, so passing in NULL for "shader" creates a dummy geometry + * shader without any decl or profile. */ + if (shader) + { + decl = shader->decl; + profile = shader->profile; + if (!(hlsl_clone_block(ctx, &initializers, &shader->initializers))) + return NULL; + } - compile->args_count = args_count; - if (!(compile->args = hlsl_alloc(ctx, sizeof(*compile->args) * args_count))) + if (!(compile = new_compile(ctx, profile, decl, &initializers, type, stream, count, output_decls, loc))) { - vkd3d_free(compile); + hlsl_block_cleanup(&initializers); return NULL; } - for (i = 0; i < compile->args_count; ++i) - hlsl_src_from_node(&compile->args[i], args[i]); return &compile->node; } @@ -2475,13 +2532,13 @@ bool hlsl_index_is_resource_access(struct hlsl_ir_index *index) return type->class == HLSL_CLASS_TEXTURE || type->class == HLSL_CLASS_UAV; } -bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index) +struct hlsl_ir_index *hlsl_index_chain_find_resource_access(struct hlsl_ir_index *index) { if (hlsl_index_is_resource_access(index)) - return true; + return index; if (index->val.node->type == HLSL_IR_INDEX) - return hlsl_index_chain_has_resource_access(hlsl_ir_index(index->val.node)); - return false; + return hlsl_index_chain_find_resource_access(hlsl_ir_index(index->val.node)); + return NULL; } bool hlsl_index_chain_has_tgsm_access(struct hlsl_ir_index *index) @@ -2546,7 +2603,7 @@ void hlsl_block_add_jump(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hl static struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, struct hlsl_block *iter, struct hlsl_block *block, enum hlsl_loop_unroll_type unroll_type, - unsigned int unroll_limit, const struct vkd3d_shader_location *loc) + struct hlsl_ir_node *unroll_limit, const struct vkd3d_shader_location *loc) { struct hlsl_ir_loop *loop; @@ -2561,13 +2618,13 @@ static struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, struct hlsl_bloc hlsl_block_add_block(&loop->iter, iter); loop->unroll_type = unroll_type; - loop->unroll_limit = unroll_limit; + hlsl_src_from_node(&loop->unroll_limit, unroll_limit); return &loop->node; } void hlsl_block_add_loop(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_block *iter, struct hlsl_block *body, enum hlsl_loop_unroll_type unroll_type, - unsigned int unroll_limit, const struct vkd3d_shader_location *loc) + struct hlsl_ir_node *unroll_limit, const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *instr = hlsl_new_loop(ctx, iter, body, unroll_type, unroll_limit, loc); @@ -2728,8 +2785,8 @@ static struct hlsl_ir_node *clone_load(struct hlsl_ctx *ctx, struct clone_instr_ static struct hlsl_ir_node *clone_loop(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_loop *src) { + struct hlsl_ir_node *dst, *unroll_limit; struct hlsl_block iter, body; - struct hlsl_ir_node *dst; if (!clone_block(ctx, &iter, &src->iter, map)) return NULL; @@ -2740,7 +2797,8 @@ static struct hlsl_ir_node *clone_loop(struct hlsl_ctx *ctx, struct clone_instr_ return NULL; } - if (!(dst = hlsl_new_loop(ctx, &iter, &body, src->unroll_type, src->unroll_limit, &src->node.loc))) + unroll_limit = map_instr(map, src->unroll_limit.node); + if (!(dst = hlsl_new_loop(ctx, &iter, &body, src->unroll_type, unroll_limit, &src->node.loc))) { hlsl_block_cleanup(&iter); hlsl_block_cleanup(&body); @@ -2798,6 +2856,7 @@ static struct hlsl_ir_node *clone_resource_store(struct hlsl_ctx *ctx, } clone_src(map, &dst->coords, &src->coords); clone_src(map, &dst->value, &src->value); + clone_src(map, &dst->byte_offset, &src->byte_offset); return &dst->node; } @@ -2878,43 +2937,17 @@ static struct hlsl_ir_node *clone_sync(struct hlsl_ctx *ctx, struct hlsl_ir_sync return &dst->node; } - static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx, struct clone_instr_map *map, struct hlsl_ir_compile *compile) { - const char *profile_name = NULL; - struct hlsl_ir_node **args; - struct hlsl_ir_node *node; - struct hlsl_block block; - unsigned int i; + struct hlsl_block initializers; - if (!(clone_block(ctx, &block, &compile->instrs, map))) - return NULL; - - if (!(args = hlsl_alloc(ctx, sizeof(*args) * compile->args_count))) - { - hlsl_block_cleanup(&block); - return NULL; - } - for (i = 0; i < compile->args_count; ++i) - { - args[i] = map_instr(map, compile->args[i].node); - VKD3D_ASSERT(args[i]); - } - - if (compile->profile) - profile_name = compile->profile->name; - - if (!(node = hlsl_new_compile(ctx, compile->compile_type, profile_name, - args, compile->args_count, &block, &compile->node.loc))) - { - hlsl_block_cleanup(&block); - vkd3d_free(args); - return NULL; - } + hlsl_clone_block(ctx, &initializers, &compile->initializers); + compile = new_compile(ctx, compile->profile, compile->decl, &initializers, compile->node.data_type, + compile->output.stream, compile->output.count, compile->output.decls, &compile->node.loc); + hlsl_block_cleanup(&initializers); - vkd3d_free(args); - return node; + return compile ? &compile->node : NULL; } static struct hlsl_ir_node *clone_sampler_state(struct hlsl_ctx *ctx, @@ -3119,7 +3152,7 @@ struct hlsl_ir_node *hlsl_clone_instr(struct hlsl_ctx *ctx, const struct hlsl_ir return ret; } -struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, +struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, uint32_t storage_modifiers, struct hlsl_type *return_type, const struct hlsl_func_parameters *parameters, const struct hlsl_semantic *semantic, const struct vkd3d_shader_location *loc) { @@ -3129,6 +3162,7 @@ struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, if (!(decl = hlsl_alloc(ctx, sizeof(*decl)))) return NULL; hlsl_block_init(&decl->body); + decl->storage_modifiers = storage_modifiers; decl->return_type = return_type; decl->parameters = *parameters; decl->loc = *loc; @@ -3978,6 +4012,11 @@ static void dump_ir_resource_store(struct hlsl_ctx *ctx, vkd3d_string_buffer_printf(buffer, ", value = "); dump_src(buffer, &store->value); } + if (store->byte_offset.node) + { + vkd3d_string_buffer_printf(buffer, ", byte_offset = "); + dump_src(buffer, &store->byte_offset); + } vkd3d_string_buffer_printf(buffer, ")"); } @@ -4069,26 +4108,24 @@ static void dump_ir_sync(struct vkd3d_string_buffer *buffer, const struct hlsl_i static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_compile *compile) { - unsigned int i; + vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name); - switch (compile->compile_type) - { - case HLSL_COMPILE_TYPE_COMPILE: - vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name); - break; + dump_block(ctx, buffer, &compile->initializers); - case HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO: - vkd3d_string_buffer_printf(buffer, "ConstructGSWithSO {\n"); - break; - } + vkd3d_string_buffer_printf(buffer, " %10s }", ""); - dump_block(ctx, buffer, &compile->instrs); + if (!compile->output.count) + return; - vkd3d_string_buffer_printf(buffer, " %10s } (", ""); - for (i = 0; i < compile->args_count; ++i) + vkd3d_string_buffer_printf(buffer, "("); + for (size_t i = 0; i < compile->output.count; ++i) { - dump_src(buffer, &compile->args[i]); - if (i + 1 < compile->args_count) + const char *output = compile->output.decls[i]; + + if (!output) + output = "NULL"; + vkd3d_string_buffer_printf(buffer, "%s", output); + if (i + 1 < compile->output.count) vkd3d_string_buffer_printf(buffer, ", "); } vkd3d_string_buffer_printf(buffer, ")"); @@ -4379,6 +4416,7 @@ static void free_ir_loop(struct hlsl_ir_loop *loop) { hlsl_block_cleanup(&loop->body); hlsl_block_cleanup(&loop->iter); + hlsl_src_remove(&loop->unroll_limit); vkd3d_free(loop); } @@ -4406,6 +4444,7 @@ static void free_ir_string_constant(struct hlsl_ir_string_constant *string) static void free_ir_resource_store(struct hlsl_ir_resource_store *store) { hlsl_cleanup_deref(&store->resource); + hlsl_src_remove(&store->byte_offset); hlsl_src_remove(&store->coords); hlsl_src_remove(&store->value); vkd3d_free(store); @@ -4455,12 +4494,11 @@ static void free_ir_sync(struct hlsl_ir_sync *sync) static void free_ir_compile(struct hlsl_ir_compile *compile) { - unsigned int i; - - for (i = 0; i < compile->args_count; ++i) - hlsl_src_remove(&compile->args[i]); - - hlsl_block_cleanup(&compile->instrs); + hlsl_block_cleanup(&compile->initializers); + for (size_t i = 0; i < compile->output.count; ++i) + { + vkd3d_free((void *)compile->output.decls[i]); + } vkd3d_free(compile); } @@ -4602,7 +4640,7 @@ static void free_function_decl(struct hlsl_ir_function_decl *decl) hlsl_free_attribute((void *)decl->attrs[i]); vkd3d_free((void *)decl->attrs); - vkd3d_free(decl->parameters.vars); + hlsl_func_parameters_cleanup(&decl->parameters); hlsl_block_cleanup(&decl->body); vkd3d_free(decl); } @@ -5296,6 +5334,8 @@ int hlsl_parse(const struct vkd3d_shader_compile_info *compile_info, if (!vsir_program_init(program, compile_info, &version, 0, VSIR_CF_STRUCTURED, normalisation_level)) return VKD3D_ERROR_OUT_OF_MEMORY; + program->f32_denorm_mode = VSIR_DENORM_FLUSH_TO_ZERO; + if ((ret = hlsl_ctx_parse(&ctx, &program->source_files, compile_info, profile, message_context)) < 0) { vsir_program_cleanup(program); @@ -5309,6 +5349,8 @@ int hlsl_parse(const struct vkd3d_shader_compile_info *compile_info, { if (!decl->has_body) continue; + if (decl->storage_modifiers & HLSL_STORAGE_STATIC) + continue; if (entry_func) { /* Depending on d3dcompiler version, either the first or last is @@ -5330,7 +5372,7 @@ int hlsl_parse(const struct vkd3d_shader_compile_info *compile_info, return VKD3D_ERROR_INVALID_SHADER; } - ret = hlsl_emit_vsir(&ctx, compile_info, entry_func, program, reflection_data); + ret = hlsl_emit_vsir(&ctx, compile_info, entry_func, NULL, program, reflection_data); hlsl_ctx_cleanup(&ctx); if (ret < 0) vsir_program_cleanup(program); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h index e12915f9fe6..87147985129 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h @@ -230,11 +230,9 @@ struct hlsl_type * If type is HLSL_CLASS_STRUCT or HLSL_CLASS_ARRAY, the reg_size of their elements and padding * (which varies according to the backend) is also included. */ unsigned int reg_size[HLSL_REGSET_LAST + 1]; - /* Offset where the type's description starts in the output bytecode, in bytes. */ - size_t bytecode_offset; - /* Offset where the type's packed description starts in the output bytecode, in bytes. */ - size_t packed_bytecode_offset; + /* ID used for indexing auxiliary data. */ + size_t type_id; bool is_typedef; @@ -425,7 +423,7 @@ struct hlsl_attribute #define HLSL_STORAGE_NOPERSPECTIVE 0x00008000 #define HLSL_STORAGE_LINEAR 0x00010000 #define HLSL_MODIFIER_SINGLE 0x00020000 -#define HLSL_MODIFIER_EXPORT 0x00040000 +#define HLSL_STORAGE_EXPORT 0x00040000 #define HLSL_STORAGE_ANNOTATION 0x00080000 #define HLSL_MODIFIER_UNORM 0x00100000 #define HLSL_MODIFIER_SNORM 0x00200000 @@ -501,6 +499,8 @@ struct hlsl_ir_var const char *string; /* Default value, in case the component is a numeric value. */ union hlsl_constant_value_component number; + /* Default value, in case the component is a shader. otherwise it is NULL. */ + struct hlsl_ir_compile *shader; } *default_values; /* Pointer to the temp copy of the variable, in case it is uniform. */ @@ -614,6 +614,11 @@ struct hlsl_func_parameters size_t count, capacity; }; +static inline void hlsl_func_parameters_cleanup(struct hlsl_func_parameters *p) +{ + vkd3d_free(p->vars); +} + struct hlsl_ir_function { /* Item entry in hlsl_ctx.functions */ @@ -635,6 +640,9 @@ struct hlsl_ir_function_decl /* Item entry in hlsl_ir_function.overloads. */ struct list entry; + /* Storage modifiers (HLSL_STORAGE_*). */ + uint32_t storage_modifiers; + /* Function to which this declaration corresponds. */ struct hlsl_ir_function *func; @@ -699,7 +707,7 @@ struct hlsl_ir_loop struct hlsl_block body; enum hlsl_loop_type type; unsigned int next_index; /* liveness index of the end of the loop */ - unsigned int unroll_limit; + struct hlsl_src unroll_limit; enum hlsl_loop_unroll_type unroll_type; }; @@ -928,7 +936,7 @@ struct hlsl_ir_resource_store struct hlsl_ir_node node; enum hlsl_resource_store_type store_type; struct hlsl_deref resource; - struct hlsl_src coords, value; + struct hlsl_src byte_offset, coords, value; uint8_t writemask; }; @@ -957,33 +965,28 @@ struct hlsl_ir_string_constant char *string; }; -/* Represents shader compilation call for effects, such as "CompileShader()". - * - * Unlike hlsl_ir_call, it is not flattened, thus, it keeps track of its - * arguments and maintains its own instruction block. */ +#define HLSL_STREAM_OUTPUT_MAX 4 + +/* Represents shader compilation call for effects, such as "CompileShader()". */ struct hlsl_ir_compile { struct hlsl_ir_node node; - enum hlsl_compile_type - { - /* A shader compilation through the CompileShader() function or the "compile" syntax. */ - HLSL_COMPILE_TYPE_COMPILE, - /* A call to ConstructGSWithSO(), which receives a geometry shader and retrieves one as well. */ - HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO, - } compile_type; - - /* Special field to store the profile argument for HLSL_COMPILE_TYPE_COMPILE. */ + /* Special field to store the profile argument. */ const struct hlsl_profile_info *profile; + struct hlsl_ir_function_decl *decl; - /* Block containing the instructions required by the arguments of the + /* Block containing the static initializers passed as arguments of the * compilation call. */ - struct hlsl_block instrs; + struct hlsl_block initializers; - /* 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; + /* Stream Output constants, filled by a ConstructGSWithSO() call. */ + struct + { + uint32_t stream; + unsigned count; + const char *decls[HLSL_STREAM_OUTPUT_MAX]; + } output; }; /* Represents a state block initialized with the "sampler_state" keyword. */ @@ -1155,6 +1158,7 @@ struct hlsl_ctx /* List containing all created hlsl_types, except builtin_types; linked by the hlsl_type.entry * fields. */ struct list types; + size_t type_count; /* Tree map for the declared functions, using hlsl_ir_function.name as key. * The functions are attached through the hlsl_ir_function.entry fields. */ struct rb_tree functions; @@ -1609,12 +1613,13 @@ struct hlsl_ir_node *hlsl_block_add_load_index(struct hlsl_ctx *ctx, struct hlsl const struct hlsl_deref *deref, struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); void hlsl_block_add_loop(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_block *iter, struct hlsl_block *body, enum hlsl_loop_unroll_type unroll_type, - unsigned int unroll_limit, const struct vkd3d_shader_location *loc); + struct hlsl_ir_node *unroll_limit, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_block_add_resource_load(struct hlsl_ctx *ctx, struct hlsl_block *block, const struct hlsl_resource_load_params *params, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_block_add_resource_store(struct hlsl_ctx *ctx, struct hlsl_block *block, - enum hlsl_resource_store_type type, const struct hlsl_deref *resource, struct hlsl_ir_node *coords, - struct hlsl_ir_node *value, uint32_t writemask, const struct vkd3d_shader_location *loc); + enum hlsl_resource_store_type type, const struct hlsl_deref *resource, + struct hlsl_ir_node *byte_offset, struct hlsl_ir_node *coords, struct hlsl_ir_node *value, + uint32_t writemask, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_block_add_simple_load(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *var, const struct vkd3d_shader_location *loc); void hlsl_block_add_simple_store(struct hlsl_ctx *ctx, struct hlsl_block *block, @@ -1657,8 +1662,8 @@ void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *body); void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body); int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out); int hlsl_emit_vsir(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info *compile_info, - struct hlsl_ir_function_decl *entry_func, struct vsir_program *program, - struct vkd3d_shader_code *reflection_data); + struct hlsl_ir_function_decl *entry_func, const struct hlsl_block *initializers, + struct vsir_program *program, struct vkd3d_shader_code *reflection_data); bool hlsl_init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_var *var, unsigned int path_len); bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_node *chain); @@ -1712,7 +1717,7 @@ struct hlsl_ir_node *hlsl_new_cast(struct hlsl_ctx *ctx, struct hlsl_ir_node *no struct hlsl_ir_node *hlsl_new_constant(struct hlsl_ctx *ctx, struct hlsl_type *type, const struct hlsl_constant_value *value, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_copy(struct hlsl_ctx *ctx, struct hlsl_ir_node *node); -struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, +struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx, uint32_t storage_modifiers, struct hlsl_type *return_type, const struct hlsl_func_parameters *parameters, const struct hlsl_semantic *semantic, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condition, struct hlsl_block *then_block, @@ -1742,12 +1747,13 @@ struct hlsl_ir_node *hlsl_new_store_index(struct hlsl_ctx *ctx, const struct hls 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_index *hlsl_index_chain_find_resource_access(struct hlsl_ir_index *index); bool hlsl_index_chain_has_tgsm_access(struct hlsl_ir_index *index); -struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, enum hlsl_compile_type compile_type, - const char *profile_name, struct hlsl_ir_node **args, unsigned int args_count, - struct hlsl_block *args_instrs, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const struct hlsl_profile_info *profile, + struct hlsl_ir_function_decl *decl, struct hlsl_block *initializer, const struct vkd3d_shader_location *loc); +struct hlsl_ir_node *hlsl_new_compile_with_so(struct hlsl_ctx *ctx, struct hlsl_ir_compile *shader, + uint32_t stream, size_t count, const char *output_decls[4], const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_interlocked(struct hlsl_ctx *ctx, enum hlsl_interlocked_op op, struct hlsl_type *type, const struct hlsl_deref *dst, struct hlsl_ir_node *coords, struct hlsl_ir_node *cmp_value, struct hlsl_ir_node *value, const struct vkd3d_shader_location *loc); @@ -1845,6 +1851,10 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref unsigned int hlsl_offset_from_deref_safe(struct hlsl_ctx *ctx, const struct hlsl_deref *deref); struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref); +struct hlsl_ir_node *hlsl_block_add_packed_index_offset_append(struct hlsl_ctx *ctx, + struct hlsl_block *block, struct hlsl_ir_node *prev_offset, struct hlsl_ir_node *idx, + struct hlsl_type *type, const struct vkd3d_shader_location *loc); + bool hlsl_copy_propagation_execute(struct hlsl_ctx *ctx, struct hlsl_block *block); struct hlsl_ir_node *hlsl_fold_binary_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block); struct hlsl_ir_node *hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.l b/libs/vkd3d/libs/vkd3d-shader/hlsl.l index c41d807cca1..24d08b314a4 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.l +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.l @@ -216,15 +216,15 @@ while {return KW_WHILE; } {IDENTIFIER} { struct hlsl_ctx *ctx = yyget_extra(yyscanner); - yylval->name = hlsl_strdup(ctx, yytext); if (hlsl_version_ge(ctx, 5, 1) && !strcmp(yytext, "ConstantBuffer")) return KW_CONSTANTBUFFER; - else if (hlsl_get_var(ctx->cur_scope, yytext) || hlsl_get_function(ctx, yytext)) + + yylval->name = hlsl_strdup(ctx, yytext); + if (hlsl_get_var(ctx->cur_scope, yytext) || hlsl_get_function(ctx, yytext)) return VAR_IDENTIFIER; - else if (hlsl_get_type(ctx->cur_scope, yytext, true, true)) + if (hlsl_get_type(ctx->cur_scope, yytext, true, true)) return TYPE_IDENTIFIER; - else - return NEW_IDENTIFIER; + return NEW_IDENTIFIER; } {STRING} { diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y index e349029521a..e74b9a6c4de 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -544,16 +544,9 @@ static void check_loop_attributes(struct hlsl_ctx *ctx, const struct parse_attri hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Unroll attribute can't be used with 'fastopt' attribute."); } -static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx, - struct hlsl_block *block, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) +static bool is_static_expression(const struct hlsl_block *block) { - struct hlsl_default_value ret = {0}; struct hlsl_ir_node *node; - struct hlsl_block expr; - struct hlsl_src src; - - if (node_from_block(block)->data_type->class == HLSL_CLASS_ERROR) - return ret; LIST_FOR_EACH_ENTRY(node, &block->instrs, struct hlsl_ir_node, entry) { @@ -582,12 +575,28 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx case HLSL_IR_SWITCH: case HLSL_IR_STATEBLOCK_CONSTANT: case HLSL_IR_SYNC: - hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, - "Expected literal expression."); - break; + return false; } } + return true; +} + +static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx, + struct hlsl_block *block, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) +{ + struct hlsl_default_value ret = {0}; + struct hlsl_ir_node *node; + struct hlsl_block expr; + struct hlsl_src src; + + if (node_from_block(block)->data_type->class == HLSL_CLASS_ERROR) + return ret; + + if (!is_static_expression(block)) + hlsl_error(ctx, &node_from_block(block)->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, + "Expected literal expression."); + if (!hlsl_clone_block(ctx, &expr, &ctx->static_initializers)) return ret; hlsl_block_add_block(&expr, block); @@ -614,6 +623,11 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx if (!(ret.string = vkd3d_strdup(string->string))) return ret; } + else if (node->type == HLSL_IR_COMPILE) + { + list_remove(&node->entry); + ret.shader = hlsl_ir_compile(node); + } else { hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, @@ -640,12 +654,12 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum hlsl_loop_type struct hlsl_block *iter, struct hlsl_block *body, const struct vkd3d_shader_location *loc) { enum hlsl_loop_unroll_type unroll_type = HLSL_LOOP_UNROLL; - unsigned int i, unroll_limit = 0; + struct hlsl_ir_node *unroll_limit = NULL; + unsigned int i; check_attribute_list_for_duplicates(ctx, attributes); check_loop_attributes(ctx, attributes, loc); - /* Ignore unroll(0) attribute, and any invalid attribute. */ for (i = 0; i < attributes->count; ++i) { const struct hlsl_attribute *attr = attributes->attrs[i]; @@ -661,12 +675,24 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum hlsl_loop_type if (attr->args_count == 1) { struct hlsl_block expr; + + if (!is_static_expression(&attr->instrs)) + { + hlsl_error(ctx, &attr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, + "Unroll limit expressions cannot have side effects."); + continue; + } + + if (!init && !(init = make_empty_block(ctx))) + return NULL; + hlsl_block_init(&expr); if (!hlsl_clone_block(ctx, &expr, &attr->instrs)) return NULL; - unroll_limit = evaluate_static_expression_as_uint(ctx, &expr, loc); - hlsl_block_cleanup(&expr); + list_move_head(&init->instrs, &expr.instrs); + unroll_limit = add_implicit_conversion(ctx, init, node_from_block(&expr), + hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc); } unroll_type = HLSL_LOOP_FORCE_UNROLL; @@ -734,7 +760,13 @@ static void cleanup_parse_attribute_list(struct parse_attribute_list *attr_list) vkd3d_free(attr_list->attrs); } -static void free_parse_initializer(struct parse_initializer *initializer) +static void parse_function_cleanup(struct parse_function *f) +{ + hlsl_func_parameters_cleanup(&f->parameters); + hlsl_cleanup_semantic(&f->return_semantic); +} + +static void cleanup_parse_initializer(struct parse_initializer *initializer) { destroy_block(initializer->instrs); vkd3d_free(initializer->args); @@ -990,7 +1022,7 @@ static struct hlsl_type *apply_type_modifiers(struct hlsl_ctx *ctx, struct hlsl_ static void free_parse_variable_def(struct parse_variable_def *v) { - free_parse_initializer(&v->initializer); + cleanup_parse_initializer(&v->initializer); vkd3d_free(v->arrays.sizes); vkd3d_free(v->name); hlsl_cleanup_semantic(&v->semantic); @@ -1082,7 +1114,7 @@ static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields, if (v->initializer.args_count) { hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Illegal initializer on a struct field."); - free_parse_initializer(&v->initializer); + cleanup_parse_initializer(&v->initializer); } if (v->reg_reservation.offset_type) hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, @@ -1185,7 +1217,7 @@ static bool add_typedef(struct hlsl_ctx *ctx, struct hlsl_type *const orig_type, if (!ret) hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED, "Type '%s' is already defined.", v->name); - free_parse_initializer(&v->initializer); + cleanup_parse_initializer(&v->initializer); vkd3d_free(v); } vkd3d_free(list); @@ -1271,7 +1303,7 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters &store_index, param->initializer.args[i], true); } - free_parse_initializer(¶m->initializer); + cleanup_parse_initializer(¶m->initializer); } hlsl_add_var(ctx, var); @@ -1968,11 +2000,172 @@ static bool invert_swizzle_matrix(const struct hlsl_matrix_swizzle *swizzle, return true; } +static bool add_resource_store(struct hlsl_ctx *ctx, struct hlsl_block *block, + struct hlsl_ir_index *lhs, struct hlsl_ir_index *resource_access, + struct hlsl_ir_node *rhs, unsigned int width, uint32_t writemask, bool matrix_writemask) +{ + struct hlsl_ir_node *coords = resource_access->idx.node; + struct hlsl_type *resource_type, *resource_format; + struct vkd3d_shader_location loc = lhs->node.loc; + unsigned int dim_count, expected_width; + struct hlsl_deref resource_deref; + + if (!hlsl_init_deref_from_index_chain(ctx, &resource_deref, resource_access->val.node)) + return false; + + resource_type = hlsl_deref_get_type(ctx, &resource_deref); + resource_format = resource_type->e.resource.format; + expected_width = resource_format->e.numeric.dimx * resource_format->e.numeric.dimy; + VKD3D_ASSERT(resource_type->class == HLSL_CLASS_TEXTURE || resource_type->class == HLSL_CLASS_UAV); + + if (resource_type->class != HLSL_CLASS_UAV) + hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Read-only resources cannot be stored to."); + + dim_count = hlsl_sampler_dim_count(resource_type->sampler_dim); + + VKD3D_ASSERT(coords->data_type->class == HLSL_CLASS_VECTOR); + VKD3D_ASSERT(coords->data_type->e.numeric.type == HLSL_TYPE_UINT); + VKD3D_ASSERT(coords->data_type->e.numeric.dimx == dim_count); + + if (resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) + { + struct hlsl_ir_node *field_offset = hlsl_block_add_uint_constant(ctx, block, 0, &loc); + struct hlsl_type *val_type = lhs->node.data_type; + struct hlsl_ir_index *ptr = lhs, *prev = NULL; + + if (rhs->data_type->class > HLSL_CLASS_LAST_NUMERIC) + { + hlsl_fixme(ctx, &loc, "Composite type structured buffer stores."); + return false; + } + + while (ptr != resource_access) + { + struct hlsl_ir_index *next = hlsl_ir_index(ptr->val.node); + struct hlsl_type *type = ptr->val.node->data_type; + + if (hlsl_index_is_noncontiguous(next)) + { + type = next->val.node->data_type; + } + else if (hlsl_index_is_noncontiguous(ptr)) + { + if (prev) + { + type = prev->val.node->data_type; + } + else + { + val_type = ptr->val.node->data_type; + type = ptr->node.data_type; + } + } + + field_offset = hlsl_block_add_packed_index_offset_append(ctx, + block, field_offset, ptr->idx.node, type, &loc); + + prev = ptr; + ptr = next; + } + + if (matrix_writemask || rhs->data_type->class == HLSL_CLASS_MATRIX) + { + /* Type of the minor inner vector. column type for row major, + * row type for column major. */ + struct hlsl_type *minor_type = hlsl_get_vector_type(ctx, + val_type->e.numeric.type, hlsl_type_minor_size(val_type)); + struct hlsl_block writes; + bool written = false; + + hlsl_block_init(&writes); + + for (unsigned int i = 0, k = 0; i < val_type->e.numeric.dimy; ++i) + { + bool row_major = hlsl_type_is_row_major(val_type); + struct hlsl_ir_node *mtx_offset; + struct hlsl_ir_node *row_c; + + row_c = hlsl_block_add_uint_constant(ctx, &writes, i, &loc); + mtx_offset = hlsl_block_add_packed_index_offset_append(ctx, &writes, + field_offset, row_c, row_major ? val_type : minor_type, &loc); + + for (unsigned int j = 0; j < val_type->e.numeric.dimx; ++j) + { + struct hlsl_ir_node *column_c, *load, *col_offset; + + if (matrix_writemask) + { + unsigned int idx = i * 4 + j; + + if (!(writemask & (1u << idx))) + continue; + } + + written = true; + column_c = hlsl_block_add_uint_constant(ctx, &writes, j, &loc); + col_offset = hlsl_block_add_packed_index_offset_append(ctx, &writes, + mtx_offset, column_c, row_major ? minor_type : val_type, &loc); + load = hlsl_add_load_component(ctx, &writes, rhs, k++, &loc); + hlsl_block_add_resource_store(ctx, &writes, HLSL_RESOURCE_STORE, + &resource_deref, col_offset, coords, load, VKD3DSP_WRITEMASK_0, &loc); + } + } + + if (written) + hlsl_block_add_block(block, &writes); + hlsl_block_cleanup(&writes); + } + else + { + unsigned int size = val_type->e.numeric.dimx; + + for (unsigned int i = 0, k = 0; i < size; ++i) + { + struct hlsl_ir_node *c, *load, *offset; + + if (!(writemask & (1u << i))) + continue; + + if (val_type->class == HLSL_CLASS_SCALAR) + { + VKD3D_ASSERT(i == 0); + VKD3D_ASSERT(size == 1); + + offset = field_offset; + } + else + { + c = hlsl_block_add_uint_constant(ctx, block, i, &loc); + offset = hlsl_block_add_packed_index_offset_append(ctx, block, field_offset, c, val_type, &loc); + } + + load = hlsl_add_load_component(ctx, block, rhs, k++, &loc); + hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STORE, + &resource_deref, offset, coords, load, VKD3DSP_WRITEMASK_0, &loc); + } + } + } + else + { + if (width != expected_width) + hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_WRITEMASK, + "Resource store expressions must write to all components."); + + hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STORE, + &resource_deref, NULL, coords, rhs, writemask, &loc); + } + + hlsl_cleanup_deref(&resource_deref); + + return true; +} + static bool add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *lhs, enum parse_assign_op assign_op, struct hlsl_ir_node *rhs, bool is_function_out_arg) { struct hlsl_type *lhs_type = lhs->data_type; unsigned int writemask = 0, width = 0; + struct hlsl_ir_index *resource_access; bool matrix_writemask = false; bool first_cast = true; @@ -2081,42 +2274,11 @@ static bool add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struc * stored to. This is corrected. */ rhs = add_cast(ctx, block, rhs, lhs_type, &rhs->loc); - if (lhs->type == HLSL_IR_INDEX && hlsl_index_chain_has_resource_access(hlsl_ir_index(lhs))) + if (lhs->type == HLSL_IR_INDEX && (resource_access = hlsl_index_chain_find_resource_access(hlsl_ir_index(lhs)))) { - struct hlsl_ir_node *coords = hlsl_ir_index(lhs)->idx.node; - struct hlsl_deref resource_deref; - struct hlsl_type *resource_type; - unsigned int dim_count; - - if (!hlsl_index_is_resource_access(hlsl_ir_index(lhs))) - { - hlsl_fixme(ctx, &lhs->loc, "Non-direct structured resource store."); - return false; - } - - if (!hlsl_init_deref_from_index_chain(ctx, &resource_deref, hlsl_ir_index(lhs)->val.node)) + if (!add_resource_store(ctx, block, hlsl_ir_index(lhs), + resource_access, rhs, width, writemask, matrix_writemask)) return false; - - resource_type = hlsl_deref_get_type(ctx, &resource_deref); - VKD3D_ASSERT(resource_type->class == HLSL_CLASS_TEXTURE || resource_type->class == HLSL_CLASS_UAV); - - if (resource_type->class != HLSL_CLASS_UAV) - hlsl_error(ctx, &lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "Read-only resources cannot be stored to."); - - dim_count = hlsl_sampler_dim_count(resource_type->sampler_dim); - - if (width != resource_type->e.resource.format->e.numeric.dimx * resource_type->e.resource.format->e.numeric.dimy) - hlsl_error(ctx, &lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_WRITEMASK, - "Resource store expressions must write to all components."); - - VKD3D_ASSERT(coords->data_type->class == HLSL_CLASS_VECTOR); - VKD3D_ASSERT(coords->data_type->e.numeric.type == HLSL_TYPE_UINT); - VKD3D_ASSERT(coords->data_type->e.numeric.dimx == dim_count); - - hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STORE, - &resource_deref, coords, rhs, writemask, &lhs->loc); - hlsl_cleanup_deref(&resource_deref); } else if (matrix_writemask) { @@ -2244,19 +2406,17 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct hlsl_block *i { struct hlsl_default_value default_value = {0}; - if (src->type == HLSL_IR_COMPILE || src->type == HLSL_IR_SAMPLER_STATE) + if ((src->type == HLSL_IR_SAMPLER_STATE || src->type == HLSL_IR_COMPILE) + && hlsl_is_numeric_type(dst_comp_type) && dst->default_values) { /* Default values are discarded if they contain an object * literal expression for a numeric component. */ - if (hlsl_is_numeric_type(dst_comp_type) && 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); - hlsl_free_default_values(dst); - } + hlsl_warning(ctx, &src->loc, VKD3D_SHADER_WARNING_HLSL_IGNORED_DEFAULT_VALUE, + "Component %u in variable '%s' initializer is an object literal. Default values discarded.", + k, dst->name); + hlsl_free_default_values(dst); } - else + else if (src->type != HLSL_IR_SAMPLER_STATE) { if (!hlsl_clone_block(ctx, &block, instrs)) return; @@ -2401,6 +2561,21 @@ static void check_invalid_object_fields(struct hlsl_ctx *ctx, const struct hlsl_ "Target profile doesn't support objects as struct members in uniform variables."); } +static void validate_groupshared_var(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var) +{ + if (type_has_object_components(var->data_type)) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, var->data_type))) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Groupshared type %s is not numeric.", string->buffer); + hlsl_release_string_buffer(ctx, string); + } + } +} + static void declare_var(struct hlsl_ctx *ctx, struct parse_variable_def *v) { uint32_t modifiers = v->modifiers | v->semantic.modifiers; @@ -2555,11 +2730,18 @@ static void declare_var(struct hlsl_ctx *ctx, struct parse_variable_def *v) hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, "Variable '%s' is declared as both \"uniform\" and \"static\".", var->name); - if ((modifiers & HLSL_STORAGE_GROUPSHARED) && ctx->profile->type != VKD3D_SHADER_TYPE_COMPUTE) + if ((modifiers & HLSL_STORAGE_GROUPSHARED)) { - modifiers &= ~HLSL_STORAGE_GROUPSHARED; - hlsl_warning(ctx, &var->loc, VKD3D_SHADER_WARNING_HLSL_IGNORED_MODIFIER, - "Ignoring the 'groupshared' modifier in a non-compute shader."); + /* d3dcompiler/fxc always validates global groupshared variables, + * regardless of whether the groupshared modifier is ignored. */ + validate_groupshared_var(ctx, var); + + if (ctx->profile->type != VKD3D_SHADER_TYPE_COMPUTE) + { + modifiers &= ~HLSL_STORAGE_GROUPSHARED; + hlsl_warning(ctx, &var->loc, VKD3D_SHADER_WARNING_HLSL_IGNORED_MODIFIER, + "Ignoring the 'groupshared' modifier in a non-compute shader."); + } } /* Mark it as uniform. We need to do this here since synthetic @@ -2670,15 +2852,17 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var if (v->initializer.args_count) { - bool is_default_values_initializer; + bool is_default_values_initializer, static_initialization; is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) || (var->storage_modifiers & HLSL_STORAGE_UNIFORM) || ctx->cur_scope->annotations; if (hlsl_get_multiarray_element_type(type)->class == HLSL_CLASS_SAMPLER) is_default_values_initializer = false; - if (hlsl_type_is_shader(type)) - is_default_values_initializer = false; + + static_initialization = var->storage_modifiers & HLSL_STORAGE_STATIC + || (var->data_type->modifiers & HLSL_MODIFIER_CONST + && is_static_expression(v->initializer.instrs)); if (is_default_values_initializer) { @@ -2708,7 +2892,7 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var { hlsl_dump_var_default_values(var); } - else if (var->storage_modifiers & HLSL_STORAGE_STATIC) + else if (static_initialization) { hlsl_block_add_block(&ctx->static_initializers, v->initializer.instrs); } @@ -2980,11 +3164,9 @@ static void add_void_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, hlsl_block_add_expr(ctx, block, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc); } -static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx, - struct hlsl_ir_function_decl *func, const struct parse_initializer *args, - bool is_compile, const struct vkd3d_shader_location *loc) +static bool parse_function_call_arguments(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *func, + const struct parse_initializer *args, bool is_compile, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *call; unsigned int i, j, k; VKD3D_ASSERT(args->args_count <= func->parameters.count); @@ -3042,12 +3224,22 @@ static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx, } } + return true; +} + +static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, + const struct parse_initializer *args, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_node *call; + unsigned int i; + + if (!parse_function_call_arguments(ctx, func, args, false, loc)) + return NULL; + if (!(call = hlsl_new_call(ctx, func, loc))) return NULL; - hlsl_block_add_instr(args->instrs, call); - if (is_compile) - return call; + hlsl_block_add_instr(args->instrs, call); for (i = 0; i < args->args_count; ++i) { @@ -3253,7 +3445,7 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_acos(struct hlsl_ctx *ctx, @@ -3393,7 +3585,7 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_atan(struct hlsl_ctx *ctx, @@ -3576,7 +3768,7 @@ static bool write_cosh_or_sinh(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_cosh(struct hlsl_ctx *ctx, @@ -3788,7 +3980,7 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_distance(struct hlsl_ctx *ctx, @@ -3858,7 +4050,7 @@ static bool intrinsic_dst(struct hlsl_ctx *ctx, const struct parse_initializer * if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_exp(struct hlsl_ctx *ctx, @@ -3912,7 +4104,7 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_f16tof32(struct hlsl_ctx *ctx, @@ -4108,7 +4300,7 @@ static bool intrinsic_frexp(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_fwidth(struct hlsl_ctx *ctx, @@ -4135,7 +4327,7 @@ static bool intrinsic_fwidth(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_isinf(struct hlsl_ctx *ctx, @@ -4235,7 +4427,7 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, if (!(func = hlsl_compile_internal_function(ctx, "lit", body))) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_log(struct hlsl_ctx *ctx, @@ -4336,7 +4528,7 @@ static bool intrinsic_modf(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_mul(struct hlsl_ctx *ctx, @@ -4585,7 +4777,7 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_round(struct hlsl_ctx *ctx, @@ -4687,7 +4879,7 @@ static bool intrinsic_sincos(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_sinh(struct hlsl_ctx *ctx, @@ -4722,7 +4914,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_sqrt(struct hlsl_ctx *ctx, @@ -4796,7 +4988,7 @@ static bool intrinsic_tanh(struct hlsl_ctx *ctx, if (!func) return false; - return !!add_user_call(ctx, func, params, false, loc); + return !!add_user_call(ctx, func, params, loc); } static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params, @@ -5180,7 +5372,7 @@ static bool intrinsic_interlocked(struct hlsl_ctx *ctx, enum hlsl_interlocked_op return false; /* TODO: groupshared variables */ - if (lhs->type == HLSL_IR_INDEX && hlsl_index_chain_has_resource_access(hlsl_ir_index(lhs))) + if (lhs->type == HLSL_IR_INDEX && hlsl_index_chain_find_resource_access(hlsl_ir_index(lhs))) { if (!hlsl_index_is_resource_access(hlsl_ir_index(lhs))) { @@ -5321,17 +5513,114 @@ static bool intrinsic_AllMemoryBarrierWithGroupSync(struct hlsl_ctx *ctx, static bool intrinsic_ConstructGSWithSO(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *compile; + const char *strings[HLSL_STREAM_OUTPUT_MAX] = {0}; + size_t string_count = params->args_count - 1; + struct hlsl_ir_compile *compile; + struct hlsl_ir_node *node; + uint32_t stream_index = 0; + struct hlsl_ir_var *var; if (params->args_count != 2 && params->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.", params->args_count); + "Unexpected number of arguments to ConstructGSWithSO(): expected 2 or 6, but got %u.", + params->args_count); + return false; + } + + if (ctx->profile->type != VKD3D_SHADER_TYPE_EFFECT) + { + if (!(node = hlsl_new_compile_with_so(ctx, NULL, 0, 0, NULL, loc))) + return false; + hlsl_block_add_instr(params->instrs, node); + return true; + } + + node = params->args[0]; + switch (node->type) + { + case HLSL_IR_COMPILE: + compile = hlsl_ir_compile(node); + break; + + case HLSL_IR_LOAD: + var = hlsl_ir_load(node)->src.var; + if (var->data_type->class == HLSL_CLASS_ARRAY || !hlsl_type_is_shader(var->data_type)) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "\"%s\" is not a shader compilation.", var->name); + return false; + } + + if (!(compile = var->default_values[0].shader)) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Stream output shaders can't be constructed with NULL shaders."); + return false; + } + break; + + case HLSL_IR_INDEX: + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Stream output shaders can't be constructed with array indexes."); + return false; + + default: + hlsl_fixme(ctx, loc, "Unhandled node type in ConstructGSWithSO()."); + return false; + } + + if (compile->profile->type != VKD3D_SHADER_TYPE_VERTEX && compile->profile->type != VKD3D_SHADER_TYPE_GEOMETRY) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Stream output shaders can only be constructed with vertex or geometry shaders."); + return false; + } + + if (params->args_count == 6) + { + struct hlsl_block stream_index_block; + + --string_count; + + if (!(node = hlsl_clone_instr(ctx, params->args[5]))) + return false; + + hlsl_block_init(&stream_index_block); + hlsl_block_add_instr(&stream_index_block, node); + + stream_index = evaluate_static_expression_as_uint(ctx, &stream_index_block, loc); - if (!(compile = hlsl_new_compile(ctx, HLSL_COMPILE_TYPE_CONSTRUCTGSWITHSO, - NULL, params->args, params->args_count, params->instrs, loc))) + hlsl_block_cleanup(&stream_index_block); + } + + for (size_t i = 0; i < string_count; ++i) + { + struct hlsl_ir_node *stream_node = params->args[i + 1]; + + switch (stream_node->type) + { + case HLSL_IR_STRING_CONSTANT: + strings[i] = hlsl_ir_string_constant(stream_node)->string; + break; + + case HLSL_IR_CONSTANT: + if (stream_node->data_type->class == HLSL_CLASS_NULL) + continue; + /* fall-through */ + default: + hlsl_error(ctx, &stream_node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Stream Output declarations must be a literal string."); + return false; + } + } + + VKD3D_ASSERT(string_count <= ARRAY_SIZE(strings)); + + if (!(node = hlsl_new_compile_with_so(ctx, compile, stream_index, string_count, strings, loc))) return false; + hlsl_block_add_instr(params->instrs, node); - hlsl_block_add_instr(params->instrs, compile); return true; } @@ -5500,21 +5789,18 @@ static int intrinsic_function_name_compare(const void *a, const void *b) static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name, struct parse_initializer *args, const struct vkd3d_shader_location *loc) { - struct intrinsic_function *intrinsic; + const struct intrinsic_function *intrinsic; struct hlsl_ir_function_decl *decl; for (unsigned int i = 0; i < args->args_count; ++i) { if (args->args[i]->data_type->class == HLSL_CLASS_ERROR) - { - args->instrs->value = ctx->error_instr; - return args->instrs; - } + goto fail; } if ((decl = find_function_call(ctx, name, args, false, loc))) { - if (!add_user_call(ctx, decl, args, false, loc)) + if (!add_user_call(ctx, decl, args, loc)) goto fail; } else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions), @@ -5566,22 +5852,24 @@ static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name, return args->instrs; fail: - free_parse_initializer(args); - return NULL; + args->instrs->value = ctx->error_instr; + vkd3d_free(args->args); + return args->instrs; } static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const char *profile_name, const char *function_name, struct parse_initializer *args, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *compile, *call_to_compile = NULL; + const struct hlsl_profile_info *profile_info; struct hlsl_ir_function_decl *decl; + struct hlsl_block *block = NULL; + struct hlsl_ir_node *compile; if (!ctx->in_state_block && ctx->cur_scope != ctx->globals) { hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE, "Shader compilation statements must be in global scope or a state block."); - free_parse_initializer(args); - return NULL; + goto out; } if (!(decl = find_function_call(ctx, function_name, args, true, loc))) @@ -5597,8 +5885,13 @@ static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const cha hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Function \"%s\" is not defined.", function_name); } - free_parse_initializer(args); - return NULL; + goto out; + } + + if (!(profile_info = hlsl_get_target_info(profile_name))) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Unknown profile \"%s\".", profile_name); + goto out; } for (unsigned int i = 0; i < args->args_count; ++i) @@ -5611,21 +5904,17 @@ static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const cha } } - if (!(call_to_compile = add_user_call(ctx, decl, args, true, loc))) - { - free_parse_initializer(args); - return NULL; - } + if (!parse_function_call_arguments(ctx, decl, args, true, loc)) + goto out; - 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; - } + if (!(compile = hlsl_new_compile(ctx, profile_info, decl, args->instrs, loc))) + goto out; + + block = make_block(ctx, compile); - free_parse_initializer(args); - return make_block(ctx, compile); +out: + cleanup_parse_initializer(args); + return block; } static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, @@ -6467,7 +6756,8 @@ static bool add_store_method_call(struct hlsl_ctx *ctx, struct hlsl_block *block if (!hlsl_init_deref_from_index_chain(ctx, &resource_deref, object)) return false; - hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STORE, &resource_deref, offset, rhs, writemask, loc); + hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STORE, + &resource_deref, NULL, offset, rhs, writemask, loc); hlsl_cleanup_deref(&resource_deref); return true; @@ -6492,7 +6782,7 @@ static bool add_so_append_method_call(struct hlsl_ctx *ctx, struct hlsl_block *b if (!(rhs = add_implicit_conversion(ctx, block, params->args[0], object->data_type->e.so.type, loc))) return false; - hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STREAM_APPEND, &so_deref, NULL, rhs, 0, loc); + hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STREAM_APPEND, &so_deref, NULL, NULL, rhs, 0, loc); hlsl_cleanup_deref(&so_deref); return true; @@ -6513,7 +6803,7 @@ static bool add_so_restartstrip_method_call(struct hlsl_ctx *ctx, struct hlsl_bl if (!hlsl_init_deref_from_index_chain(ctx, &so_deref, object)) return false; - hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STREAM_RESTART, &so_deref, NULL, NULL, 0, loc); + hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STREAM_RESTART, &so_deref, NULL, NULL, NULL, 0, loc); hlsl_cleanup_deref(&so_deref); return true; @@ -7058,6 +7348,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type <attr_list> attribute_list %type <attr_list> attribute_list_optional +%destructor { cleanup_parse_attribute_list(&$$); } <attr_list> %type <block> add_expr %type <block> assignment_expr @@ -7105,6 +7396,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type <initializer> complex_initializer_list %type <initializer> func_arguments %type <initializer> initializer_expr_list +%destructor { cleanup_parse_initializer(&$$); } <initializer> %type <if_body> if_body @@ -7116,12 +7408,14 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type <name> var_identifier %type <name> stateblock_lhs_identifier %type <name> name_opt +%destructor { vkd3d_free($$); } <name> %type <parameter> parameter %type <parameter> parameter_decl %type <parameters> param_list %type <parameters> parameters +%destructor { hlsl_func_parameters_cleanup(&$$); } <parameters> %type <reg_reservation> register_reservation %type <reg_reservation> packoffset_reservation @@ -7134,6 +7428,7 @@ static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, %type <so_type> so_type %type <state_block> state_block +%destructor { hlsl_free_state_block($$); } <state_block> %type <state_block_index> state_block_index_opt @@ -7408,6 +7703,7 @@ base_optional: if ($$->class != HLSL_CLASS_STRUCT) { hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Base type \"%s\" is not a struct.", $2); + vkd3d_free($2); YYABORT; } vkd3d_free($2); @@ -7492,7 +7788,7 @@ attribute: if (!($$ = hlsl_alloc(ctx, offsetof(struct hlsl_attribute, args[$4.args_count])))) { vkd3d_free($2); - free_parse_initializer(&$4); + cleanup_parse_initializer(&$4); YYABORT; } $$->name = $2; @@ -7502,7 +7798,7 @@ attribute: $$->args_count = $4.args_count; for (i = 0; i < $4.args_count; ++i) hlsl_src_from_node(&$$->args[i], $4.args[i]); - free_parse_initializer(&$4); + cleanup_parse_initializer(&$4); } attribute_list: @@ -7590,14 +7886,13 @@ func_declaration: hlsl_pop_scope(ctx); if (!$1.first) - { - vkd3d_free($1.parameters.vars); - hlsl_cleanup_semantic(&$1.return_semantic); - } + parse_function_cleanup(&$1); } | func_prototype ';' { hlsl_pop_scope(ctx); + if (!$1.first) + parse_function_cleanup(&$1); } func_prototype_no_attrs: @@ -7611,7 +7906,7 @@ func_prototype_no_attrs: /* Functions are unconditionally inlined. */ modifiers &= ~HLSL_MODIFIER_INLINE; - if (modifiers & ~(HLSL_MODIFIERS_MAJORITY_MASK | HLSL_MODIFIER_EXPORT)) + if (modifiers & ~(HLSL_MODIFIERS_MAJORITY_MASK | HLSL_STORAGE_EXPORT | HLSL_STORAGE_STATIC)) hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_MODIFIER, "Unexpected modifier used on a function."); if (!(type = apply_type_modifiers(ctx, $2, &modifiers, true, &@1))) @@ -7647,6 +7942,13 @@ func_prototype_no_attrs: hlsl_note(ctx, &$$.decl->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously declared here.", $3); } + if (($$.decl->storage_modifiers & HLSL_STORAGE_STATIC) != (modifiers & HLSL_STORAGE_STATIC)) + { + hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_REDEFINED, + "\"%s\" was already declared with different storage modifiers.", $3); + hlsl_note(ctx, &$$.decl->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously declared here.", $3); + } + vkd3d_free($3); /* We implement function invocation by copying to input @@ -7707,7 +8009,7 @@ func_prototype_no_attrs: } else { - if (!($$.decl = hlsl_new_func_decl(ctx, type, &$5, &$7.semantic, &@3))) + if (!($$.decl = hlsl_new_func_decl(ctx, modifiers, type, &$5, &$7.semantic, &@3))) YYABORT; hlsl_add_function(ctx, $3, $$.decl); @@ -8398,6 +8700,7 @@ type_no_void: if (hlsl_is_numeric_type(type) && type->e.numeric.type == HLSL_TYPE_INT) { + vkd3d_free($2); if (!(type = hlsl_type_clone(ctx, type, 0, 0))) YYABORT; vkd3d_free((void *)type->name); @@ -8408,6 +8711,7 @@ type_no_void: { hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "The 'unsigned' keyword can't be used with type %s.", $2); + vkd3d_free($2); } $$ = type; @@ -8817,6 +9121,7 @@ array: | '[' expr ']' { $$ = evaluate_static_expression_as_uint(ctx, $2, &@2); + destroy_block($2); if (!$$) { @@ -8831,8 +9136,6 @@ array: "Array size %u is not between 1 and 65536.", $$); YYABORT; } - - destroy_block($2); } arrays: @@ -8932,7 +9235,7 @@ var_modifiers: } | KW_EXPORT var_modifiers { - $$ = add_modifiers(ctx, $2, HLSL_MODIFIER_EXPORT, &@1); + $$ = add_modifiers(ctx, $2, HLSL_STORAGE_EXPORT, &@1); } | KW_UNORM var_modifiers { @@ -8973,6 +9276,7 @@ var_modifiers: else hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_UNKNOWN_MODIFIER, "Unknown modifier %s.", debugstr_a($1)); + vkd3d_free($1); } complex_initializer: @@ -9010,15 +9314,15 @@ complex_initializer_list: $$ = $1; if (!(new_args = hlsl_realloc(ctx, $$.args, ($$.args_count + $3.args_count) * sizeof(*$$.args)))) { - free_parse_initializer(&$$); - free_parse_initializer(&$3); + cleanup_parse_initializer(&$$); + cleanup_parse_initializer(&$3); YYABORT; } $$.args = new_args; for (i = 0; i < $3.args_count; ++i) $$.args[$$.args_count++] = $3.args[i]; hlsl_block_add_block($$.instrs, $3.instrs); - free_parse_initializer(&$3); + cleanup_parse_initializer(&$3); $$.loc = @$; } @@ -9046,7 +9350,7 @@ initializer_expr_list: $$ = $1; if (!(new_args = hlsl_realloc(ctx, $$.args, ($$.args_count + 1) * sizeof(*$$.args)))) { - free_parse_initializer(&$$); + cleanup_parse_initializer(&$$); destroy_block($3); YYABORT; } @@ -9120,7 +9424,10 @@ jump_statement: if (!($$ = make_empty_block(ctx))) YYABORT; if (!add_return(ctx, $$, NULL, &@1)) + { + destroy_block($$); YYABORT; + } } | KW_DISCARD ';' { @@ -9439,11 +9746,7 @@ primary_expr: } | var_identifier '(' func_arguments ')' { - if (!($$ = add_call(ctx, $1, &$3, &@1))) - { - vkd3d_free($1); - YYABORT; - } + $$ = add_call(ctx, $1, &$3, &@1); vkd3d_free($1); } | KW_SAMPLER_STATE '{' state_block_start state_block '}' @@ -9566,7 +9869,7 @@ postfix_expr: if (!($$ = add_constructor(ctx, $2, &$4, &@2))) { - free_parse_initializer(&$4); + cleanup_parse_initializer(&$4); YYABORT; } } @@ -9580,9 +9883,11 @@ postfix_expr: if (!add_method_call(ctx, $1, object, $3, &$5, &@3)) { destroy_block($1); + vkd3d_free($3); vkd3d_free($5.args); YYABORT; } + vkd3d_free($3); vkd3d_free($5.args); $$ = $1; } @@ -9758,7 +10063,10 @@ conditional_expr: destroy_block($5); if (!add_ternary(ctx, $1, cond, first, second)) + { + destroy_block($1); YYABORT; + } $$ = $1; } @@ -9774,7 +10082,10 @@ assignment_expr: hlsl_block_add_block($3, $1); destroy_block($1); if (!add_assignment(ctx, $3, lhs, $2, rhs, false)) + { + destroy_block($3); YYABORT; + } $$ = $3; } diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c index f1368b151aa..6f61eb92a67 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c @@ -191,8 +191,7 @@ static unsigned int struct_field_get_packed_offset(const struct hlsl_type *recor return align(offset, hlsl_type_get_packed_alignment(record->e.record.fields[field_idx].type)); } - -static struct hlsl_ir_node *hlsl_block_add_packed_index_offset_append(struct hlsl_ctx *ctx, +struct hlsl_ir_node *hlsl_block_add_packed_index_offset_append(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *prev_offset, struct hlsl_ir_node *idx, struct hlsl_type *type, const struct vkd3d_shader_location *loc) { @@ -926,6 +925,50 @@ bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, return progress; } +static bool hlsl_transform_ir_once(struct hlsl_ctx *ctx, + bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), + struct hlsl_block *block, void *context) +{ + struct hlsl_ir_node *instr, *next; + + if (ctx->result) + return false; + + LIST_FOR_EACH_ENTRY_SAFE(instr, next, &block->instrs, struct hlsl_ir_node, entry) + { + if (instr->type == HLSL_IR_IF) + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + + if (hlsl_transform_ir_once(ctx, func, &iff->then_block, context)) + return true; + if (hlsl_transform_ir_once(ctx, func, &iff->else_block, context)) + return true; + } + else if (instr->type == HLSL_IR_LOOP) + { + if (hlsl_transform_ir_once(ctx, func, &hlsl_ir_loop(instr)->body, context)) + return true; + } + else if (instr->type == HLSL_IR_SWITCH) + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + if (hlsl_transform_ir_once(ctx, func, &c->body, context)) + return true; + } + } + + if (func(ctx, instr, context)) + return true; + } + + return false; +} + typedef struct hlsl_ir_node *(*PFN_replace_func)(struct hlsl_ctx *, struct hlsl_ir_node *, struct hlsl_block *); static bool call_replace_func(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) @@ -1413,24 +1456,49 @@ static struct hlsl_ir_node *lower_matrix_swizzles(struct hlsl_ctx *ctx, return hlsl_block_add_simple_load(ctx, block, var, &instr->loc); } -/* hlsl_ir_index nodes are a parse-time construct used to represent array indexing and struct - * record access before knowing if they will be used in the lhs of an assignment --in which case - * they are lowered into a deref-- or as the load of an element within a larger value. - * For the latter case, this pass takes care of lowering hlsl_ir_indexes into individual - * hlsl_ir_loads, or individual hlsl_ir_resource_loads, in case the indexing is a - * resource access. */ -static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx, - struct hlsl_ir_node *instr, struct hlsl_block *block) +/* Usually when INDEX nodes are constructed, it's a direct variable load + * followed by the INDEX. As described below in lower_index_load(), we know in + * that case that the variable in question is unmodified and we can convert the + * INDEX to a LOAD of the same variable instead of copying it to a temp. + * This function is an unsophisticated heuristic meant to detect this case. + * + * For various reasons there may be CONSTANT or EXPR instructions between the + * two, so we have to search until we find the source node. */ +static bool is_indexed_value_known_unmodified(const struct hlsl_block *block, const struct hlsl_ir_index *index) +{ + const struct list *entry = &index->node.entry; + + while ((entry = list_prev(&block->instrs, entry))) + { + const struct hlsl_ir_node *instr = LIST_ENTRY(entry, struct hlsl_ir_node, entry); + + if (instr == index->val.node) + return true; + + switch (instr->type) + { + case HLSL_IR_CONSTANT: + case HLSL_IR_EXPR: + break; + + default: + return false; + } + } + + return false; +} + +static struct hlsl_ir_node *lower_index_load(struct hlsl_ctx *ctx, struct hlsl_ir_index *index, + struct hlsl_block *block, struct hlsl_block *containing_block) { + struct hlsl_ir_node *instr = &index->node, *ret; + const struct hlsl_deref *deref; struct hlsl_deref var_deref; - struct hlsl_ir_index *index; struct hlsl_ir_load *load; struct hlsl_ir_node *val; struct hlsl_ir_var *var; - if (instr->type != HLSL_IR_INDEX) - return NULL; - index = hlsl_ir_index(instr); val = index->val.node; if (hlsl_index_is_resource_access(index)) @@ -1453,11 +1521,39 @@ static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx, return hlsl_block_add_resource_load(ctx, block, ¶ms, &instr->loc); } + if (val->type == HLSL_IR_RESOURCE_LOAD && val->data_type->class == HLSL_CLASS_ARRAY) + { + const struct hlsl_deref *resource = &hlsl_ir_resource_load(val)->resource; + + /* Structured (i.e. arrayed) TGSM access. */ + if (resource->var->is_tgsm && !resource->path_len) + { + struct hlsl_ir_node *coords = index->idx.node; + struct hlsl_resource_load_params params = {0}; + struct hlsl_ir_load *tgsm_load; + + VKD3D_ASSERT(hlsl_is_vec1(coords->data_type)); + VKD3D_ASSERT(coords->data_type->e.numeric.type == HLSL_TYPE_UINT); + + if (!(tgsm_load = hlsl_new_var_load(ctx, resource->var, &instr->loc))) + return NULL; + + params.type = HLSL_RESOURCE_LOAD; + params.resource = &tgsm_load->node; + params.coords = coords; + params.format = val->data_type->e.array.type; + ret = hlsl_block_add_resource_load(ctx, block, ¶ms, &instr->loc); + + hlsl_free_instr(&tgsm_load->node); + return ret; + } + } + if (val->type == HLSL_IR_RESOURCE_LOAD) { struct hlsl_ir_resource_load *parent = hlsl_ir_resource_load(index->val.node); - if (parent->sampling_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) + if (parent->sampling_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER || parent->resource.var->is_tgsm) { if (hlsl_index_is_noncontiguous(index)) { @@ -1519,11 +1615,46 @@ static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx, } } - if (!(var = hlsl_new_synthetic_var(ctx, "index-val", val->data_type, &instr->loc))) - return NULL; - hlsl_init_simple_deref_from_var(&var_deref, var); + /* Indexed values don't have to be variable loads, but a LOAD must be of a + * variable, so we may need to copy the indexed value to a synthetic + * variable first. + * Even if an INDEX is of a variable load, due to the structure of our IR, + * it's legal for that variable to have been modified between the LOAD and + * the INDEX. For example, we can have a sequence like: + * + * 2: x + * 3: x = 1 + * 4: @2[...] + * + * Because the defined semantics of the IR are essentially "pass by value", + * we can't just convert @4 into a LOAD of x. We have to copy it into a + * synthetic temp first. + * + * This situation generally doesn't actually happen with the IR that comes + * from parsing, but it can happen in certain cases related to function + * calls. + * + * Always creating an extra copy is fine in theory, since copy propagation + * will later undo it. Some of these variables can be extremely large, + * however, such that we can observe a noticeable speed improvement by + * avoiding the copy in the first place. */ - hlsl_block_add_simple_store(ctx, block, var, val); + if (val->type == HLSL_IR_LOAD && is_indexed_value_known_unmodified(containing_block, index)) + { + /* Note that in a chain of indices only the first will be a LOAD. + * However, because we convert from top to bottom, and replace as we go, + * we should end up catching every index in a chain this way. */ + deref = &hlsl_ir_load(val)->src; + } + else + { + if (!(var = hlsl_new_synthetic_var(ctx, "index-val", val->data_type, &instr->loc))) + return NULL; + hlsl_init_simple_deref_from_var(&var_deref, var); + deref = &var_deref; + + hlsl_block_add_simple_store(ctx, block, var, val); + } if (hlsl_index_is_noncontiguous(index)) { @@ -1543,7 +1674,7 @@ static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx, c = hlsl_block_add_uint_constant(ctx, block, i, &instr->loc); - if (!(load = hlsl_new_load_index(ctx, &var_deref, c, &instr->loc))) + if (!(load = hlsl_new_load_index(ctx, deref, c, &instr->loc))) return NULL; hlsl_block_add_instr(block, &load->node); @@ -1557,7 +1688,67 @@ static struct hlsl_ir_node *lower_index_loads(struct hlsl_ctx *ctx, return hlsl_block_add_simple_load(ctx, block, var, &instr->loc); } - return hlsl_block_add_load_index(ctx, block, &var_deref, index->idx.node, &instr->loc); + return hlsl_block_add_load_index(ctx, block, deref, index->idx.node, &instr->loc); +} + +/* hlsl_ir_index nodes are a parse-time construct used to represent array + * indexing and struct record access before knowing if they will be used in the + * LHS of an assignment—in which case they are lowered into a deref—or as the + * load of an element within a larger value. + * For the latter case, this pass takes care of lowering hlsl_ir_indexes into + * individual hlsl_ir_load or hlsl_ir_resource_load. */ +void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *block) +{ + struct hlsl_ir_node *instr, *next; + + LIST_FOR_EACH_ENTRY_SAFE(instr, next, &block->instrs, struct hlsl_ir_node, entry) + { + switch (instr->type) + { + case HLSL_IR_INDEX: + { + struct hlsl_ir_node *replacement; + struct hlsl_block new_block; + + hlsl_block_init(&new_block); + if ((replacement = lower_index_load(ctx, hlsl_ir_index(instr), &new_block, block))) + { + list_move_before(&instr->entry, &new_block.instrs); + hlsl_replace_node(instr, replacement); + } + else + { + hlsl_block_cleanup(&new_block); + } + break; + } + + case HLSL_IR_IF: + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + hlsl_lower_index_loads(ctx, &iff->then_block); + hlsl_lower_index_loads(ctx, &iff->else_block); + break; + } + + case HLSL_IR_LOOP: + hlsl_lower_index_loads(ctx, &hlsl_ir_loop(instr)->body); + break; + + case HLSL_IR_SWITCH: + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + hlsl_lower_index_loads(ctx, &c->body); + break; + } + + default: + break; + } + } } /* Lower casts from vec1 to vecN to swizzles. */ @@ -1594,31 +1785,32 @@ static struct hlsl_ir_node *lower_broadcasts(struct hlsl_ctx *ctx, struct hlsl_i return NULL; } -/* Lowers loads from TGSMs to resource loads. */ +/* Lowers TGSM loads to resource loads. + * Note that the byte_offset, rather than coords, field of the resource load + * is used to hold the load address from TGSM loads. + * The coords field is used only for structured (i.e. arrayed) TGSM loads, + * and represents the structured array index. */ static struct hlsl_ir_node *lower_tgsm_loads(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block) { - struct hlsl_resource_load_params params = {.type = HLSL_RESOURCE_LOAD}; const struct vkd3d_shader_location *loc = &instr->loc; + struct hlsl_resource_load_params params = {0}; + const struct hlsl_ir_var *var; struct hlsl_ir_load *load; - struct hlsl_deref *deref; - if (instr->type != HLSL_IR_LOAD || !hlsl_is_numeric_type(instr->data_type)) + if (instr->type != HLSL_IR_LOAD) return NULL; load = hlsl_ir_load(instr); - deref = &load->src; + var = load->src.var; - if (!deref->var->is_tgsm) + if (!var->is_tgsm) return NULL; - if (deref->path_len) - { - hlsl_fixme(ctx, &instr->loc, "Load from indexed TGSM."); - return NULL; - } + VKD3D_ASSERT(!load->src.path_len); - params.resource = hlsl_block_add_simple_load(ctx, block, deref->var, loc); + params.type = HLSL_RESOURCE_LOAD; + params.resource = instr; + params.coords = NULL; params.format = instr->data_type; - params.coords = hlsl_block_add_uint_constant(ctx, block, 0, &instr->loc); return hlsl_block_add_resource_load(ctx, block, ¶ms, loc); } @@ -1649,7 +1841,7 @@ static struct hlsl_ir_node *lower_tgsm_stores(struct hlsl_ctx *ctx, coords = hlsl_block_add_uint_constant(ctx, block, 0, &instr->loc); return hlsl_block_add_resource_store(ctx, block, HLSL_RESOURCE_STORE, &res_deref, - coords, store->rhs.node, store->writemask, &instr->loc); + NULL, coords, store->rhs.node, store->writemask, &instr->loc); } /* Allocate a unique, ordered index to each instruction, which will be used for @@ -2520,6 +2712,12 @@ static bool copy_propagation_transform_object_load(struct hlsl_ctx *ctx, struct hlsl_ir_load *load; unsigned int start, count; + if (deref->var->is_tgsm) + { + VKD3D_ASSERT(deref->path_len == 0); + return false; + } + if (!hlsl_component_index_range_from_deref(ctx, deref, &start, &count)) return false; VKD3D_ASSERT(count == 1); @@ -3595,25 +3793,64 @@ static struct hlsl_ir_node *fold_redundant_casts(struct hlsl_ctx *ctx, * split_array_copies(), split_struct_copies() and * split_matrix_copies(). Inserts new instructions right before * "store". */ -static bool split_copy(struct hlsl_ctx *ctx, struct hlsl_ir_store *store, - const struct hlsl_ir_load *load, const unsigned int idx, struct hlsl_type *type) +static void split_copy(struct hlsl_ctx *ctx, struct hlsl_ir_store *store, + struct hlsl_ir_load *load, const unsigned int idx, struct hlsl_type *type) { - struct hlsl_ir_node *split_store, *c; - struct hlsl_ir_load *split_load; + struct hlsl_ir_node *c, *split_load; + struct hlsl_block block; - if (!(c = hlsl_new_uint_constant(ctx, idx, &store->node.loc))) - return false; - list_add_before(&store->node.entry, &c->entry); + hlsl_block_init(&block); - if (!(split_load = hlsl_new_load_index(ctx, &load->src, c, &store->node.loc))) - return false; - list_add_before(&store->node.entry, &split_load->node.entry); + c = hlsl_block_add_uint_constant(ctx, &block, idx, &store->node.loc); + split_load = hlsl_block_add_load_index(ctx, &block, &load->src, c, &store->node.loc); - if (!(split_store = hlsl_new_store_index(ctx, &store->lhs, c, &split_load->node, 0, &store->node.loc))) - return false; - list_add_before(&store->node.entry, &split_store->entry); + hlsl_block_add_store_index(ctx, &block, &store->lhs, c, split_load, 0, &store->node.loc); - return true; + list_move_before(&store->node.entry, &block.instrs); +} + +/* Copy an element of a complex variable, where rhs is a structured resource load. + * Helper for split_array_copies(), split_struct_copies() and split_matrix_copies(). + * Inserts new instructions right before "store". */ +static void split_resource_load(struct hlsl_ctx *ctx, struct hlsl_ir_store *store, + struct hlsl_ir_resource_load *load, const unsigned int idx, struct hlsl_type *type) +{ + struct hlsl_ir_node *c, *idx_offset, *split_load; + struct hlsl_block block; + + hlsl_block_init(&block); + + c = hlsl_block_add_uint_constant(ctx, &block, idx, &store->node.loc); + + /* Structured (i.e. arrayed) TGSM load. */ + if (load->resource.var->is_tgsm && !load->resource.path_len && load->node.data_type->class == HLSL_CLASS_ARRAY) + { + struct hlsl_resource_load_params params = {0}; + + params.type = HLSL_RESOURCE_LOAD; + params.resource = &load->node; + params.coords = c; + params.format = load->node.data_type->e.array.type; + split_load = hlsl_block_add_resource_load(ctx, &block, ¶ms, &load->node.loc); + } + else + { + struct hlsl_ir_resource_load *res_load; + + idx_offset = hlsl_block_add_packed_index_offset_append(ctx, &block, + load->byte_offset.node, c, load->node.data_type, &store->node.loc); + + res_load = hlsl_ir_resource_load(hlsl_clone_instr(ctx, &load->node)); + hlsl_src_remove(&res_load->byte_offset); + hlsl_src_from_node(&res_load->byte_offset, idx_offset); + res_load->node.data_type = type; + hlsl_block_add_instr(&block, &res_load->node); + + split_load = &res_load->node; + } + + hlsl_block_add_store_index(ctx, &block, &store->lhs, c, split_load, 0, &store->node.loc); + list_move_before(&store->node.entry, &block.instrs); } static bool split_array_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) @@ -3634,16 +3871,30 @@ static bool split_array_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, return false; element_type = type->e.array.type; - if (rhs->type != HLSL_IR_LOAD) + if (rhs->type != HLSL_IR_LOAD && rhs->type != HLSL_IR_RESOURCE_LOAD) { - hlsl_fixme(ctx, &instr->loc, "Array store rhs is not HLSL_IR_LOAD. Broadcast may be missing."); + hlsl_fixme(ctx, &instr->loc, "Copying from unsupported node type."); return false; } - for (i = 0; i < type->e.array.elements_count; ++i) + if (rhs->type == HLSL_IR_RESOURCE_LOAD) { - if (!split_copy(ctx, store, hlsl_ir_load(rhs), i, element_type)) - return false; + struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(rhs); + + VKD3D_ASSERT(load->resource.var->is_tgsm + || hlsl_deref_get_type(ctx, &load->resource)->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER); + + for (i = 0; i < type->e.array.elements_count; ++i) + { + split_resource_load(ctx, store, load, i, element_type); + } + } + else + { + for (i = 0; i < type->e.array.elements_count; ++i) + { + split_copy(ctx, store, hlsl_ir_load(rhs), i, element_type); + } } /* Remove the store instruction, so that we can split structs which contain @@ -3670,18 +3921,34 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr if (type->class != HLSL_CLASS_STRUCT) return false; - if (rhs->type != HLSL_IR_LOAD) + if (rhs->type != HLSL_IR_LOAD && rhs->type != HLSL_IR_RESOURCE_LOAD) { - hlsl_fixme(ctx, &instr->loc, "Struct store rhs is not HLSL_IR_LOAD. Broadcast may be missing."); + hlsl_fixme(ctx, &instr->loc, "Copying from unsupported node type."); return false; } - for (i = 0; i < type->e.record.field_count; ++i) + if (rhs->type == HLSL_IR_RESOURCE_LOAD) { - const struct hlsl_struct_field *field = &type->e.record.fields[i]; + struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(rhs); - if (!split_copy(ctx, store, hlsl_ir_load(rhs), i, field->type)) - return false; + VKD3D_ASSERT(load->resource.var->is_tgsm + || hlsl_deref_get_type(ctx, &load->resource)->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER); + + for (i = 0; i < type->e.record.field_count; ++i) + { + const struct hlsl_struct_field *field = &type->e.record.fields[i]; + + split_resource_load(ctx, store, load, i, field->type); + } + } + else + { + for (i = 0; i < type->e.record.field_count; ++i) + { + const struct hlsl_struct_field *field = &type->e.record.fields[i]; + + split_copy(ctx, store, hlsl_ir_load(rhs), i, field->type); + } } /* Remove the store instruction, so that we can split structs which contain @@ -3692,135 +3959,136 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr return true; } -struct stream_append_ctx -{ - struct list *semantic_vars; - bool created[VKD3D_MAX_STREAM_COUNT]; -}; - -static bool lower_stream_appends(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +static bool split_matrix_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { - struct stream_append_ctx *append_ctx = context; - struct hlsl_ir_resource_store *store; - struct hlsl_semantic semantic_copy; const struct hlsl_ir_node *rhs; + struct hlsl_type *element_type; const struct hlsl_type *type; - struct hlsl_ir_var *var; - struct hlsl_block block; - uint32_t stream_index; + unsigned int i; + struct hlsl_ir_store *store; - if (instr->type != HLSL_IR_RESOURCE_STORE) + if (instr->type != HLSL_IR_STORE) return false; - store = hlsl_ir_resource_store(instr); - if (store->store_type != HLSL_RESOURCE_STREAM_APPEND) + store = hlsl_ir_store(instr); + rhs = store->rhs.node; + type = rhs->data_type; + if (type->class != HLSL_CLASS_MATRIX) return false; + element_type = hlsl_get_vector_type(ctx, type->e.numeric.type, hlsl_type_minor_size(type)); - rhs = store->value.node; - var = store->resource.var; - type = hlsl_get_stream_output_type(var->data_type); - - if (rhs->type != HLSL_IR_LOAD) + if (rhs->type != HLSL_IR_LOAD && rhs->type != HLSL_IR_RESOURCE_LOAD) { - hlsl_fixme(ctx, &instr->loc, "Stream append rhs is not HLSL_IR_LOAD. Broadcast may be missing."); + hlsl_fixme(ctx, &instr->loc, "Copying from unsupported node type."); return false; } - VKD3D_ASSERT(var->regs[HLSL_REGSET_STREAM_OUTPUTS].allocated); - stream_index = var->regs[HLSL_REGSET_STREAM_OUTPUTS].index; - - VKD3D_ASSERT(stream_index < ARRAY_SIZE(append_ctx->created)); + if (rhs->type == HLSL_IR_RESOURCE_LOAD) + { + /* As we forbid non-scalar or vector types in non-structured resource + * loads, this is specific to structured buffer loads. */ + struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(rhs); - hlsl_block_init(&block); + VKD3D_ASSERT(hlsl_deref_get_type(ctx, &load->resource)->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER); - if (!hlsl_clone_semantic(ctx, &semantic_copy, &var->semantic)) - return false; - append_output_copy_recurse(ctx, &block, append_ctx->semantic_vars, type->e.so.type, hlsl_ir_load(rhs), - var->storage_modifiers, &semantic_copy, var->regs[HLSL_REGSET_STREAM_OUTPUTS].index, - false, !append_ctx->created[stream_index]); - hlsl_cleanup_semantic(&semantic_copy); + for (i = 0; i < hlsl_type_major_size(type); ++i) + { + split_resource_load(ctx, store, load, i, element_type); + } + } + else + { + for (i = 0; i < hlsl_type_major_size(type); ++i) + { + split_copy(ctx, store, hlsl_ir_load(rhs), i, element_type); + } + } - append_ctx->created[stream_index] = true; + list_remove(&store->node.entry); + hlsl_free_instr(&store->node); + return true; +} - list_move_before(&instr->entry, &block.instrs); - hlsl_src_remove(&store->value); +static void split_copies(struct hlsl_ctx *ctx, struct hlsl_block *block) +{ + bool progress; - return true; + do + { + progress = hlsl_transform_ir(ctx, split_array_copies, block, NULL); + progress |= hlsl_transform_ir(ctx, split_struct_copies, block, NULL); + } while (progress); + hlsl_transform_ir(ctx, split_matrix_copies, block, NULL); } -static void split_resource_load(struct hlsl_ctx *ctx, struct hlsl_ir_store *store, - struct hlsl_ir_resource_load *load, const unsigned int idx, struct hlsl_type *type) +struct stream_append_ctx { - struct hlsl_ir_resource_load *vector_load; - struct hlsl_ir_node *c, *idx_offset; - struct hlsl_block block; + struct list *semantic_vars; + bool created[VKD3D_MAX_STREAM_COUNT]; +}; - hlsl_block_init(&block); +static bool lower_stream_appends(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct stream_append_ctx *append_ctx = context; + struct hlsl_ir_resource_store *store; + struct hlsl_semantic semantic_copy; + const struct hlsl_type *type; + struct hlsl_ir_node *rhs; + struct hlsl_ir_var *var; + struct hlsl_block block; + uint32_t stream_index; + bool progress = false; - c = hlsl_block_add_uint_constant(ctx, &block, idx, &store->node.loc); - idx_offset = hlsl_block_add_packed_index_offset_append(ctx, &block, - load->byte_offset.node, c, load->node.data_type, &store->node.loc); + if (instr->type != HLSL_IR_RESOURCE_STORE) + return false; - vector_load = hlsl_ir_resource_load(hlsl_clone_instr(ctx, &load->node)); - hlsl_src_remove(&vector_load->byte_offset); - hlsl_src_from_node(&vector_load->byte_offset, idx_offset); - vector_load->node.data_type = type; - hlsl_block_add_instr(&block, &vector_load->node); + store = hlsl_ir_resource_store(instr); + if (store->store_type != HLSL_RESOURCE_STREAM_APPEND) + return false; - hlsl_block_add_store_index(ctx, &block, &store->lhs, c, &vector_load->node, 0, &store->node.loc); + rhs = store->value.node; + var = store->resource.var; + type = hlsl_get_stream_output_type(var->data_type); - list_move_before(&store->node.entry, &block.instrs); -} + VKD3D_ASSERT(var->regs[HLSL_REGSET_STREAM_OUTPUTS].allocated); + stream_index = var->regs[HLSL_REGSET_STREAM_OUTPUTS].index; -static bool split_matrix_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) -{ - const struct hlsl_ir_node *rhs; - struct hlsl_type *element_type; - const struct hlsl_type *type; - unsigned int i; - struct hlsl_ir_store *store; + VKD3D_ASSERT(stream_index < ARRAY_SIZE(append_ctx->created)); - if (instr->type != HLSL_IR_STORE) + if (!hlsl_clone_semantic(ctx, &semantic_copy, &var->semantic)) return false; - store = hlsl_ir_store(instr); - rhs = store->rhs.node; - type = rhs->data_type; - if (type->class != HLSL_CLASS_MATRIX) - return false; - element_type = hlsl_get_vector_type(ctx, type->e.numeric.type, hlsl_type_minor_size(type)); + hlsl_block_init(&block); - if (rhs->type != HLSL_IR_LOAD && rhs->type != HLSL_IR_RESOURCE_LOAD) + if (rhs->type != HLSL_IR_LOAD) { - hlsl_fixme(ctx, &instr->loc, "Copying from unsupported node type."); - return false; + struct hlsl_ir_var *tmp_var; + + VKD3D_ASSERT(rhs->data_type); + + /* Copy the RHS to a temporary variable, and split this copy if necessary. */ + if (!(tmp_var = hlsl_new_synthetic_var(ctx, "stream-append", rhs->data_type, &instr->loc))) + goto done; + hlsl_block_add_simple_store(ctx, &block, tmp_var, rhs); + split_copies(ctx, &block); + rhs = hlsl_block_add_simple_load(ctx, &block, tmp_var, &instr->loc); } - if (rhs->type == HLSL_IR_RESOURCE_LOAD) - { - /* As we forbid non-scalar or vector types in non-structured resource - * loads, this is specific to structured buffer loads. */ - struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(rhs); + append_output_copy_recurse(ctx, &block, append_ctx->semantic_vars, type->e.so.type, hlsl_ir_load(rhs), + var->storage_modifiers, &semantic_copy, var->regs[HLSL_REGSET_STREAM_OUTPUTS].index, + false, !append_ctx->created[stream_index]); - VKD3D_ASSERT(hlsl_deref_get_type(ctx, &load->resource)->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER); + append_ctx->created[stream_index] = true; - for (i = 0; i < hlsl_type_major_size(type); ++i) - { - split_resource_load(ctx, store, load, i, element_type); - } - } - else - { - for (i = 0; i < hlsl_type_major_size(type); ++i) - { - if (!split_copy(ctx, store, hlsl_ir_load(rhs), i, element_type)) - return false; - } - } + list_move_before(&instr->entry, &block.instrs); + hlsl_src_remove(&store->value); - list_remove(&store->node.entry); - hlsl_free_instr(&store->node); - return true; + progress = true; + +done: + hlsl_cleanup_semantic(&semantic_copy); + hlsl_block_cleanup(&block); + return progress; } static struct hlsl_ir_node *lower_narrowing_casts(struct hlsl_ctx *ctx, @@ -6027,6 +6295,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop compute_liveness_recurse(&loop->body, loop_first ? loop_first : instr->index, loop_last ? loop_last : loop->next_index); + if (loop->unroll_limit.node) + loop->unroll_limit.node->last_read = last_read; break; } case HLSL_IR_RESOURCE_LOAD: @@ -6072,6 +6342,8 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop store->coords.node->last_read = last_read; if (store->value.node) store->value.node->last_read = last_read; + if (store->byte_offset.node) + store->byte_offset.node->last_read = last_read; break; } case HLSL_IR_SWIZZLE: @@ -6424,11 +6696,24 @@ static bool track_object_components_sampler_dim(struct hlsl_ctx *ctx, struct hls static void register_deref_usage(struct hlsl_ctx *ctx, const struct hlsl_deref *deref) { struct hlsl_ir_var *var = deref->var; - enum hlsl_regset regset = hlsl_deref_get_regset(ctx, deref); uint32_t required_bind_count; + enum hlsl_regset regset; struct hlsl_type *type; unsigned int index; + if (var->is_tgsm) + { + /* At this stage all TGSM loads should have already been lowered to + * resource loads, so this deref should have only originated from the + * resource field of a resource load. Moreover, since TGSM objects can + * exist only globally, and cannot be placed inside structures, this + * deref should have no path. */ + VKD3D_ASSERT(!deref->path_len); + var->bind_count[HLSL_REGSET_NUMERIC] = 1; + return; + } + + regset = hlsl_deref_get_regset(ctx, deref); hlsl_regset_index_from_deref(ctx, deref, regset, &index); if (regset <= HLSL_REGSET_LAST_OBJECT) @@ -6439,8 +6724,9 @@ static void register_deref_usage(struct hlsl_ctx *ctx, const struct hlsl_deref * else if (regset == HLSL_REGSET_NUMERIC) { type = hlsl_deref_get_type(ctx, deref); + VKD3D_ASSERT(type->class <= HLSL_CLASS_VECTOR); - required_bind_count = align(index + type->reg_size[regset], 4) / 4; + required_bind_count = align(index + type->e.numeric.dimx, 4) / 4; var->bind_count[regset] = max(var->bind_count[regset], required_bind_count); } else @@ -7753,6 +8039,10 @@ bool hlsl_regset_index_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *index += 4 * idx; break; + case HLSL_CLASS_VECTOR: + *index += idx; + break; + default: vkd3d_unreachable(); } @@ -8511,11 +8801,6 @@ static void remove_unreachable_code(struct hlsl_ctx *ctx, struct hlsl_block *bod } } -void hlsl_lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_block *body) -{ - replace_ir(ctx, lower_index_loads, body); -} - static enum hlsl_ir_expr_op invert_comparison_op(enum hlsl_ir_expr_op op) { switch (op) @@ -8760,11 +9045,11 @@ static bool simplify_exprs(struct hlsl_ctx *ctx, struct hlsl_block *block) return any_progress; } -static void hlsl_run_folding_passes(struct hlsl_ctx *ctx, struct hlsl_block *body) +static bool hlsl_run_folding_passes(struct hlsl_ctx *ctx, struct hlsl_block *body) { - bool progress; + bool progress, any_progress; - replace_ir(ctx, fold_redundant_casts, body); + any_progress = replace_ir(ctx, fold_redundant_casts, body); do { progress = simplify_exprs(ctx, body); @@ -8772,9 +9057,12 @@ static void hlsl_run_folding_passes(struct hlsl_ctx *ctx, struct hlsl_block *bod progress |= replace_ir(ctx, fold_swizzle_chains, body); progress |= replace_ir(ctx, fold_trivial_swizzles, body); progress |= hlsl_transform_ir(ctx, remove_trivial_conditional_branches, body, NULL); - progress |= hlsl_transform_ir(ctx, flatten_conditional_branches, body, NULL); + + any_progress |= progress; } while (progress); - replace_ir(ctx, fold_redundant_casts, body); + any_progress |= replace_ir(ctx, fold_redundant_casts, body); + + return any_progress; } void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body) @@ -8786,13 +9074,7 @@ void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body) replace_ir(ctx, lower_broadcasts, body); while (replace_ir(ctx, fold_redundant_casts, body)); - do - { - progress = hlsl_transform_ir(ctx, split_array_copies, body, NULL); - progress |= hlsl_transform_ir(ctx, split_struct_copies, body, NULL); - } - while (progress); - hlsl_transform_ir(ctx, split_matrix_copies, body, NULL); + split_copies(ctx, body); replace_ir(ctx, lower_narrowing_casts, body); replace_ir(ctx, lower_int_dot, body); @@ -8805,7 +9087,11 @@ void hlsl_run_const_passes(struct hlsl_ctx *ctx, struct hlsl_block *body) replace_ir(ctx, lower_casts_to_bool, body); replace_ir(ctx, lower_float_modulus, body); - hlsl_run_folding_passes(ctx, body); + do + { + progress = hlsl_run_folding_passes(ctx, body); + progress |= hlsl_transform_ir(ctx, flatten_conditional_branches, body, NULL); + } while (progress); } static void generate_vsir_signature_entry(struct hlsl_ctx *ctx, struct vsir_program *program, @@ -9082,12 +9368,12 @@ static uint32_t generate_vsir_get_src_swizzle(uint32_t src_writemask, uint32_t d return swizzle; } -static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_block *block) +static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, + struct vsir_program *program, struct hlsl_block *block) { - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; + struct vsir_dst_operand *dst; unsigned int i, x; for (i = 0; i < ctx->constant_defs.count; ++i) @@ -9106,22 +9392,20 @@ static void sm1_generate_vsir_constant_defs(struct hlsl_ctx *ctx, struct vsir_pr return; } - dst_param = &ins->dst[0]; - vsir_register_init(&dst_param->reg, VKD3DSPR_CONST, VSIR_DATA_F32, 1); - ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; - ins->dst[0].reg.idx[0].offset = constant_reg->index; - ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; + dst = &ins->dst[0]; + vsir_dst_operand_init(dst, VKD3DSPR_CONST, VSIR_DATA_F32, 1); + dst->reg.dimension = VSIR_DIMENSION_VEC4; + dst->reg.idx[0].offset = constant_reg->index; + dst->write_mask = VKD3DSP_WRITEMASK_ALL; - src_param = &ins->src[0]; - vsir_register_init(&src_param->reg, VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); - src_param->reg.type = VKD3DSPR_IMMCONST; - src_param->reg.precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; - src_param->reg.non_uniform = false; - src_param->reg.data_type = VSIR_DATA_F32; - src_param->reg.dimension = VSIR_DIMENSION_VEC4; + src = &ins->src[0]; + vsir_src_operand_init(src, VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); + src->reg.dimension = VSIR_DIMENSION_VEC4; for (x = 0; x < 4; ++x) - src_param->reg.u.immconst_f32[x] = constant_reg->value.f[x]; - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; + { + src->reg.u.immconst_f32[x] = constant_reg->value.f[x]; + } + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; } } @@ -9130,10 +9414,10 @@ static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx, { enum vkd3d_shader_resource_type resource_type; struct vkd3d_shader_register_range *range; - struct vkd3d_shader_dst_param *dst_param; struct vkd3d_shader_semantic *semantic; struct vkd3d_shader_instruction *ins; enum hlsl_sampler_dim sampler_dim; + struct vsir_dst_operand *dst; struct hlsl_ir_var *var; unsigned int i, count; @@ -9184,14 +9468,14 @@ static void sm1_generate_vsir_sampler_dcls(struct hlsl_ctx *ctx, semantic = &ins->declaration.semantic; semantic->resource_type = resource_type; - dst_param = &semantic->resource.reg; - vsir_register_init(&dst_param->reg, VKD3DSPR_COMBINED_SAMPLER, VSIR_DATA_F32, 1); - dst_param->reg.dimension = VSIR_DIMENSION_NONE; - dst_param->reg.idx[0].offset = var->regs[HLSL_REGSET_SAMPLERS].index + i; - dst_param->write_mask = 0; + dst = &semantic->resource.reg; + vsir_register_init(&dst->reg, VKD3DSPR_COMBINED_SAMPLER, VSIR_DATA_F32, 1); + dst->reg.dimension = VSIR_DIMENSION_NONE; + dst->reg.idx[0].offset = var->regs[HLSL_REGSET_SAMPLERS].index + i; + dst->write_mask = 0; range = &semantic->resource.range; range->space = 0; - range->first = range->last = dst_param->reg.idx[0].offset; + range->first = range->last = dst->reg.idx[0].offset; } } } @@ -9252,13 +9536,13 @@ static struct vkd3d_shader_instruction *generate_vsir_add_program_instruction(st return ins; } -static void vsir_src_from_hlsl_constant_value(struct vkd3d_shader_src_param *src, +static void vsir_src_from_hlsl_constant_value(struct vsir_src_operand *src, struct hlsl_ctx *ctx, const struct hlsl_constant_value *value, enum vsir_data_type type, unsigned int width, unsigned int map_writemask) { unsigned int i, j; - vsir_src_param_init(src, VKD3DSPR_IMMCONST, type, 0); + vsir_src_operand_init(src, VKD3DSPR_IMMCONST, type, 0); if (width == 1) { src->reg.u.immconst_u32[0] = value->u[0].u; @@ -9276,8 +9560,8 @@ static void vsir_src_from_hlsl_constant_value(struct vkd3d_shader_src_param *src } } -static void vsir_src_from_hlsl_node(struct vkd3d_shader_src_param *src, - struct hlsl_ctx *ctx, const struct hlsl_ir_node *instr, uint32_t map_writemask) +static void vsir_src_from_hlsl_node(struct vsir_src_operand *src, struct hlsl_ctx *ctx, + const struct hlsl_ir_node *instr, uint32_t map_writemask) { struct hlsl_ir_constant *constant; @@ -9297,12 +9581,12 @@ static void vsir_src_from_hlsl_node(struct vkd3d_shader_src_param *src, } } -static struct vkd3d_shader_src_param *sm4_generate_vsir_new_idx_src(struct hlsl_ctx *ctx, +static struct vsir_src_operand *sm4_generate_vsir_new_idx_src(struct hlsl_ctx *ctx, struct vsir_program *program, const struct hlsl_ir_node *rel_offset) { - struct vkd3d_shader_src_param *idx_src; + struct vsir_src_operand *idx_src; - if (!(idx_src = vsir_program_get_src_params(program, 1))) + if (!(idx_src = vsir_program_get_src_operands(program, 1))) { ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; return NULL; @@ -9517,7 +9801,7 @@ static bool sm4_generate_vsir_reg_from_deref(struct hlsl_ctx *ctx, struct vsir_p reg->dimension = VSIR_DIMENSION_VEC4; reg->idx[0].offset = var->regs[HLSL_REGSET_NUMERIC].id; reg->idx_count = 1; - *writemask = (1u << data_type->e.numeric.dimx) - 1; + *writemask = VKD3DSP_WRITEMASK_ALL; } else { @@ -9526,36 +9810,38 @@ static bool sm4_generate_vsir_reg_from_deref(struct hlsl_ctx *ctx, struct vsir_p return true; } -static bool sm4_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx, struct vsir_program *program, - struct vkd3d_shader_src_param *src_param, const struct hlsl_deref *deref, +static bool sm4_generate_vsir_init_src_operand_from_deref(struct hlsl_ctx *ctx, + struct vsir_program *program, struct vsir_src_operand *src, const struct hlsl_deref *deref, unsigned int dst_writemask, const struct vkd3d_shader_location *loc) { uint32_t writemask; - if (!sm4_generate_vsir_reg_from_deref(ctx, program, &src_param->reg, &writemask, deref)) + if (!sm4_generate_vsir_reg_from_deref(ctx, program, &src->reg, &writemask, deref)) return false; - if (src_param->reg.dimension != VSIR_DIMENSION_NONE) - src_param->swizzle = generate_vsir_get_src_swizzle(writemask, dst_writemask); + if (src->reg.dimension != VSIR_DIMENSION_NONE) + src->swizzle = generate_vsir_get_src_swizzle(writemask, dst_writemask); + return true; } -static bool sm4_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx, struct vsir_program *program, - struct vkd3d_shader_dst_param *dst_param, const struct hlsl_deref *deref, +static bool sm4_generate_vsir_init_dst_operand_from_deref(struct hlsl_ctx *ctx, + struct vsir_program *program, struct vsir_dst_operand *dst, const struct hlsl_deref *deref, const struct vkd3d_shader_location *loc, unsigned int writemask) { uint32_t reg_writemask; - if (!sm4_generate_vsir_reg_from_deref(ctx, program, &dst_param->reg, ®_writemask, deref)) + if (!sm4_generate_vsir_reg_from_deref(ctx, program, &dst->reg, ®_writemask, deref)) return false; - dst_param->write_mask = hlsl_combine_writemasks(reg_writemask, writemask); + dst->write_mask = hlsl_combine_writemasks(reg_writemask, writemask); + return true; } -static void vsir_dst_from_hlsl_node(struct vkd3d_shader_dst_param *dst, +static void vsir_dst_from_hlsl_node(struct vsir_dst_operand *dst, struct hlsl_ctx *ctx, const struct hlsl_ir_node *instr) { VKD3D_ASSERT(instr->reg.allocated); - vsir_dst_param_init(dst, instr->reg.type, vsir_data_type_from_hlsl_instruction(ctx, instr), 1); + vsir_dst_operand_init(dst, instr->reg.type, vsir_data_type_from_hlsl_instruction(ctx, instr), 1); dst->reg.idx[0].offset = instr->reg.id; dst->reg.dimension = VSIR_DIMENSION_VEC4; dst->write_mask = instr->reg.writemask; @@ -9565,8 +9851,8 @@ static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_constant *constant) { struct hlsl_ir_node *instr = &constant->node; - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; VKD3D_ASSERT(instr->reg.allocated); VKD3D_ASSERT(constant->reg.allocated); @@ -9574,11 +9860,11 @@ static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_MOV, 1, 1))) return; - src_param = &ins->src[0]; - vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VSIR_DATA_F32, 1); - src_param->reg.dimension = VSIR_DIMENSION_VEC4; - src_param->reg.idx[0].offset = constant->reg.id; - src_param->swizzle = generate_vsir_get_src_swizzle(constant->reg.writemask, instr->reg.writemask); + src = &ins->src[0]; + vsir_src_operand_init(src, VKD3DSPR_CONST, VSIR_DATA_F32, 1); + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->reg.idx[0].offset = constant->reg.id; + src->swizzle = generate_vsir_get_src_swizzle(constant->reg.writemask, instr->reg.writemask); vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr); } @@ -9586,9 +9872,9 @@ static void sm1_generate_vsir_instr_constant(struct hlsl_ctx *ctx, static void sm4_generate_vsir_rasterizer_sample_count(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_expr *expr) { - struct vkd3d_shader_src_param *src_param; struct hlsl_ir_node *instr = &expr->node; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_SAMPLE_INFO, 1, 1))) return; @@ -9596,10 +9882,10 @@ static void sm4_generate_vsir_rasterizer_sample_count(struct hlsl_ctx *ctx, vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr); - src_param = &ins->src[0]; - vsir_src_param_init(src_param, VKD3DSPR_RASTERIZER, VSIR_DATA_UNUSED, 0); - src_param->reg.dimension = VSIR_DIMENSION_VEC4; - src_param->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + src = &ins->src[0]; + vsir_src_operand_init(src, VKD3DSPR_RASTERIZER, VSIR_DATA_UNUSED, 0); + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); } /* Translate ops that can be mapped to a single vsir instruction with only one dst register. */ @@ -9608,10 +9894,10 @@ static void generate_vsir_instr_expr_single_instr_op(struct hlsl_ctx *ctx, uint32_t src_mod, uint32_t dst_mod, bool map_src_swizzles) { struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; unsigned int i, src_count = 0; + struct vsir_src_operand *src; + struct vsir_dst_operand *dst; VKD3D_ASSERT(instr->reg.allocated); @@ -9625,18 +9911,17 @@ static void generate_vsir_instr_expr_single_instr_op(struct hlsl_ctx *ctx, if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, src_count))) return; - dst_param = &ins->dst[0]; - vsir_dst_from_hlsl_node(dst_param, ctx, instr); - dst_param->modifiers = dst_mod; + dst = &ins->dst[0]; + vsir_dst_from_hlsl_node(dst, ctx, instr); + dst->modifiers = dst_mod; for (i = 0; i < src_count; ++i) { struct hlsl_ir_node *operand = expr->operands[i].node; - src_param = &ins->src[i]; - vsir_src_from_hlsl_node(src_param, ctx, operand, - map_src_swizzles ? dst_param->write_mask : VKD3DSP_WRITEMASK_ALL); - src_param->modifiers = src_mod; + src = &ins->src[i]; + vsir_src_from_hlsl_node(src, ctx, operand, map_src_swizzles ? dst->write_mask : VKD3DSP_WRITEMASK_ALL); + src->modifiers = src_mod; } } @@ -9647,9 +9932,9 @@ static void sm1_generate_vsir_instr_expr_per_component_instr_op(struct hlsl_ctx { 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 vsir_src_operand *src; + struct vsir_dst_operand *dst; uint32_t src_swizzle; unsigned int i, c; @@ -9664,18 +9949,18 @@ static void sm1_generate_vsir_instr_expr_per_component_instr_op(struct hlsl_ctx if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, 1))) return; - dst_param = &ins->dst[0]; - vsir_register_init(&dst_param->reg, instr->reg.type, VSIR_DATA_F32, 1); - dst_param->reg.idx[0].offset = instr->reg.id; - dst_param->reg.dimension = VSIR_DIMENSION_VEC4; - dst_param->write_mask = 1u << i; + dst = &ins->dst[0]; + vsir_dst_operand_init(dst, instr->reg.type, VSIR_DATA_F32, 1); + dst->reg.idx[0].offset = instr->reg.id; + dst->reg.dimension = VSIR_DIMENSION_VEC4; + dst->write_mask = 1u << i; - src_param = &ins->src[0]; - vsir_register_init(&src_param->reg, operand->reg.type, VSIR_DATA_F32, 1); - src_param->reg.idx[0].offset = operand->reg.id; - src_param->reg.dimension = VSIR_DIMENSION_VEC4; + src = &ins->src[0]; + vsir_src_operand_init(src, operand->reg.type, VSIR_DATA_F32, 1); + src->reg.idx[0].offset = operand->reg.id; + src->reg.dimension = VSIR_DIMENSION_VEC4; c = vsir_swizzle_get_component(src_swizzle, i); - src_param->swizzle = vsir_swizzle_from_writemask(1u << c); + src->swizzle = vsir_swizzle_from_writemask(1u << c); } } } @@ -9685,8 +9970,8 @@ static void sm1_generate_vsir_instr_expr_sincos(struct hlsl_ctx *ctx, struct vsi { struct hlsl_ir_node *operand = expr->operands[0].node; struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; unsigned int src_count = 0; VKD3D_ASSERT(instr->reg.allocated); @@ -9700,17 +9985,17 @@ static void sm1_generate_vsir_instr_expr_sincos(struct hlsl_ctx *ctx, struct vsi if (ctx->profile->major_version < 3) { - src_param = &ins->src[1]; - vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VSIR_DATA_F32, 1); - src_param->reg.dimension = VSIR_DIMENSION_VEC4; - src_param->reg.idx[0].offset = ctx->d3dsincosconst1.id; - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; + src = &ins->src[1]; + vsir_src_operand_init(src, VKD3DSPR_CONST, VSIR_DATA_F32, 1); + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->reg.idx[0].offset = ctx->d3dsincosconst1.id; + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; - src_param = &ins->src[2]; - vsir_register_init(&src_param->reg, VKD3DSPR_CONST, VSIR_DATA_F32, 1); - src_param->reg.dimension = VSIR_DIMENSION_VEC4; - src_param->reg.idx[0].offset = ctx->d3dsincosconst2.id; - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; + src = &ins->src[2]; + vsir_src_operand_init(src, VKD3DSPR_CONST, VSIR_DATA_F32, 1); + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->reg.idx[0].offset = ctx->d3dsincosconst2.id; + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; } } @@ -9981,9 +10266,8 @@ err: return false; } -static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx, - struct vkd3d_shader_dst_param *dst_param, struct hlsl_deref *deref, - const struct vkd3d_shader_location *loc, unsigned int writemask) +static void sm1_generate_vsir_init_dst_operand_from_deref(struct hlsl_ctx *ctx, struct vsir_dst_operand *dst, + struct hlsl_deref *deref, const struct vkd3d_shader_location *loc, unsigned int writemask) { enum vkd3d_shader_register_type type = VKD3DSPR_TEMP; struct vkd3d_shader_version version; @@ -10030,16 +10314,16 @@ static void sm1_generate_vsir_init_dst_param_from_deref(struct hlsl_ctx *ctx, if (type == VKD3DSPR_DEPTHOUT) { - vsir_register_init(&dst_param->reg, type, VSIR_DATA_F32, 0); - dst_param->reg.dimension = VSIR_DIMENSION_SCALAR; + vsir_register_init(&dst->reg, type, VSIR_DATA_F32, 0); + dst->reg.dimension = VSIR_DIMENSION_SCALAR; } else { - vsir_register_init(&dst_param->reg, type, VSIR_DATA_F32, 1); - dst_param->reg.idx[0].offset = register_index; - dst_param->reg.dimension = VSIR_DIMENSION_VEC4; + vsir_register_init(&dst->reg, type, VSIR_DATA_F32, 1); + dst->reg.idx[0].offset = register_index; + dst->reg.dimension = VSIR_DIMENSION_VEC4; } - dst_param->write_mask = writemask; + dst->write_mask = writemask; if (deref->rel_offset.node) hlsl_fixme(ctx, loc, "Translate relative addressing on dst register for vsir."); @@ -10049,29 +10333,28 @@ static void sm1_generate_vsir_instr_mova(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_node *instr) { enum vkd3d_shader_opcode opcode = hlsl_version_ge(ctx, 2, 0) ? VSIR_OP_MOVA : VSIR_OP_MOV; - struct vkd3d_shader_dst_param *dst_param; struct vkd3d_shader_instruction *ins; + struct vsir_dst_operand *dst; VKD3D_ASSERT(instr->reg.allocated); if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 1, 1))) return; - dst_param = &ins->dst[0]; - vsir_register_init(&dst_param->reg, VKD3DSPR_ADDR, VSIR_DATA_F32, 0); - dst_param->write_mask = VKD3DSP_WRITEMASK_0; + dst = &ins->dst[0]; + vsir_register_init(&dst->reg, VKD3DSPR_ADDR, VSIR_DATA_F32, 0); + dst->write_mask = VKD3DSP_WRITEMASK_0; VKD3D_ASSERT(instr->data_type->class <= HLSL_CLASS_VECTOR); VKD3D_ASSERT(instr->data_type->e.numeric.dimx == 1); vsir_src_from_hlsl_node(&ins->src[0], ctx, instr, VKD3DSP_WRITEMASK_ALL); } -static struct vkd3d_shader_src_param *sm1_generate_vsir_new_address_src(struct hlsl_ctx *ctx, - struct vsir_program *program) +static struct vsir_src_operand *sm1_generate_vsir_new_address_src(struct hlsl_ctx *ctx, struct vsir_program *program) { - struct vkd3d_shader_src_param *idx_src; + struct vsir_src_operand *idx_src; - if (!(idx_src = vsir_program_get_src_params(program, 1))) + if (!(idx_src = vsir_program_get_src_operands(program, 1))) { ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; return NULL; @@ -10084,12 +10367,12 @@ static struct vkd3d_shader_src_param *sm1_generate_vsir_new_address_src(struct h return idx_src; } -static void sm1_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx, - struct vsir_program *program, struct vkd3d_shader_src_param *src_param, - struct hlsl_deref *deref, uint32_t dst_writemask, const struct vkd3d_shader_location *loc) +static void sm1_generate_vsir_init_src_operand_from_deref(struct hlsl_ctx *ctx, + struct vsir_program *program, struct vsir_src_operand *src, struct hlsl_deref *deref, + uint32_t dst_writemask, const struct vkd3d_shader_location *loc) { enum vkd3d_shader_register_type type = VKD3DSPR_TEMP; - struct vkd3d_shader_src_param *src_rel_addr = NULL; + struct vsir_src_operand *src_rel_addr = NULL; struct vkd3d_shader_version version; uint32_t register_index; unsigned int writemask; @@ -10157,11 +10440,11 @@ static void sm1_generate_vsir_init_src_param_from_deref(struct hlsl_ctx *ctx, writemask = reg.writemask; } - vsir_register_init(&src_param->reg, type, VSIR_DATA_F32, 1); - src_param->reg.dimension = VSIR_DIMENSION_VEC4; - src_param->reg.idx[0].offset = register_index; - src_param->reg.idx[0].rel_addr = src_rel_addr; - src_param->swizzle = generate_vsir_get_src_swizzle(writemask, dst_writemask); + vsir_src_operand_init(src, type, VSIR_DATA_F32, 1); + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->reg.idx[0].offset = register_index; + src->reg.idx[0].rel_addr = src_rel_addr; + src->swizzle = generate_vsir_get_src_swizzle(writemask, dst_writemask); } static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_program *program, @@ -10180,7 +10463,7 @@ static void sm1_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_progr vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr); - sm1_generate_vsir_init_src_param_from_deref(ctx, program, &ins->src[0], + sm1_generate_vsir_init_src_operand_from_deref(ctx, program, &ins->src[0], &load->src, ins->dst[0].write_mask, &ins->location); } @@ -10191,7 +10474,6 @@ static void sm1_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, 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_src_param *src_param; struct vkd3d_shader_instruction *ins; enum vkd3d_shader_opcode opcode; unsigned int src_count = 2; @@ -10235,19 +10517,14 @@ static void sm1_generate_vsir_instr_resource_load(struct hlsl_ctx *ctx, vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr); - src_param = &ins->src[0]; - vsir_src_from_hlsl_node(src_param, ctx, coords, VKD3DSP_WRITEMASK_ALL); - - sm1_generate_vsir_init_src_param_from_deref(ctx, program, &ins->src[1], &load->resource, - VKD3DSP_WRITEMASK_ALL, &ins->location); + vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, VKD3DSP_WRITEMASK_ALL); + sm1_generate_vsir_init_src_operand_from_deref(ctx, program, &ins->src[1], + &load->resource, VKD3DSP_WRITEMASK_ALL, &ins->location); if (load->load_type == HLSL_RESOURCE_SAMPLE_GRAD) { - src_param = &ins->src[2]; - vsir_src_from_hlsl_node(src_param, ctx, ddx, VKD3DSP_WRITEMASK_ALL); - - src_param = &ins->src[3]; - vsir_src_from_hlsl_node(src_param, ctx, ddy, VKD3DSP_WRITEMASK_ALL); + vsir_src_from_hlsl_node(&ins->src[2], ctx, ddx, VKD3DSP_WRITEMASK_ALL); + vsir_src_from_hlsl_node(&ins->src[3], ctx, ddy, VKD3DSP_WRITEMASK_ALL); } } @@ -10255,8 +10532,8 @@ static void generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_swizzle *swizzle_instr) { struct hlsl_ir_node *instr = &swizzle_instr->node, *val = swizzle_instr->val.node; - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; uint32_t swizzle; VKD3D_ASSERT(instr->reg.allocated); @@ -10270,29 +10547,27 @@ static void generate_vsir_instr_swizzle(struct hlsl_ctx *ctx, swizzle = hlsl_combine_swizzles(swizzle, swizzle_instr->u.vector, instr->data_type->e.numeric.dimx); swizzle = hlsl_map_swizzle(swizzle, ins->dst[0].write_mask); - src_param = &ins->src[0]; + src = &ins->src[0]; VKD3D_ASSERT(val->type != HLSL_IR_CONSTANT); - vsir_register_init(&src_param->reg, val->reg.type, vsir_data_type_from_hlsl_instruction(ctx, val), 1); - src_param->reg.idx[0].offset = val->reg.id; - src_param->reg.dimension = VSIR_DIMENSION_VEC4; - src_param->swizzle = swizzle; + vsir_src_operand_init(src, val->reg.type, vsir_data_type_from_hlsl_instruction(ctx, val), 1); + src->reg.idx[0].offset = val->reg.id; + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->swizzle = swizzle; } -static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_program *program, - struct hlsl_ir_store *store) +static void sm1_generate_vsir_instr_store(struct hlsl_ctx *ctx, + struct vsir_program *program, struct hlsl_ir_store *store) { struct hlsl_ir_node *rhs = store->rhs.node; struct hlsl_ir_node *instr = &store->node; struct vkd3d_shader_instruction *ins; - struct vkd3d_shader_src_param *src_param; if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_MOV, 1, 1))) return; - sm1_generate_vsir_init_dst_param_from_deref(ctx, &ins->dst[0], &store->lhs, &ins->location, store->writemask); + sm1_generate_vsir_init_dst_operand_from_deref(ctx, &ins->dst[0], &store->lhs, &ins->location, store->writemask); - src_param = &ins->src[0]; - vsir_src_from_hlsl_node(src_param, ctx, rhs, ins->dst[0].write_mask); + vsir_src_from_hlsl_node(&ins->src[0], ctx, rhs, ins->dst[0].write_mask); } static void sm1_generate_vsir_instr_jump(struct hlsl_ctx *ctx, @@ -10322,9 +10597,9 @@ static void sm1_generate_vsir_block(struct hlsl_ctx *ctx, struct hlsl_block *blo static void sm1_generate_vsir_instr_if(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_if *iff) { struct hlsl_ir_node *condition = iff->condition.node; - struct vkd3d_shader_src_param *src_param; struct hlsl_ir_node *instr = &iff->node; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; /* Conditional branches should have already been flattened for SM < 2.1. */ VKD3D_ASSERT(hlsl_version_ge(ctx, 2, 1)); @@ -10335,13 +10610,13 @@ static void sm1_generate_vsir_instr_if(struct hlsl_ctx *ctx, struct vsir_program return; ins->flags = VKD3D_SHADER_REL_OP_NE; - src_param = &ins->src[0]; - vsir_src_from_hlsl_node(src_param, ctx, condition, VKD3DSP_WRITEMASK_ALL); - src_param->modifiers = 0; + src = &ins->src[0]; + vsir_src_from_hlsl_node(src, ctx, condition, VKD3DSP_WRITEMASK_ALL); + src->modifiers = 0; - src_param = &ins->src[1]; - vsir_src_from_hlsl_node(src_param, ctx, condition, VKD3DSP_WRITEMASK_ALL); - src_param->modifiers = VKD3DSPSM_NEG; + src = &ins->src[1]; + vsir_src_from_hlsl_node(src, ctx, condition, VKD3DSP_WRITEMASK_ALL); + src->modifiers = VKD3DSPSM_NEG; sm1_generate_vsir_block(ctx, &iff->then_block, program); @@ -10605,11 +10880,25 @@ D3DXPARAMETER_TYPE hlsl_sm1_base_type(const struct hlsl_type *type, vkd3d_unreachable(); } -static void write_sm1_type(struct vkd3d_bytecode_buffer *buffer, struct hlsl_type *type, +struct ctab_ctx +{ + struct hlsl_ctx *hlsl; + + struct vkd3d_bytecode_buffer buffer; + + struct ctab_type_info + { + unsigned int bytecode_offset; + } *type_info; +}; + +static void ctab_write_type(struct ctab_ctx *ctab, struct hlsl_type *type, bool is_combined_sampler, enum hlsl_sampler_dim sampler_dim, unsigned int ctab_start) { const struct hlsl_type *array_type = hlsl_get_multiarray_element_type(type); + struct ctab_type_info *type_info = &ctab->type_info[type->type_id]; unsigned int array_size = hlsl_get_multiarray_size(type); + struct vkd3d_bytecode_buffer *buffer = &ctab->buffer; struct hlsl_struct_field *field; size_t i; @@ -10617,7 +10906,7 @@ static void write_sm1_type(struct vkd3d_bytecode_buffer *buffer, struct hlsl_typ * samplers. Apparently it deals with this by never deduplicating any * sampler types. This is not very efficient, but we may as well do the * same. */ - if (type->bytecode_offset && array_type->class != HLSL_CLASS_SAMPLER) + if (type_info->bytecode_offset && array_type->class != HLSL_CLASS_SAMPLER) return; if (array_type->class == HLSL_CLASS_STRUCT) @@ -10629,26 +10918,29 @@ static void write_sm1_type(struct vkd3d_bytecode_buffer *buffer, struct hlsl_typ { field = &array_type->e.record.fields[i]; field->name_bytecode_offset = put_string(buffer, field->name); - write_sm1_type(buffer, field->type, false, HLSL_SAMPLER_DIM_GENERIC, ctab_start); + ctab_write_type(ctab, field->type, false, HLSL_SAMPLER_DIM_GENERIC, ctab_start); } fields_offset = bytecode_align(buffer) - ctab_start; for (i = 0; i < field_count; ++i) { + struct ctab_type_info *field_type_info; + field = &array_type->e.record.fields[i]; + field_type_info = &ctab->type_info[field->type->type_id]; put_u32(buffer, field->name_bytecode_offset - ctab_start); - put_u32(buffer, field->type->bytecode_offset - ctab_start); + put_u32(buffer, field_type_info->bytecode_offset - ctab_start); } - type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3DXPC_STRUCT, D3DXPT_VOID)); + type_info->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3DXPC_STRUCT, D3DXPT_VOID)); put_u32(buffer, vkd3d_make_u32(1, hlsl_type_component_count(array_type))); put_u32(buffer, vkd3d_make_u32(array_size, field_count)); put_u32(buffer, fields_offset); } else { - type->bytecode_offset = put_u32(buffer, + type_info->bytecode_offset = put_u32(buffer, vkd3d_make_u32(hlsl_sm1_class(type), hlsl_sm1_base_type(array_type, is_combined_sampler, sampler_dim))); if (hlsl_is_numeric_type(array_type)) put_u32(buffer, vkd3d_make_u32(array_type->e.numeric.dimy, array_type->e.numeric.dimx)); @@ -10692,10 +10984,12 @@ static void sm1_sort_externs(struct hlsl_ctx *ctx) list_move_tail(&ctx->extern_vars, &sorted); } -static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer) +static void ctab_write_uniforms(struct ctab_ctx *ctab) { size_t ctab_start, vars_offset, vars_start, creator_offset, offset; + struct vkd3d_bytecode_buffer *buffer = &ctab->buffer; unsigned int uniform_count = 0, r; + struct hlsl_ctx *ctx = ctab->hlsl; struct hlsl_ir_var *var; LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) @@ -10764,6 +11058,8 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { + struct ctab_type_info *var_type_info = &ctab->type_info[var->data_type->type_id]; + for (r = 0; r <= HLSL_REGSET_LAST; ++r) { enum hlsl_sampler_dim sampler_dim = HLSL_SAMPLER_DIM_GENERIC; @@ -10792,8 +11088,8 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe name_offset = put_string(buffer, var->name); set_u32(buffer, var_offset, name_offset - ctab_start); - write_sm1_type(buffer, var->data_type, var->is_combined_sampler, sampler_dim, ctab_start); - set_u32(buffer, var_offset + 3 * sizeof(uint32_t), var->data_type->bytecode_offset - ctab_start); + ctab_write_type(ctab, var->data_type, var->is_combined_sampler, sampler_dim, ctab_start); + set_u32(buffer, var_offset + 3 * sizeof(uint32_t), var_type_info->bytecode_offset - ctab_start); if (var->default_values) { @@ -10858,19 +11154,42 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe set_u32(buffer, creator_offset, offset - ctab_start); } -static void sm1_generate_ctab(struct hlsl_ctx *ctx, struct vkd3d_shader_code *ctab) +static void ctab_ctx_cleanup(struct ctab_ctx *ctab) +{ + vkd3d_free(ctab->type_info); + vkd3d_bytecode_buffer_cleanup(&ctab->buffer); +} + +static int ctab_ctx_init(struct ctab_ctx *ctab, struct hlsl_ctx *hlsl) +{ + ctab->hlsl = hlsl; + + memset(&ctab->buffer, 0, sizeof(ctab->buffer)); + + if (!(ctab->type_info = vkd3d_calloc(hlsl->type_count, sizeof(*ctab->type_info)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + return VKD3D_OK; +} + +static void sm1_generate_ctab(struct hlsl_ctx *hlsl, struct vkd3d_shader_code *out) { - struct vkd3d_bytecode_buffer buffer = {0}; + struct ctab_ctx ctab; + int ret; - write_sm1_uniforms(ctx, &buffer); - if (buffer.status) + if ((ret = ctab_ctx_init(&ctab, hlsl)) < 0) { - vkd3d_free(buffer.data); - ctx->result = buffer.status; + hlsl->result = ret; return; } - ctab->code = buffer.data; - ctab->size = buffer.size; + + ctab_write_uniforms(&ctab); + if (hlsl->result >= 0 && ctab.buffer.status < 0) + hlsl->result = ctab.buffer.status; + if (hlsl->result >= 0) + vkd3d_shader_code_from_bytecode_buffer(out, &ctab.buffer); + + ctab_ctx_cleanup(&ctab); } static enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d_shader_sysval_semantic sysval, @@ -10931,10 +11250,10 @@ static void sm4_generate_vsir_instr_dcl_semantic(struct hlsl_ctx *ctx, struct vs const bool is_primitive = hlsl_type_is_primitive_array(var->data_type); const bool output = var->is_output_semantic; enum vkd3d_shader_sysval_semantic semantic; - struct vkd3d_shader_dst_param *dst_param; struct vkd3d_shader_instruction *ins; enum vkd3d_shader_register_type type; enum vkd3d_shader_opcode opcode; + struct vsir_dst_operand *dst; unsigned int idx = 0; uint32_t write_mask; bool has_idx; @@ -11013,44 +11332,44 @@ static void sm4_generate_vsir_instr_dcl_semantic(struct hlsl_ctx *ctx, struct vs { VKD3D_ASSERT(semantic == VKD3D_SHADER_SV_NONE || semantic == VKD3D_SHADER_SV_TARGET || version->type == VKD3D_SHADER_TYPE_HULL || type != VKD3DSPR_OUTPUT); - dst_param = &ins->declaration.dst; + dst = &ins->declaration.dst; } else if (opcode == VSIR_OP_DCL_INPUT || opcode == VSIR_OP_DCL_INPUT_PS) { VKD3D_ASSERT(semantic == VKD3D_SHADER_SV_NONE || is_primitive || version->type == VKD3D_SHADER_TYPE_GEOMETRY); - dst_param = &ins->declaration.dst; + dst = &ins->declaration.dst; } else { VKD3D_ASSERT(semantic != VKD3D_SHADER_SV_NONE); ins->declaration.register_semantic.sysval_semantic = vkd3d_siv_from_sysval_indexed(semantic, var->semantic.index); - dst_param = &ins->declaration.register_semantic.reg; + dst = &ins->declaration.register_semantic.reg; } if (is_primitive) { VKD3D_ASSERT(has_idx); - vsir_register_init(&dst_param->reg, type, VSIR_DATA_F32, 2); - dst_param->reg.idx[0].offset = var->data_type->e.array.elements_count; - dst_param->reg.idx[1].offset = idx; + vsir_register_init(&dst->reg, type, VSIR_DATA_F32, 2); + dst->reg.idx[0].offset = var->data_type->e.array.elements_count; + dst->reg.idx[1].offset = idx; } else if (has_idx) { - vsir_register_init(&dst_param->reg, type, VSIR_DATA_F32, 1); - dst_param->reg.idx[0].offset = idx; + vsir_register_init(&dst->reg, type, VSIR_DATA_F32, 1); + dst->reg.idx[0].offset = idx; } else { - vsir_register_init(&dst_param->reg, type, VSIR_DATA_F32, 0); + vsir_register_init(&dst->reg, type, VSIR_DATA_F32, 0); } - if (shader_sm4_is_scalar_register(&dst_param->reg)) - dst_param->reg.dimension = VSIR_DIMENSION_SCALAR; + if (shader_sm4_is_scalar_register(&dst->reg)) + dst->reg.dimension = VSIR_DIMENSION_SCALAR; else - dst_param->reg.dimension = VSIR_DIMENSION_VEC4; + dst->reg.dimension = VSIR_DIMENSION_VEC4; - dst_param->write_mask = write_mask; + dst->write_mask = write_mask; if (var->is_input_semantic && version->type == VKD3D_SHADER_TYPE_PIXEL) ins->flags = get_interpolation_mode(version, var->data_type, var->storage_modifiers); @@ -11094,20 +11413,20 @@ static void sm4_generate_vsir_cast_from_bool(struct hlsl_ctx *ctx, struct vsir_p { struct hlsl_ir_node *operand = expr->operands[0].node; const struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_dst_param *dst_param; struct hlsl_constant_value value = {0}; struct vkd3d_shader_instruction *ins; + struct vsir_dst_operand *dst; VKD3D_ASSERT(instr->reg.allocated); if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_AND, 1, 2))) return; - dst_param = &ins->dst[0]; - vsir_dst_from_hlsl_node(dst_param, ctx, instr); + dst = &ins->dst[0]; + vsir_dst_from_hlsl_node(dst, ctx, instr); ins->dst[0].reg.data_type = VSIR_DATA_U32; - vsir_src_from_hlsl_node(&ins->src[0], ctx, operand, dst_param->write_mask); + vsir_src_from_hlsl_node(&ins->src[0], ctx, operand, dst->write_mask); value.u[0].u = bits; vsir_src_from_hlsl_constant_value(&ins->src[1], ctx, &value, VSIR_DATA_U32, 1, 0); @@ -11224,8 +11543,8 @@ static void sm4_generate_vsir_expr_with_two_destinations(struct hlsl_ctx *ctx, s enum vkd3d_shader_opcode opcode, const struct hlsl_ir_expr *expr, unsigned int dst_idx) { const struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_dst_param *dst_param; struct vkd3d_shader_instruction *ins; + struct vsir_dst_operand *dst; unsigned int i, src_count; VKD3D_ASSERT(instr->reg.allocated); @@ -11239,13 +11558,13 @@ static void sm4_generate_vsir_expr_with_two_destinations(struct hlsl_ctx *ctx, s if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, opcode, 2, src_count))) return; - dst_param = &ins->dst[dst_idx]; - vsir_dst_from_hlsl_node(dst_param, ctx, instr); + dst = &ins->dst[dst_idx]; + vsir_dst_from_hlsl_node(dst, ctx, instr); - vsir_dst_param_init_null(&ins->dst[1 - dst_idx]); + vsir_dst_operand_init_null(&ins->dst[1 - dst_idx]); for (i = 0; i < src_count; ++i) - vsir_src_from_hlsl_node(&ins->src[i], ctx, expr->operands[i].node, dst_param->write_mask); + vsir_src_from_hlsl_node(&ins->src[i], ctx, expr->operands[i].node, dst->write_mask); } static void sm4_generate_vsir_rcp_using_div(struct hlsl_ctx *ctx, @@ -11253,26 +11572,26 @@ static void sm4_generate_vsir_rcp_using_div(struct hlsl_ctx *ctx, { struct hlsl_ir_node *operand = expr->operands[0].node; const struct hlsl_ir_node *instr = &expr->node; - struct vkd3d_shader_dst_param *dst_param; struct hlsl_constant_value value = {0}; struct vkd3d_shader_instruction *ins; + struct vsir_dst_operand *dst; VKD3D_ASSERT(type_is_float(expr->node.data_type)); if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_DIV, 1, 2))) return; - dst_param = &ins->dst[0]; - vsir_dst_from_hlsl_node(dst_param, ctx, instr); + dst = &ins->dst[0]; + vsir_dst_from_hlsl_node(dst, ctx, instr); value.u[0].f = 1.0f; value.u[1].f = 1.0f; value.u[2].f = 1.0f; value.u[3].f = 1.0f; vsir_src_from_hlsl_constant_value(&ins->src[0], ctx, &value, - VSIR_DATA_F32, instr->data_type->e.numeric.dimx, dst_param->write_mask); + VSIR_DATA_F32, instr->data_type->e.numeric.dimx, dst->write_mask); - vsir_src_from_hlsl_node(&ins->src[1], ctx, operand, dst_param->write_mask); + vsir_src_from_hlsl_node(&ins->src[1], ctx, operand, dst->write_mask); } static bool sm4_generate_vsir_instr_expr(struct hlsl_ctx *ctx, @@ -11772,22 +12091,20 @@ static bool sm4_generate_vsir_instr_store(struct hlsl_ctx *ctx, struct vsir_program *program, struct hlsl_ir_store *store) { struct hlsl_ir_node *instr = &store->node; - struct vkd3d_shader_dst_param *dst_param; - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; + struct vsir_dst_operand *dst; VKD3D_ASSERT(!store->lhs.var->is_tgsm); if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_MOV, 1, 1))) return false; - dst_param = &ins->dst[0]; - if (!sm4_generate_vsir_init_dst_param_from_deref(ctx, program, - dst_param, &store->lhs, &instr->loc, store->writemask)) + dst = &ins->dst[0]; + if (!sm4_generate_vsir_init_dst_operand_from_deref(ctx, program, + dst, &store->lhs, &instr->loc, store->writemask)) return false; - src_param = &ins->src[0]; - vsir_src_from_hlsl_node(src_param, ctx, store->rhs.node, dst_param->write_mask); + vsir_src_from_hlsl_node(&ins->src[0], ctx, store->rhs.node, dst->write_mask); return true; } @@ -11807,10 +12124,10 @@ static bool sm4_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_progr { const struct vkd3d_shader_version *version = &program->shader_version; const struct hlsl_type *type = load->node.data_type; - struct vkd3d_shader_dst_param *dst_param; struct hlsl_ir_node *instr = &load->node; struct vkd3d_shader_instruction *ins; struct hlsl_constant_value value; + struct vsir_dst_operand *dst; VKD3D_ASSERT(!load->src.var->is_tgsm); VKD3D_ASSERT(hlsl_is_numeric_type(type)); @@ -11822,30 +12139,30 @@ static bool sm4_generate_vsir_instr_load(struct hlsl_ctx *ctx, struct vsir_progr if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_MOVC, 1, 3))) return false; - dst_param = &ins->dst[0]; - vsir_dst_from_hlsl_node(dst_param, ctx, instr); + dst = &ins->dst[0]; + vsir_dst_from_hlsl_node(dst, ctx, instr); - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, - &ins->src[0], &load->src, dst_param->write_mask, &instr->loc)) + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, + &ins->src[0], &load->src, dst->write_mask, &instr->loc)) return false; memset(&value, 0xff, sizeof(value)); vsir_src_from_hlsl_constant_value(&ins->src[1], ctx, &value, - VSIR_DATA_U32, type->e.numeric.dimx, dst_param->write_mask); + VSIR_DATA_U32, type->e.numeric.dimx, dst->write_mask); memset(&value, 0x00, sizeof(value)); vsir_src_from_hlsl_constant_value(&ins->src[2], ctx, &value, - VSIR_DATA_U32, type->e.numeric.dimx, dst_param->write_mask); + VSIR_DATA_U32, type->e.numeric.dimx, dst->write_mask); } else { if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_MOV, 1, 1))) return false; - dst_param = &ins->dst[0]; - vsir_dst_from_hlsl_node(dst_param, ctx, instr); + dst = &ins->dst[0]; + vsir_dst_from_hlsl_node(dst, ctx, instr); - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, - &ins->src[0], &load->src, dst_param->write_mask, &instr->loc)) + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, + &ins->src[0], &load->src, dst->write_mask, &instr->loc)) return false; } return true; @@ -11859,6 +12176,7 @@ static bool sm4_generate_vsir_instr_resource_store(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr = &store->node; bool tgsm = store->resource.var->is_tgsm; struct vkd3d_shader_instruction *ins; + bool structured; if (store->store_type != HLSL_RESOURCE_STORE) { @@ -11878,8 +12196,8 @@ static bool sm4_generate_vsir_instr_resource_store(struct hlsl_ctx *ctx, if (!(ins = generate_vsir_add_program_instruction(ctx, program, &store->node.loc, opcode, 0, 1))) return false; - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, &ins->src[0], - &store->resource, VKD3DSP_WRITEMASK_ALL, &instr->loc)) + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, + &ins->src[0], &store->resource, VKD3DSP_WRITEMASK_ALL, &instr->loc)) return false; return true; @@ -11891,39 +12209,44 @@ static bool sm4_generate_vsir_instr_resource_store(struct hlsl_ctx *ctx, return false; } - if (resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) - { - hlsl_fixme(ctx, &store->node.loc, "Structured buffers store is not implemented."); - return false; - } - if (tgsm && !hlsl_is_numeric_type(resource_type)) { hlsl_fixme(ctx, &store->node.loc, "Store to structured TGSM."); return false; } - if (tgsm || resource_type->sampler_dim == HLSL_SAMPLER_DIM_RAW_BUFFER) + if ((structured = resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER)) { - if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_STORE_RAW, 1, 2))) + if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_STORE_STRUCTURED, 1, 3))) return false; - if (!sm4_generate_vsir_init_dst_param_from_deref(ctx, program, &ins->dst[0], + if (!sm4_generate_vsir_init_dst_operand_from_deref(ctx, program, &ins->dst[0], &store->resource, &instr->loc, store->writemask)) return false; + + vsir_src_from_hlsl_node(&ins->src[1], ctx, store->byte_offset.node, VKD3DSP_WRITEMASK_ALL); + } + else if (tgsm || resource_type->sampler_dim == HLSL_SAMPLER_DIM_RAW_BUFFER) + { + if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_STORE_RAW, 1, 2))) + return false; + + if (!sm4_generate_vsir_init_dst_operand_from_deref(ctx, program, + &ins->dst[0], &store->resource, &instr->loc, store->writemask)) + return false; } else { if (!(ins = generate_vsir_add_program_instruction(ctx, program, &instr->loc, VSIR_OP_STORE_UAV_TYPED, 1, 2))) return false; - if (!sm4_generate_vsir_init_dst_param_from_deref(ctx, program, + if (!sm4_generate_vsir_init_dst_operand_from_deref(ctx, program, &ins->dst[0], &store->resource, &instr->loc, VKD3DSP_WRITEMASK_ALL)) return false; } vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, VKD3DSP_WRITEMASK_ALL); - vsir_src_from_hlsl_node(&ins->src[1], ctx, value, VKD3DSP_WRITEMASK_ALL); + vsir_src_from_hlsl_node(&ins->src[structured ? 2 : 1], ctx, value, VKD3DSP_WRITEMASK_ALL); return true; } @@ -11988,17 +12311,11 @@ static bool sm4_generate_vsir_instr_ld(struct hlsl_ctx *ctx, multisampled = resource_type->class == HLSL_CLASS_TEXTURE && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); - structured = resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER; + structured = resource_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER + || (tgsm && resource_type->class == HLSL_CLASS_ARRAY); + raw = resource_type->sampler_dim == HLSL_SAMPLER_DIM_RAW_BUFFER + || (tgsm && !structured); - if (!tgsm) - { - raw = resource_type->sampler_dim == HLSL_SAMPLER_DIM_RAW_BUFFER; - } - else if (!(raw = hlsl_is_numeric_type(resource_type))) - { - hlsl_fixme(ctx, &load->node.loc, "Load from structured TGSM."); - return false; - } VKD3D_ASSERT(!(structured && multisampled)); if (structured) @@ -12036,9 +12353,17 @@ static bool sm4_generate_vsir_instr_ld(struct hlsl_ctx *ctx, coords_writemask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1 | VKD3DSP_WRITEMASK_3; } - vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, coords_writemask); + if (raw && tgsm) + { + VKD3D_ASSERT(byte_offset); + vsir_src_from_hlsl_node(&ins->src[0], ctx, byte_offset, VKD3DSP_WRITEMASK_ALL); + } + else + { + vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, coords_writemask); + } - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, &ins->src[structured ? 2 : 1], resource, ins->dst[0].write_mask, &instr->loc)) return false; @@ -12123,12 +12448,12 @@ static bool sm4_generate_vsir_instr_sample(struct hlsl_ctx *ctx, vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, VKD3DSP_WRITEMASK_ALL); - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, &ins->src[1], - resource, ins->dst[0].write_mask, &instr->loc)) + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, + &ins->src[1], resource, ins->dst[0].write_mask, &instr->loc)) return false; - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, &ins->src[2], - sampler, VKD3DSP_WRITEMASK_ALL, &instr->loc)) + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, + &ins->src[2], sampler, VKD3DSP_WRITEMASK_ALL, &instr->loc)) return false; if (opcode == VSIR_OP_SAMPLE_LOD || opcode == VSIR_OP_SAMPLE_B) @@ -12189,11 +12514,11 @@ static bool sm4_generate_vsir_instr_gather(struct hlsl_ctx *ctx, struct vsir_pro else sm4_generate_vsir_encode_texel_offset_as_aoffimmi(ins, texel_offset); - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, &ins->src[current_arg++], resource, ins->dst[0].write_mask, &instr->loc)) return false; - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, &ins->src[current_arg], sampler, VKD3DSP_WRITEMASK_ALL, &instr->loc)) return false; ins->src[current_arg].reg.dimension = VSIR_DIMENSION_VEC4; @@ -12224,7 +12549,7 @@ static bool sm4_generate_vsir_instr_sample_info(struct hlsl_ctx *ctx, vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr); - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, &ins->src[0], resource, ins->dst[0].write_mask, &instr->loc)) return false; @@ -12258,7 +12583,7 @@ static bool sm4_generate_vsir_instr_resinfo(struct hlsl_ctx *ctx, vsir_src_from_hlsl_node(&ins->src[0], ctx, load->lod.node, VKD3DSP_WRITEMASK_ALL); - if (!sm4_generate_vsir_init_src_param_from_deref(ctx, program, + if (!sm4_generate_vsir_init_src_operand_from_deref(ctx, program, &ins->src[1], resource, ins->dst[0].write_mask, &instr->loc)) return false; @@ -12378,9 +12703,9 @@ static bool sm4_generate_vsir_instr_interlocked(struct hlsl_ctx *ctx, struct hlsl_ir_node *coords = interlocked->coords.node; struct hlsl_ir_node *instr = &interlocked->node; bool is_imm = interlocked->node.reg.allocated; - struct vkd3d_shader_dst_param *dst_param; struct vkd3d_shader_instruction *ins; enum vkd3d_shader_opcode opcode; + struct vsir_dst_operand *dst; opcode = is_imm ? imm_opcodes[interlocked->op] : opcodes[interlocked->op]; @@ -12403,10 +12728,10 @@ static bool sm4_generate_vsir_instr_interlocked(struct hlsl_ctx *ctx, if (is_imm) vsir_dst_from_hlsl_node(&ins->dst[0], ctx, instr); - dst_param = is_imm ? &ins->dst[1] : &ins->dst[0]; - if (!sm4_generate_vsir_init_dst_param_from_deref(ctx, program, dst_param, &interlocked->dst, &instr->loc, 0)) + dst = is_imm ? &ins->dst[1] : &ins->dst[0]; + if (!sm4_generate_vsir_init_dst_operand_from_deref(ctx, program, dst, &interlocked->dst, &instr->loc, 0)) return false; - dst_param->reg.dimension = VSIR_DIMENSION_NONE; + dst->reg.dimension = VSIR_DIMENSION_NONE; vsir_src_from_hlsl_node(&ins->src[0], ctx, coords, VKD3DSP_WRITEMASK_ALL); if (cmp_value) @@ -12957,8 +13282,8 @@ static void sm4_generate_vsir_add_dcl_constant_buffer(struct hlsl_ctx *ctx, { unsigned int array_first = cbuffer->reg.index; unsigned int array_last = cbuffer->reg.index; /* FIXME: array end. */ - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; if (!(ins = generate_vsir_add_program_instruction(ctx, program, &cbuffer->loc, VSIR_OP_DCL_CONSTANT_BUFFER, 0, 0))) { @@ -12967,27 +13292,24 @@ static void sm4_generate_vsir_add_dcl_constant_buffer(struct hlsl_ctx *ctx, } ins->declaration.cb.size = align(cbuffer->size, 4) * sizeof(float); - - src_param = &ins->declaration.cb.src; - vsir_src_param_init(src_param, VKD3DSPR_CONSTBUFFER, VSIR_DATA_F32, 0); - src_param->reg.dimension = VSIR_DIMENSION_VEC4; - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; - ins->declaration.cb.range.space = cbuffer->reg.space; ins->declaration.cb.range.first = array_first; ins->declaration.cb.range.last = array_last; - src_param->reg.idx[0].offset = cbuffer->reg.id; - src_param->reg.idx[1].offset = array_first; - src_param->reg.idx[2].offset = array_last; - src_param->reg.idx_count = 3; + src = &ins->declaration.cb.src; + vsir_src_operand_init(src, VKD3DSPR_CONSTBUFFER, VSIR_DATA_F32, 3); + src->reg.idx[0].offset = cbuffer->reg.id; + src->reg.idx[1].offset = array_first; + src->reg.idx[2].offset = array_last; + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; } static void sm4_generate_vsir_add_dcl_sampler(struct hlsl_ctx *ctx, struct vsir_program *program, const struct extern_resource *resource) { - struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_instruction *ins; + struct vsir_src_operand *src; unsigned int i; VKD3D_ASSERT(resource->regset == HLSL_REGSET_SAMPLERS); @@ -13010,17 +13332,15 @@ static void sm4_generate_vsir_add_dcl_sampler(struct hlsl_ctx *ctx, if (resource->component_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON) ins->flags |= VKD3DSI_SAMPLER_COMPARISON_MODE; - src_param = &ins->declaration.sampler.src; - vsir_src_param_init(src_param, VKD3DSPR_SAMPLER, VSIR_DATA_UNUSED, 0); - ins->declaration.sampler.range.first = array_first; ins->declaration.sampler.range.last = array_last; ins->declaration.sampler.range.space = resource->space; - src_param->reg.idx[0].offset = resource->id + i; - src_param->reg.idx[1].offset = array_first; - src_param->reg.idx[2].offset = array_last; - src_param->reg.idx_count = 3; + src = &ins->declaration.sampler.src; + vsir_src_operand_init(src, VKD3DSPR_SAMPLER, VSIR_DATA_UNUSED, 3); + src->reg.idx[0].offset = resource->id + i; + src->reg.idx[1].offset = array_first; + src->reg.idx[2].offset = array_last; } } @@ -13156,7 +13476,7 @@ static void sm4_generate_vsir_add_dcl_texture(struct hlsl_ctx *ctx, else vsir_resource = &ins->declaration.semantic.resource; - vsir_dst_param_init(&vsir_resource->reg, uav ? VKD3DSPR_UAV : VKD3DSPR_RESOURCE, VSIR_DATA_UNUSED, 0); + vsir_dst_operand_init(&vsir_resource->reg, uav ? VKD3DSPR_UAV : VKD3DSPR_RESOURCE, VSIR_DATA_UNUSED, 0); if (uav && component_type->e.resource.rasteriser_ordered) ins->flags = VKD3DSUF_RASTERISER_ORDERED_VIEW; @@ -13206,29 +13526,37 @@ static void sm4_generate_vsir_add_dcl_texture(struct hlsl_ctx *ctx, static void sm4_generate_vsir_add_dcl_tgsm(struct hlsl_ctx *ctx, struct vsir_program *program, const struct hlsl_ir_var *var) { - struct vkd3d_shader_dst_param *dst_param; + bool raw = var->data_type->class != HLSL_CLASS_ARRAY; struct vkd3d_shader_instruction *ins; + enum vkd3d_shader_opcode opcode; + struct vsir_dst_operand *dst; - if (!hlsl_is_numeric_type(var->data_type)) + opcode = raw ? VSIR_OP_DCL_TGSM_RAW : VSIR_OP_DCL_TGSM_STRUCTURED; + if (!(ins = generate_vsir_add_program_instruction(ctx, program, &var->loc, opcode, 0, 0))) { - hlsl_fixme(ctx, &var->loc, "Structured TGSM declaration."); + ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; return; } - if (!(ins = generate_vsir_add_program_instruction(ctx, program, &var->loc, VSIR_OP_DCL_TGSM_RAW, 0, 0))) + if (raw) { - ctx->result = VKD3D_ERROR_OUT_OF_MEMORY; - return; - } + dst = &ins->declaration.tgsm_raw.reg; - dst_param = &ins->declaration.tgsm_raw.reg; + ins->declaration.tgsm_raw.byte_count = hlsl_type_get_packed_size(var->data_type); + ins->declaration.tgsm_raw.zero_init = false; + } + else + { + dst = &ins->declaration.tgsm_structured.reg; - vsir_dst_param_init(dst_param, VKD3DSPR_GROUPSHAREDMEM, VSIR_DATA_F32, 1); - dst_param->reg.dimension = VSIR_DIMENSION_NONE; - dst_param->reg.idx[0].offset = var->regs[HLSL_REGSET_NUMERIC].id; + ins->declaration.tgsm_structured.byte_stride = hlsl_type_get_packed_size(var->data_type->e.array.type); + ins->declaration.tgsm_structured.structure_count = var->data_type->e.array.elements_count; + ins->declaration.tgsm_structured.zero_init = false; + } - ins->declaration.tgsm_raw.byte_count = var->data_type->reg_size[HLSL_REGSET_NUMERIC] * 4; - ins->declaration.tgsm_raw.zero_init = false; + vsir_dst_operand_init(dst, VKD3DSPR_GROUPSHAREDMEM, VSIR_DATA_F32, 1); + dst->reg.dimension = VSIR_DIMENSION_NONE; + dst->reg.idx[0].offset = var->regs[HLSL_REGSET_NUMERIC].id; } static void sm4_generate_vsir_add_dcl_stream(struct hlsl_ctx *ctx, @@ -13242,7 +13570,7 @@ static void sm4_generate_vsir_add_dcl_stream(struct hlsl_ctx *ctx, return; } - vsir_src_param_init(&ins->src[0], VKD3DSPR_STREAM, VSIR_DATA_UNUSED, 1); + vsir_src_operand_init(&ins->src[0], VKD3DSPR_STREAM, VSIR_DATA_UNUSED, 1); ins->src[0].reg.dimension = VSIR_DIMENSION_NONE; ins->src[0].reg.idx[0].offset = var->regs[HLSL_REGSET_STREAM_OUTPUTS].index; } @@ -13478,7 +13806,7 @@ static void generate_vsir_descriptors(struct hlsl_ctx *ctx, struct vsir_program } } - program->has_descriptor_info = true; + program->normalisation_flags.has_descriptor_info = true; } /* For some reason, for matrices, values from default value initializers end @@ -13678,20 +14006,34 @@ static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type) vkd3d_unreachable(); } -static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, - struct hlsl_type *type, bool structured) +struct rdef_ctx +{ + struct hlsl_ctx *hlsl; + + struct vkd3d_bytecode_buffer buffer; + + struct rdef_type_info + { + unsigned int bytecode_offset; + unsigned int packed_bytecode_offset; + } *type_info; +}; + +static void rdef_write_type(struct rdef_ctx *rdef, struct hlsl_type *type, bool structured) { const struct hlsl_type *array_type = hlsl_get_multiarray_element_type(type); const char *name = array_type->name ? array_type->name : "<unnamed>"; - const struct hlsl_profile_info *profile = ctx->profile; + struct rdef_type_info *type_info = &rdef->type_info[type->type_id]; + const struct hlsl_profile_info *profile = rdef->hlsl->profile; + struct vkd3d_bytecode_buffer *buffer = &rdef->buffer; unsigned int array_size = 0; size_t name_offset = 0; size_t i; - if (!structured && type->bytecode_offset) + if (!structured && type_info->bytecode_offset) return; - if (structured && type->packed_bytecode_offset) + if (structured && type_info->packed_bytecode_offset) return; if (profile->major_version >= 5) @@ -13713,7 +14055,7 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b continue; field->name_bytecode_offset = put_string(buffer, field->name); - write_sm4_type(ctx, buffer, field->type, structured); + rdef_write_type(rdef, field->type, structured); ++field_count; } @@ -13722,6 +14064,7 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b for (i = 0; i < array_type->e.record.field_count; ++i) { struct hlsl_struct_field *field = &array_type->e.record.fields[i]; + const struct rdef_type_info *member_type_info; unsigned int field_type_offset, offset; if (!field->type->reg_size[HLSL_REGSET_NUMERIC]) @@ -13729,10 +14072,11 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b put_u32(buffer, field->name_bytecode_offset); + member_type_info = &rdef->type_info[field->type->type_id]; if (!structured) - field_type_offset = field->type->bytecode_offset; + field_type_offset = member_type_info->bytecode_offset; else - field_type_offset = field->type->packed_bytecode_offset; + field_type_offset = member_type_info->packed_bytecode_offset; put_u32(buffer, field_type_offset); if (!structured) @@ -13742,9 +14086,9 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b put_u32(buffer, offset); } if (!structured) - type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); + type_info->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); else - type->packed_bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); + type_info->packed_bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID)); put_u32(buffer, vkd3d_make_u32(1, hlsl_type_component_count(array_type))); put_u32(buffer, vkd3d_make_u32(array_size, field_count)); put_u32(buffer, fields_offset); @@ -13753,9 +14097,10 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b { VKD3D_ASSERT(array_type->class <= HLSL_CLASS_LAST_NUMERIC); if (!structured) - type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); + type_info->bytecode_offset = put_u32(buffer, + vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); else - type->packed_bytecode_offset = put_u32(buffer, + type_info->packed_bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type))); put_u32(buffer, vkd3d_make_u32(array_type->e.numeric.dimy, array_type->e.numeric.dimx)); put_u32(buffer, vkd3d_make_u32(array_size, 0)); @@ -13772,17 +14117,37 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b } } -static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rdef) +static void rdef_ctx_cleanup(struct rdef_ctx *rdef) +{ + vkd3d_free(rdef->type_info); + vkd3d_bytecode_buffer_cleanup(&rdef->buffer); +} + +static int rdef_ctx_init(struct rdef_ctx *rdef, struct hlsl_ctx *hlsl) +{ + rdef->hlsl = hlsl; + + memset(&rdef->buffer, 0, sizeof(rdef->buffer)); + + if (!(rdef->type_info = vkd3d_calloc(hlsl->type_count, sizeof(*rdef->type_info)))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + return VKD3D_OK; +} + +static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out) { uint32_t binding_desc_size = (hlsl_version_ge(ctx, 5, 1) ? 10 : 8) * sizeof(uint32_t); size_t buffers_offset, resources_offset, creator_offset, string_offset; size_t cbuffer_position, resource_position, creator_position; unsigned int buffer_count = 0, extern_resources_count, i, j; const struct hlsl_profile_info *profile = ctx->profile; - struct vkd3d_bytecode_buffer buffer = {0}; struct extern_resource *extern_resources; + struct vkd3d_bytecode_buffer *buffer; const struct hlsl_buffer *cbuffer; const struct hlsl_ir_var *var; + struct rdef_ctx rdef; + int ret; static const uint16_t target_types[] = { @@ -13794,6 +14159,13 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd 0x4353, /* COMPUTE */ }; + if ((ret = rdef_ctx_init(&rdef, ctx)) < 0) + { + ctx->result = ret; + return; + } + buffer = &rdef.buffer; + extern_resources = sm4_get_extern_resources(ctx, &extern_resources_count); LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry) @@ -13812,31 +14184,31 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd ++buffer_count; } - put_u32(&buffer, buffer_count); - cbuffer_position = put_u32(&buffer, 0); - put_u32(&buffer, extern_resources_count); - resource_position = put_u32(&buffer, 0); - put_u32(&buffer, vkd3d_make_u32(vkd3d_make_u16(profile->minor_version, profile->major_version), + put_u32(buffer, buffer_count); + cbuffer_position = put_u32(buffer, 0); + put_u32(buffer, extern_resources_count); + resource_position = put_u32(buffer, 0); + put_u32(buffer, vkd3d_make_u32(vkd3d_make_u16(profile->minor_version, profile->major_version), target_types[profile->type])); - put_u32(&buffer, 0); /* FIXME: compilation flags */ - creator_position = put_u32(&buffer, 0); + put_u32(buffer, 0); /* FIXME: compilation flags */ + creator_position = put_u32(buffer, 0); if (profile->major_version >= 5) { - put_u32(&buffer, hlsl_version_ge(ctx, 5, 1) ? TAG_RD11_REVERSE : TAG_RD11); - put_u32(&buffer, 15 * sizeof(uint32_t)); /* size of RDEF header including this header */ - put_u32(&buffer, 6 * sizeof(uint32_t)); /* size of buffer desc */ - put_u32(&buffer, binding_desc_size); /* size of binding desc */ - put_u32(&buffer, 10 * sizeof(uint32_t)); /* size of variable desc */ - put_u32(&buffer, 9 * sizeof(uint32_t)); /* size of type desc */ - put_u32(&buffer, 3 * sizeof(uint32_t)); /* size of member desc */ - put_u32(&buffer, 0); /* unknown; possibly a null terminator */ + put_u32(buffer, hlsl_version_ge(ctx, 5, 1) ? TAG_RD11_REVERSE : TAG_RD11); + put_u32(buffer, 15 * sizeof(uint32_t)); /* size of RDEF header including this header */ + put_u32(buffer, 6 * sizeof(uint32_t)); /* size of buffer desc */ + put_u32(buffer, binding_desc_size); /* size of binding desc */ + put_u32(buffer, 10 * sizeof(uint32_t)); /* size of variable desc */ + put_u32(buffer, 9 * sizeof(uint32_t)); /* size of type desc */ + put_u32(buffer, 3 * sizeof(uint32_t)); /* size of member desc */ + put_u32(buffer, 0); /* unknown; possibly a null terminator */ } /* Bound resources. */ - resources_offset = bytecode_align(&buffer); - set_u32(&buffer, resource_position, resources_offset); + resources_offset = bytecode_align(buffer); + set_u32(buffer, resource_position, resources_offset); for (i = 0; i < extern_resources_count; ++i) { @@ -13846,41 +14218,41 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd if (resource->is_user_packed) flags |= D3D_SIF_USERPACKED; - put_u32(&buffer, 0); /* name */ + put_u32(buffer, 0); /* name */ if (resource->buffer) - put_u32(&buffer, resource->buffer->type == HLSL_BUFFER_CONSTANT ? D3D_SIT_CBUFFER : D3D_SIT_TBUFFER); + put_u32(buffer, resource->buffer->type == HLSL_BUFFER_CONSTANT ? D3D_SIT_CBUFFER : D3D_SIT_TBUFFER); else - put_u32(&buffer, sm4_resource_type(resource->component_type)); + put_u32(buffer, sm4_resource_type(resource->component_type)); if (resource->regset == HLSL_REGSET_TEXTURES || resource->regset == HLSL_REGSET_UAVS) { bool structured = resource->component_type->sampler_dim == HLSL_SAMPLER_DIM_STRUCTURED_BUFFER; unsigned int dimx = resource->component_type->e.resource.format->e.numeric.dimx; - put_u32(&buffer, sm4_data_type(resource->component_type)); - put_u32(&buffer, sm4_rdef_resource_dimension(resource->component_type)); + put_u32(buffer, sm4_data_type(resource->component_type)); + put_u32(buffer, sm4_rdef_resource_dimension(resource->component_type)); if (structured) - put_u32(&buffer, hlsl_type_get_packed_size(resource->component_type->e.resource.format)); + put_u32(buffer, hlsl_type_get_packed_size(resource->component_type->e.resource.format)); else - put_u32(&buffer, ~0u); /* FIXME: multisample count */ + put_u32(buffer, ~0u); /* FIXME: multisample count */ if (!structured) flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; } else { - put_u32(&buffer, 0); - put_u32(&buffer, 0); - put_u32(&buffer, 0); + put_u32(buffer, 0); + put_u32(buffer, 0); + put_u32(buffer, 0); } - put_u32(&buffer, resource->index); - put_u32(&buffer, resource->bind_count); - put_u32(&buffer, flags); + put_u32(buffer, resource->index); + put_u32(buffer, resource->bind_count); + put_u32(buffer, flags); if (hlsl_version_ge(ctx, 5, 1)) { - put_u32(&buffer, resource->space); - put_u32(&buffer, resource->id); + put_u32(buffer, resource->space); + put_u32(buffer, resource->id); } } @@ -13888,14 +14260,14 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd { const struct extern_resource *resource = &extern_resources[i]; - string_offset = put_string(&buffer, resource->name); - set_u32(&buffer, resources_offset + i * binding_desc_size, string_offset); + string_offset = put_string(buffer, resource->name); + set_u32(buffer, resources_offset + i * binding_desc_size, string_offset); } /* Buffers. */ - buffers_offset = bytecode_align(&buffer); - set_u32(&buffer, cbuffer_position, buffers_offset); + buffers_offset = bytecode_align(buffer); + set_u32(buffer, cbuffer_position, buffers_offset); LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry) { unsigned int var_count = 0; @@ -13909,12 +14281,12 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd ++var_count; } - put_u32(&buffer, 0); /* name */ - put_u32(&buffer, var_count); - put_u32(&buffer, 0); /* variable offset */ - put_u32(&buffer, align(cbuffer->size, 4) * sizeof(float)); - put_u32(&buffer, 0); /* FIXME: flags */ - put_u32(&buffer, cbuffer->type == HLSL_BUFFER_CONSTANT ? D3D_CT_CBUFFER : D3D_CT_TBUFFER); + put_u32(buffer, 0); /* name */ + put_u32(buffer, var_count); + put_u32(buffer, 0); /* variable offset */ + put_u32(buffer, align(cbuffer->size, 4) * sizeof(float)); + put_u32(buffer, 0); /* FIXME: flags */ + put_u32(buffer, cbuffer->type == HLSL_BUFFER_CONSTANT ? D3D_CT_CBUFFER : D3D_CT_TBUFFER); } for (i = 0; i < extern_resources_count; ++i) @@ -13927,12 +14299,12 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd resource_type = resource->component_type->e.resource.format; - put_u32(&buffer, 0); /* name */ - put_u32(&buffer, 1); /* var count */ - put_u32(&buffer, 0); /* variable offset */ - put_u32(&buffer, hlsl_type_get_packed_size(resource_type)); /* size */ - put_u32(&buffer, 0); /* FIXME: flags */ - put_u32(&buffer, D3D_CT_RESOURCE_BIND_INFO); + put_u32(buffer, 0); /* name */ + put_u32(buffer, 1); /* var count */ + put_u32(buffer, 0); /* variable offset */ + put_u32(buffer, hlsl_type_get_packed_size(resource_type)); /* size */ + put_u32(buffer, 0); /* FIXME: flags */ + put_u32(buffer, D3D_CT_RESOURCE_BIND_INFO); } i = 0; @@ -13941,8 +14313,8 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd if (!cbuffer->reg.allocated) continue; - string_offset = put_string(&buffer, cbuffer->name); - set_u32(&buffer, buffers_offset + i++ * 6 * sizeof(uint32_t), string_offset); + string_offset = put_string(buffer, cbuffer->name); + set_u32(buffer, buffers_offset + i++ * 6 * sizeof(uint32_t), string_offset); } for (j = 0; j < extern_resources_count; ++j) @@ -13952,19 +14324,19 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd if (resource->buffer || resource->component_type->sampler_dim != HLSL_SAMPLER_DIM_STRUCTURED_BUFFER) continue; - string_offset = put_string(&buffer, resource->name); - set_u32(&buffer, buffers_offset + i++ * 6 * sizeof(uint32_t), string_offset); + string_offset = put_string(buffer, resource->name); + set_u32(buffer, buffers_offset + i++ * 6 * sizeof(uint32_t), string_offset); } i = 0; LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry) { - size_t vars_start = bytecode_align(&buffer); + size_t vars_start = bytecode_align(buffer); if (!cbuffer->reg.allocated) continue; - set_u32(&buffer, buffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start); + set_u32(buffer, buffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start); LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { @@ -13976,35 +14348,36 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd if (var->is_read) flags |= D3D_SVF_USED; - put_u32(&buffer, 0); /* name */ - put_u32(&buffer, var->buffer_offset * sizeof(float)); - put_u32(&buffer, var->data_type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float)); - put_u32(&buffer, flags); - put_u32(&buffer, 0); /* type */ - put_u32(&buffer, 0); /* default value */ + put_u32(buffer, 0); /* name */ + put_u32(buffer, var->buffer_offset * sizeof(float)); + put_u32(buffer, var->data_type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float)); + put_u32(buffer, flags); + put_u32(buffer, 0); /* type */ + put_u32(buffer, 0); /* default value */ if (profile->major_version >= 5) { - put_u32(&buffer, 0); /* texture start */ - put_u32(&buffer, 0); /* texture count */ - put_u32(&buffer, 0); /* sampler start */ - put_u32(&buffer, 0); /* sampler count */ + put_u32(buffer, 0); /* texture start */ + put_u32(buffer, 0); /* texture count */ + put_u32(buffer, 0); /* sampler start */ + put_u32(buffer, 0); /* sampler count */ } } j = 0; LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { + const struct rdef_type_info *type_info = &rdef.type_info[var->data_type->type_id]; const unsigned int var_size = (profile->major_version >= 5 ? 10 : 6); size_t var_offset = vars_start + j * var_size * sizeof(uint32_t); if (!var->is_uniform || var->buffer != cbuffer || !var->data_type->reg_size[HLSL_REGSET_NUMERIC]) continue; - string_offset = put_string(&buffer, var->name); - set_u32(&buffer, var_offset, string_offset); - write_sm4_type(ctx, &buffer, var->data_type, false); - set_u32(&buffer, var_offset + 4 * sizeof(uint32_t), var->data_type->bytecode_offset); + string_offset = put_string(buffer, var->name); + set_u32(buffer, var_offset, string_offset); + rdef_write_type(&rdef, var->data_type, false); + set_u32(buffer, var_offset + 4 * sizeof(uint32_t), type_info->bytecode_offset); if (var->default_values) { @@ -14013,8 +14386,8 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd unsigned int default_value_offset; unsigned int k; - default_value_offset = bytecode_reserve_bytes(&buffer, reg_size * sizeof(uint32_t)); - set_u32(&buffer, var_offset + 5 * sizeof(uint32_t), default_value_offset); + default_value_offset = bytecode_reserve_bytes(buffer, reg_size * sizeof(uint32_t)); + set_u32(buffer, var_offset + 5 * sizeof(uint32_t), default_value_offset); for (k = 0; k < comp_count; ++k) { @@ -14036,7 +14409,7 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd if (comp_type->e.numeric.type == HLSL_TYPE_DOUBLE) hlsl_fixme(ctx, &var->loc, "Write double default values."); - set_u32(&buffer, default_value_offset + comp_offset * sizeof(uint32_t), + set_u32(buffer, default_value_offset + comp_offset * sizeof(uint32_t), var->default_values[k].number.u); } } @@ -14049,6 +14422,7 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd for (j = 0; j < extern_resources_count; ++j) { const struct extern_resource *resource = &extern_resources[j]; + const struct rdef_type_info *type_info; struct hlsl_type *resource_type; size_t vars_start; @@ -14056,45 +14430,44 @@ static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rd continue; resource_type = resource->component_type->e.resource.format; + type_info = &rdef.type_info[resource_type->type_id]; - vars_start = bytecode_align(&buffer); + vars_start = bytecode_align(buffer); - set_u32(&buffer, buffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start); + set_u32(buffer, buffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start); - put_u32(&buffer, 0); /* name */ - put_u32(&buffer, 0); /* offset */ - put_u32(&buffer, hlsl_type_get_packed_size(resource_type)); - put_u32(&buffer, D3D_SVF_USED); - put_u32(&buffer, 0); /* type */ - put_u32(&buffer, 0); /* default value */ + put_u32(buffer, 0); /* name */ + put_u32(buffer, 0); /* offset */ + put_u32(buffer, hlsl_type_get_packed_size(resource_type)); + put_u32(buffer, D3D_SVF_USED); + put_u32(buffer, 0); /* type */ + put_u32(buffer, 0); /* default value */ if (profile->major_version >= 5) { - put_u32(&buffer, ~0u); /* texture start */ - put_u32(&buffer, 0); /* texture count */ - put_u32(&buffer, ~0u); /* sampler start */ - put_u32(&buffer, 0); /* sampler count */ + put_u32(buffer, ~0u); /* texture start */ + put_u32(buffer, 0); /* texture count */ + put_u32(buffer, ~0u); /* sampler start */ + put_u32(buffer, 0); /* sampler count */ } - string_offset = put_string(&buffer, "$Element"); - set_u32(&buffer, vars_start, string_offset); - write_sm4_type(ctx, &buffer, resource_type, true); - set_u32(&buffer, vars_start + 4 * sizeof(uint32_t), resource_type->packed_bytecode_offset); + string_offset = put_string(buffer, "$Element"); + set_u32(buffer, vars_start, string_offset); + rdef_write_type(&rdef, resource_type, true); + set_u32(buffer, vars_start + 4 * sizeof(uint32_t), type_info->packed_bytecode_offset); } - creator_offset = put_string(&buffer, vkd3d_shader_get_version(NULL, NULL)); - set_u32(&buffer, creator_position, creator_offset); + creator_offset = put_string(buffer, vkd3d_shader_get_version(NULL, NULL)); + set_u32(buffer, creator_position, creator_offset); sm4_free_extern_resources(extern_resources, extern_resources_count); - if (buffer.status) - { - vkd3d_free(buffer.data); - ctx->result = buffer.status; - return; - } - rdef->code = buffer.data; - rdef->size = buffer.size; + if (ctx->result >= 0 && buffer->status < 0) + ctx->result = buffer->status; + if (ctx->result >= 0) + vkd3d_shader_code_from_bytecode_buffer(out, buffer); + + rdef_ctx_cleanup(&rdef); } static bool loop_unrolling_generate_const_bool_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, @@ -14213,11 +14586,12 @@ static void loop_unrolling_remove_jumps(struct hlsl_ctx *ctx, struct hlsl_block while (loop_unrolling_remove_jumps_recurse(ctx, block, loop_broken, loop_continued)); } -static unsigned int loop_unrolling_get_max_iterations(struct hlsl_ctx *ctx, struct hlsl_ir_loop *loop) +static unsigned int loop_unrolling_get_max_iterations(struct hlsl_ctx *ctx, struct hlsl_ir_loop *loop, + unsigned int unroll_limit) { /* Always use the explicit limit if it has been passed. */ - if (loop->unroll_limit) - return loop->unroll_limit; + if (unroll_limit) + return unroll_limit; /* All SMs will default to 1024 if [unroll] has been specified without an explicit limit. */ if (loop->unroll_type == HLSL_LOOP_FORCE_UNROLL) @@ -14269,7 +14643,8 @@ static bool loop_unrolling_check_val(struct copy_propagation_state *state, struc return hlsl_ir_constant(v->node)->value.u[0].u; } -static bool loop_unrolling_unroll_loop(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_loop *loop) +static bool loop_unrolling_unroll_loop(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_loop *loop, + unsigned int unroll_limit) { struct hlsl_block draft, tmp_dst, loop_body; struct hlsl_ir_var *broken, *continued; @@ -14277,6 +14652,10 @@ static bool loop_unrolling_unroll_loop(struct hlsl_ctx *ctx, struct hlsl_block * struct copy_propagation_state state; struct hlsl_ir_if *target_if; + hlsl_block_init(&draft); + hlsl_block_init(&tmp_dst); + hlsl_block_init(&loop_body); + if (!(broken = hlsl_new_synthetic_var(ctx, "broken", hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL), &loop->node.loc))) goto fail; @@ -14285,14 +14664,12 @@ static bool loop_unrolling_unroll_loop(struct hlsl_ctx *ctx, struct hlsl_block * hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL), &loop->node.loc))) goto fail; - hlsl_block_init(&draft); - hlsl_block_init(&tmp_dst); - - max_iterations = loop_unrolling_get_max_iterations(ctx, loop); + max_iterations = loop_unrolling_get_max_iterations(ctx, loop, unroll_limit); copy_propagation_state_init(&state, ctx); - index = 2; + state.stop = &loop->node; - loop_unrolling_simplify(ctx, block, &state, &index); + index_instructions(block, 2); + copy_propagation_transform_block(ctx, block, &state); state.stopped = false; index = loop->node.index; @@ -14346,7 +14723,7 @@ static bool loop_unrolling_unroll_loop(struct hlsl_ctx *ctx, struct hlsl_block * /* Native will not emit an error if max_iterations has been reached with an * explicit limit. It also will not insert a loop if there are iterations left * i.e [unroll(4)] for (i = 0; i < 8; ++i)) */ - if (!loop->unroll_limit && i == max_iterations) + if (!unroll_limit && i == max_iterations) { if (loop->unroll_type == HLSL_LOOP_FORCE_UNROLL) hlsl_error(ctx, &loop->node.loc, VKD3D_SHADER_ERROR_HLSL_FAILED_FORCED_UNROLL, @@ -14375,17 +14752,34 @@ fail: static bool unroll_loops(struct hlsl_ctx *ctx, struct hlsl_ir_node *node, void *context) { struct hlsl_block *program = context; + unsigned int unroll_limit = 0; struct hlsl_ir_loop *loop; if (node->type != HLSL_IR_LOOP) - return true; + return false; loop = hlsl_ir_loop(node); - if (loop->unroll_type != HLSL_LOOP_UNROLL && loop->unroll_type != HLSL_LOOP_FORCE_UNROLL) - return true; + if (loop->unroll_type == HLSL_LOOP_FORCE_LOOP) + return false; + + if (loop->unroll_limit.node) + { + struct hlsl_ir_constant *c; + + if (loop->unroll_limit.node->type != HLSL_IR_CONSTANT) + { + hlsl_error(ctx, &loop->unroll_limit.node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, + "Unable to evaluate the unroll limit to a constant."); + return false; + } + + c = hlsl_ir_constant(loop->unroll_limit.node); + VKD3D_ASSERT(c->node.data_type->e.numeric.type == HLSL_TYPE_UINT); + unroll_limit = c->value.u[0].u; + } - if (!loop_unrolling_unroll_loop(ctx, program, loop)) + if (!loop_unrolling_unroll_loop(ctx, program, loop, unroll_limit)) loop->unroll_type = HLSL_LOOP_FORCE_LOOP; return true; @@ -14488,18 +14882,15 @@ static void resolve_continues(struct hlsl_ctx *ctx, struct hlsl_block *block, st static void loop_unrolling_execute(struct hlsl_ctx *ctx, struct hlsl_block *block) { - bool progress; - /* These are required by copy propagation, which in turn is required for * unrolling. */ - do + split_copies(ctx, block); + for (;;) { - progress = hlsl_transform_ir(ctx, split_array_copies, block, NULL); - progress |= hlsl_transform_ir(ctx, split_struct_copies, block, NULL); - } while (progress); - hlsl_transform_ir(ctx, split_matrix_copies, block, NULL); - - hlsl_transform_ir(ctx, unroll_loops, block, block); + hlsl_run_folding_passes(ctx, block); + if (!hlsl_transform_ir_once(ctx, unroll_loops, block, block)) + break; + } resolve_continues(ctx, block, NULL); hlsl_transform_ir(ctx, resolve_loops, block, NULL); } @@ -14658,8 +15049,9 @@ static struct hlsl_ir_node *lower_f16tof32(struct hlsl_ctx *ctx, struct hlsl_ir_ if (!(body = hlsl_sprintf_alloc(ctx, template, component_count, component_count))) return NULL; - - if (!(func = hlsl_compile_internal_function(ctx, "soft_f16tof32", body))) + func = hlsl_compile_internal_function(ctx, "soft_f16tof32", body); + vkd3d_free(body); + if (!func) return NULL; lhs = func->parameters.vars[0]; @@ -14722,8 +15114,9 @@ static struct hlsl_ir_node *lower_f32tof16(struct hlsl_ctx *ctx, struct hlsl_ir_ if (!(body = hlsl_sprintf_alloc(ctx, template, component_count, component_count))) return NULL; - - if (!(func = hlsl_compile_internal_function(ctx, "soft_f32tof16", body))) + func = hlsl_compile_internal_function(ctx, "soft_f32tof16", body); + vkd3d_free(body); + if (!func) return NULL; lhs = func->parameters.vars[0]; @@ -14863,8 +15256,9 @@ static struct hlsl_ir_node *lower_isinf(struct hlsl_ctx *ctx, struct hlsl_ir_nod component_count = hlsl_type_component_count(rhs->data_type); if (!(body = hlsl_sprintf_alloc(ctx, template, component_count, component_count))) return NULL; - - if (!(func = hlsl_compile_internal_function(ctx, "isinf", body))) + func = hlsl_compile_internal_function(ctx, "isinf", body); + vkd3d_free(body); + if (!func) return NULL; hlsl_block_add_simple_store(ctx, block, func->parameters.vars[0], rhs); @@ -14927,9 +15321,9 @@ static void process_entry_function(struct hlsl_ctx *ctx, struct list *semantic_v replace_ir(ctx, lower_complex_casts, body); replace_ir(ctx, lower_matrix_swizzles, body); - replace_ir(ctx, lower_index_loads, body); - replace_ir(ctx, lower_tgsm_loads, body); + hlsl_lower_index_loads(ctx, body); + replace_ir(ctx, lower_tgsm_stores, body); if (entry_func->return_var) @@ -15217,12 +15611,12 @@ static void process_entry_function(struct hlsl_ctx *ctx, struct list *semantic_v } int hlsl_emit_vsir(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info *compile_info, - struct hlsl_ir_function_decl *entry_func, struct vsir_program *program, - struct vkd3d_shader_code *reflection_data) + struct hlsl_ir_function_decl *entry_func, const struct hlsl_block *initializers, + struct vsir_program *program, struct vkd3d_shader_code *reflection_data) { - struct hlsl_block global_uniform_block, body, patch_body; uint32_t config_flags = vkd3d_shader_init_config_flags(); const struct hlsl_profile_info *profile = ctx->profile; + struct hlsl_block initializer_block, body, patch_body; struct list semantic_vars, patch_semantic_vars; struct hlsl_ir_var *var; @@ -15245,13 +15639,17 @@ int hlsl_emit_vsir(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info list_init(&ctx->extern_vars); list_init(&semantic_vars); list_init(&patch_semantic_vars); - hlsl_block_init(&global_uniform_block); + + if (!initializers) + hlsl_block_init(&initializer_block); + else if (!hlsl_clone_block(ctx, &initializer_block, initializers)) + return ctx->result; LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) { if (var->storage_modifiers & HLSL_STORAGE_UNIFORM) { - prepend_uniform_copy(ctx, &global_uniform_block, var); + prepend_uniform_copy(ctx, &initializer_block, var); } else if (var->storage_modifiers & HLSL_STORAGE_GROUPSHARED) { @@ -15260,19 +15658,22 @@ int hlsl_emit_vsir(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info } } - process_entry_function(ctx, &semantic_vars, &body, &global_uniform_block, entry_func); + process_entry_function(ctx, &semantic_vars, &body, &initializer_block, entry_func); + if (ctx->result) + { + hlsl_block_cleanup(&body); + hlsl_block_cleanup(&initializer_block); return ctx->result; + } if (profile->type == VKD3D_SHADER_TYPE_HULL) { - process_entry_function(ctx, &patch_semantic_vars, &patch_body, &global_uniform_block, ctx->patch_constant_func); + process_entry_function(ctx, &patch_semantic_vars, &patch_body, &initializer_block, ctx->patch_constant_func); if (ctx->result) - return ctx->result; + goto done; } - hlsl_block_cleanup(&global_uniform_block); - if (profile->major_version < 4) { mark_indexable_vars(ctx, &body); @@ -15298,7 +15699,7 @@ int hlsl_emit_vsir(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info } if (ctx->result) - return ctx->result; + goto done; generate_vsir_signature(ctx, program, entry_func, &semantic_vars); if (program->shader_version.type == VKD3D_SHADER_TYPE_HULL) @@ -15311,15 +15712,22 @@ int hlsl_emit_vsir(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info else sm4_generate_rdef(ctx, reflection_data); if (ctx->result) - return ctx->result; + goto done; if (program->shader_version.major < 4) sm1_generate_vsir(ctx, compile_info, entry_func, &semantic_vars, &body, config_flags, program); else sm4_generate_vsir(ctx, compile_info, entry_func, &semantic_vars, &body, &patch_semantic_vars, &patch_body, config_flags, program); + if (ctx->result) vkd3d_shader_free_shader_code(reflection_data); +done: + if (profile->type == VKD3D_SHADER_TYPE_HULL) + hlsl_block_cleanup(&patch_body); + hlsl_block_cleanup(&body); + hlsl_block_cleanup(&initializer_block); + return ctx->result; } diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c index 627418165bc..e6edbe598bc 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c @@ -142,6 +142,7 @@ static bool fold_cast(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src) { unsigned int k; + bool b = false; uint32_t u = 0; double d = 0.0; float f = 0.0f; @@ -157,6 +158,7 @@ static bool fold_cast(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, i = float_to_int(src->value.u[k].f); f = src->value.u[k].f; d = src->value.u[k].f; + b = src->value.u[k].f != 0.0f; break; case HLSL_TYPE_DOUBLE: @@ -164,6 +166,7 @@ static bool fold_cast(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, i = double_to_int(src->value.u[k].d); f = src->value.u[k].d; d = src->value.u[k].d; + b = src->value.u[k].d != 0.0; break; case HLSL_TYPE_INT: @@ -171,6 +174,7 @@ static bool fold_cast(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, i = src->value.u[k].i; f = src->value.u[k].i; d = src->value.u[k].i; + b = src->value.u[k].i; break; case HLSL_TYPE_UINT: @@ -179,6 +183,7 @@ static bool fold_cast(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, i = src->value.u[k].u; f = src->value.u[k].u; d = src->value.u[k].u; + b = src->value.u[k].u; break; case HLSL_TYPE_BOOL: @@ -186,6 +191,7 @@ static bool fold_cast(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, i = !!src->value.u[k].u; f = !!src->value.u[k].u; d = !!src->value.u[k].u; + b = !!src->value.u[k].u; break; } @@ -210,7 +216,7 @@ static bool fold_cast(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, break; case HLSL_TYPE_BOOL: - dst->u[k].u = u ? ~0u : 0u; + dst->u[k].u = b ? ~0u : 0u; break; } } diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index 6a1c5303eb4..3c5167c6266 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -76,6 +76,21 @@ const char *vsir_data_type_get_name(enum vsir_data_type t, const char *error) return error; } +const char *vsir_denorm_mode_get_name(enum vsir_denorm_mode m, const char *error) +{ + static const char * const names[] = + { + [VSIR_DENORM_ANY] = "any", + [VSIR_DENORM_PRESERVE] = "preserve", + [VSIR_DENORM_FLUSH_TO_ZERO] = "ftz", + }; + + if ((size_t)m < ARRAY_SIZE(names)) + return names[m] ? names[m] : error; + + return error; +} + const char *vsir_opcode_get_name(enum vkd3d_shader_opcode op, const char *error) { static const char * const names[] = @@ -513,6 +528,24 @@ struct vkd3d_shader_instruction *shader_instruction_array_append(struct vkd3d_sh return &array->elements[array->count - 1]; } +/* NOTE: This might be replaced by a single field in vsir_program at some point. */ +static unsigned int vsir_program_get_idxtemp_count(struct vsir_program *program) +{ + struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); + struct vkd3d_shader_instruction *ins; + size_t count = 0; + + for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + { + if (ins->opcode != VSIR_OP_DCL_INDEXABLE_TEMP) + continue; + if (count < ins->declaration.indexable_temp.register_idx + 1) + count = ins->declaration.indexable_temp.register_idx + 1; + } + + return count; +} + bool vsir_program_add_icb(struct vsir_program *program, struct vkd3d_shader_immediate_constant_buffer *icb) { if (!vkd3d_array_reserve((void **)&program->icbs, &program->icb_capacity, @@ -524,8 +557,8 @@ bool vsir_program_add_icb(struct vsir_program *program, struct vkd3d_shader_imme return true; } -static struct vkd3d_shader_src_param *vsir_program_clone_src_params( - struct vsir_program *program, const struct vkd3d_shader_src_param *params, size_t count); +static struct vsir_src_operand *vsir_program_clone_src_operands( + struct vsir_program *program, const struct vsir_src_operand *operands, size_t count); static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, struct vsir_program *program) { @@ -536,57 +569,57 @@ static bool shader_register_clone_relative_addresses(struct vkd3d_shader_registe if (!reg->idx[i].rel_addr) continue; - if (!(reg->idx[i].rel_addr = vsir_program_clone_src_params(program, reg->idx[i].rel_addr, 1))) + if (!(reg->idx[i].rel_addr = vsir_program_clone_src_operands(program, reg->idx[i].rel_addr, 1))) return false; } return true; } -static struct vkd3d_shader_dst_param *vsir_program_clone_dst_params( - struct vsir_program *program, const struct vkd3d_shader_dst_param *params, size_t count) +static struct vsir_dst_operand *vsir_program_clone_dst_operands( + struct vsir_program *program, const struct vsir_dst_operand *operands, size_t count) { - struct vkd3d_shader_dst_param *dst_params; + struct vsir_dst_operand *ret; size_t i; - if (!(dst_params = vsir_program_get_dst_params(program, count))) + if (!(ret = vsir_program_get_dst_operands(program, count))) return NULL; - memcpy(dst_params, params, count * sizeof(*params)); + memcpy(ret, operands, count * sizeof(*operands)); for (i = 0; i < count; ++i) { - if (!shader_register_clone_relative_addresses(&dst_params[i].reg, program)) + if (!shader_register_clone_relative_addresses(&ret[i].reg, program)) return NULL; } - return dst_params; + return ret; } -static struct vkd3d_shader_src_param *vsir_program_clone_src_params( - struct vsir_program *program, const struct vkd3d_shader_src_param *params, size_t count) +static struct vsir_src_operand *vsir_program_clone_src_operands( + struct vsir_program *program, const struct vsir_src_operand *operands, size_t count) { - struct vkd3d_shader_src_param *src_params; + struct vsir_src_operand *ret; size_t i; - if (!(src_params = vsir_program_get_src_params(program, count))) + if (!(ret = vsir_program_get_src_operands(program, count))) return NULL; - memcpy(src_params, params, count * sizeof(*params)); + memcpy(ret, operands, count * sizeof(*operands)); for (i = 0; i < count; ++i) { - if (!shader_register_clone_relative_addresses(&src_params[i].reg, program)) + if (!shader_register_clone_relative_addresses(&ret[i].reg, program)) return NULL; } - return src_params; + return ret; } -static void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *array) +void shader_instruction_array_cleanup(struct vkd3d_shader_instruction_array *array) { vkd3d_free(array->elements); } -static bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *array, size_t reserve) +bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *array, size_t reserve) { memset(array, 0, sizeof(*array)); @@ -667,8 +700,8 @@ bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_c /* Size the parameter initial allocations so they are large enough for most shaders. The * code path for chained allocations will be tested if a few shaders need to use it. */ - shader_param_allocator_init(&program->dst_params, reserve - reserve / 8u, sizeof(struct vkd3d_shader_dst_param)); - shader_param_allocator_init(&program->src_params, reserve * 2u, sizeof(struct vkd3d_shader_src_param)); + shader_param_allocator_init(&program->dst_operands, reserve - reserve / 8u, sizeof(struct vsir_dst_operand)); + shader_param_allocator_init(&program->src_operands, reserve * 2u, sizeof(struct vsir_src_operand)); if (!shader_instruction_array_init(&program->instructions, reserve)) { if (program->free_parameters) @@ -691,13 +724,13 @@ void vsir_program_cleanup(struct vsir_program *program) vkd3d_free((void *)program->block_names[i]); vkd3d_free(program->block_names); vkd3d_shader_source_list_cleanup(&program->source_files); - shader_instruction_array_destroy(&program->instructions); + shader_instruction_array_cleanup(&program->instructions); shader_signature_cleanup(&program->input_signature); shader_signature_cleanup(&program->output_signature); shader_signature_cleanup(&program->patch_constant_signature); vkd3d_shader_free_scan_descriptor_info1(&program->descriptors); - shader_param_allocator_destroy(&program->src_params); - shader_param_allocator_destroy(&program->dst_params); + shader_param_allocator_destroy(&program->src_operands); + shader_param_allocator_destroy(&program->dst_operands); for (i = 0; i < program->icb_count; ++i) { vkd3d_free(program->icbs[i]); @@ -749,6 +782,21 @@ bool vsir_signature_find_sysval(const struct shader_signature *signature, return false; } +unsigned int vsir_signature_next_location(const struct shader_signature *signature) +{ + unsigned int i, max_row; + + if (!signature) + return 0; + + for (i = 0, max_row = 0; i < signature->element_count; ++i) + { + max_row = max(max_row, signature->elements[i].register_index + signature->elements[i].register_count); + } + + return max_row; +} + struct vkd3d_shader_descriptor_info1 *vsir_program_add_descriptor(struct vsir_program *program, enum vkd3d_shader_descriptor_type type, unsigned int register_id, const struct vkd3d_shader_register_range *range, @@ -854,70 +902,76 @@ static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shade return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; } -void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, +void vsir_src_operand_init(struct vsir_src_operand *src, enum vkd3d_shader_register_type reg_type, enum vsir_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; + vsir_register_init(&src->reg, reg_type, data_type, idx_count); + src->swizzle = 0; + src->modifiers = VKD3DSPSM_NONE; +} + +static void vsir_src_operand_init_const_f32(struct vsir_src_operand *src, float value) +{ + vsir_src_operand_init(src, VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); + src->reg.u.immconst_f32[0] = value; } -static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value) +static void vsir_src_operand_init_const_u32(struct vsir_src_operand *src, uint32_t value) { - vsir_src_param_init(src, VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); + vsir_src_operand_init(src, VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); src->reg.u.immconst_u32[0] = value; } -static void vsir_src_param_init_io(struct vkd3d_shader_src_param *src, +static void vsir_src_operand_init_io(struct vsir_src_operand *src, enum vkd3d_shader_register_type reg_type, const struct signature_element *e, unsigned int idx_count) { - vsir_src_param_init(src, reg_type, vsir_data_type_from_component_type(e->component_type), idx_count); + vsir_src_operand_init(src, reg_type, vsir_data_type_from_component_type(e->component_type), idx_count); src->reg.dimension = VSIR_DIMENSION_VEC4; src->swizzle = vsir_swizzle_from_writemask(e->mask); } -void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) +void vsir_src_operand_init_label(struct vsir_src_operand *src, unsigned int label_id) { - vsir_src_param_init(param, VKD3DSPR_LABEL, VSIR_DATA_UNUSED, 1); - param->reg.dimension = VSIR_DIMENSION_NONE; - param->reg.idx[0].offset = label_id; + vsir_src_operand_init(src, VKD3DSPR_LABEL, VSIR_DATA_UNUSED, 1); + src->reg.dimension = VSIR_DIMENSION_NONE; + src->reg.idx[0].offset = label_id; } -static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_t idx, enum vsir_data_type type) +static void vsir_src_operand_init_parameter(struct vsir_src_operand *src, uint32_t idx, enum vsir_data_type type) { - vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1); + vsir_src_operand_init(src, VKD3DSPR_PARAMETER, type, 1); src->reg.idx[0].offset = idx; } -static void src_param_init_parameter_vec4(struct vkd3d_shader_src_param *src, uint32_t idx, enum vsir_data_type type) +static void vsir_src_operand_init_parameter_vec4(struct vsir_src_operand *src, uint32_t idx, enum vsir_data_type type) { - vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1); + vsir_src_operand_init(src, VKD3DSPR_PARAMETER, type, 1); src->reg.idx[0].offset = idx; src->reg.dimension = VSIR_DIMENSION_VEC4; src->swizzle = VKD3D_SHADER_NO_SWIZZLE; } -static void vsir_src_param_init_resource(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx) +static void vsir_src_operand_init_resource(struct vsir_src_operand *src, unsigned int id, unsigned int idx) { - vsir_src_param_init(src, VKD3DSPR_RESOURCE, VSIR_DATA_UNUSED, 2); + vsir_src_operand_init(src, VKD3DSPR_RESOURCE, VSIR_DATA_UNUSED, 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) +static void vsir_src_operand_init_sampler(struct vsir_src_operand *src, unsigned int id, unsigned int idx) { - vsir_src_param_init(src, VKD3DSPR_SAMPLER, VSIR_DATA_UNUSED, 2); + vsir_src_operand_init(src, VKD3DSPR_SAMPLER, VSIR_DATA_UNUSED, 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(struct vkd3d_shader_src_param *src, unsigned int idx, +static void vsir_src_operand_init_ssa(struct vsir_src_operand *src, unsigned int idx, enum vsir_data_type data_type, enum vsir_dimension dimension) { - vsir_src_param_init(src, VKD3DSPR_SSA, data_type, 1); + vsir_src_operand_init(src, VKD3DSPR_SSA, data_type, 1); src->reg.idx[0].offset = idx; if (dimension == VSIR_DIMENSION_VEC4) @@ -927,81 +981,81 @@ static void src_param_init_ssa(struct vkd3d_shader_src_param *src, unsigned int } } -static void src_param_init_ssa_scalar(struct vkd3d_shader_src_param *src, +static void vsir_src_operand_init_ssa_scalar(struct vsir_src_operand *src, unsigned int idx, enum vsir_data_type data_type) { - src_param_init_ssa(src, idx, data_type, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(src, idx, data_type, VSIR_DIMENSION_SCALAR); } -static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx) +static void vsir_src_operand_init_ssa_bool(struct vsir_src_operand *src, unsigned int idx) { - src_param_init_ssa_scalar(src, idx, VSIR_DATA_BOOL); + vsir_src_operand_init_ssa_scalar(src, idx, VSIR_DATA_BOOL); } -static void src_param_init_ssa_float(struct vkd3d_shader_src_param *src, unsigned int idx) +static void vsir_src_operand_init_ssa_f32(struct vsir_src_operand *src, unsigned int idx) { - src_param_init_ssa_scalar(src, idx, VSIR_DATA_F32); + vsir_src_operand_init_ssa_scalar(src, idx, VSIR_DATA_F32); } -static void src_param_init_ssa_float4(struct vkd3d_shader_src_param *src, unsigned int idx) +static void vsir_src_operand_init_ssa_f32v4(struct vsir_src_operand *src, unsigned int idx) { - src_param_init_ssa(src, idx, VSIR_DATA_F32, VSIR_DIMENSION_VEC4); + vsir_src_operand_init_ssa(src, idx, VSIR_DATA_F32, VSIR_DIMENSION_VEC4); } -static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx) +static void vsir_src_operand_init_temp_bool(struct vsir_src_operand *src, unsigned int idx) { - vsir_src_param_init(src, VKD3DSPR_TEMP, VSIR_DATA_BOOL, 1); + vsir_src_operand_init(src, VKD3DSPR_TEMP, VSIR_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) +static void vsir_src_operand_init_temp_f32(struct vsir_src_operand *src, unsigned int idx) { - vsir_src_param_init(src, VKD3DSPR_TEMP, VSIR_DATA_F32, 1); + vsir_src_operand_init(src, VKD3DSPR_TEMP, VSIR_DATA_F32, 1); src->reg.idx[0].offset = idx; } -static void src_param_init_temp_float4(struct vkd3d_shader_src_param *src, unsigned int idx) +static void vsir_src_operand_init_temp_f32v4(struct vsir_src_operand *src, unsigned int idx) { - vsir_src_param_init(src, VKD3DSPR_TEMP, VSIR_DATA_F32, 1); + vsir_src_operand_init(src, VKD3DSPR_TEMP, VSIR_DATA_F32, 1); src->reg.dimension = VSIR_DIMENSION_VEC4; src->swizzle = VKD3D_SHADER_NO_SWIZZLE; src->reg.idx[0].offset = idx; } -static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx) +static void vsir_src_operand_init_temp_u32(struct vsir_src_operand *src, unsigned int idx) { - vsir_src_param_init(src, VKD3DSPR_TEMP, VSIR_DATA_U32, 1); + vsir_src_operand_init(src, VKD3DSPR_TEMP, VSIR_DATA_U32, 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, +void vsir_dst_operand_init(struct vsir_dst_operand *dst, enum vkd3d_shader_register_type reg_type, enum vsir_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; + vsir_register_init(&dst->reg, reg_type, data_type, idx_count); + dst->write_mask = VKD3DSP_WRITEMASK_0; + dst->modifiers = VKD3DSPDM_NONE; + dst->shift = 0; } -static void vsir_dst_param_init_io(struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_register_type reg_type, +static void vsir_dst_operand_init_io(struct vsir_dst_operand *dst, enum vkd3d_shader_register_type reg_type, const struct signature_element *e, unsigned int idx_count) { - vsir_dst_param_init(dst, reg_type, vsir_data_type_from_component_type(e->component_type), idx_count); + vsir_dst_operand_init(dst, reg_type, vsir_data_type_from_component_type(e->component_type), idx_count); dst->reg.dimension = VSIR_DIMENSION_VEC4; dst->write_mask = e->mask; } -void vsir_dst_param_init_null(struct vkd3d_shader_dst_param *dst) +void vsir_dst_operand_init_null(struct vsir_dst_operand *dst) { - vsir_dst_param_init(dst, VKD3DSPR_NULL, VSIR_DATA_UNUSED, 0); + vsir_dst_operand_init(dst, VKD3DSPR_NULL, VSIR_DATA_UNUSED, 0); dst->reg.dimension = VSIR_DIMENSION_NONE; dst->write_mask = 0; } -static void dst_param_init_ssa(struct vkd3d_shader_dst_param *dst, unsigned int idx, +static void vsir_dst_operand_init_ssa(struct vsir_dst_operand *dst, unsigned int idx, enum vsir_data_type data_type, enum vsir_dimension dimension) { - vsir_dst_param_init(dst, VKD3DSPR_SSA, data_type, 1); + vsir_dst_operand_init(dst, VKD3DSPR_SSA, data_type, 1); dst->reg.idx[0].offset = idx; if (dimension == VSIR_DIMENSION_VEC4) @@ -1011,50 +1065,50 @@ static void dst_param_init_ssa(struct vkd3d_shader_dst_param *dst, unsigned int } } -static void dst_param_init_ssa_scalar(struct vkd3d_shader_dst_param *dst, +static void vsir_dst_operand_init_ssa_scalar(struct vsir_dst_operand *dst, unsigned int idx, enum vsir_data_type data_type) { - dst_param_init_ssa(dst, idx, data_type, VSIR_DIMENSION_SCALAR); + vsir_dst_operand_init_ssa(dst, idx, data_type, VSIR_DIMENSION_SCALAR); } -static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) +static void vsir_dst_operand_init_ssa_bool(struct vsir_dst_operand *dst, unsigned int idx) { - dst_param_init_ssa_scalar(dst, idx, VSIR_DATA_BOOL); + vsir_dst_operand_init_ssa_scalar(dst, idx, VSIR_DATA_BOOL); } -static void dst_param_init_ssa_float(struct vkd3d_shader_dst_param *dst, unsigned int idx) +static void vsir_dst_operand_init_ssa_f32(struct vsir_dst_operand *dst, unsigned int idx) { - dst_param_init_ssa_scalar(dst, idx, VSIR_DATA_F32); + vsir_dst_operand_init_ssa_scalar(dst, idx, VSIR_DATA_F32); } -static void dst_param_init_ssa_float4(struct vkd3d_shader_dst_param *dst, unsigned int idx) +static void vsir_dst_operand_init_ssa_f32v4(struct vsir_dst_operand *dst, unsigned int idx) { - dst_param_init_ssa(dst, idx, VSIR_DATA_F32, VSIR_DIMENSION_VEC4); + vsir_dst_operand_init_ssa(dst, idx, VSIR_DATA_F32, VSIR_DIMENSION_VEC4); } -static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) +static void vsir_dst_operand_init_temp_bool(struct vsir_dst_operand *dst, unsigned int idx) { - vsir_dst_param_init(dst, VKD3DSPR_TEMP, VSIR_DATA_BOOL, 1); + vsir_dst_operand_init(dst, VKD3DSPR_TEMP, VSIR_DATA_BOOL, 1); dst->reg.idx[0].offset = idx; } -static void dst_param_init_temp_float4(struct vkd3d_shader_dst_param *dst, unsigned int idx) +static void vsir_dst_operand_init_temp_f32v4(struct vsir_dst_operand *dst, unsigned int idx) { - vsir_dst_param_init(dst, VKD3DSPR_TEMP, VSIR_DATA_F32, 1); + vsir_dst_operand_init(dst, VKD3DSPR_TEMP, VSIR_DATA_F32, 1); dst->reg.idx[0].offset = idx; dst->reg.dimension = VSIR_DIMENSION_VEC4; } -static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx) +static void vsir_dst_operand_init_temp_u32(struct vsir_dst_operand *dst, unsigned int idx) { - vsir_dst_param_init(dst, VKD3DSPR_TEMP, VSIR_DATA_U32, 1); + vsir_dst_operand_init(dst, VKD3DSPR_TEMP, VSIR_DATA_U32, 1); dst->reg.idx[0].offset = idx; } -static void dst_param_init_output(struct vkd3d_shader_dst_param *dst, +static void vsir_dst_operand_init_output(struct vsir_dst_operand *dst, enum vsir_data_type data_type, uint32_t idx, uint32_t write_mask) { - vsir_dst_param_init(dst, VKD3DSPR_OUTPUT, data_type, 1); + vsir_dst_operand_init(dst, VKD3DSPR_OUTPUT, data_type, 1); dst->reg.idx[0].offset = idx; dst->reg.dimension = VSIR_DIMENSION_VEC4; dst->write_mask = write_mask; @@ -1079,13 +1133,13 @@ bool vsir_instruction_init_with_params(struct vsir_program *program, ins->dst_count = dst_count; ins->src_count = src_count; - if (!(ins->dst = vsir_program_get_dst_params(program, ins->dst_count))) + if (!(ins->dst = vsir_program_get_dst_operands(program, ins->dst_count))) { ERR("Failed to allocate %u destination parameters.\n", dst_count); return false; } - if (!(ins->src = vsir_program_get_src_params(program, ins->src_count))) + if (!(ins->src = vsir_program_get_src_operands(program, ins->src_count))) { ERR("Failed to allocate %u source parameters.\n", src_count); return false; @@ -1099,15 +1153,15 @@ bool vsir_instruction_init_with_params(struct vsir_program *program, 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; + struct vsir_src_operand *src; - if (!(src_param = vsir_program_get_src_params(program, 1))) + if (!(src = vsir_program_get_src_operands(program, 1))) return false; - vsir_src_param_init_label(src_param, label_id); + vsir_src_operand_init_label(src, label_id); vsir_instruction_init(ins, location, VSIR_OP_LABEL); - ins->src = src_param; + ins->src = src; ins->src_count = 1; return true; @@ -1117,7 +1171,8 @@ static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instr { enum vkd3d_shader_opcode opcode = instruction->opcode; return (VSIR_OP_DCL <= opcode && opcode <= VSIR_OP_DCL_VERTICES_OUT) - || opcode == VSIR_OP_HS_DECLS; + || opcode == VSIR_OP_HS_DECLS || opcode == VSIR_OP_DEF + || opcode == VSIR_OP_DEFI || opcode == VSIR_OP_DEFB; } /* NOTE: Immediate constant buffers are not cloned, so the source must not be destroyed while the @@ -1129,10 +1184,10 @@ static bool vsir_program_iterator_clone_instruction(struct vsir_program *program *dst = *src; - if (dst->dst_count && !(dst->dst = vsir_program_clone_dst_params(program, dst->dst, dst->dst_count))) + if (dst->dst_count && !(dst->dst = vsir_program_clone_dst_operands(program, dst->dst, dst->dst_count))) return false; - return !dst->src_count || (dst->src = vsir_program_clone_src_params(program, dst->src, dst->src_count)); + return !dst->src_count || (dst->src = vsir_program_clone_src_operands(program, dst->src, dst->src_count)); } static bool get_opcode_from_rel_op(enum vkd3d_shader_rel_op rel_op, @@ -1233,11 +1288,11 @@ static enum vkd3d_result vsir_program_normalize_addr(struct vsir_program *progra for (k = 0; k < ins->src_count; ++k) { - struct vkd3d_shader_src_param *src = &ins->src[k]; + struct vsir_src_operand *src = &ins->src[k]; for (r = 0; r < src->reg.idx_count; ++r) { - struct vkd3d_shader_src_param *rel = src->reg.idx[r].rel_addr; + struct vsir_src_operand *rel = src->reg.idx[r].rel_addr; if (rel && rel->reg.type == VKD3DSPR_ADDR) { @@ -1255,6 +1310,44 @@ static enum vkd3d_result vsir_program_normalize_addr(struct vsir_program *progra return VKD3D_OK; } +static enum vkd3d_result vsir_program_lower_dp2add(struct vsir_program *program, struct vsir_program_iterator *dp2add) +{ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(dp2add); + const struct vkd3d_shader_location location = ins->location; + const struct vsir_src_operand *src = ins->src; + const struct vsir_dst_operand *dst = ins->dst; + struct vsir_program_iterator it; + unsigned int dot_id; + + /* dp2add DST, SRC0, SRC1, SRC2 + * -> + * dp2 srDOT, SRC0, SRC1 + * add DST, srDOT, SRC2 */ + + if (!(ins = vsir_program_iterator_insert_before(dp2add, &it, 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_DP2, 1, 2)) + goto fail; + dot_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], dot_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + ins->src[0] = src[0]; + ins->src[1] = src[1]; + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_ADD, 1, 2)) + goto fail; + ins->dst[0] = dst[0]; + vsir_src_operand_init_ssa(&ins->src[0], dot_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + ins->src[1] = src[2]; + + return VKD3D_OK; + +fail: + vsir_program_iterator_nop_range(&it, dp2add, &location); + + return VKD3D_ERROR_OUT_OF_MEMORY; +} + static enum vkd3d_result vsir_program_lower_ifc(struct vsir_program *program, struct vsir_program_iterator *it, unsigned int *tmp_idx, struct vkd3d_shader_message_context *message_context) @@ -1308,6 +1401,182 @@ static enum vkd3d_result vsir_program_lower_ifc(struct vsir_program *program, return VKD3D_OK; } +static enum vkd3d_result vsir_program_lower_lrp(struct vsir_program *program, struct vsir_program_iterator *lrp) +{ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(lrp); + const struct vkd3d_shader_location location = ins->location; + const struct vsir_src_operand *src = ins->src; + const struct vsir_dst_operand *dst = ins->dst; + struct vsir_program_iterator it; + unsigned int neg_id, mad_id; + + /* lrp DST, SRC0, SRC1, SRC2 + * -> + * neg srNEG, SRC0 + * mad srMAD, srNEG, SRC2, SRC2 + * mad DST, SRC0, SRC1, srMAD */ + + if (!(ins = vsir_program_iterator_insert_before(lrp, &it, 2))) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_NEG, 1, 1)) + goto fail; + neg_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], neg_id, src[0].reg.data_type, src[0].reg.dimension); + ins->src[0] = src[0]; + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MAD, 1, 3)) + goto fail; + mad_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], mad_id, src[2].reg.data_type, src[2].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[0], neg_id, src[0].reg.data_type, src[0].reg.dimension); + ins->src[1] = src[2]; + ins->src[2] = src[2]; + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MAD, 1, 3)) + goto fail; + ins->dst[0] = dst[0]; + ins->src[0] = src[0]; + ins->src[1] = src[1]; + vsir_src_operand_init_ssa(&ins->src[2], mad_id, src[2].reg.data_type, src[2].reg.dimension); + + return VKD3D_OK; + +fail: + vsir_program_iterator_nop_range(&it, lrp, &location); + + return VKD3D_ERROR_OUT_OF_MEMORY; +} + +static enum vkd3d_result vsir_program_lower_nrm(struct vsir_program *program, struct vsir_program_iterator *nrm) +{ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(nrm); + const struct vkd3d_shader_location location = ins->location; + const struct vsir_src_operand *src = ins->src; + const struct vsir_dst_operand *dst = ins->dst; + unsigned int dot_id, rsq_id, mul_id; + struct vsir_program_iterator it; + + /* nrm DST, SRC + * -> + * dp3 srDOT, SRC, SRC + * rsq srRSQ, srDOT + * mul srMUL, srRSQ, SRC + * movc DST, srDOT, srMUL, srDOT */ + + if (!(ins = vsir_program_iterator_insert_before(nrm, &it, 3))) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_DP3, 1, 2)) + goto fail; + dot_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], dot_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + ins->src[0] = src[0]; + ins->src[1] = src[0]; + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_RSQ, 1, 1)) + goto fail; + rsq_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], rsq_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(&ins->src[0], dot_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MUL, 1, 2)) + goto fail; + mul_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], mul_id, src[0].reg.data_type, dst[0].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[0], rsq_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + ins->src[1] = src[0]; + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MOVC, 1, 3)) + goto fail; + ins->dst[0] = dst[0]; + vsir_src_operand_init_ssa(&ins->src[0], dot_id, VSIR_DATA_U32, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(&ins->src[1], mul_id, src[0].reg.data_type, dst[0].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[2], dot_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + + return VKD3D_OK; + +fail: + vsir_program_iterator_nop_range(&it, nrm, &location); + + return VKD3D_ERROR_OUT_OF_MEMORY; +} + +static enum vkd3d_result vsir_program_lower_pow(struct vsir_program *program, struct vsir_program_iterator *pow) +{ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(pow); + const struct vkd3d_shader_location location = ins->location; + unsigned int abs_id, log_id, ne_id, movc_id, mul_id; + const struct vsir_src_operand *src = ins->src; + const struct vsir_dst_operand *dst = ins->dst; + struct vsir_program_iterator it; + + /* pow DST, SRC0, SRC1 + * -> + * abs srABS, SRC0.x + * log srLOG, srABS + * ne srNE, SRC1.x, l(0.0f) + * movc srMOVC, srNE, srLOG, srABS + * mul srMUL, srMOVC, SRC1.x + * exp DST, srMUL */ + + if (!(ins = vsir_program_iterator_insert_before(pow, &it, 5))) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_ABS, 1, 1)) + goto fail; + abs_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], abs_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + ins->src[0] = src[0]; + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_LOG, 1, 1)) + goto fail; + log_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], log_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(&ins->src[0], abs_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_NEU, 1, 2)) + goto fail; + ne_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], ne_id, VSIR_DATA_U32, VSIR_DIMENSION_SCALAR); + ins->src[0] = src[1]; + vsir_src_operand_init_const_f32(&ins->src[1], 0.0f); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MOVC, 1, 3)) + goto fail; + movc_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], movc_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(&ins->src[0], ne_id, VSIR_DATA_U32, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(&ins->src[1], log_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(&ins->src[2], abs_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MUL, 1, 2)) + goto fail; + mul_id = program->ssa_count++; + vsir_dst_operand_init_ssa(&ins->dst[0], mul_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + vsir_src_operand_init_ssa(&ins->src[0], movc_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + ins->src[1] = src[1]; + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_EXP, 1, 1)) + goto fail; + ins->dst[0] = dst[0]; + vsir_src_operand_init_ssa(&ins->src[0], mul_id, src[0].reg.data_type, VSIR_DIMENSION_SCALAR); + + return VKD3D_OK; + +fail: + vsir_program_iterator_nop_range(&it, pow, &location); + + return VKD3D_ERROR_OUT_OF_MEMORY; +} + static enum vkd3d_result vsir_program_lower_texkill(struct vsir_program *program, struct vsir_program_iterator *it, unsigned int *tmp_idx) { @@ -1396,7 +1665,7 @@ static enum vkd3d_result vsir_program_lower_precise_mad(struct vsir_program *pro struct vsir_program_iterator *it) { struct vkd3d_shader_instruction *mad, *mul_ins, *add_ins; - struct vkd3d_shader_dst_param *mul_dst; + struct vsir_dst_operand *mul_dst; mad = vsir_program_iterator_current(it); @@ -1420,8 +1689,9 @@ static enum vkd3d_result vsir_program_lower_precise_mad(struct vsir_program *pro mul_dst = mul_ins->dst; *add_ins->dst = *mul_dst; - dst_param_init_ssa(mul_dst, program->ssa_count, mul_ins->src[0].reg.data_type, VSIR_DIMENSION_VEC4); - src_param_init_ssa(&add_ins->src[0], program->ssa_count++, mul_ins->src[0].reg.data_type, VSIR_DIMENSION_VEC4); + vsir_dst_operand_init_ssa(mul_dst, program->ssa_count, mul_ins->src[0].reg.data_type, VSIR_DIMENSION_VEC4); + vsir_src_operand_init_ssa(&add_ins->src[0], program->ssa_count++, + mul_ins->src[0].reg.data_type, VSIR_DIMENSION_VEC4); add_ins->src[1] = mul_ins->src[2]; @@ -1479,7 +1749,7 @@ static enum vkd3d_result vsir_program_lower_udiv(struct vsir_program *program, mov->src[0] = udiv->src[0]; src0_id = program->ssa_count++; - dst_param_init_ssa(&mov->dst[0], src0_id, udiv->src[0].reg.data_type, udiv->src[0].reg.dimension); + vsir_dst_operand_init_ssa(&mov->dst[0], src0_id, udiv->src[0].reg.data_type, udiv->src[0].reg.dimension); mov = vsir_program_iterator_next(it); if (!(vsir_instruction_init_with_params(program, mov, &udiv->location, VSIR_OP_MOV, 1, 1))) @@ -1487,14 +1757,14 @@ static enum vkd3d_result vsir_program_lower_udiv(struct vsir_program *program, mov->src[0] = udiv->src[1]; src1_id = program->ssa_count++; - dst_param_init_ssa(&mov->dst[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_dst_operand_init_ssa(&mov->dst[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); mov = vsir_program_iterator_next(it); if (!(vsir_instruction_init_with_params(program, mov, &udiv->location, VSIR_OP_MOVC, 1, 3))) return VKD3D_ERROR_OUT_OF_MEMORY; - src_param_init_ssa(&mov->src[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); - src_param_init_ssa(&mov->src[1], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&mov->src[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&mov->src[1], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); vsir_register_init(&mov->src[2].reg, VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); mov->src[2].reg.dimension = udiv->src[1].reg.dimension; mov->src[2].reg.u.immconst_u32[0] = 1; @@ -1504,7 +1774,7 @@ static enum vkd3d_result vsir_program_lower_udiv(struct vsir_program *program, if (mov->src[2].reg.dimension == VSIR_DIMENSION_VEC4) mov->src[2].swizzle = VKD3D_SHADER_NO_SWIZZLE; divisor_id = program->ssa_count++; - dst_param_init_ssa(&mov->dst[0], divisor_id, mov->src[1].reg.data_type, mov->src[1].reg.dimension); + vsir_dst_operand_init_ssa(&mov->dst[0], divisor_id, mov->src[1].reg.data_type, mov->src[1].reg.dimension); if (udiv->dst[0].reg.type != VKD3DSPR_NULL) { @@ -1515,9 +1785,10 @@ static enum vkd3d_result vsir_program_lower_udiv(struct vsir_program *program, ins->flags = udiv->flags; - src_param_init_ssa(&ins->src[0], src0_id, udiv->src[0].reg.data_type, udiv->src[0].reg.dimension); - src_param_init_ssa(&ins->src[1], divisor_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); - dst_param_init_ssa(&ins->dst[0], program->ssa_count, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[0], src0_id, udiv->src[0].reg.data_type, udiv->src[0].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[1], divisor_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_dst_operand_init_ssa(&ins->dst[0], program->ssa_count, + udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); /* Like its TPF equivalent, division by zero is well-defined for * VSIR_OP_UDIV, and returns UINT_MAX. Division by zero is undefined @@ -1526,8 +1797,9 @@ static enum vkd3d_result vsir_program_lower_udiv(struct vsir_program *program, if (!(vsir_instruction_init_with_params(program, ins, &udiv->location, VSIR_OP_MOVC, 1, 3))) return VKD3D_ERROR_OUT_OF_MEMORY; - src_param_init_ssa(&ins->src[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); - src_param_init_ssa(&ins->src[1], program->ssa_count, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[1], program->ssa_count, + udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); vsir_register_init(&ins->src[2].reg, VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); ins->src[2].reg.dimension = udiv->src[1].reg.dimension; ins->src[2].reg.u.immconst_u32[0] = UINT_MAX; @@ -1550,16 +1822,18 @@ static enum vkd3d_result vsir_program_lower_udiv(struct vsir_program *program, ins->flags = udiv->flags; - src_param_init_ssa(&ins->src[0], src0_id, udiv->src[0].reg.data_type, udiv->src[0].reg.dimension); - src_param_init_ssa(&ins->src[1], divisor_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); - dst_param_init_ssa(&ins->dst[0], program->ssa_count, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[0], src0_id, udiv->src[0].reg.data_type, udiv->src[0].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[1], divisor_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_dst_operand_init_ssa(&ins->dst[0], program->ssa_count, + udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); ins = vsir_program_iterator_next(it); if (!(vsir_instruction_init_with_params(program, ins, &udiv->location, VSIR_OP_MOVC, 1, 3))) return VKD3D_ERROR_OUT_OF_MEMORY; - src_param_init_ssa(&ins->src[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); - src_param_init_ssa(&ins->src[1], program->ssa_count, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[0], src1_id, udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[1], program->ssa_count, + udiv->src[1].reg.data_type, udiv->src[1].reg.dimension); vsir_register_init(&ins->src[2].reg, VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); ins->src[2].reg.dimension = udiv->src[1].reg.dimension; ins->src[2].reg.u.immconst_u32[0] = UINT_MAX; @@ -1602,7 +1876,7 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog s = vsir_swizzle_get_component(sincos->src->swizzle, 0); mov->src[0].swizzle = vkd3d_shader_create_swizzle(s, s, s, s); - dst_param_init_ssa_scalar(&mov->dst[0], program->ssa_count, sincos->src[0].reg.data_type); + vsir_dst_operand_init_ssa_scalar(&mov->dst[0], program->ssa_count, sincos->src[0].reg.data_type); if (sincos->dst->write_mask & VKD3DSP_WRITEMASK_1) { @@ -1613,7 +1887,7 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog ins->flags = sincos->flags; - src_param_init_ssa_scalar(&ins->src[0], program->ssa_count, sincos->src[0].reg.data_type); + vsir_src_operand_init_ssa_scalar(&ins->src[0], program->ssa_count, sincos->src[0].reg.data_type); ins->dst[0] = *sincos->dst; ins->dst[0].write_mask = VKD3DSP_WRITEMASK_1; @@ -1628,7 +1902,7 @@ static enum vkd3d_result vsir_program_lower_sm1_sincos(struct vsir_program *prog ins->flags = sincos->flags; - src_param_init_ssa_scalar(&ins->src[0], program->ssa_count, sincos->src[0].reg.data_type); + vsir_src_operand_init_ssa_scalar(&ins->src[0], program->ssa_count, sincos->src[0].reg.data_type); ins->dst[0] = *sincos->dst; ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0; @@ -1672,7 +1946,8 @@ static enum vkd3d_result vsir_program_lower_sm4_sincos(struct vsir_program *prog return VKD3D_ERROR_OUT_OF_MEMORY; mov->src[0] = sincos->src[0]; - dst_param_init_ssa(&mov->dst[0], program->ssa_count, sincos->src[0].reg.data_type, sincos->src[0].reg.dimension); + vsir_dst_operand_init_ssa(&mov->dst[0], program->ssa_count, + sincos->src[0].reg.data_type, sincos->src[0].reg.dimension); if (sincos->dst[0].reg.type != VKD3DSPR_NULL) { @@ -1683,7 +1958,7 @@ static enum vkd3d_result vsir_program_lower_sm4_sincos(struct vsir_program *prog ins->flags = sincos->flags; - src_param_init_ssa(&ins->src[0], program->ssa_count, + vsir_src_operand_init_ssa(&ins->src[0], program->ssa_count, sincos->src[0].reg.data_type, sincos->src[0].reg.dimension); ins->dst[0] = sincos->dst[0]; } @@ -1697,7 +1972,7 @@ static enum vkd3d_result vsir_program_lower_sm4_sincos(struct vsir_program *prog ins->flags = sincos->flags; - src_param_init_ssa(&ins->src[0], program->ssa_count, + vsir_src_operand_init_ssa(&ins->src[0], program->ssa_count, sincos->src[0].reg.data_type, sincos->src[0].reg.dimension); ins->dst[0] = sincos->dst[1]; } @@ -1708,6 +1983,88 @@ static enum vkd3d_result vsir_program_lower_sm4_sincos(struct vsir_program *prog return VKD3D_OK; } +static enum vkd3d_result vsir_program_lower_swapc(struct vsir_program *program, + struct vsir_program_iterator *swapc, struct vsir_transformation_context *ctx) +{ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(swapc); + const struct vkd3d_shader_location location = ins->location; + const struct vsir_src_operand *src = ins->src; + const struct vsir_dst_operand *dst = ins->dst; + unsigned int mov_start, count = 2; + struct vsir_program_iterator it; + + /* swapc DST0, DST1, SRC0, SRC1, SRC2 + * -> + * mov srS0, SRC0 + * mov srS1, SRC1 + * mov srS2, SRC2 + * movc DST0, srS0, srS2, srS1 + * movc DST1, srS0, srS1, srS2 */ + + if (ins->dst_count != 2) + { + vkd3d_shader_error(ctx->message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_INVALID_DEST_COUNT, + "Internal compiler error: invalid destination count %zu for SWAPC.", ins->dst_count); + return VKD3D_ERROR; + } + + if (dst[0].reg.type != VKD3DSPR_NULL) + ++count; + if (dst[1].reg.type != VKD3DSPR_NULL) + ++count; + + if (!(ins = vsir_program_iterator_insert_before(swapc, &it, count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + /* Save the sources in SSAs in case a destination collides with them. */ + mov_start = program->ssa_count; + for (unsigned int i = 0; i < 3; ++i) + { + if (!(vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MOV, 1, 1))) + goto fail; + + ins->src[0] = src[i]; + vsir_dst_operand_init_ssa(&ins->dst[0], mov_start + i, src[i].reg.data_type, src[i].reg.dimension); + ++program->ssa_count; + + ins = vsir_program_iterator_next(&it); + } + + if (dst[0].reg.type != VKD3DSPR_NULL) + { + if (!(vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MOVC, 1, 3))) + goto fail; + + ins->dst[0] = dst[0]; + + vsir_src_operand_init_ssa(&ins->src[0], mov_start, src[0].reg.data_type, src[0].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[1], mov_start + 2, src[2].reg.data_type, src[2].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[2], mov_start + 1, src[1].reg.data_type, src[1].reg.dimension); + + ins = vsir_program_iterator_next(&it); + } + + if (dst[1].reg.type != VKD3DSPR_NULL) + { + + if (!(vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MOVC, 1, 3))) + goto fail; + + ins->dst[0] = dst[1]; + + vsir_src_operand_init_ssa(&ins->src[0], mov_start, src[0].reg.data_type, src[0].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[1], mov_start + 1, src[1].reg.data_type, src[1].reg.dimension); + vsir_src_operand_init_ssa(&ins->src[2], mov_start + 2, src[2].reg.data_type, src[2].reg.dimension); + } + + return VKD3D_OK; + +fail: + vsir_program_iterator_nop_range(&it, swapc, &location); + + return VKD3D_ERROR_OUT_OF_MEMORY; +} + static enum vkd3d_result vsir_program_lower_texcrd(struct vsir_program *program, struct vkd3d_shader_instruction *ins, struct vkd3d_shader_message_context *message_context) { @@ -1730,7 +2087,7 @@ static enum vkd3d_result vsir_program_lower_texld_sm1(struct vsir_program *progr { const struct vkd3d_shader_descriptor_info1 *sampler; unsigned int idx = ins->dst[0].reg.idx[0].offset; - struct vkd3d_shader_src_param *srcs; + struct vsir_src_operand *srcs; /* texld DST, t# -> sample DST, t#, resource#, sampler# */ @@ -1741,13 +2098,13 @@ static enum vkd3d_result vsir_program_lower_texld_sm1(struct vsir_program *progr return VKD3D_ERROR_NOT_IMPLEMENTED; } - if (!(srcs = vsir_program_get_src_params(program, 4))) + if (!(srcs = vsir_program_get_src_operands(program, 4))) return VKD3D_ERROR_OUT_OF_MEMORY; /* Note we run before I/O normalization. */ srcs[0] = ins->src[0]; - vsir_src_param_init_resource(&srcs[1], idx, idx); - vsir_src_param_init_sampler(&srcs[2], idx, idx); + vsir_src_operand_init_resource(&srcs[1], idx, idx); + vsir_src_operand_init_sampler(&srcs[2], idx, idx); sampler = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); if (sampler->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) @@ -1800,7 +2157,7 @@ static enum vkd3d_result vsir_program_lower_texldp(struct vsir_program *program, if (!vsir_instruction_init_with_params(program, div_ins, &tex->location, VSIR_OP_DIV, 1, 2)) return VKD3D_ERROR_OUT_OF_MEMORY; - vsir_dst_param_init(&div_ins->dst[0], VKD3DSPR_TEMP, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&div_ins->dst[0], VKD3DSPR_TEMP, VSIR_DATA_F32, 1); div_ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; div_ins->dst[0].reg.idx[0].offset = *tmp_idx; div_ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; @@ -1830,17 +2187,17 @@ static enum vkd3d_result vsir_program_lower_texld(struct vsir_program *program, { const struct vkd3d_shader_descriptor_info1 *sampler; unsigned int idx = tex->src[1].reg.idx[0].offset; - struct vkd3d_shader_src_param *srcs; + struct vsir_src_operand *srcs; VKD3D_ASSERT(tex->src[1].reg.idx_count == 1); VKD3D_ASSERT(!tex->src[1].reg.idx[0].rel_addr); - if (!(srcs = vsir_program_get_src_params(program, 4))) + if (!(srcs = vsir_program_get_src_operands(program, 4))) 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); + vsir_src_operand_init_resource(&srcs[1], idx, idx); + vsir_src_operand_init_sampler(&srcs[2], idx, idx); sampler = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); if (sampler->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) @@ -1887,17 +2244,17 @@ 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; + struct vsir_src_operand *srcs; VKD3D_ASSERT(texldd->src[1].reg.idx_count == 1); VKD3D_ASSERT(!texldd->src[1].reg.idx[0].rel_addr); - if (!(srcs = vsir_program_get_src_params(program, 5))) + if (!(srcs = vsir_program_get_src_operands(program, 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); + vsir_src_operand_init_resource(&srcs[1], idx, idx); + vsir_src_operand_init_sampler(&srcs[2], idx, idx); srcs[3] = texldd->src[2]; srcs[4] = texldd->src[3]; @@ -1913,17 +2270,17 @@ static enum vkd3d_result vsir_program_lower_texldl(struct vsir_program *program, { unsigned int idx = texldl->src[1].reg.idx[0].offset; enum vkd3d_shader_swizzle_component w; - struct vkd3d_shader_src_param *srcs; + struct vsir_src_operand *srcs; VKD3D_ASSERT(texldl->src[1].reg.idx_count == 1); VKD3D_ASSERT(!texldl->src[1].reg.idx[0].rel_addr); - if (!(srcs = vsir_program_get_src_params(program, 4))) + if (!(srcs = vsir_program_get_src_operands(program, 4))) return VKD3D_ERROR_OUT_OF_MEMORY; srcs[0] = texldl->src[0]; - vsir_src_param_init_resource(&srcs[1], idx, idx); - vsir_src_param_init_sampler(&srcs[2], idx, idx); + vsir_src_operand_init_resource(&srcs[1], idx, idx); + vsir_src_operand_init_sampler(&srcs[2], idx, idx); texldl->opcode = VSIR_OP_SAMPLE_LOD; texldl->src = srcs; @@ -1936,11 +2293,39 @@ static enum vkd3d_result vsir_program_lower_texldl(struct vsir_program *program, return VKD3D_OK; } -static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, struct vkd3d_shader_instruction *ins) +static bool is_texture_projected(const struct vsir_program *program, + struct vkd3d_shader_message_context *message_context, unsigned int index) +{ + const struct vkd3d_shader_parameter1 *parameter; + + if (!(parameter = vsir_program_get_parameter(program, VKD3D_SHADER_PARAMETER_NAME_PROJECTED_TEXTURE_MASK))) + return false; + + if (parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + { + vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "Unsupported projected texture mask parameter type %#x.", parameter->type); + return false; + } + + if (parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) + { + vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid projected texture mask parameter data type %#x.", parameter->data_type); + return false; + } + + return parameter->u.immediate_constant.u.u32 & (1u << index); +} + +static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, + struct vsir_program_iterator *it, struct vkd3d_shader_message_context *message_context) { + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(it); + const struct vkd3d_shader_location location = ins->location; const struct vkd3d_shader_descriptor_info1 *sampler; unsigned int idx = ins->dst[0].reg.idx[0].offset; - struct vkd3d_shader_src_param *srcs; + struct vsir_src_operand *srcs; /* tex t# -> sample t#, t#, resource#, sampler# * Note that the t# destination will subsequently be turned into a temp. */ @@ -1948,16 +2333,46 @@ static enum vkd3d_result vsir_program_lower_tex(struct vsir_program *program, st /* We run before I/O normalization. */ VKD3D_ASSERT(program->normalisation_level < VSIR_NORMALISED_SM6); - if (!(srcs = vsir_program_get_src_params(program, 4))) + if (!(srcs = vsir_program_get_src_operands(program, 4))) return VKD3D_ERROR_OUT_OF_MEMORY; - vsir_src_param_init(&srcs[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); - srcs[0].reg.idx[0].offset = idx; - srcs[0].reg.dimension = VSIR_DIMENSION_VEC4; - srcs[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; + if (is_texture_projected(program, message_context, idx)) + { + struct vsir_dst_operand *dst = ins->dst; + uint32_t coords = program->ssa_count++; + + /* div sr0, t#, t#.w */ + + if (!vsir_program_iterator_insert_after(it, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = vsir_program_iterator_current(it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_DIV, 1, 2)) + return VKD3D_ERROR_OUT_OF_MEMORY; + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], coords); + vsir_src_operand_init(&ins->src[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); + ins->src[0].reg.idx[0].offset = idx; + ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; + ins->src[1] = ins->src[0]; + ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W); - vsir_src_param_init_resource(&srcs[1], idx, idx); - vsir_src_param_init_sampler(&srcs[2], idx, idx); + ins = vsir_program_iterator_next(it); + vsir_instruction_init(ins, &location, VSIR_OP_SAMPLE); + ins->dst_count = 1; + ins->dst = dst; + vsir_src_operand_init_ssa_f32v4(&srcs[0], coords); + } + else + { + vsir_src_operand_init(&srcs[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); + srcs[0].reg.idx[0].offset = idx; + srcs[0].reg.dimension = VSIR_DIMENSION_VEC4; + srcs[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; + } + + vsir_src_operand_init_resource(&srcs[1], idx, idx); + vsir_src_operand_init_sampler(&srcs[2], idx, idx); sampler = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); if (sampler->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) @@ -1985,7 +2400,7 @@ static enum vkd3d_result vsir_program_lower_texcoord(struct vsir_program *progra struct vkd3d_shader_instruction *ins) { unsigned int idx = ins->dst[0].reg.idx[0].offset; - struct vkd3d_shader_src_param *srcs; + struct vsir_src_operand *srcs; /* texcoord t# -> saturate t#, t# * Note that the t# destination will subsequently be turned into a temp. */ @@ -1993,10 +2408,10 @@ static enum vkd3d_result vsir_program_lower_texcoord(struct vsir_program *progra /* We run before I/O normalization. */ VKD3D_ASSERT(program->normalisation_level < VSIR_NORMALISED_SM6); - if (!(srcs = vsir_program_get_src_params(program, 1))) + if (!(srcs = vsir_program_get_src_operands(program, 1))) return VKD3D_ERROR_OUT_OF_MEMORY; - vsir_src_param_init(&srcs[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); + vsir_src_operand_init(&srcs[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); srcs[0].reg.idx[0].offset = idx; srcs[0].reg.dimension = VSIR_DIMENSION_VEC4; srcs[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; @@ -2009,8 +2424,8 @@ static enum vkd3d_result vsir_program_lower_texcoord(struct vsir_program *progra } static struct vkd3d_shader_instruction *generate_bump_coords(struct vsir_program *program, - struct vsir_program_iterator *it, uint32_t idx, const struct vkd3d_shader_src_param *coords, - const struct vkd3d_shader_src_param *perturbation, const struct vkd3d_shader_location *loc) + struct vsir_program_iterator *it, uint32_t idx, const struct vsir_src_operand *coords, + const struct vsir_src_operand *perturbation, const struct vkd3d_shader_location *loc) { struct vkd3d_shader_instruction *ins; uint32_t ssa_temp, ssa_coords; @@ -2027,23 +2442,23 @@ static struct vkd3d_shader_instruction *generate_bump_coords(struct vsir_program ins = vsir_program_iterator_current(it); if (!vsir_instruction_init_with_params(program, ins, loc, VSIR_OP_MAD, 1, 3)) return false; - dst_param_init_ssa_float4(&ins->dst[0], ssa_temp); + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], ssa_temp); ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1; ins->src[0] = *perturbation; ins->src[0].swizzle = vsir_combine_swizzles(perturbation->swizzle, VKD3D_SHADER_SWIZZLE(X, X, X, X)); - src_param_init_parameter_vec4(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_BUMP_MATRIX_0 + idx, VSIR_DATA_F32); + vsir_src_operand_init_parameter_vec4(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_BUMP_MATRIX_0 + idx, VSIR_DATA_F32); ins->src[2] = *coords; ins = vsir_program_iterator_next(it); if (!vsir_instruction_init_with_params(program, ins, loc, VSIR_OP_MAD, 1, 3)) return false; - dst_param_init_ssa_float4(&ins->dst[0], ssa_coords); + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], ssa_coords); ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1; ins->src[0] = *perturbation; ins->src[0].swizzle = vsir_combine_swizzles(perturbation->swizzle, VKD3D_SHADER_SWIZZLE(Y, Y, Y, Y)); - src_param_init_parameter_vec4(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_BUMP_MATRIX_0 + idx, VSIR_DATA_F32); + vsir_src_operand_init_parameter_vec4(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_BUMP_MATRIX_0 + idx, VSIR_DATA_F32); ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(Z, W, W, W); - src_param_init_ssa_float4(&ins->src[2], ssa_temp); + vsir_src_operand_init_ssa_f32v4(&ins->src[2], ssa_temp); ins->src[2].swizzle = VKD3D_SHADER_SWIZZLE(X, Y, Y, Y); return ins; @@ -2053,8 +2468,8 @@ static enum vkd3d_result vsir_program_lower_bem(struct vsir_program *program, st { struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(it); const struct vkd3d_shader_location location = ins->location; - const struct vkd3d_shader_src_param *src = ins->src; - const struct vkd3d_shader_dst_param *dst = ins->dst; + const struct vsir_src_operand *src = ins->src; + const struct vsir_dst_operand *dst = ins->dst; /* bem DST.xy, SRC0, SRC1 * -> @@ -2071,73 +2486,301 @@ static enum vkd3d_result vsir_program_lower_bem(struct vsir_program *program, st return VKD3D_OK; } -static enum vkd3d_result vsir_program_lower_texbem(struct vsir_program *program, - struct vsir_program_iterator *it, struct vkd3d_shader_message_context *message_context) +static enum vkd3d_result vsir_program_lower_rep(struct vsir_program *program, struct vsir_program_iterator *rep) { - struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(it); - const struct vkd3d_shader_location location = ins->location; - const struct vkd3d_shader_descriptor_info1 *descriptor; - const struct vkd3d_shader_src_param *src = ins->src; - bool is_texbeml = (ins->opcode == VSIR_OP_TEXBEML); - unsigned int idx = ins->dst[0].reg.idx[0].offset; - uint32_t ssa_coords, ssa_luminance, ssa_sample; - struct vkd3d_shader_src_param orig_coords; + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(rep); + struct vkd3d_shader_location location = ins->location; + const struct vsir_src_operand *src = ins->src; + unsigned int iter_id = program->temp_count++; + struct vsir_program_iterator it; - /* texbem t#, SRC - * -> - * bem srCOORDS.xy, t#, SRC - * texld t#, srCOORDS + /* rep SRC0 * -> - * mad srTMP.xy, SRC.xx, BUMP_MATRIX#.xy, t#.xy - * mad srCOORDS.xy, SRC.yy, BUMP_MATRIX#.zw, srTMP.xy - * sample t#, srCOORDS, resource#, sampler# - * - * Luminance then adds: - * - * mad srLUM.x, SRC.z, BUMP_LUMINANCE_SCALE#, BUMP_LUMINANCE_OFFSET# - * mul t#, t#, srLUM.xxxx - * - * Note that the t# destination will subsequently be turned into a temp. */ - - descriptor = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); - if (descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) - { - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, - "Unhandled TEXBEM(L) with a comparison sampler."); - return VKD3D_ERROR_NOT_IMPLEMENTED; - } + * mov rITER, SRC0 + * loop + * breakp_z rITER + * iadd rITER, rITER, -1 */ - descriptor = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, idx); - if (descriptor->resource_type != VKD3D_SHADER_RESOURCE_TEXTURE_2D) - { - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, - "Unhandled TEXBEM(L) with resource dimension %#x.", descriptor->resource_type); - return VKD3D_ERROR_NOT_IMPLEMENTED; - } + /* NOTE: `endrep -> endloop` is done by another pass. */ - if (!vsir_program_iterator_insert_after(it, is_texbeml ? 4 : 2)) + if (!(ins = vsir_program_iterator_insert_before(rep, &it, 3))) return VKD3D_ERROR_OUT_OF_MEMORY; + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MOV, 1, 1)) + goto fail; + ins->src[0] = src[0]; + vsir_dst_operand_init_temp_u32(&ins->dst[0], iter_id); - vsir_src_param_init(&orig_coords, VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); - orig_coords.reg.idx[0].offset = idx; - orig_coords.reg.dimension = VSIR_DIMENSION_VEC4; - orig_coords.swizzle = VKD3D_SHADER_NO_SWIZZLE; + ins = vsir_program_iterator_next(&it); + vsir_instruction_init(ins, &location, VSIR_OP_LOOP); - if (!(ins = generate_bump_coords(program, it, idx, &orig_coords, &src[0], &location))) - return VKD3D_ERROR_OUT_OF_MEMORY; - ssa_coords = ins->dst[0].reg.idx[0].offset; + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_BREAKP, 0, 1)) + goto fail; + ins->flags = VKD3D_SHADER_CONDITIONAL_OP_Z; + vsir_src_operand_init_temp_u32(&ins->src[0], iter_id); - ins = vsir_program_iterator_next(it); - if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_SAMPLE, 1, 3)) + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_IADD, 1, 2)) + goto fail; + vsir_dst_operand_init_temp_u32(&ins->dst[0], iter_id); + vsir_src_operand_init_temp_u32(&ins->src[0], iter_id); + vsir_src_operand_init_const_u32(&ins->src[1], ~0u); + + return VKD3D_OK; + +fail: + vsir_program_iterator_nop_range(&it, rep, &location); + + return VKD3D_ERROR_OUT_OF_MEMORY; +} + +static bool vsir_register_replace_loop_register_with_temp(struct vsir_program *program, + struct vkd3d_shader_register *reg, unsigned int idxtemp_idx, unsigned int temp_id) +{ + if (reg->type == VKD3DSPR_LOOP) + { + reg->type = VKD3DSPR_TEMP; + reg->idx_count = 1; + reg->idx[0].offset = temp_id; + reg->idx[0].rel_addr = NULL; + return true; + } + + if (reg->idx[0].rel_addr && reg->idx[0].rel_addr->reg.type == VKD3DSPR_LOOP) + { + if (!shader_register_clone_relative_addresses(reg, program)) + return false; + if (reg->type == VKD3DSPR_INPUT) + { + reg->type = VKD3DSPR_IDXTEMP; + reg->idx_count = 2; + reg->idx[1].offset = reg->idx[0].offset; + reg->idx[1].rel_addr = reg->idx[0].rel_addr; + vsir_src_operand_init_temp_u32(reg->idx[1].rel_addr, temp_id); + reg->idx[0].offset = idxtemp_idx; + reg->idx[0].rel_addr = NULL; + } + else + { + vsir_src_operand_init_temp_u32(reg->idx[0].rel_addr, temp_id); + } + } + + return true; +} + +static enum vkd3d_result vsir_program_lower_loop(struct vsir_program *program, + struct vsir_program_iterator *loop, unsigned int idxtmp_idx) +{ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(loop); + struct vkd3d_shader_location location = ins->location; + const struct vsir_src_operand *src = ins->src; + unsigned int iter_id, neg_id, val_id; + struct vsir_program_iterator it; + unsigned int depth = 1; + unsigned int i; + + /* loop aL, SRC1 + * <instructions, using aL> + * endloop + * -> + * mov rITER.x, SRC1.x + * ineg srNEG, SRC1.z + * iadd rVAL.x, SRC1.y, srNEG + * loop + * breakp_z rITER.x + * iadd rITER.x, rITER.x, -1 + * iadd rVAL.x, rVAL.x, SRC1.z + * <instructions, replacing + * aL -> rVAL.x + * vN[aL] -> xIDXTEMP[rVAL.x] + * > + * endloop + */ + + VKD3D_ASSERT(ins->src_count == 2); + + if (!(ins = vsir_program_iterator_insert_before(loop, &it, 6))) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MOV, 1, 1)) + goto fail; + iter_id = program->temp_count++; + vsir_dst_operand_init_temp_u32(&ins->dst[0], iter_id); + ins->src[0] = src[1]; + ins->src[0].swizzle = vsir_combine_swizzles(src[1].swizzle, VKD3D_SHADER_SWIZZLE(X, X, X, X)); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_INEG, 1, 1)) + goto fail; + neg_id = program->ssa_count++; + vsir_dst_operand_init_ssa_scalar(&ins->dst[0], neg_id, src[1].reg.data_type); + ins->src[0] = src[1]; + ins->src[0].swizzle = vsir_combine_swizzles(src[1].swizzle, VKD3D_SHADER_SWIZZLE(Z, Z, Z, Z)); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_IADD, 1, 2)) + goto fail; + val_id = program->temp_count++; + vsir_dst_operand_init_temp_u32(&ins->dst[0], val_id); + ins->src[0] = src[1]; + ins->src[0].swizzle = vsir_combine_swizzles(src[1].swizzle, VKD3D_SHADER_SWIZZLE(Y, Y, Y, Y)); + vsir_src_operand_init_ssa_scalar(&ins->src[1], neg_id, src[1].reg.data_type); + + ins = vsir_program_iterator_next(&it); + vsir_instruction_init(ins, &location, VSIR_OP_LOOP); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_BREAKP, 0, 1)) + goto fail; + ins->flags = VKD3D_SHADER_CONDITIONAL_OP_Z; + vsir_src_operand_init_temp_u32(&ins->src[0], iter_id); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_IADD, 1, 2)) + goto fail; + vsir_dst_operand_init_temp_u32(&ins->dst[0], iter_id); + vsir_src_operand_init_temp_u32(&ins->src[0], iter_id); + vsir_src_operand_init_const_u32(&ins->src[1], ~0u); + + ins = vsir_program_iterator_next(&it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_IADD, 1, 2)) + goto fail; + vsir_dst_operand_init_temp_u32(&ins->dst[0], val_id); + vsir_src_operand_init_temp_u32(&ins->src[0], val_id); + ins->src[1] = src[1]; + ins->src[1].swizzle = vsir_combine_swizzles(src[1].swizzle, VKD3D_SHADER_SWIZZLE(Z, Z, Z, Z)); + + for (ins = vsir_program_iterator_next(&it); ins; ins = vsir_program_iterator_next(&it)) + { + if (ins->opcode == VSIR_OP_LOOP) + { + ++depth; + continue; + } + + if (ins->opcode == VSIR_OP_ENDLOOP) + { + --depth; + if (!depth) + break; + continue; + } + + if (depth != 1) + continue; + + for (i = 0; i < ins->dst_count; ++i) + { + if (!vsir_register_replace_loop_register_with_temp(program, &ins->dst[i].reg, idxtmp_idx, val_id)) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < ins->src_count; ++i) + { + if (!vsir_register_replace_loop_register_with_temp(program, &ins->src[i].reg, idxtmp_idx, val_id)) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + } + + return VKD3D_OK; + +fail: + vsir_program_iterator_nop_range(&it, loop, &location); + + return VKD3D_ERROR_OUT_OF_MEMORY; +} + +static enum vkd3d_result vsir_program_lower_texbem(struct vsir_program *program, + struct vsir_program_iterator *it, struct vkd3d_shader_message_context *message_context) +{ + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(it); + const struct vkd3d_shader_location location = ins->location; + const struct vkd3d_shader_descriptor_info1 *descriptor; + bool is_texbeml = (ins->opcode == VSIR_OP_TEXBEML); + unsigned int idx = ins->dst[0].reg.idx[0].offset; + uint32_t ssa_coords, ssa_luminance, ssa_sample; + const struct vsir_src_operand *src = ins->src; + struct vsir_src_operand orig_coords; + bool projected; + + /* texbem t#, SRC + * -> + * bem srCOORDS.xy, t#, SRC + * texld t#, srCOORDS + * -> + * mad srTMP.xy, SRC.xx, BUMP_MATRIX#.xy, t#.xy + * mad srCOORDS.xy, SRC.yy, BUMP_MATRIX#.zw, srTMP.xy + * sample t#, srCOORDS, resource#, sampler# + * + * Luminance then adds: + * + * mad srLUM.x, SRC.z, BUMP_LUMINANCE_SCALE#, BUMP_LUMINANCE_OFFSET# + * mul t#, t#, srLUM.xxxx + * + * If projecting, we replace srCOORDS calculation with + * + * div srPROJ, t#, t#.w + * bem srCOORDS.xy, srPROJ.xy, SRC + * + * Note that the t# destination will subsequently be turned into a temp. */ + + descriptor = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, idx); + if (descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "Unhandled TEXBEM(L) with a comparison sampler."); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + + descriptor = vkd3d_shader_find_descriptor(&program->descriptors, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, idx); + if (descriptor->resource_type != VKD3D_SHADER_RESOURCE_TEXTURE_2D) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "Unhandled TEXBEM(L) with resource dimension %#x.", descriptor->resource_type); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + + projected = is_texture_projected(program, message_context, idx); + if (!vsir_program_iterator_insert_after(it, 2 + (is_texbeml ? 2 : 0) + (projected ? 1 : 0))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + vsir_src_operand_init(&orig_coords, VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); + orig_coords.reg.idx[0].offset = idx; + orig_coords.reg.dimension = VSIR_DIMENSION_VEC4; + orig_coords.swizzle = VKD3D_SHADER_NO_SWIZZLE; + + if (projected) + { + uint32_t ssa_proj = program->ssa_count++; + + ins = vsir_program_iterator_current(it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_DIV, 1, 2)) + return VKD3D_ERROR_OUT_OF_MEMORY; + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], ssa_proj); + ins->src[0] = orig_coords; + ins->src[1] = ins->src[0]; + ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W); + + vsir_src_operand_init_ssa_f32v4(&orig_coords, ssa_proj); + + vsir_program_iterator_next(it); + } + + if (!(ins = generate_bump_coords(program, it, idx, &orig_coords, &src[0], &location))) + return VKD3D_ERROR_OUT_OF_MEMORY; + ssa_coords = ins->dst[0].reg.idx[0].offset; + + ins = vsir_program_iterator_next(it); + if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_SAMPLE, 1, 3)) return VKD3D_ERROR_OUT_OF_MEMORY; - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = idx; ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; - src_param_init_ssa_float4(&ins->src[0], ssa_coords); + vsir_src_operand_init_ssa_f32v4(&ins->src[0], ssa_coords); ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(X, Y, Y, Y); - vsir_src_param_init_resource(&ins->src[1], idx, idx); - vsir_src_param_init_sampler(&ins->src[2], idx, idx); + vsir_src_operand_init_resource(&ins->src[1], idx, idx); + vsir_src_operand_init_sampler(&ins->src[2], idx, idx); if (is_texbeml) { @@ -2147,29 +2790,29 @@ static enum vkd3d_result vsir_program_lower_texbem(struct vsir_program *program, ssa_luminance = program->ssa_count++; /* Replace t# destination of the SAMPLE instruction with an SSA value. */ - dst_param_init_ssa_float4(&ins->dst[0], ssa_sample); + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], ssa_sample); ins = vsir_program_iterator_next(it); if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MAD, 1, 3)) return VKD3D_ERROR_OUT_OF_MEMORY; - dst_param_init_ssa_float4(&ins->dst[0], ssa_luminance); + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], ssa_luminance); ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0; ins->src[0] = src[0]; ins->src[0].swizzle = vkd3d_shader_create_swizzle(z, z, z, z); - src_param_init_parameter(&ins->src[1], + vsir_src_operand_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_SCALE_0 + idx, VSIR_DATA_F32); - src_param_init_parameter(&ins->src[2], + vsir_src_operand_init_parameter(&ins->src[2], VKD3D_SHADER_PARAMETER_NAME_BUMP_LUMINANCE_OFFSET_0 + idx, VSIR_DATA_F32); ins = vsir_program_iterator_next(it); if (!vsir_instruction_init_with_params(program, ins, &location, VSIR_OP_MUL, 1, 2)) return VKD3D_ERROR_OUT_OF_MEMORY; - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_TEXTURE, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = idx; ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; - src_param_init_ssa_float4(&ins->src[0], ssa_sample); - src_param_init_ssa_float4(&ins->src[1], ssa_luminance); + vsir_src_operand_init_ssa_f32v4(&ins->src[0], ssa_sample); + vsir_src_operand_init_ssa_f32v4(&ins->src[1], ssa_luminance); ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); } return VKD3D_OK; @@ -2263,10 +2906,35 @@ static enum vkd3d_result vsir_program_lower_d3dbc_instructions(struct vsir_progr ret = vsir_program_lower_bem(program, &it); break; + case VSIR_OP_DP2ADD: + ret = vsir_program_lower_dp2add(program, &it); + break; + + case VSIR_OP_ENDREP: + ins->opcode = VSIR_OP_ENDLOOP; + ret = VKD3D_OK; + break; + + case VSIR_OP_REP: + ret = vsir_program_lower_rep(program, &it); + break; + case VSIR_OP_IFC: ret = vsir_program_lower_ifc(program, &it, &tmp_idx, message_context); break; + case VSIR_OP_LRP: + ret = vsir_program_lower_lrp(program, &it); + break; + + case VSIR_OP_NRM: + ret = vsir_program_lower_nrm(program, &it); + break; + + case VSIR_OP_POW: + ret = vsir_program_lower_pow(program, &it); + break; + case VSIR_OP_SINCOS: ret = vsir_program_lower_sm1_sincos(program, &it); break; @@ -2290,7 +2958,7 @@ static enum vkd3d_result vsir_program_lower_d3dbc_instructions(struct vsir_progr break; case VSIR_OP_TEX: - ret = vsir_program_lower_tex(program, ins); + ret = vsir_program_lower_tex(program, &it, message_context); break; case VSIR_OP_TEXLD: @@ -2340,6 +3008,167 @@ static enum vkd3d_result vsir_program_lower_d3dbc_instructions(struct vsir_progr return VKD3D_OK; } +static struct vkd3d_shader_instruction *vsir_program_iterator_dcl_indexable_temp_before( + struct vsir_transformation_context *ctx, struct vsir_program_iterator *it, size_t idx, size_t register_size) +{ + struct vkd3d_shader_location loc = ctx->null_location; + struct vkd3d_shader_indexable_temp *t; + struct vkd3d_shader_instruction *ins; + + if ((ins = vsir_program_iterator_current(it))) + loc = ins->location; + + if (!(ins = vsir_program_iterator_insert_before_and_move(it, 1))) + return NULL; + + vsir_instruction_init(ins, &loc, VSIR_OP_DCL_INDEXABLE_TEMP); + t = &ins->declaration.indexable_temp; + t->register_idx = idx; + t->register_size = register_size; + t->alignment = 0; + t->data_type = VSIR_DATA_F32; + t->component_count = 4; + t->has_function_scope = false; + + vsir_program_iterator_next(it); + + return ins; +} + +static enum vkd3d_result vsir_program_copy_d3dbc_input_to_indexable_temp(struct vsir_program *program, + struct vsir_transformation_context *ctx, unsigned int *idxtemp_idx) +{ + struct vsir_program_iterator dcl_it = vsir_program_iterator(&program->instructions); + struct vsir_program_iterator mov_it = vsir_program_iterator(&program->instructions); + struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); + struct vkd3d_shader_location loc = ctx->null_location; + struct vkd3d_shader_instruction *ins, *dcl_ins; + struct vkd3d_shader_semantic *semantic; + size_t register_size = 0; + size_t dcl_count = 0; + + *idxtemp_idx = vsir_program_get_idxtemp_count(program); + + for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + { + if (ins->opcode == VSIR_OP_DCL) + { + semantic = &ins->declaration.semantic; + if (semantic->resource.reg.reg.type != VKD3DSPR_INPUT) + continue; + register_size = max(register_size, semantic->resource.reg.reg.idx[0].offset + 1); + ++dcl_count; + } + + if (!vsir_instruction_is_dcl(ins) && ins->opcode != VSIR_OP_NOP) + { + loc = ins->location; + break; + } + } + + if (!register_size) + return VKD3D_OK; + if (!vsir_program_iterator_dcl_indexable_temp_before(ctx, &it, *idxtemp_idx, register_size)) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (!(ins = vsir_program_iterator_insert_before(&it, &mov_it, dcl_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + for (dcl_ins = vsir_program_iterator_head(&dcl_it); dcl_ins; dcl_ins = vsir_program_iterator_next(&dcl_it)) + { + struct vsir_dst_operand *dst; + struct vsir_src_operand *src; + + if (dcl_ins->opcode == VSIR_OP_DCL) + { + semantic = &dcl_ins->declaration.semantic; + if (semantic->resource.reg.reg.type != VKD3DSPR_INPUT) + continue; + + if (!vsir_instruction_init_with_params(program, ins, &dcl_ins->location, VSIR_OP_MOV, 1, 1)) + goto fail; + + dst = &ins->dst[0]; + vsir_dst_operand_init(dst, VKD3DSPR_IDXTEMP, VSIR_DATA_F32, 2); + dst->reg.idx[0].offset = *idxtemp_idx; + dst->reg.idx[1].offset = semantic->resource.reg.reg.idx[0].offset; + dst->reg.dimension = VSIR_DIMENSION_VEC4; + dst->write_mask = semantic->resource.reg.write_mask; + + src = &ins->src[0]; + vsir_src_operand_init(src, VKD3DSPR_INPUT, VSIR_DATA_F32, 1); + src->reg.idx[0].offset = semantic->resource.reg.reg.idx[0].offset; + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->modifiers = 0; + src->swizzle = vsir_swizzle_from_writemask(semantic->resource.reg.write_mask); + + ins = vsir_program_iterator_next(&mov_it); + + if (--dcl_count == 0) + return VKD3D_OK; + } + } + vkd3d_unreachable(); + +fail: + vsir_program_iterator_prev(&it); + vsir_program_iterator_nop_range(&mov_it, &it, &loc); + return VKD3D_ERROR_OUT_OF_MEMORY; +} + +static bool is_input_register_with_loop_relative_addressing(struct vkd3d_shader_register *reg) +{ + if (reg->type != VKD3DSPR_INPUT) + return false; + if (!reg->idx_count || !reg->idx[0].rel_addr) + return false; + return reg->idx[0].rel_addr->reg.type == VKD3DSPR_LOOP; +} + +static enum vkd3d_result vsir_program_lower_d3dbc_loops( + struct vsir_program *program, struct vsir_transformation_context *ctx) +{ + struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); + bool has_loop = false, has_input_with_loop_rel_addr = false; + struct vkd3d_shader_instruction *ins; + unsigned int idxtemp_idx = 0, i; + enum vkd3d_result ret; + + for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + { + if (ins->opcode == VSIR_OP_LOOP) + has_loop = true; + + if (!vsir_instruction_is_dcl(ins)) + { + for (i = 0; i < ins->dst_count; ++i) + { + has_input_with_loop_rel_addr |= is_input_register_with_loop_relative_addressing(&ins->dst[i].reg); + } + for (i = 0; i < ins->src_count; ++i) + { + has_input_with_loop_rel_addr |= is_input_register_with_loop_relative_addressing(&ins->src[i].reg); + } + if (has_input_with_loop_rel_addr) + break; + } + } + if (!has_loop) + return VKD3D_OK; + if (has_input_with_loop_rel_addr) + vsir_program_copy_d3dbc_input_to_indexable_temp(program, ctx, &idxtemp_idx); + + for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + { + if (ins->opcode == VSIR_OP_LOOP) + { + if ((ret = vsir_program_lower_loop(program, &it, idxtemp_idx)) < 0) + return ret; + } + } + return VKD3D_OK; +} + static enum vkd3d_result vsir_program_lower_modifiers(struct vsir_program *program, struct vsir_transformation_context *ctx) { @@ -2353,7 +3182,7 @@ static enum vkd3d_result vsir_program_lower_modifiers(struct vsir_program *progr for (i = 0; i < ins->src_count; ++i) { enum vkd3d_shader_opcode new_opcodes[2] = {VSIR_OP_NOP, VSIR_OP_NOP}; - struct vkd3d_shader_src_param *src = &ins->src[i]; + struct vsir_src_operand *src = &ins->src[i]; switch (src->modifiers) { @@ -2395,8 +3224,9 @@ static enum vkd3d_result vsir_program_lower_modifiers(struct vsir_program *progr new_ins->src[0] = *src; new_ins->src[0].modifiers = VKD3DSPSM_NONE; - dst_param_init_ssa(&new_ins->dst[0], program->ssa_count, src->reg.data_type, src->reg.dimension); - src_param_init_ssa(src, program->ssa_count, src->reg.data_type, src->reg.dimension); + vsir_dst_operand_init_ssa(&new_ins->dst[0], program->ssa_count, + src->reg.data_type, src->reg.dimension); + vsir_src_operand_init_ssa(src, program->ssa_count, src->reg.data_type, src->reg.dimension); if (data_type_is_64_bit(src->reg.data_type)) { @@ -2410,7 +3240,7 @@ static enum vkd3d_result vsir_program_lower_modifiers(struct vsir_program *progr for (i = 0; i < ins->dst_count; ++i) { - struct vkd3d_shader_dst_param *dst = &ins->dst[i]; + struct vsir_dst_operand *dst = &ins->dst[i]; /* It is always legitimate to ignore _pp. */ dst->modifiers &= ~VKD3DSPDM_PARTIALPRECISION; @@ -2439,8 +3269,9 @@ static enum vkd3d_result vsir_program_lower_modifiers(struct vsir_program *progr new_ins->dst[0] = *dst; new_ins->dst[0].modifiers &= ~VKD3DSPDM_SATURATE; - dst_param_init_ssa(dst, program->ssa_count, dst->reg.data_type, dst->reg.dimension); - src_param_init_ssa(&new_ins->src[0], program->ssa_count, dst->reg.data_type, dst->reg.dimension); + vsir_dst_operand_init_ssa(dst, program->ssa_count, dst->reg.data_type, dst->reg.dimension); + vsir_src_operand_init_ssa(&new_ins->src[0], program->ssa_count, + dst->reg.data_type, dst->reg.dimension); if (data_type_is_64_bit(dst->reg.data_type)) { @@ -2453,7 +3284,7 @@ static enum vkd3d_result vsir_program_lower_modifiers(struct vsir_program *progr } } - program->has_no_modifiers = true; + program->normalisation_flags.has_no_modifiers = true; return ret; } @@ -2524,6 +3355,11 @@ static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *pr return ret; break; + case VSIR_OP_SWAPC: + if ((ret = vsir_program_lower_swapc(program, &it, ctx)) < 0) + return ret; + break; + default: break; } @@ -2556,7 +3392,7 @@ static enum vkd3d_result vsir_program_lower_texture_writes(struct vsir_program * { for (unsigned int i = 0; i < ins->src_count; ++i) { - struct vkd3d_shader_src_param *src = &ins->src[i]; + struct vsir_src_operand *src = &ins->src[i]; if (src->reg.type == VKD3DSPR_TEXTURE && bitmap_is_set(&texture_written_mask, src->reg.idx[0].offset)) { @@ -2567,7 +3403,7 @@ static enum vkd3d_result vsir_program_lower_texture_writes(struct vsir_program * for (unsigned int i = 0; i < ins->dst_count; ++i) { - struct vkd3d_shader_dst_param *dst = &ins->dst[i]; + struct vsir_dst_operand *dst = &ins->dst[i]; if (dst->reg.type == VKD3DSPR_TEXTURE) { @@ -2635,9 +3471,9 @@ static enum vkd3d_result vsir_program_normalise_ps1_output(struct vsir_program * return VKD3D_ERROR_OUT_OF_MEMORY; } - src_param_init_temp_float4(&ins->src[0], 0); + vsir_src_operand_init_temp_f32v4(&ins->src[0], 0); ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_COLOROUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_COLOROUT, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = 0; ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; @@ -2722,11 +3558,11 @@ static enum vkd3d_result vsir_program_ensure_diffuse(struct vsir_program *progra return VKD3D_ERROR_OUT_OF_MEMORY; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_ATTROUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_ATTROUT, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = 0; ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL & ~program->diffuse_written_mask; - vsir_src_param_init(&ins->src[0], VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); + vsir_src_operand_init(&ins->src[0], VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; for (i = 0; i < 4; ++i) @@ -2780,7 +3616,7 @@ static bool target_allows_subset_masks(const struct vkd3d_shader_compile_info *i } static void remove_unread_output_components(const struct shader_signature *signature, - struct vkd3d_shader_instruction *ins, struct vkd3d_shader_dst_param *dst) + struct vkd3d_shader_instruction *ins, struct vsir_dst_operand *dst) { const struct signature_element *e; @@ -2813,7 +3649,7 @@ static void remove_unread_output_components(const struct shader_signature *signa if (ins->dst_count == 1) vkd3d_shader_instruction_make_nop(ins); else - vsir_dst_param_init_null(dst); + vsir_dst_operand_init_null(dst); } } @@ -2947,8 +3783,8 @@ static enum vkd3d_result vsir_program_remap_output_signature(struct vsir_program e = &signature->elements[j]; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - dst_param_init_output(&ins->dst[0], VSIR_DATA_F32, e->register_index, e->mask); - vsir_src_param_init(&ins->src[0], VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); + vsir_dst_operand_init_output(&ins->dst[0], VSIR_DATA_F32, e->register_index, e->mask); + vsir_src_operand_init(&ins->src[0], VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; ins = vsir_program_iterator_next(&it); @@ -2982,11 +3818,6 @@ struct hull_flattener unsigned int orig_ssa_count; }; -static bool flattener_is_in_fork_or_join_phase(const struct hull_flattener *flattener) -{ - return flattener->phase == VSIR_OP_HS_FORK_PHASE || flattener->phase == VSIR_OP_HS_JOIN_PHASE; -} - static void flattener_fixup_ssa_register(struct hull_flattener *normaliser, struct vkd3d_shader_register *reg, unsigned int instance_id) { @@ -3108,9 +3939,9 @@ static enum vkd3d_result flattener_flatten_phases(struct hull_flattener *normali normaliser->phase = VSIR_OP_INVALID; for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) { - if (ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE) + if (vsir_opcode_is_fork_or_join_phase(ins->opcode)) { - b = flattener_is_in_fork_or_join_phase(normaliser); + b = vsir_opcode_is_fork_or_join_phase(normaliser->phase); /* Reset the phase info. */ phase_body_it_valid = false; normaliser->phase = ins->opcode; @@ -3194,19 +4025,14 @@ struct control_point_normaliser { struct vsir_program *program; enum vkd3d_shader_opcode phase; - struct vkd3d_shader_src_param *outpointid_param; + struct vsir_src_operand *outpointid_param; }; -static bool control_point_normaliser_is_in_control_point_phase(const struct control_point_normaliser *normaliser) -{ - return normaliser->phase == VSIR_OP_HS_CONTROL_POINT_PHASE; -} - -struct vkd3d_shader_src_param *vsir_program_create_outpointid_param(struct vsir_program *program) +struct vsir_src_operand *vsir_program_create_outpointid_param(struct vsir_program *program) { - struct vkd3d_shader_src_param *rel_addr; + struct vsir_src_operand *rel_addr; - if (!(rel_addr = vsir_program_get_src_params(program, 1))) + if (!(rel_addr = vsir_program_get_src_operands(program, 1))) return NULL; vsir_register_init(&rel_addr->reg, VKD3DSPR_OUTPOINTID, VSIR_DATA_U32, 0); @@ -3216,12 +4042,12 @@ struct vkd3d_shader_src_param *vsir_program_create_outpointid_param(struct vsir_ return rel_addr; } -static void shader_dst_param_normalise_outpointid(struct vkd3d_shader_dst_param *dst_param, +static void vsir_dst_operand_normalise_outpointid(struct vsir_dst_operand *dst, struct control_point_normaliser *normaliser) { - struct vkd3d_shader_register *reg = &dst_param->reg; + struct vkd3d_shader_register *reg = &dst->reg; - if (control_point_normaliser_is_in_control_point_phase(normaliser) && reg->type == VKD3DSPR_OUTPUT) + if (vsir_opcode_is_control_point_phase(normaliser->phase) && reg->type == VKD3DSPR_OUTPUT) { /* The TPF reader validates idx_count. */ VKD3D_ASSERT(reg->idx_count == 1); @@ -3257,9 +4083,9 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p continue; vsir_instruction_init(ins, location, VSIR_OP_MOV); - ins->dst = vsir_program_get_dst_params(normaliser->program, 1); + ins->dst = vsir_program_get_dst_operands(normaliser->program, 1); ins->dst_count = 1; - ins->src = vsir_program_get_src_params(normaliser->program, 1); + ins->src = vsir_program_get_src_operands(normaliser->program, 1); ins->src_count = 1; if (!ins->dst || ! ins->src) @@ -3270,13 +4096,13 @@ static enum vkd3d_result control_point_normaliser_emit_hs_input(struct control_p VKD3D_ASSERT(normaliser->outpointid_param); - vsir_dst_param_init_io(&ins->dst[0], VKD3DSPR_OUTPUT, e, 2); + vsir_dst_operand_init_io(&ins->dst[0], VKD3DSPR_OUTPUT, e, 2); ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->dst[0].reg.idx[0].offset = 0; ins->dst[0].reg.idx[0].rel_addr = normaliser->outpointid_param; ins->dst[0].reg.idx[1].offset = e->register_index; - vsir_src_param_init_io(&ins->src[0], VKD3DSPR_INPUT, e, 2); + vsir_src_operand_init_io(&ins->src[0], VKD3DSPR_INPUT, e, 2); ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[0].reg.idx[0].offset = 0; ins->src[0].reg.idx[0].rel_addr = normaliser->outpointid_param; @@ -3331,7 +4157,9 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i if (vsir_instruction_is_dcl(ins)) break; for (j = 0; j < ins->dst_count; ++j) - shader_dst_param_normalise_outpointid(&ins->dst[j], &normaliser); + { + vsir_dst_operand_normalise_outpointid(&ins->dst[j], &normaliser); + } break; } } @@ -3386,12 +4214,13 @@ struct io_normaliser struct shader_signature *input_signature; struct shader_signature *output_signature; struct shader_signature *patch_constant_signature; + struct vsir_normalisation_flags *normalisation_flags; enum vkd3d_shader_opcode phase; - struct vkd3d_shader_dst_param *input_dcl_params[MAX_REG_OUTPUT]; - struct vkd3d_shader_dst_param *output_dcl_params[MAX_REG_OUTPUT]; - struct vkd3d_shader_dst_param *pc_dcl_params[MAX_REG_OUTPUT]; + struct vsir_dst_operand *input_dcl_params[MAX_REG_OUTPUT]; + struct vsir_dst_operand *output_dcl_params[MAX_REG_OUTPUT]; + struct vsir_dst_operand *pc_dcl_params[MAX_REG_OUTPUT]; struct io_normaliser_register_data input_range_map[MAX_REG_OUTPUT]; struct io_normaliser_register_data output_range_map[MAX_REG_OUTPUT]; struct io_normaliser_register_data pc_range_map[MAX_REG_OUTPUT]; @@ -3399,11 +4228,6 @@ struct io_normaliser bool use_vocp; }; -static bool io_normaliser_is_in_fork_or_join_phase(const struct io_normaliser *normaliser) -{ - return normaliser->phase == VSIR_OP_HS_FORK_PHASE || normaliser->phase == VSIR_OP_HS_JOIN_PHASE; -} - static bool shader_signature_find_element_for_reg(const struct shader_signature *signature, unsigned int reg_idx, unsigned int write_mask, unsigned int *element_idx) { @@ -3521,7 +4345,7 @@ static enum vkd3d_result io_normaliser_add_index_range(struct io_normaliser *nor signature = normaliser->output_signature; break; case VKD3DSPR_OUTPUT: - if (!io_normaliser_is_in_fork_or_join_phase(normaliser)) + if (!vsir_opcode_is_fork_or_join_phase(normaliser->phase)) { range_map = normaliser->output_range_map; signature = normaliser->output_signature; @@ -3720,7 +4544,7 @@ static enum vkd3d_result shader_signature_merge(struct io_normaliser *normaliser e->interpolation_mode = f->interpolation_mode; } - vkd3d_free((void *)f->semantic_name); + vsir_signature_element_cleanup(f); } } element_count = new_count; @@ -3749,7 +4573,7 @@ static enum vkd3d_result shader_signature_merge(struct io_normaliser *normaliser { TRACE("Register %u mask %#x semantic %s%u has already been merged, dropping it.\n", e->register_index, e->mask, e->semantic_name, e->semantic_index); - vkd3d_free((void *)e->semantic_name); + vsir_signature_element_cleanup(e); continue; } @@ -3793,21 +4617,21 @@ static unsigned int shader_register_normalise_arrayed_addressing(struct vkd3d_sh return id_idx; } -static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_param, - struct io_normaliser *normaliser) - { +static bool vsir_dst_operand_io_normalise(struct vsir_dst_operand *dst, + struct io_normaliser *normaliser, struct vkd3d_shader_instruction *ins) +{ unsigned int id_idx, reg_idx, write_mask, element_idx; - struct vkd3d_shader_register *reg = &dst_param->reg; + struct vkd3d_shader_register *reg = &dst->reg; const struct shader_signature *signature; const struct signature_element *e; - write_mask = dst_param->write_mask; + write_mask = dst->write_mask; switch (reg->type) { case VKD3DSPR_OUTPUT: reg_idx = reg->idx[reg->idx_count - 1].offset; - if (io_normaliser_is_in_fork_or_join_phase(normaliser)) + if (vsir_opcode_is_fork_or_join_phase(normaliser->phase)) { signature = normaliser->patch_constant_signature; /* Convert patch constant outputs to the patch constant register type to avoid the need @@ -3851,7 +4675,7 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par if (reg->idx[0].offset > 0) { write_mask = VKD3DSP_WRITEMASK_0; - dst_param->write_mask = write_mask; + dst->write_mask = write_mask; } /* Leave point size as a system value for the backends to consume. */ if (reg->idx[0].offset == VSIR_RASTOUT_POINT_SIZE) @@ -3867,10 +4691,16 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par id_idx = reg->idx_count - 1; if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) - vkd3d_unreachable(); + { + vkd3d_shader_error(normaliser->message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "Unable to resolve I/O register type %#x, index %u, write mask %#x, to a signature element.", + reg->type, reg_idx, write_mask); + normaliser->result = VKD3D_ERROR_INVALID_SHADER; + return false; + } e = &signature->elements[element_idx]; - if ((e->register_count > 1 || vsir_sysval_semantic_is_tess_factor(e->sysval_semantic))) + if (vsir_signature_element_is_array(e, normaliser->normalisation_flags)) id_idx = shader_register_normalise_arrayed_addressing(reg, id_idx, e->register_index); /* Replace the register index with the signature element index */ @@ -3880,11 +4710,11 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par return true; } -static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_param, +static void vsir_src_operand_io_normalise(struct vsir_src_operand *src, struct io_normaliser *normaliser, struct vkd3d_shader_instruction *ins) { unsigned int i, id_idx, reg_idx, write_mask, element_idx, component_idx; - struct vkd3d_shader_register *reg = &src_param->reg; + struct vkd3d_shader_register *reg = &src->reg; const struct shader_signature *signature; const struct signature_element *e; @@ -3923,7 +4753,7 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par case VKD3DSPR_OUTCONTROLPOINT: reg->type = VKD3DSPR_OUTPUT; - if (io_normaliser_is_in_fork_or_join_phase(normaliser)) + if (vsir_opcode_is_fork_or_join_phase(normaliser->phase)) normaliser->use_vocp = true; /* fall through */ case VKD3DSPR_OUTPUT: @@ -3942,17 +4772,18 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par } id_idx = reg->idx_count - 1; - write_mask = VKD3DSP_WRITEMASK_0 << vsir_swizzle_get_component(src_param->swizzle, 0); + write_mask = VKD3DSP_WRITEMASK_0 << vsir_swizzle_get_component(src->swizzle, 0); if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx)) { vkd3d_shader_error(normaliser->message_context, &ins->location, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, - "Unable to resolve I/O register to a signature element."); + "Unable to resolve I/O register type %#x, index %u, swizzle %#x, to a signature element.", + reg->type, reg_idx, src->swizzle); normaliser->result = VKD3D_ERROR_INVALID_SHADER; return; } e = &signature->elements[element_idx]; - if ((e->register_count > 1 || vsir_sysval_semantic_is_tess_factor(e->sysval_semantic))) + if (vsir_signature_element_is_array(e, normaliser->normalisation_flags)) id_idx = shader_register_normalise_arrayed_addressing(reg, id_idx, e->register_index); reg->idx[id_idx].offset = element_idx; reg->idx_count = id_idx + 1; @@ -3960,8 +4791,10 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par if ((component_idx = vsir_write_mask_get_component_idx(e->mask))) { for (i = 0; i < VKD3D_VEC4_SIZE; ++i) - if (vsir_swizzle_get_component(src_param->swizzle, i)) - src_param->swizzle -= component_idx << VKD3D_SHADER_SWIZZLE_SHIFT(i); + { + if (vsir_swizzle_get_component(src->swizzle, i)) + src->swizzle -= component_idx << VKD3D_SHADER_SWIZZLE_SHIFT(i); + } } } @@ -3984,9 +4817,13 @@ static void shader_instruction_normalise_io_params(struct vkd3d_shader_instructi if (vsir_instruction_is_dcl(ins)) break; for (i = 0; i < ins->dst_count; ++i) - shader_dst_param_io_normalise(&ins->dst[i], normaliser); + { + vsir_dst_operand_io_normalise(&ins->dst[i], normaliser, ins); + } for (i = 0; i < ins->src_count; ++i) - shader_src_param_io_normalise(&ins->src[i], normaliser, ins); + { + vsir_src_operand_io_normalise(&ins->src[i], normaliser, ins); + } break; } } @@ -4007,6 +4844,7 @@ static enum vkd3d_result vsir_program_normalise_io_registers(struct vsir_program normaliser.input_signature = &program->input_signature; normaliser.output_signature = &program->output_signature; normaliser.patch_constant_signature = &program->patch_constant_signature; + normaliser.normalisation_flags = &program->normalisation_flags; for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) { @@ -4059,8 +4897,7 @@ struct flat_constants_normaliser }; static bool get_flat_constant_register_type(const struct vkd3d_shader_register *reg, - enum vkd3d_shader_d3dbc_constant_register *set, uint32_t *index, - struct vkd3d_shader_src_param **rel_addr) + enum vkd3d_shader_d3dbc_constant_register *set, uint32_t *index, struct vsir_src_operand **rel_addr) { static const struct { @@ -4091,43 +4928,43 @@ static bool get_flat_constant_register_type(const struct vkd3d_shader_register * return false; } -static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_param *param, +static void shader_register_normalise_flat_constants(struct vsir_src_operand *src, const struct flat_constants_normaliser *normaliser) { enum vkd3d_shader_d3dbc_constant_register set; - struct vkd3d_shader_src_param *rel_addr; + struct vsir_src_operand *rel_addr; unsigned int c; uint32_t index; size_t i, j; - if (!get_flat_constant_register_type(¶m->reg, &set, &index, &rel_addr)) + if (!get_flat_constant_register_type(&src->reg, &set, &index, &rel_addr)) return; for (i = 0; i < normaliser->def_count; ++i) { if (normaliser->defs[i].set == set && normaliser->defs[i].index == index) { - param->reg.type = VKD3DSPR_IMMCONST; - param->reg.idx_count = 0; - param->reg.dimension = VSIR_DIMENSION_VEC4; + src->reg.type = VKD3DSPR_IMMCONST; + src->reg.idx_count = 0; + src->reg.dimension = VSIR_DIMENSION_VEC4; for (j = 0; j < 4; ++j) { - c = vsir_swizzle_get_component(param->swizzle, j); - param->reg.u.immconst_u32[j] = normaliser->defs[i].value[c]; + c = vsir_swizzle_get_component(src->swizzle, j); + src->reg.u.immconst_u32[j] = normaliser->defs[i].value[c]; } - param->swizzle = VKD3D_SHADER_NO_SWIZZLE; + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; return; } } - param->reg.type = VKD3DSPR_CONSTBUFFER; - param->reg.idx[0].offset = set; /* register ID */ - param->reg.idx[0].rel_addr = NULL; - param->reg.idx[1].offset = set; /* register index */ - param->reg.idx[1].rel_addr = NULL; - param->reg.idx[2].offset = index; /* buffer index */ - param->reg.idx[2].rel_addr = rel_addr; - param->reg.idx_count = 3; + src->reg.type = VKD3DSPR_CONSTBUFFER; + src->reg.idx[0].offset = set; /* register ID */ + src->reg.idx[0].rel_addr = NULL; + src->reg.idx[1].offset = set; /* register index */ + src->reg.idx[1].rel_addr = NULL; + src->reg.idx[2].offset = index; /* buffer index */ + src->reg.idx[2].rel_addr = rel_addr; + src->reg.idx_count = 3; } static enum vkd3d_result vsir_program_normalise_flat_constants(struct vsir_program *program, @@ -4272,7 +5109,7 @@ static enum vkd3d_result vsir_program_remove_dead_code(struct vsir_program *prog static void vsir_program_replace_instructions(struct vsir_program *program, struct vkd3d_shader_instruction_array *array) { - shader_instruction_array_destroy(&program->instructions); + shader_instruction_array_cleanup(&program->instructions); program->instructions = *array; memset(array, 0, sizeof(*array)); @@ -4280,7 +5117,7 @@ static void vsir_program_replace_instructions(struct vsir_program *program, struct cf_flattener_if_info { - struct vkd3d_shader_src_param *false_param; + struct vsir_src_operand *false_param; unsigned int id; uint32_t merge_block_id; unsigned int else_block_id; @@ -4302,7 +5139,7 @@ struct cf_flattener_switch_case struct cf_flattener_switch_info { struct vsir_program_iterator ins_it; - const struct vkd3d_shader_src_param *condition; + const struct vsir_src_operand *condition; unsigned int id; unsigned int merge_block_id; unsigned int default_block_id; @@ -4392,19 +5229,20 @@ static unsigned int cf_flattener_alloc_block_id(struct cf_flattener *flattener) return ++flattener->block_id; } -static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins, +static struct vsir_src_operand *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins, unsigned int count, struct cf_flattener *flattener) { - struct vkd3d_shader_src_param *params; + struct vsir_src_operand *src; - if (!(params = vsir_program_get_src_params(flattener->program, count))) + if (!(src = vsir_program_get_src_operands(flattener->program, count))) { cf_flattener_set_error(flattener, VKD3D_ERROR_OUT_OF_MEMORY); return NULL; } - ins->src = params; + ins->src = src; ins->src_count = count; - return params; + + return src; } static void cf_flattener_emit_label(struct cf_flattener *flattener, unsigned int label_id) @@ -4421,12 +5259,11 @@ static void cf_flattener_emit_label(struct cf_flattener *flattener, unsigned int } /* For conditional branches, this returns the false target branch parameter. */ -static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flattener *flattener, - unsigned int merge_block_id, unsigned int continue_block_id, - const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int false_id, - unsigned int flags) +static struct vsir_src_operand *cf_flattener_emit_branch(struct cf_flattener *flattener, + unsigned int merge_block_id, unsigned int continue_block_id, const struct vsir_src_operand *condition, + unsigned int true_id, unsigned int false_id, unsigned int flags) { - struct vkd3d_shader_src_param *src_params, *false_branch_param; + struct vsir_src_operand *src, *false_branch; struct vkd3d_shader_instruction *ins; if (!(ins = cf_flattener_instruction_append(flattener))) @@ -4435,51 +5272,51 @@ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flatten if (condition) { - if (!(src_params = instruction_src_params_alloc(ins, 4 + !!continue_block_id, flattener))) + if (!(src = instruction_src_params_alloc(ins, 4 + !!continue_block_id, flattener))) { vkd3d_shader_instruction_make_nop(ins); return NULL; } - src_params[0] = *condition; + src[0] = *condition; if (flags == VKD3D_SHADER_CONDITIONAL_OP_Z) { - vsir_src_param_init_label(&src_params[1], false_id); - vsir_src_param_init_label(&src_params[2], true_id); - false_branch_param = &src_params[1]; + vsir_src_operand_init_label(&src[1], false_id); + vsir_src_operand_init_label(&src[2], true_id); + false_branch = &src[1]; } else { - vsir_src_param_init_label(&src_params[1], true_id); - vsir_src_param_init_label(&src_params[2], false_id); - false_branch_param = &src_params[2]; + vsir_src_operand_init_label(&src[1], true_id); + vsir_src_operand_init_label(&src[2], false_id); + false_branch = &src[2]; } - vsir_src_param_init_label(&src_params[3], merge_block_id); + vsir_src_operand_init_label(&src[3], merge_block_id); if (continue_block_id) - vsir_src_param_init_label(&src_params[4], continue_block_id); + vsir_src_operand_init_label(&src[4], continue_block_id); } else { - if (!(src_params = instruction_src_params_alloc(ins, merge_block_id ? 3 : 1, flattener))) + if (!(src = instruction_src_params_alloc(ins, merge_block_id ? 3 : 1, flattener))) { vkd3d_shader_instruction_make_nop(ins); return NULL; } - vsir_src_param_init_label(&src_params[0], true_id); + vsir_src_operand_init_label(&src[0], true_id); if (merge_block_id) { /* An unconditional branch may only have merge information for a loop, which * must have both a merge block and continue block. */ - vsir_src_param_init_label(&src_params[1], merge_block_id); - vsir_src_param_init_label(&src_params[2], continue_block_id); + vsir_src_operand_init_label(&src[1], merge_block_id); + vsir_src_operand_init_label(&src[2], continue_block_id); } - false_branch_param = NULL; + false_branch = NULL; } - return false_branch_param; + return false_branch; } static void cf_flattener_emit_conditional_branch_and_merge(struct cf_flattener *flattener, - const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int flags) + const struct vsir_src_operand *condition, unsigned int true_id, unsigned int flags) { unsigned int merge_block_id; @@ -4584,7 +5421,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte for (instruction = vsir_program_iterator_head(&it); instruction; instruction = vsir_program_iterator_next(&it)) { unsigned int loop_header_block_id, loop_body_block_id, continue_block_id, merge_block_id, true_block_id; - const struct vkd3d_shader_src_param *src = instruction->src; + struct vsir_src_operand *src = instruction->src; struct cf_flattener_info *cf_info; flattener->location = instruction->location; @@ -4747,7 +5584,6 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte case VSIR_OP_ENDSWITCH: { - struct vkd3d_shader_src_param *src_params; unsigned int j; if (!cf_info->u.switch_.default_block_id) @@ -4762,21 +5598,21 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte * when new instructions are appended to the * vkd3d_shader_instruction_array. */ dst_ins = vsir_program_iterator_current(&cf_info->u.switch_.ins_it); - if (!(src_params = instruction_src_params_alloc(dst_ins, + if (!(src = instruction_src_params_alloc(dst_ins, cf_info->u.switch_.cases_count * 2 + 3, flattener))) { vkd3d_free(cf_info->u.switch_.cases); return VKD3D_ERROR_OUT_OF_MEMORY; } - src_params[0] = *cf_info->u.switch_.condition; - vsir_src_param_init_label(&src_params[1], cf_info->u.switch_.default_block_id); - vsir_src_param_init_label(&src_params[2], cf_info->u.switch_.merge_block_id); + src[0] = *cf_info->u.switch_.condition; + vsir_src_operand_init_label(&src[1], cf_info->u.switch_.default_block_id); + vsir_src_operand_init_label(&src[2], cf_info->u.switch_.merge_block_id); for (j = 0; j < cf_info->u.switch_.cases_count; ++j) { unsigned int index = j * 2 + 3; - vsir_src_param_init(&src_params[index], VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); - src_params[index].reg.u.immconst_u32[0] = cf_info->u.switch_.cases[j].value; - vsir_src_param_init_label(&src_params[index + 1], cf_info->u.switch_.cases[j].block_id); + vsir_src_operand_init(&src[index], VKD3DSPR_IMMCONST, VSIR_DATA_U32, 0); + src[index].reg.u.immconst_u32[0] = cf_info->u.switch_.cases[j].value; + vsir_src_operand_init_label(&src[index + 1], cf_info->u.switch_.cases[j].block_id); } vkd3d_free(cf_info->u.switch_.cases); @@ -4934,7 +5770,7 @@ static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsi } else { - shader_instruction_array_destroy(&flattener.instructions); + shader_instruction_array_cleanup(&flattener.instructions); } vkd3d_free(flattener.control_flow_info); @@ -4945,10 +5781,10 @@ static enum vkd3d_result vsir_program_flatten_control_flow_constructs(struct vsi return result; } -static unsigned int label_from_src_param(const struct vkd3d_shader_src_param *param) +static unsigned int label_from_src_operand(const struct vsir_src_operand *src) { - VKD3D_ASSERT(param->reg.type == VKD3DSPR_LABEL); - return param->reg.idx[0].offset; + VKD3D_ASSERT(src->reg.type == VKD3DSPR_LABEL); + return src->reg.idx[0].offset; } /* A record represents replacing a jump from block `switch_label' to @@ -5004,7 +5840,7 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs switch (ins->opcode) { case VSIR_OP_LABEL: - current_label = label_from_src_param(&ins->src[0]); + current_label = label_from_src_operand(&ins->src[0]); if (!(dst_ins = shader_instruction_array_append(&instructions))) goto fail; *dst_ins = *ins; @@ -5021,7 +5857,7 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs } case_count = (ins->src_count - 3) / 2; - default_label = label_from_src_param(&ins->src[1]); + default_label = label_from_src_operand(&ins->src[1]); /* In principle we can have a switch with no cases, and we * just have to jump to the default label. */ @@ -5035,14 +5871,14 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs vkd3d_shader_instruction_make_nop(dst_ins); goto fail; } - vsir_src_param_init_label(&dst_ins->src[0], default_label); + vsir_src_operand_init_label(&dst_ins->src[0], default_label); } if_label = current_label; for (j = 0; j < case_count; ++j) { - unsigned int fallthrough_label, case_label = label_from_src_param(&ins->src[3 + 2 * j + 1]); + unsigned int fallthrough_label, case_label = label_from_src_operand(&ins->src[3 + 2 * j + 1]); if (!(dst_ins = shader_instruction_array_append(&instructions))) goto fail; @@ -5051,7 +5887,7 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs vkd3d_shader_instruction_make_nop(dst_ins); goto fail; } - dst_param_init_ssa_bool(&dst_ins->dst[0], ssa_count); + vsir_dst_operand_init_ssa_bool(&dst_ins->dst[0], ssa_count); dst_ins->src[0] = ins->src[0]; dst_ins->src[1] = ins->src[3 + 2 * j]; @@ -5070,9 +5906,9 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs vkd3d_shader_instruction_make_nop(dst_ins); goto fail; } - src_param_init_ssa_bool(&dst_ins->src[0], ssa_count); - vsir_src_param_init_label(&dst_ins->src[1], case_label); - vsir_src_param_init_label(&dst_ins->src[2], fallthrough_label); + vsir_src_operand_init_ssa_bool(&dst_ins->src[0], ssa_count); + vsir_src_operand_init_label(&dst_ins->src[1], case_label); + vsir_src_operand_init_label(&dst_ins->src[2], fallthrough_label); ++ssa_count; @@ -5095,7 +5931,7 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs vkd3d_shader_instruction_make_nop(dst_ins); goto fail; } - vsir_src_param_init_label(&dst_ins->src[0], ++block_count); + vsir_src_operand_init_label(&dst_ins->src[0], ++block_count); if_label = block_count; } @@ -5110,7 +5946,7 @@ static enum vkd3d_result vsir_program_lower_switch_to_selection_ladder(struct vs return VKD3D_OK; fail: - shader_instruction_array_destroy(&instructions); + shader_instruction_array_cleanup(&instructions); vkd3d_free(block_map); return VKD3D_ERROR_OUT_OF_MEMORY; @@ -5159,8 +5995,8 @@ struct ssas_to_temps_block_info { struct phi_incoming_to_temp { - struct vkd3d_shader_src_param *src; - struct vkd3d_shader_dst_param *dst; + struct vsir_src_operand *src; + struct vsir_dst_operand *dst; } *incomings; size_t incoming_capacity; size_t incoming_count; @@ -5233,7 +6069,7 @@ static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps_in_function( struct phi_incoming_to_temp *incoming; unsigned int label; - label = label_from_src_param(&ins->src[j + 1]); + label = label_from_src_operand(&ins->src[j + 1]); VKD3D_ASSERT(label); info = &block_info[label - 1]; @@ -5273,7 +6109,7 @@ static enum vkd3d_result vsir_program_materialise_phi_ssas_to_temps_in_function( switch (ins->opcode) { case VSIR_OP_LABEL: - current_label = label_from_src_param(&ins->src[0]); + current_label = label_from_src_operand(&ins->src[0]); break; case VSIR_OP_BRANCH: @@ -5517,7 +6353,7 @@ struct vsir_cfg_structure } loop; struct vsir_cfg_structure_selection { - struct vkd3d_shader_src_param *condition; + struct vsir_src_operand *condition; struct vsir_cfg_structure_list if_body; struct vsir_cfg_structure_list else_body; bool invert_condition; @@ -5534,7 +6370,7 @@ struct vsir_cfg_structure JUMP_RET, } type; unsigned int target; - struct vkd3d_shader_src_param *condition; + struct vsir_src_operand *condition; bool invert_condition; bool needs_launcher; } jump; @@ -5719,10 +6555,10 @@ static bool vsir_block_dominates(struct vsir_block *b1, struct vsir_block *b2) return bitmap_is_set(b1->dominates, b2->label - 1); } -static enum vkd3d_result vsir_cfg_add_edge(struct vsir_cfg *cfg, struct vsir_block *block, - struct vkd3d_shader_src_param *successor_param) +static enum vkd3d_result vsir_cfg_add_edge(struct vsir_cfg *cfg, + struct vsir_block *block, struct vsir_src_operand *successor_operand) { - unsigned int target = label_from_src_param(successor_param); + unsigned int target = label_from_src_operand(successor_operand); struct vsir_block *successor = &cfg->blocks[target - 1]; enum vkd3d_result ret; @@ -5903,7 +6739,7 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program case VSIR_OP_LABEL: { - unsigned int label = label_from_src_param(&ins->src[0]); + unsigned int label = label_from_src_operand(&ins->src[0]); VKD3D_ASSERT(!current_block); VKD3D_ASSERT(label > 0); @@ -5916,7 +6752,8 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program vsir_program_iterator_next(¤t_block->begin); if (!cfg->entry) cfg->entry = current_block; - ++defined_block_count; + if (label > defined_block_count) + defined_block_count = label; break; } @@ -6656,7 +7493,7 @@ static enum vkd3d_result vsir_cfg_build_structured_program(struct vsir_cfg *cfg) if (vsir_register_is_label(&end->src[0].reg)) { - unsigned int target = label_from_src_param(&end->src[0]); + unsigned int target = label_from_src_operand(&end->src[0]); struct vsir_block *successor = &cfg->blocks[target - 1]; vsir_cfg_compute_edge_action(cfg, block, successor, &action_true); @@ -6664,12 +7501,12 @@ static enum vkd3d_result vsir_cfg_build_structured_program(struct vsir_cfg *cfg) } else { - unsigned int target = label_from_src_param(&end->src[1]); + unsigned int target = label_from_src_operand(&end->src[1]); struct vsir_block *successor = &cfg->blocks[target - 1]; vsir_cfg_compute_edge_action(cfg, block, successor, &action_true); - target = label_from_src_param(&end->src[2]); + target = label_from_src_operand(&end->src[2]); successor = &cfg->blocks[target - 1]; vsir_cfg_compute_edge_action(cfg, block, successor, &action_false); @@ -7265,9 +8102,9 @@ static enum vkd3d_result vsir_cfg_structure_list_emit_loop(struct vsir_cfg *cfg, ++target->temp_count; - dst_param_init_temp_bool(&ins->dst[0], target->temp_count - 1); - src_param_init_temp_uint(&ins->src[0], target->jump_target_temp_idx); - src_param_init_const_uint(&ins->src[1], outer_continue_target); + vsir_dst_operand_init_temp_bool(&ins->dst[0], target->temp_count - 1); + vsir_src_operand_init_temp_u32(&ins->src[0], target->jump_target_temp_idx); + vsir_src_operand_init_const_u32(&ins->src[1], outer_continue_target); if (!(ins = shader_instruction_array_append(&target->instructions))) return VKD3D_ERROR_OUT_OF_MEMORY; @@ -7277,7 +8114,7 @@ static enum vkd3d_result vsir_cfg_structure_list_emit_loop(struct vsir_cfg *cfg, return VKD3D_ERROR_OUT_OF_MEMORY; } - src_param_init_temp_bool(&ins->src[0], target->temp_count - 1); + vsir_src_operand_init_temp_bool(&ins->src[0], target->temp_count - 1); ins = shader_instruction_array_append(&target->instructions); if (!vsir_instruction_init_with_params(cfg->program, ins, &no_loc, VSIR_OP_IEQ, 1, 2)) @@ -7288,9 +8125,9 @@ static enum vkd3d_result vsir_cfg_structure_list_emit_loop(struct vsir_cfg *cfg, ++target->temp_count; - dst_param_init_temp_bool(&ins->dst[0], target->temp_count - 1); - src_param_init_temp_uint(&ins->src[0], target->jump_target_temp_idx); - src_param_init_const_uint(&ins->src[1], inner_break_target); + vsir_dst_operand_init_temp_bool(&ins->dst[0], target->temp_count - 1); + vsir_src_operand_init_temp_u32(&ins->src[0], target->jump_target_temp_idx); + vsir_src_operand_init_const_u32(&ins->src[1], inner_break_target); if (!(ins = shader_instruction_array_append(&target->instructions))) return VKD3D_ERROR_OUT_OF_MEMORY; @@ -7301,7 +8138,7 @@ static enum vkd3d_result vsir_cfg_structure_list_emit_loop(struct vsir_cfg *cfg, } ins->flags |= VKD3D_SHADER_CONDITIONAL_OP_Z; - src_param_init_temp_bool(&ins->src[0], target->temp_count - 1); + vsir_src_operand_init_temp_bool(&ins->src[0], target->temp_count - 1); } return VKD3D_OK; @@ -7399,8 +8236,8 @@ static enum vkd3d_result vsir_cfg_structure_list_emit_jump(struct vsir_cfg *cfg, return VKD3D_ERROR_OUT_OF_MEMORY; } - dst_param_init_temp_uint(&ins->dst[0], target->jump_target_temp_idx); - src_param_init_const_uint(&ins->src[0], jump_target); + vsir_dst_operand_init_temp_u32(&ins->dst[0], target->jump_target_temp_idx); + vsir_src_operand_init_const_u32(&ins->src[0], jump_target); } if (!(ins = shader_instruction_array_append(&target->instructions))) @@ -7563,7 +8400,7 @@ static enum vkd3d_result vsir_program_structurize(struct vsir_program *program, return VKD3D_OK; fail: - shader_instruction_array_destroy(&target.instructions); + shader_instruction_array_cleanup(&target.instructions); return ret; } @@ -7814,7 +8651,7 @@ static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *progr vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_DISCARD, 0, 1); ins->flags = VKD3D_SHADER_CONDITIONAL_OP_Z; - src_param_init_const_uint(&ins->src[0], 0); + vsir_src_operand_init_const_u32(&ins->src[0], 0); vsir_program_iterator_next(it); return VKD3D_OK; @@ -7827,15 +8664,15 @@ static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *progr { case VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32: vsir_instruction_init_with_params(program, ins, &loc, opcodes[compare_func].float_opcode, 1, 2); - src_param_init_temp_float(&ins->src[opcodes[compare_func].swap ? 1 : 0], colour_temp); - src_param_init_parameter(&ins->src[opcodes[compare_func].swap ? 0 : 1], + vsir_src_operand_init_temp_f32(&ins->src[opcodes[compare_func].swap ? 1 : 0], colour_temp); + vsir_src_operand_init_parameter(&ins->src[opcodes[compare_func].swap ? 0 : 1], VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, VSIR_DATA_F32); break; case VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32: vsir_instruction_init_with_params(program, ins, &loc, opcodes[compare_func].uint_opcode, 1, 2); - src_param_init_temp_uint(&ins->src[opcodes[compare_func].swap ? 1 : 0], colour_temp); - src_param_init_parameter(&ins->src[opcodes[compare_func].swap ? 0 : 1], + vsir_src_operand_init_temp_u32(&ins->src[opcodes[compare_func].swap ? 1 : 0], colour_temp); + vsir_src_operand_init_parameter(&ins->src[opcodes[compare_func].swap ? 0 : 1], VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, VSIR_DATA_U32); break; @@ -7849,24 +8686,24 @@ static enum vkd3d_result insert_alpha_test_before_ret(struct vsir_program *progr return VKD3D_ERROR_NOT_IMPLEMENTED; } - dst_param_init_ssa_bool(&ins->dst[0], program->ssa_count); + vsir_dst_operand_init_ssa_bool(&ins->dst[0], program->ssa_count); ins->src[opcodes[compare_func].swap ? 1 : 0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[opcodes[compare_func].swap ? 1 : 0].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_DISCARD, 0, 1); ins->flags = VKD3D_SHADER_CONDITIONAL_OP_Z; - src_param_init_ssa_bool(&ins->src[0], program->ssa_count); + vsir_src_operand_init_ssa_bool(&ins->src[0], program->ssa_count); ++program->ssa_count; ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_OUTPUT, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = colour_signature_idx; ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->dst[0].write_mask = program->output_signature.elements[colour_signature_idx].mask; - src_param_init_temp_float(&ins->src[0], colour_temp); + vsir_src_operand_init_temp_f32(&ins->src[0], colour_temp); ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; @@ -7905,213 +8742,921 @@ static enum vkd3d_result vsir_program_insert_alpha_test(struct vsir_program *pro } if (func->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) { - vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, - "Invalid alpha test function parameter data type %#x.", func->data_type); - return VKD3D_ERROR_INVALID_ARGUMENT; + vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid alpha test function parameter data type %#x.", func->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + compare_func = func->u.immediate_constant.u.u32; + + if (compare_func == VKD3D_SHADER_COMPARISON_FUNC_ALWAYS) + return VKD3D_OK; + + /* We're going to be reading from the output, so we need to go + * through the whole shader and convert it to a temp. */ + + if (compare_func != VKD3D_SHADER_COMPARISON_FUNC_NEVER) + colour_temp = program->temp_count++; + + for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + { + if (vsir_instruction_is_dcl(ins)) + continue; + + if (ins->opcode == VSIR_OP_RET) + { + if ((ret = insert_alpha_test_before_ret(program, &it, compare_func, + ref, colour_signature_idx, colour_temp, message_context)) < 0) + return ret; + continue; + } + + /* No need to convert it if the comparison func is NEVER; we don't + * read from the output in that case. */ + if (compare_func == VKD3D_SHADER_COMPARISON_FUNC_NEVER) + continue; + + for (size_t j = 0; j < ins->dst_count; ++j) + { + struct vsir_dst_operand *dst = &ins->dst[j]; + + /* Note we run after I/O normalization. */ + if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == colour_signature_idx) + { + dst->reg.type = VKD3DSPR_TEMP; + dst->reg.idx[0].offset = colour_temp; + } + } + } + + return VKD3D_OK; +} + +static enum vkd3d_result insert_clip_planes_before_ret(struct vsir_program *program, + struct vsir_program_iterator *it, uint32_t mask, uint32_t position_signature_idx, + uint32_t position_temp, uint32_t low_signature_idx, uint32_t high_signature_idx) +{ + const struct vkd3d_shader_location loc = vsir_program_iterator_current(it)->location; + struct vkd3d_shader_instruction *ins; + unsigned int output_idx = 0; + + if (!(ins = vsir_program_iterator_insert_before_and_move(it, vkd3d_popcount(mask) + 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + for (unsigned int i = 0; i < 8; ++i) + { + if (!(mask & (1u << i))) + continue; + + vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_DP4, 1, 2); + vsir_src_operand_init_temp_f32v4(&ins->src[0], position_temp); + vsir_src_operand_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0 + i, VSIR_DATA_F32); + ins->src[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; + ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; + + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_OUTPUT, VSIR_DATA_F32, 1); + if (output_idx < 4) + ins->dst[0].reg.idx[0].offset = low_signature_idx; + else + ins->dst[0].reg.idx[0].offset = high_signature_idx; + ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->dst[0].write_mask = (1u << (output_idx % 4)); + ++output_idx; + + ins = vsir_program_iterator_next(it); + } + + vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_OUTPUT, VSIR_DATA_F32, 1); + ins->dst[0].reg.idx[0].offset = position_signature_idx; + ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->dst[0].write_mask = program->output_signature.elements[position_signature_idx].mask; + vsir_src_operand_init_temp_f32(&ins->src[0], position_temp); + ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; + ins = vsir_program_iterator_next(it); + + return VKD3D_OK; +} + +static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *program, + struct vsir_transformation_context *ctx) +{ + struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); + struct shader_signature *signature = &program->output_signature; + unsigned int low_signature_idx = ~0u, high_signature_idx = ~0u; + const struct vkd3d_shader_parameter1 *mask_parameter = NULL; + uint32_t position_signature_idx, position_temp, mask; + unsigned int plane_count, next_register_index; + struct signature_element *clip_element; + struct vkd3d_shader_instruction *ins; + int ret; + + if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX) + return VKD3D_OK; + + for (unsigned int i = 0; i < program->parameter_count; ++i) + { + const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i]; + + if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK) + mask_parameter = parameter; + } + + if (!mask_parameter) + return VKD3D_OK; + + if (mask_parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + { + vkd3d_shader_error(ctx->message_context, NULL, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "Unsupported clip plane mask parameter type %#x.", mask_parameter->type); + return VKD3D_ERROR_NOT_IMPLEMENTED; + } + if (mask_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) + { + vkd3d_shader_error(ctx->message_context, NULL, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid clip plane mask parameter data type %#x.", mask_parameter->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + mask = mask_parameter->u.immediate_constant.u.u32; + + if (!mask) + return VKD3D_OK; + + for (unsigned int i = 0; i < signature->element_count; ++i) + { + if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE) + { + vkd3d_shader_error(ctx->message_context, &ctx->null_location, VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER, + "Clip planes cannot be used if the shader writes clip distance."); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + } + + if (!vsir_signature_find_sysval(signature, VKD3D_SHADER_SV_POSITION, 0, &position_signature_idx)) + { + vkd3d_shader_error(ctx->message_context, &ctx->null_location, VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC, + "Shader does not write position."); + return VKD3D_ERROR_INVALID_SHADER; + } + + /* Append the clip plane signature indices. */ + + plane_count = vkd3d_popcount(mask); + + /* Register mask is ignored since we operate after I/O normalisation. */ + next_register_index = vsir_signature_next_location(signature); + if (!(clip_element = add_signature_element(signature, "SV_ClipDistance", 0, + vkd3d_write_mask_from_component_count(min(plane_count, 4)), next_register_index, VKD3DSIM_NONE))) + return VKD3D_ERROR_OUT_OF_MEMORY; + low_signature_idx = clip_element - signature->elements; + clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; + + if (plane_count > 4) + { + next_register_index = vsir_signature_next_location(signature); + if (!(clip_element = add_signature_element(signature, "SV_ClipDistance", 1, + vkd3d_write_mask_from_component_count(plane_count - 4), next_register_index, VKD3DSIM_NONE))) + return VKD3D_ERROR_OUT_OF_MEMORY; + high_signature_idx = clip_element - signature->elements; + clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; + } + + /* We're going to be reading from the output position, so we need to go + * through the whole shader and convert it to a temp. */ + + position_temp = program->temp_count++; + + for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + { + if (vsir_instruction_is_dcl(ins)) + continue; + + if (ins->opcode == VSIR_OP_RET) + { + if ((ret = insert_clip_planes_before_ret(program, &it, mask, position_signature_idx, + position_temp, low_signature_idx, high_signature_idx)) < 0) + return ret; + continue; + } + + for (size_t j = 0; j < ins->dst_count; ++j) + { + struct vsir_dst_operand *dst = &ins->dst[j]; + + /* Note we run after I/O normalization. */ + if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == position_signature_idx) + { + dst->reg.type = VKD3DSPR_TEMP; + dst->reg.idx[0].offset = position_temp; + } + } + } + + return VKD3D_OK; +} + +struct sysval_array_normaliser +{ + struct vsir_transformation_context *ctx; + + /* sysval semantic currently being normalised. */ + enum vkd3d_shader_sysval_semantic sysval_semantic; + bool output; + + /* Registers used by the sysval elements of the original signature. */ + struct + { + unsigned int index; + unsigned int mask; + } regs[2]; + unsigned int reg_count; + + /* Index of the signature element created for the new array. */ + unsigned int element_idx; + /* Indexable temporary reserved to store a copy of the native sysval + * values for the current phase. If ~0u, the temporary has not been + * allocated for this phase yet. */ + unsigned int idxtemp_idx; + + enum vkd3d_shader_opcode phase; +}; + +static enum vkd3d_result sysval_array_normaliser_add_components( + struct sysval_array_normaliser *normaliser, unsigned int index, unsigned int mask) +{ + unsigned int q; + + for (q = 0; q < normaliser->reg_count; ++q) + { + if (index == normaliser->regs[q].index) + break; + } + + if (q == normaliser->reg_count) + { + if (normaliser->reg_count >= ARRAY_SIZE(normaliser->regs)) + { + vkd3d_shader_error(normaliser->ctx->message_context, + &normaliser->ctx->null_location, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "Sysval semantic %#x elements require more than %zu registers.\n", + normaliser->sysval_semantic, ARRAY_SIZE(normaliser->regs)); + return VKD3D_ERROR_INVALID_SHADER; + } + normaliser->reg_count += 1; + } + normaliser->regs[q].index = index; + normaliser->regs[q].mask |= mask; + + return VKD3D_OK; +} + +static enum vkd3d_result sysval_array_normaliser_init(struct vsir_transformation_context *ctx, + const char *semantic_name, enum vkd3d_shader_sysval_semantic sysval_semantic, + bool output, struct sysval_array_normaliser *normaliser) +{ + unsigned int component_count = 0, next_register_index; + struct shader_signature *signature; + struct signature_element *element; + enum vkd3d_result res; + + memset(normaliser, 0, sizeof(*normaliser)); + normaliser->ctx = ctx; + normaliser->sysval_semantic = sysval_semantic; + normaliser->output = output; + normaliser->element_idx = ~0u; + + normaliser->phase = VSIR_OP_INVALID; + + signature = output ? &ctx->program->output_signature : &ctx->program->input_signature; + + for (unsigned int i = 0; i < signature->element_count; ++i) + { + element = &signature->elements[i]; + if (element->sysval_semantic != sysval_semantic) + continue; + + for (unsigned int j = 0; j < element->register_count; ++j) + { + if ((res = sysval_array_normaliser_add_components(normaliser, + element->register_index + j, element->mask)) < 0) + return res; + } + } + + if (!normaliser->reg_count) + return VKD3D_OK; + next_register_index = vsir_signature_next_location(signature); + if (!(element = add_signature_element(signature, semantic_name, next_register_index, + VKD3DSP_WRITEMASK_0, signature->element_count, element->interpolation_mode))) + return VKD3D_ERROR_OUT_OF_MEMORY; + element->sysval_semantic = sysval_semantic; + for (unsigned int q = 0; q < normaliser->reg_count; ++q) + { + component_count += vkd3d_popcount(normaliser->regs[q].mask); + } + element->register_count = component_count; + normaliser->element_idx = signature->element_count - 1; + + return VKD3D_OK; +} + +/* For every component 'k' that belongs to an output signature element that + * has the sysval currently being handled by the sysval_array_normaliser, add + * the following instruction before the return points of the program: + * + * mov o[k][e].x, x[idxtmp_idx][q].kkkk + * + * or in case this is the control point phase of a hull shader: + * + * mov o[k][P][e].x, x[idxtmp_idx][q].kkkk + * + * where: + * 'q' is the index of the register containing 'k' in the normaliser's + * internal list. + * '.kkkk' is the replicated swizzle that corresponds to component 'k'. + * 'e' is the new array's signature element index. + * 'idxtmp_idx' is the index of the indexable temp reserved by the + * normaliser. + * 'P' is the output control point ID. + */ +static enum vkd3d_result sysval_array_normaliser_add_output_copy( + struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it) +{ + struct vsir_program *program = normaliser->ctx->program; + struct vsir_src_operand *outpointid_param = NULL; + unsigned int output_component_count = 0; + struct vkd3d_shader_instruction *mov; + struct signature_element *element; + struct vkd3d_shader_location loc; + + if (!normaliser->output) + return VKD3D_OK; + if (vsir_opcode_is_fork_or_join_phase(normaliser->phase)) + return VKD3D_OK; + if (normaliser->idxtemp_idx == ~0u) + return VKD3D_OK; + + element = &program->output_signature.elements[normaliser->element_idx]; + loc = vsir_program_iterator_current(it)->location; + + if (program->shader_version.type == VKD3D_SHADER_TYPE_HULL + && !(outpointid_param = vsir_program_create_outpointid_param(program))) + { + ERR("Failed to allocate outpointid param.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (unsigned int q = 0; q < normaliser->reg_count; ++q) + { + for (unsigned int k = 0; k < VKD3D_VEC4_SIZE; ++k) + { + struct vsir_src_operand *src; + struct vsir_dst_operand *dst; + + if (!(normaliser->regs[q].mask & (1u << k))) + continue; + + if (!(mov = vsir_program_iterator_insert_before_and_move(it, 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if (!vsir_instruction_init_with_params(program, mov, &loc, VSIR_OP_MOV, 1, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + dst = &mov->dst[0]; + vsir_dst_operand_init(dst, VKD3DSPR_OUTPUT, VSIR_DATA_F32, 2); + dst->reg.idx[0].offset = output_component_count++; + dst->reg.idx[1].offset = normaliser->element_idx; + dst->reg.dimension = VSIR_DIMENSION_VEC4; + dst->write_mask = VKD3DSP_WRITEMASK_0; + if (outpointid_param) + { + dst->reg.idx_count = 3; + dst->reg.idx[2] = dst->reg.idx[1]; + dst->reg.idx[1].rel_addr = outpointid_param; + dst->reg.idx[1].offset = 0; + } + + src = &mov->src[0]; + vsir_src_operand_init(src, VKD3DSPR_IDXTEMP, VSIR_DATA_F32, 2); + src->reg.idx[0].offset = normaliser->idxtemp_idx; + src->reg.idx[1].offset = q; + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->swizzle = vsir_swizzle_from_writemask(1u << k); + + vsir_program_iterator_next(it); + } + } + VKD3D_ASSERT(output_component_count == element->register_count); + + return VKD3D_OK; +} + +/* For every component 'k' that belongs to an input signature element that has + * the sysval currently being handled by the sysval_array_normaliser, add the + * following single instruction at the beginning of the program: + * + * mov x[idxtmp_idx][q].k, v[k][e].x + * + * or in case there are multiple input control points, add multiple + * instructions, one for every one of them 'p': + * + * mov x[idxtmp_idx][p * reg_count + q].k, v[k][p][e].x + * + * where: + * 'q' is the index of the register containing 'k' in the normaliser's + * internal list. + * '.k' is the write mask that corresponds to component 'k' + * 'e' is the new array's signature element index. + * 'idxtmp_idx' is the index of the indexable temp reserved by the + * normaliser. + * 'reg_count' is the number of registers in the normaliser's internal + * list. + * + * NOTE: This function also does this for components 'k' that belong to an + * output signature in case the normaliser is handling an output semantic and + * this is the fork or join phase of a hull shader, where they can be used as + * source operands. Naturally, 'o' registers are used as source operands on + * such 'mov' instructions instead of 'v'. + */ +static enum vkd3d_result sysval_array_normaliser_add_input_copy( + struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it) +{ + struct vsir_program *program = normaliser->ctx->program; + struct vkd3d_shader_instruction *mov; + struct signature_element *element; + unsigned int control_point_count; + struct vkd3d_shader_location loc; + + loc = vsir_program_iterator_current(it)->location; + if (normaliser->output) + { + control_point_count = program->output_control_point_count; + element = &program->output_signature.elements[normaliser->element_idx]; + } + else + { + control_point_count = program->input_control_point_count; + element = &program->input_signature.elements[normaliser->element_idx]; + } + + if (!vsir_program_iterator_insert_before_and_move(it, max(1, control_point_count) * element->register_count)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + for (unsigned int p = 0; p < max(1, control_point_count); ++p) + { + unsigned int input_component_count = 0; + + for (unsigned int q = 0; q < normaliser->reg_count; ++q) + { + for (unsigned int k = 0; k < VKD3D_VEC4_SIZE; ++k) + { + struct vsir_src_operand *src; + struct vsir_dst_operand *dst; + + if (!(normaliser->regs[q].mask & (1u << k))) + continue; + + mov = vsir_program_iterator_current(it); + vsir_instruction_init_with_params(program, mov, &loc, VSIR_OP_MOV, 1, 1); + + dst = &mov->dst[0]; + vsir_dst_operand_init(dst, VKD3DSPR_IDXTEMP, VSIR_DATA_F32, 2); + dst->reg.idx[0].offset = normaliser->idxtemp_idx; + dst->reg.idx[1].offset = p * normaliser->reg_count + q; + dst->reg.dimension = VSIR_DIMENSION_VEC4; + dst->write_mask = 1u << k; + + src = &mov->src[0]; + if (control_point_count) + { + vsir_src_operand_init(src, normaliser->output ? VKD3DSPR_OUTPUT : VKD3DSPR_INPUT, + VSIR_DATA_F32, 3); + src->reg.idx[0].offset = input_component_count++; + src->reg.idx[1].offset = p; + src->reg.idx[2].offset = normaliser->element_idx; + } + else + { + vsir_src_operand_init(src, VKD3DSPR_INPUT, VSIR_DATA_F32, 2); + src->reg.idx[0].offset = input_component_count++; + src->reg.idx[1].offset = normaliser->element_idx; + } + src->reg.dimension = VSIR_DIMENSION_VEC4; + src->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + + vsir_program_iterator_next(it); + } + } + VKD3D_ASSERT(input_component_count == element->register_count); + } + + return VKD3D_OK; +} + +static enum vkd3d_result sysval_array_normaliser_dcl_indexable_temp( + struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it, size_t idx) +{ + struct vsir_program *program = normaliser->ctx->program; + unsigned int register_size = normaliser->reg_count; + struct vkd3d_shader_instruction *ins; + unsigned int control_point_count; + + normaliser->idxtemp_idx = idx; + control_point_count = normaliser->output + ? program->output_control_point_count : program->input_control_point_count; + + if (control_point_count && (!normaliser->output || vsir_opcode_is_fork_or_join_phase(normaliser->phase))) + register_size *= program->input_control_point_count; + + if (!(ins = vsir_program_iterator_dcl_indexable_temp_before( + normaliser->ctx, it, normaliser->idxtemp_idx, register_size))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + return VKD3D_OK; +} + +static bool vsir_program_validate_outpointid_control_point_index(const struct vkd3d_shader_register *reg) +{ + const struct vkd3d_shader_register_index *index; + + if (reg->idx_count < 2) + return false; + + index = ®->idx[reg->idx_count - 2]; + if (index->offset) + return false; + if (!index->rel_addr || index->rel_addr->reg.type != VKD3DSPR_OUTPOINTID) + return false; + if (index->rel_addr->reg.idx_count) + return false; + return true; +} + +/* If a register refers to a signature element of index 'e' that has the + * sysval being handled by the normaliser, this maps the register as follows: + * + * v[e] -> x[idxtmp_idx][q] + * + * v[i][e] -> x[idxtmp_idx][i + q] + * on shaders without control points. + * + * v[p][e] -> x[idxtmp_idx][p * reg_count + q], + * on shaders with control points. + * + * v[i][p][e] -> x[idxtmp_idx][p * reg_count + i + q] + * on shaders with control points. + * + * o[e] -> x[idxtmp_idx][q] + * + * o[i][e] -> x[idxtmp_idx][i + q] + * on shaders without control points. + * + * o[p][e] -> x[idxtmp_idx][p * reg_count + q] + * if on HS fork/join phase, where it is a src. + * + * o[P][e] -> x[idxtmp_idx][q] + * if on HS control point phase, where it is a dst. + * P is expected to always be the output control point ID. + * + * o[i][p][e] -> x[idxtmp_idx][p * reg_count + i + q] + * if on HS fork/join phase, where it is a src. + * + * o[i][P][e] -> x[idxtmp_idx][i + q] + * if on HS control point phase, where it is a dst. + * P is expected to always be the output control point ID. + * + * where: + * 'q' is the index of the register that matches signature element 'e' in + * the normaliser's internal list. + * 'idxtmp_idx' is the index of the indexable temp reserved by the + * normaliser. + * 'reg_count' is the number of registers in the normaliser's internal + * list. + * + * The swizzle (for source operands) is also combined with the mask of the + * relevant signature element 'e'. + */ +static enum vkd3d_result sysval_array_normaliser_map_register(struct sysval_array_normaliser *normaliser, + struct vsir_program_iterator *it, struct vkd3d_shader_register *reg, unsigned int *src_swizzle) +{ + struct vkd3d_shader_register_index i_idx = {0}, p_idx = {0}; + struct vsir_program *program = normaliser->ctx->program; + unsigned int element_index, control_point_count; + struct vkd3d_shader_instruction *ssa_ins; + struct shader_signature *signature; + struct signature_element *element; + struct vkd3d_shader_location loc; + unsigned int q; + + loc = vsir_program_iterator_current(it)->location; + + signature = normaliser->output ? &program->output_signature : &program->input_signature; + control_point_count = normaliser->output ? program->output_control_point_count + : program->input_control_point_count; + + for (unsigned int i = 0; i < reg->idx_count; ++i) + { + if (reg->idx[i].rel_addr) + sysval_array_normaliser_map_register(normaliser, it, + ®->idx[i].rel_addr->reg, ®->idx[i].rel_addr->swizzle); } - compare_func = func->u.immediate_constant.u.u32; - if (compare_func == VKD3D_SHADER_COMPARISON_FUNC_ALWAYS) + if (normaliser->output && reg->type != VKD3DSPR_OUTPUT) + return VKD3D_OK; + if (!normaliser->output && reg->type != VKD3DSPR_INPUT) return VKD3D_OK; - /* We're going to be reading from the output, so we need to go - * through the whole shader and convert it to a temp. */ + element_index = reg->idx[reg->idx_count - 1].offset; + element = &signature->elements[element_index]; + if (element->sysval_semantic != normaliser->sysval_semantic) + return VKD3D_OK; - if (compare_func != VKD3D_SHADER_COMPARISON_FUNC_NEVER) - colour_temp = program->temp_count++; + for (q = 0; q < normaliser->reg_count; ++q) + { + if (normaliser->regs[q].index == element->register_index) + break; + } + VKD3D_ASSERT(q < normaliser->reg_count); - for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) + if (normaliser->output && normaliser->phase == VSIR_OP_HS_CONTROL_POINT_PHASE) { - if (vsir_instruction_is_dcl(ins)) - continue; + if (!vsir_program_validate_outpointid_control_point_index(reg)) + vkd3d_shader_error(normaliser->ctx->message_context, &loc, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "Control point index of output source operand is not OUTPOINTID.\n"); + } - if (ins->opcode == VSIR_OP_RET) + if (control_point_count) + { + if (reg->idx_count == 3) { - if ((ret = insert_alpha_test_before_ret(program, &it, compare_func, - ref, colour_signature_idx, colour_temp, message_context)) < 0) - return ret; - continue; + i_idx = reg->idx[0]; + p_idx = reg->idx[1]; } - - /* No need to convert it if the comparison func is NEVER; we don't - * read from the output in that case. */ - if (compare_func == VKD3D_SHADER_COMPARISON_FUNC_NEVER) - continue; - - for (size_t j = 0; j < ins->dst_count; ++j) + else { - struct vkd3d_shader_dst_param *dst = &ins->dst[j]; - - /* Note we run after I/O normalization. */ - if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == colour_signature_idx) - { - dst->reg.type = VKD3DSPR_TEMP; - dst->reg.idx[0].offset = colour_temp; - } + p_idx = reg->idx[0]; } } + else if (reg->idx_count == 2) + { + i_idx = reg->idx[0]; + } - return VKD3D_OK; -} + reg->type = VKD3DSPR_IDXTEMP; + reg->idx[0].offset = normaliser->idxtemp_idx; + reg->idx[0].rel_addr = NULL; + reg->idx_count = 2; -static enum vkd3d_result insert_clip_planes_before_ret(struct vsir_program *program, - struct vsir_program_iterator *it, uint32_t mask, uint32_t position_signature_idx, - uint32_t position_temp, uint32_t low_signature_idx, uint32_t high_signature_idx) -{ - const struct vkd3d_shader_location loc = vsir_program_iterator_current(it)->location; - struct vkd3d_shader_instruction *ins; - unsigned int output_idx = 0; + if (p_idx.rel_addr && !(normaliser->output && normaliser->phase == VSIR_OP_HS_CONTROL_POINT_PHASE)) + { + if (!(ssa_ins = vsir_program_iterator_insert_before_and_move(it, 1 + !!i_idx.rel_addr))) + return VKD3D_ERROR_OUT_OF_MEMORY; - if (!(ins = vsir_program_iterator_insert_before_and_move(it, vkd3d_popcount(mask) + 1))) - return VKD3D_ERROR_OUT_OF_MEMORY; + if (!vsir_instruction_init_with_params(program, ssa_ins, &loc, VSIR_OP_IMUL_LOW, 1, 2)) + return VKD3D_ERROR_OUT_OF_MEMORY; - for (unsigned int i = 0; i < 8; ++i) - { - if (!(mask & (1u << i))) - continue; + vsir_register_init(&ssa_ins->dst[0].reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1); + ssa_ins->dst[0].reg.idx[0].offset = program->ssa_count++; + ssa_ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ssa_ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0; + ssa_ins->src[0] = *p_idx.rel_addr; + vsir_src_operand_init_const_u32(&ssa_ins->src[1], normaliser->reg_count); - vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_DP4, 1, 2); - src_param_init_temp_float4(&ins->src[0], position_temp); - src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_0 + i, VSIR_DATA_F32); - ins->src[1].swizzle = VKD3D_SHADER_NO_SWIZZLE; - ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; + if (i_idx.rel_addr) + { + ssa_ins = vsir_program_iterator_next(it); + if (!vsir_instruction_init_with_params(program, ssa_ins, &loc, VSIR_OP_ADD, 1, 2)) + return VKD3D_ERROR_OUT_OF_MEMORY; - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VSIR_DATA_F32, 1); - if (output_idx < 4) - ins->dst[0].reg.idx[0].offset = low_signature_idx; - else - ins->dst[0].reg.idx[0].offset = high_signature_idx; - ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; - ins->dst[0].write_mask = (1u << (output_idx % 4)); - ++output_idx; + vsir_register_init(&ssa_ins->dst[0].reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1); + ssa_ins->dst[0].reg.idx[0].offset = program->ssa_count++; + ssa_ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ssa_ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0; + vsir_register_init(&ssa_ins->src[0].reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1); + ssa_ins->src[0].reg.idx[0].offset = program->ssa_count - 2; + ssa_ins->src[1] = *i_idx.rel_addr; + } - ins = vsir_program_iterator_next(it); + vsir_program_iterator_next(it); + + reg->idx[1].offset = normaliser->reg_count * p_idx.offset + i_idx.offset + q; + if (!(reg->idx[1].rel_addr = vsir_program_get_src_operands(program, 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + vsir_register_init(®->idx[1].rel_addr->reg, VKD3DSPR_SSA, VSIR_DATA_U32, 1); + reg->idx[1].rel_addr->reg.idx[0].offset = program->ssa_count - 1; + reg->idx[1].rel_addr->reg.dimension = VSIR_DIMENSION_VEC4; + reg->idx[1].rel_addr->swizzle = VKD3D_SHADER_SWIZZLE_X; + reg->idx[1].rel_addr->modifiers = 0; + } + else + { + reg->idx[1].offset = normaliser->reg_count * p_idx.offset + i_idx.offset + q; + reg->idx[1].rel_addr = i_idx.rel_addr; } - vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_OUTPUT, VSIR_DATA_F32, 1); - ins->dst[0].reg.idx[0].offset = position_signature_idx; - ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; - ins->dst[0].write_mask = program->output_signature.elements[position_signature_idx].mask; - src_param_init_temp_float(&ins->src[0], position_temp); - ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; - ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; - ins = vsir_program_iterator_next(it); + if (src_swizzle) + *src_swizzle = vsir_combine_swizzles(vsir_swizzle_from_writemask(element->mask), *src_swizzle); return VKD3D_OK; } -static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *program, - struct vsir_transformation_context *ctx) +static enum vkd3d_result sysval_array_normaliser_map_instruction( + struct sysval_array_normaliser *normaliser, struct vsir_program_iterator *it) { - struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); - struct shader_signature *signature = &program->output_signature; - unsigned int low_signature_idx = ~0u, high_signature_idx = ~0u; - const struct vkd3d_shader_parameter1 *mask_parameter = NULL; - uint32_t position_signature_idx, position_temp, mask; - struct signature_element *clip_element; - struct vkd3d_shader_instruction *ins; - unsigned int plane_count; - int ret; + struct vkd3d_shader_instruction *ins = vsir_program_iterator_current(it); + unsigned int src_count, dst_count; + enum vkd3d_result res; - if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX) + if (vsir_instruction_is_dcl(ins)) return VKD3D_OK; - for (unsigned int i = 0; i < program->parameter_count; ++i) - { - const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i]; + dst_count = ins->dst_count; + src_count = ins->src_count; - if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_MASK) - mask_parameter = parameter; + for (unsigned int k = 0; k < dst_count; ++k) + { + ins = vsir_program_iterator_current(it); + if ((res = sysval_array_normaliser_map_register(normaliser, it, &ins->dst[k].reg, NULL))) + return res; } - if (!mask_parameter) - return VKD3D_OK; - - if (mask_parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT) + for (unsigned int k = 0; k < src_count; ++k) { - vkd3d_shader_error(ctx->message_context, NULL, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, - "Unsupported clip plane mask parameter type %#x.", mask_parameter->type); - return VKD3D_ERROR_NOT_IMPLEMENTED; + ins = vsir_program_iterator_current(it); + if ((res = sysval_array_normaliser_map_register(normaliser, it, &ins->src[k].reg, &ins->src[k].swizzle))) + return res; } - if (mask_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32) + + return VKD3D_OK; +} + +static void shader_register_remove_signature_element(struct vkd3d_shader_register *reg, + enum vkd3d_shader_register_type type, unsigned int index) +{ + unsigned int current_idx; + + for (unsigned int i = 0; i < reg->idx_count; ++i) { - vkd3d_shader_error(ctx->message_context, NULL, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, - "Invalid clip plane mask parameter data type %#x.", mask_parameter->data_type); - return VKD3D_ERROR_INVALID_ARGUMENT; + if (reg->idx[i].rel_addr) + shader_register_remove_signature_element(®->idx[i].rel_addr->reg, type, index); } - mask = mask_parameter->u.immediate_constant.u.u32; - if (!mask) - return VKD3D_OK; + if (reg->type != type) + return; - for (unsigned int i = 0; i < signature->element_count; ++i) + VKD3D_ASSERT(!reg->idx[reg->idx_count - 1].rel_addr); + current_idx = reg->idx[reg->idx_count - 1].offset; + VKD3D_ASSERT(current_idx != index); + if (current_idx > index) + --reg->idx[reg->idx_count - 1].offset; +} + +static void vsir_program_remove_signature_element(struct vsir_program *program, + enum vkd3d_shader_register_type type, unsigned int index) +{ + struct vsir_program_iterator it = vsir_program_iterator(&program->instructions); + struct vkd3d_shader_instruction *ins; + struct shader_signature *signature; + + switch (type) { - if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE) - { - vkd3d_shader_error(ctx->message_context, &ctx->null_location, VKD3D_SHADER_ERROR_VSIR_INVALID_PARAMETER, - "Clip planes cannot be used if the shader writes clip distance."); - return VKD3D_ERROR_INVALID_ARGUMENT; - } + case VKD3DSPR_INPUT: + signature = &program->input_signature; + break; + case VKD3DSPR_OUTPUT: + signature = &program->output_signature; + break; + case VKD3DSPR_PATCHCONST: + signature = &program->patch_constant_signature; + break; + default: + vkd3d_unreachable(); } - if (!vsir_signature_find_sysval(signature, VKD3D_SHADER_SV_POSITION, 0, &position_signature_idx)) + for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) { - vkd3d_shader_error(ctx->message_context, &ctx->null_location, VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC, - "Shader does not write position."); - return VKD3D_ERROR_INVALID_SHADER; + if (vsir_instruction_is_dcl(ins)) + continue; + for (unsigned int i = 0; i < ins->dst_count; ++i) + shader_register_remove_signature_element(&ins->dst[i].reg, type, index); + for (unsigned int i = 0; i < ins->src_count; ++i) + shader_register_remove_signature_element(&ins->src[i].reg, type, index); } - /* Append the clip plane signature indices. */ + vsir_signature_element_cleanup(&signature->elements[index]); + memmove(&signature->elements[index], &signature->elements[index + 1], + sizeof(*signature->elements) * (signature->element_count - 1 - index)); + --signature->element_count; +} - plane_count = vkd3d_popcount(mask); +static void sysval_array_normaliser_remove_old_signature_elements(struct sysval_array_normaliser *normaliser) +{ + struct vsir_program *program = normaliser->ctx->program; + enum vkd3d_shader_register_type type; + struct shader_signature *signature; + struct signature_element *element; - /* Register mask is ignored since we operate after I/O normalisation. */ - if (!(clip_element = add_signature_element(signature, "SV_ClipDistance", 0, - vkd3d_write_mask_from_component_count(min(plane_count, 4)), 0, VKD3DSIM_NONE))) - return VKD3D_ERROR_OUT_OF_MEMORY; - low_signature_idx = clip_element - signature->elements; - clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; + signature = normaliser->output ? &program->output_signature : &program->input_signature; + type = normaliser->output ? VKD3DSPR_OUTPUT : VKD3DSPR_INPUT; - if (plane_count > 4) + for (int i = signature->element_count - 2; i >= 0; --i) { - if (!(clip_element = add_signature_element(signature, "SV_ClipDistance", 1, - vkd3d_write_mask_from_component_count(plane_count - 4), 0, VKD3DSIM_NONE))) - return VKD3D_ERROR_OUT_OF_MEMORY; - high_signature_idx = clip_element - signature->elements; - clip_element->sysval_semantic = VKD3D_SHADER_SV_CLIP_DISTANCE; + element = &signature->elements[i]; + if (element->sysval_semantic != normaliser->sysval_semantic) + continue; + TRACE("Removing %s signature element index %u.\n", normaliser->output ? "output" : "input", i); + vsir_program_remove_signature_element(program, type, i); } +} - /* We're going to be reading from the output position, so we need to go - * through the whole shader and convert it to a temp. */ +static enum vkd3d_result vsir_program_normalise_sysval_array(struct vsir_transformation_context *ctx, + const char *semantic_name, enum vkd3d_shader_sysval_semantic sysval_semantic, bool output) +{ + struct vsir_program *program = ctx->program; + struct sysval_array_normaliser normaliser; + struct vkd3d_shader_instruction *ins; + struct vsir_program_iterator it; + bool declarations = true; + enum vkd3d_result res; - position_temp = program->temp_count++; + if ((res = sysval_array_normaliser_init(ctx, semantic_name, sysval_semantic, output, &normaliser)) < 0) + return res; + + if (!normaliser.reg_count) + return VKD3D_OK; + + if (!output && program->shader_version.type == VKD3D_SHADER_TYPE_VERTEX) + return VKD3D_OK; + it = vsir_program_iterator(&program->instructions); for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it)) { - if (vsir_instruction_is_dcl(ins)) - continue; - - if (ins->opcode == VSIR_OP_RET) + if (ins->opcode == VSIR_OP_HS_DECLS || ins->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE + || ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE) { - if ((ret = insert_clip_planes_before_ret(program, &it, mask, position_signature_idx, - position_temp, low_signature_idx, high_signature_idx)) < 0) - return ret; + normaliser.phase = ins->opcode; + declarations = true; continue; } - for (size_t j = 0; j < ins->dst_count; ++j) + if (declarations && !vsir_instruction_is_dcl(ins) && ins->opcode != VSIR_OP_NOP) { - struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + unsigned int idxtemp_idx = vsir_program_get_idxtemp_count(program); - /* Note we run after I/O normalization. */ - if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == position_signature_idx) + declarations = false; + + if ((res = sysval_array_normaliser_dcl_indexable_temp(&normaliser, &it, idxtemp_idx)) < 0) + return res; + + if (vsir_program_iterator_current(&it)->opcode == VSIR_OP_LABEL) + ins = vsir_program_iterator_next(&it); + + if ((!output || vsir_opcode_is_fork_or_join_phase(normaliser.phase)) + && (res = sysval_array_normaliser_add_input_copy(&normaliser, &it)) < 0) + return res; + + ins = vsir_program_iterator_current(&it); + } + + if (!declarations) + { + if (ins->opcode == VSIR_OP_RET || ins->opcode == VSIR_OP_EMIT || ins->opcode == VSIR_OP_EMIT_STREAM) { - dst->reg.type = VKD3DSPR_TEMP; - dst->reg.idx[0].offset = position_temp; + if ((output && !vsir_opcode_is_fork_or_join_phase(normaliser.phase)) + && (res = sysval_array_normaliser_add_output_copy(&normaliser, &it)) < 0) + return res; + } + else + { + if ((res = sysval_array_normaliser_map_instruction(&normaliser, &it)) < 0) + return res; } } } + VKD3D_ASSERT(!declarations); + sysval_array_normaliser_remove_old_signature_elements(&normaliser); + + return VKD3D_OK; +} + +/* This pass transform clip/cull system values from the Direct3D convention of + * 2 4-component registers, into the SPIR-V/GLSL convention of 8-element + * scalar float arrays. */ +static enum vkd3d_result vsir_program_normalise_clip_cull( + struct vsir_program *program, struct vsir_transformation_context *ctx) +{ + enum vkd3d_result res; + + if ((res = vsir_program_normalise_sysval_array(ctx, "SV_ClipDistance", VKD3D_SHADER_SV_CLIP_DISTANCE, false)) < 0) + return res; + if ((res = vsir_program_normalise_sysval_array(ctx, "SV_ClipDistance", VKD3D_SHADER_SV_CLIP_DISTANCE, true)) < 0) + return res; + if ((res = vsir_program_normalise_sysval_array(ctx, "SV_CullDistance", VKD3D_SHADER_SV_CULL_DISTANCE, false)) < 0) + return res; + if ((res = vsir_program_normalise_sysval_array(ctx, "SV_CullDistance", VKD3D_SHADER_SV_CULL_DISTANCE, true)) < 0) + return res; + + program->normalisation_flags.normalised_clip_cull_arrays = true; return VKD3D_OK; } @@ -8134,9 +9679,9 @@ static enum vkd3d_result insert_point_size_before_ret(struct vsir_program *progr return VKD3D_ERROR_OUT_OF_MEMORY; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; - src_param_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE, VSIR_DATA_F32); + vsir_src_operand_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE, VSIR_DATA_F32); ins = vsir_program_iterator_next(it); return VKD3D_OK; @@ -8243,12 +9788,12 @@ static enum vkd3d_result vsir_program_insert_point_size_clamp(struct vsir_progra for (size_t j = 0; j < ins->dst_count; ++j) { - struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + struct vsir_dst_operand *dst = &ins->dst[j]; /* Note we run after I/O normalization. */ if (dst->reg.type == VKD3DSPR_RASTOUT) { - dst_param_init_ssa_float(dst, program->ssa_count); + vsir_dst_operand_init_ssa_f32(dst, program->ssa_count); ssa_value = program->ssa_count++; clamp = true; } @@ -8266,16 +9811,16 @@ static enum vkd3d_result vsir_program_insert_point_size_clamp(struct vsir_progra if (min_parameter) { vsir_instruction_init_with_params(program, ins, loc, VSIR_OP_MAX, 1, 2); - src_param_init_ssa_float(&ins->src[0], ssa_value); - src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN, VSIR_DATA_F32); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_value); + vsir_src_operand_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN, VSIR_DATA_F32); if (max_parameter) { - dst_param_init_ssa_float(&ins->dst[0], program->ssa_count); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], program->ssa_count); ssa_value = program->ssa_count++; } else { - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; } ins = vsir_program_iterator_next(&it); @@ -8284,9 +9829,9 @@ static enum vkd3d_result vsir_program_insert_point_size_clamp(struct vsir_progra if (max_parameter) { vsir_instruction_init_with_params(program, ins, loc, VSIR_OP_MIN, 1, 2); - src_param_init_ssa_float(&ins->src[0], ssa_value); - src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX, VSIR_DATA_F32); - vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_value); + vsir_src_operand_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX, VSIR_DATA_F32); + vsir_dst_operand_init(&ins->dst[0], VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; ins = vsir_program_iterator_next(&it); } @@ -8307,7 +9852,7 @@ static bool has_texcoord_signature_element(const struct shader_signature *signat /* Returns true if replacement was done. */ static bool replace_texcoord_with_point_coord(struct vsir_program *program, - struct vkd3d_shader_src_param *src, unsigned int coord_temp) + struct vsir_src_operand *src, unsigned int coord_temp) { uint32_t prev_swizzle = src->swizzle; const struct signature_element *e; @@ -8458,17 +10003,17 @@ static enum vkd3d_result vsir_program_insert_point_coord(struct vsir_program *pr return VKD3D_ERROR_OUT_OF_MEMORY; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - dst_param_init_temp_float4(&ins->dst[0], coord_temp); + vsir_dst_operand_init_temp_f32v4(&ins->dst[0], coord_temp); ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1; - vsir_src_param_init(&ins->src[0], VKD3DSPR_POINT_COORD, VSIR_DATA_F32, 0); + vsir_src_operand_init(&ins->src[0], VKD3DSPR_POINT_COORD, VSIR_DATA_F32, 0); ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; ins = vsir_program_iterator_next(&it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - dst_param_init_temp_float4(&ins->dst[0], coord_temp); + vsir_dst_operand_init_temp_f32v4(&ins->dst[0], coord_temp); ins->dst[0].write_mask = VKD3DSP_WRITEMASK_2 | VKD3DSP_WRITEMASK_3; - vsir_src_param_init(&ins->src[0], VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); + vsir_src_operand_init(&ins->src[0], VKD3DSPR_IMMCONST, VSIR_DATA_F32, 0); ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[0].swizzle = VKD3D_SHADER_NO_SWIZZLE; vsir_program_iterator_next(&it); @@ -8483,6 +10028,7 @@ static enum vkd3d_result vsir_program_add_fog_input(struct vsir_program *program struct vsir_transformation_context *ctx) { struct shader_signature *signature = &program->input_signature; + struct signature_element *e; uint32_t register_idx = 0; if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL) @@ -8500,7 +10046,10 @@ static enum vkd3d_result vsir_program_add_fog_input(struct vsir_program *program return VKD3D_OK; for (unsigned int i = 0; i < signature->element_count; ++i) - register_idx = max(register_idx, signature->elements[i].register_index + 1); + { + e = &signature->elements[i]; + register_idx = max(register_idx, e->register_index + e->register_count); + } if (!add_signature_element(signature, "FOG", 0, VKD3DSP_WRITEMASK_0, register_idx, VKD3DSIM_LINEAR)) return VKD3D_ERROR_OUT_OF_MEMORY; @@ -8532,23 +10081,23 @@ static enum vkd3d_result insert_fragment_fog_before_ret(struct vsir_program *pro ssa_temp2 = program->ssa_count++; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_NEG, 1, 1); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp); - vsir_src_param_init(&ins->src[0], VKD3DSPR_INPUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp); + vsir_src_operand_init(&ins->src[0], VKD3DSPR_INPUT, VSIR_DATA_F32, 1); ins->src[0].reg.idx[0].offset = fog_signature_idx; ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_ADD, 1, 2); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp2); - src_param_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_END, VSIR_DATA_F32); - src_param_init_ssa_float(&ins->src[1], ssa_temp); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp2); + vsir_src_operand_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_END, VSIR_DATA_F32); + vsir_src_operand_init_ssa_f32(&ins->src[1], ssa_temp); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MUL, 1, 2); - dst_param_init_ssa_float(&ins->dst[0], ssa_factor); - src_param_init_ssa_float(&ins->src[0], ssa_temp2); - src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, VSIR_DATA_F32); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_factor); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_temp2); + vsir_src_operand_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, VSIR_DATA_F32); ins = vsir_program_iterator_next(it); break; @@ -8567,22 +10116,22 @@ static enum vkd3d_result insert_fragment_fog_before_ret(struct vsir_program *pro ssa_temp2 = program->ssa_count++; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MUL, 1, 2); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp); - src_param_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, VSIR_DATA_F32); - vsir_src_param_init(&ins->src[1], VKD3DSPR_INPUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp); + vsir_src_operand_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, VSIR_DATA_F32); + vsir_src_operand_init(&ins->src[1], VKD3DSPR_INPUT, VSIR_DATA_F32, 1); ins->src[1].reg.idx[0].offset = fog_signature_idx; ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_NEG, 1, 1); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp2); - src_param_init_ssa_float(&ins->src[0], ssa_temp); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp2); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_temp); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_EXP, 1, 1); - dst_param_init_ssa_float(&ins->dst[0], ssa_factor); - src_param_init_ssa_float(&ins->src[0], ssa_temp2); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_factor); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_temp2); ins = vsir_program_iterator_next(it); break; @@ -8602,28 +10151,28 @@ static enum vkd3d_result insert_fragment_fog_before_ret(struct vsir_program *pro ssa_temp3 = program->ssa_count++; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MUL, 1, 2); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp); - src_param_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, VSIR_DATA_F32); - vsir_src_param_init(&ins->src[1], VKD3DSPR_INPUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp); + vsir_src_operand_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, VSIR_DATA_F32); + vsir_src_operand_init(&ins->src[1], VKD3DSPR_INPUT, VSIR_DATA_F32, 1); ins->src[1].reg.idx[0].offset = fog_signature_idx; ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MUL, 1, 2); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp2); - src_param_init_ssa_float(&ins->src[0], ssa_temp); - src_param_init_ssa_float(&ins->src[1], ssa_temp); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp2); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_temp); + vsir_src_operand_init_ssa_f32(&ins->src[1], ssa_temp); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_NEG, 1, 1); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp3); - src_param_init_ssa_float(&ins->src[0], ssa_temp2); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp3); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_temp2); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_EXP, 1, 1); - dst_param_init_ssa_float(&ins->dst[0], ssa_factor); - src_param_init_ssa_float(&ins->src[0], ssa_temp3); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_factor); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_temp3); ins = vsir_program_iterator_next(it); break; @@ -8643,27 +10192,27 @@ static enum vkd3d_result insert_fragment_fog_before_ret(struct vsir_program *pro ssa_temp3 = program->ssa_count++; vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_NEG, 1, 1); - dst_param_init_ssa_float4(&ins->dst[0], ssa_temp); - src_param_init_parameter_vec4(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR, VSIR_DATA_F32); + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], ssa_temp); + vsir_src_operand_init_parameter_vec4(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR, VSIR_DATA_F32); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_ADD, 1, 2); - dst_param_init_ssa_float4(&ins->dst[0], ssa_temp2); - src_param_init_temp_float4(&ins->src[0], colour_temp); - src_param_init_ssa_float4(&ins->src[1], ssa_temp); + vsir_dst_operand_init_ssa_f32v4(&ins->dst[0], ssa_temp2); + vsir_src_operand_init_temp_f32v4(&ins->src[0], colour_temp); + vsir_src_operand_init_ssa_f32v4(&ins->src[1], ssa_temp); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_SATURATE, 1, 1); - dst_param_init_ssa_float(&ins->dst[0], ssa_temp3); - src_param_init_ssa_float(&ins->src[0], ssa_factor); + vsir_dst_operand_init_ssa_f32(&ins->dst[0], ssa_temp3); + vsir_src_operand_init_ssa_f32(&ins->src[0], ssa_factor); ins = vsir_program_iterator_next(it); vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MAD, 1, 3); - dst_param_init_output(&ins->dst[0], VSIR_DATA_F32, colour_signature_idx, + vsir_dst_operand_init_output(&ins->dst[0], VSIR_DATA_F32, colour_signature_idx, program->output_signature.elements[colour_signature_idx].mask); - src_param_init_ssa_float4(&ins->src[0], ssa_temp2); - src_param_init_ssa_float(&ins->src[1], ssa_temp3); - src_param_init_parameter_vec4(&ins->src[2], VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR, VSIR_DATA_F32); + vsir_src_operand_init_ssa_f32v4(&ins->src[0], ssa_temp2); + vsir_src_operand_init_ssa_f32(&ins->src[1], ssa_temp3); + vsir_src_operand_init_parameter_vec4(&ins->src[2], VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR, VSIR_DATA_F32); ins = vsir_program_iterator_next(it); return VKD3D_OK; @@ -8734,7 +10283,7 @@ static enum vkd3d_result vsir_program_insert_fragment_fog(struct vsir_program *p for (size_t j = 0; j < ins->dst_count; ++j) { - struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + struct vsir_dst_operand *dst = &ins->dst[j]; /* Note we run after I/O normalization. */ if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == colour_signature_idx) @@ -8797,8 +10346,8 @@ static enum vkd3d_result insert_vertex_fog_before_ret(struct vsir_program *progr /* Write the fog output. */ vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - dst_param_init_output(&ins->dst[0], VSIR_DATA_F32, fog_signature_idx, 0x1); - src_param_init_temp_float4(&ins->src[0], temp); + vsir_dst_operand_init_output(&ins->dst[0], VSIR_DATA_F32, fog_signature_idx, 0x1); + vsir_src_operand_init_temp_f32v4(&ins->src[0], temp); if (source == VKD3D_SHADER_FOG_SOURCE_Z) ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(Z, Z, Z, Z); else /* Position or specular W. */ @@ -8807,9 +10356,9 @@ static enum vkd3d_result insert_vertex_fog_before_ret(struct vsir_program *progr /* Write the position or specular output. */ vsir_instruction_init_with_params(program, ins, &loc, VSIR_OP_MOV, 1, 1); - dst_param_init_output(&ins->dst[0], vsir_data_type_from_component_type(e->component_type), - source_signature_idx, e->mask); - src_param_init_temp_float4(&ins->src[0], temp); + vsir_dst_operand_init_output(&ins->dst[0], + vsir_data_type_from_component_type(e->component_type), source_signature_idx, e->mask); + vsir_src_operand_init_temp_f32v4(&ins->src[0], temp); ins = vsir_program_iterator_next(it); return VKD3D_OK; @@ -8896,7 +10445,7 @@ static enum vkd3d_result vsir_program_insert_vertex_fog(struct vsir_program *pro for (size_t j = 0; j < ins->dst_count; ++j) { - struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + struct vsir_dst_operand *dst = &ins->dst[j]; /* Note we run after I/O normalization. */ if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == source_signature_idx) @@ -9303,8 +10852,7 @@ struct liveness_tracker } *ssa_regs, *temp_regs; }; -static void liveness_track_src(struct liveness_tracker *tracker, - struct vkd3d_shader_src_param *src, unsigned int index) +static void liveness_track_src(struct liveness_tracker *tracker, struct vsir_src_operand *src, unsigned int index) { for (unsigned int k = 0; k < src->reg.idx_count; ++k) { @@ -9324,7 +10872,7 @@ static void liveness_track_src(struct liveness_tracker *tracker, } } -static void liveness_track_dst(struct liveness_tracker *tracker, struct vkd3d_shader_dst_param *dst, +static void liveness_track_dst(struct liveness_tracker *tracker, struct vsir_dst_operand *dst, unsigned int index, const struct vkd3d_shader_version *version, enum vkd3d_shader_opcode opcode) { struct liveness_tracker_reg *reg; @@ -9522,7 +11070,7 @@ struct temp_allocator bool ps_1_x; }; -static void temp_allocator_set_src(struct temp_allocator *allocator, struct vkd3d_shader_src_param *src) +static void temp_allocator_set_src(struct temp_allocator *allocator, struct vsir_src_operand *src) { struct temp_allocator_reg *reg; @@ -9568,7 +11116,7 @@ static uint32_t vsir_map_swizzle(uint32_t swizzle, unsigned int writemask) return ret; } -static void vsir_remap_immconst(struct vkd3d_shader_src_param *src, unsigned int writemask) +static void vsir_remap_immconst(struct vsir_src_operand *src, unsigned int writemask) { union vsir_immediate_constant prev = src->reg.u; unsigned int src_component = 0; @@ -9580,7 +11128,7 @@ static void vsir_remap_immconst(struct vkd3d_shader_src_param *src, unsigned int } } -static void vsir_remap_immconst64(struct vkd3d_shader_src_param *src, unsigned int writemask) +static void vsir_remap_immconst64(struct vsir_src_operand *src, unsigned int writemask) { if (writemask == (VKD3DSP_WRITEMASK_2 | VKD3DSP_WRITEMASK_3)) src->reg.u.immconst_u64[1] = src->reg.u.immconst_u64[0]; @@ -9615,7 +11163,7 @@ static bool vsir_opcode_is_double(enum vkd3d_shader_opcode opcode) } static void temp_allocator_set_dst(struct temp_allocator *allocator, - struct vkd3d_shader_dst_param *dst, const struct vkd3d_shader_instruction *ins) + struct vsir_dst_operand *dst, const struct vkd3d_shader_instruction *ins) { struct temp_allocator_reg *reg; uint32_t remapped_mask; @@ -9659,7 +11207,7 @@ static void temp_allocator_set_dst(struct temp_allocator *allocator, for (unsigned int i = 0; i < ins->src_count; ++i) { - struct vkd3d_shader_src_param *src = &ins->src[i]; + struct vsir_src_operand *src = &ins->src[i]; if (vsir_src_is_masked(ins->opcode, i)) { @@ -10445,8 +11993,7 @@ static void vsir_validate_io_register(struct validation_context *ctx, const stru } element = &signature->elements[signature_idx]; - if (element->register_count > 1 || vsir_sysval_semantic_is_tess_factor(element->sysval_semantic)) - is_array = true; + is_array = vsir_signature_element_is_array(element, &ctx->program->normalisation_flags); expected_idx_count = 1 + !!has_control_point + !!is_array; control_point_index = !!is_array; @@ -10639,7 +12186,7 @@ static void vsir_validate_descriptor_indices(struct validation_context *ctx, validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL indirect address for the ID of a register of type \"%s\".", name); - if (!ctx->program->has_descriptor_info) + if (!ctx->program->normalisation_flags.has_descriptor_info) return; if (!(descriptor = vkd3d_shader_find_descriptor(&ctx->program->descriptors, type, reg->idx[0].offset))) @@ -10817,8 +12364,7 @@ static void vsir_validate_ssa_register(struct validation_context *ctx, } } -static void vsir_validate_src_param(struct validation_context *ctx, - const struct vkd3d_shader_src_param *src); +static void vsir_validate_src_operand(struct validation_context *ctx, const struct vsir_src_operand *src); static void vsir_validate_register(struct validation_context *ctx, const struct vkd3d_shader_register *reg) @@ -10871,12 +12417,13 @@ static void vsir_validate_register(struct validation_context *ctx, for (i = 0; i < min(reg->idx_count, ARRAY_SIZE(reg->idx)); ++i) { - const struct vkd3d_shader_src_param *param = reg->idx[i].rel_addr; - if (param) + const struct vsir_src_operand *src; + + if ((src = reg->idx[i].rel_addr)) { - vsir_validate_src_param(ctx, param); + vsir_validate_src_operand(ctx, src); - switch (param->reg.type) + switch (src->reg.type) { case VKD3DSPR_TEMP: case VKD3DSPR_SSA: @@ -10888,7 +12435,7 @@ static void vsir_validate_register(struct validation_context *ctx, default: validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, "Invalid register type %#x for a relative address parameter.", - param->reg.type); + src->reg.type); break; } } @@ -11011,8 +12558,7 @@ static void vsir_validate_register(struct validation_context *ctx, reg->dimension, reg->type, validation_data->dimension); } -static void vsir_validate_io_dst_param(struct validation_context *ctx, - const struct vkd3d_shader_dst_param *dst) +static void vsir_validate_io_dst_operand(struct validation_context *ctx, const struct vsir_dst_operand *dst) { struct vsir_io_register_data io_reg_data; const struct signature_element *e; @@ -11045,8 +12591,7 @@ static void vsir_validate_io_dst_param(struct validation_context *ctx, } } -static void vsir_validate_dst_param(struct validation_context *ctx, - const struct vkd3d_shader_dst_param *dst) +static void vsir_validate_dst_operand(struct validation_context *ctx, const struct vsir_dst_operand *dst) { const struct vkd3d_shader_version *version = &ctx->program->shader_version; @@ -11076,7 +12621,7 @@ static void vsir_validate_dst_param(struct validation_context *ctx, break; } - if (dst->modifiers & ~VKD3DSPDM_MASK || (ctx->program->has_no_modifiers && dst->modifiers)) + if (dst->modifiers & ~VKD3DSPDM_MASK || (ctx->program->normalisation_flags.has_no_modifiers && dst->modifiers)) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Destination has invalid modifiers %#x.", dst->modifiers); @@ -11160,23 +12705,23 @@ static void vsir_validate_dst_param(struct validation_context *ctx, break; case VKD3DSPR_INPUT: - vsir_validate_io_dst_param(ctx, dst); + vsir_validate_io_dst_operand(ctx, dst); break; case VKD3DSPR_OUTPUT: - vsir_validate_io_dst_param(ctx, dst); + vsir_validate_io_dst_operand(ctx, dst); break; case VKD3DSPR_INCONTROLPOINT: - vsir_validate_io_dst_param(ctx, dst); + vsir_validate_io_dst_operand(ctx, dst); break; case VKD3DSPR_OUTCONTROLPOINT: - vsir_validate_io_dst_param(ctx, dst); + vsir_validate_io_dst_operand(ctx, dst); break; case VKD3DSPR_PATCHCONST: - vsir_validate_io_dst_param(ctx, dst); + vsir_validate_io_dst_operand(ctx, dst); break; case VKD3DSPR_TEXTURE: @@ -11189,8 +12734,7 @@ static void vsir_validate_dst_param(struct validation_context *ctx, } } -static void vsir_validate_io_src_param(struct validation_context *ctx, - const struct vkd3d_shader_src_param *src) +static void vsir_validate_io_src_operand(struct validation_context *ctx, const struct vsir_src_operand *src) { struct vsir_io_register_data io_reg_data; @@ -11209,8 +12753,7 @@ static void vsir_validate_io_src_param(struct validation_context *ctx, #define U32_BIT (1u << VSIR_DATA_U32) #define U16_BIT (1u << VSIR_DATA_U16) -static void vsir_validate_src_param(struct validation_context *ctx, - const struct vkd3d_shader_src_param *src) +static void vsir_validate_src_operand(struct validation_context *ctx, const struct vsir_src_operand *src) { static const struct { @@ -11257,7 +12800,7 @@ static void vsir_validate_src_param(struct validation_context *ctx, validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SWIZZLE, "Immediate constant source has invalid swizzle %#x.", src->swizzle); - if (src->modifiers >= VKD3DSPSM_COUNT || (ctx->program->has_no_modifiers && src->modifiers)) + if (src->modifiers >= VKD3DSPSM_COUNT || (ctx->program->normalisation_flags.has_no_modifiers && src->modifiers)) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Source has invalid modifiers %#x.", src->modifiers); @@ -11291,23 +12834,23 @@ static void vsir_validate_src_param(struct validation_context *ctx, break; case VKD3DSPR_INPUT: - vsir_validate_io_src_param(ctx, src); + vsir_validate_io_src_operand(ctx, src); break; case VKD3DSPR_OUTPUT: - vsir_validate_io_src_param(ctx, src); + vsir_validate_io_src_operand(ctx, src); break; case VKD3DSPR_INCONTROLPOINT: - vsir_validate_io_src_param(ctx, src); + vsir_validate_io_src_operand(ctx, src); break; case VKD3DSPR_OUTCONTROLPOINT: - vsir_validate_io_src_param(ctx, src); + vsir_validate_io_src_operand(ctx, src); break; case VKD3DSPR_PATCHCONST: - vsir_validate_io_src_param(ctx, src); + vsir_validate_io_src_operand(ctx, src); break; default: @@ -12829,7 +14372,7 @@ static void vsir_validate_label(struct validation_context *ctx, const struct vkd 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_validate_src_count(ctx, instruction, ctx->program->normalisation_level >= VSIR_NORMALISED_SM4 ? 0 : 2); vsir_validator_push_block(ctx, VSIR_OP_LOOP); } @@ -13157,10 +14700,14 @@ static void vsir_validate_instruction(struct validation_context *ctx, size_t i; for (i = 0; i < instruction->dst_count; ++i) - vsir_validate_dst_param(ctx, &instruction->dst[i]); + { + vsir_validate_dst_operand(ctx, &instruction->dst[i]); + } for (i = 0; i < instruction->src_count; ++i) - vsir_validate_src_param(ctx, &instruction->src[i]); + { + vsir_validate_src_operand(ctx, &instruction->src[i]); + } if (instruction->opcode >= VSIR_OP_INVALID) { @@ -13407,6 +14954,8 @@ static void vsir_transform_( if ((ctx->result = step(ctx->program, ctx)) < 0) { WARN("Transformation \"%s\" failed with result %d.\n", step_name, ctx->result); + if (TRACE_ON()) + vsir_program_trace(ctx->program); return; } @@ -13414,6 +14963,8 @@ static void vsir_transform_( ctx->compile_info->source_name, ctx->message_context)) < 0) { WARN("Validation failed with result %d after transformation \"%s\".\n", ctx->result, step_name); + if (TRACE_ON()) + vsir_program_trace(ctx->program); return; } } @@ -13791,18 +15342,18 @@ static enum vkd3d_result vsir_program_dce(struct vsir_program *program, for (unsigned int j = 0; j < ins->dst_count; ++j) { - struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + struct vsir_dst_operand *dst = &ins->dst[j]; if (dst->reg.type == VKD3DSPR_SSA && !tracker.ssa_regs[dst->reg.idx[0].offset].last_read) { - vsir_dst_param_init_null(dst); + vsir_dst_operand_init_null(dst); ctx->progress = true; } else if (dst->reg.type == VKD3DSPR_TEMP && tracker.temp_regs[dst->reg.idx[0].offset].last_read <= i && !(program->shader_version.major == 1 && dst->reg.idx[0].offset == 0)) { - vsir_dst_param_init_null(dst); + vsir_dst_operand_init_null(dst); ctx->progress = true; } else if (dst->reg.type != VKD3DSPR_NULL) @@ -13936,6 +15487,8 @@ static bool is_read_only(const struct vsir_program *program, enum vkd3d_shader_r static bool can_propagate_ssa_source(const struct vsir_program *program, const struct vkd3d_shader_instruction *ins) { + enum vsir_data_type dst_data_type, src_data_type; + if (ins->opcode != VSIR_OP_MOV) return false; /* TODO: Propagate copies for other register types. */ @@ -13944,6 +15497,11 @@ static bool can_propagate_ssa_source(const struct vsir_program *program, const s if (ins->dst[0].modifiers || ins->dst[0].shift) return false; + dst_data_type = ins->dst[0].reg.data_type; + src_data_type = ins->src[0].reg.data_type; + if (data_type_is_64_bit(dst_data_type) != data_type_is_64_bit(src_data_type)) + return false; + /* TODO: We can perform copy-prop for read-write register types, but we * have to be sure that the register wasn't modified between the two * instructions. */ @@ -13985,9 +15543,9 @@ static enum vkd3d_result vsir_program_copy_propagation(struct vsir_program *prog { for (unsigned int j = 0; j < ins->src_count; ++j) { - struct vkd3d_shader_src_param *src = &ins->src[j]; - const struct vkd3d_shader_src_param *mov_src; + struct vsir_src_operand *src = &ins->src[j]; const struct vkd3d_shader_instruction *mov; + const struct vsir_src_operand *mov_src; enum vsir_data_type data_type; uint32_t new_swizzle = 0; @@ -14020,6 +15578,10 @@ static enum vkd3d_result vsir_program_copy_propagation(struct vsir_program *prog } if (mov_src->reg.type != VKD3DSPR_IMMCONST) src->swizzle = new_swizzle; + else if (mov_src->reg.dimension == VSIR_DIMENSION_VEC4) + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; + else + src->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); if (src->modifiers == VKD3DSPSM_NONE) src->modifiers = mov_src->modifiers; @@ -14042,22 +15604,26 @@ static enum vkd3d_result vsir_program_copy_propagation(struct vsir_program *prog return VKD3D_OK; } +static void vsir_optimize(struct vsir_transformation_context *ctx) +{ + do + { + ctx->progress = false; + vsir_transform(ctx, vsir_program_copy_propagation); + vsir_transform(ctx, vsir_program_dce); + } + while (ctx->progress); +} + enum vkd3d_result vsir_program_optimize(struct vsir_program *program, uint64_t config_flags, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) { struct vsir_transformation_context ctx; vsir_transformation_context_init(&ctx, program, config_flags, compile_info, message_context); + vsir_optimize(&ctx); - do - { - ctx.progress = false; - vsir_transform(&ctx, vsir_program_copy_propagation); - vsir_transform(&ctx, vsir_program_dce); - } - while (ctx.progress); - - if (TRACE_ON()) + if (TRACE_ON() && ctx.result >= 0) vsir_program_trace(program); return ctx.result; @@ -14095,6 +15661,7 @@ enum vkd3d_result vsir_program_lower_d3dbc(struct vsir_program *program, uint64_ struct vsir_transformation_context ctx; vsir_transformation_context_init(&ctx, program, config_flags, compile_info, message_context); + vsir_transform(&ctx, vsir_program_lower_d3dbc_loops); vsir_transform(&ctx, vsir_program_lower_d3dbc_instructions); if (program->shader_version.major == 1 && program->shader_version.type == VKD3D_SHADER_TYPE_PIXEL) @@ -14105,7 +15672,7 @@ enum vkd3d_result vsir_program_lower_d3dbc(struct vsir_program *program, uint64_ vsir_transform(&ctx, vsir_program_normalise_ps1_output); } - if (TRACE_ON()) + if (TRACE_ON() && ctx.result >= 0) vsir_program_trace(program); return ctx.result; @@ -14125,6 +15692,9 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t vsir_transform(&ctx, vsir_program_materialise_phi_ssas_to_temps); vsir_transform(&ctx, vsir_program_lower_switch_to_selection_ladder); vsir_transform(&ctx, vsir_program_structurize); + + vsir_optimize(&ctx); + if (compile_info->target_type != VKD3D_SHADER_TARGET_MSL) { vsir_transform(&ctx, vsir_program_flatten_control_flow_constructs); @@ -14150,6 +15720,9 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t vsir_transform(&ctx, instruction_array_normalise_hull_shader_control_point_io); vsir_transform(&ctx, vsir_program_normalise_io_registers); vsir_transform(&ctx, vsir_program_normalise_flat_constants); + + vsir_optimize(&ctx); + vsir_transform(&ctx, vsir_program_remove_dead_code); if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL @@ -14160,13 +15733,14 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t vsir_transform(&ctx, vsir_program_apply_flat_interpolation); vsir_transform(&ctx, vsir_program_insert_alpha_test); vsir_transform(&ctx, vsir_program_insert_clip_planes); + vsir_transform(&ctx, vsir_program_normalise_clip_cull); vsir_transform(&ctx, vsir_program_insert_point_size); vsir_transform(&ctx, vsir_program_insert_point_size_clamp); vsir_transform(&ctx, vsir_program_insert_point_coord); vsir_transform(&ctx, vsir_program_insert_fragment_fog); vsir_transform(&ctx, vsir_program_insert_vertex_fog); - if (TRACE_ON()) + if (TRACE_ON() && ctx.result >= 0) vsir_program_trace(program); return ctx.result; diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c index d34133d6d4c..2049871752c 100644 --- a/libs/vkd3d/libs/vkd3d-shader/msl.c +++ b/libs/vkd3d/libs/vkd3d-shader/msl.c @@ -34,7 +34,7 @@ struct msl_src struct msl_dst { - const struct vkd3d_shader_dst_param *vsir; + const struct vsir_dst_operand *vsir; struct vkd3d_string_buffer *register_name; struct vkd3d_string_buffer *mask; }; @@ -71,7 +71,7 @@ struct msl_resource_type_info }; static void msl_print_subscript(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, - const struct vkd3d_shader_src_param *rel_addr, unsigned int offset); + const struct vsir_src_operand *rel_addr, unsigned int offset); static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen, enum vkd3d_shader_error error, const char *fmt, ...) @@ -554,7 +554,7 @@ static void msl_print_bitcast(struct vkd3d_string_buffer *dst, struct msl_genera } static void msl_print_src_with_type(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, - const struct vkd3d_shader_src_param *vsir_src, uint32_t mask, enum vsir_data_type data_type) + const struct vsir_src_operand *vsir_src, uint32_t mask, enum vsir_data_type data_type) { const struct vkd3d_shader_register *reg = &vsir_src->reg; struct vkd3d_string_buffer *register_name; @@ -573,7 +573,7 @@ static void msl_print_src_with_type(struct vkd3d_string_buffer *buffer, struct m } static void msl_src_init(struct msl_src *msl_src, struct msl_generator *gen, - const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) + const struct vsir_src_operand *vsir_src, uint32_t mask) { msl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); msl_print_src_with_type(msl_src->str, gen, vsir_src, mask, vsir_src->reg.data_type); @@ -586,7 +586,7 @@ static void msl_dst_cleanup(struct msl_dst *dst, struct vkd3d_string_buffer_cach } static uint32_t msl_dst_init(struct msl_dst *msl_dst, struct msl_generator *gen, - const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_dst_param *vsir_dst) + const struct vkd3d_shader_instruction *ins, const struct vsir_dst_operand *vsir_dst) { uint32_t write_mask = vsir_dst->write_mask; enum msl_data_type dst_data_type; @@ -612,7 +612,7 @@ static uint32_t msl_dst_init(struct msl_dst *msl_dst, struct msl_generator *gen, } static void msl_print_subscript(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, - const struct vkd3d_shader_src_param *rel_addr, unsigned int offset) + const struct vsir_src_operand *rel_addr, unsigned int offset) { struct msl_src r; @@ -803,7 +803,7 @@ static void msl_begin_block(struct msl_generator *gen) } static void msl_print_condition(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, - enum vkd3d_shader_conditional_op op, const struct vkd3d_shader_src_param *arg) + enum vkd3d_shader_conditional_op op, const struct vsir_src_operand *arg) { const char *condition; struct msl_src src; @@ -1028,9 +1028,9 @@ static void msl_sample(struct msl_generator *gen, const struct vkd3d_shader_inst { bool bias, compare, comparison_sampler, dynamic_offset, gather, grad, lod, lod_zero, offset; const struct msl_resource_type_info *resource_type_info; - const struct vkd3d_shader_src_param *resource, *sampler; unsigned int resource_id, resource_idx, resource_space; unsigned int sampler_id, sampler_idx, sampler_space; + const struct vsir_src_operand *resource, *sampler; unsigned int srv_binding = 0, sampler_binding = 0; const struct vkd3d_shader_descriptor_info1 *d; enum vkd3d_shader_resource_type resource_type; @@ -2401,8 +2401,8 @@ int msl_compile(struct vsir_program *program, uint64_t config_flags, return ret; VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6); - VKD3D_ASSERT(program->has_descriptor_info); - VKD3D_ASSERT(program->has_no_modifiers); + VKD3D_ASSERT(program->normalisation_flags.has_descriptor_info); + VKD3D_ASSERT(program->normalisation_flags.has_no_modifiers); if ((ret = msl_generator_init(&generator, program, compile_info, message_context)) < 0) return ret; diff --git a/libs/vkd3d/libs/vkd3d-shader/preproc.l b/libs/vkd3d/libs/vkd3d-shader/preproc.l index 8913e57283a..d7130f57c34 100644 --- a/libs/vkd3d/libs/vkd3d-shader/preproc.l +++ b/libs/vkd3d/libs/vkd3d-shader/preproc.l @@ -211,6 +211,21 @@ INT_SUFFIX [uUlL]{0,2} %% +static void preproc_func_state_cleanup_arg_values(struct preproc_func_state *f) +{ + const struct preproc_macro *m; + size_t i; + + if (!(m = f->macro)) + return; + + for (i = 0; i < m->arg_count; ++i) + { + vkd3d_string_buffer_cleanup(&f->arg_values[i].text); + } + free(f->arg_values); +} + static void update_location(struct preproc_ctx *ctx) { struct preproc_buffer *buffer = &preproc_get_top_file(ctx)->buffer; @@ -725,6 +740,12 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) case '}': if (!--func_state->paren_depth) { + /* Not only can you end a macro with ] or }, if + * you do, it's treated as part of the last + * argument. */ + if (token != ')' && current_arg) + preproc_text_add(current_arg, text); + if (++func_state->arg_count == func_state->macro->arg_count) { preproc_push_expansion(ctx, &func_state->macro->body, @@ -740,6 +761,7 @@ int yylex(YYSTYPE *lval, YYLTYPE *lloc, yyscan_t scanner) return return_token(T_IDENTIFIER, lval, func_state->macro->name); vkd3d_string_buffer_printf(&ctx->buffer, "%s ", func_state->macro->name); + preproc_func_state_cleanup_arg_values(func_state); } func_state->macro = NULL; func_state->state = STATE_NONE; @@ -821,6 +843,7 @@ int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) { static const struct vkd3d_shader_preprocess_info default_preprocess_info = {0}; + struct vkd3d_shader_location loc = {0}; struct preproc_ctx ctx = {0}; char *source_name = NULL; unsigned int i; @@ -831,12 +854,12 @@ int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, ctx.preprocess_info = &default_preprocess_info; ctx.message_context = message_context; - if (!(source_name = vkd3d_strdup(compile_info->source_name ? compile_info->source_name : "<anonymous>"))) + loc.source_name = compile_info->source_name ? compile_info->source_name : "<anonymous>"; + if (!(source_name = vkd3d_strdup(loc.source_name))) goto fail; for (i = 0; i < ctx.preprocess_info->macro_count; ++i) { - const struct vkd3d_shader_location loc = {.source_name = source_name}; struct vkd3d_string_buffer body; char *name; @@ -870,20 +893,16 @@ int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, break; case STATE_ARGS: - { - const struct vkd3d_shader_location loc = {.source_name = source_name}; - preproc_warning(&ctx, &loc, VKD3D_SHADER_WARNING_PP_UNTERMINATED_MACRO, "Unterminated macro invocation."); - } /* fall through */ - case STATE_IDENTIFIER: if (preproc_is_writing(&ctx)) vkd3d_string_buffer_printf(&ctx.buffer, "%s ", ctx.text_func.macro->name); break; } + preproc_func_state_cleanup_arg_values(&ctx.text_func); while (ctx.file_count) preproc_pop_buffer(&ctx); yylex_destroy(ctx.scanner); diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c index 0d260d63542..dd62f34eb08 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -38,7 +38,7 @@ #define VKD3D_SPIRV_VERSION_1_0 0x00010000 #define VKD3D_SPIRV_VERSION_1_3 0x00010300 #define VKD3D_SPIRV_GENERATOR_ID 18 -#define VKD3D_SPIRV_GENERATOR_VERSION 18 +#define VKD3D_SPIRV_GENERATOR_VERSION 19 #define VKD3D_SPIRV_GENERATOR_MAGIC vkd3d_make_u32(VKD3D_SPIRV_GENERATOR_VERSION, VKD3D_SPIRV_GENERATOR_ID) #ifndef VKD3D_SHADER_UNSUPPORTED_SPIRV_PARSER # define VKD3D_SHADER_UNSUPPORTED_SPIRV_PARSER 0 @@ -2972,7 +2972,6 @@ struct spirv_compiler { uint32_t id; enum vsir_data_type data_type; - uint32_t array_element_mask; } *output_info; uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */ uint32_t private_output_variable_write_mask[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */ @@ -3019,16 +3018,6 @@ static bool is_in_default_phase(const struct spirv_compiler *compiler) return compiler->phase == VSIR_OP_INVALID; } -static bool is_in_control_point_phase(const struct spirv_compiler *compiler) -{ - return compiler->phase == VSIR_OP_HS_CONTROL_POINT_PHASE; -} - -static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler) -{ - return compiler->phase == VSIR_OP_HS_FORK_PHASE || compiler->phase == VSIR_OP_HS_JOIN_PHASE; -} - static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler); static size_t spirv_compiler_get_current_function_location(struct spirv_compiler *compiler); static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler); @@ -3764,7 +3753,7 @@ static uint32_t spirv_compiler_get_type_id_for_reg(struct spirv_compiler *compil } static uint32_t spirv_compiler_get_type_id_for_dst(struct spirv_compiler *compiler, - const struct vkd3d_shader_dst_param *dst) + const struct vsir_dst_operand *dst) { return spirv_compiler_get_type_id_for_reg(compiler, &dst->reg, dst->write_mask); } @@ -4117,7 +4106,7 @@ static uint32_t spirv_compiler_emit_construct_vector(struct spirv_compiler *comp } static uint32_t spirv_compiler_emit_load_src(struct spirv_compiler *compiler, - const struct vkd3d_shader_src_param *src, uint32_t write_mask); + const struct vsir_src_operand *src, uint32_t write_mask); static uint32_t spirv_compiler_emit_register_addressing(struct spirv_compiler *compiler, const struct vkd3d_shader_register_index *reg_index) @@ -4827,19 +4816,19 @@ static void spirv_compiler_emit_execution_mode1(struct spirv_compiler *compiler, } static uint32_t spirv_compiler_emit_load_src(struct spirv_compiler *compiler, - const struct vkd3d_shader_src_param *src, uint32_t write_mask) + const struct vsir_src_operand *src, uint32_t write_mask) { return spirv_compiler_emit_load_reg(compiler, &src->reg, src->swizzle, write_mask); } static uint32_t spirv_compiler_emit_load_src_with_type(struct spirv_compiler *compiler, - const struct vkd3d_shader_src_param *src, uint32_t write_mask, enum vsir_data_type data_type) + const struct vsir_src_operand *src, uint32_t write_mask, enum vsir_data_type data_type) { - struct vkd3d_shader_src_param src_param = *src; + struct vsir_src_operand src_operand = *src; - src_param.reg.data_type = data_type; + src_operand.reg.data_type = data_type; - return spirv_compiler_emit_load_src(compiler, &src_param, write_mask); + return spirv_compiler_emit_load_src(compiler, &src_operand, write_mask); } static void spirv_compiler_emit_store_scalar(struct spirv_compiler *compiler, @@ -4981,15 +4970,15 @@ static uint32_t spirv_compiler_emit_sat(struct spirv_compiler *compiler, } static void spirv_compiler_emit_store_dst(struct spirv_compiler *compiler, - const struct vkd3d_shader_dst_param *dst, uint32_t val_id) + const struct vsir_dst_operand *dst, uint32_t val_id) { spirv_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id); } static void spirv_compiler_emit_store_dst_swizzled(struct spirv_compiler *compiler, - const struct vkd3d_shader_dst_param *dst, uint32_t val_id, enum vsir_data_type data_type, uint32_t swizzle) + const struct vsir_dst_operand *dst, uint32_t val_id, enum vsir_data_type data_type, uint32_t swizzle) { - struct vkd3d_shader_dst_param typed_dst = *dst; + struct vsir_dst_operand typed_dst = *dst; val_id = spirv_compiler_emit_swizzle(compiler, val_id, VKD3DSP_WRITEMASK_ALL, data_type, swizzle, dst->write_mask); @@ -5000,7 +4989,7 @@ static void spirv_compiler_emit_store_dst_swizzled(struct spirv_compiler *compil } static void spirv_compiler_emit_store_dst_components(struct spirv_compiler *compiler, - const struct vkd3d_shader_dst_param *dst, enum vsir_data_type data_type, uint32_t *component_ids) + const struct vsir_dst_operand *dst, enum vsir_data_type data_type, uint32_t *component_ids) { unsigned int component_count = vsir_write_mask_component_count(dst->write_mask); struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; @@ -5020,7 +5009,7 @@ static void spirv_compiler_emit_store_dst_components(struct spirv_compiler *comp } static void spirv_compiler_emit_store_dst_scalar(struct spirv_compiler *compiler, - const struct vkd3d_shader_dst_param *dst, uint32_t val_id, enum vsir_data_type data_type, uint32_t swizzle) + const struct vsir_dst_operand *dst, uint32_t val_id, enum vsir_data_type data_type, uint32_t swizzle) { unsigned int component_count = vsir_write_mask_component_count(dst->write_mask); uint32_t component_ids[VKD3D_VEC4_SIZE]; @@ -5462,7 +5451,8 @@ static const struct vkd3d_shader_phase *spirv_compiler_get_current_shader_phase( if (is_in_default_phase(compiler)) return NULL; - return is_in_control_point_phase(compiler) ? &compiler->control_point_phase : &compiler->patch_constant_phase; + return vsir_opcode_is_control_point_phase(compiler->phase) + ? &compiler->control_point_phase : &compiler->patch_constant_phase; } static void spirv_compiler_decorate_xfb_output(struct spirv_compiler *compiler, @@ -5561,31 +5551,21 @@ static bool needs_private_io_variable(const struct vkd3d_spirv_builtin *builtin) return builtin && builtin->fixup_pfn; } -static unsigned int shader_signature_next_location(const struct shader_signature *signature) -{ - unsigned int i, max_row; - - if (!signature) - return 0; - - for (i = 0, max_row = 0; i < signature->element_count; ++i) - max_row = max(max_row, signature->elements[i].register_index + signature->elements[i].register_count); - return max_row; -} - static const struct vkd3d_symbol *spirv_compiler_emit_io_register(struct spirv_compiler *compiler, - const struct vkd3d_shader_dst_param *dst) + const struct vsir_dst_operand *dst) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_register *reg = &dst->reg; const struct vkd3d_spirv_builtin *builtin; struct vkd3d_symbol reg_symbol; SpvStorageClass storage_class; + unsigned int array_size; uint32_t write_mask, id; struct rb_entry *entry; - VKD3D_ASSERT(!reg->idx_count || !reg->idx[0].rel_addr); - VKD3D_ASSERT(reg->idx_count < 2); + VKD3D_ASSERT(reg->idx_count < 1 || !reg->idx[0].rel_addr); + VKD3D_ASSERT(reg->idx_count < 2 || !reg->idx[1].rel_addr); + VKD3D_ASSERT(reg->idx_count < 3); if (reg->type == VKD3DSPR_RASTOUT && reg->idx[0].offset == VSIR_RASTOUT_POINT_SIZE) { @@ -5603,7 +5583,8 @@ static const struct vkd3d_symbol *spirv_compiler_emit_io_register(struct spirv_c if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); - id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, 0); + array_size = (reg->idx_count > 1) ? reg->idx[0].offset : 0; + id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, array_size); spirv_compiler_emit_register_execution_mode(compiler, reg->type); spirv_compiler_emit_register_debug_name(builder, id, reg); @@ -5650,10 +5631,10 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler, sysval_reg_type = vsir_register_type_from_sysval_input(signature_element->sysval_semantic); if (sysval_reg_type != VKD3DSPR_INPUT) { - struct vkd3d_shader_dst_param dst; const struct vkd3d_symbol *symbol; + struct vsir_dst_operand dst; - vsir_dst_param_init(&dst, sysval_reg_type, VSIR_DATA_F32, 0); + vsir_dst_operand_init(&dst, sysval_reg_type, VSIR_DATA_F32, 0); symbol = spirv_compiler_emit_io_register(compiler, &dst); vkd3d_symbol_make_io(®_symbol, reg_type, element_idx); @@ -5667,11 +5648,8 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler, array_sizes[0] = signature_element->register_count; array_sizes[1] = (reg_type == VKD3DSPR_PATCHCONST ? 0 : compiler->input_control_point_count); - if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic) - && (!vsir_sysval_semantic_is_clip_cull(signature_element->sysval_semantic) || array_sizes[1])) - { + if (!vsir_signature_element_is_array(signature_element, &compiler->program->normalisation_flags)) array_sizes[0] = 0; - } write_mask = signature_element->mask; @@ -5708,7 +5686,7 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler, * duplicate declarations are: a single register split into multiple declarations having * different components, which should have been merged, and declarations in one phase * being repeated in another (i.e. vcp/vocp), which should have been deleted. */ - if (reg_type != VKD3DSPR_INPUT || !is_in_fork_or_join_phase(compiler)) + if (reg_type != VKD3DSPR_INPUT || !vsir_opcode_is_fork_or_join_phase(compiler->phase)) FIXME("Duplicate input definition found.\n"); return; } @@ -5729,7 +5707,7 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler, if (reg_type == VKD3DSPR_PATCHCONST) { vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0); - location += shader_signature_next_location(&compiler->program->input_signature); + location += vsir_signature_next_location(&compiler->program->input_signature); } vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, location); if (component_idx) @@ -5803,88 +5781,6 @@ static bool is_dual_source_blending(const struct spirv_compiler *compiler) return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && info && info->dual_source_blending; } -static void calculate_clip_or_cull_distance_mask(const struct signature_element *e, uint32_t *mask) -{ - unsigned int write_mask; - - if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE) - { - FIXME("Invalid semantic index %u for clip/cull distance.\n", e->semantic_index); - return; - } - - write_mask = e->mask; - *mask |= (write_mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index); -} - -/* Emits arrayed SPIR-V built-in variables. */ -static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *compiler) -{ - const struct shader_signature *output_signature = &compiler->program->output_signature; - uint32_t clip_distance_mask = 0, clip_distance_id = 0; - uint32_t cull_distance_mask = 0, cull_distance_id = 0; - const struct vkd3d_spirv_builtin *builtin; - unsigned int i, count; - - for (i = 0; i < output_signature->element_count; ++i) - { - const struct signature_element *e = &output_signature->elements[i]; - - switch (e->sysval_semantic) - { - case VKD3D_SHADER_SV_CLIP_DISTANCE: - calculate_clip_or_cull_distance_mask(e, &clip_distance_mask); - break; - - case VKD3D_SHADER_SV_CULL_DISTANCE: - calculate_clip_or_cull_distance_mask(e, &cull_distance_mask); - break; - - default: - break; - } - } - - if (clip_distance_mask) - { - count = vkd3d_popcount(clip_distance_mask); - builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SHADER_SV_CLIP_DISTANCE); - clip_distance_id = spirv_compiler_emit_builtin_variable(compiler, - builtin, SpvStorageClassOutput, count); - } - - if (cull_distance_mask) - { - count = vkd3d_popcount(cull_distance_mask); - builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SHADER_SV_CULL_DISTANCE); - cull_distance_id = spirv_compiler_emit_builtin_variable(compiler, - builtin, SpvStorageClassOutput, count); - } - - for (i = 0; i < output_signature->element_count; ++i) - { - const struct signature_element *e = &output_signature->elements[i]; - - switch (e->sysval_semantic) - { - case VKD3D_SHADER_SV_CLIP_DISTANCE: - compiler->output_info[i].id = clip_distance_id; - compiler->output_info[i].data_type = VSIR_DATA_F32; - compiler->output_info[i].array_element_mask = clip_distance_mask; - break; - - case VKD3D_SHADER_SV_CULL_DISTANCE: - compiler->output_info[i].id = cull_distance_id; - compiler->output_info[i].data_type = VSIR_DATA_F32; - compiler->output_info[i].array_element_mask = cull_distance_mask; - break; - - default: - break; - } - } -} - static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_compiler *compiler, const struct vkd3d_spirv_builtin *builtin, const unsigned int *array_sizes, unsigned int size_count) { @@ -5902,7 +5798,7 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c return *variable_id; id = spirv_compiler_emit_builtin_variable_v(compiler, builtin, SpvStorageClassOutput, array_sizes, size_count); - if (is_in_fork_or_join_phase(compiler)) + if (vsir_opcode_is_fork_or_join_phase(compiler->phase)) vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationPatch, NULL, 0); if (variable_id) @@ -5940,7 +5836,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, sysval = VKD3D_SHADER_SV_NONE; array_sizes[0] = signature_element->register_count; array_sizes[1] = (reg_type == VKD3DSPR_PATCHCONST ? 0 : compiler->output_control_point_count); - if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic)) + if (!vsir_signature_element_is_array(signature_element, &compiler->program->normalisation_flags)) array_sizes[0] = 0; builtin = vkd3d_get_spirv_builtin(compiler, reg_type, sysval); @@ -5966,8 +5862,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, use_private_variable = true; if (!is_patch_constant - && (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE - || (compiler->output_info[element_idx].id && compiler->output_info[element_idx].array_element_mask))) + && get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE) { use_private_variable = true; } @@ -6005,7 +5900,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, unsigned int location = signature_element->target_location; if (is_patch_constant) - location += shader_signature_next_location(&compiler->program->output_signature); + location += vsir_signature_next_location(&compiler->program->output_signature); else if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && signature_element->sysval_semantic == VKD3D_SHADER_SV_TARGET) location = signature_element->semantic_index; @@ -6066,36 +5961,18 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, } } -static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *compiler, - const struct signature_element *e) -{ - enum vkd3d_shader_sysval_semantic sysval = e->sysval_semantic; - const struct vkd3d_spirv_builtin *builtin; - - builtin = get_spirv_builtin_for_sysval(compiler, sysval); - - switch (sysval) - { - case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: - case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET: - return builtin->member_idx; - default: - return e->semantic_index; - } -} - static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compiler, const struct shader_signature *signature, const struct signature_element *output, const struct vkd3d_shader_output_info *output_info, uint32_t output_index_id, uint32_t val_id, uint32_t write_mask) { - uint32_t dst_write_mask, use_mask, uninit_mask, swizzle, mask; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id; + uint32_t dst_write_mask, use_mask, uninit_mask, swizzle; const struct signature_element *element; - unsigned int i, index, array_idx; + uint32_t type_id, zero_id, ptr_type_id; enum vsir_data_type data_type; uint32_t output_id; + unsigned int i; dst_write_mask = output->mask; use_mask = output->used_mask; @@ -6149,31 +6026,8 @@ static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compi output_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, output_id, output_index_id); } - if (!output_info->array_element_mask) - { - spirv_compiler_emit_store(compiler, output_id, dst_write_mask, - data_type, SpvStorageClassOutput, write_mask, val_id); - return; - } - - type_id = spirv_get_type_id(compiler, data_type, 1); - ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id); - mask = output_info->array_element_mask; - array_idx = spirv_compiler_get_output_array_index(compiler, output); - mask &= (1u << (array_idx * VKD3D_VEC4_SIZE)) - 1; - for (i = 0, index = vkd3d_popcount(mask); i < VKD3D_VEC4_SIZE; ++i) - { - if (!(write_mask & (VKD3DSP_WRITEMASK_0 << i))) - continue; - - chain_id = vkd3d_spirv_build_op_access_chain1(builder, - ptr_type_id, output_id, spirv_compiler_get_constant_uint(compiler, index)); - object_id = spirv_compiler_emit_swizzle(compiler, val_id, write_mask, - data_type, VKD3D_SHADER_NO_SWIZZLE, VKD3DSP_WRITEMASK_0 << i); - spirv_compiler_emit_store(compiler, chain_id, VKD3DSP_WRITEMASK_0, data_type, - SpvStorageClassOutput, VKD3DSP_WRITEMASK_0 << i, object_id); - ++index; - } + spirv_compiler_emit_store(compiler, output_id, dst_write_mask, + data_type, SpvStorageClassOutput, write_mask, val_id); } static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler *compiler) @@ -6190,7 +6044,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(param_type_id)); STATIC_ASSERT(ARRAY_SIZE(compiler->private_output_variable) == ARRAY_SIZE(compiler->private_output_variable_write_mask)); - is_patch_constant = is_in_fork_or_join_phase(compiler); + is_patch_constant = vsir_opcode_is_fork_or_join_phase(compiler->phase); signature = is_patch_constant ? &compiler->program->patch_constant_signature : &compiler->program->output_signature; @@ -6224,7 +6078,7 @@ static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler * param_id[i] = vkd3d_spirv_build_op_load(builder, type_id, param_id[i], SpvMemoryAccessMaskNone); } - if (is_in_control_point_phase(compiler)) + if (vsir_opcode_is_control_point_phase(compiler->phase)) output_index_id = spirv_compiler_emit_load_invocation_id(compiler); for (i = 0; i < signature->element_count; ++i) @@ -7259,7 +7113,7 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler) vkd3d_spirv_build_op_function_end(builder); - if (is_in_control_point_phase(compiler)) + if (vsir_opcode_is_control_point_phase(compiler->phase)) { if (compiler->epilogue_function_id) { @@ -7296,8 +7150,8 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, compiler->phase = instruction->opcode; spirv_compiler_emit_shader_phase_name(compiler, function_id, NULL); - phase = (instruction->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE) - ? &compiler->control_point_phase : &compiler->patch_constant_phase; + phase = vsir_opcode_is_control_point_phase(instruction->opcode) + ? &compiler->control_point_phase : &compiler->patch_constant_phase; phase->function_id = function_id; /* The insertion location must be set after the label is emitted. */ phase->function_location = 0; @@ -7310,8 +7164,8 @@ static void spirv_compiler_initialise_block(struct spirv_compiler *compiler) /* Insertion locations must point immediately after the function's initial label. */ if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) { - struct vkd3d_shader_phase *phase = (compiler->phase == VSIR_OP_HS_CONTROL_POINT_PHASE) - ? &compiler->control_point_phase : &compiler->patch_constant_phase; + struct vkd3d_shader_phase *phase = vsir_opcode_is_control_point_phase(compiler->phase) + ? &compiler->control_point_phase : &compiler->patch_constant_phase; if (!phase->function_location) phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); } @@ -7477,8 +7331,8 @@ static SpvOp spirv_compiler_map_logical_instruction(const struct vkd3d_shader_in static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t val_id; VKD3D_ASSERT(src->reg.data_type == VSIR_DATA_BOOL && dst->reg.data_type != VSIR_DATA_BOOL); @@ -7516,8 +7370,8 @@ static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compil const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t src_ids[SPIRV_MAX_SRC_COUNT]; uint32_t type_id, val_id; SpvOp op = SpvOpMax; @@ -7596,8 +7450,8 @@ static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compil static void spirv_compiler_emit_saturate(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t val_id; val_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask); @@ -7609,8 +7463,8 @@ static void spirv_compiler_emit_isfinite(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, src_id, isinf_id, isnan_id, val_id; type_id = spirv_compiler_get_type_id_for_dst(compiler, dst); @@ -7681,8 +7535,8 @@ static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *comp { uint32_t instr_set_id, type_id, val_id, rev_val_id, uint_max_id, condition_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t src_id[SPIRV_MAX_SRC_COUNT]; unsigned int i, component_count; enum GLSLstd450 glsl_inst; @@ -7741,8 +7595,8 @@ static void spirv_compiler_emit_mov(struct spirv_compiler *compiler, uint32_t val_id, dst_val_id, type_id, dst_id, src_id, write_mask32, swizzle32; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_shader_register_info dst_reg_info, src_reg_info; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; unsigned int i, component_count, write_mask; uint32_t components[VKD3D_VEC4_SIZE]; @@ -7815,9 +7669,9 @@ static void spirv_compiler_emit_movc(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; uint32_t condition_id, src1_id, src2_id, type_id, val_id; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; unsigned int component_count; condition_id = spirv_compiler_emit_load_src(compiler, &src[0], dst->write_mask); @@ -7842,39 +7696,12 @@ static void spirv_compiler_emit_movc(struct spirv_compiler *compiler, spirv_compiler_emit_store_dst(compiler, dst, val_id); } -static void spirv_compiler_emit_swapc(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) -{ - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; - uint32_t condition_id, src1_id, src2_id, type_id, val_id; - unsigned int component_count; - - VKD3D_ASSERT(dst[0].write_mask == dst[1].write_mask); - - condition_id = spirv_compiler_emit_load_src(compiler, &src[0], dst->write_mask); - src1_id = spirv_compiler_emit_load_src(compiler, &src[1], dst->write_mask); - src2_id = spirv_compiler_emit_load_src(compiler, &src[2], dst->write_mask); - - component_count = vsir_write_mask_component_count(dst->write_mask); - type_id = spirv_get_type_id(compiler, VSIR_DATA_F32, component_count); - - condition_id = spirv_compiler_emit_int_to_bool(compiler, - VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, component_count, condition_id); - - val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src2_id, src1_id); - spirv_compiler_emit_store_dst(compiler, &dst[0], val_id); - val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src1_id, src2_id); - spirv_compiler_emit_store_dst(compiler, &dst[1], val_id); -} - static void spirv_compiler_emit_dot(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, val_id, src_ids[2]; unsigned int component_count, i; enum vsir_data_type data_type; @@ -7910,8 +7737,8 @@ static void spirv_compiler_emit_rcp(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, src_id, val_id, div_id; unsigned int component_count; @@ -7931,8 +7758,8 @@ static void spirv_compiler_emit_imad(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, val_id, src_ids[3]; unsigned int i, component_count; @@ -7953,8 +7780,8 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, { uint32_t src_id, int_min_id, int_max_id, zero_id, float_max_id, condition_id, val_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t src_type_id, dst_type_id, condition_type_id; unsigned int component_count; uint32_t write_mask; @@ -8008,8 +7835,8 @@ static void spirv_compiler_emit_ftou(struct spirv_compiler *compiler, { uint32_t src_id, zero_id, uint_max_id, float_max_id, condition_id, val_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t src_type_id, dst_type_id, condition_type_id; unsigned int component_count; uint32_t write_mask; @@ -8056,8 +7883,8 @@ static void spirv_compiler_emit_dtof(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, val_id, src_id; unsigned int component_count; uint32_t write_mask; @@ -8080,8 +7907,8 @@ static void spirv_compiler_emit_bitfield_instruction(struct spirv_compiler *comp { uint32_t src_ids[4], constituents[VKD3D_VEC4_SIZE], type_id, mask_id, size_id, max_count_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; unsigned int i, j, k, src_count, size; enum vsir_data_type data_type; uint32_t write_mask; @@ -8141,8 +7968,8 @@ static void spirv_compiler_emit_f16tof32(struct spirv_compiler *compiler, { uint32_t instr_set_id, type_id, scalar_type_id, src_id, result_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t components[VKD3D_VEC4_SIZE]; uint32_t write_mask; unsigned int i, j; @@ -8173,8 +8000,8 @@ static void spirv_compiler_emit_f32tof16(struct spirv_compiler *compiler, { uint32_t instr_set_id, type_id, scalar_type_id, src_id, zero_id, constituents[2]; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t components[VKD3D_VEC4_SIZE]; uint32_t write_mask; unsigned int i, j; @@ -8207,8 +8034,8 @@ static void spirv_compiler_emit_comparison_instruction(struct spirv_compiler *co const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t src0_id, src1_id, type_id, result_id; uint32_t write_mask = dst->write_mask; unsigned int component_count; @@ -8272,8 +8099,8 @@ static void spirv_compiler_emit_orderedness_instruction(struct spirv_compiler *c const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, src0_id, src1_id, val_id; type_id = spirv_compiler_get_type_id_for_dst(compiler, dst); @@ -8292,8 +8119,8 @@ static void spirv_compiler_emit_float_comparison_instruction(struct spirv_compil const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t src0_id, src1_id, type_id, result_id; unsigned int component_count; SpvOp op; @@ -8322,7 +8149,7 @@ static uint32_t spirv_compiler_emit_conditional_branch(struct spirv_compiler *co const struct vkd3d_shader_instruction *instruction, uint32_t target_block_id) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; uint32_t condition_id, merge_block_id; condition_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0); @@ -8362,7 +8189,7 @@ static void spirv_compiler_emit_return(struct spirv_compiler *compiler, spirv_compiler_end_invocation_interlock(compiler); if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY && (is_in_default_phase(compiler) - || is_in_control_point_phase(compiler))) + || vsir_opcode_is_control_point_phase(compiler->phase))) spirv_compiler_emit_shader_epilogue_invocation(compiler); vkd3d_spirv_build_op_return(builder); @@ -8437,7 +8264,7 @@ static void spirv_compiler_emit_discard(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; uint32_t condition_id, void_id; /* discard is not a block terminator in VSIR, and emitting it as such in SPIR-V would cause @@ -8468,7 +8295,7 @@ static void spirv_compiler_emit_label(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; unsigned int block_id = src->reg.idx[0].offset; uint32_t label_id; @@ -8506,7 +8333,7 @@ static void spirv_compiler_emit_branch(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; uint32_t condition_id; if (vsir_register_is_label(&src[0].reg)) @@ -8549,7 +8376,7 @@ static void spirv_compiler_emit_switch(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; uint32_t val_id, default_id; unsigned int i, word_count; uint32_t *cases; @@ -8590,8 +8417,8 @@ static void spirv_compiler_emit_deriv_instruction(struct spirv_compiler *compile const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; const struct instruction_info *info; uint32_t type_id, src_id, val_id; unsigned int i; @@ -8824,8 +8651,8 @@ static void spirv_compiler_emit_ld(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, coordinate_id, val_id; SpvImageOperandsMask operands_mask = 0; unsigned int image_operand_count = 0; @@ -8870,9 +8697,9 @@ static void spirv_compiler_emit_lod(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; - const struct vkd3d_shader_src_param *resource, *sampler; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; + const struct vsir_src_operand *resource, *sampler; uint32_t type_id, coordinate_id, val_id; struct vkd3d_shader_image image; @@ -8895,10 +8722,10 @@ static void spirv_compiler_emit_sample(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; - const struct vkd3d_shader_src_param *resource, *sampler; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; unsigned int image_operand_count = 0, component_count; + const struct vsir_src_operand *resource, *sampler; uint32_t sampled_type_id, coordinate_id, val_id; SpvImageOperandsMask operands_mask = 0; struct vkd3d_shader_image image; @@ -8965,9 +8792,9 @@ static void spirv_compiler_emit_sample_c(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; uint32_t sampled_type_id, coordinate_id, dref_id, val_id; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; SpvImageOperandsMask operands_mask = 0; unsigned int image_operand_count = 0; struct vkd3d_shader_image image; @@ -9009,11 +8836,11 @@ static void spirv_compiler_emit_sample_c(struct spirv_compiler *compiler, static void spirv_compiler_emit_gather4(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_src_param *addr, *offset, *resource, *sampler; uint32_t sampled_type_id, coordinate_id, component_id, dref_id, val_id; + const struct vsir_src_operand *addr, *offset, *resource, *sampler; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; unsigned int image_flags = VKD3D_IMAGE_FLAG_SAMPLED; unsigned int component_count, component_idx; SpvImageOperandsMask operands_mask = 0; @@ -9080,11 +8907,11 @@ static void spirv_compiler_emit_gather4(struct spirv_compiler *compiler, static uint32_t spirv_compiler_emit_raw_structured_addressing( struct spirv_compiler *compiler, uint32_t type_id, unsigned int stride, - const struct vkd3d_shader_src_param *src0, uint32_t src0_mask, - const struct vkd3d_shader_src_param *src1, uint32_t src1_mask) + const struct vsir_src_operand *src0, uint32_t src0_mask, + const struct vsir_src_operand *src1, uint32_t src1_mask) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_src_param *offset; + const struct vsir_src_operand *offset; uint32_t structure_id = 0, offset_id; uint32_t offset_write_mask; @@ -9112,11 +8939,11 @@ static void spirv_compiler_emit_ld_raw_structured_srv_uav(struct spirv_compiler { uint32_t coordinate_id, type_id, val_id, texel_type_id, ptr_type_id, ptr_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; - const struct vkd3d_shader_src_param *resource; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; const struct vkd3d_symbol *resource_symbol; uint32_t base_coordinate_id, component_idx; + const struct vsir_src_operand *resource; uint32_t constituents[VKD3D_VEC4_SIZE]; struct vkd3d_shader_image image; bool storage_buffer_uav = false; @@ -9199,12 +9026,12 @@ static void spirv_compiler_emit_ld_tgsm(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t coordinate_id, type_id, ptr_type_id, ptr_id; - const struct vkd3d_shader_src_param *resource; struct vkd3d_shader_register_info reg_info; uint32_t base_coordinate_id, component_idx; + const struct vsir_src_operand *resource; uint32_t constituents[VKD3D_VEC4_SIZE]; unsigned int i, j; @@ -9258,11 +9085,11 @@ static void spirv_compiler_emit_store_uav_raw_structured(struct spirv_compiler * { uint32_t coordinate_id, type_id, val_id, data_id, ptr_type_id, ptr_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; const struct vkd3d_symbol *resource_symbol; uint32_t base_coordinate_id, component_idx; - const struct vkd3d_shader_src_param *data; + const struct vsir_src_operand *data; struct vkd3d_shader_image image; unsigned int component_count; uint32_t indices[2]; @@ -9335,11 +9162,11 @@ static void spirv_compiler_emit_store_tgsm(struct spirv_compiler *compiler, { uint32_t coordinate_id, type_id, val_id, ptr_type_id, ptr_id, data_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t base_coordinate_id, component_idx; struct vkd3d_shader_register_info reg_info; - struct vkd3d_shader_src_param data; + struct vsir_src_operand data; unsigned int component_count; if (!spirv_compiler_get_register_info(compiler, &dst->reg, ®_info)) @@ -9392,8 +9219,8 @@ static void spirv_compiler_emit_ld_uav_typed(struct spirv_compiler *compiler, { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t coordinate_id, type_id, val_id, ptr_type_id, ptr_id; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; const struct vkd3d_symbol *resource_symbol; struct vkd3d_shader_image image; uint32_t coordinate_mask; @@ -9434,8 +9261,8 @@ static void spirv_compiler_emit_store_uav_typed(struct spirv_compiler *compiler, { uint32_t coordinate_id, texel_id, type_id, val_id, ptr_type_id, ptr_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; const struct vkd3d_symbol *resource_symbol; struct vkd3d_shader_image image; uint32_t coordinate_mask; @@ -9474,9 +9301,9 @@ static void spirv_compiler_emit_uav_counter_instruction(struct spirv_compiler *c const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; unsigned int memory_semantics = SpvMemorySemanticsMaskNone; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t ptr_type_id, type_id, counter_id, result_id; uint32_t coordinate_id, sample_id, pointer_id; const struct vkd3d_symbol *resource_symbol; @@ -9594,13 +9421,13 @@ static void spirv_compiler_emit_atomic_instruction(struct spirv_compiler *compil const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; const struct vkd3d_symbol *resource_symbol = NULL; uint32_t ptr_type_id, type_id, val_id, result_id; - const struct vkd3d_shader_dst_param *resource; uint32_t coordinate_id, sample_id, pointer_id; struct vkd3d_shader_register_info reg_info; + const struct vsir_dst_operand *resource; struct vkd3d_shader_image image; enum vsir_data_type data_type; unsigned int structure_stride; @@ -9722,8 +9549,8 @@ static void spirv_compiler_emit_bufinfo(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; const struct vkd3d_symbol *resource_symbol; uint32_t type_id, val_id, stride_id; struct vkd3d_shader_image image; @@ -9774,8 +9601,8 @@ static void spirv_compiler_emit_resinfo(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, lod_id, val_id, miplevel_count_id; enum vsir_data_type data_type = VSIR_DATA_U32; uint32_t constituents[VKD3D_VEC4_SIZE]; @@ -9832,7 +9659,7 @@ static void spirv_compiler_emit_resinfo(struct spirv_compiler *compiler, } static uint32_t spirv_compiler_emit_query_sample_count(struct spirv_compiler *compiler, - const struct vkd3d_shader_src_param *src) + const struct vsir_src_operand *src) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_shader_image image; @@ -9859,8 +9686,8 @@ static void spirv_compiler_emit_sample_info(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; enum vsir_data_type data_type = VSIR_DATA_U32; uint32_t constituents[VKD3D_VEC4_SIZE]; uint32_t type_id, val_id; @@ -9940,7 +9767,7 @@ static void spirv_compiler_emit_sample_position(struct spirv_compiler *compiler, }; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t constituents[ARRAY_SIZE(standard_sample_positions)]; - const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t array_type_id, length_id, index_id, id; uint32_t sample_count_id, sample_index_id; uint32_t type_id, bool_id, ptr_type_id; @@ -9994,15 +9821,14 @@ static void spirv_compiler_emit_eval_attrib(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; - const struct vkd3d_shader_register *input = &src[0].reg; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t instr_set_id, type_id, val_id, src_ids[2]; struct vkd3d_shader_register_info register_info; unsigned int src_count = 0; enum GLSLstd450 op; - if (!spirv_compiler_get_register_info(compiler, input, ®ister_info)) + if (!spirv_compiler_get_register_info(compiler, &src[0].reg, ®ister_info)) return; if (register_info.storage_class != SpvStorageClassInput) @@ -10157,9 +9983,9 @@ static void spirv_compiler_emit_quad_read_across(struct spirv_compiler *compiler const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; uint32_t type_id, direction_type_id, direction_id, val_id; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; type_id = spirv_get_type_id(compiler, dst->reg.data_type, vsir_write_mask_component_count(dst->write_mask)); direction_type_id = spirv_get_type_id(compiler, VSIR_DATA_U32, 1); @@ -10175,8 +10001,8 @@ static void spirv_compiler_emit_quad_read_lane_at(struct spirv_compiler *compile const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, val_id, lane_id; if (!register_is_constant_or_undef(&src[1].reg)) @@ -10213,8 +10039,8 @@ static void spirv_compiler_emit_wave_bool_op(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, val_id; SpvOp op; @@ -10230,7 +10056,7 @@ static void spirv_compiler_emit_wave_bool_op(struct spirv_compiler *compiler, } static uint32_t spirv_compiler_emit_group_nonuniform_ballot(struct spirv_compiler *compiler, - const struct vkd3d_shader_src_param *src) + const struct vsir_src_operand *src) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, val_id; @@ -10245,7 +10071,7 @@ static uint32_t spirv_compiler_emit_group_nonuniform_ballot(struct spirv_compile static void spirv_compiler_emit_wave_active_ballot(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t val_id; val_id = spirv_compiler_emit_group_nonuniform_ballot(compiler, instruction->src); @@ -10287,8 +10113,8 @@ static void spirv_compiler_emit_wave_alu_op(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, val_id; SpvOp op; @@ -10310,7 +10136,7 @@ static void spirv_compiler_emit_wave_bit_count(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vsir_dst_operand *dst = instruction->dst; SpvGroupOperation group_op; uint32_t type_id, val_id; @@ -10328,7 +10154,7 @@ static void spirv_compiler_emit_wave_is_first_lane(struct spirv_compiler *compil const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t val_id; val_id = vkd3d_spirv_build_op_group_nonuniform_elect(builder); @@ -10339,8 +10165,8 @@ static void spirv_compiler_emit_wave_read_lane_at(struct spirv_compiler *compile const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, lane_id, val_id; type_id = spirv_get_type_id(compiler, dst->reg.data_type, vsir_write_mask_component_count(dst->write_mask)); @@ -10366,8 +10192,8 @@ static void spirv_compiler_emit_wave_read_lane_first(struct spirv_compiler *comp const struct vkd3d_shader_instruction *instruction) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_dst_param *dst = instruction->dst; - const struct vkd3d_shader_src_param *src = instruction->src; + const struct vsir_src_operand *src = instruction->src; + const struct vsir_dst_operand *dst = instruction->dst; uint32_t type_id, val_id; type_id = spirv_get_type_id(compiler, dst->reg.data_type, vsir_write_mask_component_count(dst->write_mask)); @@ -10454,9 +10280,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VSIR_OP_CMP: spirv_compiler_emit_movc(compiler, instruction); break; - case VSIR_OP_SWAPC: - spirv_compiler_emit_swapc(compiler, instruction); - break; case VSIR_OP_ADD: case VSIR_OP_AND: case VSIR_OP_BFREV: @@ -10773,7 +10596,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler) { - struct vkd3d_shader_dst_param dst; + struct vsir_dst_operand dst; for (unsigned int i = 0; i < compiler->program->input_signature.element_count; ++i) spirv_compiler_emit_input(compiler, VKD3DSPR_INPUT, i); @@ -10798,14 +10621,14 @@ static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler) if (compiler->program->has_point_size) { - vsir_dst_param_init(&dst, VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); + vsir_dst_operand_init(&dst, VKD3DSPR_RASTOUT, VSIR_DATA_F32, 1); dst.reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; spirv_compiler_emit_io_register(compiler, &dst); } if (compiler->program->has_point_coord) { - vsir_dst_param_init(&dst, VKD3DSPR_POINT_COORD, VSIR_DATA_F32, 0); + vsir_dst_operand_init(&dst, VKD3DSPR_POINT_COORD, VSIR_DATA_F32, 0); spirv_compiler_emit_io_register(compiler, &dst); } @@ -10816,7 +10639,7 @@ static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler) if (bitmap_is_set(compiler->program->io_dcls, i) || (compiler->program->shader_version.type == VKD3D_SHADER_TYPE_HULL && i == VKD3DSPR_OUTPOINTID)) { - vsir_dst_param_init(&dst, i, VSIR_DATA_F32, 0); + vsir_dst_operand_init(&dst, i, VSIR_DATA_F32, 0); spirv_compiler_emit_io_register(compiler, &dst); } } @@ -10967,9 +10790,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, || (program->shader_version.type == VKD3D_SHADER_TYPE_HULL && !spirv_compiler_is_opengl_target(compiler))) spirv_compiler_emit_tessellator_domain(compiler, program->tess_domain); - if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) - spirv_compiler_emit_shader_signature_outputs(compiler); - it = vsir_program_iterator(&program->instructions); for (ins = vsir_program_iterator_head(&it); ins && result >= 0; ins = vsir_program_iterator_next(&it)) { @@ -11071,8 +10891,9 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags, return ret; VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6); - VKD3D_ASSERT(program->has_descriptor_info); - VKD3D_ASSERT(program->has_no_modifiers); + VKD3D_ASSERT(program->normalisation_flags.normalised_clip_cull_arrays); + VKD3D_ASSERT(program->normalisation_flags.has_descriptor_info); + VKD3D_ASSERT(program->normalisation_flags.has_no_modifiers); if (!(spirv_compiler = spirv_compiler_create(program, compile_info, message_context, config_flags))) diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index 4798a75ce90..003a6635aaf 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -771,10 +771,10 @@ static bool shader_is_sm_5_1(const struct vkd3d_shader_sm4_parser *sm4) return version->major >= 5 && version->minor >= 1; } -static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, - const uint32_t *end, enum vsir_data_type data_type, struct vkd3d_shader_src_param *src_param); -static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, - const uint32_t *end, enum vsir_data_type data_type, struct vkd3d_shader_dst_param *dst_param); +static bool tpf_read_src_operand(struct vkd3d_shader_sm4_parser *tpf, const uint32_t **ptr, + const uint32_t *end, enum vsir_data_type data_type, struct vsir_src_operand *src); +static bool tpf_read_dst_operand(struct vkd3d_shader_sm4_parser *tpf, const uint32_t **ptr, + const uint32_t *end, enum vsir_data_type data_type, struct vsir_dst_operand *dst); static bool shader_sm4_read_register_space(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, const uint32_t *end, unsigned int *register_space) @@ -795,23 +795,20 @@ static bool shader_sm4_read_register_space(struct vkd3d_shader_sm4_parser *priv, } static void shader_sm4_read_conditional_op(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VSIR_DATA_U32, &ins->src[0]); + tpf_read_src_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_U32, &ins->src[0]); ins->flags = (opcode_token & VKD3D_SM4_CONDITIONAL_NZ) ? VKD3D_SHADER_CONDITIONAL_OP_NZ : VKD3D_SHADER_CONDITIONAL_OP_Z; } static void shader_sm4_read_case_condition(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VSIR_DATA_U32, &ins->src[0]); + tpf_read_src_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_U32, &ins->src[0]); if (ins->src[0].reg.type != VKD3DSPR_IMMCONST) - { - FIXME("Switch case value is not a 32-bit constant.\n"); - vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_CASE_VALUE, + vkd3d_shader_parser_error(&tpf->p, VKD3D_SHADER_ERROR_TPF_INVALID_CASE_VALUE, "Switch case value is not a 32-bit immediate constant register."); - } } static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, @@ -869,7 +866,7 @@ static void shader_sm4_set_descriptor_register_range(struct vkd3d_shader_sm4_par } static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { struct vkd3d_shader_semantic *semantic = &ins->declaration.semantic; enum vkd3d_sm4_resource_type resource_type; @@ -898,8 +895,8 @@ static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins, u } reg_data_type = VSIR_DATA_UNUSED; - shader_sm4_read_dst_param(priv, &tokens, end, reg_data_type, &semantic->resource.reg); - shader_sm4_set_descriptor_register_range(priv, &semantic->resource.reg.reg, &semantic->resource.range); + tpf_read_dst_operand(tpf, &tokens, end, reg_data_type, &semantic->resource.reg); + shader_sm4_set_descriptor_register_range(tpf, &semantic->resource.reg.reg, &semantic->resource.range); components = *tokens++; for (i = 0; i < VKD3D_VEC4_SIZE; i++) @@ -920,23 +917,23 @@ static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins, u if (opcode != VKD3D_SM4_OP_DCL_RESOURCE) ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT; - shader_sm4_read_register_space(priv, &tokens, end, &semantic->resource.range.space); + shader_sm4_read_register_space(tpf, &tokens, end, &semantic->resource.range.space); } static void shader_sm4_read_dcl_constant_buffer(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { const uint32_t *end = &tokens[token_count]; - shader_sm4_read_src_param(priv, &tokens, end, VSIR_DATA_F32, &ins->declaration.cb.src); - shader_sm4_set_descriptor_register_range(priv, &ins->declaration.cb.src.reg, &ins->declaration.cb.range); + tpf_read_src_operand(tpf, &tokens, end, VSIR_DATA_F32, &ins->declaration.cb.src); + shader_sm4_set_descriptor_register_range(tpf, &ins->declaration.cb.src.reg, &ins->declaration.cb.range); if (opcode_token & VKD3D_SM4_INDEX_TYPE_MASK) ins->flags |= VKD3DSI_INDEXED_DYNAMIC; ins->declaration.cb.size = ins->declaration.cb.src.reg.idx[2].offset; ins->declaration.cb.range.space = 0; - if (shader_is_sm_5_1(priv)) + if (shader_is_sm_5_1(tpf)) { if (tokens >= end) { @@ -945,28 +942,23 @@ static void shader_sm4_read_dcl_constant_buffer(struct vkd3d_shader_instruction } ins->declaration.cb.size = *tokens++; - shader_sm4_read_register_space(priv, &tokens, end, &ins->declaration.cb.range.space); + shader_sm4_read_register_space(tpf, &tokens, end, &ins->declaration.cb.range.space); } ins->declaration.cb.size *= VKD3D_VEC4_SIZE * sizeof(float); } static void shader_sm4_read_dcl_sampler(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, - const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { const uint32_t *end = &tokens[token_count]; ins->flags = (opcode_token & VKD3D_SM4_SAMPLER_MODE_MASK) >> VKD3D_SM4_SAMPLER_MODE_SHIFT; if (ins->flags & ~VKD3D_SM4_SAMPLER_COMPARISON) FIXME("Unhandled sampler mode %#x.\n", ins->flags); - shader_sm4_read_src_param(priv, &tokens, end, VSIR_DATA_UNUSED, &ins->declaration.sampler.src); - shader_sm4_set_descriptor_register_range(priv, &ins->declaration.sampler.src.reg, &ins->declaration.sampler.range); - shader_sm4_read_register_space(priv, &tokens, end, &ins->declaration.sampler.range.space); -} - -static bool sm4_parser_is_in_fork_or_join_phase(const struct vkd3d_shader_sm4_parser *sm4) -{ - return sm4->phase == VSIR_OP_HS_FORK_PHASE || sm4->phase == VSIR_OP_HS_JOIN_PHASE; + tpf_read_src_operand(tpf, &tokens, end, VSIR_DATA_UNUSED, &ins->declaration.sampler.src); + shader_sm4_set_descriptor_register_range(tpf, &ins->declaration.sampler.src.reg, &ins->declaration.sampler.range); + shader_sm4_read_register_space(tpf, &tokens, end, &ins->declaration.sampler.range.space); } static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins, uint32_t opcode, @@ -981,7 +973,7 @@ static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins unsigned int *io_masks; uint32_t write_mask; - shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VSIR_DATA_OPAQUE, &index_range->dst); + tpf_read_dst_operand(priv, &tokens, &tokens[token_count], VSIR_DATA_OPAQUE, &index_range->dst); index_range->register_count = *tokens; register_idx = index_range->dst.reg.idx[index_range->dst.reg.idx_count - 1].offset; @@ -997,7 +989,7 @@ static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins signature = &program->input_signature; break; case VKD3DSPR_OUTPUT: - if (sm4_parser_is_in_fork_or_join_phase(priv)) + if (vsir_opcode_is_fork_or_join_phase(priv->phase)) { io_masks = priv->patch_constant_register_masks; ranges = &priv->patch_constant_index_ranges; @@ -1141,68 +1133,54 @@ static void shader_sm4_read_declaration_count(struct vkd3d_shader_instruction *i } static void shader_sm4_read_declaration_dst(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VSIR_DATA_F32, &ins->declaration.dst); + tpf_read_dst_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_F32, &ins->declaration.dst); } static void shader_sm4_read_declaration_register_semantic(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], + tpf_read_dst_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_F32, &ins->declaration.register_semantic.reg); ins->declaration.register_semantic.sysval_semantic = *tokens; } static void shader_sm4_read_dcl_input_ps(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - struct vkd3d_shader_dst_param *dst = &ins->declaration.dst; + struct vsir_dst_operand *dst = &ins->declaration.dst; + struct signature_element *e; ins->flags = (opcode_token & VKD3D_SM4_INTERPOLATION_MODE_MASK) >> VKD3D_SM4_INTERPOLATION_MODE_SHIFT; - if (shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VSIR_DATA_F32, dst)) + if (tpf_read_dst_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_F32, dst)) { - struct signature_element *e = vsir_signature_find_element_for_reg( - &priv->program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - - if (!e) - { - WARN("No matching signature element for input register %u with mask %#x.\n", - dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, + if (!(e = vsir_signature_find_element_for_reg(&tpf->program->input_signature, + dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask))) + vkd3d_shader_parser_error(&tpf->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, "No matching signature element for input register %u with mask %#x.", dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - } else - { e->interpolation_mode = ins->flags; - } } } static void shader_sm4_read_dcl_input_ps_siv(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - struct vkd3d_shader_dst_param *dst = &ins->declaration.register_semantic.reg; + struct vsir_dst_operand *dst = &ins->declaration.register_semantic.reg; + struct signature_element *e; ins->flags = (opcode_token & VKD3D_SM4_INTERPOLATION_MODE_MASK) >> VKD3D_SM4_INTERPOLATION_MODE_SHIFT; - if (shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VSIR_DATA_F32, dst)) + if (tpf_read_dst_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_F32, dst)) { - struct signature_element *e = vsir_signature_find_element_for_reg( - &priv->program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - - if (!e) - { - WARN("No matching signature element for input register %u with mask %#x.\n", - dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, + if (!(e = vsir_signature_find_element_for_reg(&tpf->program->input_signature, + dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask))) + vkd3d_shader_parser_error(&tpf->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL, "No matching signature element for input register %u with mask %#x.", dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask); - } else - { e->interpolation_mode = ins->flags; - } } ins->declaration.register_semantic.sysval_semantic = *tokens; } @@ -1223,13 +1201,17 @@ static void shader_sm4_read_dcl_global_flags(struct vkd3d_shader_instruction *in { ins->declaration.global_flags = (opcode_token & VKD3D_SM4_GLOBAL_FLAGS_MASK) >> VKD3D_SM4_GLOBAL_FLAGS_SHIFT; sm4->program->global_flags = ins->declaration.global_flags; + + if (sm4->program->global_flags & (VKD3DSGF_ENABLE_DOUBLE_PRECISION_FLOAT_OPS + | VKD3DSGF_ENABLE_11_1_DOUBLE_EXTENSIONS)) + sm4->program->f64_denorm_mode = VSIR_DENORM_PRESERVE; } static void shader_sm5_read_fcall(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, - const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { ins->src[0].reg.u.fp_body_idx = *tokens++; - shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VSIR_DATA_OPAQUE, &ins->src[0]); + tpf_read_src_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_OPAQUE, &ins->src[0]); } static void shader_sm5_read_dcl_function_body(struct vkd3d_shader_instruction *ins, uint32_t opcode, @@ -1311,36 +1293,36 @@ static void shader_sm5_read_dcl_thread_group(struct vkd3d_shader_instruction *in } static void shader_sm5_read_dcl_uav_raw(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, - const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { struct vkd3d_shader_raw_resource *resource = &ins->declaration.raw_resource; const uint32_t *end = &tokens[token_count]; - shader_sm4_read_dst_param(priv, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); - shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); + tpf_read_dst_operand(tpf, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(tpf, &resource->resource.reg.reg, &resource->resource.range); ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT; - shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.range.space); + shader_sm4_read_register_space(tpf, &tokens, end, &resource->resource.range.space); } static void shader_sm5_read_dcl_uav_structured(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { struct vkd3d_shader_structured_resource *resource = &ins->declaration.structured_resource; const uint32_t *end = &tokens[token_count]; - shader_sm4_read_dst_param(priv, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); - shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); + tpf_read_dst_operand(tpf, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(tpf, &resource->resource.reg.reg, &resource->resource.range); ins->flags = (opcode_token & VKD3D_SM5_UAV_FLAGS_MASK) >> VKD3D_SM5_UAV_FLAGS_SHIFT; resource->byte_stride = *tokens++; if (resource->byte_stride % 4) FIXME("Byte stride %u is not multiple of 4.\n", resource->byte_stride); - shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.range.space); + shader_sm4_read_register_space(tpf, &tokens, end, &resource->resource.range.space); } static void shader_sm5_read_dcl_tgsm_raw(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VSIR_DATA_F32, &ins->declaration.tgsm_raw.reg); + tpf_read_dst_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_F32, &ins->declaration.tgsm_raw.reg); ins->declaration.tgsm_raw.byte_count = *tokens; if (ins->declaration.tgsm_raw.byte_count % 4) FIXME("Byte count %u is not multiple of 4.\n", ins->declaration.tgsm_raw.byte_count); @@ -1348,10 +1330,9 @@ static void shader_sm5_read_dcl_tgsm_raw(struct vkd3d_shader_instruction *ins, u } static void shader_sm5_read_dcl_tgsm_structured(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { - shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], - VSIR_DATA_F32, &ins->declaration.tgsm_structured.reg); + tpf_read_dst_operand(tpf, &tokens, &tokens[token_count], VSIR_DATA_F32, &ins->declaration.tgsm_structured.reg); ins->declaration.tgsm_structured.byte_stride = *tokens++; ins->declaration.tgsm_structured.structure_count = *tokens; if (ins->declaration.tgsm_structured.byte_stride % 4) @@ -1360,28 +1341,28 @@ static void shader_sm5_read_dcl_tgsm_structured(struct vkd3d_shader_instruction } static void shader_sm5_read_dcl_resource_structured(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { struct vkd3d_shader_structured_resource *resource = &ins->declaration.structured_resource; const uint32_t *end = &tokens[token_count]; - shader_sm4_read_dst_param(priv, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); - shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); + tpf_read_dst_operand(tpf, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(tpf, &resource->resource.reg.reg, &resource->resource.range); resource->byte_stride = *tokens++; if (resource->byte_stride % 4) FIXME("Byte stride %u is not multiple of 4.\n", resource->byte_stride); - shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.range.space); + shader_sm4_read_register_space(tpf, &tokens, end, &resource->resource.range.space); } static void shader_sm5_read_dcl_resource_raw(struct vkd3d_shader_instruction *ins, uint32_t opcode, - uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv) + uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *tpf) { struct vkd3d_shader_raw_resource *resource = &ins->declaration.raw_resource; const uint32_t *end = &tokens[token_count]; - shader_sm4_read_dst_param(priv, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); - shader_sm4_set_descriptor_register_range(priv, &resource->resource.reg.reg, &resource->resource.range); - shader_sm4_read_register_space(priv, &tokens, end, &resource->resource.range.space); + tpf_read_dst_operand(tpf, &tokens, end, VSIR_DATA_UNUSED, &resource->resource.reg); + shader_sm4_set_descriptor_register_range(tpf, &resource->resource.reg.reg, &resource->resource.range); + shader_sm4_read_register_space(tpf, &tokens, end, &resource->resource.range.space); } static void shader_sm5_read_sync(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token, @@ -1417,15 +1398,31 @@ struct sm4_stat struct tpf_compiler { struct vsir_program *program; + + struct vkd3d_shader_location location; + struct vkd3d_shader_message_context *message_context; + enum vkd3d_shader_error first_error; + struct vkd3d_sm4_lookup_tables lookup; struct sm4_stat *stat; - int result; - struct vkd3d_bytecode_buffer *buffer; struct dxbc_writer dxbc; }; +static void VKD3D_PRINTF_FUNC(3, 4) tpf_compiler_error(struct tpf_compiler *tpf, + enum vkd3d_shader_error error, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vkd3d_shader_verror(tpf->message_context, &tpf->location, error, fmt, args); + va_end(args); + + if (!tpf->first_error) + tpf->first_error = error; +} + static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) { unsigned int i; @@ -2006,12 +2003,12 @@ static enum vsir_data_type map_data_type(char t) } } -static bool shader_sm4_read_reg_idx(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, +static bool shader_sm4_read_reg_idx(struct vkd3d_shader_sm4_parser *tpf, const uint32_t **ptr, const uint32_t *end, uint32_t addressing, struct vkd3d_shader_register_index *reg_idx) { if (addressing & VKD3D_SM4_ADDRESSING_RELATIVE) { - struct vkd3d_shader_src_param *rel_addr = vsir_program_get_src_params(priv->program, 1); + struct vsir_src_operand *rel_addr = vsir_program_get_src_operands(tpf->program, 1); if (!(reg_idx->rel_addr = rel_addr)) { @@ -2023,7 +2020,7 @@ static bool shader_sm4_read_reg_idx(struct vkd3d_shader_sm4_parser *priv, const reg_idx->offset = *(*ptr)++; else reg_idx->offset = 0; - shader_sm4_read_src_param(priv, ptr, end, VSIR_DATA_I32, rel_addr); + tpf_read_src_operand(tpf, ptr, end, VSIR_DATA_I32, rel_addr); } else { @@ -2285,7 +2282,7 @@ static bool register_is_control_point_input(const struct vkd3d_shader_register * const struct vkd3d_shader_sm4_parser *priv) { return reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_OUTCONTROLPOINT - || (reg->type == VKD3DSPR_INPUT && (priv->phase == VSIR_OP_HS_CONTROL_POINT_PHASE + || (reg->type == VKD3DSPR_INPUT && (vsir_opcode_is_control_point_phase(priv->phase) || priv->program->shader_version.type == VKD3D_SHADER_TYPE_GEOMETRY)); } @@ -2319,8 +2316,8 @@ static bool shader_sm4_validate_input_output_register(struct vkd3d_shader_sm4_pa masks = priv->input_register_masks; break; case VKD3DSPR_OUTPUT: - masks = sm4_parser_is_in_fork_or_join_phase(priv) ? priv->patch_constant_register_masks - : priv->output_register_masks; + masks = vsir_opcode_is_fork_or_join_phase(priv->phase) + ? priv->patch_constant_register_masks : priv->output_register_masks; break; case VKD3DSPR_COLOROUT: case VKD3DSPR_OUTCONTROLPOINT: @@ -2349,8 +2346,8 @@ static bool shader_sm4_validate_input_output_register(struct vkd3d_shader_sm4_pa return true; } -static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, - const uint32_t *end, enum vsir_data_type data_type, struct vkd3d_shader_src_param *src_param) +static bool tpf_read_src_operand(struct vkd3d_shader_sm4_parser *tpf, const uint32_t **ptr, + const uint32_t *end, enum vsir_data_type data_type, struct vsir_src_operand *src) { unsigned int dimension, mask; uint32_t token; @@ -2362,7 +2359,7 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons } token = **ptr; - if (!shader_sm4_read_param(priv, ptr, end, data_type, &src_param->reg, &src_param->modifiers)) + if (!shader_sm4_read_param(tpf, ptr, end, data_type, &src->reg, &src->modifiers)) { ERR("Failed to read parameter.\n"); return false; @@ -2372,7 +2369,7 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons { case VKD3D_SM4_DIMENSION_NONE: case VKD3D_SM4_DIMENSION_SCALAR: - src_param->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + src->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); break; case VKD3D_SM4_DIMENSION_VEC4: @@ -2383,37 +2380,30 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons switch (swizzle_type) { case VKD3D_SM4_SWIZZLE_NONE: - src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE; + src->swizzle = VKD3D_SHADER_NO_SWIZZLE; mask = (token & VKD3D_SM4_WRITEMASK_MASK) >> VKD3D_SM4_WRITEMASK_SHIFT; /* Mask seems only to be used for vec4 constants and is always zero. */ - if (!register_is_constant(&src_param->reg)) - { - FIXME("Source mask %#x is not for a constant.\n", mask); - vkd3d_shader_parser_warning(&priv->p, VKD3D_SHADER_WARNING_TPF_UNHANDLED_REGISTER_MASK, + if (!register_is_constant(&src->reg)) + vkd3d_shader_parser_warning(&tpf->p, VKD3D_SHADER_WARNING_TPF_UNHANDLED_REGISTER_MASK, "Unhandled mask %#x for a non-constant source register.", mask); - } else if (mask) - { - FIXME("Unhandled mask %#x.\n", mask); - vkd3d_shader_parser_warning(&priv->p, VKD3D_SHADER_WARNING_TPF_UNHANDLED_REGISTER_MASK, + vkd3d_shader_parser_warning(&tpf->p, VKD3D_SHADER_WARNING_TPF_UNHANDLED_REGISTER_MASK, "Unhandled source register mask %#x.", mask); - } break; case VKD3D_SM4_SWIZZLE_SCALAR: - src_param->swizzle = (token & VKD3D_SM4_SWIZZLE_MASK) >> VKD3D_SM4_SWIZZLE_SHIFT; - src_param->swizzle = (src_param->swizzle & 0x3) * 0x01010101; + src->swizzle = (token & VKD3D_SM4_SWIZZLE_MASK) >> VKD3D_SM4_SWIZZLE_SHIFT; + src->swizzle = (src->swizzle & 0x3) * 0x01010101; break; case VKD3D_SM4_SWIZZLE_VEC4: - src_param->swizzle = swizzle_from_sm4((token & VKD3D_SM4_SWIZZLE_MASK) >> VKD3D_SM4_SWIZZLE_SHIFT); + src->swizzle = swizzle_from_sm4((token & VKD3D_SM4_SWIZZLE_MASK) >> VKD3D_SM4_SWIZZLE_SHIFT); break; default: - FIXME("Unhandled swizzle type %#x.\n", swizzle_type); - vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE, + vkd3d_shader_parser_error(&tpf->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE, "Source register swizzle type %#x is invalid.", swizzle_type); break; } @@ -2421,24 +2411,23 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons } default: - FIXME("Unhandled dimension %#x.\n", dimension); - vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION, + vkd3d_shader_parser_error(&tpf->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION, "Source register dimension %#x is invalid.", dimension); break; } if (data_type_is_64_bit(data_type)) - src_param->swizzle = vsir_swizzle_64_from_32(src_param->swizzle); + src->swizzle = vsir_swizzle_64_from_32(src->swizzle); - if (register_is_input_output(&src_param->reg) && !shader_sm4_validate_input_output_register(priv, - &src_param->reg, mask_from_swizzle(src_param->swizzle))) + if (register_is_input_output(&src->reg) && !shader_sm4_validate_input_output_register(tpf, + &src->reg, mask_from_swizzle(src->swizzle))) return false; return true; } -static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, const uint32_t **ptr, - const uint32_t *end, enum vsir_data_type data_type, struct vkd3d_shader_dst_param *dst_param) +static bool tpf_read_dst_operand(struct vkd3d_shader_sm4_parser *tpf, const uint32_t **ptr, + const uint32_t *end, enum vsir_data_type data_type, struct vsir_dst_operand *dst) { enum vkd3d_sm4_swizzle_type swizzle_type; enum vkd3d_shader_src_modifier modifier; @@ -2452,7 +2441,7 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons } token = **ptr; - if (!shader_sm4_read_param(priv, ptr, end, data_type, &dst_param->reg, &modifier)) + if (!shader_sm4_read_param(tpf, ptr, end, data_type, &dst->reg, &modifier)) { ERR("Failed to read parameter.\n"); return false; @@ -2467,11 +2456,11 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons switch ((dimension = (token & VKD3D_SM4_DIMENSION_MASK) >> VKD3D_SM4_DIMENSION_SHIFT)) { case VKD3D_SM4_DIMENSION_NONE: - dst_param->write_mask = 0; + dst->write_mask = 0; break; case VKD3D_SM4_DIMENSION_SCALAR: - dst_param->write_mask = VKD3DSP_WRITEMASK_0; + dst->write_mask = VKD3DSP_WRITEMASK_0; break; case VKD3D_SM4_DIMENSION_VEC4: @@ -2479,45 +2468,42 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons switch (swizzle_type) { case VKD3D_SM4_SWIZZLE_NONE: - dst_param->write_mask = (token & VKD3D_SM4_WRITEMASK_MASK) >> VKD3D_SM4_WRITEMASK_SHIFT; + dst->write_mask = (token & VKD3D_SM4_WRITEMASK_MASK) >> VKD3D_SM4_WRITEMASK_SHIFT; break; case VKD3D_SM4_SWIZZLE_VEC4: swizzle = swizzle_from_sm4((token & VKD3D_SM4_SWIZZLE_MASK) >> VKD3D_SM4_SWIZZLE_SHIFT); if (swizzle != VKD3D_SHADER_NO_SWIZZLE) { - FIXME("Unhandled swizzle %#x.\n", swizzle); - vkd3d_shader_parser_warning(&priv->p, VKD3D_SHADER_WARNING_TPF_UNHANDLED_REGISTER_SWIZZLE, + vkd3d_shader_parser_warning(&tpf->p, VKD3D_SHADER_WARNING_TPF_UNHANDLED_REGISTER_SWIZZLE, "Unhandled destination register swizzle %#x.", swizzle); } - dst_param->write_mask = VKD3DSP_WRITEMASK_ALL; + dst->write_mask = VKD3DSP_WRITEMASK_ALL; break; default: - FIXME("Unhandled swizzle type %#x.\n", swizzle_type); - vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE, + vkd3d_shader_parser_error(&tpf->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE, "Destination register swizzle type %#x is invalid.", swizzle_type); break; } break; default: - FIXME("Unhandled dimension %#x.\n", dimension); - vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION, + vkd3d_shader_parser_error(&tpf->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION, "Destination register dimension %#x is invalid.", dimension); break; } if (data_type == VSIR_DATA_F64) - dst_param->write_mask = vsir_write_mask_64_from_32(dst_param->write_mask); + dst->write_mask = vsir_write_mask_64_from_32(dst->write_mask); /* Some scalar registers are declared with no write mask in shader bytecode. */ - if (!dst_param->write_mask && shader_sm4_is_scalar_register(&dst_param->reg)) - dst_param->write_mask = VKD3DSP_WRITEMASK_0; - dst_param->modifiers = 0; - dst_param->shift = 0; + if (!dst->write_mask && shader_sm4_is_scalar_register(&dst->reg)) + dst->write_mask = VKD3DSP_WRITEMASK_0; + dst->modifiers = 0; + dst->shift = 0; - if (register_is_input_output(&dst_param->reg) && !shader_sm4_validate_input_output_register(priv, - &dst_param->reg, dst_param->write_mask)) + if (register_is_input_output(&dst->reg) + && !shader_sm4_validate_input_output_register(tpf, &dst->reg, dst->write_mask)) return false; return true; @@ -2612,9 +2598,9 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str const struct vkd3d_sm4_opcode_info *opcode_info; uint32_t opcode_token, opcode, previous_token; struct vsir_program *program = sm4->program; - struct vkd3d_shader_dst_param *dst_params; - struct vkd3d_shader_src_param *src_params; const uint32_t **ptr = &sm4->ptr; + struct vsir_src_operand *src; + struct vsir_dst_operand *dst; unsigned int i, len; const uint32_t *p; uint32_t precise; @@ -2661,7 +2647,7 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str if (ins->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE || ins->opcode == VSIR_OP_HS_FORK_PHASE || ins->opcode == VSIR_OP_HS_JOIN_PHASE) sm4->phase = ins->opcode; - sm4->has_control_point_phase |= ins->opcode == VSIR_OP_HS_CONTROL_POINT_PHASE; + sm4->has_control_point_phase |= vsir_opcode_is_control_point_phase(ins->opcode); ins->flags = 0; ins->coissue = false; ins->raw = false; @@ -2669,10 +2655,9 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str ins->predicate = NULL; ins->dst_count = opcode_info_get_dst_count(opcode_info); ins->src_count = opcode_info_get_src_count(opcode_info); - ins->src = src_params = vsir_program_get_src_params(program, ins->src_count); - if (!src_params && ins->src_count) + ins->src = src = vsir_program_get_src_operands(program, ins->src_count); + if (!src && ins->src_count) { - ERR("Failed to allocate src parameters.\n"); vkd3d_shader_parser_error(&sm4->p, VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY, "Out of memory."); ins->opcode = VSIR_OP_INVALID; return; @@ -2711,29 +2696,26 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str precise = (opcode_token & VKD3D_SM5_PRECISE_MASK) >> VKD3D_SM5_PRECISE_SHIFT; ins->flags |= precise << VKD3DSI_PRECISE_SHIFT; - ins->dst = dst_params = vsir_program_get_dst_params(program, ins->dst_count); - if (!dst_params && ins->dst_count) + ins->dst = dst = vsir_program_get_dst_operands(program, ins->dst_count); + if (!dst && ins->dst_count) { - ERR("Failed to allocate dst parameters.\n"); vkd3d_shader_parser_error(&sm4->p, VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY, "Out of memory."); ins->opcode = VSIR_OP_INVALID; return; } for (i = 0; i < ins->dst_count; ++i) { - if (!(shader_sm4_read_dst_param(sm4, &p, *ptr, map_data_type(opcode_info->dst_info[i]), - &dst_params[i]))) + if (!(tpf_read_dst_operand(sm4, &p, *ptr, map_data_type(opcode_info->dst_info[i]), &dst[i]))) { ins->opcode = VSIR_OP_INVALID; return; } - dst_params[i].modifiers |= instruction_dst_modifier; + dst[i].modifiers |= instruction_dst_modifier; } for (i = 0; i < ins->src_count; ++i) { - if (!(shader_sm4_read_src_param(sm4, &p, *ptr, map_data_type(opcode_info->src_info[i]), - &src_params[i]))) + if (!(tpf_read_src_operand(sm4, &p, *ptr, map_data_type(opcode_info->src_info[i]), &src[i]))) { ins->opcode = VSIR_OP_INVALID; return; @@ -2816,6 +2798,9 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, struct vsir_pro if (!vsir_program_init(program, compile_info, &version, token_count / 7u + 20, VSIR_CF_STRUCTURED, VSIR_NORMALISED_SM4)) return false; + + program->f32_denorm_mode = VSIR_DENORM_FLUSH_TO_ZERO; + vkd3d_shader_parser_init(&sm4->p, message_context, compile_info->source_name); sm4->ptr = sm4->start; sm4->program = program; @@ -3247,8 +3232,8 @@ static void add_section(struct tpf_compiler *tpf, uint32_t tag, struct vkd3d_byt dxbc_writer_add_section(&tpf->dxbc, tag, buffer->data, size); - if (buffer->status < 0) - tpf->result = buffer->status; + if (buffer->status < 0 && !tpf->first_error) + tpf->first_error = VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY; } static int signature_element_pointer_compare(const void *x, const void *y) @@ -3282,7 +3267,10 @@ static void tpf_write_signature(struct tpf_compiler *tpf, const struct shader_si put_u32(&buffer, 8); /* unknown */ if (!(sorted_elements = vkd3d_calloc(signature->element_count, sizeof(*sorted_elements)))) + { + vkd3d_bytecode_buffer_cleanup(&buffer); return; + } for (i = 0; i < signature->element_count; ++i) sorted_elements[i] = &signature->elements[i]; qsort(sorted_elements, signature->element_count, sizeof(*sorted_elements), signature_element_pointer_compare); @@ -3414,10 +3402,10 @@ struct sm4_instruction struct sm4_instruction_modifier modifiers[1]; unsigned int modifier_count; - struct vkd3d_shader_dst_param dsts[2]; + struct vsir_dst_operand dsts[2]; unsigned int dst_count; - struct vkd3d_shader_src_param srcs[5]; + struct vsir_src_operand srcs[5]; unsigned int src_count; unsigned int byte_stride; @@ -3425,7 +3413,7 @@ struct sm4_instruction uint32_t idx[3]; unsigned int idx_count; - struct vkd3d_shader_src_param idx_srcs[7]; + struct vsir_src_operand idx_srcs[7]; unsigned int idx_src_count; }; @@ -3518,7 +3506,7 @@ static void sm4_write_register_index(const struct tpf_compiler *tpf, const struc if (addressing & VKD3D_SM4_ADDRESSING_RELATIVE) { - const struct vkd3d_shader_src_param *idx_src = idx->rel_addr; + const struct vsir_src_operand *idx_src = idx->rel_addr; uint32_t idx_src_token; VKD3D_ASSERT(idx_src); @@ -3535,7 +3523,7 @@ static void sm4_write_register_index(const struct tpf_compiler *tpf, const struc } } -static void sm4_write_dst_register(const struct tpf_compiler *tpf, const struct vkd3d_shader_dst_param *dst) +static void sm4_write_dst_register(const struct tpf_compiler *tpf, const struct vsir_dst_operand *dst) { struct vkd3d_bytecode_buffer *buffer = tpf->buffer; uint32_t token = 0; @@ -3548,7 +3536,7 @@ static void sm4_write_dst_register(const struct tpf_compiler *tpf, const struct sm4_write_register_index(tpf, &dst->reg, j); } -static void sm4_write_src_register(const struct tpf_compiler *tpf, const struct vkd3d_shader_src_param *src) +static void sm4_write_src_register(struct tpf_compiler *tpf, const struct vsir_src_operand *src) { struct vkd3d_bytecode_buffer *buffer = tpf->buffer; uint32_t token = 0, mod_token = 0; @@ -3578,8 +3566,8 @@ static void sm4_write_src_register(const struct tpf_compiler *tpf, const struct break; default: - ERR("Unhandled register modifier %#x.\n", src->modifiers); - vkd3d_unreachable(); + tpf_compiler_error(tpf, VKD3D_SHADER_ERROR_TPF_NOT_IMPLEMENTED, + "Unhandled register modifier %#x.\n", src->modifiers); break; } @@ -3654,7 +3642,7 @@ static void sm4_update_stat_counters(const struct tpf_compiler *tpf, const struc } } -static void write_sm4_instruction(const struct tpf_compiler *tpf, const struct sm4_instruction *instr) +static void write_sm4_instruction(struct tpf_compiler *tpf, const struct sm4_instruction *instr) { uint32_t token = instr->opcode | instr->extra_bits; struct vkd3d_bytecode_buffer *buffer = tpf->buffer; @@ -3694,7 +3682,7 @@ static void write_sm4_instruction(const struct tpf_compiler *tpf, const struct s sm4_update_stat_counters(tpf, instr); } -static void tpf_dcl_constant_buffer(const struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) +static void tpf_dcl_constant_buffer(struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) { const struct vkd3d_shader_constant_buffer *cb = &ins->declaration.cb; size_t size = cb->size / VKD3D_VEC4_SIZE / sizeof(float); @@ -3731,7 +3719,7 @@ static void tpf_dcl_constant_buffer(const struct tpf_compiler *tpf, const struct write_sm4_instruction(tpf, &instr); } -static void tpf_dcl_temps(const struct tpf_compiler *tpf, unsigned int count) +static void tpf_dcl_temps(struct tpf_compiler *tpf, unsigned int count) { struct sm4_instruction instr = { @@ -3744,7 +3732,7 @@ static void tpf_dcl_temps(const struct tpf_compiler *tpf, unsigned int count) write_sm4_instruction(tpf, &instr); } -static void tpf_dcl_indexable_temp(const struct tpf_compiler *tpf, const struct vkd3d_shader_indexable_temp *temp) +static void tpf_dcl_indexable_temp(struct tpf_compiler *tpf, const struct vkd3d_shader_indexable_temp *temp) { struct sm4_instruction instr = { @@ -3757,8 +3745,8 @@ static void tpf_dcl_indexable_temp(const struct tpf_compiler *tpf, const struct write_sm4_instruction(tpf, &instr); } -static void tpf_dcl_semantic(const struct tpf_compiler *tpf, enum vkd3d_sm4_opcode opcode, - const struct vkd3d_shader_dst_param *dst, uint32_t interpolation_flags) +static void tpf_dcl_semantic(struct tpf_compiler *tpf, enum vkd3d_sm4_opcode opcode, + const struct vsir_dst_operand *dst, uint32_t interpolation_flags) { struct sm4_instruction instr = { @@ -3773,7 +3761,7 @@ static void tpf_dcl_semantic(const struct tpf_compiler *tpf, enum vkd3d_sm4_opco write_sm4_instruction(tpf, &instr); } -static void tpf_dcl_siv_semantic(const struct tpf_compiler *tpf, enum vkd3d_sm4_opcode opcode, +static void tpf_dcl_siv_semantic(struct tpf_compiler *tpf, enum vkd3d_sm4_opcode opcode, const struct vkd3d_shader_register_semantic *semantic, uint32_t interpolation_flags) { struct sm4_instruction instr = @@ -3792,7 +3780,7 @@ static void tpf_dcl_siv_semantic(const struct tpf_compiler *tpf, enum vkd3d_sm4_ write_sm4_instruction(tpf, &instr); } -static void tpf_dcl_thread_group(const struct tpf_compiler *tpf, const struct vsir_thread_group_size *group_size) +static void tpf_dcl_thread_group(struct tpf_compiler *tpf, const struct vsir_thread_group_size *group_size) { struct sm4_instruction instr = { @@ -3805,7 +3793,7 @@ static void tpf_dcl_thread_group(const struct tpf_compiler *tpf, const struct vs write_sm4_instruction(tpf, &instr); } -static void tpf_dcl_sampler(const struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) +static void tpf_dcl_sampler(struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) { const struct vkd3d_shader_sampler *sampler = &ins->declaration.sampler; struct sm4_instruction instr = @@ -3855,7 +3843,7 @@ static uint32_t pack_resource_data_type(const enum vsir_data_type *resource_data return type; } -static void tpf_dcl_texture(const struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) +static void tpf_dcl_texture(struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) { const struct vkd3d_shader_version *version = &tpf->program->shader_version; const struct vkd3d_shader_resource *resource; @@ -3916,7 +3904,7 @@ static void tpf_dcl_texture(const struct tpf_compiler *tpf, const struct vkd3d_s write_sm4_instruction(tpf, &instr); } -static void tpf_dcl_tgsm_raw(const struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) +static void tpf_dcl_tgsm_raw(struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) { const struct vkd3d_shader_tgsm_raw *tgsm = &ins->declaration.tgsm_raw; struct sm4_instruction instr = @@ -3933,7 +3921,25 @@ static void tpf_dcl_tgsm_raw(const struct tpf_compiler *tpf, const struct vkd3d_ write_sm4_instruction(tpf, &instr); } -static void write_sm4_dcl_global_flags(const struct tpf_compiler *tpf, uint32_t flags) +static void tpf_dcl_tgsm_structured(struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) +{ + const struct vkd3d_shader_tgsm_structured *tgsm = &ins->declaration.tgsm_structured; + struct sm4_instruction instr = + { + .opcode = VKD3D_SM5_OP_DCL_TGSM_STRUCTURED, + + .dsts[0] = tgsm->reg, + .dst_count = 1, + + .idx[0] = tgsm->byte_stride, + .idx[1] = tgsm->structure_count, + .idx_count = 2, + }; + + write_sm4_instruction(tpf, &instr); +} + +static void write_sm4_dcl_global_flags(struct tpf_compiler *tpf, uint32_t flags) { struct sm4_instruction instr = { @@ -3944,7 +3950,7 @@ static void write_sm4_dcl_global_flags(const struct tpf_compiler *tpf, uint32_t write_sm4_instruction(tpf, &instr); } -static void tpf_write_hs_decls(const struct tpf_compiler *tpf) +static void tpf_write_hs_decls(struct tpf_compiler *tpf) { struct sm4_instruction instr = { @@ -3954,7 +3960,7 @@ static void tpf_write_hs_decls(const struct tpf_compiler *tpf) write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_input_control_point_count(const struct tpf_compiler *tpf, const uint32_t count) +static void tpf_write_dcl_input_control_point_count(struct tpf_compiler *tpf, const uint32_t count) { struct sm4_instruction instr = { @@ -3965,7 +3971,7 @@ static void tpf_write_dcl_input_control_point_count(const struct tpf_compiler *t write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_output_control_point_count(const struct tpf_compiler *tpf, const uint32_t count) +static void tpf_write_dcl_output_control_point_count(struct tpf_compiler *tpf, const uint32_t count) { struct sm4_instruction instr = { @@ -3976,7 +3982,7 @@ static void tpf_write_dcl_output_control_point_count(const struct tpf_compiler * write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_tessellator_domain(const struct tpf_compiler *tpf, enum vkd3d_tessellator_domain domain) +static void tpf_write_dcl_tessellator_domain(struct tpf_compiler *tpf, enum vkd3d_tessellator_domain domain) { struct sm4_instruction instr = { @@ -3987,7 +3993,7 @@ static void tpf_write_dcl_tessellator_domain(const struct tpf_compiler *tpf, enu write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_tessellator_partitioning(const struct tpf_compiler *tpf, +static void tpf_write_dcl_tessellator_partitioning(struct tpf_compiler *tpf, enum vkd3d_shader_tessellator_partitioning partitioning) { struct sm4_instruction instr = @@ -3999,7 +4005,7 @@ static void tpf_write_dcl_tessellator_partitioning(const struct tpf_compiler *tp write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_tessellator_output_primitive(const struct tpf_compiler *tpf, +static void tpf_write_dcl_tessellator_output_primitive(struct tpf_compiler *tpf, enum vkd3d_shader_tessellator_output_primitive output_primitive) { struct sm4_instruction instr = @@ -4011,7 +4017,7 @@ static void tpf_write_dcl_tessellator_output_primitive(const struct tpf_compiler write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_input_primitive(const struct tpf_compiler *tpf, enum vkd3d_primitive_type input_primitive, +static void tpf_write_dcl_input_primitive(struct tpf_compiler *tpf, enum vkd3d_primitive_type input_primitive, unsigned int patch_vertex_count) { enum vkd3d_sm4_input_primitive_type sm4_input_primitive; @@ -4036,7 +4042,7 @@ static void tpf_write_dcl_input_primitive(const struct tpf_compiler *tpf, enum v write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_output_topology(const struct tpf_compiler *tpf, enum vkd3d_primitive_type output_topology) +static void tpf_write_dcl_output_topology(struct tpf_compiler *tpf, enum vkd3d_primitive_type output_topology) { struct sm4_instruction instr = { @@ -4049,7 +4055,7 @@ static void tpf_write_dcl_output_topology(const struct tpf_compiler *tpf, enum v write_sm4_instruction(tpf, &instr); } -static void tpf_write_dcl_vertices_out(const struct tpf_compiler *tpf, unsigned int count) +static void tpf_write_dcl_vertices_out(struct tpf_compiler *tpf, unsigned int count) { struct sm4_instruction instr = { @@ -4110,16 +4116,19 @@ static void tpf_simple_instruction(struct tpf_compiler *tpf, const struct vkd3d_ if (ins->dst_count != dst_count) { - ERR("Invalid destination count %zu for vsir instruction %#x (expected %u).\n", - ins->dst_count, ins->opcode, dst_count); - tpf->result = VKD3D_ERROR_INVALID_SHADER; + tpf_compiler_error(tpf, VKD3D_SHADER_ERROR_TPF_INTERNAL, + "Internal compiler error: Invalid destination operand count %zu " + "for instruction \"%s\" (%#x), expected %u.", + ins->dst_count, vsir_opcode_get_name(ins->opcode, "<unknown>"), ins->opcode, dst_count); return; } + if (ins->src_count != src_count) { - ERR("Invalid source count %zu for vsir instruction %#x (expected %u).\n", - ins->src_count, ins->opcode, src_count); - tpf->result = VKD3D_ERROR_INVALID_SHADER; + tpf_compiler_error(tpf, VKD3D_SHADER_ERROR_TPF_INTERNAL, + "Internal compiler error: Invalid source operand count %zu " + "for instruction \"%s\" (%#x), expected %u.", + ins->src_count, vsir_opcode_get_name(ins->opcode, "<unknown>"), ins->opcode, src_count); return; } @@ -4168,6 +4177,8 @@ static void tpf_simple_instruction(struct tpf_compiler *tpf, const struct vkd3d_ static void tpf_handle_instruction(struct tpf_compiler *tpf, const struct vkd3d_shader_instruction *ins) { + tpf->location = ins->location; + switch (ins->opcode) { case VSIR_OP_NOP: @@ -4229,6 +4240,10 @@ static void tpf_handle_instruction(struct tpf_compiler *tpf, const struct vkd3d_ tpf_dcl_tgsm_raw(tpf, ins); break; + case VSIR_OP_DCL_TGSM_STRUCTURED: + tpf_dcl_tgsm_structured(tpf, ins); + break; + case VSIR_OP_DCL: case VSIR_OP_DCL_RESOURCE_RAW: case VSIR_OP_DCL_RESOURCE_STRUCTURED: @@ -4351,6 +4366,7 @@ static void tpf_handle_instruction(struct tpf_compiler *tpf, const struct vkd3d_ case VSIR_OP_SINCOS: case VSIR_OP_SQRT: case VSIR_OP_STORE_RAW: + case VSIR_OP_STORE_STRUCTURED: case VSIR_OP_STORE_UAV_TYPED: case VSIR_OP_SWITCH: case VSIR_OP_UDIV: @@ -4365,7 +4381,9 @@ static void tpf_handle_instruction(struct tpf_compiler *tpf, const struct vkd3d_ break; default: - vkd3d_unreachable(); + tpf_compiler_error(tpf, VKD3D_SHADER_ERROR_TPF_NOT_IMPLEMENTED, + "Unhandled instruction \"%s\" (%#x).\n", + vsir_opcode_get_name(ins->opcode, "<unknown>"), ins->opcode); break; } } @@ -4543,6 +4561,8 @@ int tpf_compile(struct vsir_program *program, uint64_t config_flags, return ret; tpf.program = program; + tpf.location.source_name = compile_info->source_name; + tpf.message_context = message_context; tpf.buffer = NULL; tpf.stat = &stat; init_sm4_lookup_tables(&tpf.lookup); @@ -4557,11 +4577,7 @@ int tpf_compile(struct vsir_program *program, uint64_t config_flags, tpf_write_sfi0(&tpf); tpf_write_stat(&tpf); - ret = VKD3D_OK; - if (tpf.result) - ret = tpf.result; - - if (!ret) + if (!(ret = vkd3d_result_from_shader_error(tpf.first_error))) ret = dxbc_writer_write(&tpf.dxbc, out); for (i = 0; i < tpf.dxbc.section_count; ++i) vkd3d_shader_free_shader_code(&tpf.dxbc.sections[i].data); diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c index ee113f57736..ddbf91ac482 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c @@ -319,14 +319,21 @@ void vkd3d_string_buffer_release(struct vkd3d_string_buffer_cache *cache, struct cache->buffers[cache->count++] = buffer; } -void vkd3d_shader_code_from_string_buffer(struct vkd3d_shader_code *code, struct vkd3d_string_buffer *buffer) +static char *vkd3d_shader_string_from_string_buffer(struct vkd3d_string_buffer *buffer) { - code->code = buffer->buffer; - code->size = buffer->content_size; + char *s = buffer->buffer; buffer->buffer = NULL; buffer->buffer_size = 0; buffer->content_size = 0; + + return s; +} + +void vkd3d_shader_code_from_string_buffer(struct vkd3d_shader_code *code, struct vkd3d_string_buffer *buffer) +{ + code->size = buffer->content_size; + code->code = vkd3d_shader_string_from_string_buffer(buffer); } void vkd3d_shader_message_context_init(struct vkd3d_shader_message_context *context, @@ -347,23 +354,15 @@ void vkd3d_shader_message_context_trace_messages_(const struct vkd3d_shader_mess vkd3d_string_buffer_trace_(&context->messages, function); } -bool vkd3d_shader_message_context_copy_messages(struct vkd3d_shader_message_context *context, char **out) +void vkd3d_shader_string_from_message_context(char **out, struct vkd3d_shader_message_context *context) { - char *messages; - if (!out) - return true; - - *out = NULL; - - if (!context->messages.content_size) - return true; + return; - if (!(messages = vkd3d_malloc(context->messages.content_size + 1))) - return false; - memcpy(messages, context->messages.buffer, context->messages.content_size + 1); - *out = messages; - return true; + if (context->messages.content_size) + *out = vkd3d_shader_string_from_string_buffer(&context->messages); + else + *out = NULL; } void vkd3d_shader_vnote(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location, @@ -475,6 +474,11 @@ void vkd3d_shader_error(struct vkd3d_shader_message_context *context, const stru va_end(args); } +void vkd3d_bytecode_buffer_cleanup(struct vkd3d_bytecode_buffer *buffer) +{ + vkd3d_free(buffer->data); +} + size_t bytecode_align(struct vkd3d_bytecode_buffer *buffer) { size_t aligned_size = align(buffer->size, 4); @@ -553,6 +557,16 @@ void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char bytecode_set_bytes(buffer, offset, string, length); } +void vkd3d_shader_code_from_bytecode_buffer(struct vkd3d_shader_code *code, struct vkd3d_bytecode_buffer *buffer) +{ + code->size = buffer->size; + code->code = buffer->data; + + buffer->data = NULL; + buffer->size = 0; + buffer->capacity = 0; +} + struct shader_dump_data { uint8_t checksum[16]; @@ -564,8 +578,9 @@ struct shader_dump_data enum shader_dump_type { - SHADER_DUMP_TYPE_SOURCE, + SHADER_DUMP_TYPE_LOG, SHADER_DUMP_TYPE_PREPROC, + SHADER_DUMP_TYPE_SOURCE, SHADER_DUMP_TYPE_TARGET, }; @@ -595,10 +610,12 @@ static void vkd3d_shader_dump_shader(const struct shader_dump_data *dump_data, if (dump_data->profile) pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-%s", dump_data->profile); - if (type == SHADER_DUMP_TYPE_SOURCE) - pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-source.%s", dump_data->source_suffix); + if (type == SHADER_DUMP_TYPE_LOG) + pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, ".log"); else if (type == SHADER_DUMP_TYPE_PREPROC) pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-preproc.%s", dump_data->source_suffix); + else if (type == SHADER_DUMP_TYPE_SOURCE) + pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-source.%s", dump_data->source_suffix); else pos += snprintf(filename + pos, ARRAY_SIZE(filename) - pos, "-target.%s", dump_data->target_suffix); @@ -616,6 +633,17 @@ static void vkd3d_shader_dump_shader(const struct shader_dump_data *dump_data, } } +static void vkd3d_shader_dump_messages(const struct shader_dump_data *dump_data, + const struct vkd3d_shader_message_context *message_context) +{ + const struct vkd3d_string_buffer *messages = &message_context->messages; + + if (!messages->content_size) + return; + + vkd3d_shader_dump_shader(dump_data, messages->buffer, messages->content_size, SHADER_DUMP_TYPE_LOG); +} + static const char *shader_get_source_type_suffix(enum vkd3d_shader_source_type type) { switch (type) @@ -729,6 +757,7 @@ void vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, parser->location.source_name = source_name; parser->location.line = 1; parser->location.column = 0; + parser->status = VKD3D_OK; } void VKD3D_PRINTF_FUNC(3, 4) vkd3d_shader_parser_error(struct vkd3d_shader_parser *parser, @@ -962,6 +991,7 @@ struct vkd3d_shader_scan_context { VKD3D_SHADER_BLOCK_IF, VKD3D_SHADER_BLOCK_LOOP, + VKD3D_SHADER_BLOCK_REP, VKD3D_SHADER_BLOCK_SWITCH, } type; bool inside_block; @@ -1073,6 +1103,7 @@ static struct vkd3d_shader_cf_info *vkd3d_shader_scan_find_innermost_breakable_c { cf_info = &context->cf_info[--count]; if (cf_info->type == VKD3D_SHADER_BLOCK_LOOP + || cf_info->type == VKD3D_SHADER_BLOCK_REP || cf_info->type == VKD3D_SHADER_BLOCK_SWITCH) return cf_info; } @@ -1422,6 +1453,20 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte } vkd3d_shader_scan_pop_cf_info(context); break; + case VSIR_OP_REP: + cf_info = vkd3d_shader_scan_push_cf_info(context); + cf_info->type = VKD3D_SHADER_BLOCK_REP; + cf_info->inside_block = true; + break; + case VSIR_OP_ENDREP: + if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_REP) + { + vkd3d_shader_scan_error(context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + "Encountered ‘endrep’ instruction without corresponding ‘rep’ block."); + return VKD3D_ERROR_INVALID_SHADER; + } + vkd3d_shader_scan_pop_cf_info(context); + break; case VSIR_OP_SWITCH: cf_info = vkd3d_shader_scan_push_cf_info(context); cf_info->type = VKD3D_SHADER_BLOCK_SWITCH; @@ -1676,7 +1721,7 @@ static int vsir_program_scan(struct vsir_program *program, const struct vkd3d_sh add_descriptor_info = true; } - if (program->has_descriptor_info) + if (program->normalisation_flags.has_descriptor_info) add_descriptor_info = false; tessellation_info = vkd3d_find_struct(compile_info->next, SCAN_HULL_SHADER_TESSELLATION_INFO); @@ -1686,7 +1731,7 @@ static int vsir_program_scan(struct vsir_program *program, const struct vkd3d_sh add_descriptor_info ? &program->descriptors : NULL, combined_sampler_info, message_context); if (add_descriptor_info) - program->has_descriptor_info = true; + program->normalisation_flags.has_descriptor_info = true; if (TRACE_ON()) vsir_program_trace(program); @@ -1770,14 +1815,14 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char vsir_program_cleanup(&program); } + vkd3d_shader_dump_messages(&dump_data, &message_context); vkd3d_shader_message_context_trace_messages(&message_context); - if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) - ret = VKD3D_ERROR_OUT_OF_MEMORY; + vkd3d_shader_string_from_message_context(messages, &message_context); vkd3d_shader_message_context_cleanup(&message_context); return ret; } -static int vsir_program_compile(struct vsir_program *program, const struct vkd3d_shader_code *reflection_data, +int vsir_program_compile(struct vsir_program *program, const struct vkd3d_shader_code *reflection_data, uint64_t config_flags, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) { @@ -1918,9 +1963,9 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, if (ret >= 0) vkd3d_shader_dump_shader(&dump_data, out->code, out->size, SHADER_DUMP_TYPE_TARGET); + vkd3d_shader_dump_messages(&dump_data, &message_context); vkd3d_shader_message_context_trace_messages(&message_context); - if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) - ret = VKD3D_ERROR_OUT_OF_MEMORY; + vkd3d_shader_string_from_message_context(messages, &message_context); vkd3d_shader_message_context_cleanup(&message_context); return ret; } @@ -2015,7 +2060,7 @@ void shader_signature_cleanup(struct shader_signature *signature) { for (unsigned int i = 0; i < signature->element_count; ++i) { - vkd3d_free((void *)signature->elements[i].semantic_name); + vsir_signature_element_cleanup(&signature->elements[i]); } vkd3d_free(signature->elements); signature->elements = NULL; @@ -2038,9 +2083,7 @@ int vkd3d_shader_parse_input_signature(const struct vkd3d_shader_code *dxbc, ret = shader_parse_input_signature(dxbc, &message_context, &shader_signature); vkd3d_shader_message_context_trace_messages(&message_context); - if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) - ret = VKD3D_ERROR_OUT_OF_MEMORY; - + vkd3d_shader_string_from_message_context(messages, &message_context); vkd3d_shader_message_context_cleanup(&message_context); if (!vkd3d_shader_signature_from_shader_signature(signature, &shader_signature)) @@ -2244,9 +2287,9 @@ int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info if ((ret = preproc_lexer_parse(compile_info, out, &message_context)) >= 0) vkd3d_shader_dump_shader(&dump_data, out->code, out->size, SHADER_DUMP_TYPE_PREPROC); + vkd3d_shader_dump_messages(&dump_data, &message_context); vkd3d_shader_message_context_trace_messages(&message_context); - if (!vkd3d_shader_message_context_copy_messages(&message_context, messages)) - ret = VKD3D_ERROR_OUT_OF_MEMORY; + vkd3d_shader_string_from_message_context(messages, &message_context); vkd3d_shader_message_context_cleanup(&message_context); return ret; } diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 97fe5238046..7c278a63b80 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -90,6 +90,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION = 1008, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE = 1009, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL = 1010, + VKD3D_SHADER_ERROR_TPF_INTERNAL = 1011, + VKD3D_SHADER_ERROR_TPF_NOT_IMPLEMENTED = 1012, VKD3D_SHADER_WARNING_TPF_MASK_NOT_CONTIGUOUS = 1300, VKD3D_SHADER_WARNING_TPF_UNHANDLED_INDEX_RANGE_MASK = 1301, @@ -229,6 +231,11 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCE_HANDLE = 8019, VKD3D_SHADER_ERROR_DXIL_INVALID_CONSTANT = 8020, VKD3D_SHADER_ERROR_DXIL_NOT_IMPLEMENTED = 8021, + VKD3D_SHADER_ERROR_DXIL_DUPLICATED_BLOCK = 8022, + VKD3D_SHADER_ERROR_DXIL_INVALID_STRING = 8023, + VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE_KIND = 8024, + VKD3D_SHADER_ERROR_DXIL_INVALID_ATTRIBUTE = 8025, + VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE = 8026, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, @@ -241,6 +248,8 @@ enum vkd3d_shader_error VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION = 8308, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT = 8309, VKD3D_SHADER_WARNING_DXIL_UNDEFINED_OPERAND = 8310, + VKD3D_SHADER_WARNING_DXIL_IGNORING_RECORD = 8311, + VKD3D_SHADER_WARNING_DXIL_UNKNOWN_TYPE = 8312, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000, VKD3D_SHADER_ERROR_VSIR_INVALID_OPCODE = 9001, @@ -284,6 +293,22 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_FX_OUT_OF_MEMORY = 11004, }; +static inline enum vkd3d_result vkd3d_result_from_shader_error(enum vkd3d_shader_error e) +{ + if (!e) + return VKD3D_OK; + + switch (e) + { + case VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY: + return VKD3D_ERROR_OUT_OF_MEMORY; + case VKD3D_SHADER_ERROR_TPF_NOT_IMPLEMENTED: + return VKD3D_ERROR_NOT_IMPLEMENTED; + default: + return VKD3D_ERROR_INVALID_SHADER; + } +} + enum vkd3d_shader_opcode { VSIR_OP_ABS, @@ -628,6 +653,16 @@ enum vkd3d_shader_opcode const char *vsir_opcode_get_name(enum vkd3d_shader_opcode op, const char *error); +static inline bool vsir_opcode_is_fork_or_join_phase(enum vkd3d_shader_opcode op) +{ + return op == VSIR_OP_HS_FORK_PHASE || op == VSIR_OP_HS_JOIN_PHASE; +} + +static inline bool vsir_opcode_is_control_point_phase(enum vkd3d_shader_opcode op) +{ + return op == VSIR_OP_HS_CONTROL_POINT_PHASE; +} + enum vkd3d_shader_register_type { VKD3DSPR_TEMP, @@ -969,6 +1004,13 @@ struct vkd3d_shader_version uint8_t minor; }; +struct vsir_normalisation_flags +{ + bool has_descriptor_info; + bool has_no_modifiers; + bool normalised_clip_cull_arrays; +}; + struct vkd3d_shader_immediate_constant_buffer { unsigned int register_idx; @@ -993,7 +1035,7 @@ struct vkd3d_shader_indexable_temp struct vkd3d_shader_register_index { - struct vkd3d_shader_src_param *rel_addr; + struct vsir_src_operand *rel_addr; unsigned int offset; /* address is known to fall within the object (for optimisation) */ bool is_in_bounds; @@ -1052,7 +1094,7 @@ static inline enum vkd3d_shader_register_type vsir_register_type_from_sysval_inp } } -struct vkd3d_shader_dst_param +struct vsir_dst_operand { struct vkd3d_shader_register reg; uint32_t write_mask; @@ -1060,23 +1102,24 @@ struct vkd3d_shader_dst_param unsigned int shift; }; -struct vkd3d_shader_src_param +void vsir_dst_operand_init(struct vsir_dst_operand *dst, enum vkd3d_shader_register_type reg_type, + enum vsir_data_type data_type, unsigned int idx_count); +void vsir_dst_operand_init_null(struct vsir_dst_operand *dst); + +struct vsir_src_operand { struct vkd3d_shader_register reg; uint32_t swizzle; enum vkd3d_shader_src_modifier modifiers; }; -void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, - enum vsir_data_type data_type, unsigned int idx_count); -void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type, +void vsir_src_operand_init(struct vsir_src_operand *src, enum vkd3d_shader_register_type reg_type, enum vsir_data_type data_type, unsigned int idx_count); -void vsir_dst_param_init_null(struct vkd3d_shader_dst_param *dst); -void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id); +void vsir_src_operand_init_label(struct vsir_src_operand *src, unsigned int label_id); struct vkd3d_shader_index_range { - struct vkd3d_shader_dst_param dst; + struct vsir_dst_operand dst; unsigned int register_count; }; @@ -1088,7 +1131,7 @@ struct vkd3d_shader_register_range struct vkd3d_shader_resource { - struct vkd3d_shader_dst_param reg; + struct vsir_dst_operand reg; struct vkd3d_shader_register_range range; }; @@ -1152,6 +1195,17 @@ enum vkd3d_shader_input_sysval_semantic #define SIGNATURE_TARGET_LOCATION_UNUSED (~0u) +static inline bool vsir_sysval_semantic_is_tess_factor(enum vkd3d_shader_sysval_semantic sysval_semantic) +{ + return sysval_semantic >= VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE + && sysval_semantic <= VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN; +} + +static inline bool vsir_sysval_semantic_is_clip_cull(enum vkd3d_shader_sysval_semantic sysval_semantic) +{ + return sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE || sysval_semantic == VKD3D_SHADER_SV_CULL_DISTANCE; +} + struct signature_element { /* sort_index is not a property of the signature element, it is just a @@ -1175,28 +1229,37 @@ struct signature_element unsigned int target_location; }; -struct shader_signature +static inline void vsir_signature_element_cleanup(struct signature_element *e) { - struct signature_element *elements; - size_t elements_capacity; - unsigned int element_count; -}; + vkd3d_free((void *)e->semantic_name); +} -static inline bool vsir_sysval_semantic_is_tess_factor(enum vkd3d_shader_sysval_semantic sysval_semantic) +static inline bool vsir_signature_element_is_array(const struct signature_element *element, + const struct vsir_normalisation_flags *flags) { - return sysval_semantic >= VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE - && sysval_semantic <= VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN; + enum vkd3d_shader_sysval_semantic semantic = element->sysval_semantic; + + if (element->register_count > 1) + return true; + if (vsir_sysval_semantic_is_tess_factor(semantic)) + return true; + if (flags->normalised_clip_cull_arrays && vsir_sysval_semantic_is_clip_cull(semantic)) + return true; + return false; } -static inline bool vsir_sysval_semantic_is_clip_cull(enum vkd3d_shader_sysval_semantic sysval_semantic) +struct shader_signature { - return sysval_semantic == VKD3D_SHADER_SV_CLIP_DISTANCE || sysval_semantic == VKD3D_SHADER_SV_CULL_DISTANCE; -} + struct signature_element *elements; + size_t elements_capacity; + unsigned int element_count; +}; struct signature_element *vsir_signature_find_element_for_reg(const struct shader_signature *signature, unsigned int reg_idx, unsigned int write_mask); bool vsir_signature_find_sysval(const struct shader_signature *signature, enum vkd3d_shader_sysval_semantic sysval, unsigned int semantic_index, unsigned int *element_index); +unsigned int vsir_signature_next_location(const struct shader_signature *signature); void shader_signature_cleanup(struct shader_signature *signature); struct vsir_features @@ -1218,19 +1281,19 @@ struct dxbc_shader_desc struct vkd3d_shader_register_semantic { - struct vkd3d_shader_dst_param reg; + struct vsir_dst_operand reg; enum vkd3d_shader_input_sysval_semantic sysval_semantic; }; struct vkd3d_shader_sampler { - struct vkd3d_shader_src_param src; + struct vsir_src_operand src; struct vkd3d_shader_register_range range; }; struct vkd3d_shader_constant_buffer { - struct vkd3d_shader_src_param src; + struct vsir_src_operand src; unsigned int size; struct vkd3d_shader_register_range range; }; @@ -1254,7 +1317,7 @@ struct vkd3d_shader_tgsm struct vkd3d_shader_tgsm_raw { - struct vkd3d_shader_dst_param reg; + struct vsir_dst_operand reg; unsigned int alignment; unsigned int byte_count; bool zero_init; @@ -1262,7 +1325,7 @@ struct vkd3d_shader_tgsm_raw struct vkd3d_shader_tgsm_structured { - struct vkd3d_shader_dst_param reg; + struct vsir_dst_operand reg; unsigned int alignment; unsigned int byte_stride; unsigned int structure_count; @@ -1324,21 +1387,21 @@ struct vkd3d_shader_instruction uint32_t flags; size_t dst_count; size_t src_count; - struct vkd3d_shader_dst_param *dst; - struct vkd3d_shader_src_param *src; + struct vsir_dst_operand *dst; + struct vsir_src_operand *src; struct vkd3d_shader_texel_offset texel_offset; enum vkd3d_shader_resource_type resource_type; unsigned int resource_stride; enum vsir_data_type resource_data_type[VKD3D_VEC4_SIZE]; bool coissue, structured, raw; - const struct vkd3d_shader_src_param *predicate; + const struct vsir_src_operand *predicate; union { enum vsir_global_flags global_flags; struct vkd3d_shader_semantic semantic; struct vkd3d_shader_register_semantic register_semantic; struct vkd3d_shader_primitive_type primitive_type; - struct vkd3d_shader_dst_param dst; + struct vsir_dst_operand dst; struct vkd3d_shader_constant_buffer cb; struct vkd3d_shader_sampler sampler; unsigned int count; @@ -1439,6 +1502,8 @@ struct vkd3d_shader_instruction_array size_t count; }; +bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *array, size_t reserve); +void shader_instruction_array_cleanup(struct vkd3d_shader_instruction_array *array); struct vkd3d_shader_instruction *shader_instruction_array_append(struct vkd3d_shader_instruction_array *array); bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *instructions, size_t idx, size_t count); @@ -1536,6 +1601,24 @@ static inline struct vkd3d_shader_instruction *vsir_program_iterator_insert_befo return vsir_program_iterator_current(it); } +static inline void vsir_program_iterator_nop_range(const struct vsir_program_iterator *first, + const struct vsir_program_iterator *last, const struct vkd3d_shader_location *location) +{ + const struct vkd3d_shader_instruction_array *array = first->array; + size_t first_idx = first->idx; + size_t last_idx = last->idx; + size_t idx; + + VKD3D_ASSERT(last->array == array); + VKD3D_ASSERT(last_idx < array->count); + VKD3D_ASSERT(first_idx <= last_idx); + + for (idx = first_idx; idx <= last_idx; ++idx) + { + vsir_instruction_init(&array->elements[idx], location, VSIR_OP_NOP); + } +} + enum vkd3d_shader_config_flags { VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION = 0x00000001, @@ -1555,6 +1638,15 @@ enum vsir_normalisation_level VSIR_NORMALISED_SM6, }; +enum vsir_denorm_mode +{ + VSIR_DENORM_ANY = 0, + VSIR_DENORM_PRESERVE, + VSIR_DENORM_FLUSH_TO_ZERO, +}; + +const char *vsir_denorm_mode_get_name(enum vsir_denorm_mode m, const char *error); + struct vkd3d_shader_descriptor_info1 { enum vkd3d_shader_descriptor_type type; @@ -1592,7 +1684,6 @@ struct vsir_program struct shader_signature patch_constant_signature; struct vkd3d_shader_scan_descriptor_info1 descriptors; - bool has_descriptor_info; size_t descriptors_size; unsigned int parameter_count; @@ -1611,14 +1702,15 @@ struct vsir_program bool has_fog; uint8_t diffuse_written_mask; enum vsir_control_flow_type cf_type; - enum vsir_normalisation_level normalisation_level; - bool has_no_modifiers; enum vkd3d_tessellator_domain tess_domain; enum vkd3d_shader_tessellator_partitioning tess_partitioning; enum vkd3d_shader_tessellator_output_primitive tess_output_primitive; enum vkd3d_primitive_type input_primitive, output_topology; unsigned int vertices_out_count; + enum vsir_normalisation_level normalisation_level; + struct vsir_normalisation_flags normalisation_flags; + uint32_t io_dcls[VKD3D_BITMAP_SIZE(VKD3DSPR_COUNT)]; struct vsir_features features; @@ -1631,8 +1723,12 @@ struct vsir_program size_t icb_capacity; size_t icb_count; - struct vkd3d_shader_param_allocator src_params; - struct vkd3d_shader_param_allocator dst_params; + struct vkd3d_shader_param_allocator src_operands; + struct vkd3d_shader_param_allocator dst_operands; + + enum vsir_denorm_mode f16_denorm_mode; + enum vsir_denorm_mode f32_denorm_mode; + enum vsir_denorm_mode f64_denorm_mode; }; enum vkd3d_result vsir_allocate_temp_registers(struct vsir_program *program, @@ -1651,6 +1747,9 @@ const struct vkd3d_shader_parameter1 *vsir_program_get_parameter( bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_version *version, unsigned int reserve, enum vsir_control_flow_type cf_type, enum vsir_normalisation_level normalisation_level); +int vsir_program_compile(struct vsir_program *program, const struct vkd3d_shader_code *reflection_data, + uint64_t config_flags, const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); enum vkd3d_result vsir_program_lower_d3dbc(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_optimize(struct vsir_program *program, uint64_t config_flags, @@ -1661,8 +1760,7 @@ enum vkd3d_result vsir_program_transform_early(struct vsir_program *program, uin const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, const char *source_name, struct vkd3d_shader_message_context *message_context); -struct vkd3d_shader_src_param *vsir_program_create_outpointid_param( - struct vsir_program *program); +struct vsir_src_operand *vsir_program_create_outpointid_param(struct vsir_program *program); bool vsir_instruction_init_with_params(struct vsir_program *program, struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, enum vkd3d_shader_opcode opcode, unsigned int dst_count, unsigned int src_count); @@ -1672,22 +1770,22 @@ static inline struct vkd3d_shader_instruction *vsir_program_append(struct vsir_p return shader_instruction_array_append(&program->instructions); } -static inline struct vkd3d_shader_dst_param *vsir_program_get_dst_params( +static inline struct vsir_dst_operand *vsir_program_get_dst_operands( struct vsir_program *program, unsigned int count) { - struct vkd3d_shader_param_allocator *allocator = &program->dst_params; + struct vkd3d_shader_param_allocator *allocator = &program->dst_operands; - VKD3D_ASSERT(allocator->stride == sizeof(struct vkd3d_shader_dst_param)); + VKD3D_ASSERT(allocator->stride == sizeof(struct vsir_dst_operand)); return shader_param_allocator_get(allocator, count); } -static inline struct vkd3d_shader_src_param *vsir_program_get_src_params( +static inline struct vsir_src_operand *vsir_program_get_src_operands( struct vsir_program *program, unsigned int count) { - struct vkd3d_shader_param_allocator *allocator = &program->src_params; + struct vkd3d_shader_param_allocator *allocator = &program->src_operands; - VKD3D_ASSERT(allocator->stride == sizeof(struct vkd3d_shader_src_param)); + VKD3D_ASSERT(allocator->stride == sizeof(struct vsir_src_operand)); return shader_param_allocator_get(allocator, count); } @@ -1730,6 +1828,7 @@ enum vsir_asm_flags VSIR_ASM_FLAG_DUMP_SIGNATURES = 0x4, VSIR_ASM_FLAG_DUMP_DESCRIPTORS = 0x8, VSIR_ASM_FLAG_ALLOCATE_TEMPS = 0x10, + VSIR_ASM_FLAG_DUMP_DENORM_MODES = 0x20, }; enum vkd3d_result d3d_asm_compile(struct vsir_program *program, @@ -1767,6 +1866,8 @@ size_t bytecode_put_bytes_unaligned(struct vkd3d_bytecode_buffer *buffer, const size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size); void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value); void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length); +void vkd3d_bytecode_buffer_cleanup(struct vkd3d_bytecode_buffer *buffer); +void vkd3d_shader_code_from_bytecode_buffer(struct vkd3d_shader_code *code, struct vkd3d_bytecode_buffer *buffer); static inline size_t put_u32(struct vkd3d_bytecode_buffer *buffer, uint32_t value) { @@ -1797,7 +1898,6 @@ struct vkd3d_shader_message_context }; void vkd3d_shader_message_context_cleanup(struct vkd3d_shader_message_context *context); -bool vkd3d_shader_message_context_copy_messages(struct vkd3d_shader_message_context *context, char **out); void vkd3d_shader_message_context_init(struct vkd3d_shader_message_context *context, enum vkd3d_shader_log_level log_level); void vkd3d_shader_message_context_trace_messages_(const struct vkd3d_shader_message_context *context, @@ -1815,6 +1915,8 @@ void vkd3d_shader_warning(struct vkd3d_shader_message_context *context, const st void vkd3d_shader_vwarning(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location, enum vkd3d_shader_error error, const char *format, va_list args); +void vkd3d_shader_string_from_message_context(char **out, struct vkd3d_shader_message_context *context); + uint64_t vkd3d_shader_init_config_flags(void); void vkd3d_shader_trace_text_(const char *text, size_t size, const char *function); #define vkd3d_shader_trace_text(text, size) \ diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c index 69f42280e8a..84407e05cdb 100644 --- a/libs/vkd3d/libs/vkd3d/command.c +++ b/libs/vkd3d/libs/vkd3d/command.c @@ -31,6 +31,43 @@ static void d3d12_command_queue_submit_locked(struct d3d12_command_queue *queue) static HRESULT d3d12_command_queue_flush_ops(struct d3d12_command_queue *queue, bool *flushed_any); static HRESULT d3d12_command_queue_flush_ops_locked(struct d3d12_command_queue *queue, bool *flushed_any); +static void vkd3d_resource_list_cleanup(struct vkd3d_resource_list *list) +{ + vkd3d_free(list->resources); +} + +static void vkd3d_resource_list_init(struct vkd3d_resource_list *list) +{ + list->resources = NULL; + list->count = 0; + list->capacity = 0; +} + +static bool vkd3d_resource_list_contains(const struct vkd3d_resource_list *list, struct d3d12_resource *resource) +{ + size_t i; + + for (i = 0; i < list->count; i++) + { + if (list->resources[i] == resource) + return true; + } + + return false; +} + +static void vkd3d_resource_list_append(struct vkd3d_resource_list *list, struct d3d12_resource *resource) +{ + if (!vkd3d_array_reserve((void **)&list->resources, &list->capacity, list->count + 1, sizeof(*list->resources))) + ERR("Failed to grow resource list.\n"); + list->resources[list->count++] = resource; +} + +static void vkd3d_resource_list_clear(struct vkd3d_resource_list *list) +{ + list->count = 0; +} + static void vkd3d_null_event_signal(struct vkd3d_null_event *e) { vkd3d_mutex_lock(&e->mutex); @@ -1234,6 +1271,7 @@ static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device * fence->timeline_semaphore = VK_NULL_HANDLE; fence->timeline_value = 0; fence->pending_timeline_value = 0; + fence->last_waited_value = 0; if (device->vk_info.KHR_timeline_semaphore && (vr = vkd3d_create_timeline_semaphore(device, 0, &fence->timeline_semaphore)) < 0) { @@ -2533,6 +2571,9 @@ static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandL vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COMPUTE]); vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_GRAPHICS]); + vkd3d_resource_list_cleanup(&list->rtv_resources_since_last_barrier); + vkd3d_resource_list_cleanup(&list->dsv_resources_since_last_barrier); + vkd3d_free(list); d3d12_device_release(device); @@ -2659,6 +2700,10 @@ static void d3d12_command_list_reset_state(struct d3d12_command_list *list, list->fb_width = 0; list->fb_height = 0; list->fb_layer_count = 0; + memset(list->rtv_resources, 0, sizeof(list->rtv_resources)); + list->dsv_resource = NULL; + vkd3d_resource_list_clear(&list->rtv_resources_since_last_barrier); + vkd3d_resource_list_clear(&list->dsv_resources_since_last_barrier); list->xfb_enabled = false; list->has_depth_bounds = false; @@ -3469,6 +3514,82 @@ static bool d3d12_command_list_update_compute_state(struct d3d12_command_list *l return true; } +/* Add a barrier to prevent hazards between multiple render passes to the same image. */ +static void d3d12_command_list_emit_rt_barrier(struct d3d12_command_list *list, bool colour, bool depth) +{ + const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; + VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER }; + VkPipelineStageFlags srcStage = 0; + VkPipelineStageFlags dstStage = 0; + + if (colour) + { + srcStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dstStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + barrier.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + } + + if (depth) + { + srcStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dstStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + barrier.srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + } + + VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, srcStage, dstStage, + VK_DEPENDENCY_BY_REGION_BIT, 1, &barrier, 0, NULL, 0, NULL)); + if (colour) + vkd3d_resource_list_clear(&list->rtv_resources_since_last_barrier); + if (depth) + vkd3d_resource_list_clear(&list->rtv_resources_since_last_barrier); +} + +static void d3d12_command_list_check_render_pass_hazards(struct d3d12_command_list *list) +{ + struct d3d12_graphics_pipeline_state *graphics = &list->state->u.graphics; + bool rtv_hazard = false; + bool dsv_hazard = false; + unsigned int i; + + for (i = 0; i < graphics->rt_count; ++i) + { + if (graphics->null_attachment_mask & (1u << i)) + continue; + + if (!list->rtv_resources[i]) + continue; + + if (vkd3d_resource_list_contains(&list->rtv_resources_since_last_barrier, list->rtv_resources[i])) + { + rtv_hazard = true; + break; + } + } + + dsv_hazard = d3d12_command_list_has_depth_stencil_view(list) && list->dsv_resource + && vkd3d_resource_list_contains(&list->dsv_resources_since_last_barrier, list->dsv_resource); + + if (rtv_hazard || dsv_hazard) + d3d12_command_list_emit_rt_barrier(list, rtv_hazard, dsv_hazard); + + for (i = 0; i < graphics->rt_count; ++i) + { + if (graphics->null_attachment_mask & (1u << i)) + continue; + + if (!list->rtv_resources[i]) + continue; + + vkd3d_resource_list_append(&list->rtv_resources_since_last_barrier, list->rtv_resources[i]); + } + + if (d3d12_command_list_has_depth_stencil_view(list) && list->dsv_resource) + vkd3d_resource_list_append(&list->dsv_resources_since_last_barrier, list->dsv_resource); +} + static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list) { const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; @@ -3486,6 +3607,8 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list if (list->current_render_pass != VK_NULL_HANDLE) return true; + d3d12_command_list_check_render_pass_hazards(list); + vk_render_pass = list->pso_render_pass; VKD3D_ASSERT(vk_render_pass); @@ -5137,6 +5260,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi { WARN("RTV descriptor %u is not initialized.\n", i); list->rtvs[i] = VK_NULL_HANDLE; + list->rtv_resources[i] = NULL; continue; } @@ -5150,6 +5274,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi } list->rtvs[i] = view->v.u.vk_image_view; + list->rtv_resources[i] = rtv_desc->resource; list->fb_width = max(list->fb_width, rtv_desc->width); list->fb_height = max(list->fb_height, rtv_desc->height); list->fb_layer_count = max(list->fb_layer_count, rtv_desc->layer_count); @@ -5171,9 +5296,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi { WARN("Failed to add view.\n"); list->dsv = VK_NULL_HANDLE; + list->dsv_resource = NULL; } list->dsv = view->v.u.vk_image_view; + list->dsv_resource = dsv_desc->resource; list->fb_width = max(list->fb_width, dsv_desc->width); list->fb_height = max(list->fb_height, dsv_desc->height); list->fb_layer_count = max(list->fb_layer_count, dsv_desc->layer_count); @@ -5209,8 +5336,6 @@ static void d3d12_command_list_clear(struct d3d12_command_list *list, unsigned int i; VkResult vr; - d3d12_command_list_end_current_render_pass(list); - if (!rect_count) { full_rect.top = 0; @@ -5344,6 +5469,12 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(ID3D12Gra ds_reference.attachment = 0; ds_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + d3d12_command_list_end_current_render_pass(list); + + if (vkd3d_resource_list_contains(&list->dsv_resources_since_last_barrier, dsv_desc->resource)) + d3d12_command_list_emit_rt_barrier(list, false, true); + vkd3d_resource_list_append(&list->dsv_resources_since_last_barrier, dsv_desc->resource); + d3d12_command_list_clear(list, &attachment_desc, NULL, &ds_reference, dsv_desc->view, dsv_desc->width, dsv_desc->height, dsv_desc->layer_count, &clear_value, rect_count, rects); @@ -5398,6 +5529,12 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(ID3D12Gra clear_value.color.float32[3] = color[3]; } + d3d12_command_list_end_current_render_pass(list); + + if (vkd3d_resource_list_contains(&list->rtv_resources_since_last_barrier, rtv_desc->resource)) + d3d12_command_list_emit_rt_barrier(list, true, false); + vkd3d_resource_list_append(&list->rtv_resources_since_last_barrier, rtv_desc->resource); + d3d12_command_list_clear(list, &attachment_desc, &color_reference, NULL, rtv_desc->view, rtv_desc->width, rtv_desc->height, rtv_desc->layer_count, &clear_value, rect_count, rects); @@ -6395,6 +6532,9 @@ static HRESULT d3d12_command_list_init(struct d3d12_command_list *list, list->type = type; + vkd3d_resource_list_init(&list->rtv_resources_since_last_barrier); + vkd3d_resource_list_init(&list->dsv_resources_since_last_barrier); + if (FAILED(hr = vkd3d_private_store_init(&list->private_store))) return hr; @@ -7195,6 +7335,7 @@ static HRESULT d3d12_command_queue_wait_binary_semaphore_locked(struct d3d12_com command_queue->last_waited_fence = fence; command_queue->last_waited_fence_value = value; + fence->last_waited_value = value; } vkd3d_queue_release(queue); @@ -7521,8 +7662,14 @@ static HRESULT d3d12_command_queue_flush_ops_locked(struct d3d12_command_queue * vkd3d_mutex_lock(&fence->mutex); if (op->u.wait.value > fence->max_pending_value) { + uint64_t last_waited_value = fence->last_waited_value; + vkd3d_mutex_unlock(&fence->mutex); d3d12_command_queue_delete_aux_ops(queue, i); + if (op->u.wait.value <= last_waited_value) + ERR("Waiting on a value already waited on by a fence (%p %"PRIx64" <= %"PRIx64"). " + "This application probably requires Vulkan timeline semaphores to work correctly.\n", + fence, op->u.wait.value, last_waited_value); vkd3d_mutex_lock(&queue->op_mutex); return d3d12_command_queue_fixup_after_flush_locked(queue); } diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c index 6af5e2a5c7d..170ee7fe5aa 100644 --- a/libs/vkd3d/libs/vkd3d/device.c +++ b/libs/vkd3d/libs/vkd3d/device.c @@ -109,6 +109,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(EXT_FRAGMENT_SHADER_INTERLOCK, EXT_fragment_shader_interlock), VK_EXTENSION(EXT_MUTABLE_DESCRIPTOR_TYPE, EXT_mutable_descriptor_type), VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2), + VK_EXTENSION(EXT_SAMPLER_FILTER_MINMAX, EXT_sampler_filter_minmax), VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation), VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export), VK_EXTENSION(EXT_SHADER_VIEWPORT_INDEX_LAYER, EXT_shader_viewport_index_layer), @@ -232,18 +233,18 @@ static HRESULT vkd3d_vk_descriptor_heap_layouts_init(struct d3d12_device *device switch (device->vk_descriptor_heap_layouts[set].type) { case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - device->vk_descriptor_heap_layouts[set].count = limits->uniform_buffer_max_descriptors; + device->vk_descriptor_heap_layouts[set].count = limits->max_cbv_descriptor_count; break; case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - device->vk_descriptor_heap_layouts[set].count = limits->sampled_image_max_descriptors; + device->vk_descriptor_heap_layouts[set].count = limits->max_srv_descriptor_count; break; case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - device->vk_descriptor_heap_layouts[set].count = limits->storage_image_max_descriptors; + device->vk_descriptor_heap_layouts[set].count = limits->max_uav_descriptor_count; break; case VK_DESCRIPTOR_TYPE_SAMPLER: - device->vk_descriptor_heap_layouts[set].count = limits->sampler_max_descriptors; + device->vk_descriptor_heap_layouts[set].count = limits->max_sampler_descriptor_count; break; default: ERR("Unhandled descriptor type %#x.\n", device->vk_descriptor_heap_layouts[set].type); @@ -835,6 +836,7 @@ struct vkd3d_physical_device_info /* properties */ VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptor_indexing_properties; VkPhysicalDeviceMaintenance3Properties maintenance3_properties; + VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT filter_minmax_properties; VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT texel_buffer_alignment_properties; VkPhysicalDeviceTransformFeedbackPropertiesEXT xfb_properties; VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_divisor_properties; @@ -900,6 +902,8 @@ static void vkd3d_chain_physical_device_info_structures(struct vkd3d_physical_de vk_prepend_struct(&info->properties2, &info->maintenance3_properties); if (vulkan_info->EXT_descriptor_indexing) vk_prepend_struct(&info->properties2, &info->descriptor_indexing_properties); + if (vulkan_info->EXT_sampler_filter_minmax) + vk_prepend_struct(&info->properties2, &info->filter_minmax_properties); if (vulkan_info->EXT_texel_buffer_alignment) vk_prepend_struct(&info->properties2, &info->texel_buffer_alignment_properties); if (vulkan_info->EXT_transform_feedback) @@ -936,6 +940,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i info->properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; info->maintenance3_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES; info->descriptor_indexing_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT; + info->filter_minmax_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT; info->texel_buffer_alignment_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT; info->xfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT; info->vertex_divisor_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT; @@ -1017,6 +1022,7 @@ static void vkd3d_trace_physical_device_limits(const struct vkd3d_physical_devic const VkPhysicalDeviceLimits *limits = &info->properties2.properties.limits; const VkPhysicalDeviceDescriptorIndexingPropertiesEXT *descriptor_indexing; const VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *buffer_alignment; + const VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT *minmax; const VkPhysicalDeviceMaintenance3Properties *maintenance3; const VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb; @@ -1196,6 +1202,11 @@ static void vkd3d_trace_physical_device_limits(const struct vkd3d_physical_devic TRACE(" maxPerSetDescriptors: %u.\n", maintenance3->maxPerSetDescriptors); TRACE(" maxMemoryAllocationSize: %#"PRIx64".\n", maintenance3->maxMemoryAllocationSize); + minmax = &info->filter_minmax_properties; + TRACE(" VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT:\n"); + TRACE(" filterMinmaxSingleComponentFormats: %#x.\n", minmax->filterMinmaxSingleComponentFormats); + TRACE(" filterMinmaxImageComponentMapping: %#x.\n", minmax->filterMinmaxImageComponentMapping); + buffer_alignment = &info->texel_buffer_alignment_properties; TRACE(" VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT:\n"); TRACE(" storageTexelBufferOffsetAlignmentBytes: %#"PRIx64".\n", @@ -1476,11 +1487,11 @@ static void vkd3d_init_feature_level(struct vkd3d_vulkan_info *vk_info, static void vkd3d_device_descriptor_limits_init(struct vkd3d_device_descriptor_limits *limits, const VkPhysicalDeviceLimits *device_limits) { - limits->uniform_buffer_max_descriptors = device_limits->maxDescriptorSetUniformBuffers; - limits->sampled_image_max_descriptors = device_limits->maxDescriptorSetSampledImages; - limits->storage_buffer_max_descriptors = device_limits->maxDescriptorSetStorageBuffers; - limits->storage_image_max_descriptors = device_limits->maxDescriptorSetStorageImages; - limits->sampler_max_descriptors = min(device_limits->maxDescriptorSetSamplers, VKD3D_MAX_DESCRIPTOR_SET_SAMPLERS); + limits->max_cbv_descriptor_count = device_limits->maxDescriptorSetUniformBuffers; + limits->max_srv_descriptor_count = device_limits->maxDescriptorSetSampledImages; + limits->max_uav_descriptor_count = device_limits->maxDescriptorSetStorageImages; + limits->max_sampler_descriptor_count = min(device_limits->maxDescriptorSetSamplers, + VKD3D_MAX_DESCRIPTOR_SET_SAMPLERS); } static void vkd3d_device_vk_heaps_descriptor_limits_init(struct vkd3d_device_descriptor_limits *limits, @@ -1500,22 +1511,19 @@ static void vkd3d_device_vk_heaps_descriptor_limits_init(struct vkd3d_device_des uav_divisor = properties->maxDescriptorSetUpdateAfterBindSampledImages >= (3u << 20) ? 3 : 2; } - limits->uniform_buffer_max_descriptors = min(min(properties->maxDescriptorSetUpdateAfterBindUniformBuffers, + limits->max_cbv_descriptor_count = min(min(properties->maxDescriptorSetUpdateAfterBindUniformBuffers, properties->maxPerStageDescriptorUpdateAfterBindUniformBuffers - root_provision), VKD3D_MAX_DESCRIPTOR_SET_CBVS_SRVS_UAVS); - limits->sampled_image_max_descriptors = min(min(properties->maxDescriptorSetUpdateAfterBindSampledImages, + limits->max_srv_descriptor_count = min(min(properties->maxDescriptorSetUpdateAfterBindSampledImages, properties->maxPerStageDescriptorUpdateAfterBindSampledImages / srv_divisor - root_provision), VKD3D_MAX_DESCRIPTOR_SET_CBVS_SRVS_UAVS); - limits->storage_buffer_max_descriptors = min(min(properties->maxDescriptorSetUpdateAfterBindStorageBuffers, - properties->maxPerStageDescriptorUpdateAfterBindStorageBuffers - root_provision), - VKD3D_MAX_DESCRIPTOR_SET_CBVS_SRVS_UAVS); - limits->storage_image_max_descriptors = min(min(properties->maxDescriptorSetUpdateAfterBindStorageImages, + limits->max_uav_descriptor_count = min(min(properties->maxDescriptorSetUpdateAfterBindStorageImages, properties->maxPerStageDescriptorUpdateAfterBindStorageImages / uav_divisor - root_provision), VKD3D_MAX_DESCRIPTOR_SET_CBVS_SRVS_UAVS); - limits->sampler_max_descriptors = min(min(properties->maxDescriptorSetUpdateAfterBindSamplers, + limits->max_sampler_descriptor_count = min(min(properties->maxDescriptorSetUpdateAfterBindSamplers, properties->maxPerStageDescriptorUpdateAfterBindSamplers - root_provision), VKD3D_MAX_DESCRIPTOR_SET_CBVS_SRVS_UAVS); - limits->sampler_max_descriptors = min(limits->sampler_max_descriptors, VKD3D_MAX_DESCRIPTOR_SET_SAMPLERS); + limits->max_sampler_descriptor_count = min(limits->max_sampler_descriptor_count, VKD3D_MAX_DESCRIPTOR_SET_SAMPLERS); } static bool d3d12_device_supports_typed_uav_load_additional_formats(const struct d3d12_device *device) @@ -1866,6 +1874,12 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, physical_device_info->formats4444_features.formatA4B4G4R4 = VK_FALSE; + if (!vulkan_info->EXT_sampler_filter_minmax) + WARN("Sampler min/max reduction filtering is not supported.\n"); + else if (!physical_device_info->filter_minmax_properties.filterMinmaxSingleComponentFormats + || !physical_device_info->filter_minmax_properties.filterMinmaxImageComponentMapping) + WARN("Sampler min/max reduction filtering is only partially supported."); + vulkan_info->texel_buffer_alignment_properties = physical_device_info->texel_buffer_alignment_properties; if (get_spec_version(vk_extensions, vk_extension_count, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) >= 3) @@ -2713,13 +2727,13 @@ static void device_init_descriptor_pool_sizes(struct d3d12_device *device) const struct vkd3d_device_descriptor_limits *limits = &device->vk_info.descriptor_limits; unsigned int *pool_sizes = device->vk_pool_limits; - pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_CBV] = min(limits->uniform_buffer_max_descriptors, + pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_CBV] = min(limits->max_cbv_descriptor_count, VKD3D_MAX_VIRTUAL_HEAP_DESCRIPTORS_PER_TYPE); - pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_SRV] = min(limits->sampled_image_max_descriptors, + pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_SRV] = min(limits->max_srv_descriptor_count, VKD3D_MAX_VIRTUAL_HEAP_DESCRIPTORS_PER_TYPE); - pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_UAV] = min(limits->storage_image_max_descriptors, + pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_UAV] = min(limits->max_uav_descriptor_count, VKD3D_MAX_VIRTUAL_HEAP_DESCRIPTORS_PER_TYPE); - pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER] = min(limits->sampler_max_descriptors, + pool_sizes[VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER] = min(limits->max_sampler_descriptor_count, VKD3D_MAX_VIRTUAL_HEAP_DESCRIPTORS_PER_TYPE); }; diff --git a/libs/vkd3d/libs/vkd3d/resource.c b/libs/vkd3d/libs/vkd3d/resource.c index 7946445ad07..f1491cbc2b6 100644 --- a/libs/vkd3d/libs/vkd3d/resource.c +++ b/libs/vkd3d/libs/vkd3d/resource.c @@ -3661,6 +3661,24 @@ bool vkd3d_create_raw_buffer_view(struct d3d12_device *device, } /* samplers */ + +static VkSamplerReductionModeEXT vk_reduction_mode_from_d3d12(D3D12_FILTER_REDUCTION_TYPE mode) +{ + switch (mode) + { + case D3D12_FILTER_REDUCTION_TYPE_STANDARD: + case D3D12_FILTER_REDUCTION_TYPE_COMPARISON: + return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE; + case D3D12_FILTER_REDUCTION_TYPE_MINIMUM: + return VK_SAMPLER_REDUCTION_MODE_MIN; + case D3D12_FILTER_REDUCTION_TYPE_MAXIMUM: + return VK_SAMPLER_REDUCTION_MODE_MAX; + default: + FIXME("Unhandled reduction mode %#x.\n", mode); + return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE; + } +} + static VkFilter vk_filter_from_d3d12(D3D12_FILTER_TYPE type) { switch (type) @@ -3734,16 +3752,13 @@ static VkResult d3d12_create_sampler(struct d3d12_device *device, D3D12_FILTER f D3D12_COMPARISON_FUNC comparison_func, D3D12_STATIC_BORDER_COLOR border_colour, float min_lod, float max_lod, VkSampler *vk_sampler) { + VkSamplerReductionModeCreateInfoEXT reduction_desc; const struct vkd3d_vk_device_procs *vk_procs; struct VkSamplerCreateInfo sampler_desc; VkResult vr; vk_procs = &device->vk_procs; - if (D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_MINIMUM - || D3D12_DECODE_FILTER_REDUCTION(filter) == D3D12_FILTER_REDUCTION_TYPE_MAXIMUM) - FIXME("Min/max reduction mode not supported.\n"); - sampler_desc.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_desc.pNext = NULL; sampler_desc.flags = 0; @@ -3767,6 +3782,21 @@ static VkResult d3d12_create_sampler(struct d3d12_device *device, D3D12_FILTER f || address_w == D3D12_TEXTURE_ADDRESS_MODE_BORDER) sampler_desc.borderColor = vk_border_colour_from_d3d12(border_colour); + reduction_desc.reductionMode = vk_reduction_mode_from_d3d12(D3D12_DECODE_FILTER_REDUCTION(filter)); + if (reduction_desc.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE) + { + if (device->vk_info.EXT_sampler_filter_minmax) + { + reduction_desc.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT; + reduction_desc.pNext = NULL; + vk_prepend_struct(&sampler_desc, &reduction_desc); + } + else + { + FIXME("Sampler min/max reduction filtering is not supported by the device.\n"); + } + } + if ((vr = VK_CALL(vkCreateSampler(device->vk_device, &sampler_desc, NULL, vk_sampler))) < 0) WARN("Failed to create Vulkan sampler, vr %d.\n", vr); diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c index 4bd97fd599f..d733165312c 100644 --- a/libs/vkd3d/libs/vkd3d/state.c +++ b/libs/vkd3d/libs/vkd3d/state.c @@ -938,19 +938,19 @@ static unsigned int vk_binding_count_from_descriptor_range(const struct d3d12_ro switch (range->type) { case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: - limit = limits->uniform_buffer_max_descriptors; + limit = limits->max_cbv_descriptor_count; count = (limit - min(info->cbv_count, limit)) / info->cbv_unbounded_range_count; break; case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV: - limit = limits->sampled_image_max_descriptors; + limit = limits->max_srv_descriptor_count; count = (limit - min(info->srv_count, limit)) / info->srv_unbounded_range_count; break; case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV: - limit = limits->storage_image_max_descriptors; + limit = limits->max_uav_descriptor_count; count = (limit - min(info->uav_count, limit)) / info->uav_unbounded_range_count; break; case VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER: - limit = limits->sampler_max_descriptors; + limit = limits->max_sampler_descriptor_count; count = (limit - min(info->sampler_count, limit)) / info->sampler_unbounded_range_count; break; default: @@ -1084,36 +1084,36 @@ static void vkd3d_descriptor_heap_binding_from_descriptor_range(const struct d3d if (range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER) { binding->set = VKD3D_SET_INDEX_SAMPLER; - descriptor_set_size = descriptor_limits->sampler_max_descriptors; + descriptor_set_size = descriptor_limits->max_sampler_descriptor_count; } else { binding->set = VKD3D_SET_INDEX_MUTABLE; - descriptor_set_size = descriptor_limits->sampled_image_max_descriptors; + descriptor_set_size = descriptor_limits->max_srv_descriptor_count; } } else switch (range->type) { case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV: binding->set = is_buffer ? VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER : VKD3D_SET_INDEX_SAMPLED_IMAGE; - descriptor_set_size = descriptor_limits->sampled_image_max_descriptors; + descriptor_set_size = descriptor_limits->max_srv_descriptor_count; break; case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV: binding->set = is_buffer ? VKD3D_SET_INDEX_STORAGE_TEXEL_BUFFER : VKD3D_SET_INDEX_STORAGE_IMAGE; - descriptor_set_size = descriptor_limits->storage_image_max_descriptors; + descriptor_set_size = descriptor_limits->max_uav_descriptor_count; break; case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: binding->set = VKD3D_SET_INDEX_UNIFORM_BUFFER; - descriptor_set_size = descriptor_limits->uniform_buffer_max_descriptors; + descriptor_set_size = descriptor_limits->max_cbv_descriptor_count; break; case VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER: binding->set = VKD3D_SET_INDEX_SAMPLER; - descriptor_set_size = descriptor_limits->sampler_max_descriptors; + descriptor_set_size = descriptor_limits->max_sampler_descriptor_count; break; default: FIXME("Unhandled descriptor range type type %#x.\n", range->type); binding->set = VKD3D_SET_INDEX_SAMPLED_IMAGE; - descriptor_set_size = descriptor_limits->sampled_image_max_descriptors; + descriptor_set_size = descriptor_limits->max_srv_descriptor_count; break; } binding->set += root_signature->vk_set_count; @@ -1151,7 +1151,7 @@ static void d3d12_root_signature_map_vk_heap_uav_counter(struct d3d12_root_signa mapping->binding.set = root_signature->vk_set_count + VKD3D_SET_INDEX_UAV_COUNTER; mapping->binding.binding = 0; mapping->binding.count = vk_heap_binding_count_from_descriptor_range(range, - root_signature->device->vk_info.descriptor_limits.storage_image_max_descriptors); + root_signature->device->vk_info.descriptor_limits.max_uav_descriptor_count); offset->static_offset = range->offset; offset->dynamic_offset_index = context->push_constant_index; } diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h index 0a8c5aef674..e9f835acddd 100644 --- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h @@ -108,11 +108,10 @@ HRESULT hresult_from_vkd3d_result(int vkd3d_result); struct vkd3d_device_descriptor_limits { - unsigned int uniform_buffer_max_descriptors; - unsigned int sampled_image_max_descriptors; - unsigned int storage_buffer_max_descriptors; - unsigned int storage_image_max_descriptors; - unsigned int sampler_max_descriptors; + unsigned int max_cbv_descriptor_count; + unsigned int max_srv_descriptor_count; + unsigned int max_uav_descriptor_count; + unsigned int max_sampler_descriptor_count; }; struct vkd3d_vulkan_info @@ -144,6 +143,7 @@ struct vkd3d_vulkan_info bool EXT_fragment_shader_interlock; bool EXT_mutable_descriptor_type; bool EXT_robustness2; + bool EXT_sampler_filter_minmax; bool EXT_shader_demote_to_helper_invocation; bool EXT_shader_stencil_export; bool EXT_shader_viewport_index_layer; @@ -396,6 +396,7 @@ struct d3d12_fence uint64_t value; uint64_t max_pending_value; + uint64_t last_waited_value; struct vkd3d_mutex mutex; struct vkd3d_waiting_event @@ -1277,6 +1278,13 @@ enum vkd3d_pipeline_bind_point VKD3D_PIPELINE_BIND_POINT_COUNT = 0x2, }; +struct vkd3d_resource_list +{ + struct d3d12_resource **resources; + size_t count; + size_t capacity; +}; + /* ID3D12CommandList */ struct d3d12_command_list { @@ -1302,6 +1310,13 @@ struct d3d12_command_list unsigned int fb_layer_count; VkFormat dsv_format; + /* Resources for views bound to d3d12 state */ + struct d3d12_resource *rtv_resources[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT]; + struct d3d12_resource *dsv_resource; + /* Resources bound since the last pipeline barrier */ + struct vkd3d_resource_list rtv_resources_since_last_barrier; + struct vkd3d_resource_list dsv_resources_since_last_barrier; + bool xfb_enabled; bool has_depth_bounds; bool is_predicated; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10141
This merge request was approved by Matteo Bruni. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10141
participants (3)
-
Alexandre Julliard -
Alexandre Julliard (@julliard) -
Matteo Bruni (@Mystral)