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