chrome.bluetoothSocket: clean-up Listen functions
[chromium-blink-merge.git] / content / renderer / child_frame_compositing_helper.cc
blob0a651db5070eaa894a7b94171e5541b2687a6156
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.
5 #include "content/renderer/child_frame_compositing_helper.h"
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"
32 namespace content {
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) {}
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());
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);
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) {}
74 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
76 BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
77 if (!browser_plugin_)
78 return NULL;
80 return browser_plugin_->browser_plugin_manager();
83 blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() {
84 if (!browser_plugin_)
85 return NULL;
87 return browser_plugin_->container();
90 int ChildFrameCompositingHelper::GetInstanceID() {
91 if (!browser_plugin_)
92 return 0;
94 return browser_plugin_->guest_instance_id();
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));
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_, params));
118 } else if (render_frame_) {
119 render_frame_->Send(
120 new FrameHostMsg_BuffersSwappedACK(host_routing_id_, params));
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));
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());
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();
164 SendCompositorFrameSwappedACKToBrowser(params);
166 software_ack_pending_ = false;
168 if (!resource_collection_.get() || !ack_pending_)
169 return;
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);
178 SendCompositorFrameSwappedACKToBrowser(params);
180 ack_pending_ = false;
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_));
192 if (GetContainer()) {
193 GetContainer()->setWebLayer(enable ? web_layer_.get() : NULL);
194 } else if (frame_) {
195 frame_->setRemoteWebLayer(enable ? web_layer_.get() : NULL);
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);
213 // Manually manage background layer for transparent webview.
214 if (!opaque_)
215 background_layer_->SetIsDrawable(false);
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();
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;
235 if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME)
236 unacked_software_frames_.push_back(mailbox.software_frame_id);
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;
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;
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;
269 case SOFTWARE_COMPOSITOR_FRAME:
270 break;
274 void ChildFrameCompositingHelper::OnContainerDestroy() {
275 if (GetContainer())
276 GetContainer()->setWebLayer(NULL);
278 if (resource_collection_)
279 resource_collection_->SetClient(NULL);
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();
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);
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;
312 last_route_id_ = mailbox.route_id;
313 last_output_surface_id_ = mailbox.output_surface_id;
314 last_host_id_ = mailbox.host_id;
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;
323 if (!texture_layer_.get()) {
324 texture_layer_ = cc::TextureLayer::CreateForMailbox(NULL);
325 texture_layer_->SetIsDrawable(true);
326 SetContentsOpaque(opaque_);
328 background_layer_->AddChild(texture_layer_);
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());
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;
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);
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;
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);
393 void ChildFrameCompositingHelper::OnCompositorFrameSwapped(
394 scoped_ptr<cc::CompositorFrame> frame,
395 int route_id,
396 uint32 output_surface_id,
397 int host_id,
398 base::SharedMemoryHandle handle) {
400 if (frame->gl_frame_data) {
401 SwapBuffersInfo swap_info;
402 swap_info.name = frame->gl_frame_data->mailbox;
403 swap_info.type = GL_COMPOSITOR_FRAME;
404 swap_info.size = frame->gl_frame_data->size;
405 swap_info.route_id = route_id;
406 swap_info.output_surface_id = output_surface_id;
407 swap_info.host_id = host_id;
408 OnBuffersSwappedPrivate(swap_info,
409 frame->gl_frame_data->sync_point,
410 frame->metadata.device_scale_factor);
411 return;
414 if (frame->software_frame_data) {
415 cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
417 SwapBuffersInfo swap_info;
418 swap_info.type = SOFTWARE_COMPOSITOR_FRAME;
419 swap_info.size = frame_data->size;
420 swap_info.route_id = route_id;
421 swap_info.output_surface_id = output_surface_id;
422 swap_info.host_id = host_id;
423 swap_info.software_frame_id = frame_data->id;
425 scoped_ptr<base::SharedMemory> shared_memory(
426 new base::SharedMemory(handle, true));
427 const size_t size_in_bytes = 4 * frame_data->size.GetArea();
428 if (!shared_memory->Map(size_in_bytes)) {
429 LOG(ERROR) << "Failed to map shared memory of size " << size_in_bytes;
430 // Send ACK right away.
431 software_ack_pending_ = true;
432 MailboxReleased(swap_info, 0, false);
433 DidCommitCompositorFrame();
434 return;
437 swap_info.shared_memory = shared_memory.release();
438 OnBuffersSwappedPrivate(swap_info, 0, frame->metadata.device_scale_factor);
439 software_ack_pending_ = true;
440 last_route_id_ = route_id;
441 last_output_surface_id_ = output_surface_id;
442 last_host_id_ = host_id;
443 return;
446 DCHECK(!texture_layer_.get());
448 cc::DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
449 // Do nothing if we are getting destroyed or have no frame data.
450 if (!frame_data || !background_layer_)
451 return;
453 DCHECK(!frame_data->render_pass_list.empty());
454 cc::RenderPass* root_pass = frame_data->render_pass_list.back();
455 gfx::Size frame_size = root_pass->output_rect.size();
457 if (last_route_id_ != route_id ||
458 last_output_surface_id_ != output_surface_id ||
459 last_host_id_ != host_id) {
460 // Resource ids are scoped by the output surface.
461 // If the originating output surface doesn't match the last one, it
462 // indicates the guest's output surface may have been recreated, in which
463 // case we should recreate the DelegatedRendererLayer, to avoid matching
464 // resources from the old one with resources from the new one which would
465 // have the same id.
466 frame_provider_ = NULL;
468 // Drop the cc::DelegatedFrameResourceCollection so that we will not return
469 // any resources from the old output surface with the new output surface id.
470 if (resource_collection_) {
471 resource_collection_->SetClient(NULL);
473 if (resource_collection_->LoseAllResources())
474 SendReturnedDelegatedResources();
475 resource_collection_ = NULL;
477 last_output_surface_id_ = output_surface_id;
478 last_route_id_ = route_id;
479 last_host_id_ = host_id;
481 if (!resource_collection_) {
482 resource_collection_ = new cc::DelegatedFrameResourceCollection;
483 resource_collection_->SetClient(this);
485 if (!frame_provider_.get() || frame_provider_->frame_size() != frame_size) {
486 frame_provider_ = new cc::DelegatedFrameProvider(
487 resource_collection_.get(), frame->delegated_frame_data.Pass());
488 if (delegated_layer_.get())
489 delegated_layer_->RemoveFromParent();
490 delegated_layer_ =
491 cc::DelegatedRendererLayer::Create(frame_provider_.get());
492 delegated_layer_->SetIsDrawable(true);
493 SetContentsOpaque(opaque_);
494 background_layer_->AddChild(delegated_layer_);
495 } else {
496 frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
499 CheckSizeAndAdjustLayerProperties(
500 frame_data->render_pass_list.back()->output_rect.size(),
501 frame->metadata.device_scale_factor,
502 delegated_layer_.get());
504 ack_pending_ = true;
507 void ChildFrameCompositingHelper::UpdateVisibility(bool visible) {
508 if (texture_layer_.get())
509 texture_layer_->SetIsDrawable(visible);
510 if (delegated_layer_.get())
511 delegated_layer_->SetIsDrawable(visible);
514 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
515 if (ack_pending_)
516 return;
518 SendReturnedDelegatedResources();
521 void ChildFrameCompositingHelper::SendReturnedDelegatedResources() {
522 FrameHostMsg_ReclaimCompositorResources_Params params;
523 if (resource_collection_)
524 resource_collection_->TakeUnusedResourcesForChildCompositor(
525 &params.ack.resources);
526 DCHECK(!params.ack.resources.empty());
528 params.route_id = last_route_id_;
529 params.output_surface_id = last_output_surface_id_;
530 params.renderer_host_id = last_host_id_;
531 SendReclaimCompositorResourcesToBrowser(params);
534 void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque) {
535 opaque_ = opaque;
537 if (texture_layer_.get())
538 texture_layer_->SetContentsOpaque(opaque_);
539 if (delegated_layer_.get())
540 delegated_layer_->SetContentsOpaque(opaque_);
543 void ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult(
544 int request_id,
545 gfx::Size dest_size,
546 scoped_ptr<cc::CopyOutputResult> result) {
547 scoped_ptr<SkBitmap> bitmap;
548 if (result && result->HasBitmap() && !result->size().IsEmpty())
549 bitmap = result->TakeBitmap();
551 SkBitmap resized_bitmap;
552 if (bitmap) {
553 resized_bitmap =
554 skia::ImageOperations::Resize(*bitmap,
555 skia::ImageOperations::RESIZE_BEST,
556 dest_size.width(),
557 dest_size.height());
559 if (GetBrowserPluginManager()) {
560 GetBrowserPluginManager()->Send(
561 new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
562 host_routing_id_, GetInstanceID(), request_id, resized_bitmap));
566 } // namespace content