| /*------------------------------------------------------------------------- |
| * 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<std::string> 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<std::string>::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& registry = 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<std::string> 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<string> 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<std::string> 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 }, |
| }; |
| |
| 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<std::string> extensions = getExtensions(*dst, apiType); |
| |
| if (!extensions.empty()) |
| { |
| std::vector<const char*> 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 return DE_NULL; |
| } |
| |
| } // glu |