Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / cc / layers / video_layer_impl.cc
blob3ca097820faffb2504f690d19fdc9c42b5a87b54
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(provider);
39 return make_scoped_ptr(
40 new VideoLayerImpl(tree_impl, id, provider_client_impl, video_rotation));
43 VideoLayerImpl::VideoLayerImpl(
44 LayerTreeImpl* tree_impl,
45 int id,
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),
50 frame_(nullptr),
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)
80 return false;
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();
91 if (!frame_.get()) {
92 // Drop any resources used by the updater if there is no frame to display.
93 updater_ = nullptr;
95 provider_client_impl_->ReleaseLock();
96 return false;
99 if (!LayerImpl::WillDraw(draw_mode, resource_provider))
100 return false;
102 if (!updater_) {
103 updater_.reset(
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;
117 return true;
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);
130 return true;
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());
145 break;
146 case media::VIDEO_ROTATION_180:
147 transform.Rotate(180.0);
148 transform.Translate(-rotated_size.width(), -rotated_size.height());
149 break;
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:
155 break;
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 =
173 draw_properties()
174 .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
175 transform);
176 gfx::Rect visible_quad_rect =
177 occlusion_in_video_space.GetUnoccludedContentRect(quad_rect);
178 if (visible_quad_rect.IsEmpty())
179 return;
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)
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 // 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,
210 quad_rect,
211 opaque_rect,
212 visible_quad_rect,
213 software_resources_[0],
214 premultiplied_alpha,
215 uv_top_left,
216 uv_bottom_right,
217 SK_ColorTRANSPARENT,
218 opacity,
219 flipped,
220 nearest_neighbor);
221 break;
223 case VideoFrameExternalResources::YUV_RESOURCE: {
224 DCHECK_GE(frame_resources_.size(), 3u);
225 if (frame_resources_.size() < 3u)
226 break;
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);
266 break;
268 case VideoFrameExternalResources::RGB_RESOURCE: {
269 DCHECK_EQ(frame_resources_.size(), 1u);
270 if (frame_resources_.size() < 1u)
271 break;
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,
284 quad_rect,
285 opaque_rect,
286 visible_quad_rect,
287 frame_resources_[0],
288 premultiplied_alpha,
289 uv_top_left,
290 uv_bottom_right,
291 SK_ColorTRANSPARENT,
292 opacity,
293 flipped,
294 nearest_neighbor);
295 break;
297 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
298 DCHECK_EQ(frame_resources_.size(), 1u);
299 if (frame_resources_.size() < 1u)
300 break;
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,
310 frame_resources_[0],
311 scale * provider_client_impl_->StreamTextureMatrix());
312 break;
314 case VideoFrameExternalResources::IO_SURFACE: {
315 DCHECK_EQ(frame_resources_.size(), 1u);
316 if (frame_resources_.size() < 1u)
317 break;
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,
324 quad_rect,
325 opaque_rect,
326 visible_quad_rect,
327 visible_rect.size(),
328 frame_resources_[0],
329 IOSurfaceDrawQuad::UNFLIPPED);
330 break;
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
335 // people instead:
337 // wonsik@chromium.org
338 // lcwu@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,
348 quad_rect,
349 opaque_rect,
350 visible_quad_rect,
351 false,
352 SK_ColorTRANSPARENT,
353 true);
354 break;
356 #endif // defined(VIDEO_HOLE)
357 case VideoFrameExternalResources::NONE:
358 NOTIMPLEMENTED();
359 break;
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();
377 } else {
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_);
384 frame_ = nullptr;
386 provider_client_impl_->ReleaseLock();
389 void VideoLayerImpl::ReleaseResources() {
390 updater_ = nullptr;
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";
402 } // namespace cc