video_layer_impl.cc revision 3551c9c881056c480085172ff9840cab31610854
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
24namespace cc {
25
26// static
27scoped_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
38VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl, int id)
39    : LayerImpl(tree_impl, id),
40      frame_(NULL) {}
41
42VideoLayerImpl::~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
55scoped_ptr<LayerImpl> VideoLayerImpl::CreateLayerImpl(
56    LayerTreeImpl* tree_impl) {
57  return scoped_ptr<LayerImpl>(new VideoLayerImpl(tree_impl, id()));
58}
59
60void VideoLayerImpl::PushPropertiesTo(LayerImpl* layer) {
61  LayerImpl::PushPropertiesTo(layer);
62
63  VideoLayerImpl* other = static_cast<VideoLayerImpl*>(layer);
64  other->SetProviderClientImpl(provider_client_impl_);
65}
66
67void VideoLayerImpl::DidBecomeActive() {
68  provider_client_impl_->set_active_video_layer(this);
69}
70
71bool 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(
98        new VideoResourceUpdater(layer_tree_impl()->context_provider(),
99                                 layer_tree_impl()->resource_provider()));
100  }
101
102  VideoFrameExternalResources external_resources =
103      updater_->CreateExternalResourcesFromVideoFrame(frame_);
104  frame_resource_type_ = external_resources.type;
105
106  if (external_resources.type ==
107      VideoFrameExternalResources::SOFTWARE_RESOURCE) {
108    software_resources_ = external_resources.software_resources;
109    software_release_callback_ =
110        external_resources.software_release_callback;
111    return true;
112  }
113
114  for (size_t i = 0; i < external_resources.mailboxes.size(); ++i) {
115    frame_resources_.push_back(
116        resource_provider->CreateResourceFromTextureMailbox(
117            external_resources.mailboxes[i]));
118  }
119
120  return true;
121}
122
123void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
124                                 AppendQuadsData* append_quads_data) {
125  DCHECK(frame_.get());
126
127  SharedQuadState* shared_quad_state =
128      quad_sink->UseSharedQuadState(CreateSharedQuadState());
129  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
130
131  gfx::Rect quad_rect(content_bounds());
132  gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
133  gfx::Rect visible_rect = frame_->visible_rect();
134  gfx::Size coded_size = frame_->coded_size();
135
136  // Pixels for macroblocked formats.
137  float tex_width_scale =
138      static_cast<float>(visible_rect.width()) / coded_size.width();
139  float tex_height_scale =
140      static_cast<float>(visible_rect.height()) / coded_size.height();
141
142  switch (frame_resource_type_) {
143    // TODO(danakj): Remove this, hide it in the hardware path.
144    case VideoFrameExternalResources::SOFTWARE_RESOURCE: {
145      DCHECK_EQ(frame_resources_.size(), 0u);
146      DCHECK_EQ(software_resources_.size(), 1u);
147      if (software_resources_.size() < 1u)
148        break;
149      bool premultiplied_alpha = true;
150      gfx::PointF uv_top_left(0.f, 0.f);
151      gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
152      float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
153      bool flipped = false;
154      scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create();
155      texture_quad->SetNew(shared_quad_state,
156                           quad_rect,
157                           opaque_rect,
158                           software_resources_[0],
159                           premultiplied_alpha,
160                           uv_top_left,
161                           uv_bottom_right,
162                           SK_ColorTRANSPARENT,
163                           opacity,
164                           flipped);
165      quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data);
166      break;
167    }
168    case VideoFrameExternalResources::YUV_RESOURCE: {
169      DCHECK_GE(frame_resources_.size(), 3u);
170      if (frame_resources_.size() < 3u)
171        break;
172      gfx::SizeF tex_scale(tex_width_scale, tex_height_scale);
173      scoped_ptr<YUVVideoDrawQuad> yuv_video_quad = YUVVideoDrawQuad::Create();
174      yuv_video_quad->SetNew(shared_quad_state,
175                             quad_rect,
176                             opaque_rect,
177                             tex_scale,
178                             frame_resources_[0],
179                             frame_resources_[1],
180                             frame_resources_[2],
181                             frame_resources_.size() > 3 ?
182                                 frame_resources_[3] : 0);
183      quad_sink->Append(yuv_video_quad.PassAs<DrawQuad>(), append_quads_data);
184      break;
185    }
186    case VideoFrameExternalResources::RGB_RESOURCE: {
187      DCHECK_EQ(frame_resources_.size(), 1u);
188      if (frame_resources_.size() < 1u)
189        break;
190      bool premultiplied_alpha = true;
191      gfx::PointF uv_top_left(0.f, 0.f);
192      gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
193      float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
194      bool flipped = false;
195      scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create();
196      texture_quad->SetNew(shared_quad_state,
197                           quad_rect,
198                           opaque_rect,
199                           frame_resources_[0],
200                           premultiplied_alpha,
201                           uv_top_left,
202                           uv_bottom_right,
203                           SK_ColorTRANSPARENT,
204                           opacity,
205                           flipped);
206      quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data);
207      break;
208    }
209    case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
210      DCHECK_EQ(frame_resources_.size(), 1u);
211      if (frame_resources_.size() < 1u)
212        break;
213      gfx::Transform transform(
214          provider_client_impl_->stream_texture_matrix());
215      transform.Scale(tex_width_scale, tex_height_scale);
216      scoped_ptr<StreamVideoDrawQuad> stream_video_quad =
217          StreamVideoDrawQuad::Create();
218      stream_video_quad->SetNew(shared_quad_state,
219                                quad_rect,
220                                opaque_rect,
221                                frame_resources_[0],
222                                transform);
223      quad_sink->Append(stream_video_quad.PassAs<DrawQuad>(),
224                        append_quads_data);
225      break;
226    }
227    case VideoFrameExternalResources::IO_SURFACE: {
228      DCHECK_EQ(frame_resources_.size(), 1u);
229      if (frame_resources_.size() < 1u)
230        break;
231      gfx::Size visible_size(visible_rect.width(), visible_rect.height());
232      scoped_ptr<IOSurfaceDrawQuad> io_surface_quad =
233          IOSurfaceDrawQuad::Create();
234      io_surface_quad->SetNew(shared_quad_state,
235                              quad_rect,
236                              opaque_rect,
237                              visible_size,
238                              frame_resources_[0],
239                              IOSurfaceDrawQuad::UNFLIPPED);
240      quad_sink->Append(io_surface_quad.PassAs<DrawQuad>(),
241                        append_quads_data);
242      break;
243    }
244#if defined(GOOGLE_TV)
245    // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
246    // maintained by the general compositor team. Please contact the following
247    // people instead:
248    //
249    // wonsik@chromium.org
250    // ycheo@chromium.org
251    case VideoFrameExternalResources::HOLE: {
252      DCHECK_EQ(frame_resources_.size(), 0u);
253      scoped_ptr<SolidColorDrawQuad> solid_color_draw_quad =
254          SolidColorDrawQuad::Create();
255
256      // Create a solid color quad with transparent black and force no
257      // blending / no anti-aliasing.
258      solid_color_draw_quad->SetAll(
259          shared_quad_state, quad_rect, quad_rect, quad_rect, false,
260          SK_ColorTRANSPARENT, true);
261      quad_sink->Append(solid_color_draw_quad.PassAs<DrawQuad>(),
262                        append_quads_data);
263      break;
264    }
265#endif
266    case VideoFrameExternalResources::NONE:
267      NOTIMPLEMENTED();
268      break;
269  }
270}
271
272void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {
273  LayerImpl::DidDraw(resource_provider);
274
275  DCHECK(frame_.get());
276
277  if (frame_resource_type_ ==
278      VideoFrameExternalResources::SOFTWARE_RESOURCE) {
279    for (size_t i = 0; i < software_resources_.size(); ++i)
280      software_release_callback_.Run(0, false);
281
282    software_resources_.clear();
283    software_release_callback_.Reset();
284  } else {
285    for (size_t i = 0; i < frame_resources_.size(); ++i)
286      resource_provider->DeleteResource(frame_resources_[i]);
287    frame_resources_.clear();
288  }
289
290  provider_client_impl_->PutCurrentFrame(frame_);
291  frame_ = NULL;
292
293  provider_client_impl_->ReleaseLock();
294}
295
296void VideoLayerImpl::DidLoseOutputSurface() {
297  updater_.reset();
298}
299
300void VideoLayerImpl::SetNeedsRedraw() {
301  set_update_rect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
302  layer_tree_impl()->SetNeedsRedraw();
303}
304
305void VideoLayerImpl::SetProviderClientImpl(
306    scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) {
307  provider_client_impl_ = provider_client_impl;
308}
309
310const char* VideoLayerImpl::LayerTypeAsString() const {
311  return "cc::VideoLayerImpl";
312}
313
314}  // namespace cc
315