Goes atop MR 409. The last five commits belong to this MR.
-- v4: vkd3d-shader/dxil: Implement the DXIL CAST instruction.
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 1 + libs/vkd3d-shader/spirv.c | 2 ++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 4 insertions(+)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 40daa5354..210511e4c 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -152,6 +152,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_FIRSTBIT_LO ] = "firstbit_lo", [VKD3DSIH_FIRSTBIT_SHI ] = "firstbit_shi", [VKD3DSIH_FRC ] = "frc", + [VKD3DSIH_FREM ] = "frem", [VKD3DSIH_FTOD ] = "ftod", [VKD3DSIH_FTOI ] = "ftoi", [VKD3DSIH_FTOU ] = "ftou", diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 6faac0ccd..4fc2348bc 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -6602,6 +6602,7 @@ static SpvOp spirv_compiler_map_alu_instruction(const struct vkd3d_shader_instru {VKD3DSIH_DTOF, SpvOpFConvert}, {VKD3DSIH_DTOI, SpvOpConvertFToS}, {VKD3DSIH_DTOU, SpvOpConvertFToU}, + {VKD3DSIH_FREM, SpvOpFRem}, {VKD3DSIH_FTOD, SpvOpFConvert}, {VKD3DSIH_IADD, SpvOpIAdd}, {VKD3DSIH_INEG, SpvOpSNegate}, @@ -9413,6 +9414,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DTOF: case VKD3DSIH_DTOI: case VKD3DSIH_DTOU: + case VKD3DSIH_FREM: case VKD3DSIH_FTOD: case VKD3DSIH_IADD: case VKD3DSIH_INEG: diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index f6421cc8a..17e306108 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -327,6 +327,7 @@ enum vkd3d_shader_opcode VKD3DSIH_FIRSTBIT_LO, VKD3DSIH_FIRSTBIT_SHI, VKD3DSIH_FRC, + VKD3DSIH_FREM, VKD3DSIH_FTOD, VKD3DSIH_FTOI, VKD3DSIH_FTOU,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 1 + libs/vkd3d-shader/spirv.c | 20 +++++++++----------- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 210511e4c..645d99836 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -171,6 +171,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_HS_JOIN_PHASE ] = "hs_join_phase", [VKD3DSIH_IADD ] = "iadd", [VKD3DSIH_IBFE ] = "ibfe", + [VKD3DSIH_IDIV ] = "idiv", [VKD3DSIH_IEQ ] = "ieq", [VKD3DSIH_IF ] = "if", [VKD3DSIH_IFC ] = "ifc", diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 4fc2348bc..d9e11c82d 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1431,13 +1431,6 @@ static uint32_t vkd3d_spirv_build_op_udiv(struct vkd3d_spirv_builder *builder, SpvOpUDiv, result_type, operand0, operand1); }
-static uint32_t vkd3d_spirv_build_op_umod(struct vkd3d_spirv_builder *builder, - uint32_t result_type, uint32_t operand0, uint32_t operand1) -{ - return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, - SpvOpUMod, result_type, operand0, operand1); -} - static uint32_t vkd3d_spirv_build_op_isub(struct vkd3d_spirv_builder *builder, uint32_t result_type, uint32_t operand0, uint32_t operand1) { @@ -7017,7 +7010,7 @@ static void spirv_compiler_emit_imad(struct spirv_compiler *compiler, spirv_compiler_emit_store_dst(compiler, dst, val_id); }
-static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, +static void spirv_compiler_emit_int_div(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { uint32_t type_id, val_id, src0_id, src1_id, condition_id, uint_max_id; @@ -7025,6 +7018,10 @@ static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst = instruction->dst; const struct vkd3d_shader_src_param *src = instruction->src; unsigned int component_count = 0; + SpvOp div_op, mod_op; + + div_op = instruction->handler_idx == VKD3DSIH_IDIV ? SpvOpSDiv : SpvOpUDiv; + mod_op = instruction->handler_idx == VKD3DSIH_IDIV ? SpvOpSRem : SpvOpUMod;
if (dst[0].reg.type != VKD3DSPR_NULL) { @@ -7039,7 +7036,7 @@ static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, 0xffffffff, component_count);
- val_id = vkd3d_spirv_build_op_udiv(builder, type_id, src0_id, src1_id); + val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, div_op, type_id, src0_id, src1_id); /* The SPIR-V spec says: "The resulting value is undefined if Operand 2 is 0." */ val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, uint_max_id);
@@ -7062,7 +7059,7 @@ static void spirv_compiler_emit_udiv(struct spirv_compiler *compiler, 0xffffffff, component_count); }
- val_id = vkd3d_spirv_build_op_umod(builder, type_id, src0_id, src1_id); + val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, mod_op, type_id, src0_id, src1_id); /* The SPIR-V spec says: "The resulting value is undefined if Operand 2 is 0." */ val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, uint_max_id);
@@ -9473,8 +9470,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_IMAD: spirv_compiler_emit_imad(compiler, instruction); break; + case VKD3DSIH_IDIV: case VKD3DSIH_UDIV: - spirv_compiler_emit_udiv(compiler, instruction); + spirv_compiler_emit_int_div(compiler, instruction); break; case VKD3DSIH_FTOI: spirv_compiler_emit_ftoi(compiler, instruction); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 17e306108..20773c349 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -346,6 +346,7 @@ enum vkd3d_shader_opcode VKD3DSIH_HS_JOIN_PHASE, VKD3DSIH_IADD, VKD3DSIH_IBFE, + VKD3DSIH_IDIV, VKD3DSIH_IEQ, VKD3DSIH_IF, VKD3DSIH_IFC,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index d9e11c82d..4fb0d1bd6 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9465,6 +9465,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, spirv_compiler_emit_sincos(compiler, instruction); break; case VKD3DSIH_IMUL: + case VKD3DSIH_UMUL: spirv_compiler_emit_imul(compiler, instruction); break; case VKD3DSIH_IMAD:
From: Conor McCarthy cmccarthy@codeweavers.com
The DXIL parser uses unsigned types even if the source code uses signed, so unsigned values may be negated. --- libs/vkd3d-shader/spirv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 4fb0d1bd6..d48ac7999 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -3865,7 +3865,7 @@ static uint32_t spirv_compiler_emit_neg(struct spirv_compiler *compiler, type_id = spirv_compiler_get_type_id_for_reg(compiler, reg, write_mask); if (reg->data_type == VKD3D_DATA_FLOAT || reg->data_type == VKD3D_DATA_DOUBLE) return vkd3d_spirv_build_op_fnegate(builder, type_id, val_id); - else if (reg->data_type == VKD3D_DATA_INT) + else if (reg->data_type == VKD3D_DATA_INT || reg->data_type == VKD3D_DATA_UINT) return vkd3d_spirv_build_op_snegate(builder, type_id, val_id);
FIXME("Unhandled data type %#x.\n", reg->data_type);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 221 ++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + .../hlsl/arithmetic-float-uniform.shader_test | 14 +- tests/hlsl/cbuffer.shader_test | 6 +- tests/hlsl/const.shader_test | 2 +- tests/hlsl/cross.shader_test | 4 +- tests/hlsl/dot.shader_test | 2 +- tests/hlsl/expr-indexing.shader_test | 2 +- tests/hlsl/lerp.shader_test | 2 +- tests/hlsl/loop.shader_test | 10 +- tests/hlsl/math.shader_test | 2 +- tests/hlsl/object-references.shader_test | 2 +- tests/hlsl/reflect.shader_test | 2 +- tests/hlsl/writemask-assignop-0.shader_test | 2 +- tests/hlsl/writemask-assignop-1.shader_test | 2 +- 15 files changed, 249 insertions(+), 25 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 86e12afe5..63c58db72 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -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_1wil(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; @@ -2636,6 +2680,180 @@ static struct sm6_block *sm6_block_create() return block; }
+static enum vkd3d_shader_opcode sm6_parser_decode_binary_op(struct sm6_parser *sm6, + uint64_t code, const struct sm6_type *type_a, const struct sm6_type *type_b) +{ + bool is_bool = sm6_type_is_bool(type_a); + bool is_int = sm6_type_is_1wil(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: + 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 = sm6_parser_decode_binary_op(sm6, code, a->type, b->type)) == 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); + } + + 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); + dst_params[index ^ 1].reg.type = VKD3DSPR_NULL; + 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) { @@ -3235,6 +3453,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; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 20773c349..045575c8e 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -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, diff --git a/tests/hlsl/arithmetic-float-uniform.shader_test b/tests/hlsl/arithmetic-float-uniform.shader_test index 8aaca621a..4812d053a 100644 --- a/tests/hlsl/arithmetic-float-uniform.shader_test +++ b/tests/hlsl/arithmetic-float-uniform.shader_test @@ -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) diff --git a/tests/hlsl/cbuffer.shader_test b/tests/hlsl/cbuffer.shader_test index dbb49ea7e..b4dc01edd 100644 --- a/tests/hlsl/cbuffer.shader_test +++ b/tests/hlsl/cbuffer.shader_test @@ -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)
diff --git a/tests/hlsl/const.shader_test b/tests/hlsl/const.shader_test index 17427c385..9541203dc 100644 --- a/tests/hlsl/const.shader_test +++ b/tests/hlsl/const.shader_test @@ -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)] diff --git a/tests/hlsl/cross.shader_test b/tests/hlsl/cross.shader_test index b84e2eaca..22f373a6d 100644 --- a/tests/hlsl/cross.shader_test +++ b/tests/hlsl/cross.shader_test @@ -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) diff --git a/tests/hlsl/dot.shader_test b/tests/hlsl/dot.shader_test index bb71919ce..c620e5fac 100644 --- a/tests/hlsl/dot.shader_test +++ b/tests/hlsl/dot.shader_test @@ -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] diff --git a/tests/hlsl/expr-indexing.shader_test b/tests/hlsl/expr-indexing.shader_test index 1c598816e..c11fa6540 100644 --- a/tests/hlsl/expr-indexing.shader_test +++ b/tests/hlsl/expr-indexing.shader_test @@ -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)
diff --git a/tests/hlsl/lerp.shader_test b/tests/hlsl/lerp.shader_test index 27c45fe7d..413bfe833 100644 --- a/tests/hlsl/lerp.shader_test +++ b/tests/hlsl/lerp.shader_test @@ -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] diff --git a/tests/hlsl/loop.shader_test b/tests/hlsl/loop.shader_test index c15e48798..35a303595 100644 --- a/tests/hlsl/loop.shader_test +++ b/tests/hlsl/loop.shader_test @@ -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 diff --git a/tests/hlsl/math.shader_test b/tests/hlsl/math.shader_test index 8f0592275..15f579331 100644 --- a/tests/hlsl/math.shader_test +++ b/tests/hlsl/math.shader_test @@ -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 diff --git a/tests/hlsl/object-references.shader_test b/tests/hlsl/object-references.shader_test index ff405559c..c857f3885 100644 --- a/tests/hlsl/object-references.shader_test +++ b/tests/hlsl/object-references.shader_test @@ -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)
diff --git a/tests/hlsl/reflect.shader_test b/tests/hlsl/reflect.shader_test index 808b4b772..25890086b 100644 --- a/tests/hlsl/reflect.shader_test +++ b/tests/hlsl/reflect.shader_test @@ -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] diff --git a/tests/hlsl/writemask-assignop-0.shader_test b/tests/hlsl/writemask-assignop-0.shader_test index fa8ecc2e4..374a38bb4 100644 --- a/tests/hlsl/writemask-assignop-0.shader_test +++ b/tests/hlsl/writemask-assignop-0.shader_test @@ -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 diff --git a/tests/hlsl/writemask-assignop-1.shader_test b/tests/hlsl/writemask-assignop-1.shader_test index 3bebcce61..61993257c 100644 --- a/tests/hlsl/writemask-assignop-1.shader_test +++ b/tests/hlsl/writemask-assignop-1.shader_test @@ -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)
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 1 + libs/vkd3d-shader/spirv.c | 10 ++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 12 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 63c58db72..467aae52a 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -1937,6 +1937,7 @@ static void register_init_ssa_vector(struct vkd3d_shader_register *reg, const st id = sm6_parser_alloc_ssa_id(sm6); data_type = vkd3d_data_type_from_sm6_type(sm6_type_get_scalar_type(type, 0)); register_init_with_id(reg, VKD3DSPR_SSA, data_type, id); + reg->u.ssa_data_type = data_type; reg->dimension = component_count > 1 ? VSIR_DIMENSION_VEC4 : VSIR_DIMENSION_SCALAR; }
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index d48ac7999..f540fda10 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -3751,6 +3751,7 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler unsigned int swizzle) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + enum vkd3d_shader_component_type reg_component_type; unsigned int component_idx; uint32_t type_id, val_id;
@@ -3759,7 +3760,16 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler assert(vkd3d_swizzle_is_scalar(swizzle));
if (reg->dimension == VSIR_DIMENSION_SCALAR) + { + reg_component_type = vkd3d_component_type_from_data_type(reg->u.ssa_data_type); + if (component_type != reg_component_type) + { + type_id = vkd3d_spirv_get_type_id(builder, component_type, 1); + val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id); + } + return val_id; + }
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1); component_idx = vkd3d_swizzle_get_component(swizzle, 0); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 045575c8e..07e92cadf 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -803,6 +803,7 @@ struct vkd3d_shader_register uint64_t immconst_uint64[VKD3D_DVEC2_SIZE]; double immconst_double[VKD3D_DVEC2_SIZE]; unsigned fp_body_idx; + enum vkd3d_data_type ssa_data_type; } u; };
From: Conor McCarthy cmccarthy@codeweavers.com
In DXIL, bool can be the subject of a logical op, or converted to an integer or float type. --- libs/vkd3d-shader/spirv.c | 111 ++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 107 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index f540fda10..9aa3fe1d0 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1150,6 +1150,20 @@ static uint32_t vkd3d_spirv_get_op_type_pointer(struct vkd3d_spirv_builder *buil vkd3d_spirv_build_op_type_pointer); }
+static uint32_t vkd3d_spirv_build_op_constant_bool(struct vkd3d_spirv_builder *builder, + uint32_t result_type, uint32_t value) +{ + return vkd3d_spirv_build_op_tr(builder, &builder->global_stream, + value ? SpvOpConstantTrue : SpvOpConstantFalse, result_type); +} + +static uint32_t vkd3d_spirv_get_op_constant_bool(struct vkd3d_spirv_builder *builder, + uint32_t result_type, uint32_t value) +{ + return vkd3d_spirv_build_once2(builder, value ? SpvOpConstantTrue : SpvOpConstantFalse, result_type, value, + vkd3d_spirv_build_op_constant_bool); +} + /* Types larger than 32-bits are not supported. */ static uint32_t vkd3d_spirv_build_op_constant(struct vkd3d_spirv_builder *builder, uint32_t result_type, uint32_t value) @@ -1802,6 +1816,8 @@ static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder break; case VKD3D_DATA_DOUBLE: return vkd3d_spirv_get_op_type_float(builder, 64); + case VKD3D_DATA_BOOL: + return vkd3d_spirv_get_op_type_bool(builder); default: FIXME("Unhandled data type %#x.\n", data_type); return 0; @@ -2880,6 +2896,13 @@ static uint32_t spirv_compiler_get_constant(struct spirv_compiler *compiler, case VKD3D_SHADER_COMPONENT_INT: case VKD3D_SHADER_COMPONENT_FLOAT: break; + case VKD3D_SHADER_COMPONENT_BOOL: + if (component_count == 1) + return vkd3d_spirv_get_op_constant_bool(builder, type_id, *values); + FIXME("Unsupported vector of bool.\n"); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_TYPE, + "Vectors of bool type are not supported."); + return vkd3d_spirv_get_op_undef(builder, type_id); default: FIXME("Unhandled component_type %#x.\n", component_type); return vkd3d_spirv_get_op_undef(builder, type_id); @@ -4212,17 +4235,41 @@ static uint32_t spirv_compiler_emit_int_to_bool(struct spirv_compiler *compiler, }
static uint32_t spirv_compiler_emit_bool_to_int(struct spirv_compiler *compiler, - unsigned int component_count, uint32_t val_id) + unsigned int component_count, uint32_t val_id, bool signedness) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t type_id, true_id, false_id;
- true_id = spirv_compiler_get_constant_uint_vector(compiler, 0xffffffff, component_count); + true_id = spirv_compiler_get_constant_uint_vector(compiler, signedness ? 0xffffffff : 1, component_count); false_id = spirv_compiler_get_constant_uint_vector(compiler, 0, component_count); type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, component_count); return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); }
+static uint32_t spirv_compiler_emit_bool_to_float(struct spirv_compiler *compiler, + unsigned int component_count, uint32_t val_id, bool signedness) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, true_id, false_id; + + true_id = spirv_compiler_get_constant_float_vector(compiler, signedness ? -1.0f : 1.0f, component_count); + false_id = spirv_compiler_get_constant_float_vector(compiler, 0.0f, component_count); + type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count); + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); +} + +static uint32_t spirv_compiler_emit_bool_to_double(struct spirv_compiler *compiler, + unsigned int component_count, uint32_t val_id, bool signedness) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, true_id, false_id; + + true_id = spirv_compiler_get_constant_double_vector(compiler, signedness ? -1.0 : 1.0, component_count); + false_id = spirv_compiler_get_constant_double_vector(compiler, 0.0, component_count); + type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_DOUBLE, component_count); + return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id); +} + typedef uint32_t (*vkd3d_spirv_builtin_fixup_pfn)(struct spirv_compiler *compiler, uint32_t val_id);
@@ -4265,7 +4312,7 @@ static uint32_t sv_instance_id_fixup(struct spirv_compiler *compiler, static uint32_t sv_front_face_fixup(struct spirv_compiler *compiler, uint32_t front_facing_id) { - return spirv_compiler_emit_bool_to_int(compiler, 1, front_facing_id); + return spirv_compiler_emit_bool_to_int(compiler, 1, front_facing_id, true); }
/* frag_coord.w = 1.0f / frag_coord.w */ @@ -6632,6 +6679,49 @@ static SpvOp spirv_compiler_map_alu_instruction(const struct vkd3d_shader_instru return SpvOpMax; }
+static SpvOp spirv_compiler_map_logical_instruction(const struct vkd3d_shader_instruction *instruction) +{ + switch (instruction->handler_idx) + { + case VKD3DSIH_AND: + return SpvOpLogicalAnd; + case VKD3DSIH_OR: + return SpvOpLogicalOr; + case VKD3DSIH_XOR: + return SpvOpLogicalNotEqual; + default: + return SpvOpMax; + } +} + +static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vkd3d_shader_src_param *src = instruction->src; + uint32_t val_id; + + 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) + { + val_id = spirv_compiler_emit_bool_to_float(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF); + } + else if (dst->reg.data_type == VKD3D_DATA_DOUBLE) + { + val_id = spirv_compiler_emit_bool_to_double(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOD); + } + else + { + WARN("Unhandled data type %u.\n", dst->reg.data_type); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_TYPE, + "Register data type %u is unhandled.", dst->reg.data_type); + } + + spirv_compiler_emit_store_dst(compiler, dst, val_id); +} + static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { @@ -6643,7 +6733,18 @@ static void spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, unsigned int i; SpvOp op;
- op = spirv_compiler_map_alu_instruction(instruction); + if (src->reg.data_type == VKD3D_DATA_BOOL) + { + if (dst->reg.data_type == VKD3D_DATA_BOOL) + op = spirv_compiler_map_logical_instruction(instruction); + else + return spirv_compiler_emit_bool_cast(compiler, instruction); + } + else + { + op = spirv_compiler_map_alu_instruction(instruction); + } + if (op == SpvOpMax) { ERR("Unexpected instruction %#x.\n", instruction->handler_idx); @@ -7318,7 +7419,7 @@ static void spirv_compiler_emit_comparison_instruction(struct spirv_compiler *co result_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, type_id, src0_id, src1_id);
- result_id = spirv_compiler_emit_bool_to_int(compiler, component_count, result_id); + result_id = spirv_compiler_emit_bool_to_int(compiler, component_count, result_id, true); spirv_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, result_id); }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 07e92cadf..efd65bcd1 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -93,6 +93,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED = 2003, VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED = 2004, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY = 2005, + VKD3D_SHADER_ERROR_SPV_INVALID_TYPE = 2006,
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300,
From: Conor McCarthy cmccarthy@codeweavers.com
ITOI and UTOU may cast from a bool to a 32-bit integer. Cast to a 64-bit integer from a smaller type will be added later. --- libs/vkd3d-shader/d3d_asm.c | 2 ++ libs/vkd3d-shader/spirv.c | 6 ++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 2 ++ 3 files changed, 10 insertions(+)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 645d99836..97a1c098e 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -199,6 +199,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_ISHR ] = "ishr", [VKD3DSIH_ITOD ] = "itod", [VKD3DSIH_ITOF ] = "itof", + [VKD3DSIH_ITOI ] = "itoi", [VKD3DSIH_LABEL ] = "label", [VKD3DSIH_LD ] = "ld", [VKD3DSIH_LD2DMS ] = "ld2dms", @@ -306,6 +307,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_USHR ] = "ushr", [VKD3DSIH_UTOD ] = "utod", [VKD3DSIH_UTOF ] = "utof", + [VKD3DSIH_UTOU ] = "utou", [VKD3DSIH_XOR ] = "xor", };
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 9aa3fe1d0..ef1a44fa9 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -6712,6 +6712,10 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, { val_id = spirv_compiler_emit_bool_to_double(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOD); } + else if (dst->reg.data_type == VKD3D_DATA_UINT) + { + val_id = spirv_compiler_emit_bool_to_int(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOI); + } else { WARN("Unhandled data type %u.\n", dst->reg.data_type); @@ -9530,12 +9534,14 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_ISHR: case VKD3DSIH_ITOD: case VKD3DSIH_ITOF: + case VKD3DSIH_ITOI: case VKD3DSIH_MUL: case VKD3DSIH_NOT: case VKD3DSIH_OR: case VKD3DSIH_USHR: case VKD3DSIH_UTOD: case VKD3DSIH_UTOF: + case VKD3DSIH_UTOU: case VKD3DSIH_XOR: spirv_compiler_emit_alu_instruction(compiler, instruction); break; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index efd65bcd1..5b660a7a2 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -376,6 +376,7 @@ enum vkd3d_shader_opcode VKD3DSIH_ISHR, VKD3DSIH_ITOD, VKD3DSIH_ITOF, + VKD3DSIH_ITOI, VKD3DSIH_LABEL, VKD3DSIH_LD, VKD3DSIH_LD2DMS, @@ -483,6 +484,7 @@ enum vkd3d_shader_opcode VKD3DSIH_USHR, VKD3DSIH_UTOD, VKD3DSIH_UTOF, + VKD3DSIH_UTOU, VKD3DSIH_XOR,
VKD3DSIH_INVALID,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index ef1a44fa9..36de470af 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2969,12 +2969,6 @@ static uint32_t spirv_compiler_get_constant_vector(struct spirv_compiler *compil return spirv_compiler_get_constant(compiler, component_type, component_count, values); }
-static uint32_t spirv_compiler_get_constant_int_vector(struct spirv_compiler *compiler, - uint32_t value, unsigned int component_count) -{ - return spirv_compiler_get_constant_vector(compiler, VKD3D_SHADER_COMPONENT_INT, component_count, value); -} - static uint32_t spirv_compiler_get_constant_uint_vector(struct spirv_compiler *compiler, uint32_t value, unsigned int component_count) { @@ -7190,6 +7184,7 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst = instruction->dst; const struct vkd3d_shader_src_param *src = instruction->src; uint32_t src_type_id, dst_type_id, condition_type_id; + enum vkd3d_shader_component_type component_type; unsigned int component_count;
assert(instruction->dst_count == 1); @@ -7207,8 +7202,11 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, int_min_id = spirv_compiler_get_constant_float_vector(compiler, -2147483648.0f, component_count); val_id = vkd3d_spirv_build_op_glsl_std450_max(builder, src_type_id, src_id, int_min_id);
+ /* DXIL uses unsigned int but requires a signed conversion. */ + component_type = vkd3d_component_type_from_data_type(dst->reg.data_type); + float_max_id = spirv_compiler_get_constant_float_vector(compiler, 2147483648.0f, component_count); - int_max_id = spirv_compiler_get_constant_int_vector(compiler, INT_MAX, component_count); + int_max_id = spirv_compiler_get_constant_vector(compiler, component_type, component_count, INT_MAX); condition_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count); condition_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, SpvOpFOrdGreaterThanEqual, condition_type_id, val_id, float_max_id); @@ -7216,7 +7214,7 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler, val_id = vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpConvertFToS, dst_type_id, val_id); val_id = vkd3d_spirv_build_op_select(builder, dst_type_id, condition_id, int_max_id, val_id);
- zero_id = spirv_compiler_get_constant_int_vector(compiler, 0, component_count); + zero_id = spirv_compiler_get_constant_vector(compiler, component_type, component_count, 0); condition_id = vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpIsNan, condition_type_id, src_id); val_id = vkd3d_spirv_build_op_select(builder, dst_type_id, condition_id, zero_id, val_id);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 172 ++++++++++++++++++ tests/hlsl/arithmetic-int-uniform.shader_test | 14 +- tests/hlsl/array-index-expr.shader_test | 16 +- tests/hlsl/asfloat.shader_test | 2 +- tests/hlsl/asuint.shader_test | 4 +- tests/hlsl/d3dcolor-to-ubyte4.shader_test | 4 +- tests/hlsl/function-cast.shader_test | 4 +- tests/hlsl/lerp.shader_test | 2 +- .../shader-interstage-interface.shader_test | 2 +- 9 files changed, 196 insertions(+), 24 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 467aae52a..1ee516a01 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -289,6 +289,23 @@ enum dx_intrinsic_opcode DX_CBUFFER_LOAD_LEGACY = 59, };
+enum dxil_cast_code +{ + CAST_TRUNC = 0, + CAST_ZEXT = 1, + CAST_SEXT = 2, + CAST_FPTOUI = 3, + CAST_FPTOSI = 4, + CAST_UITOFP = 5, + CAST_SITOFP = 6, + CAST_FPTRUNC = 7, + CAST_FPEXT = 8, + CAST_PTRTOINT = 9, + CAST_INTTOPTR = 10, + CAST_BITCAST = 11, + CAST_ADDRSPACECAST = 12, +}; + struct sm6_pointer_info { const struct sm6_type *type; @@ -3244,6 +3261,158 @@ static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_recor fn_value->u.function.name, &operands[1], operand_count - 1, ins, dst); }
+static enum vkd3d_shader_opcode sm6_map_cast_op(uint64_t code, const struct sm6_type *from, + const struct sm6_type *to, struct sm6_parser *sm6) +{ + enum vkd3d_shader_opcode op = VKD3DSIH_INVALID; + bool from_int, to_int; + bool is_valid = false; + + /* NOTE: DXIL currently doesn't use vectors here. */ + if (!sm6_type_is_scalar(from) || !sm6_type_is_scalar(to)) + { + FIXME("Unhandled non-scalar type class %u and/or %u.\n", from->class, to->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast of non-scalar types is not implemented."); + /* width is not available for non-scalar types so we can't attempt to compile it. */ + return VKD3DSIH_INVALID; + } + if (to->u.width == 8 || from->u.width == 8) + { + FIXME("Unhandled 8-bit value.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast to/from an 8-bit type is not implemented."); + return VKD3DSIH_INVALID; + } + + from_int = sm6_type_is_integer(from); + to_int = sm6_type_is_integer(to); + + /* DXC emits minimum precision types as 16-bit. These must be emitted + * as 32-bit in VSIR, so all width extensions to 32 bits are no-ops. */ + switch (code) + { + case CAST_TRUNC: + /* nop or min precision. TODO: native 16-bit */ + if (to->u.width == from->u.width || (to->u.width == 16 && from->u.width == 32)) + op = VKD3DSIH_NOP; + else + op = VKD3DSIH_UTOU; + is_valid = from_int && to_int && to->u.width <= from->u.width; + break; + case CAST_ZEXT: + case CAST_SEXT: + /* nop or min precision. TODO: native 16-bit */ + if (to->u.width == from->u.width || (to->u.width == 32 && from->u.width == 16)) + { + op = VKD3DSIH_NOP; + is_valid = from_int && to_int; + } + else if (to->u.width > from->u.width) + { + op = (code == CAST_ZEXT) ? VKD3DSIH_UTOU : VKD3DSIH_ITOI; + assert(from->u.width == 1 || to->u.width == 64); + is_valid = from_int && to_int; + } + break; + case CAST_FPTOUI: + op = (from->u.width == 64) ? VKD3DSIH_DTOU : VKD3DSIH_FTOU; + is_valid = !from_int && to_int && to->u.width > 1; + break; + case CAST_FPTOSI: + op = (from->u.width == 64) ? VKD3DSIH_DTOI : VKD3DSIH_FTOI; + is_valid = !from_int && to_int && to->u.width > 1; + break; + case CAST_UITOFP: + op = (to->u.width == 64) ? VKD3DSIH_UTOD : VKD3DSIH_UTOF; + is_valid = from_int && !to_int; + break; + case CAST_SITOFP: + op = (to->u.width == 64) ? VKD3DSIH_ITOD : VKD3DSIH_ITOF; + is_valid = from_int && !to_int; + break; + case CAST_FPTRUNC: + /* TODO: native 16-bit */ + op = (from->u.width == 64) ? VKD3DSIH_DTOF : VKD3DSIH_NOP; + is_valid = !from_int && !to_int; + break; + case CAST_FPEXT: + /* TODO: native 16-bit */ + op = (to->u.width == 64) ? VKD3DSIH_FTOD : VKD3DSIH_NOP; + is_valid = !from_int && !to_int; + break; + case CAST_BITCAST: + op = VKD3DSIH_MOV; + is_valid = to->u.width == from->u.width; + break; + default: + FIXME("Unhandled cast op %"PRIu64".\n", code); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast operation %"PRIu64" is unhandled.\n", code); + return VKD3DSIH_INVALID; + } + + if (!is_valid) + { + FIXME("Invalid types %u and/or %u for op %"PRIu64".\n", from->class, to->class, code); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Cast operation %"PRIu64" from type class %u, width %u to type class %u, width %u is invalid.\n", + code, from->class, from->u.width, to->class, to->u.width); + return VKD3DSIH_INVALID; + } + + return op; +} + +static void sm6_parser_emit_cast(struct sm6_parser *sm6, const struct dxil_record *record, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +{ + struct vkd3d_shader_src_param *src_param; + enum vkd3d_shader_opcode handler_idx; + const struct sm6_value *value; + const struct sm6_type *type; + unsigned int i = 0; + + if (!(value = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))) + return; + + if (!dxil_record_validate_operand_count(record, i + 2, i + 2, sm6)) + return; + + if (!(type = sm6_parser_get_type(sm6, record->operands[i++]))) + return; + + dst->type = type; + + if (sm6_type_is_pointer(type)) + { + *dst = *value; + dst->type = type; + ins->handler_idx = VKD3DSIH_NOP; + return; + } + + if ((handler_idx = sm6_map_cast_op(record->operands[i], value->type, type, sm6)) == VKD3DSIH_INVALID) + return; + + vsir_instruction_init(ins, &sm6->p.location, handler_idx); + + if (handler_idx == VKD3DSIH_NOP) + { + dst->u.reg = value->u.reg; + return; + } + + src_param = instruction_src_params_alloc(ins, 1, sm6); + src_param_init_from_value(src_param, value); + + instruction_dst_param_init_ssa_scalar(ins, sm6); + + /* bitcast */ + if (handler_idx == VKD3DSIH_MOV) + src_param->reg.data_type = dst->u.reg.data_type; +} + static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil_record *record, struct vkd3d_shader_instruction *ins, struct sm6_value *dst) { @@ -3460,6 +3629,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const case FUNC_CODE_INST_CALL: sm6_parser_emit_call(sm6, record, code_block, ins, dst); break; + case FUNC_CODE_INST_CAST: + sm6_parser_emit_cast(sm6, record, ins, dst); + break; case FUNC_CODE_INST_EXTRACTVAL: sm6_parser_emit_extractval(sm6, record, ins, dst); break; diff --git a/tests/hlsl/arithmetic-int-uniform.shader_test b/tests/hlsl/arithmetic-int-uniform.shader_test index 726a191a7..7f5cdaaa6 100644 --- a/tests/hlsl/arithmetic-int-uniform.shader_test +++ b/tests/hlsl/arithmetic-int-uniform.shader_test @@ -10,7 +10,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 5.0 16.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (21.0, -11.0, 80.0, 0.0)
[pixel shader] @@ -25,7 +25,7 @@ float4 main() : SV_TARGET
[test] uniform 0 float4 5.0 16.0 0.0 0.0 -todo(sm>=6) draw quad +draw quad probe all rgba (5.0, 5.0, -5.0, 3.0)
[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 (8.0, -8.0, -8.0, 8.0)
[pixel shader] @@ -55,7 +55,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)
[pixel shader] @@ -70,7 +70,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 (9.0, -9.0, -9.0, 9.0)
[pixel shader] @@ -85,7 +85,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] @@ -117,5 +117,5 @@ float4 main() : sv_target [test] uniform 0 float4 45.0 5.0 50.0 10.0 uniform 4 float4 3.0 8.0 2.0 5.0 -todo(sm>=6) draw quad +draw quad probe all rgba (9.0, 5.0, 1.0, 3.0) diff --git a/tests/hlsl/array-index-expr.shader_test b/tests/hlsl/array-index-expr.shader_test index b7d91ea09..0b45df927 100644 --- a/tests/hlsl/array-index-expr.shader_test +++ b/tests/hlsl/array-index-expr.shader_test @@ -12,17 +12,17 @@ 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 uniform 12 float4 0 0 0 0 -todo draw quad -todo probe all rgba (1.0, 2.0, 3.0, 4.0) +todo(sm<6) draw quad +todo(sm<6) probe all rgba (1.0, 2.0, 3.0, 4.0) uniform 12 float4 1 0 0 0 -todo draw quad -todo probe all rgba (5.0, 6.0, 7.0, 8.0) +todo(sm<6) draw quad +todo(sm<6) probe all rgba (5.0, 6.0, 7.0, 8.0) uniform 12 float4 0 1 0 0 -todo draw quad -todo probe all rgba (5.0, 6.0, 7.0, 8.0) +todo(sm<6) draw quad +todo(sm<6) probe all rgba (5.0, 6.0, 7.0, 8.0) uniform 12 float4 1 1 0 0 -todo draw quad -todo probe all rgba (9.0, 10.0, 11.0, 12.0) +todo(sm<6) draw quad +todo(sm<6) probe all rgba (9.0, 10.0, 11.0, 12.0)
[pixel shader] diff --git a/tests/hlsl/asfloat.shader_test b/tests/hlsl/asfloat.shader_test index f43f2fdff..2184c1869 100644 --- a/tests/hlsl/asfloat.shader_test +++ b/tests/hlsl/asfloat.shader_test @@ -20,7 +20,7 @@ float4 main() : sv_target
[test] uniform 0 float4 123.0 -2.0 456 0.01 -todo(sm>=6) draw quad +draw quad probe (320,240) rgba (123.0, -2.0, 456.0, 0.01)
[pixel shader] diff --git a/tests/hlsl/asuint.shader_test b/tests/hlsl/asuint.shader_test index 0a2e39e53..50b0895e9 100644 --- a/tests/hlsl/asuint.shader_test +++ b/tests/hlsl/asuint.shader_test @@ -20,7 +20,7 @@ float4 main() : sv_target
[test] uniform 0 uint4 123 0xc0000000 456 0x7fd69345 -todo(sm>=6) draw quad +draw quad probe (320,240) rgba (123.0, 3221225472.0, 456.0, 2144768896.0)
@@ -37,7 +37,7 @@ float4 main() : sv_target uniform 0 uint4 11 12 0 0 uniform 4 uint4 13 14 0 0 uniform 8 uint4 20 21 22 23 -todo(sm>=6) draw quad +draw quad probe (320,240) rgba (13.0, 21.0, 0.0, 0.0)
diff --git a/tests/hlsl/d3dcolor-to-ubyte4.shader_test b/tests/hlsl/d3dcolor-to-ubyte4.shader_test index 01b7f2f64..dca307cdb 100644 --- a/tests/hlsl/d3dcolor-to-ubyte4.shader_test +++ b/tests/hlsl/d3dcolor-to-ubyte4.shader_test @@ -11,7 +11,7 @@ float4 main() : sv_target
[test] uniform 0 float4 -0.5 6.5 7.5 3.4 -todo(sm>=6) draw quad +draw quad probe all rgba (1912.0, 1657.0, -127.0, 867.0) 1
[pixel shader] @@ -24,5 +24,5 @@ float4 main() : sv_target
[test] uniform 0 float4 -0.5 6.5 7.5 3.4 -todo(sm>=6) draw quad +draw quad probe all rgba (-127.0, -127.0, -127.0, -127.0) 1 diff --git a/tests/hlsl/function-cast.shader_test b/tests/hlsl/function-cast.shader_test index a2b9cf4f4..c92289863 100644 --- a/tests/hlsl/function-cast.shader_test +++ b/tests/hlsl/function-cast.shader_test @@ -18,7 +18,7 @@ float4 main() : sv_target
[test] uniform 0 float4 -1.9 -1.0 2.9 4.0 -todo draw quad +todo(sm<6) draw quad probe all rgba (-1.0, -1.0, 2.0, 4.0)
% As above, but cast "x" to float4 first. @@ -89,5 +89,5 @@ float4 main() : sv_target
[test] uniform 0 int4 -2 0 1 -3000000 -todo draw quad +todo(sm<6) draw quad probe all rgba (-1.0, 0.0, 1.0, -3000000.0) diff --git a/tests/hlsl/lerp.shader_test b/tests/hlsl/lerp.shader_test index 413bfe833..15e90cef9 100644 --- a/tests/hlsl/lerp.shader_test +++ b/tests/hlsl/lerp.shader_test @@ -32,7 +32,7 @@ float4 main() : SV_TARGET uniform 0 int4 2 3 4 0 uniform 4 int4 0 -10 10 1000000 uniform 8 int4 0 1 -1 1000000 -todo(sm>=6) draw quad +draw quad probe all rgba (2.0, -10.0, -2.0, 1e12)
diff --git a/tests/hlsl/shader-interstage-interface.shader_test b/tests/hlsl/shader-interstage-interface.shader_test index 271eb3bbe..584b88cf9 100644 --- a/tests/hlsl/shader-interstage-interface.shader_test +++ b/tests/hlsl/shader-interstage-interface.shader_test @@ -52,5 +52,5 @@ void main(float4 position : SV_Position, float2 t0 : TEXCOORD0, }
[test] -todo(sm>=6) draw triangle strip 4 +draw triangle strip 4 probe all rgba (10.0, 8.0, 7.0, 3.0)
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/vkd3d_shader_private.h:
uint64_t immconst_uint64[VKD3D_DVEC2_SIZE]; double immconst_double[VKD3D_DVEC2_SIZE]; unsigned fp_body_idx;
enum vkd3d_data_type ssa_data_type;
What's the difference with the `data_type` field?
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/spirv.c:
}
static uint32_t spirv_compiler_emit_bool_to_int(struct spirv_compiler *compiler,
unsigned int component_count, uint32_t val_id)
unsigned int component_count, uint32_t val_id, bool signedness)
`signedness` is always `true`, maybe it should be introduced once it's really used.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/spirv.c:
- }
+}
+static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
+{
- const struct vkd3d_shader_dst_param *dst = instruction->dst;
- const struct vkd3d_shader_src_param *src = instruction->src;
- uint32_t val_id;
- 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)
- {
val_id = spirv_compiler_emit_bool_to_float(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOF);
I'm quite confused, you mean that `itof` on bools is used to indicate that `true` must be mapped to `-1.0` and something else (maybe `utof`?) is used to indicate that `true` must be mapped to `1.0`? That looks like a very peculiar operation, that I wouldn't overload on `itof`. What's the alternative op expected here?
Also, is there anything already that generates `itof` on bools? If not, like it seems to me, than that should be introduced before adding this code, so it is not dead.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/spirv.c:
case VKD3D_SHADER_COMPONENT_INT: case VKD3D_SHADER_COMPONENT_FLOAT: break;
case VKD3D_SHADER_COMPONENT_BOOL:
This part feels like it should be a separate commit.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/spirv.c:
int_min_id = spirv_compiler_get_constant_float_vector(compiler, -2147483648.0f, component_count); val_id = vkd3d_spirv_build_op_glsl_std450_max(builder, src_type_id, src_id, int_min_id);
- /* DXIL uses unsigned int but requires a signed conversion. */
I'm not sure this is appropriate. This is the SPIR-V backend, and it should work independently of where the VSIR code it processes was generated. If DXIL confuses signed and unsigned data and VSIR does not, this mismatch should be resolved in the DXIL frontend, not here.
On Fri Nov 3 13:11:36 2023 +0000, Giovanni Mascellani wrote:
What's the difference with the `data_type` field?
`ssa_data_type` is the type of the value declared with this ssa id, while `data_type` in source registers is the required type of the register, which may be different from the declaration, i.e. we can force a bitcast by changing `data_type`. For other register types we use `spirv_compiler_get_register_info()` to get the declaration type.