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 "tcuCommandLine.hpp"
28#include "deSTLUtil.hpp"
29
30#include <algorithm>
31#include <sstream>
32
33using std::string;
34using std::vector;
35
36#if !defined(EGL_EXT_platform_base)
37#	define EGL_EXT_platform_base 1
38	typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
39	typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
40	typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
41#endif // EGL_EXT_platform_base
42
43namespace eglu
44{
45
46vector<string> getPlatformExtensions (void)
47{
48	const char* const	extensionStr	= eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
49	const EGLint		result			= eglGetError();
50
51	if (result == EGL_SUCCESS)
52	{
53		std::istringstream	stream			(extensionStr);
54		string				currentExtension;
55		vector<string>		extensions;
56
57		while (std::getline(stream, currentExtension, ' '))
58			extensions.push_back(currentExtension);
59
60		return extensions;
61	}
62	else if (result != EGL_BAD_DISPLAY)
63		throw Error(result, "eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)", DE_NULL, __FILE__, __LINE__);
64	else
65		return vector<string>();
66}
67
68vector<string> getClientExtensions (EGLDisplay display)
69{
70	const char* const	extensionStr	= eglQueryString(display, EGL_EXTENSIONS);
71	const EGLint		result			= eglGetError();
72
73	if (result == EGL_SUCCESS)
74	{
75		std::istringstream	stream			(extensionStr);
76		string				currentExtension;
77		vector<string>		extensions;
78
79		while (std::getline(stream, currentExtension, ' '))
80			extensions.push_back(currentExtension);
81
82		return extensions;
83	}
84	else
85		throw Error(result, "eglQueryString(display, EGL_EXTENSIONS)", DE_NULL, __FILE__, __LINE__);
86}
87
88vector<EGLConfig> getConfigs (EGLDisplay display)
89{
90	vector<EGLConfig>	configs;
91	EGLint				configCount	= 0;
92	EGLU_CHECK_CALL(eglGetConfigs(display, DE_NULL, 0, &configCount));
93
94	if (configCount > 0)
95	{
96		configs.resize(configCount);
97		EGLU_CHECK_CALL(eglGetConfigs(display, &(configs[0]), (EGLint)configs.size(), &configCount));
98	}
99
100	return configs;
101}
102
103vector<EGLConfig> chooseConfig (EGLDisplay display, const AttribMap& attribs)
104{
105	vector<EGLint> attribList;
106
107	for (AttribMap::const_iterator it = attribs.begin(); it != attribs.end(); ++it)
108	{
109		attribList.push_back(it->first);
110		attribList.push_back(it->second);
111	}
112
113	attribList.push_back(EGL_NONE);
114
115	{
116		EGLint numConfigs = 0;
117		EGLU_CHECK_CALL(eglChooseConfig(display, &attribList.front(), DE_NULL, 0, &numConfigs));
118
119		{
120			vector<EGLConfig> configs(numConfigs);
121
122			if (numConfigs > 0)
123				EGLU_CHECK_CALL(eglChooseConfig(display, &attribList.front(), &configs.front(), numConfigs, &numConfigs));
124
125			return configs;
126		}
127	}
128}
129
130EGLConfig chooseSingleConfig (EGLDisplay display, const AttribMap& attribs)
131{
132	vector<EGLConfig> configs (chooseConfig(display, attribs));
133	if (configs.empty())
134		TCU_THROW(NotSupportedError, "No suitable EGL configuration found");
135
136	return configs.front();
137}
138
139EGLint getConfigAttribInt (EGLDisplay display, EGLConfig config, EGLint attrib)
140{
141	EGLint value = 0;
142	EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, attrib, &value));
143	return value;
144}
145
146EGLint querySurfaceInt (EGLDisplay display, EGLSurface surface, EGLint attrib)
147{
148	EGLint value = 0;
149	EGLU_CHECK_CALL(eglQuerySurface(display, surface, attrib, &value));
150	return value;
151}
152
153tcu::IVec2 getSurfaceSize (EGLDisplay display, EGLSurface surface)
154{
155	const EGLint width	= querySurfaceInt(display, surface, EGL_WIDTH);
156	const EGLint height	= querySurfaceInt(display, surface, EGL_HEIGHT);
157	return tcu::IVec2(width, height);
158}
159
160tcu::IVec2 getSurfaceResolution (EGLDisplay display, EGLSurface surface)
161{
162	const EGLint hRes	= querySurfaceInt(display, surface, EGL_HORIZONTAL_RESOLUTION);
163	const EGLint vRes	= querySurfaceInt(display, surface, EGL_VERTICAL_RESOLUTION);
164
165	if (hRes == EGL_UNKNOWN || vRes == EGL_UNKNOWN)
166		TCU_THROW(NotSupportedError, "Surface doesn't support pixel density queries");
167	return tcu::IVec2(hRes, vRes);
168}
169
170//! Get EGLdisplay using eglGetDisplay() or eglGetPlatformDisplayEXT()
171EGLDisplay getDisplay (NativeDisplay& nativeDisplay)
172{
173	const bool	supportsLegacyGetDisplay		= (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY) != 0;
174	const bool	supportsPlatformGetDisplay		= (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM) != 0;
175	bool		usePlatformExt					= false;
176	EGLDisplay	display							= EGL_NO_DISPLAY;
177
178	TCU_CHECK_INTERNAL(supportsLegacyGetDisplay || supportsPlatformGetDisplay);
179
180	if (supportsPlatformGetDisplay)
181	{
182		const vector<string> platformExts = getPlatformExtensions();
183		usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
184						 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
185	}
186
187	if (usePlatformExt)
188	{
189		const PFNEGLGETPLATFORMDISPLAYEXTPROC	getPlatformDisplay	= (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
190
191		EGLU_CHECK_MSG("eglGetProcAddress()");
192		TCU_CHECK(getPlatformDisplay);
193
194		display = getPlatformDisplay(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), DE_NULL);
195		EGLU_CHECK_MSG("eglGetPlatformDisplayEXT()");
196		TCU_CHECK(display != EGL_NO_DISPLAY);
197	}
198	else if (supportsLegacyGetDisplay)
199	{
200		display = eglGetDisplay(nativeDisplay.getLegacyNative());
201		EGLU_CHECK_MSG("eglGetDisplay()");
202		TCU_CHECK(display != EGL_NO_DISPLAY);
203	}
204	else
205		throw tcu::InternalError("No supported way to get EGL display", DE_NULL, __FILE__, __LINE__);
206
207	DE_ASSERT(display != EGL_NO_DISPLAY);
208	return display;
209}
210
211//! Create EGL window surface using eglCreateWindowSurface() or eglCreatePlatformWindowSurfaceEXT()
212EGLSurface createWindowSurface (NativeDisplay& nativeDisplay, NativeWindow& window, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
213{
214	const bool	supportsLegacyCreate			= (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
215	const bool	supportsPlatformCreate			= (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
216	bool		usePlatformExt					= false;
217	EGLSurface	surface							= EGL_NO_SURFACE;
218
219	TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
220
221	if (supportsPlatformCreate)
222	{
223		const vector<string> platformExts = getPlatformExtensions();
224		usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
225						 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
226	}
227
228	// \todo [2014-03-13 pyry] EGL 1.5 core support
229	if (usePlatformExt)
230	{
231		const PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC	createPlatformWindowSurface	= (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
232		const vector<EGLint>							legacyAttribs				= toLegacyAttribList(attribList);
233
234		EGLU_CHECK_MSG("eglGetProcAddress()");
235		TCU_CHECK(createPlatformWindowSurface);
236
237		surface = createPlatformWindowSurface(display, config, window.getPlatformNative(), &legacyAttribs[0]);
238		EGLU_CHECK_MSG("eglCreatePlatformWindowSurfaceEXT()");
239		TCU_CHECK(surface != EGL_NO_SURFACE);
240	}
241	else if (supportsLegacyCreate)
242	{
243		const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
244		surface = eglCreateWindowSurface(display, config, window.getLegacyNative(), &legacyAttribs[0]);
245		EGLU_CHECK_MSG("eglCreateWindowSurface()");
246		TCU_CHECK(surface != EGL_NO_SURFACE);
247	}
248	else
249		throw tcu::InternalError("No supported way to create EGL window surface", DE_NULL, __FILE__, __LINE__);
250
251	DE_ASSERT(surface != EGL_NO_SURFACE);
252	return surface;
253}
254
255//! Create EGL pixmap surface using eglCreatePixmapSurface() or eglCreatePlatformPixmapSurfaceEXT()
256EGLSurface createPixmapSurface (NativeDisplay& nativeDisplay, NativePixmap& pixmap, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
257{
258	const bool	supportsLegacyCreate			= (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
259	const bool	supportsPlatformCreate			= (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
260	bool		usePlatformExt					= false;
261	EGLSurface	surface							= EGL_NO_SURFACE;
262
263	TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
264
265	if (supportsPlatformCreate)
266	{
267		const vector<string> platformExts = getPlatformExtensions();
268		usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
269						 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
270	}
271
272	if (usePlatformExt)
273	{
274		const PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC	createPlatformPixmapSurface	= (PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformPixmapSurfaceEXT");
275		const vector<EGLint>							legacyAttribs				= toLegacyAttribList(attribList);
276
277		EGLU_CHECK_MSG("eglGetProcAddress()");
278		TCU_CHECK(createPlatformPixmapSurface);
279
280		surface = createPlatformPixmapSurface(display, config, pixmap.getPlatformNative(), &legacyAttribs[0]);
281		EGLU_CHECK_MSG("eglCreatePlatformPixmapSurfaceEXT()");
282		TCU_CHECK(surface != EGL_NO_SURFACE);
283	}
284	else if (supportsLegacyCreate)
285	{
286		const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
287		surface = eglCreatePixmapSurface(display, config, pixmap.getLegacyNative(), &legacyAttribs[0]);
288		EGLU_CHECK_MSG("eglCreatePixmapSurface()");
289		TCU_CHECK(surface != EGL_NO_SURFACE);
290	}
291	else
292		throw tcu::InternalError("No supported way to create EGL pixmap surface", DE_NULL, __FILE__, __LINE__);
293
294	DE_ASSERT(surface != EGL_NO_SURFACE);
295	return surface;
296}
297
298static WindowParams::Visibility getWindowVisibility (tcu::WindowVisibility visibility)
299{
300	switch (visibility)
301	{
302		case tcu::WINDOWVISIBILITY_WINDOWED:	return WindowParams::VISIBILITY_VISIBLE;
303		case tcu::WINDOWVISIBILITY_FULLSCREEN:	return WindowParams::VISIBILITY_FULLSCREEN;
304		case tcu::WINDOWVISIBILITY_HIDDEN:		return WindowParams::VISIBILITY_HIDDEN;
305
306		default:
307			DE_ASSERT(false);
308			return WindowParams::VISIBILITY_DONT_CARE;
309	}
310}
311
312WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine)
313{
314	return getWindowVisibility(commandLine.getVisibility());
315}
316
317vector<EGLint> toLegacyAttribList (const EGLAttrib* attribs)
318{
319	const deUint64	attribMask		= 0xffffffffull;	//!< Max bits that can be used
320	vector<EGLint>	legacyAttribs;
321
322	if (attribs)
323	{
324		for (const EGLAttrib* attrib = attribs; *attrib != EGL_NONE; attrib += 2)
325		{
326			if ((attrib[0] & ~attribMask) || (attrib[1] & ~attribMask))
327				throw tcu::InternalError("Failed to translate EGLAttrib to EGLint", DE_NULL, __FILE__, __LINE__);
328
329			legacyAttribs.push_back((EGLint)attrib[0]);
330			legacyAttribs.push_back((EGLint)attrib[1]);
331		}
332	}
333
334	legacyAttribs.push_back(EGL_NONE);
335
336	return legacyAttribs;
337}
338
339} // eglu
340