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 GL context factory using EGL. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "egluGLContextFactory.hpp" 25 26 #include "tcuRenderTarget.hpp" 27 #include "tcuPlatform.hpp" 28 #include "tcuCommandLine.hpp" 29 30 #include "gluDefs.hpp" 31 32 #include "egluDefs.hpp" 33 #include "egluHeaderWrapper.hpp" 34 #include "egluUtil.hpp" 35 #include "egluNativeWindow.hpp" 36 #include "egluNativePixmap.hpp" 37 #include "egluStrUtil.hpp" 38 39 #include "glwInitFunctions.hpp" 40 #include "glwInitES20Direct.hpp" 41 #include "glwInitES30Direct.hpp" 42 43 #include "deDynamicLibrary.hpp" 44 #include "deSTLUtil.hpp" 45 46 #include <string> 47 #include <string> 48 #include <sstream> 49 50 using std::string; 51 using std::vector; 52 53 #if !defined(EGL_KHR_create_context) 54 #define EGL_KHR_create_context 1 55 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 56 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB 57 #define EGL_CONTEXT_FLAGS_KHR 0x30FC 58 #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD 59 #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD 60 #define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE 61 #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF 62 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 63 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 64 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 65 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 66 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 67 #define EGL_OPENGL_ES3_BIT_KHR 0x00000040 68 #endif // EGL_KHR_create_context 69 70 // \todo [2014-03-12 pyry] Use command line arguments for libraries? 71 72 // Default library names 73 #if !defined(DEQP_GLES2_LIBRARY_PATH) 74 # if (DE_OS == DE_OS_WIN32) 75 # define DEQP_GLES2_LIBRARY_PATH "libGLESv2.dll" 76 # else 77 # define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so" 78 # endif 79 #endif 80 81 #if !defined(DEQP_GLES3_LIBRARY_PATH) 82 # define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH 83 #endif 84 85 #if !defined(DEQP_OPENGL_LIBRARY_PATH) 86 # if (DE_OS == DE_OS_WIN32) 87 # define DEQP_OPENGL_LIBRARY_PATH "opengl32.dll" 88 # else 89 # define DEQP_OPENGL_LIBRARY_PATH "libGL.so" 90 # endif 91 #endif 92 93 namespace eglu 94 { 95 96 namespace 97 { 98 99 enum 100 { 101 DEFAULT_OFFSCREEN_WIDTH = 512, 102 DEFAULT_OFFSCREEN_HEIGHT = 512 103 }; 104 105 class GetProcFuncLoader : public glw::FunctionLoader 106 { 107 public: 108 glw::GenericFuncType get (const char* name) const 109 { 110 return (glw::GenericFuncType)eglGetProcAddress(name); 111 } 112 }; 113 114 class DynamicFuncLoader : public glw::FunctionLoader 115 { 116 public: 117 DynamicFuncLoader (de::DynamicLibrary* library) 118 : m_library(library) 119 { 120 } 121 122 glw::GenericFuncType get (const char* name) const 123 { 124 return (glw::GenericFuncType)m_library->getFunction(name); 125 } 126 127 private: 128 de::DynamicLibrary* m_library; 129 }; 130 131 class RenderContext : public GLRenderContext 132 { 133 public: 134 RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config); 135 virtual ~RenderContext (void); 136 137 virtual glu::ContextType getType (void) const { return m_renderConfig.type; } 138 virtual const glw::Functions& getFunctions (void) const { return m_glFunctions; } 139 virtual const tcu::RenderTarget& getRenderTarget (void) const { return m_glRenderTarget; } 140 virtual void postIterate (void); 141 142 virtual EGLDisplay getEGLDisplay (void) const { return m_eglDisplay; } 143 virtual EGLContext getEGLContext (void) const { return m_eglContext; } 144 145 private: 146 void create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config); 147 void destroy (void); 148 149 const glu::RenderConfig m_renderConfig; 150 const NativeWindowFactory* const m_nativeWindowFactory; // Stored in case window must be re-created 151 152 NativeDisplay* m_display; 153 NativeWindow* m_window; 154 NativePixmap* m_pixmap; 155 156 EGLDisplay m_eglDisplay; 157 EGLConfig m_eglConfig; 158 EGLSurface m_eglSurface; 159 EGLContext m_eglContext; 160 161 tcu::RenderTarget m_glRenderTarget; 162 de::DynamicLibrary* m_dynamicGLLibrary; 163 glw::Functions m_glFunctions; 164 }; 165 166 RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config) 167 : m_renderConfig (config) 168 , m_nativeWindowFactory (windowFactory) 169 , m_display (DE_NULL) 170 , m_window (DE_NULL) 171 , m_pixmap (DE_NULL) 172 173 , m_eglDisplay (EGL_NO_DISPLAY) 174 , m_eglSurface (EGL_NO_SURFACE) 175 , m_eglContext (EGL_NO_CONTEXT) 176 177 , m_dynamicGLLibrary (DE_NULL) 178 { 179 DE_ASSERT(displayFactory); 180 181 try 182 { 183 create(displayFactory, windowFactory, pixmapFactory, config); 184 } 185 catch (...) 186 { 187 destroy(); 188 throw; 189 } 190 } 191 192 RenderContext::~RenderContext(void) 193 { 194 try 195 { 196 destroy(); 197 } 198 catch (...) 199 { 200 // destroy() calls EGL functions that are checked and may throw exceptions 201 } 202 203 delete m_window; 204 delete m_pixmap; 205 delete m_display; 206 delete m_dynamicGLLibrary; 207 } 208 209 bool configMatches (EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& renderConfig) 210 { 211 // \todo [2014-03-12 pyry] Check other attributes like double-buffer bit. 212 213 { 214 EGLint renderableType = 0; 215 EGLint requiredRenderable = 0; 216 217 if (glu::isContextTypeES(renderConfig.type)) 218 { 219 if (renderConfig.type.getMajorVersion() == 2) 220 requiredRenderable = EGL_OPENGL_ES2_BIT; 221 else if (renderConfig.type.getMajorVersion() == 3) 222 requiredRenderable = EGL_OPENGL_ES3_BIT_KHR; 223 else 224 throw tcu::NotSupportedError("Unsupported OpenGL ES version"); 225 } 226 else 227 { 228 DE_ASSERT(glu::isContextTypeGLCore(renderConfig.type) || glu::isContextTypeGLCompatibility(renderConfig.type)); 229 requiredRenderable = EGL_OPENGL_BIT; 230 } 231 232 EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, EGL_RENDERABLE_TYPE, &renderableType)); 233 234 if ((renderableType & requiredRenderable) == 0) 235 return false; 236 } 237 238 if (renderConfig.surfaceType != (glu::RenderConfig::SurfaceType)glu::RenderConfig::DONT_CARE) 239 { 240 EGLint surfaceType = 0; 241 EGLint requiredSurface = 0; 242 243 switch (renderConfig.surfaceType) 244 { 245 case glu::RenderConfig::SURFACETYPE_WINDOW: requiredSurface = EGL_WINDOW_BIT; break; 246 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: requiredSurface = EGL_PIXMAP_BIT; break; 247 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: requiredSurface = EGL_PBUFFER_BIT; break; 248 default: 249 DE_ASSERT(false); 250 } 251 252 EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, EGL_SURFACE_TYPE, &surfaceType)); 253 254 if ((surfaceType & requiredSurface) == 0) 255 return false; 256 } 257 258 { 259 static const struct 260 { 261 int glu::RenderConfig::*field; 262 EGLint attrib; 263 } s_attribs[] = 264 { 265 { &glu::RenderConfig::id, EGL_CONFIG_ID }, 266 { &glu::RenderConfig::redBits, EGL_RED_SIZE }, 267 { &glu::RenderConfig::greenBits, EGL_GREEN_SIZE }, 268 { &glu::RenderConfig::blueBits, EGL_BLUE_SIZE }, 269 { &glu::RenderConfig::alphaBits, EGL_ALPHA_SIZE }, 270 { &glu::RenderConfig::depthBits, EGL_DEPTH_SIZE }, 271 { &glu::RenderConfig::stencilBits, EGL_STENCIL_SIZE }, 272 { &glu::RenderConfig::numSamples, EGL_SAMPLES }, 273 }; 274 275 for (int attribNdx = 0; attribNdx < DE_LENGTH_OF_ARRAY(s_attribs); attribNdx++) 276 { 277 if (renderConfig.*s_attribs[attribNdx].field != glu::RenderConfig::DONT_CARE) 278 { 279 EGLint value = 0; 280 EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, s_attribs[attribNdx].attrib, &value)); 281 if (value != renderConfig.*s_attribs[attribNdx].field) 282 return false; 283 } 284 } 285 } 286 287 return true; 288 } 289 290 EGLConfig chooseConfig (EGLDisplay display, const glu::RenderConfig& config) 291 { 292 const std::vector<EGLConfig> configs = eglu::getConfigs(display); 293 294 for (vector<EGLConfig>::const_iterator iter = configs.begin(); iter != configs.end(); ++iter) 295 { 296 if (configMatches(display, *iter, config)) 297 return *iter; 298 } 299 300 throw tcu::NotSupportedError("Matching EGL config not found", DE_NULL, __FILE__, __LINE__); 301 } 302 303 static WindowParams::Visibility getNativeWindowVisibility (glu::RenderConfig::Visibility visibility) 304 { 305 using glu::RenderConfig; 306 307 switch (visibility) 308 { 309 case RenderConfig::VISIBILITY_HIDDEN: return WindowParams::VISIBILITY_HIDDEN; 310 case RenderConfig::VISIBILITY_VISIBLE: return WindowParams::VISIBILITY_VISIBLE; 311 case RenderConfig::VISIBILITY_FULLSCREEN: return WindowParams::VISIBILITY_FULLSCREEN; 312 default: 313 DE_ASSERT(visibility == (RenderConfig::Visibility)RenderConfig::DONT_CARE); 314 return WindowParams::VISIBILITY_DONT_CARE; 315 } 316 } 317 318 typedef std::pair<NativeWindow*, EGLSurface> WindowSurfacePair; 319 typedef std::pair<NativePixmap*, EGLSurface> PixmapSurfacePair; 320 321 WindowSurfacePair createWindow (NativeDisplay* nativeDisplay, const NativeWindowFactory* windowFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config) 322 { 323 const int width = (config.width == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE : config.width); 324 const int height = (config.height == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE : config.height); 325 const WindowParams::Visibility visibility = getNativeWindowVisibility(config.windowVisibility); 326 NativeWindow* nativeWindow = DE_NULL; 327 EGLSurface surface = EGL_NO_SURFACE; 328 const EGLAttrib attribList[] = { EGL_NONE }; 329 330 nativeWindow = windowFactory->createWindow(nativeDisplay, eglDisplay, eglConfig, &attribList[0], WindowParams(width, height, visibility)); 331 332 try 333 { 334 surface = eglu::createWindowSurface(*nativeDisplay, *nativeWindow, eglDisplay, eglConfig, attribList); 335 } 336 catch (...) 337 { 338 delete nativeWindow; 339 throw; 340 } 341 342 return WindowSurfacePair(nativeWindow, surface); 343 } 344 345 PixmapSurfacePair createPixmap (NativeDisplay* nativeDisplay, const NativePixmapFactory* pixmapFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config) 346 { 347 const int width = (config.width == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH : config.width); 348 const int height = (config.height == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT : config.height); 349 NativePixmap* nativePixmap = DE_NULL; 350 EGLSurface surface = EGL_NO_SURFACE; 351 const EGLAttrib attribList[] = { EGL_NONE }; 352 353 nativePixmap = pixmapFactory->createPixmap(nativeDisplay, eglDisplay, eglConfig, &attribList[0], width, height); 354 355 try 356 { 357 surface = eglu::createPixmapSurface(*nativeDisplay, *nativePixmap, eglDisplay, eglConfig, attribList); 358 } 359 catch (...) 360 { 361 delete nativePixmap; 362 throw; 363 } 364 365 return PixmapSurfacePair(nativePixmap, surface); 366 } 367 368 EGLSurface createPBuffer (EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& config) 369 { 370 const int width = (config.width == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH : config.width); 371 const int height = (config.height == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT : config.height); 372 EGLSurface surface; 373 const EGLint attribList[] = 374 { 375 EGL_WIDTH, width, 376 EGL_HEIGHT, height, 377 EGL_NONE 378 }; 379 380 surface = eglCreatePbufferSurface(display, eglConfig, &(attribList[0])); 381 EGLU_CHECK_MSG("eglCreatePbufferSurface()"); 382 383 return surface; 384 } 385 386 bool isClientExtensionSupported (EGLDisplay display, const std::string& extName) 387 { 388 const vector<string> exts = getClientExtensions(display); 389 return de::contains(exts.begin(), exts.end(), extName); 390 } 391 392 EGLContext createContext (EGLDisplay display, EGLContext eglConfig, const glu::RenderConfig& config) 393 { 394 const bool khrCreateContextSupported = isClientExtensionSupported(display, "EGL_KHR_create_context"); 395 EGLContext context = EGL_NO_CONTEXT; 396 EGLenum api = EGL_NONE; 397 vector<EGLint> attribList; 398 399 if (glu::isContextTypeES(config.type)) 400 { 401 api = EGL_OPENGL_ES_API; 402 403 if (config.type.getMajorVersion() <= 2) 404 { 405 attribList.push_back(EGL_CONTEXT_CLIENT_VERSION); 406 attribList.push_back(config.type.getMajorVersion()); 407 } 408 else 409 { 410 if (!khrCreateContextSupported) 411 throw tcu::NotSupportedError("EGL_KHR_create_context is required for OpenGL ES 3.0 and newer", DE_NULL, __FILE__, __LINE__); 412 413 attribList.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); 414 attribList.push_back(config.type.getMajorVersion()); 415 attribList.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); 416 attribList.push_back(config.type.getMinorVersion()); 417 } 418 } 419 else 420 { 421 DE_ASSERT(glu::isContextTypeGLCore(config.type) || glu::isContextTypeGLCompatibility(config.type)); 422 423 if (!khrCreateContextSupported) 424 throw tcu::NotSupportedError("EGL_KHR_create_context is required for OpenGL context creation", DE_NULL, __FILE__, __LINE__); 425 426 api = EGL_OPENGL_API; 427 428 attribList.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); 429 attribList.push_back(config.type.getMajorVersion()); 430 attribList.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); 431 attribList.push_back(config.type.getMinorVersion()); 432 attribList.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); 433 attribList.push_back(glu::isContextTypeGLCore(config.type) ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 434 : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); 435 } 436 437 if (config.type.getFlags() != glu::ContextFlags(0)) 438 { 439 EGLint flags = 0; 440 441 if (!khrCreateContextSupported) 442 throw tcu::NotSupportedError("EGL_KHR_create_context is required for creating robust/debug/forward-compatible contexts"); 443 444 if ((config.type.getFlags() & glu::CONTEXT_DEBUG) != 0) 445 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; 446 447 if ((config.type.getFlags() & glu::CONTEXT_ROBUST) != 0) 448 flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; 449 450 if ((config.type.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0) 451 { 452 if (!glu::isContextTypeGLCore(config.type)) 453 throw tcu::NotSupportedError("Only OpenGL core contexts can be forward-compatible"); 454 455 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; 456 } 457 458 attribList.push_back(EGL_CONTEXT_FLAGS_KHR); 459 attribList.push_back(flags); 460 } 461 462 attribList.push_back(EGL_NONE); 463 464 EGLU_CHECK_CALL(eglBindAPI(api)); 465 context = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT, &(attribList[0])); 466 EGLU_CHECK_MSG("eglCreateContext()"); 467 468 return context; 469 } 470 471 void RenderContext::create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config) 472 { 473 glu::RenderConfig::SurfaceType surfaceType = config.surfaceType; 474 475 DE_ASSERT(displayFactory); 476 477 m_display = displayFactory->createDisplay(); 478 m_eglDisplay = eglu::getDisplay(*m_display); 479 480 { 481 EGLint major = 0; 482 EGLint minor = 0; 483 EGLU_CHECK_CALL(eglInitialize(m_eglDisplay, &major, &minor)); 484 } 485 486 m_eglConfig = chooseConfig(m_eglDisplay, config); 487 488 if (surfaceType == glu::RenderConfig::SURFACETYPE_DONT_CARE) 489 { 490 // Choose based on what selected configuration supports 491 const EGLint supportedTypes = eglu::getConfigAttribInt(m_eglDisplay, m_eglConfig, EGL_SURFACE_TYPE); 492 493 if ((supportedTypes & EGL_WINDOW_BIT) != 0) 494 surfaceType = glu::RenderConfig::SURFACETYPE_WINDOW; 495 else if ((supportedTypes & EGL_PBUFFER_BIT) != 0) 496 surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC; 497 else if ((supportedTypes & EGL_PIXMAP_BIT) != 0) 498 surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE; 499 else 500 throw tcu::NotSupportedError("Selected EGL config doesn't support any surface types", DE_NULL, __FILE__, __LINE__); 501 } 502 503 switch (surfaceType) 504 { 505 case glu::RenderConfig::SURFACETYPE_WINDOW: 506 { 507 if (windowFactory) 508 { 509 const WindowSurfacePair windowSurface = createWindow(m_display, windowFactory, m_eglDisplay, m_eglConfig, config); 510 m_window = windowSurface.first; 511 m_eglSurface = windowSurface.second; 512 } 513 else 514 throw tcu::NotSupportedError("EGL platform doesn't support windows", DE_NULL, __FILE__, __LINE__); 515 break; 516 } 517 518 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: 519 { 520 if (pixmapFactory) 521 { 522 const PixmapSurfacePair pixmapSurface = createPixmap(m_display, pixmapFactory, m_eglDisplay, m_eglConfig, config); 523 m_pixmap = pixmapSurface.first; 524 m_eglSurface = pixmapSurface.second; 525 } 526 else 527 throw tcu::NotSupportedError("EGL platform doesn't support pixmaps", DE_NULL, __FILE__, __LINE__); 528 break; 529 } 530 531 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: 532 m_eglSurface = createPBuffer(m_eglDisplay, m_eglConfig, config); 533 break; 534 535 default: 536 throw tcu::InternalError("Invalid surface type"); 537 } 538 539 m_eglContext = createContext(m_eglDisplay, m_eglConfig, config); 540 541 EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)); 542 543 // Init core functions 544 545 if (isClientExtensionSupported(m_eglDisplay, "EGL_KHR_get_all_proc_addresses")) 546 { 547 // Use eglGetProcAddress() for core functions 548 GetProcFuncLoader funcLoader; 549 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI()); 550 } 551 #if !defined(DEQP_GLES2_RUNTIME_LOAD) 552 else if (config.type.getAPI() == glu::ApiType::es(2,0)) 553 { 554 glw::initES20Direct(&m_glFunctions); 555 } 556 #endif 557 #if !defined(DEQP_GLES3_RUNTIME_LOAD) 558 else if (config.type.getAPI() == glu::ApiType::es(3,0)) 559 { 560 glw::initES30Direct(&m_glFunctions); 561 } 562 #endif 563 else 564 { 565 const char* libraryPath = DE_NULL; 566 567 if (glu::isContextTypeES(config.type)) 568 { 569 if (config.type.getMinorVersion() <= 2) 570 libraryPath = DEQP_GLES2_LIBRARY_PATH; 571 else 572 libraryPath = DEQP_GLES3_LIBRARY_PATH; 573 } 574 else 575 libraryPath = DEQP_OPENGL_LIBRARY_PATH; 576 577 m_dynamicGLLibrary = new de::DynamicLibrary(libraryPath); 578 579 DynamicFuncLoader funcLoader(m_dynamicGLLibrary); 580 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI()); 581 } 582 583 // Init extension functions 584 { 585 GetProcFuncLoader extLoader; 586 glu::initExtensionFunctions(&m_glFunctions, &extLoader, config.type.getAPI()); 587 } 588 589 { 590 EGLint width, height, depthBits, stencilBits, numSamples; 591 tcu::PixelFormat pixelFmt; 592 593 eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &width); 594 eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &height); 595 596 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_RED_SIZE, &pixelFmt.redBits); 597 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_GREEN_SIZE, &pixelFmt.greenBits); 598 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_BLUE_SIZE, &pixelFmt.blueBits); 599 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_ALPHA_SIZE, &pixelFmt.alphaBits); 600 601 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_DEPTH_SIZE, &depthBits); 602 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_STENCIL_SIZE, &stencilBits); 603 eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_SAMPLES, &numSamples); 604 605 EGLU_CHECK_MSG("Failed to query config attributes"); 606 607 m_glRenderTarget = tcu::RenderTarget(width, height, pixelFmt, depthBits, stencilBits, numSamples); 608 } 609 } 610 611 void RenderContext::destroy (void) 612 { 613 if (m_eglDisplay != EGL_NO_DISPLAY) 614 { 615 EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 616 617 if (m_eglSurface != EGL_NO_SURFACE) 618 EGLU_CHECK_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface)); 619 620 if (m_eglContext != EGL_NO_CONTEXT) 621 EGLU_CHECK_CALL(eglDestroyContext(m_eglDisplay, m_eglContext)); 622 623 EGLU_CHECK_CALL(eglTerminate(m_eglDisplay)); 624 625 m_eglDisplay = EGL_NO_DISPLAY; 626 m_eglSurface = EGL_NO_SURFACE; 627 m_eglContext = EGL_NO_CONTEXT; 628 } 629 630 delete m_window; 631 delete m_pixmap; 632 delete m_display; 633 delete m_dynamicGLLibrary; 634 635 m_window = DE_NULL; 636 m_pixmap = DE_NULL; 637 m_display = DE_NULL; 638 m_dynamicGLLibrary = DE_NULL; 639 } 640 641 void RenderContext::postIterate (void) 642 { 643 if (m_window) 644 { 645 EGLBoolean swapOk = eglSwapBuffers(m_eglDisplay, m_eglSurface); 646 EGLint error = eglGetError(); 647 const bool badWindow = error == EGL_BAD_SURFACE || error == EGL_BAD_NATIVE_WINDOW; 648 649 if (!swapOk && !badWindow) 650 throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString()); 651 652 try 653 { 654 m_window->processEvents(); 655 } 656 catch (const WindowDestroyedError&) 657 { 658 tcu::print("Warning: Window destroyed, recreating...\n"); 659 660 EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 661 EGLU_CHECK_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface)); 662 m_eglSurface = EGL_NO_SURFACE; 663 664 delete m_window; 665 m_window = DE_NULL; 666 667 try 668 { 669 WindowSurfacePair windowSurface = createWindow(m_display, m_nativeWindowFactory, m_eglDisplay, m_eglConfig, m_renderConfig); 670 m_window = windowSurface.first; 671 m_eglSurface = windowSurface.second; 672 673 EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)); 674 675 swapOk = EGL_TRUE; 676 error = EGL_SUCCESS; 677 } 678 catch (const std::exception& e) 679 { 680 if (m_eglSurface) 681 { 682 eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 683 eglDestroySurface(m_eglDisplay, m_eglSurface); 684 m_eglSurface = EGL_NO_SURFACE; 685 } 686 687 delete m_window; 688 m_window = DE_NULL; 689 690 throw tcu::ResourceError(string("Failed to re-create window: ") + e.what()); 691 } 692 } 693 694 if (!swapOk) 695 { 696 DE_ASSERT(badWindow); 697 throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString()); 698 } 699 700 // Refresh dimensions 701 { 702 int newWidth = 0; 703 int newHeight = 0; 704 705 eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &newWidth); 706 eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &newHeight); 707 EGLU_CHECK_MSG("Failed to query window size"); 708 709 if (newWidth != m_glRenderTarget.getWidth() || 710 newHeight != m_glRenderTarget.getHeight()) 711 { 712 tcu::print("Warning: Window size changed (%dx%d -> %dx%d), test results might be invalid!\n", 713 m_glRenderTarget.getWidth(), m_glRenderTarget.getHeight(), newWidth, newHeight); 714 715 m_glRenderTarget = tcu::RenderTarget(newWidth, newHeight, 716 m_glRenderTarget.getPixelFormat(), 717 m_glRenderTarget.getDepthBits(), 718 m_glRenderTarget.getStencilBits(), 719 m_glRenderTarget.getNumSamples()); 720 } 721 } 722 } 723 else 724 { 725 // \todo [2014-05-02 mika] Should we call flush or finish? Old platform uses finish() but flush() is closer to the behaviour of eglSwapBuffers() 726 m_glFunctions.flush(); 727 GLU_EXPECT_NO_ERROR(m_glFunctions.getError(), "glFlush()"); 728 } 729 } 730 731 } // anonymous 732 733 GLContextFactory::GLContextFactory (const NativeDisplayFactoryRegistry& displayFactoryRegistry) 734 : glu::ContextFactory ("egl", "EGL OpenGL Context") 735 , m_displayFactoryRegistry (displayFactoryRegistry) 736 { 737 } 738 739 namespace 740 { 741 742 template<typename Factory> 743 const Factory* selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg) 744 { 745 if (cmdLineArg) 746 { 747 const Factory* factory = registry.getFactoryByName(cmdLineArg); 748 749 if (factory) 750 return factory; 751 else 752 { 753 tcu::print("ERROR: Unknown or unsupported EGL %s type '%s'", objectTypeName, cmdLineArg); 754 tcu::print("Available EGL %s types:\n", objectTypeName); 755 for (size_t ndx = 0; ndx < registry.getFactoryCount(); ndx++) 756 tcu::print(" %s: %s\n", registry.getFactoryByIndex(ndx)->getName(), registry.getFactoryByIndex(ndx)->getDescription()); 757 758 throw tcu::NotSupportedError((string("Unsupported or unknown EGL ") + objectTypeName + " type '" + cmdLineArg + "'").c_str(), DE_NULL, __FILE__, __LINE__); 759 } 760 } 761 else if (!registry.empty()) 762 return registry.getDefaultFactory(); 763 else 764 return DE_NULL; 765 } 766 767 } // anonymous 768 769 glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const 770 { 771 const NativeDisplayFactory* displayFactory = selectFactory(m_displayFactoryRegistry, "display", cmdLine.getEGLDisplayType()); 772 773 if (displayFactory) 774 { 775 // \note windowFactory & pixmapFactory are not mandatory 776 const NativeWindowFactory* windowFactory = selectFactory(displayFactory->getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType()); 777 const NativePixmapFactory* pixmapFactory = selectFactory(displayFactory->getNativePixmapRegistry(), "pixmap", cmdLine.getEGLPixmapType()); 778 779 return new RenderContext(displayFactory, windowFactory, pixmapFactory, config); 780 } 781 else 782 throw tcu::NotSupportedError("No EGL displays available", DE_NULL, __FILE__, __LINE__); 783 } 784 785 } // eglu 786