Fix GL_MAX_FRAGMENT_INTERPOLATION_OFFSET limit check
authorShahbaz Youssefi <syoussefi@google.com>
Fri, 27 Aug 2021 03:11:56 +0000 (23:11 -0400)
committerMatthew Netsch <quic_mnetsch@quicinc.com>
Fri, 24 Sep 2021 19:55:17 +0000 (19:55 +0000)
The spec is fixed to align with Vulkan, requiring the minimum value for
GL_MAX_FRAGMENT_INTERPOLATION_OFFSET to be 0.5-ULP, where

    ULP = 1/pow(2,GL_FRAGMENT_INTERPOLATION_OFFSET_BITS)

Affects:
dEQP-GL45.functional.state_query.multisample_interpolation.max_fragment_interpolation_offset.get_float
dEQP-GLES31.functional.state_query.multisample_interpolation.max_fragment_interpolation_offset.get_float
KHR-GL44.shader_multisample_interpolation.api.api
KHR-GL45.shader_multisample_interpolation.api.api
KHR-GL46.shader_multisample_interpolation.api.api
KHR-GLES31.core.shader_multisample_interpolation.api.api
KHR-GL45.limits.max_fragment_interpolation_offset
KHR-GL46.limits.max_fragment_interpolation_offset

Components: OpenGL
Khronos OpenGL issue: #149

Change-Id: I153a05ef6db8f50a6aa337188e5aeb8d504fbbdd

external/openglcts/modules/common/glcLimitTest.hpp
external/openglcts/modules/common/glcLimitTest.inl
external/openglcts/modules/common/glcShaderMultisampleInterpolationTests.cpp
modules/gles31/functional/es31fShaderMultisampleInterpolationStateQueryTests.cpp

index ef2a059..9297431 100644 (file)
@@ -42,15 +42,15 @@ template <typename DataType>
 class LimitCase : public deqp::TestCase
 {
 public:
-       LimitCase(deqp::Context& context, const char* caseName, deUint32 limitToken, DataType limitBoundry,
-                         bool isBoundryMaximum, const char* glslVersion = "", const char* glslBuiltin = "",
+       LimitCase(deqp::Context& context, const char* caseName, deUint32 limitToken, DataType limitBoundary,
+                         bool isBoundaryMaximum, const char* glslVersion = "", const char* glslBuiltin = "",
                          const char* glslExtension = "");
        virtual ~LimitCase(void);
 
        tcu::TestNode::IterateResult iterate(void);
 
 protected:
-       bool isWithinBoundry(DataType value, bool isBuiltin = false) const;
+       bool isWithinBoundary(DataType value, bool isBuiltin = false) const;
        std::string createShader() const;
 
        // those functions require specialization for some data types
@@ -64,9 +64,11 @@ private:
        LimitCase(const LimitCase&);                    // not allowed!
        LimitCase& operator=(const LimitCase&); // not allowed!
 
+       void adjustBoundaryForMaxFragmentInterpolationOffset();
+
        deUint32                  m_limitToken;
-       DataType                  m_limitBoundry; // min/max value
-       bool                      m_isBoundryMaximum;
+       DataType                  m_limitBoundary; // min/max value
+       bool                      m_isBoundaryMaximum;
        const std::string m_glslVersion;
        const std::string m_glslBuiltin;
        const std::string m_glslExtension;
index 404c4ba..8c346a9 100644 (file)
@@ -27,19 +27,22 @@ template<typename DataType>
 LimitCase<DataType>::LimitCase(deqp::Context& context,
                                                           const char* caseName,
                                                           deUint32 limitToken,
-                                                          DataType limitBoundry,
-                                                          bool isBoundryMaximum,
+                                                          DataType limitBoundary,
+                                                          bool isBoundaryMaximum,
                                                           const char* glslVersion,
                                                           const char* glslBuiltin,
                                                           const char* glslExtension)
        : deqp::TestCase(context, caseName, "Token limit validation.")
        , m_limitToken(limitToken)
-       , m_limitBoundry(limitBoundry)
-       , m_isBoundryMaximum(isBoundryMaximum)
+       , m_limitBoundary(limitBoundary)
+       , m_isBoundaryMaximum(isBoundaryMaximum)
        , m_glslVersion(glslVersion)
        , m_glslBuiltin(glslBuiltin)
        , m_glslExtension(glslExtension)
 {
+       // GL_MAX_FRAGMENT_INTERPOLATION_OFFSET is special in that its limit is dependent on
+       // GL_FRAGMENT_INTERPOLATION_OFFSET_BITS.  Adjust the limit automatically here.
+       adjustBoundaryForMaxFragmentInterpolationOffset();
 }
 
 template<typename DataType>
@@ -48,6 +51,27 @@ LimitCase<DataType>::~LimitCase(void)
 }
 
 template<typename DataType>
+void LimitCase<DataType>::adjustBoundaryForMaxFragmentInterpolationOffset()
+{
+}
+
+template<>
+void LimitCase<GLfloat>::adjustBoundaryForMaxFragmentInterpolationOffset()
+{
+       if (m_limitToken == GL_MAX_FRAGMENT_INTERPOLATION_OFFSET)
+       {
+               const Functions& gl = m_context.getRenderContext().getFunctions();
+
+               GLfloat fragmentInterpolationOffsetBits = 0;
+               gl.getFloatv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, &fragmentInterpolationOffsetBits);
+               GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
+
+               GLfloat ULP = 1.0f / powf(2, fragmentInterpolationOffsetBits);
+               m_limitBoundary -= ULP;
+       }
+}
+
+template<typename DataType>
 tcu::TestNode::IterateResult LimitCase<DataType>::iterate(void)
 {
        DataType limitValue = DataType();
@@ -59,9 +83,9 @@ tcu::TestNode::IterateResult LimitCase<DataType>::iterate(void)
        // check if limit was specified
        if (m_limitToken)
        {
-               // check if limit is not smaller or greater then boundry defined in specification
+               // check if limit is not smaller or greater then boundary defined in specification
                limitValue = getLimitValue(gl);
-               if (!isWithinBoundry(limitValue))
+               if (!isWithinBoundary(limitValue))
                {
                        m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
                        return STOP;
@@ -134,15 +158,15 @@ tcu::TestNode::IterateResult LimitCase<DataType>::iterate(void)
                        m_testCtx.getLog() << tcu::TestLog::Message
                                                           << "Shader builtin has value: "
                                                           << builtinValue
-                                                          << " which is different then the value of corresponding limit: "
+                                                          << " which is different from the value of corresponding limit: "
                                                           << limitValue
                                                           << tcu::TestLog::EndMessage;
                }
        }
        else
        {
-               // limit token was not specified - compare builtin to the boundry
-               if (isWithinBoundry(builtinValue, true))
+               // limit token was not specified - compare builtin to the boundary
+               if (isWithinBoundary(builtinValue, true))
                {
                        m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
                }
@@ -152,7 +176,7 @@ tcu::TestNode::IterateResult LimitCase<DataType>::iterate(void)
                        m_testCtx.getLog() << tcu::TestLog::Message
                                                           << "Shader builtin value is: "
                                                           << builtinValue
-                                                          << " which is outside of specified boundry."
+                                                          << " which is outside of specified boundary."
                                                           << tcu::TestLog::EndMessage;
                }
        }
@@ -161,34 +185,34 @@ tcu::TestNode::IterateResult LimitCase<DataType>::iterate(void)
 }
 
 template<typename DataType>
-bool LimitCase<DataType>::isWithinBoundry(DataType value, bool isBuiltin) const
+bool LimitCase<DataType>::isWithinBoundary(DataType value, bool isBuiltin) const
 {
-       if (m_isBoundryMaximum)
+       if (m_isBoundaryMaximum)
        {
-               // value should be smaller or euqual to boundry
-               if (isGreater(value, m_limitBoundry))
+               // value should be smaller or euqual to boundary
+               if (isGreater(value, m_limitBoundary))
                {
                        m_testCtx.getLog() << tcu::TestLog::Message
                                                           << (isBuiltin ? "Builtin" : "Limit")
                                                           << " value is: "
                                                           << value
                                                           << " when it should not be greater than "
-                                                          << m_limitBoundry
+                                                          << m_limitBoundary
                                                           << tcu::TestLog::EndMessage;
                        return false;
                }
        }
        else
        {
-               // value should be greater or euqual to boundry
-               if (isSmaller(value, m_limitBoundry))
+               // value should be greater or euqual to boundary
+               if (isSmaller(value, m_limitBoundary))
                {
                        m_testCtx.getLog() << tcu::TestLog::Message
                                                           << (isBuiltin ? "Builtin" : "Limit")
                                                           << " value is: "
                                                           << value
                                                           << "when it should not be smaller than "
-                                                          << m_limitBoundry
+                                                          << m_limitBoundary
                                                           << tcu::TestLog::EndMessage;
                        return false;
                }
index 2b56a34..79c257b 100644 (file)
@@ -190,16 +190,17 @@ ShaderMultisampleInterpolationApiCase::IterateResult ShaderMultisampleInterpolat
                isOk = false;
        }
 
-       GLfloat maxFragmentInterpolationOffset = 0.0f;
-       gl.getFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, &maxFragmentInterpolationOffset);
-       if (maxFragmentInterpolationOffset < 0.5f)
+       GLint fragmentInterpolationOffsetBits = 0;
+       gl.getIntegerv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, &fragmentInterpolationOffsetBits);
+       if (fragmentInterpolationOffsetBits < 4)
        {
                isOk = false;
        }
+       GLfloat ULP = 1.0f / powf(2, static_cast<float>(fragmentInterpolationOffsetBits));
 
-       GLint fragmentInterpolationOffsetBits = 0;
-       gl.getIntegerv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, &fragmentInterpolationOffsetBits);
-       if (fragmentInterpolationOffsetBits < 4)
+       GLfloat maxFragmentInterpolationOffset = 0.0f;
+       gl.getFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, &maxFragmentInterpolationOffset);
+       if (maxFragmentInterpolationOffset < 0.5f - ULP)
        {
                isOk = false;
        }
index 8303795..da97fa8 100644 (file)
@@ -93,9 +93,17 @@ InterpolationOffsetCase::IterateResult InterpolationOffsetCase::iterate (void)
        gl.enableLogging(true);
 
        if (m_testType == TEST_MAX_OFFSET)
-               verifyStateFloatMin(result, gl, GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, 0.5, m_verifier);
+       {
+               glw::GLfloat fragmentInterpolationOffsetBits = 0.0;
+               gl.glGetFloatv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, &fragmentInterpolationOffsetBits);
+               GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetIntegerv");
+
+               glw::GLfloat ULP = 1.0f / powf(2, fragmentInterpolationOffsetBits);
+
+               verifyStateFloatMin(result, gl, GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, 0.5f-ULP, m_verifier);
+       }
        else if (m_testType == TEST_MIN_OFFSET)
-               verifyStateFloatMax(result, gl, GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, -0.5, m_verifier);
+               verifyStateFloatMax(result, gl, GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, -0.5f, m_verifier);
        else
                DE_ASSERT(false);