Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / cc / layers / video_layer_impl.cc
blob20021167e150e379c6423bbc26b0d2ca233ee295
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/quad_sink.h"
10 #include "cc/layers/video_frame_provider_client_impl.h"
11 #include "cc/quads/io_surface_draw_quad.h"
12 #include "cc/quads/stream_video_draw_quad.h"
13 #include "cc/quads/texture_draw_quad.h"
14 #include "cc/quads/yuv_video_draw_quad.h"
15 #include "cc/resources/resource_provider.h"
16 #include "cc/resources/single_release_callback.h"
17 #include "cc/trees/layer_tree_impl.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 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());
36 return layer.Pass();
39 VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl, int id)
40 : LayerImpl(tree_impl, id),
41 frame_(NULL) {}
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)
75 return false;
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();
86 if (!frame_.get()) {
87 // Drop any resources used by the updater if there is no frame to display.
88 updater_.reset();
90 provider_client_impl_->ReleaseLock();
91 return false;
94 if (!LayerImpl::WillDraw(draw_mode, resource_provider))
95 return false;
97 if (!updater_) {
98 updater_.reset(
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;
112 return true;
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);
124 return true;
127 void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
128 AppendQuadsData* append_quads_data) {
129 DCHECK(frame_.get());
131 SharedQuadState* shared_quad_state =
132 quad_sink->UseSharedQuadState(CreateSharedQuadState());
133 AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
135 gfx::Rect quad_rect(content_bounds());
136 gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
137 gfx::Rect visible_rect = frame_->visible_rect();
138 gfx::Size coded_size = frame_->coded_size();
140 gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
141 quad_rect, draw_properties().target_space_transform);
142 if (visible_quad_rect.IsEmpty())
143 return;
145 // Pixels for macroblocked formats.
146 const float tex_width_scale =
147 static_cast<float>(visible_rect.width()) / coded_size.width();
148 const float tex_height_scale =
149 static_cast<float>(visible_rect.height()) / coded_size.height();
150 const float tex_x_offset =
151 static_cast<float>(visible_rect.x()) / coded_size.width();
152 const float tex_y_offset =
153 static_cast<float>(visible_rect.y()) / coded_size.height();
155 switch (frame_resource_type_) {
156 // TODO(danakj): Remove this, hide it in the hardware path.
157 case VideoFrameExternalResources::SOFTWARE_RESOURCE: {
158 DCHECK_EQ(frame_resources_.size(), 0u);
159 DCHECK_EQ(software_resources_.size(), 1u);
160 if (software_resources_.size() < 1u)
161 break;
162 bool premultiplied_alpha = true;
163 gfx::PointF uv_top_left(0.f, 0.f);
164 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
165 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
166 bool flipped = false;
167 scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create();
168 texture_quad->SetNew(shared_quad_state,
169 quad_rect,
170 opaque_rect,
171 visible_quad_rect,
172 software_resources_[0],
173 premultiplied_alpha,
174 uv_top_left,
175 uv_bottom_right,
176 SK_ColorTRANSPARENT,
177 opacity,
178 flipped);
179 quad_sink->Append(texture_quad.PassAs<DrawQuad>());
180 break;
182 case VideoFrameExternalResources::YUV_RESOURCE: {
183 DCHECK_GE(frame_resources_.size(), 3u);
184 if (frame_resources_.size() < 3u)
185 break;
186 YUVVideoDrawQuad::ColorSpace color_space =
187 frame_->format() == media::VideoFrame::YV12J
188 ? YUVVideoDrawQuad::REC_601_JPEG
189 : YUVVideoDrawQuad::REC_601;
190 gfx::RectF tex_coord_rect(
191 tex_x_offset, tex_y_offset, tex_width_scale, tex_height_scale);
192 scoped_ptr<YUVVideoDrawQuad> yuv_video_quad = YUVVideoDrawQuad::Create();
193 yuv_video_quad->SetNew(
194 shared_quad_state,
195 quad_rect,
196 opaque_rect,
197 visible_quad_rect,
198 tex_coord_rect,
199 frame_resources_[0],
200 frame_resources_[1],
201 frame_resources_[2],
202 frame_resources_.size() > 3 ? frame_resources_[3] : 0,
203 color_space);
204 quad_sink->Append(yuv_video_quad.PassAs<DrawQuad>());
205 break;
207 case VideoFrameExternalResources::RGB_RESOURCE: {
208 DCHECK_EQ(frame_resources_.size(), 1u);
209 if (frame_resources_.size() < 1u)
210 break;
211 bool premultiplied_alpha = true;
212 gfx::PointF uv_top_left(0.f, 0.f);
213 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
214 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
215 bool flipped = false;
216 scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create();
217 texture_quad->SetNew(shared_quad_state,
218 quad_rect,
219 opaque_rect,
220 visible_quad_rect,
221 frame_resources_[0],
222 premultiplied_alpha,
223 uv_top_left,
224 uv_bottom_right,
225 SK_ColorTRANSPARENT,
226 opacity,
227 flipped);
228 quad_sink->Append(texture_quad.PassAs<DrawQuad>());
229 break;
231 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
232 DCHECK_EQ(frame_resources_.size(), 1u);
233 if (frame_resources_.size() < 1u)
234 break;
235 gfx::Transform scale;
236 scale.Scale(tex_width_scale, tex_height_scale);
237 scoped_ptr<StreamVideoDrawQuad> stream_video_quad =
238 StreamVideoDrawQuad::Create();
239 stream_video_quad->SetNew(
240 shared_quad_state,
241 quad_rect,
242 opaque_rect,
243 visible_quad_rect,
244 frame_resources_[0],
245 scale * provider_client_impl_->stream_texture_matrix());
246 quad_sink->Append(stream_video_quad.PassAs<DrawQuad>());
247 break;
249 case VideoFrameExternalResources::IO_SURFACE: {
250 DCHECK_EQ(frame_resources_.size(), 1u);
251 if (frame_resources_.size() < 1u)
252 break;
253 scoped_ptr<IOSurfaceDrawQuad> io_surface_quad =
254 IOSurfaceDrawQuad::Create();
255 io_surface_quad->SetNew(shared_quad_state,
256 quad_rect,
257 opaque_rect,
258 visible_quad_rect,
259 visible_rect.size(),
260 frame_resources_[0],
261 IOSurfaceDrawQuad::UNFLIPPED);
262 quad_sink->Append(io_surface_quad.PassAs<DrawQuad>());
263 break;
265 #if defined(VIDEO_HOLE)
266 // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
267 // maintained by the general compositor team. Please contact the following
268 // people instead:
270 // wonsik@chromium.org
271 // ycheo@chromium.org
272 case VideoFrameExternalResources::HOLE: {
273 DCHECK_EQ(frame_resources_.size(), 0u);
274 scoped_ptr<SolidColorDrawQuad> solid_color_draw_quad =
275 SolidColorDrawQuad::Create();
277 // Create a solid color quad with transparent black and force no
278 // blending / no anti-aliasing.
279 gfx::Rect opaque_rect = quad_rect;
280 solid_color_draw_quad->SetAll(shared_quad_state,
281 quad_rect,
282 opaque_rect,
283 visible_quad_rect,
284 false,
285 SK_ColorTRANSPARENT,
286 true);
287 quad_sink->Append(solid_color_draw_quad.PassAs<DrawQuad>());
288 break;
290 #endif // defined(VIDEO_HOLE)
291 case VideoFrameExternalResources::NONE:
292 NOTIMPLEMENTED();
293 break;
297 void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {
298 LayerImpl::DidDraw(resource_provider);
300 DCHECK(frame_.get());
302 if (frame_resource_type_ ==
303 VideoFrameExternalResources::SOFTWARE_RESOURCE) {
304 for (size_t i = 0; i < software_resources_.size(); ++i)
305 software_release_callback_.Run(0, false);
307 software_resources_.clear();
308 software_release_callback_.Reset();
309 } else {
310 for (size_t i = 0; i < frame_resources_.size(); ++i)
311 resource_provider->DeleteResource(frame_resources_[i]);
312 frame_resources_.clear();
315 provider_client_impl_->PutCurrentFrame(frame_);
316 frame_ = NULL;
318 provider_client_impl_->ReleaseLock();
321 void VideoLayerImpl::ReleaseResources() {
322 updater_.reset();
325 void VideoLayerImpl::SetNeedsRedraw() {
326 SetUpdateRect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
327 layer_tree_impl()->SetNeedsRedraw();
330 void VideoLayerImpl::SetProviderClientImpl(
331 scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) {
332 provider_client_impl_ = provider_client_impl;
335 const char* VideoLayerImpl::LayerTypeAsString() const {
336 return "cc::VideoLayerImpl";
339 } // namespace cc