From: Conor McCarthy cmccarthy@codeweavers.com
Minimum precision types must always be implemented as 32-bit to match how reduced precision works in SPIR-V. --- libs/vkd3d-shader/d3d_asm.c | 2 + libs/vkd3d-shader/spirv.c | 84 ++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 8 ++- 3 files changed, 87 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 3f86bd459..26cf714c1 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -646,6 +646,8 @@ static void shader_dump_data_type(struct vkd3d_d3d_asm_compiler *compiler, enum [VKD3D_DATA_UINT8 ] = "uint8", [VKD3D_DATA_UINT64 ] = "uint64", [VKD3D_DATA_BOOL ] = "bool", + [VKD3D_DATA_UINT16 ] = "uint16", + [VKD3D_DATA_HALF ] = "half", };
const char *name; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index f84ad78ea..16b4cbf55 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -225,7 +225,7 @@ 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_FLOAT || data_type == VKD3D_DATA_DOUBLE; + return data_type == VKD3D_DATA_HALF || data_type == VKD3D_DATA_FLOAT || data_type == VKD3D_DATA_DOUBLE; }
#define VKD3D_SPIRV_VERSION 0x00010000 @@ -1830,6 +1830,7 @@ static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder { switch (data_type) { + case VKD3D_DATA_HALF: /* Minimum precision. TODO: native 16-bit */ case VKD3D_DATA_FLOAT: case VKD3D_DATA_SNORM: case VKD3D_DATA_UNORM: @@ -1837,6 +1838,7 @@ static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder break; case VKD3D_DATA_INT: case VKD3D_DATA_UINT: + case VKD3D_DATA_UINT16: /* Minimum precision. TODO: native 16-bit */ return vkd3d_spirv_get_op_type_int(builder, 32, data_type == VKD3D_DATA_INT); break; case VKD3D_DATA_DOUBLE: @@ -3741,6 +3743,70 @@ static uint32_t spirv_compiler_emit_bool_to_double(struct spirv_compiler *compil return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); }
+/* Based on the implementation in the OpenGL Mathematics library. */ +static uint32_t half_to_float(uint16_t value) +{ + uint32_t s = (value & 0x8000u) << 16; + uint32_t e = (value >> 10) & 0x1fu; + uint32_t m = value & 0x3ffu; + + if (!e) + { + if (!m) + { + /* Plus or minus zero */ + return s; + } + else + { + /* Denormalized number -- renormalize it */ + + while (!(m & 0x400u)) + { + m <<= 1; + --e; + } + + ++e; + m &= ~0x400u; + } + } + else if (e == 31u) + { + /* Positive or negative infinity for zero 'm'. + * Nan for non-zero 'm' -- preserve sign and significand bits */ + return s | 0x7f800000u | (m << 13); + } + + /* Normalized number */ + e += 127u - 15u; + m <<= 13; + + /* Assemble s, e and m. */ + return s | (e << 23) | m; +} + +static uint32_t convert_raw_constant32(enum vkd3d_data_type data_type, unsigned int uint_value) +{ + int16_t i; + + /* TODO: native 16-bit support. */ + if (data_type != VKD3D_DATA_UINT16 && data_type != VKD3D_DATA_HALF) + return uint_value; + + if (data_type == VKD3D_DATA_HALF) + return half_to_float(uint_value); + + /* Values in DXIL have no signedness, so it is ambiguous whether 16-bit constants should or + * should not be sign-extended when 16-bit execution is not supported. The AMD RX 580 Windows + * driver has no 16-bit support, and sign-extends all 16-bit constant ints to 32 bits. These + * results differ from SM 5. The RX 6750 XT supports 16-bit execution, so constants are not + * extended, and results match SM 5. It seems best to replicate the sign-extension, and if + * execution is 16-bit, the values will be truncated. */ + i = uint_value; + return (int32_t)i; +} + static uint32_t spirv_compiler_emit_load_constant(struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg, uint32_t swizzle, uint32_t write_mask) { @@ -3753,14 +3819,15 @@ static uint32_t spirv_compiler_emit_load_constant(struct spirv_compiler *compile if (reg->dimension == VSIR_DIMENSION_SCALAR) { for (i = 0; i < component_count; ++i) - values[i] = *reg->u.immconst_u32; + values[i] = convert_raw_constant32(reg->data_type, reg->u.immconst_u32[0]); } else { for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i) { if (write_mask & (VKD3DSP_WRITEMASK_0 << i)) - values[j++] = reg->u.immconst_u32[vsir_swizzle_get_component(swizzle, i)]; + values[j++] = convert_raw_constant32(reg->data_type, + reg->u.immconst_u32[vsir_swizzle_get_component(swizzle, i)]); } }
@@ -3904,6 +3971,13 @@ static uint32_t spirv_compiler_emit_constant_array(struct spirv_compiler *compil
switch (icb->data_type) { + case VKD3D_DATA_HALF: + case VKD3D_DATA_UINT16: + /* Scalar only. */ + for (i = 0; i < element_count; ++i) + elements[i] = vkd3d_spirv_get_op_constant(builder, elem_type_id, + convert_raw_constant32(icb->data_type, icb->data[i])); + break; case VKD3D_DATA_FLOAT: case VKD3D_DATA_INT: case VKD3D_DATA_UINT: @@ -6876,7 +6950,7 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, assert(src->reg.data_type == VKD3D_DATA_BOOL && dst->reg.data_type != VKD3D_DATA_BOOL);
val_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask); - if (dst->reg.data_type == VKD3D_DATA_FLOAT) + if (dst->reg.data_type == VKD3D_DATA_HALF || dst->reg.data_type == VKD3D_DATA_FLOAT) { val_id = spirv_compiler_emit_bool_to_float(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF); } @@ -6885,7 +6959,7 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, /* ITOD is not supported. Frontends which emit bool casts must use ITOF for double. */ val_id = spirv_compiler_emit_bool_to_double(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF); } - else if (dst->reg.data_type == VKD3D_DATA_UINT) + else if (dst->reg.data_type == VKD3D_DATA_UINT16 || dst->reg.data_type == VKD3D_DATA_UINT) { val_id = spirv_compiler_emit_bool_to_int(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOI); } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 1030adf98..d0f841abe 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -620,14 +620,16 @@ enum vkd3d_data_type VKD3D_DATA_UINT8, VKD3D_DATA_UINT64, VKD3D_DATA_BOOL, + VKD3D_DATA_UINT16, + VKD3D_DATA_HALF,
VKD3D_DATA_COUNT, };
static inline bool data_type_is_integer(enum vkd3d_data_type data_type) { - return data_type == VKD3D_DATA_INT || data_type == VKD3D_DATA_UINT8 || data_type == VKD3D_DATA_UINT - || data_type == VKD3D_DATA_UINT64; + return data_type == VKD3D_DATA_INT || data_type == VKD3D_DATA_UINT8 || data_type == VKD3D_DATA_UINT16 + || data_type == VKD3D_DATA_UINT || data_type == VKD3D_DATA_UINT64; }
static inline bool data_type_is_bool(enum vkd3d_data_type data_type) @@ -1518,10 +1520,12 @@ static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_ty { switch (data_type) { + case VKD3D_DATA_HALF: /* Minimum precision. TODO: native 16-bit */ case VKD3D_DATA_FLOAT: case VKD3D_DATA_UNORM: case VKD3D_DATA_SNORM: return VKD3D_SHADER_COMPONENT_FLOAT; + case VKD3D_DATA_UINT16: /* Minimum precision. TODO: native 16-bit */ case VKD3D_DATA_UINT: return VKD3D_SHADER_COMPONENT_UINT; case VKD3D_DATA_INT: