Reland: Widen internal API to support more complex YUV formats
Bug: skia:7901
Change-Id: Ic83e9f0c2a493335671fe431ffba6f649812d406
Reviewed-on: https://skia-review.googlesource.com/c/163481
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp
index 55a6575..3005ee3 100644
--- a/src/codec/SkCodecImageGenerator.cpp
+++ b/src/codec/SkCodecImageGenerator.cpp
@@ -8,6 +8,7 @@
#include "SkCodecImageGenerator.h"
#include "SkMakeUnique.h"
#include "SkPixmapPriv.h"
+#include "SkYUVAIndex.h"
std::unique_ptr<SkImageGenerator> SkCodecImageGenerator::MakeFromEncodedCodec(sk_sp<SkData> data) {
auto codec = SkCodec::MakeFromData(data);
@@ -58,13 +59,27 @@
return SkPixmapPriv::Orient(dst, fCodec->getOrigin(), decode);
}
-bool SkCodecImageGenerator::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const
-{
+bool SkCodecImageGenerator::onQueryYUVA8(SkYUVSizeInfo* sizeInfo,
+ SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+ SkYUVColorSpace* colorSpace) const {
+ // This image generator always returns 3 separate non-interleaved planes
+ yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
+ yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
+ yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 2;
+ yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
+ yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
+
return fCodec->queryYUV8(sizeInfo, colorSpace);
}
-bool SkCodecImageGenerator::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
+bool SkCodecImageGenerator::onGetYUVA8Planes(const SkYUVSizeInfo& sizeInfo,
+ const SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
+ void* planes[]) {
SkCodec::Result result = fCodec->getYUV8Planes(sizeInfo, planes);
+ // TODO: check indices
switch (result) {
case SkCodec::kSuccess:
diff --git a/src/codec/SkCodecImageGenerator.h b/src/codec/SkCodecImageGenerator.h
index b9c9d3c..9a64b7c 100644
--- a/src/codec/SkCodecImageGenerator.h
+++ b/src/codec/SkCodecImageGenerator.h
@@ -22,12 +22,14 @@
protected:
sk_sp<SkData> onRefEncodedData() override;
- bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options& opts)
- override;
+ bool onGetPixels(
+ const SkImageInfo& info, void* pixels, size_t rowBytes, const Options& opts) override;
- bool onQueryYUV8(SkYUVSizeInfo*, SkYUVColorSpace*) const override;
+ bool onQueryYUVA8(
+ SkYUVSizeInfo*, SkYUVAIndex[SkYUVAIndex::kIndexCount], SkYUVColorSpace*) const override;
- bool onGetYUV8Planes(const SkYUVSizeInfo&, void* planes[3]) override;
+ bool onGetYUVA8Planes(const SkYUVSizeInfo&, const SkYUVAIndex[SkYUVAIndex::kIndexCount],
+ void* planes[]) override;
private:
/*
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index 257b764..f5c23a2 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -831,11 +831,18 @@
}
jpeg_component_info * comp_info = dinfo->comp_info;
- for (auto i : { SkYUVSizeInfo::kY, SkYUVSizeInfo::kU, SkYUVSizeInfo::kV }) {
+ for (auto i : { SkYUVAIndex::kY_Index, SkYUVAIndex::kU_Index, SkYUVAIndex::kV_Index }) {
+ sizeInfo->fColorTypes[i] = kAlpha_8_SkColorType;
sizeInfo->fSizes[i].set(comp_info[i].downsampled_width, comp_info[i].downsampled_height);
sizeInfo->fWidthBytes[i] = comp_info[i].width_in_blocks * DCTSIZE;
}
+ // JPEG never has an alpha channel
+ sizeInfo->fColorTypes[SkYUVAIndex::kA_Index] = kUnknown_SkColorType;
+ sizeInfo->fSizes[SkYUVAIndex::kA_Index].fHeight =
+ sizeInfo->fSizes[SkYUVAIndex::kA_Index].fWidth =
+ sizeInfo->fWidthBytes[SkYUVAIndex::kA_Index] = 0;
+
if (colorSpace) {
*colorSpace = kJPEG_SkYUVColorSpace;
}
@@ -843,18 +850,22 @@
return true;
}
-SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
+SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo,
+ void* planes[SkYUVSizeInfo::kMaxCount]) {
SkYUVSizeInfo defaultInfo;
// This will check is_yuv_supported(), so we don't need to here.
bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr);
if (!supportsYUV ||
- sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeInfo::kY] ||
- sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeInfo::kU] ||
- sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeInfo::kV] ||
- sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kY] ||
- sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kU] ||
- sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kV]) {
+ kAlpha_8_SkColorType != sizeInfo.fColorTypes[0] ||
+ kAlpha_8_SkColorType != sizeInfo.fColorTypes[1] ||
+ kAlpha_8_SkColorType != sizeInfo.fColorTypes[2] ||
+ sizeInfo.fSizes[0] != defaultInfo.fSizes[0] ||
+ sizeInfo.fSizes[1] != defaultInfo.fSizes[1] ||
+ sizeInfo.fSizes[2] != defaultInfo.fSizes[2] ||
+ sizeInfo.fWidthBytes[0] < defaultInfo.fWidthBytes[0] ||
+ sizeInfo.fWidthBytes[1] < defaultInfo.fWidthBytes[1] ||
+ sizeInfo.fWidthBytes[2] < defaultInfo.fWidthBytes[2]) {
return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput);
}
@@ -879,9 +890,9 @@
// Currently, we require that the Y plane dimensions match the image dimensions
// and that the U and V planes are the same dimensions.
- SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU] == sizeInfo.fSizes[SkYUVSizeInfo::kV]);
- SkASSERT((uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].width() == dinfo->output_width &&
- (uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].height() == dinfo->output_height);
+ SkASSERT(sizeInfo.fSizes[1] == sizeInfo.fSizes[2]);
+ SkASSERT((uint32_t) sizeInfo.fSizes[0].width() == dinfo->output_width &&
+ (uint32_t) sizeInfo.fSizes[0].height() == dinfo->output_height);
// Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has
// a 2-D array of pixels for each of the components (Y, U, V) in the image.
@@ -898,20 +909,19 @@
// Initialize rowptrs.
int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
for (int i = 0; i < numYRowsPerBlock; i++) {
- rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kY],
- i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
+ rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[0], i * sizeInfo.fWidthBytes[0]);
}
for (int i = 0; i < DCTSIZE; i++) {
- rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kU],
- i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]);
- rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kV],
- i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]);
+ rowptrs[i + 2 * DCTSIZE] =
+ SkTAddOffset<JSAMPLE>(planes[1], i * sizeInfo.fWidthBytes[1]);
+ rowptrs[i + 3 * DCTSIZE] =
+ SkTAddOffset<JSAMPLE>(planes[2], i * sizeInfo.fWidthBytes[2]);
}
// After each loop iteration, we will increment pointers to Y, U, and V.
- size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY];
- size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU];
- size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV];
+ size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[0];
+ size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[1];
+ size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[2];
uint32_t numRowsPerBlock = numYRowsPerBlock;
@@ -944,7 +954,7 @@
// this requirement using a dummy row buffer.
// FIXME: Should SkCodec have an extra memory buffer that can be shared among
// all of the implementations that use temporary/garbage memory?
- SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
+ SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVAIndex::kY_Index]);
for (int i = remainingRows; i < numYRowsPerBlock; i++) {
rowptrs[i] = dummyRow.get();
}
diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h
index 5eff1d5..c102627 100644
--- a/src/codec/SkJpegCodec.h
+++ b/src/codec/SkJpegCodec.h
@@ -46,7 +46,8 @@
bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override;
- Result onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override;
+ Result onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo,
+ void* planes[SkYUVSizeInfo::kMaxCount]) override;
SkEncodedImageFormat onGetEncodedFormat() const override {
return SkEncodedImageFormat::kJPEG;
diff --git a/src/core/SkDeferredDisplayListRecorder.cpp b/src/core/SkDeferredDisplayListRecorder.cpp
index 3940a6d..99b2a7e 100644
--- a/src/core/SkDeferredDisplayListRecorder.cpp
+++ b/src/core/SkDeferredDisplayListRecorder.cpp
@@ -64,6 +64,7 @@
#include "SkImage_Gpu.h"
#include "SkImage_GpuYUVA.h"
#include "SkSurface_Gpu.h"
+#include "SkYUVSizeInfo.h"
SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c)
: fCharacterization(c) {
@@ -230,7 +231,7 @@
sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
SkYUVColorSpace yuvColorSpace,
const GrBackendFormat yuvaFormats[],
- const SkISize yuvaSizes[],
+ const SkYUVSizeInfo& yuvaSizeInfo,
const SkYUVAIndex yuvaIndices[4],
int imageWidth,
int imageHeight,
@@ -247,7 +248,7 @@
return SkImage_GpuYUVA::MakePromiseYUVATexture(fContext.get(),
yuvColorSpace,
yuvaFormats,
- yuvaSizes,
+ yuvaSizeInfo,
yuvaIndices,
imageWidth,
imageHeight,
diff --git a/src/core/SkImageGenerator.cpp b/src/core/SkImageGenerator.cpp
index e0275a1..42d5214 100644
--- a/src/core/SkImageGenerator.cpp
+++ b/src/core/SkImageGenerator.cpp
@@ -8,6 +8,7 @@
#include "SkImage.h"
#include "SkImageGenerator.h"
#include "SkNextID.h"
+#include "SkYUVAIndex.h"
SkImageGenerator::SkImageGenerator(const SkImageInfo& info, uint32_t uniqueID)
: fInfo(info)
@@ -29,28 +30,119 @@
return this->onGetPixels(info, pixels, rowBytes, defaultOpts);
}
-bool SkImageGenerator::queryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
+bool SkImageGenerator::queryYUVA8(SkYUVSizeInfo* sizeInfo,
+ SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+ SkYUVColorSpace* colorSpace) const {
SkASSERT(sizeInfo);
- return this->onQueryYUV8(sizeInfo, colorSpace);
+ if (!this->onQueryYUVA8(sizeInfo, yuvaIndices, colorSpace)) {
+ // try the deprecated method and make a guess at the other data
+ if (this->onQueryYUV8(sizeInfo, colorSpace)) {
+ // take a guess at the number of planes
+ int numPlanes = SkYUVSizeInfo::kMaxCount;
+ for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ if (sizeInfo->fSizes[i].isEmpty()) {
+ numPlanes = i;
+ break;
+ }
+ }
+ if (!numPlanes) {
+ return false;
+ }
+ switch (numPlanes) {
+ case 1:
+ // Assume 3 interleaved planes
+ sizeInfo->fColorTypes[0] = kRGBA_8888_SkColorType;
+ sizeInfo->fColorTypes[1] = kUnknown_SkColorType;
+ sizeInfo->fColorTypes[2] = kUnknown_SkColorType;
+ sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
+ yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
+ yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 0;
+ yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kG;
+ yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 0;
+ yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kB;
+ yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
+ yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
+ break;
+ case 2:
+ // Assume 1 Y plane and interleaved UV planes
+ sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
+ sizeInfo->fColorTypes[1] = kRGBA_8888_SkColorType;
+ sizeInfo->fColorTypes[2] = kUnknown_SkColorType;
+ sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
+ yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
+ yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
+ yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 1;
+ yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kG;
+ yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
+ yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
+ break;
+ case 3:
+ // Assume 3 separate non-interleaved planes
+ sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
+ sizeInfo->fColorTypes[1] = kAlpha_8_SkColorType;
+ sizeInfo->fColorTypes[2] = kAlpha_8_SkColorType;
+ sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
+ yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
+ yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
+ yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 2;
+ yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
+ yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
+ break;
+ case 4:
+ default:
+ // Assume 4 separate non-interleaved planes
+ sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
+ sizeInfo->fColorTypes[1] = kAlpha_8_SkColorType;
+ sizeInfo->fColorTypes[2] = kAlpha_8_SkColorType;
+ sizeInfo->fColorTypes[3] = kAlpha_8_SkColorType;
+ yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
+ yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
+ yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 2;
+ yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;
+ yuvaIndices[SkYUVAIndex::kA_Index].fIndex = 3;
+ yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
+ break;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ return true;
}
-bool SkImageGenerator::getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
- SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth >= 0);
- SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight >= 0);
- SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU].fWidth >= 0);
- SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight >= 0);
- SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kV].fWidth >= 0);
- SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kV].fHeight >= 0);
- SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] >=
- (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth);
- SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] >=
- (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kU].fWidth);
- SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] >=
- (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kV].fWidth);
- SkASSERT(planes && planes[0] && planes[1] && planes[2]);
+bool SkImageGenerator::getYUVA8Planes(const SkYUVSizeInfo& sizeInfo,
+ const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+ void* planes[SkYUVSizeInfo::kMaxCount]) {
- return this->onGetYUV8Planes(sizeInfo, planes);
+ for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ SkASSERT(sizeInfo.fSizes[i].fWidth >= 0);
+ SkASSERT(sizeInfo.fSizes[i].fHeight >= 0);
+ SkASSERT(sizeInfo.fWidthBytes[i] >= (size_t) sizeInfo.fSizes[i].fWidth);
+ }
+
+ int numPlanes = 0;
+ SkASSERT(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
+ SkASSERT(planes);
+ for (int i = 0; i < numPlanes; ++i) {
+ SkASSERT(planes[i]);
+ }
+
+ if (!this->onGetYUVA8Planes(sizeInfo, yuvaIndices, planes)) {
+ return this->onGetYUV8Planes(sizeInfo, planes);
+ }
+ return true;
}
#if SK_SUPPORT_GPU
diff --git a/src/core/SkYUVPlanesCache.h b/src/core/SkYUVPlanesCache.h
index 1c866a2..648f194 100644
--- a/src/core/SkYUVPlanesCache.h
+++ b/src/core/SkYUVPlanesCache.h
@@ -10,6 +10,7 @@
#include "SkCachedData.h"
#include "SkImageInfo.h"
+#include "SkYUVAIndex.h"
#include "SkYUVSizeInfo.h"
class SkResourceCache;
@@ -17,14 +18,15 @@
class SkYUVPlanesCache {
public:
/**
- * The Info struct contains data about the 3 Y, U and V planes of memory stored
+ * The Info struct contains data about the 4 Y, U, V, and A planes of memory stored
* contiguously, in that order, as a single block of memory within SkYUVPlanesCache.
*
- * fSizeInfo: fWidth, fHeight, and fWidthBytes of each of the Y, U, and V planes.
+ * fSizeInfo: fWidth, fHeight, and fWidthBytes of each of the Y, U, V, and A planes.
* fColorSpace: color space that will be used for the YUV -> RGB conversion.
*/
struct Info {
SkYUVSizeInfo fSizeInfo;
+ SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
SkYUVColorSpace fColorSpace;
};
/**
diff --git a/src/core/SkYUVSizeInfo.cpp b/src/core/SkYUVSizeInfo.cpp
new file mode 100644
index 0000000..7ebdbb9
--- /dev/null
+++ b/src/core/SkYUVSizeInfo.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkYUVSizeInfo.h"
+#include "SkTemplates.h"
+
+void SkYUVSizeInfo::computePlanes(void* base, void* planes[SkYUVSizeInfo::kMaxCount]) const {
+ planes[0] = base;
+ int i = 1;
+ for (; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ if (fSizes[i].isEmpty()) {
+ break;
+ }
+ planes[i] = SkTAddOffset<void>(planes[i - 1], fWidthBytes[i - 1] * fSizes[i - 1].height());
+ }
+ for (; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ planes[i] = nullptr;
+ }
+}
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index da86eac..beccd7d 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -22,40 +22,64 @@
#include "effects/GrYUVtoRGBEffect.h"
sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVSizeInfo* size,
+ SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
SkYUVColorSpace* colorSpace,
- const void* constPlanes[3]) {
+ const void* constPlanes[SkYUVSizeInfo::kMaxCount]) {
sk_sp<SkCachedData> data;
SkYUVPlanesCache::Info yuvInfo;
data.reset(SkYUVPlanesCache::FindAndRef(this->onGetID(), &yuvInfo));
- void* planes[3];
+ void* planes[SkYUVSizeInfo::kMaxCount];
if (data.get()) {
- planes[0] = (void*)data->data();
- planes[1] = (uint8_t*)planes[0] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] *
- yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
- planes[2] = (uint8_t*)planes[1] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] *
- yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight);
+ planes[0] = (void*)data->data(); // we should always have at least one plane
+
+ for (int i = 1; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
+ SkASSERT(kUnknown_SkColorType == yuvInfo.fSizeInfo.fColorTypes[i] &&
+ !yuvInfo.fSizeInfo.fWidthBytes[i] &&
+ !yuvInfo.fSizeInfo.fSizes[i].fHeight);
+ planes[i] = nullptr;
+ continue;
+ }
+
+ planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
+ yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
+ }
} else {
// Fetch yuv plane sizes for memory allocation.
- if (!this->onQueryYUV8(&yuvInfo.fSizeInfo, &yuvInfo.fColorSpace)) {
+ if (!this->onQueryYUVA8(&yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, &yuvInfo.fColorSpace)) {
return nullptr;
}
- // Allocate the memory for YUV
+ // Allocate the memory for YUVA
size_t totalSize(0);
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < SkYUVSizeInfo::kMaxCount; i++) {
+ SkASSERT(kUnknown_SkColorType != yuvInfo.fSizeInfo.fColorTypes[i] ||
+ (!yuvInfo.fSizeInfo.fWidthBytes[i] && !yuvInfo.fSizeInfo.fSizes[i].fHeight));
+
totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight;
}
+
data.reset(SkResourceCache::NewCachedData(totalSize));
+
planes[0] = data->writable_data();
- planes[1] = (uint8_t*)planes[0] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] *
- yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
- planes[2] = (uint8_t*)planes[1] + (yuvInfo.fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] *
- yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight);
+
+ for (int i = 1; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
+ SkASSERT(kUnknown_SkColorType == yuvInfo.fSizeInfo.fColorTypes[i] &&
+ !yuvInfo.fSizeInfo.fWidthBytes[i] &&
+ !yuvInfo.fSizeInfo.fSizes[i].fHeight);
+ planes[i] = nullptr;
+ continue;
+ }
+
+ planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
+ yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
+ }
// Get the YUV planes.
- if (!this->onGetYUV8Planes(yuvInfo.fSizeInfo, planes)) {
+ if (!this->onGetYUVA8Planes(yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, planes)) {
return nullptr;
}
@@ -64,10 +88,12 @@
}
*size = yuvInfo.fSizeInfo;
+ memcpy(yuvaIndices, yuvInfo.fYUVAIndices, sizeof(yuvInfo.fYUVAIndices));
*colorSpace = yuvInfo.fColorSpace;
constPlanes[0] = planes[0];
constPlanes[1] = planes[1];
constPlanes[2] = planes[2];
+ constPlanes[3] = planes[3];
return data;
}
@@ -81,24 +107,33 @@
SkColorSpace* srcColorSpace,
SkColorSpace* dstColorSpace) {
SkYUVSizeInfo yuvSizeInfo;
+ SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
SkYUVColorSpace yuvColorSpace;
- const void* planes[3];
+ const void* planes[SkYUVSizeInfo::kMaxCount];
- sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, &yuvColorSpace, planes);
+ sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, yuvaIndices,
+ &yuvColorSpace, planes);
if (!dataStorage) {
return nullptr;
}
- sk_sp<GrTextureProxy> yuvTextureProxies[3];
- for (int i = 0; i < 3; i++) {
+ sk_sp<GrTextureProxy> yuvTextureProxies[SkYUVSizeInfo::kMaxCount];
+ for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ if (kUnknown_SkColorType == yuvSizeInfo.fColorTypes[i]) {
+ SkASSERT(!yuvSizeInfo.fSizes[i].fWidth ||
+ !yuvSizeInfo.fSizes[i].fHeight ||
+ !yuvSizeInfo.fWidthBytes[i]);
+ continue;
+ }
+
int componentWidth = yuvSizeInfo.fSizes[i].fWidth;
int componentHeight = yuvSizeInfo.fSizes[i].fHeight;
// If the sizes of the components are not all the same we choose to create exact-match
// textures for the smaller ones rather than add a texture domain to the draw.
// TODO: revisit this decision to improve texture reuse?
SkBackingFit fit =
- (componentWidth != yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) ||
- (componentHeight != yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight)
+ (componentWidth != yuvSizeInfo.fSizes[0].fWidth) ||
+ (componentHeight != yuvSizeInfo.fSizes[0].fHeight)
? SkBackingFit::kExact : SkBackingFit::kApprox;
SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
@@ -131,17 +166,8 @@
return nullptr;
}
- // This code path only generates I420 (i.e., 3 separate plane) YUVs
- SkYUVAIndex yuvaIndices[4] = {
- { 0, SkColorChannel::kA },
- { 1, SkColorChannel::kA },
- { 2, SkColorChannel::kA },
- { -1, SkColorChannel::kA }, // no alpha
- };
-
GrPaint paint;
- auto yuvToRgbProcessor =
- GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace);
+ auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace);
paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
// If the caller expects the pixels in a different color space than the one from the image,
@@ -154,8 +180,8 @@
}
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
- const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth,
- yuvSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
+ const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
+ yuvSizeInfo.fSizes[0].fHeight);
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
diff --git a/src/gpu/GrYUVProvider.h b/src/gpu/GrYUVProvider.h
index de6ce33..505274e 100644
--- a/src/gpu/GrYUVProvider.h
+++ b/src/gpu/GrYUVProvider.h
@@ -17,6 +17,7 @@
class GrTexture;
class GrTextureProxy;
class SkCachedData;
+struct SkYUVAIndex;
/**
* There are at least 2 different ways to extract/retrieve YUV planar data...
@@ -43,7 +44,8 @@
SkColorSpace* srcColorSpace,
SkColorSpace* dstColorSpace);
- sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVColorSpace*, const void* planes[3]);
+ sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVAIndex[SkYUVAIndex::kIndexCount],
+ SkYUVColorSpace*, const void* planes[SkYUVSizeInfo::kMaxCount]);
private:
virtual uint32_t onGetID() const = 0;
@@ -54,23 +56,29 @@
* If decoding to YUV is supported, this returns true. Otherwise, this
* returns false and does not modify any of the parameters.
*
- * @param sizeInfo Output parameter indicating the sizes and required
- * allocation widths of the Y, U, and V planes.
- * @param colorSpace Output parameter.
+ * @param sizeInfo Output parameter indicating the sizes and required
+ * allocation widths of the Y, U, V, and A planes.
+ * @param yuvaIndices How the YUVA planes are used/organized
+ * @param colorSpace Output parameter.
*/
- virtual bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const = 0;
+ virtual bool onQueryYUVA8(SkYUVSizeInfo* sizeInfo,
+ SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+ SkYUVColorSpace* colorSpace) const = 0;
/**
* Returns true on success and false on failure.
* This always attempts to perform a full decode. If the client only
- * wants size, it should call onQueryYUV8().
+ * wants size, it should call onQueryYUVA8().
*
- * @param sizeInfo Needs to exactly match the values returned by the
- * query, except the WidthBytes may be larger than the
- * recommendation (but not smaller).
- * @param planes Memory for each of the Y, U, and V planes.
+ * @param sizeInfo Needs to exactly match the values returned by the
+ * query, except the WidthBytes may be larger than the
+ * recommendation (but not smaller).
+ * @param yuvaIndices How the YUVA planes are used/organized
+ * @param planes Memory for each of the Y, U, V, and A planes.
*/
- virtual bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) = 0;
+ virtual bool onGetYUVA8Planes(const SkYUVSizeInfo& sizeInfo,
+ const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+ void* planes[]) = 0;
// This is used as release callback for the YUV data that we capture in an SkImage when
// uploading to a gpu. When the upload is complete and we release the SkImage this callback will
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 0d173fa..6470f82 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -228,7 +228,8 @@
return as_IB(this)->onAsLegacyBitmap(bitmap);
}
-sk_sp<SkCachedData> SkImage_Base::getPlanes(SkYUVSizeInfo*, SkYUVColorSpace*,const void*[3]) {
+sk_sp<SkCachedData> SkImage_Base::getPlanes(SkYUVSizeInfo*, SkYUVAIndex[4],
+ SkYUVColorSpace*, const void*[4]) {
return nullptr;
}
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index 8765f89..7bbd81d 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -72,7 +72,8 @@
virtual sk_sp<SkImage> onMakeSubset(const SkIRect&) const = 0;
- virtual sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVColorSpace*, const void* planes[3]);
+ virtual sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVAIndex[4],
+ SkYUVColorSpace*, const void* planes[4]);
virtual sk_sp<SkData> onRefEncoded() const { return nullptr; }
virtual bool onAsLegacyBitmap(SkBitmap*) const;
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index 25b9349..f246508 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -16,6 +16,7 @@
#include "GrTexture.h"
#include "SkImage_Gpu.h"
#include "SkImage_GpuYUVA.h"
+#include "SkYUVSizeInfo.h"
#include "effects/GrYUVtoRGBEffect.h"
SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
@@ -182,7 +183,7 @@
sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
SkYUVColorSpace yuvColorSpace,
const GrBackendFormat yuvaFormats[],
- const SkISize yuvaSizes[],
+ const SkYUVSizeInfo& yuvaSizeInfo,
const SkYUVAIndex yuvaIndices[4],
int imageWidth,
int imageHeight,
@@ -232,24 +233,20 @@
return nullptr;
}
- // Set up color types
- SkColorType texColorTypes[4] = { kUnknown_SkColorType, kUnknown_SkColorType,
- kUnknown_SkColorType, kUnknown_SkColorType };
- for (int yuvIndex = 0; yuvIndex < 4; ++yuvIndex) {
- int texIdx = yuvaIndices[yuvIndex].fIndex;
- if (texIdx < 0) {
- SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
- continue;
- }
- if (kUnknown_SkColorType == texColorTypes[texIdx]) {
- texColorTypes[texIdx] = kAlpha_8_SkColorType;
- } else {
- texColorTypes[texIdx] = kRGBA_8888_SkColorType;
+ // verify sizeInfo with expected texture count
+ for (int i = 0; i < numTextures; ++i) {
+ if (kUnknown_SkColorType == yuvaSizeInfo.fColorTypes[i] ||
+ yuvaSizeInfo.fSizes[i].isEmpty() ||
+ !yuvaSizeInfo.fWidthBytes[i]) {
+ return nullptr;
}
}
- // If UV is interleaved, then Y will have RGBA color type
- if (kRGBA_8888_SkColorType == texColorTypes[yuvaIndices[SkYUVAIndex::kU_Index].fIndex]) {
- texColorTypes[yuvaIndices[SkYUVAIndex::kY_Index].fIndex] = kRGBA_8888_SkColorType;
+ for (int i = numTextures; i < SkYUVSizeInfo::kMaxCount; ++i) {
+ if (kUnknown_SkColorType != yuvaSizeInfo.fColorTypes[i] ||
+ !yuvaSizeInfo.fSizes[i].isEmpty() ||
+ yuvaSizeInfo.fWidthBytes[i]) {
+ return nullptr;
+ }
}
// Get lazy proxies
@@ -261,9 +258,11 @@
GrPixelConfig fConfig;
SkPromiseImageHelper fPromiseHelper;
} params;
- if (!context->contextPriv().caps()->getConfigFromBackendFormat(yuvaFormats[texIdx],
- texColorTypes[texIdx],
- ¶ms.fConfig)) {
+ bool res = context->contextPriv().caps()->getConfigFromBackendFormat(
+ yuvaFormats[texIdx],
+ yuvaSizeInfo.fColorTypes[texIdx],
+ ¶ms.fConfig);
+ if (!res) {
return nullptr;
}
params.fPromiseHelper = promiseHelpers[texIdx];
@@ -281,8 +280,8 @@
};
GrSurfaceDesc desc;
desc.fFlags = kNone_GrSurfaceFlags;
- desc.fWidth = yuvaSizes[texIdx].width();
- desc.fHeight = yuvaSizes[texIdx].height();
+ desc.fWidth = yuvaSizeInfo.fSizes[texIdx].width();
+ desc.fHeight = yuvaSizeInfo.fSizes[texIdx].height();
desc.fConfig = params.fConfig;
desc.fSampleCnt = 1;
proxies[texIdx] = proxyProvider->createLazyProxy(
diff --git a/src/image/SkImage_GpuYUVA.h b/src/image/SkImage_GpuYUVA.h
index c5f0b9d..337fb3d 100644
--- a/src/image/SkImage_GpuYUVA.h
+++ b/src/image/SkImage_GpuYUVA.h
@@ -15,6 +15,7 @@
#include "SkYUVAIndex.h"
class GrTexture;
+struct SkYUVSizeInfo;
// Wraps the 3 or 4 planes of a YUVA image for consumption by the GPU.
// Initially any direct rendering will be done by passing the individual planes to a shader.
@@ -62,7 +63,7 @@
@param context Gpu context
@param yuvColorSpace color range of expected YUV pixels
@param yuvaFormats formats of promised gpu textures for each YUVA plane
- @param yuvaSizes width and height of promised gpu textures
+ @param yuvaSizeInfo width, height, and colortype of promised gpu textures
@param yuvaIndices mapping from yuv plane index to texture representing that plane
@param width width of promised gpu texture
@param height height of promised gpu texture
@@ -77,7 +78,7 @@
static sk_sp<SkImage> MakePromiseYUVATexture(GrContext* context,
SkYUVColorSpace yuvColorSpace,
const GrBackendFormat yuvaFormats[],
- const SkISize yuvaSizes[],
+ const SkYUVSizeInfo& yuvaSizeInfo,
const SkYUVAIndex yuvaIndices[4],
int width,
int height,
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index e81c395..5c8b627 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -355,11 +355,15 @@
private:
uint32_t onGetID() const override { return fGen->uniqueID(); }
- bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override {
- return fGen->queryYUV8(sizeInfo, colorSpace);
+ bool onQueryYUVA8(SkYUVSizeInfo* sizeInfo,
+ SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+ SkYUVColorSpace* colorSpace) const override {
+ return fGen->queryYUVA8(sizeInfo, yuvaIndices, colorSpace);
}
- bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override {
- return fGen->getYUV8Planes(sizeInfo, planes);
+ bool onGetYUVA8Planes(const SkYUVSizeInfo& sizeInfo,
+ const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+ void* planes[]) override {
+ return fGen->getYUVA8Planes(sizeInfo, yuvaIndices, planes);
}
SkImageGenerator* fGen;
@@ -384,13 +388,14 @@
}
}
-sk_sp<SkCachedData> SkImage_Lazy::getPlanes(SkYUVSizeInfo* yuvSizeInfo,
+sk_sp<SkCachedData> SkImage_Lazy::getPlanes(SkYUVSizeInfo* yuvaSizeInfo,
+ SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
SkYUVColorSpace* yuvColorSpace,
- const void* planes[3]) {
+ const void* planes[SkYUVSizeInfo::kMaxCount]) {
ScopedGenerator generator(fSharedGenerator);
Generator_GrYUVProvider provider(generator);
- sk_sp<SkCachedData> data = provider.getPlanes(yuvSizeInfo, yuvColorSpace, planes);
+ sk_sp<SkCachedData> data = provider.getPlanes(yuvaSizeInfo, yuvaIndices, yuvColorSpace, planes);
if (!data) {
return nullptr;
}
diff --git a/src/image/SkImage_Lazy.h b/src/image/SkImage_Lazy.h
index a2b434a..5c30ee3 100644
--- a/src/image/SkImage_Lazy.h
+++ b/src/image/SkImage_Lazy.h
@@ -49,7 +49,8 @@
const GrSamplerState&, SkColorSpace*,
sk_sp<SkColorSpace>*,
SkScalar scaleAdjust[2]) const override;
- sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVColorSpace*, const void* planes[3]) override;
+ sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVAIndex[4],
+ SkYUVColorSpace*, const void* planes[4]) override;
#endif
sk_sp<SkData> onRefEncoded() const override;
sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;