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 "content/renderer/pepper/ppb_graphics_3d_impl.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/public/common/content_switches.h"
12 #include "content/renderer/pepper/host_globals.h"
13 #include "content/renderer/pepper/pepper_platform_context_3d.h"
14 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
15 #include "content/renderer/pepper/plugin_module.h"
16 #include "content/renderer/render_view_impl.h"
17 #include "gpu/command_buffer/client/gles2_implementation.h"
18 #include "ppapi/c/ppp_graphics_3d.h"
19 #include "ppapi/thunk/enter.h"
20 #include "third_party/WebKit/public/platform/WebString.h"
21 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
22 #include "third_party/WebKit/public/web/WebDocument.h"
23 #include "third_party/WebKit/public/web/WebElement.h"
24 #include "third_party/WebKit/public/web/WebFrame.h"
25 #include "third_party/WebKit/public/web/WebPluginContainer.h"
26 #include "webkit/common/webpreferences.h"
28 using ppapi::thunk::EnterResourceNoLock
;
29 using ppapi::thunk::PPB_Graphics3D_API
;
30 using WebKit::WebConsoleMessage
;
31 using WebKit::WebFrame
;
32 using WebKit::WebPluginContainer
;
33 using WebKit::WebString
;
38 const int32 kCommandBufferSize
= 1024 * 1024;
39 const int32 kTransferBufferSize
= 1024 * 1024;
41 PP_Bool
ShmToHandle(base::SharedMemory
* shm
,
45 if (!shm
|| !shm_handle
|| !shm_size
)
48 *shm_handle
= shm
->handle().fd
;
50 *shm_handle
= reinterpret_cast<int>(shm
->handle());
52 #error "Platform not supported."
60 PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PP_Instance instance
)
61 : PPB_Graphics3D_Shared(instance
),
62 bound_to_instance_(false),
63 commit_pending_(false),
64 weak_ptr_factory_(this) {
67 PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() {
72 PP_Bool
PPB_Graphics3D_Impl::IsGpuBlacklisted() {
73 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
75 return PP_FromBool(command_line
->HasSwitch(switches::kDisablePepper3d
));
80 PP_Resource
PPB_Graphics3D_Impl::Create(PP_Instance instance
,
81 PP_Resource share_context
,
82 const int32_t* attrib_list
) {
83 PPB_Graphics3D_API
* share_api
= NULL
;
84 if (IsGpuBlacklisted())
87 EnterResourceNoLock
<PPB_Graphics3D_API
> enter(share_context
, true);
90 share_api
= enter
.object();
92 scoped_refptr
<PPB_Graphics3D_Impl
> graphics_3d(
93 new PPB_Graphics3D_Impl(instance
));
94 if (!graphics_3d
->Init(share_api
, attrib_list
))
96 return graphics_3d
->GetReference();
100 PP_Resource
PPB_Graphics3D_Impl::CreateRaw(PP_Instance instance
,
101 PP_Resource share_context
,
102 const int32_t* attrib_list
) {
103 PPB_Graphics3D_API
* share_api
= NULL
;
104 if (IsGpuBlacklisted())
107 EnterResourceNoLock
<PPB_Graphics3D_API
> enter(share_context
, true);
110 share_api
= enter
.object();
112 scoped_refptr
<PPB_Graphics3D_Impl
> graphics_3d(
113 new PPB_Graphics3D_Impl(instance
));
114 if (!graphics_3d
->InitRaw(share_api
, attrib_list
))
116 return graphics_3d
->GetReference();
119 PP_Bool
PPB_Graphics3D_Impl::SetGetBuffer(int32_t transfer_buffer_id
) {
120 GetCommandBuffer()->SetGetBuffer(transfer_buffer_id
);
124 gpu::CommandBuffer::State
PPB_Graphics3D_Impl::GetState() {
125 return GetCommandBuffer()->GetState();
128 int32_t PPB_Graphics3D_Impl::CreateTransferBuffer(uint32_t size
) {
130 GetCommandBuffer()->CreateTransferBuffer(size
, &id
);
134 PP_Bool
PPB_Graphics3D_Impl::DestroyTransferBuffer(int32_t id
) {
135 GetCommandBuffer()->DestroyTransferBuffer(id
);
139 PP_Bool
PPB_Graphics3D_Impl::GetTransferBuffer(int32_t id
,
141 uint32_t* shm_size
) {
142 gpu::Buffer buffer
= GetCommandBuffer()->GetTransferBuffer(id
);
143 return ShmToHandle(buffer
.shared_memory
, buffer
.size
, shm_handle
, shm_size
);
146 PP_Bool
PPB_Graphics3D_Impl::Flush(int32_t put_offset
) {
147 GetCommandBuffer()->Flush(put_offset
);
151 gpu::CommandBuffer::State
PPB_Graphics3D_Impl::FlushSync(int32_t put_offset
) {
152 gpu::CommandBuffer::State state
= GetCommandBuffer()->GetState();
153 return GetCommandBuffer()->FlushSync(put_offset
, state
.get_offset
);
156 gpu::CommandBuffer::State
PPB_Graphics3D_Impl::FlushSyncFast(
158 int32_t last_known_get
) {
159 return GetCommandBuffer()->FlushSync(put_offset
, last_known_get
);
162 uint32_t PPB_Graphics3D_Impl::InsertSyncPoint() {
163 return platform_context_
->GetGpuControl()->InsertSyncPoint();
166 bool PPB_Graphics3D_Impl::BindToInstance(bool bind
) {
167 bound_to_instance_
= bind
;
171 bool PPB_Graphics3D_Impl::IsOpaque() {
172 return platform_context_
->IsOpaque();
175 void PPB_Graphics3D_Impl::ViewInitiatedPaint() {
176 commit_pending_
= false;
178 if (HasPendingSwap())
179 SwapBuffersACK(PP_OK
);
182 void PPB_Graphics3D_Impl::ViewFlushedPaint() {
185 gpu::CommandBuffer
* PPB_Graphics3D_Impl::GetCommandBuffer() {
186 return platform_context_
->GetCommandBuffer();
189 gpu::GpuControl
* PPB_Graphics3D_Impl::GetGpuControl() {
190 return platform_context_
->GetGpuControl();
193 int32
PPB_Graphics3D_Impl::DoSwapBuffers() {
194 // We do not have a GLES2 implementation when using an OOP proxy.
195 // The plugin-side proxy is responsible for adding the SwapBuffers command
196 // to the command buffer in that case.
198 gles2_impl()->SwapBuffers();
200 if (bound_to_instance_
) {
201 // If we are bound to the instance, we need to ask the compositor
202 // to commit our backing texture so that the graphics appears on the page.
203 // When the backing texture will be committed we get notified via
204 // ViewFlushedPaint().
206 // Don't need to check for NULL from GetPluginInstance since when we're
207 // bound, we know our instance is valid.
208 HostGlobals::Get()->GetInstance(pp_instance())->CommitBackingTexture();
209 commit_pending_
= true;
211 // Wait for the command to complete on the GPU to allow for throttling.
212 platform_context_
->Echo(base::Bind(&PPB_Graphics3D_Impl::OnSwapBuffers
,
213 weak_ptr_factory_
.GetWeakPtr()));
217 return PP_OK_COMPLETIONPENDING
;
220 bool PPB_Graphics3D_Impl::Init(PPB_Graphics3D_API
* share_context
,
221 const int32_t* attrib_list
) {
222 if (!InitRaw(share_context
, attrib_list
))
225 gpu::CommandBuffer
* command_buffer
= GetCommandBuffer();
226 if (!command_buffer
->Initialize())
229 gpu::gles2::GLES2Implementation
* share_gles2
= NULL
;
232 static_cast<PPB_Graphics3D_Shared
*>(share_context
)->gles2_impl();
235 return CreateGLES2Impl(kCommandBufferSize
, kTransferBufferSize
,
239 bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API
* share_context
,
240 const int32_t* attrib_list
) {
241 PepperPluginInstanceImpl
* plugin_instance
=
242 HostGlobals::Get()->GetInstance(pp_instance());
243 if (!plugin_instance
)
246 PlatformContext3D
* share_platform_context
= NULL
;
248 PPB_Graphics3D_Impl
* share_graphics
=
249 static_cast<PPB_Graphics3D_Impl
*>(share_context
);
250 share_platform_context
= share_graphics
->platform_context();
253 // If accelerated compositing of plugins is disabled, fail to create a 3D
254 // context, because it won't be visible. This allows graceful fallback in the
256 const WebPreferences
& prefs
= static_cast<RenderViewImpl
*>(plugin_instance
->
257 GetRenderView())->webkit_preferences();
258 if (!prefs
.accelerated_compositing_for_plugins_enabled
)
261 platform_context_
.reset(new PlatformContext3D
);
262 if (!platform_context_
)
265 if (!platform_context_
->Init(attrib_list
, share_platform_context
))
268 platform_context_
->SetContextLostCallback(
269 base::Bind(&PPB_Graphics3D_Impl::OnContextLost
,
270 weak_ptr_factory_
.GetWeakPtr()));
272 platform_context_
->SetOnConsoleMessageCallback(
273 base::Bind(&PPB_Graphics3D_Impl::OnConsoleMessage
,
274 weak_ptr_factory_
.GetWeakPtr()));
278 void PPB_Graphics3D_Impl::OnConsoleMessage(const std::string
& message
,
280 if (!bound_to_instance_
)
282 WebPluginContainer
* container
=
283 HostGlobals::Get()->GetInstance(pp_instance())->container();
286 WebFrame
* frame
= container
->element().document().frame();
289 WebConsoleMessage console_message
= WebConsoleMessage(
290 WebConsoleMessage::LevelError
, WebString(UTF8ToUTF16(message
)));
291 frame
->addMessageToConsole(console_message
);
294 void PPB_Graphics3D_Impl::OnSwapBuffers() {
295 if (HasPendingSwap()) {
296 // If we're off-screen, no need to trigger and wait for compositing.
297 // Just send the swap-buffers ACK to the plugin immediately.
298 commit_pending_
= false;
299 SwapBuffersACK(PP_OK
);
303 void PPB_Graphics3D_Impl::OnContextLost() {
304 // Don't need to check for NULL from GetPluginInstance since when we're
305 // bound, we know our instance is valid.
306 if (bound_to_instance_
) {
307 HostGlobals::Get()->GetInstance(pp_instance())->BindGraphics(
311 // Send context lost to plugin. This may have been caused by a PPAPI call, so
312 // avoid re-entering.
313 base::MessageLoop::current()->PostTask(
315 base::Bind(&PPB_Graphics3D_Impl::SendContextLost
,
316 weak_ptr_factory_
.GetWeakPtr()));
319 void PPB_Graphics3D_Impl::SendContextLost() {
320 // By the time we run this, the instance may have been deleted, or in the
321 // process of being deleted. Even in the latter case, we don't want to send a
322 // callback after DidDestroy.
323 PepperPluginInstanceImpl
* instance
=
324 HostGlobals::Get()->GetInstance(pp_instance());
325 if (!instance
|| !instance
->container())
328 // This PPB_Graphics3D_Impl could be deleted during the call to
329 // GetPluginInterface (which sends a sync message in some cases). We still
330 // send the Graphics3DContextLost to the plugin; the instance may care about
331 // that event even though this context has been destroyed.
332 PP_Instance this_pp_instance
= pp_instance();
333 const PPP_Graphics3D
* ppp_graphics_3d
=
334 static_cast<const PPP_Graphics3D
*>(
335 instance
->module()->GetPluginInterface(
336 PPP_GRAPHICS_3D_INTERFACE
));
338 ppp_graphics_3d
->Graphics3DContextLost(this_pp_instance
);
341 } // namespace content