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 "cc/surfaces/surface_factory.h"
15 #include "content/browser/compositor/resize_lock.h"
16 #include "content/common/gpu/client/gl_helper.h"
17 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
18 #include "content/public/common/content_switches.h"
19 #include "media/base/video_frame.h"
20 #include "media/base/video_util.h"
21 #include "skia/ext/image_operations.h"
22 #include "ui/gfx/frame_time.h"
26 ////////////////////////////////////////////////////////////////////////////////
27 // DelegatedFrameHostClient
29 bool DelegatedFrameHostClient::ShouldCreateResizeLock() {
30 // On Windows and Linux, holding pointer moves will not help throttling
32 // TODO(piman): on Windows we need to block (nested message loop?) the
33 // WM_SIZE event. On Linux we need to throttle at the WM level using
34 // _NET_WM_SYNC_REQUEST.
35 // TODO(ccameron): Mac browser window resizing is incompletely implemented.
36 #if !defined(OS_CHROMEOS)
39 return GetDelegatedFrameHost()->ShouldCreateResizeLock();
43 void DelegatedFrameHostClient::RequestCopyOfOutput(
44 scoped_ptr
<cc::CopyOutputRequest
> request
) {
45 GetDelegatedFrameHost()->RequestCopyOfOutput(request
.Pass());
48 ////////////////////////////////////////////////////////////////////////////////
51 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient
* client
)
53 use_surfaces_(base::CommandLine::ForCurrentProcess()->HasSwitch(
54 switches::kUseSurfaces
)),
55 last_output_surface_id_(0),
56 pending_delegated_ack_count_(0),
57 skipped_frames_(false),
58 can_lock_compositor_(YES_CAN_LOCK
),
59 delegated_frame_evictor_(new DelegatedFrameEvictor(this)) {
60 ImageTransportFactory::GetInstance()->AddObserver(this);
63 void DelegatedFrameHost::WasShown(const ui::LatencyInfo
& latency_info
) {
64 delegated_frame_evictor_
->SetVisible(true);
66 if (surface_id_
.is_null() && !frame_provider_
.get() &&
67 !released_front_lock_
.get()) {
68 ui::Compositor
* compositor
= client_
->GetCompositor();
70 released_front_lock_
= compositor
->GetCompositorLock();
73 ui::Compositor
* compositor
= client_
->GetCompositor();
75 compositor
->SetLatencyInfo(latency_info
);
79 bool DelegatedFrameHost::HasSavedFrame() {
80 return delegated_frame_evictor_
->HasFrame();
83 void DelegatedFrameHost::WasHidden() {
84 delegated_frame_evictor_
->SetVisible(false);
85 released_front_lock_
= NULL
;
88 void DelegatedFrameHost::MaybeCreateResizeLock() {
89 if (!client_
->ShouldCreateResizeLock())
91 DCHECK(client_
->GetCompositor());
93 // Listen to changes in the compositor lock state.
94 ui::Compositor
* compositor
= client_
->GetCompositor();
95 if (!compositor
->HasObserver(this))
96 compositor
->AddObserver(this);
98 bool defer_compositor_lock
=
99 can_lock_compositor_
== NO_PENDING_RENDERER_FRAME
||
100 can_lock_compositor_
== NO_PENDING_COMMIT
;
102 if (can_lock_compositor_
== YES_CAN_LOCK
)
103 can_lock_compositor_
= YES_DID_LOCK
;
105 resize_lock_
= client_
->CreateResizeLock(defer_compositor_lock
);
108 bool DelegatedFrameHost::ShouldCreateResizeLock() {
109 RenderWidgetHostImpl
* host
= client_
->GetHost();
114 if (host
->should_auto_resize())
117 gfx::Size desired_size
= client_
->DesiredFrameSize();
118 if (desired_size
== current_frame_size_in_dip_
|| desired_size
.IsEmpty())
121 ui::Compositor
* compositor
= client_
->GetCompositor();
128 void DelegatedFrameHost::RequestCopyOfOutput(
129 scoped_ptr
<cc::CopyOutputRequest
> request
) {
130 client_
->GetLayer()->RequestCopyOfOutput(request
.Pass());
133 void DelegatedFrameHost::CopyFromCompositingSurface(
134 const gfx::Rect
& src_subrect
,
135 const gfx::Size
& output_size
,
136 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
137 const SkColorType color_type
) {
138 // Only ARGB888 and RGB565 supported as of now.
139 bool format_support
= ((color_type
== kRGB_565_SkColorType
) ||
140 (color_type
== kN32_SkColorType
));
141 DCHECK(format_support
);
142 if (!CanCopyToBitmap()) {
143 callback
.Run(false, SkBitmap());
147 scoped_ptr
<cc::CopyOutputRequest
> request
=
148 cc::CopyOutputRequest::CreateRequest(base::Bind(
149 &DelegatedFrameHost::CopyFromCompositingSurfaceHasResult
,
153 request
->set_area(src_subrect
);
154 client_
->RequestCopyOfOutput(request
.Pass());
157 void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
158 const gfx::Rect
& src_subrect
,
159 const scoped_refptr
<media::VideoFrame
>& target
,
160 const base::Callback
<void(bool)>& callback
) {
161 if (!CanCopyToVideoFrame()) {
166 // Try get a texture to reuse.
167 scoped_refptr
<OwnedMailbox
> subscriber_texture
;
168 if (frame_subscriber_
) {
169 if (!idle_frame_subscriber_textures_
.empty()) {
170 subscriber_texture
= idle_frame_subscriber_textures_
.back();
171 idle_frame_subscriber_textures_
.pop_back();
172 } else if (GLHelper
* helper
=
173 ImageTransportFactory::GetInstance()->GetGLHelper()) {
174 subscriber_texture
= new OwnedMailbox(helper
);
178 scoped_ptr
<cc::CopyOutputRequest
> request
=
179 cc::CopyOutputRequest::CreateRequest(base::Bind(
180 &DelegatedFrameHost::
181 CopyFromCompositingSurfaceHasResultForVideo
,
182 AsWeakPtr(), // For caching the ReadbackYUVInterface on this class.
186 request
->set_area(src_subrect
);
187 if (subscriber_texture
.get()) {
188 request
->SetTextureMailbox(
189 cc::TextureMailbox(subscriber_texture
->mailbox(),
190 subscriber_texture
->target(),
191 subscriber_texture
->sync_point()));
193 client_
->RequestCopyOfOutput(request
.Pass());
196 bool DelegatedFrameHost::CanCopyToBitmap() const {
197 return client_
->GetCompositor() &&
198 client_
->GetLayer()->has_external_content();
201 bool DelegatedFrameHost::CanCopyToVideoFrame() const {
202 return client_
->GetCompositor() &&
203 client_
->GetLayer()->has_external_content();
206 bool DelegatedFrameHost::CanSubscribeFrame() const {
210 void DelegatedFrameHost::BeginFrameSubscription(
211 scoped_ptr
<RenderWidgetHostViewFrameSubscriber
> subscriber
) {
212 frame_subscriber_
= subscriber
.Pass();
215 void DelegatedFrameHost::EndFrameSubscription() {
216 idle_frame_subscriber_textures_
.clear();
217 frame_subscriber_
.reset();
220 bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip
) const {
221 // Should skip a frame only when another frame from the renderer is guaranteed
222 // to replace it. Otherwise may cause hangs when the renderer is waiting for
223 // the completion of latency infos (such as when taking a Snapshot.)
224 if (can_lock_compositor_
== NO_PENDING_RENDERER_FRAME
||
225 can_lock_compositor_
== NO_PENDING_COMMIT
||
229 return size_in_dip
!= resize_lock_
->expected_size();
232 void DelegatedFrameHost::WasResized() {
233 if (client_
->DesiredFrameSize() != current_frame_size_in_dip_
&&
234 client_
->GetHost()->is_hidden())
235 EvictDelegatedFrame();
236 MaybeCreateResizeLock();
239 gfx::Size
DelegatedFrameHost::GetRequestedRendererSize() const {
241 return resize_lock_
->expected_size();
243 return client_
->DesiredFrameSize();
246 void DelegatedFrameHost::CheckResizeLock() {
248 resize_lock_
->expected_size() != current_frame_size_in_dip_
)
251 // Since we got the size we were looking for, unlock the compositor. But delay
252 // the release of the lock until we've kicked a frame with the new texture, to
253 // avoid resizing the UI before we have a chance to draw a "good" frame.
254 resize_lock_
->UnlockCompositor();
255 ui::Compositor
* compositor
= client_
->GetCompositor();
257 if (!compositor
->HasObserver(this))
258 compositor
->AddObserver(this);
262 void DelegatedFrameHost::DidReceiveFrameFromRenderer(
263 const gfx::Rect
& damage_rect
) {
264 if (!frame_subscriber() || !CanCopyToVideoFrame())
267 const base::TimeTicks now
= gfx::FrameTime::Now();
268 base::TimeTicks present_time
;
269 if (vsync_timebase_
.is_null() || vsync_interval_
<= base::TimeDelta()) {
272 const int64 intervals_elapsed
= (now
- vsync_timebase_
) / vsync_interval_
;
273 present_time
= vsync_timebase_
+ (intervals_elapsed
+ 1) * vsync_interval_
;
276 scoped_refptr
<media::VideoFrame
> frame
;
277 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback
;
278 if (frame_subscriber()->ShouldCaptureFrame(damage_rect
, present_time
,
279 &frame
, &callback
)) {
280 CopyFromCompositingSurfaceToVideoFrame(
281 gfx::Rect(current_frame_size_in_dip_
),
283 base::Bind(callback
, present_time
));
287 void DelegatedFrameHost::SwapDelegatedFrame(
288 uint32 output_surface_id
,
289 scoped_ptr
<cc::DelegatedFrameData
> frame_data
,
290 float frame_device_scale_factor
,
291 const std::vector
<ui::LatencyInfo
>& latency_info
) {
292 RenderWidgetHostImpl
* host
= client_
->GetHost();
293 DCHECK(!frame_data
->render_pass_list
.empty());
295 cc::RenderPass
* root_pass
= frame_data
->render_pass_list
.back();
297 gfx::Size frame_size
= root_pass
->output_rect
.size();
298 gfx::Size frame_size_in_dip
=
299 ConvertSizeToDIP(frame_device_scale_factor
, frame_size
);
301 gfx::Rect damage_rect
= gfx::ToEnclosingRect(root_pass
->damage_rect
);
302 damage_rect
.Intersect(gfx::Rect(frame_size
));
303 gfx::Rect damage_rect_in_dip
=
304 ConvertRectToDIP(frame_device_scale_factor
, damage_rect
);
306 if (ShouldSkipFrame(frame_size_in_dip
)) {
307 cc::CompositorFrameAck ack
;
308 cc::TransferableResource::ReturnResources(frame_data
->resource_list
,
311 skipped_latency_info_list_
.insert(skipped_latency_info_list_
.end(),
312 latency_info
.begin(), latency_info
.end());
314 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
315 host
->GetRoutingID(), output_surface_id
,
316 host
->GetProcess()->GetID(), ack
);
317 skipped_frames_
= true;
321 if (skipped_frames_
) {
322 skipped_frames_
= false;
323 damage_rect
= gfx::Rect(frame_size
);
324 damage_rect_in_dip
= gfx::Rect(frame_size_in_dip
);
326 // Give the same damage rect to the compositor.
327 cc::RenderPass
* root_pass
= frame_data
->render_pass_list
.back();
328 root_pass
->damage_rect
= damage_rect
;
331 if (output_surface_id
!= last_output_surface_id_
) {
332 // Resource ids are scoped by the output surface.
333 // If the originating output surface doesn't match the last one, it
334 // indicates the renderer's output surface may have been recreated, in which
335 // case we should recreate the DelegatedRendererLayer, to avoid matching
336 // resources from the old one with resources from the new one which would
337 // have the same id. Changing the layer to showing painted content destroys
338 // the DelegatedRendererLayer.
339 EvictDelegatedFrame();
341 // Drop the cc::DelegatedFrameResourceCollection so that we will not return
342 // any resources from the old output surface with the new output surface id.
343 if (resource_collection_
.get()) {
344 resource_collection_
->SetClient(NULL
);
346 if (resource_collection_
->LoseAllResources())
347 SendReturnedDelegatedResources(last_output_surface_id_
);
349 resource_collection_
= NULL
;
351 last_output_surface_id_
= output_surface_id
;
353 bool modified_layers
= false;
354 if (frame_size
.IsEmpty()) {
355 DCHECK(frame_data
->resource_list
.empty());
356 EvictDelegatedFrame();
357 modified_layers
= true;
360 if (!surface_factory_
) {
361 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
362 cc::SurfaceManager
* manager
= factory
->GetSurfaceManager();
363 id_allocator_
= factory
->CreateSurfaceIdAllocator();
365 make_scoped_ptr(new cc::SurfaceFactory(manager
, this));
367 if (surface_id_
.is_null() || frame_size
!= current_surface_size_
||
368 frame_size_in_dip
!= current_frame_size_in_dip_
) {
369 // TODO(jbauman): Wait to destroy this surface until the parent has
370 // finished using it.
371 if (!surface_id_
.is_null())
372 surface_factory_
->Destroy(surface_id_
);
373 surface_id_
= id_allocator_
->GenerateId();
374 surface_factory_
->Create(surface_id_
, frame_size
);
375 client_
->GetLayer()->SetShowSurface(surface_id_
, frame_size_in_dip
);
376 current_surface_size_
= frame_size
;
377 modified_layers
= true;
379 scoped_ptr
<cc::CompositorFrame
> compositor_frame
=
380 make_scoped_ptr(new cc::CompositorFrame());
381 compositor_frame
->delegated_frame_data
= frame_data
.Pass();
382 surface_factory_
->SubmitFrame(
384 compositor_frame
.Pass(),
385 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck
,
389 if (!resource_collection_
.get()) {
390 resource_collection_
= new cc::DelegatedFrameResourceCollection
;
391 resource_collection_
->SetClient(this);
393 // If the physical frame size changes, we need a new |frame_provider_|. If
394 // the physical frame size is the same, but the size in DIP changed, we
395 // need to adjust the scale at which the frames will be drawn, and we do
396 // this by making a new |frame_provider_| also to ensure the scale change
397 // is presented in sync with the new frame content.
398 if (!frame_provider_
.get() ||
399 frame_size
!= frame_provider_
->frame_size() ||
400 frame_size_in_dip
!= current_frame_size_in_dip_
) {
401 frame_provider_
= new cc::DelegatedFrameProvider(
402 resource_collection_
.get(), frame_data
.Pass());
403 client_
->GetLayer()->SetShowDelegatedContent(frame_provider_
.get(),
406 frame_provider_
->SetFrameData(frame_data
.Pass());
408 modified_layers
= true;
411 released_front_lock_
= NULL
;
412 current_frame_size_in_dip_
= frame_size_in_dip
;
415 if (modified_layers
&& !damage_rect_in_dip
.IsEmpty()) {
416 // TODO(jbauman): Need to always tell the window observer about the
418 client_
->GetLayer()->OnDelegatedFrameDamage(damage_rect_in_dip
);
421 pending_delegated_ack_count_
++;
423 ui::Compositor
* compositor
= client_
->GetCompositor();
425 SendDelegatedFrameAck(output_surface_id
);
426 } else if (!use_surfaces_
) {
427 std::vector
<ui::LatencyInfo
>::const_iterator it
;
428 for (it
= latency_info
.begin(); it
!= latency_info
.end(); ++it
)
429 compositor
->SetLatencyInfo(*it
);
430 // If we've previously skipped any latency infos add them.
431 for (it
= skipped_latency_info_list_
.begin();
432 it
!= skipped_latency_info_list_
.end();
434 compositor
->SetLatencyInfo(*it
);
435 skipped_latency_info_list_
.clear();
436 AddOnCommitCallbackAndDisableLocks(
437 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck
,
441 DidReceiveFrameFromRenderer(damage_rect
);
442 if (frame_provider_
.get() || !surface_id_
.is_null())
443 delegated_frame_evictor_
->SwappedFrame(!host
->is_hidden());
444 // Note: the frame may have been evicted immediately.
447 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id
) {
448 RenderWidgetHostImpl
* host
= client_
->GetHost();
449 cc::CompositorFrameAck ack
;
450 if (!surface_returned_resources_
.empty())
451 ack
.resources
.swap(surface_returned_resources_
);
452 if (resource_collection_
.get())
453 resource_collection_
->TakeUnusedResourcesForChildCompositor(&ack
.resources
);
454 RenderWidgetHostImpl::SendSwapCompositorFrameAck(host
->GetRoutingID(),
456 host
->GetProcess()->GetID(),
458 DCHECK_GT(pending_delegated_ack_count_
, 0);
459 pending_delegated_ack_count_
--;
462 void DelegatedFrameHost::UnusedResourcesAreAvailable() {
463 if (pending_delegated_ack_count_
)
466 SendReturnedDelegatedResources(last_output_surface_id_
);
469 void DelegatedFrameHost::SendReturnedDelegatedResources(
470 uint32 output_surface_id
) {
471 RenderWidgetHostImpl
* host
= client_
->GetHost();
473 cc::CompositorFrameAck ack
;
474 if (!surface_returned_resources_
.empty()) {
475 ack
.resources
.swap(surface_returned_resources_
);
477 DCHECK(resource_collection_
.get());
478 resource_collection_
->TakeUnusedResourcesForChildCompositor(&ack
.resources
);
480 DCHECK(!ack
.resources
.empty());
482 RenderWidgetHostImpl::SendReclaimCompositorResources(
483 host
->GetRoutingID(),
485 host
->GetProcess()->GetID(),
489 void DelegatedFrameHost::ReturnResources(
490 const cc::ReturnedResourceArray
& resources
) {
491 if (resources
.empty())
493 std::copy(resources
.begin(),
495 std::back_inserter(surface_returned_resources_
));
496 if (!pending_delegated_ack_count_
)
497 SendReturnedDelegatedResources(last_output_surface_id_
);
500 void DelegatedFrameHost::EvictDelegatedFrame() {
501 client_
->GetLayer()->SetShowPaintedContent();
502 frame_provider_
= NULL
;
503 if (!surface_id_
.is_null()) {
504 surface_factory_
->Destroy(surface_id_
);
505 surface_id_
= cc::SurfaceId();
507 delegated_frame_evictor_
->DiscardedFrame();
511 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
512 const gfx::Size
& dst_size_in_pixel
,
513 const SkColorType color_type
,
514 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
515 scoped_ptr
<cc::CopyOutputResult
> result
) {
516 if (result
->IsEmpty() || result
->size().IsEmpty()) {
517 callback
.Run(false, SkBitmap());
521 if (result
->HasTexture()) {
522 PrepareTextureCopyOutputResult(dst_size_in_pixel
, color_type
,
528 DCHECK(result
->HasBitmap());
529 PrepareBitmapCopyOutputResult(dst_size_in_pixel
, color_type
, callback
,
533 static void CopyFromCompositingSurfaceFinished(
534 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
535 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
,
536 scoped_ptr
<SkBitmap
> bitmap
,
537 scoped_ptr
<SkAutoLockPixels
> bitmap_pixels_lock
,
539 bitmap_pixels_lock
.reset();
541 uint32 sync_point
= 0;
543 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
544 sync_point
= gl_helper
->InsertSyncPoint();
546 bool lost_resource
= sync_point
== 0;
547 release_callback
->Run(sync_point
, lost_resource
);
549 callback
.Run(result
, *bitmap
);
553 void DelegatedFrameHost::PrepareTextureCopyOutputResult(
554 const gfx::Size
& dst_size_in_pixel
,
555 const SkColorType color_type
,
556 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
557 scoped_ptr
<cc::CopyOutputResult
> result
) {
558 DCHECK(result
->HasTexture());
559 base::ScopedClosureRunner
scoped_callback_runner(
560 base::Bind(callback
, false, SkBitmap()));
562 scoped_ptr
<SkBitmap
> bitmap(new SkBitmap
);
563 if (!bitmap
->allocPixels(SkImageInfo::Make(dst_size_in_pixel
.width(),
564 dst_size_in_pixel
.height(),
566 kOpaque_SkAlphaType
)))
569 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
570 GLHelper
* gl_helper
= factory
->GetGLHelper();
574 scoped_ptr
<SkAutoLockPixels
> bitmap_pixels_lock(
575 new SkAutoLockPixels(*bitmap
));
576 uint8
* pixels
= static_cast<uint8
*>(bitmap
->getPixels());
578 cc::TextureMailbox texture_mailbox
;
579 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
;
580 result
->TakeTexture(&texture_mailbox
, &release_callback
);
581 DCHECK(texture_mailbox
.IsTexture());
583 ignore_result(scoped_callback_runner
.Release());
585 gl_helper
->CropScaleReadbackAndCleanMailbox(
586 texture_mailbox
.mailbox(),
587 texture_mailbox
.sync_point(),
589 gfx::Rect(result
->size()),
593 base::Bind(&CopyFromCompositingSurfaceFinished
,
595 base::Passed(&release_callback
),
596 base::Passed(&bitmap
),
597 base::Passed(&bitmap_pixels_lock
)),
598 GLHelper::SCALER_QUALITY_FAST
);
602 void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
603 const gfx::Size
& dst_size_in_pixel
,
604 const SkColorType color_type
,
605 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
606 scoped_ptr
<cc::CopyOutputResult
> result
) {
607 if (color_type
!= kN32_SkColorType
) {
609 callback
.Run(false, SkBitmap());
612 DCHECK(result
->HasBitmap());
613 scoped_ptr
<SkBitmap
> source
= result
->TakeBitmap();
615 SkBitmap bitmap
= skia::ImageOperations::Resize(
617 skia::ImageOperations::RESIZE_BEST
,
618 dst_size_in_pixel
.width(),
619 dst_size_in_pixel
.height());
620 callback
.Run(true, bitmap
);
624 void DelegatedFrameHost::ReturnSubscriberTexture(
625 base::WeakPtr
<DelegatedFrameHost
> dfh
,
626 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
628 if (!subscriber_texture
.get())
633 subscriber_texture
->UpdateSyncPoint(sync_point
);
635 if (dfh
->frame_subscriber_
&& subscriber_texture
->texture_id())
636 dfh
->idle_frame_subscriber_textures_
.push_back(subscriber_texture
);
639 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
640 base::WeakPtr
<DelegatedFrameHost
> dfh
,
641 const base::Callback
<void(bool)>& callback
,
642 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
643 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
,
645 callback
.Run(result
);
647 uint32 sync_point
= 0;
649 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
650 sync_point
= gl_helper
->InsertSyncPoint();
652 if (release_callback
) {
653 // A release callback means the texture came from the compositor, so there
654 // should be no |subscriber_texture|.
655 DCHECK(!subscriber_texture
.get());
656 bool lost_resource
= sync_point
== 0;
657 release_callback
->Run(sync_point
, lost_resource
);
659 ReturnSubscriberTexture(dfh
, subscriber_texture
, sync_point
);
663 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
664 base::WeakPtr
<DelegatedFrameHost
> dfh
,
665 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
666 scoped_refptr
<media::VideoFrame
> video_frame
,
667 const base::Callback
<void(bool)>& callback
,
668 scoped_ptr
<cc::CopyOutputResult
> result
) {
669 base::ScopedClosureRunner
scoped_callback_runner(base::Bind(callback
, false));
670 base::ScopedClosureRunner
scoped_return_subscriber_texture(
671 base::Bind(&ReturnSubscriberTexture
, dfh
, subscriber_texture
, 0));
675 if (result
->IsEmpty())
677 if (result
->size().IsEmpty())
680 // Compute the dest size we want after the letterboxing resize. Make the
681 // coordinates and sizes even because we letterbox in YUV space
682 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
683 // line up correctly.
684 // The video frame's coded_size() and the result's size() are both physical
686 gfx::Rect region_in_frame
=
687 media::ComputeLetterboxRegion(gfx::Rect(video_frame
->coded_size()),
689 region_in_frame
= gfx::Rect(region_in_frame
.x() & ~1,
690 region_in_frame
.y() & ~1,
691 region_in_frame
.width() & ~1,
692 region_in_frame
.height() & ~1);
693 if (region_in_frame
.IsEmpty())
696 if (!result
->HasTexture()) {
697 DCHECK(result
->HasBitmap());
698 scoped_ptr
<SkBitmap
> bitmap
= result
->TakeBitmap();
699 // Scale the bitmap to the required size, if necessary.
700 SkBitmap scaled_bitmap
;
701 if (result
->size().width() != region_in_frame
.width() ||
702 result
->size().height() != region_in_frame
.height()) {
703 skia::ImageOperations::ResizeMethod method
=
704 skia::ImageOperations::RESIZE_GOOD
;
705 scaled_bitmap
= skia::ImageOperations::Resize(*bitmap
.get(), method
,
706 region_in_frame
.width(),
707 region_in_frame
.height());
709 scaled_bitmap
= *bitmap
.get();
713 SkAutoLockPixels
scaled_bitmap_locker(scaled_bitmap
);
715 media::CopyRGBToVideoFrame(
716 reinterpret_cast<uint8
*>(scaled_bitmap
.getPixels()),
717 scaled_bitmap
.rowBytes(),
721 ignore_result(scoped_callback_runner
.Release());
726 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
727 GLHelper
* gl_helper
= factory
->GetGLHelper();
730 if (subscriber_texture
.get() && !subscriber_texture
->texture_id())
733 cc::TextureMailbox texture_mailbox
;
734 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
;
735 result
->TakeTexture(&texture_mailbox
, &release_callback
);
736 DCHECK(texture_mailbox
.IsTexture());
738 gfx::Rect
result_rect(result
->size());
740 content::ReadbackYUVInterface
* yuv_readback_pipeline
=
741 dfh
->yuv_readback_pipeline_
.get();
742 if (yuv_readback_pipeline
== NULL
||
743 yuv_readback_pipeline
->scaler()->SrcSize() != result_rect
.size() ||
744 yuv_readback_pipeline
->scaler()->SrcSubrect() != result_rect
||
745 yuv_readback_pipeline
->scaler()->DstSize() != region_in_frame
.size()) {
746 GLHelper::ScalerQuality quality
= GLHelper::SCALER_QUALITY_FAST
;
747 std::string quality_switch
= switches::kTabCaptureDownscaleQuality
;
748 // If we're scaling up, we can use the "best" quality.
749 if (result_rect
.size().width() < region_in_frame
.size().width() &&
750 result_rect
.size().height() < region_in_frame
.size().height())
751 quality_switch
= switches::kTabCaptureUpscaleQuality
;
753 std::string switch_value
=
754 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
756 if (switch_value
== "fast")
757 quality
= GLHelper::SCALER_QUALITY_FAST
;
758 else if (switch_value
== "good")
759 quality
= GLHelper::SCALER_QUALITY_GOOD
;
760 else if (switch_value
== "best")
761 quality
= GLHelper::SCALER_QUALITY_BEST
;
763 dfh
->yuv_readback_pipeline_
.reset(
764 gl_helper
->CreateReadbackPipelineYUV(quality
,
767 video_frame
->coded_size(),
771 yuv_readback_pipeline
= dfh
->yuv_readback_pipeline_
.get();
774 ignore_result(scoped_callback_runner
.Release());
775 ignore_result(scoped_return_subscriber_texture
.Release());
776 base::Callback
<void(bool result
)> finished_callback
= base::Bind(
777 &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo
,
781 base::Passed(&release_callback
));
782 yuv_readback_pipeline
->ReadbackYUV(texture_mailbox
.mailbox(),
783 texture_mailbox
.sync_point(),
788 ////////////////////////////////////////////////////////////////////////////////
789 // DelegatedFrameHost, ui::CompositorObserver implementation:
791 void DelegatedFrameHost::OnCompositingDidCommit(
792 ui::Compositor
* compositor
) {
793 RenderWidgetHostImpl
* host
= client_
->GetHost();
794 if (can_lock_compositor_
== NO_PENDING_COMMIT
) {
795 can_lock_compositor_
= YES_CAN_LOCK
;
796 if (resize_lock_
.get() && resize_lock_
->GrabDeferredLock())
797 can_lock_compositor_
= YES_DID_LOCK
;
799 RunOnCommitCallbacks();
801 resize_lock_
->expected_size() == current_frame_size_in_dip_
) {
802 resize_lock_
.reset();
804 // We may have had a resize while we had the lock (e.g. if the lock expired,
805 // or if the UI still gave us some resizes), so make sure we grab a new lock
807 MaybeCreateResizeLock();
811 void DelegatedFrameHost::OnCompositingStarted(
812 ui::Compositor
* compositor
, base::TimeTicks start_time
) {
813 last_draw_ended_
= start_time
;
816 void DelegatedFrameHost::OnCompositingEnded(
817 ui::Compositor
* compositor
) {
820 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor
* compositor
) {
823 void DelegatedFrameHost::OnCompositingLockStateChanged(
824 ui::Compositor
* compositor
) {
825 // A compositor lock that is part of a resize lock timed out. We
826 // should display a renderer frame.
827 if (!compositor
->IsLocked() && can_lock_compositor_
== YES_DID_LOCK
) {
828 can_lock_compositor_
= NO_PENDING_RENDERER_FRAME
;
832 void DelegatedFrameHost::OnUpdateVSyncParameters(
833 base::TimeTicks timebase
,
834 base::TimeDelta interval
) {
835 vsync_timebase_
= timebase
;
836 vsync_interval_
= interval
;
837 RenderWidgetHostImpl
* host
= client_
->GetHost();
838 if (client_
->IsVisible())
839 host
->UpdateVSyncParameters(timebase
, interval
);
842 ////////////////////////////////////////////////////////////////////////////////
843 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
845 void DelegatedFrameHost::OnLostResources() {
846 RenderWidgetHostImpl
* host
= client_
->GetHost();
847 if (frame_provider_
.get() || !surface_id_
.is_null())
848 EvictDelegatedFrame();
849 idle_frame_subscriber_textures_
.clear();
850 yuv_readback_pipeline_
.reset();
852 host
->ScheduleComposite();
855 ////////////////////////////////////////////////////////////////////////////////
856 // DelegatedFrameHost, private:
858 DelegatedFrameHost::~DelegatedFrameHost() {
859 ImageTransportFactory::GetInstance()->RemoveObserver(this);
861 if (!surface_id_
.is_null())
862 surface_factory_
->Destroy(surface_id_
);
863 if (resource_collection_
.get())
864 resource_collection_
->SetClient(NULL
);
866 DCHECK(!vsync_manager_
.get());
869 void DelegatedFrameHost::RunOnCommitCallbacks() {
870 for (std::vector
<base::Closure
>::const_iterator
871 it
= on_compositing_did_commit_callbacks_
.begin();
872 it
!= on_compositing_did_commit_callbacks_
.end(); ++it
) {
875 on_compositing_did_commit_callbacks_
.clear();
878 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
879 const base::Closure
& callback
) {
880 ui::Compositor
* compositor
= client_
->GetCompositor();
883 if (!compositor
->HasObserver(this))
884 compositor
->AddObserver(this);
886 can_lock_compositor_
= NO_PENDING_COMMIT
;
887 on_compositing_did_commit_callbacks_
.push_back(callback
);
890 void DelegatedFrameHost::AddedToWindow() {
891 ui::Compositor
* compositor
= client_
->GetCompositor();
893 DCHECK(!vsync_manager_
.get());
894 vsync_manager_
= compositor
->vsync_manager();
895 vsync_manager_
->AddObserver(this);
899 void DelegatedFrameHost::RemovingFromWindow() {
900 RunOnCommitCallbacks();
901 resize_lock_
.reset();
902 client_
->GetHost()->WasResized();
903 ui::Compositor
* compositor
= client_
->GetCompositor();
904 if (compositor
&& compositor
->HasObserver(this))
905 compositor
->RemoveObserver(this);
907 if (vsync_manager_
.get()) {
908 vsync_manager_
->RemoveObserver(this);
909 vsync_manager_
= NULL
;
913 void DelegatedFrameHost::LockResources() {
914 DCHECK(frame_provider_
.get() || !surface_id_
.is_null());
915 delegated_frame_evictor_
->LockFrame();
918 void DelegatedFrameHost::UnlockResources() {
919 DCHECK(frame_provider_
.get() || !surface_id_
.is_null());
920 delegated_frame_evictor_
->UnlockFrame();
923 ////////////////////////////////////////////////////////////////////////////////
924 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
926 void DelegatedFrameHost::OnLayerRecreated(ui::Layer
* old_layer
,
927 ui::Layer
* new_layer
) {
928 // The new_layer is the one that will be used by our Window, so that's the one
929 // that should keep our frame. old_layer will be returned to the
930 // RecreateLayer caller, and should have a copy.
931 if (frame_provider_
.get()) {
932 new_layer
->SetShowDelegatedContent(frame_provider_
.get(),
933 current_frame_size_in_dip_
);
935 if (!surface_id_
.is_null()) {
936 new_layer
->SetShowSurface(surface_id_
, current_frame_size_in_dip_
);
940 } // namespace content