Chromium Code Reviews| Index: webkit/plugins/ppapi/ppb_graphics_3d_impl.cc |
| =================================================================== |
| --- webkit/plugins/ppapi/ppb_graphics_3d_impl.cc (revision 80830) |
| +++ webkit/plugins/ppapi/ppb_graphics_3d_impl.cc (working copy) |
| @@ -1,18 +1,26 @@ |
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| +// 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 "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" |
| #include "base/logging.h" |
| +#include "base/message_loop.h" |
| +#include "gpu/command_buffer/client/gles2_cmd_helper.h" |
| +#include "gpu/command_buffer/client/gles2_implementation.h" |
| +#include "gpu/command_buffer/common/command_buffer.h" |
| #include "ppapi/c/pp_completion_callback.h" |
| #include "ppapi/c/pp_errors.h" |
| #include "webkit/plugins/ppapi/common.h" |
| +#include "webkit/plugins/ppapi/plugin_module.h" |
| +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
| namespace webkit { |
| namespace ppapi { |
| namespace { |
| +const int32 kCommandBufferSize = 1024 * 1024; |
| +const int32 kTransferBufferSize = 1024 * 1024; |
| int32_t GetConfigs(PP_Config3D_Dev* configs, |
| int32_t config_size, |
| @@ -52,23 +60,24 @@ |
| return context->GetReference(); |
| } |
| -PP_Bool IsGraphics3D(PP_Resource resource) { |
| - return BoolToPPBool(!!Resource::GetAs<PPB_Graphics3D_Impl>(resource)); |
| +PP_Bool IsGraphics3D(PP_Resource resource_id) { |
| + return BoolToPPBool(!!Resource::GetAs<PPB_Graphics3D_Impl>(resource_id)); |
| } |
| -int32_t GetAttribs(PP_Resource context, int32_t* attrib_list) { |
| +int32_t GetAttribs(PP_Resource context_id, int32_t* attrib_list) { |
| // TODO(alokp): Implement me. |
| return 0; |
| } |
| -int32_t SetAttribs(PP_Resource context, int32_t* attrib_list) { |
| +int32_t SetAttribs(PP_Resource context_id, int32_t* attrib_list) { |
| // TODO(alokp): Implement me. |
| return 0; |
| } |
| -int32_t SwapBuffers(PP_Resource context, PP_CompletionCallback callback) { |
| - // TODO(alokp): Implement me. |
| - return 0; |
| +int32_t SwapBuffers(PP_Resource context_id, PP_CompletionCallback callback) { |
| + scoped_refptr<PPB_Graphics3D_Impl> context( |
| + Resource::GetAs<PPB_Graphics3D_Impl>(context_id)); |
| + return context->SwapBuffers(callback); |
| } |
| const PPB_Graphics3D_Dev ppb_graphics3d = { |
| @@ -85,10 +94,25 @@ |
| } // namespace |
| PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PluginInstance* instance) |
| - : Resource(instance) { |
| + : Resource(instance), |
| + bound_to_instance_(false), |
| + transfer_buffer_id_(0), |
| + commit_initiated_(false), |
| + swap_callback_(PP_BlockUntilComplete()), |
| + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| } |
| PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() { |
| + gles2_impl_.reset(); |
| + |
| + gpu::CommandBuffer* command_buffer = GetCommandBuffer(); |
| + if (command_buffer && transfer_buffer_id_ != 0) { |
| + command_buffer->DestroyTransferBuffer(transfer_buffer_id_); |
| + transfer_buffer_id_ = 0; |
| + } |
| + |
| + command_buffer_helper_.reset(); |
| + platform_context_.reset(); |
| } |
| const PPB_Graphics3D_Dev* PPB_Graphics3D_Impl::GetInterface() { |
| @@ -102,10 +126,158 @@ |
| bool PPB_Graphics3D_Impl::Init(PP_Config3D_Dev config, |
| PP_Resource share_context, |
| const int32_t* attrib_list) { |
|
piman
2011/04/12 03:23:40
Somewhere, something needs to parse the attrib_lis
|
| - // TODO(alokp): Implement me. |
| - return false; |
| + if (!InitRaw(config, share_context, attrib_list)) |
| + return false; |
| + |
| + if (!CreateImplementation()) |
| + return false; |
| + |
| + return true; |
| } |
| +bool PPB_Graphics3D_Impl::InitRaw(PP_Config3D_Dev config, |
| + PP_Resource share_context, |
| + const int32_t* attrib_list) { |
| + platform_context_.reset(instance()->CreateContext3D()); |
| + if (!platform_context_.get()) |
| + return false; |
| + |
| + if (!platform_context_->Init()) |
| + return false; |
| + |
| + platform_context_->SetContextLostCallback( |
| + callback_factory_.NewCallback(&PPB_Graphics3D_Impl::OnContextLost)); |
| + platform_context_->SetSwapBuffersCallback( |
| + callback_factory_.NewCallback(&PPB_Graphics3D_Impl::OnSwapBuffers)); |
| + return true; |
| +} |
| + |
| +gpu::CommandBuffer* PPB_Graphics3D_Impl::GetCommandBuffer() { |
| + DCHECK(platform_context_.get()); |
| + return platform_context_->GetCommandBuffer(); |
| +} |
| + |
| +unsigned int PPB_Graphics3D_Impl::GetBackingTextureId() { |
| + DCHECK(platform_context_.get()); |
| + return platform_context_->GetBackingTextureId(); |
| +} |
| + |
| +bool PPB_Graphics3D_Impl::BindToInstance(bool bind) { |
| + bound_to_instance_ = bind; |
| + return true; |
| +} |
| + |
| +void PPB_Graphics3D_Impl::ViewInitiatedPaint() { |
| +} |
| + |
| +void PPB_Graphics3D_Impl::ViewFlushedPaint() { |
| + if (commit_initiated_ && swap_callback_.func) { |
| + commit_initiated_ = false; |
| + SendSwapBuffers(); |
| + } |
| +} |
| + |
| +int32_t PPB_Graphics3D_Impl::SwapBuffers(PP_CompletionCallback callback) { |
| + if (!callback.func) { |
| + // Blocking SwapBuffers isn't supported (since we have to be on the main |
| + // thread). |
| + return PP_ERROR_BADARGUMENT; |
| + } |
| + |
| + if (swap_callback_.func) { |
| + // Already a pending SwapBuffers that hasn't returned yet. |
| + return PP_ERROR_INPROGRESS; |
| + } |
| + |
| + swap_callback_ = callback; |
| + DCHECK(gles2_impl()); |
|
piman
2011/04/12 03:23:40
This DCHECK will fail when the interface is proxie
|
| + gles2_impl()->SwapBuffers(); |
| + return PP_ERROR_WOULDBLOCK; |
| +} |
| + |
| +bool PPB_Graphics3D_Impl::CreateImplementation() { |
| + gpu::CommandBuffer* command_buffer = platform_context_->GetCommandBuffer(); |
| + DCHECK(command_buffer); |
| + |
| + if (!command_buffer->Initialize(kCommandBufferSize)) |
| + return false; |
| + |
| + // Create the GLES2 helper, which writes the command buffer protocol. |
| + command_buffer_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer)); |
| + if (!command_buffer_helper_->Initialize(kCommandBufferSize)) |
| + return false; |
| + |
| + // Create a transfer buffer used to copy resources between the renderer |
| + // process and the GPU process. |
| + transfer_buffer_id_ = |
| + command_buffer->CreateTransferBuffer(kTransferBufferSize); |
| + if (transfer_buffer_id_ < 0) |
| + return false; |
| + |
| + // Map the buffer into the renderer process's address space. |
| + gpu::Buffer transfer_buffer = |
| + command_buffer->GetTransferBuffer(transfer_buffer_id_); |
| + if (!transfer_buffer.ptr) |
| + return false; |
| + |
| + // Create the object exposing the OpenGL API. |
| + gles2_impl_.reset(new gpu::gles2::GLES2Implementation( |
| + command_buffer_helper_.get(), |
| + transfer_buffer.size, |
| + transfer_buffer.ptr, |
| + transfer_buffer_id_, |
| + false)); |
| + |
| + return gles2_impl_.get() != NULL; |
| +} |
| + |
| +void PPB_Graphics3D_Impl::OnSwapBuffers() { |
| + if (bound_to_instance_) { |
| + // If we are bound to the instance, we need to ask the compositor |
| + // to commit our backing texture so that the graphics appears on the page. |
| + // When the backing texture will be committed we get notified via |
| + // ViewFlushedPaint(). |
| + // TODO(alokp): Check if we really need to wait for the compositor to |
| + // complete before sending the swap buffers acknowledgement. It will be |
| + // nice if we could let plugin start drawing the next frame while the |
| + // compositor is busy. |
| + instance()->CommitBackingTexture(); |
| + } else if (swap_callback_.func) { |
| + // If we're off-screen, no need to trigger and wait for compositing. |
| + // Just run the swap-buffers callback immediately. |
| + SendSwapBuffers(); |
| + } |
| +} |
| + |
| +void PPB_Graphics3D_Impl::OnContextLost() { |
| + if (bound_to_instance_) |
| + instance()->BindGraphics(0); |
| + |
| + // Send context lost to plugin. This may have been caused by a PPAPI call, so |
| + // avoid re-entering. |
| + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( |
| + this, &PPB_Graphics3D_Impl::SendContextLost)); |
| +} |
| + |
| +void PPB_Graphics3D_Impl::SendSwapBuffers() { |
| + // We must clear swap_callback_ before issuing the callback. It will be |
| + // common for the plugin to issue another SwapBuffers in response to the |
| + // callback, and we don't want to think that a callback is already pending. |
| + DCHECK(swap_callback_.func); |
| + PP_CompletionCallback callback = PP_BlockUntilComplete(); |
| + std::swap(callback, swap_callback_); |
| + PP_RunCompletionCallback(&callback, PP_OK); |
| +} |
| + |
| +void PPB_Graphics3D_Impl::SendContextLost() { |
| + const PPP_Graphics3D_Dev* ppp_graphics3d = |
| + static_cast<const PPP_Graphics3D_Dev*>( |
| + instance()->module()->GetPluginInterface( |
| + PPP_GRAPHICS_3D_DEV_INTERFACE)); |
| + if (ppp_graphics3d) |
| + ppp_graphics3d->Graphics3DContextLost(instance()->pp_instance()); |
| +} |
| + |
| } // namespace ppapi |
| } // namespace webkit |