Home | History | Annotate | Download | only in egl
      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 
     33 using std::string;
     34 using 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 
     43 namespace eglu
     44 {
     45 
     46 vector<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 
     68 vector<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 
     88 vector<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 
    103 vector<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 
    130 EGLConfig 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 
    139 EGLint 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 
    146 EGLint 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 
    153 tcu::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 
    160 tcu::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()
    171 EGLDisplay 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()
    212 EGLSurface 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()
    256 EGLSurface 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 
    298 static 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 
    312 WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine)
    313 {
    314 	return getWindowVisibility(commandLine.getVisibility());
    315 }
    316 
    317 vector<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