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