Home | History | Annotate | Download | only in layers
      1 // Copyright 2011 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 "cc/layers/video_layer_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "cc/layers/video_frame_provider_client_impl.h"
     10 #include "cc/quads/io_surface_draw_quad.h"
     11 #include "cc/quads/stream_video_draw_quad.h"
     12 #include "cc/quads/texture_draw_quad.h"
     13 #include "cc/quads/yuv_video_draw_quad.h"
     14 #include "cc/resources/resource_provider.h"
     15 #include "cc/resources/single_release_callback_impl.h"
     16 #include "cc/trees/layer_tree_impl.h"
     17 #include "cc/trees/occlusion_tracker.h"
     18 #include "cc/trees/proxy.h"
     19 #include "media/base/video_frame.h"
     20 
     21 #if defined(VIDEO_HOLE)
     22 #include "cc/quads/solid_color_draw_quad.h"
     23 #endif  // defined(VIDEO_HOLE)
     24 
     25 namespace cc {
     26 
     27 // static
     28 scoped_ptr<VideoLayerImpl> VideoLayerImpl::Create(
     29     LayerTreeImpl* tree_impl,
     30     int id,
     31     VideoFrameProvider* provider,
     32     media::VideoRotation video_rotation) {
     33   scoped_ptr<VideoLayerImpl> layer(
     34       new VideoLayerImpl(tree_impl, id, video_rotation));
     35   layer->SetProviderClientImpl(VideoFrameProviderClientImpl::Create(provider));
     36   DCHECK(tree_impl->proxy()->IsImplThread());
     37   DCHECK(tree_impl->proxy()->IsMainThreadBlocked());
     38   return layer.Pass();
     39 }
     40 
     41 VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl,
     42                                int id,
     43                                media::VideoRotation video_rotation)
     44     : LayerImpl(tree_impl, id), frame_(NULL), video_rotation_(video_rotation) {
     45 }
     46 
     47 VideoLayerImpl::~VideoLayerImpl() {
     48   if (!provider_client_impl_->Stopped()) {
     49     // In impl side painting, we may have a pending and active layer
     50     // associated with the video provider at the same time. Both have a ref
     51     // on the VideoFrameProviderClientImpl, but we stop when the first
     52     // LayerImpl (the one on the pending tree) is destroyed since we know
     53     // the main thread is blocked for this commit.
     54     DCHECK(layer_tree_impl()->proxy()->IsImplThread());
     55     DCHECK(layer_tree_impl()->proxy()->IsMainThreadBlocked());
     56     provider_client_impl_->Stop();
     57   }
     58 }
     59 
     60 scoped_ptr<LayerImpl> VideoLayerImpl::CreateLayerImpl(
     61     LayerTreeImpl* tree_impl) {
     62   VideoLayerImpl* impl = new VideoLayerImpl(tree_impl, id(), video_rotation_);
     63   return scoped_ptr<LayerImpl>(impl);
     64 }
     65 
     66 void VideoLayerImpl::PushPropertiesTo(LayerImpl* layer) {
     67   LayerImpl::PushPropertiesTo(layer);
     68 
     69   VideoLayerImpl* other = static_cast<VideoLayerImpl*>(layer);
     70   other->SetProviderClientImpl(provider_client_impl_);
     71 }
     72 
     73 void VideoLayerImpl::DidBecomeActive() {
     74   provider_client_impl_->set_active_video_layer(this);
     75 }
     76 
     77 bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
     78                               ResourceProvider* resource_provider) {
     79   if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
     80     return false;
     81 
     82   // Explicitly acquire and release the provider mutex so it can be held from
     83   // WillDraw to DidDraw. Since the compositor thread is in the middle of
     84   // drawing, the layer will not be destroyed before DidDraw is called.
     85   // Therefore, the only thing that will prevent this lock from being released
     86   // is the GPU process locking it. As the GPU process can't cause the
     87   // destruction of the provider (calling StopUsingProvider), holding this
     88   // lock should not cause a deadlock.
     89   frame_ = provider_client_impl_->AcquireLockAndCurrentFrame();
     90 
     91   if (!frame_.get()) {
     92     // Drop any resources used by the updater if there is no frame to display.
     93     updater_.reset();
     94 
     95     provider_client_impl_->ReleaseLock();
     96     return false;
     97   }
     98 
     99   if (!LayerImpl::WillDraw(draw_mode, resource_provider))
    100     return false;
    101 
    102   if (!updater_) {
    103     updater_.reset(
    104         new VideoResourceUpdater(layer_tree_impl()->context_provider(),
    105                                  layer_tree_impl()->resource_provider()));
    106   }
    107 
    108   VideoFrameExternalResources external_resources =
    109       updater_->CreateExternalResourcesFromVideoFrame(frame_);
    110   frame_resource_type_ = external_resources.type;
    111 
    112   if (external_resources.type ==
    113       VideoFrameExternalResources::SOFTWARE_RESOURCE) {
    114     software_resources_ = external_resources.software_resources;
    115     software_release_callback_ =
    116         external_resources.software_release_callback;
    117     return true;
    118   }
    119 
    120   DCHECK_EQ(external_resources.mailboxes.size(),
    121             external_resources.release_callbacks.size());
    122   for (size_t i = 0; i < external_resources.mailboxes.size(); ++i) {
    123     unsigned resource_id = resource_provider->CreateResourceFromTextureMailbox(
    124         external_resources.mailboxes[i],
    125         SingleReleaseCallbackImpl::Create(
    126             external_resources.release_callbacks[i]));
    127     frame_resources_.push_back(resource_id);
    128   }
    129 
    130   return true;
    131 }
    132 
    133 void VideoLayerImpl::AppendQuads(
    134     RenderPass* render_pass,
    135     const OcclusionTracker<LayerImpl>& occlusion_tracker,
    136     AppendQuadsData* append_quads_data) {
    137   DCHECK(frame_.get());
    138 
    139   gfx::Transform transform = draw_transform();
    140   gfx::Size rotated_size = content_bounds();
    141 
    142   switch (video_rotation_) {
    143     case media::VIDEO_ROTATION_90:
    144       rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
    145       transform.Rotate(90.0);
    146       transform.Translate(0.0, -rotated_size.height());
    147       break;
    148     case media::VIDEO_ROTATION_180:
    149       transform.Rotate(180.0);
    150       transform.Translate(-rotated_size.width(), -rotated_size.height());
    151       break;
    152     case media::VIDEO_ROTATION_270:
    153       rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
    154       transform.Rotate(270.0);
    155       transform.Translate(-rotated_size.width(), 0);
    156     case media::VIDEO_ROTATION_0:
    157       break;
    158   }
    159 
    160   SharedQuadState* shared_quad_state =
    161       render_pass->CreateAndAppendSharedQuadState();
    162   shared_quad_state->SetAll(transform,
    163                             rotated_size,
    164                             visible_content_rect(),
    165                             clip_rect(),
    166                             is_clipped(),
    167                             draw_opacity(),
    168                             blend_mode(),
    169                             sorting_context_id());
    170 
    171   AppendDebugBorderQuad(
    172       render_pass, rotated_size, shared_quad_state, append_quads_data);
    173 
    174   gfx::Rect quad_rect(rotated_size);
    175   gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
    176   gfx::Rect visible_rect = frame_->visible_rect();
    177   gfx::Size coded_size = frame_->coded_size();
    178 
    179   gfx::Rect visible_quad_rect =
    180       occlusion_tracker.GetCurrentOcclusionForLayer(transform)
    181           .GetUnoccludedContentRect(quad_rect);
    182   if (visible_quad_rect.IsEmpty())
    183     return;
    184 
    185   // Pixels for macroblocked formats.
    186   const float tex_width_scale =
    187       static_cast<float>(visible_rect.width()) / coded_size.width();
    188   const float tex_height_scale =
    189       static_cast<float>(visible_rect.height()) / coded_size.height();
    190   const float tex_x_offset =
    191       static_cast<float>(visible_rect.x()) / coded_size.width();
    192   const float tex_y_offset =
    193       static_cast<float>(visible_rect.y()) / coded_size.height();
    194 
    195   switch (frame_resource_type_) {
    196     // TODO(danakj): Remove this, hide it in the hardware path.
    197     case VideoFrameExternalResources::SOFTWARE_RESOURCE: {
    198       DCHECK_EQ(frame_resources_.size(), 0u);
    199       DCHECK_EQ(software_resources_.size(), 1u);
    200       if (software_resources_.size() < 1u)
    201         break;
    202       bool premultiplied_alpha = true;
    203       gfx::PointF uv_top_left(0.f, 0.f);
    204       gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
    205       float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
    206       bool flipped = false;
    207       TextureDrawQuad* texture_quad =
    208           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
    209       texture_quad->SetNew(shared_quad_state,
    210                            quad_rect,
    211                            opaque_rect,
    212                            visible_quad_rect,
    213                            software_resources_[0],
    214                            premultiplied_alpha,
    215                            uv_top_left,
    216                            uv_bottom_right,
    217                            SK_ColorTRANSPARENT,
    218                            opacity,
    219                            flipped);
    220       break;
    221     }
    222     case VideoFrameExternalResources::YUV_RESOURCE: {
    223       DCHECK_GE(frame_resources_.size(), 3u);
    224       if (frame_resources_.size() < 3u)
    225         break;
    226       YUVVideoDrawQuad::ColorSpace color_space =
    227           frame_->format() == media::VideoFrame::YV12J
    228               ? YUVVideoDrawQuad::REC_601_JPEG
    229               : YUVVideoDrawQuad::REC_601;
    230       gfx::RectF tex_coord_rect(
    231           tex_x_offset, tex_y_offset, tex_width_scale, tex_height_scale);
    232       YUVVideoDrawQuad* yuv_video_quad =
    233           render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
    234       yuv_video_quad->SetNew(
    235           shared_quad_state,
    236           quad_rect,
    237           opaque_rect,
    238           visible_quad_rect,
    239           tex_coord_rect,
    240           frame_resources_[0],
    241           frame_resources_[1],
    242           frame_resources_[2],
    243           frame_resources_.size() > 3 ? frame_resources_[3] : 0,
    244           color_space);
    245       break;
    246     }
    247     case VideoFrameExternalResources::RGB_RESOURCE: {
    248       DCHECK_EQ(frame_resources_.size(), 1u);
    249       if (frame_resources_.size() < 1u)
    250         break;
    251       bool premultiplied_alpha = true;
    252       gfx::PointF uv_top_left(0.f, 0.f);
    253       gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
    254       float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
    255       bool flipped = false;
    256       TextureDrawQuad* texture_quad =
    257           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
    258       texture_quad->SetNew(shared_quad_state,
    259                            quad_rect,
    260                            opaque_rect,
    261                            visible_quad_rect,
    262                            frame_resources_[0],
    263                            premultiplied_alpha,
    264                            uv_top_left,
    265                            uv_bottom_right,
    266                            SK_ColorTRANSPARENT,
    267                            opacity,
    268                            flipped);
    269       break;
    270     }
    271     case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
    272       DCHECK_EQ(frame_resources_.size(), 1u);
    273       if (frame_resources_.size() < 1u)
    274         break;
    275       gfx::Transform scale;
    276       scale.Scale(tex_width_scale, tex_height_scale);
    277       StreamVideoDrawQuad* stream_video_quad =
    278           render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
    279       stream_video_quad->SetNew(
    280           shared_quad_state,
    281           quad_rect,
    282           opaque_rect,
    283           visible_quad_rect,
    284           frame_resources_[0],
    285           scale * provider_client_impl_->stream_texture_matrix());
    286       break;
    287     }
    288     case VideoFrameExternalResources::IO_SURFACE: {
    289       DCHECK_EQ(frame_resources_.size(), 1u);
    290       if (frame_resources_.size() < 1u)
    291         break;
    292       IOSurfaceDrawQuad* io_surface_quad =
    293           render_pass->CreateAndAppendDrawQuad<IOSurfaceDrawQuad>();
    294       io_surface_quad->SetNew(shared_quad_state,
    295                               quad_rect,
    296                               opaque_rect,
    297                               visible_quad_rect,
    298                               visible_rect.size(),
    299                               frame_resources_[0],
    300                               IOSurfaceDrawQuad::UNFLIPPED);
    301       break;
    302     }
    303 #if defined(VIDEO_HOLE)
    304     // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
    305     // maintained by the general compositor team. Please contact the following
    306     // people instead:
    307     //
    308     // wonsik (at) chromium.org
    309     // ycheo (at) chromium.org
    310     case VideoFrameExternalResources::HOLE: {
    311       DCHECK_EQ(frame_resources_.size(), 0u);
    312       SolidColorDrawQuad* solid_color_draw_quad =
    313           render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
    314 
    315       // Create a solid color quad with transparent black and force no
    316       // blending / no anti-aliasing.
    317       gfx::Rect opaque_rect = quad_rect;
    318       solid_color_draw_quad->SetAll(shared_quad_state,
    319                                     quad_rect,
    320                                     opaque_rect,
    321                                     visible_quad_rect,
    322                                     false,
    323                                     SK_ColorTRANSPARENT,
    324                                     true);
    325       break;
    326     }
    327 #endif  // defined(VIDEO_HOLE)
    328     case VideoFrameExternalResources::NONE:
    329       NOTIMPLEMENTED();
    330       break;
    331   }
    332 }
    333 
    334 void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {
    335   LayerImpl::DidDraw(resource_provider);
    336 
    337   DCHECK(frame_.get());
    338 
    339   if (frame_resource_type_ ==
    340       VideoFrameExternalResources::SOFTWARE_RESOURCE) {
    341     for (size_t i = 0; i < software_resources_.size(); ++i) {
    342       software_release_callback_.Run(
    343           0, false, layer_tree_impl()->BlockingMainThreadTaskRunner());
    344     }
    345 
    346     software_resources_.clear();
    347     software_release_callback_.Reset();
    348   } else {
    349     for (size_t i = 0; i < frame_resources_.size(); ++i)
    350       resource_provider->DeleteResource(frame_resources_[i]);
    351     frame_resources_.clear();
    352   }
    353 
    354   provider_client_impl_->PutCurrentFrame(frame_);
    355   frame_ = NULL;
    356 
    357   provider_client_impl_->ReleaseLock();
    358 }
    359 
    360 void VideoLayerImpl::ReleaseResources() {
    361   updater_.reset();
    362 }
    363 
    364 void VideoLayerImpl::SetNeedsRedraw() {
    365   SetUpdateRect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
    366   layer_tree_impl()->SetNeedsRedraw();
    367 }
    368 
    369 void VideoLayerImpl::SetProviderClientImpl(
    370     scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) {
    371   provider_client_impl_ = provider_client_impl;
    372 }
    373 
    374 const char* VideoLayerImpl::LayerTypeAsString() const {
    375   return "cc::VideoLayerImpl";
    376 }
    377 
    378 }  // namespace cc
    379