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 37 namespace glu 38 { 39 40 inline bool versionGreaterOrEqual (ApiType a, ApiType b) 41 { 42 return a.getMajorVersion() > b.getMajorVersion() || 43 (a.getMajorVersion() == b.getMajorVersion() && a.getMinorVersion() >= b.getMinorVersion()); 44 } 45 46 bool contextSupports (ContextType ctxType, ApiType requiredApiType) 47 { 48 // \todo [2014-10-06 pyry] Check exact forward-compatible restrictions. 49 const bool forwardCompatible = (ctxType.getFlags() & CONTEXT_FORWARD_COMPATIBLE) != 0; 50 51 if (isContextTypeES(ctxType)) 52 { 53 DE_ASSERT(!forwardCompatible); 54 return requiredApiType.getProfile() == PROFILE_ES && 55 versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); 56 } 57 else if (isContextTypeGLCore(ctxType)) 58 { 59 if (forwardCompatible) 60 return ctxType.getAPI() == requiredApiType; 61 else 62 return requiredApiType.getProfile() == PROFILE_CORE && 63 versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); 64 } 65 else if (isContextTypeGLCompatibility(ctxType)) 66 { 67 DE_ASSERT(!forwardCompatible); 68 return (requiredApiType.getProfile() == PROFILE_CORE || requiredApiType.getProfile() == PROFILE_COMPATIBILITY) && 69 versionGreaterOrEqual(ctxType.getAPI(), requiredApiType); 70 } 71 else 72 { 73 DE_ASSERT(false); 74 return false; 75 } 76 } 77 78 static ContextFlags parseContextFlags (const std::string& flagsStr) 79 { 80 const std::vector<std::string> flagNames = de::splitString(flagsStr, ','); 81 ContextFlags flags = ContextFlags(0); 82 static const struct 83 { 84 const char* name; 85 ContextFlags flag; 86 } s_flagMap[] = 87 { 88 { "debug", CONTEXT_DEBUG }, 89 { "robust", CONTEXT_ROBUST } 90 }; 91 92 for (std::vector<std::string>::const_iterator flagIter = flagNames.begin(); flagIter != flagNames.end(); ++flagIter) 93 { 94 int ndx; 95 for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_flagMap); ndx++) 96 { 97 if (*flagIter == s_flagMap[ndx].name) 98 { 99 flags = flags | s_flagMap[ndx].flag; 100 break; 101 } 102 } 103 104 if (ndx == DE_LENGTH_OF_ARRAY(s_flagMap)) 105 { 106 tcu::print("ERROR: Unrecognized GL context flag '%s'\n", flagIter->c_str()); 107 tcu::print("Supported GL context flags:\n"); 108 109 for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_flagMap); ndx++) 110 tcu::print(" %s\n", s_flagMap[ndx].name); 111 112 throw tcu::NotSupportedError((std::string("Unknown GL context flag '") + *flagIter + "'").c_str(), DE_NULL, __FILE__, __LINE__); 113 } 114 } 115 116 return flags; 117 } 118 119 RenderContext* createDefaultRenderContext (tcu::Platform& platform, const tcu::CommandLine& cmdLine, ApiType apiType) 120 { 121 const ContextFactoryRegistry& registry = platform.getGLPlatform().getContextFactoryRegistry(); 122 RenderConfig config; 123 const char* factoryName = cmdLine.getGLContextType(); 124 const ContextFactory* factory = DE_NULL; 125 ContextFlags ctxFlags = ContextFlags(0); 126 127 if (registry.empty()) 128 throw tcu::NotSupportedError("OpenGL is not supported", DE_NULL, __FILE__, __LINE__); 129 130 if (cmdLine.getGLContextFlags()) 131 ctxFlags = parseContextFlags(cmdLine.getGLContextFlags()); 132 133 config.type = glu::ContextType(apiType, ctxFlags); 134 parseRenderConfig(&config, cmdLine); 135 136 if (factoryName) 137 { 138 factory = registry.getFactoryByName(factoryName); 139 140 if (!factory) 141 { 142 tcu::print("ERROR: Unknown or unsupported GL context type '%s'\n", factoryName); 143 tcu::print("Supported GL context types:\n"); 144 145 for (int factoryNdx = 0; factoryNdx < (int)registry.getFactoryCount(); factoryNdx++) 146 { 147 const ContextFactory* curFactory = registry.getFactoryByIndex(factoryNdx); 148 tcu::print(" %s: %s\n", curFactory->getName(), curFactory->getDescription()); 149 } 150 151 throw tcu::NotSupportedError((std::string("Unknown GL context type '") + factoryName + "'").c_str(), DE_NULL, __FILE__, __LINE__); 152 } 153 } 154 else 155 factory = registry.getDefaultFactory(); 156 157 try 158 { 159 if (cmdLine.getSurfaceType() == tcu::SURFACETYPE_FBO) 160 return new FboRenderContext(*factory, config, cmdLine); 161 else 162 return factory->createContext(config, cmdLine); 163 164 } 165 catch (const std::exception&) 166 { 167 // If ES31 context is not available, try using wrapper. 168 if (config.type.getAPI() == ApiType::es(3,1)) 169 { 170 tcu::print("Warning: Unable to create native OpenGL ES 3.1 context, will use wrapper context.\n"); 171 return new ES3PlusWrapperContext(*factory, config, cmdLine); 172 } 173 else 174 throw; 175 } 176 } 177 178 static std::vector<std::string> getExtensions (const glw::Functions& gl, ApiType apiType) 179 { 180 using std::vector; 181 using std::string; 182 183 if (apiType.getProfile() == PROFILE_ES && apiType.getMajorVersion() == 2) 184 { 185 TCU_CHECK(gl.getString); 186 187 const char* extStr = (const char*)gl.getString(GL_EXTENSIONS); 188 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetString(GL_EXTENSIONS)"); 189 190 if (extStr) 191 return de::splitString(extStr); 192 else 193 throw tcu::TestError("glGetString(GL_EXTENSIONS) returned null pointer", DE_NULL, __FILE__, __LINE__); 194 } 195 else 196 { 197 int numExtensions = 0; 198 vector<string> extensions; 199 200 TCU_CHECK(gl.getIntegerv && gl.getStringi); 201 202 gl.getIntegerv(GL_NUM_EXTENSIONS, &numExtensions); 203 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_NUM_EXTENSIONS)"); 204 205 if (numExtensions > 0) 206 { 207 extensions.resize(numExtensions); 208 209 for (int ndx = 0; ndx < numExtensions; ndx++) 210 { 211 const char* const ext = (const char*)gl.getStringi(GL_EXTENSIONS, ndx); 212 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetStringi(GL_EXTENSIONS)"); 213 214 if (ext) 215 extensions[ndx] = ext; 216 else 217 throw tcu::TestError("glGetStringi(GL_EXTENSIONS) returned null pointer", DE_NULL, __FILE__, __LINE__); 218 } 219 220 } 221 222 return extensions; 223 } 224 } 225 226 void initCoreFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) 227 { 228 static const struct 229 { 230 ApiType apiType; 231 void (*initFunc) (glw::Functions* gl, const glw::FunctionLoader* loader); 232 } s_initFuncs[] = 233 { 234 { ApiType::es(2,0), glw::initES20 }, 235 { ApiType::es(3,0), glw::initES30 }, 236 { ApiType::es(3,1), glw::initES31 }, 237 { ApiType::core(3,0), glw::initGL30Core }, 238 { ApiType::core(3,1), glw::initGL31Core }, 239 { ApiType::core(3,2), glw::initGL32Core }, 240 { ApiType::core(3,3), glw::initGL33Core }, 241 { ApiType::core(4,0), glw::initGL40Core }, 242 { ApiType::core(4,1), glw::initGL41Core }, 243 { ApiType::core(4,2), glw::initGL42Core }, 244 { ApiType::core(4,3), glw::initGL43Core }, 245 { ApiType::core(4,4), glw::initGL44Core }, 246 }; 247 248 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_initFuncs); ndx++) 249 { 250 if (s_initFuncs[ndx].apiType == apiType) 251 { 252 s_initFuncs[ndx].initFunc(dst, loader); 253 return; 254 } 255 } 256 257 throw tcu::InternalError(std::string("Don't know how to load functions for ") + de::toString(apiType)); 258 } 259 260 void initExtensionFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) 261 { 262 std::vector<std::string> extensions = getExtensions(*dst, apiType); 263 264 if (!extensions.empty()) 265 { 266 std::vector<const char*> extStr(extensions.size()); 267 268 for (size_t ndx = 0; ndx < extensions.size(); ndx++) 269 extStr[ndx] = extensions[ndx].c_str(); 270 271 initExtensionFunctions(dst, loader, apiType, (int)extStr.size(), &extStr[0]); 272 } 273 } 274 275 void initExtensionFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType, int numExtensions, const char* const* extensions) 276 { 277 if (apiType.getProfile() == PROFILE_ES) 278 glw::initExtensionsES(dst, loader, numExtensions, extensions); 279 else 280 glw::initExtensionsGL(dst, loader, numExtensions, extensions); 281 } 282 283 void initFunctions (glw::Functions* dst, const glw::FunctionLoader* loader, ApiType apiType) 284 { 285 initCoreFunctions(dst, loader, apiType); 286 initExtensionFunctions(dst, loader, apiType); 287 } 288 289 } // glu 290