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 "egluUtil.hpp" 34#include "egluGLUtil.hpp" 35#include "egluNativeWindow.hpp" 36#include "egluNativePixmap.hpp" 37#include "egluStrUtil.hpp" 38 39#include "eglwLibrary.hpp" 40#include "eglwEnums.hpp" 41 42#include "glwInitFunctions.hpp" 43#include "glwInitES20Direct.hpp" 44#include "glwInitES30Direct.hpp" 45 46#include "deDynamicLibrary.hpp" 47#include "deSTLUtil.hpp" 48 49#include <string> 50#include <string> 51#include <sstream> 52 53using std::string; 54using std::vector; 55 56// \todo [2014-03-12 pyry] Use command line arguments for libraries? 57 58// Default library names 59#if !defined(DEQP_GLES2_LIBRARY_PATH) 60# if (DE_OS == DE_OS_WIN32) 61# define DEQP_GLES2_LIBRARY_PATH "libGLESv2.dll" 62# else 63# define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so" 64# endif 65#endif 66 67#if !defined(DEQP_GLES3_LIBRARY_PATH) 68# define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH 69#endif 70 71#if !defined(DEQP_OPENGL_LIBRARY_PATH) 72# if (DE_OS == DE_OS_WIN32) 73# define DEQP_OPENGL_LIBRARY_PATH "opengl32.dll" 74# else 75# define DEQP_OPENGL_LIBRARY_PATH "libGL.so" 76# endif 77#endif 78 79namespace eglu 80{ 81 82using namespace eglw; 83 84namespace 85{ 86 87enum 88{ 89 DEFAULT_OFFSCREEN_WIDTH = 512, 90 DEFAULT_OFFSCREEN_HEIGHT = 512 91}; 92 93class GetProcFuncLoader : public glw::FunctionLoader 94{ 95public: 96 GetProcFuncLoader (const Library& egl) 97 : m_egl(egl) 98 { 99 } 100 101 glw::GenericFuncType get (const char* name) const 102 { 103 return (glw::GenericFuncType)m_egl.getProcAddress(name); 104 } 105 106protected: 107 const Library& m_egl; 108}; 109 110class DynamicFuncLoader : public glw::FunctionLoader 111{ 112public: 113 DynamicFuncLoader (de::DynamicLibrary* library) 114 : m_library(library) 115 { 116 } 117 118 glw::GenericFuncType get (const char* name) const 119 { 120 return (glw::GenericFuncType)m_library->getFunction(name); 121 } 122 123private: 124 de::DynamicLibrary* m_library; 125}; 126 127class RenderContext : public GLRenderContext 128{ 129public: 130 RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config); 131 virtual ~RenderContext (void); 132 133 virtual glu::ContextType getType (void) const { return m_renderConfig.type; } 134 virtual const glw::Functions& getFunctions (void) const { return m_glFunctions; } 135 virtual const tcu::RenderTarget& getRenderTarget (void) const { return m_glRenderTarget; } 136 virtual void postIterate (void); 137 138 virtual EGLDisplay getEGLDisplay (void) const { return m_eglDisplay; } 139 virtual EGLContext getEGLContext (void) const { return m_eglContext; } 140 141private: 142 void create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config); 143 void destroy (void); 144 145 const glu::RenderConfig m_renderConfig; 146 const NativeWindowFactory* const m_nativeWindowFactory; // Stored in case window must be re-created 147 148 NativeDisplay* m_display; 149 NativeWindow* m_window; 150 NativePixmap* m_pixmap; 151 152 EGLDisplay m_eglDisplay; 153 EGLConfig m_eglConfig; 154 EGLSurface m_eglSurface; 155 EGLContext m_eglContext; 156 157 tcu::RenderTarget m_glRenderTarget; 158 de::DynamicLibrary* m_dynamicGLLibrary; 159 glw::Functions m_glFunctions; 160}; 161 162RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config) 163 : m_renderConfig (config) 164 , m_nativeWindowFactory (windowFactory) 165 , m_display (DE_NULL) 166 , m_window (DE_NULL) 167 , m_pixmap (DE_NULL) 168 169 , m_eglDisplay (EGL_NO_DISPLAY) 170 , m_eglSurface (EGL_NO_SURFACE) 171 , m_eglContext (EGL_NO_CONTEXT) 172 173 , m_dynamicGLLibrary (DE_NULL) 174{ 175 DE_ASSERT(displayFactory); 176 177 try 178 { 179 create(displayFactory, windowFactory, pixmapFactory, config); 180 } 181 catch (...) 182 { 183 destroy(); 184 throw; 185 } 186} 187 188RenderContext::~RenderContext(void) 189{ 190 try 191 { 192 destroy(); 193 } 194 catch (...) 195 { 196 // destroy() calls EGL functions that are checked and may throw exceptions 197 } 198 199 delete m_window; 200 delete m_pixmap; 201 delete m_display; 202 delete m_dynamicGLLibrary; 203} 204 205static WindowParams::Visibility getNativeWindowVisibility (glu::RenderConfig::Visibility visibility) 206{ 207 using glu::RenderConfig; 208 209 switch (visibility) 210 { 211 case RenderConfig::VISIBILITY_HIDDEN: return WindowParams::VISIBILITY_HIDDEN; 212 case RenderConfig::VISIBILITY_VISIBLE: return WindowParams::VISIBILITY_VISIBLE; 213 case RenderConfig::VISIBILITY_FULLSCREEN: return WindowParams::VISIBILITY_FULLSCREEN; 214 default: 215 DE_ASSERT((int)visibility == RenderConfig::DONT_CARE); 216 return WindowParams::VISIBILITY_DONT_CARE; 217 } 218} 219 220typedef std::pair<NativeWindow*, EGLSurface> WindowSurfacePair; 221typedef std::pair<NativePixmap*, EGLSurface> PixmapSurfacePair; 222 223WindowSurfacePair createWindow (NativeDisplay* nativeDisplay, const NativeWindowFactory* windowFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config) 224{ 225 const int width = (config.width == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE : config.width); 226 const int height = (config.height == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE : config.height); 227 const WindowParams::Visibility visibility = getNativeWindowVisibility(config.windowVisibility); 228 NativeWindow* nativeWindow = DE_NULL; 229 EGLSurface surface = EGL_NO_SURFACE; 230 const EGLAttrib attribList[] = { EGL_NONE }; 231 232 nativeWindow = windowFactory->createWindow(nativeDisplay, eglDisplay, eglConfig, &attribList[0], WindowParams(width, height, visibility)); 233 234 try 235 { 236 surface = eglu::createWindowSurface(*nativeDisplay, *nativeWindow, eglDisplay, eglConfig, attribList); 237 } 238 catch (...) 239 { 240 delete nativeWindow; 241 throw; 242 } 243 244 return WindowSurfacePair(nativeWindow, surface); 245} 246 247PixmapSurfacePair createPixmap (NativeDisplay* nativeDisplay, const NativePixmapFactory* pixmapFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config) 248{ 249 const int width = (config.width == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH : config.width); 250 const int height = (config.height == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT : config.height); 251 NativePixmap* nativePixmap = DE_NULL; 252 EGLSurface surface = EGL_NO_SURFACE; 253 const EGLAttrib attribList[] = { EGL_NONE }; 254 255 nativePixmap = pixmapFactory->createPixmap(nativeDisplay, eglDisplay, eglConfig, &attribList[0], width, height); 256 257 try 258 { 259 surface = eglu::createPixmapSurface(*nativeDisplay, *nativePixmap, eglDisplay, eglConfig, attribList); 260 } 261 catch (...) 262 { 263 delete nativePixmap; 264 throw; 265 } 266 267 return PixmapSurfacePair(nativePixmap, surface); 268} 269 270EGLSurface createPBuffer (const Library& egl, EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& config) 271{ 272 const int width = (config.width == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH : config.width); 273 const int height = (config.height == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT : config.height); 274 EGLSurface surface; 275 const EGLint attribList[] = 276 { 277 EGL_WIDTH, width, 278 EGL_HEIGHT, height, 279 EGL_NONE 280 }; 281 282 surface = egl.createPbufferSurface(display, eglConfig, &(attribList[0])); 283 EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()"); 284 285 return surface; 286} 287 288void RenderContext::create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config) 289{ 290 glu::RenderConfig::SurfaceType surfaceType = config.surfaceType; 291 292 DE_ASSERT(displayFactory); 293 294 m_display = displayFactory->createDisplay(); 295 m_eglDisplay = eglu::getDisplay(*m_display); 296 297 const Library& egl = m_display->getLibrary(); 298 299 { 300 EGLint major = 0; 301 EGLint minor = 0; 302 EGLU_CHECK_CALL(egl, initialize(m_eglDisplay, &major, &minor)); 303 } 304 305 m_eglConfig = chooseConfig(egl, m_eglDisplay, config); 306 307 if (surfaceType == glu::RenderConfig::SURFACETYPE_DONT_CARE) 308 { 309 // Choose based on what selected configuration supports 310 const EGLint supportedTypes = eglu::getConfigAttribInt(egl, m_eglDisplay, m_eglConfig, EGL_SURFACE_TYPE); 311 312 if ((supportedTypes & EGL_WINDOW_BIT) != 0) 313 surfaceType = glu::RenderConfig::SURFACETYPE_WINDOW; 314 else if ((supportedTypes & EGL_PBUFFER_BIT) != 0) 315 surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC; 316 else if ((supportedTypes & EGL_PIXMAP_BIT) != 0) 317 surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE; 318 else 319 throw tcu::NotSupportedError("Selected EGL config doesn't support any surface types", DE_NULL, __FILE__, __LINE__); 320 } 321 322 switch (surfaceType) 323 { 324 case glu::RenderConfig::SURFACETYPE_WINDOW: 325 { 326 if (windowFactory) 327 { 328 const WindowSurfacePair windowSurface = createWindow(m_display, windowFactory, m_eglDisplay, m_eglConfig, config); 329 m_window = windowSurface.first; 330 m_eglSurface = windowSurface.second; 331 } 332 else 333 throw tcu::NotSupportedError("EGL platform doesn't support windows", DE_NULL, __FILE__, __LINE__); 334 break; 335 } 336 337 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: 338 { 339 if (pixmapFactory) 340 { 341 const PixmapSurfacePair pixmapSurface = createPixmap(m_display, pixmapFactory, m_eglDisplay, m_eglConfig, config); 342 m_pixmap = pixmapSurface.first; 343 m_eglSurface = pixmapSurface.second; 344 } 345 else 346 throw tcu::NotSupportedError("EGL platform doesn't support pixmaps", DE_NULL, __FILE__, __LINE__); 347 break; 348 } 349 350 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: 351 m_eglSurface = createPBuffer(egl, m_eglDisplay, m_eglConfig, config); 352 break; 353 354 default: 355 throw tcu::InternalError("Invalid surface type"); 356 } 357 358 m_eglContext = createGLContext(egl, m_eglDisplay, m_eglConfig, config.type); 359 360 EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)); 361 362 // Init core functions 363 364 if (hasExtension(egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses")) 365 { 366 // Use eglGetProcAddress() for core functions 367 GetProcFuncLoader funcLoader(egl); 368 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI()); 369 } 370#if !defined(DEQP_GLES2_RUNTIME_LOAD) 371 else if (config.type.getAPI() == glu::ApiType::es(2,0)) 372 { 373 glw::initES20Direct(&m_glFunctions); 374 } 375#endif 376#if !defined(DEQP_GLES3_RUNTIME_LOAD) 377 else if (config.type.getAPI() == glu::ApiType::es(3,0)) 378 { 379 glw::initES30Direct(&m_glFunctions); 380 } 381#endif 382 else 383 { 384 const char* libraryPath = DE_NULL; 385 386 if (glu::isContextTypeES(config.type)) 387 { 388 if (config.type.getMinorVersion() <= 2) 389 libraryPath = DEQP_GLES2_LIBRARY_PATH; 390 else 391 libraryPath = DEQP_GLES3_LIBRARY_PATH; 392 } 393 else 394 libraryPath = DEQP_OPENGL_LIBRARY_PATH; 395 396 m_dynamicGLLibrary = new de::DynamicLibrary(libraryPath); 397 398 DynamicFuncLoader funcLoader(m_dynamicGLLibrary); 399 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI()); 400 } 401 402 // Init extension functions 403 { 404 GetProcFuncLoader extLoader(egl); 405 glu::initExtensionFunctions(&m_glFunctions, &extLoader, config.type.getAPI()); 406 } 407 408 { 409 EGLint width, height, depthBits, stencilBits, numSamples; 410 tcu::PixelFormat pixelFmt; 411 412 egl.querySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &width); 413 egl.querySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &height); 414 415 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_RED_SIZE, &pixelFmt.redBits); 416 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_GREEN_SIZE, &pixelFmt.greenBits); 417 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_BLUE_SIZE, &pixelFmt.blueBits); 418 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_ALPHA_SIZE, &pixelFmt.alphaBits); 419 420 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_DEPTH_SIZE, &depthBits); 421 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_STENCIL_SIZE, &stencilBits); 422 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_SAMPLES, &numSamples); 423 424 EGLU_CHECK_MSG(egl, "Failed to query config attributes"); 425 426 m_glRenderTarget = tcu::RenderTarget(width, height, pixelFmt, depthBits, stencilBits, numSamples); 427 } 428} 429 430void RenderContext::destroy (void) 431{ 432 const Library& egl = m_display->getLibrary(); 433 434 if (m_eglDisplay != EGL_NO_DISPLAY) 435 { 436 EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 437 438 if (m_eglSurface != EGL_NO_SURFACE) 439 EGLU_CHECK_CALL(egl, destroySurface(m_eglDisplay, m_eglSurface)); 440 441 if (m_eglContext != EGL_NO_CONTEXT) 442 EGLU_CHECK_CALL(egl, destroyContext(m_eglDisplay, m_eglContext)); 443 444 EGLU_CHECK_CALL(egl, terminate(m_eglDisplay)); 445 446 m_eglDisplay = EGL_NO_DISPLAY; 447 m_eglSurface = EGL_NO_SURFACE; 448 m_eglContext = EGL_NO_CONTEXT; 449 } 450 451 delete m_window; 452 delete m_pixmap; 453 delete m_display; 454 delete m_dynamicGLLibrary; 455 456 m_window = DE_NULL; 457 m_pixmap = DE_NULL; 458 m_display = DE_NULL; 459 m_dynamicGLLibrary = DE_NULL; 460} 461 462void RenderContext::postIterate (void) 463{ 464 const Library& egl = m_display->getLibrary(); 465 466 if (m_window) 467 { 468 EGLBoolean swapOk = egl.swapBuffers(m_eglDisplay, m_eglSurface); 469 EGLint error = egl.getError(); 470 const bool badWindow = error == EGL_BAD_SURFACE || error == EGL_BAD_NATIVE_WINDOW; 471 472 if (!swapOk && !badWindow) 473 throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString()); 474 475 try 476 { 477 m_window->processEvents(); 478 } 479 catch (const WindowDestroyedError&) 480 { 481 tcu::print("Warning: Window destroyed, recreating...\n"); 482 483 EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 484 EGLU_CHECK_CALL(egl, destroySurface(m_eglDisplay, m_eglSurface)); 485 m_eglSurface = EGL_NO_SURFACE; 486 487 delete m_window; 488 m_window = DE_NULL; 489 490 try 491 { 492 WindowSurfacePair windowSurface = createWindow(m_display, m_nativeWindowFactory, m_eglDisplay, m_eglConfig, m_renderConfig); 493 m_window = windowSurface.first; 494 m_eglSurface = windowSurface.second; 495 496 EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)); 497 498 swapOk = EGL_TRUE; 499 error = EGL_SUCCESS; 500 } 501 catch (const std::exception& e) 502 { 503 if (m_eglSurface) 504 { 505 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 506 egl.destroySurface(m_eglDisplay, m_eglSurface); 507 m_eglSurface = EGL_NO_SURFACE; 508 } 509 510 delete m_window; 511 m_window = DE_NULL; 512 513 throw tcu::ResourceError(string("Failed to re-create window: ") + e.what()); 514 } 515 } 516 517 if (!swapOk) 518 { 519 DE_ASSERT(badWindow); 520 throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString()); 521 } 522 523 // Refresh dimensions 524 { 525 int newWidth = 0; 526 int newHeight = 0; 527 528 egl.querySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &newWidth); 529 egl.querySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &newHeight); 530 EGLU_CHECK_MSG(egl, "Failed to query window size"); 531 532 if (newWidth != m_glRenderTarget.getWidth() || 533 newHeight != m_glRenderTarget.getHeight()) 534 { 535 tcu::print("Warning: Window size changed (%dx%d -> %dx%d), test results might be invalid!\n", 536 m_glRenderTarget.getWidth(), m_glRenderTarget.getHeight(), newWidth, newHeight); 537 538 m_glRenderTarget = tcu::RenderTarget(newWidth, newHeight, 539 m_glRenderTarget.getPixelFormat(), 540 m_glRenderTarget.getDepthBits(), 541 m_glRenderTarget.getStencilBits(), 542 m_glRenderTarget.getNumSamples()); 543 } 544 } 545 } 546 else 547 m_glFunctions.flush(); 548} 549 550} // anonymous 551 552GLContextFactory::GLContextFactory (const NativeDisplayFactoryRegistry& displayFactoryRegistry) 553 : glu::ContextFactory ("egl", "EGL OpenGL Context") 554 , m_displayFactoryRegistry (displayFactoryRegistry) 555{ 556} 557 558glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const 559{ 560 const NativeDisplayFactory& displayFactory = selectNativeDisplayFactory(m_displayFactoryRegistry, cmdLine); 561 562 const NativeWindowFactory* windowFactory; 563 const NativePixmapFactory* pixmapFactory; 564 565 try 566 { 567 windowFactory = &selectNativeWindowFactory(displayFactory, cmdLine); 568 } 569 catch (const tcu::NotSupportedError&) 570 { 571 windowFactory = DE_NULL; 572 } 573 574 try 575 { 576 pixmapFactory = &selectNativePixmapFactory(displayFactory, cmdLine); 577 } 578 catch (const tcu::NotSupportedError&) 579 { 580 pixmapFactory = DE_NULL; 581 } 582 583 return new RenderContext(&displayFactory, windowFactory, pixmapFactory, config); 584} 585 586} // eglu 587