Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(446)

Side by Side Diff: cc/resources/video_resource_updater.cc

Issue 2242453002: Avoid planar YUV resources when one component EGL images are not supported (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: modify comment to explain the use of RGBA_8888 to trigger a driver workaround Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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(
176 const gfx::Size& resource_size,
177 ResourceFormat resource_format,
178 const gfx::ColorSpace& color_space,
179 bool immutable_hint) {
180 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) {
181 // Reuse resource if attributes match and the resource is a currently
182 // unreferenced texture.
183 if (it->resource_size() == resource_size &&
184 it->resource_format() == resource_format && !it->mailbox().IsZero() &&
185 !it->has_refs() &&
186 resource_provider_->GetTextureHint(it->resource_id()) !=
187 ResourceProvider::TEXTURE_HINT_IMMUTABLE) {
188 return it;
189 }
190 }
191
192 // Otherwise allocate a new resource.
193 return AllocateResource(resource_size, resource_format, color_space, true,
194 immutable_hint);
195 }
196
197 VideoResourceUpdater::ResourceList::iterator
175 VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size, 198 VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size,
176 ResourceFormat format, 199 ResourceFormat format,
177 const gfx::ColorSpace& color_space, 200 const gfx::ColorSpace& color_space,
178 bool has_mailbox, 201 bool has_mailbox,
179 bool immutable_hint) { 202 bool immutable_hint) {
180 // TODO(danakj): Abstract out hw/sw resource create/delete from 203 // TODO(danakj): Abstract out hw/sw resource create/delete from
181 // ResourceProvider and stop using ResourceProvider in this class. 204 // ResourceProvider and stop using ResourceProvider in this class.
182 const ResourceId resource_id = resource_provider_->CreateResource( 205 const ResourceId resource_id = resource_provider_->CreateResource(
183 plane_size, immutable_hint ? ResourceProvider::TEXTURE_HINT_IMMUTABLE 206 plane_size, immutable_hint ? ResourceProvider::TEXTURE_HINT_IMMUTABLE
184 : ResourceProvider::TEXTURE_HINT_DEFAULT, 207 : ResourceProvider::TEXTURE_HINT_DEFAULT,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 if (software_compositor) 262 if (software_compositor)
240 return coded_size; 263 return coded_size;
241 264
242 int plane_width = media::VideoFrame::Columns( 265 int plane_width = media::VideoFrame::Columns(
243 plane_index, input_frame->format(), coded_size.width()); 266 plane_index, input_frame->format(), coded_size.width());
244 int plane_height = media::VideoFrame::Rows(plane_index, input_frame->format(), 267 int plane_height = media::VideoFrame::Rows(plane_index, input_frame->format(),
245 coded_size.height()); 268 coded_size.height());
246 return gfx::Size(plane_width, plane_height); 269 return gfx::Size(plane_width, plane_height);
247 } 270 }
248 271
272 // Create an RGB texture by software converting YUV planar data, for the case
273 // where YUV planar textures are not renderable by the GPU.
274 VideoFrameExternalResources
275 VideoResourceUpdater::CreateRGBTextureForSoftwarePlanes(
276 media::VideoFrame* video_frame) {
277 DCHECK(media::IsYuvPlanar(video_frame->format()));
278 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
279 const ResourceFormat resource_format = ResourceFormat::RGBA_8888;
280 const gfx::Size output_plane_resource_size = video_frame->coded_size();
281 const bool is_immutable = false;
282
283 VideoResourceUpdater::ResourceList::iterator resource =
284 RecycleOrAllocateTexture(output_plane_resource_size, resource_format,
285 is_immutable);
286
287 resource->add_ref();
288
289 size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>(
290 output_plane_resource_size.width(), ResourceFormat::RGBA_8888);
291 size_t upload_image_stride =
292 MathUtil::CheckedRoundUp<size_t>(bytes_per_row, 4u);
danakj 2016/08/25 01:25:39 If the format is RGBA8888 how can the bytes per ro
Tobias Sargeant 2016/08/26 15:52:11 True, removed.
293 size_t needed_size =
294 upload_image_stride * output_plane_resource_size.height();
295 if (upload_pixels_.size() < needed_size)
296 upload_pixels_.resize(needed_size);
297
298 media::SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
299 video_frame, &upload_pixels_[0], upload_image_stride);
300
301 resource_provider_->CopyToResource(
302 resource->resource_id(), &upload_pixels_[0], resource->resource_size());
303
304 gpu::SyncToken sync_token;
305 const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM();
306 gl->ShallowFlushCHROMIUM();
307 gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
308
309 VideoFrameExternalResources external_resources;
310
311 external_resources.mailboxes.push_back(
312 TextureMailbox(resource->mailbox(), sync_token, GL_TEXTURE_2D,
313 video_frame->coded_size(), false, false));
314 external_resources.release_callbacks.push_back(
315 base::Bind(&RecycleResource, AsWeakPtr(), resource->resource_id()));
316 external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE;
317 return external_resources;
318 }
319
249 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( 320 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
250 scoped_refptr<media::VideoFrame> video_frame) { 321 scoped_refptr<media::VideoFrame> video_frame) {
251 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); 322 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes");
252 const media::VideoPixelFormat input_frame_format = video_frame->format(); 323 const media::VideoPixelFormat input_frame_format = video_frame->format();
253 324
254 // TODO(hubbe): Make this a video frame method. 325 // TODO(hubbe): Make this a video frame method.
255 int bits_per_channel = 0; 326 int bits_per_channel = 0;
256 switch (input_frame_format) { 327 switch (input_frame_format) {
257 case media::PIXEL_FORMAT_UNKNOWN: 328 case media::PIXEL_FORMAT_UNKNOWN:
258 NOTREACHED(); 329 NOTREACHED();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 if (!media::IsYuvPlanar(input_frame_format)) { 361 if (!media::IsYuvPlanar(input_frame_format)) {
291 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); 362 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format);
292 return VideoFrameExternalResources(); 363 return VideoFrameExternalResources();
293 } 364 }
294 365
295 const bool software_compositor = context_provider_ == NULL; 366 const bool software_compositor = context_provider_ == NULL;
296 367
297 ResourceFormat output_resource_format = 368 ResourceFormat output_resource_format =
298 resource_provider_->YuvResourceFormat(bits_per_channel); 369 resource_provider_->YuvResourceFormat(bits_per_channel);
299 370
371 // If GPU compositing is enabled, but the output resource format
372 // returned by the resource provider is RGBA_8888, then a GPU driver
373 // bug workaround requires that YUV frames must be converted to RGB
374 // before texture upload.
375 if (!software_compositor &&
376 output_resource_format == ResourceFormat::RGBA_8888) {
377 return CreateRGBTextureForSoftwarePlanes(video_frame.get());
378 }
379
300 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); 380 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format);
301 381
302 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB 382 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
303 // conversion here. That involves an extra copy of each frame to a bitmap. 383 // conversion here. That involves an extra copy of each frame to a bitmap.
304 // Obviously, this is suboptimal and should be addressed once ubercompositor 384 // Obviously, this is suboptimal and should be addressed once ubercompositor
305 // starts shaping up. 385 // starts shaping up.
306 if (software_compositor) { 386 if (software_compositor) {
307 output_resource_format = kRGBResourceFormat; 387 output_resource_format = kRGBResourceFormat;
308 output_plane_count = 1; 388 output_plane_count = 1;
309 } 389 }
310 390
311 // Drop recycled resources that are the wrong format. 391 // Drop recycled resources that are the wrong format.
danakj 2016/08/25 01:25:39 You're skipping code like this. I would have expec
312 for (auto it = all_resources_.begin(); it != all_resources_.end();) { 392 for (auto it = all_resources_.begin(); it != all_resources_.end();) {
313 if (!it->has_refs() && it->resource_format() != output_resource_format) 393 if (!it->has_refs() && it->resource_format() != output_resource_format)
314 DeleteResource(it++); 394 DeleteResource(it++);
315 else 395 else
316 ++it; 396 ++it;
317 } 397 }
318 398
319 const int max_resource_size = resource_provider_->max_texture_size(); 399 const int max_resource_size = resource_provider_->max_texture_size();
320 std::vector<ResourceList::iterator> plane_resources; 400 std::vector<ResourceList::iterator> plane_resources;
321 for (size_t i = 0; i < output_plane_count; ++i) { 401 for (size_t i = 0; i < output_plane_count; ++i) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 461
382 if (software_compositor) { 462 if (software_compositor) {
383 DCHECK_EQ(plane_resources.size(), 1u); 463 DCHECK_EQ(plane_resources.size(), 1u);
384 PlaneResource& plane_resource = *plane_resources[0]; 464 PlaneResource& plane_resource = *plane_resources[0];
385 DCHECK_EQ(plane_resource.resource_format(), kRGBResourceFormat); 465 DCHECK_EQ(plane_resource.resource_format(), kRGBResourceFormat);
386 DCHECK(plane_resource.mailbox().IsZero()); 466 DCHECK(plane_resource.mailbox().IsZero());
387 467
388 if (!plane_resource.Matches(video_frame->unique_id(), 0)) { 468 if (!plane_resource.Matches(video_frame->unique_id(), 0)) {
389 // We need to transfer data from |video_frame| to the plane resource. 469 // We need to transfer data from |video_frame| to the plane resource.
390 if (!video_renderer_) 470 if (!video_renderer_)
391 video_renderer_.reset(new media::SkCanvasVideoRenderer); 471 video_renderer_.reset(new media::SkCanvasVideoRenderer);
danakj 2016/08/25 01:25:39 Why are you using a diff skia thing to convert yuv
Tobias Sargeant 2016/08/26 15:52:11 I've reworked this to keep more of the original co
392 472
393 ResourceProvider::ScopedWriteLockSoftware lock( 473 ResourceProvider::ScopedWriteLockSoftware lock(
394 resource_provider_, plane_resource.resource_id()); 474 resource_provider_, plane_resource.resource_id());
395 SkCanvas canvas(lock.sk_bitmap()); 475 SkCanvas canvas(lock.sk_bitmap());
396 // This is software path, so canvas and video_frame are always backed 476 // This is software path, so canvas and video_frame are always backed
397 // by software. 477 // by software.
398 video_renderer_->Copy(video_frame, &canvas, media::Context3D()); 478 video_renderer_->Copy(video_frame, &canvas, media::Context3D());
danakj 2016/08/25 01:25:39 Then you could pass a context here when !software_
399 plane_resource.SetUniqueId(video_frame->unique_id(), 0); 479 plane_resource.SetUniqueId(video_frame->unique_id(), 0);
danakj 2016/08/25 01:25:39 And then you don't miss important stuff like this.
400 } 480 }
401 481
402 external_resources.software_resources.push_back( 482 external_resources.software_resources.push_back(
403 plane_resource.resource_id()); 483 plane_resource.resource_id());
404 external_resources.software_release_callback = 484 external_resources.software_release_callback =
405 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id()); 485 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id());
406 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; 486 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
407 return external_resources; 487 return external_resources;
408 } 488 }
409 489
410 for (size_t i = 0; i < plane_resources.size(); ++i) { 490 for (size_t i = 0; i < plane_resources.size(); ++i) {
411 PlaneResource& plane_resource = *plane_resources[i]; 491 PlaneResource& plane_resource = *plane_resources[i];
412 // Update each plane's resource id with its content. 492 // Update each plane's resource id with its content.
413 DCHECK_EQ(plane_resource.resource_format(), 493 DCHECK_EQ(plane_resource.resource_format(),
414 resource_provider_->YuvResourceFormat(bits_per_channel)); 494 resource_provider_->YuvResourceFormat(bits_per_channel));
415 495
416 if (!plane_resource.Matches(video_frame->unique_id(), i)) { 496 if (!plane_resource.Matches(video_frame->unique_id(), i)) {
417 // We need to transfer data from |video_frame| to the plane resource. 497 // We need to transfer data from |video_frame| to the plane resource.
418 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. 498 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance.
419 499
420 // The |resource_size_pixels| is the size of the resource we want to 500 // The |resource_size_pixels| is the size of the resource we want to
421 // upload to. 501 // upload to.
422 gfx::Size resource_size_pixels = plane_resource.resource_size(); 502 gfx::Size resource_size_pixels = plane_resource.resource_size();
423 // The |video_stride_bytes| is the width of the video frame we are 503 // The |video_stride_bytes| is the width of the video frame we are
424 // uploading (including non-frame data to fill in the stride). 504 // uploading (including non-frame data to fill in the stride).
425 int video_stride_bytes = video_frame->stride(i); 505 int video_stride_bytes = video_frame->stride(i);
426 506
427 size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( 507 size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>(
428 resource_size_pixels.width(), plane_resource.resource_format()); 508 resource_size_pixels.width(), plane_resource.resource_format());
429 // Use 4-byte row alignment (OpenGL default) for upload performance. 509 // Use 4-byte row alignment (OpenGL default) for upload performance.
430 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. 510 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
431 size_t upload_image_stride = 511 size_t upload_image_stride =
432 MathUtil::UncheckedRoundUp<size_t>(bytes_per_row, 4u); 512 MathUtil::CheckedRoundUp<size_t>(bytes_per_row, 4u);
433 513
434 bool needs_conversion = false; 514 bool needs_conversion = false;
435 int shift = 0; 515 int shift = 0;
436 516
437 // LUMINANCE_F16 uses half-floats, so we always need a conversion step. 517 // LUMINANCE_F16 uses half-floats, so we always need a conversion step.
438 if (plane_resource.resource_format() == LUMINANCE_F16) { 518 if (plane_resource.resource_format() == LUMINANCE_F16) {
439 needs_conversion = true; 519 needs_conversion = true;
440 // Note that the current method of converting integers to half-floats 520 // Note that the current method of converting integers to half-floats
441 // stops working if you have more than 10 bits of data. 521 // stops working if you have more than 10 bits of data.
442 DCHECK_LE(bits_per_channel, 10); 522 DCHECK_LE(bits_per_channel, 10);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 const gpu::MailboxHolder& mailbox_holder, 637 const gpu::MailboxHolder& mailbox_holder,
558 VideoFrameExternalResources* external_resources) { 638 VideoFrameExternalResources* external_resources) {
559 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); 639 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
560 SyncTokenClientImpl client(gl, mailbox_holder.sync_token); 640 SyncTokenClientImpl client(gl, mailbox_holder.sync_token);
561 641
562 const gfx::Size output_plane_resource_size = video_frame->coded_size(); 642 const gfx::Size output_plane_resource_size = video_frame->coded_size();
563 // The copy needs to be a direct transfer of pixel data, so we use an RGBA8 643 // The copy needs to be a direct transfer of pixel data, so we use an RGBA8
564 // target to avoid loss of precision or dropping any alpha component. 644 // target to avoid loss of precision or dropping any alpha component.
565 const ResourceFormat copy_target_format = ResourceFormat::RGBA_8888; 645 const ResourceFormat copy_target_format = ResourceFormat::RGBA_8888;
566 646
567 // Search for an existing resource to reuse. 647 const bool is_immutable = false;
568 VideoResourceUpdater::ResourceList::iterator resource = all_resources_.end(); 648 VideoResourceUpdater::ResourceList::iterator resource =
569 649 RecycleOrAllocateTexture(output_plane_resource_size, copy_target_format,
570 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { 650 video_frame->ColorSpace(), is_immutable);
571 // Reuse resource if attributes match and the resource is a currently
572 // unreferenced texture.
573 if (it->resource_size() == output_plane_resource_size &&
574 it->resource_format() == copy_target_format &&
575 !it->mailbox().IsZero() && !it->has_refs() &&
576 resource_provider_->GetTextureHint(it->resource_id()) !=
577 ResourceProvider::TEXTURE_HINT_IMMUTABLE) {
578 resource = it;
579 break;
580 }
581 }
582
583 // Otherwise allocate a new resource.
584 if (resource == all_resources_.end()) {
585 const bool is_immutable = false;
586 resource = AllocateResource(output_plane_resource_size, copy_target_format,
587 video_frame->ColorSpace(), true, is_immutable);
588 }
589 651
590 resource->add_ref(); 652 resource->add_ref();
591 653
592 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, 654 ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
593 resource->resource_id(), false); 655 resource->resource_id(), false);
594 DCHECK_EQ( 656 DCHECK_EQ(
595 resource_provider_->GetResourceTextureTarget(resource->resource_id()), 657 resource_provider_->GetResourceTextureTarget(resource->resource_id()),
596 (GLenum)GL_TEXTURE_2D); 658 (GLenum)GL_TEXTURE_2D);
597 659
598 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); 660 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
696 if (lost_resource) { 758 if (lost_resource) {
697 resource_it->clear_refs(); 759 resource_it->clear_refs();
698 updater->DeleteResource(resource_it); 760 updater->DeleteResource(resource_it);
699 return; 761 return;
700 } 762 }
701 763
702 resource_it->remove_ref(); 764 resource_it->remove_ref();
703 } 765 }
704 766
705 } // namespace cc 767 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698