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/video_frame_provider_client_impl.h"
10 #include "cc/quads/io_surface_draw_quad.h"
11 #include "cc/quads/stream_video_draw_quad.h"
12 #include "cc/quads/texture_draw_quad.h"
13 #include "cc/quads/yuv_video_draw_quad.h"
14 #include "cc/resources/resource_provider.h"
15 #include "cc/resources/single_release_callback.h"
16 #include "cc/trees/layer_tree_impl.h"
17 #include "cc/trees/occlusion_tracker.h"
18 #include "cc/trees/proxy.h"
19 #include "media/base/video_frame.h"
21 #if defined(VIDEO_HOLE)
22 #include "cc/quads/solid_color_draw_quad.h"
23 #endif // defined(VIDEO_HOLE)
28 scoped_ptr
<VideoLayerImpl
> VideoLayerImpl::Create(
29 LayerTreeImpl
* tree_impl
,
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());
39 VideoLayerImpl::VideoLayerImpl(LayerTreeImpl
* tree_impl
, int id
)
40 : LayerImpl(tree_impl
, id
),
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();
56 scoped_ptr
<LayerImpl
> VideoLayerImpl::CreateLayerImpl(
57 LayerTreeImpl
* tree_impl
) {
58 return scoped_ptr
<LayerImpl
>(new VideoLayerImpl(tree_impl
, id()));
61 void VideoLayerImpl::PushPropertiesTo(LayerImpl
* layer
) {
62 LayerImpl::PushPropertiesTo(layer
);
64 VideoLayerImpl
* other
= static_cast<VideoLayerImpl
*>(layer
);
65 other
->SetProviderClientImpl(provider_client_impl_
);
68 void VideoLayerImpl::DidBecomeActive() {
69 provider_client_impl_
->set_active_video_layer(this);
72 bool VideoLayerImpl::WillDraw(DrawMode draw_mode
,
73 ResourceProvider
* resource_provider
) {
74 if (draw_mode
== DRAW_MODE_RESOURCELESS_SOFTWARE
)
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();
87 // Drop any resources used by the updater if there is no frame to display.
90 provider_client_impl_
->ReleaseLock();
94 if (!LayerImpl::WillDraw(draw_mode
, resource_provider
))
99 new VideoResourceUpdater(layer_tree_impl()->context_provider(),
100 layer_tree_impl()->resource_provider()));
103 VideoFrameExternalResources external_resources
=
104 updater_
->CreateExternalResourcesFromVideoFrame(frame_
);
105 frame_resource_type_
= external_resources
.type
;
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
;
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
);
127 void VideoLayerImpl::AppendQuads(
128 RenderPass
* render_pass
,
129 const OcclusionTracker
<LayerImpl
>& occlusion_tracker
,
130 AppendQuadsData
* append_quads_data
) {
131 DCHECK(frame_
.get());
133 SharedQuadState
* shared_quad_state
=
134 render_pass
->CreateAndAppendSharedQuadState();
135 PopulateSharedQuadState(shared_quad_state
);
137 AppendDebugBorderQuad(
138 render_pass
, content_bounds(), shared_quad_state
, append_quads_data
);
140 gfx::Rect
quad_rect(content_bounds());
141 gfx::Rect
opaque_rect(contents_opaque() ? quad_rect
: gfx::Rect());
142 gfx::Rect visible_rect
= frame_
->visible_rect();
143 gfx::Size coded_size
= frame_
->coded_size();
145 gfx::Rect visible_quad_rect
= occlusion_tracker
.UnoccludedContentRect(
146 quad_rect
, draw_properties().target_space_transform
);
147 if (visible_quad_rect
.IsEmpty())
150 // Pixels for macroblocked formats.
151 const float tex_width_scale
=
152 static_cast<float>(visible_rect
.width()) / coded_size
.width();
153 const float tex_height_scale
=
154 static_cast<float>(visible_rect
.height()) / coded_size
.height();
155 const float tex_x_offset
=
156 static_cast<float>(visible_rect
.x()) / coded_size
.width();
157 const float tex_y_offset
=
158 static_cast<float>(visible_rect
.y()) / coded_size
.height();
160 switch (frame_resource_type_
) {
161 // TODO(danakj): Remove this, hide it in the hardware path.
162 case VideoFrameExternalResources::SOFTWARE_RESOURCE
: {
163 DCHECK_EQ(frame_resources_
.size(), 0u);
164 DCHECK_EQ(software_resources_
.size(), 1u);
165 if (software_resources_
.size() < 1u)
167 bool premultiplied_alpha
= true;
168 gfx::PointF
uv_top_left(0.f
, 0.f
);
169 gfx::PointF
uv_bottom_right(tex_width_scale
, tex_height_scale
);
170 float opacity
[] = {1.0f
, 1.0f
, 1.0f
, 1.0f
};
171 bool flipped
= false;
172 TextureDrawQuad
* texture_quad
=
173 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
174 texture_quad
->SetNew(shared_quad_state
,
178 software_resources_
[0],
187 case VideoFrameExternalResources::YUV_RESOURCE
: {
188 DCHECK_GE(frame_resources_
.size(), 3u);
189 if (frame_resources_
.size() < 3u)
191 YUVVideoDrawQuad::ColorSpace color_space
=
192 frame_
->format() == media::VideoFrame::YV12J
193 ? YUVVideoDrawQuad::REC_601_JPEG
194 : YUVVideoDrawQuad::REC_601
;
195 gfx::RectF
tex_coord_rect(
196 tex_x_offset
, tex_y_offset
, tex_width_scale
, tex_height_scale
);
197 YUVVideoDrawQuad
* yuv_video_quad
=
198 render_pass
->CreateAndAppendDrawQuad
<YUVVideoDrawQuad
>();
199 yuv_video_quad
->SetNew(
208 frame_resources_
.size() > 3 ? frame_resources_
[3] : 0,
212 case VideoFrameExternalResources::RGB_RESOURCE
: {
213 DCHECK_EQ(frame_resources_
.size(), 1u);
214 if (frame_resources_
.size() < 1u)
216 bool premultiplied_alpha
= true;
217 gfx::PointF
uv_top_left(0.f
, 0.f
);
218 gfx::PointF
uv_bottom_right(tex_width_scale
, tex_height_scale
);
219 float opacity
[] = {1.0f
, 1.0f
, 1.0f
, 1.0f
};
220 bool flipped
= false;
221 TextureDrawQuad
* texture_quad
=
222 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
223 texture_quad
->SetNew(shared_quad_state
,
236 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE
: {
237 DCHECK_EQ(frame_resources_
.size(), 1u);
238 if (frame_resources_
.size() < 1u)
240 gfx::Transform scale
;
241 scale
.Scale(tex_width_scale
, tex_height_scale
);
242 StreamVideoDrawQuad
* stream_video_quad
=
243 render_pass
->CreateAndAppendDrawQuad
<StreamVideoDrawQuad
>();
244 stream_video_quad
->SetNew(
250 scale
* provider_client_impl_
->stream_texture_matrix());
253 case VideoFrameExternalResources::IO_SURFACE
: {
254 DCHECK_EQ(frame_resources_
.size(), 1u);
255 if (frame_resources_
.size() < 1u)
257 IOSurfaceDrawQuad
* io_surface_quad
=
258 render_pass
->CreateAndAppendDrawQuad
<IOSurfaceDrawQuad
>();
259 io_surface_quad
->SetNew(shared_quad_state
,
265 IOSurfaceDrawQuad::UNFLIPPED
);
268 #if defined(VIDEO_HOLE)
269 // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
270 // maintained by the general compositor team. Please contact the following
273 // wonsik@chromium.org
274 // ycheo@chromium.org
275 case VideoFrameExternalResources::HOLE
: {
276 DCHECK_EQ(frame_resources_
.size(), 0u);
277 SolidColorDrawQuad
* solid_color_draw_quad
=
278 render_pass
->CreateAndAppendDrawQuad
<SolidColorDrawQuad
>();
280 // Create a solid color quad with transparent black and force no
281 // blending / no anti-aliasing.
282 gfx::Rect opaque_rect
= quad_rect
;
283 solid_color_draw_quad
->SetAll(shared_quad_state
,
292 #endif // defined(VIDEO_HOLE)
293 case VideoFrameExternalResources::NONE
:
299 void VideoLayerImpl::DidDraw(ResourceProvider
* resource_provider
) {
300 LayerImpl::DidDraw(resource_provider
);
302 DCHECK(frame_
.get());
304 if (frame_resource_type_
==
305 VideoFrameExternalResources::SOFTWARE_RESOURCE
) {
306 for (size_t i
= 0; i
< software_resources_
.size(); ++i
)
307 software_release_callback_
.Run(0, false);
309 software_resources_
.clear();
310 software_release_callback_
.Reset();
312 for (size_t i
= 0; i
< frame_resources_
.size(); ++i
)
313 resource_provider
->DeleteResource(frame_resources_
[i
]);
314 frame_resources_
.clear();
317 provider_client_impl_
->PutCurrentFrame(frame_
);
320 provider_client_impl_
->ReleaseLock();
323 void VideoLayerImpl::ReleaseResources() {
327 void VideoLayerImpl::SetNeedsRedraw() {
328 SetUpdateRect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
329 layer_tree_impl()->SetNeedsRedraw();
332 void VideoLayerImpl::SetProviderClientImpl(
333 scoped_refptr
<VideoFrameProviderClientImpl
> provider_client_impl
) {
334 provider_client_impl_
= provider_client_impl
;
337 const char* VideoLayerImpl::LayerTypeAsString() const {
338 return "cc::VideoLayerImpl";