From 4e57f9d5cfc32b37fe7b6a1563ca2101ec59887c Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 9 May 2020 04:55:15 -0300 Subject: shader_ir: Separate float-point comparisons in ordered and unordered This allows us to use native SPIR-V instructions without having to manually check for NAN. --- .../renderer_opengl/gl_shader_decompiler.cpp | 99 ++++++++++++---------- 1 file changed, 55 insertions(+), 44 deletions(-) (limited to 'src/video_core/renderer_opengl/gl_shader_decompiler.cpp') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 99fd4ae2c..d071abd84 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1840,34 +1840,31 @@ private: Type::HalfFloat}; } - template - Expression LogicalLessThan(Operation operation) { - return GenerateBinaryInfix(operation, "<", Type::Bool, type, type); - } - - template - Expression LogicalEqual(Operation operation) { - return GenerateBinaryInfix(operation, "==", Type::Bool, type, type); - } + template + Expression Comparison(Operation operation) { + static_assert(!unordered || type == Type::Float); - template - Expression LogicalLessEqual(Operation operation) { - return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type); - } - - template - Expression LogicalGreaterThan(Operation operation) { - return GenerateBinaryInfix(operation, ">", Type::Bool, type, type); + const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type); + if constexpr (!unordered) { + return expr; + } + // Unordered comparisons are always true for NaN operands. + return {fmt::format("({} || isnan({}) || isnan({}))", expr.AsBool(), + VisitOperand(operation, 0).AsFloat(), + VisitOperand(operation, 1).AsFloat()), + Type::Bool}; } - template - Expression LogicalNotEqual(Operation operation) { - return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type); + Expression FOrdered(Operation operation) { + return {fmt::format("(!isnan({}) && !isnan({}))", VisitOperand(operation, 0).AsFloat(), + VisitOperand(operation, 1).AsFloat()), + Type::Bool}; } - template - Expression LogicalGreaterEqual(Operation operation) { - return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); + Expression FUnordered(Operation operation) { + return {fmt::format("(isnan({}) || isnan({}))", VisitOperand(operation, 0).AsFloat(), + VisitOperand(operation, 1).AsFloat()), + Type::Bool}; } Expression LogicalAddCarry(Operation operation) { @@ -2324,6 +2321,13 @@ private: Func() = delete; ~Func() = delete; + static constexpr std::string_view LessThan = "<"; + static constexpr std::string_view Equal = "=="; + static constexpr std::string_view LessEqual = "<="; + static constexpr std::string_view GreaterThan = ">"; + static constexpr std::string_view NotEqual = "!="; + static constexpr std::string_view GreaterEqual = ">="; + static constexpr std::string_view Add = "Add"; static constexpr std::string_view Min = "Min"; static constexpr std::string_view Max = "Max"; @@ -2425,27 +2429,34 @@ private: &GLSLDecompiler::LogicalPick2, &GLSLDecompiler::LogicalAnd2, - &GLSLDecompiler::LogicalLessThan, - &GLSLDecompiler::LogicalEqual, - &GLSLDecompiler::LogicalLessEqual, - &GLSLDecompiler::LogicalGreaterThan, - &GLSLDecompiler::LogicalNotEqual, - &GLSLDecompiler::LogicalGreaterEqual, - &GLSLDecompiler::LogicalFIsNan, - - &GLSLDecompiler::LogicalLessThan, - &GLSLDecompiler::LogicalEqual, - &GLSLDecompiler::LogicalLessEqual, - &GLSLDecompiler::LogicalGreaterThan, - &GLSLDecompiler::LogicalNotEqual, - &GLSLDecompiler::LogicalGreaterEqual, - - &GLSLDecompiler::LogicalLessThan, - &GLSLDecompiler::LogicalEqual, - &GLSLDecompiler::LogicalLessEqual, - &GLSLDecompiler::LogicalGreaterThan, - &GLSLDecompiler::LogicalNotEqual, - &GLSLDecompiler::LogicalGreaterEqual, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::FOrdered, + &GLSLDecompiler::FUnordered, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, + &GLSLDecompiler::Comparison, &GLSLDecompiler::LogicalAddCarry, -- cgit v1.2.3 From 8b329ddcc9b39353b9545289b3bd653a77db0103 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 9 May 2020 04:56:50 -0300 Subject: gl_shader_decompiler: Properly emulate NaN behaviour on NE "Not equal" operators on GLSL seem to behave as unordered when we expect an ordered comparison. Manually emulate this checking for LGE values (numbers, not-NaNs). --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/video_core/renderer_opengl/gl_shader_decompiler.cpp') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index d071abd84..960ebf1a1 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1845,6 +1845,15 @@ private: static_assert(!unordered || type == Type::Float); const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type); + + if constexpr (op.compare("!=") == 0 && type == Type::Float && !unordered) { + // GLSL's operator!=(float, float) doesn't seem be ordered. This happens on both AMD's + // and Nvidia's proprietary stacks. Manually force an ordered comparison. + return {fmt::format("({} && !isnan({}) && !isnan({}))", expr.AsBool(), + VisitOperand(operation, 0).AsFloat(), + VisitOperand(operation, 1).AsFloat()), + Type::Bool}; + } if constexpr (!unordered) { return expr; } -- cgit v1.2.3