Index: content/browser/renderer_host/image_transport_client.cc |
diff --git a/content/browser/renderer_host/image_transport_client.cc b/content/browser/renderer_host/image_transport_client.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4d0c7fd3318b1a7613fecb0a2d087f1e0db125ec |
--- /dev/null |
+++ b/content/browser/renderer_host/image_transport_client.cc |
@@ -0,0 +1,286 @@ |
+// 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. |
+ |
+#include "content/browser/renderer_host/image_transport_client.h" |
+ |
+#include <X11/Xlib.h> |
+#include <X11/extensions/Xcomposite.h> |
+ |
+#include "base/lazy_instance.h" |
+#include "base/memory/scoped_ptr.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/size.h" |
+ |
+namespace { |
+ |
+class ScopedPtrXFree { |
+ public: |
+ void operator()(void* x) const { |
+ ::XFree(x); |
+ } |
+}; |
+ |
+GLuint CreateTexture() { |
+ GLuint texture; |
+ glGenTextures(1, &texture); |
+ glBindTexture(GL_TEXTURE_2D, texture); |
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ return texture; |
+} |
+ |
+class ImageTransportClientEGL : public ImageTransportClient { |
+ public: |
+ explicit ImageTransportClientEGL(ui::SharedResources* resources) |
+ : resources_(resources), |
+ image_(NULL) { |
+ } |
+ |
+ virtual ~ImageTransportClientEGL() { |
+ if (image_) { |
+ resources_->MakeSharedContextCurrent(); |
+ eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), image_); |
+ glFlush(); |
+ } |
+ } |
+ |
+ virtual unsigned int Initialize(uint64* surface_id) { |
+ resources_->MakeSharedContextCurrent(); |
+ image_ = eglCreateImageKHR( |
+ gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_NO_CONTEXT, |
+ EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<void*>(*surface_id), NULL); |
+ if (!image_) |
+ return 0; |
+ GLuint texture = CreateTexture(); |
+ glBindTexture(GL_TEXTURE_2D, texture); |
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image_); |
+ glFlush(); |
+ return texture; |
+ } |
+ |
+ virtual void Acquire() { } |
+ virtual void Release() { } |
+ virtual bool Flipped() { return true; } |
+ virtual TransportDIB::Handle Handle() const { |
+ return TransportDIB::DefaultHandleValue(); |
+ } |
+ |
+ private: |
+ ui::SharedResources* resources_; |
+ EGLImageKHR image_; |
+}; |
+ |
+class ImageTransportClientGLX : public ImageTransportClient { |
+ public: |
+ explicit ImageTransportClientGLX(ui::SharedResources* resources) |
+ : resources_(resources), |
+ pixmap_(0), |
+ glx_pixmap_(0), |
+ texture_(0) { |
+ } |
+ |
+ virtual ~ImageTransportClientGLX() { |
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); |
+ if (glx_pixmap_) |
+ glXDestroyGLXPixmap(dpy, glx_pixmap_); |
+ if (pixmap_) |
+ XFreePixmap(dpy, pixmap_); |
+ } |
+ |
+ virtual unsigned int Initialize(uint64* surface_id) { |
+ resources_->MakeSharedContextCurrent(); |
+ if (!InitializeOneOff()) |
+ return 0; |
+ |
+ // Create pixmap from window. |
+ // We receive a window here rather than a pixmap directly because drivers |
+ // require (or required) that the pixmap used to create the GL texture be |
+ // created in the same process as the texture. |
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); |
+ pixmap_ = XCompositeNameWindowPixmap(dpy, *surface_id); |
+ |
+ const int pixmapAttribs[] = { |
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, |
+ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, |
+ 0 |
+ }; |
+ |
+ glx_pixmap_ = glXCreatePixmap(dpy, fbconfig_.Get(), pixmap_, pixmapAttribs); |
+ |
+ texture_ = CreateTexture(); |
+ return texture_; |
+ } |
+ |
+ virtual void Acquire() { |
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); |
+ glBindTexture(GL_TEXTURE_2D, texture_); |
+ glXBindTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); |
+ } |
+ |
+ virtual void Release() { |
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); |
+ glXReleaseTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT); |
+ } |
+ |
+ virtual bool Flipped() { return false; } |
+ virtual TransportDIB::Handle Handle() const { |
+ return TransportDIB::DefaultHandleValue(); |
+ } |
+ |
+ private: |
+ static bool InitializeOneOff() { |
+ static bool initialized = false; |
+ if (initialized) |
+ return true; |
+ |
+ Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); |
+ |
+ int event_base, error_base; |
+ if (XCompositeQueryExtension(dpy, &event_base, &error_base)) { |
+ int major = 0, minor = 2; |
+ XCompositeQueryVersion(dpy, &major, &minor); |
+ if (major == 0 && minor < 2) { |
+ LOG(ERROR) << "Pixmap from window not supported."; |
+ return false; |
+ } |
+ } |
+ // Wrap the pixmap in a GLXPixmap |
+ int screen = DefaultScreen(dpy); |
+ XWindowAttributes gwa; |
+ XGetWindowAttributes(dpy, RootWindow(dpy, screen), &gwa); |
+ unsigned int visualid = XVisualIDFromVisual(gwa.visual); |
+ |
+ int nfbconfigs, config; |
+ scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> fbconfigs( |
+ glXGetFBConfigs(dpy, screen, &nfbconfigs)); |
+ |
+ for (config = 0; config < nfbconfigs; config++) { |
+ XVisualInfo* visinfo = glXGetVisualFromFBConfig( |
+ dpy, fbconfigs.get()[config]); |
+ if (!visinfo || visinfo->visualid != visualid) |
+ continue; |
+ |
+ int value; |
+ glXGetFBConfigAttrib(dpy, |
+ fbconfigs.get()[config], |
+ GLX_DRAWABLE_TYPE, |
+ &value); |
+ if (!(value & GLX_PIXMAP_BIT)) |
+ continue; |
+ |
+ glXGetFBConfigAttrib(dpy, |
+ fbconfigs.get()[config], |
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, |
+ &value); |
+ if (!(value & GLX_TEXTURE_2D_BIT_EXT)) |
+ continue; |
+ |
+ glXGetFBConfigAttrib(dpy, |
+ fbconfigs.get()[config], |
+ GLX_BIND_TO_TEXTURE_RGB_EXT, |
+ &value); |
+ if (value == GL_FALSE) |
+ continue; |
+ |
+ break; |
+ } |
+ |
+ if (config == nfbconfigs) { |
+ LOG(ERROR) |
+ << "Could not find configuration suitable for binding a pixmap " |
+ << "as a texture."; |
+ return false; |
+ } |
+ fbconfig_.Get() = fbconfigs.get()[config]; |
+ initialized = true; |
+ return initialized; |
+ } |
+ |
+ ui::SharedResources* resources_; |
+ XID pixmap_; |
+ XID glx_pixmap_; |
+ GLuint texture_; |
+ static base::LazyInstance<GLXFBConfig> fbconfig_; |
+}; |
+ |
+base::LazyInstance<GLXFBConfig> ImageTransportClientGLX::fbconfig_( |
+ base::LINKER_INITIALIZED); |
+ |
+class ImageTransportClientOSMesa : public ImageTransportClient { |
+ public: |
+ ImageTransportClientOSMesa(ui::SharedResources* resources, |
+ const gfx::Size& size) |
+ : resources_(resources), |
+ size_(size), |
+ texture_(0) { |
+ } |
+ |
+ virtual ~ImageTransportClientOSMesa() { |
+ } |
+ |
+ virtual unsigned int Initialize(uint64* surface_id) { |
+ // We expect to make the id here, so don't want the other end giving us one |
+ DCHECK_EQ(*surface_id, static_cast<uint64>(0)); |
+ |
+ // It's possible that this ID gneration could clash with IDs from other |
+ // AcceleratedSurfaceContainerTouch* objects, however we should never have |
+ // ids active from more than one type at the same time, so we have free |
+ // reign of the id namespace. |
+ *surface_id = next_id_++; |
+ |
+ shared_mem_.reset( |
+ TransportDIB::Create(size_.GetArea() * 4, // GL_RGBA=4 B/px |
+ *surface_id)); |
+ if (!shared_mem_.get()) |
+ return 0; |
+ |
+ resources_->MakeSharedContextCurrent(); |
+ texture_ = CreateTexture(); |
+ return texture_; |
+ } |
+ |
+ virtual void Acquire() { |
+ glBindTexture(GL_TEXTURE_2D, texture_); |
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, |
+ size_.width(), size_.height(), 0, |
+ GL_RGBA, GL_UNSIGNED_BYTE, shared_mem_->memory()); |
+ } |
+ |
+ virtual void Release() { } |
+ virtual bool Flipped() { return false; } |
+ virtual TransportDIB::Handle Handle() const { return shared_mem_->handle(); } |
+ |
+ private: |
+ ui::SharedResources* resources_; |
+ gfx::Size size_; |
+ scoped_ptr<TransportDIB> shared_mem_; |
+ GLuint texture_; |
+ static uint32 next_id_; |
+}; |
+uint32 ImageTransportClientOSMesa::next_id_ = 0; |
+ |
+} // anonymous namespace |
+ |
+ImageTransportClient* ImageTransportClient::Create( |
+ ui::SharedResources* resources, |
+ const gfx::Size& size) { |
+ switch (gfx::GetGLImplementation()) { |
+ case gfx::kGLImplementationDesktopGL: |
+ return new ImageTransportClientGLX(resources); |
+ case gfx::kGLImplementationEGLGLES2: |
+ return new ImageTransportClientEGL(resources); |
+ case gfx::kGLImplementationOSMesaGL: |
+ return new ImageTransportClientOSMesa(resources, size); |
+ default: |
+ NOTREACHED(); |
+ return NULL; |
+ } |
+} |