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>
This commit is contained in:
parent
bba2921c19
commit
e8e2bb1384
@ -91,6 +91,7 @@ skia_core_sources = [
|
||||
"$_src/core/SkData.cpp",
|
||||
"$_src/core/SkDataTable.cpp",
|
||||
"$_src/core/SkDebug.cpp",
|
||||
"$_src/core/SkDeferredDisplayListPriv.h",
|
||||
"$_src/core/SkDeferredDisplayList.cpp",
|
||||
"$_src/core/SkDeferredDisplayListRecorder.cpp",
|
||||
"$_src/core/SkDeque.cpp",
|
||||
|
@ -22,6 +22,7 @@ class GrContext;
|
||||
class SkCanvas;
|
||||
class SkImage;
|
||||
class SkSurface;
|
||||
struct SkYUVAIndex;
|
||||
|
||||
/*
|
||||
* This class is intended to be used as:
|
||||
@ -76,7 +77,7 @@ public:
|
||||
In other words we will never call textureFulfillProc or textureReleaseProc multiple times
|
||||
for the same textureContext before calling the other.
|
||||
|
||||
We we call the promiseDoneProc when we will no longer call the textureFulfillProc again. We
|
||||
We call the promiseDoneProc when we will no longer call the textureFulfillProc again. We
|
||||
pass in the textureContext as a parameter to the promiseDoneProc. We also guarantee that
|
||||
there will be no outstanding textureReleaseProcs that still need to be called when we call
|
||||
the textureDoneProc. Thus when the textureDoneProc gets called the client is able to cleanup
|
||||
@ -115,6 +116,24 @@ public:
|
||||
PromiseDoneProc promiseDoneProc,
|
||||
TextureContext textureContext);
|
||||
|
||||
/**
|
||||
This entry point operates the same as 'makePromiseTexture' except that its
|
||||
textureFulfillProc can be called up to four times to fetch the required YUVA
|
||||
planes (passing a different textureContext to each call). So, if the 'yuvaIndices'
|
||||
indicate that only the first two backend textures are used, 'textureFulfillProc' will
|
||||
be called with the first two 'textureContexts'.
|
||||
*/
|
||||
sk_sp<SkImage> makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace,
|
||||
const GrBackendFormat yuvaFormats[],
|
||||
const SkYUVAIndex yuvaIndices[4],
|
||||
int imageWidth,
|
||||
int imageHeight,
|
||||
GrSurfaceOrigin imageOrigin,
|
||||
sk_sp<SkColorSpace> imageColorSpace,
|
||||
TextureFulfillProc textureFulfillProc,
|
||||
TextureReleaseProc textureReleaseProc,
|
||||
PromiseDoneProc promiseDoneProc,
|
||||
TextureContext textureContexts[]);
|
||||
private:
|
||||
bool init();
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
class SkDeferredDisplayListPriv;
|
||||
class SkSurface;
|
||||
|
||||
/*
|
||||
* This class contains pre-processed gpu operations that can be replayed into
|
||||
* an SkSurface via draw(SkDeferredDisplayList*).
|
||||
@ -51,9 +51,14 @@ public:
|
||||
return fCharacterization;
|
||||
}
|
||||
|
||||
// Provides access to functions that aren't part of the public API.
|
||||
SkDeferredDisplayListPriv priv();
|
||||
const SkDeferredDisplayListPriv priv() const;
|
||||
|
||||
private:
|
||||
friend class GrDrawingManager; // for access to 'fOpLists' and 'fLazyProxyData'
|
||||
friend class SkDeferredDisplayListRecorder; // for access to 'fLazyProxyData'
|
||||
friend class SkDeferredDisplayListPriv;
|
||||
|
||||
const SkSurfaceCharacterization fCharacterization;
|
||||
|
||||
|
48
src/core/SkDeferredDisplayListPriv.h
Normal file
48
src/core/SkDeferredDisplayListPriv.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkDeferredDisplayListPriv_DEFINED
|
||||
#define SkDeferredDisplayListPriv_DEFINED
|
||||
|
||||
#include "SkDeferredDisplayList.h"
|
||||
|
||||
/** Class that adds methods to SkDeferredDisplayList that are only intended for use internal to Skia.
|
||||
This class is purely a privileged window into SkDeferredDisplayList. It should never have
|
||||
additional data members or virtual methods. */
|
||||
class SkDeferredDisplayListPriv {
|
||||
public:
|
||||
int numOpLists() const {
|
||||
#if SK_SUPPORT_GPU
|
||||
return fDDL->fOpLists.count();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
explicit SkDeferredDisplayListPriv(SkDeferredDisplayList* ddl) : fDDL(ddl) {}
|
||||
SkDeferredDisplayListPriv(const SkDeferredDisplayListPriv&); // unimpl
|
||||
SkDeferredDisplayListPriv& operator=(const SkDeferredDisplayListPriv&); // unimpl
|
||||
|
||||
// No taking addresses of this type.
|
||||
const SkDeferredDisplayListPriv* operator&() const;
|
||||
SkDeferredDisplayListPriv* operator&();
|
||||
|
||||
SkDeferredDisplayList* fDDL;
|
||||
|
||||
friend class SkDeferredDisplayList; // to construct/copy this type.
|
||||
};
|
||||
|
||||
inline SkDeferredDisplayListPriv SkDeferredDisplayList::priv() {
|
||||
return SkDeferredDisplayListPriv(this);
|
||||
}
|
||||
|
||||
inline const SkDeferredDisplayListPriv SkDeferredDisplayList::priv () const {
|
||||
return SkDeferredDisplayListPriv(const_cast<SkDeferredDisplayList*>(this));
|
||||
}
|
||||
|
||||
#endif
|
@ -38,6 +38,21 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
SkYUVColorSpace yuvColorSpace,
|
||||
const GrBackendFormat yuvaFormats[],
|
||||
const SkYUVAIndex yuvaIndices[4],
|
||||
int imageWidth,
|
||||
int imageHeight,
|
||||
GrSurfaceOrigin imageOrigin,
|
||||
sk_sp<SkColorSpace> imageColorSpace,
|
||||
TextureFulfillProc textureFulfillProc,
|
||||
TextureReleaseProc textureReleaseProc,
|
||||
PromiseDoneProc promiseDoneProc,
|
||||
TextureContext textureContexts[]) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "GrContextPriv.h"
|
||||
@ -211,4 +226,34 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
textureContext);
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
SkYUVColorSpace yuvColorSpace,
|
||||
const GrBackendFormat yuvaFormats[],
|
||||
const SkYUVAIndex yuvaIndices[4],
|
||||
int imageWidth,
|
||||
int imageHeight,
|
||||
GrSurfaceOrigin imageOrigin,
|
||||
sk_sp<SkColorSpace> imageColorSpace,
|
||||
TextureFulfillProc textureFulfillProc,
|
||||
TextureReleaseProc textureReleaseProc,
|
||||
PromiseDoneProc promiseDoneProc,
|
||||
TextureContext textureContexts[]) {
|
||||
if (!fContext) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SkImage_Gpu::MakePromiseYUVATexture(fContext.get(),
|
||||
yuvColorSpace,
|
||||
yuvaFormats,
|
||||
yuvaIndices,
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
imageOrigin,
|
||||
std::move(imageColorSpace),
|
||||
textureFulfillProc,
|
||||
textureReleaseProc,
|
||||
promiseDoneProc,
|
||||
textureContexts);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -105,7 +105,7 @@ enum SkImageSourceChannel {
|
||||
/** Describes the alpha channel; */
|
||||
kA_SkImageSourceChannel,
|
||||
|
||||
/** Describes the alpha channel; */
|
||||
/** Utility value */
|
||||
kLastEnum_SkImageSourceChannel = kA_SkImageSourceChannel,
|
||||
};
|
||||
|
||||
|
@ -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 @@ const GrCaps* DDLPromiseImageHelper::PromiseImageCallbackContext::caps() const {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DDLPromiseImageHelper::~DDLPromiseImageHelper() {}
|
||||
|
||||
sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
|
||||
SkSerialProcs procs;
|
||||
|
||||
@ -50,23 +56,45 @@ void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// The fImageInfo array gets the creation ref
|
||||
fImageInfo[i].fCallbackContext = std::move(callbackContext);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,34 +127,71 @@ sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
|
||||
|
||||
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 @@ sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
|
||||
|
||||
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::findImage(SkImage* image) const {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "SkTArray.h"
|
||||
|
||||
#include "GrBackendSurface.h"
|
||||
#include "SkCachedData.h"
|
||||
#include "SkYUVSizeInfo.h"
|
||||
|
||||
class GrContext;
|
||||
class SkDeferredDisplayListRecorder;
|
||||
@ -35,7 +37,7 @@ class SkPicture;
|
||||
// This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
|
||||
//
|
||||
// Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
|
||||
// are done the PromiseImageCallbackContext is freed and its GrBackendTexture removed
|
||||
// are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
|
||||
// from VRAM
|
||||
//
|
||||
// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
|
||||
@ -43,6 +45,7 @@ class SkPicture;
|
||||
class DDLPromiseImageHelper {
|
||||
public:
|
||||
DDLPromiseImageHelper() { }
|
||||
~DDLPromiseImageHelper();
|
||||
|
||||
// Convert the SkPicture into SkData replacing all the SkImages with an index.
|
||||
sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
|
||||
@ -58,10 +61,10 @@ public:
|
||||
void reset() { fImageInfo.reset(); }
|
||||
|
||||
private:
|
||||
// This class acts as a proxy for the single GrBackendTexture representing an image.
|
||||
// This class acts as a proxy for a GrBackendTexture that is part of an image.
|
||||
// Whenever a promise image is created for the image, the promise image receives a ref to
|
||||
// this object. Once all the promise images receive their done callbacks this object
|
||||
// is deleted - removing the GrBackendTexture from VRAM.
|
||||
// potentially several of these objects. Once all the promise images receive their done
|
||||
// callbacks this object is deleted - removing the GrBackendTexture from VRAM.
|
||||
// Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
|
||||
// a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
|
||||
// it drops all of its refs (via "reset").
|
||||
@ -72,6 +75,7 @@ private:
|
||||
~PromiseImageCallbackContext();
|
||||
|
||||
void setBackendTexture(const GrBackendTexture& backendTexture) {
|
||||
SkASSERT(!fBackendTexture.isValid());
|
||||
fBackendTexture = backendTexture;
|
||||
}
|
||||
|
||||
@ -91,10 +95,85 @@ private:
|
||||
// is all dropped via "reset".
|
||||
class PromiseImageInfo {
|
||||
public:
|
||||
int fIndex; // index in the 'fImageInfo' array
|
||||
uint32_t fOriginalUniqueID; // original ID for deduping
|
||||
SkBitmap fBitmap; // CPU-side cache of the contents
|
||||
sk_sp<PromiseImageCallbackContext> fCallbackContext;
|
||||
PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii)
|
||||
: fIndex(index)
|
||||
, fOriginalUniqueID(originalUniqueID)
|
||||
, fImageInfo(ii) {
|
||||
}
|
||||
~PromiseImageInfo() {}
|
||||
|
||||
int index() const { return fIndex; }
|
||||
uint32_t originalUniqueID() const { return fOriginalUniqueID; }
|
||||
bool isYUV() const { return SkToBool(fYUVData.get()); }
|
||||
|
||||
int overallWidth() const { return fImageInfo.width(); }
|
||||
int overallHeight() const { return fImageInfo.height(); }
|
||||
SkColorType overallColorType() const { return fImageInfo.colorType(); }
|
||||
SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
|
||||
sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
|
||||
|
||||
SkYUVColorSpace yuvColorSpace() const {
|
||||
SkASSERT(this->isYUV());
|
||||
return fYUVColorSpace;
|
||||
}
|
||||
const SkPixmap& yuvPixmap(int index) const {
|
||||
SkASSERT(this->isYUV());
|
||||
SkASSERT(index >= 0 && index < 3);
|
||||
return fYUVPlanes[index];
|
||||
}
|
||||
const SkBitmap& normalBitmap() const {
|
||||
SkASSERT(!this->isYUV());
|
||||
return fBitmap;
|
||||
}
|
||||
|
||||
void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
|
||||
SkASSERT(index >= 0 && index < (this->isYUV() ? 3 : 1));
|
||||
fCallbackContexts[index] = callbackContext;
|
||||
}
|
||||
PromiseImageCallbackContext* callbackContext(int index) {
|
||||
SkASSERT(index >= 0 && index < (this->isYUV() ? 3 : 1));
|
||||
return fCallbackContexts[index].get();
|
||||
}
|
||||
sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
|
||||
SkASSERT(index >= 0 && index < (this->isYUV() ? 3 : 1));
|
||||
return fCallbackContexts[index];
|
||||
}
|
||||
|
||||
const GrCaps* caps() const { return fCallbackContexts[0]->caps(); }
|
||||
|
||||
const GrBackendTexture& backendTexture(int index) const {
|
||||
SkASSERT(index >= 0 && index < (this->isYUV() ? 3 : 1));
|
||||
return fCallbackContexts[index]->backendTexture();
|
||||
}
|
||||
|
||||
void setNormalBitmap(const SkBitmap& bm) { fBitmap = bm; }
|
||||
|
||||
void setYUVData(sk_sp<SkCachedData> yuvData, SkYUVColorSpace cs) {
|
||||
fYUVData = yuvData;
|
||||
fYUVColorSpace = cs;
|
||||
}
|
||||
void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
|
||||
SkASSERT(this->isYUV());
|
||||
SkASSERT(index >= 0 && index < 3);
|
||||
fYUVPlanes[index].reset(ii, plane, widthBytes);
|
||||
}
|
||||
|
||||
private:
|
||||
const int fIndex; // index in the 'fImageInfo' array
|
||||
const uint32_t fOriginalUniqueID; // original ID for deduping
|
||||
|
||||
const SkImageInfo fImageInfo; // info for the overarching image
|
||||
|
||||
// CPU-side cache of a normal SkImage's contents
|
||||
SkBitmap fBitmap;
|
||||
|
||||
// CPU-side cache of a YUV SkImage's contents
|
||||
sk_sp<SkCachedData> fYUVData; // when !null, this is a YUV image
|
||||
SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
|
||||
SkPixmap fYUVPlanes[3];
|
||||
|
||||
// Up to 3 for a YUV image. Only one for a normal image.
|
||||
sk_sp<PromiseImageCallbackContext> fCallbackContexts[3];
|
||||
};
|
||||
|
||||
// This stack-based context allows each thread to re-inflate the image indices into
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "DDLPromiseImageHelper.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDeferredDisplayListPriv.h"
|
||||
#include "SkDeferredDisplayListRecorder.h"
|
||||
#include "SkImage_Gpu.h"
|
||||
#include "SkPicture.h"
|
||||
@ -31,10 +32,17 @@ void DDLTileHelper::TileData::createTileSpecificSKP(SkData* compressedPictureDat
|
||||
SkDeferredDisplayListRecorder recorder(fCharacterization);
|
||||
|
||||
fReconstitutedPicture = helper.reinflateSKP(&recorder, compressedPictureData, &fPromiseImages);
|
||||
|
||||
std::unique_ptr<SkDeferredDisplayList> ddl = recorder.detach();
|
||||
if (ddl.get()->priv().numOpLists()) {
|
||||
// TODO: remove this once skbug.com/8424 is fixed. If the DDL resulting from the
|
||||
// reinflation of the SKPs contains opLists that means some image subset operation
|
||||
// created a draw.
|
||||
fReconstitutedPicture.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void DDLTileHelper::TileData::createDDL() {
|
||||
SkASSERT(fReconstitutedPicture);
|
||||
SkASSERT(!fDisplayList);
|
||||
|
||||
SkDeferredDisplayListRecorder recorder(fCharacterization);
|
||||
@ -60,7 +68,9 @@ void DDLTileHelper::TileData::createDDL() {
|
||||
|
||||
// Note: in this use case we only render a picture to the deferred canvas
|
||||
// but, more generally, clients will use arbitrary draw calls.
|
||||
subCanvas->drawPicture(fReconstitutedPicture);
|
||||
if (fReconstitutedPicture) {
|
||||
subCanvas->drawPicture(fReconstitutedPicture);
|
||||
}
|
||||
|
||||
fDisplayList = recorder.detach();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user