Chromium Code Reviews| Index: ui/gl/gl_surface_glx.cc |
| diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc |
| index 8b705dfbe93751c899daa05752cc585d64229097..422f6a044068e5b36946aa2bb6cf5168a76e474d 100644 |
| --- a/ui/gl/gl_surface_glx.cc |
| +++ b/ui/gl/gl_surface_glx.cc |
| @@ -10,6 +10,7 @@ extern "C" { |
| #include "base/basictypes.h" |
| #include "base/debug/trace_event.h" |
| +#include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| @@ -39,7 +40,7 @@ class ScopedPtrXFree { |
| } |
| }; |
| -Display* g_display; |
| +Display* g_display = NULL; |
| const char* g_glx_extensions = NULL; |
| bool g_glx_context_create = false; |
| bool g_glx_create_context_robustness_supported = false; |
| @@ -315,7 +316,17 @@ bool GLSurfaceGLX::InitializeOneOff() { |
| // it's own thread. |
| XInitThreads(); |
| +#if defined(TOOLKIT_GTK) |
| + // Be sure to use the X display handle and not the GTK display handle if this |
| + // is the GPU process. |
| + if (base::MessageLoop::current()->type() == base::MessageLoop::TYPE_GPU) |
| + g_display = base::MessagePumpX11::GetDefaultXDisplay(); |
| + else |
| + g_display = base::MessagePumpForUI::GetDefaultXDisplay(); |
| +#else |
| g_display = base::MessagePumpForUI::GetDefaultXDisplay(); |
| +#endif |
| + |
| if (!g_display) { |
| LOG(ERROR) << "XOpenDisplay failed."; |
| return false; |
| @@ -388,31 +399,176 @@ void* GLSurfaceGLX::GetDisplay() { |
| GLSurfaceGLX::~GLSurfaceGLX() {} |
| +#if defined(TOOLKIT_GTK) |
| +// A mechanism for forwarding XExpose events from one window to another. |
| +// Because in the workaround for http://crbug.com/145600 the child window |
| +// is placed on top of the parent window, only the child window will receive |
| +// all expose events. These need to be forwared to the parent window to inform |
| +// it that it should paint. |
| +class XExposeEventForwarder : public base::MessagePumpObserver { |
|
piman
2013/09/11 23:05:09
nit: move this to an anonoymous namespace.
ccameron
2013/09/12 01:37:13
Done.
|
| + public: |
| + XExposeEventForwarder() { |
| + base::MessagePumpX11::Current()->AddObserver(this); |
| + } |
| + ~XExposeEventForwarder() { |
| + base::MessagePumpX11::Current()->RemoveObserver(this); |
|
piman
2013/09/11 23:05:09
If this is a lazy instance, the destructor will ru
ccameron
2013/09/12 01:37:13
Good catch, thanks. Moved to the Add/RemoveParentC
|
| + } |
| + |
| + void AddParentChildPair(gfx::AcceleratedWidget parent_window, |
| + gfx::AcceleratedWidget child_window) { |
| + DCHECK(child_to_parent_map_.find(child_window) == |
| + child_to_parent_map_.end()); |
| + child_to_parent_map_.insert(std::make_pair( |
| + child_window, parent_window)); |
| + } |
| + void RemoveParentChildPair(gfx::AcceleratedWidget parent_window, |
| + gfx::AcceleratedWidget child_window) { |
| + DCHECK(child_to_parent_map_.find(child_window) != |
| + child_to_parent_map_.end()); |
| + child_to_parent_map_.erase(child_window); |
| + } |
| + |
| + private: |
| + virtual base::EventStatus WillProcessEvent( |
| + const base::NativeEvent& xevent) OVERRIDE { |
| + if (xevent->type != Expose) |
| + return base::EVENT_CONTINUE; |
| + |
| + WindowMap::const_iterator found = child_to_parent_map_.find( |
| + xevent->xexpose.window); |
| + if (found == child_to_parent_map_.end()) |
| + return base::EVENT_CONTINUE; |
| + |
| + gfx::AcceleratedWidget target_window = found->second; |
| + XEvent forwarded_event = *xevent; |
| + forwarded_event.xexpose.window = target_window; |
| + XSendEvent(g_display, target_window, False, ExposureMask, |
| + &forwarded_event); |
| + return base::EVENT_CONTINUE; |
| + } |
| + virtual void DidProcessEvent(const base::NativeEvent& xevent) { |
| + } |
| + |
| + typedef std::map<gfx::AcceleratedWidget, gfx::AcceleratedWidget> WindowMap; |
| + WindowMap child_to_parent_map_; |
| +}; |
| + |
| +static base::LazyInstance<XExposeEventForwarder> g_xexpose_event_forwarder = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +bool NativeViewGLSurfaceGLX::SetBackbufferAllocation(bool allocated) { |
| + if (allocated) |
| + return CreateChildWindow(); |
| + else |
| + DestroyChildWindow(); |
| + return true; |
| +} |
| + |
| +bool NativeViewGLSurfaceGLX::CreateChildWindow() { |
| + if (child_window_) |
| + return true; |
| + |
| + XWindowAttributes attributes; |
| + if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { |
|
piman
2013/09/11 23:05:09
Could we cache this? It requires a round trip to X
ccameron
2013/09/12 01:37:13
Actually, we can just use CopyFromParent and avoid
|
| + LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ |
| + << "."; |
| + return false; |
| + } |
| + |
| + XSetWindowAttributes set_window_attributes; |
| + set_window_attributes.event_mask = ExposureMask; |
| + child_window_ = XCreateWindow( |
| + g_display, parent_window_, 0, 0, attributes.width, attributes.height, 0, |
| + attributes.depth, InputOutput, attributes.visual, CWEventMask, |
| + &set_window_attributes); |
| + g_xexpose_event_forwarder.Pointer()->AddParentChildPair( |
| + parent_window_, child_window_); |
| + |
| + XMapWindow(g_display, child_window_); |
| + XFlush(g_display); |
| + |
| + // If the dummy window was current, make the child window current now. |
| + if (dummy_window_ == glXGetCurrentDrawable()) |
| + glXMakeCurrent(g_display, child_window_, glXGetCurrentContext()); |
| + |
| + return true; |
| +} |
| + |
| +void NativeViewGLSurfaceGLX::DestroyChildWindow() { |
| + if (!child_window_) |
| + return; |
| + |
|
piman
2013/09/11 23:05:09
Do we need to glXMakeCurrent the dummy_window_ her
ccameron
2013/09/12 01:37:13
Doesn't look like it. And I may make dummy_window_
|
| + g_xexpose_event_forwarder.Pointer()->RemoveParentChildPair( |
| + parent_window_, child_window_); |
| + XDestroyWindow(g_display, child_window_); |
| + XFlush(g_display); |
| + child_window_ = 0; |
| +} |
| +#endif |
| + |
| NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) |
| - : window_(window), |
| + : parent_window_(window), |
| +#if defined(TOOLKIT_GTK) |
| + child_window_(0), |
| + dummy_window_(0), |
| +#endif |
| config_(NULL) { |
| } |
| +gfx::AcceleratedWidget NativeViewGLSurfaceGLX::GetDrawableHandle() const { |
| +#if defined(TOOLKIT_GTK) |
| + if (child_window_) |
| + return child_window_; |
| + return dummy_window_; |
| +#else |
| + return parent_window_; |
| +#endif |
| +} |
| + |
| bool NativeViewGLSurfaceGLX::Initialize() { |
| XWindowAttributes attributes; |
| - if (!XGetWindowAttributes(g_display, window_, &attributes)) { |
| - LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; |
| + if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) { |
| + LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ |
| + << "."; |
| return false; |
| } |
| size_ = gfx::Size(attributes.width, attributes.height); |
| + gfx::AcceleratedWidget window_for_vsync = parent_window_; |
| + |
| +#if defined(TOOLKIT_GTK) |
| + CreateChildWindow(); |
| + dummy_window_ = XCreateWindow( |
| + g_display, parent_window_, 0, 0, 1, 1, 0, attributes.depth, InputOutput, |
| + attributes.visual, 0, NULL); |
| + window_for_vsync = dummy_window_; |
| +#endif |
| + |
| if (g_glx_oml_sync_control_supported) |
| - vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_)); |
| + vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_for_vsync)); |
| else if (g_glx_sgi_video_sync_supported) |
| - vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_)); |
| + vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_for_vsync)); |
| return true; |
| } |
| void NativeViewGLSurfaceGLX::Destroy() { |
| +#if defined(TOOLKIT_GTK) |
| + if (dummy_window_) |
| + XDestroyWindow(g_display, dummy_window_); |
| + dummy_window_ = 0; |
| + |
| + DestroyChildWindow(); |
| +#endif |
| } |
| bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { |
| +#if defined(TOOLKIT_GTK) |
| + if (child_window_) { |
| + XResizeWindow(g_display, child_window_, size.width(), size.height()); |
| + XFlush(g_display); |
| + } |
| +#endif |
| size_ = size; |
| return true; |
| } |
| @@ -422,7 +578,7 @@ bool NativeViewGLSurfaceGLX::IsOffscreen() { |
| } |
| bool NativeViewGLSurfaceGLX::SwapBuffers() { |
| - glXSwapBuffers(g_display, window_); |
| + glXSwapBuffers(g_display, GetDrawableHandle()); |
| return true; |
| } |
| @@ -431,7 +587,7 @@ gfx::Size NativeViewGLSurfaceGLX::GetSize() { |
| } |
| void* NativeViewGLSurfaceGLX::GetHandle() { |
| - return reinterpret_cast<void*>(window_); |
| + return reinterpret_cast<void*>(GetDrawableHandle()); |
| } |
| std::string NativeViewGLSurfaceGLX::GetExtensions() { |
| @@ -460,10 +616,10 @@ void* NativeViewGLSurfaceGLX::GetConfig() { |
| XWindowAttributes attributes; |
| if (!XGetWindowAttributes( |
| g_display, |
| - window_, |
| + parent_window_, |
| &attributes)) { |
| LOG(ERROR) << "XGetWindowAttributes failed for window " << |
| - window_ << "."; |
| + parent_window_ << "."; |
| return NULL; |
| } |
| @@ -507,7 +663,7 @@ void* NativeViewGLSurfaceGLX::GetConfig() { |
| bool NativeViewGLSurfaceGLX::PostSubBuffer( |
| int x, int y, int width, int height) { |
| DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); |
| - glXCopySubBufferMESA(g_display, window_, x, y, width, height); |
| + glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height); |
| return true; |
| } |
| @@ -516,7 +672,11 @@ VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() { |
| } |
| NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() |
| - : window_(0), |
| + : parent_window_(0), |
| +#if defined(TOOLKIT_GTK) |
| + child_window_(0), |
| + dummy_window_(0), |
| +#endif |
| config_(NULL) { |
| } |