summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorbacker@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-25 14:04:12 +0000
committerbacker@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-25 14:04:12 +0000
commitb9b751f2681d39b11a692a655eb16a9e1e4eba97 (patch)
treeef152fd04b0a9730f9088aa1b968e6096097127e /ui
parent13ffb98bc729794380228ebdc09b18687d2d1d74 (diff)
downloadchromium_src-b9b751f2681d39b11a692a655eb16a9e1e4eba97.zip
chromium_src-b9b751f2681d39b11a692a655eb16a9e1e4eba97.tar.gz
chromium_src-b9b751f2681d39b11a692a655eb16a9e1e4eba97.tar.bz2
Refactor: Move app/surface to ui/gfx/surface.
This is progress towards moving app/gfx/gl to ui/gfx/gl. Currently, surface depends on gl, but gl depends on app_base (which contains surface). This refactor gets rid of this potential cyclic dependency. surface.gyp is in a separate file (not a .gypi include) because cyclic dependency checking is at the file level (not target level). BUG=none TEST=by hand and try bots Review URL: http://codereview.chromium.org/6718027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79396 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/gfx/surface/accelerated_surface_mac.cc347
-rw-r--r--ui/gfx/surface/accelerated_surface_mac.h167
-rw-r--r--ui/gfx/surface/io_surface_support_mac.cc270
-rw-r--r--ui/gfx/surface/io_surface_support_mac.h70
-rw-r--r--ui/gfx/surface/surface.gyp57
-rw-r--r--ui/gfx/surface/transport_dib.h202
-rw-r--r--ui/gfx/surface/transport_dib_linux.cc141
-rw-r--r--ui/gfx/surface/transport_dib_mac.cc98
-rw-r--r--ui/gfx/surface/transport_dib_win.cc110
9 files changed, 1462 insertions, 0 deletions
diff --git a/ui/gfx/surface/accelerated_surface_mac.cc b/ui/gfx/surface/accelerated_surface_mac.cc
new file mode 100644
index 0000000..59919f8
--- /dev/null
+++ b/ui/gfx/surface/accelerated_surface_mac.cc
@@ -0,0 +1,347 @@
+// 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 "ui/gfx/surface/accelerated_surface_mac.h"
+
+#include "app/gfx/gl/gl_bindings.h"
+#include "app/gfx/gl/gl_implementation.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/surface/io_surface_support_mac.h"
+
+AcceleratedSurface::AcceleratedSurface()
+ : io_surface_id_(0),
+ allocate_fbo_(false),
+ texture_(0),
+ fbo_(0),
+ depth_stencil_renderbuffer_(0) {
+}
+
+AcceleratedSurface::~AcceleratedSurface() {}
+
+bool AcceleratedSurface::Initialize(gfx::GLContext* share_context,
+ bool allocate_fbo) {
+ allocate_fbo_ = allocate_fbo;
+
+ // Ensure GL is initialized before trying to create an offscreen GL context.
+ if (!gfx::GLContext::InitializeOneOff())
+ return false;
+
+ // Drawing to IOSurfaces via OpenGL only works with desktop GL and
+ // not with the OSMesa software renderer.
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL)
+ return false;
+
+ gl_context_.reset(gfx::GLContext::CreateOffscreenGLContext(share_context));
+ if (!gl_context_.get())
+ return false;
+
+ // Now we're ready to handle SetSurfaceSize calls, which will
+ // allocate and/or reallocate the IOSurface and associated offscreen
+ // OpenGL structures for rendering.
+ return true;
+}
+
+void AcceleratedSurface::Destroy() {
+ // The FBO and texture objects will be destroyed when the OpenGL context,
+ // and any other contexts sharing resources with it, is. We don't want to
+ // make the context current one last time here just in order to delete
+ // these objects.
+
+ // Release the old TransportDIB in the browser.
+ if (dib_free_callback_.get() && transport_dib_.get()) {
+ dib_free_callback_->Run(transport_dib_->id());
+ }
+ transport_dib_.reset();
+
+ if (gl_context_.get())
+ gl_context_->Destroy();
+ gl_context_.reset();
+}
+
+// Call after making changes to the surface which require a visual update.
+// Makes the rendering show up in other processes.
+void AcceleratedSurface::SwapBuffers() {
+ if (io_surface_.get() != NULL) {
+ if (allocate_fbo_) {
+ // Bind and unbind the framebuffer to make changes to the
+ // IOSurface show up in the other process.
+ glFlush();
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
+ } else {
+ // Copy the current framebuffer's contents into our "live" texture.
+ // Note that the current GL context might not be ours at this point!
+ // This is deliberate, so that surrounding code using GL can produce
+ // rendering results consumed by the AcceleratedSurface.
+ // Need to save and restore OpenGL state around this call.
+ GLint current_texture = 0;
+ GLenum target_binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
+ GLenum target = GL_TEXTURE_RECTANGLE_ARB;
+ glGetIntegerv(target_binding, &current_texture);
+ glBindTexture(target, texture_);
+ glCopyTexSubImage2D(target, 0,
+ 0, 0,
+ 0, 0,
+ surface_size_.width(), surface_size_.height());
+ glBindTexture(target, current_texture);
+ }
+ } else if (transport_dib_.get() != NULL) {
+ // Pre-Mac OS X 10.6, fetch the rendered image from the current frame
+ // buffer and copy it into the TransportDIB.
+ // TODO(dspringer): There are a couple of options that can speed this up.
+ // First is to use async reads into a PBO, second is to use SPI that
+ // allows many tasks to access the same CGSSurface.
+ void* pixel_memory = transport_dib_->memory();
+ if (pixel_memory) {
+ // Note that glReadPixels does an implicit glFlush().
+ glReadPixels(0,
+ 0,
+ surface_size_.width(),
+ surface_size_.height(),
+ GL_BGRA, // This pixel format should have no conversion.
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ pixel_memory);
+ }
+ }
+}
+
+static void AddBooleanValue(CFMutableDictionaryRef dictionary,
+ const CFStringRef key,
+ bool value) {
+ CFDictionaryAddValue(dictionary, key,
+ (value ? kCFBooleanTrue : kCFBooleanFalse));
+}
+
+static void AddIntegerValue(CFMutableDictionaryRef dictionary,
+ const CFStringRef key,
+ int32 value) {
+ base::mac::ScopedCFTypeRef<CFNumberRef> number(
+ CFNumberCreate(NULL, kCFNumberSInt32Type, &value));
+ CFDictionaryAddValue(dictionary, key, number.get());
+}
+
+void AcceleratedSurface::AllocateRenderBuffers(GLenum target,
+ const gfx::Size& size) {
+ if (!texture_) {
+ // Generate the texture object.
+ glGenTextures(1, &texture_);
+ glBindTexture(target, texture_);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ // Generate and bind the framebuffer object.
+ glGenFramebuffersEXT(1, &fbo_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
+ // Generate (but don't bind) the depth buffer -- we don't need
+ // this bound in order to do offscreen rendering.
+ glGenRenderbuffersEXT(1, &depth_stencil_renderbuffer_);
+ }
+
+ // Reallocate the depth buffer.
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_renderbuffer_);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_DEPTH24_STENCIL8_EXT,
+ size.width(),
+ size.height());
+
+ // Unbind the renderbuffers.
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+
+ // Make sure that subsequent set-up code affects the render texture.
+ glBindTexture(target, texture_);
+}
+
+bool AcceleratedSurface::SetupFrameBufferObject(GLenum target) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
+ GLenum fbo_status;
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ target,
+ texture_,
+ 0);
+ fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT) {
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ depth_stencil_renderbuffer_);
+ fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ }
+ // Attach the depth and stencil buffer.
+ if (fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT) {
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ 0x8D20, // GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER_EXT,
+ depth_stencil_renderbuffer_);
+ fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ }
+ return fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT;
+}
+
+bool AcceleratedSurface::MakeCurrent() {
+ if (!gl_context_.get())
+ return false;
+ return gl_context_->MakeCurrent();
+}
+
+void AcceleratedSurface::Clear(const gfx::Rect& rect) {
+ DCHECK(gl_context_->IsCurrent());
+ glClearColor(0, 0, 0, 0);
+ glViewport(0, 0, rect.width(), rect.height());
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, rect.width(), 0, rect.height(), -1, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+uint64 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) {
+ if (surface_size_ == size) {
+ // Return 0 to indicate to the caller that no new backing store
+ // allocation occurred.
+ return 0;
+ }
+
+ // Only support IO surfaces if the GL implementation is the native desktop GL.
+ // IO surfaces will not work with, for example, OSMesa software renderer
+ // GL contexts.
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL)
+ return 0;
+
+ IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
+ if (!io_surface_support)
+ return 0; // Caller can try using SetWindowSizeForTransportDIB().
+
+ if (!MakeCurrent())
+ return 0;
+
+ // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
+ // Mac OS X and is required for IOSurface interoperability.
+ GLenum target = GL_TEXTURE_RECTANGLE_ARB;
+ if (allocate_fbo_) {
+ AllocateRenderBuffers(target, size);
+ } else if (!texture_) {
+ // Generate the texture object.
+ glGenTextures(1, &texture_);
+ glBindTexture(target, texture_);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+
+ // Allocate a new IOSurface, which is the GPU resource that can be
+ // shared across processes.
+ base::mac::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
+ properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ AddIntegerValue(properties,
+ io_surface_support->GetKIOSurfaceWidth(), size.width());
+ AddIntegerValue(properties,
+ io_surface_support->GetKIOSurfaceHeight(), size.height());
+ AddIntegerValue(properties,
+ io_surface_support->GetKIOSurfaceBytesPerElement(), 4);
+ AddBooleanValue(properties,
+ io_surface_support->GetKIOSurfaceIsGlobal(), true);
+ // I believe we should be able to unreference the IOSurfaces without
+ // synchronizing with the browser process because they are
+ // ultimately reference counted by the operating system.
+ io_surface_.reset(io_surface_support->IOSurfaceCreate(properties));
+
+ // Don't think we need to identify a plane.
+ GLuint plane = 0;
+ io_surface_support->CGLTexImageIOSurface2D(
+ static_cast<CGLContextObj>(gl_context_->GetHandle()),
+ target,
+ GL_RGBA,
+ size.width(),
+ size.height(),
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ io_surface_.get(),
+ plane);
+ if (allocate_fbo_) {
+ // Set up the frame buffer object.
+ SetupFrameBufferObject(target);
+ }
+ surface_size_ = size;
+
+ // Now send back an identifier for the IOSurface. We originally
+ // intended to send back a mach port from IOSurfaceCreateMachPort
+ // but it looks like Chrome IPC would need to be modified to
+ // properly send mach ports between processes. For the time being we
+ // make our IOSurfaces global and send back their identifiers. On
+ // the browser process side the identifier is reconstituted into an
+ // IOSurface for on-screen rendering.
+ io_surface_id_ = io_surface_support->IOSurfaceGetID(io_surface_);
+ return io_surface_id_;
+}
+
+uint64 AcceleratedSurface::GetSurfaceId() {
+ return io_surface_id_;
+}
+
+TransportDIB::Handle AcceleratedSurface::SetTransportDIBSize(
+ const gfx::Size& size) {
+ if (surface_size_ == size) {
+ // Return an invalid handle to indicate to the caller that no new backing
+ // store allocation occurred.
+ return TransportDIB::DefaultHandleValue();
+ }
+ surface_size_ = size;
+
+ // Release the old TransportDIB in the browser.
+ if (dib_free_callback_.get() && transport_dib_.get()) {
+ dib_free_callback_->Run(transport_dib_->id());
+ }
+ transport_dib_.reset();
+
+ // Ask the renderer to create a TransportDIB.
+ size_t dib_size = size.width() * 4 * size.height(); // 4 bytes per pixel.
+ TransportDIB::Handle dib_handle;
+ if (dib_alloc_callback_.get()) {
+ dib_alloc_callback_->Run(dib_size, &dib_handle);
+ }
+ if (!TransportDIB::is_valid_handle(dib_handle)) {
+ // If the allocator fails, it means the DIB was not created in the browser,
+ // so there is no need to run the deallocator here.
+ return TransportDIB::DefaultHandleValue();
+ }
+ transport_dib_.reset(TransportDIB::Map(dib_handle));
+ if (transport_dib_.get() == NULL) {
+ // TODO(dspringer): if the Map() fails, should the deallocator be run so
+ // that the DIB is deallocated in the browser?
+ return TransportDIB::DefaultHandleValue();
+ }
+
+ if (allocate_fbo_) {
+ DCHECK(gl_context_->IsCurrent());
+ // Set up the render buffers and reserve enough space on the card for the
+ // framebuffer texture.
+ GLenum target = GL_TEXTURE_RECTANGLE_ARB;
+ AllocateRenderBuffers(target, size);
+ glTexImage2D(target,
+ 0, // mipmap level 0
+ GL_RGBA8, // internal pixel format
+ size.width(),
+ size.height(),
+ 0, // 0 border
+ GL_BGRA, // Used for consistency
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ NULL); // No data, just reserve room on the card.
+ SetupFrameBufferObject(target);
+ }
+ return transport_dib_->handle();
+}
+
+void AcceleratedSurface::SetTransportDIBAllocAndFree(
+ Callback2<size_t, TransportDIB::Handle*>::Type* allocator,
+ Callback1<TransportDIB::Id>::Type* deallocator) {
+ dib_alloc_callback_.reset(allocator);
+ dib_free_callback_.reset(deallocator);
+}
diff --git a/ui/gfx/surface/accelerated_surface_mac.h b/ui/gfx/surface/accelerated_surface_mac.h
new file mode 100644
index 0000000..44ce8d5
--- /dev/null
+++ b/ui/gfx/surface/accelerated_surface_mac.h
@@ -0,0 +1,167 @@
+// 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.
+
+#ifndef UI_GFX_SURFACE_ACCELERATED_SURFACE_MAC_H_
+#define UI_GFX_SURFACE_ACCELERATED_SURFACE_MAC_H_
+#pragma once
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "app/gfx/gl/gl_context.h"
+#include "base/callback.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/scoped_ptr.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
+#include "ui/gfx/surface/transport_dib.h"
+
+// Should not include GL headers in a header file. Forward declare these types
+// instead.
+typedef struct _CGLContextObject* CGLContextObj;
+typedef unsigned int GLenum;
+typedef unsigned int GLuint;
+
+namespace gfx {
+class Rect;
+}
+
+// Encapsulates an accelerated GL surface that can be shared across processes
+// on systems that support it (10.6 and above). For systems that do not, it
+// uses a regular dib. There will either be an IOSurface or a TransportDIB,
+// never both.
+
+class AcceleratedSurface {
+ public:
+ AcceleratedSurface();
+ virtual ~AcceleratedSurface();
+
+ // Set up internal buffers. |share_context|, if non-NULL, is a context
+ // with which the internally created OpenGL context shares textures and
+ // other resources. |allocate_fbo| indicates whether or not this surface
+ // should allocate an offscreen frame buffer object (FBO) internally. If
+ // not, then the user is expected to allocate one. NOTE that allocating
+ // an FBO internally does NOT work properly with client code which uses
+ // OpenGL (i.e., via GLES2 command buffers), because the GLES2
+ // implementation does not know to bind the accelerated surface's
+ // internal FBO when the default FBO is bound. Returns false upon
+ // failure.
+ bool Initialize(gfx::GLContext* share_context, bool allocate_fbo);
+ // Tear down. Must be called before destructor to prevent leaks.
+ void Destroy();
+
+ // These methods are used only once the accelerated surface is initialized.
+
+ // Sets the accelerated surface to the given size, creating a new one if
+ // the height or width changes. Returns a unique id of the IOSurface to
+ // which the surface is bound, or 0 if no changes were made or an error
+ // occurred. MakeCurrent() will have been called on the new surface.
+ uint64 SetSurfaceSize(const gfx::Size& size);
+
+ // Returns the id of this surface's IOSruface, or 0 for
+ // transport DIB surfaces.
+ uint64 GetSurfaceId();
+
+ // Sets the GL context to be the current one for drawing. Returns true if
+ // it succeeded.
+ bool MakeCurrent();
+ // Clear the surface to be transparent. Assumes the caller has already called
+ // MakeCurrent().
+ void Clear(const gfx::Rect& rect);
+ // Call after making changes to the surface which require a visual update.
+ // Makes the rendering show up in other processes. Assumes the caller has
+ // already called MakeCurrent().
+ //
+ // If this AcceleratedSurface is configured with its own FBO, then
+ // this call causes the color buffer to be transmitted. Otherwise,
+ // it causes the frame buffer of the current GL context to be copied
+ // either into an internal texture via glCopyTexSubImage2D or into a
+ // TransportDIB via glReadPixels.
+ //
+ // The size of the rectangle copied is the size last specified via
+ // SetSurfaceSize. If another GL context than the one this
+ // AcceleratedSurface contains is responsible for the production of
+ // the pixels, then when this entry point is called, the color
+ // buffer must be in a state where a glCopyTexSubImage2D or
+ // glReadPixels is legal. (For example, if using multisampled FBOs,
+ // the FBO must have been resolved into a non-multisampled color
+ // texture.) Additionally, in this situation, the contexts must
+ // share server-side GL objects, so that this AcceleratedSurface's
+ // texture is a legal name in the namespace of the current context.
+ void SwapBuffers();
+
+ CGLContextObj context() {
+ return static_cast<CGLContextObj>(gl_context_->GetHandle());
+ }
+
+ // These methods are only used when there is a transport DIB.
+
+ // Sets the transport DIB to the given size, creating a new one if the
+ // height or width changes. Returns a handle to the new DIB, or a default
+ // handle if no changes were made. Assumes the caller has already called
+ // MakeCurrent().
+ TransportDIB::Handle SetTransportDIBSize(const gfx::Size& size);
+ // Sets the methods to use for allocating and freeing memory for the
+ // transport DIB.
+ void SetTransportDIBAllocAndFree(
+ Callback2<size_t, TransportDIB::Handle*>::Type* allocator,
+ Callback1<TransportDIB::Id>::Type* deallocator);
+
+ // Get the accelerated surface size.
+ gfx::Size GetSize() const { return surface_size_; }
+
+ private:
+ // Helper function to generate names for the backing texture, render buffers
+ // and FBO. On return, the resulting buffer names can be attached to |fbo_|.
+ // |target| is the target type for the color buffer.
+ void AllocateRenderBuffers(GLenum target, const gfx::Size& size);
+
+ // Helper function to attach the buffers previously allocated by a call to
+ // AllocateRenderBuffers(). On return, |fbo_| can be used for
+ // rendering. |target| must be the same value as used in the call to
+ // AllocateRenderBuffers(). Returns |true| if the resulting framebuffer
+ // object is valid.
+ bool SetupFrameBufferObject(GLenum target);
+
+ // The OpenGL context, and pbuffer drawable, used to transfer data
+ // to the shared region (IOSurface or TransportDIB). Strictly
+ // speaking, we do not need to allocate a GL context all of the
+ // time. We only need one if (a) we are using the IOSurface code
+ // path, or (b) if we are allocating an FBO internally.
+ scoped_ptr<gfx::GLContext> gl_context_;
+ // Either |io_surface_| or |transport_dib_| is a valid pointer, but not both.
+ // |io_surface_| is non-NULL if the IOSurface APIs are supported (Mac OS X
+ // 10.6 and later).
+ // TODO(dspringer,kbr): Should the GPU backing store be encapsulated in its
+ // own class so all this implementation detail is hidden?
+ base::mac::ScopedCFTypeRef<CFTypeRef> io_surface_;
+
+ // The id of |io_surface_| or 0 if that's NULL.
+ uint64 io_surface_id_;
+
+ // TODO(dspringer): If we end up keeping this TransportDIB mechanism, this
+ // should really be a scoped_ptr_malloc<>, with a deallocate functor that
+ // runs |dib_free_callback_|. I was not able to figure out how to
+ // make this work (or even compile).
+ scoped_ptr<TransportDIB> transport_dib_;
+ gfx::Size surface_size_;
+ // TODO(kbr): the FBO management should not be in this class at all.
+ // However, if it is factored out, care needs to be taken to not
+ // introduce another copy of the color data on the GPU; the direct
+ // binding of the internal texture to the IOSurface saves a copy.
+ bool allocate_fbo_;
+ // If the IOSurface code path is being used, then this texture
+ // object is always allocated. Otherwise, it is only allocated if
+ // the user requests an FBO be allocated.
+ GLuint texture_;
+ // The FBO and renderbuffer are only allocated if allocate_fbo_ is
+ // true.
+ GLuint fbo_;
+ GLuint depth_stencil_renderbuffer_;
+ // Allocate a TransportDIB in the renderer.
+ scoped_ptr<Callback2<size_t, TransportDIB::Handle*>::Type>
+ dib_alloc_callback_;
+ scoped_ptr<Callback1<TransportDIB::Id>::Type> dib_free_callback_;
+};
+
+#endif // UI_GFX_SURFACE_ACCELERATED_SURFACE_MAC_H_
diff --git a/ui/gfx/surface/io_surface_support_mac.cc b/ui/gfx/surface/io_surface_support_mac.cc
new file mode 100644
index 0000000..15e33dc
--- /dev/null
+++ b/ui/gfx/surface/io_surface_support_mac.cc
@@ -0,0 +1,270 @@
+// 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 <dlfcn.h>
+
+#include "base/singleton.h"
+#include "ui/gfx/surface/io_surface_support_mac.h"
+
+typedef CFTypeRef (*IOSurfaceCreateProcPtr)(CFDictionaryRef properties);
+typedef uint32 (*IOSurfaceGetIDProcPtr)(CFTypeRef io_surface);
+typedef CFTypeRef (*IOSurfaceLookupProcPtr)(uint32 io_surface_id);
+typedef mach_port_t (*IOSurfaceCreateMachPortProcPtr)(CFTypeRef io_surface);
+typedef CFTypeRef (*IOSurfaceLookupFromMachPortProcPtr)(mach_port_t port);
+typedef size_t (*IOSurfaceGetWidthPtr)(CFTypeRef io_surface);
+typedef size_t (*IOSurfaceGetHeightPtr)(CFTypeRef io_surface);
+typedef CGLError (*CGLTexImageIOSurface2DProcPtr)(CGLContextObj ctx,
+ GLenum target,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ CFTypeRef io_surface,
+ GLuint plane);
+
+class IOSurfaceSupportImpl : public IOSurfaceSupport {
+ public:
+ static IOSurfaceSupportImpl* GetInstance();
+
+ bool InitializedSuccessfully() {
+ return initialized_successfully_;
+ }
+
+ virtual CFStringRef GetKIOSurfaceWidth();
+ virtual CFStringRef GetKIOSurfaceHeight();
+ virtual CFStringRef GetKIOSurfaceBytesPerElement();
+ virtual CFStringRef GetKIOSurfaceIsGlobal();
+
+ virtual CFTypeRef IOSurfaceCreate(CFDictionaryRef properties);
+ virtual uint32 IOSurfaceGetID(CFTypeRef io_surface);
+ virtual CFTypeRef IOSurfaceLookup(uint32 io_surface_id);
+ virtual mach_port_t IOSurfaceCreateMachPort(CFTypeRef io_surface);
+ virtual CFTypeRef IOSurfaceLookupFromMachPort(mach_port_t port);
+
+ virtual size_t IOSurfaceGetWidth(CFTypeRef io_surface);
+ virtual size_t IOSurfaceGetHeight(CFTypeRef io_surface);
+
+ virtual CGLError CGLTexImageIOSurface2D(CGLContextObj ctx,
+ GLenum target,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ CFTypeRef io_surface,
+ GLuint plane);
+
+ private:
+ IOSurfaceSupportImpl();
+ ~IOSurfaceSupportImpl();
+
+ void* iosurface_handle_;
+ void* opengl_handle_;
+ CFStringRef k_io_surface_width_;
+ CFStringRef k_io_surface_height_;
+ CFStringRef k_io_surface_bytes_per_element_;
+ CFStringRef k_io_surface_is_global_;
+ IOSurfaceCreateProcPtr io_surface_create_;
+ IOSurfaceGetIDProcPtr io_surface_get_id_;
+ IOSurfaceLookupProcPtr io_surface_lookup_;
+ IOSurfaceCreateMachPortProcPtr io_surface_create_mach_port_;
+ IOSurfaceLookupFromMachPortProcPtr io_surface_lookup_from_mach_port_;
+ IOSurfaceGetWidthPtr io_surface_get_width_;
+ IOSurfaceGetHeightPtr io_surface_get_height_;
+ CGLTexImageIOSurface2DProcPtr cgl_tex_image_io_surface_2d_;
+ bool initialized_successfully_;
+
+ friend struct DefaultSingletonTraits<IOSurfaceSupportImpl>;
+ DISALLOW_COPY_AND_ASSIGN(IOSurfaceSupportImpl);
+};
+
+IOSurfaceSupportImpl* IOSurfaceSupportImpl::GetInstance() {
+ IOSurfaceSupportImpl* impl = Singleton<IOSurfaceSupportImpl>::get();
+ if (impl->InitializedSuccessfully())
+ return impl;
+ return NULL;
+}
+
+CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceWidth() {
+ return k_io_surface_width_;
+}
+
+CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceHeight() {
+ return k_io_surface_height_;
+}
+
+CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceBytesPerElement() {
+ return k_io_surface_bytes_per_element_;
+}
+
+CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceIsGlobal() {
+ return k_io_surface_is_global_;
+}
+
+CFTypeRef IOSurfaceSupportImpl::IOSurfaceCreate(CFDictionaryRef properties) {
+ return io_surface_create_(properties);
+}
+
+uint32 IOSurfaceSupportImpl::IOSurfaceGetID(
+ CFTypeRef io_surface) {
+ return io_surface_get_id_(io_surface);
+}
+
+CFTypeRef IOSurfaceSupportImpl::IOSurfaceLookup(uint32 io_surface_id) {
+ return io_surface_lookup_(io_surface_id);
+}
+
+mach_port_t IOSurfaceSupportImpl::IOSurfaceCreateMachPort(
+ CFTypeRef io_surface) {
+ return io_surface_create_mach_port_(io_surface);
+}
+
+CFTypeRef IOSurfaceSupportImpl::IOSurfaceLookupFromMachPort(mach_port_t port) {
+ return io_surface_lookup_from_mach_port_(port);
+}
+
+size_t IOSurfaceSupportImpl::IOSurfaceGetWidth(CFTypeRef io_surface) {
+ return io_surface_get_width_(io_surface);
+}
+
+size_t IOSurfaceSupportImpl::IOSurfaceGetHeight(CFTypeRef io_surface) {
+ return io_surface_get_height_(io_surface);
+}
+
+
+CGLError IOSurfaceSupportImpl::CGLTexImageIOSurface2D(CGLContextObj ctx,
+ GLenum target,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ CFTypeRef io_surface,
+ GLuint plane) {
+ return cgl_tex_image_io_surface_2d_(ctx,
+ target,
+ internal_format,
+ width,
+ height,
+ format,
+ type,
+ io_surface,
+ plane);
+}
+
+IOSurfaceSupportImpl::IOSurfaceSupportImpl()
+ : iosurface_handle_(NULL),
+ opengl_handle_(NULL),
+ k_io_surface_width_(NULL),
+ k_io_surface_height_(NULL),
+ k_io_surface_bytes_per_element_(NULL),
+ k_io_surface_is_global_(NULL),
+ io_surface_create_(NULL),
+ io_surface_get_id_(NULL),
+ io_surface_lookup_(NULL),
+ io_surface_create_mach_port_(NULL),
+ io_surface_lookup_from_mach_port_(NULL),
+ io_surface_get_width_(NULL),
+ io_surface_get_height_(NULL),
+ cgl_tex_image_io_surface_2d_(NULL),
+ initialized_successfully_(false) {
+ iosurface_handle_ = dlopen(
+ "/System/Library/Frameworks/IOSurface.framework/IOSurface",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (!iosurface_handle_)
+ return;
+ opengl_handle_ = dlopen(
+ "/System/Library/Frameworks/OpenGL.framework/OpenGL",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (!opengl_handle_) {
+ dlclose(iosurface_handle_);
+ iosurface_handle_ = NULL;
+ return;
+ }
+
+ void* surface_width_ptr = dlsym(iosurface_handle_, "kIOSurfaceWidth");
+ void* surface_height_ptr = dlsym(iosurface_handle_, "kIOSurfaceHeight");
+ void* surface_bytes_per_element_ptr =
+ dlsym(iosurface_handle_, "kIOSurfaceBytesPerElement");
+ void* surface_is_global_ptr =
+ dlsym(iosurface_handle_, "kIOSurfaceIsGlobal");
+ void* surface_create_ptr = dlsym(iosurface_handle_, "IOSurfaceCreate");
+ void* surface_get_id_ptr = dlsym(iosurface_handle_, "IOSurfaceGetID");
+ void* surface_lookup_ptr = dlsym(iosurface_handle_, "IOSurfaceLookup");
+ void* surface_create_mach_port_ptr =
+ dlsym(iosurface_handle_, "IOSurfaceCreateMachPort");
+ void* surface_lookup_from_mach_port_ptr =
+ dlsym(iosurface_handle_, "IOSurfaceLookupFromMachPort");
+ void* io_surface_get_width_ptr =
+ dlsym(iosurface_handle_, "IOSurfaceGetWidth");
+ void* io_surface_get_height_ptr =
+ dlsym(iosurface_handle_, "IOSurfaceGetHeight");
+ void* tex_image_io_surface_2d_ptr =
+ dlsym(opengl_handle_, "CGLTexImageIOSurface2D");
+ if (!surface_width_ptr ||
+ !surface_height_ptr ||
+ !surface_bytes_per_element_ptr ||
+ !surface_is_global_ptr ||
+ !surface_create_ptr ||
+ !surface_get_id_ptr ||
+ !surface_lookup_ptr ||
+ !surface_create_mach_port_ptr ||
+ !surface_lookup_from_mach_port_ptr ||
+ !io_surface_get_width_ptr ||
+ !io_surface_get_height_ptr ||
+ !tex_image_io_surface_2d_ptr) {
+ dlclose(iosurface_handle_);
+ iosurface_handle_ = NULL;
+ dlclose(opengl_handle_);
+ opengl_handle_ = NULL;
+ return;
+ }
+
+ k_io_surface_width_ = *static_cast<CFStringRef*>(surface_width_ptr);
+ k_io_surface_height_ = *static_cast<CFStringRef*>(surface_height_ptr);
+ k_io_surface_bytes_per_element_ =
+ *static_cast<CFStringRef*>(surface_bytes_per_element_ptr);
+ k_io_surface_is_global_ = *static_cast<CFStringRef*>(surface_is_global_ptr);
+ io_surface_create_ = reinterpret_cast<IOSurfaceCreateProcPtr>(
+ surface_create_ptr);
+ io_surface_get_id_ =
+ reinterpret_cast<IOSurfaceGetIDProcPtr>(surface_get_id_ptr);
+ io_surface_lookup_ =
+ reinterpret_cast<IOSurfaceLookupProcPtr>(surface_lookup_ptr);
+ io_surface_create_mach_port_ =
+ reinterpret_cast<IOSurfaceCreateMachPortProcPtr>(
+ surface_create_mach_port_ptr);
+ io_surface_lookup_from_mach_port_ =
+ reinterpret_cast<IOSurfaceLookupFromMachPortProcPtr>(
+ surface_lookup_from_mach_port_ptr);
+ io_surface_get_width_ =
+ reinterpret_cast<IOSurfaceGetWidthPtr>(
+ io_surface_get_width_ptr);
+ io_surface_get_height_ =
+ reinterpret_cast<IOSurfaceGetHeightPtr>(
+ io_surface_get_height_ptr);
+ cgl_tex_image_io_surface_2d_ =
+ reinterpret_cast<CGLTexImageIOSurface2DProcPtr>(
+ tex_image_io_surface_2d_ptr);
+ initialized_successfully_ = true;
+}
+
+IOSurfaceSupportImpl::~IOSurfaceSupportImpl() {
+ if (iosurface_handle_)
+ dlclose(iosurface_handle_);
+ if (opengl_handle_)
+ dlclose(opengl_handle_);
+}
+
+IOSurfaceSupport* IOSurfaceSupport::Initialize() {
+ return IOSurfaceSupportImpl::GetInstance();
+}
+
+IOSurfaceSupport::IOSurfaceSupport() {
+}
+
+IOSurfaceSupport::~IOSurfaceSupport() {
+}
+
diff --git a/ui/gfx/surface/io_surface_support_mac.h b/ui/gfx/surface/io_surface_support_mac.h
new file mode 100644
index 0000000..e8d01b9
--- /dev/null
+++ b/ui/gfx/surface/io_surface_support_mac.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2010 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.
+
+#ifndef UI_GFX_SURFACE_IO_SURFACE_SUPPORT_MAC_H_
+#define UI_GFX_SURFACE_IO_SURFACE_SUPPORT_MAC_H_
+#pragma once
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <mach/mach.h>
+#include <OpenGL/OpenGL.h>
+
+#include "base/basictypes.h"
+
+// This Mac OS X-specific class provides dynamically-linked access to
+// IOSurface.framework, which is only available on 10.6 and later.
+// Since Chromium is built on 10.5 we must dynamically look up all of
+// the entry points we need in this framework.
+
+// See IOSurface/IOSurfaceAPI.h and OpenGL/CGLIOSurface.h on 10.6 for
+// documentation of the fields and methods of this class.
+
+class IOSurfaceSupport {
+ public:
+ // Returns an instance of the IOSurfaceSupport class if the
+ // operating system supports it, NULL otherwise. It is safe to call
+ // this multiple times.
+ static IOSurfaceSupport* Initialize();
+
+ virtual CFStringRef GetKIOSurfaceWidth() = 0;
+ virtual CFStringRef GetKIOSurfaceHeight() = 0;
+ virtual CFStringRef GetKIOSurfaceBytesPerElement() = 0;
+ virtual CFStringRef GetKIOSurfaceIsGlobal() = 0;
+
+ virtual CFTypeRef IOSurfaceCreate(CFDictionaryRef properties) = 0;
+
+ // The following two APIs assume the IOSurface was created with the
+ // kIOSurfaceIsGlobal key set to true
+ virtual uint32 IOSurfaceGetID(CFTypeRef io_surface) = 0;
+ virtual CFTypeRef IOSurfaceLookup(uint32 io_surface_id) = 0;
+
+ // The following two APIs are more robust and secure, but
+ // unfortunately it looks like it will be a lot of work to correctly
+ // transmit a mach port from process to process (possibly requiring
+ // a side channel for or extension of the Chrome IPC mechanism)
+ virtual mach_port_t IOSurfaceCreateMachPort(CFTypeRef io_surface) = 0;
+ virtual CFTypeRef IOSurfaceLookupFromMachPort(mach_port_t port) = 0;
+
+ virtual size_t IOSurfaceGetWidth(CFTypeRef io_surface) = 0;
+ virtual size_t IOSurfaceGetHeight(CFTypeRef io_surface) = 0;
+
+ virtual CGLError CGLTexImageIOSurface2D(CGLContextObj ctx,
+ GLenum target,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ CFTypeRef io_surface,
+ GLuint plane) = 0;
+
+ protected:
+ IOSurfaceSupport();
+ virtual ~IOSurfaceSupport();
+
+ DISALLOW_COPY_AND_ASSIGN(IOSurfaceSupport);
+};
+
+#endif // UI_GFX_SURFACE_IO_SURFACE_SUPPORT_MAC_H_
+
diff --git a/ui/gfx/surface/surface.gyp b/ui/gfx/surface/surface.gyp
new file mode 100644
index 0000000..c7d1dca
--- /dev/null
+++ b/ui/gfx/surface/surface.gyp
@@ -0,0 +1,57 @@
+# 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.
+
+{
+ 'target_defaults': {
+ 'sources/': [
+ ['exclude', '/(cocoa|gtk|win)/'],
+ ['exclude', '_(cocoa|gtk|linux|mac|posix|win|x)\\.(cc|mm?)$'],
+ ['exclude', '/(gtk|win|x11)_[^/]*\\.cc$'],
+ ],
+ 'conditions': [
+ ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', {'sources/': [
+ ['include', '/gtk/'],
+ ['include', '_(gtk|linux|posix|skia|x)\\.cc$'],
+ ['include', '/(gtk|x11)_[^/]*\\.cc$'],
+ ]}],
+ ['OS=="mac"', {'sources/': [
+ ['include', '/cocoa/'],
+ ['include', '_(cocoa|mac|posix)\\.(cc|mm?)$'],
+ ]}, { # else: OS != "mac"
+ 'sources/': [
+ ['exclude', '\\.mm?$'],
+ ],
+ }],
+ ['OS=="win"',
+ {'sources/': [
+ ['include', '_(win)\\.cc$'],
+ ['include', '/win/'],
+ ['include', '/win_[^/]*\\.cc$'],
+ ]}],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'surface',
+ 'type': '<(library)',
+ 'msvs_guid': '6C99567D-6F02-43B5-BB35-D8E3F8D0D6D2',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/app/app.gyp:app_base',
+ '<(DEPTH)/skia/skia.gyp:skia',
+ '<(DEPTH)/ui/ui.gyp:ui_gfx',
+ ],
+ 'sources': [
+ 'accelerated_surface_mac.cc',
+ 'accelerated_surface_mac.h',
+ 'io_surface_support_mac.cc',
+ 'io_surface_support_mac.h',
+ 'transport_dib.h',
+ 'transport_dib_linux.cc',
+ 'transport_dib_mac.cc',
+ 'transport_dib_win.cc',
+ ],
+ },
+ ],
+}
diff --git a/ui/gfx/surface/transport_dib.h b/ui/gfx/surface/transport_dib.h
new file mode 100644
index 0000000..1834eec
--- /dev/null
+++ b/ui/gfx/surface/transport_dib.h
@@ -0,0 +1,202 @@
+// Copyright (c) 2010 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.
+
+#ifndef UI_GFX_SURFACE_TRANSPORT_DIB_H_
+#define UI_GFX_SURFACE_TRANSPORT_DIB_H_
+#pragma once
+
+#include "base/basictypes.h"
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#include "base/shared_memory.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(USE_X11)
+#include "ui/base/x/x11_util.h"
+#endif
+
+namespace skia {
+class PlatformCanvas;
+}
+
+// -----------------------------------------------------------------------------
+// A TransportDIB is a block of memory that is used to transport pixels
+// between processes: from the renderer process to the browser, and
+// between renderer and plugin processes.
+// -----------------------------------------------------------------------------
+class TransportDIB {
+ public:
+ ~TransportDIB();
+
+ // Two typedefs are defined. A Handle is the type which can be sent over
+ // the wire so that the remote side can map the transport DIB. The Id typedef
+ // is sufficient to identify the transport DIB when you know that the remote
+ // side already may have it mapped.
+#if defined(OS_WIN)
+ typedef HANDLE Handle;
+ // On Windows, the Id type includes a sequence number (epoch) to solve an ABA
+ // issue:
+ // 1) Process A creates a transport DIB with HANDLE=1 and sends to B.
+ // 2) Process B maps the transport DIB and caches 1 -> DIB.
+ // 3) Process A closes the transport DIB and creates a new one. The new DIB
+ // is also assigned HANDLE=1.
+ // 4) Process A sends the Handle to B, but B incorrectly believes that it
+ // already has it cached.
+ struct HandleAndSequenceNum {
+ HandleAndSequenceNum()
+ : handle(NULL),
+ sequence_num(0) {
+ }
+
+ HandleAndSequenceNum(HANDLE h, uint32 seq_num)
+ : handle(h),
+ sequence_num(seq_num) {
+ }
+
+ bool operator<(const HandleAndSequenceNum& other) const {
+ // Use the lexicographic order on the tuple <handle, sequence_num>.
+ if (other.handle != handle)
+ return other.handle < handle;
+ return other.sequence_num < sequence_num;
+ }
+
+ HANDLE handle;
+ uint32 sequence_num;
+ };
+ typedef HandleAndSequenceNum Id;
+
+ // Returns a default, invalid handle, that is meant to indicate a missing
+ // Transport DIB.
+ static Handle DefaultHandleValue() { return NULL; }
+
+ // Returns a value that is ONLY USEFUL FOR TESTS WHERE IT WON'T BE
+ // ACTUALLY USED AS A REAL HANDLE.
+ static Handle GetFakeHandleForTest() {
+ static int fake_handle = 10;
+ return reinterpret_cast<Handle>(fake_handle++);
+ }
+#elif defined(OS_MACOSX)
+ typedef base::SharedMemoryHandle Handle;
+ // On Mac, the inode number of the backing file is used as an id.
+ typedef base::SharedMemoryId Id;
+
+ // Returns a default, invalid handle, that is meant to indicate a missing
+ // Transport DIB.
+ static Handle DefaultHandleValue() { return Handle(); }
+
+ // Returns a value that is ONLY USEFUL FOR TESTS WHERE IT WON'T BE
+ // ACTUALLY USED AS A REAL HANDLE.
+ static Handle GetFakeHandleForTest() {
+ static int fake_handle = 10;
+ return Handle(fake_handle++, false);
+ }
+#elif defined(USE_X11)
+ typedef int Handle; // These two ints are SysV IPC shared memory keys
+ struct Id {
+ // Ensure that default initialized Ids are invalid.
+ Id() : shmkey(-1) {
+ }
+
+ bool operator<(const Id& other) const {
+ return shmkey < other.shmkey;
+ }
+
+ int shmkey;
+ };
+
+ // Returns a default, invalid handle, that is meant to indicate a missing
+ // Transport DIB.
+ static Handle DefaultHandleValue() { return -1; }
+
+ // Returns a value that is ONLY USEFUL FOR TESTS WHERE IT WON'T BE
+ // ACTUALLY USED AS A REAL HANDLE.
+ static Handle GetFakeHandleForTest() {
+ static int fake_handle = 10;
+ return fake_handle++;
+ }
+#endif
+
+ // Create a new TransportDIB, returning NULL on failure.
+ //
+ // The size is the minimum size in bytes of the memory backing the transport
+ // DIB (we may actually allocate more than that to give us better reuse when
+ // cached).
+ //
+ // The sequence number is used to uniquely identify the transport DIB. It
+ // should be unique for all transport DIBs ever created in the same
+ // renderer.
+ static TransportDIB* Create(size_t size, uint32 sequence_num);
+
+ // Map the referenced transport DIB. The caller owns the returned object.
+ // Returns NULL on failure.
+ static TransportDIB* Map(Handle transport_dib);
+
+ // Create a new |TransportDIB| with a handle to the shared memory. This
+ // always returns a valid pointer. The DIB is not mapped.
+ static TransportDIB* CreateWithHandle(Handle handle);
+
+ // Returns true if the handle is valid.
+ static bool is_valid_handle(Handle dib);
+
+ // Returns true if the ID refers to a valid dib.
+ static bool is_valid_id(Id id);
+
+ // Returns a canvas using the memory of this TransportDIB. The returned
+ // pointer will be owned by the caller. The bitmap will be of the given size,
+ // which should fit inside this memory.
+ //
+ // On POSIX, this |TransportDIB| will be mapped if not already. On Windows,
+ // this |TransportDIB| will NOT be mapped and should not be mapped prior,
+ // because PlatformCanvas will map the file internally.
+ //
+ // Will return NULL on allocation failure. This could be because the image
+ // is too large to map into the current process' address space.
+ skia::PlatformCanvas* GetPlatformCanvas(int w, int h);
+
+ // Map the DIB into the current process if it is not already. This is used to
+ // map a DIB that has already been created. Returns true if the DIB is mapped.
+ bool Map();
+
+ // Return a pointer to the shared memory.
+ void* memory() const;
+
+ // Return the maximum size of the shared memory. This is not the amount of
+ // data which is valid, you have to know that via other means, this is simply
+ // the maximum amount that /could/ be valid.
+ size_t size() const { return size_; }
+
+ // Return the identifier which can be used to refer to this shared memory
+ // on the wire.
+ Id id() const;
+
+ // Return a handle to the underlying shared memory. This can be sent over the
+ // wire to give this transport DIB to another process.
+ Handle handle() const;
+
+#if defined(USE_X11)
+ // Map the shared memory into the X server and return an id for the shared
+ // segment.
+ XID MapToX(Display* connection);
+#endif
+
+ private:
+ TransportDIB();
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ explicit TransportDIB(base::SharedMemoryHandle dib);
+ base::SharedMemory shared_memory_;
+ uint32 sequence_num_;
+#elif defined(USE_X11)
+ Id key_; // SysV shared memory id
+ void* address_; // mapped address
+ XSharedMemoryId x_shm_; // X id for the shared segment
+ Display* display_; // connection to the X server
+#endif
+ size_t size_; // length, in bytes
+
+ DISALLOW_COPY_AND_ASSIGN(TransportDIB);
+};
+
+#endif // UI_GFX_SURFACE_TRANSPORT_DIB_H_
diff --git a/ui/gfx/surface/transport_dib_linux.cc b/ui/gfx/surface/transport_dib_linux.cc
new file mode 100644
index 0000000..3e31c7b
--- /dev/null
+++ b/ui/gfx/surface/transport_dib_linux.cc
@@ -0,0 +1,141 @@
+// 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 "ui/gfx/surface/transport_dib.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "skia/ext/platform_canvas.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/size.h"
+
+// The shmat system call uses this as it's invalid return address
+static void *const kInvalidAddress = (void*) -1;
+
+TransportDIB::TransportDIB()
+ : address_(kInvalidAddress),
+ x_shm_(0),
+ display_(NULL),
+ size_(0) {
+}
+
+TransportDIB::~TransportDIB() {
+ if (address_ != kInvalidAddress) {
+ shmdt(address_);
+ address_ = kInvalidAddress;
+ }
+
+ if (x_shm_) {
+ DCHECK(display_);
+ ui::DetachSharedMemory(display_, x_shm_);
+ }
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
+ // We use a mode of 0666 since the X server won't attach to memory which is
+ // 0600 since it can't know if it (as a root process) is being asked to map
+ // someone else's private shared memory region.
+ const int shmkey = shmget(IPC_PRIVATE, size, 0666);
+ if (shmkey == -1) {
+ DLOG(ERROR) << "Failed to create SysV shared memory region"
+ << " errno:" << errno;
+ return NULL;
+ }
+
+ void* address = shmat(shmkey, NULL /* desired address */, 0 /* flags */);
+ // Here we mark the shared memory for deletion. Since we attached it in the
+ // line above, it doesn't actually get deleted but, if we crash, this means
+ // that the kernel will automatically clean it up for us.
+ shmctl(shmkey, IPC_RMID, 0);
+ if (address == kInvalidAddress)
+ return NULL;
+
+ TransportDIB* dib = new TransportDIB;
+
+ dib->key_.shmkey = shmkey;
+ dib->address_ = address;
+ dib->size_ = size;
+ return dib;
+}
+
+// static
+TransportDIB* TransportDIB::Map(Handle handle) {
+ scoped_ptr<TransportDIB> dib(CreateWithHandle(handle));
+ if (!dib->Map())
+ return NULL;
+ return dib.release();
+}
+
+// static
+TransportDIB* TransportDIB::CreateWithHandle(Handle shmkey) {
+ TransportDIB* dib = new TransportDIB;
+ dib->key_.shmkey = shmkey;
+ return dib;
+}
+
+// static
+bool TransportDIB::is_valid_handle(Handle dib) {
+ return dib >= 0;
+}
+
+// static
+bool TransportDIB::is_valid_id(Id id) {
+ return id.shmkey != -1;
+}
+
+skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
+ if (address_ == kInvalidAddress && !Map())
+ return NULL;
+ scoped_ptr<skia::PlatformCanvas> canvas(new skia::PlatformCanvas);
+ if (!canvas->initialize(w, h, true, reinterpret_cast<uint8_t*>(memory())))
+ return NULL;
+ return canvas.release();
+}
+
+bool TransportDIB::Map() {
+ if (!is_valid_id(key_))
+ return false;
+ if (address_ != kInvalidAddress)
+ return true;
+
+ struct shmid_ds shmst;
+ if (shmctl(key_.shmkey, IPC_STAT, &shmst) == -1)
+ return false;
+
+ void* address = shmat(key_.shmkey, NULL /* desired address */, 0 /* flags */);
+ if (address == kInvalidAddress)
+ return false;
+
+ address_ = address;
+ size_ = shmst.shm_segsz;
+ return true;
+}
+
+void* TransportDIB::memory() const {
+ DCHECK_NE(address_, kInvalidAddress);
+ return address_;
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return key_;
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return key_.shmkey;
+}
+
+XID TransportDIB::MapToX(Display* display) {
+ if (!x_shm_) {
+ x_shm_ = ui::AttachSharedMemory(display, key_.shmkey);
+ display_ = display;
+ }
+
+ return x_shm_;
+}
diff --git a/ui/gfx/surface/transport_dib_mac.cc b/ui/gfx/surface/transport_dib_mac.cc
new file mode 100644
index 0000000..268bce1
--- /dev/null
+++ b/ui/gfx/surface/transport_dib_mac.cc
@@ -0,0 +1,98 @@
+// 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 "ui/gfx/surface/transport_dib.h"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/shared_memory.h"
+#include "skia/ext/platform_canvas.h"
+
+TransportDIB::TransportDIB()
+ : size_(0) {
+}
+
+TransportDIB::TransportDIB(TransportDIB::Handle dib)
+ : shared_memory_(dib, false /* read write */),
+ size_(0) {
+}
+
+TransportDIB::~TransportDIB() {
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
+ TransportDIB* dib = new TransportDIB;
+ if (!dib->shared_memory_.CreateAndMapAnonymous(size)) {
+ delete dib;
+ return NULL;
+ }
+
+ dib->size_ = size;
+ return dib;
+}
+
+// static
+TransportDIB* TransportDIB::Map(Handle handle) {
+ scoped_ptr<TransportDIB> dib(CreateWithHandle(handle));
+ if (!dib->Map())
+ return NULL;
+ return dib.release();
+}
+
+// static
+TransportDIB* TransportDIB::CreateWithHandle(Handle handle) {
+ return new TransportDIB(handle);
+}
+
+// static
+bool TransportDIB::is_valid_handle(Handle dib) {
+ return dib.fd >= 0;
+}
+
+// static
+bool TransportDIB::is_valid_id(Id id) {
+ return id != 0;
+}
+
+skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
+ if (!memory() && !Map())
+ return NULL;
+ scoped_ptr<skia::PlatformCanvas> canvas(new skia::PlatformCanvas);
+ if (!canvas->initialize(w, h, true, reinterpret_cast<uint8_t*>(memory())))
+ return NULL;
+ return canvas.release();
+}
+
+bool TransportDIB::Map() {
+ if (!is_valid_handle(handle()))
+ return false;
+ if (memory())
+ return true;
+
+ struct stat st;
+ if ((fstat(shared_memory_.handle().fd, &st) != 0) ||
+ (!shared_memory_.Map(st.st_size))) {
+ return false;
+ }
+
+ size_ = st.st_size;
+ return true;
+}
+
+void* TransportDIB::memory() const {
+ return shared_memory_.memory();
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return shared_memory_.id();
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return shared_memory_.handle();
+}
diff --git a/ui/gfx/surface/transport_dib_win.cc b/ui/gfx/surface/transport_dib_win.cc
new file mode 100644
index 0000000..977153f
--- /dev/null
+++ b/ui/gfx/surface/transport_dib_win.cc
@@ -0,0 +1,110 @@
+// 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 "ui/gfx/surface/transport_dib.h"
+
+#include <windows.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/sys_info.h"
+#include "skia/ext/platform_canvas.h"
+
+TransportDIB::TransportDIB() {
+}
+
+TransportDIB::~TransportDIB() {
+}
+
+TransportDIB::TransportDIB(HANDLE handle)
+ : shared_memory_(handle, false /* read write */) {
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
+ size_t allocation_granularity = base::SysInfo::VMAllocationGranularity();
+ size = size / allocation_granularity + 1;
+ size = size * allocation_granularity;
+
+ TransportDIB* dib = new TransportDIB;
+
+ if (!dib->shared_memory_.CreateAnonymous(size)) {
+ delete dib;
+ return NULL;
+ }
+
+ dib->size_ = size;
+ dib->sequence_num_ = sequence_num;
+
+ return dib;
+}
+
+// static
+TransportDIB* TransportDIB::Map(Handle handle) {
+ scoped_ptr<TransportDIB> dib(CreateWithHandle(handle));
+ if (!dib->Map())
+ return NULL;
+ return dib.release();
+}
+
+// static
+TransportDIB* TransportDIB::CreateWithHandle(Handle handle) {
+ return new TransportDIB(handle);
+}
+
+// static
+bool TransportDIB::is_valid_handle(Handle dib) {
+ return dib != NULL;
+}
+
+// static
+bool TransportDIB::is_valid_id(TransportDIB::Id id) {
+ return is_valid_handle(id.handle);
+}
+
+skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
+ // This DIB already mapped the file into this process, but PlatformCanvas
+ // will map it again.
+ DCHECK(!memory()) << "Mapped file twice in the same process.";
+
+ scoped_ptr<skia::PlatformCanvas> canvas(new skia::PlatformCanvas);
+ if (!canvas->initialize(w, h, true, handle()))
+ return NULL;
+ return canvas.release();
+}
+
+bool TransportDIB::Map() {
+ if (!is_valid_handle(handle()))
+ return false;
+ if (memory())
+ return true;
+
+ if (!shared_memory_.Map(0 /* map whole shared memory segment */)) {
+ LOG(ERROR) << "Failed to map transport DIB"
+ << " handle:" << shared_memory_.handle()
+ << " error:" << ::GetLastError();
+ return false;
+ }
+
+ // There doesn't seem to be any way to find the size of the shared memory
+ // region! GetFileSize indicates that the handle is invalid. Thus, we
+ // conservatively set the size to the maximum and hope that the renderer
+ // isn't about to ask us to read off the end of the array.
+ size_ = std::numeric_limits<size_t>::max();
+ return true;
+}
+
+void* TransportDIB::memory() const {
+ return shared_memory_.memory();
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return shared_memory_.handle();
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return Id(handle(), sequence_num_);
+}