Skip to content

Commit

Permalink
Specify YUVA info with SkYUVAPixmapInfo in image generators.
Browse files Browse the repository at this point in the history
This is a more structured way of specifying planar configurations that
makes it easier to add new configurations (i.e. alpha planes) and will
allow Skia to improve rendering quality by having a more precise
specification of the YUVA planar structure (e.g. correct handling
odd-dimensioned images with chroma subsampling and eventually
accounting for different sitings).

QueryYUVA now is told whether 16bit (either unorm or float) is supported
by the GPU decode cache based on texture format support.

Bug: skia:10632

Change-Id: Ibb240358a43a7f742d5ed7a5618b64a53fa4efc2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2365353
Reviewed-by: Khushal <khushalsagar@chromium.org>
Reviewed-by: Leon Scroggins <scroggo@google.com>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Cr-Commit-Position: refs/heads/master@{#806184}
  • Loading branch information
bsalomon authored and Commit Bot committed Sep 11, 2020
1 parent 2f409d1 commit 19618de
Show file tree
Hide file tree
Showing 29 changed files with 694 additions and 797 deletions.
53 changes: 17 additions & 36 deletions cc/paint/paint_image.cc
Original file line number Diff line number Diff line change
Expand Up @@ -212,19 +212,14 @@ bool PaintImage::Decode(void* memory,
client_id);
}

bool PaintImage::DecodeYuv(
void* planes[SkYUVASizeInfo::kMaxCount],
size_t frame_index,
GeneratorClientId client_id,
const SkYUVASizeInfo& yuva_size_info,
SkColorType color_type,
SkYUVAIndex plane_indices[SkYUVAIndex::kIndexCount]) const {
DCHECK(plane_indices != nullptr);
bool PaintImage::DecodeYuv(const SkYUVAPixmaps& pixmaps,
size_t frame_index,
GeneratorClientId client_id) const {
DCHECK(pixmaps.isValid());
DCHECK(paint_image_generator_);
const uint32_t lazy_pixel_ref = unique_id();
return paint_image_generator_->GetYUVAPlanes(yuva_size_info, color_type,
plane_indices, planes,
frame_index, lazy_pixel_ref);
return paint_image_generator_->GetYUVAPlanes(pixmaps, frame_index,
lazy_pixel_ref);
}

bool PaintImage::DecodeFromGenerator(void* memory,
Expand Down Expand Up @@ -347,31 +342,16 @@ const ImageHeaderMetadata* PaintImage::GetImageHeaderMetadata() const {
return nullptr;
}

bool PaintImage::IsYuv(SkYUVASizeInfo* yuva_size_info,
SkYUVAIndex* plane_indices,
SkYUVColorSpace* yuv_color_space,
uint8_t* bit_depth) const {
SkYUVASizeInfo temp_yuva_size_info;
SkYUVAIndex temp_plane_indices[SkYUVAIndex::kIndexCount];
SkYUVColorSpace temp_yuv_color_space;
uint8_t temp_bit_depth;
if (!yuva_size_info) {
yuva_size_info = &temp_yuva_size_info;
}
if (!plane_indices) {
plane_indices = temp_plane_indices;
}
if (!yuv_color_space) {
yuv_color_space = &temp_yuv_color_space;
}
if (!bit_depth) {
bit_depth = &temp_bit_depth;
}
// ImageDecoder will fill out the value of |yuv_color_space| depending on
// the codec's specification.
bool PaintImage::IsYuv(
const SkYUVAPixmapInfo::SupportedDataTypes& supported_data_types,
SkYUVAPixmapInfo* info) const {
SkYUVAPixmapInfo temp_info;
if (!info)
info = &temp_info;
// ImageDecoder will fill out the SkYUVColorSpace in |info| depending on the
// codec's specification.
return paint_image_generator_ &&
paint_image_generator_->QueryYUVA(yuva_size_info, plane_indices,
yuv_color_space, bit_depth);
paint_image_generator_->QueryYUVA(supported_data_types, info);
}

const std::vector<FrameMetadata>& PaintImage::GetFrameMetadata() const {
Expand Down Expand Up @@ -421,7 +401,8 @@ std::string PaintImage::ToString() const {
<< " id_: " << id_
<< " animation_type_: " << static_cast<int>(animation_type_)
<< " completion_state_: " << static_cast<int>(completion_state_)
<< " is_multipart_: " << is_multipart_ << " is YUV: " << IsYuv();
<< " is_multipart_: " << is_multipart_
<< " is YUV: " << IsYuv(SkYUVAPixmapInfo::SupportedDataTypes::All());
return str.str();
}

Expand Down
46 changes: 18 additions & 28 deletions cc/paint/paint_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
#include "cc/paint/paint_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkYUVAIndex.h"
#include "third_party/skia/include/core/SkYUVASizeInfo.h"
#include "third_party/skia/include/core/SkYUVAPixmaps.h"
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
Expand All @@ -34,6 +33,11 @@ enum class ImageType { kPNG, kJPEG, kWEBP, kGIF, kICO, kBMP, kAVIF, kInvalid };

enum class YUVSubsampling { k410, k411, k420, k422, k440, k444, kUnknown };

enum class YUVIndex { kY, kU, kV };

// Should match the number of YUVIndex values.
static constexpr int kNumYUVPlanes = 3;

struct CC_PAINT_EXPORT ImageHeaderMetadata {
public:
ImageHeaderMetadata();
Expand Down Expand Up @@ -206,29 +210,16 @@ class CC_PAINT_EXPORT PaintImage {
size_t frame_index,
GeneratorClientId client_id) const;

// Decode the image into YUV into |planes| for the given SkYUVASizeInfo.
// - Elements of the |planes| array are pointers to some underlying memory
// for each plane. It is assumed to have been split up by a call to
// SkYUVASizeInfo::computePlanes with the given |yuva_size_info|.
// - The amount of memory allocated must be at least
// |yuva_size_info|.computeTotalBytes(), though there are places in the
// code that assume YUV420 without alpha because it is currently the only
// subsampling supported for direct YUV rendering.
// - The dimensions of YUV planes are tracked in |yuva_size_info|.
// This struct is initialized by QueryYUVA in calls to
// PaintImage::IsYuv(), including within this method.
// Decode the image into YUV into |pixmaps|.
// - SkPixmaps owned by |pixmaps| are preallocated to store the
// planar data. They must have have color types, row bytes,
// and sizes as indicated by PaintImage::IsYuv().
// - The |frame_index| parameter will be passed along to
// ImageDecoder::DecodeToYUV but for multi-frame YUV support, ImageDecoder
// needs a separate YUV frame buffer cache.
// - The mapping of source planes to channels is tracked by |plane_indices|.
// This struct is initialized by QueryYUVA in calls to
// PaintImage::IsYuv(), including within this method.
bool DecodeYuv(void* planes[SkYUVASizeInfo::kMaxCount],
bool DecodeYuv(const SkYUVAPixmaps& pixmaps,
size_t frame_index,
GeneratorClientId client_id,
const SkYUVASizeInfo& yuva_size_info,
SkColorType yuva_color_type,
SkYUVAIndex* plane_indices) const;
GeneratorClientId client_id) const;

// Returns the SkImage associated with this PaintImage. If PaintImage is
// texture backed, this API will always do a readback from GPU to CPU memory,
Expand Down Expand Up @@ -284,13 +275,12 @@ class CC_PAINT_EXPORT PaintImage {
gfx::ContentColorUsage GetContentColorUsage() const;

// Returns whether this image will be decoded and rendered from YUV data
// and fills out plane size info, plane index info, and the matrix for
// conversion from YUV to RGB in, respectively, |yuva_size_info|,
// |plane_indices|, and |yuv_color_space| if any are provided.
bool IsYuv(SkYUVASizeInfo* yuva_size_info = nullptr,
SkYUVAIndex* plane_indices = nullptr,
SkYUVColorSpace* yuv_color_space = nullptr,
uint8_t* bit_depth = nullptr) const;
// and fills out |info|. |supported_data_types| indicates the bit depths and
// data types allowed. If successful, the caller can use |info| to allocate
// SkPixmaps to pass DecodeYuv() and render with the correct YUV->RGB
// transformation.
bool IsYuv(const SkYUVAPixmapInfo::SupportedDataTypes& supported_data_types,
SkYUVAPixmapInfo* info = nullptr) const;

// Get metadata associated with this image.
SkColorType GetColorType() const;
Expand Down
38 changes: 16 additions & 22 deletions cc/paint/paint_image_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkYUVAIndex.h"
#include "third_party/skia/include/core/SkYUVASizeInfo.h"
#include "third_party/skia/include/core/SkYUVAPixmaps.h"

namespace cc {

Expand Down Expand Up @@ -45,29 +44,24 @@ class CC_PAINT_EXPORT PaintImageGenerator : public SkRefCnt {
PaintImage::GeneratorClientId client_id,
uint32_t lazy_pixel_ref) = 0;

// Returns true if the generator supports YUV decoding, providing the output
// information in |info| and |color_space|.
virtual bool QueryYUVA(SkYUVASizeInfo* info,
SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
SkYUVColorSpace* color_space,
uint8_t* bit_depth) const = 0;

// Decodes to YUV into the provided |planes| for each of the Y, U, and V
// planes, and returns true on success. The method should only be used if
// QueryYUVA returns true.
// |info| and |indices| need to exactly match the values returned by the
// query, except the info.fWidthBytes may be larger than the recommendation
// (but not smaller).
// Returns true if the generator supports YUV decoding, providing the details
// about planar configuration and conversion to RGB in |info|.
// |supported_data_types| indicates the allowed bit depth and types allowed
// for Y, U, V, and A values.
virtual bool QueryYUVA(
const SkYUVAPixmapInfo::SupportedDataTypes& supported_data_types,
SkYUVAPixmapInfo* info) const = 0;

// Decodes to YUV, storing planar data in the SkPixmaps in the provided
// |pixmaps|. The method should only be used if QueryYUVA returns true.
// SkPixmaps owned by |pixmaps| have been configured as indicated by
// QueryYUVA.
//
// TODO(khushalsagar): |lazy_pixel_ref| is only present for
// DecodingImageGenerator tracing needs. Remove it.
virtual bool GetYUVAPlanes(
const SkYUVASizeInfo& info,
SkColorType color_type,
const SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
void* planes[3],
size_t frame_index,
uint32_t lazy_pixel_ref) = 0;
virtual bool GetYUVAPlanes(const SkYUVAPixmaps& pixmaps,
size_t frame_index,
uint32_t lazy_pixel_ref) = 0;

// Returns the smallest size that is at least as big as the requested size,
// such that we can decode to exactly that scale.
Expand Down
44 changes: 15 additions & 29 deletions cc/paint/paint_image_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,44 +74,30 @@ TEST(PaintImageTest, GetSkImageForFrameNotGeneratorBacked) {

TEST(PaintImageTest, DecodeToYuv420NoAlpha) {
const SkISize full_size = SkISize::Make(10, 10);
const SkISize uv_size = SkISize::Make(5, 5);
SkYUVASizeInfo yuva_size_info;
yuva_size_info.fSizes[SkYUVAIndex::kY_Index] = full_size;
yuva_size_info.fWidthBytes[SkYUVAIndex::kY_Index] =
base::checked_cast<size_t>(full_size.width());

yuva_size_info.fSizes[SkYUVAIndex::kU_Index] = uv_size;
yuva_size_info.fWidthBytes[SkYUVAIndex::kU_Index] =
base::checked_cast<size_t>(uv_size.width());

yuva_size_info.fSizes[SkYUVAIndex::kV_Index] = uv_size;
yuva_size_info.fWidthBytes[SkYUVAIndex::kV_Index] =
base::checked_cast<size_t>(uv_size.width());

yuva_size_info.fSizes[SkYUVAIndex::kA_Index] = SkISize::MakeEmpty();
yuva_size_info.fWidthBytes[SkYUVAIndex::kA_Index] = 0u;

SkYUVAInfo yuva_info(full_size, SkYUVAInfo::PlanarConfig::kY_U_V_420,
kJPEG_Full_SkYUVColorSpace);
SkYUVAPixmapInfo yuva_pixmap_info(yuva_info,
SkYUVAPixmapInfo::DataType::kUnorm8,
/*row bytes*/ nullptr);
sk_sp<FakePaintImageGenerator> yuv_generator =
sk_make_sp<FakePaintImageGenerator>(SkImageInfo::MakeN32Premul(full_size),
yuva_size_info);
yuva_pixmap_info);
PaintImage image = PaintImageBuilder::WithDefault()
.set_id(PaintImage::GetNextId())
.set_paint_image_generator(yuv_generator)
.TakePaintImage();

std::vector<uint8_t> memory(yuva_size_info.computeTotalBytes());
void* planes[SkYUVASizeInfo::kMaxCount];
yuva_size_info.computePlanes(memory.data(), planes);
std::vector<uint8_t> memory(yuva_pixmap_info.computeTotalBytes());
auto pixmaps =
SkYUVAPixmaps::FromExternalMemory(yuva_pixmap_info, memory.data());

SkYUVASizeInfo image_yuv_size_info;
SkYUVAIndex image_plane_indices[SkYUVAIndex::kIndexCount];
ASSERT_TRUE(image.IsYuv(&image_yuv_size_info, image_plane_indices));
ASSERT_EQ(yuva_size_info, image_yuv_size_info);
SkYUVAPixmapInfo image_yuva_pixmap_info;
ASSERT_TRUE(image.IsYuv(SkYUVAPixmapInfo::SupportedDataTypes::All(),
&image_yuva_pixmap_info));
ASSERT_EQ(yuva_pixmap_info, image_yuva_pixmap_info);

SkYUVAIndex plane_indices[SkYUVAIndex::kIndexCount];
image.DecodeYuv(planes, 1u /* frame_index */,
PaintImage::kDefaultGeneratorClientId, yuva_size_info,
kGray_8_SkColorType /* color_type */, plane_indices);
image.DecodeYuv(pixmaps, 1u /* frame_index */,
PaintImage::kDefaultGeneratorClientId);
ASSERT_EQ(yuv_generator->frames_decoded().size(), 1u);
EXPECT_EQ(yuv_generator->frames_decoded().count(1u), 1u);
yuv_generator->reset_frames_decoded();
Expand Down
27 changes: 12 additions & 15 deletions cc/paint/skia_paint_image_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,20 @@ bool SkiaPaintImageGenerator::onGetPixels(const SkImageInfo& info,
info, pixels, row_bytes, frame_index_, client_id_, uniqueID());
}

bool SkiaPaintImageGenerator::onQueryYUVA8(
SkYUVASizeInfo* size_info,
SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
SkYUVColorSpace* color_space) const {
// Only 8-bit YUV is supported by the SkImageGenerator.
uint8_t bit_depth = 8;
const bool result = paint_image_generator_->QueryYUVA(
size_info, indices, color_space, &bit_depth);
return result && bit_depth == 8;
bool SkiaPaintImageGenerator::onQueryYUVAInfo(
const SkYUVAPixmapInfo::SupportedDataTypes& supported_data_types,
SkYUVAPixmapInfo* yuva_pixmap_info) const {
if (!paint_image_generator_->QueryYUVA(supported_data_types,
yuva_pixmap_info)) {
return false;
}
// TODO(skbug.com/10632): Enable other bit depths now that they are supported
// by SkImageGenerator. There's no known reason that this should not work.
return yuva_pixmap_info->dataType() == SkYUVAPixmapInfo::DataType::kUnorm8;
}

bool SkiaPaintImageGenerator::onGetYUVA8Planes(
const SkYUVASizeInfo& size_info,
const SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
void* planes[4]) {
return paint_image_generator_->GetYUVAPlanes(size_info, kGray_8_SkColorType,
indices, planes, frame_index_,
bool SkiaPaintImageGenerator::onGetYUVAPlanes(const SkYUVAPixmaps& planes) {
return paint_image_generator_->GetYUVAPlanes(planes, frame_index_,
uniqueID());
}

Expand Down
12 changes: 6 additions & 6 deletions cc/paint/skia_paint_image_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ class CC_PAINT_EXPORT SkiaPaintImageGenerator final : public SkImageGenerator {
void* pixels,
size_t row_bytes,
const Options& options) override;
bool onQueryYUVA8(SkYUVASizeInfo* size_info,
SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
SkYUVColorSpace* color_space) const override;
bool onGetYUVA8Planes(const SkYUVASizeInfo& size_info,
const SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
void* planes[3]) override;

bool onQueryYUVAInfo(
const SkYUVAPixmapInfo::SupportedDataTypes& supported_data_types,
SkYUVAPixmapInfo* yuva_pixmap_info) const override;

bool onGetYUVAPlanes(const SkYUVAPixmaps& planes) override;

private:
sk_sp<PaintImageGenerator> paint_image_generator_;
Expand Down
Loading

0 comments on commit 19618de

Please sign in to comment.