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 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 DeleteResource(it++); | 339 DeleteResource(it++); |
| 340 else | 340 else |
| 341 ++it; | 341 ++it; |
| 342 } | 342 } |
| 343 | 343 |
| 344 const int max_resource_size = resource_provider_->max_texture_size(); | 344 const int max_resource_size = resource_provider_->max_texture_size(); |
| 345 std::vector<ResourceList::iterator> plane_resources; | 345 std::vector<ResourceList::iterator> plane_resources; |
| 346 for (size_t i = 0; i < output_plane_count; ++i) { | 346 for (size_t i = 0; i < output_plane_count; ++i) { |
| 347 gfx::Size output_plane_resource_size = | 347 gfx::Size output_plane_resource_size = |
| 348 SoftwarePlaneDimension(video_frame.get(), software_compositor, i); | 348 SoftwarePlaneDimension(video_frame.get(), software_compositor, i); |
| 349 ResourceFormat plane_resource_format = output_resource_format; | |
| 350 if ((input_frame_format == media::PIXEL_FORMAT_NV12) && (i == 1)) { | |
|
danakj
2016/04/13 00:24:18
If all of this is for tests I'd prefer to just not
| |
| 351 // A two-byte-per-pixel format would avoid wasting space, but this is | |
| 352 // only used in testing. | |
| 353 plane_resource_format = RGBA_8888; | |
| 354 } | |
| 349 if (output_plane_resource_size.IsEmpty() || | 355 if (output_plane_resource_size.IsEmpty() || |
| 350 output_plane_resource_size.width() > max_resource_size || | 356 output_plane_resource_size.width() > max_resource_size || |
| 351 output_plane_resource_size.height() > max_resource_size) { | 357 output_plane_resource_size.height() > max_resource_size) { |
| 352 break; | 358 break; |
| 353 } | 359 } |
| 354 | 360 |
| 355 // Try recycle a previously-allocated resource. | 361 // Try recycle a previously-allocated resource. |
| 356 ResourceList::iterator resource_it = all_resources_.end(); | 362 ResourceList::iterator resource_it = all_resources_.end(); |
| 357 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { | 363 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { |
| 358 if (it->resource_size == output_plane_resource_size && | 364 if (it->resource_size == output_plane_resource_size && |
| 359 it->resource_format == output_resource_format) { | 365 it->resource_format == plane_resource_format) { |
| 360 if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) { | 366 if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) { |
| 361 // Bingo, we found a resource that already contains the data we are | 367 // Bingo, we found a resource that already contains the data we are |
| 362 // planning to put in it. It's safe to reuse it even if | 368 // planning to put in it. It's safe to reuse it even if |
| 363 // resource_provider_ holds some references to it, because those | 369 // resource_provider_ holds some references to it, because those |
| 364 // references are read-only. | 370 // references are read-only. |
| 365 resource_it = it; | 371 resource_it = it; |
| 366 break; | 372 break; |
| 367 } | 373 } |
| 368 | 374 |
| 369 // This extra check is needed because resources backed by SharedMemory | 375 // This extra check is needed because resources backed by SharedMemory |
| 370 // are not ref-counted, unlike mailboxes. Full discussion in | 376 // are not ref-counted, unlike mailboxes. Full discussion in |
| 371 // codereview.chromium.org/145273021. | 377 // codereview.chromium.org/145273021. |
| 372 const bool in_use = | 378 const bool in_use = |
| 373 software_compositor && | 379 software_compositor && |
| 374 resource_provider_->InUseByConsumer(it->resource_id); | 380 resource_provider_->InUseByConsumer(it->resource_id); |
| 375 if (it->ref_count == 0 && !in_use) { | 381 if (it->ref_count == 0 && !in_use) { |
| 376 // We found a resource with the correct size that we can overwrite. | 382 // We found a resource with the correct size that we can overwrite. |
| 377 resource_it = it; | 383 resource_it = it; |
| 378 } | 384 } |
| 379 } | 385 } |
| 380 } | 386 } |
| 381 | 387 |
| 382 // Check if we need to allocate a new resource. | 388 // Check if we need to allocate a new resource. |
| 383 if (resource_it == all_resources_.end()) { | 389 if (resource_it == all_resources_.end()) { |
| 384 const bool is_immutable = true; | 390 const bool is_immutable = true; |
| 385 resource_it = | 391 resource_it = |
| 386 AllocateResource(output_plane_resource_size, output_resource_format, | 392 AllocateResource(output_plane_resource_size, plane_resource_format, |
| 387 !software_compositor, is_immutable); | 393 !software_compositor, is_immutable); |
| 388 } | 394 } |
| 389 if (resource_it == all_resources_.end()) | 395 if (resource_it == all_resources_.end()) |
| 390 break; | 396 break; |
| 391 | 397 |
| 392 ++resource_it->ref_count; | 398 ++resource_it->ref_count; |
| 393 plane_resources.push_back(resource_it); | 399 plane_resources.push_back(resource_it); |
| 394 } | 400 } |
| 395 | 401 |
| 396 if (plane_resources.size() != output_plane_count) { | 402 if (plane_resources.size() != output_plane_count) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 433 external_resources.software_resources.push_back(plane_resource.resource_id); | 439 external_resources.software_resources.push_back(plane_resource.resource_id); |
| 434 external_resources.software_release_callback = | 440 external_resources.software_release_callback = |
| 435 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id); | 441 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id); |
| 436 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; | 442 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; |
| 437 return external_resources; | 443 return external_resources; |
| 438 } | 444 } |
| 439 | 445 |
| 440 for (size_t i = 0; i < plane_resources.size(); ++i) { | 446 for (size_t i = 0; i < plane_resources.size(); ++i) { |
| 441 PlaneResource& plane_resource = *plane_resources[i]; | 447 PlaneResource& plane_resource = *plane_resources[i]; |
| 442 // Update each plane's resource id with its content. | 448 // Update each plane's resource id with its content. |
| 443 DCHECK_EQ(plane_resource.resource_format, | |
| 444 resource_provider_->YuvResourceFormat(bits_per_channel)); | |
| 445 | |
| 446 if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) { | 449 if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) { |
| 447 // We need to transfer data from |video_frame| to the plane resource. | 450 // We need to transfer data from |video_frame| to the plane resource. |
| 448 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. | 451 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. |
| 449 | 452 |
| 450 // The |resource_size_pixels| is the size of the resource we want to | 453 // The |resource_size_pixels| is the size of the resource we want to |
| 451 // upload to. | 454 // upload to. |
| 452 gfx::Size resource_size_pixels = plane_resource.resource_size; | 455 gfx::Size resource_size_pixels = plane_resource.resource_size; |
| 453 // The |video_stride_bytes| is the width of the video frame we are | 456 // The |video_stride_bytes| is the width of the video frame we are |
| 454 // uploading (including non-frame data to fill in the stride). | 457 // uploading (including non-frame data to fill in the stride). |
| 455 int video_stride_bytes = video_frame->stride(i); | 458 int video_stride_bytes = video_frame->stride(i); |
| 456 | 459 |
| 457 size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( | 460 size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( |
| 458 resource_size_pixels.width(), plane_resource.resource_format); | 461 resource_size_pixels.width(), plane_resource.resource_format); |
| 459 // Use 4-byte row alignment (OpenGL default) for upload performance. | 462 // Use 4-byte row alignment (OpenGL default) for upload performance. |
| 460 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. | 463 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. |
| 461 size_t upload_image_stride = | 464 size_t upload_image_stride = |
| 462 MathUtil::UncheckedRoundUp<size_t>(bytes_per_row, 4u); | 465 MathUtil::UncheckedRoundUp<size_t>(bytes_per_row, 4u); |
| 463 | 466 |
| 464 bool needs_conversion = false; | 467 bool needs_conversion = false; |
| 465 int shift = 0; | 468 int shift = 0; |
| 469 bool needs_expansion = false; | |
| 466 | 470 |
| 467 // LUMINANCE_F16 uses half-floats, so we always need a conversion step. | 471 // LUMINANCE_F16 uses half-floats, so we always need a conversion step. |
| 468 if (plane_resource.resource_format == LUMINANCE_F16) { | 472 if (plane_resource.resource_format == LUMINANCE_F16) { |
| 469 needs_conversion = true; | 473 needs_conversion = true; |
| 470 // Note that the current method of converting integers to half-floats | 474 // Note that the current method of converting integers to half-floats |
| 471 // stops working if you have more than 10 bits of data. | 475 // stops working if you have more than 10 bits of data. |
| 472 DCHECK_LE(bits_per_channel, 10); | 476 DCHECK_LE(bits_per_channel, 10); |
| 473 } else if (bits_per_channel > 8) { | 477 } else if (bits_per_channel > 8) { |
| 474 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to | 478 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to |
| 475 // shift the data down and create an 8-bit texture. | 479 // shift the data down and create an 8-bit texture. |
| 476 needs_conversion = true; | 480 needs_conversion = true; |
| 477 shift = bits_per_channel - 8; | 481 shift = bits_per_channel - 8; |
| 482 } else if ((input_frame_format == media::PIXEL_FORMAT_NV12) && (i == 1)) { | |
| 483 DCHECK_EQ(RGBA_8888, plane_resource.resource_format); | |
| 484 needs_conversion = true; | |
| 485 // Expand each 2 byte pixel into 4 bytes. | |
| 486 needs_expansion = true; | |
| 478 } | 487 } |
| 479 const uint8_t* pixels; | 488 const uint8_t* pixels; |
| 480 if (static_cast<int>(upload_image_stride) == video_stride_bytes && | 489 if (static_cast<int>(upload_image_stride) == video_stride_bytes && |
| 481 !needs_conversion) { | 490 !needs_conversion) { |
| 482 pixels = video_frame->data(i); | 491 pixels = video_frame->data(i); |
| 483 } else { | 492 } else { |
| 484 // Avoid malloc for each frame/plane if possible. | 493 // Avoid malloc for each frame/plane if possible. |
| 485 size_t needed_size = | 494 size_t needed_size = |
| 486 upload_image_stride * resource_size_pixels.height(); | 495 upload_image_stride * resource_size_pixels.height(); |
| 487 if (upload_pixels_.size() < needed_size) | 496 if (upload_pixels_.size() < needed_size) |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 501 for (size_t i = 0; i < bytes_per_row / 2; i++) | 510 for (size_t i = 0; i < bytes_per_row / 2; i++) |
| 502 dst[i] = src[i] | 0x3800; | 511 dst[i] = src[i] | 0x3800; |
| 503 } else if (shift != 0) { | 512 } else if (shift != 0) { |
| 504 // We have more-than-8-bit input which we need to shift | 513 // We have more-than-8-bit input which we need to shift |
| 505 // down to fit it into an 8-bit texture. | 514 // down to fit it into an 8-bit texture. |
| 506 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; | 515 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; |
| 507 const uint16_t* src = reinterpret_cast<uint16_t*>( | 516 const uint16_t* src = reinterpret_cast<uint16_t*>( |
| 508 video_frame->data(i) + (video_stride_bytes * row)); | 517 video_frame->data(i) + (video_stride_bytes * row)); |
| 509 for (size_t i = 0; i < bytes_per_row; i++) | 518 for (size_t i = 0; i < bytes_per_row; i++) |
| 510 dst[i] = src[i] >> shift; | 519 dst[i] = src[i] >> shift; |
| 520 } else if (needs_expansion) { | |
| 521 uint32_t* dst = reinterpret_cast<uint32_t*>( | |
| 522 &upload_pixels_[upload_image_stride * row]); | |
| 523 const uint8_t* src = | |
| 524 video_frame->data(i) + (video_stride_bytes * row); | |
| 525 for (size_t i = 0; i < bytes_per_row / 4; i++) { | |
| 526 // The first channel (U) goes in the R component, and the second | |
| 527 // (V) goes in the G component. B and A are black. | |
| 528 dst[i] = ((src[i * 2] << 24) | (src[i * 2 + 1] << 16)); | |
| 529 } | |
| 511 } else { | 530 } else { |
| 512 // Input and output are the same size and format, but | 531 // Input and output are the same size and format, but |
| 513 // differ in stride, copy one row at a time. | 532 // differ in stride, copy one row at a time. |
| 514 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; | 533 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; |
| 515 const uint8_t* src = | 534 const uint8_t* src = |
| 516 video_frame->data(i) + (video_stride_bytes * row); | 535 video_frame->data(i) + (video_stride_bytes * row); |
| 517 memcpy(dst, src, bytes_per_row); | 536 memcpy(dst, src, bytes_per_row); |
| 518 } | 537 } |
| 519 } | 538 } |
| 520 pixels = &upload_pixels_[0]; | 539 pixels = &upload_pixels_[0]; |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 757 plane_resource.plane_index == 0; | 776 plane_resource.plane_index == 0; |
| 758 }); | 777 }); |
| 759 if (resource_it == updater->all_resources_.end()) | 778 if (resource_it == updater->all_resources_.end()) |
| 760 return; | 779 return; |
| 761 | 780 |
| 762 resource_it->destructed = true; | 781 resource_it->destructed = true; |
| 763 } | 782 } |
| 764 #endif | 783 #endif |
| 765 | 784 |
| 766 } // namespace cc | 785 } // namespace cc |
| OLD | NEW |