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/browser/compositor/delegated_frame_host.h"
7 #include "base/callback_helpers.h"
8 #include "base/command_line.h"
9 #include "cc/output/compositor_frame.h"
10 #include "cc/output/compositor_frame_ack.h"
11 #include "cc/output/copy_output_request.h"
12 #include "cc/resources/single_release_callback.h"
13 #include "cc/resources/texture_mailbox.h"
14 #include "content/browser/compositor/resize_lock.h"
15 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
16 #include "content/public/common/content_switches.h"
17 #include "media/base/video_frame.h"
18 #include "media/base/video_util.h"
19 #include "skia/ext/image_operations.h"
23 ////////////////////////////////////////////////////////////////////////////////
24 // DelegatedFrameHostClient
26 bool DelegatedFrameHostClient::ShouldCreateResizeLock() {
27 return GetDelegatedFrameHost()->ShouldCreateResizeLock();
30 void DelegatedFrameHostClient::RequestCopyOfOutput(
31 scoped_ptr
<cc::CopyOutputRequest
> request
) {
32 return GetDelegatedFrameHost()->RequestCopyOfOutput(request
.Pass());
35 ////////////////////////////////////////////////////////////////////////////////
38 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient
* client
)
40 last_output_surface_id_(0),
41 pending_delegated_ack_count_(0),
42 skipped_frames_(false),
43 can_lock_compositor_(YES
),
44 delegated_frame_evictor_(new DelegatedFrameEvictor(this)) {
45 ImageTransportFactory::GetInstance()->AddObserver(this);
48 void DelegatedFrameHost::WasShown() {
49 RenderWidgetHostImpl
* host
= client_
->GetHost();
50 delegated_frame_evictor_
->SetVisible(true);
52 if (host
->is_accelerated_compositing_active() &&
53 !released_front_lock_
.get()) {
54 ui::Compositor
* compositor
= client_
->GetCompositor();
56 released_front_lock_
= compositor
->GetCompositorLock();
60 void DelegatedFrameHost::WasHidden() {
61 delegated_frame_evictor_
->SetVisible(false);
62 released_front_lock_
= NULL
;
65 void DelegatedFrameHost::MaybeCreateResizeLock() {
66 if (!client_
->ShouldCreateResizeLock())
68 DCHECK(client_
->GetCompositor());
70 // Listen to changes in the compositor lock state.
71 ui::Compositor
* compositor
= client_
->GetCompositor();
72 if (!compositor
->HasObserver(this))
73 compositor
->AddObserver(this);
75 bool defer_compositor_lock
=
76 can_lock_compositor_
== NO_PENDING_RENDERER_FRAME
||
77 can_lock_compositor_
== NO_PENDING_COMMIT
;
79 if (can_lock_compositor_
== YES
)
80 can_lock_compositor_
= YES_DID_LOCK
;
82 resize_lock_
= client_
->CreateResizeLock(defer_compositor_lock
);
85 bool DelegatedFrameHost::ShouldCreateResizeLock() {
86 RenderWidgetHostImpl
* host
= client_
->GetHost();
88 // On Windows while resizing, the the resize locks makes us mis-paint a white
89 // vertical strip (including the non-client area) if the content composition
90 // is lagging the UI composition. So here we disable the throttling so that
91 // the UI bits can draw ahead of the content thereby reducing the amount of
92 // whiteout. Because this causes the content to be drawn at wrong sizes while
93 // resizing we compensate by blocking the UI thread in Compositor::Draw() by
94 // issuing a FinishAllRendering() if we are resizing.
101 if (host
->should_auto_resize())
103 if (!host
->is_accelerated_compositing_active())
106 gfx::Size desired_size
= client_
->DesiredFrameSize();
107 if (desired_size
== current_frame_size_in_dip_
)
110 ui::Compositor
* compositor
= client_
->GetCompositor();
118 void DelegatedFrameHost::RequestCopyOfOutput(
119 scoped_ptr
<cc::CopyOutputRequest
> request
) {
120 client_
->GetLayer()->RequestCopyOfOutput(request
.Pass());
123 gfx::Rect
DelegatedFrameHost::GetViewBoundsWithResizeLock(
124 const gfx::Rect
& bounds
) const {
125 if (resize_lock_
.get())
126 return gfx::Rect(bounds
.origin(), resize_lock_
->expected_size());
131 void DelegatedFrameHost::CopyFromCompositingSurface(
132 const gfx::Rect
& src_subrect
,
133 const gfx::Size
& dst_size
,
134 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
135 const SkBitmap::Config config
) {
136 // Only ARGB888 and RGB565 supported as of now.
137 bool format_support
= ((config
== SkBitmap::kRGB_565_Config
) ||
138 (config
== SkBitmap::kARGB_8888_Config
));
139 if (!format_support
) {
140 DCHECK(format_support
);
141 callback
.Run(false, SkBitmap());
144 if (!CanCopyToBitmap()) {
145 callback
.Run(false, SkBitmap());
149 const gfx::Size
& dst_size_in_pixel
= client_
->ConvertViewSizeToPixel(
151 scoped_ptr
<cc::CopyOutputRequest
> request
=
152 cc::CopyOutputRequest::CreateRequest(base::Bind(
153 &DelegatedFrameHost::CopyFromCompositingSurfaceHasResult
,
157 gfx::Rect src_subrect_in_pixel
=
158 ConvertRectToPixel(client_
->CurrentDeviceScaleFactor(), src_subrect
);
159 request
->set_area(src_subrect_in_pixel
);
160 client_
->RequestCopyOfOutput(request
.Pass());
163 void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
164 const gfx::Rect
& src_subrect
,
165 const scoped_refptr
<media::VideoFrame
>& target
,
166 const base::Callback
<void(bool)>& callback
) {
167 if (!CanCopyToVideoFrame()) {
172 // Try get a texture to reuse.
173 scoped_refptr
<OwnedMailbox
> subscriber_texture
;
174 if (frame_subscriber_
) {
175 if (!idle_frame_subscriber_textures_
.empty()) {
176 subscriber_texture
= idle_frame_subscriber_textures_
.back();
177 idle_frame_subscriber_textures_
.pop_back();
178 } else if (GLHelper
* helper
=
179 ImageTransportFactory::GetInstance()->GetGLHelper()) {
180 subscriber_texture
= new OwnedMailbox(helper
);
182 if (subscriber_texture
.get())
183 active_frame_subscriber_textures_
.insert(subscriber_texture
.get());
186 scoped_ptr
<cc::CopyOutputRequest
> request
=
187 cc::CopyOutputRequest::CreateRequest(base::Bind(
188 &DelegatedFrameHost::
189 CopyFromCompositingSurfaceHasResultForVideo
,
190 AsWeakPtr(), // For caching the ReadbackYUVInterface on this class.
194 gfx::Rect src_subrect_in_pixel
=
195 ConvertRectToPixel(client_
->CurrentDeviceScaleFactor(), src_subrect
);
196 request
->set_area(src_subrect_in_pixel
);
197 if (subscriber_texture
.get()) {
198 request
->SetTextureMailbox(
199 cc::TextureMailbox(subscriber_texture
->mailbox(),
200 subscriber_texture
->target(),
201 subscriber_texture
->sync_point()));
203 client_
->RequestCopyOfOutput(request
.Pass());
206 bool DelegatedFrameHost::CanCopyToBitmap() const {
207 return client_
->GetCompositor() &&
208 client_
->GetLayer()->has_external_content();
211 bool DelegatedFrameHost::CanCopyToVideoFrame() const {
212 RenderWidgetHostImpl
* host
= client_
->GetHost();
213 return client_
->GetCompositor() &&
214 client_
->GetLayer()->has_external_content() &&
215 host
->is_accelerated_compositing_active();
218 bool DelegatedFrameHost::CanSubscribeFrame() const {
222 void DelegatedFrameHost::BeginFrameSubscription(
223 scoped_ptr
<RenderWidgetHostViewFrameSubscriber
> subscriber
) {
224 frame_subscriber_
= subscriber
.Pass();
227 void DelegatedFrameHost::EndFrameSubscription() {
228 idle_frame_subscriber_textures_
.clear();
229 frame_subscriber_
.reset();
232 bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip
) const {
233 if (can_lock_compositor_
== NO_PENDING_RENDERER_FRAME
||
234 can_lock_compositor_
== NO_PENDING_COMMIT
||
238 return size_in_dip
!= resize_lock_
->expected_size();
241 void DelegatedFrameHost::WasResized() {
242 MaybeCreateResizeLock();
245 void DelegatedFrameHost::CheckResizeLock() {
247 resize_lock_
->expected_size() != current_frame_size_in_dip_
)
250 // Since we got the size we were looking for, unlock the compositor. But delay
251 // the release of the lock until we've kicked a frame with the new texture, to
252 // avoid resizing the UI before we have a chance to draw a "good" frame.
253 resize_lock_
->UnlockCompositor();
254 ui::Compositor
* compositor
= client_
->GetCompositor();
256 if (!compositor
->HasObserver(this))
257 compositor
->AddObserver(this);
261 void DelegatedFrameHost::DidReceiveFrameFromRenderer() {
262 if (frame_subscriber() && CanCopyToVideoFrame()) {
263 const base::TimeTicks present_time
= base::TimeTicks::Now();
264 scoped_refptr
<media::VideoFrame
> frame
;
265 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback
;
266 if (frame_subscriber()->ShouldCaptureFrame(present_time
,
267 &frame
, &callback
)) {
268 CopyFromCompositingSurfaceToVideoFrame(
269 gfx::Rect(current_frame_size_in_dip_
),
271 base::Bind(callback
, present_time
));
276 void DelegatedFrameHost::SwapDelegatedFrame(
277 uint32 output_surface_id
,
278 scoped_ptr
<cc::DelegatedFrameData
> frame_data
,
279 float frame_device_scale_factor
,
280 const std::vector
<ui::LatencyInfo
>& latency_info
) {
281 RenderWidgetHostImpl
* host
= client_
->GetHost();
282 DCHECK_NE(0u, frame_data
->render_pass_list
.size());
284 cc::RenderPass
* root_pass
= frame_data
->render_pass_list
.back();
286 gfx::Size frame_size
= root_pass
->output_rect
.size();
287 gfx::Size frame_size_in_dip
=
288 ConvertSizeToDIP(frame_device_scale_factor
, frame_size
);
290 gfx::Rect damage_rect
= gfx::ToEnclosingRect(root_pass
->damage_rect
);
291 damage_rect
.Intersect(gfx::Rect(frame_size
));
292 gfx::Rect damage_rect_in_dip
=
293 ConvertRectToDIP(frame_device_scale_factor
, damage_rect
);
295 if (ShouldSkipFrame(frame_size_in_dip
)) {
296 cc::CompositorFrameAck ack
;
297 cc::TransferableResource::ReturnResources(frame_data
->resource_list
,
299 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
300 host
->GetRoutingID(), output_surface_id
,
301 host
->GetProcess()->GetID(), ack
);
302 skipped_frames_
= true;
306 if (skipped_frames_
) {
307 skipped_frames_
= false;
308 damage_rect
= gfx::Rect(frame_size
);
309 damage_rect_in_dip
= gfx::Rect(frame_size_in_dip
);
311 // Give the same damage rect to the compositor.
312 cc::RenderPass
* root_pass
= frame_data
->render_pass_list
.back();
313 root_pass
->damage_rect
= damage_rect
;
316 if (output_surface_id
!= last_output_surface_id_
) {
317 // Resource ids are scoped by the output surface.
318 // If the originating output surface doesn't match the last one, it
319 // indicates the renderer's output surface may have been recreated, in which
320 // case we should recreate the DelegatedRendererLayer, to avoid matching
321 // resources from the old one with resources from the new one which would
322 // have the same id. Changing the layer to showing painted content destroys
323 // the DelegatedRendererLayer.
324 EvictDelegatedFrame();
326 // Drop the cc::DelegatedFrameResourceCollection so that we will not return
327 // any resources from the old output surface with the new output surface id.
328 if (resource_collection_
.get()) {
329 resource_collection_
->SetClient(NULL
);
331 if (resource_collection_
->LoseAllResources())
332 SendReturnedDelegatedResources(last_output_surface_id_
);
334 resource_collection_
= NULL
;
336 last_output_surface_id_
= output_surface_id
;
338 if (frame_size
.IsEmpty()) {
339 DCHECK_EQ(0u, frame_data
->resource_list
.size());
340 EvictDelegatedFrame();
342 if (!resource_collection_
) {
343 resource_collection_
= new cc::DelegatedFrameResourceCollection
;
344 resource_collection_
->SetClient(this);
346 // If the physical frame size changes, we need a new |frame_provider_|. If
347 // the physical frame size is the same, but the size in DIP changed, we
348 // need to adjust the scale at which the frames will be drawn, and we do
349 // this by making a new |frame_provider_| also to ensure the scale change
350 // is presented in sync with the new frame content.
351 if (!frame_provider_
.get() || frame_size
!= frame_provider_
->frame_size() ||
352 frame_size_in_dip
!= current_frame_size_in_dip_
) {
353 frame_provider_
= new cc::DelegatedFrameProvider(
354 resource_collection_
.get(), frame_data
.Pass());
355 client_
->GetLayer()->SetShowDelegatedContent(frame_provider_
.get(),
358 frame_provider_
->SetFrameData(frame_data
.Pass());
361 released_front_lock_
= NULL
;
362 current_frame_size_in_dip_
= frame_size_in_dip
;
365 client_
->SchedulePaintInRect(damage_rect_in_dip
);
367 pending_delegated_ack_count_
++;
369 ui::Compositor
* compositor
= client_
->GetCompositor();
371 SendDelegatedFrameAck(output_surface_id
);
373 for (size_t i
= 0; i
< latency_info
.size(); i
++)
374 compositor
->SetLatencyInfo(latency_info
[i
]);
375 AddOnCommitCallbackAndDisableLocks(
376 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck
,
380 DidReceiveFrameFromRenderer();
381 if (frame_provider_
.get())
382 delegated_frame_evictor_
->SwappedFrame(!host
->is_hidden());
383 // Note: the frame may have been evicted immediately.
386 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id
) {
387 RenderWidgetHostImpl
* host
= client_
->GetHost();
388 cc::CompositorFrameAck ack
;
389 if (resource_collection_
)
390 resource_collection_
->TakeUnusedResourcesForChildCompositor(&ack
.resources
);
391 RenderWidgetHostImpl::SendSwapCompositorFrameAck(host
->GetRoutingID(),
393 host
->GetProcess()->GetID(),
395 DCHECK_GT(pending_delegated_ack_count_
, 0);
396 pending_delegated_ack_count_
--;
399 void DelegatedFrameHost::UnusedResourcesAreAvailable() {
400 if (pending_delegated_ack_count_
)
403 SendReturnedDelegatedResources(last_output_surface_id_
);
406 void DelegatedFrameHost::SendReturnedDelegatedResources(
407 uint32 output_surface_id
) {
408 RenderWidgetHostImpl
* host
= client_
->GetHost();
409 DCHECK(resource_collection_
);
411 cc::CompositorFrameAck ack
;
412 resource_collection_
->TakeUnusedResourcesForChildCompositor(&ack
.resources
);
413 DCHECK(!ack
.resources
.empty());
415 RenderWidgetHostImpl::SendReclaimCompositorResources(
416 host
->GetRoutingID(),
418 host
->GetProcess()->GetID(),
422 void DelegatedFrameHost::EvictDelegatedFrame() {
423 client_
->GetLayer()->SetShowPaintedContent();
424 frame_provider_
= NULL
;
425 delegated_frame_evictor_
->DiscardedFrame();
429 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
430 const gfx::Size
& dst_size_in_pixel
,
431 const SkBitmap::Config config
,
432 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
433 scoped_ptr
<cc::CopyOutputResult
> result
) {
434 if (result
->IsEmpty() || result
->size().IsEmpty()) {
435 callback
.Run(false, SkBitmap());
439 if (result
->HasTexture()) {
440 PrepareTextureCopyOutputResult(dst_size_in_pixel
, config
,
446 DCHECK(result
->HasBitmap());
447 PrepareBitmapCopyOutputResult(dst_size_in_pixel
, config
, callback
,
451 static void CopyFromCompositingSurfaceFinished(
452 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
453 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
,
454 scoped_ptr
<SkBitmap
> bitmap
,
455 scoped_ptr
<SkAutoLockPixels
> bitmap_pixels_lock
,
457 bitmap_pixels_lock
.reset();
459 uint32 sync_point
= 0;
461 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
462 sync_point
= gl_helper
->InsertSyncPoint();
464 bool lost_resource
= sync_point
== 0;
465 release_callback
->Run(sync_point
, lost_resource
);
467 callback
.Run(result
, *bitmap
);
471 void DelegatedFrameHost::PrepareTextureCopyOutputResult(
472 const gfx::Size
& dst_size_in_pixel
,
473 const SkBitmap::Config config
,
474 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
475 scoped_ptr
<cc::CopyOutputResult
> result
) {
476 DCHECK(result
->HasTexture());
477 base::ScopedClosureRunner
scoped_callback_runner(
478 base::Bind(callback
, false, SkBitmap()));
480 scoped_ptr
<SkBitmap
> bitmap(new SkBitmap
);
481 bitmap
->setConfig(config
,
482 dst_size_in_pixel
.width(), dst_size_in_pixel
.height(),
483 0, kOpaque_SkAlphaType
);
484 if (!bitmap
->allocPixels())
487 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
488 GLHelper
* gl_helper
= factory
->GetGLHelper();
492 scoped_ptr
<SkAutoLockPixels
> bitmap_pixels_lock(
493 new SkAutoLockPixels(*bitmap
));
494 uint8
* pixels
= static_cast<uint8
*>(bitmap
->getPixels());
496 cc::TextureMailbox texture_mailbox
;
497 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
;
498 result
->TakeTexture(&texture_mailbox
, &release_callback
);
499 DCHECK(texture_mailbox
.IsTexture());
500 if (!texture_mailbox
.IsTexture())
503 ignore_result(scoped_callback_runner
.Release());
505 gl_helper
->CropScaleReadbackAndCleanMailbox(
506 texture_mailbox
.mailbox(),
507 texture_mailbox
.sync_point(),
509 gfx::Rect(result
->size()),
513 base::Bind(&CopyFromCompositingSurfaceFinished
,
515 base::Passed(&release_callback
),
516 base::Passed(&bitmap
),
517 base::Passed(&bitmap_pixels_lock
)));
521 void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
522 const gfx::Size
& dst_size_in_pixel
,
523 const SkBitmap::Config config
,
524 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
525 scoped_ptr
<cc::CopyOutputResult
> result
) {
526 if (config
!= SkBitmap::kARGB_8888_Config
) {
528 callback
.Run(false, SkBitmap());
531 DCHECK(result
->HasBitmap());
532 base::ScopedClosureRunner
scoped_callback_runner(
533 base::Bind(callback
, false, SkBitmap()));
535 scoped_ptr
<SkBitmap
> source
= result
->TakeBitmap();
540 ignore_result(scoped_callback_runner
.Release());
542 SkBitmap bitmap
= skia::ImageOperations::Resize(
544 skia::ImageOperations::RESIZE_BEST
,
545 dst_size_in_pixel
.width(),
546 dst_size_in_pixel
.height());
547 callback
.Run(true, bitmap
);
551 void DelegatedFrameHost::ReturnSubscriberTexture(
552 base::WeakPtr
<DelegatedFrameHost
> dfh
,
553 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
555 if (!subscriber_texture
.get())
560 dfh
->active_frame_subscriber_textures_
.count(subscriber_texture
.get()),
563 subscriber_texture
->UpdateSyncPoint(sync_point
);
565 dfh
->active_frame_subscriber_textures_
.erase(subscriber_texture
.get());
566 if (dfh
->frame_subscriber_
&& subscriber_texture
->texture_id())
567 dfh
->idle_frame_subscriber_textures_
.push_back(subscriber_texture
);
570 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
571 base::WeakPtr
<DelegatedFrameHost
> dfh
,
572 const base::Callback
<void(bool)>& callback
,
573 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
574 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
,
576 callback
.Run(result
);
578 uint32 sync_point
= 0;
580 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
581 sync_point
= gl_helper
->InsertSyncPoint();
583 if (release_callback
) {
584 // A release callback means the texture came from the compositor, so there
585 // should be no |subscriber_texture|.
586 DCHECK(!subscriber_texture
);
587 bool lost_resource
= sync_point
== 0;
588 release_callback
->Run(sync_point
, lost_resource
);
590 ReturnSubscriberTexture(dfh
, subscriber_texture
, sync_point
);
594 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
595 base::WeakPtr
<DelegatedFrameHost
> dfh
,
596 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
597 scoped_refptr
<media::VideoFrame
> video_frame
,
598 const base::Callback
<void(bool)>& callback
,
599 scoped_ptr
<cc::CopyOutputResult
> result
) {
600 base::ScopedClosureRunner
scoped_callback_runner(base::Bind(callback
, false));
601 base::ScopedClosureRunner
scoped_return_subscriber_texture(
602 base::Bind(&ReturnSubscriberTexture
, dfh
, subscriber_texture
, 0));
606 if (result
->IsEmpty())
608 if (result
->size().IsEmpty())
611 // Compute the dest size we want after the letterboxing resize. Make the
612 // coordinates and sizes even because we letterbox in YUV space
613 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
614 // line up correctly.
615 // The video frame's coded_size() and the result's size() are both physical
617 gfx::Rect region_in_frame
=
618 media::ComputeLetterboxRegion(gfx::Rect(video_frame
->coded_size()),
620 region_in_frame
= gfx::Rect(region_in_frame
.x() & ~1,
621 region_in_frame
.y() & ~1,
622 region_in_frame
.width() & ~1,
623 region_in_frame
.height() & ~1);
624 if (region_in_frame
.IsEmpty())
627 if (!result
->HasTexture()) {
628 DCHECK(result
->HasBitmap());
629 scoped_ptr
<SkBitmap
> bitmap
= result
->TakeBitmap();
630 // Scale the bitmap to the required size, if necessary.
631 SkBitmap scaled_bitmap
;
632 if (result
->size().width() != region_in_frame
.width() ||
633 result
->size().height() != region_in_frame
.height()) {
634 skia::ImageOperations::ResizeMethod method
=
635 skia::ImageOperations::RESIZE_GOOD
;
636 scaled_bitmap
= skia::ImageOperations::Resize(*bitmap
.get(), method
,
637 region_in_frame
.width(),
638 region_in_frame
.height());
640 scaled_bitmap
= *bitmap
.get();
644 SkAutoLockPixels
scaled_bitmap_locker(scaled_bitmap
);
646 media::CopyRGBToVideoFrame(
647 reinterpret_cast<uint8
*>(scaled_bitmap
.getPixels()),
648 scaled_bitmap
.rowBytes(),
652 ignore_result(scoped_callback_runner
.Release());
657 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
658 GLHelper
* gl_helper
= factory
->GetGLHelper();
661 if (subscriber_texture
.get() && !subscriber_texture
->texture_id())
664 cc::TextureMailbox texture_mailbox
;
665 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
;
666 result
->TakeTexture(&texture_mailbox
, &release_callback
);
667 DCHECK(texture_mailbox
.IsTexture());
668 if (!texture_mailbox
.IsTexture())
671 gfx::Rect
result_rect(result
->size());
673 content::ReadbackYUVInterface
* yuv_readback_pipeline
=
674 dfh
->yuv_readback_pipeline_
.get();
675 if (yuv_readback_pipeline
== NULL
||
676 yuv_readback_pipeline
->scaler()->SrcSize() != result_rect
.size() ||
677 yuv_readback_pipeline
->scaler()->SrcSubrect() != result_rect
||
678 yuv_readback_pipeline
->scaler()->DstSize() != region_in_frame
.size()) {
679 GLHelper::ScalerQuality quality
= GLHelper::SCALER_QUALITY_FAST
;
680 std::string quality_switch
= switches::kTabCaptureDownscaleQuality
;
681 // If we're scaling up, we can use the "best" quality.
682 if (result_rect
.size().width() < region_in_frame
.size().width() &&
683 result_rect
.size().height() < region_in_frame
.size().height())
684 quality_switch
= switches::kTabCaptureUpscaleQuality
;
686 std::string switch_value
=
687 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(quality_switch
);
688 if (switch_value
== "fast")
689 quality
= GLHelper::SCALER_QUALITY_FAST
;
690 else if (switch_value
== "good")
691 quality
= GLHelper::SCALER_QUALITY_GOOD
;
692 else if (switch_value
== "best")
693 quality
= GLHelper::SCALER_QUALITY_BEST
;
695 dfh
->yuv_readback_pipeline_
.reset(
696 gl_helper
->CreateReadbackPipelineYUV(quality
,
699 video_frame
->coded_size(),
703 yuv_readback_pipeline
= dfh
->yuv_readback_pipeline_
.get();
706 ignore_result(scoped_callback_runner
.Release());
707 ignore_result(scoped_return_subscriber_texture
.Release());
708 base::Callback
<void(bool result
)> finished_callback
= base::Bind(
709 &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo
,
713 base::Passed(&release_callback
));
714 yuv_readback_pipeline
->ReadbackYUV(texture_mailbox
.mailbox(),
715 texture_mailbox
.sync_point(),
720 ////////////////////////////////////////////////////////////////////////////////
721 // DelegatedFrameHost, ui::CompositorObserver implementation:
723 void DelegatedFrameHost::OnCompositingDidCommit(
724 ui::Compositor
* compositor
) {
725 RenderWidgetHostImpl
* host
= client_
->GetHost();
726 if (can_lock_compositor_
== NO_PENDING_COMMIT
) {
727 can_lock_compositor_
= YES
;
728 if (resize_lock_
.get() && resize_lock_
->GrabDeferredLock())
729 can_lock_compositor_
= YES_DID_LOCK
;
731 RunOnCommitCallbacks();
733 resize_lock_
->expected_size() == current_frame_size_in_dip_
) {
734 resize_lock_
.reset();
736 // We may have had a resize while we had the lock (e.g. if the lock expired,
737 // or if the UI still gave us some resizes), so make sure we grab a new lock
739 MaybeCreateResizeLock();
743 void DelegatedFrameHost::OnCompositingStarted(
744 ui::Compositor
* compositor
, base::TimeTicks start_time
) {
745 last_draw_ended_
= start_time
;
748 void DelegatedFrameHost::OnCompositingEnded(
749 ui::Compositor
* compositor
) {
752 void DelegatedFrameHost::OnCompositingAborted(
753 ui::Compositor
* compositor
) {
756 void DelegatedFrameHost::OnCompositingLockStateChanged(
757 ui::Compositor
* compositor
) {
758 // A compositor lock that is part of a resize lock timed out. We
759 // should display a renderer frame.
760 if (!compositor
->IsLocked() && can_lock_compositor_
== YES_DID_LOCK
) {
761 can_lock_compositor_
= NO_PENDING_RENDERER_FRAME
;
765 void DelegatedFrameHost::OnUpdateVSyncParameters(
766 base::TimeTicks timebase
,
767 base::TimeDelta interval
) {
768 RenderWidgetHostImpl
* host
= client_
->GetHost();
769 if (client_
->IsVisible())
770 host
->UpdateVSyncParameters(timebase
, interval
);
773 ////////////////////////////////////////////////////////////////////////////////
774 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
776 void DelegatedFrameHost::OnLostResources() {
777 RenderWidgetHostImpl
* host
= client_
->GetHost();
778 if (frame_provider_
.get())
779 EvictDelegatedFrame();
780 idle_frame_subscriber_textures_
.clear();
781 yuv_readback_pipeline_
.reset();
783 host
->ScheduleComposite();
786 ////////////////////////////////////////////////////////////////////////////////
787 // DelegatedFrameHost, private:
789 DelegatedFrameHost::~DelegatedFrameHost() {
790 ImageTransportFactory::GetInstance()->RemoveObserver(this);
792 if (resource_collection_
.get())
793 resource_collection_
->SetClient(NULL
);
795 // An OwnedMailbox should not refer to the GLHelper anymore once the DFH is
796 // destroyed, as it may then outlive the GLHelper.
797 for (std::set
<OwnedMailbox
*>::iterator it
=
798 active_frame_subscriber_textures_
.begin();
799 it
!= active_frame_subscriber_textures_
.end();
803 active_frame_subscriber_textures_
.clear();
804 DCHECK(!vsync_manager_
);
807 void DelegatedFrameHost::RunOnCommitCallbacks() {
808 for (std::vector
<base::Closure
>::const_iterator
809 it
= on_compositing_did_commit_callbacks_
.begin();
810 it
!= on_compositing_did_commit_callbacks_
.end(); ++it
) {
813 on_compositing_did_commit_callbacks_
.clear();
816 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
817 const base::Closure
& callback
) {
818 ui::Compositor
* compositor
= client_
->GetCompositor();
821 if (!compositor
->HasObserver(this))
822 compositor
->AddObserver(this);
824 can_lock_compositor_
= NO_PENDING_COMMIT
;
825 on_compositing_did_commit_callbacks_
.push_back(callback
);
828 void DelegatedFrameHost::AddedToWindow() {
829 ui::Compositor
* compositor
= client_
->GetCompositor();
831 DCHECK(!vsync_manager_
);
832 vsync_manager_
= compositor
->vsync_manager();
833 vsync_manager_
->AddObserver(this);
837 void DelegatedFrameHost::RemovingFromWindow() {
838 RunOnCommitCallbacks();
839 resize_lock_
.reset();
840 client_
->GetHost()->WasResized();
841 ui::Compositor
* compositor
= client_
->GetCompositor();
842 if (compositor
&& compositor
->HasObserver(this))
843 compositor
->RemoveObserver(this);
845 if (vsync_manager_
) {
846 vsync_manager_
->RemoveObserver(this);
847 vsync_manager_
= NULL
;
851 void DelegatedFrameHost::LockResources() {
852 DCHECK(frame_provider_
);
853 delegated_frame_evictor_
->LockFrame();
856 void DelegatedFrameHost::UnlockResources() {
857 DCHECK(frame_provider_
);
858 delegated_frame_evictor_
->UnlockFrame();
861 ////////////////////////////////////////////////////////////////////////////////
862 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
864 void DelegatedFrameHost::OnLayerRecreated(ui::Layer
* old_layer
,
865 ui::Layer
* new_layer
) {
866 // The new_layer is the one that will be used by our Window, so that's the one
867 // that should keep our frame. old_layer will be returned to the
868 // RecreateLayer caller, and should have a copy.
869 if (frame_provider_
.get()) {
870 new_layer
->SetShowDelegatedContent(frame_provider_
.get(),
871 current_frame_size_in_dip_
);
875 } // namespace content