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