diff options
Diffstat (limited to 'gfx/skia/skia/src/core/SkYUVAPixmaps.cpp')
-rw-r--r-- | gfx/skia/skia/src/core/SkYUVAPixmaps.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/core/SkYUVAPixmaps.cpp b/gfx/skia/skia/src/core/SkYUVAPixmaps.cpp new file mode 100644 index 0000000000..aed0aea289 --- /dev/null +++ b/gfx/skia/skia/src/core/SkYUVAPixmaps.cpp @@ -0,0 +1,297 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkYUVAPixmaps.h" + +#include "src/base/SkRectMemcpy.h" +#include "src/core/SkImageInfoPriv.h" +#include "src/core/SkYUVAInfoLocation.h" + +#if defined(SK_GANESH) +#include "include/private/gpu/ganesh/GrImageContext.h" +#endif + + +SkYUVAPixmapInfo::SupportedDataTypes::SupportedDataTypes(const GrImageContext& context) { +#if defined(SK_GANESH) + for (int n = 1; n <= 4; ++n) { + if (context.defaultBackendFormat(DefaultColorTypeForDataType(DataType::kUnorm8, n), + GrRenderable::kNo).isValid()) { + this->enableDataType(DataType::kUnorm8, n); + } + if (context.defaultBackendFormat(DefaultColorTypeForDataType(DataType::kUnorm16, n), + GrRenderable::kNo).isValid()) { + this->enableDataType(DataType::kUnorm16, n); + } + if (context.defaultBackendFormat(DefaultColorTypeForDataType(DataType::kFloat16, n), + GrRenderable::kNo).isValid()) { + this->enableDataType(DataType::kFloat16, n); + } + if (context.defaultBackendFormat(DefaultColorTypeForDataType(DataType::kUnorm10_Unorm2, n), + GrRenderable::kNo).isValid()) { + this->enableDataType(DataType::kUnorm10_Unorm2, n); + } + } +#endif +} + +void SkYUVAPixmapInfo::SupportedDataTypes::enableDataType(DataType type, int numChannels) { + if (numChannels < 1 || numChannels > 4) { + return; + } + fDataTypeSupport[static_cast<size_t>(type) + (numChannels - 1)*kDataTypeCnt] = true; +} + +////////////////////////////////////////////////////////////////////////////// + +std::tuple<int, SkYUVAPixmapInfo::DataType> SkYUVAPixmapInfo::NumChannelsAndDataType( + SkColorType ct) { + // We could allow BGR[A] color types, but then we'd have to decide whether B should be the 0th + // or 2nd channel. Our docs currently say channel order is always R=0, G=1, B=2[, A=3]. + 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}; + + case kR8G8_unorm_SkColorType: return {2, DataType::kUnorm8 }; + case kR16G16_unorm_SkColorType: return {2, DataType::kUnorm16 }; + case kR16G16_float_SkColorType: return {2, DataType::kFloat16 }; + + case kRGB_888x_SkColorType: return {3, DataType::kUnorm8 }; + case kRGB_101010x_SkColorType: return {3, DataType::kUnorm10_Unorm2 }; + + case kRGBA_8888_SkColorType: return {4, DataType::kUnorm8 }; + case kR16G16B16A16_unorm_SkColorType: return {4, DataType::kUnorm16 }; + case kRGBA_F16_SkColorType: return {4, DataType::kFloat16 }; + case kRGBA_F16Norm_SkColorType: return {4, DataType::kFloat16 }; + case kRGBA_1010102_SkColorType: return {4, DataType::kUnorm10_Unorm2 }; + + default: return {0, DataType::kUnorm8 }; + } +} + +SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo, + const SkColorType colorTypes[kMaxPlanes], + const size_t rowBytes[kMaxPlanes]) + : fYUVAInfo(yuvaInfo) { + if (!yuvaInfo.isValid()) { + *this = {}; + SkASSERT(!this->isValid()); + return; + } + SkISize planeDimensions[4]; + int n = yuvaInfo.planeDimensions(planeDimensions); + size_t tempRowBytes[kMaxPlanes]; + if (!rowBytes) { + for (int i = 0; i < n; ++i) { + tempRowBytes[i] = SkColorTypeBytesPerPixel(colorTypes[i]) * planeDimensions[i].width(); + } + rowBytes = tempRowBytes; + } + bool ok = true; + for (size_t i = 0; i < static_cast<size_t>(n); ++i) { + fRowBytes[i] = rowBytes[i]; + // Use kUnpremul so that we never multiply alpha when copying data in. + fPlaneInfos[i] = SkImageInfo::Make(planeDimensions[i], + colorTypes[i], + kUnpremul_SkAlphaType); + int numRequiredChannels = yuvaInfo.numChannelsInPlane(i); + SkASSERT(numRequiredChannels > 0); + 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 = {}; + SkASSERT(!this->isValid()); + } else { + SkASSERT(this->isValid()); + } +} + +SkYUVAPixmapInfo::SkYUVAPixmapInfo(const SkYUVAInfo& yuvaInfo, + DataType dataType, + const size_t rowBytes[kMaxPlanes]) { + SkColorType colorTypes[kMaxPlanes] = {}; + int numPlanes = yuvaInfo.numPlanes(); + for (int i = 0; i < numPlanes; ++i) { + int numChannels = yuvaInfo.numChannelsInPlane(i); + colorTypes[i] = DefaultColorTypeForDataType(dataType, numChannels); + } + *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) { + std::fill_n(planeSizes, kMaxPlanes, 0); + } + return 0; + } + return fYUVAInfo.computeTotalBytes(fRowBytes.data(), planeSizes); +} + +bool SkYUVAPixmapInfo::initPixmapsFromSingleAllocation(void* memory, + SkPixmap pixmaps[kMaxPlanes]) const { + if (!this->isValid()) { + return false; + } + SkASSERT(pixmaps); + char* addr = static_cast<char*>(memory); + int n = this->numPlanes(); + for (int i = 0; i < n; ++i) { + SkASSERT(fPlaneInfos[i].validRowBytes(fRowBytes[i])); + pixmaps[i].reset(fPlaneInfos[i], addr, fRowBytes[i]); + size_t planeSize = pixmaps[i].rowBytes()*pixmaps[i].height(); + SkASSERT(planeSize); + addr += planeSize; + } + for (int i = n; i < kMaxPlanes; ++i) { + pixmaps[i] = {}; + } + return true; +} + +bool SkYUVAPixmapInfo::isSupported(const SupportedDataTypes& supportedDataTypes) const { + if (!this->isValid()) { + return false; + } + return supportedDataTypes.supported(fYUVAInfo.planeConfig(), fDataType); +} + +////////////////////////////////////////////////////////////////////////////// + +SkColorType SkYUVAPixmaps::RecommendedRGBAColorType(DataType dataType) { + switch (dataType) { + case DataType::kUnorm8: return kRGBA_8888_SkColorType; + // F16 has better GPU support than 16 bit unorm. Often "16" bit unorm values are actually + // lower precision. + case DataType::kUnorm16: return kRGBA_F16_SkColorType; + case DataType::kFloat16: return kRGBA_F16_SkColorType; + case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType; + } + SkUNREACHABLE; +} + +SkYUVAPixmaps SkYUVAPixmaps::Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo) { + if (!yuvaPixmapInfo.isValid()) { + return {}; + } + return SkYUVAPixmaps(yuvaPixmapInfo, + SkData::MakeUninitialized(yuvaPixmapInfo.computeTotalBytes())); +} + +SkYUVAPixmaps SkYUVAPixmaps::FromData(const SkYUVAPixmapInfo& yuvaPixmapInfo, sk_sp<SkData> data) { + if (!yuvaPixmapInfo.isValid()) { + return {}; + } + if (yuvaPixmapInfo.computeTotalBytes() > data->size()) { + return {}; + } + return SkYUVAPixmaps(yuvaPixmapInfo, std::move(data)); +} + +SkYUVAPixmaps SkYUVAPixmaps::MakeCopy(const SkYUVAPixmaps& src) { + if (!src.isValid()) { + return {}; + } + SkYUVAPixmaps result = Allocate(src.pixmapsInfo()); + int n = result.numPlanes(); + for (int i = 0; i < n; ++i) { + // We use SkRectMemCpy rather than readPixels to ensure that we don't do any alpha type + // conversion. + const SkPixmap& s = src.plane(i); + const SkPixmap& d = result.plane(i); + SkRectMemcpy(d.writable_addr(), + d.rowBytes(), + s.addr(), + s.rowBytes(), + s.info().minRowBytes(), + s.height()); + } + return result; +} + +SkYUVAPixmaps SkYUVAPixmaps::FromExternalMemory(const SkYUVAPixmapInfo& yuvaPixmapInfo, + void* memory) { + if (!yuvaPixmapInfo.isValid()) { + return {}; + } + SkPixmap pixmaps[kMaxPlanes]; + yuvaPixmapInfo.initPixmapsFromSingleAllocation(memory, pixmaps); + return SkYUVAPixmaps(yuvaPixmapInfo.yuvaInfo(), yuvaPixmapInfo.dataType(), pixmaps); +} + +SkYUVAPixmaps SkYUVAPixmaps::FromExternalPixmaps(const SkYUVAInfo& yuvaInfo, + const SkPixmap pixmaps[kMaxPlanes]) { + SkColorType colorTypes[kMaxPlanes] = {}; + size_t rowBytes[kMaxPlanes] = {}; + int numPlanes = yuvaInfo.numPlanes(); + for (int i = 0; i < numPlanes; ++i) { + colorTypes[i] = pixmaps[i].colorType(); + rowBytes[i] = pixmaps[i].rowBytes(); + } + SkYUVAPixmapInfo yuvaPixmapInfo(yuvaInfo, colorTypes, rowBytes); + if (!yuvaPixmapInfo.isValid()) { + return {}; + } + return SkYUVAPixmaps(yuvaInfo, yuvaPixmapInfo.dataType(), pixmaps); +} + +SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAPixmapInfo& yuvaPixmapInfo, sk_sp<SkData> data) + : fData(std::move(data)) + , fYUVAInfo(yuvaPixmapInfo.yuvaInfo()) + , fDataType(yuvaPixmapInfo.dataType()) { + SkASSERT(yuvaPixmapInfo.isValid()); + SkASSERT(yuvaPixmapInfo.computeTotalBytes() <= fData->size()); + SkAssertResult(yuvaPixmapInfo.initPixmapsFromSingleAllocation(fData->writable_data(), + fPlanes.data())); +} + +SkYUVAPixmaps::SkYUVAPixmaps(const SkYUVAInfo& yuvaInfo, + DataType dataType, + const SkPixmap pixmaps[kMaxPlanes]) + : fYUVAInfo(yuvaInfo), fDataType(dataType) { + std::copy_n(pixmaps, yuvaInfo.numPlanes(), fPlanes.data()); +} + +SkYUVAPixmapInfo SkYUVAPixmaps::pixmapsInfo() const { + if (!this->isValid()) { + return {}; + } + SkColorType colorTypes[kMaxPlanes] = {}; + size_t rowBytes[kMaxPlanes] = {}; + int numPlanes = this->numPlanes(); + for (int i = 0; i < numPlanes; ++i) { + colorTypes[i] = fPlanes[i].colorType(); + rowBytes[i] = fPlanes[i].rowBytes(); + } + return {fYUVAInfo, colorTypes, rowBytes}; +} + +SkYUVAInfo::YUVALocations SkYUVAPixmaps::toYUVALocations() const { + uint32_t channelFlags[] = {SkColorTypeChannelFlags(fPlanes[0].colorType()), + SkColorTypeChannelFlags(fPlanes[1].colorType()), + SkColorTypeChannelFlags(fPlanes[2].colorType()), + SkColorTypeChannelFlags(fPlanes[3].colorType())}; + auto result = fYUVAInfo.toYUVALocations(channelFlags); + SkDEBUGCODE(int numPlanes;) + SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(result, &numPlanes)); + SkASSERT(numPlanes == this->numPlanes()); + return result; +} |