From ed6344458750c0389b7ccce588b96d0c25397b19 Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Tue, 1 Sep 2020 15:01:15 -0400 Subject: [PATCH] Add idea of DataType to SkYUVAPixmapInfo. DataType describes the data type of YUVA channels independent of how they are grouped into planes. Adds mapping functions between SkColorType/channel count and DataType. SkYUVAPixmapInfo can be constructed from DataType and will choose appropriate SkColorTypes for each plane. Valid SkYUVAPixmapInfos now have the same DataType for each plane (could relax this in the future, esp for alpha plane). SkYUVAPixmapInfo::SupportedDataTypes specifies the supported combinations of SkYUVAInfo::PlanarConfig and kYUVAPixmapInfo::DataType supported by a GrContext (based on supported texture formats). SkImageGenerator/SkCodec YUVA query API now takes a SupportedDataTypes. Change-Id: I8791234638e6ba3396d1e7960b7bc210edc6dd57 Bug: skia:10632 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/314276 Reviewed-by: Leon Scroggins Reviewed-by: Robert Phillips Commit-Queue: Brian Salomon --- RELEASE_NOTES.txt | 1 + dm/DMSrcSink.cpp | 5 +- include/codec/SkCodec.h | 18 +++-- include/core/SkImageGenerator.h | 16 +++-- include/core/SkYUVAPixmaps.h | 89 ++++++++++++++++++++++-- src/codec/SkCodec.cpp | 6 +- src/codec/SkCodecImageGenerator.cpp | 6 +- src/codec/SkCodecImageGenerator.h | 3 +- src/codec/SkJpegCodec.cpp | 14 ++-- src/codec/SkJpegCodec.h | 3 +- src/core/SkImageGenerator.cpp | 6 +- src/core/SkYUVAPixmaps.cpp | 104 ++++++++++++++++++++++------ src/image/SkImage_Lazy.cpp | 16 +++-- src/image/SkImage_Lazy.h | 5 +- tests/YUVTest.cpp | 21 ++++-- tools/DDLPromiseImageHelper.cpp | 2 +- tools/DDLPromiseImageHelper.h | 4 +- tools/gpu/YUVUtils.cpp | 2 +- tools/skpbench/skpbench.cpp | 3 +- 19 files changed, 251 insertions(+), 73 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index b98ac93054..ccb5bcf00e 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -21,6 +21,7 @@ Milestone 87 Doesn't assume 8bit planar values. https://review.skia.org/309658 https://review.skia.org/312886 + https://review.skia.org/314276 * Added VkImageUsageFlags to GrVkImageInfo struct. diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index a4c3b93ad3..88a0d9ec37 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -1814,7 +1814,8 @@ Result GPUDDLSink::ddlDraw(const Src& src, // this is our ultimate final drawing area/rect SkIRect viewport = SkIRect::MakeWH(size.fWidth, size.fHeight); - DDLPromiseImageHelper promiseImageHelper; + SkYUVAPixmapInfo::SupportedDataTypes supportedYUVADataTypes(*gpuThreadCtx); + DDLPromiseImageHelper promiseImageHelper(supportedYUVADataTypes); sk_sp compressedPictureData = promiseImageHelper.deflateSKP(inputPicture.get()); if (!compressedPictureData) { return Result::Fatal("GPUDDLSink: Couldn't deflate SkPicture"); @@ -2270,7 +2271,7 @@ Result ViaDDL::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkStrin // this is our ultimate final drawing area/rect SkIRect viewport = SkIRect::MakeWH(size.fWidth, size.fHeight); - DDLPromiseImageHelper promiseImageHelper; + DDLPromiseImageHelper promiseImageHelper(SkYUVAPixmapInfo::SupportedDataTypes::All()); sk_sp compressedPictureData = promiseImageHelper.deflateSKP(inputPicture.get()); if (!compressedPictureData) { return Result::Fatal("ViaDDL: Couldn't deflate SkPicture"); diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index 1f655d7349..8b1fc3bdcf 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -381,11 +381,18 @@ public: } /** - * If decoding to YUVA is supported, this returns true and updates yuvaPixmapInfo to be a - * specification of the planar layout, YUVA->RGBA transformation, per-plane color types and row - * bytes. If YUVA decoding is not supported then returns false. + * If decoding to YUV is supported, this returns true. Otherwise, this + * returns false and the caller will ignore output parameter yuvaPixmapInfo. + * + * @param supportedDataTypes Indicates the data type/planar config combinations that are + * supported by the caller. If the generator supports decoding to + * YUV(A), but not as a type in supportedDataTypes, this method + * returns false. + * @param yuvaPixmapInfo Output parameter that specifies the planar configuration, subsampling, + * orientation, chroma siting, plane color types, and row bytes. */ - bool queryYUVAInfo(SkYUVAPixmapInfo* yuvaPixmapInfo) const; + bool queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVAPixmapInfo* yuvaPixmapInfo) const; /** * Returns kSuccess, or another value explaining the type of failure. @@ -732,7 +739,8 @@ protected: void* pixels, size_t rowBytes, const Options&, int* rowsDecoded) = 0; - virtual bool onQueryYUVAInfo(SkYUVAPixmapInfo*) const { return false; } + virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, + SkYUVAPixmapInfo*) const { return false; } virtual Result onGetYUVAPlanes(const SkYUVAPixmaps&) { return kUnimplemented; } diff --git a/include/core/SkImageGenerator.h b/include/core/SkImageGenerator.h index 2e3122f4de..380cb73329 100644 --- a/include/core/SkImageGenerator.h +++ b/include/core/SkImageGenerator.h @@ -91,12 +91,17 @@ public: /** * If decoding to YUV is supported, this returns true. Otherwise, this - * returns false and does not modify yuvaPixmapInfo. + * returns false and the caller will ignore output parameter yuvaPixmapInfo. * - * @param yuvaPixmapInfo Specifies the planar configuration, subsampling, orientation, - * chroma siting, plane color types, and row bytes. + * @param supportedDataTypes Indicates the data type/planar config combinations that are + * supported by the caller. If the generator supports decoding to + * YUV(A), but not as a type in supportedDataTypes, this method + * returns false. + * @param yuvaPixmapInfo Output parameter that specifies the planar configuration, subsampling, + * orientation, chroma siting, plane color types, and row bytes. */ - bool queryYUVAInfo(SkYUVAPixmapInfo* yuvaPixmapInfo) const; + bool queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVAPixmapInfo* yuvaPixmapInfo) const; /** * Returns true on success and false on failure. @@ -204,7 +209,8 @@ protected: struct Options {}; virtual bool onGetPixels(const SkImageInfo&, void*, size_t, const Options&) { return false; } virtual bool onIsValid(GrRecordingContext*) const { return true; } - virtual bool onQueryYUVAInfo(SkYUVAPixmapInfo*) const { return false; } + virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, + SkYUVAPixmapInfo*) const { return false; } virtual bool onGetYUVAPlanes(const SkYUVAPixmaps&) { return false; } virtual bool onQueryYUVA8(SkYUVASizeInfo*, SkYUVAIndex[SkYUVAIndex::kIndexCount], SkYUVColorSpace*) const { return false; } diff --git a/include/core/SkYUVAPixmaps.h b/include/core/SkYUVAPixmaps.h index 6e524d2b48..9a1f2793e1 100644 --- a/include/core/SkYUVAPixmaps.h +++ b/include/core/SkYUVAPixmaps.h @@ -15,7 +15,9 @@ #include "include/private/SkTo.h" #include +#include +class GrImageContext; struct SkYUVASizeInfo; struct SkYUVAIndex; @@ -27,6 +29,67 @@ class SK_API SkYUVAPixmapInfo { public: static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; + using PlanarConfig = SkYUVAInfo::PlanarConfig; + + /** + * Data type for Y, U, V, and possibly A channels independent of how values are packed into + * planes. + **/ + enum class DataType { + kUnorm8, ///< 8 bit unsigned normalized + kUnorm16, ///< 16 bit unsigned normalized + kFloat16, ///< 16 bit (half) floating point + + kLast = kFloat16 + }; + static constexpr int kDataTypeCnt = static_cast(DataType::kLast) + 1; + + class SupportedDataTypes { + public: + /** Defaults to nothing supported. */ + constexpr SupportedDataTypes() = default; + + /** Init based on texture formats supported by the context. */ + SupportedDataTypes(const GrImageContext&); + + /** All combinations of PlanarConfig and DataType are supported. */ + static constexpr SupportedDataTypes All() { + SupportedDataTypes combinations; + combinations.fDataTypeSupport = std::bitset(~(0ULL)); + return combinations; + } + + constexpr bool supported(PlanarConfig, DataType type) const { + return fDataTypeSupport[static_cast(type)]; + } + + /** + * Update to add support for pixmaps with numChannel channels where each channel is + * represented as DataType. + */ + void enableDataType(DataType, int numChannels); + + private: + // Because all of our PlanarConfigs are currently single channel per-plane, we just need to + // keep track of whether each data type is supported (implicitly as a single channel plane). + // As we add multi-channel per-plane PlanarConfigs this will have to change. + std::bitset fDataTypeSupport = {}; + }; + + /** + * Gets the default SkColorType to use with numChannels channels, each represented as DataType. + * Returns kUnknown_SkColorType if no such color type. + */ + static SkColorType DefaultColorTypeForDataType(DataType dataType, int numChannels); + + /** + * If the SkColorType is supported for YUVA pixmaps this will return the number of YUVA channels + * that can be stored in a plane of this color type and what the DataType is of those channels. + * If the SkColorType is not supported as a YUVA plane the number of channels is reported as 0 + * and the DataType returned should be ignored. + */ + static std::tuple NumChannelsAndDataType(SkColorType); + /** Default SkYUVAPixmapInfo is invalid. */ SkYUVAPixmapInfo() = default; @@ -34,7 +97,8 @@ public: * Initializes the SkYUVAPixmapInfo from a SkYUVAInfo with per-plane color types and row bytes. * This will be invalid if the colorTypes aren't compatible with the SkYUVAInfo or if a * rowBytes entry is not valid for the plane dimensions and color type. Color type and - * row byte values beyond the number of planes in SkYUVAInfo are ignored. + * row byte values beyond the number of planes in SkYUVAInfo are ignored. All SkColorTypes + * must have the same DataType or this will be invalid. * * If rowBytes is nullptr then bpp*width is assumed for each plane. */ @@ -42,14 +106,18 @@ public: const SkColorType[kMaxPlanes], const size_t rowBytes[kMaxPlanes]); /** - * Like above but uses the same color type for all planes. + * Like above but uses DefaultColorTypeForDataType to determine each plane's SkColorType. If + * rowBytes is nullptr then bpp*width is assumed for each plane. */ - SkYUVAPixmapInfo(const SkYUVAInfo&, SkColorType, const size_t rowBytes[kMaxPlanes]); + SkYUVAPixmapInfo(const SkYUVAInfo&, DataType, const size_t rowBytes[kMaxPlanes]); SkYUVAPixmapInfo(const SkYUVAPixmapInfo&) = default; SkYUVAPixmapInfo& operator=(const SkYUVAPixmapInfo&) = default; + bool operator==(const SkYUVAPixmapInfo&) const; + bool operator!=(const SkYUVAPixmapInfo& that) const { return !(*this == that); } + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); } @@ -57,14 +125,17 @@ public: /** The number of SkPixmap planes, 0 if this SkYUVAPixmapInfo is invalid. */ int numPlanes() const { return this->isValid() ? fYUVAInfo.numPlanes() : 0; } + /** The per-YUV[A] channel data type. */ + DataType dataType() const { return fDataType; } + /** * Row bytes for the ith plane. Returns zero if i >= numPlanes() or this SkYUVAPixmapInfo is * invalid. */ - size_t rowBytes(int i) const { return fRowBytes[i]; } + size_t rowBytes(int i) const { return fRowBytes[static_cast(i)]; } /** Image info for the ith plane, or default SkImageInfo if i >= numPlanes() */ - const SkImageInfo& planeInfo(int i) const { return fPlaneInfos[i]; } + const SkImageInfo& planeInfo(int i) const { return fPlaneInfos[static_cast(i)]; } /** * Determine size to allocate for all planes. Optionally retrieves the per-plane sizes in @@ -86,10 +157,14 @@ public: */ bool isValid() const { return fPlaneInfos[0].colorType() != kUnknown_SkColorType; } + /** Is this valid and does it use color types allowed by the passed SupportedDataTypes? */ + bool isSupported(const SupportedDataTypes&) const; + private: SkYUVAInfo fYUVAInfo; - SkImageInfo fPlaneInfos[kMaxPlanes] = {}; - size_t fRowBytes[kMaxPlanes] = {}; + std::array fPlaneInfos = {}; + std::array fRowBytes = {}; + DataType fDataType = DataType::kUnorm8; static_assert(kUnknown_SkColorType == 0, "default init isn't kUnknown"); }; diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 2c64513cb0..3a9ce20ce2 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -167,11 +167,13 @@ SkCodec::SkCodec(SkEncodedInfo&& info, XformFormat srcFormat, std::unique_ptronQueryYUVAInfo(yuvaPixmapInfo) && yuvaPixmapInfo->isValid(); + return this->onQueryYUVAInfo(supportedDataTypes, yuvaPixmapInfo) && + yuvaPixmapInfo->isSupported(supportedDataTypes); } SkCodec::Result SkCodec::getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) { diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp index 2d8c7fea4d..5639080d93 100644 --- a/src/codec/SkCodecImageGenerator.cpp +++ b/src/codec/SkCodecImageGenerator.cpp @@ -69,8 +69,10 @@ bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& requestInfo, void* re return this->getPixels(requestInfo, requestPixels, requestRowBytes, nullptr); } -bool SkCodecImageGenerator::onQueryYUVAInfo(SkYUVAPixmapInfo* yuvaPixmapInfo) const { - return fCodec->queryYUVAInfo(yuvaPixmapInfo); +bool SkCodecImageGenerator::onQueryYUVAInfo( + const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVAPixmapInfo* yuvaPixmapInfo) const { + return fCodec->queryYUVAInfo(supportedDataTypes, yuvaPixmapInfo); } bool SkCodecImageGenerator::onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) { diff --git a/src/codec/SkCodecImageGenerator.h b/src/codec/SkCodecImageGenerator.h index 1f68f5059a..2326c65848 100644 --- a/src/codec/SkCodecImageGenerator.h +++ b/src/codec/SkCodecImageGenerator.h @@ -98,7 +98,8 @@ protected: size_t rowBytes, const Options& opts) override; - bool onQueryYUVAInfo(SkYUVAPixmapInfo* yuvaPixmapInfo) const override; + bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, + SkYUVAPixmapInfo*) const override; bool onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) override; diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 53b5cae320..d7b3974e88 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -745,6 +745,7 @@ bool SkJpegCodec::onSkipScanlines(int count) { static bool is_yuv_supported(const jpeg_decompress_struct* dinfo, const SkJpegCodec& codec, + const SkYUVAPixmapInfo::SupportedDataTypes* supportedDataTypes, SkYUVAPixmapInfo* yuvaPixmapInfo) { // Scaling is not supported in raw data mode. SkASSERT(dinfo->scale_num == dinfo->scale_denom); @@ -811,6 +812,10 @@ static bool is_yuv_supported(const jpeg_decompress_struct* dinfo, } else { return false; } + if (supportedDataTypes && + !supportedDataTypes->supported(tempPlanarConfig, SkYUVAPixmapInfo::DataType::kUnorm8)) { + return false; + } if (yuvaPixmapInfo) { SkColorType colorTypes[SkYUVAPixmapInfo::kMaxPlanes]; size_t rowBytes[SkYUVAPixmapInfo::kMaxPlanes]; @@ -829,15 +834,16 @@ static bool is_yuv_supported(const jpeg_decompress_struct* dinfo, return true; } -bool SkJpegCodec::onQueryYUVAInfo(SkYUVAPixmapInfo* yuvaPixmapInfo) const { +bool SkJpegCodec::onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVAPixmapInfo* yuvaPixmapInfo) const { jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); - return is_yuv_supported(dinfo, *this, yuvaPixmapInfo); + return is_yuv_supported(dinfo, *this, &supportedDataTypes, yuvaPixmapInfo); } SkCodec::Result SkJpegCodec::onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) { // Get a pointer to the decompress info since we will use it quite frequently jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); - if (!is_yuv_supported(dinfo, *this, nullptr)) { + if (!is_yuv_supported(dinfo, *this, nullptr, nullptr)) { return fDecoderMgr->returnFailure("onGetYUVAPlanes", kInvalidInput); } // Set the jump location for libjpeg errors @@ -860,7 +866,7 @@ SkCodec::Result SkJpegCodec::onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) { // was caused by a bug in the old code, but we'll be safe and check here. // Also check that pixmap properties agree with expectations. SkYUVAPixmapInfo info; - SkASSERT(is_yuv_supported(dinfo, *this, &info)); + SkASSERT(is_yuv_supported(dinfo, *this, nullptr, &info)); SkASSERT(info.yuvaInfo() == yuvaPixmaps.yuvaInfo()); for (int i = 0; i < info.numPlanes(); ++i) { SkASSERT(planes[i].colorType() == kAlpha_8_SkColorType); diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h index 650072090b..7a0b50a4e4 100644 --- a/src/codec/SkJpegCodec.h +++ b/src/codec/SkJpegCodec.h @@ -44,7 +44,8 @@ protected: Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, int*) override; - bool onQueryYUVAInfo(SkYUVAPixmapInfo*) const override; + bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, + SkYUVAPixmapInfo*) const override; Result onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) override; diff --git a/src/core/SkImageGenerator.cpp b/src/core/SkImageGenerator.cpp index 6fa57bc11f..7f3306e3a4 100644 --- a/src/core/SkImageGenerator.cpp +++ b/src/core/SkImageGenerator.cpp @@ -30,10 +30,12 @@ bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t r return this->onGetPixels(info, pixels, rowBytes, defaultOpts); } -bool SkImageGenerator::queryYUVAInfo(SkYUVAPixmapInfo* yuvaPixmapInfo) const { +bool SkImageGenerator::queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVAPixmapInfo* yuvaPixmapInfo) const { SkASSERT(yuvaPixmapInfo); - return this->onQueryYUVAInfo(yuvaPixmapInfo); + return this->onQueryYUVAInfo(supportedDataTypes, yuvaPixmapInfo) && + yuvaPixmapInfo->isSupported(supportedDataTypes); } bool SkImageGenerator::getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) { diff --git a/src/core/SkYUVAPixmaps.cpp b/src/core/SkYUVAPixmaps.cpp index f249cab75c..9dfa4a569f 100644 --- a/src/core/SkYUVAPixmaps.cpp +++ b/src/core/SkYUVAPixmaps.cpp @@ -11,6 +11,60 @@ #include "include/core/SkYUVASizeInfo.h" #include "include/private/SkImageInfoPriv.h" +#if SK_SUPPORT_GPU +#include "include/private/GrImageContext.h" +#endif + +void SkYUVAPixmapInfo::SupportedDataTypes::enableDataType(DataType type, int numChannels) { + // All of our PlanarConfigs are one channel per plane so far. + if (numChannels != 1) { + return; + } + fDataTypeSupport[static_cast(type)] = true; +} + +SkYUVAPixmapInfo::SupportedDataTypes::SupportedDataTypes(const GrImageContext& context) { +#if SK_SUPPORT_GPU + if (context.defaultBackendFormat(DefaultColorTypeForDataType(DataType::kUnorm8, 1), + GrRenderable::kNo).isValid()) { + this->enableDataType(DataType::kUnorm8, 1); + } + if (context.defaultBackendFormat(DefaultColorTypeForDataType(DataType::kUnorm16, 1), + GrRenderable::kNo).isValid()) { + this->enableDataType(DataType::kUnorm16, 1); + } + if (context.defaultBackendFormat(DefaultColorTypeForDataType(DataType::kFloat16, 1), + GrRenderable::kNo).isValid()) { + this->enableDataType(DataType::kFloat16, 1); + } +#endif +} + +////////////////////////////////////////////////////////////////////////////// + +SkColorType SkYUVAPixmapInfo::DefaultColorTypeForDataType(DataType dataType, int numChannels) { + if (numChannels != 1) { + return kUnknown_SkColorType; + } + switch (dataType) { + case DataType::kUnorm8: return kGray_8_SkColorType; + case DataType::kUnorm16: return kA16_unorm_SkColorType; + case DataType::kFloat16: return kA16_float_SkColorType; + } + SkUNREACHABLE; +} + +std::tuple SkYUVAPixmapInfo::NumChannelsAndDataType( + SkColorType ct) { + switch (ct) { + case kAlpha_8_SkColorType: + case kGray_8_SkColorType: return {1, DataType::kUnorm8 }; + case kA16_unorm_SkColorType: return {1, DataType::kUnorm16}; + case kA16_float_SkColorType: return {1, DataType::kFloat16}; + default: return {0, DataType::kUnorm8 }; + } +} + static int num_channels_in_plane(SkYUVAInfo::PlanarConfig config, int planeIdx) { switch (config) { case SkYUVAInfo::PlanarConfig::kY_U_V_444: @@ -54,30 +108,15 @@ SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo, rowBytes = tempRowBytes; } bool ok = true; - for (int i = 0; i < n; ++i) { + for (size_t i = 0; i < static_cast(n); ++i) { fRowBytes[i] = rowBytes[i]; fPlaneInfos[i] = SkImageInfo::Make(planeDimensions[i], colorTypes[i], kPremul_SkAlphaType); int numRequiredChannels = num_channels_in_plane(yuvaInfo.planarConfig(), i); - switch (SkColorTypeChannelFlags(colorTypes[i])) { - case kGray_SkColorChannelFlag: - case kRed_SkColorChannelFlag: - case kAlpha_SkColorChannelFlag: - ok |= numRequiredChannels == 1; - break; - case kRG_SkColorChannelFlags: - ok |= numRequiredChannels <= 2; - break; - case kRGB_SkColorChannelFlags: - ok |= numRequiredChannels <= 3; - break; - case kRGBA_SkColorChannelFlags: - ok |= numRequiredChannels <= 4; - break; - default: - ok = false; - break; - } + auto [numColorTypeChannels, colorTypeDataType] = NumChannelsAndDataType(colorTypes[i]); + ok |= i == 0 || colorTypeDataType == fDataType; + ok |= numColorTypeChannels >= numRequiredChannels; ok |= fPlaneInfos[i].validRowBytes(fRowBytes[i]); + fDataType = colorTypeDataType; } if (!ok) { *this = {}; @@ -88,13 +127,25 @@ SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo, } SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo, - const SkColorType colorType, + DataType dataType, const size_t rowBytes[kMaxPlanes]) { SkColorType colorTypes[kMaxPlanes]; - std::fill_n(colorTypes, kMaxPlanes, colorType); + int n = yuvaInfo.numPlanes(); + for (int i = 0; i < n; ++i) { + // Currently all PlanarConfigs have 1 channel per plane. + colorTypes[i] = DefaultColorTypeForDataType(dataType, 1); + } *this = SkYUVAPixmapInfo(yuvaInfo, colorTypes, rowBytes); } +bool SkYUVAPixmapInfo::operator==(const SkYUVAPixmapInfo& that) const { + bool result = fYUVAInfo == that.fYUVAInfo && + fPlaneInfos == that.fPlaneInfos && + fRowBytes == that.fRowBytes; + SkASSERT(!result || fDataType == that.fDataType); + return result; +} + size_t SkYUVAPixmapInfo::computeTotalBytes(size_t planeSizes[kMaxPlanes]) const { if (!this->isValid()) { if (planeSizes) { @@ -102,7 +153,7 @@ size_t SkYUVAPixmapInfo::computeTotalBytes(size_t planeSizes[kMaxPlanes]) const } return 0; } - return fYUVAInfo.computeTotalBytes(fRowBytes, planeSizes); + return fYUVAInfo.computeTotalBytes(fRowBytes.data(), planeSizes); } bool SkYUVAPixmapInfo::initPixmapsFromSingleAllocation(void* memory, @@ -126,6 +177,13 @@ bool SkYUVAPixmapInfo::initPixmapsFromSingleAllocation(void* memory, return true; } +bool SkYUVAPixmapInfo::isSupported(const SupportedDataTypes& supportedDataTypes) const { + if (!this->isValid()) { + return false; + } + return supportedDataTypes.supported(fYUVAInfo.planarConfig(), fDataType); +} + ////////////////////////////////////////////////////////////////////////////// SkYUVAPixmaps SkYUVAPixmaps::Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo) { diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp index b2dc9faa4b..e231a4d9a0 100644 --- a/src/image/SkImage_Lazy.cpp +++ b/src/image/SkImage_Lazy.cpp @@ -266,8 +266,9 @@ GrSurfaceProxyView SkImage_Lazy::textureProxyViewFromPlanes(GrRecordingContext* SkYUVColorSpace yuvColorSpace; SkPixmap planes[SkYUVASizeInfo::kMaxCount]; + SkYUVAPixmapInfo::SupportedDataTypes supportedDataTypes(*ctx); sk_sp dataStorage = - this->getPlanes(&yuvSizeInfo, yuvaIndices, &yuvColorSpace, planes); + this->getPlanes(supportedDataTypes, &yuvSizeInfo, yuvaIndices, &yuvColorSpace, planes); if (!dataStorage) { return {}; } @@ -359,10 +360,12 @@ GrSurfaceProxyView SkImage_Lazy::textureProxyViewFromPlanes(GrRecordingContext* return renderTargetContext->readSurfaceView(); } -sk_sp SkImage_Lazy::getPlanes(SkYUVASizeInfo* yuvaSizeInfo, - SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount], - SkYUVColorSpace* yuvColorSpace, - SkPixmap planes[SkYUVASizeInfo::kMaxCount]) const { +sk_sp SkImage_Lazy::getPlanes( + const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVASizeInfo* yuvaSizeInfo, + SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount], + SkYUVColorSpace* yuvColorSpace, + SkPixmap planes[SkYUVASizeInfo::kMaxCount]) const { ScopedGenerator generator(fSharedGenerator); SkYUVPlanesCache::Info yuvInfo; @@ -370,9 +373,8 @@ sk_sp SkImage_Lazy::getPlanes(SkYUVASizeInfo* yuvaSizeInfo, // Try the new more descriptive SkImageGenerator/SkCodec YUVA interface. if (SkYUVAPixmapInfo yuvaPixmapInfo; - !data && generator->queryYUVAInfo(&yuvaPixmapInfo) && + !data && generator->queryYUVAInfo(supportedDataTypes, &yuvaPixmapInfo) && yuvaPixmapInfo.yuvaInfo().dimensions() == this->dimensions()) { - data.reset(SkResourceCache::NewCachedData(yuvaPixmapInfo.computeTotalBytes())); auto pixmaps = SkYUVAPixmaps::FromExternalMemory(yuvaPixmapInfo, data->writable_data()); SkASSERT(pixmaps.isValid()); diff --git a/src/image/SkImage_Lazy.h b/src/image/SkImage_Lazy.h index 763d176a11..89b5c1d35d 100644 --- a/src/image/SkImage_Lazy.h +++ b/src/image/SkImage_Lazy.h @@ -15,7 +15,7 @@ #if SK_SUPPORT_GPU #include "include/core/SkYUVAIndex.h" -#include "include/core/SkYUVAInfo.h" +#include "include/core/SkYUVAPixmaps.h" #include "include/core/SkYUVASizeInfo.h" #include "src/gpu/GrTextureMaker.h" #endif @@ -69,7 +69,8 @@ public: private: void addUniqueIDListener(sk_sp) const; #if SK_SUPPORT_GPU - sk_sp getPlanes(SkYUVASizeInfo* yuvaSizeInfo, + sk_sp getPlanes(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVASizeInfo* yuvaSizeInfo, SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount], SkYUVColorSpace* yuvColorSpace, SkPixmap planes[SkYUVASizeInfo::kMaxCount]) const; diff --git a/tests/YUVTest.cpp b/tests/YUVTest.cpp index 72e13191e7..6c947d9d8d 100644 --- a/tests/YUVTest.cpp +++ b/tests/YUVTest.cpp @@ -30,10 +30,17 @@ static void codec_yuv(skiatest::Reporter* reporter, // Test queryYUBAInfo() SkYUVAPixmapInfo yuvaPixmapInfo; - // Param is required to be non-null. - bool success = codec->queryYUVAInfo(nullptr); + static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All(); + static constexpr auto kNoTypes = SkYUVAPixmapInfo::SupportedDataTypes(); + + // SkYUVAInfo param is required to be non-null. + bool success = codec->queryYUVAInfo(kAllTypes, nullptr); REPORTER_ASSERT(reporter, !success); - success = codec->queryYUVAInfo(&yuvaPixmapInfo); + // Fails when there is no support for YUVA planes. + success = codec->queryYUVAInfo(kNoTypes, &yuvaPixmapInfo); + REPORTER_ASSERT(reporter, !success); + + success = codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo); REPORTER_ASSERT(reporter, SkToBool(expectedInfo) == success); if (!success) { return; @@ -42,13 +49,15 @@ static void codec_yuv(skiatest::Reporter* reporter, int numPlanes = yuvaPixmapInfo.numPlanes(); REPORTER_ASSERT(reporter, numPlanes <= SkYUVAInfo::kMaxPlanes); - size_t totalBytes = 0; for (int i = 0; i < numPlanes; ++i) { const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i); + SkColorType planeCT = planeInfo.colorType(); REPORTER_ASSERT(reporter, !planeInfo.isEmpty()); - REPORTER_ASSERT(reporter, planeInfo.colorType() != kUnknown_SkColorType); + REPORTER_ASSERT(reporter, planeCT != kUnknown_SkColorType); REPORTER_ASSERT(reporter, planeInfo.validRowBytes(yuvaPixmapInfo.rowBytes(i))); - totalBytes += planeInfo.height()*yuvaPixmapInfo.rowBytes(i); + // Currently all planes must share a data type, gettable as SkYUVAPixmapInfo::dataType(). + auto [numChannels, planeDataType] = SkYUVAPixmapInfo::NumChannelsAndDataType(planeCT); + REPORTER_ASSERT(reporter, planeDataType == yuvaPixmapInfo.dataType()); } for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) { const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i); diff --git a/tools/DDLPromiseImageHelper.cpp b/tools/DDLPromiseImageHelper.cpp index bcc249b55f..11827c42f2 100644 --- a/tools/DDLPromiseImageHelper.cpp +++ b/tools/DDLPromiseImageHelper.cpp @@ -444,7 +444,7 @@ int DDLPromiseImageHelper::addImage(SkImage* image) { auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(ib->refEncodedData()); SkYUVAPixmapInfo yuvaInfo; - if (codec && codec->queryYUVAInfo(&yuvaInfo)) { + if (codec && codec->queryYUVAInfo(fSupportedYUVADataTypes, &yuvaInfo)) { auto yuvaPixmaps = SkYUVAPixmaps::Allocate(yuvaInfo); SkAssertResult(codec->getYUVAPlanes(yuvaPixmaps)); SkASSERT(yuvaPixmaps.isValid()); diff --git a/tools/DDLPromiseImageHelper.h b/tools/DDLPromiseImageHelper.h index 29cdc873fb..f49ffdf354 100644 --- a/tools/DDLPromiseImageHelper.h +++ b/tools/DDLPromiseImageHelper.h @@ -124,7 +124,8 @@ private: // all the replaying is complete. This will pin the GrBackendTextures in VRAM. class DDLPromiseImageHelper { public: - DDLPromiseImageHelper() = default; + DDLPromiseImageHelper(const SkYUVAPixmapInfo::SupportedDataTypes& supportedYUVADataTypes) + : fSupportedYUVADataTypes(supportedYUVADataTypes) {} ~DDLPromiseImageHelper() = default; // Convert the SkPicture into SkData replacing all the SkImages with an index. @@ -270,6 +271,7 @@ private: // returns -1 on failure int findOrDefineImage(SkImage* image); + SkYUVAPixmapInfo::SupportedDataTypes fSupportedYUVADataTypes; SkTArray fImageInfo; }; diff --git a/tools/gpu/YUVUtils.cpp b/tools/gpu/YUVUtils.cpp index 4535d910bf..d4f0488d29 100644 --- a/tools/gpu/YUVUtils.cpp +++ b/tools/gpu/YUVUtils.cpp @@ -48,7 +48,7 @@ bool LazyYUVImage::reset(sk_sp data, GrMipmapped mipmapped) { } SkYUVAPixmapInfo yuvaPixmapInfo; - if (!codec->queryYUVAInfo(&yuvaPixmapInfo)) { + if (!codec->queryYUVAInfo(SkYUVAPixmapInfo::SupportedDataTypes::All(), &yuvaPixmapInfo)) { return false; } fPixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo); diff --git a/tools/skpbench/skpbench.cpp b/tools/skpbench/skpbench.cpp index 85e98f6436..5a7527b1f9 100644 --- a/tools/skpbench/skpbench.cpp +++ b/tools/skpbench/skpbench.cpp @@ -258,7 +258,8 @@ static void run_ddl_benchmark(sk_gpu_test::TestContext* testContext, GrDirectCon SkIRect viewport = dstSurface->imageInfo().bounds(); - DDLPromiseImageHelper promiseImageHelper; + SkYUVAPixmapInfo::SupportedDataTypes supportedYUVADataTypes(*context); + DDLPromiseImageHelper promiseImageHelper(supportedYUVADataTypes); sk_sp compressedPictureData = promiseImageHelper.deflateSKP(inputPicture); if (!compressedPictureData) { exitf(ExitErr::kUnavailable, "DDL: conversion of skp failed");