vkd3d-shader/spirv: Introduce HALF and UINT16 types for minimum precision.

Minimum precision types must always be implemented as 32-bit to match how
reduced precision works in SPIR-V.
This commit is contained in:
Conor McCarthy 2023-12-13 15:40:48 +10:00 committed by Alexandre Julliard
parent 58123c2e10
commit 066ea75945
Notes: Alexandre Julliard 2024-03-11 23:07:09 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Conor McCarthy (@cmccarthy)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/519
3 changed files with 87 additions and 7 deletions

View File

@ -649,6 +649,8 @@ static void shader_dump_data_type(struct vkd3d_d3d_asm_compiler *compiler, enum
[VKD3D_DATA_UINT8 ] = "uint8", [VKD3D_DATA_UINT8 ] = "uint8",
[VKD3D_DATA_UINT64 ] = "uint64", [VKD3D_DATA_UINT64 ] = "uint64",
[VKD3D_DATA_BOOL ] = "bool", [VKD3D_DATA_BOOL ] = "bool",
[VKD3D_DATA_UINT16 ] = "uint16",
[VKD3D_DATA_HALF ] = "half",
}; };
const char *name; const char *name;

View File

@ -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) 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 #define VKD3D_SPIRV_VERSION 0x00010000
@ -1843,6 +1843,7 @@ static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder
{ {
switch (data_type) switch (data_type)
{ {
case VKD3D_DATA_HALF: /* Minimum precision. TODO: native 16-bit */
case VKD3D_DATA_FLOAT: case VKD3D_DATA_FLOAT:
case VKD3D_DATA_SNORM: case VKD3D_DATA_SNORM:
case VKD3D_DATA_UNORM: case VKD3D_DATA_UNORM:
@ -1850,6 +1851,7 @@ static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder
break; break;
case VKD3D_DATA_INT: case VKD3D_DATA_INT:
case VKD3D_DATA_UINT: 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); return vkd3d_spirv_get_op_type_int(builder, 32, data_type == VKD3D_DATA_INT);
break; break;
case VKD3D_DATA_DOUBLE: case VKD3D_DATA_DOUBLE:
@ -3758,6 +3760,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); 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, 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) const struct vkd3d_shader_register *reg, uint32_t swizzle, uint32_t write_mask)
{ {
@ -3770,14 +3836,15 @@ static uint32_t spirv_compiler_emit_load_constant(struct spirv_compiler *compile
if (reg->dimension == VSIR_DIMENSION_SCALAR) if (reg->dimension == VSIR_DIMENSION_SCALAR)
{ {
for (i = 0; i < component_count; ++i) 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 else
{ {
for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i) for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
{ {
if (write_mask & (VKD3DSP_WRITEMASK_0 << 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)]);
} }
} }
@ -3921,6 +3988,13 @@ static uint32_t spirv_compiler_emit_constant_array(struct spirv_compiler *compil
switch (icb->data_type) 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_FLOAT:
case VKD3D_DATA_INT: case VKD3D_DATA_INT:
case VKD3D_DATA_UINT: case VKD3D_DATA_UINT:
@ -6908,7 +6982,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); 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); 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); val_id = spirv_compiler_emit_bool_to_float(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF);
} }
@ -6917,7 +6991,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. */ /* 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); 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); val_id = spirv_compiler_emit_bool_to_int(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOI);
} }

View File

@ -623,14 +623,16 @@ enum vkd3d_data_type
VKD3D_DATA_UINT8, VKD3D_DATA_UINT8,
VKD3D_DATA_UINT64, VKD3D_DATA_UINT64,
VKD3D_DATA_BOOL, VKD3D_DATA_BOOL,
VKD3D_DATA_UINT16,
VKD3D_DATA_HALF,
VKD3D_DATA_COUNT, VKD3D_DATA_COUNT,
}; };
static inline bool data_type_is_integer(enum vkd3d_data_type data_type) 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 return data_type == VKD3D_DATA_INT || data_type == VKD3D_DATA_UINT8 || data_type == VKD3D_DATA_UINT16
|| data_type == VKD3D_DATA_UINT64; || data_type == VKD3D_DATA_UINT || data_type == VKD3D_DATA_UINT64;
} }
static inline bool data_type_is_bool(enum vkd3d_data_type data_type) static inline bool data_type_is_bool(enum vkd3d_data_type data_type)
@ -1531,10 +1533,12 @@ static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_ty
{ {
switch (data_type) switch (data_type)
{ {
case VKD3D_DATA_HALF: /* Minimum precision. TODO: native 16-bit */
case VKD3D_DATA_FLOAT: case VKD3D_DATA_FLOAT:
case VKD3D_DATA_UNORM: case VKD3D_DATA_UNORM:
case VKD3D_DATA_SNORM: case VKD3D_DATA_SNORM:
return VKD3D_SHADER_COMPONENT_FLOAT; return VKD3D_SHADER_COMPONENT_FLOAT;
case VKD3D_DATA_UINT16: /* Minimum precision. TODO: native 16-bit */
case VKD3D_DATA_UINT: case VKD3D_DATA_UINT:
return VKD3D_SHADER_COMPONENT_UINT; return VKD3D_SHADER_COMPONENT_UINT;
case VKD3D_DATA_INT: case VKD3D_DATA_INT: