Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / cc / layers / video_layer_impl.cc
blob3313aa5cfb1a7c2245f4de78854a6c10169ebf2a
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"
7 #include "base/bind.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)
25 namespace cc {
27 // static
28 scoped_ptr<VideoLayerImpl> VideoLayerImpl::Create(
29 LayerTreeImpl* tree_impl,
30 int id,
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(
38 provider, tree_impl->GetVideoFrameControllerClient());
40 return make_scoped_ptr(
41 new VideoLayerImpl(tree_impl, id, provider_client_impl, video_rotation));
44 VideoLayerImpl::VideoLayerImpl(
45 LayerTreeImpl* tree_impl,
46 int id,
47 const scoped_refptr<VideoFrameProviderClientImpl>& provider_client_impl,
48 media::VideoRotation video_rotation)
49 : LayerImpl(tree_impl, id),
50 provider_client_impl_(provider_client_impl),
51 frame_(nullptr),
52 video_rotation_(video_rotation) {
55 VideoLayerImpl::~VideoLayerImpl() {
56 if (!provider_client_impl_->Stopped()) {
57 // In impl side painting, we may have a pending and active layer
58 // associated with the video provider at the same time. Both have a ref
59 // on the VideoFrameProviderClientImpl, but we stop when the first
60 // LayerImpl (the one on the pending tree) is destroyed since we know
61 // the main thread is blocked for this commit.
62 DCHECK(layer_tree_impl()->proxy()->IsImplThread());
63 DCHECK(layer_tree_impl()->proxy()->IsMainThreadBlocked());
64 provider_client_impl_->Stop();
68 scoped_ptr<LayerImpl> VideoLayerImpl::CreateLayerImpl(
69 LayerTreeImpl* tree_impl) {
70 return make_scoped_ptr(new VideoLayerImpl(
71 tree_impl, id(), provider_client_impl_, video_rotation_));
74 void VideoLayerImpl::DidBecomeActive() {
75 provider_client_impl_->SetActiveVideoLayer(this);
78 bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
79 ResourceProvider* resource_provider) {
80 if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
81 return false;
83 // Explicitly acquire and release the provider mutex so it can be held from
84 // WillDraw to DidDraw. Since the compositor thread is in the middle of
85 // drawing, the layer will not be destroyed before DidDraw is called.
86 // Therefore, the only thing that will prevent this lock from being released
87 // is the GPU process locking it. As the GPU process can't cause the
88 // destruction of the provider (calling StopUsingProvider), holding this
89 // lock should not cause a deadlock.
90 frame_ = provider_client_impl_->AcquireLockAndCurrentFrame();
92 if (!frame_.get()) {
93 // Drop any resources used by the updater if there is no frame to display.
94 updater_ = nullptr;
96 provider_client_impl_->ReleaseLock();
97 return false;
100 if (!LayerImpl::WillDraw(draw_mode, resource_provider))
101 return false;
103 if (!updater_) {
104 updater_.reset(
105 new VideoResourceUpdater(layer_tree_impl()->context_provider(),
106 layer_tree_impl()->resource_provider()));
109 VideoFrameExternalResources external_resources =
110 updater_->CreateExternalResourcesFromVideoFrame(frame_);
111 frame_resource_type_ = external_resources.type;
113 if (external_resources.type ==
114 VideoFrameExternalResources::SOFTWARE_RESOURCE) {
115 software_resources_ = external_resources.software_resources;
116 software_release_callback_ =
117 external_resources.software_release_callback;
118 return true;
121 DCHECK_EQ(external_resources.mailboxes.size(),
122 external_resources.release_callbacks.size());
123 for (size_t i = 0; i < external_resources.mailboxes.size(); ++i) {
124 unsigned resource_id = resource_provider->CreateResourceFromTextureMailbox(
125 external_resources.mailboxes[i],
126 SingleReleaseCallbackImpl::Create(
127 external_resources.release_callbacks[i]),
128 external_resources.read_lock_fences_enabled);
129 frame_resources_.push_back(FrameResource(
130 resource_id, external_resources.mailboxes[i].size_in_pixels(),
131 external_resources.mailboxes[i].allow_overlay()));
134 return true;
137 void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
138 AppendQuadsData* append_quads_data) {
139 DCHECK(frame_.get());
141 gfx::Transform transform = draw_transform();
142 gfx::Size rotated_size = bounds();
144 switch (video_rotation_) {
145 case media::VIDEO_ROTATION_90:
146 rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
147 transform.Rotate(90.0);
148 transform.Translate(0.0, -rotated_size.height());
149 break;
150 case media::VIDEO_ROTATION_180:
151 transform.Rotate(180.0);
152 transform.Translate(-rotated_size.width(), -rotated_size.height());
153 break;
154 case media::VIDEO_ROTATION_270:
155 rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
156 transform.Rotate(270.0);
157 transform.Translate(-rotated_size.width(), 0);
158 case media::VIDEO_ROTATION_0:
159 break;
162 SharedQuadState* shared_quad_state =
163 render_pass->CreateAndAppendSharedQuadState();
164 shared_quad_state->SetAll(transform, rotated_size, visible_layer_rect(),
165 clip_rect(), is_clipped(), draw_opacity(),
166 draw_blend_mode(), sorting_context_id());
168 AppendDebugBorderQuad(
169 render_pass, rotated_size, shared_quad_state, append_quads_data);
171 gfx::Rect quad_rect(rotated_size);
172 gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
173 gfx::Rect visible_rect = frame_->visible_rect();
174 gfx::Size coded_size = frame_->coded_size();
176 Occlusion occlusion_in_video_space =
177 draw_properties()
178 .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
179 transform);
180 gfx::Rect visible_quad_rect =
181 occlusion_in_video_space.GetUnoccludedContentRect(quad_rect);
182 if (visible_quad_rect.IsEmpty())
183 return;
185 // Pixels for macroblocked formats.
186 const float tex_width_scale =
187 static_cast<float>(visible_rect.width()) / coded_size.width();
188 const float tex_height_scale =
189 static_cast<float>(visible_rect.height()) / 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)
197 break;
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 TextureDrawQuad* texture_quad =
205 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
206 texture_quad->SetNew(shared_quad_state,
207 quad_rect,
208 opaque_rect,
209 visible_quad_rect,
210 software_resources_[0],
211 premultiplied_alpha,
212 uv_top_left,
213 uv_bottom_right,
214 SK_ColorTRANSPARENT,
215 opacity,
216 flipped,
217 nearest_neighbor);
218 ValidateQuadResources(texture_quad);
219 break;
221 case VideoFrameExternalResources::YUV_RESOURCE: {
222 DCHECK_GE(frame_resources_.size(), 3u);
224 YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601;
225 int videoframe_color_space;
226 if (frame_->metadata()->GetInteger(media::VideoFrameMetadata::COLOR_SPACE,
227 &videoframe_color_space)) {
228 if (videoframe_color_space == media::COLOR_SPACE_JPEG) {
229 color_space = YUVVideoDrawQuad::JPEG;
230 } else if (videoframe_color_space == media::COLOR_SPACE_HD_REC709) {
231 color_space = YUVVideoDrawQuad::REC_709;
235 const gfx::Size ya_tex_size = coded_size;
236 gfx::Size uv_tex_size;
238 if (frame_->HasTextures()) {
239 DCHECK_EQ(media::PIXEL_FORMAT_I420, frame_->format());
240 DCHECK_EQ(3u, frame_resources_.size()); // Alpha is not supported yet.
241 DCHECK(visible_rect.origin().IsOrigin());
242 DCHECK(visible_rect.size() == coded_size);
243 uv_tex_size.SetSize((ya_tex_size.width() + 1) / 2,
244 (ya_tex_size.height() + 1) / 2);
245 } else {
246 uv_tex_size = media::VideoFrame::PlaneSize(
247 frame_->format(), media::VideoFrame::kUPlane, coded_size);
248 DCHECK(uv_tex_size ==
249 media::VideoFrame::PlaneSize(
250 frame_->format(), media::VideoFrame::kVPlane, coded_size));
251 DCHECK_IMPLIES(
252 frame_resources_.size() > 3,
253 ya_tex_size ==
254 media::VideoFrame::PlaneSize(
255 frame_->format(), media::VideoFrame::kAPlane, coded_size));
258 // Compute the UV sub-sampling factor based on the ratio between
259 // |ya_tex_size| and |uv_tex_size|.
260 float uv_subsampling_factor_x =
261 static_cast<float>(ya_tex_size.width()) / uv_tex_size.width();
262 float uv_subsampling_factor_y =
263 static_cast<float>(ya_tex_size.height()) / uv_tex_size.height();
264 gfx::RectF ya_tex_coord_rect(visible_rect);
265 gfx::RectF uv_tex_coord_rect(
266 visible_rect.x() / uv_subsampling_factor_x,
267 visible_rect.y() / uv_subsampling_factor_y,
268 visible_rect.width() / uv_subsampling_factor_x,
269 visible_rect.height() / uv_subsampling_factor_y);
271 YUVVideoDrawQuad* yuv_video_quad =
272 render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
273 yuv_video_quad->SetNew(
274 shared_quad_state, quad_rect, opaque_rect, visible_quad_rect,
275 ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size, uv_tex_size,
276 frame_resources_[0].id, frame_resources_[1].id,
277 frame_resources_[2].id,
278 frame_resources_.size() > 3 ? frame_resources_[3].id : 0,
279 color_space);
280 ValidateQuadResources(yuv_video_quad);
281 break;
283 case VideoFrameExternalResources::RGBA_RESOURCE:
284 case VideoFrameExternalResources::RGB_RESOURCE: {
285 DCHECK_EQ(frame_resources_.size(), 1u);
286 if (frame_resources_.size() < 1u)
287 break;
288 bool premultiplied_alpha =
289 (frame_resource_type_ == VideoFrameExternalResources::RGBA_RESOURCE);
290 gfx::PointF uv_top_left(0.f, 0.f);
291 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
292 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
293 bool flipped = false;
294 bool nearest_neighbor = false;
295 TextureDrawQuad* texture_quad =
296 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
297 texture_quad->SetNew(shared_quad_state, quad_rect, opaque_rect,
298 visible_quad_rect, frame_resources_[0].id,
299 premultiplied_alpha, uv_top_left, uv_bottom_right,
300 SK_ColorTRANSPARENT, opacity, flipped,
301 nearest_neighbor);
302 ValidateQuadResources(texture_quad);
303 break;
305 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
306 DCHECK_EQ(frame_resources_.size(), 1u);
307 if (frame_resources_.size() < 1u)
308 break;
309 gfx::Transform scale;
310 scale.Scale(tex_width_scale, tex_height_scale);
311 StreamVideoDrawQuad* stream_video_quad =
312 render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
313 stream_video_quad->SetNew(
314 shared_quad_state, quad_rect, opaque_rect, visible_quad_rect,
315 frame_resources_[0].id, frame_resources_[0].size_in_pixels,
316 frame_resources_[0].allow_overlay,
317 scale * provider_client_impl_->StreamTextureMatrix());
318 ValidateQuadResources(stream_video_quad);
319 break;
321 case VideoFrameExternalResources::IO_SURFACE: {
322 DCHECK_EQ(frame_resources_.size(), 1u);
323 if (frame_resources_.size() < 1u)
324 break;
325 IOSurfaceDrawQuad* io_surface_quad =
326 render_pass->CreateAndAppendDrawQuad<IOSurfaceDrawQuad>();
327 io_surface_quad->SetNew(shared_quad_state, quad_rect, opaque_rect,
328 visible_quad_rect, visible_rect.size(),
329 frame_resources_[0].id,
330 IOSurfaceDrawQuad::UNFLIPPED,
331 frame_resources_[0].allow_overlay);
332 ValidateQuadResources(io_surface_quad);
333 break;
335 #if defined(VIDEO_HOLE)
336 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
337 // maintained by the general compositor team. Please contact the following
338 // people instead:
340 // wonsik@chromium.org
341 // lcwu@chromium.org
342 case VideoFrameExternalResources::HOLE: {
343 DCHECK_EQ(frame_resources_.size(), 0u);
344 SolidColorDrawQuad* solid_color_draw_quad =
345 render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
347 // Create a solid color quad with transparent black and force no
348 // blending / no anti-aliasing.
349 gfx::Rect opaque_rect = quad_rect;
350 solid_color_draw_quad->SetAll(shared_quad_state,
351 quad_rect,
352 opaque_rect,
353 visible_quad_rect,
354 false,
355 SK_ColorTRANSPARENT,
356 true);
357 break;
359 #endif // defined(VIDEO_HOLE)
360 case VideoFrameExternalResources::NONE:
361 NOTIMPLEMENTED();
362 break;
366 void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {
367 LayerImpl::DidDraw(resource_provider);
369 DCHECK(frame_.get());
371 if (frame_resource_type_ ==
372 VideoFrameExternalResources::SOFTWARE_RESOURCE) {
373 for (size_t i = 0; i < software_resources_.size(); ++i) {
374 software_release_callback_.Run(
375 0, false, layer_tree_impl()->BlockingMainThreadTaskRunner());
378 software_resources_.clear();
379 software_release_callback_.Reset();
380 } else {
381 for (size_t i = 0; i < frame_resources_.size(); ++i)
382 resource_provider->DeleteResource(frame_resources_[i].id);
383 frame_resources_.clear();
386 provider_client_impl_->PutCurrentFrame();
387 frame_ = nullptr;
389 provider_client_impl_->ReleaseLock();
392 SimpleEnclosedRegion VideoLayerImpl::VisibleOpaqueRegion() const {
393 // If we don't have a frame yet, then we don't have an opaque region.
394 if (!provider_client_impl_->HasCurrentFrame())
395 return SimpleEnclosedRegion();
396 return LayerImpl::VisibleOpaqueRegion();
399 void VideoLayerImpl::ReleaseResources() {
400 updater_ = nullptr;
403 void VideoLayerImpl::SetNeedsRedraw() {
404 SetUpdateRect(gfx::UnionRects(update_rect(), gfx::Rect(bounds())));
405 layer_tree_impl()->SetNeedsRedraw();
408 const char* VideoLayerImpl::LayerTypeAsString() const {
409 return "cc::VideoLayerImpl";
412 } // namespace cc