wine-staging/patches/vkd3d-latest/0006-Updated-vkd3d-to-e17e481130e095315d57a3d8cc66cc98c4b.patch
2024-04-19 07:53:37 +10:00

1715 lines
76 KiB
Diff

From bb098748c521482ac9e4c4c8760a91207ad36000 Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Thu, 18 Apr 2024 12:17:44 +1000
Subject: [PATCH] Updated vkd3d to e17e481130e095315d57a3d8cc66cc98c4b3f244.
---
libs/vkd3d/include/vkd3d_shader.h | 11 +
libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 132 +++--
libs/vkd3d/libs/vkd3d-shader/dxil.c | 529 +++++++++++++++++-
libs/vkd3d/libs/vkd3d-shader/glsl.c | 6 +-
libs/vkd3d/libs/vkd3d-shader/ir.c | 162 +++++-
libs/vkd3d/libs/vkd3d-shader/spirv.c | 27 +-
.../libs/vkd3d-shader/vkd3d_shader_main.c | 2 +-
.../libs/vkd3d-shader/vkd3d_shader_private.h | 14 +-
libs/vkd3d/libs/vkd3d/command.c | 20 +
libs/vkd3d/libs/vkd3d/device.c | 22 +
libs/vkd3d/libs/vkd3d/state.c | 6 +-
libs/vkd3d/libs/vkd3d/utils.c | 10 +
libs/vkd3d/libs/vkd3d/vkd3d_main.c | 18 +-
libs/vkd3d/libs/vkd3d/vkd3d_private.h | 3 +
14 files changed, 866 insertions(+), 96 deletions(-)
diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h
index 5cc36e186e2..2b32b8a3e98 100644
--- a/libs/vkd3d/include/vkd3d_shader.h
+++ b/libs/vkd3d/include/vkd3d_shader.h
@@ -215,6 +215,15 @@ enum vkd3d_shader_compile_option_feature_flags
* This corresponds to the "shaderFloat64" feature in the Vulkan API, and
* the "GL_ARB_gpu_shader_fp64" extension in the OpenGL API. */
VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLOAT64 = 0x00000002,
+ /** The SPIR-V target environment supports wave operations.
+ * This flag is valid only in VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1
+ * or greater, and corresponds to the following minimum requirements in
+ * VkPhysicalDeviceSubgroupProperties:
+ * - subgroupSize >= 4.
+ * - supportedOperations has BASIC, VOTE, ARITHMETIC, BALLOT, SHUFFLE and
+ * QUAD bits set.
+ * - supportedStages include COMPUTE and FRAGMENT. \since 1.12 */
+ VKD3D_SHADER_COMPILE_OPTION_FEATURE_WAVE_OPS = 0x00000004,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLAGS),
};
@@ -923,6 +932,8 @@ enum vkd3d_shader_spirv_environment
VKD3D_SHADER_SPIRV_ENVIRONMENT_NONE,
VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5,
VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0, /* default target */
+ /** \since 1.12 */
+ VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SPIRV_ENVIRONMENT),
};
diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c
index 459fdfc9abf..cd8ba0a7d2b 100644
--- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c
+++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c
@@ -353,18 +353,6 @@ struct vkd3d_d3d_asm_compiler
const struct vkd3d_shader_instruction *current;
};
-static int VKD3D_PRINTF_FUNC(2, 3) shader_addline(struct vkd3d_string_buffer *buffer, const char *format, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, format);
- ret = vkd3d_string_buffer_vprintf(buffer, format, args);
- va_end(args);
-
- return ret;
-}
-
/* Convert floating point offset relative to a register file to an absolute
* offset for float constants. */
static unsigned int shader_get_float_offset(enum vkd3d_shader_register_type register_type, UINT register_idx)
@@ -1572,19 +1560,37 @@ static void shader_dump_ins_modifiers(struct vkd3d_d3d_asm_compiler *compiler,
switch (dst->shift)
{
- case 0: break;
- case 13: shader_addline(buffer, "_d8"); break;
- case 14: shader_addline(buffer, "_d4"); break;
- case 15: shader_addline(buffer, "_d2"); break;
- case 1: shader_addline(buffer, "_x2"); break;
- case 2: shader_addline(buffer, "_x4"); break;
- case 3: shader_addline(buffer, "_x8"); break;
- default: shader_addline(buffer, "_unhandled_shift(%d)", dst->shift); break;
+ case 0:
+ break;
+ case 13:
+ vkd3d_string_buffer_printf(buffer, "_d8");
+ break;
+ case 14:
+ vkd3d_string_buffer_printf(buffer, "_d4");
+ break;
+ case 15:
+ vkd3d_string_buffer_printf(buffer, "_d2");
+ break;
+ case 1:
+ vkd3d_string_buffer_printf(buffer, "_x2");
+ break;
+ case 2:
+ vkd3d_string_buffer_printf(buffer, "_x4");
+ break;
+ case 3:
+ vkd3d_string_buffer_printf(buffer, "_x8");
+ break;
+ default:
+ vkd3d_string_buffer_printf(buffer, "_unhandled_shift(%d)", dst->shift);
+ break;
}
- if (mmask & VKD3DSPDM_SATURATE) shader_addline(buffer, "_sat");
- if (mmask & VKD3DSPDM_PARTIALPRECISION) shader_addline(buffer, "_pp");
- if (mmask & VKD3DSPDM_MSAMPCENTROID) shader_addline(buffer, "_centroid");
+ if (mmask & VKD3DSPDM_SATURATE)
+ vkd3d_string_buffer_printf(buffer, "_sat");
+ if (mmask & VKD3DSPDM_PARTIALPRECISION)
+ vkd3d_string_buffer_printf(buffer, "_pp");
+ if (mmask & VKD3DSPDM_MSAMPCENTROID)
+ vkd3d_string_buffer_printf(buffer, "_centroid");
mmask &= ~VKD3DSPDM_MASK;
if (mmask) FIXME("Unrecognised modifier %#x.\n", mmask);
@@ -1730,9 +1736,15 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile
case VKD3DSIH_RETP:
switch (ins->flags)
{
- case VKD3D_SHADER_CONDITIONAL_OP_NZ: shader_addline(buffer, "_nz"); break;
- case VKD3D_SHADER_CONDITIONAL_OP_Z: shader_addline(buffer, "_z"); break;
- default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags); break;
+ case VKD3D_SHADER_CONDITIONAL_OP_NZ:
+ vkd3d_string_buffer_printf(buffer, "_nz");
+ break;
+ case VKD3D_SHADER_CONDITIONAL_OP_Z:
+ vkd3d_string_buffer_printf(buffer, "_z");
+ break;
+ default:
+ vkd3d_string_buffer_printf(buffer, "_unrecognized(%#x)", ins->flags);
+ break;
}
break;
@@ -1740,32 +1752,58 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile
case VKD3DSIH_BREAKC:
switch (ins->flags)
{
- case VKD3D_SHADER_REL_OP_GT: shader_addline(buffer, "_gt"); break;
- case VKD3D_SHADER_REL_OP_EQ: shader_addline(buffer, "_eq"); break;
- case VKD3D_SHADER_REL_OP_GE: shader_addline(buffer, "_ge"); break;
- case VKD3D_SHADER_REL_OP_LT: shader_addline(buffer, "_lt"); break;
- case VKD3D_SHADER_REL_OP_NE: shader_addline(buffer, "_ne"); break;
- case VKD3D_SHADER_REL_OP_LE: shader_addline(buffer, "_le"); break;
- default: shader_addline(buffer, "_(%u)", ins->flags);
+ case VKD3D_SHADER_REL_OP_GT:
+ vkd3d_string_buffer_printf(buffer, "_gt");
+ break;
+ case VKD3D_SHADER_REL_OP_EQ:
+ vkd3d_string_buffer_printf(buffer, "_eq");
+ break;
+ case VKD3D_SHADER_REL_OP_GE:
+ vkd3d_string_buffer_printf(buffer, "_ge");
+ break;
+ case VKD3D_SHADER_REL_OP_LT:
+ vkd3d_string_buffer_printf(buffer, "_lt");
+ break;
+ case VKD3D_SHADER_REL_OP_NE:
+ vkd3d_string_buffer_printf(buffer, "_ne");
+ break;
+ case VKD3D_SHADER_REL_OP_LE:
+ vkd3d_string_buffer_printf(buffer, "_le");
+ break;
+ default:
+ vkd3d_string_buffer_printf(buffer, "_(%u)", ins->flags);
+ break;
}
break;
case VKD3DSIH_RESINFO:
switch (ins->flags)
{
- case VKD3DSI_NONE: break;
- case VKD3DSI_RESINFO_RCP_FLOAT: shader_addline(buffer, "_rcpFloat"); break;
- case VKD3DSI_RESINFO_UINT: shader_addline(buffer, "_uint"); break;
- default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags);
+ case VKD3DSI_NONE:
+ break;
+ case VKD3DSI_RESINFO_RCP_FLOAT:
+ vkd3d_string_buffer_printf(buffer, "_rcpFloat");
+ break;
+ case VKD3DSI_RESINFO_UINT:
+ vkd3d_string_buffer_printf(buffer, "_uint");
+ break;
+ default:
+ vkd3d_string_buffer_printf(buffer, "_unrecognized(%#x)", ins->flags);
+ break;
}
break;
case VKD3DSIH_SAMPLE_INFO:
switch (ins->flags)
{
- case VKD3DSI_NONE: break;
- case VKD3DSI_SAMPLE_INFO_UINT: shader_addline(buffer, "_uint"); break;
- default: shader_addline(buffer, "_unrecognized(%#x)", ins->flags);
+ case VKD3DSI_NONE:
+ break;
+ case VKD3DSI_SAMPLE_INFO_UINT:
+ vkd3d_string_buffer_printf(buffer, "_uint");
+ break;
+ default:
+ vkd3d_string_buffer_printf(buffer, "_unrecognized(%#x)", ins->flags);
+ break;
}
break;
@@ -1788,14 +1826,14 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile
case VKD3DSIH_TEX:
if (vkd3d_shader_ver_ge(&compiler->shader_version, 2, 0) && (ins->flags & VKD3DSI_TEXLD_PROJECT))
- shader_addline(buffer, "p");
+ vkd3d_string_buffer_printf(buffer, "p");
break;
case VKD3DSIH_ISHL:
case VKD3DSIH_ISHR:
case VKD3DSIH_USHR:
if (ins->flags & VKD3DSI_SHIFT_UNMASKED)
- shader_addline(buffer, "_unmasked");
+ vkd3d_string_buffer_printf(buffer, "_unmasked");
/* fall through */
default:
shader_dump_precise_flags(compiler, ins->flags);
@@ -1842,7 +1880,7 @@ static void shader_dump_icb(struct vkd3d_d3d_asm_compiler *compiler,
shader_print_hex_literal(compiler, ", ", icb->data[4 * i + 3], "},\n");
}
}
- shader_addline(buffer, "}");
+ vkd3d_string_buffer_printf(buffer, "}");
}
static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
@@ -1880,7 +1918,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
shader_print_subscript(compiler, ins->declaration.cb.size, NULL);
else if (vkd3d_shader_ver_ge(&compiler->shader_version, 5, 1))
shader_print_subscript(compiler, ins->declaration.cb.size / VKD3D_VEC4_SIZE / sizeof(float), NULL);
- shader_addline(buffer, ", %s",
+ vkd3d_string_buffer_printf(buffer, ", %s",
ins->flags & VKD3DSI_INDEXED_DYNAMIC ? "dynamicIndexed" : "immediateIndexed");
shader_dump_register_space(compiler, ins->declaration.cb.range.space);
break;
@@ -2057,7 +2095,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
if (ins->resource_type != VKD3D_SHADER_RESOURCE_NONE)
{
- shader_addline(buffer, "_indexable(");
+ vkd3d_string_buffer_printf(buffer, "_indexable(");
if (ins->raw)
vkd3d_string_buffer_printf(buffer, "raw_");
if (ins->structured)
@@ -2065,7 +2103,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
shader_dump_resource_type(compiler, ins->resource_type);
if (ins->resource_stride)
shader_print_uint_literal(compiler, ", stride=", ins->resource_stride, "");
- shader_addline(buffer, ")");
+ vkd3d_string_buffer_printf(buffer, ")");
}
if (vkd3d_shader_instruction_has_texel_offset(ins))
@@ -2095,7 +2133,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
break;
}
- shader_addline(buffer, "\n");
+ vkd3d_string_buffer_printf(buffer, "\n");
}
static const char *get_sysval_semantic_name(enum vkd3d_shader_sysval_semantic semantic)
diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c
index da8ba662dbc..d0a799b100e 100644
--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c
+++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c
@@ -401,6 +401,9 @@ enum dx_intrinsic_opcode
DX_GET_DIMENSIONS = 72,
DX_TEXTURE_GATHER = 73,
DX_TEXTURE_GATHER_CMP = 74,
+ DX_TEX2DMS_GET_SAMPLE_POS = 75,
+ DX_RT_GET_SAMPLE_POS = 76,
+ DX_RT_GET_SAMPLE_COUNT = 77,
DX_ATOMIC_BINOP = 78,
DX_ATOMIC_CMP_XCHG = 79,
DX_BARRIER = 80,
@@ -416,6 +419,7 @@ enum dx_intrinsic_opcode
DX_FLATTENED_THREAD_ID_IN_GROUP = 96,
DX_MAKE_DOUBLE = 101,
DX_SPLIT_DOUBLE = 102,
+ DX_PRIMITIVE_ID = 108,
DX_LEGACY_F32TOF16 = 130,
DX_LEGACY_F16TOF32 = 131,
DX_RAW_BUFFER_LOAD = 139,
@@ -791,6 +795,7 @@ struct sm6_parser
size_t global_symbol_count;
const char *entry_point;
+ const char *patch_constant_function;
struct vkd3d_shader_dst_param *output_params;
struct vkd3d_shader_dst_param *input_params;
@@ -1933,6 +1938,25 @@ static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type
return NULL;
}
+static const struct sm6_type *sm6_type_get_cmpxchg_result_struct(struct sm6_parser *sm6)
+{
+ const struct sm6_type *type;
+ unsigned int i;
+
+ for (i = 0; i < sm6->type_count; ++i)
+ {
+ type = &sm6->types[i];
+ if (sm6_type_is_struct(type) && type->u.struc->elem_count == 2
+ && sm6_type_is_i32(type->u.struc->elem_types[0])
+ && sm6_type_is_bool(type->u.struc->elem_types[1]))
+ {
+ return type;
+ }
+ }
+
+ return NULL;
+}
+
/* Call for aggregate types only. */
static const struct sm6_type *sm6_type_get_element_type_at_index(const struct sm6_type *type, uint64_t elem_idx)
{
@@ -2574,6 +2598,26 @@ static bool sm6_value_validate_is_texture_handle(const struct sm6_value *value,
return true;
}
+static bool sm6_value_validate_is_texture_2dms_handle(const struct sm6_value *value, enum dx_intrinsic_opcode op,
+ struct sm6_parser *sm6)
+{
+ enum dxil_resource_kind kind;
+
+ if (!sm6_value_validate_is_handle(value, sm6))
+ return false;
+
+ kind = value->u.handle.d->kind;
+ if (!resource_kind_is_multisampled(kind))
+ {
+ WARN("Resource kind %u for op %u is not a 2DMS texture.\n", kind, op);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCE_HANDLE,
+ "Resource kind %u for texture operation %u is not a 2DMS texture.", kind, op);
+ return false;
+ }
+
+ return true;
+}
+
static bool sm6_value_validate_is_sampler_handle(const struct sm6_value *value, enum dx_intrinsic_opcode op,
struct sm6_parser *sm6)
{
@@ -2643,6 +2687,18 @@ static bool sm6_value_validate_is_pointer_to_i32(const struct sm6_value *value,
return true;
}
+static bool sm6_value_validate_is_i32(const struct sm6_value *value, struct sm6_parser *sm6)
+{
+ if (!sm6_type_is_i32(value->type))
+ {
+ WARN("Operand result type %u is not i32.\n", value->type->class);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "An int32 operand passed to a DXIL instruction is not an int32.");
+ return false;
+ }
+ return true;
+}
+
static const struct sm6_value *sm6_parser_get_value_safe(struct sm6_parser *sm6, unsigned int idx)
{
if (idx < sm6->value_count)
@@ -2790,7 +2846,7 @@ static inline uint64_t decode_rotated_signed_value(uint64_t value)
return value << 63;
}
-static inline float bitcast_uint64_to_float(uint64_t value)
+static float bitcast_uint_to_float(unsigned int value)
{
union
{
@@ -2814,6 +2870,23 @@ static inline double bitcast_uint64_to_double(uint64_t value)
return u.double_value;
}
+static float register_get_float_value(const struct vkd3d_shader_register *reg)
+{
+ if (!register_is_constant(reg) || !data_type_is_floating_point(reg->data_type))
+ return 0.0;
+
+ if (reg->dimension == VSIR_DIMENSION_VEC4)
+ WARN("Returning vec4.x.\n");
+
+ if (reg->type == VKD3DSPR_IMMCONST64)
+ {
+ WARN("Truncating double to float.\n");
+ return bitcast_uint64_to_double(reg->u.immconst_u64[0]);
+ }
+
+ return bitcast_uint_to_float(reg->u.immconst_u32[0]);
+}
+
static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, const struct sm6_type *type,
const uint64_t *operands, struct sm6_parser *sm6)
{
@@ -3098,7 +3171,7 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const
if (type->u.width == 16)
dst->u.reg.u.immconst_u32[0] = record->operands[0];
else if (type->u.width == 32)
- dst->u.reg.u.immconst_f32[0] = bitcast_uint64_to_float(record->operands[0]);
+ dst->u.reg.u.immconst_f32[0] = bitcast_uint_to_float(record->operands[0]);
else if (type->u.width == 64)
dst->u.reg.u.immconst_f64[0] = bitcast_uint64_to_double(record->operands[0]);
else
@@ -4567,6 +4640,22 @@ static void sm6_parser_dcl_register_builtin(struct sm6_parser *sm6,
}
}
+static void sm6_parser_emit_dx_input_register_mov(struct sm6_parser *sm6,
+ struct vkd3d_shader_instruction *ins, enum vkd3d_shader_register_type reg_type, enum vkd3d_data_type data_type)
+{
+ struct vkd3d_shader_src_param *src_param;
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
+
+ if (!(src_param = instruction_src_params_alloc(ins, 1, sm6)))
+ return;
+ sm6_parser_dcl_register_builtin(sm6, reg_type, data_type, 1);
+ vsir_register_init(&src_param->reg, reg_type, data_type, 0);
+ src_param_init(src_param);
+
+ instruction_dst_param_init_ssa_scalar(ins, sm6);
+}
+
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)
{
@@ -4928,6 +5017,12 @@ static void sm6_parser_emit_dx_make_double(struct sm6_parser *sm6, enum dx_intri
instruction_dst_param_init_ssa_scalar(ins, sm6);
}
+static void sm6_parser_emit_dx_primitive_id(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_PRIMID, VKD3D_DATA_UINT);
+}
+
static void sm6_parser_emit_dx_raw_buffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
const struct sm6_value **operands, struct function_emission_state *state)
{
@@ -5150,6 +5245,59 @@ static void sm6_parser_emit_dx_buffer_store(struct sm6_parser *sm6, enum dx_intr
dst_param->reg = resource->u.handle.reg;
}
+static void sm6_parser_emit_dx_get_sample_count(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, VKD3DSIH_SAMPLE_INFO);
+ ins->flags = VKD3DSI_SAMPLE_INFO_UINT;
+
+ if (!(src_param = instruction_src_params_alloc(ins, 1, sm6)))
+ return;
+ vsir_register_init(&src_param->reg, VKD3DSPR_RASTERIZER, VKD3D_DATA_FLOAT, 0);
+ src_param->reg.dimension = VSIR_DIMENSION_VEC4;
+ src_param_init(src_param);
+
+ instruction_dst_param_init_ssa_scalar(ins, sm6);
+ ins->dst->reg.data_type = VKD3D_DATA_FLOAT;
+}
+
+static void sm6_parser_emit_dx_get_sample_pos(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 = NULL;
+
+ if (op == DX_TEX2DMS_GET_SAMPLE_POS)
+ {
+ resource = operands[0];
+ if (!sm6_value_validate_is_texture_2dms_handle(resource, op, sm6))
+ return;
+ }
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_SAMPLE_POS);
+
+ if (!(src_params = instruction_src_params_alloc(ins, 2, sm6)))
+ return;
+ if (op == DX_TEX2DMS_GET_SAMPLE_POS)
+ {
+ src_param_init_vector_from_reg(&src_params[0], &resource->u.handle.reg);
+ src_param_init_from_value(&src_params[1], operands[1]);
+ }
+ else
+ {
+ src_param_init_vector(&src_params[0], 2);
+ vsir_register_init(&src_params[0].reg, VKD3DSPR_RASTERIZER, VKD3D_DATA_FLOAT, 0);
+ src_params[0].reg.dimension = VSIR_DIMENSION_VEC4;
+ src_param_init_from_value(&src_params[1], operands[0]);
+ }
+
+ instruction_dst_param_init_ssa_vector(ins, 2, sm6);
+}
+
static unsigned int sm6_value_get_texel_offset(const struct sm6_value *value)
{
return sm6_value_is_undef(value) ? 0 : sm6_value_get_constant_uint(value);
@@ -5590,6 +5738,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] =
[DX_LOAD_INPUT ] = {"o", "ii8i", sm6_parser_emit_dx_load_input},
[DX_LOG ] = {"g", "R", sm6_parser_emit_dx_unary},
[DX_MAKE_DOUBLE ] = {"d", "ii", sm6_parser_emit_dx_make_double},
+ [DX_PRIMITIVE_ID ] = {"i", "", sm6_parser_emit_dx_primitive_id},
[DX_RAW_BUFFER_LOAD ] = {"o", "Hii8i", sm6_parser_emit_dx_raw_buffer_load},
[DX_RAW_BUFFER_STORE ] = {"v", "Hiioooocc", sm6_parser_emit_dx_raw_buffer_store},
[DX_ROUND_NE ] = {"g", "R", sm6_parser_emit_dx_unary},
@@ -5597,6 +5746,8 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] =
[DX_ROUND_PI ] = {"g", "R", sm6_parser_emit_dx_unary},
[DX_ROUND_Z ] = {"g", "R", sm6_parser_emit_dx_unary},
[DX_RSQRT ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_RT_GET_SAMPLE_COUNT ] = {"i", "", sm6_parser_emit_dx_get_sample_count},
+ [DX_RT_GET_SAMPLE_POS ] = {"o", "i", sm6_parser_emit_dx_get_sample_pos},
[DX_SAMPLE ] = {"o", "HHffffiiif", sm6_parser_emit_dx_sample},
[DX_SAMPLE_B ] = {"o", "HHffffiiiff", sm6_parser_emit_dx_sample},
[DX_SAMPLE_C ] = {"o", "HHffffiiiff", sm6_parser_emit_dx_sample},
@@ -5609,6 +5760,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] =
[DX_SQRT ] = {"g", "R", sm6_parser_emit_dx_unary},
[DX_STORE_OUTPUT ] = {"v", "ii8o", sm6_parser_emit_dx_store_output},
[DX_TAN ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_TEX2DMS_GET_SAMPLE_POS ] = {"o", "Hi", sm6_parser_emit_dx_get_sample_pos},
[DX_TEXTURE_GATHER ] = {"o", "HHffffiic", sm6_parser_emit_dx_texture_gather},
[DX_TEXTURE_GATHER_CMP ] = {"o", "HHffffiicf", sm6_parser_emit_dx_texture_gather},
[DX_TEXTURE_LOAD ] = {"o", "HiiiiCCC", sm6_parser_emit_dx_texture_load},
@@ -6130,6 +6282,87 @@ static void sm6_parser_emit_cmp2(struct sm6_parser *sm6, const struct dxil_recor
instruction_dst_param_init_ssa_scalar(ins, sm6);
}
+static void sm6_parser_emit_cmpxchg(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+{
+ uint64_t success_ordering, failure_ordering;
+ struct vkd3d_shader_dst_param *dst_params;
+ struct vkd3d_shader_src_param *src_params;
+ const struct sm6_value *ptr, *cmp, *new;
+ const struct sm6_type *type;
+ unsigned int i = 0;
+ bool is_volatile;
+ uint64_t code;
+
+ if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))
+ || !sm6_value_validate_is_pointer_to_i32(ptr, sm6))
+ return;
+
+ if (ptr->u.reg.type != VKD3DSPR_GROUPSHAREDMEM)
+ {
+ WARN("Register is not groupshared.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "The destination register for a cmpxchg instruction is not groupshared memory.");
+ return;
+ }
+
+ if (!(dst->type = sm6_type_get_cmpxchg_result_struct(sm6)))
+ {
+ WARN("Failed to find result struct.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
+ "Module does not define a result struct type for a cmpxchg instruction.");
+ return;
+ }
+
+ type = ptr->type->u.pointer.type;
+ cmp = sm6_parser_get_value_by_ref(sm6, record, type, &i);
+ new = sm6_parser_get_value_by_ref(sm6, record, type, &i);
+ if (!cmp || !new)
+ return;
+
+ if (!sm6_value_validate_is_i32(cmp, sm6)
+ || !sm6_value_validate_is_i32(new, sm6)
+ || !dxil_record_validate_operand_count(record, i + 3, i + 5, sm6))
+ {
+ return;
+ }
+
+ is_volatile = record->operands[i++];
+ success_ordering = record->operands[i++];
+
+ if ((code = record->operands[i++]) != 1)
+ FIXME("Ignoring synchronisation scope %"PRIu64".\n", code);
+
+ failure_ordering = (record->operand_count > i) ? record->operands[i++] : success_ordering;
+
+ /* It's currently not possible to specify an atomic ordering in HLSL, and it defaults to seq_cst. */
+ if (success_ordering != ORDERING_SEQCST)
+ FIXME("Unhandled success ordering %"PRIu64".\n", success_ordering);
+ if (success_ordering != failure_ordering)
+ FIXME("Unhandled failure ordering %"PRIu64".\n", failure_ordering);
+
+ if (record->operand_count > i && record->operands[i])
+ FIXME("Ignoring weak cmpxchg.\n");
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_IMM_ATOMIC_CMP_EXCH);
+ ins->flags = is_volatile ? VKD3DARF_SEQ_CST | VKD3DARF_VOLATILE : VKD3DARF_SEQ_CST;
+
+ if (!(src_params = instruction_src_params_alloc(ins, 3, sm6)))
+ return;
+ src_param_make_constant_uint(&src_params[0], 0);
+ src_param_init_from_value(&src_params[1], cmp);
+ src_param_init_from_value(&src_params[2], new);
+
+ if (!(dst_params = instruction_dst_params_alloc(ins, 2, sm6)))
+ return;
+ register_init_ssa_scalar(&dst_params[0].reg, dst->type, dst, sm6);
+ dst_param_init(&dst_params[0]);
+ dst_params[1].reg = ptr->u.reg;
+ dst_param_init(&dst_params[1]);
+
+ dst->u.reg = dst_params[0].reg;
+}
+
static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil_record *record,
struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
{
@@ -6728,6 +6961,25 @@ static bool sm6_metadata_get_uint64_value(const struct sm6_parser *sm6,
return true;
}
+static bool sm6_metadata_get_float_value(const struct sm6_parser *sm6,
+ const struct sm6_metadata_value *m, float *f)
+{
+ const struct sm6_value *value;
+
+ if (!m || m->type != VKD3D_METADATA_VALUE)
+ return false;
+
+ value = m->u.value;
+ if (!sm6_value_is_constant(value))
+ return false;
+ if (!sm6_type_is_floating_point(value->type))
+ return false;
+
+ *f = register_get_float_value(&value->u.reg);
+
+ return true;
+}
+
static void sm6_parser_metadata_attachment_block_init(struct sm6_parser *sm6, const struct dxil_block *target_block,
const struct dxil_block *block)
{
@@ -7115,6 +7367,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
case FUNC_CODE_INST_CMP2:
sm6_parser_emit_cmp2(sm6, record, ins, dst);
break;
+ case FUNC_CODE_INST_CMPXCHG:
+ sm6_parser_emit_cmpxchg(sm6, record, ins, dst);
+ break;
case FUNC_CODE_INST_EXTRACTVAL:
sm6_parser_emit_extractval(sm6, record, ins, dst);
break;
@@ -7685,9 +7940,40 @@ static const enum vkd3d_shader_sysval_semantic sysval_semantic_table[] =
[SEMANTIC_KIND_TARGET] = VKD3D_SHADER_SV_TARGET,
};
-static enum vkd3d_shader_sysval_semantic sysval_semantic_from_dxil_semantic_kind(enum dxil_semantic_kind kind)
+static enum vkd3d_shader_sysval_semantic sysval_semantic_from_dxil_semantic_kind(enum dxil_semantic_kind kind,
+ enum vkd3d_tessellator_domain domain)
{
- if (kind < ARRAY_SIZE(sysval_semantic_table))
+ if (kind == SEMANTIC_KIND_TESSFACTOR)
+ {
+ switch (domain)
+ {
+ case VKD3D_TESSELLATOR_DOMAIN_LINE:
+ return VKD3D_SHADER_SV_TESS_FACTOR_LINEDET;
+ case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE:
+ return VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE;
+ case VKD3D_TESSELLATOR_DOMAIN_QUAD:
+ return VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE;
+ default:
+ /* Error is handled during parsing. */
+ return VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE;
+ }
+ }
+ else if (kind == SEMANTIC_KIND_INSIDETESSFACTOR)
+ {
+ switch (domain)
+ {
+ case VKD3D_TESSELLATOR_DOMAIN_LINE:
+ return VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN;
+ case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE:
+ return VKD3D_SHADER_SV_TESS_FACTOR_TRIINT;
+ case VKD3D_TESSELLATOR_DOMAIN_QUAD:
+ return VKD3D_SHADER_SV_TESS_FACTOR_QUADINT;
+ default:
+ /* Error is handled during parsing. */
+ return VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE;
+ }
+ }
+ else if (kind < ARRAY_SIZE(sysval_semantic_table))
{
return sysval_semantic_table[kind];
}
@@ -8443,7 +8729,7 @@ static void signature_element_read_additional_element_values(struct signature_el
}
static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const struct sm6_metadata_value *m,
- struct shader_signature *s)
+ struct shader_signature *s, enum vkd3d_tessellator_domain tessellator_domain)
{
unsigned int i, j, column_count, operand_count, index;
const struct sm6_metadata_node *node, *element_node;
@@ -8536,7 +8822,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const
e->min_precision = minimum_precision_from_dxil_component_type(values[2]);
j = values[3];
- e->sysval_semantic = sysval_semantic_from_dxil_semantic_kind(j);
+ e->sysval_semantic = sysval_semantic_from_dxil_semantic_kind(j, tessellator_domain);
if (j != SEMANTIC_KIND_ARBITRARY && j != SEMANTIC_KIND_TARGET && e->sysval_semantic == VKD3D_SHADER_SV_NONE)
{
WARN("Unhandled semantic kind %u.\n", j);
@@ -8619,7 +8905,8 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const
return VKD3D_OK;
}
-static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, const struct sm6_metadata_value *m)
+static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, const struct sm6_metadata_value *m,
+ enum vkd3d_tessellator_domain tessellator_domain)
{
enum vkd3d_result ret;
@@ -8632,12 +8919,12 @@ static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, cons
}
if (m->u.node->operand_count && (ret = sm6_parser_read_signature(sm6, m->u.node->operands[0],
- &sm6->p.program.input_signature)) < 0)
+ &sm6->p.program.input_signature, tessellator_domain)) < 0)
{
return ret;
}
if (m->u.node->operand_count > 1 && (ret = sm6_parser_read_signature(sm6, m->u.node->operands[1],
- &sm6->p.program.output_signature)) < 0)
+ &sm6->p.program.output_signature, tessellator_domain)) < 0)
{
return ret;
}
@@ -8730,10 +9017,216 @@ static enum vkd3d_result sm6_parser_emit_thread_group(struct sm6_parser *sm6, co
return VKD3D_OK;
}
+static void sm6_parser_emit_dcl_count(struct sm6_parser *sm6, enum vkd3d_shader_opcode handler_idx, unsigned int count)
+{
+ struct vkd3d_shader_instruction *ins;
+
+ ins = sm6_parser_add_instruction(sm6, handler_idx);
+ ins->declaration.count = count;
+}
+
+static void sm6_parser_emit_dcl_tessellator_domain(struct sm6_parser *sm6,
+ enum vkd3d_tessellator_domain tessellator_domain)
+{
+ struct vkd3d_shader_instruction *ins;
+
+ if (tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID || tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT)
+ {
+ WARN("Unhandled domain %u.\n", tessellator_domain);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Domain shader tessellator domain %u is unhandled.", tessellator_domain);
+ }
+
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_TESSELLATOR_DOMAIN);
+ ins->declaration.tessellator_domain = tessellator_domain;
+}
+
+static void sm6_parser_validate_control_point_count(struct sm6_parser *sm6, unsigned int count,
+ const char *type)
+{
+ if (!count || count > 32)
+ {
+ WARN("%s control point count %u invalid.\n", type, count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "%s control point count %u is invalid.", type, count);
+ }
+}
+
+static void sm6_parser_emit_dcl_tessellator_partitioning(struct sm6_parser *sm6,
+ enum vkd3d_shader_tessellator_partitioning tessellator_partitioning)
+{
+ struct vkd3d_shader_instruction *ins;
+
+ if (!tessellator_partitioning || tessellator_partitioning > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN)
+ {
+ WARN("Unhandled partitioning %u.\n", tessellator_partitioning);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Hull shader tessellator partitioning %u is unhandled.", tessellator_partitioning);
+ }
+
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_TESSELLATOR_PARTITIONING);
+ ins->declaration.tessellator_partitioning = tessellator_partitioning;
+}
+
+static void sm6_parser_emit_dcl_tessellator_output_primitive(struct sm6_parser *sm6,
+ enum vkd3d_shader_tessellator_output_primitive primitive)
+{
+ struct vkd3d_shader_instruction *ins;
+
+ if (!primitive || primitive > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW)
+ {
+ WARN("Unhandled output primitive %u.\n", primitive);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Hull shader tessellator output primitive %u is unhandled.", primitive);
+ }
+
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE);
+ ins->declaration.tessellator_output_primitive = primitive;
+}
+
+static void sm6_parser_emit_dcl_max_tessellation_factor(struct sm6_parser *sm6, struct sm6_metadata_value *m)
+{
+ struct vkd3d_shader_instruction *ins;
+ float max_tessellation_factor;
+
+ if (!sm6_metadata_get_float_value(sm6, m, &max_tessellation_factor))
+ {
+ WARN("Max tess factor property is not a float value.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Hull shader max tessellation factor property operand is not a float.");
+ return;
+ }
+
+ /* Exclude non-finite values. */
+ if (!(max_tessellation_factor >= 1.0f && max_tessellation_factor <= 64.0f))
+ {
+ WARN("Invalid max tess factor %f.\n", max_tessellation_factor);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Hull shader max tessellation factor %f is invalid.", max_tessellation_factor);
+ }
+
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_HS_MAX_TESSFACTOR);
+ ins->declaration.max_tessellation_factor = max_tessellation_factor;
+}
+
+static enum vkd3d_tessellator_domain sm6_parser_ds_properties_init(struct sm6_parser *sm6,
+ const struct sm6_metadata_value *m)
+{
+ const struct sm6_metadata_node *node;
+ unsigned int operands[2] = {0};
+ unsigned int i;
+
+ if (!m || !sm6_metadata_value_is_node(m))
+ {
+ WARN("Missing or invalid DS properties.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Domain shader properties node is missing or invalid.");
+ return 0;
+ }
+
+ node = m->u.node;
+ if (node->operand_count < ARRAY_SIZE(operands))
+ {
+ WARN("Invalid operand count %u.\n", node->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Domain shader properties operand count %u is invalid.", node->operand_count);
+ return 0;
+ }
+ if (node->operand_count > ARRAY_SIZE(operands))
+ {
+ WARN("Ignoring %zu extra operands.\n", node->operand_count - ARRAY_SIZE(operands));
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring %zu extra operands for domain shader properties.",
+ node->operand_count - ARRAY_SIZE(operands));
+ }
+
+ for (i = 0; i < node->operand_count; ++i)
+ {
+ if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &operands[i]))
+ {
+ WARN("DS property at index %u is not a uint value.\n", i);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Domain shader properties operand at index %u is not an integer.", i);
+ }
+ }
+
+ sm6_parser_emit_dcl_tessellator_domain(sm6, operands[0]);
+ sm6_parser_validate_control_point_count(sm6, operands[1], "Domain shader input");
+ sm6->p.program.input_control_point_count = operands[1];
+
+ return operands[0];
+}
+
+static enum vkd3d_tessellator_domain sm6_parser_hs_properties_init(struct sm6_parser *sm6,
+ const struct sm6_metadata_value *m)
+{
+ const struct sm6_metadata_node *node;
+ unsigned int operands[6] = {0};
+ unsigned int i;
+
+ if (!m || !sm6_metadata_value_is_node(m))
+ {
+ WARN("Missing or invalid HS properties.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Hull shader properties node is missing or invalid.");
+ return 0;
+ }
+
+ node = m->u.node;
+ if (node->operand_count < 7)
+ {
+ WARN("Invalid operand count %u.\n", node->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Hull shader properties operand count %u is invalid.", node->operand_count);
+ return 0;
+ }
+ if (node->operand_count > 7)
+ {
+ WARN("Ignoring %u extra operands.\n", node->operand_count - 7);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring %u extra operands for hull shader properties.", node->operand_count - 7);
+ }
+
+ m = node->operands[0];
+ if (!sm6_metadata_value_is_value(m) || !sm6_value_is_function_dcl(m->u.value))
+ {
+ WARN("Patch constant function node is not a function value.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Hull shader patch constant function node is not a function value.");
+ }
+ else
+ {
+ sm6->patch_constant_function = m->u.value->u.function.name;
+ }
+
+ for (i = 1; i < min(node->operand_count, ARRAY_SIZE(operands)); ++i)
+ {
+ if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &operands[i]))
+ {
+ WARN("HS property at index %u is not a uint value.\n", i);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
+ "Hull shader properties operand at index %u is not an integer.", i);
+ }
+ }
+
+ sm6_parser_validate_control_point_count(sm6, operands[1], "Hull shader input");
+ sm6->p.program.input_control_point_count = operands[1];
+ sm6_parser_validate_control_point_count(sm6, operands[2], "Hull shader output");
+ sm6_parser_emit_dcl_count(sm6, VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT, operands[2]);
+ sm6->p.program.output_control_point_count = operands[2];
+ sm6_parser_emit_dcl_tessellator_domain(sm6, operands[3]);
+ sm6_parser_emit_dcl_tessellator_partitioning(sm6, operands[4]);
+ sm6_parser_emit_dcl_tessellator_output_primitive(sm6, operands[5]);
+ sm6_parser_emit_dcl_max_tessellation_factor(sm6, node->operands[6]);
+
+ return operands[3];
+}
+
static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6)
{
const struct sm6_metadata_value *m = sm6_parser_find_named_metadata(sm6, "dx.entryPoints");
const struct sm6_metadata_node *node, *entry_node = m ? m->u.node : NULL;
+ enum vkd3d_tessellator_domain tessellator_domain = 0;
unsigned int i, operand_count, tag;
const struct sm6_value *value;
enum vkd3d_result ret;
@@ -8772,12 +9265,6 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6)
"Entry point function name %s does not match the name in metadata.", sm6->entry_point);
}
- if (entry_node->operand_count >= 3 && (m = entry_node->operands[2])
- && (ret = sm6_parser_signatures_init(sm6, m)) < 0)
- {
- return ret;
- }
-
if (entry_node->operand_count >= 5 && (m = entry_node->operands[4]))
{
if (!sm6_metadata_value_is_node(m))
@@ -8812,6 +9299,12 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6)
case SHADER_PROPERTIES_FLAGS:
sm6_parser_emit_global_flags(sm6, node->operands[i + 1]);
break;
+ case SHADER_PROPERTIES_DOMAIN:
+ tessellator_domain = sm6_parser_ds_properties_init(sm6, node->operands[i + 1]);
+ break;
+ case SHADER_PROPERTIES_HULL:
+ tessellator_domain = sm6_parser_hs_properties_init(sm6, node->operands[i + 1]);
+ break;
case SHADER_PROPERTIES_COMPUTE:
if ((ret = sm6_parser_emit_thread_group(sm6, node->operands[i + 1])) < 0)
return ret;
@@ -8825,6 +9318,12 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6)
}
}
+ if (entry_node->operand_count >= 3 && (m = entry_node->operands[2])
+ && (ret = sm6_parser_signatures_init(sm6, m, tessellator_domain)) < 0)
+ {
+ return ret;
+ }
+
return VKD3D_OK;
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c
index 3977852a48d..f1012d06c6a 100644
--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c
+++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c
@@ -139,12 +139,16 @@ static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen,
gen->message_context = message_context;
}
-int glsl_compile(struct vsir_program *program, struct vkd3d_shader_code *out,
+int glsl_compile(struct vsir_program *program, uint64_t config_flags,
+ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out,
struct vkd3d_shader_message_context *message_context)
{
struct vkd3d_glsl_generator generator;
int ret;
+ if ((ret = vsir_program_normalise(program, config_flags, compile_info, message_context)) < 0)
+ return ret;
+
vkd3d_glsl_generator_init(&generator, program, message_context);
ret = vkd3d_glsl_generator_generate(&generator, out);
vkd3d_glsl_generator_cleanup(&generator);
diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c
index 610d907d981..eca18f4eb28 100644
--- a/libs/vkd3d/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c
@@ -232,6 +232,7 @@ static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *pr
return ret;
break;
+ case VKD3DSIH_DCL_CONSTANT_BUFFER:
case VKD3DSIH_DCL_TEMPS:
vkd3d_shader_instruction_make_nop(ins);
break;
@@ -2986,6 +2987,8 @@ struct vsir_cfg_structure
{
struct vsir_cfg_structure_list body;
unsigned idx;
+ bool needs_trampoline;
+ struct vsir_cfg_structure *outer_loop;
} loop;
struct vsir_cfg_structure_selection
{
@@ -3008,6 +3011,7 @@ struct vsir_cfg_structure
unsigned int target;
struct vkd3d_shader_src_param *condition;
bool invert_condition;
+ bool needs_launcher;
} jump;
} u;
};
@@ -3257,7 +3261,8 @@ static void vsir_cfg_structure_dump(struct vsir_cfg *cfg, struct vsir_cfg_struct
vsir_cfg_structure_list_dump(cfg, &structure->u.loop.body);
- TRACE("%s} # %u\n", cfg->debug_buffer.buffer, structure->u.loop.idx);
+ TRACE("%s} # %u%s\n", cfg->debug_buffer.buffer, structure->u.loop.idx,
+ structure->u.loop.needs_trampoline ? ", tramp" : "");
break;
case STRUCTURE_TYPE_SELECTION:
@@ -3301,8 +3306,9 @@ static void vsir_cfg_structure_dump(struct vsir_cfg *cfg, struct vsir_cfg_struct
vkd3d_unreachable();
}
- TRACE("%s%s%s %u\n", cfg->debug_buffer.buffer, type_str,
- structure->u.jump.condition ? "c" : "", structure->u.jump.target);
+ TRACE("%s%s%s %u%s\n", cfg->debug_buffer.buffer, type_str,
+ structure->u.jump.condition ? "c" : "", structure->u.jump.target,
+ structure->u.jump.needs_launcher ? " # launch" : "");
break;
}
@@ -4268,6 +4274,17 @@ static enum vkd3d_result vsir_cfg_move_breaks_out_of_selections(struct vsir_cfg
--cfg->loop_intervals[else_target].target_count;
}
+ /* If a branch becomes empty, make it the else branch, so we save a block. */
+ if (selection->u.selection.if_body.count == 0)
+ {
+ struct vsir_cfg_structure_list tmp;
+
+ selection->u.selection.invert_condition = !selection->u.selection.invert_condition;
+ tmp = selection->u.selection.if_body;
+ selection->u.selection.if_body = selection->u.selection.else_body;
+ selection->u.selection.else_body = tmp;
+ }
+
return VKD3D_OK;
}
@@ -4492,6 +4509,90 @@ static void vsir_cfg_count_targets(struct vsir_cfg *cfg, struct vsir_cfg_structu
}
}
+/* Trampolines are code gadgets used to emulate multilevel jumps (which are not natively supported
+ * by SPIR-V). A trampoline is inserted just after a loop and checks whether control has reached the
+ * intended site (i.e., we just jumped out of the target block) or if other levels of jumping are
+ * needed. For each jump a trampoline is required for all the loops between the jump itself and the
+ * target loop, excluding the target loop itself. */
+static void vsir_cfg_mark_trampolines(struct vsir_cfg *cfg, struct vsir_cfg_structure_list *list,
+ struct vsir_cfg_structure *loop)
+{
+ size_t i;
+
+ for (i = 0; i < list->count; ++i)
+ {
+ struct vsir_cfg_structure *structure = &list->structures[i];
+
+ switch (structure->type)
+ {
+ case STRUCTURE_TYPE_BLOCK:
+ break;
+
+ case STRUCTURE_TYPE_LOOP:
+ structure->u.loop.outer_loop = loop;
+ vsir_cfg_mark_trampolines(cfg, &structure->u.loop.body, structure);
+ break;
+
+ case STRUCTURE_TYPE_SELECTION:
+ vsir_cfg_mark_trampolines(cfg, &structure->u.selection.if_body, loop);
+ vsir_cfg_mark_trampolines(cfg, &structure->u.selection.else_body, loop);
+ break;
+
+ case STRUCTURE_TYPE_JUMP:
+ {
+ struct vsir_cfg_structure *l;
+ if (structure->u.jump.type != JUMP_BREAK && structure->u.jump.type != JUMP_CONTINUE)
+ break;
+ for (l = loop; l && l->u.loop.idx != structure->u.jump.target; l = l->u.loop.outer_loop)
+ {
+ assert(l->type == STRUCTURE_TYPE_LOOP);
+ l->u.loop.needs_trampoline = true;
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* Launchers are the counterpart of trampolines. A launcher is inserted just before a jump, and
+ * writes in a well-known variable what is the target of the jump. Trampolines will then read that
+ * variable to decide how to redirect the jump to its intended target. A launcher is needed each
+ * time the innermost loop containing the jump itself has a trampoline (independently of whether the
+ * jump is targeting that loop or not). */
+static void vsir_cfg_mark_launchers(struct vsir_cfg *cfg, struct vsir_cfg_structure_list *list,
+ struct vsir_cfg_structure *loop)
+{
+ size_t i;
+
+ for (i = 0; i < list->count; ++i)
+ {
+ struct vsir_cfg_structure *structure = &list->structures[i];
+
+ switch (structure->type)
+ {
+ case STRUCTURE_TYPE_BLOCK:
+ break;
+
+ case STRUCTURE_TYPE_LOOP:
+ vsir_cfg_mark_launchers(cfg, &structure->u.loop.body, structure);
+ break;
+
+ case STRUCTURE_TYPE_SELECTION:
+ vsir_cfg_mark_launchers(cfg, &structure->u.selection.if_body, loop);
+ vsir_cfg_mark_launchers(cfg, &structure->u.selection.else_body, loop);
+ break;
+
+ case STRUCTURE_TYPE_JUMP:
+ if (structure->u.jump.type != JUMP_BREAK && structure->u.jump.type != JUMP_CONTINUE)
+ break;
+ assert(loop && loop->type == STRUCTURE_TYPE_LOOP);
+ if (loop->u.loop.needs_trampoline)
+ structure->u.jump.needs_launcher = true;
+ break;
+ }
+ }
+}
+
static enum vkd3d_result vsir_cfg_optimize(struct vsir_cfg *cfg)
{
enum vkd3d_result ret;
@@ -4500,6 +4601,14 @@ static enum vkd3d_result vsir_cfg_optimize(struct vsir_cfg *cfg)
ret = vsir_cfg_optimize_recurse(cfg, &cfg->structured_program);
+ /* Trampolines and launchers cannot be marked with the same pass,
+ * because a jump might have to be marked as launcher even when it
+ * targets its innermost loop, if other jumps in the same loop
+ * need a trampoline anyway. So launchers can be discovered only
+ * once all the trampolines are known. */
+ vsir_cfg_mark_trampolines(cfg, &cfg->structured_program, NULL);
+ vsir_cfg_mark_launchers(cfg, &cfg->structured_program, NULL);
+
if (TRACE_ON())
vsir_cfg_dump_structured_program(cfg);
@@ -4548,7 +4657,7 @@ static enum vkd3d_result vsir_cfg_structure_list_emit_loop(struct vsir_cfg *cfg,
/* Add a trampoline to implement multilevel jumping depending on the stored
* jump_target value. */
- if (loop_idx != UINT_MAX)
+ if (loop->needs_trampoline)
{
/* If the multilevel jump is a `continue' and the target is the loop we're inside
* right now, then we can finally do the `continue'. */
@@ -4685,7 +4794,7 @@ static enum vkd3d_result vsir_cfg_structure_list_emit_jump(struct vsir_cfg *cfg,
if (!reserve_instructions(&target->instructions, &target->ins_capacity, target->ins_count + 2))
return VKD3D_ERROR_OUT_OF_MEMORY;
- if (opcode == VKD3DSIH_BREAK || opcode == VKD3DSIH_BREAKP)
+ if (jump->needs_launcher)
{
if (!vsir_instruction_init_with_params(cfg->program, &target->instructions[target->ins_count],
&no_loc, VKD3DSIH_MOV, 1, 1))
@@ -5433,6 +5542,46 @@ static void vsir_validate_instruction(struct validation_context *ctx)
ctx->dcl_temps_found = false;
return;
+ case VKD3DSIH_DCL_HS_MAX_TESSFACTOR:
+ /* Exclude non-finite values. */
+ if (!(instruction->declaration.max_tessellation_factor >= 1.0f
+ && instruction->declaration.max_tessellation_factor <= 64.0f))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Max tessellation factor %f is invalid.",
+ instruction->declaration.max_tessellation_factor);
+ return;
+
+ /* The DXIL parser can generate these outside phases, but this is not an issue. */
+ case VKD3DSIH_DCL_INPUT:
+ case VKD3DSIH_DCL_OUTPUT:
+ return;
+
+ case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT:
+ if (!instruction->declaration.count || instruction->declaration.count > 32)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Output control point count %u is invalid.",
+ instruction->declaration.count);
+ return;
+
+ case VKD3DSIH_DCL_TESSELLATOR_DOMAIN:
+ if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID
+ || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION,
+ "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain);
+ return;
+
+ case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE:
+ if (!instruction->declaration.tessellator_output_primitive
+ || instruction->declaration.tessellator_output_primitive > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION,
+ "Tessellator output primitive %#x is invalid.", instruction->declaration.tessellator_output_primitive);
+ return;
+
+ case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING:
+ if (!instruction->declaration.tessellator_partitioning
+ || instruction->declaration.tessellator_partitioning > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION,
+ "Tessellator partitioning %#x is invalid.", instruction->declaration.tessellator_partitioning);
+ return;
+
default:
break;
}
@@ -5863,7 +6012,8 @@ enum vkd3d_result vsir_program_normalise(struct vsir_program *program, uint64_t
if ((result = vsir_program_normalise_combined_samplers(program, message_context)) < 0)
return result;
- if ((result = vsir_program_flatten_control_flow_constructs(program, message_context)) < 0)
+ if (compile_info->target_type != VKD3D_SHADER_TARGET_GLSL
+ && (result = vsir_program_flatten_control_flow_constructs(program, message_context)) < 0)
return result;
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c
index dfab1cb229b..c4e712b8471 100644
--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c
@@ -45,6 +45,8 @@ static spv_target_env spv_target_env_from_vkd3d(enum vkd3d_shader_spirv_environm
return SPV_ENV_OPENGL_4_5;
case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0:
return SPV_ENV_VULKAN_1_0;
+ case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1:
+ return SPV_ENV_VULKAN_1_1;
default:
ERR("Invalid environment %#x.\n", environment);
return SPV_ENV_VULKAN_1_0;
@@ -223,12 +225,8 @@ enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d
}
}
-static bool data_type_is_floating_point(enum vkd3d_data_type data_type)
-{
- return data_type == VKD3D_DATA_HALF || data_type == VKD3D_DATA_FLOAT || data_type == VKD3D_DATA_DOUBLE;
-}
-
-#define VKD3D_SPIRV_VERSION 0x00010000
+#define VKD3D_SPIRV_VERSION_1_0 0x00010000
+#define VKD3D_SPIRV_VERSION_1_3 0x00010300
#define VKD3D_SPIRV_GENERATOR_ID 18
#define VKD3D_SPIRV_GENERATOR_VERSION 11
#define VKD3D_SPIRV_GENERATOR_MAGIC vkd3d_make_u32(VKD3D_SPIRV_GENERATOR_VERSION, VKD3D_SPIRV_GENERATOR_ID)
@@ -1920,7 +1918,7 @@ static void vkd3d_spirv_builder_free(struct vkd3d_spirv_builder *builder)
}
static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder,
- struct vkd3d_shader_code *spirv, const char *entry_point)
+ struct vkd3d_shader_code *spirv, const char *entry_point, enum vkd3d_shader_spirv_environment environment)
{
uint64_t capability_mask = builder->capability_mask;
struct vkd3d_spirv_stream stream;
@@ -1931,7 +1929,8 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder,
vkd3d_spirv_stream_init(&stream);
vkd3d_spirv_build_word(&stream, SpvMagicNumber);
- vkd3d_spirv_build_word(&stream, VKD3D_SPIRV_VERSION);
+ vkd3d_spirv_build_word(&stream, (environment == VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1)
+ ? VKD3D_SPIRV_VERSION_1_3 : VKD3D_SPIRV_VERSION_1_0);
vkd3d_spirv_build_word(&stream, VKD3D_SPIRV_GENERATOR_MAGIC);
vkd3d_spirv_build_word(&stream, builder->current_id); /* bound */
vkd3d_spirv_build_word(&stream, 0); /* schema, reserved */
@@ -2480,6 +2479,7 @@ static struct spirv_compiler *spirv_compiler_create(const struct vsir_program *p
{
case VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5:
case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0:
+ case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1:
break;
default:
WARN("Invalid target environment %#x.\n", target_info->environment);
@@ -9263,7 +9263,11 @@ static void spirv_compiler_emit_atomic_instruction(struct spirv_compiler *compil
val_id = spirv_compiler_emit_load_src_with_type(compiler, &src[1], VKD3DSP_WRITEMASK_0, component_type);
if (instruction->flags & VKD3DARF_VOLATILE)
+ {
WARN("Ignoring 'volatile' attribute.\n");
+ spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_IGNORING_FLAG,
+ "Ignoring the 'volatile' attribute flag for atomic instruction %#x.", instruction->handler_idx);
+ }
memory_semantic = (instruction->flags & VKD3DARF_SEQ_CST)
? SpvMemorySemanticsSequentiallyConsistentMask
@@ -10052,7 +10056,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
spirv_compiler_emit_cut_stream(compiler, instruction);
break;
case VKD3DSIH_DCL:
- case VKD3DSIH_DCL_CONSTANT_BUFFER:
case VKD3DSIH_DCL_HS_MAX_TESSFACTOR:
case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT:
case VKD3DSIH_DCL_INPUT_SGV:
@@ -10157,6 +10160,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
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;
@@ -10241,12 +10245,12 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
if (compiler->strip_debug)
vkd3d_spirv_stream_clear(&builder->debug_stream);
- if (!vkd3d_spirv_compile_module(builder, spirv, spirv_compiler_get_entry_point_name(compiler)))
+ environment = spirv_compiler_get_target_environment(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)
{
- enum vkd3d_shader_spirv_environment environment = spirv_compiler_get_target_environment(compiler);
struct vkd3d_string_buffer buffer;
if (TRACE_ON())
@@ -10274,7 +10278,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
if (compile_info->target_type == VKD3D_SHADER_TARGET_SPIRV_TEXT)
{
struct vkd3d_shader_code text;
- enum vkd3d_shader_spirv_environment environment = spirv_compiler_get_target_environment(compiler);
if (vkd3d_spirv_binary_to_text(spirv, environment, compiler->formatting, &text) != VKD3D_OK)
return VKD3D_ERROR;
vkd3d_shader_free_shader_code(spirv);
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
index 81ac84896d4..3cc32ced280 100644
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -1576,7 +1576,7 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser,
case VKD3D_SHADER_TARGET_GLSL:
if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0)
return ret;
- ret = glsl_compile(program, out, message_context);
+ ret = glsl_compile(program, parser->config_flags, compile_info, out, message_context);
vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info);
break;
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
index 9b37bbef70b..36eb903ed84 100644
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -100,6 +100,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300,
VKD3D_SHADER_WARNING_SPV_INVALID_UAV_FLAGS = 2301,
+ VKD3D_SHADER_WARNING_SPV_IGNORING_FLAG = 2302,
VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY = 3000,
VKD3D_SHADER_ERROR_RS_INVALID_VERSION = 3001,
@@ -220,6 +221,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX = 9015,
VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW = 9016,
VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE = 9017,
+ VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION = 9018,
VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300,
};
@@ -641,6 +643,11 @@ static inline bool data_type_is_bool(enum vkd3d_data_type data_type)
return data_type == VKD3D_DATA_BOOL;
}
+static inline bool data_type_is_floating_point(enum vkd3d_data_type data_type)
+{
+ return data_type == VKD3D_DATA_HALF || data_type == VKD3D_DATA_FLOAT || data_type == VKD3D_DATA_DOUBLE;
+}
+
static inline bool data_type_is_64_bit(enum vkd3d_data_type data_type)
{
return data_type == VKD3D_DATA_DOUBLE || data_type == VKD3D_DATA_UINT64;
@@ -763,9 +770,13 @@ enum vkd3d_shader_atomic_rmw_flags
enum vkd3d_tessellator_domain
{
+ VKD3D_TESSELLATOR_DOMAIN_INVALID = 0,
+
VKD3D_TESSELLATOR_DOMAIN_LINE = 1,
VKD3D_TESSELLATOR_DOMAIN_TRIANGLE = 2,
VKD3D_TESSELLATOR_DOMAIN_QUAD = 3,
+
+ VKD3D_TESSELLATOR_DOMAIN_COUNT = 4,
};
#define VKD3DSI_NONE 0x0
@@ -1527,7 +1538,8 @@ int shader_extract_from_dxbc(const struct vkd3d_shader_code *dxbc,
int shader_parse_input_signature(const struct vkd3d_shader_code *dxbc,
struct vkd3d_shader_message_context *message_context, struct shader_signature *signature);
-int glsl_compile(struct vsir_program *program, struct vkd3d_shader_code *out,
+int glsl_compile(struct vsir_program *program, uint64_t config_flags,
+ const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out,
struct vkd3d_shader_message_context *message_context);
#define SPIRV_MAX_SRC_COUNT 6
diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c
index 7115a74a6f2..4a69ff530da 100644
--- a/libs/vkd3d/libs/vkd3d/command.c
+++ b/libs/vkd3d/libs/vkd3d/command.c
@@ -5414,6 +5414,26 @@ static const struct vkd3d_format *vkd3d_fixup_clear_uav_uint_colour(struct d3d12
| ((colour->uint32[2] & 0x3ff) << 22);
return vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false);
+ case DXGI_FORMAT_B5G6R5_UNORM:
+ colour->uint32[0] = (colour->uint32[2] & 0x1f)
+ | ((colour->uint32[1] & 0x3f) << 5)
+ | ((colour->uint32[0] & 0x1f) << 11);
+ return vkd3d_get_format(device, DXGI_FORMAT_R16_UINT, false);
+
+ case DXGI_FORMAT_B5G5R5A1_UNORM:
+ colour->uint32[0] = (colour->uint32[2] & 0x1f)
+ | ((colour->uint32[1] & 0x1f) << 5)
+ | ((colour->uint32[0] & 0x1f) << 10)
+ | ((colour->uint32[3] & 0x1) << 15);
+ return vkd3d_get_format(device, DXGI_FORMAT_R16_UINT, false);
+
+ case DXGI_FORMAT_B4G4R4A4_UNORM:
+ colour->uint32[0] = (colour->uint32[2] & 0xf)
+ | ((colour->uint32[1] & 0xf) << 4)
+ | ((colour->uint32[0] & 0xf) << 8)
+ | ((colour->uint32[3] & 0xf) << 12);
+ return vkd3d_get_format(device, DXGI_FORMAT_R16_UINT, false);
+
default:
return NULL;
}
diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c
index 90de27c53b6..a394e3f7592 100644
--- a/libs/vkd3d/libs/vkd3d/device.c
+++ b/libs/vkd3d/libs/vkd3d/device.c
@@ -89,6 +89,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] =
VK_EXTENSION(KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, KHR_sampler_mirror_clamp_to_edge),
VK_EXTENSION(KHR_TIMELINE_SEMAPHORE, KHR_timeline_semaphore),
/* EXT extensions */
+ VK_EXTENSION(EXT_4444_FORMATS, EXT_4444_formats),
VK_EXTENSION(EXT_CALIBRATED_TIMESTAMPS, EXT_calibrated_timestamps),
VK_EXTENSION(EXT_CONDITIONAL_RENDERING, EXT_conditional_rendering),
VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker),
@@ -558,12 +559,14 @@ static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance,
const struct vkd3d_optional_instance_extensions_info *optional_extensions;
const struct vkd3d_application_info *vkd3d_application_info;
const struct vkd3d_host_time_domain_info *time_domain_info;
+ PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
bool *user_extension_supported = NULL;
VkApplicationInfo application_info;
VkInstanceCreateInfo instance_info;
char application_name[PATH_MAX];
uint32_t extension_count;
const char **extensions;
+ uint32_t vk_api_version;
VkInstance vk_instance;
VkResult vr;
HRESULT hr;
@@ -616,6 +619,16 @@ static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance,
application_info.apiVersion = VK_API_VERSION_1_0;
instance->api_version = VKD3D_API_VERSION_1_0;
+ /* vkEnumerateInstanceVersion was added in Vulkan 1.1, and its absence indicates only 1.0 is supported. */
+ vkEnumerateInstanceVersion = (void *)vk_global_procs->vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
+ if (vkEnumerateInstanceVersion && vkEnumerateInstanceVersion(&vk_api_version) >= 0
+ && vk_api_version >= VK_API_VERSION_1_1)
+ {
+ TRACE("Vulkan API version 1.1 is available; requesting it.\n");
+ application_info.apiVersion = VK_API_VERSION_1_1;
+ }
+ instance->vk_api_version = application_info.apiVersion;
+
if ((vkd3d_application_info = vkd3d_find_struct(create_info->next, APPLICATION_INFO)))
{
if (vkd3d_application_info->application_name)
@@ -798,6 +811,7 @@ struct vkd3d_physical_device_info
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features;
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore_features;
VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutable_features;
+ VkPhysicalDevice4444FormatsFeaturesEXT formats4444_features;
VkPhysicalDeviceFeatures2 features2;
};
@@ -821,6 +835,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
VkPhysicalDeviceMaintenance3Properties *maintenance3_properties;
VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb_properties;
VkPhysicalDevice physical_device = device->vk_physical_device;
+ VkPhysicalDevice4444FormatsFeaturesEXT *formats4444_features;
VkPhysicalDeviceTransformFeedbackFeaturesEXT *xfb_features;
struct vkd3d_vulkan_info *vulkan_info = &device->vk_info;
@@ -839,6 +854,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
vertex_divisor_properties = &info->vertex_divisor_properties;
timeline_semaphore_features = &info->timeline_semaphore_features;
mutable_features = &info->mutable_features;
+ formats4444_features = &info->formats4444_features;
xfb_features = &info->xfb_features;
xfb_properties = &info->xfb_properties;
@@ -866,6 +882,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
vk_prepend_struct(&info->features2, timeline_semaphore_features);
mutable_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT;
vk_prepend_struct(&info->features2, mutable_features);
+ formats4444_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT;
+ vk_prepend_struct(&info->features2, formats4444_features);
if (vulkan_info->KHR_get_physical_device_properties2)
VK_CALL(vkGetPhysicalDeviceFeatures2KHR(physical_device, &info->features2));
@@ -1655,6 +1673,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
if (!physical_device_info->timeline_semaphore_features.timelineSemaphore)
vulkan_info->KHR_timeline_semaphore = false;
+ physical_device_info->formats4444_features.formatA4B4G4R4 = VK_FALSE;
+
vulkan_info->texel_buffer_alignment_properties = physical_device_info->texel_buffer_alignment_properties;
if (get_spec_version(vk_extensions, count, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) >= 3)
@@ -5117,6 +5137,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
device->vk_info = instance->vk_info;
device->signal_event = instance->signal_event;
device->wchar_size = instance->wchar_size;
+ device->environment = (instance->vk_api_version >= VK_API_VERSION_1_1)
+ ? VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1 : VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
device->adapter_luid = create_info->adapter_luid;
device->removed_reason = S_OK;
diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c
index b8328216a29..6ba29c18004 100644
--- a/libs/vkd3d/libs/vkd3d/state.c
+++ b/libs/vkd3d/libs/vkd3d/state.c
@@ -2452,7 +2452,7 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st
memset(&target_info, 0, sizeof(target_info));
target_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SPIRV_TARGET_INFO;
- target_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
+ target_info.environment = device->environment;
target_info.extensions = device->vk_info.shader_extensions;
target_info.extension_count = device->vk_info.shader_extension_count;
@@ -3177,7 +3177,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
ps_target_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SPIRV_TARGET_INFO;
ps_target_info.next = NULL;
ps_target_info.entry_point = "main";
- ps_target_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
+ ps_target_info.environment = device->environment;
ps_target_info.extensions = vk_info->shader_extensions;
ps_target_info.extension_count = vk_info->shader_extension_count;
ps_target_info.parameters = ps_shader_parameters;
@@ -3207,7 +3207,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
memset(&target_info, 0, sizeof(target_info));
target_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SPIRV_TARGET_INFO;
- target_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
+ target_info.environment = device->environment;
target_info.extensions = vk_info->shader_extensions;
target_info.extension_count = vk_info->shader_extension_count;
diff --git a/libs/vkd3d/libs/vkd3d/utils.c b/libs/vkd3d/libs/vkd3d/utils.c
index ac79ae5ddff..58747342b5c 100644
--- a/libs/vkd3d/libs/vkd3d/utils.c
+++ b/libs/vkd3d/libs/vkd3d/utils.c
@@ -87,6 +87,8 @@ static const struct vkd3d_format vkd3d_formats[] =
{DXGI_FORMAT_R8_SNORM, VK_FORMAT_R8_SNORM, 1, 1, 1, 1, COLOR, 1},
{DXGI_FORMAT_R8_SINT, VK_FORMAT_R8_SINT, 1, 1, 1, 1, COLOR, 1, SINT},
{DXGI_FORMAT_A8_UNORM, VK_FORMAT_R8_UNORM, 1, 1, 1, 1, COLOR, 1},
+ {DXGI_FORMAT_B5G6R5_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16, 2, 1, 1, 1, COLOR, 1},
+ {DXGI_FORMAT_B5G5R5A1_UNORM, VK_FORMAT_A1R5G5B5_UNORM_PACK16, 2, 1, 1, 1, COLOR, 1},
{DXGI_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, 4, 1, 1, 1, COLOR, 1},
{DXGI_FORMAT_B8G8R8X8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, 4, 1, 1, 1, COLOR, 1},
{DXGI_FORMAT_B8G8R8A8_TYPELESS, VK_FORMAT_B8G8R8A8_UNORM, 4, 1, 1, 1, COLOR, 1, TYPELESS},
@@ -116,6 +118,9 @@ static const struct vkd3d_format vkd3d_formats[] =
{DXGI_FORMAT_BC7_UNORM_SRGB, VK_FORMAT_BC7_SRGB_BLOCK, 1, 4, 4, 16, COLOR, 1},
};
+static const struct vkd3d_format format_b4g4r4a4 =
+ {DXGI_FORMAT_B4G4R4A4_UNORM, VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT, 2, 1, 1, 1, COLOR, 1};
+
/* Each depth/stencil format is only compatible with itself in Vulkan. */
static const struct vkd3d_format vkd3d_depth_stencil_formats[] =
{
@@ -449,6 +454,11 @@ const struct vkd3d_format *vkd3d_get_format(const struct d3d12_device *device,
return &vkd3d_formats[i];
}
+ /* Do not check VkPhysicalDevice4444FormatsFeaturesEXT because apps
+ * should query format support, which returns more detailed info. */
+ if (dxgi_format == format_b4g4r4a4.dxgi_format && device->vk_info.EXT_4444_formats)
+ return &format_b4g4r4a4;
+
return NULL;
}
diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_main.c b/libs/vkd3d/libs/vkd3d/vkd3d_main.c
index e0345deaa0f..29305fbdc63 100644
--- a/libs/vkd3d/libs/vkd3d/vkd3d_main.c
+++ b/libs/vkd3d/libs/vkd3d/vkd3d_main.c
@@ -453,11 +453,10 @@ HRESULT vkd3d_serialize_root_signature(const D3D12_ROOT_SIGNATURE_DESC *desc,
if ((ret = vkd3d_shader_serialize_root_signature(&vkd3d_desc, &dxbc, &messages)) < 0)
{
WARN("Failed to serialize root signature, vkd3d result %d.\n", ret);
- if (error_blob && messages)
- {
- if (FAILED(hr = vkd3d_blob_create(messages, strlen(messages), error_blob)))
- ERR("Failed to create error blob, hr %s.\n", debugstr_hresult(hr));
- }
+ if (!error_blob)
+ vkd3d_shader_free_messages(messages);
+ else if (messages && FAILED(hr = vkd3d_blob_create(messages, strlen(messages), error_blob)))
+ ERR("Failed to create error blob, hr %s.\n", debugstr_hresult(hr));
return hresult_from_vkd3d_result(ret);
}
vkd3d_shader_free_messages(messages);
@@ -494,11 +493,10 @@ HRESULT vkd3d_serialize_versioned_root_signature(const D3D12_VERSIONED_ROOT_SIGN
if ((ret = vkd3d_shader_serialize_root_signature(vkd3d_desc, &dxbc, &messages)) < 0)
{
WARN("Failed to serialize root signature, vkd3d result %d.\n", ret);
- if (error_blob && messages)
- {
- if (FAILED(hr = vkd3d_blob_create(messages, strlen(messages), error_blob)))
- ERR("Failed to create error blob, hr %s.\n", debugstr_hresult(hr));
- }
+ if (!error_blob)
+ vkd3d_shader_free_messages(messages);
+ else if (messages && FAILED(hr = vkd3d_blob_create(messages, strlen(messages), error_blob)))
+ ERR("Failed to create error blob, hr %s.\n", debugstr_hresult(hr));
return hresult_from_vkd3d_result(ret);
}
vkd3d_shader_free_messages(messages);
diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h
index 9f5f759667a..e0a7acb306d 100644
--- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h
@@ -128,6 +128,7 @@ struct vkd3d_vulkan_info
bool KHR_sampler_mirror_clamp_to_edge;
bool KHR_timeline_semaphore;
/* EXT device extensions */
+ bool EXT_4444_formats;
bool EXT_calibrated_timestamps;
bool EXT_conditional_rendering;
bool EXT_debug_marker;
@@ -185,6 +186,7 @@ struct vkd3d_instance
struct vkd3d_vulkan_info vk_info;
struct vkd3d_vk_global_procs vk_global_procs;
void *libvulkan;
+ uint32_t vk_api_version;
uint64_t config_flags;
enum vkd3d_api_version api_version;
@@ -1678,6 +1680,7 @@ struct d3d12_device
struct vkd3d_vk_device_procs vk_procs;
PFN_vkd3d_signal_event signal_event;
size_t wchar_size;
+ enum vkd3d_shader_spirv_environment environment;
struct vkd3d_gpu_va_allocator gpu_va_allocator;
--
2.43.0