1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
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 EGL utilities
22  *//*--------------------------------------------------------------------*/
23 
24 #include "egluUtil.hpp"
25 #include "egluDefs.hpp"
26 #include "egluNativeDisplay.hpp"
27 #include "egluConfigFilter.hpp"
28 #include "eglwLibrary.hpp"
29 #include "eglwEnums.hpp"
30 #include "tcuCommandLine.hpp"
31 #include "deSTLUtil.hpp"
32 #include "deStringUtil.hpp"
33 #include "glwEnums.hpp"
34 
35 #include <algorithm>
36 #include <sstream>
37 
38 using std::string;
39 using std::vector;
40 
41 namespace eglu
42 {
43 
44 using namespace eglw;
45 
attribMapToList(const AttribMap & attribs)46 vector<EGLint> attribMapToList (const AttribMap& attribs)
47 {
48 	vector<EGLint> attribList;
49 
50 	for (AttribMap::const_iterator it = attribs.begin(); it != attribs.end(); ++it)
51 	{
52 		attribList.push_back(it->first);
53 		attribList.push_back(it->second);
54 	}
55 
56 	attribList.push_back(EGL_NONE);
57 
58 	return attribList;
59 }
60 
getVersion(const Library & egl,EGLDisplay display)61 Version getVersion (const Library& egl, EGLDisplay display)
62 {
63 	EGLint major, minor;
64 
65 	// eglInitialize on already initialized displays just returns the version.
66 	EGLU_CHECK_CALL(egl, initialize(display, &major, &minor));
67 
68 	return Version(major, minor);
69 }
70 
getExtensions(const Library & egl,EGLDisplay display)71 vector<string> getExtensions (const Library& egl, EGLDisplay display)
72 {
73 	const char*	const extensionStr = egl.queryString(display, EGL_EXTENSIONS);
74 
75 	EGLU_CHECK_MSG(egl, "Querying extensions failed");
76 
77 	return de::splitString(extensionStr, ' ');
78 }
79 
hasExtension(const Library & egl,EGLDisplay display,const string & str)80 bool hasExtension (const Library& egl, EGLDisplay display, const string& str)
81 {
82 	const vector<string> extensions = getExtensions(egl, display);
83 	return de::contains(extensions.begin(), extensions.end(), str);
84 }
85 
getPlatformExtensions(const Library & egl)86 vector<string> getPlatformExtensions (const Library& egl)
87 {
88 	return getExtensions(egl, EGL_NO_DISPLAY);
89 }
90 
getClientExtensions(const Library & egl,EGLDisplay display)91 vector<string> getClientExtensions (const Library& egl, EGLDisplay display)
92 {
93 	DE_ASSERT(display != EGL_NO_DISPLAY);
94 
95 	return getExtensions(egl, display);
96 }
97 
getConfigs(const Library & egl,EGLDisplay display)98 vector<EGLConfig> getConfigs (const Library& egl, EGLDisplay display)
99 {
100 	vector<EGLConfig>	configs;
101 	EGLint				configCount	= 0;
102 	EGLU_CHECK_CALL(egl, getConfigs(display, DE_NULL, 0, &configCount));
103 
104 	if (configCount > 0)
105 	{
106 		configs.resize(configCount);
107 		EGLU_CHECK_CALL(egl, getConfigs(display, &(configs[0]), (EGLint)configs.size(), &configCount));
108 	}
109 
110 	return configs;
111 }
112 
chooseConfigs(const Library & egl,EGLDisplay display,const EGLint * attribList)113 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const EGLint* attribList)
114 {
115 	EGLint	numConfigs	= 0;
116 
117 	EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, DE_NULL, 0, &numConfigs));
118 
119 	{
120 		vector<EGLConfig> configs(numConfigs);
121 
122 		if (numConfigs > 0)
123 			EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, &configs.front(), numConfigs, &numConfigs));
124 
125 		return configs;
126 	}
127 }
128 
chooseConfigs(const Library & egl,EGLDisplay display,const FilterList & filters)129 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const FilterList& filters)
130 {
131 	const vector<EGLConfig>	allConfigs		(getConfigs(egl, display));
132 	vector<EGLConfig>		matchingConfigs;
133 
134 	for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg)
135 	{
136 		if (filters.match(egl, display, *cfg))
137 			matchingConfigs.push_back(*cfg);
138 	}
139 
140 	return matchingConfigs;
141 }
142 
chooseSingleConfig(const Library & egl,EGLDisplay display,const FilterList & filters)143 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const FilterList& filters)
144 {
145 	const vector<EGLConfig>	allConfigs	(getConfigs(egl, display));
146 
147 	for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg)
148 	{
149 		if (filters.match(egl, display, *cfg))
150 			return *cfg;
151 	}
152 
153 	TCU_THROW(NotSupportedError, "No matching EGL config found");
154 }
155 
chooseSingleConfig(const Library & egl,EGLDisplay display,const EGLint * attribList)156 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const EGLint* attribList)
157 {
158 	const vector<EGLConfig> configs (chooseConfigs(egl, display, attribList));
159 	if (configs.empty())
160 		TCU_THROW(NotSupportedError, "No matching EGL config found");
161 
162 	return configs.front();
163 }
164 
chooseConfigs(const Library & egl,EGLDisplay display,const AttribMap & attribs)165 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const AttribMap& attribs)
166 {
167 	const vector<EGLint>	attribList	= attribMapToList(attribs);
168 	return chooseConfigs(egl, display, &attribList.front());
169 }
170 
chooseSingleConfig(const Library & egl,EGLDisplay display,const AttribMap & attribs)171 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const AttribMap& attribs)
172 {
173 	const vector<EGLint>	attribList	= attribMapToList(attribs);
174 	return chooseSingleConfig(egl, display, &attribList.front());
175 }
176 
chooseConfigByID(const Library & egl,EGLDisplay display,EGLint id)177 EGLConfig chooseConfigByID (const Library& egl, EGLDisplay display, EGLint id)
178 {
179 	AttribMap attribs;
180 
181 	attribs[EGL_CONFIG_ID]			= id;
182 	attribs[EGL_TRANSPARENT_TYPE]	= EGL_DONT_CARE;
183 	attribs[EGL_COLOR_BUFFER_TYPE]	= EGL_DONT_CARE;
184 	attribs[EGL_RENDERABLE_TYPE]	= EGL_DONT_CARE;
185 	attribs[EGL_SURFACE_TYPE]		= EGL_DONT_CARE;
186 
187 	return chooseSingleConfig(egl, display, attribs);
188 }
189 
getConfigAttribInt(const Library & egl,EGLDisplay display,EGLConfig config,EGLint attrib)190 EGLint getConfigAttribInt (const Library& egl, EGLDisplay display, EGLConfig config, EGLint attrib)
191 {
192 	EGLint value = 0;
193 	EGLU_CHECK_CALL(egl, getConfigAttrib(display, config, attrib, &value));
194 	return value;
195 }
196 
getConfigID(const Library & egl,EGLDisplay display,EGLConfig config)197 EGLint getConfigID (const Library& egl, EGLDisplay display, EGLConfig config)
198 {
199 	return getConfigAttribInt(egl, display, config, EGL_CONFIG_ID);
200 }
201 
querySurfaceInt(const Library & egl,EGLDisplay display,EGLSurface surface,EGLint attrib)202 EGLint querySurfaceInt (const Library& egl, EGLDisplay display, EGLSurface surface, EGLint attrib)
203 {
204 	EGLint value = 0;
205 	EGLU_CHECK_CALL(egl, querySurface(display, surface, attrib, &value));
206 	return value;
207 }
208 
getSurfaceSize(const Library & egl,EGLDisplay display,EGLSurface surface)209 tcu::IVec2 getSurfaceSize (const Library& egl, EGLDisplay display, EGLSurface surface)
210 {
211 	const EGLint width	= querySurfaceInt(egl, display, surface, EGL_WIDTH);
212 	const EGLint height	= querySurfaceInt(egl, display, surface, EGL_HEIGHT);
213 	return tcu::IVec2(width, height);
214 }
215 
getSurfaceResolution(const Library & egl,EGLDisplay display,EGLSurface surface)216 tcu::IVec2 getSurfaceResolution (const Library& egl, EGLDisplay display, EGLSurface surface)
217 {
218 	const EGLint hRes	= querySurfaceInt(egl, display, surface, EGL_HORIZONTAL_RESOLUTION);
219 	const EGLint vRes	= querySurfaceInt(egl, display, surface, EGL_VERTICAL_RESOLUTION);
220 
221 	if (hRes == EGL_UNKNOWN || vRes == EGL_UNKNOWN)
222 		TCU_THROW(NotSupportedError, "Surface doesn't support pixel density queries");
223 	return tcu::IVec2(hRes, vRes);
224 }
225 
226 //! Get EGLdisplay using eglGetDisplay() or eglGetPlatformDisplayEXT()
getDisplay(NativeDisplay & nativeDisplay)227 EGLDisplay getDisplay (NativeDisplay& nativeDisplay)
228 {
229 	const Library&	egl								= nativeDisplay.getLibrary();
230 	const bool		supportsLegacyGetDisplay		= (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY) != 0;
231 	const bool		supportsPlatformGetDisplay		= (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM) != 0;
232 	bool			usePlatformExt					= false;
233 	EGLDisplay		display							= EGL_NO_DISPLAY;
234 
235 	TCU_CHECK_INTERNAL(supportsLegacyGetDisplay || supportsPlatformGetDisplay);
236 
237 	if (supportsPlatformGetDisplay)
238 	{
239 		const vector<string> platformExts = getPlatformExtensions(egl);
240 		usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
241 						 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
242 	}
243 
244 	if (usePlatformExt)
245 	{
246 		const vector<EGLint>	legacyAttribs	= toLegacyAttribList(nativeDisplay.getPlatformAttributes());
247 
248 		display = egl.getPlatformDisplayEXT(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), &legacyAttribs[0]);
249 		EGLU_CHECK_MSG(egl, "eglGetPlatformDisplayEXT()");
250 		TCU_CHECK(display != EGL_NO_DISPLAY);
251 	}
252 	else if (supportsLegacyGetDisplay)
253 	{
254 		display = egl.getDisplay(nativeDisplay.getLegacyNative());
255 		EGLU_CHECK_MSG(egl, "eglGetDisplay()");
256 		TCU_CHECK(display != EGL_NO_DISPLAY);
257 	}
258 	else
259 		throw tcu::InternalError("No supported way to get EGL display", DE_NULL, __FILE__, __LINE__);
260 
261 	DE_ASSERT(display != EGL_NO_DISPLAY);
262 	return display;
263 }
264 
getAndInitDisplay(NativeDisplay & nativeDisplay,Version * version)265 EGLDisplay getAndInitDisplay (NativeDisplay& nativeDisplay, Version* version)
266 {
267 	const Library&	egl		= nativeDisplay.getLibrary();
268 	EGLDisplay		display	= getDisplay(nativeDisplay);
269 	int				major, minor;
270 
271 	EGLU_CHECK_CALL(egl, initialize(display, &major, &minor));
272 
273 	if (version)
274 		*version = Version(major, minor);
275 
276 	return display;
277 }
278 
279 //! Create EGL window surface using eglCreateWindowSurface() or eglCreatePlatformWindowSurfaceEXT()
createWindowSurface(NativeDisplay & nativeDisplay,NativeWindow & window,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList)280 EGLSurface createWindowSurface (NativeDisplay& nativeDisplay, NativeWindow& window, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
281 {
282 	const Library&	egl							= nativeDisplay.getLibrary();
283 	const bool		supportsLegacyCreate		= (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
284 	const bool		supportsPlatformCreate		= (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
285 	bool			usePlatformExt				= false;
286 	EGLSurface		surface						= EGL_NO_SURFACE;
287 
288 	TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
289 
290 	if (supportsPlatformCreate)
291 	{
292 		const vector<string> platformExts = getPlatformExtensions(egl);
293 		usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
294 						 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
295 	}
296 
297 	// \todo [2014-03-13 pyry] EGL 1.5 core support
298 	if (usePlatformExt)
299 	{
300 		const vector<EGLint>	legacyAttribs	= toLegacyAttribList(attribList);
301 
302 		surface = egl.createPlatformWindowSurfaceEXT(display, config, window.getPlatformNative(), &legacyAttribs[0]);
303 		EGLU_CHECK_MSG(egl, "eglCreatePlatformWindowSurfaceEXT()");
304 		TCU_CHECK(surface != EGL_NO_SURFACE);
305 	}
306 	else if (supportsLegacyCreate)
307 	{
308 		const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
309 		surface = egl.createWindowSurface(display, config, window.getLegacyNative(), &legacyAttribs[0]);
310 		EGLU_CHECK_MSG(egl, "eglCreateWindowSurface()");
311 		TCU_CHECK(surface != EGL_NO_SURFACE);
312 	}
313 	else
314 		throw tcu::InternalError("No supported way to create EGL window surface", DE_NULL, __FILE__, __LINE__);
315 
316 	DE_ASSERT(surface != EGL_NO_SURFACE);
317 	return surface;
318 }
319 
320 //! Create EGL pixmap surface using eglCreatePixmapSurface() or eglCreatePlatformPixmapSurfaceEXT()
createPixmapSurface(NativeDisplay & nativeDisplay,NativePixmap & pixmap,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList)321 EGLSurface createPixmapSurface (NativeDisplay& nativeDisplay, NativePixmap& pixmap, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
322 {
323 	const Library&	egl							= nativeDisplay.getLibrary();
324 	const bool		supportsLegacyCreate		= (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
325 	const bool		supportsPlatformCreate		= (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
326 	bool			usePlatformExt				= false;
327 	EGLSurface		surface						= EGL_NO_SURFACE;
328 
329 	TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
330 
331 	if (supportsPlatformCreate)
332 	{
333 		const vector<string> platformExts = getPlatformExtensions(egl);
334 		usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
335 						 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
336 	}
337 
338 	if (usePlatformExt)
339 	{
340 		const vector<EGLint>	legacyAttribs	= toLegacyAttribList(attribList);
341 
342 		surface = egl.createPlatformPixmapSurfaceEXT(display, config, pixmap.getPlatformNative(), &legacyAttribs[0]);
343 		EGLU_CHECK_MSG(egl, "eglCreatePlatformPixmapSurfaceEXT()");
344 		TCU_CHECK(surface != EGL_NO_SURFACE);
345 	}
346 	else if (supportsLegacyCreate)
347 	{
348 		const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
349 		surface = egl.createPixmapSurface(display, config, pixmap.getLegacyNative(), &legacyAttribs[0]);
350 		EGLU_CHECK_MSG(egl, "eglCreatePixmapSurface()");
351 		TCU_CHECK(surface != EGL_NO_SURFACE);
352 	}
353 	else
354 		throw tcu::InternalError("No supported way to create EGL pixmap surface", DE_NULL, __FILE__, __LINE__);
355 
356 	DE_ASSERT(surface != EGL_NO_SURFACE);
357 	return surface;
358 }
359 
getWindowVisibility(tcu::WindowVisibility visibility)360 static WindowParams::Visibility getWindowVisibility (tcu::WindowVisibility visibility)
361 {
362 	switch (visibility)
363 	{
364 		case tcu::WINDOWVISIBILITY_WINDOWED:	return WindowParams::VISIBILITY_VISIBLE;
365 		case tcu::WINDOWVISIBILITY_FULLSCREEN:	return WindowParams::VISIBILITY_FULLSCREEN;
366 		case tcu::WINDOWVISIBILITY_HIDDEN:		return WindowParams::VISIBILITY_HIDDEN;
367 
368 		default:
369 			DE_ASSERT(false);
370 			return WindowParams::VISIBILITY_DONT_CARE;
371 	}
372 }
373 
parseWindowVisibility(const tcu::CommandLine & commandLine)374 WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine)
375 {
376 	return getWindowVisibility(commandLine.getVisibility());
377 }
378 
parseClientAPI(const std::string & api)379 EGLenum parseClientAPI (const std::string& api)
380 {
381 	if (api == "OpenGL")
382 		return EGL_OPENGL_API;
383 	else if (api == "OpenGL_ES")
384 		return EGL_OPENGL_ES_API;
385 	else if (api == "OpenVG")
386 		return EGL_OPENVG_API;
387 	else
388 		throw tcu::InternalError("Unknown EGL client API '" + api + "'");
389 }
390 
parseClientAPIs(const std::string & apiList)391 vector<EGLenum> parseClientAPIs (const std::string& apiList)
392 {
393 	const vector<string>	apiStrs	= de::splitString(apiList, ' ');
394 	vector<EGLenum>			apis;
395 
396 	for (vector<string>::const_iterator api = apiStrs.begin(); api != apiStrs.end(); ++api)
397 		apis.push_back(parseClientAPI(*api));
398 
399 	return apis;
400 }
401 
getClientAPIs(const eglw::Library & egl,eglw::EGLDisplay display)402 vector<EGLenum> getClientAPIs (const eglw::Library& egl, eglw::EGLDisplay display)
403 {
404 	return parseClientAPIs(egl.queryString(display, EGL_CLIENT_APIS));
405 }
406 
getRenderableAPIsMask(const eglw::Library & egl,eglw::EGLDisplay display)407 EGLint getRenderableAPIsMask (const eglw::Library& egl, eglw::EGLDisplay display)
408 {
409 	const vector<EGLConfig>	configs	= getConfigs(egl, display);
410 	EGLint					allAPIs	= 0;
411 
412 	for (vector<EGLConfig>::const_iterator i = configs.begin(); i != configs.end(); ++i)
413 		allAPIs |= getConfigAttribInt(egl, display, *i, EGL_RENDERABLE_TYPE);
414 
415 	return allAPIs;
416 }
417 
toLegacyAttribList(const EGLAttrib * attribs)418 vector<EGLint> toLegacyAttribList (const EGLAttrib* attribs)
419 {
420 	const deUint64	attribMask		= 0xffffffffull;	//!< Max bits that can be used
421 	vector<EGLint>	legacyAttribs;
422 
423 	if (attribs)
424 	{
425 		for (const EGLAttrib* attrib = attribs; *attrib != EGL_NONE; attrib += 2)
426 		{
427 			if ((attrib[0] & ~attribMask) || (attrib[1] & ~attribMask))
428 				throw tcu::InternalError("Failed to translate EGLAttrib to EGLint", DE_NULL, __FILE__, __LINE__);
429 
430 			legacyAttribs.push_back((EGLint)attrib[0]);
431 			legacyAttribs.push_back((EGLint)attrib[1]);
432 		}
433 	}
434 
435 	legacyAttribs.push_back(EGL_NONE);
436 
437 	return legacyAttribs;
438 }
439 
440 template<typename Factory>
selectFactory(const tcu::FactoryRegistry<Factory> & registry,const char * objectTypeName,const char * cmdLineArg)441 static const Factory& selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg)
442 {
443 	if (cmdLineArg)
444 	{
445 		const Factory* factory = registry.getFactoryByName(cmdLineArg);
446 
447 		if (factory)
448 			return *factory;
449 		else
450 		{
451 			tcu::print("ERROR: Unknown or unsupported EGL %s type '%s'", objectTypeName, cmdLineArg);
452 			tcu::print("Available EGL %s types:\n", objectTypeName);
453 			for (size_t ndx = 0; ndx < registry.getFactoryCount(); ndx++)
454 				tcu::print("  %s: %s\n", registry.getFactoryByIndex(ndx)->getName(), registry.getFactoryByIndex(ndx)->getDescription());
455 
456 			TCU_THROW(NotSupportedError, (string("Unsupported or unknown EGL ") + objectTypeName + " type '" + cmdLineArg + "'").c_str());
457 		}
458 	}
459 	else if (!registry.empty())
460 		return *registry.getDefaultFactory();
461 	else
462 		TCU_THROW(NotSupportedError, (string("No factory supporting EGL '") + objectTypeName + "' type").c_str());
463 }
464 
selectNativeDisplayFactory(const NativeDisplayFactoryRegistry & registry,const tcu::CommandLine & cmdLine)465 const NativeDisplayFactory& selectNativeDisplayFactory (const NativeDisplayFactoryRegistry& registry, const tcu::CommandLine& cmdLine)
466 {
467 	return selectFactory(registry, "display", cmdLine.getEGLDisplayType());
468 }
469 
selectNativeWindowFactory(const NativeDisplayFactory & factory,const tcu::CommandLine & cmdLine)470 const NativeWindowFactory& selectNativeWindowFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine)
471 {
472 	return selectFactory(factory.getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType());
473 }
474 
selectNativePixmapFactory(const NativeDisplayFactory & factory,const tcu::CommandLine & cmdLine)475 const NativePixmapFactory& selectNativePixmapFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine)
476 {
477 	return selectFactory(factory.getNativePixmapRegistry(), "pixmap", cmdLine.getEGLPixmapType());
478 }
479 
480 } // eglu
481