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 Platform that uses X11 via GLX. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "tcuLnxX11GlxPlatform.hpp" 25 26 #include "tcuRenderTarget.hpp" 27 #include "glwInitFunctions.hpp" 28 #include "deUniquePtr.hpp" 29 #include "glwEnums.hpp" 30 31 #include <sstream> 32 #include <iterator> 33 #include <set> 34 35 #define GLX_GLXEXT_PROTOTYPES 36 #include <GL/glx.h> 37 38 #ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB 39 #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 40 #endif 41 42 namespace tcu 43 { 44 namespace lnx 45 { 46 namespace x11 47 { 48 namespace glx 49 { 50 51 using de::UniquePtr; 52 using de::MovePtr; 53 using glu::ApiType; 54 using glu::ContextFactory; 55 using glu::ContextType; 56 using glu::RenderConfig; 57 using glu::RenderContext; 58 using tcu::CommandLine; 59 using tcu::RenderTarget; 60 using std::string; 61 using std::set; 62 using std::istringstream; 63 using std::ostringstream; 64 using std::istream_iterator; 65 66 typedef RenderConfig::Visibility Visibility; 67 68 69 template<typename T> 70 static inline T checkGLX(T value, const char* expr, const char* file, int line) 71 { 72 if (!value) 73 throw tcu::TestError("GLX call failed", expr, file, line); 74 return value; 75 } 76 77 #define TCU_CHECK_GLX(EXPR) checkGLX(EXPR, #EXPR, __FILE__, __LINE__) 78 #define TCU_CHECK_GLX_CONFIG(EXPR) checkGLX((EXPR) == Success, #EXPR, __FILE__, __LINE__) 79 80 class GlxContextFactory : public glu::ContextFactory 81 { 82 public: 83 GlxContextFactory (EventState& eventState); 84 ~GlxContextFactory (void); 85 RenderContext* createContext (const RenderConfig& config, 86 const CommandLine& cmdLine) const; 87 88 EventState& getEventState (void) const { return m_eventState;} 89 90 const PFNGLXCREATECONTEXTATTRIBSARBPROC 91 m_glXCreateContextAttribsARB; 92 93 private: 94 EventState& m_eventState; 95 }; 96 97 class GlxDisplay : public XlibDisplay 98 { 99 public: 100 GlxDisplay (EventState& eventState, 101 const char* name); 102 int getGlxMajorVersion (void) const { return m_majorVersion; } 103 int getGlxMinorVersion (void) const { return m_minorVersion; } 104 bool isGlxExtensionSupported (const char* extName) const; 105 106 private: 107 int m_errorBase; 108 int m_eventBase; 109 int m_majorVersion; 110 int m_minorVersion; 111 set<string> m_extensions; 112 }; 113 114 class GlxVisual 115 { 116 public: 117 GlxVisual (GlxDisplay& display, GLXFBConfig fbConfig); 118 int getAttrib (int attribute); 119 Visual* getXVisual (void) { return m_visual; } 120 GLXContext createContext (const GlxContextFactory& factory, 121 const ContextType& contextType, 122 glu::ResetNotificationStrategy resetNotificationStrategy); 123 GLXWindow createWindow (::Window xWindow); 124 GlxDisplay& getGlxDisplay (void) { return m_display; } 125 ::Display* getXDisplay (void) { return m_display.getXDisplay(); } 126 127 private: 128 GlxDisplay& m_display; 129 ::Visual* m_visual; 130 const GLXFBConfig m_fbConfig; 131 }; 132 133 class GlxDrawable 134 { 135 public: 136 virtual ~GlxDrawable (void) {} 137 138 virtual void processEvents (void) {} 139 virtual void getDimensions (int* width, int* height) = 0; 140 int getWidth (void); 141 int getHeight (void); 142 void swapBuffers (void) { glXSwapBuffers(getXDisplay(), getGLXDrawable()); } 143 144 virtual ::Display* getXDisplay (void) = 0; 145 virtual GLXDrawable getGLXDrawable (void) = 0; 146 147 protected: 148 GlxDrawable () {} 149 unsigned int getAttrib (int attribute); 150 }; 151 152 class GlxWindow : public GlxDrawable 153 { 154 public: 155 GlxWindow (GlxVisual& visual, const RenderConfig& cfg); 156 ~GlxWindow (void); 157 void processEvents (void) { m_x11Window.processEvents(); } 158 ::Display* getXDisplay (void) { return m_x11Display.getXDisplay(); } 159 void getDimensions (int* width, int* height); 160 161 protected: 162 GLXDrawable getGLXDrawable () { return m_GLXDrawable; } 163 164 private: 165 XlibDisplay& m_x11Display; 166 XlibWindow m_x11Window; 167 const GLXDrawable m_GLXDrawable; 168 }; 169 170 class GlxRenderContext : public RenderContext 171 { 172 public: 173 GlxRenderContext (const GlxContextFactory& factory, 174 const RenderConfig& config); 175 ~GlxRenderContext (void); 176 virtual ContextType getType (void) const; 177 virtual void postIterate (void); 178 virtual void makeCurrent (void); 179 void clearCurrent (void); 180 virtual const glw::Functions& getFunctions (void) const; 181 virtual const tcu::RenderTarget& getRenderTarget (void) const; 182 183 private: 184 GlxDisplay m_glxDisplay; 185 GlxVisual m_glxVisual; 186 ContextType m_type; 187 GLXContext m_GLXContext; 188 UniquePtr<GlxDrawable> m_glxDrawable; 189 RenderTarget m_renderTarget; 190 glw::Functions m_functions; 191 }; 192 193 extern "C" 194 { 195 static int tcuLnxX11GlxErrorHandler (::Display* display, XErrorEvent* event) 196 { 197 char buf[80]; 198 XGetErrorText(display, event->error_code, buf, sizeof(buf)); 199 tcu::print("X operation %u:%u failed: %s\n", 200 event->request_code, event->minor_code, buf); 201 return 0; 202 } 203 } 204 205 GlxContextFactory::GlxContextFactory (EventState& eventState) 206 : glu::ContextFactory ("glx", "X11 GLX OpenGL Context") 207 , m_glXCreateContextAttribsARB ( 208 reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>( 209 TCU_CHECK_GLX( 210 glXGetProcAddress( 211 reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB"))))) 212 , m_eventState (eventState) 213 { 214 XSetErrorHandler(tcuLnxX11GlxErrorHandler); 215 } 216 217 RenderContext* GlxContextFactory::createContext (const RenderConfig& config, 218 const CommandLine& cmdLine) const 219 { 220 DE_UNREF(cmdLine); 221 GlxRenderContext* const renderContext = new GlxRenderContext(*this, config); 222 return renderContext; 223 } 224 225 GlxContextFactory::~GlxContextFactory (void) 226 { 227 } 228 229 GlxDisplay::GlxDisplay (EventState& eventState, const char* name) 230 : XlibDisplay (eventState, name) 231 { 232 const Bool supported = glXQueryExtension(m_display, &m_errorBase, &m_eventBase); 233 if (!supported) 234 TCU_THROW(NotSupportedError, "GLX protocol not supported by X server"); 235 236 TCU_CHECK_GLX(glXQueryVersion(m_display, &m_majorVersion, &m_minorVersion)); 237 238 { 239 const int screen = XDefaultScreen(m_display); 240 // nVidia doesn't seem to report client-side extensions correctly, 241 // so only use server side 242 const char* const extensions = 243 TCU_CHECK_GLX(glXQueryServerString(m_display, screen, GLX_EXTENSIONS)); 244 istringstream extStream(extensions); 245 m_extensions = set<string>(istream_iterator<string>(extStream), 246 istream_iterator<string>()); 247 } 248 } 249 250 251 bool GlxDisplay::isGlxExtensionSupported (const char* extName) const 252 { 253 return m_extensions.find(extName) != m_extensions.end(); 254 } 255 256 //! Throw `tcu::NotSupportedError` if `dpy` is not compatible with GLX 257 //! version `major`.`minor`. 258 static void checkGlxVersion (const GlxDisplay& dpy, int major, int minor) 259 { 260 const int dpyMajor = dpy.getGlxMajorVersion(); 261 const int dpyMinor = dpy.getGlxMinorVersion(); 262 if (!(dpyMajor == major && dpyMinor >= minor)) 263 { 264 ostringstream oss; 265 oss << "Server GLX version " 266 << dpyMajor << "." << dpyMinor 267 << " not compatible with required version " 268 << major << "." << minor; 269 TCU_THROW(NotSupportedError, oss.str().c_str()); 270 } 271 } 272 273 //! Throw `tcu::NotSupportedError` if `dpy` does not support extension `extName`. 274 static void checkGlxExtension (const GlxDisplay& dpy, const char* extName) 275 { 276 if (!dpy.isGlxExtensionSupported(extName)) 277 { 278 ostringstream oss; 279 oss << "GLX extension \"" << extName << "\" not supported"; 280 TCU_THROW(NotSupportedError, oss.str().c_str()); 281 } 282 } 283 284 GlxVisual::GlxVisual (GlxDisplay& display, GLXFBConfig fbConfig) 285 : m_display (display) 286 , m_visual (DE_NULL) 287 , m_fbConfig (fbConfig) 288 { 289 XVisualInfo* visualInfo = glXGetVisualFromFBConfig(getXDisplay(), fbConfig); 290 291 if (!visualInfo) 292 TCU_THROW(ResourceError, "glXGetVisualFromFBConfig() returned NULL"); 293 294 m_visual = visualInfo->visual; 295 XFree(visualInfo); 296 } 297 298 int GlxVisual::getAttrib (int attribute) 299 { 300 int fbvalue; 301 TCU_CHECK_GLX_CONFIG(glXGetFBConfigAttrib(getXDisplay(), m_fbConfig, attribute, &fbvalue)); 302 return fbvalue; 303 } 304 305 GLXContext GlxVisual::createContext (const GlxContextFactory& factory, 306 const ContextType& contextType, 307 glu::ResetNotificationStrategy resetNotificationStrategy) 308 { 309 std::vector<int> attribs; 310 311 checkGlxVersion(m_display, 1, 4); 312 checkGlxExtension(m_display, "GLX_ARB_create_context"); 313 checkGlxExtension(m_display, "GLX_ARB_create_context_profile"); 314 315 { 316 const ApiType apiType = contextType.getAPI(); 317 int profileMask = 0; 318 319 switch (apiType.getProfile()) 320 { 321 case glu::PROFILE_ES: 322 checkGlxExtension(m_display, "GLX_EXT_create_context_es2_profile"); 323 profileMask = GLX_CONTEXT_ES2_PROFILE_BIT_EXT; 324 break; 325 case glu::PROFILE_CORE: 326 profileMask = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; 327 break; 328 case glu::PROFILE_COMPATIBILITY: 329 profileMask = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; 330 break; 331 default: 332 DE_FATAL("Impossible context profile"); 333 } 334 335 attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB); 336 attribs.push_back(apiType.getMajorVersion()); 337 attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB); 338 attribs.push_back(apiType.getMinorVersion()); 339 attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB); 340 attribs.push_back(profileMask); 341 } 342 343 // Context flags 344 { 345 int flags = 0; 346 347 if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0) 348 { 349 if (glu::isContextTypeES(contextType)) 350 TCU_THROW(InternalError, "Only OpenGL core contexts can be forward-compatible"); 351 352 flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; 353 } 354 355 if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0) 356 flags |= GLX_CONTEXT_DEBUG_BIT_ARB; 357 358 if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0) 359 flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; 360 361 if ((contextType.getFlags() & glu::CONTEXT_NO_ERROR) != 0) 362 { 363 if (m_display.isGlxExtensionSupported("GLX_ARB_create_context_no_error")) 364 { 365 attribs.push_back(GLX_CONTEXT_OPENGL_NO_ERROR_ARB); 366 attribs.push_back(True); 367 } 368 else 369 TCU_THROW(NotSupportedError, "GLX_ARB_create_context_no_error is required for creating no-error contexts"); 370 } 371 372 if (flags != 0) 373 { 374 attribs.push_back(GLX_CONTEXT_FLAGS_ARB); 375 attribs.push_back(flags); 376 } 377 } 378 379 if (resetNotificationStrategy != glu::RESET_NOTIFICATION_STRATEGY_NOT_SPECIFIED) 380 { 381 attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); 382 383 if (resetNotificationStrategy == glu::RESET_NOTIFICATION_STRATEGY_NO_RESET_NOTIFICATION) 384 attribs.push_back(GLX_NO_RESET_NOTIFICATION_ARB); 385 else if (resetNotificationStrategy == glu::RESET_NOTIFICATION_STRATEGY_LOSE_CONTEXT_ON_RESET) 386 attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); 387 else 388 TCU_THROW(InternalError, "Unknown reset notification strategy"); 389 } 390 391 // Terminate attrib list 392 attribs.push_back(None); 393 394 return TCU_CHECK_GLX(factory.m_glXCreateContextAttribsARB( 395 getXDisplay(), m_fbConfig, DE_NULL, True, &attribs[0])); 396 } 397 398 GLXWindow GlxVisual::createWindow (::Window xWindow) 399 { 400 return TCU_CHECK_GLX(glXCreateWindow(getXDisplay(), m_fbConfig, xWindow, NULL)); 401 } 402 403 unsigned GlxDrawable::getAttrib (int attrib) 404 { 405 unsigned int value = 0; 406 glXQueryDrawable(getXDisplay(), getGLXDrawable(), attrib, &value); 407 return value; 408 } 409 410 int GlxDrawable::getWidth (void) 411 { 412 int width = 0; 413 getDimensions(&width, DE_NULL); 414 return width; 415 } 416 417 int GlxDrawable::getHeight (void) 418 { 419 int height = 0; 420 getDimensions(DE_NULL, &height); 421 return height; 422 } 423 424 GlxWindow::GlxWindow (GlxVisual& visual, const RenderConfig& cfg) 425 : m_x11Display (visual.getGlxDisplay()) 426 , m_x11Window (m_x11Display, cfg.width, cfg.height, 427 visual.getXVisual()) 428 , m_GLXDrawable (visual.createWindow(m_x11Window.getXID())) 429 { 430 m_x11Window.setVisibility(cfg.windowVisibility != RenderConfig::VISIBILITY_HIDDEN); 431 } 432 433 void GlxWindow::getDimensions (int* width, int* height) 434 { 435 if (width != DE_NULL) 436 *width = getAttrib(GLX_WIDTH); 437 if (height != DE_NULL) 438 *height = getAttrib(GLX_HEIGHT); 439 440 // glXQueryDrawable may be buggy, so fall back to X geometry if needed 441 if ((width != DE_NULL && *width == 0) || (height != DE_NULL && *height == 0)) 442 m_x11Window.getDimensions(width, height); 443 } 444 445 GlxWindow::~GlxWindow (void) 446 { 447 glXDestroyWindow(m_x11Display.getXDisplay(), m_GLXDrawable); 448 } 449 450 static const struct Attribute 451 { 452 int glxAttribute; 453 int RenderConfig::* cfgMember; 454 } s_attribs[] = 455 { 456 { GLX_RED_SIZE, &RenderConfig::redBits }, 457 { GLX_GREEN_SIZE, &RenderConfig::greenBits }, 458 { GLX_BLUE_SIZE, &RenderConfig::blueBits }, 459 { GLX_ALPHA_SIZE, &RenderConfig::alphaBits }, 460 { GLX_DEPTH_SIZE, &RenderConfig::depthBits }, 461 { GLX_STENCIL_SIZE, &RenderConfig::stencilBits }, 462 { GLX_SAMPLES, &RenderConfig::numSamples }, 463 { GLX_FBCONFIG_ID, &RenderConfig::id }, 464 }; 465 466 static deUint32 surfaceTypeToDrawableBits (RenderConfig::SurfaceType type) 467 { 468 switch (type) 469 { 470 case RenderConfig::SURFACETYPE_WINDOW: 471 return GLX_WINDOW_BIT; 472 case RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: 473 return GLX_PIXMAP_BIT; 474 case RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: 475 return GLX_PBUFFER_BIT; 476 case RenderConfig::SURFACETYPE_DONT_CARE: 477 return GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; 478 default: 479 DE_FATAL("Impossible case"); 480 } 481 return 0; 482 } 483 484 static bool configMatches (GlxVisual& visual, const RenderConfig& renderCfg) 485 { 486 if (renderCfg.id != RenderConfig::DONT_CARE) 487 return visual.getAttrib(GLX_FBCONFIG_ID) == renderCfg.id; 488 489 for (const Attribute* it = DE_ARRAY_BEGIN(s_attribs); it != DE_ARRAY_END(s_attribs); it++) 490 { 491 const int requested = renderCfg.*it->cfgMember; 492 if (requested != RenderConfig::DONT_CARE && 493 requested != visual.getAttrib(it->glxAttribute)) 494 return false; 495 } 496 497 { 498 deUint32 bits = surfaceTypeToDrawableBits(renderCfg.surfaceType); 499 500 if ((visual.getAttrib(GLX_DRAWABLE_TYPE) & bits) == 0) 501 return false; 502 503 // It shouldn't be possible to have GLX_WINDOW_BIT set without a visual, 504 // but let's make sure. 505 if (renderCfg.surfaceType == RenderConfig::SURFACETYPE_WINDOW && 506 visual.getXVisual() == DE_NULL) 507 return false; 508 } 509 510 return true; 511 } 512 513 class Rank 514 { 515 public: 516 Rank (void) : m_value(0), m_bitsLeft(64) {} 517 void add (size_t bits, deUint32 value); 518 void sub (size_t bits, deUint32 value); 519 deUint64 getValue (void) { return m_value; } 520 521 private: 522 deUint64 m_value; 523 size_t m_bitsLeft; 524 }; 525 526 void Rank::add (size_t bits, deUint32 value) 527 { 528 TCU_CHECK_INTERNAL(m_bitsLeft >= bits); 529 m_bitsLeft -= bits; 530 m_value = m_value << bits | de::min((1U << bits) - 1, value); 531 } 532 533 void Rank::sub (size_t bits, deUint32 value) 534 { 535 TCU_CHECK_INTERNAL(m_bitsLeft >= bits); 536 m_bitsLeft -= bits; 537 m_value = m_value << bits | ((1U << bits) - 1 - de::min((1U << bits) - 1U, value)); 538 } 539 540 static deUint64 configRank (GlxVisual& visual) 541 { 542 // Sanity checks. 543 if (visual.getAttrib(GLX_DOUBLEBUFFER) == False || 544 (visual.getAttrib(GLX_RENDER_TYPE) & GLX_RGBA_BIT) == 0) 545 return 0; 546 547 Rank rank; 548 int caveat = visual.getAttrib(GLX_CONFIG_CAVEAT); 549 int redSize = visual.getAttrib(GLX_RED_SIZE); 550 int greenSize = visual.getAttrib(GLX_GREEN_SIZE); 551 int blueSize = visual.getAttrib(GLX_BLUE_SIZE); 552 int alphaSize = visual.getAttrib(GLX_ALPHA_SIZE); 553 int depthSize = visual.getAttrib(GLX_DEPTH_SIZE); 554 int stencilSize = visual.getAttrib(GLX_STENCIL_SIZE); 555 int minRGB = de::min(redSize, de::min(greenSize, blueSize)); 556 557 // Prefer conformant configurations. 558 rank.add(1, (caveat != GLX_NON_CONFORMANT_CONFIG)); 559 560 // Prefer non-transparent configurations. 561 rank.add(1, visual.getAttrib(GLX_TRANSPARENT_TYPE) == GLX_NONE); 562 563 // Avoid stereo 564 rank.add(1, visual.getAttrib(GLX_STEREO) == False); 565 566 // Avoid overlays 567 rank.add(1, visual.getAttrib(GLX_LEVEL) == 0); 568 569 // Prefer to have some alpha. 570 rank.add(1, alphaSize > 0); 571 572 // Prefer to have a depth buffer. 573 rank.add(1, depthSize > 0); 574 575 // Prefer to have a stencil buffer. 576 rank.add(1, stencilSize > 0); 577 578 // Avoid slow configurations. 579 rank.add(1, (caveat != GLX_SLOW_CONFIG)); 580 581 // Prefer larger, evenly distributed color depths 582 rank.add(4, de::min(minRGB, alphaSize)); 583 584 // If alpha is low, choose best RGB 585 rank.add(4, minRGB); 586 587 // Prefer larger depth and stencil buffers 588 rank.add(6, deUint32(depthSize + stencilSize)); 589 590 // Avoid excessive sampling 591 rank.sub(5, visual.getAttrib(GLX_SAMPLES)); 592 593 // Prefer True/DirectColor 594 int visualType = visual.getAttrib(GLX_X_VISUAL_TYPE); 595 rank.add(1, visualType == GLX_TRUE_COLOR || visualType == GLX_DIRECT_COLOR); 596 597 return rank.getValue(); 598 } 599 600 static GlxVisual chooseVisual (GlxDisplay& display, const RenderConfig& cfg) 601 { 602 ::Display* dpy = display.getXDisplay(); 603 deUint64 maxRank = 0; 604 GLXFBConfig maxConfig = DE_NULL; 605 int numElems = 0; 606 607 GLXFBConfig* const fbConfigs = glXGetFBConfigs(dpy, DefaultScreen(dpy), &numElems); 608 TCU_CHECK_MSG(fbConfigs != DE_NULL, "Couldn't query framebuffer configurations"); 609 610 for (int i = 0; i < numElems; i++) 611 { 612 try 613 { 614 GlxVisual visual(display, fbConfigs[i]); 615 616 if (!configMatches(visual, cfg)) 617 continue; 618 619 deUint64 cfgRank = configRank(visual); 620 621 if (cfgRank > maxRank) 622 { 623 maxRank = cfgRank; 624 maxConfig = fbConfigs[i]; 625 } 626 } 627 catch (const tcu::ResourceError&) 628 { 629 // Some drivers report invalid visuals. Ignore them. 630 } 631 } 632 XFree(fbConfigs); 633 634 if (maxRank == 0) 635 TCU_THROW(NotSupportedError, "Requested GLX configuration not found or unusable"); 636 637 return GlxVisual(display, maxConfig); 638 } 639 640 GlxDrawable* createDrawable (GlxVisual& visual, const RenderConfig& config) 641 { 642 RenderConfig::SurfaceType surfaceType = config.surfaceType; 643 644 if (surfaceType == RenderConfig::SURFACETYPE_DONT_CARE) 645 { 646 if (visual.getXVisual() == DE_NULL) 647 // No visual, cannot create X window 648 surfaceType = RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE; 649 else 650 surfaceType = RenderConfig::SURFACETYPE_WINDOW; 651 } 652 653 switch (surfaceType) 654 { 655 case RenderConfig::SURFACETYPE_DONT_CARE: 656 DE_FATAL("Impossible case"); 657 658 case RenderConfig::SURFACETYPE_WINDOW: 659 return new GlxWindow(visual, config); 660 break; 661 662 case RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: 663 // \todo [2013-11-28 lauri] Pixmaps 664 665 case RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: 666 // \todo [2013-11-28 lauri] Pbuffers 667 668 default: 669 TCU_THROW(NotSupportedError, "Unsupported surface type"); 670 } 671 672 return DE_NULL; 673 } 674 675 struct GlxFunctionLoader : public glw::FunctionLoader 676 { 677 GlxFunctionLoader (void) {} 678 679 glw::GenericFuncType get (const char* name) const 680 { 681 return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name)); 682 } 683 }; 684 685 GlxRenderContext::GlxRenderContext (const GlxContextFactory& factory, 686 const RenderConfig& config) 687 : m_glxDisplay (factory.getEventState(), DE_NULL) 688 , m_glxVisual (chooseVisual(m_glxDisplay, config)) 689 , m_type (config.type) 690 , m_GLXContext (m_glxVisual.createContext(factory, config.type, config.resetNotificationStrategy)) 691 , m_glxDrawable (createDrawable(m_glxVisual, config)) 692 , m_renderTarget (m_glxDrawable->getWidth(), m_glxDrawable->getHeight(), 693 PixelFormat(m_glxVisual.getAttrib(GLX_RED_SIZE), 694 m_glxVisual.getAttrib(GLX_GREEN_SIZE), 695 m_glxVisual.getAttrib(GLX_BLUE_SIZE), 696 m_glxVisual.getAttrib(GLX_ALPHA_SIZE)), 697 m_glxVisual.getAttrib(GLX_DEPTH_SIZE), 698 m_glxVisual.getAttrib(GLX_STENCIL_SIZE), 699 m_glxVisual.getAttrib(GLX_SAMPLES)) 700 { 701 const GlxFunctionLoader loader; 702 makeCurrent(); 703 glu::initFunctions(&m_functions, &loader, config.type.getAPI()); 704 } 705 706 GlxRenderContext::~GlxRenderContext (void) 707 { 708 clearCurrent(); 709 if (m_GLXContext != DE_NULL) 710 glXDestroyContext(m_glxDisplay.getXDisplay(), m_GLXContext); 711 } 712 713 void GlxRenderContext::makeCurrent (void) 714 { 715 const GLXDrawable drawRead = m_glxDrawable->getGLXDrawable(); 716 TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(), 717 drawRead, drawRead, m_GLXContext)); 718 } 719 720 void GlxRenderContext::clearCurrent (void) 721 { 722 TCU_CHECK_GLX(glXMakeContextCurrent(m_glxDisplay.getXDisplay(), 723 None, None, DE_NULL)); 724 } 725 726 ContextType GlxRenderContext::getType (void) const 727 { 728 return m_type; 729 } 730 731 void GlxRenderContext::postIterate (void) 732 { 733 m_glxDrawable->swapBuffers(); 734 m_glxDrawable->processEvents(); 735 m_glxDisplay.processEvents(); 736 } 737 738 const RenderTarget& GlxRenderContext::getRenderTarget (void) const 739 { 740 return m_renderTarget; 741 } 742 743 const glw::Functions& GlxRenderContext::getFunctions (void) const 744 { 745 return m_functions; 746 } 747 748 MovePtr<ContextFactory> createContextFactory (EventState& eventState) 749 { 750 return MovePtr<ContextFactory>(new GlxContextFactory(eventState)); 751 } 752 753 } // glx 754 } // x11 755 } // lnx 756 } // tcu 757