/*------------------------------------------------------------------------- * 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<deUint32 Pname> 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<deUint32 Pname> 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<deUint32 Pname> 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<typename DataType> 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<typename DataType> ShaderBuiltinConstantCase<DataType>::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<typename DataType> ShaderBuiltinConstantCase<DataType>::~ShaderBuiltinConstantCase (void) { } template<typename DataType> void ShaderBuiltinConstantCase<DataType>::init (void) { const bool supportsES32 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); if (m_requiredExt == "GL_OES_sample_variables" || m_requiredExt == "GL_EXT_geometry_shader" || m_requiredExt == "GL_EXT_tessellation_shader") { if(!supportsES32) { const std::string message = "The test requires a 3.2 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 (!supportsES32 && (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 3.2 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 supportsES32 = contextSupports(renderCtx.getType(), glu::ApiType::es(3, 2)); ShaderSpec shaderSpec; shaderSpec.version = supportsES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES; shaderSpec.source = string("result = ") + varName + ";\n"; shaderSpec.outputs.push_back(Symbol("result", glu::VarType(dataType, glu::PRECISION_HIGHP))); if (!extName.empty() && !(supportsES32 && (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<typename DataType> static void logVarValue (tcu::TestLog& log, const std::string& varName, DataType value) { log << TestLog::Message << varName << " = " << value << TestLog::EndMessage; } template<> void logVarValue<int> (tcu::TestLog& log, const std::string& varName, int value) { log << TestLog::Integer(varName, varName, "", QP_KEY_TAG_NONE, value); } template<typename DataType> bool ShaderBuiltinConstantCase<DataType>::verifyInShaderType (glu::ShaderType shaderType, DataType reference) { using namespace gls::ShaderExecUtil; const de::UniquePtr<ShaderExecutor> shaderExecutor (createGetConstantExecutor(m_context.getRenderContext(), shaderType, glu::dataTypeOf<DataType>(), 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<typename DataType> TestCase::IterateResult ShaderBuiltinConstantCase<DataType>::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; } } // anonymous 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<int>::GetConstantValueFunc getValue; } intConstants[] = { { "gl_MaxVertexAttribs", getInteger<GL_MAX_VERTEX_ATTRIBS> }, { "gl_MaxVertexUniformVectors", getInteger<GL_MAX_VERTEX_UNIFORM_VECTORS> }, { "gl_MaxVertexOutputVectors", getVectorsFromComps<GL_MAX_VERTEX_OUTPUT_COMPONENTS> }, { "gl_MaxFragmentInputVectors", getVectorsFromComps<GL_MAX_FRAGMENT_INPUT_COMPONENTS> }, { "gl_MaxFragmentUniformVectors", getInteger<GL_MAX_FRAGMENT_UNIFORM_VECTORS> }, { "gl_MaxDrawBuffers", getInteger<GL_MAX_DRAW_BUFFERS> }, { "gl_MaxVertexTextureImageUnits", getInteger<GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS> }, { "gl_MaxCombinedTextureImageUnits", getInteger<GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS> }, { "gl_MaxTextureImageUnits", getInteger<GL_MAX_TEXTURE_IMAGE_UNITS> }, { "gl_MinProgramTexelOffset", getInteger<GL_MIN_PROGRAM_TEXEL_OFFSET> }, { "gl_MaxProgramTexelOffset", getInteger<GL_MAX_PROGRAM_TEXEL_OFFSET> }, { "gl_MaxImageUnits", getInteger<GL_MAX_IMAGE_UNITS> }, { "gl_MaxVertexImageUniforms", getInteger<GL_MAX_VERTEX_IMAGE_UNIFORMS> }, { "gl_MaxFragmentImageUniforms", getInteger<GL_MAX_FRAGMENT_IMAGE_UNIFORMS> }, { "gl_MaxComputeImageUniforms", getInteger<GL_MAX_COMPUTE_IMAGE_UNIFORMS> }, { "gl_MaxCombinedImageUniforms", getInteger<GL_MAX_COMBINED_IMAGE_UNIFORMS> }, { "gl_MaxCombinedShaderOutputResources", getInteger<GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES> }, { "gl_MaxComputeUniformComponents", getInteger<GL_MAX_COMPUTE_UNIFORM_COMPONENTS> }, { "gl_MaxComputeTextureImageUnits", getInteger<GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS> }, { "gl_MaxComputeAtomicCounters", getInteger<GL_MAX_COMPUTE_ATOMIC_COUNTERS> }, { "gl_MaxComputeAtomicCounterBuffers", getInteger<GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS> }, { "gl_MaxVertexAtomicCounters", getInteger<GL_MAX_VERTEX_ATOMIC_COUNTERS> }, { "gl_MaxFragmentAtomicCounters", getInteger<GL_MAX_FRAGMENT_ATOMIC_COUNTERS> }, { "gl_MaxCombinedAtomicCounters", getInteger<GL_MAX_COMBINED_ATOMIC_COUNTERS> }, { "gl_MaxAtomicCounterBindings", getInteger<GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS> }, { "gl_MaxVertexAtomicCounterBuffers", getInteger<GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS> }, { "gl_MaxFragmentAtomicCounterBuffers", getInteger<GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS> }, { "gl_MaxCombinedAtomicCounterBuffers", getInteger<GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS> }, { "gl_MaxAtomicCounterBufferSize", getInteger<GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE> }, }; static const struct { const char* varName; ShaderBuiltinConstantCase<tcu::IVec3>::GetConstantValueFunc getValue; } ivec3Constants[] = { { "gl_MaxComputeWorkGroupCount", getIVec3<GL_MAX_COMPUTE_WORK_GROUP_COUNT> }, { "gl_MaxComputeWorkGroupSize", getIVec3<GL_MAX_COMPUTE_WORK_GROUP_SIZE> }, }; 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<int>(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<tcu::IVec3>(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<int>(m_context, "gl_MaxSamples", getInteger<GL_MAX_SAMPLES>, "GL_OES_sample_variables")); } // EXT_geometry_shader { static const struct { const char* varName; ShaderBuiltinConstantCase<int>::GetConstantValueFunc getValue; } intConstants[] = { { "gl_MaxGeometryInputComponents", getInteger<GL_MAX_GEOMETRY_INPUT_COMPONENTS> }, { "gl_MaxGeometryOutputComponents", getInteger<GL_MAX_GEOMETRY_OUTPUT_COMPONENTS> }, { "gl_MaxGeometryImageUniforms", getInteger<GL_MAX_GEOMETRY_IMAGE_UNIFORMS> }, { "gl_MaxGeometryTextureImageUnits", getInteger<GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS> }, { "gl_MaxGeometryOutputVertices", getInteger<GL_MAX_GEOMETRY_OUTPUT_VERTICES> }, { "gl_MaxGeometryTotalOutputComponents", getInteger<GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS> }, { "gl_MaxGeometryUniformComponents", getInteger<GL_MAX_GEOMETRY_UNIFORM_COMPONENTS> }, { "gl_MaxGeometryAtomicCounters", getInteger<GL_MAX_GEOMETRY_ATOMIC_COUNTERS> }, { "gl_MaxGeometryAtomicCounterBuffers", getInteger<GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS> }, }; 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<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_geometry_shader")); } // EXT_tessellation_shader { static const struct { const char* varName; ShaderBuiltinConstantCase<int>::GetConstantValueFunc getValue; } intConstants[] = { { "gl_MaxTessControlInputComponents", getInteger<GL_MAX_TESS_CONTROL_INPUT_COMPONENTS> }, { "gl_MaxTessControlOutputComponents", getInteger<GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS> }, { "gl_MaxTessControlTextureImageUnits", getInteger<GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS> }, { "gl_MaxTessControlUniformComponents", getInteger<GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS> }, { "gl_MaxTessControlTotalOutputComponents", getInteger<GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS> }, { "gl_MaxTessControlImageUniforms", getInteger<GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS> }, { "gl_MaxTessEvaluationImageUniforms", getInteger<GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS> }, { "gl_MaxTessControlAtomicCounters", getInteger<GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS> }, { "gl_MaxTessEvaluationAtomicCounters", getInteger<GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS> }, { "gl_MaxTessControlAtomicCounterBuffers", getInteger<GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS> }, { "gl_MaxTessEvaluationAtomicCounterBuffers", getInteger<GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS> }, { "gl_MaxTessEvaluationInputComponents", getInteger<GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS> }, { "gl_MaxTessEvaluationOutputComponents", getInteger<GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS> }, { "gl_MaxTessEvaluationTextureImageUnits", getInteger<GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS> }, { "gl_MaxTessEvaluationUniformComponents", getInteger<GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS> }, { "gl_MaxTessPatchComponents", getInteger<GL_MAX_TESS_PATCH_COMPONENTS> }, { "gl_MaxPatchVertices", getInteger<GL_MAX_PATCH_VERTICES> }, { "gl_MaxTessGenLevel", getInteger<GL_MAX_TESS_GEN_LEVEL> }, }; 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<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_tessellation_shader")); } } } // Functional } // gles31 } // deqp