Remove implicit conversions from scoped_refptr to T* in content/browser/service_worker
[chromium-blink-merge.git] / content / browser / compositor / delegated_frame_host.cc
blobd68feac611deef79c3ec29557051fab9cdb61263
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_.get() &&
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(
383 surface_id_,
384 compositor_frame.Pass(),
385 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
386 AsWeakPtr(),
387 output_surface_id));
388 } else {
389 if (!resource_collection_.get()) {
390 resource_collection_ = new cc::DelegatedFrameResourceCollection;
391 resource_collection_->SetClient(this);
393 // If the physical frame size changes, we need a new |frame_provider_|. If
394 // the physical frame size is the same, but the size in DIP changed, we
395 // need to adjust the scale at which the frames will be drawn, and we do
396 // this by making a new |frame_provider_| also to ensure the scale change
397 // is presented in sync with the new frame content.
398 if (!frame_provider_.get() ||
399 frame_size != frame_provider_->frame_size() ||
400 frame_size_in_dip != current_frame_size_in_dip_) {
401 frame_provider_ = new cc::DelegatedFrameProvider(
402 resource_collection_.get(), frame_data.Pass());
403 client_->GetLayer()->SetShowDelegatedContent(frame_provider_.get(),
404 frame_size_in_dip);
405 } else {
406 frame_provider_->SetFrameData(frame_data.Pass());
408 modified_layers = true;
411 released_front_lock_ = NULL;
412 current_frame_size_in_dip_ = frame_size_in_dip;
413 CheckResizeLock();
415 if (modified_layers && !damage_rect_in_dip.IsEmpty()) {
416 // TODO(jbauman): Need to always tell the window observer about the
417 // damage.
418 client_->GetLayer()->OnDelegatedFrameDamage(damage_rect_in_dip);
421 pending_delegated_ack_count_++;
423 ui::Compositor* compositor = client_->GetCompositor();
424 if (!compositor) {
425 SendDelegatedFrameAck(output_surface_id);
426 } else if (!use_surfaces_) {
427 std::vector<ui::LatencyInfo>::const_iterator it;
428 for (it = latency_info.begin(); it != latency_info.end(); ++it)
429 compositor->SetLatencyInfo(*it);
430 // If we've previously skipped any latency infos add them.
431 for (it = skipped_latency_info_list_.begin();
432 it != skipped_latency_info_list_.end();
433 ++it)
434 compositor->SetLatencyInfo(*it);
435 skipped_latency_info_list_.clear();
436 AddOnCommitCallbackAndDisableLocks(
437 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
438 AsWeakPtr(),
439 output_surface_id));
441 DidReceiveFrameFromRenderer(damage_rect);
442 if (frame_provider_.get() || !surface_id_.is_null())
443 delegated_frame_evictor_->SwappedFrame(!host->is_hidden());
444 // Note: the frame may have been evicted immediately.
447 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) {
448 RenderWidgetHostImpl* host = client_->GetHost();
449 cc::CompositorFrameAck ack;
450 if (!surface_returned_resources_.empty())
451 ack.resources.swap(surface_returned_resources_);
452 if (resource_collection_.get())
453 resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
454 RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(),
455 output_surface_id,
456 host->GetProcess()->GetID(),
457 ack);
458 DCHECK_GT(pending_delegated_ack_count_, 0);
459 pending_delegated_ack_count_--;
462 void DelegatedFrameHost::UnusedResourcesAreAvailable() {
463 if (pending_delegated_ack_count_)
464 return;
466 SendReturnedDelegatedResources(last_output_surface_id_);
469 void DelegatedFrameHost::SendReturnedDelegatedResources(
470 uint32 output_surface_id) {
471 RenderWidgetHostImpl* host = client_->GetHost();
473 cc::CompositorFrameAck ack;
474 if (!surface_returned_resources_.empty()) {
475 ack.resources.swap(surface_returned_resources_);
476 } else {
477 DCHECK(resource_collection_.get());
478 resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
480 DCHECK(!ack.resources.empty());
482 RenderWidgetHostImpl::SendReclaimCompositorResources(
483 host->GetRoutingID(),
484 output_surface_id,
485 host->GetProcess()->GetID(),
486 ack);
489 void DelegatedFrameHost::ReturnResources(
490 const cc::ReturnedResourceArray& resources) {
491 if (resources.empty())
492 return;
493 std::copy(resources.begin(),
494 resources.end(),
495 std::back_inserter(surface_returned_resources_));
496 if (!pending_delegated_ack_count_)
497 SendReturnedDelegatedResources(last_output_surface_id_);
500 void DelegatedFrameHost::EvictDelegatedFrame() {
501 client_->GetLayer()->SetShowPaintedContent();
502 frame_provider_ = NULL;
503 if (!surface_id_.is_null()) {
504 surface_factory_->Destroy(surface_id_);
505 surface_id_ = cc::SurfaceId();
507 delegated_frame_evictor_->DiscardedFrame();
510 // static
511 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
512 const gfx::Size& dst_size_in_pixel,
513 const SkColorType color_type,
514 const base::Callback<void(bool, const SkBitmap&)>& callback,
515 scoped_ptr<cc::CopyOutputResult> result) {
516 if (result->IsEmpty() || result->size().IsEmpty()) {
517 callback.Run(false, SkBitmap());
518 return;
521 if (result->HasTexture()) {
522 PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type,
523 callback,
524 result.Pass());
525 return;
528 DCHECK(result->HasBitmap());
529 PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback,
530 result.Pass());
533 static void CopyFromCompositingSurfaceFinished(
534 const base::Callback<void(bool, const SkBitmap&)>& callback,
535 scoped_ptr<cc::SingleReleaseCallback> release_callback,
536 scoped_ptr<SkBitmap> bitmap,
537 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
538 bool result) {
539 bitmap_pixels_lock.reset();
541 uint32 sync_point = 0;
542 if (result) {
543 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
544 sync_point = gl_helper->InsertSyncPoint();
546 bool lost_resource = sync_point == 0;
547 release_callback->Run(sync_point, lost_resource);
549 callback.Run(result, *bitmap);
552 // static
553 void DelegatedFrameHost::PrepareTextureCopyOutputResult(
554 const gfx::Size& dst_size_in_pixel,
555 const SkColorType color_type,
556 const base::Callback<void(bool, const SkBitmap&)>& callback,
557 scoped_ptr<cc::CopyOutputResult> result) {
558 DCHECK(result->HasTexture());
559 base::ScopedClosureRunner scoped_callback_runner(
560 base::Bind(callback, false, SkBitmap()));
562 scoped_ptr<SkBitmap> bitmap(new SkBitmap);
563 if (!bitmap->allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
564 dst_size_in_pixel.height(),
565 color_type,
566 kOpaque_SkAlphaType)))
567 return;
569 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
570 GLHelper* gl_helper = factory->GetGLHelper();
571 if (!gl_helper)
572 return;
574 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
575 new SkAutoLockPixels(*bitmap));
576 uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
578 cc::TextureMailbox texture_mailbox;
579 scoped_ptr<cc::SingleReleaseCallback> release_callback;
580 result->TakeTexture(&texture_mailbox, &release_callback);
581 DCHECK(texture_mailbox.IsTexture());
583 ignore_result(scoped_callback_runner.Release());
585 gl_helper->CropScaleReadbackAndCleanMailbox(
586 texture_mailbox.mailbox(),
587 texture_mailbox.sync_point(),
588 result->size(),
589 gfx::Rect(result->size()),
590 dst_size_in_pixel,
591 pixels,
592 color_type,
593 base::Bind(&CopyFromCompositingSurfaceFinished,
594 callback,
595 base::Passed(&release_callback),
596 base::Passed(&bitmap),
597 base::Passed(&bitmap_pixels_lock)),
598 GLHelper::SCALER_QUALITY_FAST);
601 // static
602 void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
603 const gfx::Size& dst_size_in_pixel,
604 const SkColorType color_type,
605 const base::Callback<void(bool, const SkBitmap&)>& callback,
606 scoped_ptr<cc::CopyOutputResult> result) {
607 if (color_type != kN32_SkColorType) {
608 NOTIMPLEMENTED();
609 callback.Run(false, SkBitmap());
610 return;
612 DCHECK(result->HasBitmap());
613 scoped_ptr<SkBitmap> source = result->TakeBitmap();
614 DCHECK(source);
615 SkBitmap bitmap = skia::ImageOperations::Resize(
616 *source,
617 skia::ImageOperations::RESIZE_BEST,
618 dst_size_in_pixel.width(),
619 dst_size_in_pixel.height());
620 callback.Run(true, bitmap);
623 // static
624 void DelegatedFrameHost::ReturnSubscriberTexture(
625 base::WeakPtr<DelegatedFrameHost> dfh,
626 scoped_refptr<OwnedMailbox> subscriber_texture,
627 uint32 sync_point) {
628 if (!subscriber_texture.get())
629 return;
630 if (!dfh)
631 return;
633 subscriber_texture->UpdateSyncPoint(sync_point);
635 if (dfh->frame_subscriber_ && subscriber_texture->texture_id())
636 dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
639 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
640 base::WeakPtr<DelegatedFrameHost> dfh,
641 const base::Callback<void(bool)>& callback,
642 scoped_refptr<OwnedMailbox> subscriber_texture,
643 scoped_ptr<cc::SingleReleaseCallback> release_callback,
644 bool result) {
645 callback.Run(result);
647 uint32 sync_point = 0;
648 if (result) {
649 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
650 sync_point = gl_helper->InsertSyncPoint();
652 if (release_callback) {
653 // A release callback means the texture came from the compositor, so there
654 // should be no |subscriber_texture|.
655 DCHECK(!subscriber_texture.get());
656 bool lost_resource = sync_point == 0;
657 release_callback->Run(sync_point, lost_resource);
659 ReturnSubscriberTexture(dfh, subscriber_texture, sync_point);
662 // static
663 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
664 base::WeakPtr<DelegatedFrameHost> dfh,
665 scoped_refptr<OwnedMailbox> subscriber_texture,
666 scoped_refptr<media::VideoFrame> video_frame,
667 const base::Callback<void(bool)>& callback,
668 scoped_ptr<cc::CopyOutputResult> result) {
669 base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
670 base::ScopedClosureRunner scoped_return_subscriber_texture(
671 base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture, 0));
673 if (!dfh)
674 return;
675 if (result->IsEmpty())
676 return;
677 if (result->size().IsEmpty())
678 return;
680 // Compute the dest size we want after the letterboxing resize. Make the
681 // coordinates and sizes even because we letterbox in YUV space
682 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
683 // line up correctly.
684 // The video frame's coded_size() and the result's size() are both physical
685 // pixels.
686 gfx::Rect region_in_frame =
687 media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()),
688 result->size());
689 region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
690 region_in_frame.y() & ~1,
691 region_in_frame.width() & ~1,
692 region_in_frame.height() & ~1);
693 if (region_in_frame.IsEmpty())
694 return;
696 if (!result->HasTexture()) {
697 DCHECK(result->HasBitmap());
698 scoped_ptr<SkBitmap> bitmap = result->TakeBitmap();
699 // Scale the bitmap to the required size, if necessary.
700 SkBitmap scaled_bitmap;
701 if (result->size().width() != region_in_frame.width() ||
702 result->size().height() != region_in_frame.height()) {
703 skia::ImageOperations::ResizeMethod method =
704 skia::ImageOperations::RESIZE_GOOD;
705 scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method,
706 region_in_frame.width(),
707 region_in_frame.height());
708 } else {
709 scaled_bitmap = *bitmap.get();
713 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
715 media::CopyRGBToVideoFrame(
716 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
717 scaled_bitmap.rowBytes(),
718 region_in_frame,
719 video_frame.get());
721 ignore_result(scoped_callback_runner.Release());
722 callback.Run(true);
723 return;
726 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
727 GLHelper* gl_helper = factory->GetGLHelper();
728 if (!gl_helper)
729 return;
730 if (subscriber_texture.get() && !subscriber_texture->texture_id())
731 return;
733 cc::TextureMailbox texture_mailbox;
734 scoped_ptr<cc::SingleReleaseCallback> release_callback;
735 result->TakeTexture(&texture_mailbox, &release_callback);
736 DCHECK(texture_mailbox.IsTexture());
738 gfx::Rect result_rect(result->size());
740 content::ReadbackYUVInterface* yuv_readback_pipeline =
741 dfh->yuv_readback_pipeline_.get();
742 if (yuv_readback_pipeline == NULL ||
743 yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
744 yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
745 yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
746 GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST;
747 std::string quality_switch = switches::kTabCaptureDownscaleQuality;
748 // If we're scaling up, we can use the "best" quality.
749 if (result_rect.size().width() < region_in_frame.size().width() &&
750 result_rect.size().height() < region_in_frame.size().height())
751 quality_switch = switches::kTabCaptureUpscaleQuality;
753 std::string switch_value =
754 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
755 quality_switch);
756 if (switch_value == "fast")
757 quality = GLHelper::SCALER_QUALITY_FAST;
758 else if (switch_value == "good")
759 quality = GLHelper::SCALER_QUALITY_GOOD;
760 else if (switch_value == "best")
761 quality = GLHelper::SCALER_QUALITY_BEST;
763 dfh->yuv_readback_pipeline_.reset(
764 gl_helper->CreateReadbackPipelineYUV(quality,
765 result_rect.size(),
766 result_rect,
767 video_frame->coded_size(),
768 region_in_frame,
769 true,
770 true));
771 yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
774 ignore_result(scoped_callback_runner.Release());
775 ignore_result(scoped_return_subscriber_texture.Release());
776 base::Callback<void(bool result)> finished_callback = base::Bind(
777 &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo,
778 dfh->AsWeakPtr(),
779 callback,
780 subscriber_texture,
781 base::Passed(&release_callback));
782 yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
783 texture_mailbox.sync_point(),
784 video_frame.get(),
785 finished_callback);
788 ////////////////////////////////////////////////////////////////////////////////
789 // DelegatedFrameHost, ui::CompositorObserver implementation:
791 void DelegatedFrameHost::OnCompositingDidCommit(
792 ui::Compositor* compositor) {
793 RenderWidgetHostImpl* host = client_->GetHost();
794 if (can_lock_compositor_ == NO_PENDING_COMMIT) {
795 can_lock_compositor_ = YES_CAN_LOCK;
796 if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
797 can_lock_compositor_ = YES_DID_LOCK;
799 RunOnCommitCallbacks();
800 if (resize_lock_ &&
801 resize_lock_->expected_size() == current_frame_size_in_dip_) {
802 resize_lock_.reset();
803 host->WasResized();
804 // We may have had a resize while we had the lock (e.g. if the lock expired,
805 // or if the UI still gave us some resizes), so make sure we grab a new lock
806 // if necessary.
807 MaybeCreateResizeLock();
811 void DelegatedFrameHost::OnCompositingStarted(
812 ui::Compositor* compositor, base::TimeTicks start_time) {
813 last_draw_ended_ = start_time;
816 void DelegatedFrameHost::OnCompositingEnded(
817 ui::Compositor* compositor) {
820 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {
823 void DelegatedFrameHost::OnCompositingLockStateChanged(
824 ui::Compositor* compositor) {
825 // A compositor lock that is part of a resize lock timed out. We
826 // should display a renderer frame.
827 if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) {
828 can_lock_compositor_ = NO_PENDING_RENDERER_FRAME;
832 void DelegatedFrameHost::OnUpdateVSyncParameters(
833 base::TimeTicks timebase,
834 base::TimeDelta interval) {
835 vsync_timebase_ = timebase;
836 vsync_interval_ = interval;
837 RenderWidgetHostImpl* host = client_->GetHost();
838 if (client_->IsVisible())
839 host->UpdateVSyncParameters(timebase, interval);
842 ////////////////////////////////////////////////////////////////////////////////
843 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
845 void DelegatedFrameHost::OnLostResources() {
846 RenderWidgetHostImpl* host = client_->GetHost();
847 if (frame_provider_.get() || !surface_id_.is_null())
848 EvictDelegatedFrame();
849 idle_frame_subscriber_textures_.clear();
850 yuv_readback_pipeline_.reset();
852 host->ScheduleComposite();
855 ////////////////////////////////////////////////////////////////////////////////
856 // DelegatedFrameHost, private:
858 DelegatedFrameHost::~DelegatedFrameHost() {
859 ImageTransportFactory::GetInstance()->RemoveObserver(this);
861 if (!surface_id_.is_null())
862 surface_factory_->Destroy(surface_id_);
863 if (resource_collection_.get())
864 resource_collection_->SetClient(NULL);
866 DCHECK(!vsync_manager_.get());
869 void DelegatedFrameHost::RunOnCommitCallbacks() {
870 for (std::vector<base::Closure>::const_iterator
871 it = on_compositing_did_commit_callbacks_.begin();
872 it != on_compositing_did_commit_callbacks_.end(); ++it) {
873 it->Run();
875 on_compositing_did_commit_callbacks_.clear();
878 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
879 const base::Closure& callback) {
880 ui::Compositor* compositor = client_->GetCompositor();
881 DCHECK(compositor);
883 if (!compositor->HasObserver(this))
884 compositor->AddObserver(this);
886 can_lock_compositor_ = NO_PENDING_COMMIT;
887 on_compositing_did_commit_callbacks_.push_back(callback);
890 void DelegatedFrameHost::AddedToWindow() {
891 ui::Compositor* compositor = client_->GetCompositor();
892 if (compositor) {
893 DCHECK(!vsync_manager_.get());
894 vsync_manager_ = compositor->vsync_manager();
895 vsync_manager_->AddObserver(this);
899 void DelegatedFrameHost::RemovingFromWindow() {
900 RunOnCommitCallbacks();
901 resize_lock_.reset();
902 client_->GetHost()->WasResized();
903 ui::Compositor* compositor = client_->GetCompositor();
904 if (compositor && compositor->HasObserver(this))
905 compositor->RemoveObserver(this);
907 if (vsync_manager_.get()) {
908 vsync_manager_->RemoveObserver(this);
909 vsync_manager_ = NULL;
913 void DelegatedFrameHost::LockResources() {
914 DCHECK(frame_provider_.get() || !surface_id_.is_null());
915 delegated_frame_evictor_->LockFrame();
918 void DelegatedFrameHost::UnlockResources() {
919 DCHECK(frame_provider_.get() || !surface_id_.is_null());
920 delegated_frame_evictor_->UnlockFrame();
923 ////////////////////////////////////////////////////////////////////////////////
924 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
926 void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
927 ui::Layer* new_layer) {
928 // The new_layer is the one that will be used by our Window, so that's the one
929 // that should keep our frame. old_layer will be returned to the
930 // RecreateLayer caller, and should have a copy.
931 if (frame_provider_.get()) {
932 new_layer->SetShowDelegatedContent(frame_provider_.get(),
933 current_frame_size_in_dip_);
935 if (!surface_id_.is_null()) {
936 new_layer->SetShowSurface(surface_id_, current_frame_size_in_dip_);
940 } // namespace content