diff options
author | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-22 23:28:15 +0000 |
---|---|---|
committer | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-22 23:28:15 +0000 |
commit | 7477ea6f6a173b586622fd276433a346760ffbf4 (patch) | |
tree | 678229a49ae5c4bb1a54a61374466cdddf57db59 /chrome/renderer | |
parent | e4f7cec0a45a803faf00875a070090b165ff1fc5 (diff) | |
download | chromium_src-7477ea6f6a173b586622fd276433a346760ffbf4.zip chromium_src-7477ea6f6a173b586622fd276433a346760ffbf4.tar.gz chromium_src-7477ea6f6a173b586622fd276433a346760ffbf4.tar.bz2 |
Added Pepper 3D device that instantiates the GPU plugin and sends GLES2 commands to it via a command buffer.
Added API for managing buffers to Pepper 3D device.
Removed DCHECK from WebPluginImpl::SetWindow that checks against a windowless plugin being given a window handle. Please check this! Now an initially windowless plugin instance gets a handle when it requests a Pepper 3D context. Perhaps the window handle should be concealed from the underlying plugin isntance.
Removed enable_gpu gyp variable and C macro. GPU code is always built on windows but not mac or linux. It is enabled at runtime with the --enable-gpu-plugin switch.
Redesigned CommandBuffer interface so it exposes shared memory through a Buffer. This was necessary because Pepper has no notion of shared memory handles. The Buffer exposes the shared memory as both a handle (through base::SharedMemory) and the mapped address and size.
Refactored CommandBufferEngine so mapped shared memory addresses and sizes are returned with a single call rather than two separate calls.
Added 3D demo to pepper test plugin.
TEST=try servers
BUG=none
Review URL: http://codereview.chromium.org/367002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35185 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/command_buffer_proxy.cc | 70 | ||||
-rw-r--r-- | chrome/renderer/command_buffer_proxy.h | 8 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 5 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_pepper.cc | 178 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_pepper.h | 41 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.cc | 2 |
6 files changed, 246 insertions, 58 deletions
diff --git a/chrome/renderer/command_buffer_proxy.cc b/chrome/renderer/command_buffer_proxy.cc index 262bb8e..b78fa84 100644 --- a/chrome/renderer/command_buffer_proxy.cc +++ b/chrome/renderer/command_buffer_proxy.cc @@ -8,6 +8,9 @@ #include "chrome/common/plugin_messages.h" #include "chrome/renderer/command_buffer_proxy.h" #include "chrome/renderer/plugin_channel_host.h" +#include "gpu/command_buffer/common/cmd_buffer_common.h" + +using gpu::Buffer; CommandBufferProxy::CommandBufferProxy( PluginChannelHost* channel, @@ -18,6 +21,14 @@ CommandBufferProxy::CommandBufferProxy( } CommandBufferProxy::~CommandBufferProxy() { + // Delete all the locally cached shared memory objects, closing the handle + // in this process. + for (TransferBufferMap::iterator it = transfer_buffers_.begin(); + it != transfer_buffers_.end(); + ++it) { + delete it->second.shared_memory; + it->second.shared_memory = NULL; + } } bool CommandBufferProxy::Send(IPC::Message* msg) { @@ -30,10 +41,10 @@ bool CommandBufferProxy::Send(IPC::Message* msg) { return false; } -base::SharedMemory* CommandBufferProxy::Initialize(int32 size) { +bool CommandBufferProxy::Initialize(int32 size) { DCHECK(!ring_buffer_.get()); - // Initialize the service. Assuming we are in the renderer process, the GPU + // Initialize the service. Assuming we are sandboxed, the GPU // process is responsible for duplicating the handle. This might not be true // for NaCl. base::SharedMemoryHandle handle; @@ -42,18 +53,22 @@ base::SharedMemory* CommandBufferProxy::Initialize(int32 size) { ring_buffer_.reset(new base::SharedMemory(handle, false)); if (ring_buffer_->Map(size * sizeof(int32))) { size_ = size; - return ring_buffer_.get(); + return true; } ring_buffer_.reset(); } - return NULL; + return false; } -base::SharedMemory* CommandBufferProxy::GetRingBuffer() { +Buffer CommandBufferProxy::GetRingBuffer() { // Return locally cached ring buffer. - return ring_buffer_.get(); + Buffer buffer; + buffer.ptr = ring_buffer_->memory(); + buffer.size = size_ * sizeof(gpu::CommandBufferEntry); + buffer.shared_memory = ring_buffer_.get(); + return buffer; } int32 CommandBufferProxy::GetSize() { @@ -107,30 +122,55 @@ int32 CommandBufferProxy::CreateTransferBuffer(size_t size) { void CommandBufferProxy::DestroyTransferBuffer(int32 id) { // Remove the transfer buffer from the client side4 cache. - transfer_buffers_.erase(id); + TransferBufferMap::iterator it = transfer_buffers_.find(id); + DCHECK(it != transfer_buffers_.end()); + + // Delete the shared memory object, closing the handle in this process. + delete it->second.shared_memory; + + transfer_buffers_.erase(it); Send(new CommandBufferMsg_DestroyTransferBuffer(route_id_, id)); } -base::SharedMemory* CommandBufferProxy::GetTransferBuffer(int32 id) { +Buffer CommandBufferProxy::GetTransferBuffer(int32 id) { // Check local cache to see if there is already a client side shared memory // object for this id. TransferBufferMap::iterator it = transfer_buffers_.find(id); - if (it != transfer_buffers_.end()) - return it->second.get(); + if (it != transfer_buffers_.end()) { + return it->second; + } // Assuming we are in the renderer process, the service is responsible for // duplicating the handle. This might not be true for NaCl. base::SharedMemoryHandle handle; - if (!Send(new CommandBufferMsg_GetTransferBuffer(route_id_, id, &handle))) - return NULL; + size_t size; + if (!Send(new CommandBufferMsg_GetTransferBuffer(route_id_, + id, + &handle, + &size))) { + return Buffer(); + } // Cache the transfer buffer shared memory object client side. - base::SharedMemory* transfer_buffer = + base::SharedMemory* shared_memory = new base::SharedMemory(handle, false, base::GetCurrentProcessHandle()); - transfer_buffers_[id].reset(transfer_buffer); - return transfer_buffer; + // Map the shared memory on demand. + if (!shared_memory->memory()) { + if (!shared_memory->Map(shared_memory->max_size())) { + delete shared_memory; + return Buffer(); + } + } + + Buffer buffer; + buffer.ptr = shared_memory->memory(); + buffer.size = size; + buffer.shared_memory = shared_memory; + transfer_buffers_[id] = buffer; + + return buffer; } int32 CommandBufferProxy::GetToken() { diff --git a/chrome/renderer/command_buffer_proxy.h b/chrome/renderer/command_buffer_proxy.h index 5abfead..7453988 100644 --- a/chrome/renderer/command_buffer_proxy.h +++ b/chrome/renderer/command_buffer_proxy.h @@ -33,8 +33,8 @@ class CommandBufferProxy : public gpu::CommandBuffer, virtual bool Send(IPC::Message* msg); // CommandBuffer implementation: - virtual base::SharedMemory* Initialize(int32 size); - virtual base::SharedMemory* GetRingBuffer(); + virtual bool Initialize(int32 size); + virtual gpu::Buffer GetRingBuffer(); virtual int32 GetSize(); virtual int32 SyncOffsets(int32 put_offset); virtual int32 GetGetOffset(); @@ -43,7 +43,7 @@ class CommandBufferProxy : public gpu::CommandBuffer, virtual void SetPutOffsetChangeCallback(Callback0::Type* callback); virtual int32 CreateTransferBuffer(size_t size); virtual void DestroyTransferBuffer(int32 id); - virtual base::SharedMemory* GetTransferBuffer(int32 handle); + virtual gpu::Buffer GetTransferBuffer(int32 handle); virtual int32 GetToken(); virtual void SetToken(int32 token); virtual int32 ResetParseError(); @@ -57,7 +57,7 @@ class CommandBufferProxy : public gpu::CommandBuffer, scoped_ptr<base::SharedMemory> ring_buffer_; // Local cache of id to transfer buffer mapping. - typedef std::map<int32, linked_ptr<base::SharedMemory> > TransferBufferMap; + typedef std::map<int32, gpu::Buffer> TransferBufferMap; TransferBufferMap transfer_buffers_; scoped_refptr<PluginChannelHost> channel_; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index c4f7483..6313755 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -2671,7 +2671,10 @@ webkit_glue::WebPluginDelegate* RenderView::CreatePluginDelegate( #if defined(OS_WIN) // In-proc plugins aren't supported on Linux or Mac. if (use_pepper_host) { return WebPluginDelegatePepper::Create( - path, *mime_type_to_use, gfx::NativeViewFromId(host_window_)); + path, + *mime_type_to_use, + AsWeakPtr(), + gfx::NativeViewFromId(host_window_)); } else { return WebPluginDelegateImpl::Create( path, *mime_type_to_use, gfx::NativeViewFromId(host_window_)); diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc index 5fc549c..4c32b7b 100644 --- a/chrome/renderer/webplugin_delegate_pepper.cc +++ b/chrome/renderer/webplugin_delegate_pepper.cc @@ -18,6 +18,7 @@ #include "base/string_util.h" #include "chrome/common/render_messages.h" #include "chrome/renderer/render_thread.h" +#include "chrome/renderer/webplugin_delegate_proxy.h" #include "third_party/npapi/bindings/npapi_extensions.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" #include "webkit/glue/glue_util.h" @@ -28,6 +29,11 @@ #include "webkit/glue/plugins/plugin_stream_url.h" #include "webkit/glue/webkit_glue.h" +#if defined(ENABLE_GPU) +#include "webkit/glue/plugins/plugin_constants_win.h" +#endif + +using gpu::Buffer; using webkit_glue::WebPlugin; using webkit_glue::WebPluginDelegate; using webkit_glue::WebPluginResourceClient; @@ -53,6 +59,7 @@ uint32 WebPluginDelegatePepper::next_buffer_id = 0; WebPluginDelegatePepper* WebPluginDelegatePepper::Create( const FilePath& filename, const std::string& mime_type, + const base::WeakPtr<RenderView>& render_view, gfx::PluginWindowHandle containing_view) { scoped_refptr<NPAPI::PluginLib> plugin_lib = NPAPI::PluginLib::CreatePluginLib(filename); @@ -65,7 +72,9 @@ WebPluginDelegatePepper* WebPluginDelegatePepper::Create( scoped_refptr<NPAPI::PluginInstance> instance = plugin_lib->CreateInstance(mime_type); - return new WebPluginDelegatePepper(containing_view, instance.get()); + return new WebPluginDelegatePepper(render_view, + containing_view, + instance.get()); } bool WebPluginDelegatePepper::Initialize( @@ -98,9 +107,6 @@ bool WebPluginDelegatePepper::Initialize( // retreived via NPN_GetValue of NPNVnetscapeWindow. instance_->set_window_handle(parent_); - // This is a windowless plugin, so set it to have a NULL handle. - plugin_->SetWindow(NULL); - plugin_url_ = url.spec(); return true; @@ -147,6 +153,10 @@ 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 (!instance()) return; @@ -247,6 +257,11 @@ NPError WebPluginDelegatePepper::Device2DQueryConfig( NPError WebPluginDelegatePepper::Device2DInitializeContext( const NPDeviceContext2DConfig* config, NPDeviceContext2D* context) { + // This is a windowless plugin, so set it to have a NULL handle. Defer this + // until we know the plugin will use the 2D device. If it uses the 3D device + // it will have a window handle. + plugin_->SetWindow(NULL); + int width = window_rect_.width(); int height = window_rect_.height(); uint32 buffer_size = width * height * kBytesPerPixel; @@ -392,6 +407,49 @@ NPError WebPluginDelegatePepper::Device3DQueryConfig( NPError WebPluginDelegatePepper::Device3DInitializeContext( const NPDeviceContext3DConfig* config, NPDeviceContext3D* context) { +#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(kGPUPluginMimeType, + 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)) { + // Ask the GPU plugin to create a command buffer and return a proxy. + command_buffer_.reset(nested_delegate_->CreateCommandBuffer()); + if (command_buffer_.get()) { + // Initialize the proxy command buffer. + if (command_buffer_->Initialize(config->commandBufferEntries)) { + // Initialize the 3D context. + context->reserved = NULL; + Buffer ring_buffer = command_buffer_->GetRingBuffer(); + context->commandBuffer = ring_buffer.ptr; + context->commandBufferEntries = command_buffer_->GetSize(); + context->getOffset = command_buffer_->GetGetOffset(); + context->putOffset = command_buffer_->GetPutOffset(); + + // Ensure the service knows the window size before rendering anything. + nested_delegate_->UpdateGeometry(window_rect_, clip_rect_); + + return NPERR_NO_ERROR; + } + } + + command_buffer_.reset(); + } + + nested_delegate_->PluginDestroyed(); + nested_delegate_ = NULL; +#endif // ENABLE_GPU + return NPERR_GENERIC_ERROR; } @@ -406,7 +464,32 @@ NPError WebPluginDelegatePepper::Device3DGetStateContext( NPDeviceContext3D* context, int32 state, int32* value) { - return NPERR_GENERIC_ERROR; +#if defined(ENABLE_GPU) + if (!command_buffer_.get()) + return NPERR_GENERIC_ERROR; + + switch (state) { + case NPDeviceContext3DState_GetOffset: + context->getOffset = *value = command_buffer_->GetGetOffset(); + break; + case NPDeviceContext3DState_PutOffset: + *value = command_buffer_->GetPutOffset(); + break; + case NPDeviceContext3DState_Token: + *value = command_buffer_->GetToken(); + break; + case NPDeviceContext3DState_ParseError: + *value = command_buffer_->ResetParseError(); + break; + case NPDeviceContext3DState_ErrorStatus: + *value = command_buffer_->GetErrorStatus() ? 1 : 0; + break; + default: + return NPERR_GENERIC_ERROR; + }; +#endif // ENABLE_GPU + + return NPERR_NO_ERROR; } NPError WebPluginDelegatePepper::Device3DFlushContext( @@ -414,37 +497,75 @@ NPError WebPluginDelegatePepper::Device3DFlushContext( NPDeviceContext3D* context, NPDeviceFlushContextCallbackPtr callback, void* user_data) { - return NPERR_GENERIC_ERROR; +#if defined(ENABLE_GPU) + DCHECK(callback == NULL); + context->getOffset = command_buffer_->SyncOffsets(context->putOffset); +#endif // ENABLE_GPU + return NPERR_NO_ERROR; } NPError WebPluginDelegatePepper::Device3DDestroyContext( NPDeviceContext3D* context) { - return NPERR_GENERIC_ERROR; +#if defined(ENABLE_GPU) + command_buffer_.reset(); + + if (nested_delegate_) { + nested_delegate_->PluginDestroyed(); + nested_delegate_ = NULL; + } +#endif // ENABLE_GPU + + return NPERR_NO_ERROR; } -bool WebPluginDelegatePepper::IsPluginDelegateWindow( - gfx::NativeWindow window) { - return false; +NPError WebPluginDelegatePepper::Device3DCreateBuffer( + NPDeviceContext3D* context, + size_t size, + int32* id) { +#if defined(ENABLE_GPU) + *id = command_buffer_->CreateTransferBuffer(size); + if (*id < 0) + return NPERR_GENERIC_ERROR; +#endif // ENABLE_GPU + + return NPERR_NO_ERROR; } -bool WebPluginDelegatePepper::GetPluginNameFromWindow( - gfx::NativeWindow window, std::wstring *plugin_name) { - return false; +NPError WebPluginDelegatePepper::Device3DDestroyBuffer( + NPDeviceContext3D* context, + int32 id) { +#if defined(ENABLE_GPU) + command_buffer_->DestroyTransferBuffer(id); +#endif // ENABLE_GPU + return NPERR_NO_ERROR; } -bool WebPluginDelegatePepper::IsDummyActivationWindow( - gfx::NativeWindow window) { - return false; +NPError WebPluginDelegatePepper::Device3DMapBuffer( + NPDeviceContext3D* context, + int32 id, + NPDeviceBuffer* np_buffer) { +#if defined(ENABLE_GPU) + Buffer 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; } WebPluginDelegatePepper::WebPluginDelegatePepper( + const base::WeakPtr<RenderView>& render_view, gfx::PluginWindowHandle containing_view, NPAPI::PluginInstance *instance) - : plugin_(NULL), + : render_view_(render_view), + plugin_(NULL), instance_(instance), parent_(containing_view), buffer_size_(0), - plugin_buffer_(0) { + plugin_buffer_(0), + nested_delegate_(NULL) { // For now we keep a window struct, although it isn't used. memset(&window_, 0, sizeof(window_)); // All Pepper plugins are windowless and transparent. @@ -458,18 +579,27 @@ WebPluginDelegatePepper::~WebPluginDelegatePepper() { } void WebPluginDelegatePepper::PluginDestroyed() { + if (nested_delegate_) { + nested_delegate_->PluginDestroyed(); + nested_delegate_ = NULL; + } delete this; } void WebPluginDelegatePepper::Paint(WebKit::WebCanvas* canvas, const gfx::Rect& rect) { #if defined(OS_WIN) - // Blit from background_context to context. - if (!committed_bitmap_.isNull()) { - gfx::Point origin(window_rect_.origin().x(), window_rect_.origin().y()); - canvas->drawBitmap(committed_bitmap_, - SkIntToScalar(window_rect_.origin().x()), - SkIntToScalar(window_rect_.origin().y())); + 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()) { + gfx::Point origin(window_rect_.origin().x(), window_rect_.origin().y()); + canvas->drawBitmap(committed_bitmap_, + SkIntToScalar(window_rect_.origin().x()), + SkIntToScalar(window_rect_.origin().y())); + } } #endif } diff --git a/chrome/renderer/webplugin_delegate_pepper.h b/chrome/renderer/webplugin_delegate_pepper.h index aa798d7..2e78500 100644 --- a/chrome/renderer/webplugin_delegate_pepper.h +++ b/chrome/renderer/webplugin_delegate_pepper.h @@ -18,7 +18,10 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/task.h" +#include "base/weak_ptr.h" #include "chrome/common/transport_dib.h" +#include "chrome/renderer/render_view.h" +#include "chrome/renderer/command_buffer_proxy.h" #include "skia/ext/platform_canvas.h" #include "third_party/npapi/bindings/npapi.h" #include "third_party/npapi/bindings/npapi_extensions.h" @@ -32,16 +35,11 @@ class PluginInstance; // An implementation of WebPluginDelegate for Pepper in-process plugins. class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate { public: - static WebPluginDelegatePepper* Create(const FilePath& filename, - const std::string& mime_type, gfx::PluginWindowHandle containing_view); - - static bool IsPluginDelegateWindow(gfx::NativeWindow window); - static bool GetPluginNameFromWindow(gfx::NativeWindow window, - std::wstring *plugin_name); - - // Returns true if the window handle passed in is that of the dummy - // activation window for windowless plugins. - static bool IsDummyActivationWindow(gfx::NativeWindow window); + static WebPluginDelegatePepper* Create( + const FilePath& filename, + const std::string& mime_type, + const base::WeakPtr<RenderView>& render_view, + gfx::PluginWindowHandle containing_view); // WebPluginDelegate implementation virtual bool Initialize(const GURL& url, @@ -118,9 +116,16 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate { NPDeviceFlushContextCallbackPtr callback, void* user_data); virtual NPError Device3DDestroyContext(NPDeviceContext3D* context); + virtual NPError Device3DCreateBuffer(NPDeviceContext3D* context, + size_t size, + int32* id); + virtual NPError Device3DDestroyBuffer(NPDeviceContext3D* context, + int32 id); + virtual NPError Device3DMapBuffer(NPDeviceContext3D* context, + int32 id, + NPDeviceBuffer* buffer); // End of WebPluginDelegate implementation. - bool IsWindowless() const { return true; } gfx::Rect GetRect() const { return window_rect_; } gfx::Rect GetClipRect() const { return clip_rect_; } @@ -128,8 +133,10 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate { FilePath GetPluginPath(); private: - WebPluginDelegatePepper(gfx::PluginWindowHandle containing_view, - NPAPI::PluginInstance *instance); + WebPluginDelegatePepper( + const base::WeakPtr<RenderView>& render_view, + gfx::PluginWindowHandle containing_view, + NPAPI::PluginInstance *instance); ~WebPluginDelegatePepper(); // Tells the plugin about the current state of the window. @@ -144,6 +151,8 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate { // Closes down and destroys our plugin instance. void DestroyInstance(); + base::WeakPtr<RenderView> render_view_; + webkit_glue::WebPlugin* plugin_; scoped_refptr<NPAPI::PluginInstance> instance_; @@ -176,6 +185,12 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate { // The url with which the plugin was instantiated. std::string plugin_url_; + // The nested GPU plugin and its command buffer proxy. + WebPluginDelegateProxy* nested_delegate_; +#if defined(ENABLE_GPU) + scoped_ptr<CommandBufferProxy> command_buffer_; +#endif + DISALLOW_COPY_AND_ASSIGN(WebPluginDelegatePepper); }; diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 78f3dfe..f459b51 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -1153,7 +1153,7 @@ CommandBufferProxy* WebPluginDelegateProxy::CreateCommandBuffer() { return new CommandBufferProxy(channel_host_, command_buffer_id); #else return NULL; -#endif +#endif // ENABLE_GPU } void WebPluginDelegateProxy::OnCancelDocumentLoad() { |