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