1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 3 * ------------------------------------------------ 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief OpenGL ES rendering context. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "gluRenderContext.hpp" 25 #include "gluDefs.hpp" 26 #include "gluRenderConfig.hpp" 27 #include "gluES3PlusWrapperContext.hpp" 28 #include "gluFboRenderContext.hpp" 29 #include "gluPlatform.hpp" 30 #include "gluStrUtil.hpp" 31 #include "glwInitFunctions.hpp" 32 #include "glwEnums.hpp" 33 #include "tcuPlatform.hpp" 34 #include "tcuCommandLine.hpp" 35 #include "deStringUtil.hpp" 36 #include "deSTLUtil.hpp" 37 38 namespace glu 39 { 40 41 inline bool versionGreaterOrEqual (ApiType a, ApiType b) 42 { 43 return a.getMajorVersion() > b.getMajorVersion() || 44 (a.getMajorVersion() == b.getMajorVersion() && a.getMinorVersion() >= b.getMinorVersion()); 45 } 46 47 bool contextSupports (ContextType ctxType, ApiType requiredApiType) 48 { 49 // \todo [2014-10-06 pyry] Check exact forward-compatible restrictions. 50 const bool forwardCompatible = (ctxType.getFlags() & CONTEXT_FORWARD_COMPATIBLE) != 0; 51 52 if (isContextTypeES(ctxType)) 53 { 54 DE_ASSERT(!forwardCompatible); 55 return requiredApiType.getProfile() == PROFILE_ES && 56 versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); 57 } 58 else if (isContextTypeGLCore(ctxType)) 59 { 60 if (forwardCompatible) 61 return ctxType.getAPI() == requiredApiType; 62 else 63 return requiredApiType.getProfile() == PROFILE_CORE && 64 versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); 65 } 66 else if (isContextTypeGLCompatibility(ctxType)) 67 { 68 DE_ASSERT(!forwardCompatible); 69 return (requiredApiType.getProfile() == PROFILE_CORE || requiredApiType.getProfile() == PROFILE_COMPATIBILITY) && 70 versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); 71 } 72 else 73 { 74 DE_ASSERT(false); 75 return false; 76 } 77 } 78 79 static ContextFlags parseContextFlags (const std::string& flagsStr) 80 { 81 const std::vector<std::string> flagNames = de::splitString(flagsStr, ','); 82 ContextFlags flags = ContextFlags(0); 83 static const struct 84 { 85 const char* name; 86 ContextFlags flag; 87 } s_flagMap[] = 88 { 89 { "debug", CONTEXT_DEBUG }, 90 { "robust", CONTEXT_ROBUST } 91 }; 92 93 for (std::vector<std::string>::const_iterator flagIter = flagNames.begin(); flagIter != flagNames.end(); ++flagIter) 94 { 95 int ndx; 96 for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_flagMap); ndx++) 97 { 98 if (*flagIter == s_flagMap[ndx].name) 99 { 100 flags = flags | s_flagMap[ndx].flag; 101 break; 102 } 103 } 104 105 if (ndx == DE_LENGTH_OF_ARRAY(s_flagMap)) 106 { 107 tcu::print("ERROR: Unrecognized GL context flag '%s'\n", flagIter->c_str()); 108 tcu::print("Supported GL context flags:\n"); 109 110 for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_flagMap); ndx++) 111 tcu::print(" %s\n", s_flagMap[ndx].name); 112 113 throw tcu::NotSupportedError((std::string("Unknown GL context flag '") + *flagIter + "'").c_str(), DE_NULL, __FILE__, __LINE__); 114 } 115 } 116 117 return flags; 118 } 119 120 RenderContext* createDefaultRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, ApiType apiType) 121 { 122 const ContextFactoryRegistry& registry = platform.getGLPlatform().getContextFactoryRegistry(); 123 RenderConfig config; 124 const char* factoryName = cmdLine.getGLContextType(); 125 const ContextFactory* factory = DE_NULL; 126 ContextFlags ctxFlags = ContextFlags(0); 127 128 if (registry.empty()) 129 throw tcu::NotSupportedError("OpenGL is not supported", DE_NULL, __FILE__, __LINE__); 130 131 if (cmdLine.getGLContextFlags()) 132 ctxFlags = parseContextFlags(cmdLine.getGLContextFlags()); 133 134 config.type = glu::ContextType(apiType, ctxFlags); 135 parseRenderConfig(&config, cmdLine); 136 137 if (factoryName) 138 { 139 factory = registry.getFactoryByName(factoryName); 140 141 if (!factory) 142 { 143 tcu::print("ERROR: Unknown or unsupported GL context type '%s'\n", factoryName); 144 tcu::print("Supported GL context types:\n"); 145 146 for (int factoryNdx = 0; factoryNdx < (int)registry.getFactoryCount(); factoryNdx++) 147 { 148 const ContextFactory* curFactory = registry.getFactoryByIndex(factoryNdx); 149 tcu::print(" %s: %s\n", curFactory->getName(), curFactory->getDescription()); 150 } 151 152 throw tcu::NotSupportedError((std::string("Unknown GL context type '") + factoryName + "'").c_str(), DE_NULL, __FILE__, __LINE__); 153 } 154 } 155 else 156 factory = registry.getDefaultFactory(); 157 158 if (cmdLine.getSurfaceType() == tcu::SURFACETYPE_FBO) 159 return new FboRenderContext(*factory, config, cmdLine); 160 else 161 return factory->createContext(config, cmdLine); 162 } 163 164 static std::vector<std::string> getExtensions (const glw::Functions& gl, ApiType apiType) 165 { 166 using std::vector; 167 using std::string; 168 169 if (apiType.getProfile() == PROFILE_ES && apiType.getMajorVersion() == 2) 170 { 171 TCU_CHECK(gl.getString); 172 173 const char* extStr = (const char*)gl.getString(GL_EXTENSIONS); 174 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetString(GL_EXTENSIONS)"); 175 176 if (extStr) 177 return de::splitString(extStr); 178 else 179 throw tcu::TestError("glGetString(GL_EXTENSIONS) returned null pointer", DE_NULL, __FILE__, __LINE__); 180 } 181 else 182 { 183 int numExtensions = 0; 184 vector<string> extensions; 185 186 TCU_CHECK(gl.getIntegerv && gl.getStringi); 187 188 gl.getIntegerv(GL_NUM_EXTENSIONS, &numExtensions); 189 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_NUM_EXTENSIONS)"); 190 191 if (numExtensions > 0) 192 { 193 extensions.resize(numExtensions); 194 195 for (int ndx = 0; ndx < numExtensions; ndx++) 196 { 197 const char* const ext = (const char*)gl.getStringi(GL_EXTENSIONS, ndx); 198 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetStringi(GL_EXTENSIONS)"); 199 200 if (ext) 201 extensions[ndx] = ext; 202 else 203 throw tcu::TestError("glGetStringi(GL_EXTENSIONS) returned null pointer", DE_NULL, __FILE__, __LINE__); 204 } 205 206 } 207 208 return extensions; 209 } 210 } 211 212 bool hasExtension (const glw::Functions& gl, ApiType apiType, const std::string& extension) 213 { 214 std::vector<std::string> extensions(getExtensions(gl, apiType)); 215 216 return de::contains(extensions.begin(), extensions.end(), extension); 217 } 218 219 void initCoreFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) 220 { 221 static const struct 222 { 223 ApiType apiType; 224 void (*initFunc) (glw::Functions* gl, const glw::FunctionLoader* loader); 225 } s_initFuncs[] = 226 { 227 { ApiType::es(2,0), glw::initES20 }, 228 { ApiType::es(3,0), glw::initES30 }, 229 { ApiType::es(3,1), glw::initES31 }, 230 { ApiType::es(3,2), glw::initES32 }, 231 { ApiType::core(3,0), glw::initGL30Core }, 232 { ApiType::core(3,1), glw::initGL31Core }, 233 { ApiType::core(3,2), glw::initGL32Core }, 234 { ApiType::core(3,3), glw::initGL33Core }, 235 { ApiType::core(4,0), glw::initGL40Core }, 236 { ApiType::core(4,1), glw::initGL41Core }, 237 { ApiType::core(4,2), glw::initGL42Core }, 238 { ApiType::core(4,3), glw::initGL43Core }, 239 { ApiType::core(4,4), glw::initGL44Core }, 240 }; 241 242 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_initFuncs); ndx++) 243 { 244 if (s_initFuncs[ndx].apiType == apiType) 245 { 246 s_initFuncs[ndx].initFunc(dst, loader); 247 return; 248 } 249 } 250 251 throw tcu::InternalError(std::string("Don't know how to load functions for ") + de::toString(apiType)); 252 } 253 254 void initExtensionFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) 255 { 256 std::vector<std::string> extensions = getExtensions(*dst, apiType); 257 258 if (!extensions.empty()) 259 { 260 std::vector<const char*> extStr(extensions.size()); 261 262 for (size_t ndx = 0; ndx < extensions.size(); ndx++) 263 extStr[ndx] = extensions[ndx].c_str(); 264 265 initExtensionFunctions(dst, loader, apiType, (int)extStr.size(), &extStr[0]); 266 } 267 } 268 269 void initExtensionFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType, int numExtensions, const char* const* extensions) 270 { 271 if (apiType.getProfile() == PROFILE_ES) 272 glw::initExtensionsES(dst, loader, numExtensions, extensions); 273 else 274 glw::initExtensionsGL(dst, loader, numExtensions, extensions); 275 } 276 277 void initFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) 278 { 279 initCoreFunctions(dst, loader, apiType); 280 initExtensionFunctions(dst, loader, apiType); 281 } 282 283 } // glu 284