| 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 |