Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / child_frame_compositing_helper.cc
1 // Copyright 2014 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.
4
5 #include "content/renderer/child_frame_compositing_helper.h"
6
7 #include "cc/layers/delegated_frame_provider.h"
8 #include "cc/layers/delegated_frame_resource_collection.h"
9 #include "cc/layers/delegated_renderer_layer.h"
10 #include "cc/layers/solid_color_layer.h"
11 #include "cc/layers/texture_layer.h"
12 #include "cc/output/context_provider.h"
13 #include "cc/output/copy_output_request.h"
14 #include "cc/output/copy_output_result.h"
15 #include "cc/resources/single_release_callback.h"
16 #include "content/common/browser_plugin/browser_plugin_messages.h"
17 #include "content/common/frame_messages.h"
18 #include "content/common/gpu/client/context_provider_command_buffer.h"
19 #include "content/renderer/browser_plugin/browser_plugin.h"
20 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
21 #include "content/renderer/render_frame_impl.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "skia/ext/image_operations.h"
24 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
25 #include "third_party/WebKit/public/web/WebFrame.h"
26 #include "third_party/WebKit/public/web/WebPluginContainer.h"
27 #include "third_party/khronos/GLES2/gl2.h"
28 #include "ui/gfx/size_conversions.h"
29 #include "ui/gfx/skia_util.h"
30 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
31
32 namespace content {
33
34 ChildFrameCompositingHelper::SwapBuffersInfo::SwapBuffersInfo()
35     : route_id(0),
36       output_surface_id(0),
37       host_id(0),
38       software_frame_id(0),
39       shared_memory(NULL) {}
40
41 ChildFrameCompositingHelper*
42 ChildFrameCompositingHelper::CreateCompositingHelperForBrowserPlugin(
43     const base::WeakPtr<BrowserPlugin>& browser_plugin) {
44   return new ChildFrameCompositingHelper(
45       browser_plugin, NULL, NULL, browser_plugin->render_view_routing_id());
46 }
47
48 ChildFrameCompositingHelper*
49 ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
50     blink::WebFrame* frame,
51     RenderFrameImpl* render_frame,
52     int host_routing_id) {
53   return new ChildFrameCompositingHelper(
54       base::WeakPtr<BrowserPlugin>(), frame, render_frame, host_routing_id);
55 }
56
57 ChildFrameCompositingHelper::ChildFrameCompositingHelper(
58     const base::WeakPtr<BrowserPlugin>& browser_plugin,
59     blink::WebFrame* frame,
60     RenderFrameImpl* render_frame,
61     int host_routing_id)
62     : host_routing_id_(host_routing_id),
63       last_route_id_(0),
64       last_output_surface_id_(0),
65       last_host_id_(0),
66       last_mailbox_valid_(false),
67       ack_pending_(true),
68       software_ack_pending_(false),
69       opaque_(true),
70       browser_plugin_(browser_plugin),
71       render_frame_(render_frame),
72       frame_(frame) {}
73
74 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
75
76 BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
77   if (!browser_plugin_)
78     return NULL;
79
80   return browser_plugin_->browser_plugin_manager();
81 }
82
83 blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() {
84   if (!browser_plugin_)
85     return NULL;
86
87   return browser_plugin_->container();
88 }
89
90 int ChildFrameCompositingHelper::GetInstanceID() {
91   if (!browser_plugin_)
92     return 0;
93
94   return browser_plugin_->guest_instance_id();
95 }
96
97 void ChildFrameCompositingHelper::SendCompositorFrameSwappedACKToBrowser(
98     FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
99   // This function will be removed when BrowserPluginManager is removed and
100   // BrowserPlugin is modified to use a RenderFrame.
101   if (GetBrowserPluginManager()) {
102     GetBrowserPluginManager()->Send(
103         new BrowserPluginHostMsg_CompositorFrameSwappedACK(
104             host_routing_id_, GetInstanceID(), params));
105   } else if (render_frame_) {
106     render_frame_->Send(
107         new FrameHostMsg_CompositorFrameSwappedACK(host_routing_id_, params));
108   }
109 }
110
111 void ChildFrameCompositingHelper::SendBuffersSwappedACKToBrowser(
112     FrameHostMsg_BuffersSwappedACK_Params& params) {
113   // This function will be removed when BrowserPluginManager is removed and
114   // BrowserPlugin is modified to use a RenderFrame.
115   if (GetBrowserPluginManager()) {
116     GetBrowserPluginManager()->Send(new BrowserPluginHostMsg_BuffersSwappedACK(
117         host_routing_id_, GetInstanceID(), params));
118   } else if (render_frame_) {
119     render_frame_->Send(
120         new FrameHostMsg_BuffersSwappedACK(host_routing_id_, params));
121   }
122 }
123
124 void ChildFrameCompositingHelper::SendReclaimCompositorResourcesToBrowser(
125     FrameHostMsg_ReclaimCompositorResources_Params& params) {
126   // This function will be removed when BrowserPluginManager is removed and
127   // BrowserPlugin is modified to use a RenderFrame.
128   if (GetBrowserPluginManager()) {
129     GetBrowserPluginManager()->Send(
130         new BrowserPluginHostMsg_ReclaimCompositorResources(
131             host_routing_id_, GetInstanceID(), params));
132   } else if (render_frame_) {
133     render_frame_->Send(
134         new FrameHostMsg_ReclaimCompositorResources(host_routing_id_, params));
135   }
136 }
137
138 void ChildFrameCompositingHelper::CopyFromCompositingSurface(
139     int request_id,
140     gfx::Rect source_rect,
141     gfx::Size dest_size) {
142   CHECK(background_layer_);
143   scoped_ptr<cc::CopyOutputRequest> request =
144       cc::CopyOutputRequest::CreateBitmapRequest(base::Bind(
145           &ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult,
146           this,
147           request_id,
148           dest_size));
149   request->set_area(source_rect);
150   background_layer_->RequestCopyOfOutput(request.Pass());
151 }
152
153 void ChildFrameCompositingHelper::DidCommitCompositorFrame() {
154   if (software_ack_pending_) {
155     FrameHostMsg_CompositorFrameSwappedACK_Params params;
156     params.producing_host_id = last_host_id_;
157     params.producing_route_id = last_route_id_;
158     params.output_surface_id = last_output_surface_id_;
159     if (!unacked_software_frames_.empty()) {
160       params.ack.last_software_frame_id = unacked_software_frames_.back();
161       unacked_software_frames_.pop_back();
162     }
163
164     SendCompositorFrameSwappedACKToBrowser(params);
165
166     software_ack_pending_ = false;
167   }
168   if (!resource_collection_.get() || !ack_pending_)
169     return;
170
171   FrameHostMsg_CompositorFrameSwappedACK_Params params;
172   params.producing_host_id = last_host_id_;
173   params.producing_route_id = last_route_id_;
174   params.output_surface_id = last_output_surface_id_;
175   resource_collection_->TakeUnusedResourcesForChildCompositor(
176       &params.ack.resources);
177
178   SendCompositorFrameSwappedACKToBrowser(params);
179
180   ack_pending_ = false;
181 }
182
183 void ChildFrameCompositingHelper::EnableCompositing(bool enable) {
184   if (enable && !background_layer_.get()) {
185     background_layer_ = cc::SolidColorLayer::Create();
186     background_layer_->SetMasksToBounds(true);
187     background_layer_->SetBackgroundColor(
188         SkColorSetARGBInline(255, 255, 255, 255));
189     web_layer_.reset(new webkit::WebLayerImpl(background_layer_));
190   }
191
192   if (GetContainer()) {
193     GetContainer()->setWebLayer(enable ? web_layer_.get() : NULL);
194   } else if (frame_) {
195     frame_->setRemoteWebLayer(enable ? web_layer_.get() : NULL);
196   }
197 }
198
199 void ChildFrameCompositingHelper::CheckSizeAndAdjustLayerProperties(
200     const gfx::Size& new_size,
201     float device_scale_factor,
202     cc::Layer* layer) {
203   if (buffer_size_ != new_size) {
204     buffer_size_ = new_size;
205     // The container size is in DIP, so is the layer size.
206     // Buffer size is in physical pixels, so we need to adjust
207     // it by the device scale factor.
208     gfx::Size device_scale_adjusted_size = gfx::ToFlooredSize(
209         gfx::ScaleSize(buffer_size_, 1.0f / device_scale_factor));
210     layer->SetBounds(device_scale_adjusted_size);
211   }
212
213   // Manually manage background layer for transparent webview.
214   if (!opaque_)
215     background_layer_->SetIsDrawable(false);
216 }
217
218 void ChildFrameCompositingHelper::MailboxReleased(SwapBuffersInfo mailbox,
219                                                   uint32 sync_point,
220                                                   bool lost_resource) {
221   if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME) {
222     delete mailbox.shared_memory;
223     mailbox.shared_memory = NULL;
224   } else if (lost_resource) {
225     // Reset mailbox's name if the resource was lost.
226     mailbox.name.SetZero();
227   }
228
229   // This means the GPU process crashed or guest crashed.
230   if (last_host_id_ != mailbox.host_id ||
231       last_output_surface_id_ != mailbox.output_surface_id ||
232       last_route_id_ != mailbox.route_id)
233     return;
234
235   if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME)
236     unacked_software_frames_.push_back(mailbox.software_frame_id);
237
238   // We need to send an ACK to for every buffer sent to us.
239   // However, if a buffer is freed up from
240   // the compositor in cases like switching back to SW mode without a new
241   // buffer arriving, no ACK is needed.
242   if (!ack_pending_) {
243     last_mailbox_valid_ = false;
244     return;
245   }
246   ack_pending_ = false;
247   switch (mailbox.type) {
248     case TEXTURE_IMAGE_TRANSPORT: {
249       FrameHostMsg_BuffersSwappedACK_Params params;
250       params.gpu_host_id = mailbox.host_id;
251       params.gpu_route_id = mailbox.route_id;
252       params.mailbox = mailbox.name;
253       params.sync_point = sync_point;
254       SendBuffersSwappedACKToBrowser(params);
255       break;
256     }
257     case GL_COMPOSITOR_FRAME: {
258       FrameHostMsg_CompositorFrameSwappedACK_Params params;
259       params.producing_host_id = mailbox.host_id;
260       params.producing_route_id = mailbox.route_id;
261       params.output_surface_id = mailbox.output_surface_id;
262       params.ack.gl_frame_data.reset(new cc::GLFrameData());
263       params.ack.gl_frame_data->mailbox = mailbox.name;
264       params.ack.gl_frame_data->size = mailbox.size;
265       params.ack.gl_frame_data->sync_point = sync_point;
266       SendCompositorFrameSwappedACKToBrowser(params);
267       break;
268     }
269     case SOFTWARE_COMPOSITOR_FRAME:
270       break;
271   }
272 }
273
274 void ChildFrameCompositingHelper::OnContainerDestroy() {
275   if (GetContainer())
276     GetContainer()->setWebLayer(NULL);
277
278   if (resource_collection_)
279     resource_collection_->SetClient(NULL);
280
281   ack_pending_ = false;
282   software_ack_pending_ = false;
283   resource_collection_ = NULL;
284   frame_provider_ = NULL;
285   texture_layer_ = NULL;
286   delegated_layer_ = NULL;
287   background_layer_ = NULL;
288   web_layer_.reset();
289 }
290
291 void ChildFrameCompositingHelper::ChildFrameGone() {
292   background_layer_->SetBackgroundColor(SkColorSetARGBInline(255, 0, 128, 0));
293   background_layer_->RemoveAllChildren();
294   background_layer_->SetIsDrawable(true);
295   background_layer_->SetContentsOpaque(true);
296 }
297
298 void ChildFrameCompositingHelper::OnBuffersSwappedPrivate(
299     const SwapBuffersInfo& mailbox,
300     uint32 sync_point,
301     float device_scale_factor) {
302   DCHECK(!delegated_layer_.get());
303   // If these mismatch, we are either just starting up, GPU process crashed or
304   // guest renderer crashed.
305   // In this case, we are communicating with a new image transport
306   // surface and must ACK with the new ID's and an empty mailbox.
307   if (last_route_id_ != mailbox.route_id ||
308       last_output_surface_id_ != mailbox.output_surface_id ||
309       last_host_id_ != mailbox.host_id)
310     last_mailbox_valid_ = false;
311
312   last_route_id_ = mailbox.route_id;
313   last_output_surface_id_ = mailbox.output_surface_id;
314   last_host_id_ = mailbox.host_id;
315
316   ack_pending_ = true;
317   // Browser plugin getting destroyed, do a fast ACK.
318   if (!background_layer_.get()) {
319     MailboxReleased(mailbox, sync_point, false);
320     return;
321   }
322
323   if (!texture_layer_.get()) {
324     texture_layer_ = cc::TextureLayer::CreateForMailbox(NULL);
325     texture_layer_->SetIsDrawable(true);
326     SetContentsOpaque(opaque_);
327
328     background_layer_->AddChild(texture_layer_);
329   }
330
331   // The size of browser plugin container is not always equal to the size
332   // of the buffer that arrives here. This could be for a number of reasons,
333   // including autosize and a resize in progress.
334   // During resize, the container size changes first and then some time
335   // later, a new buffer with updated size will arrive. During this process,
336   // we need to make sure that things are still displayed pixel perfect.
337   // We accomplish this by modifying bounds of the texture layer only
338   // when a new buffer arrives.
339   // Visually, this will either display a smaller part of the buffer
340   // or introduce a gutter around it.
341   CheckSizeAndAdjustLayerProperties(
342       mailbox.size, device_scale_factor, texture_layer_.get());
343
344   bool is_software_frame = mailbox.type == SOFTWARE_COMPOSITOR_FRAME;
345   bool current_mailbox_valid = is_software_frame ? mailbox.shared_memory != NULL
346                                                  : !mailbox.name.IsZero();
347   if (!is_software_frame && !last_mailbox_valid_) {
348     SwapBuffersInfo empty_info = mailbox;
349     empty_info.name.SetZero();
350     MailboxReleased(empty_info, 0, false);
351     if (!current_mailbox_valid)
352       return;
353   }
354
355   cc::TextureMailbox texture_mailbox;
356   scoped_ptr<cc::SingleReleaseCallback> release_callback;
357   if (current_mailbox_valid) {
358     release_callback =
359         cc::SingleReleaseCallback::Create(
360             base::Bind(&ChildFrameCompositingHelper::MailboxReleased,
361                        scoped_refptr<ChildFrameCompositingHelper>(this),
362                        mailbox)).Pass();
363     if (is_software_frame) {
364       texture_mailbox = cc::TextureMailbox(mailbox.shared_memory, mailbox.size);
365     } else {
366       texture_mailbox =
367           cc::TextureMailbox(mailbox.name, GL_TEXTURE_2D, sync_point);
368     }
369   }
370
371   texture_layer_->SetFlipped(!is_software_frame);
372   texture_layer_->SetTextureMailbox(texture_mailbox, release_callback.Pass());
373   texture_layer_->SetNeedsDisplay();
374   last_mailbox_valid_ = current_mailbox_valid;
375 }
376
377 void ChildFrameCompositingHelper::OnBuffersSwapped(
378     const gfx::Size& size,
379     const gpu::Mailbox& mailbox,
380     int gpu_route_id,
381     int gpu_host_id,
382     float device_scale_factor) {
383   SwapBuffersInfo swap_info;
384   swap_info.name = mailbox;
385   swap_info.type = TEXTURE_IMAGE_TRANSPORT;
386   swap_info.size = size;
387   swap_info.route_id = gpu_route_id;
388   swap_info.output_surface_id = 0;
389   swap_info.host_id = gpu_host_id;
390   OnBuffersSwappedPrivate(swap_info, 0, device_scale_factor);
391 }
392
393 void ChildFrameCompositingHelper::OnCompositorFrameSwapped(
394     scoped_ptr<cc::CompositorFrame> frame,
395     int route_id,
396     uint32 output_surface_id,
397     int host_id) {
398
399   if (frame->gl_frame_data) {
400     SwapBuffersInfo swap_info;
401     swap_info.name = frame->gl_frame_data->mailbox;
402     swap_info.type = GL_COMPOSITOR_FRAME;
403     swap_info.size = frame->gl_frame_data->size;
404     swap_info.route_id = route_id;
405     swap_info.output_surface_id = output_surface_id;
406     swap_info.host_id = host_id;
407     OnBuffersSwappedPrivate(swap_info,
408                             frame->gl_frame_data->sync_point,
409                             frame->metadata.device_scale_factor);
410     return;
411   }
412
413   if (frame->software_frame_data) {
414     cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
415
416     SwapBuffersInfo swap_info;
417     swap_info.type = SOFTWARE_COMPOSITOR_FRAME;
418     swap_info.size = frame_data->size;
419     swap_info.route_id = route_id;
420     swap_info.output_surface_id = output_surface_id;
421     swap_info.host_id = host_id;
422     swap_info.software_frame_id = frame_data->id;
423
424     scoped_ptr<base::SharedMemory> shared_memory(
425         new base::SharedMemory(frame_data->handle, true));
426     const size_t size_in_bytes = 4 * frame_data->size.GetArea();
427     if (!shared_memory->Map(size_in_bytes)) {
428       LOG(ERROR) << "Failed to map shared memory of size " << size_in_bytes;
429       // Send ACK right away.
430       software_ack_pending_ = true;
431       MailboxReleased(swap_info, 0, false);
432       DidCommitCompositorFrame();
433       return;
434     }
435
436     swap_info.shared_memory = shared_memory.release();
437     OnBuffersSwappedPrivate(swap_info, 0, frame->metadata.device_scale_factor);
438     software_ack_pending_ = true;
439     last_route_id_ = route_id;
440     last_output_surface_id_ = output_surface_id;
441     last_host_id_ = host_id;
442     return;
443   }
444
445   DCHECK(!texture_layer_.get());
446
447   cc::DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
448   // Do nothing if we are getting destroyed or have no frame data.
449   if (!frame_data || !background_layer_)
450     return;
451
452   DCHECK(!frame_data->render_pass_list.empty());
453   cc::RenderPass* root_pass = frame_data->render_pass_list.back();
454   gfx::Size frame_size = root_pass->output_rect.size();
455
456   if (last_route_id_ != route_id ||
457       last_output_surface_id_ != output_surface_id ||
458       last_host_id_ != host_id) {
459     // Resource ids are scoped by the output surface.
460     // If the originating output surface doesn't match the last one, it
461     // indicates the guest's output surface may have been recreated, in which
462     // case we should recreate the DelegatedRendererLayer, to avoid matching
463     // resources from the old one with resources from the new one which would
464     // have the same id.
465     frame_provider_ = NULL;
466
467     // Drop the cc::DelegatedFrameResourceCollection so that we will not return
468     // any resources from the old output surface with the new output surface id.
469     if (resource_collection_) {
470       resource_collection_->SetClient(NULL);
471
472       if (resource_collection_->LoseAllResources())
473         SendReturnedDelegatedResources();
474       resource_collection_ = NULL;
475     }
476     last_output_surface_id_ = output_surface_id;
477     last_route_id_ = route_id;
478     last_host_id_ = host_id;
479   }
480   if (!resource_collection_) {
481     resource_collection_ = new cc::DelegatedFrameResourceCollection;
482     resource_collection_->SetClient(this);
483   }
484   if (!frame_provider_.get() || frame_provider_->frame_size() != frame_size) {
485     frame_provider_ = new cc::DelegatedFrameProvider(
486         resource_collection_.get(), frame->delegated_frame_data.Pass());
487     if (delegated_layer_.get())
488       delegated_layer_->RemoveFromParent();
489     delegated_layer_ =
490         cc::DelegatedRendererLayer::Create(frame_provider_.get());
491     delegated_layer_->SetIsDrawable(true);
492     SetContentsOpaque(opaque_);
493     background_layer_->AddChild(delegated_layer_);
494   } else {
495     frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
496   }
497
498   CheckSizeAndAdjustLayerProperties(
499       frame_data->render_pass_list.back()->output_rect.size(),
500       frame->metadata.device_scale_factor,
501       delegated_layer_.get());
502
503   ack_pending_ = true;
504 }
505
506 void ChildFrameCompositingHelper::UpdateVisibility(bool visible) {
507   if (texture_layer_.get())
508     texture_layer_->SetIsDrawable(visible);
509   if (delegated_layer_.get())
510     delegated_layer_->SetIsDrawable(visible);
511 }
512
513 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
514   if (ack_pending_)
515     return;
516
517   SendReturnedDelegatedResources();
518 }
519
520 void ChildFrameCompositingHelper::SendReturnedDelegatedResources() {
521   FrameHostMsg_ReclaimCompositorResources_Params params;
522   if (resource_collection_)
523     resource_collection_->TakeUnusedResourcesForChildCompositor(
524         &params.ack.resources);
525   DCHECK(!params.ack.resources.empty());
526
527   params.route_id = last_route_id_;
528   params.output_surface_id = last_output_surface_id_;
529   params.renderer_host_id = last_host_id_;
530   SendReclaimCompositorResourcesToBrowser(params);
531 }
532
533 void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque) {
534   opaque_ = opaque;
535
536   if (texture_layer_.get())
537     texture_layer_->SetContentsOpaque(opaque_);
538   if (delegated_layer_.get())
539     delegated_layer_->SetContentsOpaque(opaque_);
540 }
541
542 void ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult(
543     int request_id,
544     gfx::Size dest_size,
545     scoped_ptr<cc::CopyOutputResult> result) {
546   scoped_ptr<SkBitmap> bitmap;
547   if (result && result->HasBitmap() && !result->size().IsEmpty())
548     bitmap = result->TakeBitmap();
549
550   SkBitmap resized_bitmap;
551   if (bitmap) {
552     resized_bitmap =
553         skia::ImageOperations::Resize(*bitmap,
554                                       skia::ImageOperations::RESIZE_BEST,
555                                       dest_size.width(),
556                                       dest_size.height());
557   }
558   if (GetBrowserPluginManager()) {
559     GetBrowserPluginManager()->Send(
560         new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
561             host_routing_id_, GetInstanceID(), request_id, resized_bitmap));
562   }
563 }
564
565 }  // namespace content