/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES Utilities * ------------------------------------------------ * * 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 OpenGL ES rendering context. *//*--------------------------------------------------------------------*/ #include "gluRenderContext.hpp" #include "gluDefs.hpp" #include "gluRenderConfig.hpp" #include "gluES3PlusWrapperContext.hpp" #include "gluFboRenderContext.hpp" #include "gluPlatform.hpp" #include "gluStrUtil.hpp" #include "glwInitFunctions.hpp" #include "glwEnums.hpp" #include "tcuPlatform.hpp" #include "tcuCommandLine.hpp" #include "deStringUtil.hpp" #include "deSTLUtil.hpp" namespace glu { inline bool versionGreaterOrEqual (ApiType a, ApiType b) { return a.getMajorVersion() > b.getMajorVersion() || (a.getMajorVersion() == b.getMajorVersion() && a.getMinorVersion() >= b.getMinorVersion()); } bool contextSupports (ContextType ctxType, ApiType requiredApiType) { // \todo [2014-10-06 pyry] Check exact forward-compatible restrictions. const bool forwardCompatible = (ctxType.getFlags() & CONTEXT_FORWARD_COMPATIBLE) != 0; if (isContextTypeES(ctxType)) { DE_ASSERT(!forwardCompatible); return requiredApiType.getProfile() == PROFILE_ES && versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); } else if (isContextTypeGLCore(ctxType)) { if (forwardCompatible) return ctxType.getAPI() == requiredApiType; else return requiredApiType.getProfile() == PROFILE_CORE && versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); } else if (isContextTypeGLCompatibility(ctxType)) { DE_ASSERT(!forwardCompatible); return (requiredApiType.getProfile() == PROFILE_CORE || requiredApiType.getProfile() == PROFILE_COMPATIBILITY) && versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); } else { DE_ASSERT(false); return false; } } static ContextFlags parseContextFlags (const std::string& flagsStr) { const std::vector flagNames = de::splitString(flagsStr, ','); ContextFlags flags = ContextFlags(0); static const struct { const char* name; ContextFlags flag; } s_flagMap[] = { { "debug", CONTEXT_DEBUG }, { "robust", CONTEXT_ROBUST } }; for (std::vector::const_iterator flagIter = flagNames.begin(); flagIter != flagNames.end(); ++flagIter) { int ndx; for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_flagMap); ndx++) { if (*flagIter == s_flagMap[ndx].name) { flags = flags | s_flagMap[ndx].flag; break; } } if (ndx == DE_LENGTH_OF_ARRAY(s_flagMap)) { tcu::print("ERROR: Unrecognized GL context flag '%s'\n", flagIter->c_str()); tcu::print("Supported GL context flags:\n"); for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_flagMap); ndx++) tcu::print(" %s\n", s_flagMap[ndx].name); throw tcu::NotSupportedError((std::string("Unknown GL context flag '") + *flagIter + "'").c_str(), DE_NULL, __FILE__, __LINE__); } } return flags; } RenderContext* createDefaultRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, ApiType apiType) { const ContextFactoryRegistry& registry = platform.getGLPlatform().getContextFactoryRegistry(); RenderConfig config; const char* factoryName = cmdLine.getGLContextType(); const ContextFactory* factory = DE_NULL; ContextFlags ctxFlags = ContextFlags(0); if (registry.empty()) throw tcu::NotSupportedError("OpenGL is not supported", DE_NULL, __FILE__, __LINE__); if (cmdLine.getGLContextFlags()) ctxFlags = parseContextFlags(cmdLine.getGLContextFlags()); config.type = glu::ContextType(apiType, ctxFlags); parseRenderConfig(&config, cmdLine); if (factoryName) { factory = registry.getFactoryByName(factoryName); if (!factory) { tcu::print("ERROR: Unknown or unsupported GL context type '%s'\n", factoryName); tcu::print("Supported GL context types:\n"); for (int factoryNdx = 0; factoryNdx < (int)registry.getFactoryCount(); factoryNdx++) { const ContextFactory* curFactory = registry.getFactoryByIndex(factoryNdx); tcu::print(" %s: %s\n", curFactory->getName(), curFactory->getDescription()); } throw tcu::NotSupportedError((std::string("Unknown GL context type '") + factoryName + "'").c_str(), DE_NULL, __FILE__, __LINE__); } } else factory = registry.getDefaultFactory(); if (cmdLine.getSurfaceType() == tcu::SURFACETYPE_FBO) return new FboRenderContext(*factory, config, cmdLine); else return factory->createContext(config, cmdLine); } static std::vector getExtensions (const glw::Functions& gl, ApiType apiType) { using std::vector; using std::string; if (apiType.getProfile() == PROFILE_ES && apiType.getMajorVersion() == 2) { TCU_CHECK(gl.getString); const char* extStr = (const char*)gl.getString(GL_EXTENSIONS); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetString(GL_EXTENSIONS)"); if (extStr) return de::splitString(extStr); else throw tcu::TestError("glGetString(GL_EXTENSIONS) returned null pointer", DE_NULL, __FILE__, __LINE__); } else { int numExtensions = 0; vector extensions; TCU_CHECK(gl.getIntegerv && gl.getStringi); gl.getIntegerv(GL_NUM_EXTENSIONS, &numExtensions); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_NUM_EXTENSIONS)"); if (numExtensions > 0) { extensions.resize(numExtensions); for (int ndx = 0; ndx < numExtensions; ndx++) { const char* const ext = (const char*)gl.getStringi(GL_EXTENSIONS, ndx); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetStringi(GL_EXTENSIONS)"); if (ext) extensions[ndx] = ext; else throw tcu::TestError("glGetStringi(GL_EXTENSIONS) returned null pointer", DE_NULL, __FILE__, __LINE__); } } return extensions; } } bool hasExtension (const glw::Functions& gl, ApiType apiType, const std::string& extension) { std::vector extensions(getExtensions(gl, apiType)); return de::contains(extensions.begin(), extensions.end(), extension); } void initCoreFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) { static const struct { ApiType apiType; void (*initFunc) (glw::Functions* gl, const glw::FunctionLoader* loader); } s_initFuncs[] = { { ApiType::es(2,0), glw::initES20 }, { ApiType::es(3,0), glw::initES30 }, { ApiType::es(3,1), glw::initES31 }, { ApiType::es(3,2), glw::initES32 }, { ApiType::core(3,0), glw::initGL30Core }, { ApiType::core(3,1), glw::initGL31Core }, { ApiType::core(3,2), glw::initGL32Core }, { ApiType::core(3,3), glw::initGL33Core }, { ApiType::core(4,0), glw::initGL40Core }, { ApiType::core(4,1), glw::initGL41Core }, { ApiType::core(4,2), glw::initGL42Core }, { ApiType::core(4,3), glw::initGL43Core }, { ApiType::core(4,4), glw::initGL44Core }, }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_initFuncs); ndx++) { if (s_initFuncs[ndx].apiType == apiType) { s_initFuncs[ndx].initFunc(dst, loader); return; } } throw tcu::InternalError(std::string("Don't know how to load functions for ") + de::toString(apiType)); } void initExtensionFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) { std::vector extensions = getExtensions(*dst, apiType); if (!extensions.empty()) { std::vector extStr(extensions.size()); for (size_t ndx = 0; ndx < extensions.size(); ndx++) extStr[ndx] = extensions[ndx].c_str(); initExtensionFunctions(dst, loader, apiType, (int)extStr.size(), &extStr[0]); } } void initExtensionFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType, int numExtensions, const char* const* extensions) { if (apiType.getProfile() == PROFILE_ES) glw::initExtensionsES(dst, loader, numExtensions, extensions); else glw::initExtensionsGL(dst, loader, numExtensions, extensions); } void initFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) { initCoreFunctions(dst, loader, apiType); initExtensionFunctions(dst, loader, apiType); } } // glu