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