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