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 "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 
     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 
     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 
     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 
     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 
     86 vector<string> getClientExtensions (const Library& egl)
     87 {
     88 	return getExtensions(egl, EGL_NO_DISPLAY);
     89 }
     90 
     91 vector<string> getDisplayExtensions (const Library& egl, EGLDisplay display)
     92 {
     93 	DE_ASSERT(display != EGL_NO_DISPLAY);
     94 
     95 	return getExtensions(egl, display);
     96 }
     97 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    197 EGLint getConfigID (const Library& egl, EGLDisplay display, EGLConfig config)
    198 {
    199 	return getConfigAttribInt(egl, display, config, EGL_CONFIG_ID);
    200 }
    201 
    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 
    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 
    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()
    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 = getClientExtensions(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 
    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()
    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 = getClientExtensions(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()
    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 = getClientExtensions(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 
    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 
    374 WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine)
    375 {
    376 	return getWindowVisibility(commandLine.getVisibility());
    377 }
    378 
    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 
    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 
    402 vector<EGLenum> getClientAPIs (const eglw::Library& egl, eglw::EGLDisplay display)
    403 {
    404 	return parseClientAPIs(egl.queryString(display, EGL_CLIENT_APIS));
    405 }
    406 
    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 
    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>
    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 
    465 const NativeDisplayFactory& selectNativeDisplayFactory (const NativeDisplayFactoryRegistry& registry, const tcu::CommandLine& cmdLine)
    466 {
    467 	return selectFactory(registry, "display", cmdLine.getEGLDisplayType());
    468 }
    469 
    470 const NativeWindowFactory& selectNativeWindowFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine)
    471 {
    472 	return selectFactory(factory.getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType());
    473 }
    474 
    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