1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 extern "C" { 6 #include <X11/Xlib.h> 7 } 8 9 #include "ui/gl/gl_surface_glx.h" 10 11 #include "base/basictypes.h" 12 #include "base/debug/trace_event.h" 13 #include "base/lazy_instance.h" 14 #include "base/logging.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/message_loop/message_loop.h" 18 #include "base/synchronization/cancellation_flag.h" 19 #include "base/synchronization/lock.h" 20 #include "base/threading/non_thread_safe.h" 21 #include "base/threading/thread.h" 22 #include "base/time/time.h" 23 #include "third_party/mesa/src/include/GL/osmesa.h" 24 #include "ui/gfx/x/x11_types.h" 25 #include "ui/gl/gl_bindings.h" 26 #include "ui/gl/gl_implementation.h" 27 #include "ui/gl/sync_control_vsync_provider.h" 28 29 namespace gfx { 30 31 namespace { 32 33 // scoped_ptr functor for XFree(). Use as follows: 34 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); 35 // where "XVisualInfo" is any X type that is freed with XFree. 36 class ScopedPtrXFree { 37 public: 38 void operator()(void* x) const { 39 ::XFree(x); 40 } 41 }; 42 43 Display* g_display = NULL; 44 const char* g_glx_extensions = NULL; 45 bool g_glx_context_create = false; 46 bool g_glx_create_context_robustness_supported = false; 47 bool g_glx_texture_from_pixmap_supported = false; 48 bool g_glx_oml_sync_control_supported = false; 49 50 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a 51 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML 52 // always fails even though GLX_OML_sync_control is reported as being supported. 53 bool g_glx_get_msc_rate_oml_supported = false; 54 55 bool g_glx_sgi_video_sync_supported = false; 56 57 class OMLSyncControlVSyncProvider 58 : public gfx::SyncControlVSyncProvider { 59 public: 60 explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window) 61 : SyncControlVSyncProvider(), 62 window_(window) { 63 } 64 65 virtual ~OMLSyncControlVSyncProvider() { } 66 67 protected: 68 virtual bool GetSyncValues(int64* system_time, 69 int64* media_stream_counter, 70 int64* swap_buffer_counter) OVERRIDE { 71 return glXGetSyncValuesOML(g_display, window_, system_time, 72 media_stream_counter, swap_buffer_counter); 73 } 74 75 virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE { 76 if (!g_glx_get_msc_rate_oml_supported) 77 return false; 78 79 if (!glXGetMscRateOML(g_display, window_, numerator, denominator)) { 80 // Once glXGetMscRateOML has been found to fail, don't try again, 81 // since each failing call may spew an error message. 82 g_glx_get_msc_rate_oml_supported = false; 83 return false; 84 } 85 86 return true; 87 } 88 89 private: 90 XID window_; 91 92 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider); 93 }; 94 95 class SGIVideoSyncThread 96 : public base::Thread, 97 public base::NonThreadSafe, 98 public base::RefCounted<SGIVideoSyncThread> { 99 public: 100 static scoped_refptr<SGIVideoSyncThread> Create() { 101 if (!g_video_sync_thread) { 102 g_video_sync_thread = new SGIVideoSyncThread(); 103 g_video_sync_thread->Start(); 104 } 105 return g_video_sync_thread; 106 } 107 108 private: 109 friend class base::RefCounted<SGIVideoSyncThread>; 110 111 SGIVideoSyncThread() : base::Thread("SGI_video_sync") { 112 DCHECK(CalledOnValidThread()); 113 } 114 115 virtual ~SGIVideoSyncThread() { 116 DCHECK(CalledOnValidThread()); 117 g_video_sync_thread = NULL; 118 Stop(); 119 } 120 121 static SGIVideoSyncThread* g_video_sync_thread; 122 123 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread); 124 }; 125 126 class SGIVideoSyncProviderThreadShim { 127 public: 128 explicit SGIVideoSyncProviderThreadShim(XID window) 129 : window_(window), 130 context_(NULL), 131 message_loop_(base::MessageLoopProxy::current()), 132 cancel_vsync_flag_(), 133 vsync_lock_() { 134 // This ensures that creation of |window_| has occured when this shim 135 // is executing in the same process as the call to create |window_|. 136 XSync(g_display, False); 137 } 138 139 virtual ~SGIVideoSyncProviderThreadShim() { 140 if (context_) { 141 glXDestroyContext(display_, context_); 142 context_ = NULL; 143 } 144 } 145 146 base::CancellationFlag* cancel_vsync_flag() { 147 return &cancel_vsync_flag_; 148 } 149 150 base::Lock* vsync_lock() { 151 return &vsync_lock_; 152 } 153 154 void Initialize() { 155 DCHECK(display_); 156 157 XWindowAttributes attributes; 158 if (!XGetWindowAttributes(display_, window_, &attributes)) { 159 LOG(ERROR) << "XGetWindowAttributes failed for window " << 160 window_ << "."; 161 return; 162 } 163 164 XVisualInfo visual_info_template; 165 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); 166 167 int visual_info_count = 0; 168 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( 169 XGetVisualInfo(display_, VisualIDMask, 170 &visual_info_template, &visual_info_count)); 171 172 DCHECK(visual_info_list.get()); 173 if (visual_info_count == 0) { 174 LOG(ERROR) << "No visual info for visual ID."; 175 return; 176 } 177 178 context_ = glXCreateContext(display_, visual_info_list.get(), NULL, True); 179 180 DCHECK(NULL != context_); 181 } 182 183 void GetVSyncParameters(const VSyncProvider::UpdateVSyncCallback& callback) { 184 base::TimeTicks now; 185 { 186 // Don't allow |window_| destruction while we're probing vsync. 187 base::AutoLock locked(vsync_lock_); 188 189 if (!context_ || cancel_vsync_flag_.IsSet()) 190 return; 191 192 glXMakeCurrent(display_, window_, context_); 193 194 unsigned int retrace_count = 0; 195 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0) 196 return; 197 198 TRACE_EVENT_INSTANT0("gpu", "vblank", TRACE_EVENT_SCOPE_THREAD); 199 now = base::TimeTicks::HighResNow(); 200 201 glXMakeCurrent(display_, 0, 0); 202 } 203 204 const base::TimeDelta kDefaultInterval = 205 base::TimeDelta::FromSeconds(1) / 60; 206 207 message_loop_->PostTask( 208 FROM_HERE, base::Bind(callback, now, kDefaultInterval)); 209 } 210 211 private: 212 // For initialization of display_ in GLSurface::InitializeOneOff before 213 // the sandbox goes up. 214 friend class gfx::GLSurfaceGLX; 215 216 static Display* display_; 217 218 XID window_; 219 GLXContext context_; 220 221 scoped_refptr<base::MessageLoopProxy> message_loop_; 222 223 base::CancellationFlag cancel_vsync_flag_; 224 base::Lock vsync_lock_; 225 226 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim); 227 }; 228 229 class SGIVideoSyncVSyncProvider 230 : public gfx::VSyncProvider, 231 public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> { 232 public: 233 explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget window) 234 : vsync_thread_(SGIVideoSyncThread::Create()), 235 shim_(new SGIVideoSyncProviderThreadShim(window)), 236 cancel_vsync_flag_(shim_->cancel_vsync_flag()), 237 vsync_lock_(shim_->vsync_lock()) { 238 vsync_thread_->message_loop()->PostTask( 239 FROM_HERE, 240 base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, 241 base::Unretained(shim_.get()))); 242 } 243 244 virtual ~SGIVideoSyncVSyncProvider() { 245 { 246 base::AutoLock locked(*vsync_lock_); 247 cancel_vsync_flag_->Set(); 248 } 249 250 // Hand-off |shim_| to be deleted on the |vsync_thread_|. 251 vsync_thread_->message_loop()->DeleteSoon( 252 FROM_HERE, 253 shim_.release()); 254 } 255 256 virtual void GetVSyncParameters( 257 const VSyncProvider::UpdateVSyncCallback& callback) OVERRIDE { 258 // Only one outstanding request per surface. 259 if (!pending_callback_) { 260 pending_callback_.reset( 261 new VSyncProvider::UpdateVSyncCallback(callback)); 262 vsync_thread_->message_loop()->PostTask( 263 FROM_HERE, 264 base::Bind(&SGIVideoSyncProviderThreadShim::GetVSyncParameters, 265 base::Unretained(shim_.get()), 266 base::Bind( 267 &SGIVideoSyncVSyncProvider::PendingCallbackRunner, 268 AsWeakPtr()))); 269 } 270 } 271 272 private: 273 void PendingCallbackRunner(const base::TimeTicks timebase, 274 const base::TimeDelta interval) { 275 DCHECK(pending_callback_); 276 pending_callback_->Run(timebase, interval); 277 pending_callback_.reset(); 278 } 279 280 scoped_refptr<SGIVideoSyncThread> vsync_thread_; 281 282 // Thread shim through which the sync provider is accessed on |vsync_thread_|. 283 scoped_ptr<SGIVideoSyncProviderThreadShim> shim_; 284 285 scoped_ptr<VSyncProvider::UpdateVSyncCallback> pending_callback_; 286 287 // Raw pointers to sync primitives owned by the shim_. 288 // These will only be referenced before we post a task to destroy 289 // the shim_, so they are safe to access. 290 base::CancellationFlag* cancel_vsync_flag_; 291 base::Lock* vsync_lock_; 292 293 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); 294 }; 295 296 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL; 297 298 // In order to take advantage of GLX_SGI_video_sync, we need a display 299 // for use on a separate thread. We must allocate this before the sandbox 300 // goes up (rather than on-demand when we start the thread). 301 Display* SGIVideoSyncProviderThreadShim::display_ = NULL; 302 303 #if defined(TOOLKIT_GTK) 304 // A mechanism for forwarding XExpose events from one window to another. 305 // Because in the workaround for http://crbug.com/145600 the child window 306 // is placed on top of the parent window, only the child window will receive 307 // all expose events. These need to be forwared to the parent window to inform 308 // it that it should paint. 309 class XExposeEventForwarder : public base::MessagePumpObserver { 310 public: 311 XExposeEventForwarder() {} 312 virtual ~XExposeEventForwarder() { 313 DCHECK(child_to_parent_map_.empty()); 314 } 315 void AddParentChildPair(gfx::AcceleratedWidget parent_window, 316 gfx::AcceleratedWidget child_window) { 317 if (child_to_parent_map_.empty()) 318 base::MessagePumpX11::Current()->AddObserver(this); 319 320 DCHECK(child_to_parent_map_.find(child_window) == 321 child_to_parent_map_.end()); 322 child_to_parent_map_.insert(std::make_pair( 323 child_window, parent_window)); 324 } 325 void RemoveParentChildPair(gfx::AcceleratedWidget parent_window, 326 gfx::AcceleratedWidget child_window) { 327 DCHECK(child_to_parent_map_.find(child_window) != 328 child_to_parent_map_.end()); 329 child_to_parent_map_.erase(child_window); 330 331 if (child_to_parent_map_.empty()) 332 base::MessagePumpX11::Current()->RemoveObserver(this); 333 } 334 335 private: 336 virtual base::EventStatus WillProcessEvent ( 337 const base::NativeEvent& xevent) OVERRIDE { 338 if (xevent->type != Expose) 339 return base::EVENT_CONTINUE; 340 341 WindowMap::const_iterator found = child_to_parent_map_.find( 342 xevent->xexpose.window); 343 if (found == child_to_parent_map_.end()) 344 return base::EVENT_CONTINUE; 345 346 gfx::AcceleratedWidget target_window = found->second; 347 XEvent forwarded_event = *xevent; 348 forwarded_event.xexpose.window = target_window; 349 XSendEvent(g_display, target_window, False, ExposureMask, 350 &forwarded_event); 351 return base::EVENT_CONTINUE; 352 } 353 virtual void DidProcessEvent(const base::NativeEvent& xevent) OVERRIDE { 354 } 355 356 typedef std::map<gfx::AcceleratedWidget, gfx::AcceleratedWidget> WindowMap; 357 WindowMap child_to_parent_map_; 358 359 DISALLOW_COPY_AND_ASSIGN(XExposeEventForwarder); 360 }; 361 362 static base::LazyInstance<XExposeEventForwarder> g_xexpose_event_forwarder = 363 LAZY_INSTANCE_INITIALIZER; 364 365 // Do not use this workaround when running in test harnesses that do not have 366 // a message loop or do not have a TYPE_GPU message loop. 367 bool g_create_child_windows = false; 368 #endif 369 370 } // namespace 371 372 GLSurfaceGLX::GLSurfaceGLX() {} 373 374 bool GLSurfaceGLX::InitializeOneOff() { 375 static bool initialized = false; 376 if (initialized) 377 return true; 378 379 // http://crbug.com/245466 380 setenv("force_s3tc_enable", "true", 1); 381 382 // SGIVideoSyncProviderShim (if instantiated) will issue X commands on 383 // it's own thread. 384 XInitThreads(); 385 386 #if defined(TOOLKIT_GTK) 387 // Be sure to use the X display handle and not the GTK display handle if this 388 // is the GPU process. 389 g_create_child_windows = 390 base::MessageLoop::current() && 391 base::MessageLoop::current()->type() == base::MessageLoop::TYPE_GPU; 392 393 if (g_create_child_windows) 394 g_display = base::MessagePumpX11::GetDefaultXDisplay(); 395 else 396 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); 397 #else 398 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); 399 #endif 400 401 if (!g_display) { 402 LOG(ERROR) << "XOpenDisplay failed."; 403 return false; 404 } 405 406 int major, minor; 407 if (!glXQueryVersion(g_display, &major, &minor)) { 408 LOG(ERROR) << "glxQueryVersion failed"; 409 return false; 410 } 411 412 if (major == 1 && minor < 3) { 413 LOG(ERROR) << "GLX 1.3 or later is required."; 414 return false; 415 } 416 417 g_glx_extensions = glXQueryExtensionsString(g_display, 0); 418 g_glx_context_create = 419 HasGLXExtension("GLX_ARB_create_context"); 420 g_glx_create_context_robustness_supported = 421 HasGLXExtension("GLX_ARB_create_context_robustness"); 422 g_glx_texture_from_pixmap_supported = 423 HasGLXExtension("GLX_EXT_texture_from_pixmap"); 424 g_glx_oml_sync_control_supported = 425 HasGLXExtension("GLX_OML_sync_control"); 426 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported; 427 g_glx_sgi_video_sync_supported = 428 HasGLXExtension("GLX_SGI_video_sync"); 429 430 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) 431 SGIVideoSyncProviderThreadShim::display_ = XOpenDisplay(NULL); 432 433 initialized = true; 434 return true; 435 } 436 437 // static 438 const char* GLSurfaceGLX::GetGLXExtensions() { 439 return g_glx_extensions; 440 } 441 442 // static 443 bool GLSurfaceGLX::HasGLXExtension(const char* name) { 444 return ExtensionsContain(GetGLXExtensions(), name); 445 } 446 447 // static 448 bool GLSurfaceGLX::IsCreateContextSupported() { 449 return g_glx_context_create; 450 } 451 452 // static 453 bool GLSurfaceGLX::IsCreateContextRobustnessSupported() { 454 return g_glx_create_context_robustness_supported; 455 } 456 457 // static 458 bool GLSurfaceGLX::IsTextureFromPixmapSupported() { 459 return g_glx_texture_from_pixmap_supported; 460 } 461 462 // static 463 bool GLSurfaceGLX::IsOMLSyncControlSupported() { 464 return g_glx_oml_sync_control_supported; 465 } 466 467 void* GLSurfaceGLX::GetDisplay() { 468 return g_display; 469 } 470 471 GLSurfaceGLX::~GLSurfaceGLX() {} 472 473 #if defined(TOOLKIT_GTK) 474 bool NativeViewGLSurfaceGLX::SetBackbufferAllocation(bool allocated) { 475 backbuffer_allocated_ = allocated; 476 AdjustBufferAllocation(); 477 return true; 478 } 479 480 void NativeViewGLSurfaceGLX::SetFrontbufferAllocation(bool allocated) { 481 frontbuffer_allocated_ = allocated; 482 AdjustBufferAllocation(); 483 } 484 485 void NativeViewGLSurfaceGLX::AdjustBufferAllocation() { 486 if (!g_create_child_windows) 487 return; 488 489 if (frontbuffer_allocated_ || backbuffer_allocated_) 490 CreateChildWindow(); 491 else 492 DestroyChildWindow(); 493 } 494 495 void NativeViewGLSurfaceGLX::CreateChildWindow() { 496 DCHECK(g_create_child_windows); 497 498 if (child_window_) 499 return; 500 501 XSetWindowAttributes set_window_attributes; 502 set_window_attributes.event_mask = ExposureMask; 503 child_window_ = XCreateWindow( 504 g_display, parent_window_, 0, 0, size_.width(), size_.height(), 0, 505 CopyFromParent, InputOutput, CopyFromParent, CWEventMask, 506 &set_window_attributes); 507 g_xexpose_event_forwarder.Pointer()->AddParentChildPair( 508 parent_window_, child_window_); 509 510 XMapWindow(g_display, child_window_); 511 XFlush(g_display); 512 } 513 514 void NativeViewGLSurfaceGLX::DestroyChildWindow() { 515 if (!child_window_) 516 return; 517 518 g_xexpose_event_forwarder.Pointer()->RemoveParentChildPair( 519 parent_window_, child_window_); 520 XDestroyWindow(g_display, child_window_); 521 XFlush(g_display); 522 child_window_ = 0; 523 } 524 #endif 525 526 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) 527 : parent_window_(window), 528 #if defined(TOOLKIT_GTK) 529 child_window_(0), 530 dummy_window_(0), 531 backbuffer_allocated_(true), 532 frontbuffer_allocated_(true), 533 #endif 534 config_(NULL) { 535 } 536 537 gfx::AcceleratedWidget NativeViewGLSurfaceGLX::GetDrawableHandle() const { 538 #if defined(TOOLKIT_GTK) 539 if (g_create_child_windows) { 540 if (child_window_) 541 return child_window_; 542 return dummy_window_; 543 } 544 #endif 545 return parent_window_; 546 } 547 548 bool NativeViewGLSurfaceGLX::Initialize() { 549 XWindowAttributes attributes; 550 if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { 551 LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ 552 << "."; 553 return false; 554 } 555 size_ = gfx::Size(attributes.width, attributes.height); 556 557 gfx::AcceleratedWidget window_for_vsync = parent_window_; 558 559 #if defined(TOOLKIT_GTK) 560 if (g_create_child_windows) { 561 dummy_window_ = XCreateWindow( 562 g_display, 563 RootWindow(g_display, XScreenNumberOfScreen(attributes.screen)), 564 0, 0, 1, 1, 0, CopyFromParent, InputOutput, attributes.visual, 0, NULL); 565 window_for_vsync = dummy_window_; 566 CreateChildWindow(); 567 } 568 #endif 569 570 if (g_glx_oml_sync_control_supported) 571 vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_for_vsync)); 572 else if (g_glx_sgi_video_sync_supported) 573 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_for_vsync)); 574 575 return true; 576 } 577 578 void NativeViewGLSurfaceGLX::Destroy() { 579 #if defined(TOOLKIT_GTK) 580 DestroyChildWindow(); 581 if (dummy_window_) 582 XDestroyWindow(g_display, dummy_window_); 583 dummy_window_ = 0; 584 #endif 585 } 586 587 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { 588 #if defined(TOOLKIT_GTK) 589 if (child_window_) { 590 XResizeWindow(g_display, child_window_, size.width(), size.height()); 591 XFlush(g_display); 592 } 593 #endif 594 size_ = size; 595 return true; 596 } 597 598 bool NativeViewGLSurfaceGLX::IsOffscreen() { 599 return false; 600 } 601 602 bool NativeViewGLSurfaceGLX::SwapBuffers() { 603 glXSwapBuffers(g_display, GetDrawableHandle()); 604 return true; 605 } 606 607 gfx::Size NativeViewGLSurfaceGLX::GetSize() { 608 return size_; 609 } 610 611 void* NativeViewGLSurfaceGLX::GetHandle() { 612 return reinterpret_cast<void*>(GetDrawableHandle()); 613 } 614 615 std::string NativeViewGLSurfaceGLX::GetExtensions() { 616 std::string extensions = GLSurface::GetExtensions(); 617 if (gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer) { 618 extensions += extensions.empty() ? "" : " "; 619 extensions += "GL_CHROMIUM_post_sub_buffer"; 620 } 621 return extensions; 622 } 623 624 void* NativeViewGLSurfaceGLX::GetConfig() { 625 if (!config_) { 626 // This code path is expensive, but we only take it when 627 // attempting to use GLX_ARB_create_context_robustness, in which 628 // case we need a GLXFBConfig for the window in order to create a 629 // context for it. 630 // 631 // TODO(kbr): this is not a reliable code path. On platforms which 632 // support it, we should use glXChooseFBConfig in the browser 633 // process to choose the FBConfig and from there the X Visual to 634 // use when creating the window in the first place. Then we can 635 // pass that FBConfig down rather than attempting to reconstitute 636 // it. 637 638 XWindowAttributes attributes; 639 if (!XGetWindowAttributes( 640 g_display, 641 parent_window_, 642 &attributes)) { 643 LOG(ERROR) << "XGetWindowAttributes failed for window " << 644 parent_window_ << "."; 645 return NULL; 646 } 647 648 int visual_id = XVisualIDFromVisual(attributes.visual); 649 650 int num_elements = 0; 651 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( 652 glXGetFBConfigs(g_display, 653 DefaultScreen(g_display), 654 &num_elements)); 655 if (!configs.get()) { 656 LOG(ERROR) << "glXGetFBConfigs failed."; 657 return NULL; 658 } 659 if (!num_elements) { 660 LOG(ERROR) << "glXGetFBConfigs returned 0 elements."; 661 return NULL; 662 } 663 bool found = false; 664 int i; 665 for (i = 0; i < num_elements; ++i) { 666 int value; 667 if (glXGetFBConfigAttrib( 668 g_display, configs.get()[i], GLX_VISUAL_ID, &value)) { 669 LOG(ERROR) << "glXGetFBConfigAttrib failed."; 670 return NULL; 671 } 672 if (value == visual_id) { 673 found = true; 674 break; 675 } 676 } 677 if (found) { 678 config_ = configs.get()[i]; 679 } 680 } 681 682 return config_; 683 } 684 685 bool NativeViewGLSurfaceGLX::PostSubBuffer( 686 int x, int y, int width, int height) { 687 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); 688 glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height); 689 return true; 690 } 691 692 VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() { 693 return vsync_provider_.get(); 694 } 695 696 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() 697 : parent_window_(0), 698 #if defined(TOOLKIT_GTK) 699 child_window_(0), 700 dummy_window_(0), 701 backbuffer_allocated_(true), 702 frontbuffer_allocated_(true), 703 #endif 704 config_(NULL) { 705 } 706 707 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { 708 Destroy(); 709 } 710 711 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size) 712 : size_(size), 713 config_(NULL), 714 pbuffer_(0) { 715 } 716 717 bool PbufferGLSurfaceGLX::Initialize() { 718 DCHECK(!pbuffer_); 719 720 static const int config_attributes[] = { 721 GLX_BUFFER_SIZE, 32, 722 GLX_ALPHA_SIZE, 8, 723 GLX_BLUE_SIZE, 8, 724 GLX_GREEN_SIZE, 8, 725 GLX_RED_SIZE, 8, 726 GLX_RENDER_TYPE, GLX_RGBA_BIT, 727 GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, 728 GLX_DOUBLEBUFFER, False, 729 0 730 }; 731 732 int num_elements = 0; 733 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( 734 glXChooseFBConfig(g_display, 735 DefaultScreen(g_display), 736 config_attributes, 737 &num_elements)); 738 if (!configs.get()) { 739 LOG(ERROR) << "glXChooseFBConfig failed."; 740 return false; 741 } 742 if (!num_elements) { 743 LOG(ERROR) << "glXChooseFBConfig returned 0 elements."; 744 return false; 745 } 746 747 config_ = configs.get()[0]; 748 749 const int pbuffer_attributes[] = { 750 GLX_PBUFFER_WIDTH, size_.width(), 751 GLX_PBUFFER_HEIGHT, size_.height(), 752 0 753 }; 754 pbuffer_ = glXCreatePbuffer(g_display, 755 static_cast<GLXFBConfig>(config_), 756 pbuffer_attributes); 757 if (!pbuffer_) { 758 Destroy(); 759 LOG(ERROR) << "glXCreatePbuffer failed."; 760 return false; 761 } 762 763 return true; 764 } 765 766 void PbufferGLSurfaceGLX::Destroy() { 767 if (pbuffer_) { 768 glXDestroyPbuffer(g_display, pbuffer_); 769 pbuffer_ = 0; 770 } 771 772 config_ = NULL; 773 } 774 775 bool PbufferGLSurfaceGLX::IsOffscreen() { 776 return true; 777 } 778 779 bool PbufferGLSurfaceGLX::SwapBuffers() { 780 NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; 781 return false; 782 } 783 784 gfx::Size PbufferGLSurfaceGLX::GetSize() { 785 return size_; 786 } 787 788 void* PbufferGLSurfaceGLX::GetHandle() { 789 return reinterpret_cast<void*>(pbuffer_); 790 } 791 792 void* PbufferGLSurfaceGLX::GetConfig() { 793 return config_; 794 } 795 796 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { 797 Destroy(); 798 } 799 800 } // namespace gfx 801