Rename Animate as Begin(Main)Frame
[chromium-blink-merge.git] / content / browser / compositor / delegated_frame_host.cc
blob7a56f02e20ee6f6558dfe340f566d5b650fdffe8
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"
24 namespace content {
26 ////////////////////////////////////////////////////////////////////////////////
27 // DelegatedFrameHostClient
29 bool DelegatedFrameHostClient::ShouldCreateResizeLock() {
30 // On Windows and Linux, holding pointer moves will not help throttling
31 // resizes.
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)
37 return false;
38 #else
39 return GetDelegatedFrameHost()->ShouldCreateResizeLock();
40 #endif
43 void DelegatedFrameHostClient::RequestCopyOfOutput(
44 scoped_ptr<cc::CopyOutputRequest> request) {
45 GetDelegatedFrameHost()->RequestCopyOfOutput(request.Pass());
48 ////////////////////////////////////////////////////////////////////////////////
49 // DelegatedFrameHost
51 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
52 : client_(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_ &&
67 !released_front_lock_.get()) {
68 ui::Compositor* compositor = client_->GetCompositor();
69 if (compositor)
70 released_front_lock_ = compositor->GetCompositorLock();
73 ui::Compositor* compositor = client_->GetCompositor();
74 if (compositor) {
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())
90 return;
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();
111 if (resize_lock_)
112 return false;
114 if (host->should_auto_resize())
115 return false;
117 gfx::Size desired_size = client_->DesiredFrameSize();
118 if (desired_size == current_frame_size_in_dip_ || desired_size.IsEmpty())
119 return false;
121 ui::Compositor* compositor = client_->GetCompositor();
122 if (!compositor)
123 return false;
125 return true;
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());
144 return;
147 scoped_ptr<cc::CopyOutputRequest> request =
148 cc::CopyOutputRequest::CreateRequest(base::Bind(
149 &DelegatedFrameHost::CopyFromCompositingSurfaceHasResult,
150 output_size,
151 color_type,
152 callback));
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()) {
162 callback.Run(false);
163 return;
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.
183 subscriber_texture,
184 target,
185 callback));
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 {
207 return true;
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 ||
226 !resize_lock_.get())
227 return false;
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 {
240 if (resize_lock_)
241 return resize_lock_->expected_size();
242 else
243 return client_->DesiredFrameSize();
246 void DelegatedFrameHost::CheckResizeLock() {
247 if (!resize_lock_ ||
248 resize_lock_->expected_size() != current_frame_size_in_dip_)
249 return;
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();
256 if (compositor) {
257 if (!compositor->HasObserver(this))
258 compositor->AddObserver(this);
262 void DelegatedFrameHost::DidReceiveFrameFromRenderer(
263 const gfx::Rect& damage_rect) {
264 if (!frame_subscriber() || !CanCopyToVideoFrame())
265 return;
267 const base::TimeTicks now = gfx::FrameTime::Now();
268 base::TimeTicks present_time;
269 if (vsync_timebase_.is_null() || vsync_interval_ <= base::TimeDelta()) {
270 present_time = now;
271 } else {
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_),
282 frame,
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,
309 &ack.resources);
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;
318 return;
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;
358 } else {
359 if (use_surfaces_) {
360 if (!surface_factory_) {
361 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
362 cc::SurfaceManager* manager = factory->GetSurfaceManager();
363 id_allocator_ = factory->CreateSurfaceIdAllocator();
364 surface_factory_ =
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(surface_id_, compositor_frame.Pass());
383 } else {
384 if (!resource_collection_) {
385 resource_collection_ = new cc::DelegatedFrameResourceCollection;
386 resource_collection_->SetClient(this);
388 // If the physical frame size changes, we need a new |frame_provider_|. If
389 // the physical frame size is the same, but the size in DIP changed, we
390 // need to adjust the scale at which the frames will be drawn, and we do
391 // this by making a new |frame_provider_| also to ensure the scale change
392 // is presented in sync with the new frame content.
393 if (!frame_provider_.get() ||
394 frame_size != frame_provider_->frame_size() ||
395 frame_size_in_dip != current_frame_size_in_dip_) {
396 frame_provider_ = new cc::DelegatedFrameProvider(
397 resource_collection_.get(), frame_data.Pass());
398 client_->GetLayer()->SetShowDelegatedContent(frame_provider_.get(),
399 frame_size_in_dip);
400 } else {
401 frame_provider_->SetFrameData(frame_data.Pass());
403 modified_layers = true;
406 released_front_lock_ = NULL;
407 current_frame_size_in_dip_ = frame_size_in_dip;
408 CheckResizeLock();
410 if (modified_layers) {
411 // TODO(jbauman): Need to always tell the window observer about the
412 // damage.
413 client_->SchedulePaintInRect(damage_rect_in_dip);
416 pending_delegated_ack_count_++;
418 ui::Compositor* compositor = client_->GetCompositor();
419 if (!compositor || !modified_layers) {
420 SendDelegatedFrameAck(output_surface_id);
421 } else {
422 std::vector<ui::LatencyInfo>::const_iterator it;
423 for (it = latency_info.begin(); it != latency_info.end(); ++it)
424 compositor->SetLatencyInfo(*it);
425 // If we've previously skipped any latency infos add them.
426 for (it = skipped_latency_info_list_.begin();
427 it != skipped_latency_info_list_.end();
428 ++it)
429 compositor->SetLatencyInfo(*it);
430 skipped_latency_info_list_.clear();
431 AddOnCommitCallbackAndDisableLocks(
432 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
433 AsWeakPtr(),
434 output_surface_id));
436 DidReceiveFrameFromRenderer(damage_rect);
437 if (frame_provider_.get() || !surface_id_.is_null())
438 delegated_frame_evictor_->SwappedFrame(!host->is_hidden());
439 // Note: the frame may have been evicted immediately.
442 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) {
443 RenderWidgetHostImpl* host = client_->GetHost();
444 cc::CompositorFrameAck ack;
445 if (!surface_returned_resources_.empty())
446 ack.resources.swap(surface_returned_resources_);
447 if (resource_collection_)
448 resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
449 RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(),
450 output_surface_id,
451 host->GetProcess()->GetID(),
452 ack);
453 DCHECK_GT(pending_delegated_ack_count_, 0);
454 pending_delegated_ack_count_--;
457 void DelegatedFrameHost::UnusedResourcesAreAvailable() {
458 if (pending_delegated_ack_count_)
459 return;
461 SendReturnedDelegatedResources(last_output_surface_id_);
464 void DelegatedFrameHost::SendReturnedDelegatedResources(
465 uint32 output_surface_id) {
466 RenderWidgetHostImpl* host = client_->GetHost();
468 cc::CompositorFrameAck ack;
469 if (!surface_returned_resources_.empty()) {
470 ack.resources.swap(surface_returned_resources_);
471 } else {
472 DCHECK(resource_collection_);
473 resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
475 DCHECK(!ack.resources.empty());
477 RenderWidgetHostImpl::SendReclaimCompositorResources(
478 host->GetRoutingID(),
479 output_surface_id,
480 host->GetProcess()->GetID(),
481 ack);
484 void DelegatedFrameHost::ReturnResources(
485 const cc::ReturnedResourceArray& resources) {
486 if (resources.empty())
487 return;
488 std::copy(resources.begin(),
489 resources.end(),
490 std::back_inserter(surface_returned_resources_));
491 if (!pending_delegated_ack_count_)
492 SendReturnedDelegatedResources(last_output_surface_id_);
495 void DelegatedFrameHost::EvictDelegatedFrame() {
496 client_->GetLayer()->SetShowPaintedContent();
497 frame_provider_ = NULL;
498 if (!surface_id_.is_null()) {
499 surface_factory_->Destroy(surface_id_);
500 surface_id_ = cc::SurfaceId();
502 delegated_frame_evictor_->DiscardedFrame();
505 // static
506 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
507 const gfx::Size& dst_size_in_pixel,
508 const SkColorType color_type,
509 const base::Callback<void(bool, const SkBitmap&)>& callback,
510 scoped_ptr<cc::CopyOutputResult> result) {
511 if (result->IsEmpty() || result->size().IsEmpty()) {
512 callback.Run(false, SkBitmap());
513 return;
516 if (result->HasTexture()) {
517 PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type,
518 callback,
519 result.Pass());
520 return;
523 DCHECK(result->HasBitmap());
524 PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback,
525 result.Pass());
528 static void CopyFromCompositingSurfaceFinished(
529 const base::Callback<void(bool, const SkBitmap&)>& callback,
530 scoped_ptr<cc::SingleReleaseCallback> release_callback,
531 scoped_ptr<SkBitmap> bitmap,
532 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
533 bool result) {
534 bitmap_pixels_lock.reset();
536 uint32 sync_point = 0;
537 if (result) {
538 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
539 sync_point = gl_helper->InsertSyncPoint();
541 bool lost_resource = sync_point == 0;
542 release_callback->Run(sync_point, lost_resource);
544 callback.Run(result, *bitmap);
547 // static
548 void DelegatedFrameHost::PrepareTextureCopyOutputResult(
549 const gfx::Size& dst_size_in_pixel,
550 const SkColorType color_type,
551 const base::Callback<void(bool, const SkBitmap&)>& callback,
552 scoped_ptr<cc::CopyOutputResult> result) {
553 DCHECK(result->HasTexture());
554 base::ScopedClosureRunner scoped_callback_runner(
555 base::Bind(callback, false, SkBitmap()));
557 scoped_ptr<SkBitmap> bitmap(new SkBitmap);
558 if (!bitmap->allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
559 dst_size_in_pixel.height(),
560 color_type,
561 kOpaque_SkAlphaType)))
562 return;
564 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
565 GLHelper* gl_helper = factory->GetGLHelper();
566 if (!gl_helper)
567 return;
569 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
570 new SkAutoLockPixels(*bitmap));
571 uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
573 cc::TextureMailbox texture_mailbox;
574 scoped_ptr<cc::SingleReleaseCallback> release_callback;
575 result->TakeTexture(&texture_mailbox, &release_callback);
576 DCHECK(texture_mailbox.IsTexture());
578 ignore_result(scoped_callback_runner.Release());
580 gl_helper->CropScaleReadbackAndCleanMailbox(
581 texture_mailbox.mailbox(),
582 texture_mailbox.sync_point(),
583 result->size(),
584 gfx::Rect(result->size()),
585 dst_size_in_pixel,
586 pixels,
587 color_type,
588 base::Bind(&CopyFromCompositingSurfaceFinished,
589 callback,
590 base::Passed(&release_callback),
591 base::Passed(&bitmap),
592 base::Passed(&bitmap_pixels_lock)),
593 GLHelper::SCALER_QUALITY_FAST);
596 // static
597 void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
598 const gfx::Size& dst_size_in_pixel,
599 const SkColorType color_type,
600 const base::Callback<void(bool, const SkBitmap&)>& callback,
601 scoped_ptr<cc::CopyOutputResult> result) {
602 if (color_type != kN32_SkColorType) {
603 NOTIMPLEMENTED();
604 callback.Run(false, SkBitmap());
605 return;
607 DCHECK(result->HasBitmap());
608 scoped_ptr<SkBitmap> source = result->TakeBitmap();
609 DCHECK(source);
610 SkBitmap bitmap = skia::ImageOperations::Resize(
611 *source,
612 skia::ImageOperations::RESIZE_BEST,
613 dst_size_in_pixel.width(),
614 dst_size_in_pixel.height());
615 callback.Run(true, bitmap);
618 // static
619 void DelegatedFrameHost::ReturnSubscriberTexture(
620 base::WeakPtr<DelegatedFrameHost> dfh,
621 scoped_refptr<OwnedMailbox> subscriber_texture,
622 uint32 sync_point) {
623 if (!subscriber_texture.get())
624 return;
625 if (!dfh)
626 return;
628 subscriber_texture->UpdateSyncPoint(sync_point);
630 if (dfh->frame_subscriber_ && subscriber_texture->texture_id())
631 dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
634 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
635 base::WeakPtr<DelegatedFrameHost> dfh,
636 const base::Callback<void(bool)>& callback,
637 scoped_refptr<OwnedMailbox> subscriber_texture,
638 scoped_ptr<cc::SingleReleaseCallback> release_callback,
639 bool result) {
640 callback.Run(result);
642 uint32 sync_point = 0;
643 if (result) {
644 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
645 sync_point = gl_helper->InsertSyncPoint();
647 if (release_callback) {
648 // A release callback means the texture came from the compositor, so there
649 // should be no |subscriber_texture|.
650 DCHECK(!subscriber_texture);
651 bool lost_resource = sync_point == 0;
652 release_callback->Run(sync_point, lost_resource);
654 ReturnSubscriberTexture(dfh, subscriber_texture, sync_point);
657 // static
658 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
659 base::WeakPtr<DelegatedFrameHost> dfh,
660 scoped_refptr<OwnedMailbox> subscriber_texture,
661 scoped_refptr<media::VideoFrame> video_frame,
662 const base::Callback<void(bool)>& callback,
663 scoped_ptr<cc::CopyOutputResult> result) {
664 base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
665 base::ScopedClosureRunner scoped_return_subscriber_texture(
666 base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture, 0));
668 if (!dfh)
669 return;
670 if (result->IsEmpty())
671 return;
672 if (result->size().IsEmpty())
673 return;
675 // Compute the dest size we want after the letterboxing resize. Make the
676 // coordinates and sizes even because we letterbox in YUV space
677 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
678 // line up correctly.
679 // The video frame's coded_size() and the result's size() are both physical
680 // pixels.
681 gfx::Rect region_in_frame =
682 media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()),
683 result->size());
684 region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
685 region_in_frame.y() & ~1,
686 region_in_frame.width() & ~1,
687 region_in_frame.height() & ~1);
688 if (region_in_frame.IsEmpty())
689 return;
691 if (!result->HasTexture()) {
692 DCHECK(result->HasBitmap());
693 scoped_ptr<SkBitmap> bitmap = result->TakeBitmap();
694 // Scale the bitmap to the required size, if necessary.
695 SkBitmap scaled_bitmap;
696 if (result->size().width() != region_in_frame.width() ||
697 result->size().height() != region_in_frame.height()) {
698 skia::ImageOperations::ResizeMethod method =
699 skia::ImageOperations::RESIZE_GOOD;
700 scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method,
701 region_in_frame.width(),
702 region_in_frame.height());
703 } else {
704 scaled_bitmap = *bitmap.get();
708 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
710 media::CopyRGBToVideoFrame(
711 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
712 scaled_bitmap.rowBytes(),
713 region_in_frame,
714 video_frame.get());
716 ignore_result(scoped_callback_runner.Release());
717 callback.Run(true);
718 return;
721 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
722 GLHelper* gl_helper = factory->GetGLHelper();
723 if (!gl_helper)
724 return;
725 if (subscriber_texture.get() && !subscriber_texture->texture_id())
726 return;
728 cc::TextureMailbox texture_mailbox;
729 scoped_ptr<cc::SingleReleaseCallback> release_callback;
730 result->TakeTexture(&texture_mailbox, &release_callback);
731 DCHECK(texture_mailbox.IsTexture());
733 gfx::Rect result_rect(result->size());
735 content::ReadbackYUVInterface* yuv_readback_pipeline =
736 dfh->yuv_readback_pipeline_.get();
737 if (yuv_readback_pipeline == NULL ||
738 yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
739 yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
740 yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
741 GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST;
742 std::string quality_switch = switches::kTabCaptureDownscaleQuality;
743 // If we're scaling up, we can use the "best" quality.
744 if (result_rect.size().width() < region_in_frame.size().width() &&
745 result_rect.size().height() < region_in_frame.size().height())
746 quality_switch = switches::kTabCaptureUpscaleQuality;
748 std::string switch_value =
749 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
750 quality_switch);
751 if (switch_value == "fast")
752 quality = GLHelper::SCALER_QUALITY_FAST;
753 else if (switch_value == "good")
754 quality = GLHelper::SCALER_QUALITY_GOOD;
755 else if (switch_value == "best")
756 quality = GLHelper::SCALER_QUALITY_BEST;
758 dfh->yuv_readback_pipeline_.reset(
759 gl_helper->CreateReadbackPipelineYUV(quality,
760 result_rect.size(),
761 result_rect,
762 video_frame->coded_size(),
763 region_in_frame,
764 true,
765 true));
766 yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
769 ignore_result(scoped_callback_runner.Release());
770 ignore_result(scoped_return_subscriber_texture.Release());
771 base::Callback<void(bool result)> finished_callback = base::Bind(
772 &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo,
773 dfh->AsWeakPtr(),
774 callback,
775 subscriber_texture,
776 base::Passed(&release_callback));
777 yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
778 texture_mailbox.sync_point(),
779 video_frame.get(),
780 finished_callback);
783 ////////////////////////////////////////////////////////////////////////////////
784 // DelegatedFrameHost, ui::CompositorObserver implementation:
786 void DelegatedFrameHost::OnCompositingDidCommit(
787 ui::Compositor* compositor) {
788 RenderWidgetHostImpl* host = client_->GetHost();
789 if (can_lock_compositor_ == NO_PENDING_COMMIT) {
790 can_lock_compositor_ = YES_CAN_LOCK;
791 if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
792 can_lock_compositor_ = YES_DID_LOCK;
794 RunOnCommitCallbacks();
795 if (resize_lock_ &&
796 resize_lock_->expected_size() == current_frame_size_in_dip_) {
797 resize_lock_.reset();
798 host->WasResized();
799 // We may have had a resize while we had the lock (e.g. if the lock expired,
800 // or if the UI still gave us some resizes), so make sure we grab a new lock
801 // if necessary.
802 MaybeCreateResizeLock();
806 void DelegatedFrameHost::OnCompositingStarted(
807 ui::Compositor* compositor, base::TimeTicks start_time) {
808 last_draw_ended_ = start_time;
811 void DelegatedFrameHost::OnCompositingEnded(
812 ui::Compositor* compositor) {
815 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {
818 void DelegatedFrameHost::OnCompositingLockStateChanged(
819 ui::Compositor* compositor) {
820 // A compositor lock that is part of a resize lock timed out. We
821 // should display a renderer frame.
822 if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) {
823 can_lock_compositor_ = NO_PENDING_RENDERER_FRAME;
827 void DelegatedFrameHost::OnUpdateVSyncParameters(
828 base::TimeTicks timebase,
829 base::TimeDelta interval) {
830 vsync_timebase_ = timebase;
831 vsync_interval_ = interval;
832 RenderWidgetHostImpl* host = client_->GetHost();
833 if (client_->IsVisible())
834 host->UpdateVSyncParameters(timebase, interval);
837 ////////////////////////////////////////////////////////////////////////////////
838 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
840 void DelegatedFrameHost::OnLostResources() {
841 RenderWidgetHostImpl* host = client_->GetHost();
842 if (frame_provider_.get() || !surface_id_.is_null())
843 EvictDelegatedFrame();
844 idle_frame_subscriber_textures_.clear();
845 yuv_readback_pipeline_.reset();
847 host->ScheduleComposite();
850 ////////////////////////////////////////////////////////////////////////////////
851 // DelegatedFrameHost, private:
853 DelegatedFrameHost::~DelegatedFrameHost() {
854 ImageTransportFactory::GetInstance()->RemoveObserver(this);
856 if (!surface_id_.is_null())
857 surface_factory_->Destroy(surface_id_);
858 if (resource_collection_.get())
859 resource_collection_->SetClient(NULL);
861 DCHECK(!vsync_manager_);
864 void DelegatedFrameHost::RunOnCommitCallbacks() {
865 for (std::vector<base::Closure>::const_iterator
866 it = on_compositing_did_commit_callbacks_.begin();
867 it != on_compositing_did_commit_callbacks_.end(); ++it) {
868 it->Run();
870 on_compositing_did_commit_callbacks_.clear();
873 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
874 const base::Closure& callback) {
875 ui::Compositor* compositor = client_->GetCompositor();
876 DCHECK(compositor);
878 if (!compositor->HasObserver(this))
879 compositor->AddObserver(this);
881 can_lock_compositor_ = NO_PENDING_COMMIT;
882 on_compositing_did_commit_callbacks_.push_back(callback);
885 void DelegatedFrameHost::AddedToWindow() {
886 ui::Compositor* compositor = client_->GetCompositor();
887 if (compositor) {
888 DCHECK(!vsync_manager_);
889 vsync_manager_ = compositor->vsync_manager();
890 vsync_manager_->AddObserver(this);
894 void DelegatedFrameHost::RemovingFromWindow() {
895 RunOnCommitCallbacks();
896 resize_lock_.reset();
897 client_->GetHost()->WasResized();
898 ui::Compositor* compositor = client_->GetCompositor();
899 if (compositor && compositor->HasObserver(this))
900 compositor->RemoveObserver(this);
902 if (vsync_manager_) {
903 vsync_manager_->RemoveObserver(this);
904 vsync_manager_ = NULL;
908 void DelegatedFrameHost::LockResources() {
909 DCHECK(frame_provider_ || !surface_id_.is_null());
910 delegated_frame_evictor_->LockFrame();
913 void DelegatedFrameHost::UnlockResources() {
914 DCHECK(frame_provider_ || !surface_id_.is_null());
915 delegated_frame_evictor_->UnlockFrame();
918 ////////////////////////////////////////////////////////////////////////////////
919 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
921 void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
922 ui::Layer* new_layer) {
923 // The new_layer is the one that will be used by our Window, so that's the one
924 // that should keep our frame. old_layer will be returned to the
925 // RecreateLayer caller, and should have a copy.
926 if (frame_provider_.get()) {
927 new_layer->SetShowDelegatedContent(frame_provider_.get(),
928 current_frame_size_in_dip_);
930 if (!surface_id_.is_null()) {
931 new_layer->SetShowSurface(surface_id_, current_frame_size_in_dip_);
935 } // namespace content