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

Unified Diff: content/common/gpu/image_transport_surface_linux.cc

Issue 7395020: Create new GLSurface for cross process image transport. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: "" Created 9 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/common/gpu/image_transport_surface_linux.h ('k') | content/content_common.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/common/gpu/image_transport_surface_linux.cc
diff --git a/content/common/gpu/image_transport_surface_linux.cc b/content/common/gpu/image_transport_surface_linux.cc
new file mode 100644
index 0000000000000000000000000000000000000000..93a067a9793bb46974fa0f5922f99bf7d7a58edf
--- /dev/null
+++ b/content/common/gpu/image_transport_surface_linux.cc
@@ -0,0 +1,448 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(ENABLE_GPU)
+
+#include "content/common/gpu/image_transport_surface_linux.h"
+
+// This conflicts with the defines in Xlib.h and must come first.
+#include "content/common/gpu/gpu_messages.h"
+
+#include <map>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xcomposite.h>
+
+#include "base/callback.h"
+#include "content/common/gpu/gpu_channel.h"
+#include "content/common/gpu/gpu_channel_manager.h"
+#include "content/common/gpu/gpu_command_buffer_stub.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "third_party/angle/include/EGL/egl.h"
+#include "third_party/angle/include/EGL/eglext.h"
+#include "ui/gfx/gl/gl_bindings.h"
+#include "ui/gfx/gl/gl_implementation.h"
+#include "ui/gfx/gl/gl_surface_egl.h"
+#include "ui/gfx/gl/gl_surface_glx.h"
+#include "ui/gfx/surface/accelerated_surface_linux.h"
+
+namespace {
+
+// We are backed by an Pbuffer offscreen surface for the purposes of creating a
+// context, but use FBOs to render to X Pixmap backed EGLImages.
+class EGLImageTransportSurface : public ImageTransportSurface,
+ public gfx::PbufferGLSurfaceEGL {
+ public:
+ explicit EGLImageTransportSurface(GpuCommandBufferStub* stub);
+
+ // GLSurface implementation
+ virtual bool Initialize() OVERRIDE;
+ virtual void Destroy() OVERRIDE;
+ virtual bool IsOffscreen() OVERRIDE;
+ virtual bool SwapBuffers() OVERRIDE;
+ virtual gfx::Size GetSize() OVERRIDE;
+ virtual void OnMakeCurrent() OVERRIDE;
+ virtual unsigned int GetBackingFrameBufferObject() OVERRIDE;
+
+ protected:
+ // ImageTransportSurface implementation
+ virtual void OnSetSurfaceACK(uint64 surface_id) OVERRIDE;
+ virtual void OnBuffersSwappedACK() OVERRIDE;
+ virtual void Resize(gfx::Size size) OVERRIDE;
+
+ private:
+ virtual ~EGLImageTransportSurface() OVERRIDE;
+ void ReleaseSurface(scoped_refptr<AcceleratedSurface>& surface);
+
+ uint32 fbo_id_;
+ uint32 depth_id_;
+ gfx::Size depth_buffer_size_;
+
+ scoped_refptr<AcceleratedSurface> back_surface_;
+ scoped_refptr<AcceleratedSurface> front_surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(EGLImageTransportSurface);
+};
+
+// We are backed by an Pbuffer offscreen surface for the purposes of creating a
+// context, but use FBOs to render to X Pixmap backed EGLImages.
+class GLXImageTransportSurface : public ImageTransportSurface,
+ public gfx::NativeViewGLSurfaceGLX {
+ public:
+ explicit GLXImageTransportSurface(GpuCommandBufferStub* stub);
+
+ // gfx::GLSurface implementation:
+ virtual bool Initialize() OVERRIDE;
+ virtual void Destroy() OVERRIDE;
+ virtual bool SwapBuffers() OVERRIDE;
+ virtual gfx::Size GetSize() OVERRIDE;
+
+ protected:
+ // ImageTransportSurface implementation:
+ void OnSetSurfaceACK(uint64 surface_id) OVERRIDE;
+ void OnBuffersSwappedACK() OVERRIDE;
+ void Resize(gfx::Size size) OVERRIDE;
+
+ private:
+ virtual ~GLXImageTransportSurface();
+
+ // Tell the browser to release the surface.
+ void ReleaseSurface();
+
+ XID dummy_parent_;
+ gfx::Size size_;
+
+ // Whether or not the image has been bound on the browser side.
+ bool bound_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLXImageTransportSurface);
+};
+
+EGLImageTransportSurface::EGLImageTransportSurface(GpuCommandBufferStub* stub) :
+ ImageTransportSurface(stub),
+ gfx::PbufferGLSurfaceEGL(false, gfx::Size(1,1)),
+ fbo_id_(0) {
+}
+
+EGLImageTransportSurface::~EGLImageTransportSurface() {
+}
+
+bool EGLImageTransportSurface::Initialize() {
+ if (!ImageTransportSurface::Initialize())
+ return false;
+ return PbufferGLSurfaceEGL::Initialize();
+}
+
+void EGLImageTransportSurface::Destroy() {
+ if (depth_id_) {
+ glDeleteRenderbuffersEXT(1, &depth_id_);
+ depth_id_ = 0;
+ }
+
+ if (back_surface_.get())
+ ReleaseSurface(back_surface_);
+ if (front_surface_.get())
+ ReleaseSurface(front_surface_);
+
+ ImageTransportSurface::Destroy();
+ PbufferGLSurfaceEGL::Destroy();
+}
+
+bool EGLImageTransportSurface::IsOffscreen() {
+ return false;
+}
+
+void EGLImageTransportSurface::OnMakeCurrent() {
+ if (fbo_id_)
+ return;
+
+ glGenFramebuffersEXT(1, &fbo_id_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_id_);
+ Resize(gfx::Size(1,1));
+
+ GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ LOG(ERROR) << "Framebuffer incomplete.";
+ }
+}
+
+unsigned int EGLImageTransportSurface::GetBackingFrameBufferObject() {
+ return fbo_id_;
+}
+
+void EGLImageTransportSurface::ReleaseSurface(
+ scoped_refptr<AcceleratedSurface>& surface) {
+ if (surface.get()) {
+ GpuHostMsg_AcceleratedSurfaceRelease_Params params;
+ params.renderer_id = stub()->renderer_id();
+ params.render_view_id = stub()->render_view_id();
+ params.identifier = back_surface_->pixmap();
+ params.route_id = route_id();
+ Send(new GpuHostMsg_AcceleratedSurfaceRelease(params));
+ surface = NULL;
+ }
+}
+
+void EGLImageTransportSurface::Resize(gfx::Size size) {
+ if (back_surface_.get())
+ ReleaseSurface(back_surface_);
+
+ if (depth_id_ && depth_buffer_size_ != size) {
+ glDeleteRenderbuffersEXT(1, &depth_id_);
+ depth_id_ = 0;
+ }
+
+ if (!depth_id_) {
+ glGenRenderbuffersEXT(1, &depth_id_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, depth_id_);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER,
+ GL_DEPTH24_STENCIL8,
+ size.width(),
+ size.height());
+ glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER,
+ depth_id_);
+ depth_buffer_size_ = size;
+ }
+
+ back_surface_ = new AcceleratedSurface(size);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ back_surface_->texture(),
+ 0);
+ glFlush();
+
+ GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params;
+ params.renderer_id = stub()->renderer_id();
+ params.render_view_id = stub()->render_view_id();
+ params.width = size.width();
+ params.height = size.height();
+ params.identifier = back_surface_->pixmap();
+ params.route_id = route_id();
+ Send(new GpuHostMsg_AcceleratedSurfaceSetIOSurface(params));
+
+ scheduler()->SetScheduled(false);
+}
+
+bool EGLImageTransportSurface::SwapBuffers() {
+ front_surface_.swap(back_surface_);
+ DCHECK_NE(front_surface_.get(), static_cast<AcceleratedSurface*>(NULL));
+ glFlush();
+
+ GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
+ params.renderer_id = stub()->renderer_id();
+ params.render_view_id = stub()->render_view_id();
+ params.surface_id = front_surface_->pixmap();
+ params.route_id = route_id();
+ Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
+
+ gfx::Size expected_size = front_surface_->size();
+ if (!back_surface_.get() || back_surface_->size() != expected_size) {
+ Resize(expected_size);
+ } else {
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ back_surface_->texture(),
+ 0);
+ }
+ scheduler()->SetScheduled(false);
+ return true;
+}
+
+gfx::Size EGLImageTransportSurface::GetSize() {
+ return back_surface_->size();
+}
+
+void EGLImageTransportSurface::OnSetSurfaceACK(
+ uint64 surface_id) {
+ DCHECK_EQ(back_surface_->pixmap(), surface_id);
+ scheduler()->SetScheduled(true);
+}
+
+void EGLImageTransportSurface::OnBuffersSwappedACK() {
+ scheduler()->SetScheduled(true);
+}
+
+GLXImageTransportSurface::GLXImageTransportSurface(GpuCommandBufferStub* stub) :
+ ImageTransportSurface(stub),
+ gfx::NativeViewGLSurfaceGLX(),
+ dummy_parent_(0),
+ size_(1, 1),
+ bound_(false) {
+}
+
+GLXImageTransportSurface::~GLXImageTransportSurface() {
+}
+
+bool GLXImageTransportSurface::Initialize() {
+ // Create a dummy window to host the real window.
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay();
+ XSetWindowAttributes swa;
+ swa.event_mask = StructureNotifyMask;
+ swa.override_redirect = True;
+ dummy_parent_ = XCreateWindow(
+ dpy,
+ RootWindow(dpy, DefaultScreen(dpy)), // parent
+ -100, -100, 1, 1,
+ 0, // border width
+ CopyFromParent, // depth
+ InputOutput,
+ CopyFromParent, // visual
+ CWEventMask | CWOverrideRedirect, &swa);
+ XMapWindow(dpy, dummy_parent_);
+
+ swa.event_mask = StructureNotifyMask;
+ swa.override_redirect = false;
+ window_ = XCreateWindow(dpy,
+ dummy_parent_,
+ 0, 0, size_.width(), size_.height(),
+ 0, // border width
+ CopyFromParent, // depth
+ InputOutput,
+ CopyFromParent, // visual
+ CWEventMask, &swa);
+ XMapWindow(dpy, window_);
+ while(1) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ if (event.type == MapNotify && event.xmap.window == window_)
+ break;
+ }
+ // Manual setting must be used to avoid unnecessary rendering by server.
+ XCompositeRedirectWindow(dpy, window_, CompositeRedirectManual);
+ Resize(size_);
+
+ if (!ImageTransportSurface::Initialize())
+ return false;
+ return gfx::NativeViewGLSurfaceGLX::Initialize();
+}
+
+void GLXImageTransportSurface::Destroy() {
+ if (bound_)
+ ReleaseSurface();
+
+ if (window_) {
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay();
+ XDestroyWindow(dpy, window_);
+ XDestroyWindow(dpy, dummy_parent_);
+ }
+
+ ImageTransportSurface::Destroy();
+ gfx::NativeViewGLSurfaceGLX::Destroy();
+}
+
+void GLXImageTransportSurface::ReleaseSurface() {
+ DCHECK(bound_);
+ GpuHostMsg_AcceleratedSurfaceRelease_Params params;
+ params.renderer_id = stub()->renderer_id();
+ params.render_view_id = stub()->render_view_id();
+ params.identifier = window_;
+ params.route_id = route_id();
+ Send(new GpuHostMsg_AcceleratedSurfaceRelease(params));
+}
+
+void GLXImageTransportSurface::Resize(gfx::Size size) {
+ size_ = size;
+ if (bound_) {
+ ReleaseSurface();
+ bound_ = false;
+ }
+
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay();
+ XResizeWindow(dpy, window_, size_.width(), size_.height());
+ XFlush(dpy);
+
+ GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params;
+ params.renderer_id = stub()->renderer_id();
+ params.render_view_id = stub()->render_view_id();
+ params.width = size_.width();
+ params.height = size_.height();
+ params.identifier = window_;
+ params.route_id = route_id();
+ Send(new GpuHostMsg_AcceleratedSurfaceSetIOSurface(params));
+
+ scheduler()->SetScheduled(false);
+}
+
+bool GLXImageTransportSurface::SwapBuffers() {
+ gfx::NativeViewGLSurfaceGLX::SwapBuffers();
+ glFlush();
+
+ GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
+ params.renderer_id = stub()->renderer_id();
+ params.render_view_id = stub()->render_view_id();
+ params.surface_id = window_;
+ params.route_id = route_id();
+ Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
+
+ return true;
+}
+
+gfx::Size GLXImageTransportSurface::GetSize() {
+ return size_;
+}
+
+void GLXImageTransportSurface::OnSetSurfaceACK(
+ uint64 surface_id) {
+ DCHECK(!bound_);
+ bound_ = true;
+ scheduler()->SetScheduled(true);
+}
+
+void GLXImageTransportSurface::OnBuffersSwappedACK() {
+}
+
+} // namespace
+
+ImageTransportSurface::ImageTransportSurface(GpuCommandBufferStub* stub) :
+ stub_(stub) {
+ GpuChannelManager* gpu_channel_manager
+ = stub_->channel()->gpu_channel_manager();
+ route_id_ = gpu_channel_manager->GenerateRouteID();
+ gpu_channel_manager->AddRoute(route_id_, this);
+}
+
+ImageTransportSurface::~ImageTransportSurface() {
+ GpuChannelManager* gpu_channel_manager
+ = stub_->channel()->gpu_channel_manager();
+ gpu_channel_manager->RemoveRoute(route_id_);
+}
+
+bool ImageTransportSurface::Initialize() {
+ scheduler()->SetResizeCallback(
+ NewCallback(this, &ImageTransportSurface::Resize));
+ return true;
+}
+
+void ImageTransportSurface::Destroy() {
+ scheduler()->SetResizeCallback(NULL);
+}
+
+bool ImageTransportSurface::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ImageTransportSurface, message)
+ IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_SetSurfaceACK,
+ OnSetSurfaceACK)
+ IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_BuffersSwappedACK,
+ OnBuffersSwappedACK)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+bool ImageTransportSurface::Send(IPC::Message* message) {
+ GpuChannelManager* gpu_channel_manager =
+ stub_->channel()->gpu_channel_manager();
+ return gpu_channel_manager->Send(message);
+}
+
+gpu::GpuScheduler* ImageTransportSurface::scheduler() {
+ return stub_->scheduler();
+}
+
+// static
+scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface(
+ GpuCommandBufferStub* stub) {
+ scoped_refptr<gfx::GLSurface> surface;
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationDesktopGL:
+ surface = new GLXImageTransportSurface(stub);
+ break;
+ case gfx::kGLImplementationEGLGLES2:
+ surface = new EGLImageTransportSurface(stub);
+ break;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+ if (surface->Initialize())
+ return surface;
+ else
+ return NULL;
+}
+
+#endif // defined(USE_GPU)
« no previous file with comments | « content/common/gpu/image_transport_surface_linux.h ('k') | content/content_common.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698