summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm7
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/common/accelerated_surface_mac.cc334
-rw-r--r--chrome/common/accelerated_surface_mac.h108
-rw-r--r--chrome/common/plugin_messages_internal.h6
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h2
-rw-r--r--chrome/plugin/webplugin_proxy.cc22
-rw-r--r--chrome/plugin/webplugin_proxy.h9
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc29
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h8
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc346
-rw-r--r--webkit/glue/plugins/plugin_host.cc42
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h39
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_mac.mm93
-rw-r--r--webkit/glue/webplugin.h20
-rw-r--r--webkit/tools/test_shell/mac/accelerated_surface_stub.cc52
-rw-r--r--webkit/tools/test_shell/test_shell.gypi1
-rw-r--r--webkit/webkit.gyp5
18 files changed, 766 insertions, 359 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index 079cecd..0d20f6b 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -83,6 +83,10 @@ const size_t kMaxTooltipLength = 1024;
forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp *)timeStamp {
renderWidgetHostView_->DrawGPUPluginInstances(glContext);
+ [super drawInCGLContext:glContext
+ pixelFormat:pixelFormat
+ forLayerTime:timeInterval
+ displayTime:timeStamp];
}
@end
@@ -579,6 +583,7 @@ void RenderWidgetHostViewMac::DrawGPUPluginInstances(CGLContextObj context) {
glOrtho(0, rect.width(), rect.height(), 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
+
plugin_container_manager_.Draw(context);
}
@@ -1469,7 +1474,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// TODO(hbono): Even though many input method works without implementing
// this method, we need to save a copy of the string in the setMarkedText
// method and create a NSAttributedString with the given range.
- NOTIMPLEMENTED();
+ // http://crbug.com/37715
return nil;
}
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 934e097..4fb4c85 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -23,6 +23,8 @@
# .cc, .h, and .mm files under chrome/common that are used on all
# platforms, including both 32-bit and 64-bit Windows.
# Test files are not included.
+ 'common/accelerated_surface_mac.cc',
+ 'common/accelerated_surface_mac.h',
'common/app_mode_constants_mac.h',
'common/app_mode_constants_mac.mm',
'common/bindings_policy.h',
diff --git a/chrome/common/accelerated_surface_mac.cc b/chrome/common/accelerated_surface_mac.cc
new file mode 100644
index 0000000..d12ecb6
--- /dev/null
+++ b/chrome/common/accelerated_surface_mac.cc
@@ -0,0 +1,334 @@
+// 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.
+
+#include "chrome/common/accelerated_surface_mac.h"
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "chrome/common/io_surface_support_mac.h"
+
+AcceleratedSurface::AcceleratedSurface()
+ : gl_context_(NULL),
+ pbuffer_(NULL),
+ surface_width_(0),
+ surface_height_(0),
+ texture_(0),
+ fbo_(0),
+ depth_stencil_renderbuffer_(0),
+ bound_fbo_(0),
+ bound_renderbuffer_(0) {
+}
+
+bool AcceleratedSurface::Initialize() {
+ // Create a 1x1 pbuffer and associated context to bootstrap things
+ static const CGLPixelFormatAttribute attribs[] = {
+ (CGLPixelFormatAttribute) kCGLPFAPBuffer,
+ (CGLPixelFormatAttribute) 0
+ };
+ CGLPixelFormatObj pixel_format;
+ GLint num_pixel_formats;
+ if (CGLChoosePixelFormat(attribs,
+ &pixel_format,
+ &num_pixel_formats) != kCGLNoError) {
+ DLOG(ERROR) << "Error choosing pixel format.";
+ return false;
+ }
+ if (!pixel_format) {
+ return false;
+ }
+ CGLContextObj context;
+ CGLError res = CGLCreateContext(pixel_format, 0, &context);
+ CGLDestroyPixelFormat(pixel_format);
+ if (res != kCGLNoError) {
+ DLOG(ERROR) << "Error creating context.";
+ return false;
+ }
+ CGLPBufferObj pbuffer;
+ if (CGLCreatePBuffer(1, 1,
+ GL_TEXTURE_2D, GL_RGBA,
+ 0, &pbuffer) != kCGLNoError) {
+ CGLDestroyContext(context);
+ DLOG(ERROR) << "Error creating pbuffer.";
+ return false;
+ }
+ if (CGLSetPBuffer(context, pbuffer, 0, 0, 0) != kCGLNoError) {
+ CGLDestroyContext(context);
+ CGLDestroyPBuffer(pbuffer);
+ DLOG(ERROR) << "Error attaching pbuffer to context.";
+ return false;
+ }
+ gl_context_ = context;
+ pbuffer_ = pbuffer;
+ // Now we're ready to handle SetWindowSize calls, which will
+ // allocate and/or reallocate the IOSurface and associated offscreen
+ // OpenGL structures for rendering.
+ return true;
+}
+
+void AcceleratedSurface::Destroy() {
+ // 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_)
+ CGLDestroyContext(gl_context_);
+ if (pbuffer_)
+ CGLDestroyPBuffer(pbuffer_);
+}
+
+// Call after making changes to the surface which require a visual update.
+// Makes the rendering show up in other processes.
+void AcceleratedSurface::SwapBuffers() {
+ if (bound_fbo_ != fbo_) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
+ }
+ if (io_surface_.get() != NULL) {
+ // 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 if (transport_dib_.get() != NULL) {
+ // Pre-Mac OS X 10.6, fetch the rendered image from the FBO 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().
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glReadPixels(0,
+ 0,
+ surface_width_,
+ surface_height_,
+ GL_BGRA, // This pixel format should have no conversion.
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ pixel_memory);
+ }
+ }
+ if (bound_fbo_ != fbo_) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bound_fbo_);
+ }
+}
+
+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) {
+ CFNumberRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
+ CFDictionaryAddValue(dictionary, key, number);
+}
+
+void AcceleratedSurface::AllocateRenderBuffers(GLenum target,
+ int32 width, int32 height) {
+ 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);
+ // Generate and bind the framebuffer object.
+ glGenFramebuffersEXT(1, &fbo_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
+ bound_fbo_ = 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,
+ width,
+ height);
+
+ // Unbind the renderbuffers.
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, bound_renderbuffer_);
+
+ // Make sure that subsequent set-up code affects the render texture.
+ glBindTexture(target, texture_);
+}
+
+bool AcceleratedSurface::SetupFrameBufferObject(GLenum target) {
+ if (bound_fbo_ != fbo_) {
+ 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);
+ }
+ if (bound_fbo_ != fbo_) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bound_fbo_);
+ }
+ return fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT;
+}
+
+bool AcceleratedSurface::MakeCurrent() {
+ if (CGLGetCurrentContext() != gl_context_) {
+ if (CGLSetCurrentContext(gl_context_) != kCGLNoError) {
+ DLOG(ERROR) << "Unable to make gl context current.";
+ return false;
+ }
+ }
+ return true;
+}
+
+void AcceleratedSurface::Clear(const gfx::Rect& rect) {
+ glClearColor(1.0, 1.0, 1.0, 1.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(int32 width, int32 height) {
+ if (surface_width_ == width && surface_height_ == height) {
+ // Return 0 to indicate to the caller that no new backing store
+ // allocation occurred.
+ 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;
+ AllocateRenderBuffers(target, width, height);
+
+ // Allocate a new IOSurface, which is the GPU resource that can be
+ // shared across processes.
+ scoped_cftyperef<CFMutableDictionaryRef> properties;
+ properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ AddIntegerValue(properties,
+ io_surface_support->GetKIOSurfaceWidth(), width);
+ AddIntegerValue(properties,
+ io_surface_support->GetKIOSurfaceHeight(), 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(gl_context_,
+ target,
+ GL_RGBA,
+ width,
+ height,
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ io_surface_.get(),
+ plane);
+ // Set up the frame buffer object.
+ SetupFrameBufferObject(target);
+ surface_width_ = width;
+ surface_height_ = height;
+
+ // 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.
+ return io_surface_support->IOSurfaceGetID(io_surface_);
+}
+
+TransportDIB::Handle AcceleratedSurface::SetTransportDIBSize(
+ int32 width, int32 height) {
+ if (surface_width_ == width && surface_height_ == height) {
+ // Return an invalid handle to indicate to the caller that no new backing
+ // store allocation occurred.
+ return TransportDIB::DefaultHandleValue();
+ }
+ surface_width_ = width;
+ surface_height_ = height;
+
+ // 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 = width * 4 * 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(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();
+ }
+
+ // Set up the render buffers and reserve enough space on the card for the
+ // framebuffer texture.
+ GLenum target = GL_TEXTURE_RECTANGLE_ARB;
+ AllocateRenderBuffers(target, width, height);
+ glTexImage2D(target,
+ 0, // mipmap level 0
+ GL_RGBA8, // internal pixel format
+ width,
+ 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/chrome/common/accelerated_surface_mac.h b/chrome/common/accelerated_surface_mac.h
new file mode 100644
index 0000000..e8c27af
--- /dev/null
+++ b/chrome/common/accelerated_surface_mac.h
@@ -0,0 +1,108 @@
+// 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 CHROME_COMMON_ACCELERATED_SURFACE_MAC_H_
+#define CHROME_COMMON_ACCELERATED_SURFACE_MAC_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <OpenGL/OpenGL.h>
+
+#include "base/callback.h"
+#include "base/scoped_cftyperef.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/transport_dib.h"
+
+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 a GL Context or a TransportDIB,
+// never both.
+
+class AcceleratedSurface {
+ public:
+ AcceleratedSurface();
+ virtual ~AcceleratedSurface() { }
+
+ // Set up internal buffers. Returns false upon failure.
+ bool Initialize();
+ // Tear down. Must be called before destructor to prevent leaks.
+ void Destroy();
+
+ // These methods are used only when there is a GL surface.
+
+ // 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(int32 width, int32 height);
+ // Sets the GL context to be the current one for drawing. Returns true if
+ // it succeeded.
+ bool MakeCurrent();
+ // Clear the surface to all white. 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.
+ void SwapBuffers();
+ CGLContextObj context() { return gl_context_; }
+
+ // 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.
+ TransportDIB::Handle SetTransportDIBSize(int32 width, int32 height);
+ // 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);
+
+ 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, int32 width, int32 height);
+
+ // 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);
+
+ CGLContextObj gl_context_;
+ CGLPBufferObj pbuffer_;
+ // 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?
+ scoped_cftyperef<CFTypeRef> io_surface_;
+ // 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_;
+ int32 surface_width_;
+ int32 surface_height_;
+ GLuint texture_;
+ GLuint fbo_;
+ GLuint depth_stencil_renderbuffer_;
+ // For tracking whether the default framebuffer / renderbuffer or
+ // ones created by the end user are currently bound
+ // TODO(kbr): Need to property hook up and track the OpenGL state and hook
+ // up the notion of the currently bound FBO.
+ GLuint bound_fbo_;
+ GLuint bound_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 // CHROME_COMMON_ACCELERATED_SURFACE_MAC_H_
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index 3a5594c..08e1aba 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -416,6 +416,12 @@ IPC_BEGIN_MESSAGES(PluginHost)
int32 /* height */,
TransportDIB::Handle /* handle to the TransportDIB */)
+ // Synthesize a fake window handle for the plug-in to identify the instance
+ // to the browser, allowing mapping to a surface for hardware accelleration
+ // of plug-in content. The browser generates the handle which is then set on
+ // the plug-in.
+ IPC_MESSAGE_ROUTED0(PluginHostMsg_BindFakePluginWindowHandle)
+
// This message, used only on 10.6 and later, is sent from the
// plug-in process to the renderer process to indicate that the GPU
// plugin allocated a new IOSurface object of the given width and
diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h
index 1bbd04d..64dea79d 100644
--- a/chrome/plugin/webplugin_delegate_stub.h
+++ b/chrome/plugin/webplugin_delegate_stub.h
@@ -33,7 +33,7 @@ class WebInputEvent;
class WebPluginDelegateImpl;
// Converts the IPC messages from WebPluginDelegateProxy into calls to the
-// actual WebPluginDelegate object.
+// actual WebPluginDelegateImpl object.
class WebPluginDelegateStub : public IPC::Channel::Listener,
public IPC::Message::Sender,
public base::RefCounted<WebPluginDelegateStub> {
diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc
index ffda5c1..e7826fd 100644
--- a/chrome/plugin/webplugin_proxy.cc
+++ b/chrome/plugin/webplugin_proxy.cc
@@ -576,6 +576,28 @@ void WebPluginProxy::SetDeferResourceLoading(unsigned long resource_id,
Send(new PluginHostMsg_DeferResourceLoading(route_id_, resource_id, defer));
}
+#if defined(OS_MACOSX)
+void WebPluginProxy::BindFakePluginWindowHandle() {
+ Send(new PluginHostMsg_BindFakePluginWindowHandle(route_id_));
+}
+
+void WebPluginProxy::AcceleratedFrameBuffersDidSwap(
+ gfx::PluginWindowHandle window) {
+ // TODO(pinkerton): Rename this message.
+ Send(new PluginHostMsg_GPUPluginBuffersSwapped(route_id_, window));
+}
+
+void WebPluginProxy::SetAcceleratedSurface(gfx::PluginWindowHandle window,
+ int32 width,
+ int32 height,
+ uint64 accelerated_surface_identifier) {
+ // TODO(pinkerton): Rename this message.
+ Send(new PluginHostMsg_GPUPluginSetIOSurface(route_id_, window, width,
+ height,
+ accelerated_surface_identifier));
+}
+#endif
+
void WebPluginProxy::OnPaint(const gfx::Rect& damaged_rect) {
child_process_logging::SetActiveURL(page_url_);
diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h
index 0beb9cb..9329d6c 100644
--- a/chrome/plugin/webplugin_proxy.h
+++ b/chrome/plugin/webplugin_proxy.h
@@ -132,6 +132,15 @@ class WebPluginProxy : public webkit_glue::WebPlugin {
webkit_glue::WebPluginResourceClient* resource_client);
gfx::NativeViewId containing_window() { return containing_window_; }
+#if defined(OS_MACOSX)
+ virtual void BindFakePluginWindowHandle();
+ virtual void AcceleratedFrameBuffersDidSwap(gfx::PluginWindowHandle window);
+ virtual void SetAcceleratedSurface(gfx::PluginWindowHandle window,
+ int32 width,
+ int32 height,
+ uint64 accelerated_surface_identifier);
+#endif
+
private:
bool Send(IPC::Message* msg);
diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc
index b00f1b5..10bf1f8 100644
--- a/chrome/renderer/webplugin_delegate_proxy.cc
+++ b/chrome/renderer/webplugin_delegate_proxy.cc
@@ -402,6 +402,8 @@ void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) {
OnDeferResourceLoading)
#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_BindFakePluginWindowHandle,
+ OnBindFakePluginWindowHandle);
IPC_MESSAGE_HANDLER(PluginHostMsg_UpdateGeometry_ACK,
OnUpdateGeometry_ACK)
// Used only on 10.6 and later.
@@ -1255,25 +1257,38 @@ WebPluginDelegateProxy::CreateSeekableResourceClient(
return proxy;
}
-CommandBufferProxy* WebPluginDelegateProxy::CreateCommandBuffer() {
-#if defined(ENABLE_GPU)
#if defined(OS_MACOSX)
- // We need to synthesize a fake window handle for this nested
- // delegate to identify the instance of the GPU plugin back to the
- // browser.
+void WebPluginDelegateProxy::OnBindFakePluginWindowHandle() {
+ BindFakePluginWindowHandle();
+}
+
+// Synthesize a fake window handle for the plug-in to identify the instance
+// to the browser, allowing mapping to a surface for hardware acceleration
+// of plug-in content. The browser generates the handle which is then set on
+// the plug-in. Returns true if it successfully sets the window handle on the
+// plug-in.
+bool WebPluginDelegateProxy::BindFakePluginWindowHandle() {
gfx::PluginWindowHandle fake_window = NULL;
if (render_view_)
fake_window = render_view_->AllocateFakePluginWindowHandle();
// If we aren't running on 10.6, this allocation will fail.
if (!fake_window)
- return NULL;
+ return false;
OnSetWindow(fake_window);
if (!Send(new PluginMsg_SetFakeGPUPluginWindowHandle(instance_id_,
fake_window))) {
- return NULL;
+ return false;
}
+ return true;
+}
#endif
+CommandBufferProxy* WebPluginDelegateProxy::CreateCommandBuffer() {
+#if defined(ENABLE_GPU)
+#if defined(OS_MACOSX)
+ if (!BindFakePluginWindowHandle())
+ return NULL;
+#endif
int command_buffer_id;
if (!Send(new PluginMsg_CreateCommandBuffer(instance_id_,
&command_buffer_id))) {
diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h
index 212758e..cdeb62a 100644
--- a/chrome/renderer/webplugin_delegate_proxy.h
+++ b/chrome/renderer/webplugin_delegate_proxy.h
@@ -149,6 +149,7 @@ class WebPluginDelegateProxy
void OnDeferResourceLoading(unsigned long resource_id, bool defer);
#if defined(OS_MACOSX)
+ void OnBindFakePluginWindowHandle();
void OnUpdateGeometry_ACK(int ack_key);
void OnGPUPluginSetIOSurface(gfx::PluginWindowHandle window,
int32 width,
@@ -188,6 +189,13 @@ class WebPluginDelegateProxy
void WillDestroyWindow();
#if defined(OS_MACOSX)
+ // Synthesize a fake window handle for the plug-in to identify the instance
+ // to the browser, allowing mapping to a surface for hardware acceleration
+ // of plug-in content. The browser generates the handle which is then set on
+ // the plug-in. Returns true if it successfully sets the window handle on the
+ // plug-in.
+ bool BindFakePluginWindowHandle();
+
// The Mac TransportDIB implementation uses base::SharedMemory, which
// cannot be disposed of if an in-flight UpdateGeometry message refers to
// the shared memory file descriptor. The old_transport_dibs_ map holds
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index e07dc99..b9637e9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -31,13 +31,7 @@
// XWindowWrapper is stubbed out for unit-tests.
#include "gpu/command_buffer/service/x_utils.h"
#elif defined(OS_MACOSX)
-// The following two #includes CAN NOT go above the inclusion of
-// gl_utils.h and therefore glew.h regardless of what the Google C++
-// style guide says.
-#include <CoreFoundation/CoreFoundation.h> // NOLINT
-#include <OpenGL/OpenGL.h> // NOLINT
-#include "base/scoped_cftyperef.h"
-#include "chrome/common/io_surface_support_mac.h"
+#include "chrome/common/accelerated_surface_mac.h"
#endif
namespace gpu {
@@ -564,20 +558,6 @@ class GLES2DecoderImpl : public GLES2Decoder {
#undef GLES2_CMD_OP
-#if defined(OS_MACOSX)
- // 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, int32 width, int32 height);
-
- // 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);
-#endif
-
// Current GL error bits.
uint32 error_bits_;
@@ -626,32 +606,7 @@ class GLES2DecoderImpl : public GLES2Decoder {
HGLRC gl_context_;
HPBUFFERARB pbuffer_;
#elif defined(OS_MACOSX)
- CGLContextObj gl_context_;
- CGLPBufferObj pbuffer_;
- // 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?
- scoped_cftyperef<CFTypeRef> io_surface_;
- // 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_;
- int32 surface_width_;
- int32 surface_height_;
- GLuint texture_;
- GLuint fbo_;
- GLuint depth_stencil_renderbuffer_;
- // For tracking whether the default framebuffer / renderbuffer or
- // ones created by the end user are currently bound
- GLuint bound_fbo_;
- GLuint bound_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_;
+ AcceleratedSurface surface_;
#endif
bool anti_aliased_;
@@ -684,16 +639,6 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
gl_device_context_(NULL),
gl_context_(NULL),
pbuffer_(NULL),
-#elif defined(OS_MACOSX)
- gl_context_(NULL),
- pbuffer_(NULL),
- surface_width_(0),
- surface_height_(0),
- texture_(0),
- fbo_(0),
- depth_stencil_renderbuffer_(0),
- bound_fbo_(0),
- bound_renderbuffer_(0),
#endif
anti_aliased_(false) {
}
@@ -1001,13 +946,7 @@ bool GLES2DecoderImpl::MakeCurrent() {
#elif defined(OS_LINUX)
return window()->MakeCurrent();
#elif defined(OS_MACOSX)
- if (CGLGetCurrentContext() != gl_context_) {
- if (CGLSetCurrentContext(gl_context_) != kCGLNoError) {
- DLOG(ERROR) << "Unable to make gl context current.";
- return false;
- }
- }
- return true;
+ return surface_.MakeCurrent();
#else
NOTREACHED();
return false;
@@ -1113,48 +1052,7 @@ bool GLES2DecoderImpl::InitPlatformSpecific() {
if (!window()->Initialize())
return false;
#elif defined(OS_MACOSX)
- // Create a 1x1 pbuffer and associated context to bootstrap things
- static const CGLPixelFormatAttribute attribs[] = {
- (CGLPixelFormatAttribute) kCGLPFAPBuffer,
- (CGLPixelFormatAttribute) 0
- };
- CGLPixelFormatObj pixel_format;
- GLint num_pixel_formats;
- if (CGLChoosePixelFormat(attribs,
- &pixel_format,
- &num_pixel_formats) != kCGLNoError) {
- DLOG(ERROR) << "Error choosing pixel format.";
- return false;
- }
- if (!pixel_format) {
- return false;
- }
- CGLContextObj context;
- CGLError res = CGLCreateContext(pixel_format, 0, &context);
- CGLDestroyPixelFormat(pixel_format);
- if (res != kCGLNoError) {
- DLOG(ERROR) << "Error creating context.";
- return false;
- }
- CGLPBufferObj pbuffer;
- if (CGLCreatePBuffer(1, 1,
- GL_TEXTURE_2D, GL_RGBA,
- 0, &pbuffer) != kCGLNoError) {
- CGLDestroyContext(context);
- DLOG(ERROR) << "Error creating pbuffer.";
- return false;
- }
- if (CGLSetPBuffer(context, pbuffer, 0, 0, 0) != kCGLNoError) {
- CGLDestroyContext(context);
- CGLDestroyPBuffer(pbuffer);
- DLOG(ERROR) << "Error attaching pbuffer to context.";
- return false;
- }
- gl_context_ = context;
- pbuffer_ = pbuffer;
- // Now we're ready to handle SetWindowSize calls, which will
- // allocate and/or reallocate the IOSurface and associated offscreen
- // OpenGL structures for rendering.
+ return surface_.Initialize();
#endif
return true;
@@ -1240,151 +1138,12 @@ void GLES2DecoderImpl::DestroyPlatformSpecific() {
}
#if defined(OS_MACOSX)
-#if !defined(UNIT_TEST)
-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) {
- CFNumberRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
- CFDictionaryAddValue(dictionary, key, number);
-}
-#endif // !defined(UNIT_TEST)
-
-void GLES2DecoderImpl::AllocateRenderBuffers(GLenum target,
- int32 width, int32 height) {
- 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);
- // Generate and bind the framebuffer object.
- glGenFramebuffersEXT(1, &fbo_);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
- bound_fbo_ = 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,
- width,
- height);
-
- // Unbind the renderbuffers.
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, bound_renderbuffer_);
-
- // Make sure that subsequent set-up code affects the render texture.
- glBindTexture(target, texture_);
-}
-
-bool GLES2DecoderImpl::SetupFrameBufferObject(GLenum target) {
- if (bound_fbo_ != fbo_) {
- 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,
- GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER_EXT,
- depth_stencil_renderbuffer_);
- fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
- }
- if (bound_fbo_ != fbo_) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bound_fbo_);
- }
- return fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT;
-}
uint64 GLES2DecoderImpl::SetWindowSizeForIOSurface(int32 width, int32 height) {
#if defined(UNIT_TEST)
return 0;
#else
- if (surface_width_ == width && surface_height_ == height) {
- // Return 0 to indicate to the caller that no new backing store
- // allocation occurred.
- 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;
- AllocateRenderBuffers(target, width, height);
-
- // Allocate a new IOSurface, which is the GPU resource that can be
- // shared across processes.
- scoped_cftyperef<CFMutableDictionaryRef> properties;
- properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks));
- AddIntegerValue(properties,
- io_surface_support->GetKIOSurfaceWidth(), width);
- AddIntegerValue(properties,
- io_surface_support->GetKIOSurfaceHeight(), 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(gl_context_,
- target,
- GL_RGBA,
- width,
- height,
- GL_BGRA,
- GL_UNSIGNED_INT_8_8_8_8_REV,
- io_surface_.get(),
- plane);
- // Set up the frame buffer object.
- SetupFrameBufferObject(target);
- surface_width_ = width;
- surface_height_ = height;
-
- // 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.
- return io_surface_support->IOSurfaceGetID(io_surface_);
+ return surface_.SetSurfaceSize(width, height);
#endif // !defined(UNIT_TEST)
}
@@ -1393,61 +1152,14 @@ TransportDIB::Handle GLES2DecoderImpl::SetWindowSizeForTransportDIB(
#if defined(UNIT_TEST)
return TransportDIB::DefaultHandleValue();
#else
- if (surface_width_ == width && surface_height_ == height) {
- // Return an invalid handle to indicate to the caller that no new backing
- // store allocation occurred.
- return TransportDIB::DefaultHandleValue();
- }
- surface_width_ = width;
- surface_height_ = height;
-
- // 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 = width * 4 * 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(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();
- }
-
- // Set up the render buffers and reserve enough space on the card for the
- // framebuffer texture.
- GLenum target = GL_TEXTURE_RECTANGLE_ARB;
- AllocateRenderBuffers(target, width, height);
- glTexImage2D(target,
- 0, // mipmap level 0
- GL_RGBA8, // internal pixel format
- width,
- 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();
+ return surface_.SetTransportDIBSize(width, height);
#endif // !defined(UNIT_TEST)
}
void GLES2DecoderImpl::SetTransportDIBAllocAndFree(
Callback2<size_t, TransportDIB::Handle*>::Type* allocator,
Callback1<TransportDIB::Id>::Type* deallocator) {
- dib_alloc_callback_.reset(allocator);
- dib_free_callback_.reset(deallocator);
+ surface_.SetTransportDIBAllocAndFree(allocator, deallocator);
}
#endif // defined(OS_MACOSX)
@@ -1461,15 +1173,7 @@ void GLES2DecoderImpl::Destroy() {
DCHECK(window());
window()->Destroy();
#elif defined(OS_MACOSX)
- // 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_)
- CGLDestroyContext(gl_context_);
- if (pbuffer_)
- CGLDestroyPBuffer(pbuffer_);
+ surface_.Destroy();
#endif
DestroyPlatformSpecific();
@@ -1728,37 +1432,9 @@ void GLES2DecoderImpl::DoSwapBuffers() {
DCHECK(window());
window()->SwapBuffers();
#elif defined(OS_MACOSX)
- if (bound_fbo_ != fbo_) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
- }
- if (io_surface_.get() != NULL) {
- // 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 if (transport_dib_.get() != NULL) {
- // Pre-Mac OS X 10.6, fetch the rendered image from the FBO 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().
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
- glReadPixels(0,
- 0,
- surface_width_,
- surface_height_,
- GL_BGRA, // This pixel format should have no conversion.
- GL_UNSIGNED_INT_8_8_8_8_REV,
- pixel_memory);
- }
- }
- if (bound_fbo_ != fbo_) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bound_fbo_);
- }
+ // TODO(kbr): Need to property hook up and track the OpenGL state and hook
+ // up the notion of the currently bound FBO.
+ surface_.SwapBuffers();
#endif
if (swap_buffers_callback_.get()) {
swap_buffers_callback_->Run();
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
index 0db965c..4cd5b3b 100644
--- a/webkit/glue/plugins/plugin_host.cc
+++ b/webkit/glue/plugins/plugin_host.cc
@@ -9,6 +9,9 @@
#include "base/scoped_ptr.h"
#include "base/string_piece.h"
#include "base/string_util.h"
+#if defined(OS_MACOSX)
+#include "base/sys_info.h"
+#endif
#include "base/sys_string_conversions.h"
#include "net/base/net_util.h"
#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
@@ -36,6 +39,21 @@ static NPAPI::PluginInstance* FindInstance(NPP id) {
return reinterpret_cast<NPAPI::PluginInstance*>(id->ndata);
}
+#if defined(OS_MACOSX)
+// Returns true if the OS supports shared accelerated surfaces via IOSurface.
+// This is true on Snow Leopard and higher.
+static bool SupportsSharingAcceleratedSurfaces() {
+ int32 major, minor, bugfix;
+ base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+#if PINK_USE_COREANIMATION
+ // TODO(pinkerton): enable this, http://crbug.com/32012
+ return major > 10 || (major == 10 && minor > 5);
+#else
+ return false;
+#endif
+}
+#endif
+
namespace NPAPI {
scoped_refptr<PluginHost> PluginHost::singleton_;
@@ -757,7 +775,10 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) {
}
#ifndef NP_NO_QUICKDRAW
case NPNVsupportsQuickDrawBool: {
- // we do not admit to supporting the QuickDraw drawing model.
+ // We do not admit to supporting the QuickDraw drawing model. The logic
+ // here is that our QuickDraw plugin support is so rudimentary that we
+ // only want to use it as a fallback to keep plugins from crashing: if a
+ // plugin knows enough to ask, we want them to use CoreGraphics.
NPBool* supports_qd = reinterpret_cast<NPBool*>(value);
*supports_qd = FALSE;
rv = NPERR_NO_ERROR;
@@ -775,9 +796,16 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) {
rv = NPERR_NO_ERROR;
break;
}
- case NPNVsupportsOpenGLBool:
case NPNVsupportsCoreAnimationBool: {
- // we do not support these drawing and event models.
+ // We only support the Core Animation model on 10.6 and higher
+ NPBool* supports_model = reinterpret_cast<NPBool*>(value);
+ *supports_model = SupportsSharingAcceleratedSurfaces() ? TRUE : FALSE;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVsupportsOpenGLBool: {
+ // This drawing model was never widely supported, and we don't plan to
+ // support it.
NPBool* supports_model = reinterpret_cast<NPBool*>(value);
*supports_model = FALSE;
rv = NPERR_NO_ERROR;
@@ -838,14 +866,14 @@ NPError NPN_SetValue(NPP id, NPPVariable variable, void* value) {
return NPERR_GENERIC_ERROR;
#if defined(OS_MACOSX)
case NPPVpluginDrawingModel: {
- // We only admit to supporting the CoreGraphics drawing model. The logic
- // here is that our QuickDraw plugin support is so rudimentary that we
- // only want to use it as a fallback to keep plugins from crashing: if
- // a plugin knows enough to ask, we want them to use CoreGraphics.
int model = reinterpret_cast<int>(value);
if (model == NPDrawingModelCoreGraphics) {
plugin->set_drawing_model(model);
return NPERR_NO_ERROR;
+ } else if (model == NPDrawingModelCoreAnimation &&
+ SupportsSharingAcceleratedSurfaces()) {
+ plugin->set_drawing_model(model);
+ return NPERR_NO_ERROR;
}
return NPERR_GENERIC_ERROR;
}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
index 1327464..8cf0d03 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl.h
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -16,10 +16,15 @@
#include "base/gfx/rect.h"
#include "base/ref_counted.h"
#include "base/task.h"
+#include "base/timer.h"
#include "third_party/npapi/bindings/npapi.h"
#include "webkit/glue/webcursor.h"
#include "webkit/glue/webplugin_delegate.h"
+#if defined(OS_MACOSX)
+#include "chrome/common/accelerated_surface_mac.h"
+#endif
+
#if defined(USE_X11)
typedef struct _GdkDrawable GdkPixmap;
#endif
@@ -32,8 +37,19 @@ namespace WebKit {
class WebMouseEvent;
}
-// An implementation of WebPluginDelegate that proxies all calls to
-// the plugin process.
+#if defined(OS_MACOSX)
+class CoreAnimationRedrawTimerSource;
+#ifdef __OBJC__
+@class CALayer;
+@class CARenderer;
+#else
+class CALayer;
+class CARenderer;
+#endif
+#endif
+
+// An implementation of WebPluginDelegate that runs in the plugin process,
+// proxied from the renderer by WebPluginDelegateProxy.
class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
public:
enum PluginQuirks {
@@ -146,6 +162,12 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// Informs the delegate that the plugin set a Cocoa NSCursor.
void SetNSCursor(NSCursor* cursor);
+ // Informs the browser about the updated accelerated drawing surface.
+ void UpdateAcceleratedSurface();
+
+ // Uses a CARenderer to draw the plug-in's layer in our OpenGL surface.
+ void DrawLayerInSurface();
+
#ifndef NP_NO_CARBON
// Indicates that it's time to send the plugin a null event.
void FireIdleEvent();
@@ -157,10 +179,11 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
}
#if defined(OS_MACOSX)
- // On Mac OS X and for the GPU plugin only, this handle is a fake
- // one and comes in from the outside world.
+ // Allow setting a "fake" window handle to associate this plug-in with
+ // an IOSurface in the browser. Used for accelerated drawing surfaces.
void set_windowed_handle(gfx::PluginWindowHandle handle) {
windowed_handle_ = handle;
+ UpdateAcceleratedSurface();
}
#endif
@@ -244,7 +267,7 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// used for windowed plugins
// Note: on Mac OS X, the only time the windowed handle is non-zero
- // is the case of the GPU plugin, which uses a fake window handle to
+ // is the case of accelerated rendering, which uses a fake window handle to
// identify itself back to the browser. It still performs all of its
// work offscreen.
gfx::PluginWindowHandle windowed_handle_;
@@ -301,6 +324,10 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
#ifndef NP_NO_QUICKDRAW
NP_Port qd_port_;
#endif
+ CALayer* layer_; // Used for CA drawing mode. Weak, retained by plug-in.
+ AcceleratedSurface surface_;
+ CARenderer* renderer_; // Renders layer_ to surface_.
+ scoped_ptr<base::RepeatingTimer<WebPluginDelegateImpl> > redraw_timer_;
#endif
gfx::Rect window_rect_;
gfx::Rect clip_rect_;
@@ -356,7 +383,7 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
#ifndef NP_NO_CARBON
// Moves our dummy window to match the current screen location of the plugin.
void UpdateDummyWindowBounds(const gfx::Point& plugin_origin);
-
+
#ifndef NP_NO_QUICKDRAW
// Scrapes the contents of our dummy window into the given context.
void ScrapeDummyWindowIntoContext(CGContextRef context);
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
index 0a1e84e..c944c64 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
+++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#import <Cocoa/Cocoa.h>
+#import <QuartzCore/QuartzCore.h>
#include "webkit/glue/plugins/webplugin_delegate_impl.h"
@@ -16,7 +17,6 @@
#include "base/scoped_ptr.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
-#include "base/timer.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "webkit/default_plugin/plugin_impl.h"
#include "webkit/glue/webplugin.h"
@@ -49,6 +49,8 @@ using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;
using WebKit::WebMouseWheelEvent;
+const int kCoreAnimationRedrawPeriodMs = 20; // 50fps
+
// Important implementation notes: The Mac definition of NPAPI, particularly
// the distinction between windowed and windowless modes, differs from the
// Windows and Linux definitions. Most of those differences are
@@ -169,16 +171,21 @@ class CarbonIdleEventSource {
} // namespace
+#pragma mark -
+
WebPluginDelegateImpl::WebPluginDelegateImpl(
gfx::PluginWindowHandle containing_view,
NPAPI::PluginInstance *instance)
- : windowless_needs_set_window_(true),
+ : windowed_handle_(NULL),
+ windowless_needs_set_window_(true),
// all Mac plugins are "windowless" in the Windows/X11 sense
windowless_(true),
plugin_(NULL),
instance_(instance),
parent_(containing_view),
buffer_context_(NULL),
+ layer_(nil),
+ renderer_(nil),
quirks_(0),
have_focus_(false),
focus_notifier_(NULL),
@@ -256,6 +263,31 @@ void WebPluginDelegateImpl::PlatformInitialize() {
#endif
window_.type = NPWindowTypeDrawable;
break;
+ case NPDrawingModelCoreAnimation: { // Assumes Cocoa event model.
+ window_.type = NPWindowTypeDrawable;
+ // Ask the plug-in for the CALayer it created for rendering content. Have
+ // the renderer tell the browser to create a "windowed plugin" to host
+ // the IOSurface. The surface itself will be created when the plug-in
+ // is sized.
+ CALayer* layer = nil;
+ NPError err = instance()->NPP_GetValue(NPPVpluginCoreAnimationLayer,
+ reinterpret_cast<void*>(&layer));
+ if (!err) {
+ layer_ = layer;
+ plugin_->BindFakePluginWindowHandle();
+ surface_.Initialize();
+ UpdateAcceleratedSurface();
+ renderer_ = [[CARenderer rendererWithCGLContext:surface_.context()
+ options:NULL] retain];
+ [renderer_ setLayer:layer_];
+ redraw_timer_.reset(new base::RepeatingTimer<WebPluginDelegateImpl>);
+ redraw_timer_->Start(
+ base::TimeDelta::FromMilliseconds(kCoreAnimationRedrawPeriodMs),
+ this,
+ &WebPluginDelegateImpl::DrawLayerInSurface);
+ }
+ break;
+ }
default:
NOTREACHED();
break;
@@ -286,6 +318,12 @@ void WebPluginDelegateImpl::PlatformDestroyInstance() {
if (instance()->event_model() == NPEventModelCarbon)
CarbonIdleEventSource::SharedInstance()->UnregisterDelegate(this);
#endif
+ if (redraw_timer_.get())
+ redraw_timer_->Stop();
+ [renderer_ release];
+ renderer_ = nil;
+ layer_ = nil;
+ surface_.Destroy();
}
void WebPluginDelegateImpl::UpdateGeometryAndContext(
@@ -379,8 +417,32 @@ void WebPluginDelegateImpl::WindowlessUpdateGeometry(
WindowlessSetWindow(true);
}
+void WebPluginDelegateImpl::DrawLayerInSurface() {
+ surface_.MakeCurrent();
+
+ surface_.Clear(window_rect_);
+
+ // Ensure all changes are made before rendering. Not sure where the |-begin|
+ // comes from, but not doing this causes nothing to render.
+ [CATransaction commit];
+ [renderer_ beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
+ CGRect layerRect = [layer_ bounds];
+ [renderer_ addUpdateRect:layerRect];
+ [renderer_ render];
+ [renderer_ endFrame];
+
+ surface_.SwapBuffers();
+ plugin_->AcceleratedFrameBuffersDidSwap(windowed_handle());
+}
+
void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context,
const gfx::Rect& damage_rect) {
+ // There is currently nothing to do for the Core Animation drawing model,
+ // but there have been discussions on the plugin-futures mailing list that
+ // might require future work.
+ if (instance()->drawing_model() == NPDrawingModelCoreAnimation)
+ return;
+
// If we somehow get a paint before we've set up the plugin buffer, bail.
if (!buffer_context_)
return;
@@ -458,6 +520,8 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
SetWindowHasFocus(initial_window_focus_);
}
+ UpdateAcceleratedSurface();
+
DCHECK(err == NPERR_NO_ERROR);
}
@@ -580,6 +644,30 @@ void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) {
}
}
+// Generate an IOSurface for accelerated drawing (but only in the case where a
+// window handle has been set). Once the surface has been updated for the
+// current size of the plug-in, tell the browser host view so it can adjust its
+// bookkeeping and CALayer appropriately.
+void WebPluginDelegateImpl::UpdateAcceleratedSurface() {
+ // Will only have a window handle when using the CoreAnimation drawing model.
+ if (!windowed_handle() ||
+ instance()->drawing_model() != NPDrawingModelCoreAnimation)
+ return;
+
+ [layer_ setFrame:CGRectMake(0, 0,
+ window_rect_.width(), window_rect_.height())];
+ [renderer_ setBounds:[layer_ bounds]];
+
+ uint64 io_surface_id = surface_.SetSurfaceSize(window_rect_.width(),
+ window_rect_.height());
+ if (io_surface_id) {
+ plugin_->SetAcceleratedSurface(windowed_handle(),
+ window_rect_.width(),
+ window_rect_.height(),
+ io_surface_id);
+ }
+}
+
void WebPluginDelegateImpl::WindowFrameChanged(gfx::Rect window_frame,
gfx::Rect view_frame) {
instance()->set_window_frame(window_frame);
@@ -600,6 +688,7 @@ void WebPluginDelegateImpl::SetNSCursor(NSCursor* cursor) {
void WebPluginDelegateImpl::SetPluginRect(const gfx::Rect& rect) {
window_rect_ = rect;
+ UpdateAcceleratedSurface();
PluginScreenLocationChanged();
}
diff --git a/webkit/glue/webplugin.h b/webkit/glue/webplugin.h
index d83601a..3f9c7e5 100644
--- a/webkit/glue/webplugin.h
+++ b/webkit/glue/webplugin.h
@@ -144,6 +144,26 @@ class WebPlugin {
virtual void SetDeferResourceLoading(unsigned long resource_id,
bool defer) = 0;
+#if defined(OS_MACOSX)
+ // Synthesize a fake window handle for the plug-in to identify the instance
+ // to the browser, allowing mapping to a surface for hardware accelleration
+ // of plug-in content. The browser generates the handle which is then set on
+ // the plug-in.
+ virtual void BindFakePluginWindowHandle() {}
+
+ // Tell the browser (via the renderer) to invalidate because the
+ // accelerated buffers have changed.
+ virtual void AcceleratedFrameBuffersDidSwap(gfx::PluginWindowHandle window) {}
+
+ // Tell the renderer and browser to associate the given plugin handle with
+ // |accelerated_surface_identifier|. The geometry is used to resize any
+ // native "window" (which on the Mac is a CALayer).
+ virtual void SetAcceleratedSurface(gfx::PluginWindowHandle window,
+ int32 width,
+ int32 height,
+ uint64 accelerated_surface_identifier) {}
+#endif
+
// Gets the WebPluginDelegate that implements the interface.
// This API is only for use with Pepper, and is only overridden
// by in-renderer implementations.
diff --git a/webkit/tools/test_shell/mac/accelerated_surface_stub.cc b/webkit/tools/test_shell/mac/accelerated_surface_stub.cc
new file mode 100644
index 0000000..77ca622
--- /dev/null
+++ b/webkit/tools/test_shell/mac/accelerated_surface_stub.cc
@@ -0,0 +1,52 @@
+// 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.
+
+// This file is a complete and total hack intended to stub out some classes
+// used by WebPluginDelegateImpl on Mac. Unfortunately, they live in
+// chrome/common, so we can't compile them into TestShell. Instead, provide
+// some stubs. It will need to be updated if new methods are added to
+// AcceleratedSurface that get called from WebPluginDelegateImpl. It's not
+// like plug-ins work in TestShell anyway.
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <OpenGL/OpenGL.h>
+
+#include "base/basictypes.h"
+#include "base/gfx/rect.h"
+#include "base/scoped_ptr.h"
+
+class TransportDIB {
+ public:
+ TransportDIB() { }
+ ~TransportDIB() { }
+};
+
+class AcceleratedSurface {
+ public:
+ AcceleratedSurface();
+ virtual ~AcceleratedSurface();
+
+ bool Initialize();
+ void Destroy();
+ uint64 SetSurfaceSize(int32 width, int32 height);
+ bool MakeCurrent();
+ void Clear(const gfx::Rect& rect);
+ void SwapBuffers();
+ CGLContextObj context() { return NULL; }
+ private:
+ scoped_ptr<TransportDIB> ignore_;
+};
+
+AcceleratedSurface::AcceleratedSurface() { }
+AcceleratedSurface::~AcceleratedSurface() { }
+bool AcceleratedSurface::Initialize() { return false; }
+void AcceleratedSurface::Destroy() { }
+uint64 AcceleratedSurface::SetSurfaceSize(int32 width, int32 height)
+ { return 0; }
+bool AcceleratedSurface::MakeCurrent() { return false; }
+void AcceleratedSurface::Clear(const gfx::Rect& rect) { }
+void AcceleratedSurface::SwapBuffers() { }
+
+// Needs to be instantiated in order to generate the dtor for the scoped_ptr.
+AcceleratedSurface s;
diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi
index a28daf2..a1bd3cb 100644
--- a/webkit/tools/test_shell/test_shell.gypi
+++ b/webkit/tools/test_shell/test_shell.gypi
@@ -48,6 +48,7 @@
],
'msvs_guid': '77C32787-1B96-CB84-B905-7F170629F0AC',
'sources': [
+ 'mac/accelerated_surface_stub.cc',
'mac/DumpRenderTreePasteboard.h',
'mac/DumpRenderTreePasteboard.m',
'mac/test_shell_webview.h',
diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp
index 282bb3b..0754c9f 100644
--- a/webkit/webkit.gyp
+++ b/webkit/webkit.gyp
@@ -408,6 +408,11 @@
['exclude', r'/mac_']],
}, { # else: OS=="mac"
'sources/': [['exclude', 'plugin_(lib|list)_posix\\.cc$']],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/QuartzCore.framework',
+ ],
+ },
}],
['enable_gpu==1', {
'dependencies': [