vkd3d-shader/dxil: Implement the DXIL BINOP instruction.

This commit is contained in:
Conor McCarthy 2023-10-16 15:41:17 +10:00 committed by Alexandre Julliard
parent 3e0638148a
commit 749df8dec2
Notes: Alexandre Julliard 2023-11-06 23:18:07 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/409
15 changed files with 256 additions and 25 deletions

View File

@ -242,6 +242,45 @@ enum dxil_shader_properties_tag
SHADER_PROPERTIES_ENTRY_ROOT_SIG = 12,
};
enum dxil_binop_code
{
BINOP_ADD = 0,
BINOP_SUB = 1,
BINOP_MUL = 2,
BINOP_UDIV = 3,
BINOP_SDIV = 4,
BINOP_UREM = 5,
BINOP_SREM = 6,
BINOP_SHL = 7,
BINOP_LSHR = 8,
BINOP_ASHR = 9,
BINOP_AND = 10,
BINOP_OR = 11,
BINOP_XOR = 12
};
enum dxil_fast_fp_flags
{
FP_ALLOW_UNSAFE_ALGEBRA = 0x1,
FP_NO_NAN = 0x2,
FP_NO_INF = 0x4,
FP_NO_SIGNED_ZEROS = 0x8,
FP_ALLOW_RECIPROCAL = 0x10,
};
enum dxil_overflowing_binop_flags
{
/* Operation is known to never overflow. */
OB_NO_UNSIGNED_WRAP = 0x1,
OB_NO_SIGNED_WRAP = 0x2,
};
enum dxil_possibly_exact_binop_flags
{
/* "A udiv or sdiv instruction, which can be marked as "exact", indicating that no bits are destroyed." */
PEB_EXACT = 0x1,
};
enum dx_intrinsic_opcode
{
DX_LOAD_INPUT = 4,
@ -1463,6 +1502,11 @@ static inline bool sm6_type_is_integer(const struct sm6_type *type)
return type->class == TYPE_CLASS_INTEGER;
}
static bool sm6_type_is_bool_i16_i32_i64(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_INTEGER && (type->u.width == 1 || type->u.width >= 16);
}
static bool sm6_type_is_bool(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_INTEGER && type->u.width == 1;
@ -2634,6 +2678,187 @@ static struct sm6_block *sm6_block_create()
return block;
}
static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_type *type_a,
const struct sm6_type *type_b, struct sm6_parser *sm6)
{
bool is_int = sm6_type_is_bool_i16_i32_i64(type_a);
bool is_bool = sm6_type_is_bool(type_a);
enum vkd3d_shader_opcode op;
bool is_valid;
if (!is_int && !sm6_type_is_floating_point(type_a))
{
WARN("Argument type %u is not bool, int16/32/64 or floating point.\n", type_a->class);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
"An argument to a binary operation is not bool, int16/32/64 or floating point.");
return VKD3DSIH_INVALID;
}
if (type_a != type_b)
{
WARN("Type mismatch, type %u width %u vs type %u width %u.\n", type_a->class,
type_a->u.width, type_b->class, type_b->u.width);
vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
"Type mismatch in binary operation arguments.");
}
switch (code)
{
case BINOP_ADD:
case BINOP_SUB:
/* NEG is applied later for subtraction. */
op = is_int ? VKD3DSIH_IADD : VKD3DSIH_ADD;
is_valid = !is_bool;
break;
case BINOP_AND:
op = VKD3DSIH_AND;
is_valid = is_int;
break;
case BINOP_ASHR:
op = VKD3DSIH_ISHR;
is_valid = is_int && !is_bool;
break;
case BINOP_LSHR:
op = VKD3DSIH_USHR;
is_valid = is_int && !is_bool;
break;
case BINOP_MUL:
op = is_int ? VKD3DSIH_UMUL : VKD3DSIH_MUL;
is_valid = !is_bool;
break;
case BINOP_OR:
op = VKD3DSIH_OR;
is_valid = is_int;
break;
case BINOP_SDIV:
op = is_int ? VKD3DSIH_IDIV : VKD3DSIH_DIV;
is_valid = !is_bool;
break;
case BINOP_SREM:
op = is_int ? VKD3DSIH_IDIV : VKD3DSIH_FREM;
is_valid = !is_bool;
break;
case BINOP_SHL:
op = VKD3DSIH_ISHL;
is_valid = is_int && !is_bool;
break;
case BINOP_UDIV:
case BINOP_UREM:
op = VKD3DSIH_UDIV;
is_valid = is_int && !is_bool;
break;
case BINOP_XOR:
op = VKD3DSIH_XOR;
is_valid = is_int;
break;
default:
FIXME("Unhandled binary op %#"PRIx64".\n", code);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
"Binary operation %#"PRIx64" is unhandled.", code);
return VKD3DSIH_INVALID;
}
if (!is_valid)
{
WARN("Invalid operation %u for type %u, width %u.\n", op, type_a->class, type_a->u.width);
vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION,
"Binary operation %u is invalid on type class %u, width %u.", op, type_a->class, type_a->u.width);
}
return op;
}
static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_record *record,
struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
{
struct vkd3d_shader_src_param *src_params;
enum vkd3d_shader_opcode handler_idx;
const struct sm6_value *a, *b;
unsigned int i = 0;
uint64_t code;
a = sm6_parser_get_value_by_ref(sm6, record, NULL, &i);
b = sm6_parser_get_value_by_ref(sm6, record, a->type, &i);
if (!a || !b)
return;
if (!dxil_record_validate_operand_count(record, i + 1, i + 2, sm6))
return;
code = record->operands[i++];
if ((handler_idx = map_binary_op(code, a->type, b->type, sm6)) == VKD3DSIH_INVALID)
return;
vsir_instruction_init(ins, &sm6->p.location, handler_idx);
if (record->operand_count > i && record->operands[i])
{
uint64_t flags = record->operands[i];
bool silence_warning = false;
switch (handler_idx)
{
case VKD3DSIH_ADD:
case VKD3DSIH_MUL:
case VKD3DSIH_DIV:
case VKD3DSIH_FREM:
if (!(flags & FP_ALLOW_UNSAFE_ALGEBRA))
ins->flags |= VKD3DSI_PRECISE_X;
flags &= ~FP_ALLOW_UNSAFE_ALGEBRA;
/* SPIR-V FPFastMathMode is only available in the Kernel executon model. */
silence_warning = !(flags & ~(FP_NO_NAN | FP_NO_INF | FP_NO_SIGNED_ZEROS | FP_ALLOW_RECIPROCAL));
break;
case VKD3DSIH_IADD:
case VKD3DSIH_UMUL:
case VKD3DSIH_ISHL:
silence_warning = !(flags & ~(OB_NO_UNSIGNED_WRAP | OB_NO_SIGNED_WRAP));
break;
case VKD3DSIH_ISHR:
case VKD3DSIH_USHR:
case VKD3DSIH_IDIV:
case VKD3DSIH_UDIV:
silence_warning = !(flags & ~PEB_EXACT);
break;
default:
break;
}
/* The above flags are very common and cause warning spam. */
if (flags && silence_warning)
{
TRACE("Ignoring flags %#"PRIx64".\n", flags);
}
else if (flags)
{
WARN("Ignoring flags %#"PRIx64".\n", flags);
vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
"Ignoring flags %#"PRIx64" for a binary operation.", flags);
}
}
src_params = instruction_src_params_alloc(ins, 2, sm6);
src_param_init_from_value(&src_params[0], a);
src_param_init_from_value(&src_params[1], b);
if (code == BINOP_SUB)
src_params[1].modifiers = VKD3DSPSM_NEG;
dst->type = a->type;
if (handler_idx == VKD3DSIH_UMUL || handler_idx == VKD3DSIH_UDIV || handler_idx == VKD3DSIH_IDIV)
{
struct vkd3d_shader_dst_param *dst_params = instruction_dst_params_alloc(ins, 2, sm6);
unsigned int index = code != BINOP_UDIV && code != BINOP_SDIV;
dst_param_init(&dst_params[0]);
dst_param_init(&dst_params[1]);
register_init_ssa_scalar(&dst_params[index].reg, a->type, sm6);
vsir_register_init(&dst_params[index ^ 1].reg, VKD3DSPR_NULL, VKD3D_DATA_UNUSED, 0);
dst->u.reg = dst_params[index].reg;
}
else
{
instruction_dst_param_init_ssa_scalar(ins, sm6);
}
}
static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, struct sm6_block *code_block,
enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
{
@ -3233,6 +3458,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
record = block->records[i];
switch (record->code)
{
case FUNC_CODE_INST_BINOP:
sm6_parser_emit_binop(sm6, record, ins, dst);
break;
case FUNC_CODE_INST_CALL:
sm6_parser_emit_call(sm6, record, code_block, ins, dst);
break;

View File

@ -192,6 +192,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH = 8305,
VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH = 8306,
VKD3D_SHADER_WARNING_DXIL_INVALID_MASK = 8307,
VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION = 8308,
VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000,
VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER = 9001,

View File

@ -10,7 +10,7 @@ float4 main() : SV_TARGET
[test]
uniform 0 float4 5.0 15.0 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (20.0, -10.0, 75.0, 0.33333333) 1
[pixel shader]
@ -25,7 +25,7 @@ float4 main() : SV_TARGET
[test]
uniform 0 float4 5.0 15.0 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (5.0, 5.0, -5.0, 3.0) 1
[pixel shader]
@ -40,7 +40,7 @@ float4 main() : SV_TARGET
[test]
uniform 0 float4 42.0 5.0 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (2.0, -2.0, 2.0, -2.0) 16
[pixel shader]
@ -55,7 +55,7 @@ float4 main() : SV_TARGET
[test]
uniform 0 float4 45.0 5.0 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (0.0, 0.0, 0.0, 0.0)
[pixel shader]
@ -69,8 +69,8 @@ float4 main() : sv_target
[test]
uniform 0 float4 5.0 -42.1 4.0 45.0
uniform 4 float4 15.0 -5.0 4.1 5.0
todo(sm>=6) draw quad
probe all rgba (5.0, -2.1, 4.0, 0.0) 4
draw quad
probe all rgba (5.0, -2.1, 4.0, 0.0) 6
[require]
% Infinities are not allowed in SM1
@ -88,5 +88,5 @@ float4 main() : SV_TARGET
[test]
uniform 0 float4 1.0 0.0 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (1e99, 1e99, 1e99, 1e99)

View File

@ -176,7 +176,7 @@ float4 main() : sv_target
uniform 0 float4 1.0 2.0 3.0 4.0
uniform 4 float4 5.0 6.0 7.0 8.0
uniform 8 float4 9.0 10.0 11.0 12.0
todo(sm>=6) draw quad
draw quad
probe all rgba (509, 610, 711, 812)
@ -204,7 +204,7 @@ uniform 0 float4 0.0 1.0 2.0 3.0
uniform 4 float4 4.0 5.0 6.0 7.0
uniform 8 float4 8.0 9.0 10.0 11.0
uniform 12 float4 12.0 13.0 14.0 15.0
todo(sm>=6) draw quad
draw quad
probe all rgba (12468.0, 13509.0, 14010.0, 15011.0)
@ -326,7 +326,7 @@ float4 main() : sv_target
uniform 0 float 1.0
uniform 1 float 2.0
uniform 4 float4 5.0 6.0 7.0 8.0
todo(sm>=6) draw quad
draw quad
probe all rgba (512.0, 612.0, 712.0, 812.0)

View File

@ -10,7 +10,7 @@ float4 main() : sv_target
[test]
uniform 0 float4 1.0 2.0 3.0 4.0
uniform 4 float4 0.1 0.2 0.3 0.4
todo(sm>=6) draw quad
draw quad
probe all rgba (1.1, 2.2, 3.3, 4.4)
[pixel shader fail(sm<6)]

View File

@ -12,7 +12,7 @@ float4 main() : sv_target
[test]
uniform 0 float4 1 -2 3 4
uniform 4 float4 10 100 1000 10000
todo(sm>=6) draw quad
draw quad
probe all rgba (-2300, -970, 120, 0)
@ -29,5 +29,5 @@ float4 main() : sv_target
[test]
uniform 0 float4 1 -2 3 4
todo(sm>=6) draw quad
draw quad
probe all rgba (-20, 8, 12, 3.5)

View File

@ -71,7 +71,7 @@ float4 main() : SV_TARGET
% Account for both the SM1 and SM4 uniform layout
uniform 0 float4 2.0 3.0 0.0 0.0
uniform 4 float4 3.0 0.0 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (6.0, 6.0, 6.0, 6.0)
[pixel shader]

View File

@ -9,7 +9,7 @@ float4 main() : sv_target
[test]
uniform 0 float4 1.0 2.0 3.0 4.0
uniform 4 float4 5.0 6.0 7.0 8.0
todo(sm>=6) draw quad
draw quad
probe all rgba (8.0, 8.0, 8.0, 8.0)

View File

@ -12,7 +12,7 @@ float4 main() : SV_TARGET
uniform 0 float4 2.0 3.0 4.0 5.0
uniform 4 float4 0.0 -10.0 10.0 100.0
uniform 8 float4 0.0 1.0 -1.0 0.75
todo(sm>=6) draw quad
draw quad
probe all rgba (2.0, -10.0, -2.0, 76.25)
[require]

View File

@ -1,3 +1,5 @@
% TODO: dxcompiler emits no loops for any of these test shaders.
[pixel shader]
float a;
@ -16,7 +18,7 @@ float4 main() : sv_target
[test]
uniform 0 float 5.0
todo(sm>=6) draw quad
draw quad
probe all rgba (50.0, 50.0, 50.0, 50.0)
@ -39,7 +41,7 @@ float4 main() : sv_target
[test]
uniform 0 float 4.0
todo(sm>=6) draw quad
draw quad
probe all rgba (20.0, 20.0, 20.0, 20.0)
[pixel shader]
@ -68,7 +70,7 @@ float4 main() : sv_target
[test]
uniform 0 float 4.0
todo(sm>=6) draw quad
draw quad
probe all rgba (409.1, 409.1, 409.1, 409.1)
[pixel shader]
@ -98,7 +100,7 @@ float4 main() : sv_target
[test]
uniform 0 float 4.0
todo(sm>=6) draw quad
draw quad
probe all rgba (410.1, 410.1, 410.1, 410.1)
% loop attribute by itself

View File

@ -14,5 +14,5 @@ float4 main() : SV_TARGET
[test]
uniform 0 float4 2.5 0.3 0.2 0.7
uniform 4 float4 0.1 1.5 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (-12.43, 9.833333, 1.6, 35.0) 1

View File

@ -202,7 +202,7 @@ float4 main() : sv_target
[test]
uniform 0 float 10.0
todo(sm>=6) draw quad
draw quad
probe (0, 0) rgba (11.0, 12.0, 13.0, 11.0)

View File

@ -62,7 +62,7 @@ float4 main() : sv_target
[test]
uniform 0 float4 0.5 0.0 0.0 0.0
uniform 4 float4 0.6 0.0 0.0 0.0
todo(sm>=6) draw quad
draw quad
probe all rgba (0.14, 0.14, 0.14, 0.14) 4
[pixel shader]

View File

@ -11,5 +11,5 @@ float4 main() : SV_target
[test]
uniform 0 float4 0.0303 0.08 0.07 0.0202
todo(sm>=6) draw quad
draw quad
probe all rgba (-0.4697, -0.02, 0.57, 0.3202) 2

View File

@ -12,5 +12,5 @@ float4 main() : SV_target
[test]
uniform 0 float4 0.0303 0.08 0.07 0.0202
todo(sm>=6) draw quad
draw quad
probe all rgba (0.5697, -0.08, -0.27, -0.4202)