/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2017 The Khronos Group Inc. * * 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 glcLimitTest.cpp * \brief Definition of template class. */ /*-------------------------------------------------------------------*/ using namespace glw; template LimitCase::LimitCase(deqp::Context& context, const char* caseName, deUint32 limitToken, DataType limitBoundry, bool isBoundryMaximum, 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_glslVersion(glslVersion) , m_glslBuiltin(glslBuiltin) , m_glslExtension(glslExtension) { } template LimitCase::~LimitCase(void) { } template tcu::TestNode::IterateResult LimitCase::iterate(void) { DataType limitValue = DataType(); const Functions& gl = m_context.getRenderContext().getFunctions(); // make sure that limit or builtin was specified DE_ASSERT(m_limitToken || !m_glslBuiltin.empty()); // check if limit was specified if (m_limitToken) { // check if limit is not smaller or greater then boundry defined in specification limitValue = getLimitValue(gl); if (!isWithinBoundry(limitValue)) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } // if glsl builtin wasn't defined then test already passed if (m_glslBuiltin.empty()) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } } // create compute shader to check glsl builtin std::string shaderSource = createShader(); const GLchar* source = shaderSource.c_str(); const GLuint program = gl.createProgram(); GLuint shader = gl.createShader(GL_COMPUTE_SHADER); gl.attachShader(program, shader); gl.deleteShader(shader); gl.shaderSource(shader, 1, &source, NULL); gl.compileShader(shader); gl.linkProgram(program); GLint status; gl.getProgramiv(program, GL_LINK_STATUS, &status); GLint length; gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &length); if (length > 1) { std::vector log(length); gl.getProgramInfoLog(program, length, NULL, &log[0]); m_testCtx.getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage; } if (status == GL_FALSE) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } gl.useProgram(program); GLuint buffer; gl.genBuffers(1, &buffer); gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer); gl.bufferData(GL_SHADER_STORAGE_BUFFER, sizeof(DataType), NULL, GL_DYNAMIC_DRAW); gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); gl.dispatchCompute(1, 1, 1); gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); DataType* data = static_cast(gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(DataType), GL_MAP_READ_BIT)); DataType builtinValue = data[0]; gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); if (m_limitToken) { // limit token was specified - compare builtin to it if (isEqual(limitValue, builtinValue)) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); m_testCtx.getLog() << tcu::TestLog::Message << "Shader builtin has value: " << builtinValue << " which is different then the value of corresponding limit: " << limitValue << tcu::TestLog::EndMessage; } } else { // limit token was not specified - compare builtin to the boundry if (isWithinBoundry(builtinValue, true)) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); m_testCtx.getLog() << tcu::TestLog::Message << "Shader builtin value is: " << builtinValue << " which is outside of specified boundry." << tcu::TestLog::EndMessage; } } return STOP; } template bool LimitCase::isWithinBoundry(DataType value, bool isBuiltin) const { if (m_isBoundryMaximum) { // value should be smaller or euqual to boundry if (isGreater(value, m_limitBoundry)) { m_testCtx.getLog() << tcu::TestLog::Message << (isBuiltin ? "Builtin" : "Limit") << " value is: " << value << " when it should not be greater than " << m_limitBoundry << tcu::TestLog::EndMessage; return false; } } else { // value should be greater or euqual to boundry if (isSmaller(value, m_limitBoundry)) { m_testCtx.getLog() << tcu::TestLog::Message << (isBuiltin ? "Builtin" : "Limit") << " value is: " << value << "when it should not be smaller than " << m_limitBoundry << tcu::TestLog::EndMessage; return false; } } return true; } template std::string LimitCase::createShader() const { std::stringstream shader; shader << "#version " << m_glslVersion << "\n"; if (!m_glslExtension.empty()) shader << "#extension " + m_glslExtension + " : require\n"; shader << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" "layout(std430) buffer Output {\n" << getGLSLDataType() <<" data; } g_out;" "void main() { " "g_out.data = " << m_glslBuiltin << "; }"; return shader.str(); } template std::string LimitCase::getGLSLDataType() const { return "int"; } template<> std::string LimitCase::getGLSLDataType() const { return "float"; } template<> std::string LimitCase::getGLSLDataType() const { return "ivec3"; } template bool LimitCase::isEqual(DataType a, DataType b) const { return a == b; } template<> bool LimitCase::isEqual(tcu::IVec3 a, tcu::IVec3 b) const { tcu::BVec3 bVec = tcu::equal(a, b); return tcu::boolAll(bVec); } template bool LimitCase::isGreater(DataType a, DataType b) const { return a > b; } template<> bool LimitCase::isGreater(tcu::IVec3 a, tcu::IVec3 b) const { tcu::BVec3 bVec = tcu::greaterThan(a, b); return tcu::boolAll(bVec); } template bool LimitCase::isSmaller(DataType a, DataType b) const { return a < b; } template<> bool LimitCase::isSmaller(tcu::IVec3 a, tcu::IVec3 b) const { tcu::BVec3 bVec = tcu::lessThan(a, b); return tcu::boolAll(bVec); } template DataType LimitCase::getLimitValue(const Functions&) const { return DataType(); } template<> GLint LimitCase::getLimitValue(const Functions& gl) const { GLint value = -1; gl.getIntegerv(m_limitToken, &value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv"); return value; } template<> GLint64 LimitCase::getLimitValue(const Functions& gl) const { GLint64 value = -1; gl.getInteger64v(m_limitToken, &value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v"); return value; } template<> GLuint64 LimitCase::getLimitValue(const Functions& gl) const { GLint64 value = -1; gl.getInteger64v(m_limitToken, &value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v"); return static_cast(value); } template<> GLfloat LimitCase::getLimitValue(const Functions& gl) const { GLfloat value = -1; gl.getFloatv(m_limitToken, &value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv"); return value; } template<> tcu::IVec3 LimitCase::getLimitValue(const Functions& gl) const { tcu::IVec3 value(-1); for (int i = 0; i < 3; i++) gl.getIntegeri_v(m_limitToken, (GLuint)i, &value[i]); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegeri_v"); return value; }