Home | History | Annotate | Download | only in compositor
      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.
      4 
      5 #include "content/browser/compositor/delegated_frame_host.h"
      6 
      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/common/gpu/client/gl_helper.h"
     16 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
     17 #include "content/public/common/content_switches.h"
     18 #include "media/base/video_frame.h"
     19 #include "media/base/video_util.h"
     20 #include "skia/ext/image_operations.h"
     21 
     22 namespace content {
     23 
     24 ////////////////////////////////////////////////////////////////////////////////
     25 // DelegatedFrameHostClient
     26 
     27 bool DelegatedFrameHostClient::ShouldCreateResizeLock() {
     28   // On Windows and Linux, holding pointer moves will not help throttling
     29   // resizes.
     30   // TODO(piman): on Windows we need to block (nested message loop?) the
     31   // WM_SIZE event. On Linux we need to throttle at the WM level using
     32   // _NET_WM_SYNC_REQUEST.
     33   // TODO(ccameron): Mac browser window resizing is incompletely implemented.
     34 #if !defined(OS_CHROMEOS)
     35   return false;
     36 #else
     37   return GetDelegatedFrameHost()->ShouldCreateResizeLock();
     38 #endif
     39 }
     40 
     41 void DelegatedFrameHostClient::RequestCopyOfOutput(
     42     scoped_ptr<cc::CopyOutputRequest> request) {
     43   GetDelegatedFrameHost()->RequestCopyOfOutput(request.Pass());
     44 }
     45 
     46 ////////////////////////////////////////////////////////////////////////////////
     47 // DelegatedFrameHost
     48 
     49 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
     50     : client_(client),
     51       last_output_surface_id_(0),
     52       pending_delegated_ack_count_(0),
     53       skipped_frames_(false),
     54       can_lock_compositor_(YES_CAN_LOCK),
     55       delegated_frame_evictor_(new DelegatedFrameEvictor(this)) {
     56   ImageTransportFactory::GetInstance()->AddObserver(this);
     57 }
     58 
     59 void DelegatedFrameHost::WasShown() {
     60   delegated_frame_evictor_->SetVisible(true);
     61 
     62   if (!released_front_lock_.get()) {
     63     ui::Compositor* compositor = client_->GetCompositor();
     64     if (compositor)
     65       released_front_lock_ = compositor->GetCompositorLock();
     66   }
     67 }
     68 
     69 void DelegatedFrameHost::WasHidden() {
     70   delegated_frame_evictor_->SetVisible(false);
     71   released_front_lock_ = NULL;
     72 }
     73 
     74 void DelegatedFrameHost::MaybeCreateResizeLock() {
     75   if (!client_->ShouldCreateResizeLock())
     76     return;
     77   DCHECK(client_->GetCompositor());
     78 
     79   // Listen to changes in the compositor lock state.
     80   ui::Compositor* compositor = client_->GetCompositor();
     81   if (!compositor->HasObserver(this))
     82     compositor->AddObserver(this);
     83 
     84   bool defer_compositor_lock =
     85       can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
     86       can_lock_compositor_ == NO_PENDING_COMMIT;
     87 
     88   if (can_lock_compositor_ == YES_CAN_LOCK)
     89     can_lock_compositor_ = YES_DID_LOCK;
     90 
     91   resize_lock_ = client_->CreateResizeLock(defer_compositor_lock);
     92 }
     93 
     94 bool DelegatedFrameHost::ShouldCreateResizeLock() {
     95   RenderWidgetHostImpl* host = client_->GetHost();
     96 
     97   if (resize_lock_)
     98     return false;
     99 
    100   if (host->should_auto_resize())
    101     return false;
    102 
    103   gfx::Size desired_size = client_->DesiredFrameSize();
    104   if (desired_size == current_frame_size_in_dip_ || desired_size.IsEmpty())
    105     return false;
    106 
    107   ui::Compositor* compositor = client_->GetCompositor();
    108   if (!compositor)
    109     return false;
    110 
    111   return true;
    112 }
    113 
    114 void DelegatedFrameHost::RequestCopyOfOutput(
    115     scoped_ptr<cc::CopyOutputRequest> request) {
    116   client_->GetLayer()->RequestCopyOfOutput(request.Pass());
    117 }
    118 
    119 void DelegatedFrameHost::CopyFromCompositingSurface(
    120     const gfx::Rect& src_subrect,
    121     const gfx::Size& dst_size,
    122     const base::Callback<void(bool, const SkBitmap&)>& callback,
    123     const SkBitmap::Config config) {
    124   // Only ARGB888 and RGB565 supported as of now.
    125   bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
    126                          (config == SkBitmap::kARGB_8888_Config));
    127   DCHECK(format_support);
    128   if (!CanCopyToBitmap()) {
    129     callback.Run(false, SkBitmap());
    130     return;
    131   }
    132 
    133   const gfx::Size& dst_size_in_pixel =
    134       client_->ConvertViewSizeToPixel(dst_size);
    135   scoped_ptr<cc::CopyOutputRequest> request =
    136       cc::CopyOutputRequest::CreateRequest(base::Bind(
    137           &DelegatedFrameHost::CopyFromCompositingSurfaceHasResult,
    138           dst_size_in_pixel,
    139           config,
    140           callback));
    141   gfx::Rect src_subrect_in_pixel =
    142       ConvertRectToPixel(client_->CurrentDeviceScaleFactor(), src_subrect);
    143   request->set_area(src_subrect_in_pixel);
    144   client_->RequestCopyOfOutput(request.Pass());
    145 }
    146 
    147 void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
    148       const gfx::Rect& src_subrect,
    149       const scoped_refptr<media::VideoFrame>& target,
    150       const base::Callback<void(bool)>& callback) {
    151   if (!CanCopyToVideoFrame()) {
    152     callback.Run(false);
    153     return;
    154   }
    155 
    156   // Try get a texture to reuse.
    157   scoped_refptr<OwnedMailbox> subscriber_texture;
    158   if (frame_subscriber_) {
    159     if (!idle_frame_subscriber_textures_.empty()) {
    160       subscriber_texture = idle_frame_subscriber_textures_.back();
    161       idle_frame_subscriber_textures_.pop_back();
    162     } else if (GLHelper* helper =
    163                    ImageTransportFactory::GetInstance()->GetGLHelper()) {
    164       subscriber_texture = new OwnedMailbox(helper);
    165     }
    166   }
    167 
    168   scoped_ptr<cc::CopyOutputRequest> request =
    169       cc::CopyOutputRequest::CreateRequest(base::Bind(
    170           &DelegatedFrameHost::
    171                CopyFromCompositingSurfaceHasResultForVideo,
    172           AsWeakPtr(),  // For caching the ReadbackYUVInterface on this class.
    173           subscriber_texture,
    174           target,
    175           callback));
    176   gfx::Rect src_subrect_in_pixel =
    177       ConvertRectToPixel(client_->CurrentDeviceScaleFactor(), src_subrect);
    178   request->set_area(src_subrect_in_pixel);
    179   if (subscriber_texture.get()) {
    180     request->SetTextureMailbox(
    181         cc::TextureMailbox(subscriber_texture->mailbox(),
    182                            subscriber_texture->target(),
    183                            subscriber_texture->sync_point()));
    184   }
    185   client_->RequestCopyOfOutput(request.Pass());
    186 }
    187 
    188 bool DelegatedFrameHost::CanCopyToBitmap() const {
    189   return client_->GetCompositor() &&
    190          client_->GetLayer()->has_external_content();
    191 }
    192 
    193 bool DelegatedFrameHost::CanCopyToVideoFrame() const {
    194   return client_->GetCompositor() &&
    195          client_->GetLayer()->has_external_content();
    196 }
    197 
    198 bool DelegatedFrameHost::CanSubscribeFrame() const {
    199   return true;
    200 }
    201 
    202 void DelegatedFrameHost::BeginFrameSubscription(
    203     scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
    204   frame_subscriber_ = subscriber.Pass();
    205 }
    206 
    207 void DelegatedFrameHost::EndFrameSubscription() {
    208   idle_frame_subscriber_textures_.clear();
    209   frame_subscriber_.reset();
    210 }
    211 
    212 bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const {
    213   // Should skip a frame only when another frame from the renderer is guaranteed
    214   // to replace it. Otherwise may cause hangs when the renderer is waiting for
    215   // the completion of latency infos (such as when taking a Snapshot.)
    216   if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
    217       can_lock_compositor_ == NO_PENDING_COMMIT ||
    218       !resize_lock_.get())
    219     return false;
    220 
    221   return size_in_dip != resize_lock_->expected_size();
    222 }
    223 
    224 void DelegatedFrameHost::WasResized() {
    225   MaybeCreateResizeLock();
    226 }
    227 
    228 gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const {
    229   if (resize_lock_)
    230     return resize_lock_->expected_size();
    231   else
    232     return client_->DesiredFrameSize();
    233 }
    234 
    235 void DelegatedFrameHost::CheckResizeLock() {
    236   if (!resize_lock_ ||
    237       resize_lock_->expected_size() != current_frame_size_in_dip_)
    238     return;
    239 
    240   // Since we got the size we were looking for, unlock the compositor. But delay
    241   // the release of the lock until we've kicked a frame with the new texture, to
    242   // avoid resizing the UI before we have a chance to draw a "good" frame.
    243   resize_lock_->UnlockCompositor();
    244   ui::Compositor* compositor = client_->GetCompositor();
    245   if (compositor) {
    246     if (!compositor->HasObserver(this))
    247       compositor->AddObserver(this);
    248   }
    249 }
    250 
    251 void DelegatedFrameHost::DidReceiveFrameFromRenderer() {
    252   if (frame_subscriber() && CanCopyToVideoFrame()) {
    253     const base::TimeTicks present_time = base::TimeTicks::Now();
    254     scoped_refptr<media::VideoFrame> frame;
    255     RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
    256     if (frame_subscriber()->ShouldCaptureFrame(present_time,
    257                                                &frame, &callback)) {
    258       CopyFromCompositingSurfaceToVideoFrame(
    259           gfx::Rect(current_frame_size_in_dip_),
    260           frame,
    261           base::Bind(callback, present_time));
    262     }
    263   }
    264 }
    265 
    266 void DelegatedFrameHost::SwapDelegatedFrame(
    267     uint32 output_surface_id,
    268     scoped_ptr<cc::DelegatedFrameData> frame_data,
    269     float frame_device_scale_factor,
    270     const std::vector<ui::LatencyInfo>& latency_info) {
    271   RenderWidgetHostImpl* host = client_->GetHost();
    272   DCHECK(!frame_data->render_pass_list.empty());
    273 
    274   cc::RenderPass* root_pass = frame_data->render_pass_list.back();
    275 
    276   gfx::Size frame_size = root_pass->output_rect.size();
    277   gfx::Size frame_size_in_dip =
    278       ConvertSizeToDIP(frame_device_scale_factor, frame_size);
    279 
    280   gfx::Rect damage_rect = gfx::ToEnclosingRect(root_pass->damage_rect);
    281   damage_rect.Intersect(gfx::Rect(frame_size));
    282   gfx::Rect damage_rect_in_dip =
    283       ConvertRectToDIP(frame_device_scale_factor, damage_rect);
    284 
    285   if (ShouldSkipFrame(frame_size_in_dip)) {
    286     cc::CompositorFrameAck ack;
    287     cc::TransferableResource::ReturnResources(frame_data->resource_list,
    288                                               &ack.resources);
    289 
    290     skipped_latency_info_list_.insert(skipped_latency_info_list_.end(),
    291         latency_info.begin(), latency_info.end());
    292 
    293     RenderWidgetHostImpl::SendSwapCompositorFrameAck(
    294         host->GetRoutingID(), output_surface_id,
    295         host->GetProcess()->GetID(), ack);
    296     skipped_frames_ = true;
    297     return;
    298   }
    299 
    300   if (skipped_frames_) {
    301     skipped_frames_ = false;
    302     damage_rect = gfx::Rect(frame_size);
    303     damage_rect_in_dip = gfx::Rect(frame_size_in_dip);
    304 
    305     // Give the same damage rect to the compositor.
    306     cc::RenderPass* root_pass = frame_data->render_pass_list.back();
    307     root_pass->damage_rect = damage_rect;
    308   }
    309 
    310   if (output_surface_id != last_output_surface_id_) {
    311     // Resource ids are scoped by the output surface.
    312     // If the originating output surface doesn't match the last one, it
    313     // indicates the renderer's output surface may have been recreated, in which
    314     // case we should recreate the DelegatedRendererLayer, to avoid matching
    315     // resources from the old one with resources from the new one which would
    316     // have the same id. Changing the layer to showing painted content destroys
    317     // the DelegatedRendererLayer.
    318     EvictDelegatedFrame();
    319 
    320     // Drop the cc::DelegatedFrameResourceCollection so that we will not return
    321     // any resources from the old output surface with the new output surface id.
    322     if (resource_collection_.get()) {
    323       resource_collection_->SetClient(NULL);
    324 
    325       if (resource_collection_->LoseAllResources())
    326         SendReturnedDelegatedResources(last_output_surface_id_);
    327 
    328       resource_collection_ = NULL;
    329     }
    330     last_output_surface_id_ = output_surface_id;
    331   }
    332   if (frame_size.IsEmpty()) {
    333     DCHECK(frame_data->resource_list.empty());
    334     EvictDelegatedFrame();
    335   } else {
    336     if (!resource_collection_) {
    337       resource_collection_ = new cc::DelegatedFrameResourceCollection;
    338       resource_collection_->SetClient(this);
    339     }
    340     // If the physical frame size changes, we need a new |frame_provider_|. If
    341     // the physical frame size is the same, but the size in DIP changed, we
    342     // need to adjust the scale at which the frames will be drawn, and we do
    343     // this by making a new |frame_provider_| also to ensure the scale change
    344     // is presented in sync with the new frame content.
    345     if (!frame_provider_.get() || frame_size != frame_provider_->frame_size() ||
    346         frame_size_in_dip != current_frame_size_in_dip_) {
    347       frame_provider_ = new cc::DelegatedFrameProvider(
    348           resource_collection_.get(), frame_data.Pass());
    349       client_->GetLayer()->SetShowDelegatedContent(frame_provider_.get(),
    350                                                    frame_size_in_dip);
    351     } else {
    352       frame_provider_->SetFrameData(frame_data.Pass());
    353     }
    354   }
    355   released_front_lock_ = NULL;
    356   current_frame_size_in_dip_ = frame_size_in_dip;
    357   CheckResizeLock();
    358 
    359   client_->SchedulePaintInRect(damage_rect_in_dip);
    360 
    361   pending_delegated_ack_count_++;
    362 
    363   ui::Compositor* compositor = client_->GetCompositor();
    364   if (!compositor) {
    365     SendDelegatedFrameAck(output_surface_id);
    366   } else {
    367     std::vector<ui::LatencyInfo>::const_iterator it;
    368     for (it = latency_info.begin(); it != latency_info.end(); ++it)
    369       compositor->SetLatencyInfo(*it);
    370     // If we've previously skipped any latency infos add them.
    371     for (it = skipped_latency_info_list_.begin();
    372         it != skipped_latency_info_list_.end();
    373         ++it)
    374       compositor->SetLatencyInfo(*it);
    375     skipped_latency_info_list_.clear();
    376     AddOnCommitCallbackAndDisableLocks(
    377         base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
    378                    AsWeakPtr(),
    379                    output_surface_id));
    380   }
    381   DidReceiveFrameFromRenderer();
    382   if (frame_provider_.get())
    383     delegated_frame_evictor_->SwappedFrame(!host->is_hidden());
    384   // Note: the frame may have been evicted immediately.
    385 }
    386 
    387 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) {
    388   RenderWidgetHostImpl* host = client_->GetHost();
    389   cc::CompositorFrameAck ack;
    390   if (resource_collection_)
    391     resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
    392   RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(),
    393                                                    output_surface_id,
    394                                                    host->GetProcess()->GetID(),
    395                                                    ack);
    396   DCHECK_GT(pending_delegated_ack_count_, 0);
    397   pending_delegated_ack_count_--;
    398 }
    399 
    400 void DelegatedFrameHost::UnusedResourcesAreAvailable() {
    401   if (pending_delegated_ack_count_)
    402     return;
    403 
    404   SendReturnedDelegatedResources(last_output_surface_id_);
    405 }
    406 
    407 void DelegatedFrameHost::SendReturnedDelegatedResources(
    408     uint32 output_surface_id) {
    409   RenderWidgetHostImpl* host = client_->GetHost();
    410   DCHECK(resource_collection_);
    411 
    412   cc::CompositorFrameAck ack;
    413   resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
    414   DCHECK(!ack.resources.empty());
    415 
    416   RenderWidgetHostImpl::SendReclaimCompositorResources(
    417       host->GetRoutingID(),
    418       output_surface_id,
    419       host->GetProcess()->GetID(),
    420       ack);
    421 }
    422 
    423 void DelegatedFrameHost::EvictDelegatedFrame() {
    424   client_->GetLayer()->SetShowPaintedContent();
    425   frame_provider_ = NULL;
    426   delegated_frame_evictor_->DiscardedFrame();
    427 }
    428 
    429 // static
    430 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
    431     const gfx::Size& dst_size_in_pixel,
    432     const SkBitmap::Config config,
    433     const base::Callback<void(bool, const SkBitmap&)>& callback,
    434     scoped_ptr<cc::CopyOutputResult> result) {
    435   if (result->IsEmpty() || result->size().IsEmpty()) {
    436     callback.Run(false, SkBitmap());
    437     return;
    438   }
    439 
    440   if (result->HasTexture()) {
    441     PrepareTextureCopyOutputResult(dst_size_in_pixel, config,
    442                                    callback,
    443                                    result.Pass());
    444     return;
    445   }
    446 
    447   DCHECK(result->HasBitmap());
    448   PrepareBitmapCopyOutputResult(dst_size_in_pixel, config, callback,
    449                                 result.Pass());
    450 }
    451 
    452 static void CopyFromCompositingSurfaceFinished(
    453     const base::Callback<void(bool, const SkBitmap&)>& callback,
    454     scoped_ptr<cc::SingleReleaseCallback> release_callback,
    455     scoped_ptr<SkBitmap> bitmap,
    456     scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
    457     bool result) {
    458   bitmap_pixels_lock.reset();
    459 
    460   uint32 sync_point = 0;
    461   if (result) {
    462     GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
    463     sync_point = gl_helper->InsertSyncPoint();
    464   }
    465   bool lost_resource = sync_point == 0;
    466   release_callback->Run(sync_point, lost_resource);
    467 
    468   callback.Run(result, *bitmap);
    469 }
    470 
    471 // static
    472 void DelegatedFrameHost::PrepareTextureCopyOutputResult(
    473     const gfx::Size& dst_size_in_pixel,
    474     const SkBitmap::Config config,
    475     const base::Callback<void(bool, const SkBitmap&)>& callback,
    476     scoped_ptr<cc::CopyOutputResult> result) {
    477   DCHECK(result->HasTexture());
    478   base::ScopedClosureRunner scoped_callback_runner(
    479       base::Bind(callback, false, SkBitmap()));
    480 
    481   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
    482   bitmap->setConfig(config,
    483                     dst_size_in_pixel.width(), dst_size_in_pixel.height(),
    484                     0, kOpaque_SkAlphaType);
    485   if (!bitmap->allocPixels())
    486     return;
    487 
    488   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
    489   GLHelper* gl_helper = factory->GetGLHelper();
    490   if (!gl_helper)
    491     return;
    492 
    493   scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
    494       new SkAutoLockPixels(*bitmap));
    495   uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
    496 
    497   cc::TextureMailbox texture_mailbox;
    498   scoped_ptr<cc::SingleReleaseCallback> release_callback;
    499   result->TakeTexture(&texture_mailbox, &release_callback);
    500   DCHECK(texture_mailbox.IsTexture());
    501 
    502   ignore_result(scoped_callback_runner.Release());
    503 
    504   gl_helper->CropScaleReadbackAndCleanMailbox(
    505       texture_mailbox.mailbox(),
    506       texture_mailbox.sync_point(),
    507       result->size(),
    508       gfx::Rect(result->size()),
    509       dst_size_in_pixel,
    510       pixels,
    511       config,
    512       base::Bind(&CopyFromCompositingSurfaceFinished,
    513                  callback,
    514                  base::Passed(&release_callback),
    515                  base::Passed(&bitmap),
    516                  base::Passed(&bitmap_pixels_lock)),
    517       GLHelper::SCALER_QUALITY_FAST);
    518 }
    519 
    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;
    530   }
    531   DCHECK(result->HasBitmap());
    532   scoped_ptr<SkBitmap> source = result->TakeBitmap();
    533   DCHECK(source);
    534   SkBitmap bitmap = skia::ImageOperations::Resize(
    535       *source,
    536       skia::ImageOperations::RESIZE_BEST,
    537       dst_size_in_pixel.width(),
    538       dst_size_in_pixel.height());
    539   callback.Run(true, bitmap);
    540 }
    541 
    542 // static
    543 void DelegatedFrameHost::ReturnSubscriberTexture(
    544     base::WeakPtr<DelegatedFrameHost> dfh,
    545     scoped_refptr<OwnedMailbox> subscriber_texture,
    546     uint32 sync_point) {
    547   if (!subscriber_texture.get())
    548     return;
    549   if (!dfh)
    550     return;
    551 
    552   subscriber_texture->UpdateSyncPoint(sync_point);
    553 
    554   if (dfh->frame_subscriber_ && subscriber_texture->texture_id())
    555     dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
    556 }
    557 
    558 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
    559     base::WeakPtr<DelegatedFrameHost> dfh,
    560     const base::Callback<void(bool)>& callback,
    561     scoped_refptr<OwnedMailbox> subscriber_texture,
    562     scoped_ptr<cc::SingleReleaseCallback> release_callback,
    563     bool result) {
    564   callback.Run(result);
    565 
    566   uint32 sync_point = 0;
    567   if (result) {
    568     GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
    569     sync_point = gl_helper->InsertSyncPoint();
    570   }
    571   if (release_callback) {
    572     // A release callback means the texture came from the compositor, so there
    573     // should be no |subscriber_texture|.
    574     DCHECK(!subscriber_texture);
    575     bool lost_resource = sync_point == 0;
    576     release_callback->Run(sync_point, lost_resource);
    577   }
    578   ReturnSubscriberTexture(dfh, subscriber_texture, sync_point);
    579 }
    580 
    581 // static
    582 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
    583     base::WeakPtr<DelegatedFrameHost> dfh,
    584     scoped_refptr<OwnedMailbox> subscriber_texture,
    585     scoped_refptr<media::VideoFrame> video_frame,
    586     const base::Callback<void(bool)>& callback,
    587     scoped_ptr<cc::CopyOutputResult> result) {
    588   base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
    589   base::ScopedClosureRunner scoped_return_subscriber_texture(
    590       base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture, 0));
    591 
    592   if (!dfh)
    593     return;
    594   if (result->IsEmpty())
    595     return;
    596   if (result->size().IsEmpty())
    597     return;
    598 
    599   // Compute the dest size we want after the letterboxing resize. Make the
    600   // coordinates and sizes even because we letterbox in YUV space
    601   // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
    602   // line up correctly.
    603   // The video frame's coded_size() and the result's size() are both physical
    604   // pixels.
    605   gfx::Rect region_in_frame =
    606       media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()),
    607                                     result->size());
    608   region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
    609                               region_in_frame.y() & ~1,
    610                               region_in_frame.width() & ~1,
    611                               region_in_frame.height() & ~1);
    612   if (region_in_frame.IsEmpty())
    613     return;
    614 
    615   if (!result->HasTexture()) {
    616     DCHECK(result->HasBitmap());
    617     scoped_ptr<SkBitmap> bitmap = result->TakeBitmap();
    618     // Scale the bitmap to the required size, if necessary.
    619     SkBitmap scaled_bitmap;
    620     if (result->size().width() != region_in_frame.width() ||
    621         result->size().height() != region_in_frame.height()) {
    622       skia::ImageOperations::ResizeMethod method =
    623           skia::ImageOperations::RESIZE_GOOD;
    624       scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method,
    625                                                     region_in_frame.width(),
    626                                                     region_in_frame.height());
    627     } else {
    628       scaled_bitmap = *bitmap.get();
    629     }
    630 
    631     {
    632       SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
    633 
    634       media::CopyRGBToVideoFrame(
    635           reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
    636           scaled_bitmap.rowBytes(),
    637           region_in_frame,
    638           video_frame.get());
    639     }
    640     ignore_result(scoped_callback_runner.Release());
    641     callback.Run(true);
    642     return;
    643   }
    644 
    645   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
    646   GLHelper* gl_helper = factory->GetGLHelper();
    647   if (!gl_helper)
    648     return;
    649   if (subscriber_texture.get() && !subscriber_texture->texture_id())
    650     return;
    651 
    652   cc::TextureMailbox texture_mailbox;
    653   scoped_ptr<cc::SingleReleaseCallback> release_callback;
    654   result->TakeTexture(&texture_mailbox, &release_callback);
    655   DCHECK(texture_mailbox.IsTexture());
    656 
    657   gfx::Rect result_rect(result->size());
    658 
    659   content::ReadbackYUVInterface* yuv_readback_pipeline =
    660       dfh->yuv_readback_pipeline_.get();
    661   if (yuv_readback_pipeline == NULL ||
    662       yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
    663       yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
    664       yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
    665     GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST;
    666     std::string quality_switch = switches::kTabCaptureDownscaleQuality;
    667     // If we're scaling up, we can use the "best" quality.
    668     if (result_rect.size().width() < region_in_frame.size().width() &&
    669         result_rect.size().height() < region_in_frame.size().height())
    670       quality_switch = switches::kTabCaptureUpscaleQuality;
    671 
    672     std::string switch_value =
    673         CommandLine::ForCurrentProcess()->GetSwitchValueASCII(quality_switch);
    674     if (switch_value == "fast")
    675       quality = GLHelper::SCALER_QUALITY_FAST;
    676     else if (switch_value == "good")
    677       quality = GLHelper::SCALER_QUALITY_GOOD;
    678     else if (switch_value == "best")
    679       quality = GLHelper::SCALER_QUALITY_BEST;
    680 
    681     dfh->yuv_readback_pipeline_.reset(
    682         gl_helper->CreateReadbackPipelineYUV(quality,
    683                                              result_rect.size(),
    684                                              result_rect,
    685                                              video_frame->coded_size(),
    686                                              region_in_frame,
    687                                              true,
    688                                              true));
    689     yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
    690   }
    691 
    692   ignore_result(scoped_callback_runner.Release());
    693   ignore_result(scoped_return_subscriber_texture.Release());
    694   base::Callback<void(bool result)> finished_callback = base::Bind(
    695       &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo,
    696       dfh->AsWeakPtr(),
    697       callback,
    698       subscriber_texture,
    699       base::Passed(&release_callback));
    700   yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
    701                                      texture_mailbox.sync_point(),
    702                                      video_frame.get(),
    703                                      finished_callback);
    704 }
    705 
    706 ////////////////////////////////////////////////////////////////////////////////
    707 // DelegatedFrameHost, ui::CompositorObserver implementation:
    708 
    709 void DelegatedFrameHost::OnCompositingDidCommit(
    710     ui::Compositor* compositor) {
    711   RenderWidgetHostImpl* host = client_->GetHost();
    712   if (can_lock_compositor_ == NO_PENDING_COMMIT) {
    713     can_lock_compositor_ = YES_CAN_LOCK;
    714     if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
    715       can_lock_compositor_ = YES_DID_LOCK;
    716   }
    717   RunOnCommitCallbacks();
    718   if (resize_lock_ &&
    719       resize_lock_->expected_size() == current_frame_size_in_dip_) {
    720     resize_lock_.reset();
    721     host->WasResized();
    722     // We may have had a resize while we had the lock (e.g. if the lock expired,
    723     // or if the UI still gave us some resizes), so make sure we grab a new lock
    724     // if necessary.
    725     MaybeCreateResizeLock();
    726   }
    727 }
    728 
    729 void DelegatedFrameHost::OnCompositingStarted(
    730     ui::Compositor* compositor, base::TimeTicks start_time) {
    731   last_draw_ended_ = start_time;
    732 }
    733 
    734 void DelegatedFrameHost::OnCompositingEnded(
    735     ui::Compositor* compositor) {
    736 }
    737 
    738 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {
    739 }
    740 
    741 void DelegatedFrameHost::OnCompositingLockStateChanged(
    742     ui::Compositor* compositor) {
    743   // A compositor lock that is part of a resize lock timed out. We
    744   // should display a renderer frame.
    745   if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) {
    746     can_lock_compositor_ = NO_PENDING_RENDERER_FRAME;
    747   }
    748 }
    749 
    750 void DelegatedFrameHost::OnUpdateVSyncParameters(
    751     base::TimeTicks timebase,
    752     base::TimeDelta interval) {
    753   RenderWidgetHostImpl* host = client_->GetHost();
    754   if (client_->IsVisible())
    755     host->UpdateVSyncParameters(timebase, interval);
    756 }
    757 
    758 ////////////////////////////////////////////////////////////////////////////////
    759 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
    760 
    761 void DelegatedFrameHost::OnLostResources() {
    762   RenderWidgetHostImpl* host = client_->GetHost();
    763   if (frame_provider_.get())
    764     EvictDelegatedFrame();
    765   idle_frame_subscriber_textures_.clear();
    766   yuv_readback_pipeline_.reset();
    767 
    768   host->ScheduleComposite();
    769 }
    770 
    771 ////////////////////////////////////////////////////////////////////////////////
    772 // DelegatedFrameHost, private:
    773 
    774 DelegatedFrameHost::~DelegatedFrameHost() {
    775   ImageTransportFactory::GetInstance()->RemoveObserver(this);
    776 
    777   if (resource_collection_.get())
    778     resource_collection_->SetClient(NULL);
    779 
    780   DCHECK(!vsync_manager_);
    781 }
    782 
    783 void DelegatedFrameHost::RunOnCommitCallbacks() {
    784   for (std::vector<base::Closure>::const_iterator
    785       it = on_compositing_did_commit_callbacks_.begin();
    786       it != on_compositing_did_commit_callbacks_.end(); ++it) {
    787     it->Run();
    788   }
    789   on_compositing_did_commit_callbacks_.clear();
    790 }
    791 
    792 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
    793     const base::Closure& callback) {
    794   ui::Compositor* compositor = client_->GetCompositor();
    795   DCHECK(compositor);
    796 
    797   if (!compositor->HasObserver(this))
    798     compositor->AddObserver(this);
    799 
    800   can_lock_compositor_ = NO_PENDING_COMMIT;
    801   on_compositing_did_commit_callbacks_.push_back(callback);
    802 }
    803 
    804 void DelegatedFrameHost::AddedToWindow() {
    805   ui::Compositor* compositor = client_->GetCompositor();
    806   if (compositor) {
    807     DCHECK(!vsync_manager_);
    808     vsync_manager_ = compositor->vsync_manager();
    809     vsync_manager_->AddObserver(this);
    810   }
    811 }
    812 
    813 void DelegatedFrameHost::RemovingFromWindow() {
    814   RunOnCommitCallbacks();
    815   resize_lock_.reset();
    816   client_->GetHost()->WasResized();
    817   ui::Compositor* compositor = client_->GetCompositor();
    818   if (compositor && compositor->HasObserver(this))
    819     compositor->RemoveObserver(this);
    820 
    821   if (vsync_manager_) {
    822     vsync_manager_->RemoveObserver(this);
    823     vsync_manager_ = NULL;
    824   }
    825 }
    826 
    827 void DelegatedFrameHost::LockResources() {
    828   DCHECK(frame_provider_);
    829   delegated_frame_evictor_->LockFrame();
    830 }
    831 
    832 void DelegatedFrameHost::UnlockResources() {
    833   DCHECK(frame_provider_);
    834   delegated_frame_evictor_->UnlockFrame();
    835 }
    836 
    837 ////////////////////////////////////////////////////////////////////////////////
    838 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
    839 
    840 void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
    841                                                 ui::Layer* new_layer) {
    842   // The new_layer is the one that will be used by our Window, so that's the one
    843   // that should keep our frame. old_layer will be returned to the
    844   // RecreateLayer caller, and should have a copy.
    845   if (frame_provider_.get()) {
    846     new_layer->SetShowDelegatedContent(frame_provider_.get(),
    847                                        current_frame_size_in_dip_);
    848   }
    849 }
    850 
    851 }  // namespace content
    852 
    853