Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(195)

Side by Side Diff: ui/gl/gl_surface_glx.cc

Issue 23452026: Destroy GLX windows when they are backgrounded (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Make clang builds happy Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gl/gl_surface_glx.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 extern "C" { 5 extern "C" {
6 #include <X11/Xlib.h> 6 #include <X11/Xlib.h>
7 } 7 }
8 8
9 #include "ui/gl/gl_surface_glx.h" 9 #include "ui/gl/gl_surface_glx.h"
10 10
11 #include "base/basictypes.h" 11 #include "base/basictypes.h"
12 #include "base/debug/trace_event.h" 12 #include "base/debug/trace_event.h"
13 #include "base/lazy_instance.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/weak_ptr.h" 16 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
17 #include "base/synchronization/cancellation_flag.h" 18 #include "base/synchronization/cancellation_flag.h"
18 #include "base/synchronization/lock.h" 19 #include "base/synchronization/lock.h"
19 #include "base/threading/non_thread_safe.h" 20 #include "base/threading/non_thread_safe.h"
20 #include "base/threading/thread.h" 21 #include "base/threading/thread.h"
21 #include "base/time/time.h" 22 #include "base/time/time.h"
22 #include "third_party/mesa/src/include/GL/osmesa.h" 23 #include "third_party/mesa/src/include/GL/osmesa.h"
23 #include "ui/base/x/x11_util.h" 24 #include "ui/base/x/x11_util.h"
24 #include "ui/gl/gl_bindings.h" 25 #include "ui/gl/gl_bindings.h"
25 #include "ui/gl/gl_implementation.h" 26 #include "ui/gl/gl_implementation.h"
26 #include "ui/gl/vsync_provider.h" 27 #include "ui/gl/vsync_provider.h"
27 28
28 namespace gfx { 29 namespace gfx {
29 30
30 namespace { 31 namespace {
31 32
32 // scoped_ptr functor for XFree(). Use as follows: 33 // scoped_ptr functor for XFree(). Use as follows:
33 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); 34 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
34 // where "XVisualInfo" is any X type that is freed with XFree. 35 // where "XVisualInfo" is any X type that is freed with XFree.
35 class ScopedPtrXFree { 36 class ScopedPtrXFree {
36 public: 37 public:
37 void operator()(void* x) const { 38 void operator()(void* x) const {
38 ::XFree(x); 39 ::XFree(x);
39 } 40 }
40 }; 41 };
41 42
42 Display* g_display; 43 Display* g_display = NULL;
43 const char* g_glx_extensions = NULL; 44 const char* g_glx_extensions = NULL;
44 bool g_glx_context_create = false; 45 bool g_glx_context_create = false;
45 bool g_glx_create_context_robustness_supported = false; 46 bool g_glx_create_context_robustness_supported = false;
46 bool g_glx_texture_from_pixmap_supported = false; 47 bool g_glx_texture_from_pixmap_supported = false;
47 bool g_glx_oml_sync_control_supported = false; 48 bool g_glx_oml_sync_control_supported = false;
48 49
49 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a 50 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a
50 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML 51 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML
51 // always fails even though GLX_OML_sync_control is reported as being supported. 52 // always fails even though GLX_OML_sync_control is reported as being supported.
52 bool g_glx_get_msc_rate_oml_supported = false; 53 bool g_glx_get_msc_rate_oml_supported = false;
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider); 293 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider);
293 }; 294 };
294 295
295 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL; 296 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL;
296 297
297 // In order to take advantage of GLX_SGI_video_sync, we need a display 298 // In order to take advantage of GLX_SGI_video_sync, we need a display
298 // for use on a separate thread. We must allocate this before the sandbox 299 // for use on a separate thread. We must allocate this before the sandbox
299 // goes up (rather than on-demand when we start the thread). 300 // goes up (rather than on-demand when we start the thread).
300 Display* SGIVideoSyncProviderThreadShim::display_ = NULL; 301 Display* SGIVideoSyncProviderThreadShim::display_ = NULL;
301 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 #endif
365
302 } // namespace 366 } // namespace
303 367
304 GLSurfaceGLX::GLSurfaceGLX() {} 368 GLSurfaceGLX::GLSurfaceGLX() {}
305 369
306 bool GLSurfaceGLX::InitializeOneOff() { 370 bool GLSurfaceGLX::InitializeOneOff() {
307 static bool initialized = false; 371 static bool initialized = false;
308 if (initialized) 372 if (initialized)
309 return true; 373 return true;
310 374
311 // http://crbug.com/245466 375 // http://crbug.com/245466
312 setenv("force_s3tc_enable", "true", 1); 376 setenv("force_s3tc_enable", "true", 1);
313 377
314 // SGIVideoSyncProviderShim (if instantiated) will issue X commands on 378 // SGIVideoSyncProviderShim (if instantiated) will issue X commands on
315 // it's own thread. 379 // it's own thread.
316 XInitThreads(); 380 XInitThreads();
317 381
382 #if defined(TOOLKIT_GTK)
383 // Be sure to use the X display handle and not the GTK display handle if this
384 // is the GPU process.
385 if (base::MessageLoop::current()->type() == base::MessageLoop::TYPE_GPU)
386 g_display = base::MessagePumpX11::GetDefaultXDisplay();
387 else
388 g_display = base::MessagePumpForUI::GetDefaultXDisplay();
389 #else
318 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); 390 g_display = base::MessagePumpForUI::GetDefaultXDisplay();
391 #endif
392
319 if (!g_display) { 393 if (!g_display) {
320 LOG(ERROR) << "XOpenDisplay failed."; 394 LOG(ERROR) << "XOpenDisplay failed.";
321 return false; 395 return false;
322 } 396 }
323 397
324 int major, minor; 398 int major, minor;
325 if (!glXQueryVersion(g_display, &major, &minor)) { 399 if (!glXQueryVersion(g_display, &major, &minor)) {
326 LOG(ERROR) << "glxQueryVersion failed"; 400 LOG(ERROR) << "glxQueryVersion failed";
327 return false; 401 return false;
328 } 402 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 bool GLSurfaceGLX::IsOMLSyncControlSupported() { 455 bool GLSurfaceGLX::IsOMLSyncControlSupported() {
382 return g_glx_oml_sync_control_supported; 456 return g_glx_oml_sync_control_supported;
383 } 457 }
384 458
385 void* GLSurfaceGLX::GetDisplay() { 459 void* GLSurfaceGLX::GetDisplay() {
386 return g_display; 460 return g_display;
387 } 461 }
388 462
389 GLSurfaceGLX::~GLSurfaceGLX() {} 463 GLSurfaceGLX::~GLSurfaceGLX() {}
390 464
465 #if defined(TOOLKIT_GTK)
466 bool NativeViewGLSurfaceGLX::SetBackbufferAllocation(bool allocated) {
467 backbuffer_allocated_ = allocated;
468 AdjustBufferAllocation();
469 return true;
470 }
471
472 void NativeViewGLSurfaceGLX::SetFrontbufferAllocation(bool allocated) {
473 frontbuffer_allocated_ = allocated;
474 AdjustBufferAllocation();
475 }
476
477 void NativeViewGLSurfaceGLX::AdjustBufferAllocation() {
478 if (frontbuffer_allocated_ || backbuffer_allocated_)
479 CreateChildWindow();
480 else
481 DestroyChildWindow();
482 }
483
484 void NativeViewGLSurfaceGLX::CreateChildWindow() {
485 if (child_window_)
486 return;
487
488 XSetWindowAttributes set_window_attributes;
489 set_window_attributes.event_mask = ExposureMask;
490 child_window_ = XCreateWindow(
491 g_display, parent_window_, 0, 0, size_.width(), size_.height(), 0,
492 CopyFromParent, InputOutput, CopyFromParent, CWEventMask,
493 &set_window_attributes);
494 g_xexpose_event_forwarder.Pointer()->AddParentChildPair(
495 parent_window_, child_window_);
496
497 XMapWindow(g_display, child_window_);
498 XFlush(g_display);
499 }
500
501 void NativeViewGLSurfaceGLX::DestroyChildWindow() {
502 if (!child_window_)
503 return;
504
505 g_xexpose_event_forwarder.Pointer()->RemoveParentChildPair(
506 parent_window_, child_window_);
507 XDestroyWindow(g_display, child_window_);
508 XFlush(g_display);
509 child_window_ = 0;
510 }
511 #endif
512
391 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) 513 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
392 : window_(window), 514 : parent_window_(window),
515 #if defined(TOOLKIT_GTK)
516 child_window_(0),
517 dummy_window_(0),
518 backbuffer_allocated_(true),
519 frontbuffer_allocated_(true),
520 #endif
393 config_(NULL) { 521 config_(NULL) {
394 } 522 }
395 523
524 gfx::AcceleratedWidget NativeViewGLSurfaceGLX::GetDrawableHandle() const {
525 #if defined(TOOLKIT_GTK)
526 if (child_window_)
527 return child_window_;
528 return dummy_window_;
529 #else
530 return parent_window_;
531 #endif
532 }
533
396 bool NativeViewGLSurfaceGLX::Initialize() { 534 bool NativeViewGLSurfaceGLX::Initialize() {
397 XWindowAttributes attributes; 535 XWindowAttributes attributes;
398 if (!XGetWindowAttributes(g_display, window_, &attributes)) { 536 if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) {
399 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; 537 LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_
538 << ".";
400 return false; 539 return false;
401 } 540 }
402 size_ = gfx::Size(attributes.width, attributes.height); 541 size_ = gfx::Size(attributes.width, attributes.height);
403 542
543 gfx::AcceleratedWidget window_for_vsync = parent_window_;
544
545 #if defined(TOOLKIT_GTK)
546 dummy_window_ = XCreateWindow(
547 g_display,
548 RootWindow(g_display, XScreenNumberOfScreen(attributes.screen)),
549 0, 0, 1, 1, 0, CopyFromParent, InputOutput, attributes.visual, 0, NULL);
550 window_for_vsync = dummy_window_;
551 CreateChildWindow();
552 #endif
553
404 if (g_glx_oml_sync_control_supported) 554 if (g_glx_oml_sync_control_supported)
405 vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_)); 555 vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_for_vsync));
406 else if (g_glx_sgi_video_sync_supported) 556 else if (g_glx_sgi_video_sync_supported)
407 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_)); 557 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_for_vsync));
408 558
409 return true; 559 return true;
410 } 560 }
411 561
412 void NativeViewGLSurfaceGLX::Destroy() { 562 void NativeViewGLSurfaceGLX::Destroy() {
563 #if defined(TOOLKIT_GTK)
564 DestroyChildWindow();
565 if (dummy_window_)
566 XDestroyWindow(g_display, dummy_window_);
567 dummy_window_ = 0;
568 #endif
413 } 569 }
414 570
415 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { 571 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) {
572 #if defined(TOOLKIT_GTK)
573 if (child_window_) {
574 XResizeWindow(g_display, child_window_, size.width(), size.height());
575 XFlush(g_display);
576 }
577 #endif
416 size_ = size; 578 size_ = size;
417 return true; 579 return true;
418 } 580 }
419 581
420 bool NativeViewGLSurfaceGLX::IsOffscreen() { 582 bool NativeViewGLSurfaceGLX::IsOffscreen() {
421 return false; 583 return false;
422 } 584 }
423 585
424 bool NativeViewGLSurfaceGLX::SwapBuffers() { 586 bool NativeViewGLSurfaceGLX::SwapBuffers() {
425 glXSwapBuffers(g_display, window_); 587 glXSwapBuffers(g_display, GetDrawableHandle());
426 return true; 588 return true;
427 } 589 }
428 590
429 gfx::Size NativeViewGLSurfaceGLX::GetSize() { 591 gfx::Size NativeViewGLSurfaceGLX::GetSize() {
430 return size_; 592 return size_;
431 } 593 }
432 594
433 void* NativeViewGLSurfaceGLX::GetHandle() { 595 void* NativeViewGLSurfaceGLX::GetHandle() {
434 return reinterpret_cast<void*>(window_); 596 return reinterpret_cast<void*>(GetDrawableHandle());
435 } 597 }
436 598
437 std::string NativeViewGLSurfaceGLX::GetExtensions() { 599 std::string NativeViewGLSurfaceGLX::GetExtensions() {
438 std::string extensions = GLSurface::GetExtensions(); 600 std::string extensions = GLSurface::GetExtensions();
439 if (gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer) { 601 if (gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer) {
440 extensions += extensions.empty() ? "" : " "; 602 extensions += extensions.empty() ? "" : " ";
441 extensions += "GL_CHROMIUM_post_sub_buffer"; 603 extensions += "GL_CHROMIUM_post_sub_buffer";
442 } 604 }
443 return extensions; 605 return extensions;
444 } 606 }
445 607
446 void* NativeViewGLSurfaceGLX::GetConfig() { 608 void* NativeViewGLSurfaceGLX::GetConfig() {
447 if (!config_) { 609 if (!config_) {
448 // This code path is expensive, but we only take it when 610 // This code path is expensive, but we only take it when
449 // attempting to use GLX_ARB_create_context_robustness, in which 611 // attempting to use GLX_ARB_create_context_robustness, in which
450 // case we need a GLXFBConfig for the window in order to create a 612 // case we need a GLXFBConfig for the window in order to create a
451 // context for it. 613 // context for it.
452 // 614 //
453 // TODO(kbr): this is not a reliable code path. On platforms which 615 // TODO(kbr): this is not a reliable code path. On platforms which
454 // support it, we should use glXChooseFBConfig in the browser 616 // support it, we should use glXChooseFBConfig in the browser
455 // process to choose the FBConfig and from there the X Visual to 617 // process to choose the FBConfig and from there the X Visual to
456 // use when creating the window in the first place. Then we can 618 // use when creating the window in the first place. Then we can
457 // pass that FBConfig down rather than attempting to reconstitute 619 // pass that FBConfig down rather than attempting to reconstitute
458 // it. 620 // it.
459 621
460 XWindowAttributes attributes; 622 XWindowAttributes attributes;
461 if (!XGetWindowAttributes( 623 if (!XGetWindowAttributes(
462 g_display, 624 g_display,
463 window_, 625 parent_window_,
464 &attributes)) { 626 &attributes)) {
465 LOG(ERROR) << "XGetWindowAttributes failed for window " << 627 LOG(ERROR) << "XGetWindowAttributes failed for window " <<
466 window_ << "."; 628 parent_window_ << ".";
467 return NULL; 629 return NULL;
468 } 630 }
469 631
470 int visual_id = XVisualIDFromVisual(attributes.visual); 632 int visual_id = XVisualIDFromVisual(attributes.visual);
471 633
472 int num_elements = 0; 634 int num_elements = 0;
473 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( 635 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
474 glXGetFBConfigs(g_display, 636 glXGetFBConfigs(g_display,
475 DefaultScreen(g_display), 637 DefaultScreen(g_display),
476 &num_elements)); 638 &num_elements));
(...skipping 23 matching lines...) Expand all
500 config_ = configs.get()[i]; 662 config_ = configs.get()[i];
501 } 663 }
502 } 664 }
503 665
504 return config_; 666 return config_;
505 } 667 }
506 668
507 bool NativeViewGLSurfaceGLX::PostSubBuffer( 669 bool NativeViewGLSurfaceGLX::PostSubBuffer(
508 int x, int y, int width, int height) { 670 int x, int y, int width, int height) {
509 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); 671 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
510 glXCopySubBufferMESA(g_display, window_, x, y, width, height); 672 glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height);
511 return true; 673 return true;
512 } 674 }
513 675
514 VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() { 676 VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
515 return vsync_provider_.get(); 677 return vsync_provider_.get();
516 } 678 }
517 679
518 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() 680 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX()
519 : window_(0), 681 : parent_window_(0),
682 #if defined(TOOLKIT_GTK)
683 child_window_(0),
684 dummy_window_(0),
685 backbuffer_allocated_(true),
686 frontbuffer_allocated_(true),
687 #endif
520 config_(NULL) { 688 config_(NULL) {
521 } 689 }
522 690
523 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { 691 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
524 Destroy(); 692 Destroy();
525 } 693 }
526 694
527 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size) 695 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size)
528 : size_(size), 696 : size_(size),
529 config_(NULL), 697 config_(NULL),
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 775
608 void* PbufferGLSurfaceGLX::GetConfig() { 776 void* PbufferGLSurfaceGLX::GetConfig() {
609 return config_; 777 return config_;
610 } 778 }
611 779
612 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { 780 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() {
613 Destroy(); 781 Destroy();
614 } 782 }
615 783
616 } // namespace gfx 784 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gl/gl_surface_glx.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698