From: Conor McCarthy cmccarthy@codeweavers.com
--- tests/hlsl/float-comparison.shader_test | 33 +++++++------------------ 1 file changed, 9 insertions(+), 24 deletions(-)
diff --git a/tests/hlsl/float-comparison.shader_test b/tests/hlsl/float-comparison.shader_test index b66543443..d3f2ebf07 100644 --- a/tests/hlsl/float-comparison.shader_test +++ b/tests/hlsl/float-comparison.shader_test @@ -32,41 +32,26 @@ float4 main() : sv_target result.z += (n != f.y) ? 100000.0 : 0.0; result.z += !(n == f.y) ? 1000000.0 : 0.0; result.z += !(n != f.y) ? 10000000.0 : 0.0; - /* It doesn't seem possible to generate DXIL instructions for 'is ordered' or 'is unordered'. - * Expressions 'isnan(n)' and '(isnan(n) || isnan(f.x))' compile into intrinsics. */ - result.w = 0; + // These compile to FCMP_ORD, but prepending a ! does not result in FCMP_UNO + result.w = (f.y < f.x || f.y >= f.x) ? 1.0 : 0.0; + result.w += (n < f.x || n >= f.x) ? 10.0 : 0.0; return result; }
-% SM1-3 apparently treats '0/0' as zero. -[require] -shader model < 4.0 - [test] uniform 0 float4 0.0 1.5 1.5 0.0 -todo(sm<4) draw quad -todo probe all rgba (1010101.0, 11001100.0, 1101001.0, 0.0) - +todo(sm<4 | sm>=6) draw quad +% SM1-3 apparently treats '0/0' as zero. +if(sm<4) todo probe all rgba (1010101.0, 11001100.0, 1101001.0, 1.0) % SM4-5 optimises away the 'not' by inverting the condition, even though this is invalid for NaN. -[require] -shader model >= 4.0 -shader model < 6.0 +if(sm>=4 & sm<6) todo probe all rgba (1010101.0, 0.0, 1101001.0, 1.0) +% SM6 emits the correct ordered/unordered instructions, so comparisons are false for NaN, and are made true with 'not'. +if(sm>=6) probe all rgba (1010101.0, 11110000.0, 1101001.0, 1.0)
-[test] -uniform 0 float4 0.0 1.5 1.5 0.0 -draw quad -todo probe all rgba (1010101.0, 0.0, 1101001.0, 0.0)
-% SM6 emits the correct ordered/unordered instructions, so comparisons are false for NaN, and are made true with 'not'. [require] shader model >= 6.0
-[test] -uniform 0 float4 0.0 1.5 1.5 0.0 -draw quad -probe all rgba (1010101.0, 11110000.0, 1101001.0, 0.0) - - [pixel shader] uniform float4 f;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 2 ++ libs/vkd3d-shader/dxil.c | 4 ++-- libs/vkd3d-shader/vkd3d_shader_private.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 3f86bd459..a65311e98 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -250,6 +250,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_NOT ] = "not", [VKD3DSIH_NRM ] = "nrm", [VKD3DSIH_OR ] = "or", + [VKD3DSIH_ORD ] = "ord", [VKD3DSIH_PHASE ] = "phase", [VKD3DSIH_PHI ] = "phi", [VKD3DSIH_POW ] = "pow", @@ -321,6 +322,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_UMAX ] = "umax", [VKD3DSIH_UMIN ] = "umin", [VKD3DSIH_UMUL ] = "umul", + [VKD3DSIH_UNO ] = "uno", [VKD3DSIH_USHR ] = "ushr", [VKD3DSIH_UTOD ] = "utod", [VKD3DSIH_UTOF ] = "utof", diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 26a8a5c1c..a202d208f 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -5187,8 +5187,8 @@ static const struct sm6_cmp_info *sm6_map_cmp2_op(uint64_t code) [FCMP_OLT] = {VKD3DSIH_LTO}, [FCMP_OLE] = {VKD3DSIH_GEO, true}, [FCMP_ONE] = {VKD3DSIH_NEO}, - [FCMP_ORD] = {VKD3DSIH_INVALID}, - [FCMP_UNO] = {VKD3DSIH_INVALID}, + [FCMP_ORD] = {VKD3DSIH_ORD}, + [FCMP_UNO] = {VKD3DSIH_UNO}, [FCMP_UEQ] = {VKD3DSIH_EQU}, [FCMP_UGT] = {VKD3DSIH_LTU, true}, [FCMP_UGE] = {VKD3DSIH_GEU}, diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 4b322b95b..43e22cba3 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -445,6 +445,7 @@ enum vkd3d_shader_opcode VKD3DSIH_NOT, VKD3DSIH_NRM, VKD3DSIH_OR, + VKD3DSIH_ORD, VKD3DSIH_PHASE, VKD3DSIH_PHI, VKD3DSIH_POW, @@ -516,6 +517,7 @@ enum vkd3d_shader_opcode VKD3DSIH_UMAX, VKD3DSIH_UMIN, VKD3DSIH_UMUL, + VKD3DSIH_UNO, VKD3DSIH_USHR, VKD3DSIH_UTOD, VKD3DSIH_UTOF,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 38 +++++++++++++++++++++++++ tests/hlsl/float-comparison.shader_test | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index a3baeea75..a1cfebf59 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1524,6 +1524,19 @@ static uint32_t vkd3d_spirv_build_op_logical_equal(struct vkd3d_spirv_builder *b SpvOpLogicalEqual, result_type, operand0, operand1); }
+static uint32_t vkd3d_spirv_build_op_logical_or(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, + SpvOpLogicalOr, result_type, operand0, operand1); +} + +static uint32_t vkd3d_spirv_build_op_logical_not(struct vkd3d_spirv_builder *builder, + uint32_t result_type, uint32_t operand) +{ + return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpLogicalNot, result_type, operand); +} + static uint32_t vkd3d_spirv_build_op_convert_utof(struct vkd3d_spirv_builder *builder, uint32_t result_type, uint32_t unsigned_value) { @@ -7684,6 +7697,27 @@ static void spirv_compiler_emit_comparison_instruction(struct spirv_compiler *co spirv_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, result_id); }
+static void spirv_compiler_emit_orderedness_instruction(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_dst_param *dst = instruction->dst; + const struct vkd3d_shader_src_param *src = instruction->src; + uint32_t type_id, src0_id, src1_id, val_id; + + type_id = spirv_compiler_get_type_id_for_dst(compiler, dst); + src0_id = spirv_compiler_emit_load_src(compiler, &src[0], dst->write_mask); + src1_id = spirv_compiler_emit_load_src(compiler, &src[1], dst->write_mask); + /* OpOrdered and OpUnordered are only available in Kernel mode, and the definition of + * OpOrdered differs from that of LLVM FCMP_ORD (no NaNs). */ + src0_id = vkd3d_spirv_build_op_is_nan(builder, type_id, src0_id); + src1_id = vkd3d_spirv_build_op_is_nan(builder, type_id, src1_id); + val_id = vkd3d_spirv_build_op_logical_or(builder, type_id, src0_id, src1_id); + if (instruction->handler_idx == VKD3DSIH_ORD) + val_id = vkd3d_spirv_build_op_logical_not(builder, type_id, val_id); + spirv_compiler_emit_store_dst(compiler, dst, val_id); +} + static uint32_t spirv_compiler_emit_conditional_branch(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction, uint32_t target_block_id) { @@ -9669,6 +9703,10 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_ULT: spirv_compiler_emit_comparison_instruction(compiler, instruction); break; + case VKD3DSIH_ORD: + case VKD3DSIH_UNO: + spirv_compiler_emit_orderedness_instruction(compiler, instruction); + break; case VKD3DSIH_BFI: case VKD3DSIH_IBFE: case VKD3DSIH_UBFE: diff --git a/tests/hlsl/float-comparison.shader_test b/tests/hlsl/float-comparison.shader_test index d3f2ebf07..b6c1395c6 100644 --- a/tests/hlsl/float-comparison.shader_test +++ b/tests/hlsl/float-comparison.shader_test @@ -40,7 +40,7 @@ float4 main() : sv_target
[test] uniform 0 float4 0.0 1.5 1.5 0.0 -todo(sm<4 | sm>=6) draw quad +todo(sm<4) draw quad % SM1-3 apparently treats '0/0' as zero. if(sm<4) todo probe all rgba (1010101.0, 11001100.0, 1101001.0, 1.0) % SM4-5 optimises away the 'not' by inverting the condition, even though this is invalid for NaN.