/*------------------------------------------------------------------------- * 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, uint32_t 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, uint32_t 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, uint32_t 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 << glu::SHADERTYPE_VERTEX), TC = (1 << glu::SHADERTYPE_TESSELLATION_CONTROL), TE = (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION), GS = (1 << glu::SHADERTYPE_GEOMETRY), FS = (1 << glu::SHADERTYPE_FRAGMENT), CS = (1 << glu::SHADERTYPE_COMPUTE), SHADER_TYPES = VS | TC | TE | GS | FS | CS }; template 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 << shaderType)) != 0) { const char *const shaderTypeName = glu::getShaderTypeName(glu::ShaderType(shaderType)); const tcu::ScopedLogSection section(m_testCtx.getLog(), shaderTypeName, shaderTypeName); try { const bool isOk = verifyInShaderType(glu::ShaderType(shaderType), reference); DE_ASSERT(isOk || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS); DE_UNREF(isOk); } catch (const tcu::NotSupportedError &e) { m_testCtx.getLog() << TestLog::Message << "Not checking " << shaderTypeName << ": " << e.what() << TestLog::EndMessage; } catch (const tcu::TestError &e) { m_testCtx.getLog() << TestLog::Message << e.what() << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, e.getMessage()); } } } return STOP; } } // namespace ShaderBuiltinConstantTests::ShaderBuiltinConstantTests(Context &context) : TestCaseGroup(context, "builtin_constants", "Built-in Constant Tests") { } ShaderBuiltinConstantTests::~ShaderBuiltinConstantTests(void) { } void ShaderBuiltinConstantTests::init(void) { // Core builtin constants { static const struct { const char *varName; ShaderBuiltinConstantCase::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")); } } } // namespace Functional } // namespace gles31 } // namespace deqp