OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/layers/video_layer_impl.h" | |
6 | |
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" | |
20 | |
21 #if defined(VIDEO_HOLE) | |
22 #include "cc/quads/solid_color_draw_quad.h" | |
23 #endif // defined(VIDEO_HOLE) | |
24 | |
25 namespace cc { | |
26 | |
27 // static | |
28 scoped_ptr<VideoLayerImpl> VideoLayerImpl::Create( | |
29 LayerTreeImpl* tree_impl, | |
30 int id, | |
31 VideoFrameProvider* provider, | |
32 media::VideoRotation video_rotation) { | |
33 scoped_ptr<VideoLayerImpl> layer( | |
34 new VideoLayerImpl(tree_impl, id, video_rotation)); | |
35 layer->SetProviderClientImpl(VideoFrameProviderClientImpl::Create(provider)); | |
36 DCHECK(tree_impl->proxy()->IsImplThread()); | |
37 DCHECK(tree_impl->proxy()->IsMainThreadBlocked()); | |
38 return layer.Pass(); | |
39 } | |
40 | |
41 VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl, | |
42 int id, | |
43 media::VideoRotation video_rotation) | |
44 : LayerImpl(tree_impl, id), | |
45 frame_(nullptr), | |
46 video_rotation_(video_rotation) { | |
47 } | |
48 | |
49 VideoLayerImpl::~VideoLayerImpl() { | |
50 if (!provider_client_impl_->Stopped()) { | |
51 // In impl side painting, we may have a pending and active layer | |
52 // associated with the video provider at the same time. Both have a ref | |
53 // on the VideoFrameProviderClientImpl, but we stop when the first | |
54 // LayerImpl (the one on the pending tree) is destroyed since we know | |
55 // the main thread is blocked for this commit. | |
56 DCHECK(layer_tree_impl()->proxy()->IsImplThread()); | |
57 DCHECK(layer_tree_impl()->proxy()->IsMainThreadBlocked()); | |
58 provider_client_impl_->Stop(); | |
59 } | |
60 } | |
61 | |
62 scoped_ptr<LayerImpl> VideoLayerImpl::CreateLayerImpl( | |
63 LayerTreeImpl* tree_impl) { | |
64 return make_scoped_ptr(new VideoLayerImpl(tree_impl, id(), video_rotation_)); | |
65 } | |
66 | |
67 void VideoLayerImpl::PushPropertiesTo(LayerImpl* layer) { | |
68 LayerImpl::PushPropertiesTo(layer); | |
69 | |
70 VideoLayerImpl* other = static_cast<VideoLayerImpl*>(layer); | |
71 other->SetProviderClientImpl(provider_client_impl_); | |
72 } | |
73 | |
74 void VideoLayerImpl::DidBecomeActive() { | |
75 provider_client_impl_->SetActiveVideoLayer(this); | |
76 } | |
77 | |
78 bool VideoLayerImpl::WillDraw(DrawMode draw_mode, | |
79 ResourceProvider* resource_provider) { | |
80 if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) | |
81 return false; | |
82 | |
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(); | |
91 | |
92 if (!frame_.get()) { | |
93 // Drop any resources used by the updater if there is no frame to display. | |
94 updater_ = nullptr; | |
95 | |
96 provider_client_impl_->ReleaseLock(); | |
97 return false; | |
98 } | |
99 | |
100 if (!LayerImpl::WillDraw(draw_mode, resource_provider)) | |
101 return false; | |
102 | |
103 if (!updater_) { | |
104 updater_.reset( | |
105 new VideoResourceUpdater(layer_tree_impl()->context_provider(), | |
106 layer_tree_impl()->resource_provider())); | |
107 } | |
108 | |
109 VideoFrameExternalResources external_resources = | |
110 updater_->CreateExternalResourcesFromVideoFrame(frame_); | |
111 frame_resource_type_ = external_resources.type; | |
112 | |
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; | |
119 } | |
120 | |
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 frame_resources_.push_back(resource_id); | |
129 } | |
130 | |
131 return true; | |
132 } | |
133 | |
134 void VideoLayerImpl::AppendQuads(RenderPass* render_pass, | |
135 AppendQuadsData* append_quads_data) { | |
136 DCHECK(frame_.get()); | |
137 | |
138 gfx::Transform transform = draw_transform(); | |
139 gfx::Size rotated_size = content_bounds(); | |
140 | |
141 switch (video_rotation_) { | |
142 case media::VIDEO_ROTATION_90: | |
143 rotated_size = gfx::Size(rotated_size.height(), rotated_size.width()); | |
144 transform.Rotate(90.0); | |
145 transform.Translate(0.0, -rotated_size.height()); | |
146 break; | |
147 case media::VIDEO_ROTATION_180: | |
148 transform.Rotate(180.0); | |
149 transform.Translate(-rotated_size.width(), -rotated_size.height()); | |
150 break; | |
151 case media::VIDEO_ROTATION_270: | |
152 rotated_size = gfx::Size(rotated_size.height(), rotated_size.width()); | |
153 transform.Rotate(270.0); | |
154 transform.Translate(-rotated_size.width(), 0); | |
155 case media::VIDEO_ROTATION_0: | |
156 break; | |
157 } | |
158 | |
159 SharedQuadState* shared_quad_state = | |
160 render_pass->CreateAndAppendSharedQuadState(); | |
161 shared_quad_state->SetAll(transform, rotated_size, visible_content_rect(), | |
162 clip_rect(), is_clipped(), draw_opacity(), | |
163 draw_blend_mode(), sorting_context_id()); | |
164 | |
165 AppendDebugBorderQuad( | |
166 render_pass, rotated_size, shared_quad_state, append_quads_data); | |
167 | |
168 gfx::Rect quad_rect(rotated_size); | |
169 gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect()); | |
170 gfx::Rect visible_rect = frame_->visible_rect(); | |
171 gfx::Size coded_size = frame_->coded_size(); | |
172 | |
173 Occlusion occlusion_in_video_space = | |
174 draw_properties() | |
175 .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform( | |
176 transform); | |
177 gfx::Rect visible_quad_rect = | |
178 occlusion_in_video_space.GetUnoccludedContentRect(quad_rect); | |
179 if (visible_quad_rect.IsEmpty()) | |
180 return; | |
181 | |
182 // Pixels for macroblocked formats. | |
183 const float tex_width_scale = | |
184 static_cast<float>(visible_rect.width()) / coded_size.width(); | |
185 const float tex_height_scale = | |
186 static_cast<float>(visible_rect.height()) / coded_size.height(); | |
187 const float tex_x_offset = | |
188 static_cast<float>(visible_rect.x()) / coded_size.width(); | |
189 const float tex_y_offset = | |
190 static_cast<float>(visible_rect.y()) / coded_size.height(); | |
191 | |
192 switch (frame_resource_type_) { | |
193 // TODO(danakj): Remove this, hide it in the hardware path. | |
194 case VideoFrameExternalResources::SOFTWARE_RESOURCE: { | |
195 DCHECK_EQ(frame_resources_.size(), 0u); | |
196 DCHECK_EQ(software_resources_.size(), 1u); | |
197 if (software_resources_.size() < 1u) | |
198 break; | |
199 bool premultiplied_alpha = true; | |
200 gfx::PointF uv_top_left(0.f, 0.f); | |
201 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale); | |
202 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; | |
203 bool flipped = false; | |
204 bool nearest_neighbor = false; | |
205 TextureDrawQuad* texture_quad = | |
206 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); | |
207 texture_quad->SetNew(shared_quad_state, | |
208 quad_rect, | |
209 opaque_rect, | |
210 visible_quad_rect, | |
211 software_resources_[0], | |
212 premultiplied_alpha, | |
213 uv_top_left, | |
214 uv_bottom_right, | |
215 SK_ColorTRANSPARENT, | |
216 opacity, | |
217 flipped, | |
218 nearest_neighbor); | |
219 break; | |
220 } | |
221 case VideoFrameExternalResources::YUV_RESOURCE: { | |
222 DCHECK_GE(frame_resources_.size(), 3u); | |
223 if (frame_resources_.size() < 3u) | |
224 break; | |
225 YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601; | |
226 if (frame_->format() == media::VideoFrame::YV12J) { | |
227 color_space = YUVVideoDrawQuad::JPEG; | |
228 } else if (frame_->format() == media::VideoFrame::YV12HD) { | |
229 color_space = YUVVideoDrawQuad::REC_709; | |
230 } | |
231 | |
232 gfx::RectF tex_coord_rect( | |
233 tex_x_offset, tex_y_offset, tex_width_scale, tex_height_scale); | |
234 YUVVideoDrawQuad* yuv_video_quad = | |
235 render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>(); | |
236 yuv_video_quad->SetNew( | |
237 shared_quad_state, quad_rect, opaque_rect, visible_quad_rect, | |
238 tex_coord_rect, coded_size, frame_resources_[0], frame_resources_[1], | |
239 frame_resources_[2], | |
240 frame_resources_.size() > 3 ? frame_resources_[3] : 0, color_space); | |
241 break; | |
242 } | |
243 case VideoFrameExternalResources::RGB_RESOURCE: { | |
244 DCHECK_EQ(frame_resources_.size(), 1u); | |
245 if (frame_resources_.size() < 1u) | |
246 break; | |
247 bool premultiplied_alpha = true; | |
248 gfx::PointF uv_top_left(0.f, 0.f); | |
249 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale); | |
250 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; | |
251 bool flipped = false; | |
252 bool nearest_neighbor = false; | |
253 TextureDrawQuad* texture_quad = | |
254 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); | |
255 texture_quad->SetNew(shared_quad_state, | |
256 quad_rect, | |
257 opaque_rect, | |
258 visible_quad_rect, | |
259 frame_resources_[0], | |
260 premultiplied_alpha, | |
261 uv_top_left, | |
262 uv_bottom_right, | |
263 SK_ColorTRANSPARENT, | |
264 opacity, | |
265 flipped, | |
266 nearest_neighbor); | |
267 break; | |
268 } | |
269 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: { | |
270 DCHECK_EQ(frame_resources_.size(), 1u); | |
271 if (frame_resources_.size() < 1u) | |
272 break; | |
273 gfx::Transform scale; | |
274 scale.Scale(tex_width_scale, tex_height_scale); | |
275 StreamVideoDrawQuad* stream_video_quad = | |
276 render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>(); | |
277 stream_video_quad->SetNew( | |
278 shared_quad_state, | |
279 quad_rect, | |
280 opaque_rect, | |
281 visible_quad_rect, | |
282 frame_resources_[0], | |
283 scale * provider_client_impl_->stream_texture_matrix()); | |
284 break; | |
285 } | |
286 case VideoFrameExternalResources::IO_SURFACE: { | |
287 DCHECK_EQ(frame_resources_.size(), 1u); | |
288 if (frame_resources_.size() < 1u) | |
289 break; | |
290 IOSurfaceDrawQuad* io_surface_quad = | |
291 render_pass->CreateAndAppendDrawQuad<IOSurfaceDrawQuad>(); | |
292 io_surface_quad->SetNew(shared_quad_state, | |
293 quad_rect, | |
294 opaque_rect, | |
295 visible_quad_rect, | |
296 visible_rect.size(), | |
297 frame_resources_[0], | |
298 IOSurfaceDrawQuad::UNFLIPPED); | |
299 break; | |
300 } | |
301 #if defined(VIDEO_HOLE) | |
302 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not | |
303 // maintained by the general compositor team. Please contact the following | |
304 // people instead: | |
305 // | |
306 // wonsik@chromium.org | |
307 // lcwu@chromium.org | |
308 case VideoFrameExternalResources::HOLE: { | |
309 DCHECK_EQ(frame_resources_.size(), 0u); | |
310 SolidColorDrawQuad* solid_color_draw_quad = | |
311 render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); | |
312 | |
313 // Create a solid color quad with transparent black and force no | |
314 // blending / no anti-aliasing. | |
315 gfx::Rect opaque_rect = quad_rect; | |
316 solid_color_draw_quad->SetAll(shared_quad_state, | |
317 quad_rect, | |
318 opaque_rect, | |
319 visible_quad_rect, | |
320 false, | |
321 SK_ColorTRANSPARENT, | |
322 true); | |
323 break; | |
324 } | |
325 #endif // defined(VIDEO_HOLE) | |
326 case VideoFrameExternalResources::NONE: | |
327 NOTIMPLEMENTED(); | |
328 break; | |
329 } | |
330 } | |
331 | |
332 void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) { | |
333 LayerImpl::DidDraw(resource_provider); | |
334 | |
335 DCHECK(frame_.get()); | |
336 | |
337 if (frame_resource_type_ == | |
338 VideoFrameExternalResources::SOFTWARE_RESOURCE) { | |
339 for (size_t i = 0; i < software_resources_.size(); ++i) { | |
340 software_release_callback_.Run( | |
341 0, false, layer_tree_impl()->BlockingMainThreadTaskRunner()); | |
342 } | |
343 | |
344 software_resources_.clear(); | |
345 software_release_callback_.Reset(); | |
346 } else { | |
347 for (size_t i = 0; i < frame_resources_.size(); ++i) | |
348 resource_provider->DeleteResource(frame_resources_[i]); | |
349 frame_resources_.clear(); | |
350 } | |
351 | |
352 provider_client_impl_->PutCurrentFrame(frame_); | |
353 frame_ = nullptr; | |
354 | |
355 provider_client_impl_->ReleaseLock(); | |
356 } | |
357 | |
358 void VideoLayerImpl::ReleaseResources() { | |
359 updater_ = nullptr; | |
360 } | |
361 | |
362 void VideoLayerImpl::SetNeedsRedraw() { | |
363 SetUpdateRect(gfx::UnionRects(update_rect(), gfx::Rect(bounds()))); | |
364 layer_tree_impl()->SetNeedsRedraw(); | |
365 } | |
366 | |
367 void VideoLayerImpl::SetProviderClientImpl( | |
368 scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) { | |
369 provider_client_impl_ = provider_client_impl; | |
370 } | |
371 | |
372 const char* VideoLayerImpl::LayerTypeAsString() const { | |
373 return "cc::VideoLayerImpl"; | |
374 } | |
375 | |
376 } // namespace cc | |
OLD | NEW |