From 2d21093fb4c3716f6bb02e4021d23e3ead9d381a Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 24 Jan 2024 08:40:28 +1100 Subject: [PATCH] Updated vkd3d to 72e2eeaf146e856497890241213a98327c098c6d. --- libs/vkd3d/include/private/vkd3d_common.h | 34 +- libs/vkd3d/include/vkd3d_shader.h | 2 + libs/vkd3d/libs/vkd3d-common/blob.c | 6 +- libs/vkd3d/libs/vkd3d-common/debug.c | 6 +- libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 28 +- libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 44 +- libs/vkd3d/libs/vkd3d-shader/dxil.c | 1064 ++++++++++++++++- libs/vkd3d/libs/vkd3d-shader/glsl.c | 6 +- libs/vkd3d/libs/vkd3d-shader/hlsl.y | 40 + libs/vkd3d/libs/vkd3d-shader/ir.c | 372 +++++- libs/vkd3d/libs/vkd3d-shader/spirv.c | 93 +- libs/vkd3d/libs/vkd3d-shader/tpf.c | 22 +- .../libs/vkd3d-shader/vkd3d_shader_main.c | 19 +- .../libs/vkd3d-shader/vkd3d_shader_private.h | 51 +- libs/vkd3d/libs/vkd3d/command.c | 6 +- libs/vkd3d/libs/vkd3d/device.c | 9 +- libs/vkd3d/libs/vkd3d/vkd3d_private.h | 3 +- 17 files changed, 1571 insertions(+), 234 deletions(-) diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h index 63e21c22067..979676c4d5a 100644 --- a/libs/vkd3d/include/private/vkd3d_common.h +++ b/libs/vkd3d/include/private/vkd3d_common.h @@ -278,30 +278,42 @@ static inline uint64_t vkd3d_atomic_add_fetch_u64(uint64_t volatile *x, uint64_t #endif } +static inline uint32_t vkd3d_atomic_add_fetch_u32(uint32_t volatile *x, uint32_t val) +{ +#if HAVE_SYNC_ADD_AND_FETCH + return __sync_add_and_fetch(x, val); +#elif defined(_WIN32) + return InterlockedAdd((LONG *)x, val); +#else +# error "vkd3d_atomic_add_fetch_u32() not implemented for this platform" +#endif +} + static inline uint64_t vkd3d_atomic_increment_u64(uint64_t volatile *x) { return vkd3d_atomic_add_fetch_u64(x, 1); } +static inline uint32_t vkd3d_atomic_decrement_u32(uint32_t volatile *x) +{ + return vkd3d_atomic_add_fetch_u32(x, ~0u); +} + +static inline uint32_t vkd3d_atomic_increment_u32(uint32_t volatile *x) +{ + return vkd3d_atomic_add_fetch_u32(x, 1); +} + #ifndef _WIN32 -# if HAVE_SYNC_ADD_AND_FETCH static inline LONG InterlockedIncrement(LONG volatile *x) { - return __sync_add_and_fetch(x, 1); + return vkd3d_atomic_increment_u32((uint32_t *)x); } -# else -# error "InterlockedIncrement() not implemented for this platform" -# endif /* HAVE_SYNC_ADD_AND_FETCH */ -# if HAVE_SYNC_SUB_AND_FETCH static inline LONG InterlockedDecrement(LONG volatile *x) { - return __sync_sub_and_fetch(x, 1); + return vkd3d_atomic_decrement_u32((uint32_t *)x); } -# else -# error "InterlockedDecrement() not implemented for this platform" -# endif - #endif /* _WIN32 */ static inline void vkd3d_parse_version(const char *version, int *major, int *minor) diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h index a9c9ccc4a52..449b3684a10 100644 --- a/libs/vkd3d/include/vkd3d_shader.h +++ b/libs/vkd3d/include/vkd3d_shader.h @@ -876,6 +876,8 @@ enum vkd3d_shader_spirv_extension VKD3D_SHADER_SPIRV_EXTENSION_EXT_DESCRIPTOR_INDEXING, /** \since 1.3 */ VKD3D_SHADER_SPIRV_EXTENSION_EXT_STENCIL_EXPORT, + /** \since 1.11 */ + VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SPIRV_EXTENSION), }; diff --git a/libs/vkd3d/libs/vkd3d-common/blob.c b/libs/vkd3d/libs/vkd3d-common/blob.c index fa2812619ac..4d347acef05 100644 --- a/libs/vkd3d/libs/vkd3d-common/blob.c +++ b/libs/vkd3d/libs/vkd3d-common/blob.c @@ -27,7 +27,7 @@ struct vkd3d_blob { ID3D10Blob ID3DBlob_iface; - LONG refcount; + unsigned int refcount; void *buffer; SIZE_T size; @@ -59,7 +59,7 @@ static HRESULT STDMETHODCALLTYPE vkd3d_blob_QueryInterface(ID3DBlob *iface, REFI static ULONG STDMETHODCALLTYPE vkd3d_blob_AddRef(ID3DBlob *iface) { struct vkd3d_blob *blob = impl_from_ID3DBlob(iface); - ULONG refcount = InterlockedIncrement(&blob->refcount); + unsigned int refcount = vkd3d_atomic_increment_u32(&blob->refcount); TRACE("%p increasing refcount to %u.\n", blob, refcount); @@ -69,7 +69,7 @@ static ULONG STDMETHODCALLTYPE vkd3d_blob_AddRef(ID3DBlob *iface) static ULONG STDMETHODCALLTYPE vkd3d_blob_Release(ID3DBlob *iface) { struct vkd3d_blob *blob = impl_from_ID3DBlob(iface); - ULONG refcount = InterlockedDecrement(&blob->refcount); + unsigned int refcount = vkd3d_atomic_decrement_u32(&blob->refcount); TRACE("%p decreasing refcount to %u.\n", blob, refcount); diff --git a/libs/vkd3d/libs/vkd3d-common/debug.c b/libs/vkd3d/libs/vkd3d-common/debug.c index aa7df5bd764..e12cd39450a 100644 --- a/libs/vkd3d/libs/vkd3d-common/debug.c +++ b/libs/vkd3d/libs/vkd3d-common/debug.c @@ -126,10 +126,10 @@ void vkd3d_dbg_set_log_callback(PFN_vkd3d_log callback) static char *get_buffer(void) { static char buffers[VKD3D_DEBUG_BUFFER_COUNT][VKD3D_DEBUG_BUFFER_SIZE]; - static LONG buffer_index; - LONG current_index; + static unsigned int buffer_index; + unsigned int current_index; - current_index = InterlockedIncrement(&buffer_index) % ARRAY_SIZE(buffers); + current_index = vkd3d_atomic_increment_u32(&buffer_index) % ARRAY_SIZE(buffers); return buffers[current_index]; } diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c index 5685fe4d4a4..d9751945d8a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c @@ -242,6 +242,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_NRM ] = "nrm", [VKD3DSIH_OR ] = "or", [VKD3DSIH_PHASE ] = "phase", + [VKD3DSIH_PHI ] = "phi", [VKD3DSIH_POW ] = "pow", [VKD3DSIH_RCP ] = "rcp", [VKD3DSIH_REP ] = "rep", @@ -830,6 +831,13 @@ static void shader_print_uint_literal(struct vkd3d_d3d_asm_compiler *compiler, prefix, compiler->colours.literal, i, compiler->colours.reset, suffix); } +static void shader_print_uint64_literal(struct vkd3d_d3d_asm_compiler *compiler, + const char *prefix, uint64_t i, const char *suffix) +{ + vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%"PRIu64"%s%s", + prefix, compiler->colours.literal, i, compiler->colours.reset, suffix); +} + static void shader_print_hex_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, unsigned int i, const char *suffix) { @@ -1222,6 +1230,12 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const if (reg->dimension == VSIR_DIMENSION_VEC4) shader_print_double_literal(compiler, ", ", reg->u.immconst_f64[1], ""); } + else if (reg->data_type == VKD3D_DATA_UINT64) + { + shader_print_uint64_literal(compiler, "", reg->u.immconst_u64[0], ""); + if (reg->dimension == VSIR_DIMENSION_VEC4) + shader_print_uint64_literal(compiler, "", reg->u.immconst_u64[1], ""); + } else { shader_addline(buffer, "", reg->data_type); @@ -2003,10 +2017,11 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, shader_addline(buffer, "\n"); } -enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, - const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, +enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vsir_program *program, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, enum vsir_asm_dialect dialect) { + const struct vkd3d_shader_version *shader_version = &program->shader_version; enum vkd3d_shader_compile_option_formatting_flags formatting; struct vkd3d_d3d_asm_compiler compiler = { @@ -2075,9 +2090,9 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio shader_version->minor, compiler.colours.reset); indent = 0; - for (i = 0; i < instructions->count; ++i) + for (i = 0; i < program->instructions.count; ++i) { - struct vkd3d_shader_instruction *ins = &instructions->elements[i]; + struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; switch (ins->handler_idx) { @@ -2131,13 +2146,12 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio return result; } -void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instructions, - const struct vkd3d_shader_version *shader_version) +void vkd3d_shader_trace(const struct vsir_program *program) { const char *p, *q, *end; struct vkd3d_shader_code code; - if (vkd3d_dxbc_binary_to_text(instructions, shader_version, NULL, &code, VSIR_ASM_VSIR) != VKD3D_OK) + if (vkd3d_dxbc_binary_to_text(program, NULL, &code, VSIR_ASM_VSIR) != VKD3D_OK) return; end = (const char *)code.code + code.size; diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c index aa0dd8f4b0d..035095d5b48 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c @@ -414,6 +414,7 @@ static bool has_relative_address(uint32_t param) static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info( const struct vkd3d_shader_sm1_parser *sm1, enum vkd3d_sm1_opcode opcode) { + const struct vkd3d_shader_version *version = &sm1->p.program.shader_version; const struct vkd3d_sm1_opcode_info *info; unsigned int i = 0; @@ -424,8 +425,8 @@ static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info( return NULL; if (opcode == info->sm1_opcode - && vkd3d_shader_ver_ge(&sm1->p.shader_version, info->min_version.major, info->min_version.minor) - && (vkd3d_shader_ver_le(&sm1->p.shader_version, info->max_version.major, info->max_version.minor) + && vkd3d_shader_ver_ge(version, info->min_version.major, info->min_version.minor) + && (vkd3d_shader_ver_le(version, info->max_version.major, info->max_version.minor) || !info->max_version.major)) return info; } @@ -444,7 +445,7 @@ static uint32_t swizzle_from_sm1(uint32_t swizzle) shader_sm1_get_swizzle_component(swizzle, 3)); } -static void shader_sm1_parse_src_param(uint32_t param, const struct vkd3d_shader_src_param *rel_addr, +static void shader_sm1_parse_src_param(uint32_t param, struct vkd3d_shader_src_param *rel_addr, struct vkd3d_shader_src_param *src) { enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT) @@ -465,7 +466,7 @@ static void shader_sm1_parse_src_param(uint32_t param, const struct vkd3d_shader src->modifiers = (param & VKD3D_SM1_SRC_MODIFIER_MASK) >> VKD3D_SM1_SRC_MODIFIER_SHIFT; } -static void shader_sm1_parse_dst_param(uint32_t param, const struct vkd3d_shader_src_param *rel_addr, +static void shader_sm1_parse_dst_param(uint32_t param, struct vkd3d_shader_src_param *rel_addr, struct vkd3d_shader_dst_param *dst) { enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT) @@ -567,7 +568,7 @@ static bool add_signature_element(struct vkd3d_shader_sm1_parser *sm1, bool outp element->register_count = 1; element->mask = mask; element->used_mask = is_dcl ? 0 : mask; - if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && !output) + if (sm1->p.program.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && !output) element->interpolation_mode = VKD3DSIM_LINEAR; return true; @@ -597,20 +598,20 @@ static void add_signature_mask(struct vkd3d_shader_sm1_parser *sm1, bool output, static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser *sm1, const struct vkd3d_shader_register *reg, bool is_dcl, unsigned int mask) { + const struct vkd3d_shader_version *version = &sm1->p.program.shader_version; unsigned int register_index = reg->idx[0].offset; switch (reg->type) { case VKD3DSPR_TEMP: - if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL - && sm1->p.shader_version.major == 1 && !register_index) + if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major == 1 && !register_index) return add_signature_element(sm1, true, "COLOR", 0, VKD3D_SHADER_SV_TARGET, 0, is_dcl, mask); return true; 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 (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX || sm1->p.shader_version.major == 3) + if (version->type == VKD3D_SHADER_TYPE_VERTEX || version->major == 3) { add_signature_mask(sm1, false, register_index, mask); return true; @@ -620,19 +621,19 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser * case VKD3DSPR_TEXTURE: /* For vertex shaders, this is ADDR. */ - if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX) + if (version->type == VKD3D_SHADER_TYPE_VERTEX) return true; return add_signature_element(sm1, false, "TEXCOORD", register_index, VKD3D_SHADER_SV_NONE, register_index, is_dcl, mask); case VKD3DSPR_OUTPUT: - if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX) + if (version->type == VKD3D_SHADER_TYPE_VERTEX) { /* For sm < 2 vertex shaders, this is TEXCRDOUT. * * For sm3 vertex shaders, this is OUTPUT, but we already * should have had a DCL instruction. */ - if (sm1->p.shader_version.major == 3) + if (version->major == 3) { add_signature_mask(sm1, true, register_index, mask); return true; @@ -700,6 +701,7 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser * static bool add_signature_element_from_semantic(struct vkd3d_shader_sm1_parser *sm1, const struct vkd3d_shader_semantic *semantic) { + const struct vkd3d_shader_version *version = &sm1->p.program.shader_version; const struct vkd3d_shader_register *reg = &semantic->resource.reg.reg; enum vkd3d_shader_sysval_semantic sysval = VKD3D_SHADER_SV_NONE; unsigned int mask = semantic->resource.reg.write_mask; @@ -731,13 +733,13 @@ static bool add_signature_element_from_semantic(struct vkd3d_shader_sm1_parser * return add_signature_element_from_register(sm1, reg, true, mask); /* sm2 pixel shaders use DCL but don't provide a semantic. */ - if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && sm1->p.shader_version.major == 2) + if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major == 2) return add_signature_element_from_register(sm1, reg, true, mask); /* With the exception of vertex POSITION output, none of these are system * values. Pixel POSITION input is not equivalent to SV_Position; the closer * equivalent is VPOS, which is not declared as a semantic. */ - if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX + if (version->type == VKD3D_SHADER_TYPE_VERTEX && output && semantic->usage == VKD3D_DECL_USAGE_POSITION) sysval = VKD3D_SHADER_SV_POSITION; @@ -763,13 +765,13 @@ static void record_constant_register(struct vkd3d_shader_sm1_parser *sm1, static void shader_sm1_scan_register(struct vkd3d_shader_sm1_parser *sm1, const struct vkd3d_shader_register *reg, unsigned int mask, bool from_def) { - struct vkd3d_shader_desc *desc = &sm1->p.shader_desc; + struct vsir_program *program = &sm1->p.program; uint32_t register_index = reg->idx[0].offset; switch (reg->type) { case VKD3DSPR_TEMP: - desc->temp_count = max(desc->temp_count, register_index + 1); + program->temp_count = max(program->temp_count, register_index + 1); break; case VKD3DSPR_CONST: @@ -824,7 +826,7 @@ static void shader_sm1_read_param(struct vkd3d_shader_sm1_parser *sm1, * VS >= 2.0 have relative addressing (with token) * VS >= 1.0 < 2.0 have relative addressing (without token) * The version check below should work in general. */ - if (sm1->p.shader_version.major < 2) + if (sm1->p.program.shader_version.major < 2) { *addr_token = (1u << 31) | ((VKD3DSPR_ADDR << VKD3D_SM1_REGISTER_TYPE_SHIFT2) & VKD3D_SM1_REGISTER_TYPE_MASK2) @@ -853,7 +855,7 @@ static void shader_sm1_skip_opcode(const struct vkd3d_shader_sm1_parser *sm1, co /* Version 2.0+ shaders may contain address tokens, but fortunately they * have a useful length mask - use it here. Version 1.x shaders contain no * such tokens. */ - if (sm1->p.shader_version.major >= 2) + if (sm1->p.program.shader_version.major >= 2) { length = (opcode_token & VKD3D_SM1_INSTRUCTION_LENGTH_MASK) >> VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT; *ptr += length; @@ -883,7 +885,7 @@ static void shader_sm1_destroy(struct vkd3d_shader_parser *parser) { struct vkd3d_shader_sm1_parser *sm1 = vkd3d_shader_sm1_parser(parser); - shader_instruction_array_destroy(&parser->instructions); + vsir_program_cleanup(&parser->program); free_shader_desc(&sm1->p.shader_desc); vkd3d_free(sm1); } @@ -1109,7 +1111,7 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE, "Invalid opcode %#x (token 0x%08x, shader version %u.%u).", opcode_token & VKD3D_SM1_OPCODE_MASK, opcode_token, - sm1->p.shader_version.major, sm1->p.shader_version.minor); + sm1->p.program.shader_version.major, sm1->p.program.shader_version.minor); goto fail; } @@ -1334,7 +1336,7 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi return ret; } - instructions = &sm1->p.instructions; + instructions = &sm1->p.program.instructions; while (!shader_sm1_is_end(sm1)) { if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) @@ -1389,7 +1391,7 @@ bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_sem enum vkd3d_shader_type shader_type; unsigned int major_version; D3DSHADER_PARAM_REGISTER_TYPE type; - DWORD offset; + unsigned int offset; } register_table[] = { diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c index 78c1a052539..15cc380f5f2 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -171,6 +171,35 @@ enum bitcode_linkage LINKAGE_INTERNAL = 3, }; +enum dxil_resource_kind +{ + RESOURCE_KIND_INVALID = 0, + RESOURCE_KIND_TEXTURE1D = 1, + RESOURCE_KIND_TEXTURE2D = 2, + RESOURCE_KIND_TEXTURE2DMS = 3, + RESOURCE_KIND_TEXTURE3D = 4, + RESOURCE_KIND_TEXTURECUBE = 5, + RESOURCE_KIND_TEXTURE1DARRAY = 6, + RESOURCE_KIND_TEXTURE2DARRAY = 7, + RESOURCE_KIND_TEXTURE2DMSARRAY = 8, + RESOURCE_KIND_TEXTURECUBEARRAY = 9, + RESOURCE_KIND_TYPEDBUFFER = 10, + RESOURCE_KIND_RAWBUFFER = 11, + RESOURCE_KIND_STRUCTUREDBUFFER = 12, + RESOURCE_KIND_CBUFFER = 13, + RESOURCE_KIND_SAMPLER = 14, + RESOURCE_KIND_TBUFFER = 15, + RESOURCE_KIND_RTACCELERATIONSTRUCTURE = 16, + RESOURCE_KIND_FEEDBACKTEXTURE2D = 17, + RESOURCE_KIND_FEEDBACKTEXTURE2DARRAY = 18, +}; + +enum dxil_resource_type +{ + RESOURCE_TYPE_NON_RAW_STRUCTURED = 0, + RESOURCE_TYPE_RAW_STRUCTURED = 1, +}; + enum dxil_component_type { COMPONENT_TYPE_INVALID = 0, @@ -315,6 +344,7 @@ enum dx_intrinsic_opcode DX_FIRST_BIT_SHI = 34, DX_CREATE_HANDLE = 57, DX_CBUFFER_LOAD_LEGACY = 59, + DX_BUFFER_LOAD = 68, DX_DERIV_COARSEX = 83, DX_DERIV_COARSEY = 84, DX_DERIV_FINEX = 85, @@ -472,18 +502,67 @@ struct sm6_symbol const char *name; }; +struct incoming_value +{ + const struct sm6_block *block; + struct vkd3d_shader_register reg; +}; + +struct sm6_phi +{ + struct vkd3d_shader_register reg; + 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; }; struct sm6_function { const struct sm6_value *declaration; - struct sm6_block *blocks[1]; + struct sm6_block **blocks; + size_t block_capacity; size_t block_count; size_t value_count; @@ -565,6 +644,11 @@ 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 vkd3d_data_type resource_data_type; + enum vkd3d_shader_register_type reg_type; + enum vkd3d_data_type reg_data_type; }; struct sm6_parser @@ -1937,6 +2021,12 @@ static inline bool sm6_value_is_constant(const struct sm6_value *value) return sm6_value_is_register(value) && register_is_constant(&value->u.reg); } +static bool sm6_value_is_constant_zero(const struct sm6_value *value) +{ + /* Constant vectors do not occur. */ + return sm6_value_is_register(value) && register_is_scalar_constant_zero(&value->u.reg); +} + static inline bool sm6_value_is_undef(const struct sm6_value *value) { return sm6_value_is_register(value) && value->u.reg.type == VKD3DSPR_UNDEF; @@ -1947,6 +2037,11 @@ static bool sm6_value_is_icb(const struct sm6_value *value) return value->value_type == VALUE_TYPE_ICB; } +static bool sm6_value_is_ssa(const struct sm6_value *value) +{ + return sm6_value_is_register(value) && register_is_ssa(&value->u.reg); +} + static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *value) { if (!sm6_value_is_constant(value)) @@ -1954,11 +2049,25 @@ static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *v return register_get_uint_value(&value->u.reg); } +static uint64_t sm6_value_get_constant_uint64(const struct sm6_value *value) +{ + if (!sm6_value_is_constant(value)) + return UINT64_MAX; + return register_get_uint64_value(&value->u.reg); +} + static unsigned int sm6_parser_alloc_ssa_id(struct sm6_parser *sm6) { return sm6->ssa_next_id++; } +static void instruction_init_with_resource(struct vkd3d_shader_instruction *ins, + enum vkd3d_shader_opcode handler_idx, const struct sm6_value *resource, struct sm6_parser *sm6) +{ + vsir_instruction_init(ins, &sm6->p.location, handler_idx); + ins->resource_type = resource->u.handle.d->resource_type; +} + static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins, unsigned int count, struct sm6_parser *sm6) { @@ -2463,7 +2572,7 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co "Out of memory allocating an immediate constant buffer of count %u.", count); return VKD3D_ERROR_OUT_OF_MEMORY; } - if (!shader_instruction_array_add_icb(&sm6->p.instructions, icb)) + if (!shader_instruction_array_add_icb(&sm6->p.program.instructions, icb)) { ERR("Failed to store icb object.\n"); vkd3d_free(icb); @@ -2659,12 +2768,12 @@ static bool bitcode_parse_alignment(uint64_t encoded_alignment, unsigned int *al static struct vkd3d_shader_instruction *sm6_parser_require_space(struct sm6_parser *sm6, size_t extra) { - if (!shader_instruction_array_reserve(&sm6->p.instructions, sm6->p.instructions.count + extra)) + if (!shader_instruction_array_reserve(&sm6->p.program.instructions, sm6->p.program.instructions.count + extra)) { ERR("Failed to allocate instruction.\n"); return NULL; } - return &sm6->p.instructions.elements[sm6->p.instructions.count]; + return &sm6->p.program.instructions.elements[sm6->p.program.instructions.count]; } /* Space should be reserved before calling this. It is intended to require no checking of the returned pointer. */ @@ -2674,7 +2783,7 @@ static struct vkd3d_shader_instruction *sm6_parser_add_instruction(struct sm6_pa struct vkd3d_shader_instruction *ins = sm6_parser_require_space(sm6, 1); assert(ins); vsir_instruction_init(ins, &sm6->p.location, handler_idx); - ++sm6->p.instructions.count; + ++sm6->p.program.instructions.count; return ins; } @@ -2937,9 +3046,9 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) } /* Resolve initialiser forward references. */ - for (i = 0; i < sm6->p.instructions.count; ++i) + for (i = 0; i < sm6->p.program.instructions.count; ++i) { - ins = &sm6->p.instructions.elements[i]; + ins = &sm6->p.program.instructions.elements[i]; if (ins->handler_idx == VKD3DSIH_DCL_INDEXABLE_TEMP && ins->declaration.indexable_temp.initialiser) { ins->declaration.indexable_temp.initialiser = resolve_forward_initialiser( @@ -3032,6 +3141,32 @@ static struct sm6_block *sm6_block_create() return block; } +static struct sm6_phi *sm6_block_phi_require_space(struct sm6_block *block, struct sm6_parser *sm6) +{ + struct sm6_phi *phi; + + if (!vkd3d_array_reserve((void **)&block->phi, &block->phi_capacity, block->phi_count + 1, sizeof(*block->phi))) + { + ERR("Failed to allocate phi array.\n"); + 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; + + return phi; +} + +struct function_emission_state +{ + struct sm6_block *code_block; + struct vkd3d_shader_instruction *ins; +}; + static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_record *record, struct vkd3d_shader_instruction *ins, struct sm6_value *dst) { @@ -3294,6 +3429,61 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco } } +static const struct sm6_block *sm6_function_get_block(const struct sm6_function *function, uint64_t index, + struct sm6_parser *sm6) +{ + 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, + "Invalid code block index %#"PRIx64" for a control flow instruction.", index); + return NULL; + } + return function->blocks[index]; +} + +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) +{ + 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, + "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); + } + else + { + if (!sm6->bool_type) + { + WARN("Bool type not found.\n"); + vkd3d_shader_parser_error(&sm6->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)) + return; + dxil_record_validate_operand_max_count(record, i, sm6); + + code_block->terminator.type = TERMINATOR_COND_BR; + code_block->terminator.conditional_reg = value->u.reg; + 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); + } + + ins->handler_idx = VKD3DSIH_NOP; +} + static enum vkd3d_shader_opcode map_dx_unary_op(enum dx_intrinsic_opcode op) { switch (op) @@ -3343,9 +3533,10 @@ 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, struct sm6_block *code_block, - enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) +static void sm6_parser_emit_dx_unary(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_param; vsir_instruction_init(ins, &sm6->p.location, map_dx_unary_op(op)); @@ -3355,10 +3546,11 @@ static void sm6_parser_emit_dx_unary(struct sm6_parser *sm6, struct sm6_block *c instruction_dst_param_init_ssa_scalar(ins, sm6); } -static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, struct sm6_block *code_block, - enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) +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; const struct sm6_value *buffer; const struct sm6_type *type; @@ -3406,9 +3598,10 @@ static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_pa return NULL; } -static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_block *code_block, - enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) +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 vkd3d_shader_register *reg; @@ -3430,9 +3623,8 @@ static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_ dst->u.handle.d = d; reg = &dst->u.handle.reg; - /* Set idx_count to 3 for use with load instructions. - * TODO: set register type from resource type when other types are supported. */ - vsir_register_init(reg, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3); + /* Set idx_count to 3 for use with load/store instructions. */ + vsir_register_init(reg, d->reg_type, d->reg_data_type, 3); reg->dimension = VSIR_DIMENSION_VEC4; reg->idx[0].offset = id; register_index_address_init(®->idx[1], operands[2], sm6); @@ -3442,9 +3634,10 @@ static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_ ins->handler_idx = VKD3DSIH_NOP; } -static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_block *code_block, - enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) +static void sm6_parser_emit_dx_load_input(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_param; const struct shader_signature *signature; unsigned int row_index, column_index; @@ -3474,9 +3667,45 @@ static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_blo instruction_dst_param_init_ssa_scalar(ins, sm6); } -static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, struct sm6_block *code_block, - enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins) +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; + const struct sm6_value *resource; + + resource = operands[0]; + if (!sm6_value_validate_is_handle(resource, sm6)) + return; + + 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."); + } + + instruction_init_with_resource(ins, (resource->u.handle.d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) + ? VKD3DSIH_LD_UAV_TYPED : VKD3DSIH_LD, resource, sm6); + + src_params = instruction_src_params_alloc(ins, 2, sm6); + src_param_init_from_value(&src_params[0], operands[1]); + 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_reg(&src_params[1], &resource->u.handle.reg); + + instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6); +} + +static void sm6_parser_emit_dx_store_output(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_param; struct vkd3d_shader_dst_param *dst_param; const struct shader_signature *signature; @@ -3531,8 +3760,8 @@ struct sm6_dx_opcode_info { const char *ret_type; const char *operand_info; - void (*handler)(struct sm6_parser *, struct sm6_block *, enum dx_intrinsic_opcode, - const struct sm6_value **, struct vkd3d_shader_instruction *); + void (*handler)(struct sm6_parser *, enum dx_intrinsic_opcode, const struct sm6_value **, + struct function_emission_state *); }; /* @@ -3551,6 +3780,7 @@ struct sm6_dx_opcode_info static const struct sm6_dx_opcode_info sm6_dx_op_table[] = { [DX_BFREV ] = {"m0", "m", sm6_parser_emit_dx_unary}, + [DX_BUFFER_LOAD ] = {"o", "Hii", sm6_parser_emit_dx_buffer_load}, [DX_CBUFFER_LOAD_LEGACY ] = {"o", "Hi", sm6_parser_emit_dx_cbuffer_load}, [DX_COUNT_BITS ] = {"i", "m", sm6_parser_emit_dx_unary}, [DX_CREATE_HANDLE ] = {"H", "ccib", sm6_parser_emit_dx_create_handle}, @@ -3684,27 +3914,27 @@ static void sm6_parser_emit_unhandled(struct sm6_parser *sm6, struct vkd3d_shade /* dst->is_undefined is not set here because it flags only explicitly undefined values. */ } -static void sm6_parser_decode_dx_op(struct sm6_parser *sm6, struct sm6_block *code_block, enum dx_intrinsic_opcode op, +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 vkd3d_shader_instruction *ins, struct sm6_value *dst) + 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, ins, dst); + sm6_parser_emit_unhandled(sm6, state->ins, dst); return; } if (sm6_parser_validate_dx_op(sm6, op, name, operands, operand_count, dst)) - sm6_dx_op_table[op].handler(sm6, code_block, op, operands, ins); + sm6_dx_op_table[op].handler(sm6, op, operands, state); else - sm6_parser_emit_unhandled(sm6, ins, dst); + sm6_parser_emit_unhandled(sm6, state->ins, dst); } static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_record *record, - struct sm6_block *code_block, struct vkd3d_shader_instruction *ins, struct sm6_value *dst) + struct function_emission_state *state, struct sm6_value *dst) { const struct sm6_value *operands[DXIL_OP_MAX_OPERANDS]; const struct sm6_value *fn_value, *op_value; @@ -3786,8 +4016,8 @@ static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_recor "Expected a constant integer dx intrinsic function id."); return; } - sm6_parser_decode_dx_op(sm6, code_block, register_get_uint_value(&op_value->u.reg), - fn_value->u.function.name, &operands[1], operand_count - 1, ins, dst); + sm6_parser_decode_dx_op(sm6, register_get_uint_value(&op_value->u.reg), + fn_value->u.function.name, &operands[1], operand_count - 1, state, dst); } static enum vkd3d_shader_opcode sm6_map_cast_op(uint64_t code, const struct sm6_type *from, @@ -4288,6 +4518,102 @@ static void sm6_parser_emit_load(struct sm6_parser *sm6, const struct dxil_recor instruction_dst_param_init_ssa_scalar(ins, sm6); } +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); +} + +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) +{ + struct incoming_value *incoming; + 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, + "Invalid operand count %u for phi instruction.", record->operand_count); + return; + } + + if (!(type = sm6_parser_get_type(sm6, 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, + "Result type class %u of a phi instruction is not scalar numeric.", type->class); + return; + } + + dst->type = type; + register_init_ssa_scalar(&dst->u.reg, type, sm6); + + if (!(phi = sm6_block_phi_require_space(code_block, sm6))) + return; + phi->reg = dst->u.reg; + phi->incoming_count = record->operand_count / 2u; + + if (!vkd3d_array_reserve((void **)&phi->incoming, &phi->incoming_capacity, phi->incoming_count, + sizeof(*phi->incoming))) + { + ERR("Failed to allocate phi incoming array.\n"); + vkd3d_shader_parser_error(&sm6->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) + { + 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; + } + + 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); + } + + ins->handler_idx = VKD3DSIH_NOP; + + qsort(incoming, phi->incoming_count, sizeof(*incoming), phi_incoming_compare); + + for (i = 1, j = 1; i < phi->incoming_count; ++i) + { + if (incoming[i].block != incoming[i - 1].block) + { + 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, + "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; +} + 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) { @@ -4297,6 +4623,8 @@ static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record if (record->operand_count) FIXME("Non-void return is not implemented.\n"); + code_block->terminator.type = TERMINATOR_RET; + ins->handler_idx = VKD3DSIH_NOP; } @@ -4351,6 +4679,89 @@ static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_reco dst_param->reg.alignment = alignment; } +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) +{ + struct sm6_block_terminator *terminator = &code_block->terminator; + const struct sm6_type *type; + const struct sm6_value *src; + unsigned int i = 1, j; + + 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, + "Invalid operand count %u for a switch instruction.", record->operand_count); + return; + } + + if (!(type = sm6_parser_get_type(sm6, record->operands[0]))) + return; + + if (!(src = sm6_parser_get_value_by_ref(sm6, record, type, &i)) + || !sm6_value_validate_is_register(src, sm6)) + return; + assert(i == 2); + + if (src->type != type) + { + WARN("Type mismatch.\n"); + vkd3d_shader_parser_warning(&sm6->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, + "Selector type class %u of a switch instruction is not scalar integer.", type->class); + return; + } + + terminator->conditional_reg = src->u.reg; + terminator->type = TERMINATOR_SWITCH; + + 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."); + return; + } + + /* Executes 'operand_count / 2' times because operand_count is uneven. */ + for (; i < record->operand_count; i += 2) + { + 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; + } + + for (i = 3; i < record->operand_count; i += 2) + { + if (!(src = sm6_parser_get_value_safe(sm6, record->operands[i]))) + return; + + if (src->type != type) + { + WARN("Type mismatch.\n"); + vkd3d_shader_parser_warning(&sm6->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, + "A switch case value is not a constant."); + } + + terminator->cases[i / 2u].value = sm6_value_get_constant_uint64(src); + } + + ins->handler_idx = VKD3DSIH_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) { @@ -4401,6 +4812,12 @@ static bool sm6_metadata_value_is_string(const struct sm6_metadata_value *m) return m && m->type == VKD3D_METADATA_STRING; } +static bool sm6_metadata_value_is_zero_or_undef(const struct sm6_metadata_value *m) +{ + return sm6_metadata_value_is_value(m) + && (sm6_value_is_undef(m->u.value) || sm6_value_is_constant_zero(m->u.value)); +} + static bool sm6_metadata_get_uint_value(const struct sm6_parser *sm6, const struct sm6_metadata_value *m, unsigned int *u) { @@ -4641,6 +5058,70 @@ static void metadata_attachment_record_apply(const struct dxil_record *record, e } } +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; +} + +static enum vkd3d_result sm6_function_resolve_phi_incomings(const struct sm6_function *function, + struct sm6_parser *sm6) +{ + 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]; + + for (i = 0; i < block->phi_count; ++i) + { + struct sm6_phi *phi = &block->phi[i]; + const struct sm6_value *src; + + 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->u.reg.data_type != phi->reg.data_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."); + } + phi->incoming[j].reg = src->u.reg; + } + } + } + + return VKD3D_OK; +} + static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, struct sm6_function *function) { @@ -4680,16 +5161,18 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const WARN("Function contains no blocks.\n"); return VKD3D_ERROR_INVALID_SHADER; } - if (block_count > 1) - { - FIXME("Branched shaders are not supported yet.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - if (!(function->blocks[0] = sm6_block_create())) - { - ERR("Failed to allocate code block.\n"); + 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]; @@ -4708,10 +5191,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const return VKD3D_ERROR_INVALID_SHADER; } - /* block->record_count - 1 is the instruction count, but some instructions - * can emit >1 IR instruction, so extra may be used. */ + /* Some instructions can emit >1 IR instruction, so extra may be used. */ if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity, - max(code_block->instruction_count + 1, block->record_count), sizeof(*code_block->instructions))) + code_block->instruction_count + 1, sizeof(*code_block->instructions))) { ERR("Failed to allocate instructions.\n"); return VKD3D_ERROR_OUT_OF_MEMORY; @@ -4734,9 +5216,16 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const case FUNC_CODE_INST_BINOP: sm6_parser_emit_binop(sm6, record, ins, dst); break; + case FUNC_CODE_INST_BR: + sm6_parser_emit_br(sm6, record, function, code_block, ins); + is_terminator = true; + break; case FUNC_CODE_INST_CALL: - sm6_parser_emit_call(sm6, record, code_block, ins, dst); + { + struct function_emission_state state = {code_block, ins}; + sm6_parser_emit_call(sm6, record, &state, dst); break; + } case FUNC_CODE_INST_CAST: sm6_parser_emit_cast(sm6, record, ins, dst); break; @@ -4752,6 +5241,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const case FUNC_CODE_INST_LOAD: sm6_parser_emit_load(sm6, record, ins, dst); break; + case FUNC_CODE_INST_PHI: + sm6_parser_emit_phi(sm6, record, function, code_block, ins, dst); + break; case FUNC_CODE_INST_RET: sm6_parser_emit_ret(sm6, record, code_block, ins); is_terminator = true; @@ -4760,6 +5252,10 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const case FUNC_CODE_INST_STORE: sm6_parser_emit_store(sm6, record, ins, dst); break; + case FUNC_CODE_INST_SWITCH: + sm6_parser_emit_switch(sm6, record, function, code_block, ins); + is_terminator = true; + break; case FUNC_CODE_INST_VSELECT: sm6_parser_emit_vselect(sm6, record, ins, dst); break; @@ -4794,22 +5290,130 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const return VKD3D_ERROR_INVALID_SHADER; } - return VKD3D_OK; + return sm6_function_resolve_phi_incomings(function, sm6); } -static bool sm6_block_emit_instructions(struct sm6_block *block, struct sm6_parser *sm6) +static void sm6_block_emit_terminator(const struct sm6_block *block, struct sm6_parser *sm6) { - struct vkd3d_shader_instruction *ins = sm6_parser_require_space(sm6, block->instruction_count + 1); + struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_instruction *ins; + unsigned int i, count; - if (!ins) - return false; + switch (block->terminator.type) + { + case TERMINATOR_UNCOND_BR: + if (!block->terminator.true_block) + return; + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_BRANCH); + if (!(src_params = instruction_src_params_alloc(ins, 1, sm6))) + return; + vsir_src_param_init_label(&src_params[0], block->terminator.true_block->id); + break; - memcpy(ins, block->instructions, block->instruction_count * sizeof(*block->instructions)); - sm6->p.instructions.count += block->instruction_count; + case TERMINATOR_COND_BR: + if (!block->terminator.true_block || !block->terminator.false_block) + return; + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_BRANCH); + if (!(src_params = instruction_src_params_alloc(ins, 3, sm6))) + 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; - sm6_parser_add_instruction(sm6, VKD3DSIH_RET); + case TERMINATOR_SWITCH: + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_SWITCH_MONOLITHIC); + if (!(src_params = instruction_src_params_alloc(ins, block->terminator.case_count * 2u + 1, sm6))) + 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); - return true; + for (i = 0, count = 3; i < block->terminator.case_count; ++i) + { + const struct terminator_case *switch_case; + const struct sm6_block *case_block; + + switch_case = &block->terminator.cases[i]; + if (!(case_block = switch_case->block)) + { + assert(sm6->p.failed); + continue; + } + if (switch_case->is_default) + { + vsir_src_param_init_label(&src_params[1], case_block->id); + continue; + } + + if (src_params[0].reg.data_type == VKD3D_DATA_UINT64) + { + vsir_src_param_init(&src_params[count], VKD3DSPR_IMMCONST64, VKD3D_DATA_UINT64, 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, VKD3D_DATA_UINT, 0); + src_params[count++].reg.u.immconst_u32[0] = switch_case->value; + } + vsir_src_param_init_label(&src_params[count++], case_block->id); + } + + break; + + case TERMINATOR_RET: + sm6_parser_add_instruction(sm6, VKD3DSIH_RET); + break; + + default: + vkd3d_unreachable(); + } +} + +static void sm6_block_emit_phi(const struct sm6_block *block, struct sm6_parser *sm6) +{ + struct vkd3d_shader_instruction *ins; + unsigned int i, j, incoming_count; + const struct sm6_phi *src_phi; + + for (i = 0; i < block->phi_count; ++i) + { + struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_dst_param *dst_param; + + src_phi = &block->phi[i]; + incoming_count = src_phi->incoming_count; + + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_PHI); + if (!(src_params = instruction_src_params_alloc(ins, incoming_count * 2u, sm6))) + return; + if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) + return; + + for (j = 0; j < incoming_count; ++j) + { + const struct sm6_block *incoming_block = src_phi->incoming[j].block; + unsigned int index = j * 2; + + 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 + assert(sm6->p.failed); + } + + dst_param_init(dst_param); + dst_param->reg = src_phi->reg; + } } static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const struct dxil_block *block, @@ -4881,6 +5485,36 @@ static void sm6_parser_emit_label(struct sm6_parser *sm6, unsigned int label_id) vsir_src_param_init_label(src_param, label_id); } +static enum vkd3d_result sm6_function_emit_blocks(const struct sm6_function *function, struct sm6_parser *sm6) +{ + unsigned int i; + + sm6->p.shader_desc.block_count = function->block_count; + + for (i = 0; i < function->block_count; ++i) + { + const struct sm6_block *block = function->blocks[i]; + + /* Space for the label and terminator. */ + if (!sm6_parser_require_space(sm6, block->instruction_count + block->phi_count + 2)) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory emitting shader instructions."); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + sm6_parser_emit_label(sm6, block->id); + sm6_block_emit_phi(block, sm6); + + memcpy(&sm6->p.program.instructions.elements[sm6->p.program.instructions.count], block->instructions, + block->instruction_count * sizeof(*block->instructions)); + sm6->p.program.instructions.count += block->instruction_count; + + sm6_block_emit_terminator(block, sm6); + } + + return VKD3D_OK; +} + static bool sm6_parser_allocate_named_metadata(struct sm6_parser *sm6) { struct dxil_block *block; @@ -5155,7 +5789,9 @@ static enum vkd3d_shader_minimum_precision minimum_precision_from_dxil_component static const enum vkd3d_shader_sysval_semantic sysval_semantic_table[] = { [SEMANTIC_KIND_ARBITRARY] = VKD3D_SHADER_SV_NONE, + [SEMANTIC_KIND_VERTEXID] = VKD3D_SHADER_SV_VERTEX_ID, [SEMANTIC_KIND_POSITION] = VKD3D_SHADER_SV_POSITION, + [SEMANTIC_KIND_ISFRONTFACE] = VKD3D_SHADER_SV_IS_FRONT_FACE, [SEMANTIC_KIND_TARGET] = VKD3D_SHADER_SV_TARGET, }; @@ -5238,6 +5874,288 @@ static bool sm6_parser_resources_load_register_range(struct sm6_parser *sm6, return true; } +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_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; + + switch (kind) + { + case RESOURCE_KIND_TYPEDBUFFER: + return VKD3D_SHADER_RESOURCE_BUFFER; + default: + return VKD3D_SHADER_RESOURCE_NONE; + } +} + +static const enum vkd3d_data_type data_type_table[] = +{ + [COMPONENT_TYPE_INVALID] = VKD3D_DATA_UNUSED, + [COMPONENT_TYPE_I1] = VKD3D_DATA_UNUSED, + [COMPONENT_TYPE_I16] = VKD3D_DATA_INT, + [COMPONENT_TYPE_U16] = VKD3D_DATA_UINT, + [COMPONENT_TYPE_I32] = VKD3D_DATA_INT, + [COMPONENT_TYPE_U32] = VKD3D_DATA_UINT, + [COMPONENT_TYPE_I64] = VKD3D_DATA_UNUSED, + [COMPONENT_TYPE_U64] = VKD3D_DATA_UNUSED, + [COMPONENT_TYPE_F16] = VKD3D_DATA_FLOAT, + [COMPONENT_TYPE_F32] = VKD3D_DATA_FLOAT, + [COMPONENT_TYPE_F64] = VKD3D_DATA_DOUBLE, + [COMPONENT_TYPE_SNORMF16] = VKD3D_DATA_SNORM, + [COMPONENT_TYPE_UNORMF16] = VKD3D_DATA_UNORM, + [COMPONENT_TYPE_SNORMF32] = VKD3D_DATA_SNORM, + [COMPONENT_TYPE_UNORMF32] = VKD3D_DATA_UNORM, + [COMPONENT_TYPE_SNORMF64] = VKD3D_DATA_DOUBLE, + [COMPONENT_TYPE_UNORMF64] = VKD3D_DATA_DOUBLE, + [COMPONENT_TYPE_PACKEDS8X32] = VKD3D_DATA_UNUSED, + [COMPONENT_TYPE_PACKEDU8X32] = VKD3D_DATA_UNUSED, +}; + +static enum vkd3d_data_type vkd3d_data_type_from_dxil_component_type(enum dxil_component_type type, + struct sm6_parser *sm6) +{ + enum vkd3d_data_type data_type; + + if (type >= ARRAY_SIZE(data_type_table) || (data_type = data_type_table[type]) == VKD3D_DATA_UNUSED) + { + FIXME("Unhandled component type %u.\n", type); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource descriptor component type %u is unhandled.", type); + return VKD3D_DATA_FLOAT; + } + + return data_type; +} + +static struct vkd3d_shader_resource *sm6_parser_resources_load_common_info(struct sm6_parser *sm6, + const struct sm6_metadata_value *type_value, bool is_uav, enum dxil_resource_kind kind, + const struct sm6_metadata_value *m, struct vkd3d_shader_instruction *ins) +{ + enum vkd3d_shader_resource_type resource_type; + enum dxil_resource_type dxil_resource_type; + const struct sm6_metadata_node *node; + enum vkd3d_data_type data_type; + unsigned int i, values[2]; + + if (!(resource_type = shader_resource_type_from_dxil_resource_kind(kind))) + { + FIXME("Unhandled resource kind %u.\n", kind); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource kind %u is unhandled.", kind); + return NULL; + } + ins->resource_type = resource_type; + + if (!sm6_metadata_value_is_node(m)) + { + WARN("Resource metadata list is not a node.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource descriptor metadata list is not a node."); + return NULL; + } + + node = m->u.node; + + if (node->operand_count < 2) + { + WARN("Invalid operand count %u.\n", node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Invalid operand count %u for a resource descriptor.", node->operand_count); + return NULL; + } + if (node->operand_count > 2) + { + WARN("Ignoring %u extra operands.\n", node->operand_count - 2); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for a resource descriptor.", node->operand_count - 2); + } + + for (i = 0; i < 2; ++i) + { + if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &values[i])) + { + WARN("Failed to load uint value at index %u.\n", i); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "A resource descriptor operand metadata value is not an integer."); + return NULL; + } + } + + if ((dxil_resource_type = values[0]) == RESOURCE_TYPE_NON_RAW_STRUCTURED) + { + if (kind != RESOURCE_KIND_TYPEDBUFFER && !resource_kind_is_texture(kind)) + { + WARN("Unhandled resource kind %u.\n", kind); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource kind %u for a typed resource is unhandled.", kind); + return NULL; + } + + data_type = vkd3d_data_type_from_dxil_component_type(values[1], sm6); + ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_TYPED : VKD3DSIH_DCL; + for (i = 0; i < VKD3D_VEC4_SIZE; ++i) + ins->declaration.semantic.resource_data_type[i] = data_type; + ins->declaration.semantic.resource_type = resource_type; + ins->declaration.semantic.resource.reg.write_mask = VKD3DSP_WRITEMASK_ALL; + + return &ins->declaration.semantic.resource; + } + else + { + FIXME("Unhandled resource type %u.\n", dxil_resource_type); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "Resource type %u is unhandled.", dxil_resource_type); + } + + return NULL; +} + +static void init_resource_declaration(struct vkd3d_shader_resource *resource, + enum vkd3d_shader_register_type reg_type, enum vkd3d_data_type data_type, unsigned int id, + const struct vkd3d_shader_register_range *range) +{ + struct vkd3d_shader_dst_param *param = &resource->reg; + + param->modifiers = 0; + param->shift = 0; + vsir_register_init(¶m->reg, reg_type, data_type, 3); + param->reg.idx[0].offset = id; + param->reg.idx[1].offset = range->first; + param->reg.idx[2].offset = range->last; + + resource->range = *range; +} + +static enum vkd3d_result sm6_parser_resources_load_srv(struct sm6_parser *sm6, + const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins) +{ + struct vkd3d_shader_resource *resource; + unsigned int kind; + + if (node->operand_count < 9) + { + WARN("Invalid operand count %u.\n", node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Invalid operand count %u for an SRV descriptor.", node->operand_count); + return VKD3D_ERROR_INVALID_SHADER; + } + if (node->operand_count > 9) + { + WARN("Ignoring %u extra operands.\n", node->operand_count - 9); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for an SRV descriptor.", node->operand_count - 9); + } + + if (!sm6_metadata_get_uint_value(sm6, node->operands[6], &kind)) + { + WARN("Failed to load resource type.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "SRV resource type metadata value is not an integer."); + return VKD3D_ERROR_INVALID_SHADER; + } + + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_INVALID); + + if (!(resource = sm6_parser_resources_load_common_info(sm6, node->operands[1], false, kind, + node->operands[8], ins))) + { + return VKD3D_ERROR_INVALID_SHADER; + } + + d->resource_type = ins->resource_type; + d->kind = kind; + d->reg_type = VKD3DSPR_RESOURCE; + d->reg_data_type = (ins->resource_type == VKD3D_SHADER_RESOURCE_BUFFER) ? VKD3D_DATA_UINT : VKD3D_DATA_RESOURCE; + d->resource_data_type = ins->declaration.semantic.resource_data_type[0]; + + init_resource_declaration(resource, VKD3DSPR_RESOURCE, d->reg_data_type, d->id, &d->range); + + if (resource_kind_is_multisampled(kind)) + { + if (!sm6_metadata_get_uint_value(sm6, node->operands[7], &ins->declaration.semantic.sample_count)) + { + WARN("Failed to load sample count.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "SRV sample count metadata value is not an integer."); + return VKD3D_ERROR_INVALID_SHADER; + } + } + else if (!sm6_metadata_value_is_zero_or_undef(node->operands[7])) + { + WARN("Ignoring sample count value.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring an SRV descriptor sample count metadata value which is not constant zero or undefined."); + } + + return VKD3D_OK; +} + +static enum vkd3d_result sm6_parser_resources_load_uav(struct sm6_parser *sm6, + const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins) +{ + struct vkd3d_shader_resource *resource; + unsigned int i, values[4]; + + if (node->operand_count < 11) + { + WARN("Invalid operand count %u.\n", node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Invalid operand count %u for a UAV descriptor.", node->operand_count); + return VKD3D_ERROR_INVALID_SHADER; + } + if (node->operand_count > 11) + { + WARN("Ignoring %u extra operands.\n", node->operand_count - 11); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for a UAV descriptor.", node->operand_count - 11); + } + + for (i = 6; i < 10; ++i) + { + if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &values[i - 6])) + { + WARN("Failed to load uint value at index %u.\n", i); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, + "A UAV descriptor operand metadata value is not an integer."); + return VKD3D_ERROR_INVALID_SHADER; + } + } + + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_INVALID); + if (values[1]) + ins->flags = VKD3DSUF_GLOBALLY_COHERENT; + if (values[2]) + ins->flags |= VKD3DSUF_ORDER_PRESERVING_COUNTER; + if (values[3]) + ins->flags |= VKD3DSUF_RASTERISER_ORDERED_VIEW; + + if (!(resource = sm6_parser_resources_load_common_info(sm6, node->operands[1], true, values[0], + node->operands[10], ins))) + { + return VKD3D_ERROR_INVALID_SHADER; + } + + d->resource_type = ins->resource_type; + d->kind = values[0]; + d->reg_type = VKD3DSPR_UAV; + d->reg_data_type = (ins->resource_type == VKD3D_SHADER_RESOURCE_BUFFER) ? VKD3D_DATA_UINT : VKD3D_DATA_UAV; + d->resource_data_type = ins->declaration.semantic.resource_data_type[0]; + + init_resource_declaration(resource, VKD3DSPR_UAV, d->reg_data_type, d->id, &d->range); + + return VKD3D_OK; +} + static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6, const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins) { @@ -5280,6 +6198,10 @@ 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 = VKD3D_DATA_FLOAT; + d->resource_data_type = VKD3D_DATA_FLOAT; + return VKD3D_OK; } @@ -5351,6 +6273,14 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, if ((ret = sm6_parser_resources_load_cbv(sm6, node, d, ins)) < 0) return ret; break; + case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV: + if ((ret = sm6_parser_resources_load_srv(sm6, node, d, ins)) < 0) + return ret; + break; + case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV: + if ((ret = sm6_parser_resources_load_uav(sm6, node, d, ins)) < 0) + return ret; + break; default: FIXME("Unsupported descriptor type %u.\n", type); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES, @@ -5359,7 +6289,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6, } ++sm6->descriptor_count; - ++sm6->p.instructions.count; + ++sm6->p.program.instructions.count; } return VKD3D_OK; @@ -5709,9 +6639,9 @@ static enum vkd3d_result sm6_parser_emit_thread_group(struct sm6_parser *sm6, co unsigned int group_sizes[3]; unsigned int i; - if (sm6->p.shader_version.type != VKD3D_SHADER_TYPE_COMPUTE) + if (sm6->p.program.shader_version.type != VKD3D_SHADER_TYPE_COMPUTE) { - WARN("Shader of type %#x has thread group dimensions.\n", sm6->p.shader_version.type); + WARN("Shader of type %#x has thread group dimensions.\n", sm6->p.program.shader_version.type); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, "Shader has thread group dimensions but is not a compute shader."); return VKD3D_ERROR_INVALID_SHADER; @@ -5930,9 +6860,20 @@ static void sm6_symtab_cleanup(struct sm6_symbol *symbols, size_t count) vkd3d_free(symbols); } +static void sm6_phi_destroy(struct sm6_phi *phi) +{ + vkd3d_free(phi->incoming); +} + static void sm6_block_destroy(struct sm6_block *block) { + unsigned int i; + 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); } @@ -5944,6 +6885,7 @@ static void sm6_functions_cleanup(struct sm6_function *functions, size_t count) { for (j = 0; j < functions[i].block_count; ++j) sm6_block_destroy(functions[i].blocks[j]); + vkd3d_free(functions[i].blocks); } vkd3d_free(functions); } @@ -5954,7 +6896,7 @@ static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) dxil_block_destroy(&sm6->root_block); dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); - shader_instruction_array_destroy(&parser->instructions); + vsir_program_cleanup(&parser->program); 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); @@ -6228,8 +7170,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t return VKD3D_ERROR_OUT_OF_MEMORY; } - sm6->p.shader_desc.ssa_count = sm6->ssa_next_id; - sm6->p.shader_desc.block_count = 1; + sm6->p.program.ssa_count = sm6->ssa_next_id; if (!(fn = sm6_parser_get_function(sm6, sm6->entry_point))) { @@ -6240,13 +7181,8 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t } assert(sm6->function_count == 1); - sm6_parser_emit_label(sm6, 1); - if (!sm6_block_emit_instructions(fn->blocks[0], sm6)) - { - vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, - "Out of memory emitting shader instructions."); - return VKD3D_ERROR_OUT_OF_MEMORY; - } + if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) + return ret; dxil_block_destroy(&sm6->root_block); diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c index f8d68b5a798..bdd03c1e72a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/glsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c @@ -91,7 +91,7 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *generator } int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *generator, - struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *out) + struct vsir_program *program, struct vkd3d_shader_code *out) { unsigned int i; void *code; @@ -100,10 +100,10 @@ int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *generator, vkd3d_string_buffer_printf(&generator->buffer, "void main()\n{\n"); generator->location.column = 0; - for (i = 0; i < parser->instructions.count; ++i) + for (i = 0; i < program->instructions.count; ++i) { generator->location.line = i + 1; - vkd3d_glsl_handle_instruction(generator, &parser->instructions.elements[i]); + vkd3d_glsl_handle_instruction(generator, &program->instructions.elements[i]); } if (generator->failed) diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y index e30b3dc5f55..c308916e07e 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -4089,14 +4089,54 @@ static bool add_ternary(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *cond, struct hlsl_ir_node *first, struct hlsl_ir_node *second) { struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; + struct hlsl_type *cond_type = cond->data_type; struct hlsl_type *common_type; + if (cond_type->class > HLSL_CLASS_LAST_NUMERIC) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, cond_type))) + hlsl_error(ctx, &cond->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Ternary condition type '%s' is not numeric.", string->buffer); + hlsl_release_string_buffer(ctx, string); + } + if (first->data_type->class <= HLSL_CLASS_LAST_NUMERIC && second->data_type->class <= HLSL_CLASS_LAST_NUMERIC) { if (!(common_type = get_common_numeric_type(ctx, first, second, &first->loc))) return false; + if (cond_type->dimx == 1 && cond_type->dimy == 1) + { + cond_type = hlsl_get_numeric_type(ctx, common_type->class, + HLSL_TYPE_BOOL, common_type->dimx, common_type->dimy); + if (!(cond = add_implicit_conversion(ctx, block, cond, cond_type, &cond->loc))) + return false; + } + else if (common_type->dimx == 1 && common_type->dimy == 1) + { + common_type = hlsl_get_numeric_type(ctx, cond_type->class, + common_type->base_type, cond_type->dimx, cond_type->dimy); + } + else if (cond_type->dimx != common_type->dimx || cond_type->dimy != common_type->dimy) + { + /* This condition looks wrong but is correct. + * floatN is compatible with float1xN, but not with floatNx1. */ + + struct vkd3d_string_buffer *cond_string, *value_string; + + cond_string = hlsl_type_to_string(ctx, cond_type); + value_string = hlsl_type_to_string(ctx, common_type); + if (cond_string && value_string) + hlsl_error(ctx, &first->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Ternary condition type '%s' is not compatible with value type '%s'.", + cond_string->buffer, value_string->buffer); + hlsl_release_string_buffer(ctx, cond_string); + hlsl_release_string_buffer(ctx, value_string); + } + if (!(first = add_implicit_conversion(ctx, block, first, common_type, &first->loc))) return false; diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index d6978171beb..a797e49308a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -18,6 +18,17 @@ #include "vkd3d_shader_private.h" +bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve) +{ + program->shader_version = *version; + return shader_instruction_array_init(&program->instructions, reserve); +} + +void vsir_program_cleanup(struct vsir_program *program) +{ + shader_instruction_array_destroy(&program->instructions); +} + static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg) { return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; @@ -312,7 +323,7 @@ void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_reg reg->alignment = 0; } -static void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, +void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, enum vkd3d_data_type data_type, unsigned int idx_count) { vsir_register_init(¶m->reg, reg_type, data_type, idx_count); @@ -840,6 +851,7 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map unsigned int i, j, element_count, new_count, register_count; struct signature_element *elements; struct signature_element *e, *f; + bool used; element_count = s->element_count; if (!(elements = vkd3d_malloc(element_count * sizeof(*elements)))) @@ -860,14 +872,15 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map if (range_map_get_register_count(range_map, e->register_index, e->mask) > 1) continue; + used = e->used_mask; + for (; j < element_count; ++j) { f = &elements[j]; /* Merge different components of the same register unless sysvals are different, - * interpolation modes are different, or it will be relative-addressed. */ + * or it will be relative-addressed. */ if (f->register_index != e->register_index || f->sysval_semantic != e->sysval_semantic - || f->interpolation_mode != e->interpolation_mode || range_map_get_register_count(range_map, f->register_index, f->mask) > 1) break; @@ -878,6 +891,16 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map e->mask |= f->mask; e->used_mask |= f->used_mask; e->semantic_index = min(e->semantic_index, f->semantic_index); + + /* The first element may have no interpolation mode if it is unused. Elements which + * actually have different interpolation modes are assigned different registers. */ + if (f->used_mask && !used) + { + if (e->interpolation_mode && e->interpolation_mode != f->interpolation_mode) + FIXME("Mismatching interpolation modes %u and %u.\n", e->interpolation_mode, f->interpolation_mode); + else + e->interpolation_mode = f->interpolation_mode; + } } } element_count = new_count; @@ -1217,21 +1240,22 @@ static void shader_instruction_normalise_io_params(struct vkd3d_shader_instructi static enum vkd3d_result shader_normalise_io_registers(struct vkd3d_shader_parser *parser) { - struct io_normaliser normaliser = {parser->instructions}; + struct io_normaliser normaliser = {parser->program.instructions}; + struct vsir_program *program = &parser->program; struct vkd3d_shader_instruction *ins; bool has_control_point_phase; unsigned int i, j; normaliser.phase = VKD3DSIH_INVALID; - normaliser.shader_type = parser->shader_version.type; - normaliser.major = parser->shader_version.major; + normaliser.shader_type = program->shader_version.type; + normaliser.major = program->shader_version.major; normaliser.input_signature = &parser->shader_desc.input_signature; normaliser.output_signature = &parser->shader_desc.output_signature; normaliser.patch_constant_signature = &parser->shader_desc.patch_constant_signature; - for (i = 0, has_control_point_phase = false; i < parser->instructions.count; ++i) + for (i = 0, has_control_point_phase = false; i < program->instructions.count; ++i) { - ins = &parser->instructions.elements[i]; + ins = &program->instructions.elements[i]; switch (ins->handler_idx) { @@ -1274,7 +1298,7 @@ static enum vkd3d_result shader_normalise_io_registers(struct vkd3d_shader_parse || !shader_signature_merge(&parser->shader_desc.output_signature, normaliser.output_range_map, false) || !shader_signature_merge(&parser->shader_desc.patch_constant_signature, normaliser.pc_range_map, true)) { - parser->instructions = normaliser.instructions; + program->instructions = normaliser.instructions; return VKD3D_ERROR_OUT_OF_MEMORY; } @@ -1282,8 +1306,8 @@ static enum vkd3d_result shader_normalise_io_registers(struct vkd3d_shader_parse for (i = 0; i < normaliser.instructions.count; ++i) shader_instruction_normalise_io_params(&normaliser.instructions.elements[i], &normaliser); - parser->instructions = normaliser.instructions; - parser->shader_desc.use_vocp = normaliser.use_vocp; + program->instructions = normaliser.instructions; + program->use_vocp = normaliser.use_vocp; return VKD3D_OK; } @@ -1296,7 +1320,6 @@ struct flat_constant_def struct flat_constants_normaliser { - struct vkd3d_shader_parser *parser; struct flat_constant_def *defs; size_t def_count, defs_capacity; }; @@ -1371,14 +1394,14 @@ static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_par param->reg.idx_count = 3; } -static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d_shader_parser *parser) +static enum vkd3d_result instruction_array_normalise_flat_constants(struct vsir_program *program) { - struct flat_constants_normaliser normaliser = {.parser = parser}; + struct flat_constants_normaliser normaliser = {0}; unsigned int i, j; - for (i = 0; i < parser->instructions.count; ++i) + for (i = 0; i < program->instructions.count; ++i) { - struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i]; + struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; if (ins->handler_idx == VKD3DSIH_DEF || ins->handler_idx == VKD3DSIH_DEFI || ins->handler_idx == VKD3DSIH_DEFB) { @@ -1410,14 +1433,14 @@ static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d return VKD3D_OK; } -static void remove_dead_code(struct vkd3d_shader_parser *parser) +static void remove_dead_code(struct vsir_program *program) { size_t i, depth = 0; bool dead = false; - for (i = 0; i < parser->instructions.count; ++i) + for (i = 0; i < program->instructions.count; ++i) { - struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i]; + struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; switch (ins->handler_idx) { @@ -1504,15 +1527,15 @@ static enum vkd3d_result normalise_combined_samplers(struct vkd3d_shader_parser { unsigned int i; - for (i = 0; i < parser->instructions.count; ++i) + for (i = 0; i < parser->program.instructions.count; ++i) { - struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i]; + struct vkd3d_shader_instruction *ins = &parser->program.instructions.elements[i]; struct vkd3d_shader_src_param *srcs; switch (ins->handler_idx) { case VKD3DSIH_TEX: - if (!(srcs = shader_src_param_allocator_get(&parser->instructions.src_params, 3))) + if (!(srcs = shader_src_param_allocator_get(&parser->program.instructions.src_params, 3))) return VKD3D_ERROR_OUT_OF_MEMORY; memset(srcs, 0, sizeof(*srcs) * 3); @@ -1857,11 +1880,12 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte bool main_block_open, is_hull_shader, after_declarations_section; struct vkd3d_shader_parser *parser = flattener->parser; struct vkd3d_shader_instruction_array *instructions; + struct vsir_program *program = &parser->program; struct vkd3d_shader_instruction *dst_ins; size_t i; - instructions = &parser->instructions; - is_hull_shader = parser->shader_version.type == VKD3D_SHADER_TYPE_HULL; + instructions = &program->instructions; + is_hull_shader = program->shader_version.type == VKD3D_SHADER_TYPE_HULL; main_block_open = !is_hull_shader; after_declarations_section = is_hull_shader; @@ -2208,10 +2232,10 @@ static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_par if (result >= 0) { - vkd3d_free(parser->instructions.elements); - parser->instructions.elements = flattener.instructions; - parser->instructions.capacity = flattener.instruction_capacity; - parser->instructions.count = flattener.instruction_count; + vkd3d_free(parser->program.instructions.elements); + parser->program.instructions.elements = flattener.instructions; + parser->program.instructions.capacity = flattener.instruction_capacity; + parser->program.instructions.count = flattener.instruction_count; parser->shader_desc.block_count = flattener.block_id; } else @@ -2230,17 +2254,17 @@ static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_par enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, const struct vkd3d_shader_compile_info *compile_info) { - struct vkd3d_shader_instruction_array *instructions = &parser->instructions; + struct vkd3d_shader_instruction_array *instructions = &parser->program.instructions; enum vkd3d_result result = VKD3D_OK; if (parser->shader_desc.is_dxil) return result; - if (parser->shader_version.type != VKD3D_SHADER_TYPE_PIXEL + if (parser->program.shader_version.type != VKD3D_SHADER_TYPE_PIXEL && (result = remap_output_signature(parser, compile_info)) < 0) return result; - if (parser->shader_version.type == VKD3D_SHADER_TYPE_HULL + if (parser->program.shader_version.type == VKD3D_SHADER_TYPE_HULL && (result = instruction_array_flatten_hull_shader_phases(instructions)) >= 0) { result = instruction_array_normalise_hull_shader_control_point_io(instructions, @@ -2250,10 +2274,10 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, result = shader_normalise_io_registers(parser); if (result >= 0) - result = instruction_array_normalise_flat_constants(parser); + result = instruction_array_normalise_flat_constants(&parser->program); if (result >= 0) - remove_dead_code(parser); + remove_dead_code(&parser->program); if (result >= 0) result = flatten_control_flow_constructs(parser); @@ -2262,7 +2286,7 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, result = normalise_combined_samplers(parser); if (result >= 0 && TRACE_ON()) - vkd3d_shader_trace(instructions, &parser->shader_version); + vkd3d_shader_trace(&parser->program); if (result >= 0 && !parser->failed) result = vsir_validate(parser); @@ -2276,11 +2300,18 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, struct validation_context { struct vkd3d_shader_parser *parser; + const struct vsir_program *program; size_t instruction_idx; bool invalid_instruction_idx; bool dcl_temps_found; unsigned int temp_count; enum vkd3d_shader_opcode phase; + enum cf_type + { + CF_TYPE_UNKNOWN = 0, + CF_TYPE_STRUCTURED, + CF_TYPE_BLOCKS, + } cf_type; struct validation_context_temp_data { @@ -2337,8 +2368,8 @@ static void vsir_validate_register(struct validation_context *ctx, unsigned int i, temp_count = ctx->temp_count; /* SM1-3 shaders do not include a DCL_TEMPS instruction. */ - if (ctx->parser->shader_version.major <= 3) - temp_count = ctx->parser->shader_desc.temp_count; + if (ctx->program->shader_version.major <= 3) + temp_count = ctx->program->temp_count; if (reg->type >= VKD3DSPR_COUNT) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, "Invalid register type %#x.", @@ -2390,10 +2421,10 @@ static void vsir_validate_register(struct validation_context *ctx, break; } - /* parser->shader_desc.temp_count might be smaller then - * temp_count if the parser made a mistake; we still don't - * want to overflow the array. */ - if (reg->idx[0].offset >= ctx->parser->shader_desc.temp_count) + /* program->temp_count might be smaller then temp_count if the + * parser made a mistake; we still don't want to overflow the + * array. */ + if (reg->idx[0].offset >= ctx->program->temp_count) break; data = &ctx->temps[reg->idx[0].offset]; @@ -2434,10 +2465,11 @@ static void vsir_validate_register(struct validation_context *ctx, if (reg->idx[0].rel_addr) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a SSA register."); - if (reg->idx[0].offset >= ctx->parser->shader_desc.ssa_count) + if (reg->idx[0].offset >= ctx->program->ssa_count) { - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "SSA register index %u exceeds the maximum count %u.", - reg->idx[0].offset, ctx->parser->shader_desc.ssa_count); + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, + "SSA register index %u exceeds the maximum count %u.", + reg->idx[0].offset, ctx->program->ssa_count); break; } @@ -2466,6 +2498,37 @@ static void vsir_validate_register(struct validation_context *ctx, break; } + case VKD3DSPR_LABEL: + if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, "Invalid precision %#x for a LABEL register.", + reg->precision); + + if (reg->data_type != VKD3D_DATA_UINT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, "Invalid data type %#x for a LABEL register.", + reg->data_type); + + if (reg->dimension != VSIR_DIMENSION_NONE) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a LABEL register.", + reg->dimension); + + if (reg->idx_count != 1) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a LABEL register.", + reg->idx_count); + break; + } + + if (reg->idx[0].rel_addr) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a LABEL register."); + + /* Index == 0 is invalid, but it is temporarily allowed + * for intermediate stages. Once we support validation + * dialects we can selectively check for that. */ + if (reg->idx[0].offset > ctx->parser->shader_desc.block_count) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "LABEL register index %u exceeds the maximum count %u.", + reg->idx[0].offset, ctx->parser->shader_desc.block_count); + break; + case VKD3DSPR_NULL: if (reg->idx_count != 0) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a NULL register.", @@ -2538,7 +2601,7 @@ static void vsir_validate_dst_param(struct validation_context *ctx, dst->shift); } - if (dst->reg.type == VKD3DSPR_SSA && dst->reg.idx[0].offset < ctx->parser->shader_desc.ssa_count) + if (dst->reg.type == VKD3DSPR_SSA && dst->reg.idx[0].offset < ctx->program->ssa_count) { struct validation_context_ssa_data *data = &ctx->ssas[dst->reg.idx[0].offset]; @@ -2573,7 +2636,7 @@ static void vsir_validate_src_param(struct validation_context *ctx, validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Source has invalid modifiers %#x.", src->modifiers); - if (src->reg.type == VKD3DSPR_SSA && src->reg.idx[0].offset < ctx->parser->shader_desc.ssa_count) + if (src->reg.type == VKD3DSPR_SSA && src->reg.idx[0].offset < ctx->program->ssa_count) { struct validation_context_ssa_data *data = &ctx->ssas[src->reg.idx[0].offset]; unsigned int i; @@ -2601,11 +2664,64 @@ static void vsir_validate_src_count(struct validation_context *ctx, instruction->src_count, instruction->handler_idx, count); } +static bool vsir_validate_src_min_count(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction, unsigned int count) +{ + if (instruction->src_count < count) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, + "Invalid source count %u for an instruction of type %#x, expected at least %u.", + instruction->src_count, instruction->handler_idx, count); + return false; + } + + return true; +} + +static bool vsir_validate_src_max_count(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction, unsigned int count) +{ + if (instruction->src_count > count) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, + "Invalid source count %u for an instruction of type %#x, expected at most %u.", + instruction->src_count, instruction->handler_idx, count); + return false; + } + + return true; +} + +static const char *name_from_cf_type(enum cf_type type) +{ + switch (type) + { + case CF_TYPE_STRUCTURED: + return "structured"; + case CF_TYPE_BLOCKS: + return "block-based"; + default: + vkd3d_unreachable(); + } +} + +static void vsir_validate_cf_type(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction, enum cf_type expected_type) +{ + assert(ctx->cf_type != CF_TYPE_UNKNOWN); + assert(expected_type != CF_TYPE_UNKNOWN); + if (ctx->cf_type != expected_type) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x in %s shader.", + instruction->handler_idx, name_from_cf_type(ctx->cf_type)); +} + static void vsir_validate_instruction(struct validation_context *ctx) { - const struct vkd3d_shader_instruction *instruction = &ctx->parser->instructions.elements[ctx->instruction_idx]; + const struct vkd3d_shader_version *version = &ctx->program->shader_version; + const struct vkd3d_shader_instruction *instruction; size_t i; + instruction = &ctx->program->instructions.elements[ctx->instruction_idx]; ctx->parser->location = instruction->location; for (i = 0; i < instruction->dst_count; ++i) @@ -2628,11 +2744,11 @@ static void vsir_validate_instruction(struct validation_context *ctx) case VKD3DSIH_HS_JOIN_PHASE: vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 0); - if (ctx->parser->shader_version.type != VKD3D_SHADER_TYPE_HULL) + if (version->type != VKD3D_SHADER_TYPE_HULL) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, "Phase instruction %#x is only valid in a hull shader.", instruction->handler_idx); if (ctx->depth != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "Phase instruction %#x must appear to top level.", + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Phase instruction %#x must appear to top level.", instruction->handler_idx); ctx->phase = instruction->handler_idx; ctx->dcl_temps_found = false; @@ -2643,11 +2759,28 @@ static void vsir_validate_instruction(struct validation_context *ctx) break; } - if (ctx->parser->shader_version.type == VKD3D_SHADER_TYPE_HULL && - ctx->phase == VKD3DSIH_INVALID) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, "Instruction %#x appear before any phase instruction in a hull shader.", + if (version->type == VKD3D_SHADER_TYPE_HULL && ctx->phase == VKD3DSIH_INVALID) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, + "Instruction %#x appear before any phase instruction in a hull shader.", instruction->handler_idx); + /* We support two different control flow types in shaders: + * block-based, like DXIL and SPIR-V, and structured, like D3DBC + * and TPF. The shader is detected as block-based when its first + * instruction, except for DCL_* and phases, is a LABEL. Currently + * we mandate that each shader is either purely block-based or + * purely structured. In principle we could allow structured + * constructs in a block, provided they are confined in a single + * block, but need for that hasn't arisen yet, so we don't. */ + if (ctx->cf_type == CF_TYPE_UNKNOWN && !(instruction->handler_idx >= VKD3DSIH_DCL + && instruction->handler_idx <= VKD3DSIH_DCL_VERTICES_OUT)) + { + if (instruction->handler_idx == VKD3DSIH_LABEL) + ctx->cf_type = CF_TYPE_BLOCKS; + else + ctx->cf_type = CF_TYPE_STRUCTURED; + } + switch (instruction->handler_idx) { case VKD3DSIH_DCL_TEMPS: @@ -2655,14 +2788,16 @@ static void vsir_validate_instruction(struct validation_context *ctx) vsir_validate_src_count(ctx, instruction, 0); if (ctx->dcl_temps_found) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS, "Duplicate DCL_TEMPS instruction."); - if (instruction->declaration.count > ctx->parser->shader_desc.temp_count) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, "Invalid DCL_TEMPS count %u, expected at most %u.", - instruction->declaration.count, ctx->parser->shader_desc.temp_count); + if (instruction->declaration.count > ctx->program->temp_count) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, + "Invalid DCL_TEMPS count %u, expected at most %u.", + instruction->declaration.count, ctx->program->temp_count); ctx->dcl_temps_found = true; ctx->temp_count = instruction->declaration.count; break; case VKD3DSIH_IF: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 1); if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) @@ -2671,6 +2806,7 @@ static void vsir_validate_instruction(struct validation_context *ctx) break; case VKD3DSIH_IFC: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 2); if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) @@ -2679,41 +2815,46 @@ static void vsir_validate_instruction(struct validation_context *ctx) break; case VKD3DSIH_ELSE: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 0); if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ELSE instruction doesn't terminate IF block."); + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ELSE instruction doesn't terminate IF block."); else ctx->blocks[ctx->depth - 1] = instruction->handler_idx; break; case VKD3DSIH_ENDIF: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 0); if (ctx->depth == 0 || (ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF && ctx->blocks[ctx->depth - 1] != VKD3DSIH_ELSE)) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDIF instruction doesn't terminate IF/ELSE block."); + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDIF instruction doesn't terminate IF/ELSE block."); else --ctx->depth; break; case VKD3DSIH_LOOP: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); - vsir_validate_src_count(ctx, instruction, ctx->parser->shader_version.major <= 3 ? 2 : 0); + vsir_validate_src_count(ctx, instruction, version->major <= 3 ? 2 : 0); if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) return; ctx->blocks[ctx->depth++] = instruction->handler_idx; break; case VKD3DSIH_ENDLOOP: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 0); if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_LOOP) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDLOOP instruction doesn't terminate LOOP block."); + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDLOOP instruction doesn't terminate LOOP block."); else --ctx->depth; break; case VKD3DSIH_REP: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 1); if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) @@ -2722,15 +2863,17 @@ static void vsir_validate_instruction(struct validation_context *ctx) break; case VKD3DSIH_ENDREP: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 0); if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_REP) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDREP instruction doesn't terminate REP block."); + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDREP instruction doesn't terminate REP block."); else --ctx->depth; break; case VKD3DSIH_SWITCH: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 1); if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks))) @@ -2739,14 +2882,112 @@ static void vsir_validate_instruction(struct validation_context *ctx) break; case VKD3DSIH_ENDSWITCH: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED); vsir_validate_dst_count(ctx, instruction, 0); vsir_validate_src_count(ctx, instruction, 0); if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_SWITCH) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDSWITCH instruction doesn't terminate SWITCH block."); + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDSWITCH instruction doesn't terminate SWITCH block."); else --ctx->depth; break; + case VKD3DSIH_RET: + vsir_validate_dst_count(ctx, instruction, 0); + vsir_validate_src_count(ctx, instruction, 0); + break; + + case VKD3DSIH_LABEL: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); + vsir_validate_dst_count(ctx, instruction, 0); + vsir_validate_src_count(ctx, instruction, 1); + if (instruction->src_count >= 1 && !vsir_register_is_label(&instruction->src[0].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid register of type %#x in a LABEL instruction, expected LABEL.", + instruction->src[0].reg.type); + break; + + case VKD3DSIH_BRANCH: + vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); + vsir_validate_dst_count(ctx, instruction, 0); + if (!vsir_validate_src_min_count(ctx, instruction, 1)) + break; + if (vsir_register_is_label(&instruction->src[0].reg)) + { + /* Unconditional branch: parameters are jump label, + * optional merge label, optional continue label. */ + vsir_validate_src_max_count(ctx, instruction, 3); + + for (i = 0; i < instruction->src_count; ++i) + { + if (!vsir_register_is_label(&instruction->src[i].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid register of type %#x in unconditional BRANCH instruction, expected LABEL.", + instruction->src[i].reg.type); + } + } + else + { + /* Conditional branch: parameters are condition, true + * jump label, false jump label, optional merge label, + * optional continue label. */ + vsir_validate_src_min_count(ctx, instruction, 3); + vsir_validate_src_max_count(ctx, instruction, 5); + + for (i = 1; i < instruction->src_count; ++i) + { + if (!vsir_register_is_label(&instruction->src[i].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid register of type %#x in conditional BRANCH instruction, expected LABEL.", + instruction->src[i].reg.type); + } + } + break; + + case VKD3DSIH_SWITCH_MONOLITHIC: + { + unsigned int case_count; + + vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS); + vsir_validate_dst_count(ctx, instruction, 0); + /* Parameters are source, default label, merge label and + * then pairs of constant value and case label. */ + if (!vsir_validate_src_min_count(ctx, instruction, 3)) + break; + if (instruction->src_count % 2 != 1) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT, + "Invalid source count %u for a monolithic SWITCH instruction, it must be an odd number.", + instruction->src_count); + + if (!vsir_register_is_label(&instruction->src[1].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid default label register of type %#x in monolithic SWITCH instruction, expected LABEL.", + instruction->src[1].reg.type); + + if (!vsir_register_is_label(&instruction->src[2].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid merge label register of type %#x in monolithic SWITCH instruction, expected LABEL.", + instruction->src[2].reg.type); + + case_count = (instruction->src_count - 3) / 2; + + for (i = 0; i < case_count; ++i) + { + unsigned int value_idx = 3 + 2 * i; + unsigned int label_idx = 3 + 2 * i + 1; + + if (!register_is_constant(&instruction->src[value_idx].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid value register for case %zu of type %#x in monolithic SWITCH instruction, " + "expected IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type); + + if (!vsir_register_is_label(&instruction->src[label_idx].reg)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid label register for case %zu of type %#x in monolithic SWITCH instruction, " + "expected LABEL.", i, instruction->src[value_idx].reg.type); + } + break; + } + default: break; } @@ -2757,6 +2998,7 @@ enum vkd3d_result vsir_validate(struct vkd3d_shader_parser *parser) struct validation_context ctx = { .parser = parser, + .program = &parser->program, .phase = VKD3DSIH_INVALID, }; unsigned int i; @@ -2764,21 +3006,21 @@ enum vkd3d_result vsir_validate(struct vkd3d_shader_parser *parser) if (!(parser->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION)) return VKD3D_OK; - if (!(ctx.temps = vkd3d_calloc(parser->shader_desc.temp_count, sizeof(*ctx.temps)))) + if (!(ctx.temps = vkd3d_calloc(ctx.program->temp_count, sizeof(*ctx.temps)))) goto fail; - if (!(ctx.ssas = vkd3d_calloc(parser->shader_desc.ssa_count, sizeof(*ctx.ssas)))) + if (!(ctx.ssas = vkd3d_calloc(ctx.program->ssa_count, sizeof(*ctx.ssas)))) goto fail; - for (ctx.instruction_idx = 0; ctx.instruction_idx < parser->instructions.count; ++ctx.instruction_idx) + for (ctx.instruction_idx = 0; ctx.instruction_idx < parser->program.instructions.count; ++ctx.instruction_idx) vsir_validate_instruction(&ctx); ctx.invalid_instruction_idx = true; if (ctx.depth != 0) - validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "%zu nested blocks were not closed.", ctx.depth); + validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "%zu nested blocks were not closed.", ctx.depth); - for (i = 0; i < parser->shader_desc.ssa_count; ++i) + for (i = 0; i < ctx.program->ssa_count; ++i) { struct validation_context_ssa_data *data = &ctx.ssas[i]; diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c index 0eeb04bfe59..e99724ca21c 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -1933,6 +1933,8 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_descriptor_indexing"); if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityStencilExportEXT)) vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_shader_stencil_export"); + if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityShaderViewportIndexLayerEXT)) + vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_shader_viewport_index_layer"); if (builder->ext_instr_set_glsl_450) vkd3d_spirv_build_op_ext_inst_import(&stream, builder->ext_instr_set_glsl_450, "GLSL.std.450"); @@ -3852,7 +3854,12 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler ssa = spirv_compiler_get_ssa_register_info(compiler, reg); val_id = ssa->id; - assert(val_id); + if (!val_id) + { + /* Should only be from a missing instruction implementation. */ + assert(compiler->failed); + return 0; + } assert(vkd3d_swizzle_is_scalar(swizzle)); if (reg->dimension == VSIR_DIMENSION_SCALAR) @@ -4236,10 +4243,58 @@ static void spirv_compiler_decorate_builtin(struct spirv_compiler *compiler, spirv_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthReplacing, NULL, 0); break; case SpvBuiltInLayer: - vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry); + switch (compiler->shader_type) + { + case VKD3D_SHADER_TYPE_PIXEL: + case VKD3D_SHADER_TYPE_GEOMETRY: + vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry); + break; + + case VKD3D_SHADER_TYPE_VERTEX: + case VKD3D_SHADER_TYPE_DOMAIN: + if (!spirv_compiler_is_target_extension_supported(compiler, + VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER)) + { + FIXME("The target environment does not support decoration Layer.\n"); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE, + "Cannot use SV_RenderTargetArrayIndex. " + "The target environment does not support decoration Layer."); + } + vkd3d_spirv_enable_capability(builder, SpvCapabilityShaderViewportIndexLayerEXT); + break; + + default: + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_SHADER, + "Invalid use of SV_RenderTargetArrayIndex."); + break; + } break; case SpvBuiltInViewportIndex: - vkd3d_spirv_enable_capability(builder, SpvCapabilityMultiViewport); + switch (compiler->shader_type) + { + case VKD3D_SHADER_TYPE_PIXEL: + case VKD3D_SHADER_TYPE_GEOMETRY: + vkd3d_spirv_enable_capability(builder, SpvCapabilityMultiViewport); + break; + + case VKD3D_SHADER_TYPE_VERTEX: + case VKD3D_SHADER_TYPE_DOMAIN: + if (!spirv_compiler_is_target_extension_supported(compiler, + VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER)) + { + FIXME("The target environment does not support decoration ViewportIndex.\n"); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE, + "Cannot use SV_ViewportArrayIndex. " + "The target environment does not support decoration ViewportIndex."); + } + vkd3d_spirv_enable_capability(builder, SpvCapabilityShaderViewportIndexLayerEXT); + break; + + default: + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_SHADER, + "Invalid use of SV_ViewportArrayIndex."); + break; + } break; case SpvBuiltInSampleId: vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading); @@ -6887,11 +6942,11 @@ static enum GLSLstd450 spirv_compiler_map_ext_glsl_instruction( static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { + 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; uint32_t src_id[SPIRV_MAX_SRC_COUNT]; - uint32_t instr_set_id, type_id, val_id; unsigned int i, component_count; enum GLSLstd450 glsl_inst; @@ -6920,8 +6975,12 @@ static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *comp { /* In D3D bits are numbered from the most significant bit. */ component_count = vsir_write_mask_component_count(dst->write_mask); - val_id = vkd3d_spirv_build_op_isub(builder, type_id, + uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, UINT32_MAX, component_count); + condition_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, SpvOpIEqual, + vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count), val_id, uint_max_id); + rev_val_id = vkd3d_spirv_build_op_isub(builder, type_id, spirv_compiler_get_constant_uint_vector(compiler, 31, component_count), val_id); + val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, rev_val_id); } spirv_compiler_emit_store_dst(compiler, dst, val_id); @@ -8319,7 +8378,6 @@ static void spirv_compiler_emit_ld_raw_structured_srv_uav(struct spirv_compiler type_id, val_id, 0); } } - assert(dst->reg.data_type == VKD3D_DATA_UINT); spirv_compiler_emit_store_dst_components(compiler, dst, VKD3D_SHADER_COMPONENT_UINT, constituents); } @@ -9672,27 +9730,28 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_shader_desc *shader_desc = &parser->shader_desc; struct vkd3d_shader_instruction_array instructions; + struct vsir_program *program = &parser->program; enum vkd3d_result result = VKD3D_OK; unsigned int i; - if (parser->shader_desc.temp_count) - spirv_compiler_emit_temps(compiler, parser->shader_desc.temp_count); - if (parser->shader_desc.ssa_count) - spirv_compiler_allocate_ssa_register_ids(compiler, parser->shader_desc.ssa_count); + if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0) + return result; + + if (program->temp_count) + spirv_compiler_emit_temps(compiler, program->temp_count); + if (program->ssa_count) + spirv_compiler_allocate_ssa_register_ids(compiler, program->ssa_count); spirv_compiler_emit_descriptor_declarations(compiler); compiler->location.column = 0; compiler->location.line = 1; - if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0) - return result; - if (parser->shader_desc.block_count && !spirv_compiler_init_blocks(compiler, parser->shader_desc.block_count)) return VKD3D_ERROR_OUT_OF_MEMORY; - instructions = parser->instructions; - memset(&parser->instructions, 0, sizeof(parser->instructions)); + instructions = program->instructions; + memset(&program->instructions, 0, sizeof(program->instructions)); compiler->input_signature = shader_desc->input_signature; compiler->output_signature = shader_desc->output_signature; @@ -9700,7 +9759,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, memset(&shader_desc->input_signature, 0, sizeof(shader_desc->input_signature)); memset(&shader_desc->output_signature, 0, sizeof(shader_desc->output_signature)); memset(&shader_desc->patch_constant_signature, 0, sizeof(shader_desc->patch_constant_signature)); - compiler->use_vocp = parser->shader_desc.use_vocp; + compiler->use_vocp = program->use_vocp; compiler->block_names = parser->shader_desc.block_names; compiler->block_name_count = parser->shader_desc.block_name_count; @@ -9802,7 +9861,7 @@ int spirv_compile(struct vkd3d_shader_parser *parser, struct spirv_compiler *spirv_compiler; int ret; - if (!(spirv_compiler = spirv_compiler_create(&parser->shader_version, &parser->shader_desc, + if (!(spirv_compiler = spirv_compiler_create(&parser->program.shader_version, &parser->shader_desc, compile_info, scan_descriptor_info, message_context, &parser->location, parser->config_flags))) { ERR("Failed to create SPIR-V compiler.\n"); diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index e4dfb5235ec..df10cd254d6 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -711,7 +711,7 @@ static struct vkd3d_shader_sm4_parser *vkd3d_shader_sm4_parser(struct vkd3d_shad static bool shader_is_sm_5_1(const struct vkd3d_shader_sm4_parser *sm4) { - const struct vkd3d_shader_version *version = &sm4->p.shader_version; + const struct vkd3d_shader_version *version = &sm4->p.program.shader_version; return version->major >= 5 && version->minor >= 1; } @@ -796,7 +796,7 @@ static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, ui icb->element_count = icb_size / VKD3D_VEC4_SIZE; icb->is_null = false; memcpy(icb->data, tokens, sizeof(*tokens) * icb_size); - shader_instruction_array_add_icb(&priv->p.instructions, icb); + shader_instruction_array_add_icb(&priv->p.program.instructions, icb); ins->declaration.icb = icb; } @@ -1072,7 +1072,7 @@ static void shader_sm4_read_declaration_count(struct vkd3d_shader_instruction *i { ins->declaration.count = *tokens; if (opcode == VKD3D_SM4_OP_DCL_TEMPS) - priv->p.shader_desc.temp_count = max(priv->p.shader_desc.temp_count, *tokens); + priv->p.program.temp_count = max(priv->p.program.temp_count, *tokens); } static void shader_sm4_read_declaration_dst(struct vkd3d_shader_instruction *ins, uint32_t opcode, @@ -1732,7 +1732,7 @@ static void shader_sm4_destroy(struct vkd3d_shader_parser *parser) { struct vkd3d_shader_sm4_parser *sm4 = vkd3d_shader_sm4_parser(parser); - shader_instruction_array_destroy(&parser->instructions); + vsir_program_cleanup(&parser->program); free_shader_desc(&parser->shader_desc); vkd3d_free(sm4); } @@ -2020,7 +2020,7 @@ static bool register_is_control_point_input(const struct vkd3d_shader_register * { return reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_OUTCONTROLPOINT || (reg->type == VKD3DSPR_INPUT && (priv->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE - || priv->p.shader_version.type == VKD3D_SHADER_TYPE_GEOMETRY)); + || priv->p.program.shader_version.type == VKD3D_SHADER_TYPE_GEOMETRY)); } static uint32_t mask_from_swizzle(uint32_t swizzle) @@ -2662,7 +2662,7 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi /* DXBC stores used masks inverted for output signatures, for some reason. * We return them un-inverted. */ uninvert_used_masks(&shader_desc->output_signature); - if (sm4->p.shader_version.type == VKD3D_SHADER_TYPE_HULL) + if (sm4->p.program.shader_version.type == VKD3D_SHADER_TYPE_HULL) uninvert_used_masks(&shader_desc->patch_constant_signature); if (!shader_sm4_parser_validate_signature(sm4, &shader_desc->input_signature, @@ -2676,7 +2676,7 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi return VKD3D_ERROR_INVALID_SHADER; } - instructions = &sm4->p.instructions; + instructions = &sm4->p.program.instructions; while (sm4->ptr != sm4->end) { if (!shader_instruction_array_reserve(instructions, instructions->count + 1)) @@ -2697,7 +2697,8 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi } ++instructions->count; } - if (sm4->p.shader_version.type == VKD3D_SHADER_TYPE_HULL && !sm4->has_control_point_phase && !sm4->p.failed) + if (sm4->p.program.shader_version.type == VKD3D_SHADER_TYPE_HULL + && !sm4->has_control_point_phase && !sm4->p.failed) shader_sm4_validate_default_phase_index_ranges(sm4); if (!sm4->p.failed) @@ -2806,6 +2807,8 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant {"position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_IS_FRONT_FACE}, + {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_RENDER_TARGET_ARRAY_INDEX}, + {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_VIEWPORT_ARRAY_INDEX}, {"color", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET}, {"depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH}, @@ -2814,9 +2817,12 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant {"sv_position", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_UNDEFINED}, {"sv_vertexid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VERTEX_ID}, + {"sv_instanceid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_INSTANCE_ID}, {"position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION}, + {"sv_rendertargetarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_RENDER_TARGET_ARRAY_INDEX}, + {"sv_viewportarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VIEWPORT_ARRAY_INDEX}, }; bool needs_compat_mapping = ascii_strncasecmp(semantic->name, "sv_", 3); diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c index 61e46f5538e..14d885fb666 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c @@ -539,10 +539,9 @@ bool vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, parser->location.source_name = source_name; parser->location.line = 1; parser->location.column = 0; - parser->shader_version = *version; parser->ops = ops; parser->config_flags = vkd3d_shader_init_config_flags(); - return shader_instruction_array_init(&parser->instructions, instruction_reserve); + return vsir_program_init(&parser->program, version, instruction_reserve); } void VKD3D_PRINTF_FUNC(3, 4) vkd3d_shader_parser_error(struct vkd3d_shader_parser *parser, @@ -1402,17 +1401,15 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info descriptor_info1 = &local_descriptor_info1; } - vkd3d_shader_scan_context_init(&context, &parser->shader_version, compile_info, + vkd3d_shader_scan_context_init(&context, &parser->program.shader_version, compile_info, descriptor_info1, combined_sampler_info, message_context); if (TRACE_ON()) - { - vkd3d_shader_trace(&parser->instructions, &parser->shader_version); - } + vkd3d_shader_trace(&parser->program); - for (i = 0; i < parser->instructions.count; ++i) + for (i = 0; i < parser->program.instructions.count; ++i) { - instruction = &parser->instructions.elements[i]; + instruction = &parser->program.instructions.elements[i]; if ((ret = vkd3d_shader_scan_instruction(&context, instruction)) < 0) break; } @@ -1585,13 +1582,13 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, switch (compile_info->target_type) { case VKD3D_SHADER_TARGET_D3D_ASM: - ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out, VSIR_ASM_D3D); + ret = vkd3d_dxbc_binary_to_text(&parser->program, compile_info, out, VSIR_ASM_D3D); break; case VKD3D_SHADER_TARGET_GLSL: if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0) return ret; - if (!(glsl_generator = vkd3d_glsl_generator_create(&parser->shader_version, + if (!(glsl_generator = vkd3d_glsl_generator_create(&parser->program.shader_version, message_context, &parser->location))) { ERR("Failed to create GLSL generator.\n"); @@ -1599,7 +1596,7 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, return VKD3D_ERROR; } - ret = vkd3d_glsl_generator_generate(glsl_generator, parser, out); + ret = vkd3d_glsl_generator_generate(glsl_generator, &parser->program, out); vkd3d_glsl_generator_destroy(glsl_generator); vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); break; diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index ace58161e6b..2d5e25d7f05 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -215,7 +215,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS = 9013, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS = 9014, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX = 9015, - VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING = 9016, + VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW = 9016, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE = 9017, VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300, @@ -436,6 +436,7 @@ enum vkd3d_shader_opcode VKD3DSIH_NRM, VKD3DSIH_OR, VKD3DSIH_PHASE, + VKD3DSIH_PHI, VKD3DSIH_POW, VKD3DSIH_RCP, VKD3DSIH_REP, @@ -826,7 +827,7 @@ struct vkd3d_shader_indexable_temp struct vkd3d_shader_register_index { - const struct vkd3d_shader_src_param *rel_addr; + struct vkd3d_shader_src_param *rel_addr; unsigned int offset; /* address is known to fall within the object (for optimisation) */ bool is_in_bounds; @@ -886,6 +887,8 @@ struct vkd3d_shader_src_param 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 vkd3d_data_type data_type, unsigned int idx_count); void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id); struct vkd3d_shader_index_range @@ -1019,8 +1022,6 @@ struct vkd3d_shader_desc unsigned int input_control_point_count, output_control_point_count; - uint32_t temp_count; - unsigned int ssa_count; unsigned int block_count; struct @@ -1028,8 +1029,6 @@ struct vkd3d_shader_desc uint32_t used, external; } flat_constant_count[3]; - bool use_vocp; - const char **block_names; size_t block_name_count; }; @@ -1194,11 +1193,22 @@ static inline bool register_is_constant(const struct vkd3d_shader_register *reg) return (reg->type == VKD3DSPR_IMMCONST || reg->type == VKD3DSPR_IMMCONST64); } +static inline bool register_is_scalar_constant_zero(const struct vkd3d_shader_register *reg) +{ + return register_is_constant(reg) && reg->dimension == VSIR_DIMENSION_SCALAR + && (data_type_is_64_bit(reg->data_type) ? !reg->u.immconst_u64[0] : !reg->u.immconst_u32[0]); +} + static inline bool vsir_register_is_label(const struct vkd3d_shader_register *reg) { return reg->type == VKD3DSPR_LABEL; } +static inline bool register_is_ssa(const struct vkd3d_shader_register *reg) +{ + return reg->type == VKD3DSPR_SSA; +} + struct vkd3d_shader_param_node { struct vkd3d_shader_param_node *next; @@ -1256,6 +1266,19 @@ enum vkd3d_shader_config_flags VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION = 0x00000001, }; +struct vsir_program +{ + struct vkd3d_shader_version shader_version; + struct vkd3d_shader_instruction_array instructions; + + unsigned int temp_count; + unsigned int ssa_count; + bool use_vocp; +}; + +bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve); +void vsir_program_cleanup(struct vsir_program *program); + struct vkd3d_shader_parser { struct vkd3d_shader_message_context *message_context; @@ -1263,9 +1286,8 @@ struct vkd3d_shader_parser bool failed; struct vkd3d_shader_desc shader_desc; - struct vkd3d_shader_version shader_version; const struct vkd3d_shader_parser_ops *ops; - struct vkd3d_shader_instruction_array instructions; + struct vsir_program program; uint64_t config_flags; }; @@ -1287,13 +1309,13 @@ void vkd3d_shader_parser_warning(struct vkd3d_shader_parser *parser, static inline struct vkd3d_shader_dst_param *shader_parser_get_dst_params( struct vkd3d_shader_parser *parser, unsigned int count) { - return shader_dst_param_allocator_get(&parser->instructions.dst_params, count); + return shader_dst_param_allocator_get(&parser->program.instructions.dst_params, count); } static inline struct vkd3d_shader_src_param *shader_parser_get_src_params( struct vkd3d_shader_parser *parser, unsigned int count) { - return shader_src_param_allocator_get(&parser->instructions.src_params, count); + return shader_src_param_allocator_get(&parser->program.instructions.src_params, count); } static inline void vkd3d_shader_parser_destroy(struct vkd3d_shader_parser *parser) @@ -1322,8 +1344,7 @@ struct vkd3d_shader_scan_descriptor_info1 unsigned int descriptor_count; }; -void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instructions, - const struct vkd3d_shader_version *shader_version); +void vkd3d_shader_trace(const struct vsir_program *program); const char *shader_get_type_prefix(enum vkd3d_shader_type type); @@ -1345,8 +1366,8 @@ enum vsir_asm_dialect VSIR_ASM_D3D, }; -enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, - const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, +enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vsir_program *program, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, enum vsir_asm_dialect dialect); void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer); struct vkd3d_string_buffer *vkd3d_string_buffer_get(struct vkd3d_string_buffer_cache *list); @@ -1447,7 +1468,7 @@ struct vkd3d_glsl_generator; struct vkd3d_glsl_generator *vkd3d_glsl_generator_create(const struct vkd3d_shader_version *version, struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location); int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *generator, - struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *out); + struct vsir_program *program, struct vkd3d_shader_code *out); void vkd3d_glsl_generator_destroy(struct vkd3d_glsl_generator *generator); #define SPIRV_MAX_SRC_COUNT 6 diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c index 4c39d00de24..d146e322d25 100644 --- a/libs/vkd3d/libs/vkd3d/command.c +++ b/libs/vkd3d/libs/vkd3d/command.c @@ -313,7 +313,7 @@ static void vkd3d_wait_for_gpu_fence(struct vkd3d_fence_worker *worker, TRACE("Signaling fence %p value %#"PRIx64".\n", waiting_fence->fence, waiting_fence->value); if (FAILED(hr = d3d12_fence_signal(waiting_fence->fence, waiting_fence->value, waiting_fence->u.vk_fence, false))) - ERR("Failed to signal D3D12 fence, hr %#x.\n", hr); + ERR("Failed to signal d3d12 fence, hr %s.\n", debugstr_hresult(hr)); d3d12_fence_decref(waiting_fence->fence); @@ -3706,7 +3706,7 @@ static void d3d12_command_list_copy_incompatible_texture_region(struct d3d12_com buffer_image_copy.imageExtent.height * buffer_image_copy.imageExtent.depth * layer_count; if (FAILED(hr = d3d12_command_list_allocate_transfer_buffer(list, buffer_size, &transfer_buffer))) { - ERR("Failed to allocate transfer buffer, hr %#x.\n", hr); + ERR("Failed to allocate transfer buffer, hr %s.\n", debugstr_hresult(hr)); return; } @@ -6564,7 +6564,7 @@ static void d3d12_command_queue_submit_locked(struct d3d12_command_queue *queue) if (queue->op_queue.count == 1 && !queue->is_flushing) { if (FAILED(hr = d3d12_command_queue_flush_ops_locked(queue, &flushed_any))) - ERR("Cannot flush queue, hr %#x.\n", hr); + ERR("Failed to flush queue, hr %s.\n", debugstr_hresult(hr)); } } diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c index ea243977c22..75efa41fd32 100644 --- a/libs/vkd3d/libs/vkd3d/device.c +++ b/libs/vkd3d/libs/vkd3d/device.c @@ -98,6 +98,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2), 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), VK_EXTENSION(EXT_TEXEL_BUFFER_ALIGNMENT, EXT_texel_buffer_alignment), VK_EXTENSION(EXT_TRANSFORM_FEEDBACK, EXT_transform_feedback), VK_EXTENSION(EXT_VERTEX_ATTRIBUTE_DIVISOR, EXT_vertex_attribute_divisor), @@ -1546,8 +1547,6 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, device->feature_options.StandardSwizzle64KBSupported = FALSE; device->feature_options.CrossNodeSharingTier = D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED; device->feature_options.CrossAdapterRowMajorTextureSupported = FALSE; - /* SPV_EXT_shader_viewport_index_layer */ - device->feature_options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation = FALSE; device->feature_options.ResourceHeapTier = D3D12_RESOURCE_HEAP_TIER_2; /* Shader Model 6 support. */ @@ -1653,6 +1652,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, vkd3d_free(vk_extensions); device->feature_options.PSSpecifiedStencilRefSupported = vulkan_info->EXT_shader_stencil_export; + device->feature_options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation = + vulkan_info->EXT_shader_viewport_index_layer; vkd3d_init_feature_level(vulkan_info, features, &device->feature_options); if (vulkan_info->max_feature_level < create_info->minimum_feature_level) @@ -1678,6 +1679,10 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, vulkan_info->shader_extensions[vulkan_info->shader_extension_count++] = VKD3D_SHADER_SPIRV_EXTENSION_EXT_STENCIL_EXPORT; + if (vulkan_info->EXT_shader_viewport_index_layer) + vulkan_info->shader_extensions[vulkan_info->shader_extension_count++] + = VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER; + /* Disable unused Vulkan features. */ features->shaderTessellationAndGeometryPointSize = VK_FALSE; diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h index 4abe7df3a95..13802c97773 100644 --- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h @@ -55,7 +55,7 @@ #define VKD3D_MAX_COMPATIBLE_FORMAT_COUNT 6u #define VKD3D_MAX_QUEUE_FAMILY_COUNT 3u -#define VKD3D_MAX_SHADER_EXTENSIONS 3u +#define VKD3D_MAX_SHADER_EXTENSIONS 4u #define VKD3D_MAX_SHADER_STAGES 5u #define VKD3D_MAX_VK_SYNC_OBJECTS 4u #define VKD3D_MAX_DEVICE_BLOCKED_QUEUES 16u @@ -137,6 +137,7 @@ struct vkd3d_vulkan_info bool EXT_robustness2; bool EXT_shader_demote_to_helper_invocation; bool EXT_shader_stencil_export; + bool EXT_shader_viewport_index_layer; bool EXT_texel_buffer_alignment; bool EXT_transform_feedback; bool EXT_vertex_attribute_divisor; -- 2.43.0