Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / pepper / ppb_graphics_3d_impl.cc
bloba4ff059b9c527b7a6ea22bd8017f0a0022daadb3
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"
7 #include "base/bind.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/common/gpu/client/command_buffer_proxy_impl.h"
12 #include "content/common/gpu/client/gpu_channel_host.h"
13 #include "content/public/common/content_switches.h"
14 #include "content/public/common/web_preferences.h"
15 #include "content/renderer/pepper/host_globals.h"
16 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
17 #include "content/renderer/pepper/plugin_module.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "content/renderer/render_view_impl.h"
20 #include "gpu/command_buffer/client/gles2_implementation.h"
21 #include "ppapi/c/ppp_graphics_3d.h"
22 #include "ppapi/thunk/enter.h"
23 #include "third_party/WebKit/public/platform/WebString.h"
24 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
25 #include "third_party/WebKit/public/web/WebDocument.h"
26 #include "third_party/WebKit/public/web/WebElement.h"
27 #include "third_party/WebKit/public/web/WebLocalFrame.h"
28 #include "third_party/WebKit/public/web/WebPluginContainer.h"
30 using ppapi::thunk::EnterResourceNoLock;
31 using ppapi::thunk::PPB_Graphics3D_API;
32 using blink::WebConsoleMessage;
33 using blink::WebLocalFrame;
34 using blink::WebPluginContainer;
35 using blink::WebString;
37 namespace content {
39 namespace {
40 const int32 kCommandBufferSize = 1024 * 1024;
41 const int32 kTransferBufferSize = 1024 * 1024;
43 } // namespace.
45 PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PP_Instance instance)
46 : PPB_Graphics3D_Shared(instance),
47 bound_to_instance_(false),
48 commit_pending_(false),
49 sync_point_(0),
50 has_alpha_(false),
51 command_buffer_(NULL),
52 weak_ptr_factory_(this) {}
54 PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() {
55 DestroyGLES2Impl();
56 if (command_buffer_) {
57 DCHECK(channel_.get());
58 channel_->DestroyCommandBuffer(command_buffer_);
59 command_buffer_ = NULL;
62 channel_ = NULL;
65 // static
66 PP_Resource PPB_Graphics3D_Impl::Create(PP_Instance instance,
67 PP_Resource share_context,
68 const int32_t* attrib_list) {
69 PPB_Graphics3D_API* share_api = NULL;
70 if (share_context) {
71 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
72 if (enter.failed())
73 return 0;
74 share_api = enter.object();
76 scoped_refptr<PPB_Graphics3D_Impl> graphics_3d(
77 new PPB_Graphics3D_Impl(instance));
78 if (!graphics_3d->Init(share_api, attrib_list))
79 return 0;
80 return graphics_3d->GetReference();
83 // static
84 PP_Resource PPB_Graphics3D_Impl::CreateRaw(PP_Instance instance,
85 PP_Resource share_context,
86 const int32_t* attrib_list) {
87 PPB_Graphics3D_API* share_api = NULL;
88 if (share_context) {
89 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
90 if (enter.failed())
91 return 0;
92 share_api = enter.object();
94 scoped_refptr<PPB_Graphics3D_Impl> graphics_3d(
95 new PPB_Graphics3D_Impl(instance));
96 if (!graphics_3d->InitRaw(share_api, attrib_list))
97 return 0;
98 return graphics_3d->GetReference();
101 PP_Bool PPB_Graphics3D_Impl::SetGetBuffer(int32_t transfer_buffer_id) {
102 GetCommandBuffer()->SetGetBuffer(transfer_buffer_id);
103 return PP_TRUE;
106 scoped_refptr<gpu::Buffer> PPB_Graphics3D_Impl::CreateTransferBuffer(
107 uint32_t size,
108 int32_t* id) {
109 return GetCommandBuffer()->CreateTransferBuffer(size, id);
112 PP_Bool PPB_Graphics3D_Impl::DestroyTransferBuffer(int32_t id) {
113 GetCommandBuffer()->DestroyTransferBuffer(id);
114 return PP_TRUE;
117 PP_Bool PPB_Graphics3D_Impl::Flush(int32_t put_offset) {
118 GetCommandBuffer()->Flush(put_offset);
119 return PP_TRUE;
122 gpu::CommandBuffer::State PPB_Graphics3D_Impl::WaitForTokenInRange(
123 int32_t start,
124 int32_t end) {
125 GetCommandBuffer()->WaitForTokenInRange(start, end);
126 return GetCommandBuffer()->GetLastState();
129 gpu::CommandBuffer::State PPB_Graphics3D_Impl::WaitForGetOffsetInRange(
130 int32_t start,
131 int32_t end) {
132 GetCommandBuffer()->WaitForGetOffsetInRange(start, end);
133 return GetCommandBuffer()->GetLastState();
136 uint32_t PPB_Graphics3D_Impl::InsertSyncPoint() {
137 return command_buffer_->InsertSyncPoint();
140 uint32_t PPB_Graphics3D_Impl::InsertFutureSyncPoint() {
141 return command_buffer_->InsertFutureSyncPoint();
144 void PPB_Graphics3D_Impl::RetireSyncPoint(uint32_t sync_point) {
145 return command_buffer_->RetireSyncPoint(sync_point);
148 bool PPB_Graphics3D_Impl::BindToInstance(bool bind) {
149 bound_to_instance_ = bind;
150 return true;
153 bool PPB_Graphics3D_Impl::IsOpaque() { return !has_alpha_; }
155 void PPB_Graphics3D_Impl::ViewInitiatedPaint() {
156 commit_pending_ = false;
158 if (HasPendingSwap())
159 SwapBuffersACK(PP_OK);
162 void PPB_Graphics3D_Impl::ViewFlushedPaint() {}
164 int PPB_Graphics3D_Impl::GetCommandBufferRouteId() {
165 DCHECK(command_buffer_);
166 return command_buffer_->GetRouteID();
169 gpu::CommandBuffer* PPB_Graphics3D_Impl::GetCommandBuffer() {
170 return command_buffer_;
173 gpu::GpuControl* PPB_Graphics3D_Impl::GetGpuControl() {
174 return command_buffer_;
177 int32 PPB_Graphics3D_Impl::DoSwapBuffers() {
178 DCHECK(command_buffer_);
179 // We do not have a GLES2 implementation when using an OOP proxy.
180 // The plugin-side proxy is responsible for adding the SwapBuffers command
181 // to the command buffer in that case.
182 if (gles2_impl())
183 gles2_impl()->SwapBuffers();
185 // Since the backing texture has been updated, a new sync point should be
186 // inserted.
187 sync_point_ = command_buffer_->InsertSyncPoint();
189 if (bound_to_instance_) {
190 // If we are bound to the instance, we need to ask the compositor
191 // to commit our backing texture so that the graphics appears on the page.
192 // When the backing texture will be committed we get notified via
193 // ViewFlushedPaint().
195 // Don't need to check for NULL from GetPluginInstance since when we're
196 // bound, we know our instance is valid.
197 HostGlobals::Get()->GetInstance(pp_instance())->CommitBackingTexture();
198 commit_pending_ = true;
199 } else {
200 // Wait for the command to complete on the GPU to allow for throttling.
201 command_buffer_->Echo(base::Bind(&PPB_Graphics3D_Impl::OnSwapBuffers,
202 weak_ptr_factory_.GetWeakPtr()));
205 return PP_OK_COMPLETIONPENDING;
208 bool PPB_Graphics3D_Impl::Init(PPB_Graphics3D_API* share_context,
209 const int32_t* attrib_list) {
210 if (!InitRaw(share_context, attrib_list))
211 return false;
213 gpu::gles2::GLES2Implementation* share_gles2 = NULL;
214 if (share_context) {
215 share_gles2 =
216 static_cast<PPB_Graphics3D_Shared*>(share_context)->gles2_impl();
219 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize, share_gles2);
222 bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context,
223 const int32_t* attrib_list) {
224 PepperPluginInstanceImpl* plugin_instance =
225 HostGlobals::Get()->GetInstance(pp_instance());
226 if (!plugin_instance)
227 return false;
229 const WebPreferences& prefs =
230 static_cast<RenderViewImpl*>(plugin_instance->GetRenderView())
231 ->webkit_preferences();
232 // 3D access might be disabled or blacklisted.
233 if (!prefs.pepper_3d_enabled)
234 return false;
236 RenderThreadImpl* render_thread = RenderThreadImpl::current();
237 if (!render_thread)
238 return false;
240 channel_ = render_thread->EstablishGpuChannelSync(
241 CAUSE_FOR_GPU_LAUNCH_PEPPERPLATFORMCONTEXT3DIMPL_INITIALIZE);
242 if (!channel_.get())
243 return false;
245 gfx::Size surface_size;
246 std::vector<int32> attribs;
247 gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
248 // TODO(alokp): Change GpuChannelHost::CreateOffscreenCommandBuffer()
249 // interface to accept width and height in the attrib_list so that
250 // we do not need to filter for width and height here.
251 if (attrib_list) {
252 for (const int32_t* attr = attrib_list; attr[0] != PP_GRAPHICS3DATTRIB_NONE;
253 attr += 2) {
254 switch (attr[0]) {
255 case PP_GRAPHICS3DATTRIB_WIDTH:
256 surface_size.set_width(attr[1]);
257 break;
258 case PP_GRAPHICS3DATTRIB_HEIGHT:
259 surface_size.set_height(attr[1]);
260 break;
261 case PP_GRAPHICS3DATTRIB_GPU_PREFERENCE:
262 gpu_preference =
263 (attr[1] == PP_GRAPHICS3DATTRIB_GPU_PREFERENCE_LOW_POWER)
264 ? gfx::PreferIntegratedGpu
265 : gfx::PreferDiscreteGpu;
266 break;
267 case PP_GRAPHICS3DATTRIB_ALPHA_SIZE:
268 has_alpha_ = attr[1] > 0;
269 // fall-through
270 default:
271 attribs.push_back(attr[0]);
272 attribs.push_back(attr[1]);
273 break;
276 attribs.push_back(PP_GRAPHICS3DATTRIB_NONE);
279 CommandBufferProxyImpl* share_buffer = NULL;
280 if (share_context) {
281 PPB_Graphics3D_Impl* share_graphics =
282 static_cast<PPB_Graphics3D_Impl*>(share_context);
283 share_buffer = share_graphics->command_buffer_;
286 command_buffer_ = channel_->CreateOffscreenCommandBuffer(
287 surface_size, share_buffer, attribs, GURL::EmptyGURL(), gpu_preference);
288 if (!command_buffer_)
289 return false;
290 if (!command_buffer_->Initialize())
291 return false;
292 mailbox_ = gpu::Mailbox::Generate();
293 if (!command_buffer_->ProduceFrontBuffer(mailbox_))
294 return false;
295 sync_point_ = command_buffer_->InsertSyncPoint();
297 command_buffer_->SetChannelErrorCallback(base::Bind(
298 &PPB_Graphics3D_Impl::OnContextLost, weak_ptr_factory_.GetWeakPtr()));
300 command_buffer_->SetOnConsoleMessageCallback(base::Bind(
301 &PPB_Graphics3D_Impl::OnConsoleMessage, weak_ptr_factory_.GetWeakPtr()));
302 return true;
305 void PPB_Graphics3D_Impl::OnConsoleMessage(const std::string& message, int id) {
306 if (!bound_to_instance_)
307 return;
308 WebPluginContainer* container =
309 HostGlobals::Get()->GetInstance(pp_instance())->container();
310 if (!container)
311 return;
312 WebLocalFrame* frame = container->element().document().frame();
313 if (!frame)
314 return;
315 WebConsoleMessage console_message = WebConsoleMessage(
316 WebConsoleMessage::LevelError, WebString(base::UTF8ToUTF16(message)));
317 frame->addMessageToConsole(console_message);
320 void PPB_Graphics3D_Impl::OnSwapBuffers() {
321 if (HasPendingSwap()) {
322 // If we're off-screen, no need to trigger and wait for compositing.
323 // Just send the swap-buffers ACK to the plugin immediately.
324 commit_pending_ = false;
325 SwapBuffersACK(PP_OK);
329 void PPB_Graphics3D_Impl::OnContextLost() {
330 // Don't need to check for NULL from GetPluginInstance since when we're
331 // bound, we know our instance is valid.
332 if (bound_to_instance_) {
333 HostGlobals::Get()->GetInstance(pp_instance())->BindGraphics(pp_instance(),
337 // Send context lost to plugin. This may have been caused by a PPAPI call, so
338 // avoid re-entering.
339 base::MessageLoop::current()->PostTask(
340 FROM_HERE,
341 base::Bind(&PPB_Graphics3D_Impl::SendContextLost,
342 weak_ptr_factory_.GetWeakPtr()));
345 void PPB_Graphics3D_Impl::SendContextLost() {
346 // By the time we run this, the instance may have been deleted, or in the
347 // process of being deleted. Even in the latter case, we don't want to send a
348 // callback after DidDestroy.
349 PepperPluginInstanceImpl* instance =
350 HostGlobals::Get()->GetInstance(pp_instance());
351 if (!instance || !instance->container())
352 return;
354 // This PPB_Graphics3D_Impl could be deleted during the call to
355 // GetPluginInterface (which sends a sync message in some cases). We still
356 // send the Graphics3DContextLost to the plugin; the instance may care about
357 // that event even though this context has been destroyed.
358 PP_Instance this_pp_instance = pp_instance();
359 const PPP_Graphics3D* ppp_graphics_3d = static_cast<const PPP_Graphics3D*>(
360 instance->module()->GetPluginInterface(PPP_GRAPHICS_3D_INTERFACE));
361 // We have to check *again* that the instance exists, because it could have
362 // been deleted during GetPluginInterface(). Even the PluginModule could be
363 // deleted, but in that case, the instance should also be gone, so the
364 // GetInstance check covers both cases.
365 if (ppp_graphics_3d && HostGlobals::Get()->GetInstance(this_pp_instance))
366 ppp_graphics_3d->Graphics3DContextLost(this_pp_instance);
369 } // namespace content