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.
5 #include "cc/layers/video_layer_impl.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"
20 #if defined(GOOGLE_TV)
21 #include "cc/quads/solid_color_draw_quad.h"
27 scoped_ptr
<VideoLayerImpl
> VideoLayerImpl::Create(
28 LayerTreeImpl
* tree_impl
,
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());
38 VideoLayerImpl::VideoLayerImpl(LayerTreeImpl
* tree_impl
, int id
)
39 : LayerImpl(tree_impl
, id
),
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();
55 scoped_ptr
<LayerImpl
> VideoLayerImpl::CreateLayerImpl(
56 LayerTreeImpl
* tree_impl
) {
57 return scoped_ptr
<LayerImpl
>(new VideoLayerImpl(tree_impl
, id()));
60 void VideoLayerImpl::PushPropertiesTo(LayerImpl
* layer
) {
61 LayerImpl::PushPropertiesTo(layer
);
63 VideoLayerImpl
* other
= static_cast<VideoLayerImpl
*>(layer
);
64 other
->SetProviderClientImpl(provider_client_impl_
);
67 void VideoLayerImpl::DidBecomeActive() {
68 provider_client_impl_
->set_active_video_layer(this);
71 bool VideoLayerImpl::WillDraw(DrawMode draw_mode
,
72 ResourceProvider
* resource_provider
) {
73 if (draw_mode
== DRAW_MODE_RESOURCELESS_SOFTWARE
)
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();
86 // Drop any resources used by the updater if there is no frame to display.
89 provider_client_impl_
->ReleaseLock();
93 if (!LayerImpl::WillDraw(draw_mode
, resource_provider
))
98 new VideoResourceUpdater(layer_tree_impl()->context_provider(),
99 layer_tree_impl()->resource_provider()));
102 VideoFrameExternalResources external_resources
=
103 updater_
->CreateExternalResourcesFromVideoFrame(frame_
);
104 frame_resource_type_
= external_resources
.type
;
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
;
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
]));
123 void VideoLayerImpl::AppendQuads(QuadSink
* quad_sink
,
124 AppendQuadsData
* append_quads_data
) {
125 DCHECK(frame_
.get());
127 SharedQuadState
* shared_quad_state
=
128 quad_sink
->UseSharedQuadState(CreateSharedQuadState());
129 AppendDebugBorderQuad(quad_sink
, shared_quad_state
, append_quads_data
);
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();
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();
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)
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
,
158 software_resources_
[0],
165 quad_sink
->Append(texture_quad
.PassAs
<DrawQuad
>(), append_quads_data
);
168 case VideoFrameExternalResources::YUV_RESOURCE
: {
169 DCHECK_GE(frame_resources_
.size(), 3u);
170 if (frame_resources_
.size() < 3u)
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
,
181 frame_resources_
.size() > 3 ?
182 frame_resources_
[3] : 0);
183 quad_sink
->Append(yuv_video_quad
.PassAs
<DrawQuad
>(), append_quads_data
);
186 case VideoFrameExternalResources::RGB_RESOURCE
: {
187 DCHECK_EQ(frame_resources_
.size(), 1u);
188 if (frame_resources_
.size() < 1u)
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
,
206 quad_sink
->Append(texture_quad
.PassAs
<DrawQuad
>(), append_quads_data
);
209 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE
: {
210 DCHECK_EQ(frame_resources_
.size(), 1u);
211 if (frame_resources_
.size() < 1u)
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
,
223 quad_sink
->Append(stream_video_quad
.PassAs
<DrawQuad
>(),
227 case VideoFrameExternalResources::IO_SURFACE
: {
228 DCHECK_EQ(frame_resources_
.size(), 1u);
229 if (frame_resources_
.size() < 1u)
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
,
239 IOSurfaceDrawQuad::UNFLIPPED
);
240 quad_sink
->Append(io_surface_quad
.PassAs
<DrawQuad
>(),
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
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();
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
>(),
266 case VideoFrameExternalResources::NONE
:
272 void VideoLayerImpl::DidDraw(ResourceProvider
* resource_provider
) {
273 LayerImpl::DidDraw(resource_provider
);
275 DCHECK(frame_
.get());
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);
282 software_resources_
.clear();
283 software_release_callback_
.Reset();
285 for (size_t i
= 0; i
< frame_resources_
.size(); ++i
)
286 resource_provider
->DeleteResource(frame_resources_
[i
]);
287 frame_resources_
.clear();
290 provider_client_impl_
->PutCurrentFrame(frame_
);
293 provider_client_impl_
->ReleaseLock();
296 void VideoLayerImpl::DidLoseOutputSurface() {
300 void VideoLayerImpl::SetNeedsRedraw() {
301 set_update_rect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
302 layer_tree_impl()->SetNeedsRedraw();
305 void VideoLayerImpl::SetProviderClientImpl(
306 scoped_refptr
<VideoFrameProviderClientImpl
> provider_client_impl
) {
307 provider_client_impl_
= provider_client_impl
;
310 const char* VideoLayerImpl::LayerTypeAsString() const {
311 return "cc::VideoLayerImpl";