0

[GPU] Get GPU process running on the mac

Initial port of GPU process / plugin to Mac OS X. Uses new IOSurface
APIs and therefore currently runs only on 10.6. Alternate strategy
will need to be devised for 10.5.

Slight UI issues remain such as GPU plugins initially showing up in
the wrong place on the page. These will be fixed in follow-on bugs.

Minimal changes made to command buffer code to get it to compile on
Mac OS X. Commented out use of nested anonymous namespaces in
gles2_cmd_decoder.cc which were causing the linker to crash with a seg
fault.

Refactored gyp files so the OS test enabling the GPU plugin is in one
place, common.gypi, and other files test only the variable enable_gpu.

Slight change to gles2_demo_cc.cc to add some simple animation to
verify that updates from the GPU plugin are reaching the screen.
Changed Pepper test plugin to use 3D view by default and commented out
use of audio context because of recent issues.

TEST=none (ran Pepper Test Plugin with 3D view enabled)
BUG=http://crbug.com/25988

Review URL: http://codereview.chromium.org/558035

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37934 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
kbr@google.com
2010-02-03 02:28:48 +00:00
parent 2d48004e1f
commit 43f28f83bc
55 changed files with 1638 additions and 46 deletions

@ -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

@ -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',
],

@ -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(

@ -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.

@ -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)

@ -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);
};

@ -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 {

@ -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) {

@ -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)

@ -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',
],

@ -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',

@ -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',

@ -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',

@ -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)

@ -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,

@ -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() {
}

@ -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_

@ -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)

@ -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

@ -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()
}

@ -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_;

@ -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

@ -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);

@ -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

@ -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_;

@ -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

@ -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();

@ -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();

@ -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

@ -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",
]

@ -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);

@ -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) {

@ -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);

@ -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) {

@ -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();

@ -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));

@ -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

@ -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

@ -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

@ -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',
],
},
],
],
},
{

@ -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

@ -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

@ -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;
}

@ -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_

@ -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;
}

@ -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_

@ -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

@ -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

@ -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) {

@ -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'
],

@ -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() {

@ -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>
</html>

@ -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(

@ -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',
],