Test YUV images in DDL
The main two CLs calved off (and landed independently) from this CL are:
https://skia-review.googlesource.com/c/skia/+/156761 (Add SkImage_Gpu::MakePromiseYUVATexture)
-- adds internal place holder for YUVA promise images (only returns Y channel)
https://skia-review.googlesource.com/c/skia/+/156140 (Add SkImage_Base API to access planar data)
-- adds ability to grab planes for testing purposes (not externally visible)
Bug: skia:7903
Bug: skia:8424
Change-Id: Id0f2f84851dacc66c2c266a30cafa0b628b12eb4
Reviewed-on: https://skia-review.googlesource.com/151983
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/tools/DDLPromiseImageHelper.cpp b/tools/DDLPromiseImageHelper.cpp
index 0d4e0ff..51225b3 100644
--- a/tools/DDLPromiseImageHelper.cpp
+++ b/tools/DDLPromiseImageHelper.cpp
@@ -10,7 +10,11 @@
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrGpu.h"
+#include "SkCachedData.h"
#include "SkDeferredDisplayListRecorder.h"
+#include "SkImage_Base.h"
+#include "SkImagePriv.h"
+#include "SkYUVSizeInfo.h"
DDLPromiseImageHelper::PromiseImageCallbackContext::~PromiseImageCallbackContext() {
GrGpu* gpu = fContext->contextPriv().getGpu();
@@ -26,6 +30,8 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
+DDLPromiseImageHelper::~DDLPromiseImageHelper() {}
+
sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
SkSerialProcs procs;
@@ -50,23 +56,45 @@
SkASSERT(gpu);
for (int i = 0; i < fImageInfo.count(); ++i) {
- sk_sp<PromiseImageCallbackContext> callbackContext(
- new PromiseImageCallbackContext(context));
-
const PromiseImageInfo& info = fImageInfo[i];
// DDL TODO: how can we tell if we need mipmapping!
- callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
- info.fBitmap.getPixels(),
- info.fBitmap.width(),
- info.fBitmap.height(),
- info.fBitmap.colorType(),
- false, GrMipMapped::kNo));
- // The GMs sometimes request too large an image
- //SkAssertResult(callbackContext->backendTexture().isValid());
+ if (info.isYUV()) {
+ for (int j = 0; j < 3; ++j) {
+ const SkPixmap& yuvPixmap = info.yuvPixmap(j);
- // The fImageInfo array gets the creation ref
- fImageInfo[i].fCallbackContext = std::move(callbackContext);
+ sk_sp<PromiseImageCallbackContext> callbackContext(
+ new PromiseImageCallbackContext(context));
+ callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
+ yuvPixmap.addr(),
+ yuvPixmap.width(),
+ yuvPixmap.height(),
+ yuvPixmap.colorType(),
+ false, GrMipMapped::kNo,
+ yuvPixmap.rowBytes()));
+ SkAssertResult(callbackContext->backendTexture().isValid());
+
+ fImageInfo[i].setCallbackContext(j, std::move(callbackContext));
+ }
+ } else {
+ sk_sp<PromiseImageCallbackContext> callbackContext(
+ new PromiseImageCallbackContext(context));
+
+ const SkBitmap& bm = info.normalBitmap();
+
+ callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
+ bm.getPixels(),
+ bm.width(),
+ bm.height(),
+ bm.colorType(),
+ false, GrMipMapped::kNo,
+ bm.rowBytes()));
+ // The GMs sometimes request too large an image
+ //SkAssertResult(callbackContext->backendTexture().isValid());
+
+ fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
+ }
+
}
}
@@ -99,34 +127,71 @@
const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
- if (!curImage.fCallbackContext->backendTexture().isValid()) {
+ if (!curImage.backendTexture(0).isValid()) {
+ SkASSERT(!curImage.isYUV());
// We weren't able to make a backend texture for this SkImage. In this case we create
// a separate bitmap-backed image for each thread.
- SkASSERT(curImage.fBitmap.isImmutable());
- return SkImage::MakeFromBitmap(curImage.fBitmap);
+ SkASSERT(curImage.normalBitmap().isImmutable());
+ return SkImage::MakeFromBitmap(curImage.normalBitmap());
}
- SkASSERT(curImage.fIndex == *indexPtr);
+ SkASSERT(curImage.index() == *indexPtr);
- const GrCaps* caps = curImage.fCallbackContext->caps();
- const GrBackendTexture& backendTex = curImage.fCallbackContext->backendTexture();
- GrBackendFormat backendFormat = caps->createFormatFromBackendTexture(backendTex);
+ const GrCaps* caps = curImage.caps();
- // Each DDL recorder gets its own ref on the promise callback context for the
- // promise images it creates.
- // DDL TODO: sort out mipmapping
- sk_sp<SkImage> image = recorder->makePromiseTexture(
- backendFormat,
- curImage.fBitmap.width(),
- curImage.fBitmap.height(),
- GrMipMapped::kNo,
- GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
- curImage.fBitmap.colorType(),
- curImage.fBitmap.alphaType(),
- curImage.fBitmap.refColorSpace(),
- DDLPromiseImageHelper::PromiseImageFulfillProc,
- DDLPromiseImageHelper::PromiseImageReleaseProc,
- DDLPromiseImageHelper::PromiseImageDoneProc,
- (void*) SkSafeRef(curImage.fCallbackContext.get()));
+ sk_sp<SkImage> image;
+ if (curImage.isYUV()) {
+ GrBackendFormat backendFormats[4];
+ void* contexts[4] = { nullptr, nullptr, nullptr, nullptr };
+
+ for (int i = 0; i < 3; ++i) {
+ const GrBackendTexture& backendTex = curImage.backendTexture(i);
+ backendFormats[i] = caps->createFormatFromBackendTexture(backendTex);
+
+ contexts[i] = curImage.refCallbackContext(i).release();
+ }
+
+ SkYUVAIndex yuvaIndices[4] = {
+ SkYUVAIndex{0, SkImageSourceChannel::kA_SkImageSourceChannel},
+ SkYUVAIndex{1, SkImageSourceChannel::kA_SkImageSourceChannel},
+ SkYUVAIndex{2, SkImageSourceChannel::kA_SkImageSourceChannel},
+ SkYUVAIndex{-1, SkImageSourceChannel::kA_SkImageSourceChannel}
+ };
+
+ int tempWidth = curImage.backendTexture(0).width();
+ int tempHeight = curImage.backendTexture(0).height();
+
+ image = recorder->makeYUVAPromiseTexture(curImage.yuvColorSpace(),
+ backendFormats,
+ yuvaIndices,
+ tempWidth, //curImage.overallWidth(),
+ tempHeight, //curImage.overallHeight(),
+ GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
+ curImage.refOverallColorSpace(),
+ DDLPromiseImageHelper::PromiseImageFulfillProc,
+ DDLPromiseImageHelper::PromiseImageReleaseProc,
+ DDLPromiseImageHelper::PromiseImageDoneProc,
+ contexts);
+
+ } else {
+ const GrBackendTexture& backendTex = curImage.backendTexture(0);
+ GrBackendFormat backendFormat = caps->createFormatFromBackendTexture(backendTex);
+
+ // Each DDL recorder gets its own ref on the promise callback context for the
+ // promise images it creates.
+ // DDL TODO: sort out mipmapping
+ image = recorder->makePromiseTexture(backendFormat,
+ curImage.overallWidth(),
+ curImage.overallHeight(),
+ GrMipMapped::kNo,
+ GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
+ curImage.overallColorType(),
+ curImage.overallAlphaType(),
+ curImage.refOverallColorSpace(),
+ DDLPromiseImageHelper::PromiseImageFulfillProc,
+ DDLPromiseImageHelper::PromiseImageReleaseProc,
+ DDLPromiseImageHelper::PromiseImageDoneProc,
+ (void*) curImage.refCallbackContext(0).release());
+ }
perRecorderContext->fPromiseImages->push_back(image);
SkASSERT(image);
return image;
@@ -134,9 +199,9 @@
int DDLPromiseImageHelper::findImage(SkImage* image) const {
for (int i = 0; i < fImageInfo.count(); ++i) {
- if (fImageInfo[i].fOriginalUniqueID == image->uniqueID()) { // trying to dedup here
- SkASSERT(fImageInfo[i].fIndex == i);
- SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].fIndex));
+ if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
+ SkASSERT(fImageInfo[i].index() == i);
+ SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
return i;
}
}
@@ -144,26 +209,42 @@
}
int DDLPromiseImageHelper::addImage(SkImage* image) {
- sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
+ SkImage_Base* ib = as_IB(image);
- SkImageInfo ii = SkImageInfo::Make(rasterImage->width(), rasterImage->height(),
- rasterImage->colorType(), rasterImage->alphaType(),
- rasterImage->refColorSpace());
+ SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
+ image->colorType(), image->alphaType(),
+ image->refColorSpace());
- SkBitmap bm;
- bm.allocPixels(ii);
+ PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
+ image->uniqueID(),
+ overallII);
- if (!rasterImage->readPixels(bm.pixmap(), 0, 0)) {
- return -1;
+ SkYUVSizeInfo yuvSizeInfo;
+ SkYUVColorSpace yuvColorSpace;
+ const void* planes[3];
+ sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvSizeInfo, &yuvColorSpace, planes);
+ if (yuvData) {
+ newImageInfo.setYUVData(std::move(yuvData), yuvColorSpace);
+
+ for (int i = 0; i < 3; ++i) {
+ SkImageInfo planeII = SkImageInfo::MakeA8(yuvSizeInfo.fSizes[i].fWidth,
+ yuvSizeInfo.fSizes[i].fHeight);
+ newImageInfo.addYUVPlane(i, planeII, planes[i], yuvSizeInfo.fWidthBytes[i]);
+ }
+ } else {
+ sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
+
+ SkBitmap tmp;
+ tmp.allocPixels(overallII);
+
+ if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
+ return -1;
+ }
+
+ tmp.setImmutable();
+ newImageInfo.setNormalBitmap(tmp);
}
-
- bm.setImmutable();
-
- PromiseImageInfo& newImageInfo = fImageInfo.push_back();
- newImageInfo.fIndex = fImageInfo.count()-1;
- newImageInfo.fOriginalUniqueID = image->uniqueID();
- newImageInfo.fBitmap = bm;
- /* fCallbackContext is filled in by uploadAllToGPU */
+ // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
return fImageInfo.count()-1;
}