From 64c8a6f765bc07221a5b9d0b78bb12db0eae898e Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 3 May 2024 07:31:39 +1000 Subject: [PATCH] Updated vkd3d to 62a512c4f8c4070f0f4f3ed8e70b6f0bc885da30. --- libs/vkd3d/include/vkd3d.h | 91 +++++++++- libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 11 ++ libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 22 +-- libs/vkd3d/libs/vkd3d-shader/dxil.c | 155 +++++++++++++++++- libs/vkd3d/libs/vkd3d-shader/hlsl.c | 39 +++-- libs/vkd3d/libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 1 + .../libs/vkd3d-shader/hlsl_constant_ops.c | 130 +++++++++++++++ libs/vkd3d/libs/vkd3d-shader/spirv.c | 113 +++++++++++-- .../libs/vkd3d-shader/vkd3d_shader_main.c | 44 ++--- .../libs/vkd3d-shader/vkd3d_shader_private.h | 31 ++-- libs/vkd3d/libs/vkd3d/command.c | 21 +-- libs/vkd3d/libs/vkd3d/device.c | 36 +++- libs/vkd3d/libs/vkd3d/state.c | 2 + 14 files changed, 595 insertions(+), 102 deletions(-) diff --git a/libs/vkd3d/include/vkd3d.h b/libs/vkd3d/include/vkd3d.h index 71c56331d86..38249f0bf5c 100644 --- a/libs/vkd3d/include/vkd3d.h +++ b/libs/vkd3d/include/vkd3d.h @@ -237,47 +237,134 @@ struct vkd3d_host_time_domain_info uint64_t ticks_per_second; }; +/** + * A chained structure containing device creation parameters. + */ struct vkd3d_device_create_info { + /** Must be set to VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO. */ enum vkd3d_structure_type type; + /** Optional pointer to a structure containing further parameters. */ const void *next; + /** The minimum feature level to request. Device creation will fail with E_INVALIDARG if the + * Vulkan device doesn't have the features needed to fulfill the request. */ D3D_FEATURE_LEVEL minimum_feature_level; + /** + * The vkd3d instance to use to create a device. Either this or instance_create_info must be + * set. + */ struct vkd3d_instance *instance; + /** + * The parameters used to create an instance, which is then used to create a device. Either + * this or instance must be set. + */ const struct vkd3d_instance_create_info *instance_create_info; + /** + * The Vulkan physical device to use. If it is NULL, the first physical device found is used, + * prioritizing discrete GPUs over integrated GPUs and integrated GPUs over all the others. + * + * This parameter can be overridden by setting environment variable VKD3D_VULKAN_DEVICE. + */ VkPhysicalDevice vk_physical_device; + /** + * A list of Vulkan device extensions to request. They are intended as required, so device + * creation will fail if any of them is not available. + */ const char * const *device_extensions; + /** The number of elements in the device_extensions array. */ uint32_t device_extension_count; + /** + * An object to be set as the device parent. This is not used by vkd3d except for being + * returned by vkd3d_get_device_parent. + */ IUnknown *parent; + /** + * The adapter LUID to be set for the device. This is not used by vkd3d except for being + * returned by GetAdapterLuid. + */ LUID adapter_luid; }; -/* Extends vkd3d_device_create_info. Available since 1.2. */ +/** + * A chained structure to specify optional device extensions. + * + * This structure extends vkd3d_device_create_info. + * + * \since 1.2 + */ struct vkd3d_optional_device_extensions_info { + /** Must be set to VKD3D_STRUCTURE_TYPE_OPTIONAL_DEVICE_EXTENSIONS_INFO. */ enum vkd3d_structure_type type; + /** Optional pointer to a structure containing further parameters. */ const void *next; + /** + * A list of optional Vulkan device extensions to request. Device creation does not fail if + * they are not available. + */ const char * const *extensions; + /** The number of elements in the extensions array. */ uint32_t extension_count; }; -/* vkd3d_image_resource_create_info flags */ +/** + * When specified as a flag of vkd3d_image_resource_create_info, it means that vkd3d will do the + * initial transition operation on the image from VK_IMAGE_LAYOUT_UNDEFINED to its appropriate + * Vulkan layout (depending on its D3D12 resource state). If this flag is not specified the caller + * is responsible for transitioning the Vulkan image to the appropriate layout. + */ #define VKD3D_RESOURCE_INITIAL_STATE_TRANSITION 0x00000001 +/** + * When specified as a flag of vkd3d_image_resource_create_info, it means that field present_state + * is honored. + */ #define VKD3D_RESOURCE_PRESENT_STATE_TRANSITION 0x00000002 +/** + * A chained structure containing the parameters to create a D3D12 resource backed by a Vulkan + * image. + */ struct vkd3d_image_resource_create_info { + /** Must be set to VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO. */ enum vkd3d_structure_type type; + /** Optional pointer to a structure containing further parameters. */ const void *next; + /** The Vulkan image that backs the resource. */ VkImage vk_image; + /** The resource description. */ D3D12_RESOURCE_DESC desc; + /** + * A combination of zero or more flags. The valid flags are + * VKD3D_RESOURCE_INITIAL_STATE_TRANSITION and VKD3D_RESOURCE_PRESENT_STATE_TRANSITION. + */ unsigned int flags; + /** + * This field specifies how to handle resource state D3D12_RESOURCE_STATE_PRESENT for + * the resource. Notice that on D3D12 there is no difference between + * D3D12_RESOURCE_STATE_COMMON and D3D12_RESOURCE_STATE_PRESENT (they have the same value), + * while on Vulkan two different layouts are used (VK_IMAGE_LAYOUT_GENERAL and + * VK_IMAGE_LAYOUT_PRESENT_SRC_KHR). + * + * * When flag VKD3D_RESOURCE_PRESENT_STATE_TRANSITION is not specified, field + * present_state is ignored and resource state D3D12_RESOURCE_STATE_COMMON/_PRESENT is + * mapped to VK_IMAGE_LAYOUT_GENERAL; this is useful for non-swapchain resources. + * * Otherwise, when present_state is D3D12_RESOURCE_STATE_PRESENT/_COMMON, resource state + * D3D12_RESOURCE_STATE_COMMON/_PRESENT is mapped to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + * this is useful for swapchain resources that are directly backed by a Vulkan swapchain + * image. + * * Otherwise, resource state D3D12_RESOURCE_STATE_COMMON/_PRESENT is treated as resource + * state present_state; this is useful for swapchain resources that backed by a Vulkan + * non-swapchain image, which the client will likely consume with a copy or drawing + * operation at presentation time. + */ D3D12_RESOURCE_STATES present_state; }; diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c index cd8ba0a7d2b..b2f329cd199 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c @@ -327,6 +327,9 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_UTOD ] = "utod", [VKD3DSIH_UTOF ] = "utof", [VKD3DSIH_UTOU ] = "utou", + [VKD3DSIH_WAVE_ACTIVE_ALL_EQUAL ] = "wave_active_all_equal", + [VKD3DSIH_WAVE_ALL_TRUE ] = "wave_all_true", + [VKD3DSIH_WAVE_ANY_TRUE ] = "wave_any_true", [VKD3DSIH_XOR ] = "xor", }; @@ -1161,6 +1164,14 @@ static void shader_print_register(struct vkd3d_d3d_asm_compiler *compiler, const vkd3d_string_buffer_printf(buffer, "sr"); break; + case VKD3DSPR_WAVELANECOUNT: + vkd3d_string_buffer_printf(buffer, "vWaveLaneCount"); + break; + + case VKD3DSPR_WAVELANEINDEX: + vkd3d_string_buffer_printf(buffer, "vWaveLaneIndex"); + break; + default: vkd3d_string_buffer_printf(buffer, "%s%s", compiler->colours.error, reg->type, compiler->colours.reset); diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c index 09e4f596241..aa2358440e5 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c @@ -215,8 +215,12 @@ struct vkd3d_shader_sm1_parser struct vkd3d_shader_parser p; + struct + { #define MAX_CONSTANT_COUNT 8192 - uint32_t constant_def_mask[3][VKD3D_BITMAP_SIZE(MAX_CONSTANT_COUNT)]; + uint32_t def_mask[VKD3D_BITMAP_SIZE(MAX_CONSTANT_COUNT)]; + uint32_t count; + } constants[3]; }; /* This table is not order or position dependent. */ @@ -750,15 +754,13 @@ static bool add_signature_element_from_semantic(struct vkd3d_shader_sm1_parser * static void record_constant_register(struct vkd3d_shader_sm1_parser *sm1, enum vkd3d_shader_d3dbc_constant_register set, uint32_t index, bool from_def) { - struct vkd3d_shader_desc *desc = &sm1->p.shader_desc; - - desc->flat_constant_count[set].used = max(desc->flat_constant_count[set].used, index + 1); + sm1->constants[set].count = max(sm1->constants[set].count, index + 1); if (from_def) { /* d3d shaders have a maximum of 8192 constants; we should not overrun * this array. */ - assert((index / 32) <= ARRAY_SIZE(sm1->constant_def_mask[set])); - bitmap_set(sm1->constant_def_mask[set], index); + assert((index / 32) <= ARRAY_SIZE(sm1->constants[set].def_mask)); + bitmap_set(sm1->constants[set].def_mask, index); } } @@ -1301,9 +1303,9 @@ static uint32_t get_external_constant_count(struct vkd3d_shader_sm1_parser *sm1, /* Find the highest constant index which is not written by a DEF * instruction. We can't (easily) use an FFZ function for this since it * needs to be limited by the highest used register index. */ - for (j = sm1->p.shader_desc.flat_constant_count[set].used; j > 0; --j) + for (j = sm1->constants[set].count; j > 0; --j) { - if (!bitmap_is_set(sm1->constant_def_mask[set], j - 1)) + if (!bitmap_is_set(sm1->constants[set].def_mask, j - 1)) return j; } @@ -1354,8 +1356,8 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi ++instructions->count; } - for (i = 0; i < ARRAY_SIZE(sm1->p.shader_desc.flat_constant_count); ++i) - sm1->p.shader_desc.flat_constant_count[i].external = get_external_constant_count(sm1, i); + for (i = 0; i < ARRAY_SIZE(sm1->p.program.flat_constant_count); ++i) + sm1->p.program.flat_constant_count[i] = get_external_constant_count(sm1, i); if (!sm1->p.failed) ret = vkd3d_shader_parser_validate(&sm1->p); diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c index 6a1fb6bddb7..e636ad917db 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -31,7 +31,7 @@ static const uint64_t GLOBALVAR_FLAG_EXPLICIT_TYPE = 2; static const unsigned int GLOBALVAR_ADDRESS_SPACE_SHIFT = 2; static const uint64_t ALLOCA_FLAG_IN_ALLOCA = 0x20; static const uint64_t ALLOCA_FLAG_EXPLICIT_TYPE = 0x40; -static const uint64_t ALLOCA_ALIGNMENT_MASK = ALLOCA_FLAG_IN_ALLOCA - 1; +static const uint64_t ALLOCA_ALIGNMENT_MASK = 0x1f; static const unsigned int SHADER_DESCRIPTOR_TYPE_COUNT = 4; static const size_t MAX_IR_INSTRUCTIONS_PER_DXIL_INSTRUCTION = 11; @@ -103,6 +103,7 @@ enum bitcode_constant_code CST_CODE_INTEGER = 4, CST_CODE_FLOAT = 6, CST_CODE_STRING = 8, + CST_CODE_CE_CAST = 11, CST_CODE_CE_GEP = 12, CST_CODE_CE_INBOUNDS_GEP = 20, CST_CODE_DATA = 22, @@ -413,6 +414,7 @@ enum dx_intrinsic_opcode DX_DERIV_COARSEY = 84, DX_DERIV_FINEX = 85, DX_DERIV_FINEY = 86, + DX_COVERAGE = 91, DX_THREAD_ID = 93, DX_GROUP_ID = 94, DX_THREAD_ID_IN_GROUP = 95, @@ -425,6 +427,11 @@ enum dx_intrinsic_opcode DX_STORE_PATCH_CONSTANT = 106, DX_OUTPUT_CONTROL_POINT_ID = 107, DX_PRIMITIVE_ID = 108, + DX_WAVE_GET_LANE_INDEX = 111, + DX_WAVE_GET_LANE_COUNT = 112, + DX_WAVE_ANY_TRUE = 113, + DX_WAVE_ALL_TRUE = 114, + DX_WAVE_ACTIVE_ALL_EQUAL = 115, DX_LEGACY_F32TOF16 = 130, DX_LEGACY_F16TOF32 = 131, DX_RAW_BUFFER_LOAD = 139, @@ -606,6 +613,7 @@ struct sm6_value enum sm6_value_type value_type; unsigned int structure_stride; bool is_undefined; + bool is_back_ref; union { struct sm6_function_data function; @@ -2216,6 +2224,11 @@ static bool sm6_value_is_ssa(const struct sm6_value *value) return sm6_value_is_register(value) && register_is_ssa(&value->u.reg); } +static bool sm6_value_is_numeric_array(const struct sm6_value *value) +{ + return sm6_value_is_register(value) && register_is_numeric_array(&value->u.reg); +} + static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *value) { if (!sm6_value_is_constant(value)) @@ -2658,6 +2671,18 @@ static bool sm6_value_validate_is_pointer(const struct sm6_value *value, struct return true; } +static bool sm6_value_validate_is_backward_ref(const struct sm6_value *value, struct sm6_parser *sm6) +{ + if (!value->is_back_ref) + { + FIXME("Forward-referenced pointers are not supported.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Forward-referenced pointer declarations are not supported."); + return false; + } + return true; +} + static bool sm6_value_validate_is_numeric(const struct sm6_value *value, struct sm6_parser *sm6) { if (!sm6_type_is_numeric(value->type)) @@ -3086,15 +3111,16 @@ static enum vkd3d_result sm6_parser_init_constexpr_gep(struct sm6_parser *sm6, c static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) { enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; - const struct sm6_type *type, *elem_type; + const struct sm6_type *type, *elem_type, *ptr_type; + size_t i, base_value_idx, value_idx; enum vkd3d_data_type reg_data_type; const struct dxil_record *record; + const struct sm6_value *src; enum vkd3d_result ret; struct sm6_value *dst; - size_t i, value_idx; uint64_t value; - for (i = 0, type = NULL; i < block->record_count; ++i) + for (i = 0, type = NULL, base_value_idx = sm6->value_count; i < block->record_count; ++i) { sm6->p.location.column = i; record = block->records[i]; @@ -3135,6 +3161,7 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const dst = sm6_parser_get_current_value(sm6); dst->type = type; dst->value_type = VALUE_TYPE_REG; + dst->is_back_ref = true; vsir_register_init(&dst->u.reg, reg_type, reg_data_type, 0); switch (record->code) @@ -3209,6 +3236,48 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const return ret; break; + case CST_CODE_CE_CAST: + if (!dxil_record_validate_operand_count(record, 3, 3, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + if ((value = record->operands[0]) != CAST_BITCAST) + { + WARN("Unhandled constexpr cast op %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Constexpr cast op %"PRIu64" is unhandled.", value); + return VKD3D_ERROR_INVALID_SHADER; + } + + ptr_type = sm6_parser_get_type(sm6, record->operands[1]); + if (!sm6_type_is_pointer(ptr_type)) + { + WARN("Constexpr cast at constant idx %zu is not a pointer.\n", value_idx); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Constexpr cast source operand is not a pointer."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if ((value = record->operands[2]) >= sm6->cur_max_value) + { + WARN("Invalid value index %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value index %"PRIu64".", value); + return VKD3D_ERROR_INVALID_SHADER; + } + else if (value == value_idx) + { + WARN("Invalid value self-reference at %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value self-reference for a constexpr cast."); + return VKD3D_ERROR_INVALID_SHADER; + } + + /* Resolve later in case forward refs exist. */ + dst->type = type; + dst->u.reg.type = VKD3DSPR_COUNT; + dst->u.reg.idx[0].offset = value; + break; + case CST_CODE_UNDEF: dxil_record_validate_operand_max_count(record, 0, sm6); dst->u.reg.type = VKD3DSPR_UNDEF; @@ -3234,6 +3303,29 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const ++sm6->value_count; } + /* Resolve cast forward refs. */ + for (i = base_value_idx; i < sm6->value_count; ++i) + { + dst = &sm6->values[i]; + if (dst->u.reg.type != VKD3DSPR_COUNT) + continue; + + type = dst->type; + + src = &sm6->values[dst->u.reg.idx[0].offset]; + if (!sm6_value_is_numeric_array(src)) + { + WARN("Value is not an array.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Constexpr cast source value is not a global array element."); + return VKD3D_ERROR_INVALID_SHADER; + } + + *dst = *src; + dst->type = type; + dst->u.reg.data_type = vkd3d_data_type_from_sm6_type(type->u.pointer.type); + } + return VKD3D_OK; } @@ -3462,6 +3554,7 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_ dst = sm6_parser_get_current_value(sm6); dst->type = type; dst->value_type = VALUE_TYPE_REG; + dst->is_back_ref = true; if (is_constant && !init) { @@ -3946,7 +4039,8 @@ static void sm6_parser_emit_atomicrmw(struct sm6_parser *sm6, const struct dxil_ uint64_t code; if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) - || !sm6_value_validate_is_pointer_to_i32(ptr, sm6)) + || !sm6_value_validate_is_pointer_to_i32(ptr, sm6) + || !sm6_value_validate_is_backward_ref(ptr, sm6)) return; if (ptr->u.reg.type != VKD3DSPR_GROUPSHAREDMEM) @@ -4421,6 +4515,12 @@ static enum vkd3d_shader_opcode map_dx_unary_op(enum dx_intrinsic_opcode op) return VKD3DSIH_F32TOF16; case DX_LEGACY_F16TOF32: return VKD3DSIH_F16TOF32; + case DX_WAVE_ACTIVE_ALL_EQUAL: + return VKD3DSIH_WAVE_ACTIVE_ALL_EQUAL; + case DX_WAVE_ALL_TRUE: + return VKD3DSIH_WAVE_ALL_TRUE; + case DX_WAVE_ANY_TRUE: + return VKD3DSIH_WAVE_ANY_TRUE; default: vkd3d_unreachable(); } @@ -4729,6 +4829,12 @@ static void sm6_parser_emit_dx_input_register_mov(struct sm6_parser *sm6, instruction_dst_param_init_ssa_scalar(ins, sm6); } +static void sm6_parser_emit_dx_coverage(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + sm6_parser_emit_dx_input_register_mov(sm6, state->ins, VKD3DSPR_COVERAGE, VKD3D_DATA_UINT); +} + static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_parser *sm6, enum vkd3d_shader_descriptor_type type, unsigned int id, const struct sm6_value *address) { @@ -5804,6 +5910,26 @@ static void sm6_parser_emit_dx_texture_store(struct sm6_parser *sm6, enum dx_int dst_param_init_with_mask(dst_param, write_mask); } +static void sm6_parser_emit_dx_wave_builtin(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + enum vkd3d_shader_register_type type; + + switch (op) + { + case DX_WAVE_GET_LANE_COUNT: + type = VKD3DSPR_WAVELANECOUNT; + break; + case DX_WAVE_GET_LANE_INDEX: + type = VKD3DSPR_WAVELANEINDEX; + break; + default: + vkd3d_unreachable(); + } + + sm6_parser_emit_dx_input_register_mov(sm6, state->ins, type, VKD3D_DATA_UINT); +} + struct sm6_dx_opcode_info { const char *ret_type; @@ -5820,6 +5946,7 @@ struct sm6_dx_opcode_info C -> constant or undefined int8/16/32 i -> int32 m -> int16/32/64 + n -> any numeric f -> float d -> double e -> half/float @@ -5847,6 +5974,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_CBUFFER_LOAD_LEGACY ] = {"o", "Hi", sm6_parser_emit_dx_cbuffer_load}, [DX_COS ] = {"g", "R", sm6_parser_emit_dx_sincos}, [DX_COUNT_BITS ] = {"i", "m", sm6_parser_emit_dx_unary}, + [DX_COVERAGE ] = {"i", "", sm6_parser_emit_dx_coverage}, [DX_CREATE_HANDLE ] = {"H", "ccib", sm6_parser_emit_dx_create_handle}, [DX_DERIV_COARSEX ] = {"e", "R", sm6_parser_emit_dx_unary}, [DX_DERIV_COARSEY ] = {"e", "R", sm6_parser_emit_dx_unary}, @@ -5922,6 +6050,11 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_UMAD ] = {"m", "RRR", sm6_parser_emit_dx_ma}, [DX_UMAX ] = {"m", "RR", sm6_parser_emit_dx_binary}, [DX_UMIN ] = {"m", "RR", sm6_parser_emit_dx_binary}, + [DX_WAVE_ACTIVE_ALL_EQUAL ] = {"1", "n", sm6_parser_emit_dx_unary}, + [DX_WAVE_ALL_TRUE ] = {"1", "1", sm6_parser_emit_dx_unary}, + [DX_WAVE_ANY_TRUE ] = {"1", "1", sm6_parser_emit_dx_unary}, + [DX_WAVE_GET_LANE_COUNT ] = {"i", "", sm6_parser_emit_dx_wave_builtin}, + [DX_WAVE_GET_LANE_INDEX ] = {"i", "", sm6_parser_emit_dx_wave_builtin}, }; static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_value *value, char info_type, @@ -5953,6 +6086,8 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc return sm6_type_is_i32(type); case 'm': return sm6_type_is_i16_i32_i64(type); + case 'n': + return sm6_type_is_numeric(type); case 'f': return sm6_type_is_float(type); case 'd': @@ -6446,7 +6581,8 @@ static void sm6_parser_emit_cmpxchg(struct sm6_parser *sm6, const struct dxil_re uint64_t code; if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) - || !sm6_value_validate_is_pointer_to_i32(ptr, sm6)) + || !sm6_value_validate_is_pointer_to_i32(ptr, sm6) + || !sm6_value_validate_is_backward_ref(ptr, sm6)) return; if (ptr->u.reg.type != VKD3DSPR_GROUPSHAREDMEM) @@ -6687,6 +6823,7 @@ static void sm6_parser_emit_load(struct sm6_parser *sm6, const struct dxil_recor return; if (!sm6_value_validate_is_register(ptr, sm6) || !sm6_value_validate_is_pointer(ptr, sm6) + || !sm6_value_validate_is_backward_ref(ptr, sm6) || !dxil_record_validate_operand_count(record, i + 2, i + 3, sm6)) return; @@ -6870,7 +7007,8 @@ static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_reco if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)) || !sm6_value_validate_is_register(ptr, sm6) - || !sm6_value_validate_is_pointer(ptr, sm6)) + || !sm6_value_validate_is_pointer(ptr, sm6) + || !sm6_value_validate_is_backward_ref(ptr, sm6)) { return; } @@ -7478,6 +7616,7 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const fwd_type = dst->type; dst->type = NULL; dst->value_type = VALUE_TYPE_REG; + dst->is_back_ref = true; is_terminator = false; record = block->records[i]; @@ -8081,7 +8220,9 @@ 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_INSTANCEID] = VKD3D_SHADER_SV_INSTANCE_ID, [SEMANTIC_KIND_POSITION] = VKD3D_SHADER_SV_POSITION, + [SEMANTIC_KIND_PRIMITIVEID] = VKD3D_SHADER_SV_PRIMITIVE_ID, [SEMANTIC_KIND_ISFRONTFACE] = VKD3D_SHADER_SV_IS_FRONT_FACE, [SEMANTIC_KIND_TARGET] = VKD3D_SHADER_SV_TARGET, [SEMANTIC_KIND_DEPTH] = VKD3D_SHADER_SV_DEPTH, diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c index 4fc1493bdce..0b48b17d21c 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c @@ -3517,6 +3517,7 @@ static int compare_function_rb(const void *key, const struct rb_entry *entry) static void declare_predefined_types(struct hlsl_ctx *ctx) { + struct vkd3d_string_buffer *name; unsigned int x, y, bt, i, v; struct hlsl_type *type; @@ -3529,7 +3530,6 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) "uint", "bool", }; - char name[15]; static const char *const variants_float[] = {"min10float", "min16float"}; static const char *const variants_int[] = {"min12int", "min16int"}; @@ -3573,28 +3573,34 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) {"technique11", 11}, }; + if (!(name = hlsl_get_string_buffer(ctx))) + return; + for (bt = 0; bt <= HLSL_TYPE_LAST_SCALAR; ++bt) { for (y = 1; y <= 4; ++y) { for (x = 1; x <= 4; ++x) { - sprintf(name, "%s%ux%u", names[bt], y, x); - type = hlsl_new_type(ctx, name, HLSL_CLASS_MATRIX, bt, x, y); + vkd3d_string_buffer_clear(name); + vkd3d_string_buffer_printf(name, "%s%ux%u", names[bt], y, x); + type = hlsl_new_type(ctx, name->buffer, HLSL_CLASS_MATRIX, bt, x, y); hlsl_scope_add_type(ctx->globals, type); ctx->builtin_types.matrix[bt][x - 1][y - 1] = type; if (y == 1) { - sprintf(name, "%s%u", names[bt], x); - type = hlsl_new_type(ctx, name, HLSL_CLASS_VECTOR, bt, x, y); + vkd3d_string_buffer_clear(name); + vkd3d_string_buffer_printf(name, "%s%u", names[bt], x); + type = hlsl_new_type(ctx, name->buffer, HLSL_CLASS_VECTOR, bt, x, y); hlsl_scope_add_type(ctx->globals, type); ctx->builtin_types.vector[bt][x - 1] = type; if (x == 1) { - sprintf(name, "%s", names[bt]); - type = hlsl_new_type(ctx, name, HLSL_CLASS_SCALAR, bt, x, y); + vkd3d_string_buffer_clear(name); + vkd3d_string_buffer_printf(name, "%s", names[bt]); + type = hlsl_new_type(ctx, name->buffer, HLSL_CLASS_SCALAR, bt, x, y); hlsl_scope_add_type(ctx->globals, type); ctx->builtin_types.scalar[bt] = type; } @@ -3637,22 +3643,25 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) { for (x = 1; x <= 4; ++x) { - sprintf(name, "%s%ux%u", variants[v], y, x); - type = hlsl_new_type(ctx, name, HLSL_CLASS_MATRIX, bt, x, y); + vkd3d_string_buffer_clear(name); + vkd3d_string_buffer_printf(name, "%s%ux%u", variants[v], y, x); + type = hlsl_new_type(ctx, name->buffer, HLSL_CLASS_MATRIX, bt, x, y); type->is_minimum_precision = 1; hlsl_scope_add_type(ctx->globals, type); if (y == 1) { - sprintf(name, "%s%u", variants[v], x); - type = hlsl_new_type(ctx, name, HLSL_CLASS_VECTOR, bt, x, y); + vkd3d_string_buffer_clear(name); + vkd3d_string_buffer_printf(name, "%s%u", variants[v], x); + type = hlsl_new_type(ctx, name->buffer, HLSL_CLASS_VECTOR, bt, x, y); type->is_minimum_precision = 1; hlsl_scope_add_type(ctx->globals, type); if (x == 1) { - sprintf(name, "%s", variants[v]); - type = hlsl_new_type(ctx, name, HLSL_CLASS_SCALAR, bt, x, y); + vkd3d_string_buffer_clear(name); + vkd3d_string_buffer_printf(name, "%s", variants[v]); + type = hlsl_new_type(ctx, name->buffer, HLSL_CLASS_SCALAR, bt, x, y); type->is_minimum_precision = 1; hlsl_scope_add_type(ctx->globals, type); } @@ -3690,6 +3699,8 @@ static void declare_predefined_types(struct hlsl_ctx *ctx) type->e.version = technique_types[i].version; hlsl_scope_add_type(ctx->globals, type); } + + hlsl_release_string_buffer(ctx, name); } static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info *compile_info, @@ -3965,7 +3976,7 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d } if (ret >= 0) { - ret = vkd3d_shader_parser_compile(parser, &info, out, message_context); + ret = vsir_program_compile(&parser->program, parser->config_flags, &info, out, message_context); vkd3d_shader_parser_destroy(parser); } vkd3d_shader_free_shader_code(&info.source); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h index 1e5f0805152..c3a4c6bd291 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h @@ -1422,6 +1422,7 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere bool hlsl_copy_propagation_execute(struct hlsl_ctx *ctx, struct hlsl_block *block); bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); +bool hlsl_fold_constant_identities(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); bool hlsl_fold_constant_swizzles(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), struct hlsl_block *block, void *context); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c index a6d6b336b40..94acb70fff9 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c @@ -5427,6 +5427,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry do { progress = hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL); + progress |= hlsl_transform_ir(ctx, hlsl_fold_constant_identities, body, NULL); progress |= hlsl_transform_ir(ctx, hlsl_fold_constant_swizzles, body, NULL); progress |= hlsl_copy_propagation_execute(ctx, body); progress |= hlsl_transform_ir(ctx, fold_swizzle_chains, body, NULL); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c index 4cea98e9286..51f2f9cc050 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_constant_ops.c @@ -1396,6 +1396,136 @@ bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, return success; } +static bool constant_is_zero(struct hlsl_ir_constant *const_arg) +{ + struct hlsl_type *data_type = const_arg->node.data_type; + unsigned int k; + + for (k = 0; k < data_type->dimx; ++k) + { + switch (data_type->base_type) + { + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_HALF: + if (const_arg->value.u[k].f != 0.0f) + return false; + break; + + case HLSL_TYPE_DOUBLE: + if (const_arg->value.u[k].d != 0.0) + return false; + break; + + case HLSL_TYPE_UINT: + case HLSL_TYPE_INT: + case HLSL_TYPE_BOOL: + if (const_arg->value.u[k].u != 0) + return false; + break; + + default: + return false; + } + } + return true; +} + +static bool constant_is_one(struct hlsl_ir_constant *const_arg) +{ + struct hlsl_type *data_type = const_arg->node.data_type; + unsigned int k; + + for (k = 0; k < data_type->dimx; ++k) + { + switch (data_type->base_type) + { + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_HALF: + if (const_arg->value.u[k].f != 1.0f) + return false; + break; + + case HLSL_TYPE_DOUBLE: + if (const_arg->value.u[k].d != 1.0) + return false; + break; + + case HLSL_TYPE_UINT: + case HLSL_TYPE_INT: + case HLSL_TYPE_BOOL: + if (const_arg->value.u[k].u != 1) + return false; + break; + + default: + return false; + } + } + return true; +} + +bool hlsl_fold_constant_identities(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_constant *const_arg = NULL; + struct hlsl_ir_node *mut_arg = NULL; + struct hlsl_ir_node *res_node; + struct hlsl_ir_expr *expr; + unsigned int i; + + if (instr->type != HLSL_IR_EXPR) + return false; + expr = hlsl_ir_expr(instr); + + if (instr->data_type->class > HLSL_CLASS_VECTOR) + return false; + + /* Verify that the expression has two operands. */ + for (i = 0; i < ARRAY_SIZE(expr->operands); ++i) + { + if (!!expr->operands[i].node != (i < 2)) + return false; + } + + if (expr->operands[0].node->type == HLSL_IR_CONSTANT) + { + const_arg = hlsl_ir_constant(expr->operands[0].node); + mut_arg = expr->operands[1].node; + } + else if (expr->operands[1].node->type == HLSL_IR_CONSTANT) + { + mut_arg = expr->operands[0].node; + const_arg = hlsl_ir_constant(expr->operands[1].node); + } + else + { + return false; + } + + res_node = NULL; + switch (expr->op) + { + case HLSL_OP2_ADD: + if (constant_is_zero(const_arg)) + res_node = mut_arg; + break; + + case HLSL_OP2_MUL: + if (constant_is_one(const_arg)) + res_node = mut_arg; + break; + + default: + break; + } + + if (res_node) + { + hlsl_replace_node(&expr->node, res_node); + return true; + } + return false; +} + bool hlsl_fold_constant_swizzles(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { struct hlsl_constant_value value; diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c index c4e712b8471..dc9e8c06a5e 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -361,6 +361,7 @@ struct vkd3d_spirv_builder uint32_t type_sampler_id; uint32_t type_bool_id; uint32_t type_void_id; + uint32_t scope_subgroup_id; struct vkd3d_spirv_stream debug_stream; /* debug instructions */ struct vkd3d_spirv_stream annotation_stream; /* decoration instructions */ @@ -1741,6 +1742,16 @@ static void vkd3d_spirv_build_op_memory_barrier(struct vkd3d_spirv_builder *buil SpvOpMemoryBarrier, memory_id, memory_semantics_id); } +static uint32_t vkd3d_spirv_build_op_scope_subgroup(struct vkd3d_spirv_builder *builder) +{ + return vkd3d_spirv_get_op_constant(builder, vkd3d_spirv_get_op_type_int(builder, 32, 0), SpvScopeSubgroup); +} + +static uint32_t vkd3d_spirv_get_op_scope_subgroup(struct vkd3d_spirv_builder *builder) +{ + return vkd3d_spirv_build_once(builder, &builder->scope_subgroup_id, vkd3d_spirv_build_op_scope_subgroup); +} + static uint32_t vkd3d_spirv_build_op_glsl_std450_tr1(struct vkd3d_spirv_builder *builder, enum GLSLstd450 op, uint32_t result_type, uint32_t operand) { @@ -2453,8 +2464,7 @@ static void spirv_compiler_destroy(struct spirv_compiler *compiler) static struct spirv_compiler *spirv_compiler_create(const struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info, - struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location, - uint64_t config_flags) + struct vkd3d_shader_message_context *message_context, uint64_t config_flags) { const struct shader_signature *patch_constant_signature = &program->patch_constant_signature; const struct shader_signature *output_signature = &program->output_signature; @@ -2470,7 +2480,7 @@ static struct spirv_compiler *spirv_compiler_create(const struct vsir_program *p memset(compiler, 0, sizeof(*compiler)); compiler->message_context = message_context; - compiler->location = *location; + compiler->location.source_name = compile_info->source_name; compiler->config_flags = config_flags; if ((target_info = vkd3d_find_struct(compile_info->next, SPIRV_TARGET_INFO))) @@ -2632,6 +2642,11 @@ static bool spirv_compiler_is_opengl_target(const struct spirv_compiler *compile return spirv_compiler_get_target_environment(compiler) == VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5; } +static bool spirv_compiler_is_spirv_min_1_3_target(const struct spirv_compiler *compiler) +{ + return spirv_compiler_get_target_environment(compiler) == VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1; +} + static bool spirv_compiler_is_target_extension_supported(const struct spirv_compiler *compiler, enum vkd3d_shader_spirv_extension extension) { @@ -3150,6 +3165,12 @@ static bool spirv_compiler_get_register_name(char *buffer, unsigned int buffer_s case VKD3DSPR_OUTSTENCILREF: snprintf(buffer, buffer_size, "oStencilRef"); break; + case VKD3DSPR_WAVELANECOUNT: + snprintf(buffer, buffer_size, "vWaveLaneCount"); + break; + case VKD3DSPR_WAVELANEINDEX: + snprintf(buffer, buffer_size, "vWaveLaneIndex"); + break; default: FIXME("Unhandled register %#x.\n", reg->type); snprintf(buffer, buffer_size, "unrecognized_%#x", reg->type); @@ -4535,6 +4556,10 @@ static void spirv_compiler_decorate_builtin(struct spirv_compiler *compiler, case SpvBuiltInCullDistance: vkd3d_spirv_enable_capability(builder, SpvCapabilityCullDistance); break; + case SpvBuiltInSubgroupSize: + case SpvBuiltInSubgroupLocalInvocationId: + vkd3d_spirv_enable_capability(builder, SpvCapabilityGroupNonUniform); + break; default: break; } @@ -4724,6 +4749,9 @@ vkd3d_register_builtins[] = {VKD3DSPR_DEPTHOUTLE, {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInFragDepth}}, {VKD3DSPR_OUTSTENCILREF, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInFragStencilRefEXT}}, + + {VKD3DSPR_WAVELANECOUNT, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSubgroupSize}}, + {VKD3DSPR_WAVELANEINDEX, {VKD3D_SHADER_COMPONENT_UINT, 1, SpvBuiltInSubgroupLocalInvocationId}}, }; static void spirv_compiler_emit_register_execution_mode(struct spirv_compiler *compiler, @@ -5772,6 +5800,23 @@ static void spirv_compiler_emit_dcl_global_flags(struct spirv_compiler *compiler flags &= ~VKD3DSGF_ENABLE_INT64; } + if (flags & VKD3DSGF_ENABLE_WAVE_INTRINSICS) + { + if (!(compiler->features & VKD3D_SHADER_COMPILE_OPTION_FEATURE_WAVE_OPS)) + { + WARN("Unsupported wave ops.\n"); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE, + "The target environment does not support wave ops."); + } + else if (!spirv_compiler_is_spirv_min_1_3_target(compiler)) + { + WARN("Wave ops enabled but environment does not support SPIR-V 1.3 or greater.\n"); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE, + "The target environment uses wave ops but does not support SPIR-V 1.3 or greater."); + } + flags &= ~VKD3DSGF_ENABLE_WAVE_INTRINSICS; + } + if (flags & ~(VKD3DSGF_REFACTORING_ALLOWED | VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS)) FIXME("Unhandled global flags %#"PRIx64".\n", (uint64_t)flags); else @@ -9713,6 +9758,41 @@ static void spirv_compiler_emit_cut_stream(struct spirv_compiler *compiler, vkd3d_spirv_build_op_end_primitive(builder); } +static SpvOp map_wave_bool_op(enum vkd3d_shader_opcode handler_idx) +{ + switch (handler_idx) + { + case VKD3DSIH_WAVE_ACTIVE_ALL_EQUAL: + return SpvOpGroupNonUniformAllEqual; + case VKD3DSIH_WAVE_ALL_TRUE: + return SpvOpGroupNonUniformAll; + case VKD3DSIH_WAVE_ANY_TRUE: + return SpvOpGroupNonUniformAny; + default: + vkd3d_unreachable(); + } +} + +static void spirv_compiler_emit_wave_bool_op(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vkd3d_shader_src_param *src = instruction->src; + uint32_t type_id, val_id; + SpvOp op; + + vkd3d_spirv_enable_capability(builder, SpvCapabilityGroupNonUniformVote); + + op = map_wave_bool_op(instruction->handler_idx); + type_id = vkd3d_spirv_get_op_type_bool(builder); + val_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask); + val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, + type_id, vkd3d_spirv_get_op_scope_subgroup(builder), val_id); + + spirv_compiler_emit_store_dst(compiler, dst, val_id); +} + /* This function is called after declarations are processed. */ static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler) { @@ -9732,6 +9812,8 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, { int ret = VKD3D_OK; + compiler->location = instruction->location; + switch (instruction->handler_idx) { case VKD3DSIH_DCL_GLOBAL_FLAGS: @@ -10055,6 +10137,11 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_CUT_STREAM: spirv_compiler_emit_cut_stream(compiler, instruction); break; + case VKD3DSIH_WAVE_ACTIVE_ALL_EQUAL: + case VKD3DSIH_WAVE_ALL_TRUE: + case VKD3DSIH_WAVE_ANY_TRUE: + spirv_compiler_emit_wave_bool_op(compiler, instruction); + break; case VKD3DSIH_DCL: case VKD3DSIH_DCL_HS_MAX_TESSFACTOR: case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT: @@ -10151,15 +10238,13 @@ static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *c } } -static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser, - struct vkd3d_shader_code *spirv) +static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct vsir_program *program, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *spirv) { const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info; const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_shader_instruction_array instructions; - struct vsir_program *program = &parser->program; enum vkd3d_shader_spirv_environment environment; enum vkd3d_result result = VKD3D_OK; unsigned int i; @@ -10175,9 +10260,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, spirv_compiler_emit_descriptor_declarations(compiler); - compiler->location.column = 0; - compiler->location.line = 1; - if (program->block_count && !spirv_compiler_init_blocks(compiler, program->block_count)) return VKD3D_ERROR_OUT_OF_MEMORY; @@ -10202,7 +10284,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, for (i = 0; i < instructions.count && result >= 0; ++i) { - compiler->location.line = i + 1; result = spirv_compiler_handle_instruction(compiler, &instructions.elements[i]); } @@ -10249,7 +10330,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, if (!vkd3d_spirv_compile_module(builder, spirv, spirv_compiler_get_entry_point_name(compiler), environment)) return VKD3D_ERROR; - if (TRACE_ON() || parser->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION) + if (TRACE_ON() || compiler->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION) { struct vkd3d_string_buffer buffer; @@ -10287,7 +10368,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, return VKD3D_OK; } -int spirv_compile(struct vkd3d_shader_parser *parser, +int spirv_compile(struct vsir_program *program, uint64_t config_flags, const struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) @@ -10295,14 +10376,14 @@ int spirv_compile(struct vkd3d_shader_parser *parser, struct spirv_compiler *spirv_compiler; int ret; - if (!(spirv_compiler = spirv_compiler_create(&parser->program, compile_info, - scan_descriptor_info, message_context, &parser->location, parser->config_flags))) + if (!(spirv_compiler = spirv_compiler_create(program, compile_info, + scan_descriptor_info, message_context, config_flags))) { ERR("Failed to create SPIR-V compiler.\n"); return VKD3D_ERROR; } - ret = spirv_compiler_generate_spirv(spirv_compiler, compile_info, parser, out); + ret = spirv_compiler_generate_spirv(spirv_compiler, program, compile_info, out); spirv_compiler_destroy(spirv_compiler); return ret; diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c index cb37efb53f7..29b2c1482a9 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1395,9 +1395,9 @@ static void vkd3d_shader_free_scan_descriptor_info1(struct vkd3d_shader_scan_des vkd3d_free(scan_descriptor_info->descriptors); } -static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info, +static int vsir_program_scan(struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context, - struct vkd3d_shader_scan_descriptor_info1 *descriptor_info1, struct vkd3d_shader_parser *parser) + struct vkd3d_shader_scan_descriptor_info1 *descriptor_info1) { struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info; struct vkd3d_shader_scan_descriptor_info1 local_descriptor_info1 = {0}; @@ -1428,27 +1428,27 @@ 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->program.shader_version, compile_info, + vkd3d_shader_scan_context_init(&context, &program->shader_version, compile_info, descriptor_info1, combined_sampler_info, message_context); if (TRACE_ON()) - vkd3d_shader_trace(&parser->program); + vkd3d_shader_trace(program); - for (i = 0; i < parser->program.instructions.count; ++i) + for (i = 0; i < program->instructions.count; ++i) { - instruction = &parser->program.instructions.elements[i]; + instruction = &program->instructions.elements[i]; if ((ret = vkd3d_shader_scan_instruction(&context, instruction)) < 0) break; } - for (i = 0; i < ARRAY_SIZE(parser->shader_desc.flat_constant_count); ++i) + for (i = 0; i < ARRAY_SIZE(program->flat_constant_count); ++i) { - unsigned int size = parser->shader_desc.flat_constant_count[i].external; struct vkd3d_shader_register_range range = {.space = 0, .first = i, .last = i}; struct vkd3d_shader_register reg = {.idx[0].offset = i, .idx_count = 1}; + unsigned int size = program->flat_constant_count[i]; struct vkd3d_shader_descriptor_info1 *d; - if (parser->shader_desc.flat_constant_count[i].external) + if (size) { if ((d = vkd3d_shader_scan_add_descriptor(&context, VKD3D_SHADER_DESCRIPTOR_TYPE_CBV, ®, &range, VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT))) @@ -1458,11 +1458,11 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info if (!ret && signature_info) { - if (!vkd3d_shader_signature_from_shader_signature(&signature_info->input, &parser->program.input_signature) + if (!vkd3d_shader_signature_from_shader_signature(&signature_info->input, &program->input_signature) || !vkd3d_shader_signature_from_shader_signature(&signature_info->output, - &parser->program.output_signature) + &program->output_signature) || !vkd3d_shader_signature_from_shader_signature(&signature_info->patch_constant, - &parser->program.patch_constant_signature)) + &program->patch_constant_signature)) { ret = VKD3D_ERROR_OUT_OF_MEMORY; } @@ -1544,7 +1544,7 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char } else { - ret = scan_with_parser(compile_info, &message_context, NULL, parser); + ret = vsir_program_scan(&parser->program, compile_info, &message_context, NULL); vkd3d_shader_parser_destroy(parser); } } @@ -1556,12 +1556,11 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char return ret; } -int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, - const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) +int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, + struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_scan_descriptor_info1 scan_descriptor_info; - struct vsir_program *program = &parser->program; struct vkd3d_shader_compile_info scan_info; int ret; @@ -1574,17 +1573,18 @@ int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, break; case VKD3D_SHADER_TARGET_GLSL: - if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0) + if ((ret = vsir_program_scan(program, &scan_info, message_context, &scan_descriptor_info)) < 0) return ret; - ret = glsl_compile(program, parser->config_flags, compile_info, out, message_context); + ret = glsl_compile(program, config_flags, compile_info, out, message_context); vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); break; case VKD3D_SHADER_TARGET_SPIRV_BINARY: case VKD3D_SHADER_TARGET_SPIRV_TEXT: - if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0) + if ((ret = vsir_program_scan(program, &scan_info, message_context, &scan_descriptor_info)) < 0) return ret; - ret = spirv_compile(parser, &scan_descriptor_info, compile_info, out, message_context); + ret = spirv_compile(program, config_flags, &scan_descriptor_info, + compile_info, out, message_context); vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); break; @@ -1665,7 +1665,7 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, } else { - ret = vkd3d_shader_parser_compile(parser, compile_info, out, &message_context); + ret = vsir_program_compile(&parser->program, parser->config_flags, compile_info, out, &message_context); vkd3d_shader_parser_destroy(parser); } } diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 4434e6e98f2..07b5818cba9 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -527,6 +527,9 @@ enum vkd3d_shader_opcode VKD3DSIH_UTOD, VKD3DSIH_UTOF, VKD3DSIH_UTOU, + VKD3DSIH_WAVE_ACTIVE_ALL_EQUAL, + VKD3DSIH_WAVE_ALL_TRUE, + VKD3DSIH_WAVE_ANY_TRUE, VKD3DSIH_XOR, VKD3DSIH_INVALID, @@ -590,6 +593,8 @@ enum vkd3d_shader_register_type VKD3DSPR_OUTSTENCILREF, VKD3DSPR_UNDEF, VKD3DSPR_SSA, + VKD3DSPR_WAVELANECOUNT, + VKD3DSPR_WAVELANEINDEX, VKD3DSPR_COUNT, @@ -1061,14 +1066,6 @@ struct dxbc_shader_desc struct shader_signature patch_constant_signature; }; -struct vkd3d_shader_desc -{ - struct - { - uint32_t used, external; - } flat_constant_count[3]; -}; - struct vkd3d_shader_register_semantic { struct vkd3d_shader_dst_param reg; @@ -1249,6 +1246,12 @@ static inline bool register_is_scalar_constant_zero(const struct vkd3d_shader_re && (data_type_is_64_bit(reg->data_type) ? !reg->u.immconst_u64[0] : !reg->u.immconst_u32[0]); } +static inline bool register_is_numeric_array(const struct vkd3d_shader_register *reg) +{ + return (reg->type == VKD3DSPR_IMMCONSTBUFFER || reg->type == VKD3DSPR_IDXTEMP + || reg->type == VKD3DSPR_GROUPSHAREDMEM); +} + static inline bool vsir_register_is_label(const struct vkd3d_shader_register *reg) { return reg->type == VKD3DSPR_LABEL; @@ -1332,6 +1335,7 @@ struct vsir_program struct shader_signature patch_constant_signature; unsigned int input_control_point_count, output_control_point_count; + unsigned int flat_constant_count[3]; unsigned int block_count; unsigned int temp_count; unsigned int ssa_count; @@ -1341,8 +1345,11 @@ struct vsir_program size_t block_name_count; }; -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); +int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, + struct vkd3d_shader_message_context *message_context); +bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve); enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t config_flags, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t config_flags, @@ -1366,7 +1373,6 @@ struct vkd3d_shader_parser struct vkd3d_shader_location location; bool failed; - struct vkd3d_shader_desc shader_desc; const struct vkd3d_shader_parser_ops *ops; struct vsir_program program; @@ -1378,9 +1384,6 @@ struct vkd3d_shader_parser_ops void (*parser_destroy)(struct vkd3d_shader_parser *parser); }; -int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, - const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, - struct vkd3d_shader_message_context *message_context); void vkd3d_shader_parser_error(struct vkd3d_shader_parser *parser, enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4); bool vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser, @@ -1552,7 +1555,7 @@ int glsl_compile(struct vsir_program *program, uint64_t config_flags, #define SPIRV_MAX_SRC_COUNT 6 -int spirv_compile(struct vkd3d_shader_parser *parser, +int spirv_compile(struct vsir_program *program, uint64_t config_flags, const struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c index 4a69ff530da..95366d3441b 100644 --- a/libs/vkd3d/libs/vkd3d/command.c +++ b/libs/vkd3d/libs/vkd3d/command.c @@ -2052,20 +2052,15 @@ static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, * state when GPU finishes execution of a command list. */ if (is_swapchain_image) { - if (resource->present_state == D3D12_RESOURCE_STATE_PRESENT) - { - *access_mask = VK_ACCESS_MEMORY_READ_BIT; - *stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - if (image_layout) - *image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - return true; - } - else if (resource->present_state != D3D12_RESOURCE_STATE_COMMON) - { - vk_barrier_parameters_from_d3d12_resource_state(resource->present_state, 0, + if (resource->present_state != D3D12_RESOURCE_STATE_PRESENT) + return vk_barrier_parameters_from_d3d12_resource_state(resource->present_state, 0, resource, vk_queue_flags, vk_info, access_mask, stage_flags, image_layout); - return true; - } + + *access_mask = VK_ACCESS_MEMORY_READ_BIT; + *stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + if (image_layout) + *image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + return true; } *access_mask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT; diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c index cb2b6ad0364..3f3332dd3e3 100644 --- a/libs/vkd3d/libs/vkd3d/device.c +++ b/libs/vkd3d/libs/vkd3d/device.c @@ -788,6 +788,11 @@ VkInstance vkd3d_instance_get_vk_instance(struct vkd3d_instance *instance) return instance->vk_instance; } +static bool d3d12_device_environment_is_vulkan_min_1_1(struct d3d12_device *device) +{ + return device->environment == VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1; +} + struct vkd3d_physical_device_info { /* properties */ @@ -796,6 +801,7 @@ struct vkd3d_physical_device_info VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT texel_buffer_alignment_properties; VkPhysicalDeviceTransformFeedbackPropertiesEXT xfb_properties; VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_divisor_properties; + VkPhysicalDeviceSubgroupProperties subgroup_properties; VkPhysicalDeviceProperties2KHR properties2; @@ -838,6 +844,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i VkPhysicalDevice4444FormatsFeaturesEXT *formats4444_features; VkPhysicalDeviceTransformFeedbackFeaturesEXT *xfb_features; struct vkd3d_vulkan_info *vulkan_info = &device->vk_info; + VkPhysicalDeviceSubgroupProperties *subgroup_properties; memset(info, 0, sizeof(*info)); conditional_rendering_features = &info->conditional_rendering_features; @@ -857,6 +864,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i formats4444_features = &info->formats4444_features; xfb_features = &info->xfb_features; xfb_properties = &info->xfb_properties; + subgroup_properties = &info->subgroup_properties; info->features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; @@ -902,6 +910,9 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i vk_prepend_struct(&info->properties2, xfb_properties); vertex_divisor_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT; vk_prepend_struct(&info->properties2, vertex_divisor_properties); + subgroup_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; + if (d3d12_device_environment_is_vulkan_min_1_1(device)) + vk_prepend_struct(&info->properties2, subgroup_properties); if (vulkan_info->KHR_get_physical_device_properties2) VK_CALL(vkGetPhysicalDeviceProperties2KHR(physical_device, &info->properties2)); @@ -1509,6 +1520,7 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, struct vkd3d_physical_device_info *physical_device_info, uint32_t *device_extension_count, bool **user_extension_supported) { + const VkPhysicalDeviceSubgroupProperties *subgroup_properties = &physical_device_info->subgroup_properties; const struct vkd3d_vk_instance_procs *vk_procs = &device->vkd3d_instance->vk_procs; VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *fragment_shader_interlock; const struct vkd3d_optional_device_extensions_info *optional_extensions; @@ -1520,6 +1532,16 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, uint32_t count; VkResult vr; + /* SHUFFLE is required to implement WaveReadLaneAt with dynamically uniform index before SPIR-V 1.5 / Vulkan 1.2. */ + static const VkSubgroupFeatureFlags required_subgroup_features = VK_SUBGROUP_FEATURE_ARITHMETIC_BIT + | VK_SUBGROUP_FEATURE_BASIC_BIT + | VK_SUBGROUP_FEATURE_BALLOT_BIT + | VK_SUBGROUP_FEATURE_SHUFFLE_BIT + | VK_SUBGROUP_FEATURE_QUAD_BIT + | VK_SUBGROUP_FEATURE_VOTE_BIT; + + static const VkSubgroupFeatureFlags required_stages = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + *device_extension_count = 0; vkd3d_trace_physical_device(physical_device, physical_device_info, vk_procs); @@ -1583,10 +1605,12 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, device->feature_options.ResourceHeapTier = D3D12_RESOURCE_HEAP_TIER_2; /* Shader Model 6 support. */ - device->feature_options1.WaveOps = FALSE; - device->feature_options1.WaveLaneCountMin = 0; - device->feature_options1.WaveLaneCountMax = 0; - device->feature_options1.TotalLaneCount = 0; + device->feature_options1.WaveOps = subgroup_properties->subgroupSize >= 4 + && (subgroup_properties->supportedOperations & required_subgroup_features) == required_subgroup_features + && (subgroup_properties->supportedStages & required_stages) == required_stages; + device->feature_options1.WaveLaneCountMin = subgroup_properties->subgroupSize; + device->feature_options1.WaveLaneCountMax = subgroup_properties->subgroupSize; + device->feature_options1.TotalLaneCount = 32 * subgroup_properties->subgroupSize; /* approx. */ device->feature_options1.ExpandedComputeResourceStates = TRUE; device->feature_options1.Int64ShaderOps = features->shaderInt64; @@ -3434,7 +3458,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CheckFeatureSupport(ID3D12Device9 TRACE("Request shader model %#x.\n", data->HighestShaderModel); +#ifdef VKD3D_SHADER_UNSUPPORTED_DXIL + data->HighestShaderModel = D3D_SHADER_MODEL_6_0; +#else data->HighestShaderModel = D3D_SHADER_MODEL_5_1; +#endif TRACE("Shader model %#x.\n", data->HighestShaderModel); return S_OK; diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c index 6ba29c18004..199d8043ffe 100644 --- a/libs/vkd3d/libs/vkd3d/state.c +++ b/libs/vkd3d/libs/vkd3d/state.c @@ -2159,6 +2159,8 @@ static unsigned int feature_flags_compile_option(const struct d3d12_device *devi flags |= VKD3D_SHADER_COMPILE_OPTION_FEATURE_INT64; if (device->feature_options.DoublePrecisionFloatShaderOps) flags |= VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLOAT64; + if (device->feature_options1.WaveOps) + flags |= VKD3D_SHADER_COMPILE_OPTION_FEATURE_WAVE_OPS; return flags; } -- 2.43.0