Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/resources/video_resource_updater.h" | 5 #include "cc/resources/video_resource_updater.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 : context_provider_(context_provider), | 165 : context_provider_(context_provider), |
| 166 resource_provider_(resource_provider) { | 166 resource_provider_(resource_provider) { |
| 167 } | 167 } |
| 168 | 168 |
| 169 VideoResourceUpdater::~VideoResourceUpdater() { | 169 VideoResourceUpdater::~VideoResourceUpdater() { |
| 170 for (const PlaneResource& plane_resource : all_resources_) | 170 for (const PlaneResource& plane_resource : all_resources_) |
| 171 resource_provider_->DeleteResource(plane_resource.resource_id()); | 171 resource_provider_->DeleteResource(plane_resource.resource_id()); |
| 172 } | 172 } |
| 173 | 173 |
| 174 VideoResourceUpdater::ResourceList::iterator | 174 VideoResourceUpdater::ResourceList::iterator |
| 175 VideoResourceUpdater::RecycleOrAllocateTexture(const gfx::Size& resource_size, | |
| 176 ResourceFormat resource_format, | |
| 177 bool immutable_hint) { | |
| 178 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { | |
| 179 // Reuse resource if attributes match and the resource is a currently | |
| 180 // unreferenced texture. | |
| 181 if (it->resource_size() == resource_size && | |
| 182 it->resource_format() == resource_format && !it->mailbox().IsZero() && | |
| 183 !it->has_refs() && | |
| 184 resource_provider_->GetTextureHint(it->resource_id()) != | |
| 185 ResourceProvider::TEXTURE_HINT_IMMUTABLE) { | |
| 186 return it; | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 // Otherwise allocate a new resource. | |
| 191 return AllocateResource(resource_size, resource_format, true, immutable_hint); | |
| 192 } | |
| 193 | |
| 194 VideoResourceUpdater::ResourceList::iterator | |
| 175 VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size, | 195 VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size, |
| 176 ResourceFormat format, | 196 ResourceFormat format, |
| 177 bool has_mailbox, | 197 bool has_mailbox, |
| 178 bool immutable_hint) { | 198 bool immutable_hint) { |
| 179 // TODO(danakj): Abstract out hw/sw resource create/delete from | 199 // TODO(danakj): Abstract out hw/sw resource create/delete from |
| 180 // ResourceProvider and stop using ResourceProvider in this class. | 200 // ResourceProvider and stop using ResourceProvider in this class. |
| 181 const ResourceId resource_id = resource_provider_->CreateResource( | 201 const ResourceId resource_id = resource_provider_->CreateResource( |
| 182 plane_size, immutable_hint ? ResourceProvider::TEXTURE_HINT_IMMUTABLE | 202 plane_size, immutable_hint ? ResourceProvider::TEXTURE_HINT_IMMUTABLE |
| 183 : ResourceProvider::TEXTURE_HINT_DEFAULT, | 203 : ResourceProvider::TEXTURE_HINT_DEFAULT, |
| 184 format); | 204 format); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 if (software_compositor) | 258 if (software_compositor) |
| 239 return coded_size; | 259 return coded_size; |
| 240 | 260 |
| 241 int plane_width = media::VideoFrame::Columns( | 261 int plane_width = media::VideoFrame::Columns( |
| 242 plane_index, input_frame->format(), coded_size.width()); | 262 plane_index, input_frame->format(), coded_size.width()); |
| 243 int plane_height = media::VideoFrame::Rows(plane_index, input_frame->format(), | 263 int plane_height = media::VideoFrame::Rows(plane_index, input_frame->format(), |
| 244 coded_size.height()); | 264 coded_size.height()); |
| 245 return gfx::Size(plane_width, plane_height); | 265 return gfx::Size(plane_width, plane_height); |
| 246 } | 266 } |
| 247 | 267 |
| 268 // Create an RGB texture by software converting YUV planar data, for the case | |
| 269 // where YUV planar textures are not renderable by the GPU. | |
| 270 VideoFrameExternalResources | |
| 271 VideoResourceUpdater::CreateRGBTextureForSoftwarePlanes( | |
| 272 media::VideoFrame* video_frame) { | |
| 273 DCHECK(media::IsYuvPlanar(video_frame->format())); | |
| 274 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | |
| 275 const ResourceFormat resource_format = ResourceFormat::RGBA_8888; | |
| 276 const gfx::Size output_plane_resource_size = video_frame->coded_size(); | |
| 277 const bool is_immutable = false; | |
| 278 | |
| 279 VideoResourceUpdater::ResourceList::iterator resource = | |
| 280 RecycleOrAllocateTexture(output_plane_resource_size, resource_format, | |
| 281 is_immutable); | |
| 282 | |
| 283 resource->add_ref(); | |
| 284 | |
| 285 size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( | |
| 286 output_plane_resource_size.width(), ResourceFormat::RGBA_8888); | |
| 287 size_t upload_image_stride = | |
| 288 MathUtil::UncheckedRoundUp<size_t>(bytes_per_row, 4u); | |
|
dcheng
2016/08/12 22:50:47
Sorry, I think I've asked this before, but can the
Tobias Sargeant
2016/08/15 09:33:04
Ack. Commented in reply.
| |
| 289 size_t needed_size = | |
| 290 upload_image_stride * output_plane_resource_size.height(); | |
| 291 if (upload_pixels_.size() < needed_size) | |
| 292 upload_pixels_.resize(needed_size); | |
| 293 | |
| 294 media::SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( | |
| 295 video_frame, &upload_pixels_[0], upload_image_stride); | |
| 296 | |
| 297 resource_provider_->CopyToResource( | |
| 298 resource->resource_id(), &upload_pixels_[0], resource->resource_size()); | |
| 299 | |
| 300 gpu::SyncToken sync_token; | |
| 301 const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); | |
| 302 gl->ShallowFlushCHROMIUM(); | |
| 303 gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); | |
| 304 | |
| 305 VideoFrameExternalResources external_resources; | |
| 306 | |
| 307 external_resources.mailboxes.push_back( | |
| 308 TextureMailbox(resource->mailbox(), sync_token, GL_TEXTURE_2D, | |
| 309 video_frame->coded_size(), false, false)); | |
| 310 external_resources.release_callbacks.push_back( | |
| 311 base::Bind(&RecycleResource, AsWeakPtr(), resource->resource_id())); | |
| 312 external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE; | |
| 313 return external_resources; | |
| 314 } | |
| 315 | |
| 248 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( | 316 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( |
| 249 scoped_refptr<media::VideoFrame> video_frame) { | 317 scoped_refptr<media::VideoFrame> video_frame) { |
| 250 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); | 318 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); |
| 251 const media::VideoPixelFormat input_frame_format = video_frame->format(); | 319 const media::VideoPixelFormat input_frame_format = video_frame->format(); |
| 252 | 320 |
| 253 // TODO(hubbe): Make this a video frame method. | 321 // TODO(hubbe): Make this a video frame method. |
| 254 int bits_per_channel = 0; | 322 int bits_per_channel = 0; |
| 255 switch (input_frame_format) { | 323 switch (input_frame_format) { |
| 256 case media::PIXEL_FORMAT_UNKNOWN: | 324 case media::PIXEL_FORMAT_UNKNOWN: |
| 257 NOTREACHED(); | 325 NOTREACHED(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 289 if (!media::IsYuvPlanar(input_frame_format)) { | 357 if (!media::IsYuvPlanar(input_frame_format)) { |
| 290 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); | 358 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); |
| 291 return VideoFrameExternalResources(); | 359 return VideoFrameExternalResources(); |
| 292 } | 360 } |
| 293 | 361 |
| 294 const bool software_compositor = context_provider_ == NULL; | 362 const bool software_compositor = context_provider_ == NULL; |
| 295 | 363 |
| 296 ResourceFormat output_resource_format = | 364 ResourceFormat output_resource_format = |
| 297 resource_provider_->YuvResourceFormat(bits_per_channel); | 365 resource_provider_->YuvResourceFormat(bits_per_channel); |
| 298 | 366 |
| 367 if (!software_compositor && | |
|
liberato (no reviews please)
2016/08/12 22:09:23
is it possible to avoid switching the resource for
Tobias Sargeant
2016/08/15 09:33:04
It will only be set to 8888 for GPU resources, so
liberato (no reviews please)
2016/08/16 14:55:46
makes sense. probably deserves a comment to that
Tobias Sargeant
2016/08/16 15:19:10
I updated the comment to make the intent clearer.
| |
| 368 output_resource_format == ResourceFormat::RGBA_8888) { | |
| 369 // If the output resource format is RGB, then YUV frames must be converted | |
| 370 // to RGB before texture upload. | |
| 371 return CreateRGBTextureForSoftwarePlanes(video_frame.get()); | |
| 372 } | |
| 373 | |
| 299 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); | 374 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); |
| 300 | 375 |
| 301 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB | 376 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB |
| 302 // conversion here. That involves an extra copy of each frame to a bitmap. | 377 // conversion here. That involves an extra copy of each frame to a bitmap. |
| 303 // Obviously, this is suboptimal and should be addressed once ubercompositor | 378 // Obviously, this is suboptimal and should be addressed once ubercompositor |
| 304 // starts shaping up. | 379 // starts shaping up. |
| 305 if (software_compositor) { | 380 if (software_compositor) { |
| 306 output_resource_format = kRGBResourceFormat; | 381 output_resource_format = kRGBResourceFormat; |
| 307 output_plane_count = 1; | 382 output_plane_count = 1; |
| 308 } | 383 } |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 556 const gpu::MailboxHolder& mailbox_holder, | 631 const gpu::MailboxHolder& mailbox_holder, |
| 557 VideoFrameExternalResources* external_resources) { | 632 VideoFrameExternalResources* external_resources) { |
| 558 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 633 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 559 SyncTokenClientImpl client(gl, mailbox_holder.sync_token); | 634 SyncTokenClientImpl client(gl, mailbox_holder.sync_token); |
| 560 | 635 |
| 561 const gfx::Size output_plane_resource_size = video_frame->coded_size(); | 636 const gfx::Size output_plane_resource_size = video_frame->coded_size(); |
| 562 // The copy needs to be a direct transfer of pixel data, so we use an RGBA8 | 637 // The copy needs to be a direct transfer of pixel data, so we use an RGBA8 |
| 563 // target to avoid loss of precision or dropping any alpha component. | 638 // target to avoid loss of precision or dropping any alpha component. |
| 564 const ResourceFormat copy_target_format = ResourceFormat::RGBA_8888; | 639 const ResourceFormat copy_target_format = ResourceFormat::RGBA_8888; |
| 565 | 640 |
| 566 // Search for an existing resource to reuse. | 641 const bool is_immutable = false; |
| 567 VideoResourceUpdater::ResourceList::iterator resource = all_resources_.end(); | 642 VideoResourceUpdater::ResourceList::iterator resource = |
| 568 | 643 RecycleOrAllocateTexture(output_plane_resource_size, copy_target_format, |
| 569 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { | 644 is_immutable); |
| 570 // Reuse resource if attributes match and the resource is a currently | |
| 571 // unreferenced texture. | |
| 572 if (it->resource_size() == output_plane_resource_size && | |
| 573 it->resource_format() == copy_target_format && | |
| 574 !it->mailbox().IsZero() && !it->has_refs() && | |
| 575 resource_provider_->GetTextureHint(it->resource_id()) != | |
| 576 ResourceProvider::TEXTURE_HINT_IMMUTABLE) { | |
| 577 resource = it; | |
| 578 break; | |
| 579 } | |
| 580 } | |
| 581 | |
| 582 // Otherwise allocate a new resource. | |
| 583 if (resource == all_resources_.end()) { | |
| 584 const bool is_immutable = false; | |
| 585 resource = AllocateResource(output_plane_resource_size, copy_target_format, | |
| 586 true, is_immutable); | |
| 587 } | |
| 588 | 645 |
| 589 resource->add_ref(); | 646 resource->add_ref(); |
| 590 | 647 |
| 591 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, | 648 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, |
| 592 resource->resource_id(), false); | 649 resource->resource_id(), false); |
| 593 DCHECK_EQ( | 650 DCHECK_EQ( |
| 594 resource_provider_->GetResourceTextureTarget(resource->resource_id()), | 651 resource_provider_->GetResourceTextureTarget(resource->resource_id()), |
| 595 (GLenum)GL_TEXTURE_2D); | 652 (GLenum)GL_TEXTURE_2D); |
| 596 | 653 |
| 597 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); | 654 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 if (lost_resource) { | 752 if (lost_resource) { |
| 696 resource_it->clear_refs(); | 753 resource_it->clear_refs(); |
| 697 updater->DeleteResource(resource_it); | 754 updater->DeleteResource(resource_it); |
| 698 return; | 755 return; |
| 699 } | 756 } |
| 700 | 757 |
| 701 resource_it->remove_ref(); | 758 resource_it->remove_ref(); |
| 702 } | 759 } |
| 703 | 760 |
| 704 } // namespace cc | 761 } // namespace cc |
| OLD | NEW |