Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / webkit / plugins / ppapi / ppb_graphics_3d_impl.cc
blobe19534b85b478ef88eb536cf21c9e70cda9d55ed
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop.h"
10 #include "base/utf_string_conversions.h"
11 #include "gpu/command_buffer/client/gles2_implementation.h"
12 #include "ppapi/c/ppp_graphics_3d.h"
13 #include "ppapi/thunk/enter.h"
14 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
20 #include "webkit/plugins/plugin_switches.h"
21 #include "webkit/plugins/ppapi/plugin_module.h"
22 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
23 #include "webkit/plugins/ppapi/resource_helper.h"
25 using ppapi::thunk::EnterResourceNoLock;
26 using ppapi::thunk::PPB_Graphics3D_API;
27 using WebKit::WebConsoleMessage;
28 using WebKit::WebFrame;
29 using WebKit::WebPluginContainer;
30 using WebKit::WebString;
32 namespace webkit {
33 namespace ppapi {
35 namespace {
36 const int32 kCommandBufferSize = 1024 * 1024;
37 const int32 kTransferBufferSize = 1024 * 1024;
39 PP_Bool ShmToHandle(base::SharedMemory* shm,
40 size_t size,
41 int* shm_handle,
42 uint32_t* shm_size) {
43 if (!shm || !shm_handle || !shm_size)
44 return PP_FALSE;
45 #if defined(OS_POSIX)
46 *shm_handle = shm->handle().fd;
47 #elif defined(OS_WIN)
48 *shm_handle = reinterpret_cast<int>(shm->handle());
49 #else
50 #error "Platform not supported."
51 #endif
52 *shm_size = size;
53 return PP_TRUE;
56 PP_Graphics3DTrustedState PPStateFromGPUState(
57 const gpu::CommandBuffer::State& s) {
58 PP_Graphics3DTrustedState state = {
59 s.num_entries,
60 s.get_offset,
61 s.put_offset,
62 s.token,
63 static_cast<PPB_Graphics3DTrustedError>(s.error),
64 s.generation
66 return state;
68 } // namespace.
70 PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PP_Instance instance)
71 : PPB_Graphics3D_Shared(instance),
72 bound_to_instance_(false),
73 commit_pending_(false),
74 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
77 PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() {
78 DestroyGLES2Impl();
81 // static
82 PP_Bool PPB_Graphics3D_Impl::IsGpuBlacklisted() {
83 CommandLine* command_line = CommandLine::ForCurrentProcess();
84 if (command_line)
85 return PP_FromBool(
86 command_line->HasSwitch(switches::kDisablePepper3d));
87 return PP_TRUE;
90 // static
91 PP_Resource PPB_Graphics3D_Impl::Create(PP_Instance instance,
92 PP_Resource share_context,
93 const int32_t* attrib_list) {
94 PPB_Graphics3D_API* share_api = NULL;
95 if (IsGpuBlacklisted())
96 return 0;
97 if (share_context) {
98 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
99 if (enter.failed())
100 return 0;
101 share_api = enter.object();
103 scoped_refptr<PPB_Graphics3D_Impl> graphics_3d(
104 new PPB_Graphics3D_Impl(instance));
105 if (!graphics_3d->Init(share_api, attrib_list))
106 return 0;
107 return graphics_3d->GetReference();
110 // static
111 PP_Resource PPB_Graphics3D_Impl::CreateRaw(PP_Instance instance,
112 PP_Resource share_context,
113 const int32_t* attrib_list) {
114 PPB_Graphics3D_API* share_api = NULL;
115 if (IsGpuBlacklisted())
116 return 0;
117 if (share_context) {
118 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
119 if (enter.failed())
120 return 0;
121 share_api = enter.object();
123 scoped_refptr<PPB_Graphics3D_Impl> graphics_3d(
124 new PPB_Graphics3D_Impl(instance));
125 if (!graphics_3d->InitRaw(share_api, attrib_list))
126 return 0;
127 return graphics_3d->GetReference();
130 PP_Bool PPB_Graphics3D_Impl::InitCommandBuffer() {
131 return PP_FromBool(GetCommandBuffer()->Initialize());
134 PP_Bool PPB_Graphics3D_Impl::SetGetBuffer(int32_t transfer_buffer_id) {
135 GetCommandBuffer()->SetGetBuffer(transfer_buffer_id);
136 return PP_TRUE;
139 PP_Graphics3DTrustedState PPB_Graphics3D_Impl::GetState() {
140 return PPStateFromGPUState(GetCommandBuffer()->GetState());
143 int32_t PPB_Graphics3D_Impl::CreateTransferBuffer(uint32_t size) {
144 int32_t id = -1;
145 GetCommandBuffer()->CreateTransferBuffer(size, &id);
146 return id;
149 PP_Bool PPB_Graphics3D_Impl::DestroyTransferBuffer(int32_t id) {
150 GetCommandBuffer()->DestroyTransferBuffer(id);
151 return PP_TRUE;
154 PP_Bool PPB_Graphics3D_Impl::GetTransferBuffer(int32_t id,
155 int* shm_handle,
156 uint32_t* shm_size) {
157 gpu::Buffer buffer = GetCommandBuffer()->GetTransferBuffer(id);
158 return ShmToHandle(buffer.shared_memory, buffer.size, shm_handle, shm_size);
161 PP_Bool PPB_Graphics3D_Impl::Flush(int32_t put_offset) {
162 GetCommandBuffer()->Flush(put_offset);
163 return PP_TRUE;
166 PP_Graphics3DTrustedState PPB_Graphics3D_Impl::FlushSync(int32_t put_offset) {
167 gpu::CommandBuffer::State state = GetCommandBuffer()->GetState();
168 return PPStateFromGPUState(
169 GetCommandBuffer()->FlushSync(put_offset, state.get_offset));
172 PP_Graphics3DTrustedState PPB_Graphics3D_Impl::FlushSyncFast(
173 int32_t put_offset,
174 int32_t last_known_get) {
175 return PPStateFromGPUState(
176 GetCommandBuffer()->FlushSync(put_offset, last_known_get));
179 uint32_t PPB_Graphics3D_Impl::InsertSyncPoint() {
180 return GetCommandBuffer()->InsertSyncPoint();
183 bool PPB_Graphics3D_Impl::BindToInstance(bool bind) {
184 bound_to_instance_ = bind;
185 return true;
188 unsigned int PPB_Graphics3D_Impl::GetBackingTextureId() {
189 return platform_context_->GetBackingTextureId();
192 bool PPB_Graphics3D_Impl::IsOpaque() {
193 return platform_context_->IsOpaque();
196 void PPB_Graphics3D_Impl::ViewWillInitiatePaint() {
199 void PPB_Graphics3D_Impl::ViewInitiatedPaint() {
200 commit_pending_ = false;
202 if (HasPendingSwap())
203 SwapBuffersACK(PP_OK);
206 void PPB_Graphics3D_Impl::ViewFlushedPaint() {
209 gpu::CommandBuffer* PPB_Graphics3D_Impl::GetCommandBuffer() {
210 return platform_context_->GetCommandBuffer();
213 int32 PPB_Graphics3D_Impl::DoSwapBuffers() {
214 // We do not have a GLES2 implementation when using an OOP proxy.
215 // The plugin-side proxy is responsible for adding the SwapBuffers command
216 // to the command buffer in that case.
217 if (gles2_impl())
218 gles2_impl()->SwapBuffers();
220 if (bound_to_instance_) {
221 // If we are bound to the instance, we need to ask the compositor
222 // to commit our backing texture so that the graphics appears on the page.
223 // When the backing texture will be committed we get notified via
224 // ViewFlushedPaint().
226 // Don't need to check for NULL from GetPluginInstance since when we're
227 // bound, we know our instance is valid.
228 ResourceHelper::GetPluginInstance(this)->CommitBackingTexture();
229 commit_pending_ = true;
230 } else {
231 // Wait for the command to complete on the GPU to allow for throttling.
232 platform_context_->Echo(base::Bind(&PPB_Graphics3D_Impl::OnSwapBuffers,
233 weak_ptr_factory_.GetWeakPtr()));
237 return PP_OK_COMPLETIONPENDING;
240 bool PPB_Graphics3D_Impl::Init(PPB_Graphics3D_API* share_context,
241 const int32_t* attrib_list) {
242 if (!InitRaw(share_context, attrib_list))
243 return false;
245 gpu::CommandBuffer* command_buffer = GetCommandBuffer();
246 if (!command_buffer->Initialize())
247 return false;
249 gpu::gles2::GLES2Implementation* share_gles2 = NULL;
250 if (share_context) {
251 share_gles2 =
252 static_cast<PPB_Graphics3D_Shared*>(share_context)->gles2_impl();
255 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize,
256 share_gles2);
259 bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context,
260 const int32_t* attrib_list) {
261 PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(this);
262 if (!plugin_instance)
263 return false;
265 PluginDelegate::PlatformContext3D* share_platform_context = NULL;
266 if (share_context) {
267 PPB_Graphics3D_Impl* share_graphics =
268 static_cast<PPB_Graphics3D_Impl*>(share_context);
269 share_platform_context = share_graphics->platform_context();
272 platform_context_.reset(plugin_instance->CreateContext3D());
273 if (!platform_context_.get())
274 return false;
276 if (!platform_context_->Init(attrib_list, share_platform_context))
277 return false;
279 platform_context_->SetContextLostCallback(
280 base::Bind(&PPB_Graphics3D_Impl::OnContextLost,
281 weak_ptr_factory_.GetWeakPtr()));
283 platform_context_->SetOnConsoleMessageCallback(
284 base::Bind(&PPB_Graphics3D_Impl::OnConsoleMessage,
285 weak_ptr_factory_.GetWeakPtr()));
286 return true;
289 void PPB_Graphics3D_Impl::OnConsoleMessage(const std::string& message,
290 int id) {
291 if (!bound_to_instance_)
292 return;
293 WebPluginContainer* container =
294 ResourceHelper::GetPluginInstance(this)->container();
295 if (!container)
296 return;
297 WebFrame* frame = container->element().document().frame();
298 if (!frame)
299 return;
300 WebConsoleMessage console_message = WebConsoleMessage(
301 WebConsoleMessage::LevelError, WebString(UTF8ToUTF16(message)));
302 frame->addMessageToConsole(console_message);
305 void PPB_Graphics3D_Impl::OnSwapBuffers() {
306 if (HasPendingSwap()) {
307 // If we're off-screen, no need to trigger and wait for compositing.
308 // Just send the swap-buffers ACK to the plugin immediately.
309 commit_pending_ = false;
310 SwapBuffersACK(PP_OK);
314 void PPB_Graphics3D_Impl::OnContextLost() {
315 // Don't need to check for NULL from GetPluginInstance since when we're
316 // bound, we know our instance is valid.
317 if (bound_to_instance_)
318 ResourceHelper::GetPluginInstance(this)->BindGraphics(pp_instance(), 0);
320 // Send context lost to plugin. This may have been caused by a PPAPI call, so
321 // avoid re-entering.
322 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
323 &PPB_Graphics3D_Impl::SendContextLost, weak_ptr_factory_.GetWeakPtr()));
326 void PPB_Graphics3D_Impl::SendContextLost() {
327 // By the time we run this, the instance may have been deleted, or in the
328 // process of being deleted. Even in the latter case, we don't want to send a
329 // callback after DidDestroy.
330 PluginInstance* instance = ResourceHelper::GetPluginInstance(this);
331 if (!instance || !instance->container())
332 return;
334 const PPP_Graphics3D* ppp_graphics_3d =
335 static_cast<const PPP_Graphics3D*>(
336 instance->module()->GetPluginInterface(
337 PPP_GRAPHICS_3D_INTERFACE));
338 if (ppp_graphics_3d)
339 ppp_graphics_3d->Graphics3DContextLost(pp_instance());
342 } // namespace ppapi
343 } // namespace webkit