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_impl.h"
16 #include "cc/trees/layer_tree_impl.h"
17 #include "cc/trees/occlusion.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 media::VideoRotation video_rotation
) {
33 DCHECK(tree_impl
->proxy()->IsMainThreadBlocked());
34 DCHECK(tree_impl
->proxy()->IsImplThread());
36 scoped_refptr
<VideoFrameProviderClientImpl
> provider_client_impl
=
37 VideoFrameProviderClientImpl::Create(provider
);
39 return make_scoped_ptr(
40 new VideoLayerImpl(tree_impl
, id
, provider_client_impl
, video_rotation
));
43 VideoLayerImpl::VideoLayerImpl(
44 LayerTreeImpl
* tree_impl
,
46 const scoped_refptr
<VideoFrameProviderClientImpl
>& provider_client_impl
,
47 media::VideoRotation video_rotation
)
48 : LayerImpl(tree_impl
, id
),
49 provider_client_impl_(provider_client_impl
),
51 video_rotation_(video_rotation
) {
54 VideoLayerImpl::~VideoLayerImpl() {
55 if (!provider_client_impl_
->Stopped()) {
56 // In impl side painting, we may have a pending and active layer
57 // associated with the video provider at the same time. Both have a ref
58 // on the VideoFrameProviderClientImpl, but we stop when the first
59 // LayerImpl (the one on the pending tree) is destroyed since we know
60 // the main thread is blocked for this commit.
61 DCHECK(layer_tree_impl()->proxy()->IsImplThread());
62 DCHECK(layer_tree_impl()->proxy()->IsMainThreadBlocked());
63 provider_client_impl_
->Stop();
67 scoped_ptr
<LayerImpl
> VideoLayerImpl::CreateLayerImpl(
68 LayerTreeImpl
* tree_impl
) {
69 return make_scoped_ptr(new VideoLayerImpl(
70 tree_impl
, id(), provider_client_impl_
, video_rotation_
));
73 void VideoLayerImpl::DidBecomeActive() {
74 provider_client_impl_
->SetActiveVideoLayer(this);
77 bool VideoLayerImpl::WillDraw(DrawMode draw_mode
,
78 ResourceProvider
* resource_provider
) {
79 if (draw_mode
== DRAW_MODE_RESOURCELESS_SOFTWARE
)
82 // Explicitly acquire and release the provider mutex so it can be held from
83 // WillDraw to DidDraw. Since the compositor thread is in the middle of
84 // drawing, the layer will not be destroyed before DidDraw is called.
85 // Therefore, the only thing that will prevent this lock from being released
86 // is the GPU process locking it. As the GPU process can't cause the
87 // destruction of the provider (calling StopUsingProvider), holding this
88 // lock should not cause a deadlock.
89 frame_
= provider_client_impl_
->AcquireLockAndCurrentFrame();
92 // Drop any resources used by the updater if there is no frame to display.
95 provider_client_impl_
->ReleaseLock();
99 if (!LayerImpl::WillDraw(draw_mode
, resource_provider
))
104 new VideoResourceUpdater(layer_tree_impl()->context_provider(),
105 layer_tree_impl()->resource_provider()));
108 VideoFrameExternalResources external_resources
=
109 updater_
->CreateExternalResourcesFromVideoFrame(frame_
);
110 frame_resource_type_
= external_resources
.type
;
112 if (external_resources
.type
==
113 VideoFrameExternalResources::SOFTWARE_RESOURCE
) {
114 software_resources_
= external_resources
.software_resources
;
115 software_release_callback_
=
116 external_resources
.software_release_callback
;
120 DCHECK_EQ(external_resources
.mailboxes
.size(),
121 external_resources
.release_callbacks
.size());
122 for (size_t i
= 0; i
< external_resources
.mailboxes
.size(); ++i
) {
123 unsigned resource_id
= resource_provider
->CreateResourceFromTextureMailbox(
124 external_resources
.mailboxes
[i
],
125 SingleReleaseCallbackImpl::Create(
126 external_resources
.release_callbacks
[i
]));
127 frame_resources_
.push_back(resource_id
);
133 void VideoLayerImpl::AppendQuads(RenderPass
* render_pass
,
134 AppendQuadsData
* append_quads_data
) {
135 DCHECK(frame_
.get());
137 gfx::Transform transform
= draw_transform();
138 gfx::Size rotated_size
= content_bounds();
140 switch (video_rotation_
) {
141 case media::VIDEO_ROTATION_90
:
142 rotated_size
= gfx::Size(rotated_size
.height(), rotated_size
.width());
143 transform
.Rotate(90.0);
144 transform
.Translate(0.0, -rotated_size
.height());
146 case media::VIDEO_ROTATION_180
:
147 transform
.Rotate(180.0);
148 transform
.Translate(-rotated_size
.width(), -rotated_size
.height());
150 case media::VIDEO_ROTATION_270
:
151 rotated_size
= gfx::Size(rotated_size
.height(), rotated_size
.width());
152 transform
.Rotate(270.0);
153 transform
.Translate(-rotated_size
.width(), 0);
154 case media::VIDEO_ROTATION_0
:
158 SharedQuadState
* shared_quad_state
=
159 render_pass
->CreateAndAppendSharedQuadState();
160 shared_quad_state
->SetAll(transform
, rotated_size
, visible_content_rect(),
161 clip_rect(), is_clipped(), draw_opacity(),
162 draw_blend_mode(), sorting_context_id());
164 AppendDebugBorderQuad(
165 render_pass
, rotated_size
, shared_quad_state
, append_quads_data
);
167 gfx::Rect
quad_rect(rotated_size
);
168 gfx::Rect
opaque_rect(contents_opaque() ? quad_rect
: gfx::Rect());
169 gfx::Rect visible_rect
= frame_
->visible_rect();
170 gfx::Size coded_size
= frame_
->coded_size();
172 Occlusion occlusion_in_video_space
=
174 .occlusion_in_content_space
.GetOcclusionWithGivenDrawTransform(
176 gfx::Rect visible_quad_rect
=
177 occlusion_in_video_space
.GetUnoccludedContentRect(quad_rect
);
178 if (visible_quad_rect
.IsEmpty())
181 // Pixels for macroblocked formats.
182 const float tex_width_scale
=
183 static_cast<float>(visible_rect
.width()) / coded_size
.width();
184 const float tex_height_scale
=
185 static_cast<float>(visible_rect
.height()) / coded_size
.height();
186 const float tex_x_offset
=
187 static_cast<float>(visible_rect
.x()) / coded_size
.width();
188 const float tex_y_offset
=
189 static_cast<float>(visible_rect
.y()) / coded_size
.height();
191 switch (frame_resource_type_
) {
192 // TODO(danakj): Remove this, hide it in the hardware path.
193 case VideoFrameExternalResources::SOFTWARE_RESOURCE
: {
194 DCHECK_EQ(frame_resources_
.size(), 0u);
195 DCHECK_EQ(software_resources_
.size(), 1u);
196 if (software_resources_
.size() < 1u)
198 bool premultiplied_alpha
= true;
199 gfx::PointF
uv_top_left(0.f
, 0.f
);
200 gfx::PointF
uv_bottom_right(tex_width_scale
, tex_height_scale
);
201 float opacity
[] = {1.0f
, 1.0f
, 1.0f
, 1.0f
};
202 bool flipped
= false;
203 bool nearest_neighbor
= false;
204 // TODO(danakj): crbug.com/455931
205 layer_tree_impl()->resource_provider()->ValidateResource(
206 software_resources_
[0]);
207 TextureDrawQuad
* texture_quad
=
208 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
209 texture_quad
->SetNew(shared_quad_state
,
213 software_resources_
[0],
223 case VideoFrameExternalResources::YUV_RESOURCE
: {
224 DCHECK_GE(frame_resources_
.size(), 3u);
225 if (frame_resources_
.size() < 3u)
227 YUVVideoDrawQuad::ColorSpace color_space
= YUVVideoDrawQuad::REC_601
;
228 if (frame_
->format() == media::VideoFrame::YV12J
) {
229 color_space
= YUVVideoDrawQuad::JPEG
;
230 } else if (frame_
->format() == media::VideoFrame::YV12HD
) {
231 color_space
= YUVVideoDrawQuad::REC_709
;
234 const gfx::Size ya_tex_size
= coded_size
;
235 const gfx::Size uv_tex_size
= media::VideoFrame::PlaneSize(
236 frame_
->format(), media::VideoFrame::kUPlane
, coded_size
);
237 DCHECK(uv_tex_size
==
238 media::VideoFrame::PlaneSize(
239 frame_
->format(), media::VideoFrame::kVPlane
, coded_size
));
240 if (frame_resources_
.size() > 3) {
241 DCHECK(ya_tex_size
==
242 media::VideoFrame::PlaneSize(
243 frame_
->format(), media::VideoFrame::kAPlane
, coded_size
));
246 // TODO(danakj): crbug.com/455931
247 layer_tree_impl()->resource_provider()->ValidateResource(
248 frame_resources_
[0]);
249 layer_tree_impl()->resource_provider()->ValidateResource(
250 frame_resources_
[1]);
251 layer_tree_impl()->resource_provider()->ValidateResource(
252 frame_resources_
[2]);
253 if (frame_resources_
.size() > 3) {
254 layer_tree_impl()->resource_provider()->ValidateResource(
255 frame_resources_
[3]);
257 gfx::RectF
tex_coord_rect(
258 tex_x_offset
, tex_y_offset
, tex_width_scale
, tex_height_scale
);
259 YUVVideoDrawQuad
* yuv_video_quad
=
260 render_pass
->CreateAndAppendDrawQuad
<YUVVideoDrawQuad
>();
261 yuv_video_quad
->SetNew(
262 shared_quad_state
, quad_rect
, opaque_rect
, visible_quad_rect
,
263 tex_coord_rect
, ya_tex_size
, uv_tex_size
, frame_resources_
[0],
264 frame_resources_
[1], frame_resources_
[2],
265 frame_resources_
.size() > 3 ? frame_resources_
[3] : 0, color_space
);
268 case VideoFrameExternalResources::RGB_RESOURCE
: {
269 DCHECK_EQ(frame_resources_
.size(), 1u);
270 if (frame_resources_
.size() < 1u)
272 bool premultiplied_alpha
= true;
273 gfx::PointF
uv_top_left(0.f
, 0.f
);
274 gfx::PointF
uv_bottom_right(tex_width_scale
, tex_height_scale
);
275 float opacity
[] = {1.0f
, 1.0f
, 1.0f
, 1.0f
};
276 bool flipped
= false;
277 bool nearest_neighbor
= false;
278 // TODO(danakj): crbug.com/455931
279 layer_tree_impl()->resource_provider()->ValidateResource(
280 frame_resources_
[0]);
281 TextureDrawQuad
* texture_quad
=
282 render_pass
->CreateAndAppendDrawQuad
<TextureDrawQuad
>();
283 texture_quad
->SetNew(shared_quad_state
,
297 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE
: {
298 DCHECK_EQ(frame_resources_
.size(), 1u);
299 if (frame_resources_
.size() < 1u)
301 // TODO(danakj): crbug.com/455931
302 layer_tree_impl()->resource_provider()->ValidateResource(
303 frame_resources_
[0]);
304 gfx::Transform scale
;
305 scale
.Scale(tex_width_scale
, tex_height_scale
);
306 StreamVideoDrawQuad
* stream_video_quad
=
307 render_pass
->CreateAndAppendDrawQuad
<StreamVideoDrawQuad
>();
308 stream_video_quad
->SetNew(
309 shared_quad_state
, quad_rect
, opaque_rect
, visible_quad_rect
,
311 scale
* provider_client_impl_
->StreamTextureMatrix());
314 case VideoFrameExternalResources::IO_SURFACE
: {
315 DCHECK_EQ(frame_resources_
.size(), 1u);
316 if (frame_resources_
.size() < 1u)
318 // TODO(danakj): crbug.com/455931
319 layer_tree_impl()->resource_provider()->ValidateResource(
320 frame_resources_
[0]);
321 IOSurfaceDrawQuad
* io_surface_quad
=
322 render_pass
->CreateAndAppendDrawQuad
<IOSurfaceDrawQuad
>();
323 io_surface_quad
->SetNew(shared_quad_state
,
329 IOSurfaceDrawQuad::UNFLIPPED
);
332 #if defined(VIDEO_HOLE)
333 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
334 // maintained by the general compositor team. Please contact the following
337 // wonsik@chromium.org
339 case VideoFrameExternalResources::HOLE
: {
340 DCHECK_EQ(frame_resources_
.size(), 0u);
341 SolidColorDrawQuad
* solid_color_draw_quad
=
342 render_pass
->CreateAndAppendDrawQuad
<SolidColorDrawQuad
>();
344 // Create a solid color quad with transparent black and force no
345 // blending / no anti-aliasing.
346 gfx::Rect opaque_rect
= quad_rect
;
347 solid_color_draw_quad
->SetAll(shared_quad_state
,
356 #endif // defined(VIDEO_HOLE)
357 case VideoFrameExternalResources::NONE
:
363 void VideoLayerImpl::DidDraw(ResourceProvider
* resource_provider
) {
364 LayerImpl::DidDraw(resource_provider
);
366 DCHECK(frame_
.get());
368 if (frame_resource_type_
==
369 VideoFrameExternalResources::SOFTWARE_RESOURCE
) {
370 for (size_t i
= 0; i
< software_resources_
.size(); ++i
) {
371 software_release_callback_
.Run(
372 0, false, layer_tree_impl()->BlockingMainThreadTaskRunner());
375 software_resources_
.clear();
376 software_release_callback_
.Reset();
378 for (size_t i
= 0; i
< frame_resources_
.size(); ++i
)
379 resource_provider
->DeleteResource(frame_resources_
[i
]);
380 frame_resources_
.clear();
383 provider_client_impl_
->PutCurrentFrame(frame_
);
386 provider_client_impl_
->ReleaseLock();
389 void VideoLayerImpl::ReleaseResources() {
393 void VideoLayerImpl::SetNeedsRedraw() {
394 SetUpdateRect(gfx::UnionRects(update_rect(), gfx::Rect(bounds())));
395 layer_tree_impl()->SetNeedsRedraw();
398 const char* VideoLayerImpl::LayerTypeAsString() const {
399 return "cc::VideoLayerImpl";