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 "base/time/default_tick_clock.h"
10 #include "cc/output/compositor_frame.h"
11 #include "cc/output/compositor_frame_ack.h"
12 #include "cc/output/copy_output_request.h"
13 #include "cc/resources/single_release_callback.h"
14 #include "cc/resources/texture_mailbox.h"
15 #include "cc/surfaces/surface.h"
16 #include "cc/surfaces/surface_factory.h"
17 #include "cc/surfaces/surface_hittest.h"
18 #include "cc/surfaces/surface_manager.h"
19 #include "content/browser/compositor/resize_lock.h"
20 #include "content/browser/compositor/surface_utils.h"
21 #include "content/browser/gpu/compositor_util.h"
22 #include "content/common/gpu/client/gl_helper.h"
23 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
24 #include "content/public/common/content_switches.h"
25 #include "media/base/video_frame.h"
26 #include "media/base/video_util.h"
27 #include "skia/ext/image_operations.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkPaint.h"
30 #include "third_party/skia/include/effects/SkLumaColorFilter.h"
31 #include "ui/gfx/geometry/dip_util.h"
37 void SatisfyCallback(cc::SurfaceManager
* manager
,
38 cc::SurfaceSequence sequence
) {
39 std::vector
<uint32_t> sequences
;
40 sequences
.push_back(sequence
.sequence
);
41 manager
->DidSatisfySequences(sequence
.id_namespace
, &sequences
);
44 void RequireCallback(cc::SurfaceManager
* manager
,
46 cc::SurfaceSequence sequence
) {
47 cc::Surface
* surface
= manager
->GetSurfaceForId(id
);
49 LOG(ERROR
) << "Attempting to require callback on nonexistent surface";
52 surface
->AddDestructionDependency(sequence
);
57 ////////////////////////////////////////////////////////////////////////////////
60 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient
* client
)
63 use_surfaces_(UseSurfacesEnabled()),
64 tick_clock_(new base::DefaultTickClock()),
65 last_output_surface_id_(0),
66 pending_delegated_ack_count_(0),
67 skipped_frames_(false),
68 current_scale_factor_(1.f
),
69 can_lock_compositor_(YES_CAN_LOCK
),
70 delegated_frame_evictor_(new DelegatedFrameEvictor(this)) {
71 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
72 factory
->AddObserver(this);
73 id_allocator_
= factory
->GetContextFactory()->CreateSurfaceIdAllocator();
76 void DelegatedFrameHost::WasShown(const ui::LatencyInfo
& latency_info
) {
77 delegated_frame_evictor_
->SetVisible(true);
79 if (surface_id_
.is_null() && !frame_provider_
.get() &&
80 !released_front_lock_
.get()) {
82 released_front_lock_
= compositor_
->GetCompositorLock();
86 compositor_
->SetLatencyInfo(latency_info
);
90 bool DelegatedFrameHost::HasSavedFrame() {
91 return delegated_frame_evictor_
->HasFrame();
94 void DelegatedFrameHost::WasHidden() {
95 delegated_frame_evictor_
->SetVisible(false);
96 released_front_lock_
= NULL
;
99 void DelegatedFrameHost::MaybeCreateResizeLock() {
100 if (!ShouldCreateResizeLock())
104 bool defer_compositor_lock
=
105 can_lock_compositor_
== NO_PENDING_RENDERER_FRAME
||
106 can_lock_compositor_
== NO_PENDING_COMMIT
;
108 if (can_lock_compositor_
== YES_CAN_LOCK
)
109 can_lock_compositor_
= YES_DID_LOCK
;
112 client_
->DelegatedFrameHostCreateResizeLock(defer_compositor_lock
);
115 bool DelegatedFrameHost::ShouldCreateResizeLock() {
116 if (!client_
->DelegatedFrameCanCreateResizeLock())
122 gfx::Size desired_size
= client_
->DelegatedFrameHostDesiredSizeInDIP();
123 if (desired_size
== current_frame_size_in_dip_
|| desired_size
.IsEmpty())
132 void DelegatedFrameHost::CopyFromCompositingSurface(
133 const gfx::Rect
& src_subrect
,
134 const gfx::Size
& output_size
,
135 ReadbackRequestCallback
& callback
,
136 const SkColorType preferred_color_type
) {
137 // Only ARGB888 and RGB565 supported as of now.
138 bool format_support
= ((preferred_color_type
== kAlpha_8_SkColorType
) ||
139 (preferred_color_type
== kRGB_565_SkColorType
) ||
140 (preferred_color_type
== kN32_SkColorType
));
141 DCHECK(format_support
);
142 if (!CanCopyToBitmap()) {
143 callback
.Run(SkBitmap(), content::READBACK_SURFACE_UNAVAILABLE
);
147 scoped_ptr
<cc::CopyOutputRequest
> request
=
148 cc::CopyOutputRequest::CreateRequest(
149 base::Bind(&DelegatedFrameHost::CopyFromCompositingSurfaceHasResult
,
150 output_size
, preferred_color_type
, callback
));
151 if (!src_subrect
.IsEmpty())
152 request
->set_area(src_subrect
);
153 RequestCopyOfOutput(request
.Pass());
156 void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
157 const gfx::Rect
& src_subrect
,
158 const scoped_refptr
<media::VideoFrame
>& target
,
159 const base::Callback
<void(bool)>& callback
) {
160 if (!CanCopyToVideoFrame()) {
165 scoped_ptr
<cc::CopyOutputRequest
> request
=
166 cc::CopyOutputRequest::CreateRequest(base::Bind(
167 &DelegatedFrameHost::
168 CopyFromCompositingSurfaceHasResultForVideo
,
169 AsWeakPtr(), // For caching the ReadbackYUVInterface on this class.
173 request
->set_area(src_subrect
);
174 RequestCopyOfOutput(request
.Pass());
177 bool DelegatedFrameHost::CanCopyToBitmap() const {
178 return compositor_
&&
179 client_
->DelegatedFrameHostGetLayer()->has_external_content();
182 bool DelegatedFrameHost::CanCopyToVideoFrame() const {
183 return compositor_
&&
184 client_
->DelegatedFrameHostGetLayer()->has_external_content();
187 bool DelegatedFrameHost::CanSubscribeFrame() const {
191 void DelegatedFrameHost::BeginFrameSubscription(
192 scoped_ptr
<RenderWidgetHostViewFrameSubscriber
> subscriber
) {
193 frame_subscriber_
= subscriber
.Pass();
196 void DelegatedFrameHost::EndFrameSubscription() {
197 idle_frame_subscriber_textures_
.clear();
198 frame_subscriber_
.reset();
201 uint32_t DelegatedFrameHost::GetSurfaceIdNamespace() {
205 return id_allocator_
->id_namespace();
208 cc::SurfaceId
DelegatedFrameHost::SurfaceIdAtPoint(
209 const gfx::Point
& point
,
210 gfx::Point
* transformed_point
) {
211 if (surface_id_
.is_null())
213 cc::SurfaceHittest
hittest(GetSurfaceManager());
214 return hittest
.GetTargetSurfaceAtPoint(surface_id_
, point
, transformed_point
);
217 bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip
) const {
218 // Should skip a frame only when another frame from the renderer is guaranteed
219 // to replace it. Otherwise may cause hangs when the renderer is waiting for
220 // the completion of latency infos (such as when taking a Snapshot.)
221 if (can_lock_compositor_
== NO_PENDING_RENDERER_FRAME
||
222 can_lock_compositor_
== NO_PENDING_COMMIT
||
226 return size_in_dip
!= resize_lock_
->expected_size();
229 void DelegatedFrameHost::WasResized() {
230 if (client_
->DelegatedFrameHostDesiredSizeInDIP() !=
231 current_frame_size_in_dip_
&&
232 !client_
->DelegatedFrameHostIsVisible())
233 EvictDelegatedFrame();
234 MaybeCreateResizeLock();
237 gfx::Size
DelegatedFrameHost::GetRequestedRendererSize() const {
239 return resize_lock_
->expected_size();
241 return client_
->DelegatedFrameHostDesiredSizeInDIP();
244 void DelegatedFrameHost::CheckResizeLock() {
246 resize_lock_
->expected_size() != current_frame_size_in_dip_
)
249 // Since we got the size we were looking for, unlock the compositor. But delay
250 // the release of the lock until we've kicked a frame with the new texture, to
251 // avoid resizing the UI before we have a chance to draw a "good" frame.
252 resize_lock_
->UnlockCompositor();
255 void DelegatedFrameHost::DidReceiveFrameFromRenderer(
256 const gfx::Rect
& damage_rect
) {
257 if (!frame_subscriber() || !CanCopyToVideoFrame())
260 const base::TimeTicks now
= tick_clock_
->NowTicks();
261 base::TimeTicks present_time
;
262 if (vsync_interval_
<= base::TimeDelta()) {
265 const int64 intervals_elapsed
= (now
- vsync_timebase_
) / vsync_interval_
;
266 present_time
= vsync_timebase_
+ (intervals_elapsed
+ 1) * vsync_interval_
;
269 scoped_refptr
<media::VideoFrame
> frame
;
270 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback
;
271 if (!frame_subscriber()->ShouldCaptureFrame(damage_rect
, present_time
,
275 // Get a texture to re-use; else, create a new one.
276 scoped_refptr
<OwnedMailbox
> subscriber_texture
;
277 if (!idle_frame_subscriber_textures_
.empty()) {
278 subscriber_texture
= idle_frame_subscriber_textures_
.back();
279 idle_frame_subscriber_textures_
.pop_back();
280 } else if (GLHelper
* helper
=
281 ImageTransportFactory::GetInstance()->GetGLHelper()) {
282 subscriber_texture
= new OwnedMailbox(helper
);
285 scoped_ptr
<cc::CopyOutputRequest
> request
=
286 cc::CopyOutputRequest::CreateRequest(base::Bind(
287 &DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo
,
291 base::Bind(callback
, present_time
)));
292 // Setting the source in this copy request asks that the layer abort any prior
293 // uncommitted copy requests made on behalf of the same frame subscriber.
294 // This will not affect any of the copy requests spawned elsewhere from
295 // DelegatedFrameHost (e.g., a call to CopyFromCompositingSurface() for
296 // screenshots) since those copy requests do not specify |frame_subscriber()|
298 request
->set_source(frame_subscriber());
299 request
->set_area(gfx::Rect(current_frame_size_in_dip_
));
300 if (subscriber_texture
.get()) {
301 request
->SetTextureMailbox(
302 cc::TextureMailbox(subscriber_texture
->mailbox(),
303 subscriber_texture
->target(),
304 subscriber_texture
->sync_point()));
306 RequestCopyOfOutput(request
.Pass());
309 void DelegatedFrameHost::SwapDelegatedFrame(
310 uint32 output_surface_id
,
311 scoped_ptr
<cc::DelegatedFrameData
> frame_data
,
312 float frame_device_scale_factor
,
313 const std::vector
<ui::LatencyInfo
>& latency_info
,
314 std::vector
<uint32_t>* satisfies_sequences
) {
315 DCHECK(!frame_data
->render_pass_list
.empty());
317 cc::RenderPass
* root_pass
= frame_data
->render_pass_list
.back();
319 gfx::Size frame_size
= root_pass
->output_rect
.size();
320 gfx::Size frame_size_in_dip
=
321 gfx::ConvertSizeToDIP(frame_device_scale_factor
, frame_size
);
323 gfx::Rect damage_rect
= root_pass
->damage_rect
;
324 damage_rect
.Intersect(gfx::Rect(frame_size
));
325 gfx::Rect damage_rect_in_dip
=
326 gfx::ConvertRectToDIP(frame_device_scale_factor
, damage_rect
);
328 if (ShouldSkipFrame(frame_size_in_dip
)) {
329 cc::CompositorFrameAck ack
;
330 cc::TransferableResource::ReturnResources(frame_data
->resource_list
,
333 skipped_latency_info_list_
.insert(skipped_latency_info_list_
.end(),
334 latency_info
.begin(), latency_info
.end());
336 client_
->DelegatedFrameHostSendCompositorSwapAck(output_surface_id
, ack
);
337 skipped_frames_
= true;
341 if (skipped_frames_
) {
342 skipped_frames_
= false;
343 damage_rect
= gfx::Rect(frame_size
);
344 damage_rect_in_dip
= gfx::Rect(frame_size_in_dip
);
346 // Give the same damage rect to the compositor.
347 cc::RenderPass
* root_pass
= frame_data
->render_pass_list
.back();
348 root_pass
->damage_rect
= damage_rect
;
351 if (output_surface_id
!= last_output_surface_id_
) {
352 // Resource ids are scoped by the output surface.
353 // If the originating output surface doesn't match the last one, it
354 // indicates the renderer's output surface may have been recreated, in which
355 // case we should recreate the DelegatedRendererLayer, to avoid matching
356 // resources from the old one with resources from the new one which would
357 // have the same id. Changing the layer to showing painted content destroys
358 // the DelegatedRendererLayer.
359 EvictDelegatedFrame();
361 surface_factory_
.reset();
362 if (!surface_returned_resources_
.empty())
363 SendReturnedDelegatedResources(last_output_surface_id_
);
365 // Drop the cc::DelegatedFrameResourceCollection so that we will not return
366 // any resources from the old output surface with the new output surface id.
367 if (resource_collection_
.get()) {
368 resource_collection_
->SetClient(NULL
);
370 if (resource_collection_
->LoseAllResources())
371 SendReturnedDelegatedResources(last_output_surface_id_
);
373 resource_collection_
= NULL
;
375 last_output_surface_id_
= output_surface_id
;
377 bool immediate_ack
= !compositor_
;
378 pending_delegated_ack_count_
++;
380 if (frame_size
.IsEmpty()) {
381 DCHECK(frame_data
->resource_list
.empty());
382 EvictDelegatedFrame();
385 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
386 cc::SurfaceManager
* manager
= factory
->GetSurfaceManager();
387 if (!surface_factory_
) {
389 make_scoped_ptr(new cc::SurfaceFactory(manager
, this));
391 if (surface_id_
.is_null() || frame_size
!= current_surface_size_
||
392 frame_size_in_dip
!= current_frame_size_in_dip_
) {
393 if (!surface_id_
.is_null())
394 surface_factory_
->Destroy(surface_id_
);
395 surface_id_
= id_allocator_
->GenerateId();
396 surface_factory_
->Create(surface_id_
);
397 // manager must outlive compositors using it.
398 client_
->DelegatedFrameHostGetLayer()->SetShowSurface(
400 base::Bind(&SatisfyCallback
, base::Unretained(manager
)),
401 base::Bind(&RequireCallback
, base::Unretained(manager
)), frame_size
,
402 frame_device_scale_factor
, frame_size_in_dip
);
403 current_surface_size_
= frame_size
;
404 current_scale_factor_
= frame_device_scale_factor
;
406 scoped_ptr
<cc::CompositorFrame
> compositor_frame
=
407 make_scoped_ptr(new cc::CompositorFrame());
408 compositor_frame
->delegated_frame_data
= frame_data
.Pass();
410 compositor_frame
->metadata
.latency_info
.swap(skipped_latency_info_list_
);
411 compositor_frame
->metadata
.latency_info
.insert(
412 compositor_frame
->metadata
.latency_info
.end(),
413 latency_info
.begin(),
415 compositor_frame
->metadata
.satisfies_sequences
.swap(*satisfies_sequences
);
417 gfx::Size desired_size
= client_
->DelegatedFrameHostDesiredSizeInDIP();
418 if (desired_size
!= frame_size_in_dip
&& !desired_size
.IsEmpty())
419 immediate_ack
= true;
421 cc::SurfaceFactory::DrawCallback ack_callback
;
422 if (compositor_
&& !immediate_ack
) {
423 ack_callback
= base::Bind(&DelegatedFrameHost::SurfaceDrawn
,
424 AsWeakPtr(), output_surface_id
);
426 surface_factory_
->SubmitCompositorFrame(
427 surface_id_
, compositor_frame
.Pass(), ack_callback
);
429 if (!resource_collection_
.get()) {
430 resource_collection_
= new cc::DelegatedFrameResourceCollection
;
431 resource_collection_
->SetClient(this);
433 // If the physical frame size changes, we need a new |frame_provider_|. If
434 // the physical frame size is the same, but the size in DIP changed, we
435 // need to adjust the scale at which the frames will be drawn, and we do
436 // this by making a new |frame_provider_| also to ensure the scale change
437 // is presented in sync with the new frame content.
438 if (!frame_provider_
.get() ||
439 frame_size
!= frame_provider_
->frame_size() ||
440 frame_size_in_dip
!= current_frame_size_in_dip_
) {
441 frame_provider_
= new cc::DelegatedFrameProvider(
442 resource_collection_
.get(), frame_data
.Pass());
443 client_
->DelegatedFrameHostGetLayer()->SetShowDelegatedContent(
444 frame_provider_
.get(), frame_size_in_dip
);
446 frame_provider_
->SetFrameData(frame_data
.Pass());
450 released_front_lock_
= NULL
;
451 current_frame_size_in_dip_
= frame_size_in_dip
;
454 if (!damage_rect_in_dip
.IsEmpty())
455 client_
->DelegatedFrameHostGetLayer()->OnDelegatedFrameDamage(
459 SendDelegatedFrameAck(output_surface_id
);
460 } else if (!use_surfaces_
) {
461 std::vector
<ui::LatencyInfo
>::const_iterator it
;
462 for (it
= latency_info
.begin(); it
!= latency_info
.end(); ++it
)
463 compositor_
->SetLatencyInfo(*it
);
464 // If we've previously skipped any latency infos add them.
465 for (it
= skipped_latency_info_list_
.begin();
466 it
!= skipped_latency_info_list_
.end();
468 compositor_
->SetLatencyInfo(*it
);
469 skipped_latency_info_list_
.clear();
470 AddOnCommitCallbackAndDisableLocks(
471 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck
,
472 AsWeakPtr(), output_surface_id
));
474 AddOnCommitCallbackAndDisableLocks(base::Closure());
476 DidReceiveFrameFromRenderer(damage_rect
);
477 if (frame_provider_
.get() || !surface_id_
.is_null())
478 delegated_frame_evictor_
->SwappedFrame(
479 client_
->DelegatedFrameHostIsVisible());
480 // Note: the frame may have been evicted immediately.
483 void DelegatedFrameHost::ClearDelegatedFrame() {
484 if (frame_provider_
.get() || !surface_id_
.is_null())
485 EvictDelegatedFrame();
488 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id
) {
489 cc::CompositorFrameAck ack
;
490 if (!surface_returned_resources_
.empty())
491 ack
.resources
.swap(surface_returned_resources_
);
492 if (resource_collection_
.get())
493 resource_collection_
->TakeUnusedResourcesForChildCompositor(&ack
.resources
);
494 client_
->DelegatedFrameHostSendCompositorSwapAck(output_surface_id
, ack
);
495 DCHECK_GT(pending_delegated_ack_count_
, 0);
496 pending_delegated_ack_count_
--;
499 void DelegatedFrameHost::SurfaceDrawn(uint32 output_surface_id
,
500 cc::SurfaceDrawStatus drawn
) {
501 SendDelegatedFrameAck(output_surface_id
);
504 void DelegatedFrameHost::UnusedResourcesAreAvailable() {
505 if (pending_delegated_ack_count_
)
508 SendReturnedDelegatedResources(last_output_surface_id_
);
511 void DelegatedFrameHost::SendReturnedDelegatedResources(
512 uint32 output_surface_id
) {
513 cc::CompositorFrameAck ack
;
514 if (!surface_returned_resources_
.empty()) {
515 ack
.resources
.swap(surface_returned_resources_
);
517 DCHECK(resource_collection_
.get());
518 resource_collection_
->TakeUnusedResourcesForChildCompositor(&ack
.resources
);
520 DCHECK(!ack
.resources
.empty());
522 client_
->DelegatedFrameHostSendReclaimCompositorResources(output_surface_id
,
526 void DelegatedFrameHost::ReturnResources(
527 const cc::ReturnedResourceArray
& resources
) {
528 if (resources
.empty())
530 std::copy(resources
.begin(),
532 std::back_inserter(surface_returned_resources_
));
533 if (!pending_delegated_ack_count_
)
534 SendReturnedDelegatedResources(last_output_surface_id_
);
537 void DelegatedFrameHost::EvictDelegatedFrame() {
538 client_
->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
539 frame_provider_
= NULL
;
540 if (!surface_id_
.is_null()) {
541 surface_factory_
->Destroy(surface_id_
);
542 surface_id_
= cc::SurfaceId();
544 delegated_frame_evictor_
->DiscardedFrame();
548 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
549 const gfx::Size
& dst_size_in_pixel
,
550 const SkColorType color_type
,
551 ReadbackRequestCallback
& callback
,
552 scoped_ptr
<cc::CopyOutputResult
> result
) {
553 if (result
->IsEmpty() || result
->size().IsEmpty()) {
554 callback
.Run(SkBitmap(), content::READBACK_FAILED
);
558 gfx::Size output_size_in_pixel
;
559 if (dst_size_in_pixel
.IsEmpty())
560 output_size_in_pixel
= result
->size();
562 output_size_in_pixel
= dst_size_in_pixel
;
564 if (result
->HasTexture()) {
565 // GPU-accelerated path
566 PrepareTextureCopyOutputResult(output_size_in_pixel
, color_type
,
572 DCHECK(result
->HasBitmap());
574 PrepareBitmapCopyOutputResult(output_size_in_pixel
, color_type
, callback
,
578 static void CopyFromCompositingSurfaceFinished(
579 ReadbackRequestCallback
& callback
,
580 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
,
581 scoped_ptr
<SkBitmap
> bitmap
,
582 scoped_ptr
<SkAutoLockPixels
> bitmap_pixels_lock
,
584 bitmap_pixels_lock
.reset();
586 uint32 sync_point
= 0;
588 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
590 sync_point
= gl_helper
->InsertSyncPoint();
592 bool lost_resource
= sync_point
== 0;
593 release_callback
->Run(sync_point
, lost_resource
);
595 callback
.Run(*bitmap
,
596 result
? content::READBACK_SUCCESS
: content::READBACK_FAILED
);
600 void DelegatedFrameHost::PrepareTextureCopyOutputResult(
601 const gfx::Size
& dst_size_in_pixel
,
602 const SkColorType color_type
,
603 ReadbackRequestCallback
& callback
,
604 scoped_ptr
<cc::CopyOutputResult
> result
) {
605 DCHECK(result
->HasTexture());
606 base::ScopedClosureRunner
scoped_callback_runner(
607 base::Bind(callback
, SkBitmap(), content::READBACK_FAILED
));
609 // TODO(siva.gunturi): We should be able to validate the format here using
610 // GLHelper::IsReadbackConfigSupported before we processs the result.
611 // See crbug.com/415682 and crbug.com/415131.
612 scoped_ptr
<SkBitmap
> bitmap(new SkBitmap
);
613 if (!bitmap
->tryAllocPixels(SkImageInfo::Make(
614 dst_size_in_pixel
.width(), dst_size_in_pixel
.height(), color_type
,
615 kOpaque_SkAlphaType
))) {
616 scoped_callback_runner
.Reset(base::Bind(
617 callback
, SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE
));
621 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
622 GLHelper
* gl_helper
= factory
->GetGLHelper();
626 scoped_ptr
<SkAutoLockPixels
> bitmap_pixels_lock(
627 new SkAutoLockPixels(*bitmap
));
628 uint8
* pixels
= static_cast<uint8
*>(bitmap
->getPixels());
630 cc::TextureMailbox texture_mailbox
;
631 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
;
632 result
->TakeTexture(&texture_mailbox
, &release_callback
);
633 DCHECK(texture_mailbox
.IsTexture());
635 ignore_result(scoped_callback_runner
.Release());
637 gl_helper
->CropScaleReadbackAndCleanMailbox(
638 texture_mailbox
.mailbox(),
639 texture_mailbox
.sync_point(),
641 gfx::Rect(result
->size()),
645 base::Bind(&CopyFromCompositingSurfaceFinished
,
647 base::Passed(&release_callback
),
648 base::Passed(&bitmap
),
649 base::Passed(&bitmap_pixels_lock
)),
650 GLHelper::SCALER_QUALITY_GOOD
);
654 void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
655 const gfx::Size
& dst_size_in_pixel
,
656 const SkColorType preferred_color_type
,
657 ReadbackRequestCallback
& callback
,
658 scoped_ptr
<cc::CopyOutputResult
> result
) {
659 SkColorType color_type
= preferred_color_type
;
660 if (color_type
!= kN32_SkColorType
&& color_type
!= kAlpha_8_SkColorType
) {
661 // Switch back to default colortype if format not supported.
662 color_type
= kN32_SkColorType
;
664 DCHECK(result
->HasBitmap());
665 scoped_ptr
<SkBitmap
> source
= result
->TakeBitmap();
667 SkBitmap scaled_bitmap
;
668 if (source
->width() != dst_size_in_pixel
.width() ||
669 source
->height() != dst_size_in_pixel
.height()) {
671 skia::ImageOperations::Resize(*source
,
672 skia::ImageOperations::RESIZE_BEST
,
673 dst_size_in_pixel
.width(),
674 dst_size_in_pixel
.height());
676 scaled_bitmap
= *source
;
678 if (color_type
== kN32_SkColorType
) {
679 DCHECK_EQ(scaled_bitmap
.colorType(), kN32_SkColorType
);
680 callback
.Run(scaled_bitmap
, READBACK_SUCCESS
);
683 DCHECK_EQ(color_type
, kAlpha_8_SkColorType
);
684 // The software path currently always returns N32 bitmap regardless of the
685 // |color_type| we ask for.
686 DCHECK_EQ(scaled_bitmap
.colorType(), kN32_SkColorType
);
687 // Paint |scaledBitmap| to alpha-only |grayscale_bitmap|.
688 SkBitmap grayscale_bitmap
;
689 bool success
= grayscale_bitmap
.tryAllocPixels(
690 SkImageInfo::MakeA8(scaled_bitmap
.width(), scaled_bitmap
.height()));
692 callback
.Run(SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE
);
695 SkCanvas
canvas(grayscale_bitmap
);
697 skia::RefPtr
<SkColorFilter
> filter
=
698 skia::AdoptRef(SkLumaColorFilter::Create());
699 paint
.setColorFilter(filter
.get());
700 canvas
.drawBitmap(scaled_bitmap
, SkIntToScalar(0), SkIntToScalar(0), &paint
);
701 callback
.Run(grayscale_bitmap
, READBACK_SUCCESS
);
705 void DelegatedFrameHost::ReturnSubscriberTexture(
706 base::WeakPtr
<DelegatedFrameHost
> dfh
,
707 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
709 if (!subscriber_texture
.get())
714 subscriber_texture
->UpdateSyncPoint(sync_point
);
716 if (dfh
->frame_subscriber_
&& subscriber_texture
->texture_id())
717 dfh
->idle_frame_subscriber_textures_
.push_back(subscriber_texture
);
721 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
722 base::WeakPtr
<DelegatedFrameHost
> dfh
,
723 const base::Callback
<void(bool)>& callback
,
724 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
725 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
,
727 callback
.Run(result
);
729 uint32 sync_point
= 0;
731 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
732 sync_point
= gl_helper
->InsertSyncPoint();
734 if (release_callback
) {
735 // A release callback means the texture came from the compositor, so there
736 // should be no |subscriber_texture|.
737 DCHECK(!subscriber_texture
.get());
738 bool lost_resource
= sync_point
== 0;
739 release_callback
->Run(sync_point
, lost_resource
);
741 ReturnSubscriberTexture(dfh
, subscriber_texture
, sync_point
);
745 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
746 base::WeakPtr
<DelegatedFrameHost
> dfh
,
747 scoped_refptr
<OwnedMailbox
> subscriber_texture
,
748 scoped_refptr
<media::VideoFrame
> video_frame
,
749 const base::Callback
<void(bool)>& callback
,
750 scoped_ptr
<cc::CopyOutputResult
> result
) {
751 base::ScopedClosureRunner
scoped_callback_runner(base::Bind(callback
, false));
752 base::ScopedClosureRunner
scoped_return_subscriber_texture(
753 base::Bind(&ReturnSubscriberTexture
, dfh
, subscriber_texture
, 0));
757 if (result
->IsEmpty())
759 if (result
->size().IsEmpty())
762 // Compute the dest size we want after the letterboxing resize. Make the
763 // coordinates and sizes even because we letterbox in YUV space
764 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
765 // line up correctly.
766 // The video frame's visible_rect() and the result's size() are both physical
768 gfx::Rect region_in_frame
= media::ComputeLetterboxRegion(
769 video_frame
->visible_rect(), result
->size());
770 region_in_frame
= gfx::Rect(region_in_frame
.x() & ~1,
771 region_in_frame
.y() & ~1,
772 region_in_frame
.width() & ~1,
773 region_in_frame
.height() & ~1);
774 if (region_in_frame
.IsEmpty())
777 if (!result
->HasTexture()) {
778 DCHECK(result
->HasBitmap());
779 scoped_ptr
<SkBitmap
> bitmap
= result
->TakeBitmap();
780 // Scale the bitmap to the required size, if necessary.
781 SkBitmap scaled_bitmap
;
782 if (result
->size() != region_in_frame
.size()) {
783 skia::ImageOperations::ResizeMethod method
=
784 skia::ImageOperations::RESIZE_GOOD
;
785 scaled_bitmap
= skia::ImageOperations::Resize(*bitmap
.get(), method
,
786 region_in_frame
.width(),
787 region_in_frame
.height());
789 scaled_bitmap
= *bitmap
.get();
793 SkAutoLockPixels
scaled_bitmap_locker(scaled_bitmap
);
795 media::CopyRGBToVideoFrame(
796 reinterpret_cast<uint8
*>(scaled_bitmap
.getPixels()),
797 scaled_bitmap
.rowBytes(),
801 ignore_result(scoped_callback_runner
.Release());
806 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
807 GLHelper
* gl_helper
= factory
->GetGLHelper();
810 if (subscriber_texture
.get() && !subscriber_texture
->texture_id())
813 cc::TextureMailbox texture_mailbox
;
814 scoped_ptr
<cc::SingleReleaseCallback
> release_callback
;
815 result
->TakeTexture(&texture_mailbox
, &release_callback
);
816 DCHECK(texture_mailbox
.IsTexture());
818 gfx::Rect
result_rect(result
->size());
820 content::ReadbackYUVInterface
* yuv_readback_pipeline
=
821 dfh
->yuv_readback_pipeline_
.get();
822 if (yuv_readback_pipeline
== NULL
||
823 yuv_readback_pipeline
->scaler()->SrcSize() != result_rect
.size() ||
824 yuv_readback_pipeline
->scaler()->SrcSubrect() != result_rect
||
825 yuv_readback_pipeline
->scaler()->DstSize() != region_in_frame
.size()) {
826 GLHelper::ScalerQuality quality
= GLHelper::SCALER_QUALITY_FAST
;
827 std::string quality_switch
= switches::kTabCaptureDownscaleQuality
;
828 // If we're scaling up, we can use the "best" quality.
829 if (result_rect
.size().width() < region_in_frame
.size().width() &&
830 result_rect
.size().height() < region_in_frame
.size().height())
831 quality_switch
= switches::kTabCaptureUpscaleQuality
;
833 std::string switch_value
=
834 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
836 if (switch_value
== "fast")
837 quality
= GLHelper::SCALER_QUALITY_FAST
;
838 else if (switch_value
== "good")
839 quality
= GLHelper::SCALER_QUALITY_GOOD
;
840 else if (switch_value
== "best")
841 quality
= GLHelper::SCALER_QUALITY_BEST
;
843 dfh
->yuv_readback_pipeline_
.reset(
844 gl_helper
->CreateReadbackPipelineYUV(quality
,
847 region_in_frame
.size(),
850 yuv_readback_pipeline
= dfh
->yuv_readback_pipeline_
.get();
853 ignore_result(scoped_callback_runner
.Release());
854 ignore_result(scoped_return_subscriber_texture
.Release());
855 base::Callback
<void(bool result
)> finished_callback
= base::Bind(
856 &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo
,
860 base::Passed(&release_callback
));
861 yuv_readback_pipeline
->ReadbackYUV(texture_mailbox
.mailbox(),
862 texture_mailbox
.sync_point(),
864 region_in_frame
.origin(),
868 ////////////////////////////////////////////////////////////////////////////////
869 // DelegatedFrameHost, ui::CompositorObserver implementation:
871 void DelegatedFrameHost::OnCompositingDidCommit(
872 ui::Compositor
* compositor
) {
873 if (can_lock_compositor_
== NO_PENDING_COMMIT
) {
874 can_lock_compositor_
= YES_CAN_LOCK
;
875 if (resize_lock_
.get() && resize_lock_
->GrabDeferredLock())
876 can_lock_compositor_
= YES_DID_LOCK
;
878 RunOnCommitCallbacks();
880 resize_lock_
->expected_size() == current_frame_size_in_dip_
) {
881 resize_lock_
.reset();
882 client_
->DelegatedFrameHostResizeLockWasReleased();
883 // We may have had a resize while we had the lock (e.g. if the lock expired,
884 // or if the UI still gave us some resizes), so make sure we grab a new lock
886 MaybeCreateResizeLock();
890 void DelegatedFrameHost::OnCompositingStarted(
891 ui::Compositor
* compositor
, base::TimeTicks start_time
) {
892 last_draw_ended_
= start_time
;
895 void DelegatedFrameHost::OnCompositingEnded(
896 ui::Compositor
* compositor
) {
899 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor
* compositor
) {
902 void DelegatedFrameHost::OnCompositingLockStateChanged(
903 ui::Compositor
* compositor
) {
904 // A compositor lock that is part of a resize lock timed out. We
905 // should display a renderer frame.
906 if (!compositor
->IsLocked() && can_lock_compositor_
== YES_DID_LOCK
) {
907 can_lock_compositor_
= NO_PENDING_RENDERER_FRAME
;
911 void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor
* compositor
) {
912 DCHECK_EQ(compositor
, compositor_
);
914 DCHECK(!compositor_
);
917 void DelegatedFrameHost::OnUpdateVSyncParameters(
918 base::TimeTicks timebase
,
919 base::TimeDelta interval
) {
920 SetVSyncParameters(timebase
, interval
);
921 if (client_
->DelegatedFrameHostIsVisible())
922 client_
->DelegatedFrameHostUpdateVSyncParameters(timebase
, interval
);
925 ////////////////////////////////////////////////////////////////////////////////
926 // DelegatedFrameHost, ImageTransportFactoryObserver implementation:
928 void DelegatedFrameHost::OnLostResources() {
929 if (frame_provider_
.get() || !surface_id_
.is_null())
930 EvictDelegatedFrame();
931 idle_frame_subscriber_textures_
.clear();
932 yuv_readback_pipeline_
.reset();
934 client_
->DelegatedFrameHostOnLostCompositorResources();
937 ////////////////////////////////////////////////////////////////////////////////
938 // DelegatedFrameHost, private:
940 DelegatedFrameHost::~DelegatedFrameHost() {
941 DCHECK(!compositor_
);
942 ImageTransportFactory::GetInstance()->RemoveObserver(this);
944 if (!surface_id_
.is_null())
945 surface_factory_
->Destroy(surface_id_
);
946 if (resource_collection_
.get())
947 resource_collection_
->SetClient(NULL
);
949 DCHECK(!vsync_manager_
.get());
952 void DelegatedFrameHost::RunOnCommitCallbacks() {
953 for (std::vector
<base::Closure
>::const_iterator
954 it
= on_compositing_did_commit_callbacks_
.begin();
955 it
!= on_compositing_did_commit_callbacks_
.end(); ++it
) {
958 on_compositing_did_commit_callbacks_
.clear();
961 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
962 const base::Closure
& callback
) {
965 can_lock_compositor_
= NO_PENDING_COMMIT
;
966 if (!callback
.is_null())
967 on_compositing_did_commit_callbacks_
.push_back(callback
);
970 void DelegatedFrameHost::SetCompositor(ui::Compositor
* compositor
) {
971 DCHECK(!compositor_
);
974 compositor_
= compositor
;
975 compositor_
->AddObserver(this);
976 DCHECK(!vsync_manager_
.get());
977 vsync_manager_
= compositor_
->vsync_manager();
978 vsync_manager_
->AddObserver(this);
981 void DelegatedFrameHost::ResetCompositor() {
984 RunOnCommitCallbacks();
986 resize_lock_
.reset();
987 client_
->DelegatedFrameHostResizeLockWasReleased();
989 if (compositor_
->HasObserver(this))
990 compositor_
->RemoveObserver(this);
991 if (vsync_manager_
.get()) {
992 vsync_manager_
->RemoveObserver(this);
993 vsync_manager_
= NULL
;
995 compositor_
= nullptr;
998 void DelegatedFrameHost::SetVSyncParameters(const base::TimeTicks
& timebase
,
999 const base::TimeDelta
& interval
) {
1000 vsync_timebase_
= timebase
;
1001 vsync_interval_
= interval
;
1004 void DelegatedFrameHost::LockResources() {
1005 DCHECK(frame_provider_
.get() || !surface_id_
.is_null());
1006 delegated_frame_evictor_
->LockFrame();
1009 void DelegatedFrameHost::RequestCopyOfOutput(
1010 scoped_ptr
<cc::CopyOutputRequest
> request
) {
1011 if (!request_copy_of_output_callback_for_testing_
.is_null())
1012 request_copy_of_output_callback_for_testing_
.Run(request
.Pass());
1014 client_
->DelegatedFrameHostGetLayer()->RequestCopyOfOutput(request
.Pass());
1017 void DelegatedFrameHost::UnlockResources() {
1018 DCHECK(frame_provider_
.get() || !surface_id_
.is_null());
1019 delegated_frame_evictor_
->UnlockFrame();
1022 ////////////////////////////////////////////////////////////////////////////////
1023 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
1025 void DelegatedFrameHost::OnLayerRecreated(ui::Layer
* old_layer
,
1026 ui::Layer
* new_layer
) {
1027 // The new_layer is the one that will be used by our Window, so that's the one
1028 // that should keep our frame. old_layer will be returned to the
1029 // RecreateLayer caller, and should have a copy.
1030 if (frame_provider_
.get()) {
1031 new_layer
->SetShowDelegatedContent(frame_provider_
.get(),
1032 current_frame_size_in_dip_
);
1034 if (!surface_id_
.is_null()) {
1035 ImageTransportFactory
* factory
= ImageTransportFactory::GetInstance();
1036 cc::SurfaceManager
* manager
= factory
->GetSurfaceManager();
1037 new_layer
->SetShowSurface(
1038 surface_id_
, base::Bind(&SatisfyCallback
, base::Unretained(manager
)),
1039 base::Bind(&RequireCallback
, base::Unretained(manager
)),
1040 current_surface_size_
, current_scale_factor_
,
1041 current_frame_size_in_dip_
);
1045 } // namespace content