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