diff options
55 files changed, 1638 insertions, 46 deletions
diff --git a/app/gfx/native_widget_types.h b/app/gfx/native_widget_types.h index ba845a0..af5baa9 100644 --- a/app/gfx/native_widget_types.h +++ b/app/gfx/native_widget_types.h @@ -140,8 +140,15 @@ NativeViewId IdFromNativeView(NativeView view); // On OS X we don't have windowed plugins. // We use a NULL/0 PluginWindowHandle in shared code to indicate there // is no window present, so mirror that behavior here. - typedef bool PluginWindowHandle; - const PluginWindowHandle kNullPluginWindow = false; + // + // The GPU plugin is currently an exception to this rule. As of this + // writing it uses some NPAPI infrastructure, and minimally we need + // to identify the plugin instance via this window handle. When the + // GPU plugin becomes a full-on GPU process, this typedef can be + // returned to a bool. For now we use a type large enough to hold a + // pointer on 64-bit architectures in case we need this capability. + typedef uint64 PluginWindowHandle; + const PluginWindowHandle kNullPluginWindow = 0; #endif } // namespace gfx diff --git a/build/common.gypi b/build/common.gypi index e8fd690..a100fa1 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -280,6 +280,15 @@ 'NACL_WIN64', ], }], + # Compute based on OS and target architecture whether the GPU + # plugin / process is supported. + [ 'OS=="win" or (OS=="linux" and target_arch!="arm") or OS=="mac"', { + # Enable a variable used elsewhere throughout the GYP files to determine + # whether to compile in the sources for the GPU plugin / process. + 'enable_gpu%': 1, + }, { # GPU plugin not supported + 'enable_gpu%': 0, + }], ], # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_' @@ -346,7 +355,7 @@ }], ], }], - ['OS=="win" or (OS=="linux" and target_arch!="arm")', { + ['enable_gpu==1', { 'defines': [ 'ENABLE_GPU=1', ], diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index cde8932..6a20f26 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -143,6 +143,15 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnMsgGetScreenInfo) IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect) IPC_MESSAGE_HANDLER(ViewHostMsg_GetRootWindowRect, OnMsgGetRootWindowRect) + // The following messages are only used on 10.6 and later + IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateFakePluginWindowHandle, + OnAllocateFakePluginWindowHandle) + IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyFakePluginWindowHandle, + OnDestroyFakePluginWindowHandle) + IPC_MESSAGE_HANDLER(ViewHostMsg_GPUPluginSetIOSurface, + OnGPUPluginSetIOSurface) + IPC_MESSAGE_HANDLER(ViewHostMsg_GPUPluginBuffersSwapped, + OnGPUPluginBuffersSwapped) #endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP_EX() @@ -874,6 +883,41 @@ void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id, } } +void RenderWidgetHost::OnAllocateFakePluginWindowHandle( + gfx::PluginWindowHandle* id) { + // TODO(kbr): similar potential issue here as in OnMsgCreatePluginContainer. + // Possibly less of an issue because this is only used for the GPU plugin. + if (view_) { + *id = view_->AllocateFakePluginWindowHandle(); + } else { + NOTIMPLEMENTED(); + } +} + +void RenderWidgetHost::OnDestroyFakePluginWindowHandle( + gfx::PluginWindowHandle id) { + if (view_) { + view_->DestroyFakePluginWindowHandle(id); + } else { + NOTIMPLEMENTED(); + } +} + +void RenderWidgetHost::OnGPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 mach_port) { + if (view_) { + view_->GPUPluginSetIOSurface(window, width, height, mach_port); + } +} + +void RenderWidgetHost::OnGPUPluginBuffersSwapped( + gfx::PluginWindowHandle window) { + if (view_) { + view_->GPUPluginBuffersSwapped(window); + } +} #endif void RenderWidgetHost::PaintBackingStoreRect( diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index f08dee3..ea6c843 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -444,6 +444,14 @@ class RenderWidgetHost : public IPC::Channel::Listener, WebKit::WebScreenInfo* results); void OnMsgGetWindowRect(gfx::NativeViewId window_id, gfx::Rect* results); void OnMsgGetRootWindowRect(gfx::NativeViewId window_id, gfx::Rect* results); + // The following handlers are only used on 10.6 and later + void OnAllocateFakePluginWindowHandle(gfx::PluginWindowHandle* id); + void OnDestroyFakePluginWindowHandle(gfx::PluginWindowHandle id); + void OnGPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 mach_port); + void OnGPUPluginBuffersSwapped(gfx::PluginWindowHandle window); #endif // Paints the given bitmap to the current backing store at the given location. diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index 0a87d3d..ccb1b31 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -5,6 +5,10 @@ #ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_H_ #define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_H_ +#if defined(OS_MACOSX) +#include <OpenGL/OpenGL.h> +#endif + #include "app/gfx/native_widget_types.h" #include "base/shared_memory.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -166,6 +170,18 @@ class RenderWidgetHostView { // message and renderer-side handling) can be removed in favor of using // WasHidden/DidBecomeSelected. virtual void SetWindowVisibility(bool visible) = 0; + + // Methods associated with GPU plugin instances + virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle() = 0; + virtual void DestroyFakePluginWindowHandle( + gfx::PluginWindowHandle window) = 0; + virtual void GPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier) = 0; + virtual void GPUPluginBuffersSwapped(gfx::PluginWindowHandle window) = 0; + // Draws the current GPU plugin instances into the given context. + virtual void DrawGPUPluginInstances(CGLContextObj context) = 0; #endif #if defined(OS_LINUX) diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index 4edfa1ef..c9834bf 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_MAC_H_ #import <Cocoa/Cocoa.h> +#import <QuartzCore/CALayer.h> #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" @@ -15,6 +16,7 @@ #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "webkit/glue/webcursor.h" #include "webkit/glue/webmenuitem.h" +#include "webkit/glue/plugins/mac_gpu_plugin_container_manager.h" class RenderWidgetHostViewMac; class RWHVMEditCommandHelper; @@ -112,6 +114,17 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void SetWindowVisibility(bool visible); virtual void SetBackground(const SkBitmap& background); + // Methods associated with GPU plugin instances + virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(); + virtual void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window); + virtual void GPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier); + virtual void GPUPluginBuffersSwapped(gfx::PluginWindowHandle window); + // Draws the current GPU plugin instances into the given context. + virtual void DrawGPUPluginInstances(CGLContextObj context); + void KillSelf(); void set_parent_view(BaseView* parent_view) { parent_view_ = parent_view; } @@ -181,6 +194,9 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { // methods needs it. NSRect im_caret_rect_; + // The Core Animation layer, if any, hosting the GPU plugins' output. + scoped_nsobject<CALayer> gpu_plugin_layer_; + private: // Updates the display cursor to the current cursor if the cursor is over this // render view. @@ -220,6 +236,9 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { // Used for positioning a popup menu. BaseView* parent_view_; + // Helper class for managing instances of the GPU plugin. + MacGPUPluginContainerManager plugin_container_manager_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac); }; 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 a20ff65..db78a46 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <QuartzCore/CAOpenGLLayer.h> + #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" #import "base/chrome_application_mac.h" @@ -20,6 +22,7 @@ #include "chrome/common/edit_command.h" #include "chrome/common/plugin_messages.h" #include "chrome/common/render_messages.h" +#include "chrome/common/io_surface_support_mac.h" #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" @@ -53,6 +56,35 @@ const size_t kMaxTooltipLength = 1024; } +// GPUPluginLayer -------------------------------------------------------------- + +// This subclass of CAOpenGLLayer hosts the output of the GPU plugins +// on the page. + +@interface GPUPluginLayer : CAOpenGLLayer { + RenderWidgetHostViewMac* renderWidgetHostView_; // weak +} + +- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; +@end + +@implementation GPUPluginLayer +- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { + self = [super init]; + if (self != nil) { + renderWidgetHostView_ = r; + } + return self; +} + +-(void)drawInCGLContext:(CGLContextObj)glContext + pixelFormat:(CGLPixelFormatObj)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval + displayTime:(const CVTimeStamp *)timeStamp { + renderWidgetHostView_->DrawGPUPluginInstances(glContext); +} +@end + // RenderWidgetHostView -------------------------------------------------------- // static @@ -174,6 +206,26 @@ gfx::NativeView RenderWidgetHostViewMac::GetNativeView() { void RenderWidgetHostViewMac::MovePluginWindows( const std::vector<webkit_glue::WebPluginGeometry>& moves) { + // The only case we need to notice plugin window moves is the case + // of the GPU plugin. As soon as the GPU plugin becomes the GPU + // process all of this code will go away. + if (moves.size() > 0) { + for (std::vector<webkit_glue::WebPluginGeometry>::const_iterator iter = + moves.begin(); + iter != moves.end(); + ++iter) { + webkit_glue::WebPluginGeometry geom = *iter; + // Ignore bogus moves which claim to move the plugin to (0, 0) + // with width and height (0, 0) + if (geom.window_rect.x() != 0 || + geom.window_rect.y() != 0 || + geom.window_rect.width() != 0 || + geom.window_rect.height() != 0) { + plugin_container_manager_.MovePluginContainer(geom); + } + } + } + // All plugin stuff is TBD. TODO(avi,awalker): fill in // http://crbug.com/8192 } @@ -440,6 +492,73 @@ void RenderWidgetHostViewMac::KillSelf() { } } +gfx::PluginWindowHandle +RenderWidgetHostViewMac::AllocateFakePluginWindowHandle() { + // We currently only support the GPU plugin on 10.6 and later. + if (!IOSurfaceSupport::Initialize()) + return 0; + + // If we don't already have a GPUPluginLayer allocated for our view, + // set one up now. + if (gpu_plugin_layer_.get() == nil) { + RenderWidgetHostViewCocoa* our_view = native_view(); + // Try to get AppKit to allocate the layer + [our_view setWantsLayer:YES]; + CALayer* root_layer = [our_view layer]; + if (root_layer == nil) { + root_layer = [CALayer layer]; + [our_view setLayer:root_layer]; + } + + GPUPluginLayer* gpu_layer = + [[GPUPluginLayer alloc] initWithRenderWidgetHostViewMac:this]; + + // Make our layer resize to fit the superlayer + gpu_layer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; + // Set up its initial size + [gpu_layer setFrame:NSRectToCGRect([our_view bounds])]; + + [root_layer addSublayer:gpu_layer]; + gpu_plugin_layer_.reset(gpu_layer); + } + + return plugin_container_manager_.AllocateFakePluginWindowHandle(); +} + +void RenderWidgetHostViewMac::DestroyFakePluginWindowHandle( + gfx::PluginWindowHandle window) { + plugin_container_manager_.DestroyFakePluginWindowHandle(window); +} + +void RenderWidgetHostViewMac::GPUPluginSetIOSurface( + gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier) { + plugin_container_manager_.SetSizeAndBackingStore(window, + width, + height, + io_surface_identifier); +} + +void RenderWidgetHostViewMac::GPUPluginBuffersSwapped( + gfx::PluginWindowHandle window) { + [gpu_plugin_layer_.get() setNeedsDisplay]; +} + +void RenderWidgetHostViewMac::DrawGPUPluginInstances(CGLContextObj context) { + CGLSetCurrentContext(context); + gfx::Rect rect = GetWindowRect(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + // Note that we place the origin at the upper left corner with +y + // going down + glOrtho(0, rect.width(), rect.height(), 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + plugin_container_manager_.Draw(context); +} + void RenderWidgetHostViewMac::ShutdownHost() { shutdown_factory_.RevokeAll(); render_widget_host_->Shutdown(); @@ -870,6 +989,10 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) { if (renderWidgetHostView_->whiteout_start_time_.is_null()) renderWidgetHostView_->whiteout_start_time_ = base::TimeTicks::Now(); } + + // This helps keep the GPU plugins' output in better sync with the + // window as it resizes. + [renderWidgetHostView_->gpu_plugin_layer_.get() setNeedsDisplay]; } - (BOOL)canBecomeKeyView { diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc index 95c5b7b..776ef53 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -91,6 +91,29 @@ gfx::Rect TestRenderWidgetHostView::GetRootWindowRect() { void TestRenderWidgetHostView::SetActive(bool active) { // <viettrungluu@gmail.com>: Do I need to do anything here? } + +gfx::PluginWindowHandle +TestRenderWidgetHostView::AllocateFakePluginWindowHandle() { + return NULL; +} + +void TestRenderWidgetHostView::DestroyFakePluginWindowHandle( + gfx::PluginWindowHandle window) { +} + +void TestRenderWidgetHostView::GPUPluginSetIOSurface( + gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier) { +} + +void TestRenderWidgetHostView::GPUPluginBuffersSwapped( + gfx::PluginWindowHandle window) { +} + +void TestRenderWidgetHostView::DrawGPUPluginInstances(CGLContextObj context) { +} #endif void RenderViewHostTestHarness::NavigateAndCommit(const GURL& url) { diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index 7ec1304..fde21b5 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -78,6 +78,14 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual gfx::Rect GetRootWindowRect(); virtual void SetActive(bool active); virtual void SetWindowVisibility(bool visible) {} + virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(); + virtual void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window); + virtual void GPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier); + virtual void GPUPluginBuffersSwapped(gfx::PluginWindowHandle window); + virtual void DrawGPUPluginInstances(CGLContextObj context); #endif #if defined(OS_LINUX) diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 72c1349..1c6d346 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -526,7 +526,7 @@ 'third_party/wtl/include', ], }], - ['OS=="win" or (OS=="linux" and target_arch!="arm")', { + ['enable_gpu==1', { 'dependencies': [ '../gpu/gpu.gyp:command_buffer_service', ], diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index c181704e..88cf2aa 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2179,6 +2179,7 @@ 'libraries': [ '$(SDKROOT)/System/Library/Frameworks/SecurityInterface.framework', '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework', + '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework', ], 'mac_bundle_resources': [ 'browser/utility.sb', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index e928f01..c7b405f 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -57,6 +57,8 @@ 'common/devtools_messages_internal.h', 'common/gpu_messages.h', 'common/gpu_messages_internal.h', + 'common/io_surface_support_mac.cc', + 'common/io_surface_support_mac.h', 'common/logging_chrome.cc', 'common/logging_chrome.h', 'common/main_function_params.h', diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index a15c82b..1a41678 100755 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -185,7 +185,7 @@ }], ], }], - ['OS=="win" or (OS=="linux" and target_arch!="arm")', { + ['enable_gpu==1', { 'sources': [ 'renderer/command_buffer_proxy.cc', 'renderer/command_buffer_proxy.h', diff --git a/chrome/common/command_buffer_messages_internal.h b/chrome/common/command_buffer_messages_internal.h index 274223b5..f6fb423 100644 --- a/chrome/common/command_buffer_messages_internal.h +++ b/chrome/common/command_buffer_messages_internal.h @@ -41,4 +41,15 @@ IPC_BEGIN_MESSAGES(CommandBuffer) base::SharedMemoryHandle /* transfer_buffer */, size_t /* size */) +#if defined(OS_MACOSX) + // On Mac OS X the GPU plugin must be offscreen, because there is no + // true cross-process window hierarchy. For this reason we must send + // resize events explicitly to the command buffer stub so it can + // reallocate its backing store and send the new one back to the + // browser. This message is currently used only on 10.6 and later. + IPC_MESSAGE_ROUTED2(CommandBufferMsg_SetWindowSize, + int32 /* width */, + int32 /* height */) +#endif + IPC_END_MESSAGES(CommandBuffer) diff --git a/chrome/common/gpu_plugin.cc b/chrome/common/gpu_plugin.cc index fc79cbb..d9d67db 100644 --- a/chrome/common/gpu_plugin.cc +++ b/chrome/common/gpu_plugin.cc @@ -27,7 +27,7 @@ void RegisterInternalGPUPlugin() { L"", L"", { -#if !defined(OS_LINUX) +#if !defined(OS_POSIX) || defined(OS_MACOSX) gpu_plugin::NP_GetEntryPoints, #endif gpu_plugin::NP_Initialize, diff --git a/chrome/common/io_surface_support_mac.cc b/chrome/common/io_surface_support_mac.cc new file mode 100644 index 0000000..80b2539 --- /dev/null +++ b/chrome/common/io_surface_support_mac.cc @@ -0,0 +1,242 @@ +// 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 <dlfcn.h> + +#include "base/singleton.h" +#include "chrome/common/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 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* Initialize(); + + 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 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_; + CGLTexImageIOSurface2DProcPtr cgl_tex_image_io_surface_2d_; + bool initialized_successfully_; + + friend struct DefaultSingletonTraits<IOSurfaceSupportImpl>; + DISALLOW_EVIL_CONSTRUCTORS(IOSurfaceSupportImpl); +}; + +static Singleton<IOSurfaceSupportImpl> sole_instance_; + +IOSurfaceSupportImpl* IOSurfaceSupportImpl::Initialize() { + IOSurfaceSupportImpl* impl = sole_instance_.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); +} + +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), + 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* 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 || + !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); + 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::Initialize(); +} + +IOSurfaceSupport::IOSurfaceSupport() { +} + +IOSurfaceSupport::~IOSurfaceSupport() { +} + diff --git a/chrome/common/io_surface_support_mac.h b/chrome/common/io_surface_support_mac.h new file mode 100644 index 0000000..6ad116f --- /dev/null +++ b/chrome/common/io_surface_support_mac.h @@ -0,0 +1,66 @@ +// 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_IO_SURFACE_SUPPORT_MAC_H_ +#define CHROME_COMMON_IO_SURFACE_SUPPORT_MAC_H_ + +#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 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 // CHROME_COMMON_IO_SURFACE_SUPPORT_MAC_H_ + diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index aecccac..05e532b 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -291,6 +291,15 @@ IPC_BEGIN_MESSAGES(Plugin) IPC_MESSAGE_CONTROL1(PluginMsg_ResetModalDialogEvent, gfx::NativeViewId /* containing_window */) + +#if defined(OS_MACOSX) + // This message, used only on 10.6 and later, transmits the "fake" + // window handle allocated by the browser on behalf of the renderer + // to the GPU plugin. + IPC_MESSAGE_ROUTED1(PluginMsg_SetFakeGPUPluginWindowHandle, + gfx::PluginWindowHandle /* window */) +#endif + IPC_END_MESSAGES(Plugin) @@ -385,6 +394,29 @@ IPC_BEGIN_MESSAGES(PluginHost) #if defined(OS_MACOSX) IPC_MESSAGE_ROUTED1(PluginHostMsg_UpdateGeometry_ACK, int /* ack_key */) + + // 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 + // height. This information is then forwarded on to the browser + // process. + // + // NOTE: the original intent was to pass a mach port as the + // IOSurface identifier but it looks like that will be a lot of + // work. For now we pass an ID from IOSurfaceGetID. + IPC_MESSAGE_ROUTED4(PluginHostMsg_GPUPluginSetIOSurface, + gfx::PluginWindowHandle /* window */, + int32 /* width */, + int32 /* height */, + uint64 /* identifier for IOSurface */) + + // This message, currently used only on 10.6 and later, notifies the + // renderer process (and from there the browser process) that the + // GPU plugin swapped the buffers associated with the given + // "window", which should cause the browser to redraw the various + // GPU plugins' contents. + IPC_MESSAGE_ROUTED1(PluginHostMsg_GPUPluginBuffersSwapped, + gfx::PluginWindowHandle /* window */) #endif IPC_END_MESSAGES(PluginHost) diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 1dcef7e..7b25b7a 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1781,6 +1781,41 @@ IPC_BEGIN_MESSAGES(ViewHost) // renderer is finished with them. IPC_MESSAGE_CONTROL1(ViewHostMsg_FreeTransportDIB, TransportDIB::Id /* DIB id */) + + //--------------------------------------------------------------------------- + // Messages related to the GPU plugin on Mac OS X 10.6 and later + + // This is sent from the renderer to the browser to allocate a fake + // PluginWindowHandle on the browser side which is used to identify + // the plugin to the browser later when backing store is allocated + // or reallocated. + IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_AllocateFakePluginWindowHandle, + gfx::PluginWindowHandle /* id */) + + // Destroys a fake window handle previously allocated using + // AllocateFakePluginWindowHandle. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DestroyFakePluginWindowHandle, + gfx::PluginWindowHandle /* id */) + + // This message is sent from the renderer to the browser on behalf + // of the GPU plugin to indicate that a new backing store was + // allocated for that GPU plugin instance. + // + // NOTE: the original intent was to pass a mach port as the + // IOSurface identifier but it looks like that will be a lot of + // work. For now we pass an ID from IOSurfaceGetID. + IPC_MESSAGE_ROUTED4(ViewHostMsg_GPUPluginSetIOSurface, + gfx::PluginWindowHandle /* window */, + int32 /* width */, + int32 /* height */, + uint64 /* identifier for IOSurface */) + + // This message notifies the browser process that the GPU plugin + // swapped the buffers associated with the given "window", which + // should cause the browser to redraw the various GPU plugins' + // contents. + IPC_MESSAGE_ROUTED1(ViewHostMsg_GPUPluginBuffersSwapped, + gfx::PluginWindowHandle /* window */) #endif // A renderer sends this to the browser process when it wants to create a diff --git a/chrome/plugin/command_buffer_stub.cc b/chrome/plugin/command_buffer_stub.cc index 4b062e8..b019b1f 100644 --- a/chrome/plugin/command_buffer_stub.cc +++ b/chrome/plugin/command_buffer_stub.cc @@ -5,14 +5,17 @@ #include "base/process_util.h" #include "base/shared_memory.h" #include "chrome/common/command_buffer_messages.h" +#include "chrome/common/plugin_messages.h" #include "chrome/plugin/command_buffer_stub.h" #include "chrome/plugin/plugin_channel.h" using gpu::Buffer; CommandBufferStub::CommandBufferStub(PluginChannel* channel, + int plugin_host_route_id, gfx::PluginWindowHandle window) : channel_(channel), + plugin_host_route_id_(plugin_host_route_id), window_(window) { route_id_ = channel->GenerateRouteID(); channel->AddRoute(route_id_, this, false); @@ -58,6 +61,11 @@ void CommandBufferStub::OnInitialize(int32 size, command_buffer_->SetPutOffsetChangeCallback( NewCallback(processor_.get(), &gpu::GPUProcessor::ProcessCommands)); +#if defined(OS_MACOSX) + processor_->SetSwapBuffersCallback( + NewCallback(this, + &CommandBufferStub::SwapBuffersCallback)); +#endif buffer.shared_memory->ShareToProcess(peer_handle, ring_buffer); } else { processor_ = NULL; @@ -108,6 +116,24 @@ void CommandBufferStub::OnGetTransferBuffer( base::CloseProcessHandle(peer_handle); } +#if defined(OS_MACOSX) +void CommandBufferStub::OnSetWindowSize(int32 width, int32 height) { + uint64 new_backing_store = processor_->SetWindowSize(width, height); + if (new_backing_store) { + Send(new PluginHostMsg_GPUPluginSetIOSurface(plugin_host_route_id_, + window_, + width, + height, + new_backing_store)); + } +} + +void CommandBufferStub::SwapBuffersCallback() { + Send(new PluginHostMsg_GPUPluginBuffersSwapped(plugin_host_route_id_, + window_)); +} +#endif + void CommandBufferStub::OnMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(CommandBufferStub, msg) IPC_MESSAGE_HANDLER(CommandBufferMsg_Initialize, OnInitialize); @@ -119,6 +145,9 @@ void CommandBufferStub::OnMessageReceived(const IPC::Message& msg) { OnDestroyTransferBuffer); IPC_MESSAGE_HANDLER(CommandBufferMsg_GetTransferBuffer, OnGetTransferBuffer); +#if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(CommandBufferMsg_SetWindowSize, OnSetWindowSize); +#endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() } diff --git a/chrome/plugin/command_buffer_stub.h b/chrome/plugin/command_buffer_stub.h index 1001ce9..7759392 100644 --- a/chrome/plugin/command_buffer_stub.h +++ b/chrome/plugin/command_buffer_stub.h @@ -22,7 +22,9 @@ class CommandBufferService; class CommandBufferStub : public IPC::Channel::Listener, public IPC::Message::Sender { public: - CommandBufferStub(PluginChannel* channel, gfx::PluginWindowHandle window); + CommandBufferStub(PluginChannel* channel, + int plugin_host_route_id, + gfx::PluginWindowHandle window); virtual ~CommandBufferStub(); @@ -45,8 +47,13 @@ class CommandBufferStub : public IPC::Channel::Listener, void OnGetTransferBuffer(int32 id, base::SharedMemoryHandle* transfer_buffer, size_t* size); +#if defined(OS_MACOSX) + void OnSetWindowSize(int32 width, int32 height); + void SwapBuffersCallback(); +#endif scoped_refptr<PluginChannel> channel_; + int plugin_host_route_id_; gfx::PluginWindowHandle window_; int route_id_; scoped_ptr<gpu::CommandBufferService> command_buffer_; diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index cf6e842..80d6e62 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -139,6 +139,10 @@ void WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { OnHTTPRangeRequestReply) IPC_MESSAGE_HANDLER(PluginMsg_CreateCommandBuffer, OnCreateCommandBuffer) +#if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(PluginMsg_SetFakeGPUPluginWindowHandle, + OnSetFakeGPUPluginWindowHandle) +#endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() @@ -375,7 +379,8 @@ void WebPluginDelegateStub::OnInstallMissingPlugin() { void WebPluginDelegateStub::OnCreateCommandBuffer(int* route_id) { #if defined(ENABLE_GPU) command_buffer_stub_.reset(new CommandBufferStub( - static_cast<PluginChannel*>(PluginChannelBase::GetCurrentChannel()), + channel_, + instance_id_, delegate_->windowed_handle())); *route_id = command_buffer_stub_->route_id(); @@ -428,3 +433,11 @@ void WebPluginDelegateStub::OnHTTPRangeRequestReply( delegate_->CreateSeekableResourceClient(resource_id, range_request_id); webplugin_->OnResourceCreated(resource_id, resource_client); } + +#if defined(OS_MACOSX) +void WebPluginDelegateStub::OnSetFakeGPUPluginWindowHandle( + gfx::PluginWindowHandle window) { + delegate_->set_windowed_handle(window); +} +#endif + diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index b783832..5a04758 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -115,6 +115,14 @@ class WebPluginDelegateStub : public IPC::Channel::Listener, // If this is the GPU plugin, the stub object that forwards to the // command buffer service. scoped_ptr<CommandBufferStub> command_buffer_stub_; + +#if defined(OS_MACOSX) + // If this is the GPU plugin, we need to be receive a fake window + // handle which is used for subsequent communication back to the + // browser. + void OnSetFakeGPUPluginWindowHandle(gfx::PluginWindowHandle window); +#endif + #endif DISALLOW_IMPLICIT_CONSTRUCTORS(WebPluginDelegateStub); diff --git a/chrome/renderer/command_buffer_proxy.cc b/chrome/renderer/command_buffer_proxy.cc index 2b08090..9c337c9 100644 --- a/chrome/renderer/command_buffer_proxy.cc +++ b/chrome/renderer/command_buffer_proxy.cc @@ -169,3 +169,10 @@ void CommandBufferProxy::SetParseError( // Not implemented in proxy. NOTREACHED(); } + +#if defined(OS_MACOSX) +void CommandBufferProxy::SetWindowSize(int32 width, int32 height) { + Send(new CommandBufferMsg_SetWindowSize(route_id_, width, height)); +} +#endif + diff --git a/chrome/renderer/command_buffer_proxy.h b/chrome/renderer/command_buffer_proxy.h index 077b0c5..b7bed4e 100644 --- a/chrome/renderer/command_buffer_proxy.h +++ b/chrome/renderer/command_buffer_proxy.h @@ -44,6 +44,10 @@ class CommandBufferProxy : public gpu::CommandBuffer, virtual void SetToken(int32 token); virtual void SetParseError(gpu::error::Error error); +#if defined(OS_MACOSX) + virtual void SetWindowSize(int32 width, int32 height); +#endif + private: // As with the service, the client takes ownership of the ring buffer. int32 size_; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 0594162..96b38c9 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -4234,3 +4234,30 @@ bool RenderView::SendAndRunNestedMessageLoop(IPC::SyncMessage* message) { return rv; } + +#if defined(OS_MACOSX) +gfx::PluginWindowHandle RenderView::AllocateFakePluginWindowHandle() { + gfx::PluginWindowHandle window = NULL; + Send(new ViewHostMsg_AllocateFakePluginWindowHandle( + routing_id(), &window)); + return window; +} + +void RenderView::DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window) { + if (window) + Send(new ViewHostMsg_DestroyFakePluginWindowHandle(routing_id(), window)); +} + +void RenderView::GPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier) { + Send(new ViewHostMsg_GPUPluginSetIOSurface( + routing_id(), window, width, height, io_surface_identifier)); +} + +void RenderView::GPUPluginBuffersSwapped(gfx::PluginWindowHandle window) { + Send(new ViewHostMsg_GPUPluginBuffersSwapped(routing_id(), window)); +} +#endif + diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 7545654..1bb7c97 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -469,6 +469,18 @@ class RenderView : public RenderWidget, // 'zh-TW' for Traditional Chinse. std::string DetectLanguage(); +#if defined(OS_MACOSX) + // Helper routines for GPU plugin support. Used by the + // WebPluginDelegateProxy, which has a pointer to the RenderView. + gfx::PluginWindowHandle AllocateFakePluginWindowHandle(); + void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window); + void GPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier); + void GPUPluginBuffersSwapped(gfx::PluginWindowHandle window); +#endif + protected: // RenderWidget overrides: virtual void Close(); diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc index 4a17fc8..4c02715 100644 --- a/chrome/renderer/webplugin_delegate_pepper.cc +++ b/chrome/renderer/webplugin_delegate_pepper.cc @@ -152,6 +152,18 @@ void WebPluginDelegatePepper::UpdateGeometry( if (nested_delegate_) nested_delegate_->UpdateGeometry(window_rect, clip_rect); +#if defined(ENABLE_GPU) +#if defined(OS_MACOSX) + // Send the new window size to the command buffer service code so it + // can allocate a new backing store. The handle to the new backing + // store is sent back to the browser asynchronously. + if (command_buffer_.get()) { + command_buffer_->SetWindowSize(window_rect_.width(), + window_rect_.height()); + } +#endif // OS_MACOSX +#endif // ENABLE_GPU + if (!instance()) return; @@ -350,6 +362,10 @@ NPError WebPluginDelegatePepper::Device3DInitializeContext( // Ensure the service knows the window size before rendering anything. nested_delegate_->UpdateGeometry(window_rect_, clip_rect_); +#if defined(OS_MACOSX) + command_buffer_->SetWindowSize(window_rect_.width(), + window_rect_.height()); +#endif // OS_MACOSX // Save the implementation information (the CommandBuffer). Device3DImpl* impl = new Device3DImpl; impl->command_buffer = command_buffer_.get(); diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index b71798e..7059890 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -386,6 +386,11 @@ void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) { #if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(PluginHostMsg_UpdateGeometry_ACK, OnUpdateGeometry_ACK) + // Used only on 10.6 and later + IPC_MESSAGE_HANDLER(PluginHostMsg_GPUPluginSetIOSurface, + OnGPUPluginSetIOSurface) + IPC_MESSAGE_HANDLER(PluginHostMsg_GPUPluginBuffersSwapped, + OnGPUPluginBuffersSwapped) #endif IPC_MESSAGE_UNHANDLED_ERROR() @@ -891,6 +896,14 @@ void WebPluginDelegateProxy::OnSetWindow(gfx::PluginWindowHandle window) { void WebPluginDelegateProxy::WillDestroyWindow() { DCHECK(window_); plugin_->WillDestroyWindow(window_); +#if defined(OS_MACOSX) + if (window_) { + // This is actually a "fake" window handle only for the GPU + // plugin. Deallocate it on the browser side. + if (render_view_) + render_view_->DestroyFakePluginWindowHandle(window_); + } +#endif window_ = gfx::kNullPluginWindow; } @@ -1199,6 +1212,23 @@ WebPluginDelegateProxy::CreateSeekableResourceClient( 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. + 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; + OnSetWindow(fake_window); + if (!Send(new PluginMsg_SetFakeGPUPluginWindowHandle(instance_id_, + fake_window))) { + return NULL; + } +#endif + int command_buffer_id; if (!Send(new PluginMsg_CreateCommandBuffer(instance_id_, &command_buffer_id))) { @@ -1247,4 +1277,20 @@ void WebPluginDelegateProxy::OnUpdateGeometry_ACK(int ack_key) { old_transport_dibs_.erase(iterator); } + +void WebPluginDelegateProxy::OnGPUPluginSetIOSurface( + gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier) { + if (render_view_) + render_view_->GPUPluginSetIOSurface(window, width, height, + io_surface_identifier); +} + +void WebPluginDelegateProxy::OnGPUPluginBuffersSwapped( + gfx::PluginWindowHandle window) { + if (render_view_) + render_view_->GPUPluginBuffersSwapped(window); +} #endif diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index 6a71bdb..a56da38 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -145,6 +145,11 @@ class WebPluginDelegateProxy #if defined(OS_MACOSX) void OnUpdateGeometry_ACK(int ack_key); + void OnGPUPluginSetIOSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 io_surface_identifier); + void OnGPUPluginBuffersSwapped(gfx::PluginWindowHandle window); #endif // Draw a graphic indicating a crashed plugin. @@ -4,4 +4,8 @@ include_rules = [ # For gfx::PluginWindowHandle "+app/gfx", + + # For IOSurfaceSupport on Mac OS X, service-side code only. + # Can consider moving these files if this dependency is undesirable. + "+chrome/common", ] diff --git a/gpu/command_buffer/client/gles2_demo_cc.cc b/gpu/command_buffer/client/gles2_demo_cc.cc index 0478e32..2544f42 100644 --- a/gpu/command_buffer/client/gles2_demo_cc.cc +++ b/gpu/command_buffer/client/gles2_demo_cc.cc @@ -5,6 +5,7 @@ // This file is here so other GLES2 related files can have a common set of // includes where appropriate. +#include <math.h> #include <GLES2/gl2.h> #include "gpu/command_buffer/client/gles2_demo_cc.h" @@ -13,8 +14,10 @@ namespace { GLuint g_texture = 0; int g_textureLoc = -1; GLuint g_programObject = 0; +GLuint g_worldMatrixLoc = 0; GLuint g_vbo = 0; GLsizei g_texCoordOffset = 0; +int g_angle = 0; void CheckGLError() { GLenum error = glGetError(); @@ -49,12 +52,14 @@ GLuint LoadShader(GLenum type, const char* shaderSrc) { void InitShaders() { static const char* vShaderStr = + "uniform mat4 worldMatrix;\n" "attribute vec3 g_Position;\n" "attribute vec2 g_TexCoord0;\n" "varying vec2 texCoord;\n" "void main()\n" "{\n" - " gl_Position = vec4(g_Position.x, g_Position.y, g_Position.z, 1.0);\n" + " gl_Position = worldMatrix *\n" + " vec4(g_Position.x, g_Position.y, g_Position.z, 1.0);\n" " texCoord = g_TexCoord0;\n" "}\n"; static const char* fShaderStr = @@ -94,6 +99,7 @@ void InitShaders() { return; } g_programObject = programObject; + g_worldMatrixLoc = glGetUniformLocation(g_programObject, "worldMatrix"); g_textureLoc = glGetUniformLocation(g_programObject, "tex"); glGenBuffers(1, &g_vbo); glBindBuffer(GL_ARRAY_BUFFER, g_vbo); @@ -124,7 +130,36 @@ void InitShaders() { CheckGLError(); } +#define PI 3.1415926535897932384626433832795f + void Draw() { + // TODO(kbr): base the angle on time rather than on ticks + g_angle = (g_angle + 1) % 360; + // Rotate about the Z axis + GLfloat rot_matrix[16]; + GLfloat cos_angle = cosf(static_cast<GLfloat>(g_angle) * PI / 180.0f); + GLfloat sin_angle = sinf(static_cast<GLfloat>(g_angle) * PI / 180.0f); + // OpenGL matrices are column-major + rot_matrix[0] = cos_angle; + rot_matrix[1] = sin_angle; + rot_matrix[2] = 0.0f; + rot_matrix[3] = 0.0f; + + rot_matrix[4] = -sin_angle; + rot_matrix[5] = cos_angle; + rot_matrix[6] = 0.0f; + rot_matrix[7] = 0.0f; + + rot_matrix[8] = 0.0f; + rot_matrix[9] = 0.0f; + rot_matrix[10] = 1.0f; + rot_matrix[11] = 0.0f; + + rot_matrix[12] = 0.0f; + rot_matrix[13] = 0.0f; + rot_matrix[14] = 0.0f; + rot_matrix[15] = 1.0f; + // Note: the viewport is automatically set up to cover the entire Canvas. // Clear the color buffer glClear(GL_COLOR_BUFFER_BIT); @@ -132,6 +167,9 @@ void Draw() { // Use the program object glUseProgram(g_programObject); CheckGLError(); + // Set up the model matrix + glUniformMatrix4fv(g_worldMatrixLoc, 1, GL_FALSE, rot_matrix); + // Load the vertex data glBindBuffer(GL_ARRAY_BUFFER, g_vbo); glEnableVertexAttribArray(0); diff --git a/gpu/command_buffer/common/cmd_buffer_common.cc b/gpu/command_buffer/common/cmd_buffer_common.cc index 936d67c..bf965cc 100644 --- a/gpu/command_buffer/common/cmd_buffer_common.cc +++ b/gpu/command_buffer/common/cmd_buffer_common.cc @@ -8,8 +8,10 @@ #include "gpu/command_buffer/common/cmd_buffer_common.h" namespace gpu { -const int32 CommandHeader::kMaxSize = (1 << 21) - 1; - +#if !defined(OS_WIN) +// gcc needs this to link, but MSVC requires it not be present +const int32 CommandHeader::kMaxSize; +#endif namespace cmd { const char* GetCommandName(CommandId command_id) { diff --git a/gpu/command_buffer/common/cmd_buffer_common.h b/gpu/command_buffer/common/cmd_buffer_common.h index 7ae59e7..5b23620 100644 --- a/gpu/command_buffer/common/cmd_buffer_common.h +++ b/gpu/command_buffer/common/cmd_buffer_common.h @@ -38,7 +38,7 @@ struct CommandHeader { Uint32 size:21; Uint32 command:11; - static const int32 kMaxSize; + static const int32 kMaxSize = (1 << 21) - 1; void Init(uint32 _command, int32 _size) { DCHECK_LE(_size, kMaxSize); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index e708a69..ddfc358 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -17,9 +17,18 @@ #include "gpu/command_buffer/service/cmd_buffer_engine.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/gles2_cmd_validation.h" -#if defined(OS_LINUX) && !defined(UNIT_TEST) +#if defined(UNIT_TEST) +#elif defined(OS_LINUX) // 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" #endif namespace gpu { @@ -38,9 +47,11 @@ COMPILE_ASSERT(sizeof(GLsizei) == sizeof(uint32), // NOLINT COMPILE_ASSERT(sizeof(GLfloat) == sizeof(float), // NOLINT GLfloat_not_same_size_as_float); -namespace { +// TODO(kbr): the use of this anonymous namespace core dumps the +// linker on Mac OS X 10.6 when the symbol ordering file is used +// namespace { -size_t GetGLTypeSize(GLenum type) { +static size_t GetGLTypeSize(GLenum type) { switch (type) { case GL_BYTE: return sizeof(GLbyte); // NOLINT @@ -147,7 +158,7 @@ GLenum GLErrorBitToGLError(uint32 error_bit) { } } -} // anonymous namespace. +// } // anonymous namespace. #if defined(UNIT_TEST) GLES2Decoder::GLES2Decoder() @@ -551,6 +562,13 @@ class GLES2DecoderImpl : public GLES2Decoder { virtual bool MakeCurrent(); virtual uint32 GetServiceIdForTesting(uint32 client_id); +#if !defined(UNIT_TEST) && defined(OS_MACOSX) + // Overridden from GLES2Decoder. + virtual uint64 SetWindowSize(int32 width, int32 height); +#endif + + virtual void SetSwapBuffersCallback(Callback0::Type* callback); + // Removes any buffers in the VertexAtrribInfos and BufferInfos. This is used // on glDeleteBuffers so we can make sure the user does not try to render // with deleted buffers. @@ -729,10 +747,25 @@ class GLES2DecoderImpl : public GLES2Decoder { #elif defined(OS_WIN) HDC device_context_; HGLRC gl_context_; +#elif defined(OS_MACOSX) + CGLContextObj gl_context_; + CGLPBufferObj pbuffer_; + scoped_cftyperef<CFTypeRef> io_surface_; + int32 surface_width_; + int32 surface_height_; + GLuint texture_; + GLuint fbo_; + GLuint depth_renderbuffer_; + // For tracking whether the default framebuffer / renderbuffer or + // ones created by the end user are currently bound + GLuint bound_fbo_; + GLuint bound_renderbuffer_; #endif bool anti_aliased_; + scoped_ptr<Callback0::Type> swap_buffers_callback_; + DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl); }; @@ -754,6 +787,16 @@ GLES2DecoderImpl::GLES2DecoderImpl() #elif defined(OS_WIN) device_context_(NULL), gl_context_(NULL), +#elif defined(OS_MACOSX) + gl_context_(NULL), + pbuffer_(NULL), + surface_width_(0), + surface_height_(0), + texture_(0), + fbo_(0), + depth_renderbuffer_(0), + bound_fbo_(0), + bound_renderbuffer_(0), #endif anti_aliased_(false) { } @@ -790,7 +833,9 @@ bool GLES2DecoderImpl::Initialize() { return success; } -namespace { +// TODO(kbr): the use of this anonymous namespace core dumps the +// linker on Mac OS X 10.6 when the symbol ordering file is used +// namespace { #if defined(UNIT_TEST) #elif defined(OS_WIN) @@ -1007,7 +1052,7 @@ void GLDeleteTexturesHelper( glDeleteTextures(n, ids); } -} // anonymous namespace +// } // anonymous namespace bool GLES2DecoderImpl::MakeCurrent() { #if defined(UNIT_TEST) @@ -1024,6 +1069,14 @@ bool GLES2DecoderImpl::MakeCurrent() { return true; #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; #else NOTREACHED(); return false; @@ -1103,6 +1156,49 @@ bool GLES2DecoderImpl::InitPlatformSpecific() { DCHECK(window()); 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 pixelFormat; + GLint numPixelFormats; + if (CGLChoosePixelFormat(attribs, + &pixelFormat, + &numPixelFormats) != kCGLNoError) { + DLOG(ERROR) << "Error choosing pixel format."; + return false; + } + if (!pixelFormat) { + return false; + } + CGLContextObj context; + CGLError res = CGLCreateContext(pixelFormat, 0, &context); + CGLDestroyPixelFormat(pixelFormat); + 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. #endif return true; @@ -1164,11 +1260,141 @@ bool GLES2DecoderImpl::InitGlew() { return true; } +#if !defined(UNIT_TEST) && defined(OS_MACOSX) +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); +} + +uint64 GLES2DecoderImpl::SetWindowSize(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; + + 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 (!texture_) { + // Generate the texture object. + glGenTextures(1, &texture_); + glBindTexture(target, texture_); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(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_renderbuffer_); + } + + // 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)); + + // Reallocate the depth buffer. + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_renderbuffer_); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, + GL_DEPTH_COMPONENT, + width, + height); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, bound_renderbuffer_); + + // Reallocate the texture object. + glBindTexture(target, texture_); + // 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. + if (bound_fbo_ != fbo_) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_); + } + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, + texture_, + 0); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + depth_renderbuffer_); + if (bound_fbo_ != fbo_) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bound_fbo_); + } + + 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_); +} +#endif // !defined(UNIT_TEST) && defined(OS_MACOSX) + +void GLES2DecoderImpl::SetSwapBuffersCallback(Callback0::Type* callback) { + swap_buffers_callback_.reset(callback); +} + void GLES2DecoderImpl::Destroy() { #if defined(UNIT_TEST) #elif defined(OS_LINUX) DCHECK(window()); window()->Destroy(); +#elif defined(OS_MACOSX) + if (gl_context_) + CGLDestroyContext(gl_context_); + if (pbuffer_) + CGLDestroyPBuffer(pbuffer_); #endif } @@ -1332,7 +1558,18 @@ void GLES2DecoderImpl::DoSwapBuffers() { #elif defined(OS_LINUX) DCHECK(window()); window()->SwapBuffers(); +#elif defined(OS_MACOSX) + if (bound_fbo_ == 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_); + } #endif + if (swap_buffers_callback_.get()) { + swap_buffers_callback_->Run(); + } } void GLES2DecoderImpl::DoUseProgram(GLuint program) { @@ -1476,7 +1713,9 @@ error::Error GLES2DecoderImpl::HandleDrawElements( return error::kNoError; } -namespace { +// TODO(kbr): the use of this anonymous namespace core dumps the +// linker on Mac OS X 10.6 when the symbol ordering file is used +// namespace { // Calls glShaderSource for the various versions of the ShaderSource command. // Assumes that data / data_size points to a piece of memory that is in range @@ -1505,7 +1744,7 @@ error::Error ShaderSourceHelper( return error::kNoError; } -} // anonymous namespace. +// } // anonymous namespace. error::Error GLES2DecoderImpl::HandleShaderSource( uint32 immediate_data_size, const gles2::ShaderSource& c) { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index db91d55..9e6b9c8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -11,6 +11,7 @@ #if defined(OS_WIN) #include <windows.h> #endif +#include "base/task.h" #include "gpu/command_buffer/service/common_decoder.h" namespace gpu { @@ -55,6 +56,8 @@ class GLES2Decoder : public CommonDecoder { HWND hwnd() const { return hwnd_; } +#elif !defined(UNIT_TEST) && defined(OS_MACOSX) + virtual uint64 SetWindowSize(int32 width, int32 height) = 0; #endif // Initializes the graphics context. @@ -71,6 +74,9 @@ class GLES2Decoder : public CommonDecoder { // Gets a service id by client id. virtual uint32 GetServiceIdForTesting(uint32 client_id) = 0; + // Sets a callback which is called when a SwapBuffers command is processed. + virtual void SetSwapBuffersCallback(Callback0::Type* callback) = 0; + protected: GLES2Decoder(); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index dba1043..fa60d41 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -26,6 +26,7 @@ class MockGLES2Decoder : public GLES2Decoder { MOCK_METHOD0(Destroy, void()); MOCK_METHOD0(MakeCurrent, bool()); MOCK_METHOD1(GetServiceIdForTesting, uint32(uint32 client_id)); + MOCK_METHOD1(SetSwapBuffersCallback, void(Callback0::Type*)); MOCK_METHOD3(DoCommand, error::Error(unsigned int command, unsigned int arg_count, const void* cmd_data)); diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc index c9b8c6f..7272115 100644 --- a/gpu/command_buffer/service/gpu_processor.cc +++ b/gpu/command_buffer/service/gpu_processor.cc @@ -82,4 +82,15 @@ int32 GPUProcessor::GetGetOffset() { return parser_->get(); } +#if defined(OS_MACOSX) +uint64 GPUProcessor::SetWindowSize(int32 width, int32 height) { + return decoder_->SetWindowSize(width, height); +} +#endif + +void GPUProcessor::SetSwapBuffersCallback( + Callback0::Type* callback) { + decoder_->SetSwapBuffersCallback(callback); +} + } // namespace gpu diff --git a/gpu/command_buffer/service/gpu_processor.h b/gpu/command_buffer/service/gpu_processor.h index dd22ac4..f22f249 100644 --- a/gpu/command_buffer/service/gpu_processor.h +++ b/gpu/command_buffer/service/gpu_processor.h @@ -44,6 +44,19 @@ class GPUProcessor : public base::RefCounted<GPUProcessor>, virtual bool SetGetOffset(int32 offset); virtual int32 GetGetOffset(); +#if defined(OS_MACOSX) + // Needed only on Mac OS X, which does not render into an on-screen + // window and therefore requires the backing store to be resized + // manually. Returns an opaque identifier for the new backing store. + virtual uint64 SetWindowSize(int32 width, int32 height); + +#endif + + // Sets a callback which is called when a SwapBuffers command is processed. + // Must be called after Initialize(). + // It is not defined on which thread this callback is called. + virtual void SetSwapBuffersCallback(Callback0::Type* callback); + private: // The GPUProcessor holds a weak reference to the CommandBuffer. The // CommandBuffer owns the GPUProcessor and holds a strong reference to it diff --git a/gpu/command_buffer/service/gpu_processor_mac.cc b/gpu/command_buffer/service/gpu_processor_mac.cc new file mode 100644 index 0000000..a36560c --- /dev/null +++ b/gpu/command_buffer/service/gpu_processor_mac.cc @@ -0,0 +1,39 @@ +// 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 "gpu/command_buffer/service/gpu_processor.h" + +using ::base::SharedMemory; + +namespace gpu { + +bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) { + // At this level we do not need the PluginWindowHandle. It is only + // needed at the CommandBufferStub level to identify which GPU + // plugin instance is creating a new backing store in response to a + // resize event. + + // Map the ring buffer and create the parser. + Buffer ring_buffer = command_buffer_->GetRingBuffer(); + if (ring_buffer.ptr) { + parser_.reset(new CommandParser(ring_buffer.ptr, + ring_buffer.size, + 0, + ring_buffer.size, + 0, + decoder_.get())); + } else { + parser_.reset(new CommandParser(NULL, 0, 0, 0, 0, + decoder_.get())); + } + + // Initialize GAPI. + return decoder_->Initialize(); +} + +void GPUProcessor::Destroy() { + decoder_->Destroy(); +} +} // namespace gpu + diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index c20338e..df0a25f 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -19,9 +19,6 @@ 'command_buffer/service/gl_utils.h', ], }, - 'includes': [ - '../build/common.gypi', - ], 'targets': [ { 'target_name': 'gl_libs', @@ -138,6 +135,12 @@ 'dependencies': [ 'gles2_cmd_helper', ], + 'all_dependent_settings': { + 'include_dirs': [ + # For GLES2/gl2.h + 'command_buffer/common', + ], + }, 'sources': [ 'command_buffer/client/gles2_implementation_autogen.h', 'command_buffer/client/gles2_implementation.cc', @@ -266,6 +269,13 @@ ], }, ], + ['OS == "mac"', + { + 'sources': [ + 'command_buffer/service/gpu_processor_mac.cc', + ], + }, + ], ], }, { diff --git a/gpu/gpu_plugin/gpu_plugin.cc b/gpu/gpu_plugin/gpu_plugin.cc index 5bccbe4..d274936 100644 --- a/gpu/gpu_plugin/gpu_plugin.cc +++ b/gpu/gpu_plugin/gpu_plugin.cc @@ -120,7 +120,7 @@ NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* funcs) { return NPERR_NO_ERROR; } -#if defined(OS_LINUX) +#if defined(OS_POSIX) && !defined(OS_MACOSX) NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs, NPPluginFuncs* plugin_funcs) { #else @@ -129,7 +129,7 @@ NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs) { if (!browser_funcs) return NPERR_INVALID_FUNCTABLE_ERROR; -#if defined(OS_LINUX) +#if defined(OS_POSIX) && !defined(OS_MACOSX) NP_GetEntryPoints(plugin_funcs); #endif diff --git a/gpu/gpu_plugin/gpu_plugin.h b/gpu/gpu_plugin/gpu_plugin.h index b6bfc89..b973d7cf 100644 --- a/gpu/gpu_plugin/gpu_plugin.h +++ b/gpu/gpu_plugin/gpu_plugin.h @@ -17,7 +17,7 @@ namespace gpu_plugin { NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* funcs); -#if defined(OS_LINUX) +#if defined(OS_POSIX) && !defined(OS_MACOSX) NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs, NPPluginFuncs* plugin_funcs); #else diff --git a/webkit/glue/plugins/mac_gpu_plugin_container.cc b/webkit/glue/plugins/mac_gpu_plugin_container.cc new file mode 100644 index 0000000..e38234f --- /dev/null +++ b/webkit/glue/plugins/mac_gpu_plugin_container.cc @@ -0,0 +1,104 @@ +// 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 "webkit/glue/plugins/mac_gpu_plugin_container.h" + +#include "webkit/glue/webplugin.h" +#include "webkit/glue/plugins/mac_gpu_plugin_container_manager.h" +#include "chrome/common/io_surface_support_mac.h" + +MacGPUPluginContainer::MacGPUPluginContainer() + : x_(0), + y_(0), + surface_(NULL), + width_(0), + height_(0), + texture_(0) { +} + +MacGPUPluginContainer::~MacGPUPluginContainer() { + ReleaseIOSurface(); +} + +void MacGPUPluginContainer::ReleaseIOSurface() { + if (surface_) { + CFRelease(surface_); + surface_ = NULL; + } +} + +void MacGPUPluginContainer::SetSizeAndBackingStore( + int32 width, + int32 height, + uint64 io_surface_identifier, + MacGPUPluginContainerManager* manager) { + ReleaseIOSurface(); + IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); + if (io_surface_support) { + surface_ = io_surface_support->IOSurfaceLookup( + static_cast<uint32>(io_surface_identifier)); + EnqueueTextureForDeletion(manager); + width_ = width; + height_ = height; + } +} + +void MacGPUPluginContainer::MoveTo( + const webkit_glue::WebPluginGeometry& geom) { + // TODO(kbr): figure out whether additional information is necessary + // to keep around. + x_ = geom.window_rect.x(); + y_ = geom.window_rect.y(); +} + +void MacGPUPluginContainer::Draw(CGLContextObj context) { + IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); + if (!io_surface_support) + return; + + GLenum target = GL_TEXTURE_RECTANGLE_ARB; + if (!texture_ && surface_) { + glGenTextures(1, &texture_); + glBindTexture(target, texture_); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // Don't think we need to identify a plane. + GLuint plane = 0; + io_surface_support->CGLTexImageIOSurface2D(context, + target, + GL_RGBA, + width_, + height_, + GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, + surface_, + plane); + } + + if (texture_) { + // TODO(kbr): convert this to use only OpenGL ES 2.0 functionality + glBindTexture(target, texture_); + glEnable(target); + glBegin(GL_TRIANGLE_STRIP); + int x = x_; + int y = y_; + glTexCoord2f(0, height_); + glVertex3f(x, y, 0); + glTexCoord2f(width_, height_); + glVertex3f(x + width_, y, 0); + glTexCoord2f(0, 0); + glVertex3f(x, y + height_, 0); + glTexCoord2f(width_, 0); + glVertex3f(x + width_, y + height_, 0); + glDisable(target); + glEnd(); + } +} + +void MacGPUPluginContainer::EnqueueTextureForDeletion( + MacGPUPluginContainerManager* manager) { + manager->EnqueueTextureForDeletion(texture_); + texture_ = 0; +} + diff --git a/webkit/glue/plugins/mac_gpu_plugin_container.h b/webkit/glue/plugins/mac_gpu_plugin_container.h new file mode 100644 index 0000000..92e9fcb --- /dev/null +++ b/webkit/glue/plugins/mac_gpu_plugin_container.h @@ -0,0 +1,98 @@ +// 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 WEBKIT_GLUE_PLUGINS_MAC_GPU_PLUGIN_CONTAINER_H_ +#define WEBKIT_GLUE_PLUGINS_MAC_GPU_PLUGIN_CONTAINER_H_ + +// The "GPU plugin" is currently implemented as a special kind of +// NPAPI plugin to provide high-performance on-screen 3D rendering for +// Pepper 3D. +// +// On Windows and X11 platforms the GPU plugin relies on cross-process +// parenting of windows, which is not supported via any public APIs in +// the Mac OS X window system. +// +// To achieve full hardware acceleration we use the new IOSurface APIs +// introduced in Mac OS X 10.6. The GPU plugin's process produces an +// IOSurface and renders into it using OpenGL. It uses the +// IOSurfaceGetID and IOSurfaceLookup APIs to pass a reference to this +// surface to the browser process for on-screen rendering. The GPU +// plugin essentially looks like a windowless plugin; the browser +// process gets all of the mouse events, because the plugin process +// does not have an on-screen window. +// +// This class encapsulates some of the management of these data +// structures, in conjunction with the MacGPUPluginContainerManager. + +#include <CoreFoundation/CoreFoundation.h> +#include <OpenGL/OpenGL.h> + +#include "app/gfx/native_widget_types.h" +#include "base/basictypes.h" + +namespace webkit_glue { +struct WebPluginGeometry; +} + +class MacGPUPluginContainerManager; + +class MacGPUPluginContainer { + public: + MacGPUPluginContainer(); + virtual ~MacGPUPluginContainer(); + + // Sets the backing store and size of this plugin container. + void SetSizeAndBackingStore(int32 width, + int32 height, + uint64 io_surface_identifier, + MacGPUPluginContainerManager* manager); + + // Tells the plugin container that it has moved relative to the + // origin of the window, for example because of a scroll event. + void MoveTo(const webkit_glue::WebPluginGeometry& geom); + + // Draws this plugin's contents, texture mapped onto a quad in the + // given OpenGL context. TODO(kbr): figure out and define exactly + // how the coordinate system will work out. + void Draw(CGLContextObj context); + + // Enqueue our texture for later deletion. Call this before deleting + // this object. + void EnqueueTextureForDeletion(MacGPUPluginContainerManager* manager); + + private: + // We currently only have a viable implementation of this class on + // Snow Leopard. We need to think about fallback strategies that + // will work on Leopard. + + // The x and y coordinates of the plugin window on the web page. + // TODO(kbr): see whether additional clipping information is + // necessary. + int x_; + int y_; + + void ReleaseIOSurface(); + + // The IOSurfaceRef, if any, that has been handed from the GPU + // plugin process back to the browser process for drawing. + // This is held as a CFTypeRef because we can't refer to the + // IOSurfaceRef type when building on 10.5. + CFTypeRef surface_; + + // The width and height of the surface. + int32 width_; + int32 height_; + + // The "live" OpenGL texture referring to this IOSurfaceRef. Note + // that per the CGLTexImageIOSurface2D API we do not need to + // explicitly update this texture's contents once created. All we + // need to do is ensure it is re-bound before attempting to draw + // with it. + GLuint texture_; + + DISALLOW_COPY_AND_ASSIGN(MacGPUPluginContainer); +}; + +#endif // WEBKIT_GLUE_PLUGINS_MAC_GPU_PLUGIN_CONTAINER_H_ + diff --git a/webkit/glue/plugins/mac_gpu_plugin_container_manager.cc b/webkit/glue/plugins/mac_gpu_plugin_container_manager.cc new file mode 100644 index 0000000..185754e --- /dev/null +++ b/webkit/glue/plugins/mac_gpu_plugin_container_manager.cc @@ -0,0 +1,89 @@ +// 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 "webkit/glue/plugins/mac_gpu_plugin_container_manager.h" + +#include "base/logging.h" +#include "webkit/glue/webplugin.h" +#include "webkit/glue/plugins/mac_gpu_plugin_container.h" + +MacGPUPluginContainerManager::MacGPUPluginContainerManager() + : current_id_(0) { +} + +gfx::PluginWindowHandle +MacGPUPluginContainerManager::AllocateFakePluginWindowHandle() { + MacGPUPluginContainer* container = new MacGPUPluginContainer(); + gfx::PluginWindowHandle res = + static_cast<gfx::PluginWindowHandle>(++current_id_); + plugin_window_to_container_map_.insert(std::make_pair(res, container)); + return res; +} + +void MacGPUPluginContainerManager::DestroyFakePluginWindowHandle( + gfx::PluginWindowHandle id) { + MacGPUPluginContainer* container = MapIDToContainer(id); + if (container) + delete container; + plugin_window_to_container_map_.erase(id); +} + +void MacGPUPluginContainerManager::SetSizeAndBackingStore( + gfx::PluginWindowHandle id, + int32 width, + int32 height, + uint64 io_surface_identifier) { + MacGPUPluginContainer* container = MapIDToContainer(id); + if (container) + container->SetSizeAndBackingStore(width, height, + io_surface_identifier, this); +} + +void MacGPUPluginContainerManager::MovePluginContainer( + const webkit_glue::WebPluginGeometry& move) { + MacGPUPluginContainer* container = MapIDToContainer(move.window); + if (container) + container->MoveTo(move); +} + +void MacGPUPluginContainerManager::Draw(CGLContextObj context) { + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + GLenum target = GL_TEXTURE_RECTANGLE_ARB; + glTexEnvi(target, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + for (PluginWindowToContainerMap::const_iterator i = + plugin_window_to_container_map_.begin(); + i != plugin_window_to_container_map_.end(); ++i) { + MacGPUPluginContainer* container = i->second; + container->Draw(context); + } + + // Unbind any texture from the texture target to ensure that the + // next time through we will have to re-bind the texture and thereby + // pick up modifications from the other process. + glBindTexture(target, 0); + + glFlush(); +} + +void MacGPUPluginContainerManager::EnqueueTextureForDeletion(GLuint texture) { + if (texture) { + textures_pending_deletion_.push_back(texture); + } +} + +MacGPUPluginContainer* MacGPUPluginContainerManager::MapIDToContainer( + gfx::PluginWindowHandle id) { + PluginWindowToContainerMap::const_iterator i = + plugin_window_to_container_map_.find(id); + if (i != plugin_window_to_container_map_.end()) + return i->second; + + LOG(ERROR) << "Request for plugin container for unknown window id " << id; + + return NULL; +} + diff --git a/webkit/glue/plugins/mac_gpu_plugin_container_manager.h b/webkit/glue/plugins/mac_gpu_plugin_container_manager.h new file mode 100644 index 0000000..ed63f10 --- /dev/null +++ b/webkit/glue/plugins/mac_gpu_plugin_container_manager.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 WEBKIT_GLUE_PLUGINS_MAC_GPU_PLUGIN_CONTAINER_MANAGER_H_ +#define WEBKIT_GLUE_PLUGINS_MAC_GPU_PLUGIN_CONTAINER_MANAGER_H_ + +#include <OpenGL/OpenGL.h> +#include <map> +#include <vector> + +#include "app/gfx/native_widget_types.h" +#include "base/basictypes.h" + +namespace webkit_glue { +struct WebPluginGeometry; +} + +class MacGPUPluginContainer; + +// Helper class that manages the backing store and on-screen rendering +// of instances of the GPU plugin on the Mac. +class MacGPUPluginContainerManager { + public: + MacGPUPluginContainerManager(); + + // Allocates a new "fake" PluginWindowHandle, which is used as the + // key for the other operations. + gfx::PluginWindowHandle AllocateFakePluginWindowHandle(); + + // Destroys a fake PluginWindowHandle and associated storage. + void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle id); + + // Sets the size and backing store of the plugin instance. + void SetSizeAndBackingStore(gfx::PluginWindowHandle id, + int32 width, + int32 height, + uint64 io_surface_identifier); + + // Takes an update from WebKit about a plugin's position and size and moves + // the plugin accordingly. + void MovePluginContainer(const webkit_glue::WebPluginGeometry& move); + + // Draws all of the managed plugin containers into the given OpenGL + // context, which must already be current. + void Draw(CGLContextObj context); + + // Called by the container to enqueue its OpenGL texture objects for + // deletion. + void EnqueueTextureForDeletion(GLuint texture); + + private: + uint32 current_id_; + + // Maps a "fake" plugin window handle to the corresponding container. + MacGPUPluginContainer* MapIDToContainer(gfx::PluginWindowHandle id); + + // A map that associates plugin window handles with their containers. + typedef std::map<gfx::PluginWindowHandle, MacGPUPluginContainer*> + PluginWindowToContainerMap; + PluginWindowToContainerMap plugin_window_to_container_map_; + + // A list of OpenGL textures waiting to be deleted + std::vector<GLuint> textures_pending_deletion_; + + DISALLOW_COPY_AND_ASSIGN(MacGPUPluginContainerManager); +}; + +#endif // WEBKIT_GLUE_PLUGINS_MAC_GPU_PLUGIN_CONTAINER_MANAGER_H_ + diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index e6e5d20..32dca05 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -147,10 +147,16 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { #endif #endif // OS_MACOSX -#if !defined(OS_MACOSX) gfx::PluginWindowHandle windowed_handle() const { return windowed_handle_; } + +#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. + void set_windowed_handle(gfx::PluginWindowHandle handle) { + windowed_handle_ = handle; + } #endif private: @@ -225,11 +231,15 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { // Closes down and destroys our plugin instance. void DestroyInstance(); -#if !defined(OS_MACOSX) + // 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 + // identify itself back to the browser. It still performs all of its + // work offscreen. gfx::PluginWindowHandle windowed_handle_; gfx::Rect windowed_last_pos_; -#endif + bool windowed_did_set_window_; // TODO(dglazkov): No longer used by Windows, make sure the removal diff --git a/webkit/glue/webplugin.h b/webkit/glue/webplugin.h index 051eb2c..1c79876 100644 --- a/webkit/glue/webplugin.h +++ b/webkit/glue/webplugin.h @@ -39,6 +39,15 @@ struct WebPluginGeometry { // On Windows, this is the plugin window in the plugin process. // On X11, this is the XID of the plugin-side GtkPlug containing the // GtkSocket hosting the actual plugin window. + // + // On Mac OS X, all of the plugin types are currently "windowless" + // (window == 0) except for the special case of the GPU plugin, + // which currently performs rendering on behalf of the Pepper 3D API + // and WebGL. The GPU plugin uses a simple integer for the + // PluginWindowHandle which is used to map to a side data structure + // containing information about the plugin. Soon this plugin will be + // generalized, at which point this mechanism will be rethought or + // removed. gfx::PluginWindowHandle window; gfx::Rect window_rect; // Clip rect (include) and cutouts (excludes), relative to diff --git a/webkit/glue/webplugin_impl.cc b/webkit/glue/webplugin_impl.cc index ceb4239..20b86b4 100644 --- a/webkit/glue/webplugin_impl.cc +++ b/webkit/glue/webplugin_impl.cc @@ -406,6 +406,23 @@ WebPluginImpl::~WebPluginImpl() { } void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) { +#if defined(OS_MACOSX) + // The only time this is called twice, and the second time with a + // non-zero PluginWindowHandle, is the case when this WebPluginImpl + // is created on behalf of the GPU plugin. This entire code path + // will go away soon, as soon as the GPU plugin becomes the GPU + // process, so it is being separated out for easy deletion. + + // The logic we want here is: if (window) DCHECK(!window_); + DCHECK(!(window_ && window)); + window_ = window; + // Lie to ourselves about being windowless even if we got a fake + // plugin window handle, so we continue to get input events. + windowless_ = true; + accepts_input_events_ = true; + // We do not really need to notify the page delegate that a plugin + // window was created -- so don't. +#else if (window) { DCHECK(!windowless_); window_ = window; @@ -420,6 +437,7 @@ void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) { windowless_ = true; accepts_input_events_ = true; } +#endif } void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) { diff --git a/webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp b/webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp index f36abf7..0f799f5 100644 --- a/webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp +++ b/webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp @@ -58,25 +58,19 @@ 'cflags': ['-fPIC'], 'defines': ['INDEPENDENT_PLUGIN'], }, { + # Dependencies for all other OS/CPU combinations except the Linux ones above 'dependencies': [ '../../../base/base.gyp:base', '../../../skia/skia.gyp:skia', + '../../../gpu/gpu.gyp:gles2_demo_lib', + '../../../gpu/gpu.gyp:pgl', ], - 'conditions': [ - ['OS!="mac"', { - 'dependencies': [ - '../../../gpu/gpu.gyp:gles2_demo_lib', - '../../../gpu/gpu.gyp:pgl', - ], - }], - ] }], ['OS=="mac"', { 'type': 'loadable_module', 'mac_bundle': 1, 'product_name': 'PepperTestPlugin', 'product_extension': 'plugin', - 'defines': ['INDEPENDENT_PLUGIN'], 'sources+': [ 'Info.plist' ], diff --git a/webkit/tools/pepper_test_plugin/plugin_object.cc b/webkit/tools/pepper_test_plugin/plugin_object.cc index a2075ec..013702b 100644 --- a/webkit/tools/pepper_test_plugin/plugin_object.cc +++ b/webkit/tools/pepper_test_plugin/plugin_object.cc @@ -34,8 +34,9 @@ #define CHECK(x) #else #include "base/logging.h" +#include "build/build_config.h" #include "gpu/command_buffer/client/gles2_demo_cc.h" -#include "gpu/command_buffer/common/GLES2/gl2.h" +#include <GLES2/gl2.h> // NOLINT #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/effects/SkGradientShader.h" @@ -308,7 +309,10 @@ PluginObject::PluginObject(NPP npp) } PluginObject::~PluginObject() { + // TODO(kbr): add audio portion of test +#if !defined(OS_MACOSX) deviceaudio_->destroyContext(npp_, &context_audio_); +#endif // FIXME(brettw) destroy the context. browser->releaseobject(test_object_); } @@ -347,8 +351,11 @@ void PluginObject::New(NPMIMEType pluginType, device3d_ = extensions->acquireDevice(npp_, NPPepper3DDevice); CHECK(device3d_); + // TODO(kbr): add audio portion of test +#if !defined(OS_MACOSX) deviceaudio_ = extensions->acquireDevice(npp_, NPPepperAudioDevice); CHECK(deviceaudio_); +#endif } void PluginObject::SetWindow(const NPWindow& window) { @@ -389,6 +396,8 @@ void PluginObject::SetWindow(const NPWindow& window) { #endif } + // TODO(kbr): put back in audio portion of test +#if !defined(OS_MACOSX) // testing any field would do if (!context_audio_.config.callback) { NPDeviceContextAudioConfig cfg; @@ -401,6 +410,7 @@ void PluginObject::SetWindow(const NPWindow& window) { cfg.callback = &SineWaveCallback<200, int16>; deviceaudio_->initializeContext(npp_, &cfg, &context_audio_); } +#endif } void PluginObject::Draw3D() { diff --git a/webkit/tools/pepper_test_plugin/test_page.html b/webkit/tools/pepper_test_plugin/test_page.html index 5a3e609..5c20d6d 100644 --- a/webkit/tools/pepper_test_plugin/test_page.html +++ b/webkit/tools/pepper_test_plugin/test_page.html @@ -29,7 +29,7 @@ This page embeds a file declared as the pepper test plugins MIME type so that it <table> <tr> <td valign="top" width="50%"> -<object id="plugin" type="pepper-application/x-pepper-test-plugin" width="400" height="400" dimensions="2" /> +<object id="plugin" type="pepper-application/x-pepper-test-plugin" width="400" height="400" dimensions="3" /> </td> <td valign="top" style="background-color:Silver" width="50%"> <div id="event_text_box" style="width:400px; height:400px; overflow:auto"> @@ -39,4 +39,4 @@ This page embeds a file declared as the pepper test plugins MIME type so that it </table> </body> -</html>
\ No newline at end of file +</html> diff --git a/webkit/tools/test_shell/mac/test_webview_delegate.mm b/webkit/tools/test_shell/mac/test_webview_delegate.mm index 483e776..cb2a392 100644 --- a/webkit/tools/test_shell/mac/test_webview_delegate.mm +++ b/webkit/tools/test_shell/mac/test_webview_delegate.mm @@ -171,7 +171,7 @@ webkit_glue::WebPluginDelegate* TestWebViewDelegate::CreatePluginDelegate( WebWidgetHost *host = GetWidgetHost(); if (!host) return NULL; - gfx::NativeView view = host->view_handle(); + gfx::PluginWindowHandle containing_view = NULL; bool allow_wildcard = true; WebPluginInfo info; @@ -181,9 +181,11 @@ webkit_glue::WebPluginDelegate* TestWebViewDelegate::CreatePluginDelegate( } if (actual_mime_type && !actual_mime_type->empty()) - return WebPluginDelegateImpl::Create(info.path, *actual_mime_type, view); + return WebPluginDelegateImpl::Create(info.path, *actual_mime_type, + containing_view); else - return WebPluginDelegateImpl::Create(info.path, mime_type, view); + return WebPluginDelegateImpl::Create(info.path, mime_type, + containing_view); } void TestWebViewDelegate::CreatedPluginWindow( diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 3270eac..0863370 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -262,6 +262,10 @@ 'glue/plugins/gtk_plugin_container.cc', 'glue/plugins/gtk_plugin_container_manager.h', 'glue/plugins/gtk_plugin_container_manager.cc', + 'glue/plugins/mac_gpu_plugin_container.h', + 'glue/plugins/mac_gpu_plugin_container.cc', + 'glue/plugins/mac_gpu_plugin_container_manager.h', + 'glue/plugins/mac_gpu_plugin_container_manager.cc', 'glue/plugins/npapi_extension_thunk.cc', 'glue/plugins/npapi_extension_thunk.h', 'glue/plugins/plugin_constants_win.h', @@ -416,9 +420,10 @@ ['exclude', r'/gtk_']], }], ['OS!="mac"', { - 'sources/': [['exclude', '_mac\\.(cc|mm)$']], + 'sources/': [['exclude', '_mac\\.(cc|mm)$'], + ['exclude', r'/mac_']], }], - ['OS=="win" or (OS=="linux" and target_arch!="arm")', { + ['enable_gpu==1', { 'dependencies': [ '../gpu/gpu.gyp:gpu_plugin', ], |