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 const char* const extensionStr = egl.queryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); 89 const EGLint eglError = egl.getError(); 90 if (eglError == EGL_BAD_DISPLAY && extensionStr == DE_NULL) { 91 // We do not support client extensions 92 TCU_THROW(NotSupportedError, "EGL_EXT_client_extensions not supported"); 93 } 94 95 EGLU_CHECK_MSG(egl, "Querying extensions failed"); 96 97 return de::splitString(extensionStr, ' '); 98 } 99 100 vector<string> getDisplayExtensions (const Library& egl, EGLDisplay display) 101 { 102 DE_ASSERT(display != EGL_NO_DISPLAY); 103 104 return getExtensions(egl, display); 105 } 106 107 vector<EGLConfig> getConfigs (const Library& egl, EGLDisplay display) 108 { 109 vector<EGLConfig> configs; 110 EGLint configCount = 0; 111 EGLU_CHECK_CALL(egl, getConfigs(display, DE_NULL, 0, &configCount)); 112 113 if (configCount > 0) 114 { 115 configs.resize(configCount); 116 EGLU_CHECK_CALL(egl, getConfigs(display, &(configs[0]), (EGLint)configs.size(), &configCount)); 117 } 118 119 return configs; 120 } 121 122 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const EGLint* attribList) 123 { 124 EGLint numConfigs = 0; 125 126 EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, DE_NULL, 0, &numConfigs)); 127 128 { 129 vector<EGLConfig> configs(numConfigs); 130 131 if (numConfigs > 0) 132 EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, &configs.front(), numConfigs, &numConfigs)); 133 134 return configs; 135 } 136 } 137 138 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const FilterList& filters) 139 { 140 const vector<EGLConfig> allConfigs (getConfigs(egl, display)); 141 vector<EGLConfig> matchingConfigs; 142 143 for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg) 144 { 145 if (filters.match(egl, display, *cfg)) 146 matchingConfigs.push_back(*cfg); 147 } 148 149 return matchingConfigs; 150 } 151 152 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const FilterList& filters) 153 { 154 const vector<EGLConfig> allConfigs (getConfigs(egl, display)); 155 156 for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg) 157 { 158 if (filters.match(egl, display, *cfg)) 159 return *cfg; 160 } 161 162 TCU_THROW(NotSupportedError, "No matching EGL config found"); 163 } 164 165 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const EGLint* attribList) 166 { 167 const vector<EGLConfig> configs (chooseConfigs(egl, display, attribList)); 168 if (configs.empty()) 169 TCU_THROW(NotSupportedError, "No matching EGL config found"); 170 171 return configs.front(); 172 } 173 174 vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const AttribMap& attribs) 175 { 176 const vector<EGLint> attribList = attribMapToList(attribs); 177 return chooseConfigs(egl, display, &attribList.front()); 178 } 179 180 EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const AttribMap& attribs) 181 { 182 const vector<EGLint> attribList = attribMapToList(attribs); 183 return chooseSingleConfig(egl, display, &attribList.front()); 184 } 185 186 EGLConfig chooseConfigByID (const Library& egl, EGLDisplay display, EGLint id) 187 { 188 AttribMap attribs; 189 190 attribs[EGL_CONFIG_ID] = id; 191 attribs[EGL_TRANSPARENT_TYPE] = EGL_DONT_CARE; 192 attribs[EGL_COLOR_BUFFER_TYPE] = EGL_DONT_CARE; 193 attribs[EGL_RENDERABLE_TYPE] = EGL_DONT_CARE; 194 attribs[EGL_SURFACE_TYPE] = EGL_DONT_CARE; 195 196 return chooseSingleConfig(egl, display, attribs); 197 } 198 199 EGLint getConfigAttribInt (const Library& egl, EGLDisplay display, EGLConfig config, EGLint attrib) 200 { 201 EGLint value = 0; 202 EGLU_CHECK_CALL(egl, getConfigAttrib(display, config, attrib, &value)); 203 return value; 204 } 205 206 EGLint getConfigID (const Library& egl, EGLDisplay display, EGLConfig config) 207 { 208 return getConfigAttribInt(egl, display, config, EGL_CONFIG_ID); 209 } 210 211 EGLint querySurfaceInt (const Library& egl, EGLDisplay display, EGLSurface surface, EGLint attrib) 212 { 213 EGLint value = 0; 214 EGLU_CHECK_CALL(egl, querySurface(display, surface, attrib, &value)); 215 return value; 216 } 217 218 tcu::IVec2 getSurfaceSize (const Library& egl, EGLDisplay display, EGLSurface surface) 219 { 220 const EGLint width = querySurfaceInt(egl, display, surface, EGL_WIDTH); 221 const EGLint height = querySurfaceInt(egl, display, surface, EGL_HEIGHT); 222 return tcu::IVec2(width, height); 223 } 224 225 tcu::IVec2 getSurfaceResolution (const Library& egl, EGLDisplay display, EGLSurface surface) 226 { 227 const EGLint hRes = querySurfaceInt(egl, display, surface, EGL_HORIZONTAL_RESOLUTION); 228 const EGLint vRes = querySurfaceInt(egl, display, surface, EGL_VERTICAL_RESOLUTION); 229 230 if (hRes == EGL_UNKNOWN || vRes == EGL_UNKNOWN) 231 TCU_THROW(NotSupportedError, "Surface doesn't support pixel density queries"); 232 return tcu::IVec2(hRes, vRes); 233 } 234 235 //! Get EGLdisplay using eglGetDisplay() or eglGetPlatformDisplayEXT() 236 EGLDisplay getDisplay (NativeDisplay& nativeDisplay) 237 { 238 const Library& egl = nativeDisplay.getLibrary(); 239 const bool supportsLegacyGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY) != 0; 240 bool maySupportPlatformGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM) != 0; 241 bool maySupportPlatformGetDisplayEXT = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM_EXT) != 0; 242 bool usePlatformExt = false; 243 EGLDisplay display = EGL_NO_DISPLAY; 244 245 TCU_CHECK_INTERNAL(supportsLegacyGetDisplay || maySupportPlatformGetDisplay); 246 247 if (maySupportPlatformGetDisplayEXT) 248 { 249 try 250 { 251 const vector<string> platformExts = eglu::getClientExtensions(egl); 252 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) && 253 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName())); 254 255 } 256 catch (const tcu::NotSupportedError& error) 257 { 258 // If we can't get the client extension string we must not have EGL 1.5 support or the appropriate extensions. 259 maySupportPlatformGetDisplay = false; 260 maySupportPlatformGetDisplayEXT = false; 261 usePlatformExt = false; 262 } 263 } 264 265 if (maySupportPlatformGetDisplay) 266 { 267 display = egl.getPlatformDisplay(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), nativeDisplay.getPlatformAttributes()); 268 EGLU_CHECK_MSG(egl, "eglGetPlatformDisplay()"); 269 TCU_CHECK(display != EGL_NO_DISPLAY); 270 } 271 else if (usePlatformExt) 272 { 273 const vector<EGLint> legacyAttribs = toLegacyAttribList(nativeDisplay.getPlatformAttributes()); 274 275 display = egl.getPlatformDisplayEXT(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), &legacyAttribs[0]); 276 EGLU_CHECK_MSG(egl, "eglGetPlatformDisplayEXT()"); 277 TCU_CHECK(display != EGL_NO_DISPLAY); 278 } 279 else if (supportsLegacyGetDisplay) 280 { 281 display = egl.getDisplay(nativeDisplay.getLegacyNative()); 282 EGLU_CHECK_MSG(egl, "eglGetDisplay()"); 283 TCU_CHECK(display != EGL_NO_DISPLAY); 284 } 285 else 286 throw tcu::InternalError("No supported way to get EGL display", DE_NULL, __FILE__, __LINE__); 287 288 DE_ASSERT(display != EGL_NO_DISPLAY); 289 return display; 290 } 291 292 EGLDisplay getAndInitDisplay (NativeDisplay& nativeDisplay, Version* version) 293 { 294 const Library& egl = nativeDisplay.getLibrary(); 295 EGLDisplay display = getDisplay(nativeDisplay); 296 int major, minor; 297 298 EGLU_CHECK_CALL(egl, initialize(display, &major, &minor)); 299 300 if (version) 301 *version = Version(major, minor); 302 303 return display; 304 } 305 306 void terminateDisplay(const Library& egl, EGLDisplay display) 307 { 308 EGLU_CHECK_CALL(egl, terminate(display)); 309 } 310 311 //! Create EGL window surface using eglCreatePlatformWindowSurface, eglCreateWindowSurface() or eglCreatePlatformWindowSurfaceEXT() 312 EGLSurface createWindowSurface (NativeDisplay& nativeDisplay, NativeWindow& window, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList) 313 { 314 const Library& egl = nativeDisplay.getLibrary(); 315 const bool supportsLegacyCreate = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY) != 0; 316 bool maySupportPlatformCreate = ((window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0 317 && eglu::getVersion(egl, display) >= eglu::Version(1, 5)); 318 bool maySupportPlatformCreateExtension = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION) != 0; 319 bool usePlatformExt = false; 320 EGLSurface surface = EGL_NO_SURFACE; 321 322 TCU_CHECK_INTERNAL(supportsLegacyCreate || maySupportPlatformCreateExtension || maySupportPlatformCreate); 323 324 if (maySupportPlatformCreateExtension) 325 { 326 try 327 { 328 const vector<string> platformExts = eglu::getClientExtensions(egl); 329 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) && 330 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName())); 331 332 } 333 catch (const tcu::NotSupportedError& error) 334 { 335 maySupportPlatformCreate = false; 336 maySupportPlatformCreateExtension = false; 337 usePlatformExt = false; 338 } 339 } 340 341 if (maySupportPlatformCreate) 342 { 343 surface = egl.createPlatformWindowSurface(display, config, window.getPlatformNative(), attribList); 344 EGLU_CHECK_MSG(egl, "eglCreatePlatformWindowSurface()"); 345 TCU_CHECK(surface != EGL_NO_SURFACE); 346 } 347 else if (usePlatformExt) 348 { 349 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); 350 surface = egl.createPlatformWindowSurfaceEXT(display, config, window.getPlatformExtension(), &legacyAttribs[0]); 351 EGLU_CHECK_MSG(egl, "eglCreatePlatformWindowSurfaceEXT()"); 352 TCU_CHECK(surface != EGL_NO_SURFACE); 353 } 354 else if (supportsLegacyCreate) 355 { 356 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); 357 surface = egl.createWindowSurface(display, config, window.getLegacyNative(), &legacyAttribs[0]); 358 EGLU_CHECK_MSG(egl, "eglCreateWindowSurface()"); 359 TCU_CHECK(surface != EGL_NO_SURFACE); 360 } 361 else 362 throw tcu::InternalError("No supported way to create EGL window surface", DE_NULL, __FILE__, __LINE__); 363 364 DE_ASSERT(surface != EGL_NO_SURFACE); 365 return surface; 366 } 367 368 //! Create EGL pixmap surface using eglCreatePixmapSurface() or eglCreatePlatformPixmapSurfaceEXT() 369 EGLSurface createPixmapSurface (NativeDisplay& nativeDisplay, NativePixmap& pixmap, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList) 370 { 371 const Library& egl = nativeDisplay.getLibrary(); 372 const bool supportsLegacyCreate = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY) != 0; 373 bool maySupportPlatformCreateExtension = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION) != 0; 374 bool maySupportPlatformCreate = ((pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0 375 && eglu::getVersion(egl, display) >= eglu::Version(1, 5)); 376 bool usePlatformExt = false; 377 EGLSurface surface = EGL_NO_SURFACE; 378 379 TCU_CHECK_INTERNAL(supportsLegacyCreate || maySupportPlatformCreateExtension || maySupportPlatformCreate); 380 381 if (maySupportPlatformCreateExtension) 382 { 383 try 384 { 385 const vector<string> platformExts = eglu::getClientExtensions(egl); 386 usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) && 387 de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName())); 388 389 } 390 catch (const tcu::NotSupportedError& error) 391 { 392 maySupportPlatformCreate = false; 393 maySupportPlatformCreateExtension = false; 394 usePlatformExt = false; 395 } 396 } 397 398 if (maySupportPlatformCreate) 399 { 400 surface = egl.createPlatformPixmapSurface(display, config, pixmap.getPlatformNative(), attribList); 401 EGLU_CHECK_MSG(egl, "eglCreatePlatformPixmapSurface()"); 402 TCU_CHECK(surface != EGL_NO_SURFACE); 403 } 404 else if (usePlatformExt) 405 { 406 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); 407 408 surface = egl.createPlatformPixmapSurfaceEXT(display, config, pixmap.getPlatformExtension(), &legacyAttribs[0]); 409 EGLU_CHECK_MSG(egl, "eglCreatePlatformPixmapSurfaceEXT()"); 410 TCU_CHECK(surface != EGL_NO_SURFACE); 411 } 412 else if (supportsLegacyCreate) 413 { 414 const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); 415 surface = egl.createPixmapSurface(display, config, pixmap.getLegacyNative(), &legacyAttribs[0]); 416 EGLU_CHECK_MSG(egl, "eglCreatePixmapSurface()"); 417 TCU_CHECK(surface != EGL_NO_SURFACE); 418 } 419 else 420 throw tcu::InternalError("No supported way to create EGL pixmap surface", DE_NULL, __FILE__, __LINE__); 421 422 DE_ASSERT(surface != EGL_NO_SURFACE); 423 return surface; 424 } 425 426 static WindowParams::Visibility getWindowVisibility (tcu::WindowVisibility visibility) 427 { 428 switch (visibility) 429 { 430 case tcu::WINDOWVISIBILITY_WINDOWED: return WindowParams::VISIBILITY_VISIBLE; 431 case tcu::WINDOWVISIBILITY_FULLSCREEN: return WindowParams::VISIBILITY_FULLSCREEN; 432 case tcu::WINDOWVISIBILITY_HIDDEN: return WindowParams::VISIBILITY_HIDDEN; 433 434 default: 435 DE_ASSERT(false); 436 return WindowParams::VISIBILITY_DONT_CARE; 437 } 438 } 439 440 WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine) 441 { 442 return getWindowVisibility(commandLine.getVisibility()); 443 } 444 445 EGLenum parseClientAPI (const std::string& api) 446 { 447 if (api == "OpenGL") 448 return EGL_OPENGL_API; 449 else if (api == "OpenGL_ES") 450 return EGL_OPENGL_ES_API; 451 else if (api == "OpenVG") 452 return EGL_OPENVG_API; 453 else 454 throw tcu::InternalError("Unknown EGL client API '" + api + "'"); 455 } 456 457 vector<EGLenum> parseClientAPIs (const std::string& apiList) 458 { 459 const vector<string> apiStrs = de::splitString(apiList, ' '); 460 vector<EGLenum> apis; 461 462 for (vector<string>::const_iterator api = apiStrs.begin(); api != apiStrs.end(); ++api) 463 apis.push_back(parseClientAPI(*api)); 464 465 return apis; 466 } 467 468 vector<EGLenum> getClientAPIs (const eglw::Library& egl, eglw::EGLDisplay display) 469 { 470 return parseClientAPIs(egl.queryString(display, EGL_CLIENT_APIS)); 471 } 472 473 EGLint getRenderableAPIsMask (const eglw::Library& egl, eglw::EGLDisplay display) 474 { 475 const vector<EGLConfig> configs = getConfigs(egl, display); 476 EGLint allAPIs = 0; 477 478 for (vector<EGLConfig>::const_iterator i = configs.begin(); i != configs.end(); ++i) 479 allAPIs |= getConfigAttribInt(egl, display, *i, EGL_RENDERABLE_TYPE); 480 481 return allAPIs; 482 } 483 484 vector<EGLint> toLegacyAttribList (const EGLAttrib* attribs) 485 { 486 const deUint64 attribMask = 0xffffffffull; //!< Max bits that can be used 487 vector<EGLint> legacyAttribs; 488 489 if (attribs) 490 { 491 for (const EGLAttrib* attrib = attribs; *attrib != EGL_NONE; attrib += 2) 492 { 493 if ((attrib[0] & ~attribMask) || (attrib[1] & ~attribMask)) 494 throw tcu::InternalError("Failed to translate EGLAttrib to EGLint", DE_NULL, __FILE__, __LINE__); 495 496 legacyAttribs.push_back((EGLint)attrib[0]); 497 legacyAttribs.push_back((EGLint)attrib[1]); 498 } 499 } 500 501 legacyAttribs.push_back(EGL_NONE); 502 503 return legacyAttribs; 504 } 505 506 template<typename Factory> 507 static const Factory& selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg) 508 { 509 if (cmdLineArg) 510 { 511 const Factory* factory = registry.getFactoryByName(cmdLineArg); 512 513 if (factory) 514 return *factory; 515 else 516 { 517 tcu::print("ERROR: Unknown or unsupported EGL %s type '%s'", objectTypeName, cmdLineArg); 518 tcu::print("Available EGL %s types:\n", objectTypeName); 519 for (size_t ndx = 0; ndx < registry.getFactoryCount(); ndx++) 520 tcu::print(" %s: %s\n", registry.getFactoryByIndex(ndx)->getName(), registry.getFactoryByIndex(ndx)->getDescription()); 521 522 TCU_THROW(NotSupportedError, (string("Unsupported or unknown EGL ") + objectTypeName + " type '" + cmdLineArg + "'").c_str()); 523 } 524 } 525 else if (!registry.empty()) 526 return *registry.getDefaultFactory(); 527 else 528 TCU_THROW(NotSupportedError, (string("No factory supporting EGL '") + objectTypeName + "' type").c_str()); 529 } 530 531 const NativeDisplayFactory& selectNativeDisplayFactory (const NativeDisplayFactoryRegistry& registry, const tcu::CommandLine& cmdLine) 532 { 533 return selectFactory(registry, "display", cmdLine.getEGLDisplayType()); 534 } 535 536 const NativeWindowFactory& selectNativeWindowFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine) 537 { 538 return selectFactory(factory.getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType()); 539 } 540 541 const NativePixmapFactory& selectNativePixmapFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine) 542 { 543 return selectFactory(factory.getNativePixmapRegistry(), "pixmap", cmdLine.getEGLPixmapType()); 544 } 545 546 } // eglu 547