/*------------------------------------------------------------------------- * 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 "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 { // RenderContext glw::GenericFuncType RenderContext::getProcAddress(const char *) const { return (glw::GenericFuncType)DE_NULL; } void RenderContext::makeCurrent(void) { TCU_THROW(InternalError, "RenderContext::makeCurrent() is not implemented"); } // Utilities 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 *createRenderContext(tcu::Platform &platform, const tcu::CommandLine &cmdLine, const RenderConfig &config, const RenderContext *sharedContext) { const ContextFactoryRegistry ®istry = platform.getGLPlatform().getContextFactoryRegistry(); const char *factoryName = cmdLine.getGLContextType(); const ContextFactory *factory = DE_NULL; if (registry.empty()) throw tcu::NotSupportedError("OpenGL is not supported", DE_NULL, __FILE__, __LINE__); 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) { if (sharedContext) TCU_FAIL("Shared context not implemented for FBO surface type"); return new FboRenderContext(*factory, config, cmdLine); } else return factory->createContext(config, cmdLine, sharedContext); } RenderContext *createDefaultRenderContext(tcu::Platform &platform, const tcu::CommandLine &cmdLine, ApiType apiType) { RenderConfig config; ContextFlags ctxFlags = ContextFlags(0); if (cmdLine.getGLContextFlags()) ctxFlags = parseContextFlags(cmdLine.getGLContextFlags()); config.type = glu::ContextType(apiType, ctxFlags); parseRenderConfig(&config, cmdLine); return createRenderContext(platform, cmdLine, config); } static std::vector getExtensions(const glw::Functions &gl, ApiType apiType) { using std::string; using std::vector; 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}, {ApiType::core(4, 5), glw::initGL45Core}, {ApiType::core(4, 6), glw::initGL46Core}, // TODO: initialise actual compat functions rather than using core as a dummy {ApiType::compatibility(3, 2), glw::initGL32Core}, {ApiType::compatibility(3, 3), glw::initGL33Core}, {ApiType::compatibility(4, 0), glw::initGL40Core}, {ApiType::compatibility(4, 1), glw::initGL41Core}, {ApiType::compatibility(4, 2), glw::initGL42Core}, {ApiType::compatibility(4, 3), glw::initGL43Core}, {ApiType::compatibility(4, 4), glw::initGL44Core}, {ApiType::compatibility(4, 5), glw::initGL45Core}, {ApiType::compatibility(4, 6), glw::initGL46Core}, }; 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); } const char *getApiTypeDescription(ApiType type) { if (type == glu::ApiType::es(2, 0)) return "OpenGL ES 2"; else if (type == glu::ApiType::es(3, 0)) return "OpenGL ES 3"; else if (type == glu::ApiType::es(3, 1)) return "OpenGL ES 3.1"; else if (type == glu::ApiType::es(3, 2)) return "OpenGL ES 3.2"; else if (type == glu::ApiType::core(3, 0)) return "OpenGL 3.0 core"; else if (type == glu::ApiType::core(3, 1)) return "OpenGL 3.1 core"; else if (type == glu::ApiType::core(3, 2)) return "OpenGL 3.2 core"; else if (type == glu::ApiType::core(3, 3)) return "OpenGL 3.3 core"; else if (type == glu::ApiType::core(4, 0)) return "OpenGL 4.0 core"; else if (type == glu::ApiType::core(4, 1)) return "OpenGL 4.1 core"; else if (type == glu::ApiType::core(4, 2)) return "OpenGL 4.2 core"; else if (type == glu::ApiType::core(4, 3)) return "OpenGL 4.3 core"; else if (type == glu::ApiType::core(4, 4)) return "OpenGL 4.4 core"; else if (type == glu::ApiType::core(4, 5)) return "OpenGL 4.5 core"; else if (type == glu::ApiType::core(4, 6)) return "OpenGL 4.6 core"; else if (type == glu::ApiType::compatibility(3, 2)) return "OpenGL 3.2 compatibility"; else if (type == glu::ApiType::compatibility(3, 3)) return "OpenGL 3.3 compatibility"; else if (type == glu::ApiType::compatibility(4, 0)) return "OpenGL 4.0 compatibility"; else if (type == glu::ApiType::compatibility(4, 1)) return "OpenGL 4.1 compatibility"; else if (type == glu::ApiType::compatibility(4, 2)) return "OpenGL 4.2 compatibility"; else if (type == glu::ApiType::compatibility(4, 3)) return "OpenGL 4.3 compatibility"; else if (type == glu::ApiType::compatibility(4, 4)) return "OpenGL 4.4 compatibility"; else if (type == glu::ApiType::compatibility(4, 5)) return "OpenGL 4.5 compatibility"; else if (type == glu::ApiType::compatibility(4, 6)) return "OpenGL 4.6 compatibility"; else return DE_NULL; } } // namespace glu