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
versionGreaterOrEqual(ApiType a,ApiType b)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
contextSupports(ContextType ctxType,ApiType requiredApiType)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
parseContextFlags(const std::string & flagsStr)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
createDefaultRenderContext(tcu::Platform & platform,const tcu::CommandLine & cmdLine,ApiType apiType)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
getExtensions(const glw::Functions & gl,ApiType apiType)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
initCoreFunctions(glw::Functions * dst,const glw::FunctionLoader * loader,ApiType apiType)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
initExtensionFunctions(glw::Functions * dst,const glw::FunctionLoader * loader,ApiType apiType)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
initExtensionFunctions(glw::Functions * dst,const glw::FunctionLoader * loader,ApiType apiType,int numExtensions,const char * const * extensions)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
initFunctions(glw::Functions * dst,const glw::FunctionLoader * loader,ApiType apiType)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