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