summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/chrome_main.cc6
-rw-r--r--chrome/chrome.gyp10
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/gpu_plugin.cc36
-rw-r--r--chrome/common/gpu_plugin.h16
-rw-r--r--chrome/common/plugin_messages_internal.h5
-rw-r--r--chrome/plugin/command_buffer_stub.cc195
-rw-r--r--chrome/plugin/command_buffer_stub.h84
-rw-r--r--chrome/plugin/command_buffer_stub_win.cc73
-rw-r--r--chrome/plugin/plugin_main.cc2
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc38
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h9
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.cc455
-rw-r--r--chrome/renderer/webplugin_delegate_pepper.h37
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc31
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h4
-rw-r--r--chrome/test/ui/pepper_uitest.cc47
-rw-r--r--content/browser/plugin_process_host.cc1
-rw-r--r--content/browser/plugin_service.cc3
-rw-r--r--gpu/gpu.gyp20
-rw-r--r--webkit/glue/webkit_glue.gypi5
22 files changed, 1061 insertions, 19 deletions
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index b8f5a15..71bb4c2 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -517,6 +517,12 @@ int ChromeMain(int argc, char** argv) {
return 1;
#endif
+ if (command_line.HasSwitch(switches::kEnableNaCl)) {
+ // NaCl currently requires two flags to run
+ CommandLine* singleton_command_line = CommandLine::ForCurrentProcess();
+ singleton_command_line->AppendSwitch(switches::kEnableGPUPlugin);
+ }
+
base::ProcessId browser_pid = base::GetCurrentProcId();
if (SubprocessIsBrowserChild(process_type)) {
#if defined(OS_WIN) || defined(OS_MACOSX)
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index f7a2c0f..49b2219 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -601,6 +601,16 @@
'<(DEPTH)/third_party/wtl/include',
],
}],
+ ['enable_gpu==1', {
+ 'dependencies': [
+ '../gpu/gpu.gyp:command_buffer_service',
+ ],
+ 'sources': [
+ 'plugin/command_buffer_stub.cc',
+ 'plugin/command_buffer_stub.h',
+ 'plugin/command_buffer_stub_win.cc',
+ ],
+ },],
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
'dependencies': [
'../build/linux/system.gyp:gtk',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 8b678d1..3fad755 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -303,6 +303,8 @@
'common/font_loader_mac.h',
'common/font_loader_mac.mm',
'common/gears_api.h',
+ 'common/gpu_plugin.cc',
+ 'common/gpu_plugin.h',
'common/important_file_writer.cc',
'common/important_file_writer.h',
'common/json_pref_store.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 31b3f76..83b46df 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -591,6 +591,7 @@
'test/ui/named_interface_uitest.cc',
'test/ui/npapi_uitest.cc',
'test/ui/omnibox_uitest.cc',
+ 'test/ui/pepper_uitest.cc',
'test/ui/ppapi_uitest.cc',
'test/ui/sandbox_uitests.cc',
'test/ui/sunspider_uitest.cc',
diff --git a/chrome/common/gpu_plugin.cc b/chrome/common/gpu_plugin.cc
new file mode 100644
index 0000000..fd4c680
--- /dev/null
+++ b/chrome/common/gpu_plugin.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/gpu_plugin.h"
+
+#include "base/command_line.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/chrome_switches.h"
+#include "gpu/gpu_plugin/gpu_plugin.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+
+namespace chrome {
+
+void RegisterInternalGPUPlugin() {
+#if defined(ENABLE_GPU)
+ const webkit::npapi::PluginEntryPoints entry_points = {
+#if !defined(OS_POSIX) || defined(OS_MACOSX)
+ gpu_plugin::NP_GetEntryPoints,
+#endif
+ gpu_plugin::NP_Initialize,
+ gpu_plugin::NP_Shutdown
+ };
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableGPUPlugin))
+ webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(
+ FilePath(FILE_PATH_LITERAL("gpu-plugin")),
+ "GPU Plug-in",
+ "GPU Rendering Plug-in",
+ "application/vnd.google.chrome.gpu-plugin",
+ entry_points);
+#endif // ENABLE_GPU
+}
+
+} // namespace chrome
diff --git a/chrome/common/gpu_plugin.h b/chrome/common/gpu_plugin.h
new file mode 100644
index 0000000..938cbc2e
--- /dev/null
+++ b/chrome/common/gpu_plugin.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2009 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_GPU_PLUGIN_H_
+#define CHROME_COMMON_GPU_PLUGIN_H_
+#pragma once
+
+namespace chrome {
+
+// Register the GPU plugin as an internal plugin in the PluginList.
+void RegisterInternalGPUPlugin();
+
+} // namespace chrome
+
+#endif // CHROME_COMMON_GPU_PLUGIN_H_
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index dec7a89..98ed543 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -285,6 +285,11 @@ IPC_MESSAGE_ROUTED2(PluginMsg_HTTPRangeRequestReply,
unsigned long /* resource_id */,
int /* range_request_id */)
+IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_CreateCommandBuffer,
+ int /* route_id */)
+
+IPC_MESSAGE_ROUTED0(PluginMsg_DestroyCommandBuffer)
+
IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent,
gfx::NativeViewId /* containing_window */)
diff --git a/chrome/plugin/command_buffer_stub.cc b/chrome/plugin/command_buffer_stub.cc
new file mode 100644
index 0000000..9aea1ee
--- /dev/null
+++ b/chrome/plugin/command_buffer_stub.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/plugin/command_buffer_stub.h"
+
+#include "base/callback.h"
+#include "base/scoped_open_process.h"
+#include "base/shared_memory.h"
+#include "chrome/common/gpu_messages.h"
+#include "chrome/common/plugin_messages.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, NULL);
+}
+
+CommandBufferStub::~CommandBufferStub() {
+ Destroy();
+ channel_->RemoveRoute(route_id_);
+}
+
+bool CommandBufferStub::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(CommandBufferStub, message)
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Initialize, OnInitialize);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetState, OnGetState);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncGetState, OnAsyncGetState);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Flush, OnFlush);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateTransferBuffer,
+ OnCreateTransferBuffer);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer,
+ OnDestroyTransferBuffer);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetTransferBuffer,
+ OnGetTransferBuffer);
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetWindowSize, OnSetWindowSize);
+#endif
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ DCHECK(handled);
+ return handled;
+}
+
+void CommandBufferStub::OnChannelError() {
+ NOTREACHED() << "CommandBufferService::OnChannelError called";
+}
+
+bool CommandBufferStub::Send(IPC::Message* message) {
+ if (!channel_) {
+ delete message;
+ return false;
+ }
+
+ return channel_->Send(message);
+}
+
+void CommandBufferStub::NotifyRepaint() {
+ Send(new GpuCommandBufferMsg_NotifyRepaint(route_id_));
+}
+
+void CommandBufferStub::OnInitialize(base::SharedMemoryHandle ring_buffer,
+ int32 size,
+ bool* result) {
+ // TODO(apatrick): Pepper3D v1 is not used anymore. This function is never
+ // called. Delete the GPU plugin.
+ NOTREACHED();
+ *result = false;
+}
+
+void CommandBufferStub::OnGetState(gpu::CommandBuffer::State* state) {
+ *state = command_buffer_->GetState();
+}
+
+void CommandBufferStub::OnAsyncGetState() {
+ gpu::CommandBuffer::State state = command_buffer_->GetState();
+ Send(new GpuCommandBufferMsg_UpdateState(route_id_, state));
+}
+
+void CommandBufferStub::OnFlush(int32 put_offset,
+ gpu::CommandBuffer::State* state) {
+ *state = command_buffer_->FlushSync(put_offset);
+}
+
+void CommandBufferStub::OnAsyncFlush(int32 put_offset) {
+ gpu::CommandBuffer::State state = command_buffer_->FlushSync(put_offset);
+ Send(new GpuCommandBufferMsg_UpdateState(route_id_, state));
+}
+
+void CommandBufferStub::OnCreateTransferBuffer(int32 size, int32* id) {
+ *id = command_buffer_->CreateTransferBuffer(size);
+}
+
+void CommandBufferStub::OnDestroyTransferBuffer(int32 id) {
+ command_buffer_->DestroyTransferBuffer(id);
+}
+
+void CommandBufferStub::OnGetTransferBuffer(
+ int32 id,
+ base::SharedMemoryHandle* transfer_buffer,
+ uint32* size) {
+ *transfer_buffer = base::SharedMemoryHandle();
+ *size = 0;
+
+ // Assume service is responsible for duplicating the handle to the calling
+ // process.
+ base::ProcessHandle peer_handle;
+ if (!base::OpenProcessHandle(channel_->peer_pid(), &peer_handle))
+ return;
+
+ Buffer buffer = command_buffer_->GetTransferBuffer(id);
+ if (buffer.shared_memory) {
+ buffer.shared_memory->ShareToProcess(peer_handle, transfer_buffer);
+ *size = buffer.shared_memory->created_size();
+ }
+
+ base::CloseProcessHandle(peer_handle);
+}
+
+void CommandBufferStub::Destroy() {
+ processor_.reset();
+ command_buffer_.reset();
+
+ DestroyPlatformSpecific();
+}
+
+#if !defined(OS_WIN)
+bool CommandBufferStub::InitializePlatformSpecific() {
+ return true;
+}
+
+void CommandBufferStub::DestroyPlatformSpecific() {
+}
+#endif // defined(OS_WIN)
+
+#if defined(OS_MACOSX)
+void CommandBufferStub::OnSetWindowSize(const gfx::Size& size) {
+ // Try using the IOSurface version first.
+ bool notify_repaint = false;
+ uint64 new_backing_store = processor_->SetWindowSizeForIOSurface(size);
+ if (new_backing_store) {
+ Send(new PluginHostMsg_AcceleratedSurfaceSetIOSurface(
+ plugin_host_route_id_,
+ window_,
+ size.width(),
+ size.height(),
+ new_backing_store));
+ notify_repaint = true;
+ } else {
+ // If |new_backing_store| is 0, it might mean that the IOSurface APIs are
+ // not available. In this case, see if TransportDIBs are supported.
+ TransportDIB::Handle transport_dib =
+ processor_->SetWindowSizeForTransportDIB(size);
+ if (TransportDIB::is_valid(transport_dib)) {
+ Send(new PluginHostMsg_AcceleratedSurfaceSetTransportDIB(
+ plugin_host_route_id_,
+ window_,
+ size.width(),
+ size.height(),
+ transport_dib));
+ notify_repaint = true;
+ }
+ }
+ if (notify_repaint) {
+ // Indicate to the client that at least one repaint is needed.
+ NotifyRepaint();
+ }
+}
+
+void CommandBufferStub::SwapBuffersCallback() {
+ Send(new PluginHostMsg_AcceleratedSurfaceBuffersSwapped(
+ plugin_host_route_id_, window_, processor_->GetSurfaceId()));
+}
+
+void CommandBufferStub::AllocTransportDIB(const size_t size,
+ TransportDIB::Handle* dib_handle) {
+ Send(new PluginHostMsg_AllocTransportDIB(plugin_host_route_id_,
+ size,
+ dib_handle));
+}
+
+void CommandBufferStub::FreeTransportDIB(TransportDIB::Id dib_id) {
+ Send(new PluginHostMsg_FreeTransportDIB(plugin_host_route_id_,
+ dib_id));
+}
+#endif
diff --git a/chrome/plugin/command_buffer_stub.h b/chrome/plugin/command_buffer_stub.h
new file mode 100644
index 0000000..a2667f1
--- /dev/null
+++ b/chrome/plugin/command_buffer_stub.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2009 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_PLUGIN_COMMAND_BUFFER_STUB_H_
+#define CHROME_PLUGIN_COMMAND_BUFFER_STUB_H_
+#pragma once
+
+#if defined(ENABLE_GPU)
+
+#include "app/surface/transport_dib.h"
+#include "base/ref_counted.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gpu_processor.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_message.h"
+#include "ui/gfx/native_widget_types.h"
+
+class PluginChannel;
+
+class CommandBufferService;
+
+class CommandBufferStub : public IPC::Channel::Listener,
+ public IPC::Message::Sender {
+ public:
+ CommandBufferStub(PluginChannel* channel,
+ int plugin_host_route_id,
+ gfx::PluginWindowHandle window);
+
+ virtual ~CommandBufferStub();
+
+ // IPC::Channel::Listener implementation:
+ virtual bool OnMessageReceived(const IPC::Message& message);
+ virtual void OnChannelError();
+
+ // IPC::Message::Sender implementation:
+ virtual bool Send(IPC::Message* msg);
+
+ int route_id() const { return route_id_; }
+
+ // Notify the client that it must repaint due to the window becoming invalid
+ // or a lost context.
+ void NotifyRepaint();
+
+ private:
+ // Message handlers:
+ void OnInitialize(base::SharedMemoryHandle ring_buffer,
+ int32 size,
+ bool* result);
+ void OnGetState(gpu::CommandBuffer::State* state);
+ void OnAsyncGetState();
+ void OnFlush(int32 put_offset, gpu::CommandBuffer::State* state);
+ void OnAsyncFlush(int32 put_offset);
+ void OnCreateTransferBuffer(int32 size, int32* id);
+ void OnDestroyTransferBuffer(int32 id);
+ void OnGetTransferBuffer(int32 id,
+ base::SharedMemoryHandle* transfer_buffer,
+ uint32* size);
+
+ // Destroy all owned objects.
+ void Destroy();
+
+ bool InitializePlatformSpecific();
+ void DestroyPlatformSpecific();
+
+#if defined(OS_MACOSX)
+ void OnSetWindowSize(const gfx::Size& size);
+ void SwapBuffersCallback();
+ void AllocTransportDIB(const size_t size, TransportDIB::Handle* dib_handle);
+ void FreeTransportDIB(TransportDIB::Id dib_id);
+#endif
+
+ scoped_refptr<PluginChannel> channel_;
+ int plugin_host_route_id_;
+ gfx::PluginWindowHandle window_;
+ int route_id_;
+ scoped_ptr<gpu::CommandBufferService> command_buffer_;
+ scoped_ptr<gpu::GPUProcessor> processor_;
+};
+
+#endif // ENABLE_GPU
+
+#endif // CHROME_PLUGIN_COMMAND_BUFFER_STUB_H_
diff --git a/chrome/plugin/command_buffer_stub_win.cc b/chrome/plugin/command_buffer_stub_win.cc
new file mode 100644
index 0000000..11369a6
--- /dev/null
+++ b/chrome/plugin/command_buffer_stub_win.cc
@@ -0,0 +1,73 @@
+// 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 <windows.h>
+
+#include "chrome/plugin/command_buffer_stub.h"
+
+namespace {
+const wchar_t* kPreviousWndProcProperty = L"CommandBufferStubPrevWndProc";
+const wchar_t* kCommandBufferStubProperty = L"CommandBufferStub";
+
+// Message handler for the GPU plugin's child window. Used to intercept
+// WM_PAINT events and forward repaint notifications to the client.
+LRESULT WINAPI WndProc(HWND handle,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ WNDPROC previous_wnd_proc = reinterpret_cast<WNDPROC>(
+ ::GetProp(handle, kPreviousWndProcProperty));
+ CommandBufferStub* stub = reinterpret_cast<CommandBufferStub*>(
+ ::GetProp(handle, kCommandBufferStubProperty));
+
+ switch (message) {
+ case WM_ERASEBKGND:
+ // Do not clear background. Avoids flickering.
+ return 1;
+ case WM_PAINT:
+ // Validate the whole window to prevent another WM_PAINT message.
+ ValidateRect(handle, NULL);
+
+ // Notify client that the window is invalid and needs to be repainted.
+ stub->NotifyRepaint();
+
+ return 1;
+ default:
+ return CallWindowProc(previous_wnd_proc,
+ handle,
+ message,
+ w_param,
+ l_param);
+ }
+}
+} // namespace anonymous
+
+bool CommandBufferStub::InitializePlatformSpecific() {
+ // Subclass window.
+ WNDPROC previous_wnd_proc = reinterpret_cast<WNDPROC>(
+ ::GetWindowLongPtr(window_, GWLP_WNDPROC));
+ ::SetProp(window_,
+ kPreviousWndProcProperty,
+ reinterpret_cast<HANDLE>(previous_wnd_proc));
+ ::SetWindowLongPtr(window_,
+ GWLP_WNDPROC,
+ reinterpret_cast<LONG_PTR>(WndProc));
+
+ // Record pointer to this in window.
+ ::SetProp(window_,
+ kCommandBufferStubProperty,
+ reinterpret_cast<HANDLE>(this));
+
+ return true;
+}
+
+void CommandBufferStub::DestroyPlatformSpecific() {
+ // Restore window.
+ WNDPROC previous_wnd_proc = reinterpret_cast<WNDPROC>(
+ ::GetProp(window_, kPreviousWndProcProperty));
+ ::SetWindowLongPtr(window_, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(
+ previous_wnd_proc));
+ ::RemoveProp(window_, kPreviousWndProcProperty);
+ ::RemoveProp(window_, kCommandBufferStubProperty);
+}
diff --git a/chrome/plugin/plugin_main.cc b/chrome/plugin/plugin_main.cc
index d8264fe..5c94e52 100644
--- a/chrome/plugin/plugin_main.cc
+++ b/chrome/plugin/plugin_main.cc
@@ -17,6 +17,7 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/default_plugin.h"
+#include "chrome/common/gpu_plugin.h"
#include "chrome/common/hi_res_timer_manager.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/main_function_params.h"
@@ -173,6 +174,7 @@ int PluginMain(const MainFunctionParams& parameters) {
#endif
chrome::RegisterInternalDefaultPlugin();
+ chrome::RegisterInternalGPUPlugin();
MessageLoop::current()->Run();
}
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc
index 0624e3e..75a3dc8 100644
--- a/chrome/plugin/webplugin_delegate_stub.cc
+++ b/chrome/plugin/webplugin_delegate_stub.cc
@@ -28,6 +28,10 @@
#include "printing/native_metafile.h"
#endif // defined(OS_WIN)
+#if defined(ENABLE_GPU)
+#include "app/gfx/gl/gl_context.h"
+#endif
+
using WebKit::WebBindings;
using WebKit::WebCursorInfo;
using webkit::npapi::WebPlugin;
@@ -68,6 +72,13 @@ WebPluginDelegateStub::~WebPluginDelegateStub() {
in_destructor_ = true;
child_process_logging::SetActiveURL(page_url_);
+#if defined(ENABLE_GPU)
+ // Make sure there is no command buffer before destroying the window handle.
+ // The GPU service code might otherwise asynchronously perform an operation
+ // using the window handle.
+ command_buffer_stub_.reset();
+#endif
+
if (channel_->in_send()) {
// The delegate or an npobject is in the callstack, so don't delete it
// right away.
@@ -133,6 +144,10 @@ bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) {
OnHandleURLRequestReply)
IPC_MESSAGE_HANDLER(PluginMsg_HTTPRangeRequestReply,
OnHTTPRangeRequestReply)
+ IPC_MESSAGE_HANDLER(PluginMsg_CreateCommandBuffer,
+ OnCreateCommandBuffer)
+ IPC_MESSAGE_HANDLER(PluginMsg_DestroyCommandBuffer,
+ OnDestroyCommandBuffer)
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(PluginMsg_SetFakeAcceleratedSurfaceWindowHandle,
OnSetFakeAcceleratedSurfaceWindowHandle)
@@ -401,6 +416,29 @@ void WebPluginDelegateStub::OnInstallMissingPlugin() {
delegate_->InstallMissingPlugin();
}
+void WebPluginDelegateStub::OnCreateCommandBuffer(int* route_id) {
+ *route_id = 0;
+#if defined(ENABLE_GPU)
+ // Fail to create the command buffer if some GL implementation cannot be
+ // initialized.
+ if (!gfx::GLContext::InitializeOneOff())
+ return;
+
+ command_buffer_stub_.reset(new CommandBufferStub(
+ channel_,
+ instance_id_,
+ delegate_->windowed_handle()));
+
+ *route_id = command_buffer_stub_->route_id();
+#endif // ENABLE_GPU
+}
+
+void WebPluginDelegateStub::OnDestroyCommandBuffer() {
+#if defined(ENABLE_GPU)
+ command_buffer_stub_.reset();
+#endif
+}
+
void WebPluginDelegateStub::CreateSharedBuffer(
uint32 size,
base::SharedMemory* shared_buf,
diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h
index b56bca7..e769a84 100644
--- a/chrome/plugin/webplugin_delegate_stub.h
+++ b/chrome/plugin/webplugin_delegate_stub.h
@@ -12,10 +12,10 @@
#include "base/ref_counted.h"
#include "base/shared_memory.h"
#include "base/task.h"
+#include "chrome/plugin/command_buffer_stub.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_channel.h"
#include "third_party/npapi/bindings/npapi.h"
-#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
class PluginChannel;
@@ -103,6 +103,8 @@ class WebPluginDelegateStub : public IPC::Channel::Listener,
const GURL& url,
int notify_id);
void OnHTTPRangeRequestReply(unsigned long resource_id, int range_request_id);
+ void OnCreateCommandBuffer(int* route_id);
+ void OnDestroyCommandBuffer();
void CreateSharedBuffer(uint32 size,
base::SharedMemory* shared_buf,
@@ -121,12 +123,17 @@ class WebPluginDelegateStub : public IPC::Channel::Listener,
GURL page_url_;
#if defined(ENABLE_GPU)
+ // 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 a GPU-accelerated plug-in, we need to be able to receive a fake
// window handle which is used for subsequent communication back to the
// browser.
void OnSetFakeAcceleratedSurfaceWindowHandle(gfx::PluginWindowHandle window);
#endif
+
#endif
DISALLOW_IMPLICIT_CONSTRUCTORS(WebPluginDelegateStub);
diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc
index 7a9e4ea..43709f8 100644
--- a/chrome/renderer/webplugin_delegate_pepper.cc
+++ b/chrome/renderer/webplugin_delegate_pepper.cc
@@ -63,6 +63,14 @@
#include "ui/gfx/gdi_util.h"
#endif
+#if defined(ENABLE_GPU)
+#include "webkit/plugins/npapi/plugin_constants_win.h"
+#endif
+
+#if defined(ENABLE_GPU)
+using gpu::Buffer;
+#endif
+
using webkit::npapi::WebPlugin;
using webkit::npapi::WebPluginDelegate;
using webkit::npapi::WebPluginResourceClient;
@@ -79,6 +87,15 @@ struct Device2DImpl {
TransportDIB* dib;
};
+struct Device3DImpl {
+#if defined(ENABLE_GPU)
+ gpu::CommandBuffer* command_buffer;
+#endif
+ bool dynamically_created;
+};
+
+const int32 kDefaultCommandBufferSize = 1024 * 1024;
+
} // namespace
static const float kPointsPerInch = 72.0;
@@ -180,6 +197,22 @@ void WebPluginDelegatePepper::DestroyInstance() {
instance_ = 0;
}
+
+ // Destroy the nested GPU plugin only after first destroying the underlying
+ // Pepper plugin. This is so the Pepper plugin does not attempt to issue
+ // rendering commands after the GPU plugin has stopped processing them and
+ // responding to them.
+ if (nested_delegate_) {
+#if defined(ENABLE_GPU)
+ if (command_buffer_) {
+ nested_delegate_->DestroyCommandBuffer(command_buffer_);
+ command_buffer_ = NULL;
+ }
+#endif
+
+ nested_delegate_->PluginDestroyed();
+ nested_delegate_ = NULL;
+ }
}
void WebPluginDelegatePepper::UpdateGeometry(
@@ -204,6 +237,21 @@ void WebPluginDelegatePepper::UpdateGeometry(
new_committed.allocPixels();
committed_bitmap_ = new_committed;
+ // Forward the new geometry to the nested plugin instance.
+ 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_) {
+ command_buffer_->SetWindowSize(window_rect_.size());
+ }
+#endif // OS_MACOSX
+#endif // ENABLE_GPU
+
if (!instance())
return;
@@ -519,7 +567,8 @@ NPError WebPluginDelegatePepper::Device2DInitializeContext(
}
// This is a windowless plugin, so set it to have no handle. Defer this
- // until we know the plugin will use the 2D device.
+ // until we know the plugin will use the 2D device. If it uses the 3D device
+ // it will have a window handle.
plugin_->SetWindow(gfx::kNullPluginWindow);
scoped_ptr<Graphics2DDeviceContext> g2d(new Graphics2DDeviceContext(this));
@@ -620,6 +669,76 @@ NPError WebPluginDelegatePepper::Device3DQueryConfig(
NPError WebPluginDelegatePepper::Device3DInitializeContext(
const NPDeviceContext3DConfig* config,
NPDeviceContext3D* context) {
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+#if defined(ENABLE_GPU)
+ // Check to see if the GPU plugin is already initialized and fail if so.
+ if (nested_delegate_)
+ return NPERR_GENERIC_ERROR;
+
+ // Create an instance of the GPU plugin that is responsible for 3D
+ // rendering.
+ nested_delegate_ = new WebPluginDelegateProxy(
+ "application/vnd.google.chrome.gpu-plugin", render_view_);
+
+ // TODO(apatrick): should the GPU plugin be attached to plugin_?
+ if (nested_delegate_->Initialize(GURL(),
+ std::vector<std::string>(),
+ std::vector<std::string>(),
+ plugin_,
+ false)) {
+ plugin_->SetAcceptsInputEvents(true);
+
+ // Ensure the window has the correct size before initializing the
+ // command buffer.
+ nested_delegate_->UpdateGeometry(window_rect_, clip_rect_);
+
+ // Ask the GPU plugin to create a command buffer and return a proxy.
+ command_buffer_ = nested_delegate_->CreateCommandBuffer();
+ if (command_buffer_) {
+ // Initialize the proxy command buffer.
+ if (command_buffer_->Initialize(config->commandBufferSize)) {
+ // Get the initial command buffer state.
+ gpu::CommandBuffer::State state = command_buffer_->GetState();
+
+ // Initialize the 3D context.
+ context->reserved = NULL;
+ context->waitForProgress = true;
+ Buffer ring_buffer = command_buffer_->GetRingBuffer();
+ context->commandBuffer = ring_buffer.ptr;
+ context->commandBufferSize = state.num_entries;
+ context->repaintCallback = NULL;
+ Synchronize3DContext(context, state);
+
+ ScheduleHandleRepaint(instance_->npp(), context);
+
+#if defined(OS_MACOSX)
+ command_buffer_->SetWindowSize(window_rect_.size());
+#endif // OS_MACOSX
+
+ // Make sure the nested delegate shows up in the right place
+ // on the page.
+ SendNestedDelegateGeometryToBrowser(window_rect_, clip_rect_);
+
+ // Save the implementation information (the CommandBuffer).
+ Device3DImpl* impl = new Device3DImpl;
+ impl->command_buffer = command_buffer_;
+ impl->dynamically_created = false;
+ context->reserved = impl;
+
+ return NPERR_NO_ERROR;
+ }
+
+ nested_delegate_->DestroyCommandBuffer(command_buffer_);
+ command_buffer_ = NULL;
+ }
+ }
+
+ nested_delegate_->PluginDestroyed();
+ nested_delegate_ = NULL;
+#endif // ENABLE_GPU
+
return NPERR_GENERIC_ERROR;
}
@@ -642,49 +761,212 @@ NPError WebPluginDelegatePepper::Device3DFlushContext(
NPDeviceContext3D* context,
NPDeviceFlushContextCallbackPtr callback,
void* user_data) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+#if defined(ENABLE_GPU)
+ gpu::CommandBuffer::State state;
+
+ if (context->waitForProgress) {
+ if (callback) {
+ command_buffer_->AsyncFlush(
+ context->putOffset,
+ method_factory3d_.NewRunnableMethod(
+ &WebPluginDelegatePepper::Device3DUpdateState,
+ id,
+ context,
+ callback,
+ user_data));
+ } else {
+ state = command_buffer_->FlushSync(context->putOffset);
+ Synchronize3DContext(context, state);
+ }
+ } else {
+ if (callback) {
+ command_buffer_->AsyncGetState(
+ method_factory3d_.NewRunnableMethod(
+ &WebPluginDelegatePepper::Device3DUpdateState,
+ id,
+ context,
+ callback,
+ user_data));
+ } else {
+ state = command_buffer_->GetState();
+ Synchronize3DContext(context, state);
+ }
+ }
+#endif // ENABLE_GPU
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DDestroyContext(
NPDeviceContext3D* context) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+#if defined(ENABLE_GPU)
+ // Prevent any async flush callbacks from being invoked after the context
+ // has been destroyed.
+ method_factory3d_.RevokeAll();
+
+ // TODO(apatrick): this will be much simpler when we switch to the new device
+ // API. There should be no need for the Device3DImpl and the context will
+ // always be destroyed dynamically.
+ Device3DImpl* impl = static_cast<Device3DImpl*>(context->reserved);
+ bool dynamically_created = impl->dynamically_created;
+ delete impl;
+ context->reserved = NULL;
+ if (dynamically_created) {
+ delete context;
+ }
+
+ if (nested_delegate_) {
+ if (command_buffer_) {
+ nested_delegate_->DestroyCommandBuffer(command_buffer_);
+ command_buffer_ = NULL;
+ }
+
+ nested_delegate_->PluginDestroyed();
+ nested_delegate_ = NULL;
+ }
+#endif // ENABLE_GPU
+
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DCreateBuffer(
NPDeviceContext3D* context,
size_t size,
int32* id) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+#if defined(ENABLE_GPU)
+ *id = command_buffer_->CreateTransferBuffer(size);
+ if (*id < 0)
+ return NPERR_GENERIC_ERROR;
+#endif // ENABLE_GPU
+
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DDestroyBuffer(
NPDeviceContext3D* context,
int32 id) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+#if defined(ENABLE_GPU)
+ command_buffer_->DestroyTransferBuffer(id);
+#endif // ENABLE_GPU
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DMapBuffer(
NPDeviceContext3D* context,
int32 id,
NPDeviceBuffer* np_buffer) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+#if defined(ENABLE_GPU)
+ Buffer gpu_buffer;
+ if (id == NP3DCommandBufferId) {
+ gpu_buffer = command_buffer_->GetRingBuffer();
+ } else {
+ gpu_buffer = command_buffer_->GetTransferBuffer(id);
+ }
+
+ np_buffer->ptr = gpu_buffer.ptr;
+ np_buffer->size = gpu_buffer.size;
+ if (!np_buffer->ptr)
+ return NPERR_GENERIC_ERROR;
+#endif // ENABLE_GPU
+
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DGetNumConfigs(int32* num_configs) {
- return NPERR_GENERIC_ERROR;
+ if (!num_configs)
+ return NPERR_GENERIC_ERROR;
+
+ *num_configs = 1;
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DGetConfigAttribs(
int32 config,
int32* attrib_list) {
- return NPERR_GENERIC_ERROR;
+ // Only one config available currently.
+ if (config != 0)
+ return NPERR_GENERIC_ERROR;
+
+ if (attrib_list) {
+ for (int32* attrib_pair = attrib_list; *attrib_pair; attrib_pair += 2) {
+ switch (attrib_pair[0]) {
+ case NP3DAttrib_BufferSize:
+ attrib_pair[1] = 32;
+ break;
+ case NP3DAttrib_AlphaSize:
+ case NP3DAttrib_BlueSize:
+ case NP3DAttrib_GreenSize:
+ case NP3DAttrib_RedSize:
+ attrib_pair[1] = 8;
+ break;
+ case NP3DAttrib_DepthSize:
+ attrib_pair[1] = 24;
+ break;
+ case NP3DAttrib_StencilSize:
+ attrib_pair[1] = 8;
+ break;
+ case NP3DAttrib_SurfaceType:
+ attrib_pair[1] = 0;
+ break;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+ }
+
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DCreateContext(
int32 config,
const int32* attrib_list,
NPDeviceContext3D** context) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+ // Only one config available currently.
+ if (config != 0)
+ return NPERR_GENERIC_ERROR;
+
+ // For now, just use the old API to initialize the context.
+ NPDeviceContext3DConfig old_config;
+ old_config.commandBufferSize = kDefaultCommandBufferSize;
+ if (attrib_list) {
+ for (const int32* attrib_pair = attrib_list; *attrib_pair;
+ attrib_pair += 2) {
+ switch (attrib_pair[0]) {
+ case NP3DAttrib_CommandBufferSize:
+ old_config.commandBufferSize = attrib_pair[1];
+ break;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+ }
+
+ *context = new NPDeviceContext3D;
+ Device3DInitializeContext(&old_config, *context);
+
+ // Flag the context as dynamically created by the browser. TODO(apatrick):
+ // take this out when all contexts are dynamically created.
+ Device3DImpl* impl = static_cast<Device3DImpl*>((*context)->reserved);
+ impl->dynamically_created = true;
+
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DRegisterCallback(
@@ -693,7 +975,19 @@ NPError WebPluginDelegatePepper::Device3DRegisterCallback(
int32 callback_type,
NPDeviceGenericCallbackPtr callback,
void* callback_data) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+ switch (callback_type) {
+ case NP3DCallback_Repaint:
+ context->repaintCallback = reinterpret_cast<NPDeviceContext3DRepaintPtr>(
+ callback);
+ break;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::Device3DSynchronizeContext(
@@ -704,7 +998,58 @@ NPError WebPluginDelegatePepper::Device3DSynchronizeContext(
int32* output_attrib_list,
NPDeviceSynchronizeContextCallbackPtr callback,
void* callback_data) {
- return NPERR_GENERIC_ERROR;
+ if (!context)
+ return NPERR_GENERIC_ERROR;
+
+ // Copy input attributes into context.
+ if (input_attrib_list) {
+ for (const int32* attrib_pair = input_attrib_list;
+ *attrib_pair;
+ attrib_pair += 2) {
+ switch (attrib_pair[0]) {
+ case NP3DAttrib_PutOffset:
+ context->putOffset = attrib_pair[1];
+ break;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+ }
+
+ // Use existing flush mechanism for now.
+ if (mode != NPDeviceSynchronizationMode_Cached) {
+ context->waitForProgress = mode == NPDeviceSynchronizationMode_Flush;
+ Device3DFlushContext(id, context, callback, callback_data);
+ }
+
+ // Copy most recent output attributes from context.
+ // To read output attributes after the completion of an asynchronous flush,
+ // invoke SynchronizeContext again with mode
+ // NPDeviceSynchronizationMode_Cached from the callback function.
+ if (output_attrib_list) {
+ for (int32* attrib_pair = output_attrib_list;
+ *attrib_pair;
+ attrib_pair += 2) {
+ switch (attrib_pair[0]) {
+ case NP3DAttrib_CommandBufferSize:
+ attrib_pair[1] = context->commandBufferSize;
+ break;
+ case NP3DAttrib_GetOffset:
+ attrib_pair[1] = context->getOffset;
+ break;
+ case NP3DAttrib_PutOffset:
+ attrib_pair[1] = context->putOffset;
+ break;
+ case NP3DAttrib_Token:
+ attrib_pair[1] = context->token;
+ break;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+ }
+
+ return NPERR_NO_ERROR;
}
NPError WebPluginDelegatePepper::DeviceAudioQueryCapability(int32 capability,
@@ -1038,11 +1383,16 @@ WebPluginDelegatePepper::WebPluginDelegatePepper(
: render_view_(render_view),
plugin_(NULL),
instance_(instance),
+ nested_delegate_(NULL),
current_printer_dpi_(-1),
#if defined (OS_LINUX)
num_pages_(0),
pdf_output_done_(false),
#endif // (OS_LINUX)
+#if defined(ENABLE_GPU)
+ command_buffer_(NULL),
+ method_factory3d_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+#endif
find_identifier_(-1),
current_choose_file_callback_(NULL),
current_choose_file_user_data_(NULL) {
@@ -1080,16 +1430,21 @@ void WebPluginDelegatePepper::PluginDestroyed() {
void WebPluginDelegatePepper::Paint(WebKit::WebCanvas* canvas,
const gfx::Rect& rect) {
- // Blit from background_context to context.
- if (!committed_bitmap_.isNull()) {
+ if (nested_delegate_) {
+ // TODO(apatrick): The GPU plugin will render to an offscreen render target.
+ // Need to copy it to the screen here.
+ } else {
+ // Blit from background_context to context.
+ if (!committed_bitmap_.isNull()) {
#if defined(OS_MACOSX)
- DrawSkBitmapToCanvas(committed_bitmap_, canvas, window_rect_,
- static_cast<int>(CGBitmapContextGetHeight(canvas)));
+ DrawSkBitmapToCanvas(committed_bitmap_, canvas, window_rect_,
+ static_cast<int>(CGBitmapContextGetHeight(canvas)));
#else
- canvas->drawBitmap(committed_bitmap_,
- SkIntToScalar(window_rect_.origin().x()),
- SkIntToScalar(window_rect_.origin().y()));
+ canvas->drawBitmap(committed_bitmap_,
+ SkIntToScalar(window_rect_.origin().x()),
+ SkIntToScalar(window_rect_.origin().y()));
#endif
+ }
}
}
@@ -1229,6 +1584,70 @@ bool WebPluginDelegatePepper::HandleInputEvent(const WebInputEvent& event,
return rv;
}
+#if defined(ENABLE_GPU)
+
+void WebPluginDelegatePepper::ScheduleHandleRepaint(
+ NPP npp, NPDeviceContext3D* context) {
+ command_buffer_->SetNotifyRepaintTask(method_factory3d_.NewRunnableMethod(
+ &WebPluginDelegatePepper::ForwardHandleRepaint,
+ npp,
+ context));
+}
+
+void WebPluginDelegatePepper::ForwardHandleRepaint(
+ NPP npp, NPDeviceContext3D* context) {
+ if (context->repaintCallback)
+ context->repaintCallback(npp, context);
+ ScheduleHandleRepaint(npp, context);
+}
+
+void WebPluginDelegatePepper::Synchronize3DContext(
+ NPDeviceContext3D* context,
+ const gpu::CommandBuffer::State& state) {
+ context->getOffset = state.get_offset;
+ context->putOffset = state.put_offset;
+ context->token = state.token;
+ context->error = static_cast<NPDeviceContext3DError>(state.error);
+}
+
+void WebPluginDelegatePepper::Device3DUpdateState(
+ NPP npp,
+ NPDeviceContext3D* context,
+ NPDeviceFlushContextCallbackPtr callback,
+ void* user_data) {
+ if (command_buffer_) {
+ Synchronize3DContext(context, command_buffer_->GetLastState());
+ if (callback)
+ callback(npp, context, NPERR_NO_ERROR, user_data);
+ }
+}
+
+#endif // ENABLE_GPU
+
+void WebPluginDelegatePepper::SendNestedDelegateGeometryToBrowser(
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect) {
+ // Inform the browser about the location of the plugin on the page.
+ // It appears that initially the plugin does not get laid out correctly --
+ // possibly due to lazy creation of the nested delegate.
+ if (!nested_delegate_ ||
+ !nested_delegate_->GetPluginWindowHandle() ||
+ !render_view_) {
+ return;
+ }
+
+ webkit::npapi::WebPluginGeometry geom;
+ geom.window = nested_delegate_->GetPluginWindowHandle();
+ geom.window_rect = window_rect;
+ geom.clip_rect = clip_rect;
+ // Rects_valid must be true for this to work in the Gtk port;
+ // hopefully not having the cutout rects will not cause incorrect
+ // clipping.
+ geom.rects_valid = true;
+ geom.visible = true;
+ render_view_->DidMovePlugin(geom);
+}
+
bool WebPluginDelegatePepper::CalculatePrintedPageDimensions(
int page_number,
NPPPrintExtensions* print_extensions,
diff --git a/chrome/renderer/webplugin_delegate_pepper.h b/chrome/renderer/webplugin_delegate_pepper.h
index 9dbeb1a..81a5d67 100644
--- a/chrome/renderer/webplugin_delegate_pepper.h
+++ b/chrome/renderer/webplugin_delegate_pepper.h
@@ -16,6 +16,7 @@
#include "base/weak_ptr.h"
#include "base/task.h"
#include "chrome/renderer/pepper_devices.h"
+#include "chrome/renderer/command_buffer_proxy.h"
#include "third_party/npapi/bindings/npapi.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserCompletion.h"
@@ -212,6 +213,10 @@ class WebPluginDelegatePepper : public webkit::npapi::WebPluginDelegate,
webkit::npapi::PluginInstance *instance);
~WebPluginDelegatePepper();
+ // Set a task that calls the repaint callback the next time the window
+ // is invalid and needs to be repainted.
+ void ScheduleHandleRepaint(NPP npp, NPDeviceContext3D* context);
+
//-----------------------------------------
// used for windowed and windowless plugins
@@ -245,6 +250,27 @@ class WebPluginDelegatePepper : public webkit::npapi::WebPluginDelegate,
const gfx::Rect& dest_rect, int canvas_height);
#endif // OS_MACOSX
+#if defined(ENABLE_GPU)
+
+ void ForwardHandleRepaint(NPP npp, NPDeviceContext3D* context);
+
+ // Synchronize a 3D context state with the service.
+ void Synchronize3DContext(NPDeviceContext3D* context,
+ const gpu::CommandBuffer::State& state);
+
+ // Synchronize the 3D context state with the proxy and invoke the async
+ // flush callback.
+ void Device3DUpdateState(NPP npp,
+ NPDeviceContext3D* context,
+ NPDeviceFlushContextCallbackPtr callback,
+ void* user_data);
+#endif
+
+ // Tells the browser out-of-band where the nested delegate lives on
+ // the page.
+ void SendNestedDelegateGeometryToBrowser(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect);
+
// Returns the selection. If nothing is selected, returns an empty string.
// If html is true, it will return a string only if html data is available.
string16 GetSelectedText(bool html) const;
@@ -270,6 +296,9 @@ class WebPluginDelegatePepper : public webkit::npapi::WebPluginDelegate,
// The url with which the plugin was instantiated.
std::string plugin_url_;
+ // The nested GPU plugin.
+ WebPluginDelegateProxy* nested_delegate_;
+
// The last printable_area passed in to PrintBegin. We remember this because
// we need to stretch the printed raster bitmap to these dimensions. It is
// cleared in PrintEnd.
@@ -294,6 +323,14 @@ class WebPluginDelegatePepper : public webkit::npapi::WebPluginDelegate,
bool pdf_output_done_;
#endif // defined(OS_LINUX)
+#if defined(ENABLE_GPU)
+ // The command buffer used to issue commands to the nested GPU plugin.
+ CommandBufferProxy* command_buffer_;
+
+ // Runnable methods that must be cancelled when the 3D context is destroyed.
+ ScopedRunnableMethodFactory<WebPluginDelegatePepper> method_factory3d_;
+#endif
+
// The id of the current find operation, or -1 if none is in process.
int find_identifier_;
diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc
index 6554c74..bc65843 100644
--- a/chrome/renderer/webplugin_delegate_proxy.cc
+++ b/chrome/renderer/webplugin_delegate_proxy.cc
@@ -1450,6 +1450,37 @@ bool WebPluginDelegateProxy::BindFakePluginWindowHandle(bool opaque) {
}
#endif
+CommandBufferProxy* WebPluginDelegateProxy::CreateCommandBuffer() {
+#if defined(ENABLE_GPU)
+#if defined(OS_MACOSX)
+ if (!BindFakePluginWindowHandle(true))
+ return NULL;
+#endif
+ int command_buffer_id;
+ if (!Send(new PluginMsg_CreateCommandBuffer(instance_id_,
+ &command_buffer_id))) {
+ return NULL;
+ }
+
+ CommandBufferProxy* command_buffer =
+ new CommandBufferProxy(channel_host_, command_buffer_id);
+ channel_host_->AddRoute(command_buffer_id, command_buffer, NULL);
+ return command_buffer;
+#else
+ return NULL;
+#endif // ENABLE_GPU
+}
+
+void WebPluginDelegateProxy::DestroyCommandBuffer(
+ CommandBufferProxy* command_buffer) {
+ DCHECK(command_buffer);
+#if defined(ENABLE_GPU)
+ Send(new PluginMsg_DestroyCommandBuffer(instance_id_));
+ channel_host_->RemoveRoute(command_buffer->route_id());
+ delete command_buffer;
+#endif
+}
+
gfx::PluginWindowHandle WebPluginDelegateProxy::GetPluginWindowHandle() {
return window_;
}
diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h
index 1c99113..ba9fe88 100644
--- a/chrome/renderer/webplugin_delegate_proxy.h
+++ b/chrome/renderer/webplugin_delegate_proxy.h
@@ -26,6 +26,7 @@
#include "base/linked_ptr.h"
#endif
+class CommandBufferProxy;
struct NPObject;
class NPObjectStub;
struct NPVariant_Param;
@@ -120,6 +121,9 @@ class WebPluginDelegateProxy
virtual webkit::npapi::WebPluginResourceClient* CreateSeekableResourceClient(
unsigned long resource_id, int range_request_id);
+ CommandBufferProxy* CreateCommandBuffer();
+ void DestroyCommandBuffer(CommandBufferProxy* command_buffer);
+
gfx::PluginWindowHandle GetPluginWindowHandle();
protected:
diff --git a/chrome/test/ui/pepper_uitest.cc b/chrome/test/ui/pepper_uitest.cc
new file mode 100644
index 0000000..f34346d
--- /dev/null
+++ b/chrome/test/ui/pepper_uitest.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_path.h"
+
+#include "app/app_switches.h"
+#include "base/test/test_timeouts.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/ui/npapi_test_helper.h"
+#include "chrome/test/ui_test_utils.h"
+
+using npapi_test::kTestCompleteCookie;
+using npapi_test::kTestCompleteSuccess;
+
+// Helper class pepper NPAPI tests.
+class PepperTester : public NPAPITesterBase {
+ protected:
+ PepperTester() : NPAPITesterBase() {}
+
+ virtual void SetUp() {
+ // TODO(alokp): Remove no-sandbox flag once gpu plugin can run in sandbox.
+ launch_arguments_.AppendSwitch(switches::kNoSandbox);
+ launch_arguments_.AppendSwitch(switches::kInternalPepper);
+ launch_arguments_.AppendSwitch(switches::kEnableGPUPlugin);
+ // Use Mesa software renderer so it can run on testbots without any
+ // graphics hardware.
+ launch_arguments_.AppendSwitchASCII(switches::kUseGL, "osmesa");
+ NPAPITesterBase::SetUp();
+ }
+};
+
+// Test that a pepper 3d plugin loads and renders.
+// TODO(alokp): Enable the test after making sure it works on all platforms
+// and buildbots have OpenGL support.
+#if defined(OS_WIN)
+// Marked as FAILS (46662): failing on buildbots but passes on trybots.
+TEST_F(PepperTester, FAILS_Pepper3D) {
+ const FilePath dir(FILE_PATH_LITERAL("pepper"));
+ const FilePath file(FILE_PATH_LITERAL("pepper_3d.html"));
+ GURL url = ui_test_utils::GetTestUrl(dir, file);
+ ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
+ WaitForFinish("pepper_3d", "1", url,
+ kTestCompleteCookie, kTestCompleteSuccess,
+ TestTimeouts::action_max_timeout_ms());
+}
+#endif
diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc
index 83cf193..4d1301a 100644
--- a/content/browser/plugin_process_host.cc
+++ b/content/browser/plugin_process_host.cc
@@ -221,6 +221,7 @@ bool PluginProcessHost::Init(const webkit::npapi::WebPluginInfo& info,
switches::kSilentDumpOnDCHECK,
switches::kMemoryProfiling,
switches::kEnableStatsTable,
+ switches::kEnableGPUPlugin,
switches::kUseGL,
#if defined(OS_CHROMEOS)
switches::kLoginProfile,
diff --git a/content/browser/plugin_service.cc b/content/browser/plugin_service.cc
index 2c775ed..78f994e 100644
--- a/content/browser/plugin_service.cc
+++ b/content/browser/plugin_service.cc
@@ -23,6 +23,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/default_plugin.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/gpu_plugin.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
@@ -133,6 +134,8 @@ PluginService::PluginService()
plugin_selection_policy_->StartInit();
#endif
+ chrome::RegisterInternalGPUPlugin();
+
// Start watching for changes in the plugin list. This means watching
// for changes in the Windows registry keys and on both Windows and POSIX
// watch for changes in the paths that are expected to contain plugins.
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 0fb7581..87b17a7 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -221,6 +221,26 @@
],
},
{
+ 'target_name': 'gpu_plugin',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ 'command_buffer_service',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'sources': [
+ 'gpu_plugin/gpu_plugin.cc',
+ 'gpu_plugin/gpu_plugin.h',
+ ],
+ },
+ {
'target_name': 'gpu_unittests',
'type': 'executable',
'dependencies': [
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index e662392..45ca5db 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -510,6 +510,11 @@
'../plugins/ppapi/ppb_open_gl_es_impl.cc',
],
}],
+ ['enable_gpu==1', {
+ 'dependencies': [
+ '<(DEPTH)/gpu/gpu.gyp:gpu_plugin',
+ ],
+ }],
['OS!="win"', {
'sources/': [['exclude', '_win\\.cc$']],
'sources!': [