/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.1 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 Shader built-in constant tests. *//*--------------------------------------------------------------------*/ #include "es31fShaderBuiltinConstantTests.hpp" #include "glsShaderExecUtil.hpp" #include "deUniquePtr.hpp" #include "deStringUtil.hpp" #include "tcuTestLog.hpp" #include "gluStrUtil.hpp" #include "gluContextInfo.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" using std::string; using std::vector; using tcu::TestLog; namespace deqp { namespace gles31 { namespace Functional { namespace { static int getInteger (const glw::Functions& gl, deUint32 pname) { int value = -1; gl.getIntegerv(pname, &value); GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str()); return value; } template static int getInteger (const glw::Functions& gl) { return getInteger(gl, Pname); } static int getVectorsFromComps (const glw::Functions& gl, deUint32 pname) { int value = -1; gl.getIntegerv(pname, &value); GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str()); TCU_CHECK_MSG(value%4 == 0, ("Expected " + glu::getGettableStateStr((int)pname).toString() + " to be divisible by 4").c_str()); return value/4; } template static int getVectorsFromComps (const glw::Functions& gl) { return getVectorsFromComps(gl, Pname); } static tcu::IVec3 getIVec3 (const glw::Functions& gl, deUint32 pname) { tcu::IVec3 value(-1); for (int ndx = 0; ndx < 3; ndx++) gl.getIntegeri_v(pname, (glw::GLuint)ndx, &value[ndx]); GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegeri_v(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str()); return value; } template static tcu::IVec3 getIVec3 (const glw::Functions& gl) { return getIVec3(gl, Pname); } static std::string makeCaseName (const std::string& varName) { DE_ASSERT(varName.length() > 3); DE_ASSERT(varName.substr(0,3) == "gl_"); std::ostringstream name; name << de::toLower(char(varName[3])); for (size_t ndx = 4; ndx < varName.length(); ndx++) { const char c = char(varName[ndx]); if (de::isUpper(c)) name << '_' << de::toLower(c); else name << c; } return name.str(); } enum { VS = (1< class ShaderBuiltinConstantCase : public TestCase { public: typedef DataType (*GetConstantValueFunc) (const glw::Functions& gl); ShaderBuiltinConstantCase (Context& context, const char* varName, GetConstantValueFunc getValue, const char* requiredExt); ~ShaderBuiltinConstantCase (void); void init (void); IterateResult iterate (void); private: bool verifyInShaderType (glu::ShaderType shaderType, DataType reference); const std::string m_varName; const GetConstantValueFunc m_getValue; const std::string m_requiredExt; }; template ShaderBuiltinConstantCase::ShaderBuiltinConstantCase (Context& context, const char* varName, GetConstantValueFunc getValue, const char* requiredExt) : TestCase (context, makeCaseName(varName).c_str(), varName) , m_varName (varName) , m_getValue (getValue) , m_requiredExt (requiredExt ? requiredExt : "") { DE_ASSERT(!requiredExt == m_requiredExt.empty()); } template ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void) { } template void ShaderBuiltinConstantCase::init (void) { const bool supportsES32orGL45 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) || contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)); if(!glu::isContextTypeES(m_context.getRenderContext().getType())) { if(m_varName == "gl_MaxVertexOutputVectors" || m_varName == "gl_MaxFragmentInputVectors") { std::string message = "The test requires a GLES context. The constant '" + m_varName + "' is not supported."; TCU_THROW(NotSupportedError, message.c_str()); } } if (m_requiredExt == "GL_OES_sample_variables" || m_requiredExt == "GL_EXT_geometry_shader" || m_requiredExt == "GL_EXT_tessellation_shader") { if(!supportsES32orGL45) { const std::string message = "The test requires a GLES 3.2 or GL 4.5 context or support for the extension " + m_requiredExt + "."; TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported(m_requiredExt.c_str()), message.c_str()); } } else if (!m_requiredExt.empty() && !m_context.getContextInfo().isExtensionSupported(m_requiredExt.c_str())) throw tcu::NotSupportedError(m_requiredExt + " not supported"); if (!supportsES32orGL45 && (m_varName == "gl_MaxTessControlImageUniforms" || m_varName == "gl_MaxTessEvaluationImageUniforms" || m_varName == "gl_MaxTessControlAtomicCounters" || m_varName == "gl_MaxTessEvaluationAtomicCounters" || m_varName == "gl_MaxTessControlAtomicCounterBuffers" || m_varName == "gl_MaxTessEvaluationAtomicCounterBuffers")) { std::string message = "The test requires a GLES 3.2 or GL 4.5 context. The constant '" + m_varName + "' is not supported."; TCU_THROW(NotSupportedError, message.c_str()); } } static gls::ShaderExecUtil::ShaderExecutor* createGetConstantExecutor (const glu::RenderContext& renderCtx, glu::ShaderType shaderType, glu::DataType dataType, const std::string& varName, const std::string& extName) { using namespace gls::ShaderExecUtil; const bool supportsES32orGL45 = contextSupports(renderCtx.getType(), glu::ApiType::es(3, 2)) || contextSupports(renderCtx.getType(), glu::ApiType::core(4, 5)); ShaderSpec shaderSpec; shaderSpec.version = glu::getContextTypeGLSLVersion(renderCtx.getType()); shaderSpec.source = string("result = ") + varName + ";\n"; shaderSpec.outputs.push_back(Symbol("result", glu::VarType(dataType, glu::PRECISION_HIGHP))); if (!extName.empty() && !(supportsES32orGL45 && (extName == "GL_OES_sample_variables" || extName == "GL_EXT_geometry_shader" || extName == "GL_EXT_tessellation_shader"))) shaderSpec.globalDeclarations = "#extension " + extName + " : require\n"; return createExecutor(renderCtx, shaderType, shaderSpec); } template static void logVarValue (tcu::TestLog& log, const std::string& varName, DataType value) { log << TestLog::Message << varName << " = " << value << TestLog::EndMessage; } template<> void logVarValue (tcu::TestLog& log, const std::string& varName, int value) { log << TestLog::Integer(varName, varName, "", QP_KEY_TAG_NONE, value); } template bool ShaderBuiltinConstantCase::verifyInShaderType (glu::ShaderType shaderType, DataType reference) { using namespace gls::ShaderExecUtil; const de::UniquePtr shaderExecutor (createGetConstantExecutor(m_context.getRenderContext(), shaderType, glu::dataTypeOf(), m_varName, m_requiredExt)); DataType result = DataType(-1); void* const outputs = &result; if (!shaderExecutor->isOk()) { shaderExecutor->log(m_testCtx.getLog()); TCU_FAIL("Compile failed"); } shaderExecutor->useProgram(); shaderExecutor->execute(1, DE_NULL, &outputs); logVarValue(m_testCtx.getLog(), m_varName, result); if (result != reference) { m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << m_varName << " = " << reference << TestLog::EndMessage << TestLog::Message << "Test shader:" << TestLog::EndMessage; shaderExecutor->log(m_testCtx.getLog()); m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid builtin constant value"); return false; } else return true; } template TestCase::IterateResult ShaderBuiltinConstantCase::iterate (void) { const DataType reference = m_getValue(m_context.getRenderContext().getFunctions()); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++) { if ((SHADER_TYPES & (1<::GetConstantValueFunc getValue; } intConstants[] = { { "gl_MaxVertexAttribs", getInteger }, { "gl_MaxVertexUniformVectors", getInteger }, { "gl_MaxVertexOutputVectors", getVectorsFromComps }, { "gl_MaxFragmentInputVectors", getVectorsFromComps }, { "gl_MaxFragmentUniformVectors", getInteger }, { "gl_MaxDrawBuffers", getInteger }, { "gl_MaxVertexTextureImageUnits", getInteger }, { "gl_MaxCombinedTextureImageUnits", getInteger }, { "gl_MaxTextureImageUnits", getInteger }, { "gl_MinProgramTexelOffset", getInteger }, { "gl_MaxProgramTexelOffset", getInteger }, { "gl_MaxImageUnits", getInteger }, { "gl_MaxVertexImageUniforms", getInteger }, { "gl_MaxFragmentImageUniforms", getInteger }, { "gl_MaxComputeImageUniforms", getInteger }, { "gl_MaxCombinedImageUniforms", getInteger }, { "gl_MaxCombinedShaderOutputResources", getInteger }, { "gl_MaxComputeUniformComponents", getInteger }, { "gl_MaxComputeTextureImageUnits", getInteger }, { "gl_MaxComputeAtomicCounters", getInteger }, { "gl_MaxComputeAtomicCounterBuffers", getInteger }, { "gl_MaxVertexAtomicCounters", getInteger }, { "gl_MaxFragmentAtomicCounters", getInteger }, { "gl_MaxCombinedAtomicCounters", getInteger }, { "gl_MaxAtomicCounterBindings", getInteger }, { "gl_MaxVertexAtomicCounterBuffers", getInteger }, { "gl_MaxFragmentAtomicCounterBuffers", getInteger }, { "gl_MaxCombinedAtomicCounterBuffers", getInteger }, { "gl_MaxAtomicCounterBufferSize", getInteger }, }; static const struct { const char* varName; ShaderBuiltinConstantCase::GetConstantValueFunc getValue; } ivec3Constants[] = { { "gl_MaxComputeWorkGroupCount", getIVec3 }, { "gl_MaxComputeWorkGroupSize", getIVec3 }, }; tcu::TestCaseGroup* const coreGroup = new tcu::TestCaseGroup(m_testCtx, "core", "Core Specification"); addChild(coreGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++) coreGroup->addChild(new ShaderBuiltinConstantCase(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, DE_NULL)); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ivec3Constants); ndx++) coreGroup->addChild(new ShaderBuiltinConstantCase(m_context, ivec3Constants[ndx].varName, ivec3Constants[ndx].getValue, DE_NULL)); } // OES_sample_variables { tcu::TestCaseGroup* const sampleVarGroup = new tcu::TestCaseGroup(m_testCtx, "sample_variables", "GL_OES_sample_variables"); addChild(sampleVarGroup); sampleVarGroup->addChild(new ShaderBuiltinConstantCase(m_context, "gl_MaxSamples", getInteger, "GL_OES_sample_variables")); } // EXT_geometry_shader { static const struct { const char* varName; ShaderBuiltinConstantCase::GetConstantValueFunc getValue; } intConstants[] = { { "gl_MaxGeometryInputComponents", getInteger }, { "gl_MaxGeometryOutputComponents", getInteger }, { "gl_MaxGeometryImageUniforms", getInteger }, { "gl_MaxGeometryTextureImageUnits", getInteger }, { "gl_MaxGeometryOutputVertices", getInteger }, { "gl_MaxGeometryTotalOutputComponents", getInteger }, { "gl_MaxGeometryUniformComponents", getInteger }, { "gl_MaxGeometryAtomicCounters", getInteger }, { "gl_MaxGeometryAtomicCounterBuffers", getInteger }, }; tcu::TestCaseGroup* const geomGroup = new tcu::TestCaseGroup(m_testCtx, "geometry_shader", "GL_EXT_geometry_shader"); addChild(geomGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++) geomGroup->addChild(new ShaderBuiltinConstantCase(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_geometry_shader")); } // EXT_tessellation_shader { static const struct { const char* varName; ShaderBuiltinConstantCase::GetConstantValueFunc getValue; } intConstants[] = { { "gl_MaxTessControlInputComponents", getInteger }, { "gl_MaxTessControlOutputComponents", getInteger }, { "gl_MaxTessControlTextureImageUnits", getInteger }, { "gl_MaxTessControlUniformComponents", getInteger }, { "gl_MaxTessControlTotalOutputComponents", getInteger }, { "gl_MaxTessControlImageUniforms", getInteger }, { "gl_MaxTessEvaluationImageUniforms", getInteger }, { "gl_MaxTessControlAtomicCounters", getInteger }, { "gl_MaxTessEvaluationAtomicCounters", getInteger }, { "gl_MaxTessControlAtomicCounterBuffers", getInteger }, { "gl_MaxTessEvaluationAtomicCounterBuffers", getInteger }, { "gl_MaxTessEvaluationInputComponents", getInteger }, { "gl_MaxTessEvaluationOutputComponents", getInteger }, { "gl_MaxTessEvaluationTextureImageUnits", getInteger }, { "gl_MaxTessEvaluationUniformComponents", getInteger }, { "gl_MaxTessPatchComponents", getInteger }, { "gl_MaxPatchVertices", getInteger }, { "gl_MaxTessGenLevel", getInteger }, }; tcu::TestCaseGroup* const tessGroup = new tcu::TestCaseGroup(m_testCtx, "tessellation_shader", "GL_EXT_tessellation_shader"); addChild(tessGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++) tessGroup->addChild(new ShaderBuiltinConstantCase(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_tessellation_shader")); } } } // Functional } // gles31 } // deqp