Index: webkit/plugins/ppapi/ppb_graphics_3d_impl.cc |
=================================================================== |
--- webkit/plugins/ppapi/ppb_graphics_3d_impl.cc (revision 92908) |
+++ webkit/plugins/ppapi/ppb_graphics_3d_impl.cc (working copy) |
@@ -4,22 +4,60 @@ |
#include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" |
-#include "base/logging.h" |
-#include "ppapi/c/pp_completion_callback.h" |
-#include "ppapi/c/pp_errors.h" |
+#include "base/message_loop.h" |
+#include "gpu/command_buffer/client/gles2_implementation.h" |
+#include "webkit/plugins/ppapi/plugin_module.h" |
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
-#include "webkit/plugins/ppapi/resource_tracker.h" |
using ppapi::thunk::PPB_Graphics3D_API; |
namespace webkit { |
namespace ppapi { |
+namespace { |
+const int32 kCommandBufferSize = 1024 * 1024; |
+const int32 kTransferBufferSize = 1024 * 1024; |
+ |
+PP_Bool ShmToHandle(base::SharedMemory* shm, |
+ size_t size, |
+ int* shm_handle, |
+ uint32_t* shm_size) { |
+ if (!shm || !shm_handle || !shm_size) |
+ return PP_FALSE; |
+#if defined(OS_POSIX) |
+ *shm_handle = shm->handle().fd; |
+#elif defined(OS_WIN) |
+ *shm_handle = reinterpret_cast<int>(shm->handle()); |
+#else |
+ #error "Platform not supported." |
+#endif |
+ *shm_size = size; |
+ return PP_TRUE; |
+} |
+ |
+PP_Graphics3DTrustedState PPStateFromGPUState( |
+ const gpu::CommandBuffer::State& s) { |
+ PP_Graphics3DTrustedState state = { |
+ s.num_entries, |
+ s.get_offset, |
+ s.put_offset, |
+ s.token, |
+ static_cast<PPB_Graphics3DTrustedError>(s.error), |
+ s.generation |
+ }; |
+ return state; |
+} |
+} // namespace. |
+ |
PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PluginInstance* instance) |
- : Resource(instance) { |
+ : Resource(instance), |
+ bound_to_instance_(false), |
+ commit_pending_(false), |
+ callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
} |
PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() { |
+ DestroyGLES2Impl(); |
} |
// static |
@@ -27,38 +65,189 @@ |
PP_Config3D_Dev config, |
PP_Resource share_context, |
const int32_t* attrib_list) { |
- scoped_refptr<PPB_Graphics3D_Impl> t(new PPB_Graphics3D_Impl(instance)); |
- if (!t->Init(config, share_context, attrib_list)) |
+ scoped_refptr<PPB_Graphics3D_Impl> graphics_3d( |
+ new PPB_Graphics3D_Impl(instance)); |
+ |
+ if (!graphics_3d->Init(config, share_context, attrib_list)) |
return 0; |
- return t->GetReference(); |
+ |
+ return graphics_3d->GetReference(); |
} |
+PP_Resource PPB_Graphics3D_Impl::CreateRaw(PluginInstance* instance, |
+ PP_Config3D_Dev config, |
+ PP_Resource share_context, |
+ const int32_t* attrib_list) { |
+ scoped_refptr<PPB_Graphics3D_Impl> graphics_3d( |
+ new PPB_Graphics3D_Impl(instance)); |
+ |
+ if (!graphics_3d->InitRaw(config, share_context, attrib_list)) |
+ return 0; |
+ |
+ return graphics_3d->GetReference(); |
+} |
+ |
PPB_Graphics3D_API* PPB_Graphics3D_Impl::AsPPB_Graphics3D_API() { |
return this; |
} |
-int32_t PPB_Graphics3D_Impl::GetAttribs(int32_t* attrib_list) { |
- // TODO(alokp): Implement me. |
- return PP_ERROR_FAILED; |
+PP_Bool PPB_Graphics3D_Impl::InitCommandBuffer(int32_t size) { |
+ return PP_FromBool(GetCommandBuffer()->Initialize(size)); |
} |
-int32_t PPB_Graphics3D_Impl::SetAttribs(int32_t* attrib_list) { |
- // TODO(alokp): Implement me. |
- return PP_ERROR_FAILED; |
+PP_Bool PPB_Graphics3D_Impl::GetRingBuffer(int* shm_handle, |
+ uint32_t* shm_size) { |
+ gpu::Buffer buffer = GetCommandBuffer()->GetRingBuffer(); |
+ return ShmToHandle(buffer.shared_memory, buffer.size, shm_handle, shm_size); |
} |
-int32_t PPB_Graphics3D_Impl::SwapBuffers(PP_CompletionCallback callback) { |
- // TODO(alokp): Implement me. |
- return PP_ERROR_FAILED; |
+PP_Graphics3DTrustedState PPB_Graphics3D_Impl::GetState() { |
+ return PPStateFromGPUState(GetCommandBuffer()->GetState()); |
} |
+int32_t PPB_Graphics3D_Impl::CreateTransferBuffer(uint32_t size) { |
+ return GetCommandBuffer()->CreateTransferBuffer(size, -1); |
+} |
+ |
+PP_Bool PPB_Graphics3D_Impl::DestroyTransferBuffer(int32_t id) { |
+ GetCommandBuffer()->DestroyTransferBuffer(id); |
+ return PP_TRUE; |
+} |
+ |
+PP_Bool PPB_Graphics3D_Impl::GetTransferBuffer(int32_t id, |
+ int* shm_handle, |
+ uint32_t* shm_size) { |
+ gpu::Buffer buffer = GetCommandBuffer()->GetTransferBuffer(id); |
+ return ShmToHandle(buffer.shared_memory, buffer.size, shm_handle, shm_size); |
+} |
+ |
+PP_Bool PPB_Graphics3D_Impl::Flush(int32_t put_offset) { |
+ GetCommandBuffer()->Flush(put_offset); |
+ return PP_TRUE; |
+} |
+ |
+PP_Graphics3DTrustedState PPB_Graphics3D_Impl::FlushSync(int32_t put_offset) { |
+ gpu::CommandBuffer::State state = GetCommandBuffer()->GetState(); |
+ return PPStateFromGPUState( |
+ GetCommandBuffer()->FlushSync(put_offset, state.get_offset)); |
+} |
+ |
+PP_Graphics3DTrustedState PPB_Graphics3D_Impl::FlushSyncFast( |
+ int32_t put_offset, |
+ int32_t last_known_get) { |
+ return PPStateFromGPUState( |
+ GetCommandBuffer()->FlushSync(put_offset, last_known_get)); |
+} |
+ |
+bool PPB_Graphics3D_Impl::BindToInstance(bool bind) { |
+ bound_to_instance_ = bind; |
+ return true; |
+} |
+ |
+unsigned int PPB_Graphics3D_Impl::GetBackingTextureId() { |
+ return platform_context_->GetBackingTextureId(); |
+} |
+ |
+void PPB_Graphics3D_Impl::ViewInitiatedPaint() { |
+} |
+ |
+void PPB_Graphics3D_Impl::ViewFlushedPaint() { |
+ commit_pending_ = false; |
+ |
+ if (HasPendingSwap()) |
+ SwapBuffersACK(PP_OK); |
+} |
+ |
+gpu::CommandBuffer* PPB_Graphics3D_Impl::GetCommandBuffer() { |
+ return platform_context_->GetCommandBuffer(); |
+} |
+ |
+int32 PPB_Graphics3D_Impl::DoSwapBuffers() { |
+ // We do not have a GLES2 implementation when using an OOP proxy. |
+ // The plugin-side proxy is responsible for adding the SwapBuffers command |
+ // to the command buffer in that case. |
+ if (gles2_impl()) |
+ gles2_impl()->SwapBuffers(); |
+ |
+ return PP_OK_COMPLETIONPENDING; |
+} |
+ |
bool PPB_Graphics3D_Impl::Init(PP_Config3D_Dev config, |
PP_Resource share_context, |
const int32_t* attrib_list) { |
- // TODO(alokp): Implement me. |
- return false; |
+ if (!InitRaw(config, share_context, attrib_list)) |
+ return false; |
+ |
+ gpu::CommandBuffer* command_buffer = GetCommandBuffer(); |
+ if (!command_buffer->Initialize(kCommandBufferSize)) |
+ return false; |
+ |
+ return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize); |
} |
+bool PPB_Graphics3D_Impl::InitRaw(PP_Config3D_Dev config, |
+ PP_Resource share_context, |
+ const int32_t* attrib_list) { |
+ // TODO(alokp): Support shared context. |
+ DCHECK_EQ(0, share_context); |
+ if (share_context != 0) |
+ return 0; |
+ |
+ 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; |
+} |
+ |
+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(). |
+ instance()->CommitBackingTexture(); |
+ commit_pending_ = true; |
+ } else if (HasPendingSwap()) { |
+ // If we're off-screen, no need to trigger and wait for compositing. |
+ // Just send the swap-buffers ACK to the plugin immediately. |
+ commit_pending_ = false; |
+ SwapBuffersACK(PP_OK); |
+ } |
+} |
+ |
+void PPB_Graphics3D_Impl::OnContextLost() { |
+ if (bound_to_instance_) |
+ instance()->BindGraphics(instance()->pp_instance(), 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::SendContextLost() { |
+ // By the time we run this, the instance may have been deleted, or in the |
+ // process of being deleted. Even in the latter case, we don't want to send a |
+ // callback after DidDestroy. |
+ if (!instance() || !instance()->container()) |
+ return; |
+ |
+ const PPP_Graphics3D_Dev* ppp_graphics_3d = |
+ static_cast<const PPP_Graphics3D_Dev*>( |
+ instance()->module()->GetPluginInterface( |
+ PPP_GRAPHICS_3D_DEV_INTERFACE)); |
+ if (ppp_graphics_3d) |
+ ppp_graphics_3d->Graphics3DContextLost(instance()->pp_instance()); |
+} |
+ |
} // namespace ppapi |
} // namespace webkit |