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