/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 2.0 Module * ------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Float State Query tests. *//*--------------------------------------------------------------------*/ #include "es2fFloatStateQueryTests.hpp" #include "glsStateQueryUtil.hpp" #include "es2fApiCase.hpp" #include "gluRenderContext.hpp" #include "tcuRenderTarget.hpp" #include "tcuFormatUtil.hpp" #include "deRandom.hpp" #include "deMath.h" #include "glwEnums.hpp" #include <limits> using namespace glw; // GLint and other GL types using namespace deqp::gls; using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard; namespace deqp { namespace gles2 { namespace Functional { namespace FloatStateQueryVerifiers { namespace { const int FLOAT_EXPANSION_E = 0x03FF; // 10 bits error allowed, requires 22 accurate bits const int FLOAT_EXPANSION_E_64 = 0x07FF; GLint64 expandGLFloatToInteger (GLfloat f) { const GLuint64 referenceValue = (GLint64)((f * double(0xFFFFFFFFULL) - 1) / 2); return referenceValue; } GLint clampToGLint (GLint64 val) { return (GLint)de::clamp<GLint64>(val, std::numeric_limits<GLint>::min(), std::numeric_limits<GLint>::max()); } } // anonymous // StateVerifier class StateVerifier : protected glu::CallLogWrapper { public: StateVerifier (const glw::Functions& gl, tcu::TestLog& log, const char* testNamePostfix); virtual ~StateVerifier (); // make GCC happy const char* getTestNamePostfix (void) const; virtual void verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference) = DE_NULL; // "Expanded" == Float to int conversion converts from [-1.0 to 1.0] -> [MIN_INT MAX_INT] virtual void verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference) = DE_NULL; virtual void verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1) = DE_NULL; virtual void verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3) = DE_NULL; // verify that the given range is completely whitin the GL state range virtual void verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max) = DE_NULL; private: const char* const m_testNamePostfix; }; StateVerifier::StateVerifier (const glw::Functions& gl, tcu::TestLog& log, const char* testNamePostfix) : glu::CallLogWrapper (gl, log) , m_testNamePostfix (testNamePostfix) { enableLogging(true); } StateVerifier::~StateVerifier () { } const char* StateVerifier::getTestNamePostfix (void) const { return m_testNamePostfix; } // GetBooleanVerifier class GetBooleanVerifier : public StateVerifier { public: GetBooleanVerifier (const glw::Functions& gl, tcu::TestLog& log); void verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1); void verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3); void verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max); }; GetBooleanVerifier::GetBooleanVerifier (const glw::Functions& gl, tcu::TestLog& log) : StateVerifier(gl, log, "_getboolean") { } void GetBooleanVerifier::verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { using tcu::TestLog; StateQueryMemoryWriteGuard<GLboolean> state; glGetBooleanv(name, &state); if (!state.verifyValidity(testCtx)) return; const GLboolean expectedGLState = reference != 0.0f ? GL_TRUE : GL_FALSE; if (state != expectedGLState) { testCtx.getLog() << TestLog::Message << "// ERROR: expected " << (expectedGLState==GL_TRUE ? "GL_TRUE" : "GL_FALSE") << "; got " << (state == GL_TRUE ? "GL_TRUE" : (state == GL_FALSE ? "GL_FALSE" : "non-boolean")) << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid boolean value"); } } void GetBooleanVerifier::verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { DE_ASSERT(de::inRange(reference, -1.0f, 1.0f)); verifyFloat(testCtx, name, reference); } void GetBooleanVerifier::verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1) { DE_ASSERT(de::inRange(reference0, -1.0f, 1.0f)); DE_ASSERT(de::inRange(reference1, -1.0f, 1.0f)); using tcu::TestLog; const GLboolean referenceAsGLBoolean[] = { reference0 != 0.0f ? GLboolean(GL_TRUE) : GLboolean(GL_FALSE), reference1 != 0.0f ? GLboolean(GL_TRUE) : GLboolean(GL_FALSE), }; StateQueryMemoryWriteGuard<GLboolean[2]> boolVector2; glGetBooleanv(name, boolVector2); if (!boolVector2.verifyValidity(testCtx)) return; if (boolVector2[0] != referenceAsGLBoolean[0] || boolVector2[1] != referenceAsGLBoolean[1]) { testCtx.getLog() << TestLog::Message << "// ERROR: expected " << (boolVector2[0] ? "GL_TRUE" : "GL_FALSE") << " " << (boolVector2[1] ? "GL_TRUE" : "GL_FALSE") << " " << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid boolean value"); } } void GetBooleanVerifier::verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3) { using tcu::TestLog; const GLboolean referenceAsGLBoolean[] = { reference0 != 0.0f ? GLboolean(GL_TRUE) : GLboolean(GL_FALSE), reference1 != 0.0f ? GLboolean(GL_TRUE) : GLboolean(GL_FALSE), reference2 != 0.0f ? GLboolean(GL_TRUE) : GLboolean(GL_FALSE), reference3 != 0.0f ? GLboolean(GL_TRUE) : GLboolean(GL_FALSE), }; StateQueryMemoryWriteGuard<GLboolean[4]> boolVector4; glGetBooleanv(name, boolVector4); if (!boolVector4.verifyValidity(testCtx)) return; if (boolVector4[0] != referenceAsGLBoolean[0] || boolVector4[1] != referenceAsGLBoolean[1] || boolVector4[2] != referenceAsGLBoolean[2] || boolVector4[3] != referenceAsGLBoolean[3]) { testCtx.getLog() << TestLog::Message << "// ERROR: expected " << (referenceAsGLBoolean[0] ? "GL_TRUE" : "GL_FALSE") << " " << (referenceAsGLBoolean[1] ? "GL_TRUE" : "GL_FALSE") << " " << (referenceAsGLBoolean[2] ? "GL_TRUE" : "GL_FALSE") << " " << (referenceAsGLBoolean[3] ? "GL_TRUE" : "GL_FALSE") << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid boolean value"); } } void GetBooleanVerifier::verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max) { using tcu::TestLog; StateQueryMemoryWriteGuard<GLboolean[2]> range; glGetBooleanv(name, range); if (!range.verifyValidity(testCtx)) return; if (range[0] == GL_FALSE) { if (max < 0 || min < 0) { testCtx.getLog() << TestLog::Message << "// ERROR: range [" << min << ", " << max << "] is not in range [" << (range[0] == GL_TRUE ? "GL_TRUE" : (range[0] == GL_FALSE ? "GL_FALSE" : "non-boolean")) << ", " << (range[1] == GL_TRUE ? "GL_TRUE" : (range[1] == GL_FALSE ? "GL_FALSE" : "non-boolean")) << "]" << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid boolean range"); return; } } if (range[1] == GL_FALSE) { if (max > 0 || min > 0) { testCtx.getLog() << TestLog::Message << "// ERROR: range [" << min << ", " << max << "] is not in range [" << (range[0] == GL_TRUE ? "GL_TRUE" : (range[0] == GL_FALSE ? "GL_FALSE" : "non-boolean")) << ", " << (range[1] == GL_TRUE ? "GL_TRUE" : (range[1] == GL_FALSE ? "GL_FALSE" : "non-boolean")) << "]" << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid boolean range"); return; } } } //GetIntegerVerifier class GetIntegerVerifier : public StateVerifier { public: GetIntegerVerifier (const glw::Functions& gl, tcu::TestLog& log); void verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1); void verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3); void verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max); }; GetIntegerVerifier::GetIntegerVerifier (const glw::Functions& gl, tcu::TestLog& log) : StateVerifier(gl, log, "_getinteger") { } void GetIntegerVerifier::verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { using tcu::TestLog; const GLint expectedGLStateMax = StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<GLint>(reference); const GLint expectedGLStateMin = StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<GLint>(reference); StateQueryMemoryWriteGuard<GLint> state; glGetIntegerv(name, &state); if (!state.verifyValidity(testCtx)) return; if (state < expectedGLStateMin || state > expectedGLStateMax) { testCtx.getLog() << TestLog::Message << "// ERROR: expected rounding to the nearest integer, valid range [" << expectedGLStateMin << "," << expectedGLStateMax << "]; got " << state << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetIntegerVerifier::verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { DE_ASSERT(de::inRange(reference, -1.0f, 1.0f)); using tcu::TestLog; using tcu::toHex; const GLint expectedGLStateMax = clampToGLint(expandGLFloatToInteger(reference) + FLOAT_EXPANSION_E); const GLint expectedGLStateMin = clampToGLint(expandGLFloatToInteger(reference) - FLOAT_EXPANSION_E); StateQueryMemoryWriteGuard<GLint> state; glGetIntegerv(name, &state); if (!state.verifyValidity(testCtx)) return; if (state < expectedGLStateMin || state > expectedGLStateMax) { testCtx.getLog() << TestLog::Message << "// ERROR: expected in range [" << toHex(expectedGLStateMin) << "," << toHex(expectedGLStateMax) << "]; got " << toHex((GLint)state) << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetIntegerVerifier::verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1) { DE_ASSERT(de::inRange(reference0, -1.0f, 1.0f)); DE_ASSERT(de::inRange(reference1, -1.0f, 1.0f)); using tcu::TestLog; using tcu::toHex; const GLint referenceAsGLintMin[] = { clampToGLint(expandGLFloatToInteger(reference0) - FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference1) - FLOAT_EXPANSION_E) }; const GLint referenceAsGLintMax[] = { clampToGLint(expandGLFloatToInteger(reference0) + FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference1) + FLOAT_EXPANSION_E) }; StateQueryMemoryWriteGuard<GLint[2]> floatVector2; glGetIntegerv(name, floatVector2); if (!floatVector2.verifyValidity(testCtx)) return; if (floatVector2[0] < referenceAsGLintMin[0] || floatVector2[0] > referenceAsGLintMax[0] || floatVector2[1] < referenceAsGLintMin[1] || floatVector2[1] > referenceAsGLintMax[1]) { testCtx.getLog() << TestLog::Message << "// ERROR: expected in ranges " << "[" << toHex(referenceAsGLintMin[0]) << " " << toHex(referenceAsGLintMax[0]) << "], " << "[" << toHex(referenceAsGLintMin[1]) << " " << toHex(referenceAsGLintMax[1]) << "]" << "; got " << toHex(floatVector2[0]) << ", " << toHex(floatVector2[1]) << " "<< TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetIntegerVerifier::verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3) { using tcu::TestLog; using tcu::toHex; const GLint referenceAsGLintMin[] = { clampToGLint(expandGLFloatToInteger(reference0) - FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference1) - FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference2) - FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference3) - FLOAT_EXPANSION_E) }; const GLint referenceAsGLintMax[] = { clampToGLint(expandGLFloatToInteger(reference0) + FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference1) + FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference2) + FLOAT_EXPANSION_E), clampToGLint(expandGLFloatToInteger(reference3) + FLOAT_EXPANSION_E) }; StateQueryMemoryWriteGuard<GLint[4]> floatVector4; glGetIntegerv(name, floatVector4); if (!floatVector4.verifyValidity(testCtx)) return; if (floatVector4[0] < referenceAsGLintMin[0] || floatVector4[0] > referenceAsGLintMax[0] || floatVector4[1] < referenceAsGLintMin[1] || floatVector4[1] > referenceAsGLintMax[1] || floatVector4[2] < referenceAsGLintMin[2] || floatVector4[2] > referenceAsGLintMax[2] || floatVector4[3] < referenceAsGLintMin[3] || floatVector4[3] > referenceAsGLintMax[3]) { testCtx.getLog() << TestLog::Message << "// ERROR: expected in ranges " << "[" << toHex(referenceAsGLintMin[0]) << " " << toHex(referenceAsGLintMax[0]) << "], " << "[" << toHex(referenceAsGLintMin[1]) << " " << toHex(referenceAsGLintMax[1]) << "], " << "[" << toHex(referenceAsGLintMin[2]) << " " << toHex(referenceAsGLintMax[2]) << "], " << "[" << toHex(referenceAsGLintMin[3]) << " " << toHex(referenceAsGLintMax[3]) << "]" << "; got " << toHex(floatVector4[0]) << ", " << toHex(floatVector4[1]) << ", " << toHex(floatVector4[2]) << ", " << toHex(floatVector4[3]) << " "<< TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetIntegerVerifier::verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max) { using tcu::TestLog; const GLint testRangeAsGLint[] = { StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<GLint>(min), StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<GLint>(max) }; StateQueryMemoryWriteGuard<GLint[2]> range; glGetIntegerv(name, range); if (!range.verifyValidity(testCtx)) return; // check if test range outside of gl state range if (testRangeAsGLint[0] < range[0] || testRangeAsGLint[1] > range[1]) { testCtx.getLog() << TestLog::Message << "// ERROR: range [" << testRangeAsGLint[0] << ", " << testRangeAsGLint[1] << "]" << " is not in range [" << range[0] << ", " << range[1] << "]" << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer range"); } } //GetInteger64Verifier class GetInteger64Verifier : public StateVerifier { public: GetInteger64Verifier (const glw::Functions& gl, tcu::TestLog& log); void verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1); void verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3); void verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max); }; GetInteger64Verifier::GetInteger64Verifier (const glw::Functions& gl, tcu::TestLog& log) : StateVerifier(gl, log, "_getinteger64") { } void GetInteger64Verifier::verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { using tcu::TestLog; const GLint64 expectedGLStateMax = StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<GLint64>(reference); const GLint64 expectedGLStateMin = StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<GLint64>(reference); StateQueryMemoryWriteGuard<GLint64> state; glGetInteger64v(name, &state); if (!state.verifyValidity(testCtx)) return; if (state < expectedGLStateMin || state > expectedGLStateMax) { testCtx.getLog() << TestLog::Message << "// ERROR: expected rounding to the nearest integer, valid range [" << expectedGLStateMin << "," << expectedGLStateMax << "]; got " << state << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetInteger64Verifier::verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { DE_ASSERT(de::inRange(reference, -1.0f, 1.0f)); using tcu::TestLog; using tcu::toHex; const GLint64 expectedGLStateMax = expandGLFloatToInteger(reference) + FLOAT_EXPANSION_E_64; const GLint64 expectedGLStateMin = expandGLFloatToInteger(reference) - FLOAT_EXPANSION_E_64; StateQueryMemoryWriteGuard<GLint64> state; glGetInteger64v(name, &state); if (!state.verifyValidity(testCtx)) return; if (state < expectedGLStateMin || state > expectedGLStateMax) { testCtx.getLog() << TestLog::Message << "// ERROR: expected in range [" << toHex(expectedGLStateMin) << "," << toHex(expectedGLStateMax) << "]; got " << toHex((GLint64)state) << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetInteger64Verifier::verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1) { DE_ASSERT(de::inRange(reference0, -1.0f, 1.0f)); DE_ASSERT(de::inRange(reference1, -1.0f, 1.0f)); using tcu::TestLog; using tcu::toHex; const GLint64 referenceAsGLintMin[] = { expandGLFloatToInteger(reference0) - FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference1) - FLOAT_EXPANSION_E_64 }; const GLint64 referenceAsGLintMax[] = { expandGLFloatToInteger(reference0) + FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference1) + FLOAT_EXPANSION_E_64 }; StateQueryMemoryWriteGuard<GLint64[2]> floatVector2; glGetInteger64v(name, floatVector2); if (!floatVector2.verifyValidity(testCtx)) return; if (floatVector2[0] < referenceAsGLintMin[0] || floatVector2[0] > referenceAsGLintMax[0] || floatVector2[1] < referenceAsGLintMin[1] || floatVector2[1] > referenceAsGLintMax[1]) { testCtx.getLog() << TestLog::Message << "// ERROR: expected in ranges " << "[" << toHex(referenceAsGLintMin[0]) << " " << toHex(referenceAsGLintMax[0]) << "], " << "[" << toHex(referenceAsGLintMin[1]) << " " << toHex(referenceAsGLintMax[1]) << "]" << "; got " << toHex(floatVector2[0]) << ", " << toHex(floatVector2[1]) << " "<< TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetInteger64Verifier::verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3) { using tcu::TestLog; using tcu::toHex; const GLint64 referenceAsGLintMin[] = { expandGLFloatToInteger(reference0) - FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference1) - FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference2) - FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference3) - FLOAT_EXPANSION_E_64 }; const GLint64 referenceAsGLintMax[] = { expandGLFloatToInteger(reference0) + FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference1) + FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference2) + FLOAT_EXPANSION_E_64, expandGLFloatToInteger(reference3) + FLOAT_EXPANSION_E_64 }; StateQueryMemoryWriteGuard<GLint64[4]> floatVector4; glGetInteger64v(name, floatVector4); if (!floatVector4.verifyValidity(testCtx)) return; if (floatVector4[0] < referenceAsGLintMin[0] || floatVector4[0] > referenceAsGLintMax[0] || floatVector4[1] < referenceAsGLintMin[1] || floatVector4[1] > referenceAsGLintMax[1] || floatVector4[2] < referenceAsGLintMin[2] || floatVector4[2] > referenceAsGLintMax[2] || floatVector4[3] < referenceAsGLintMin[3] || floatVector4[3] > referenceAsGLintMax[3]) { testCtx.getLog() << TestLog::Message << "// ERROR: expected in ranges " << "[" << toHex(referenceAsGLintMin[0]) << " " << toHex(referenceAsGLintMax[0]) << "], " << "[" << toHex(referenceAsGLintMin[1]) << " " << toHex(referenceAsGLintMax[1]) << "], " << "[" << toHex(referenceAsGLintMin[2]) << " " << toHex(referenceAsGLintMax[2]) << "], " << "[" << toHex(referenceAsGLintMin[3]) << " " << toHex(referenceAsGLintMax[3]) << "]" << "; got " << toHex(floatVector4[0]) << ", " << toHex(floatVector4[1]) << ", " << toHex(floatVector4[2]) << ", " << toHex(floatVector4[3]) << " "<< TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer value"); } } void GetInteger64Verifier::verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max) { using tcu::TestLog; const GLint64 testRangeAsGLint[] = { StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<GLint64>(min), StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<GLint64>(max) }; StateQueryMemoryWriteGuard<GLint64[2]> range; glGetInteger64v(name, range); if (!range.verifyValidity(testCtx)) return; // check if test range outside of gl state range if (testRangeAsGLint[0] < range[0] || testRangeAsGLint[1] > range[1]) { testCtx.getLog() << TestLog::Message << "// ERROR: range [" << testRangeAsGLint[0] << ", " << testRangeAsGLint[1] << "]" << " is not in range [" << range[0] << ", " << range[1] << "]" << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid integer range"); } } //GetFloatVerifier class GetFloatVerifier : public StateVerifier { public: GetFloatVerifier (const glw::Functions& gl, tcu::TestLog& log); void verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference); void verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1); void verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3); void verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max); }; GetFloatVerifier::GetFloatVerifier (const glw::Functions& gl, tcu::TestLog& log) : StateVerifier(gl, log, "_getfloat") { } void GetFloatVerifier::verifyFloat (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { using tcu::TestLog; StateQueryMemoryWriteGuard<GLfloat> state; glGetFloatv(name, &state); if (!state.verifyValidity(testCtx)) return; if (state != reference) { testCtx.getLog() << TestLog::Message << "// ERROR: expected " << reference << "; got " << state << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid float value"); } } void GetFloatVerifier::verifyFloatExpanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference) { DE_ASSERT(de::inRange(reference, -1.0f, 1.0f)); verifyFloat(testCtx, name, reference); } void GetFloatVerifier::verifyFloat2Expanded (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1) { DE_ASSERT(de::inRange(reference0, -1.0f, 1.0f)); DE_ASSERT(de::inRange(reference1, -1.0f, 1.0f)); using tcu::TestLog; StateQueryMemoryWriteGuard<GLfloat[2]> floatVector2; glGetFloatv(name, floatVector2); if (!floatVector2.verifyValidity(testCtx)) return; if (floatVector2[0] != reference0 || floatVector2[1] != reference1) { testCtx.getLog() << TestLog::Message << "// ERROR: expected " << reference0 << ", " << reference1 << "; got " << floatVector2[0] << " " << floatVector2[1] << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid float value"); } } void GetFloatVerifier::verifyFloat4Color (tcu::TestContext& testCtx, GLenum name, GLfloat reference0, GLfloat reference1, GLfloat reference2, GLfloat reference3) { using tcu::TestLog; StateQueryMemoryWriteGuard<GLfloat[4]> floatVector4; glGetFloatv(name, floatVector4); if (!floatVector4.verifyValidity(testCtx)) return; if (floatVector4[0] != reference0 || floatVector4[1] != reference1 || floatVector4[2] != reference2 || floatVector4[3] != reference3) { testCtx.getLog() << TestLog::Message << "// ERROR: expected "<< reference0 << ", " << reference1 << ", " << reference2 << ", " << reference3 << "; got " << floatVector4[0] << ", " << floatVector4[1] << ", " << floatVector4[2] << ", " << floatVector4[3] << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid float value"); } } void GetFloatVerifier::verifyFloatRange (tcu::TestContext& testCtx, GLenum name, GLfloat min, GLfloat max) { using tcu::TestLog; StateQueryMemoryWriteGuard<GLfloat[2]> floatVector2; glGetFloatv(name, floatVector2); if (!floatVector2.verifyValidity(testCtx)) return; if (floatVector2[0] > min || floatVector2[1] < max) { testCtx.getLog() << TestLog::Message << "// ERROR: expected in range [" << min << ", " << max << "]; got [" << floatVector2[0] << " " << floatVector2[1] << "]" << TestLog::EndMessage; if (testCtx.getTestResult() == QP_TEST_RESULT_PASS) testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid float range"); } } } // FloatStateQueryVerifiers namespace { using namespace FloatStateQueryVerifiers; class DepthRangeCase : public ApiCase { public: DepthRangeCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { de::Random rnd(0xabcdef); m_verifier->verifyFloat2Expanded(m_testCtx, GL_DEPTH_RANGE, 0.0f, 1.0f); expectError(GL_NO_ERROR); { const struct FixedTest { float n, f; } fixedTests[] = { { 0.5f, 1.0f }, { 0.0f, 0.5f }, { 0.0f, 0.0f }, { 1.0f, 1.0f } }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(fixedTests); ++ndx) { glDepthRangef(fixedTests[ndx].n, fixedTests[ndx].f); m_verifier->verifyFloat2Expanded(m_testCtx, GL_DEPTH_RANGE, fixedTests[ndx].n, fixedTests[ndx].f); expectError(GL_NO_ERROR); } } { const int numIterations = 120; for (int i = 0; i < numIterations; ++i) { GLfloat n = rnd.getFloat(0, 1); GLfloat f = rnd.getFloat(0, 1); glDepthRangef(n, f); m_verifier->verifyFloat2Expanded(m_testCtx, GL_DEPTH_RANGE, n, f); expectError(GL_NO_ERROR); } } } private: StateVerifier* m_verifier; }; class LineWidthCase : public ApiCase { public: LineWidthCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { de::Random rnd(0xabcdef); GLfloat range[2] = {1}; glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range); expectError(GL_NO_ERROR); m_verifier->verifyFloat(m_testCtx, GL_LINE_WIDTH, 1.0f); expectError(GL_NO_ERROR); const int numIterations = 120; for (int i = 0; i < numIterations; ++i) { const GLfloat reference = rnd.getFloat(range[0], range[1]); glLineWidth(reference); m_verifier->verifyFloat(m_testCtx, GL_LINE_WIDTH, reference); expectError(GL_NO_ERROR); } } private: StateVerifier* m_verifier; }; class PolygonOffsetFactorCase : public ApiCase { public: PolygonOffsetFactorCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { de::Random rnd(0xabcdef); m_verifier->verifyFloat(m_testCtx, GL_POLYGON_OFFSET_FACTOR, 0.0f); expectError(GL_NO_ERROR); { const float fixedTests[] = { 0.0f, 0.5f, -0.5f, 1.5f }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(fixedTests); ++ndx) { glPolygonOffset(fixedTests[ndx], 0); m_verifier->verifyFloat(m_testCtx, GL_POLYGON_OFFSET_FACTOR, fixedTests[ndx]); expectError(GL_NO_ERROR); } } { const int numIterations = 120; for (int i = 0; i < numIterations; ++i) { const GLfloat reference = rnd.getFloat(-64000, 64000); glPolygonOffset(reference, 0); m_verifier->verifyFloat(m_testCtx, GL_POLYGON_OFFSET_FACTOR, reference); expectError(GL_NO_ERROR); } } } private: StateVerifier* m_verifier; }; class PolygonOffsetUnitsCase : public ApiCase { public: PolygonOffsetUnitsCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { de::Random rnd(0xabcdef); m_verifier->verifyFloat(m_testCtx, GL_POLYGON_OFFSET_UNITS, 0.0f); expectError(GL_NO_ERROR); { const float fixedTests[] = { 0.0f, 0.5f, -0.5f, 1.5f }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(fixedTests); ++ndx) { glPolygonOffset(0, fixedTests[ndx]); m_verifier->verifyFloat(m_testCtx, GL_POLYGON_OFFSET_UNITS, fixedTests[ndx]); expectError(GL_NO_ERROR); } } { const int numIterations = 120; for (int i = 0; i < numIterations; ++i) { const GLfloat reference = rnd.getFloat(-64000, 64000); glPolygonOffset(0, reference); m_verifier->verifyFloat(m_testCtx, GL_POLYGON_OFFSET_UNITS, reference); expectError(GL_NO_ERROR); } } } private: StateVerifier* m_verifier; }; class SampleCoverageCase : public ApiCase { public: SampleCoverageCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { de::Random rnd(0xabcdef); m_verifier->verifyFloat(m_testCtx, GL_SAMPLE_COVERAGE_VALUE, 1.0f); expectError(GL_NO_ERROR); { const float fixedTests[] = { 0.0f, 0.5f, 0.45f, 0.55f }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(fixedTests); ++ndx) { glSampleCoverage(fixedTests[ndx], GL_FALSE); m_verifier->verifyFloat(m_testCtx, GL_SAMPLE_COVERAGE_VALUE, fixedTests[ndx]); expectError(GL_NO_ERROR); } } { const float clampTests[] = { -1.0f, -1.5f, 1.45f, 3.55f }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(clampTests); ++ndx) { glSampleCoverage(clampTests[ndx], GL_FALSE); m_verifier->verifyFloat(m_testCtx, GL_SAMPLE_COVERAGE_VALUE, de::clamp(clampTests[ndx], 0.0f, 1.0f)); expectError(GL_NO_ERROR); } } { const int numIterations = 120; for (int i = 0; i < numIterations; ++i) { GLfloat reference = rnd.getFloat(0, 1); GLboolean invert = rnd.getBool() ? GL_TRUE : GL_FALSE; glSampleCoverage(reference, invert); m_verifier->verifyFloat(m_testCtx, GL_SAMPLE_COVERAGE_VALUE, reference); expectError(GL_NO_ERROR); } } } private: StateVerifier* m_verifier; }; class ColorClearCase : public ApiCase { public: ColorClearCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { de::Random rnd(0xabcdef); // \note Initial color clear value check is temorarily removed. (until the framework does not alter it) //m_verifier->verifyFloat4Color(m_testCtx, GL_COLOR_CLEAR_VALUE, 0, 0, 0, 0); //expectError(GL_NO_ERROR); { const struct FixedTest { float r, g, b, a; } fixedTests[] = { { 0.5f, 1.0f, 0.5f, 1.0f }, { 0.0f, 0.5f, 0.0f, 0.5f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }, }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(fixedTests); ++ndx) { glClearColor(fixedTests[ndx].r, fixedTests[ndx].g, fixedTests[ndx].b, fixedTests[ndx].a); m_verifier->verifyFloat4Color(m_testCtx, GL_COLOR_CLEAR_VALUE, fixedTests[ndx].r, fixedTests[ndx].g, fixedTests[ndx].b, fixedTests[ndx].a); expectError(GL_NO_ERROR); } } { const int numIterations = 120; for (int i = 0; i < numIterations; ++i) { const GLfloat r = rnd.getFloat(0, 1); const GLfloat g = rnd.getFloat(0, 1); const GLfloat b = rnd.getFloat(0, 1); const GLfloat a = rnd.getFloat(0, 1); glClearColor(r, g, b, a); m_verifier->verifyFloat4Color(m_testCtx, GL_COLOR_CLEAR_VALUE, r, g, b, a); expectError(GL_NO_ERROR); } } } private: StateVerifier* m_verifier; }; class DepthClearCase : public ApiCase { public: DepthClearCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { const int numIterations = 120; de::Random rnd(0xabcdef); m_verifier->verifyFloatExpanded(m_testCtx, GL_DEPTH_CLEAR_VALUE, 1); expectError(GL_NO_ERROR); for (int i = 0; i < numIterations; ++i) { const GLfloat ref = rnd.getFloat(0, 1); glClearDepthf(ref); m_verifier->verifyFloatExpanded(m_testCtx, GL_DEPTH_CLEAR_VALUE, ref); expectError(GL_NO_ERROR); } } private: StateVerifier* m_verifier; }; class AliasedPointSizeRangeCase : public ApiCase { public: AliasedPointSizeRangeCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { m_verifier->verifyFloatRange(m_testCtx, GL_ALIASED_POINT_SIZE_RANGE, 1, 1); expectError(GL_NO_ERROR); } private: StateVerifier* m_verifier; }; class AliasedLineWidthRangeCase : public ApiCase { public: AliasedLineWidthRangeCase (Context& context, StateVerifier* verifier, const char* name, const char* description) : ApiCase (context, name, description) , m_verifier (verifier) { } void test (void) { m_verifier->verifyFloatRange(m_testCtx, GL_ALIASED_LINE_WIDTH_RANGE, 1, 1); expectError(GL_NO_ERROR); } private: StateVerifier* m_verifier; }; #define FOR_EACH_VERIFIER(VERIFIERS, CODE_BLOCK) \ for (int _verifierNdx = 0; _verifierNdx < DE_LENGTH_OF_ARRAY(VERIFIERS); _verifierNdx++) \ { \ StateVerifier* verifier = VERIFIERS[_verifierNdx]; \ CODE_BLOCK; \ } } // anonymous FloatStateQueryTests::FloatStateQueryTests (Context& context) : TestCaseGroup (context, "floats", "Float Values") , m_verifierBoolean (DE_NULL) , m_verifierInteger (DE_NULL) , m_verifierFloat (DE_NULL) { } FloatStateQueryTests::~FloatStateQueryTests (void) { deinit(); } void FloatStateQueryTests::init (void) { DE_ASSERT(m_verifierBoolean == DE_NULL); DE_ASSERT(m_verifierInteger == DE_NULL); DE_ASSERT(m_verifierFloat == DE_NULL); m_verifierBoolean = new GetBooleanVerifier (m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog()); m_verifierInteger = new GetIntegerVerifier (m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog()); m_verifierFloat = new GetFloatVerifier (m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog()); StateVerifier* verifiers[] = {m_verifierBoolean, m_verifierInteger, m_verifierFloat}; FOR_EACH_VERIFIER(verifiers, addChild(new DepthRangeCase (m_context, verifier, (std::string("depth_range") + verifier->getTestNamePostfix()).c_str(), "DEPTH_RANGE"))); FOR_EACH_VERIFIER(verifiers, addChild(new LineWidthCase (m_context, verifier, (std::string("line_width") + verifier->getTestNamePostfix()).c_str(), "LINE_WIDTH"))); FOR_EACH_VERIFIER(verifiers, addChild(new PolygonOffsetFactorCase (m_context, verifier, (std::string("polygon_offset_factor") + verifier->getTestNamePostfix()).c_str(), "POLYGON_OFFSET_FACTOR"))); FOR_EACH_VERIFIER(verifiers, addChild(new PolygonOffsetUnitsCase (m_context, verifier, (std::string("polygon_offset_units") + verifier->getTestNamePostfix()).c_str(), "POLYGON_OFFSET_UNITS"))); FOR_EACH_VERIFIER(verifiers, addChild(new SampleCoverageCase (m_context, verifier, (std::string("sample_coverage_value") + verifier->getTestNamePostfix()).c_str(), "SAMPLE_COVERAGE_VALUE"))); FOR_EACH_VERIFIER(verifiers, addChild(new ColorClearCase (m_context, verifier, (std::string("color_clear_value") + verifier->getTestNamePostfix()).c_str(), "COLOR_CLEAR_VALUE"))); FOR_EACH_VERIFIER(verifiers, addChild(new DepthClearCase (m_context, verifier, (std::string("depth_clear_value") + verifier->getTestNamePostfix()).c_str(), "DEPTH_CLEAR_VALUE"))); FOR_EACH_VERIFIER(verifiers, addChild(new AliasedPointSizeRangeCase (m_context, verifier, (std::string("aliased_point_size_range") + verifier->getTestNamePostfix()).c_str(), "ALIASED_POINT_SIZE_RANGE"))); FOR_EACH_VERIFIER(verifiers, addChild(new AliasedLineWidthRangeCase (m_context, verifier, (std::string("aliased_line_width_range") + verifier->getTestNamePostfix()).c_str(), "ALIASED_LINE_WIDTH_RANGE"))); } void FloatStateQueryTests::deinit (void) { if (m_verifierBoolean) { delete m_verifierBoolean; m_verifierBoolean = DE_NULL; } if (m_verifierInteger) { delete m_verifierInteger; m_verifierInteger = DE_NULL; } if (m_verifierFloat) { delete m_verifierFloat; m_verifierFloat = DE_NULL; } this->TestCaseGroup::deinit(); } } // Functional } // gles2 } // deqp