Add option to skip intermediate release/fulfill calls for promise images.
SkiaRenderer does not delete promise image textures when they are released but not done. Refulfilling promise image textures takes a significant amount of CPU time. This allows us to fulfill each promise image once. Bug: skia:8736 Change-Id: I7ad7fa9678ed0ec4bb714b71fbf920ab4a845409 Reviewed-on: https://skia-review.googlesource.com/c/188039 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
d20cf33472
commit
f55e8d5232
@ -1954,7 +1954,15 @@ Error ViaDDL::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString
|
||||
// this is our ultimate final drawing area/rect
|
||||
SkIRect viewport = SkIRect::MakeWH(size.fWidth, size.fHeight);
|
||||
|
||||
DDLPromiseImageHelper promiseImageHelper;
|
||||
// When we're only doing one replay we exercise the code path that delays calling release
|
||||
// until the SkImage is destroyed.
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback delayReleaseCallback;
|
||||
if (fNumReplays > 1) {
|
||||
delayReleaseCallback = SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo;
|
||||
} else {
|
||||
delayReleaseCallback = SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes;
|
||||
}
|
||||
DDLPromiseImageHelper promiseImageHelper(delayReleaseCallback);
|
||||
sk_sp<SkData> compressedPictureData = promiseImageHelper.deflateSKP(inputPicture.get());
|
||||
if (!compressedPictureData) {
|
||||
return SkStringPrintf("ViaDDL: Couldn't deflate SkPicture");
|
||||
|
@ -63,6 +63,8 @@ public:
|
||||
GrBackendTexture*);
|
||||
using TextureContext = PromiseImageTextureContext;
|
||||
|
||||
enum class DelayReleaseCallback : bool { kNo = false, kYes = true };
|
||||
|
||||
/**
|
||||
Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The main
|
||||
difference is that the client doesn't have the backend texture on the gpu yet but they know
|
||||
@ -74,19 +76,31 @@ public:
|
||||
match those set during the SkImage creation, and it must have a valid backend gpu texture.
|
||||
The gpu texture supplied by the client must stay valid until we call the textureReleaseProc.
|
||||
|
||||
When we are done with the texture returned by the textureFulfillProc we will call the
|
||||
textureReleaseProc passing in the textureContext. This is a signal to the client that they
|
||||
are free to delete the underlying gpu texture. If future draws also use the same promise
|
||||
image we will call the textureFulfillProc again if we've already called the
|
||||
textureReleaseProc. We will always call textureFulfillProc and textureReleaseProc in pairs.
|
||||
In other words we will never call textureFulfillProc or textureReleaseProc multiple times
|
||||
for the same textureContext before calling the other.
|
||||
The following applies when DelayReleaseCallback is kNo:
|
||||
When we are done with the texture returned by the textureFulfillProc we will call the
|
||||
textureReleaseProc passing in the textureContext. This is a signal to the client that
|
||||
they are free to delete the underlying gpu texture. If future draws also use the same
|
||||
promise image we will call the textureFulfillProc again if we've already called the
|
||||
textureReleaseProc. We will always call textureFulfillProc and textureReleaseProc in
|
||||
pairs. In other words we will never call textureFulfillProc or textureReleaseProc
|
||||
multiple times for the same textureContext before calling the other.
|
||||
|
||||
We call the textureDoneProc when we will no longer call the textureFulfillProc again. We
|
||||
pass in the textureContext as a parameter to the textureDoneProc. 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 all GPU objects and meta data needed for the textureFulfill call.
|
||||
|
||||
When delayReleaseCallback is kYes:
|
||||
When all the following are true:
|
||||
* the promise image is deleted,
|
||||
* any SkDeferredDisplayLists that recorded draws referencing the image are deleted,
|
||||
* and the texture is safe to delete in the underlying API with respect to drawn
|
||||
SkDeferredDisplayLists that reference the image
|
||||
the textureReleaseProc and then textureDoneProc are called. The texture can be deleted
|
||||
by the client as soon as textureReleaseProc is called. In this mode there is only one
|
||||
call to each of textureFulfillProc, textureReleaseProc, and textureDoneProc.
|
||||
|
||||
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
|
||||
all GPU objects and meta data needed for the textureFulfill call.
|
||||
|
||||
This call is only valid if the SkDeferredDisplayListRecorder is backed by a gpu context.
|
||||
|
||||
@ -119,7 +133,27 @@ public:
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext);
|
||||
PromiseImageTextureContext textureContext,
|
||||
DelayReleaseCallback delayReleaseCallback);
|
||||
|
||||
/** Deprecated version that assumes DelayReleaseCallback::kNo. */
|
||||
sk_sp<SkImage> makePromiseTexture(const GrBackendFormat& backendFormat,
|
||||
int width,
|
||||
int height,
|
||||
GrMipMapped mipMapped,
|
||||
GrSurfaceOrigin origin,
|
||||
SkColorType colorType,
|
||||
SkAlphaType alphaType,
|
||||
sk_sp<SkColorSpace> colorSpace,
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
return this->makePromiseTexture(backendFormat, width, height, mipMapped, origin, colorType,
|
||||
alphaType, colorSpace, textureFulfillProc,
|
||||
textureReleaseProc, textureDoneProc, textureContext,
|
||||
DelayReleaseCallback::kNo);
|
||||
}
|
||||
|
||||
/**
|
||||
This entry point operates the same as 'makePromiseTexture' except that its
|
||||
@ -139,7 +173,27 @@ public:
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]);
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
DelayReleaseCallback delayReleaseCallback);
|
||||
|
||||
/** Deprecated version that assumes DelayReleaseCallback::kNo. */
|
||||
sk_sp<SkImage> makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace,
|
||||
const GrBackendFormat yuvaFormats[],
|
||||
const SkISize yuvaSizes[],
|
||||
const SkYUVAIndex yuvaIndices[4],
|
||||
int imageWidth,
|
||||
int imageHeight,
|
||||
GrSurfaceOrigin imageOrigin,
|
||||
sk_sp<SkColorSpace> imageColorSpace,
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]) {
|
||||
return this->makeYUVAPromiseTexture(
|
||||
yuvColorSpace, yuvaFormats, yuvaSizes, yuvaIndices, imageWidth, imageHeight,
|
||||
imageOrigin, std::move(imageColorSpace), textureFulfillProc, textureReleaseProc,
|
||||
textureDoneProc, textureContexts, DelayReleaseCallback::kNo);
|
||||
}
|
||||
|
||||
private:
|
||||
bool init();
|
||||
|
@ -34,7 +34,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureContext textureContext,
|
||||
DelayReleaseCallback delayReleaseCallback) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -50,7 +51,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]) {
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
DelayReleaseCallback delayReleaseCallback) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -220,7 +222,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureContext textureContext,
|
||||
DelayReleaseCallback delayReleaseCallback) {
|
||||
if (!fContext) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -237,7 +240,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
textureFulfillProc,
|
||||
textureReleaseProc,
|
||||
textureDoneProc,
|
||||
textureContext);
|
||||
textureContext,
|
||||
delayReleaseCallback);
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
@ -252,7 +256,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]) {
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
DelayReleaseCallback delayReleaseCallback) {
|
||||
if (!fContext) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -269,7 +274,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
textureFulfillProc,
|
||||
textureReleaseProc,
|
||||
textureDoneProc,
|
||||
textureContexts);
|
||||
textureContexts,
|
||||
delayReleaseCallback);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -392,15 +392,16 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
|
||||
sk_sp<SkColorSpace> colorSpace,
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc promiseDoneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext,
|
||||
DelayReleaseCallback delayReleaseCallback) {
|
||||
// The contract here is that if 'promiseDoneProc' is passed in it should always be called,
|
||||
// even if creation of the SkImage fails. Once we call MakePromiseImageLazyProxy it takes
|
||||
// responsibility for calling the done proc.
|
||||
if (!promiseDoneProc) {
|
||||
if (!textureDoneProc) {
|
||||
return nullptr;
|
||||
}
|
||||
SkScopeExit callDone([promiseDoneProc, textureContext]() { promiseDoneProc(textureContext); });
|
||||
SkScopeExit callDone([textureDoneProc, textureContext]() { textureDoneProc(textureContext); });
|
||||
|
||||
SkImageInfo info = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
|
||||
if (!SkImageInfoIsValid(info)) {
|
||||
@ -424,7 +425,7 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
|
||||
callDone.clear();
|
||||
auto proxy = MakePromiseImageLazyProxy(context, width, height, origin, config, backendFormat,
|
||||
mipMapped, textureFulfillProc, textureReleaseProc,
|
||||
promiseDoneProc, textureContext);
|
||||
textureDoneProc, textureContext, delayReleaseCallback);
|
||||
if (!proxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -40,48 +40,7 @@ public:
|
||||
sk_sp<SkImage> onMakeColorTypeAndColorSpace(SkColorType, sk_sp<SkColorSpace>) const final;
|
||||
|
||||
/**
|
||||
Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The main
|
||||
difference is that the client doesn't have the backend texture on the gpu yet but they know
|
||||
all the properties of the texture. So instead of passing in a GrBackendTexture the client
|
||||
supplies a GrBackendFormat, width, height, and GrMipMapped state.
|
||||
|
||||
When we actually send the draw calls to the GPU, we will call the textureFulfillProc and
|
||||
the client will return a GrBackendTexture to us. The properties of the GrBackendTexture must
|
||||
match those set during the SkImage creation, and it must have a valid backend gpu texture.
|
||||
The gpu texture supplied by the client must stay valid until we call the textureReleaseProc.
|
||||
|
||||
When we are done with the texture returned by the textureFulfillProc we will call the
|
||||
textureReleaseProc passing in the textureContext. This is a signal to the client that they
|
||||
are free to delete the underlying gpu texture. If future draws also use the same promise
|
||||
image we will call the textureFulfillProc again if we've already called the
|
||||
textureReleaseProc. We will always call textureFulfillProc and textureReleaseProc in pairs.
|
||||
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
|
||||
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 all GPU objects and meta data needed for the textureFulfill call.
|
||||
|
||||
@param context Gpu context
|
||||
@param backendFormat format of promised gpu texture
|
||||
@param width width of promised gpu texture
|
||||
@param height height of promised gpu texture
|
||||
@param mipMapped mip mapped state of promised gpu texture
|
||||
@param origin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
|
||||
@param colorType one of: kUnknown_SkColorType, kAlpha_8_SkColorType,
|
||||
kRGB_565_SkColorType, kARGB_4444_SkColorType,
|
||||
kRGBA_8888_SkColorType, kBGRA_8888_SkColorType,
|
||||
kGray_8_SkColorType, kRGBA_F16_SkColorType
|
||||
@param alphaType one of: kUnknown_SkAlphaType, kOpaque_SkAlphaType,
|
||||
kPremul_SkAlphaType, kUnpremul_SkAlphaType
|
||||
@param colorSpace range of colors; may be nullptr
|
||||
@param textureFulfillProc function called to get actual gpu texture
|
||||
@param textureReleaseProc function called when texture can be released
|
||||
@param textureDoneProc function called when we will no longer call textureFulfillProc
|
||||
@param textureContext state passed to textureFulfillProc, textureReleaseProc, and
|
||||
promiseDoneProc
|
||||
@return created SkImage, or nullptr
|
||||
* This is the implementation of SkDeferredDisplayListRecorder::makePromiseImage.
|
||||
*/
|
||||
static sk_sp<SkImage> MakePromiseTexture(GrContext* context,
|
||||
const GrBackendFormat& backendFormat,
|
||||
@ -95,7 +54,8 @@ public:
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext);
|
||||
PromiseImageTextureContext textureContext,
|
||||
DelayReleaseCallback delayReleaseCallback);
|
||||
|
||||
static sk_sp<SkImage> ConvertYUVATexturesToRGB(GrContext*, SkYUVColorSpace yuvColorSpace,
|
||||
const GrBackendTexture yuvaTextures[],
|
||||
|
@ -360,7 +360,8 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
PromiseImageTextureFulfillProc fulfillProc,
|
||||
PromiseImageTextureReleaseProc releaseProc,
|
||||
PromiseImageTextureDoneProc doneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureContext textureContext,
|
||||
DelayReleaseCallback delayReleaseCallback) {
|
||||
SkASSERT(context);
|
||||
SkASSERT(width > 0 && height > 0);
|
||||
SkASSERT(doneProc);
|
||||
@ -402,9 +403,11 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
PromiseImageTextureReleaseProc releaseProc,
|
||||
PromiseImageTextureDoneProc doneProc,
|
||||
PromiseImageTextureContext context,
|
||||
DelayReleaseCallback delayReleaseCallback,
|
||||
GrPixelConfig config)
|
||||
: fFulfillProc(fulfillProc)
|
||||
, fConfig(config) {
|
||||
, fConfig(config)
|
||||
, fDelayReleaseCallback(delayReleaseCallback) {
|
||||
auto doneHelper = sk_make_sp<GrReleaseProcHelper>(doneProc, context);
|
||||
fReleaseContext = sk_make_sp<IdleContext::PromiseImageReleaseContext>(
|
||||
releaseProc, context, std::move(doneHelper));
|
||||
@ -414,8 +417,14 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
|
||||
sk_sp<GrSurface> operator()(GrResourceProvider* resourceProvider) {
|
||||
if (!resourceProvider) {
|
||||
if (fDelayedReleaseTexture) {
|
||||
fDelayedReleaseTexture.reset();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
if (fDelayedReleaseTexture) {
|
||||
return fDelayedReleaseTexture;
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> cachedTexture;
|
||||
SkASSERT(fLastFulfilledKey.isValid() == (fLastFulfillID > 0));
|
||||
@ -459,6 +468,7 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
|
||||
sk_sp<GrTexture> tex;
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey::Builder builder(&fLastFulfilledKey, kDomain, 2, "promise");
|
||||
builder[0] = promiseTexture->uniqueID();
|
||||
@ -467,7 +477,6 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
// A texture with this key may already exist from a different instance of this lazy
|
||||
// callback. This could happen if the client fulfills a promise image with a texture
|
||||
// that was previously used to fulfill a different promise image.
|
||||
sk_sp<GrTexture> tex;
|
||||
if (auto surf = resourceProvider->findByUniqueKey<GrSurface>(fLastFulfilledKey)) {
|
||||
tex = sk_ref_sp(surf->asTexture());
|
||||
SkASSERT(tex);
|
||||
@ -484,6 +493,9 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
}
|
||||
}
|
||||
this->addToIdleContext(tex.get());
|
||||
if (fDelayReleaseCallback == DelayReleaseCallback::kYes) {
|
||||
fDelayedReleaseTexture = tex;
|
||||
}
|
||||
tex->resourcePriv().setUniqueKey(fLastFulfilledKey);
|
||||
SkASSERT(fContextID == SK_InvalidUniqueID ||
|
||||
fContextID == tex->getContext()->uniqueID());
|
||||
@ -567,15 +579,17 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
}
|
||||
|
||||
sk_sp<IdleContext::PromiseImageReleaseContext> fReleaseContext;
|
||||
sk_sp<GrTexture> fDelayedReleaseTexture;
|
||||
PromiseImageTextureFulfillProc fFulfillProc;
|
||||
GrPixelConfig fConfig;
|
||||
DelayReleaseCallback fDelayReleaseCallback;
|
||||
|
||||
// ID of the last SkPromiseImageTexture given to us by the client.
|
||||
uint32_t fLastFulfillID = 0;
|
||||
// ID of the GrContext that we are interacting with.
|
||||
uint32_t fContextID = SK_InvalidUniqueID;
|
||||
GrUniqueKey fLastFulfilledKey;
|
||||
} callback(fulfillProc, releaseProc, doneProc, textureContext, config);
|
||||
} callback(fulfillProc, releaseProc, doneProc, textureContext, delayReleaseCallback, config);
|
||||
|
||||
GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
|
||||
|
||||
|
@ -78,6 +78,7 @@ public:
|
||||
using PromiseImageTextureReleaseProc =
|
||||
SkDeferredDisplayListRecorder::PromiseImageTextureReleaseProc;
|
||||
using PromiseImageTextureDoneProc = SkDeferredDisplayListRecorder::PromiseImageTextureDoneProc;
|
||||
using DelayReleaseCallback = SkDeferredDisplayListRecorder::DelayReleaseCallback;
|
||||
|
||||
protected:
|
||||
// Helper for making a lazy proxy for a promise image. The PromiseDoneProc we be called,
|
||||
@ -87,7 +88,7 @@ protected:
|
||||
static sk_sp<GrTextureProxy> MakePromiseImageLazyProxy(
|
||||
GrContext*, int width, int height, GrSurfaceOrigin, GrPixelConfig, GrBackendFormat,
|
||||
GrMipMapped, PromiseImageTextureFulfillProc, PromiseImageTextureReleaseProc,
|
||||
PromiseImageTextureDoneProc, PromiseImageTextureContext);
|
||||
PromiseImageTextureDoneProc, PromiseImageTextureContext, DelayReleaseCallback);
|
||||
|
||||
static bool RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* renderTargetContext,
|
||||
const SkRect& rect, SkYUVColorSpace yuvColorSpace,
|
||||
|
@ -260,7 +260,8 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc promiseDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]) {
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
DelayReleaseCallback delayReleaseCallback) {
|
||||
int numTextures;
|
||||
bool valid = SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures);
|
||||
|
||||
@ -320,7 +321,7 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
|
||||
proxies[texIdx] = MakePromiseImageLazyProxy(
|
||||
context, yuvaSizes[texIdx].width(), yuvaSizes[texIdx].height(), imageOrigin, config,
|
||||
yuvaFormats[texIdx], GrMipMapped::kNo, textureFulfillProc, textureReleaseProc,
|
||||
promiseDoneProc, textureContexts[texIdx]);
|
||||
promiseDoneProc, textureContexts[texIdx], delayReleaseCallback);
|
||||
++proxiesCreated;
|
||||
if (!proxies[texIdx]) {
|
||||
return nullptr;
|
||||
|
@ -58,45 +58,7 @@ public:
|
||||
SkColorSpace* targetColorSpace() const { return fTargetColorSpace.get(); }
|
||||
|
||||
/**
|
||||
Create a new SkImage_GpuYUVA that's very similar to SkImage created by MakeFromYUVATextures.
|
||||
The main difference is that the client doesn't have the backend textures on the gpu yet but
|
||||
they know all the properties of the texture. So instead of passing in GrBackendTextures the
|
||||
client supplies GrBackendFormats and the image size.
|
||||
|
||||
When we actually send the draw calls to the GPU, we will call the textureFulfillProc and
|
||||
the client will return the GrBackendTextures to us. The properties of the GrBackendTextures
|
||||
must match those set during the SkImage creation, and it must have valid backend gpu
|
||||
textures. The gpu textures supplied by the client must stay valid until we call the
|
||||
textureReleaseProc.
|
||||
|
||||
When we are done with the texture returned by the textureFulfillProc we will call the
|
||||
textureReleaseProc passing in the textureContext. This is a signal to the client that they
|
||||
are free to delete the underlying gpu textures. If future draws also use the same promise
|
||||
image we will call the textureFulfillProc again if we've already called the
|
||||
textureReleaseProc. We will always call textureFulfillProc and textureReleaseProc in pairs.
|
||||
In other words we will never call textureFulfillProc or textureReleaseProc multiple times
|
||||
for the same textureContext before calling the other.
|
||||
|
||||
We call the promiseDoneProc when we will no longer call the textureFulfillProc again. 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 all GPU objects and meta data needed for the textureFulfill call.
|
||||
|
||||
@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 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
|
||||
@param imageOrigin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
|
||||
@param imageColorSpace range of colors; may be nullptr
|
||||
@param textureFulfillProc function called to get actual gpu texture
|
||||
@param textureReleaseProc function called when texture can be released
|
||||
@param textureDoneProc function called when we will no longer call textureFulfillProc
|
||||
@param textureContexts per-texture state passed to textureFulfillProc,
|
||||
textureReleaseProc, and textureDoneProc
|
||||
@return created SkImage, or nullptr
|
||||
* This is the implementation of SkDeferredDisplayListRecorder::makeYUVAPromiseTexture.
|
||||
*/
|
||||
static sk_sp<SkImage> MakePromiseYUVATexture(GrContext* context,
|
||||
SkYUVColorSpace yuvColorSpace,
|
||||
@ -110,7 +72,8 @@ public:
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]);
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
DelayReleaseCallback delayReleaseCallback);
|
||||
|
||||
private:
|
||||
SkImage_GpuYUVA(const SkImage_GpuYUVA* image, sk_sp<SkColorSpace>);
|
||||
|
@ -771,14 +771,16 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
|
||||
|
||||
GrBackendFormat format = create_backend_format(context, kRGBA_8888_SkColorType,
|
||||
kRGBA_8888_GrPixelConfig);
|
||||
sk_sp<SkImage> image = recorder.makePromiseTexture(format, 32, 32, GrMipMapped::kNo,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType, nullptr,
|
||||
dummy_fulfill_proc,
|
||||
dummy_release_proc,
|
||||
dummy_done_proc,
|
||||
nullptr);
|
||||
sk_sp<SkImage> image = recorder.makePromiseTexture(
|
||||
format, 32, 32, GrMipMapped::kNo,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType, nullptr,
|
||||
dummy_fulfill_proc,
|
||||
dummy_release_proc,
|
||||
dummy_done_proc,
|
||||
nullptr,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo);
|
||||
REPORTER_ASSERT(reporter, !image);
|
||||
}
|
||||
|
||||
@ -875,14 +877,16 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLTextureFlagsTest, reporter, ctxInfo) {
|
||||
for (auto mipMapped : { GrMipMapped::kNo, GrMipMapped::kYes }) {
|
||||
GrBackendFormat format = GrBackendFormat::MakeGL(GR_GL_RGBA8, target);
|
||||
|
||||
sk_sp<SkImage> image = recorder.makePromiseTexture(format, 32, 32, mipMapped,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType, nullptr,
|
||||
dummy_fulfill_proc,
|
||||
dummy_release_proc,
|
||||
dummy_done_proc,
|
||||
nullptr);
|
||||
sk_sp<SkImage> image = recorder.makePromiseTexture(
|
||||
format, 32, 32, mipMapped,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType, nullptr,
|
||||
dummy_fulfill_proc,
|
||||
dummy_release_proc,
|
||||
dummy_done_proc,
|
||||
nullptr,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo);
|
||||
if (GR_GL_TEXTURE_2D != target && mipMapped == GrMipMapped::kYes) {
|
||||
REPORTER_ASSERT(reporter, !image);
|
||||
continue;
|
||||
|
@ -5,6 +5,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkExchange.h"
|
||||
#include "Test.h"
|
||||
|
||||
#include "GrBackendSurface.h"
|
||||
@ -43,11 +44,7 @@ struct PromiseTextureChecker {
|
||||
*/
|
||||
sk_sp<const SkPromiseImageTexture> replaceTexture(
|
||||
const GrBackendTexture& tex = GrBackendTexture()) {
|
||||
// Can't change this while in active fulfillment.
|
||||
REPORTER_ASSERT(fReporter, fFulfillCount == fReleaseCount);
|
||||
auto temp = std::move(fTexture);
|
||||
fTexture = SkPromiseImageTexture::Make(tex);
|
||||
return std::move(temp);
|
||||
return skstd::exchange(fTexture, SkPromiseImageTexture::Make(tex));
|
||||
}
|
||||
|
||||
SkTArray<GrUniqueKey> uniqueKeys() const {
|
||||
@ -74,11 +71,14 @@ struct PromiseTextureChecker {
|
||||
}
|
||||
};
|
||||
|
||||
// Because Vulkan may delay when it actually calls the ReleaseProcs depending on when command
|
||||
// buffers finish their work, we need some slight wiggle room in what values we expect for fulfill
|
||||
// and release counts.
|
||||
enum class ReleaseBalanceExpecation {
|
||||
kBalanced,
|
||||
kBalancedOrPlusOne,
|
||||
kAny
|
||||
};
|
||||
|
||||
static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker,
|
||||
bool countsMustBeEqual,
|
||||
ReleaseBalanceExpecation balanceExpecation,
|
||||
int expectedFulfillCnt,
|
||||
int expectedReleaseCnt,
|
||||
bool expectedRequired,
|
||||
@ -88,12 +88,16 @@ static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseC
|
||||
int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
|
||||
// FulfillCount should always equal ReleaseCount or be at most one higher
|
||||
if (countDiff != 0) {
|
||||
if (countsMustBeEqual) {
|
||||
if (balanceExpecation == ReleaseBalanceExpecation::kBalanced) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, 0 == countDiff);
|
||||
} else if (countDiff != 1) {
|
||||
} else if (countDiff != 1 &&
|
||||
balanceExpecation == ReleaseBalanceExpecation::kBalancedOrPlusOne) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, 0 == countDiff || 1 == countDiff);
|
||||
} else if (countDiff < 0) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, countDiff >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +133,7 @@ static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseC
|
||||
return result;
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestNoDelayedRelease, reporter, ctxInfo) {
|
||||
const int kWidth = 10;
|
||||
const int kHeight = 10;
|
||||
|
||||
@ -147,14 +151,16 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
PromiseTextureChecker promiseChecker(backendTex, reporter, false);
|
||||
GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
|
||||
sk_sp<SkImage> refImg(
|
||||
SkImage_Gpu::MakePromiseTexture(ctx, backendFormat, kWidth, kHeight,
|
||||
GrMipMapped::kNo, texOrigin,
|
||||
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr,
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker));
|
||||
SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendFormat, kWidth, kHeight,
|
||||
GrMipMapped::kNo, texOrigin,
|
||||
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr,
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
|
||||
|
||||
SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
|
||||
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
|
||||
@ -163,10 +169,11 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
int expectedFulfillCnt = 0;
|
||||
int expectedReleaseCnt = 0;
|
||||
int expectedDoneCnt = 0;
|
||||
ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -177,8 +184,11 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
canvas->flush();
|
||||
expectedFulfillCnt++;
|
||||
expectedReleaseCnt++;
|
||||
if (isVulkan) {
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
|
||||
}
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
!isVulkan,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
@ -186,8 +196,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
reporter));
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -203,7 +214,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -218,8 +229,11 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
canvas->flush();
|
||||
expectedFulfillCnt++;
|
||||
expectedReleaseCnt++;
|
||||
if (isVulkan) {
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
|
||||
}
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
!isVulkan,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
@ -233,7 +247,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
}
|
||||
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
!isVulkan,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
@ -248,8 +262,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
if (releaseImageEarly) {
|
||||
expectedDoneCnt++;
|
||||
}
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
@ -264,7 +279,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
}
|
||||
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -275,6 +290,129 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestDelayedRelease, reporter, ctxInfo) {
|
||||
const int kWidth = 10;
|
||||
const int kHeight = 10;
|
||||
|
||||
GrContext* ctx = ctxInfo.grContext();
|
||||
GrGpu* gpu = ctx->contextPriv().getGpu();
|
||||
|
||||
GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
|
||||
nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo);
|
||||
REPORTER_ASSERT(reporter, backendTex.isValid());
|
||||
|
||||
GrBackendFormat backendFormat = backendTex.getBackendFormat();
|
||||
REPORTER_ASSERT(reporter, backendFormat.isValid());
|
||||
|
||||
PromiseTextureChecker promiseChecker(backendTex, reporter, false);
|
||||
GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
|
||||
sk_sp<SkImage> refImg(
|
||||
SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendFormat, kWidth, kHeight,
|
||||
GrMipMapped::kNo, texOrigin,
|
||||
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr,
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes));
|
||||
|
||||
SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
|
||||
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
|
||||
int expectedFulfillCnt = 0;
|
||||
int expectedReleaseCnt = 0;
|
||||
int expectedDoneCnt = 0;
|
||||
ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
bool isVulkan = GrBackendApi::kVulkan == ctx->backend();
|
||||
canvas->flush();
|
||||
expectedFulfillCnt++;
|
||||
// Because we've delayed release, we expect a +1 balance.
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
|
||||
canvas->flush();
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
|
||||
refImg.reset();
|
||||
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
canvas->flush();
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
// We released the image already and we flushed and synced.
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
expectedReleaseCnt++;
|
||||
expectedDoneCnt++;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex);
|
||||
}
|
||||
|
||||
// Tests replacing the backing texture for a promise image after a release and then refulfilling in
|
||||
// the SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo case.
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo) {
|
||||
const int kWidth = 10;
|
||||
const int kHeight = 10;
|
||||
@ -300,14 +438,16 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
PromiseTextureChecker promiseChecker(backendTex1, reporter, true);
|
||||
GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
|
||||
sk_sp<SkImage> refImg(
|
||||
SkImage_Gpu::MakePromiseTexture(ctx, backendFormat, kWidth, kHeight,
|
||||
GrMipMapped::kNo, texOrigin,
|
||||
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr,
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker));
|
||||
SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendFormat, kWidth, kHeight,
|
||||
GrMipMapped::kNo, texOrigin,
|
||||
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr,
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
|
||||
|
||||
SkImageInfo info =
|
||||
SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
|
||||
@ -320,8 +460,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
canvas->drawImage(refImg, 5, 5);
|
||||
ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -332,8 +473,11 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
canvas->flush();
|
||||
expectedFulfillCnt++;
|
||||
expectedReleaseCnt++;
|
||||
if (isVulkan) {
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
|
||||
}
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
!isVulkan,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
@ -352,8 +496,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey1));
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -373,7 +518,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -383,6 +528,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
canvas->flush();
|
||||
expectedFulfillCnt++;
|
||||
expectedReleaseCnt++;
|
||||
if (isVulkan) {
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
|
||||
}
|
||||
// Second texture should be in the cache.
|
||||
keys = promiseChecker.uniqueKeys();
|
||||
REPORTER_ASSERT(reporter, keys.count() == 1);
|
||||
@ -394,7 +542,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2));
|
||||
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
!isVulkan,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
@ -404,8 +552,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
promiseChecker.fLastFulfilledTexture, backendTex2));
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -424,7 +573,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
expectedFulfillCnt++;
|
||||
expectedReleaseCnt++;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -453,7 +602,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
expectedFulfillCnt++;
|
||||
expectedReleaseCnt++;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -473,14 +622,16 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
|
||||
// Make a new promise image also backed by texture 3.
|
||||
sk_sp<SkImage> refImg2(
|
||||
SkImage_Gpu::MakePromiseTexture(ctx, backendFormat, kWidth, kHeight,
|
||||
GrMipMapped::kNo, texOrigin,
|
||||
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr,
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker));
|
||||
SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendFormat, kWidth, kHeight,
|
||||
GrMipMapped::kNo, texOrigin,
|
||||
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr,
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
canvas->drawImage(refImg2, 1, 1);
|
||||
|
||||
@ -489,7 +640,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
expectedFulfillCnt += 2;
|
||||
expectedReleaseCnt += 2;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -518,7 +669,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
refImg.reset();
|
||||
++expectedDoneCnt;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -527,7 +678,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo)
|
||||
refImg2.reset();
|
||||
++expectedDoneCnt;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -553,75 +704,82 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, repo
|
||||
GrBackendTexture backendTex2 = gpu->createTestingOnlyBackendTexture(
|
||||
nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo);
|
||||
REPORTER_ASSERT(reporter, backendTex2.isValid());
|
||||
if (backendTex1.getBackendFormat() != backendTex2.getBackendFormat()) {
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex1);
|
||||
return;
|
||||
}
|
||||
// We only needed this texture to check that alpha and gray color types use the same format.
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex2);
|
||||
|
||||
SkImageInfo info =
|
||||
SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
|
||||
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
|
||||
if (backendTex1.getBackendFormat() != backendTex2.getBackendFormat()) {
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex1);
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex2);
|
||||
return;
|
||||
}
|
||||
PromiseTextureChecker promiseChecker(backendTex1, reporter, true);
|
||||
sk_sp<SkImage> alphaImg(SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
|
||||
kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
|
||||
PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker));
|
||||
REPORTER_ASSERT(reporter, alphaImg);
|
||||
for (auto delayRelease : {SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes}) {
|
||||
PromiseTextureChecker promiseChecker(backendTex1, reporter, true);
|
||||
sk_sp<SkImage> alphaImg(SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
|
||||
kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
|
||||
PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker, delayRelease));
|
||||
REPORTER_ASSERT(reporter, alphaImg);
|
||||
|
||||
sk_sp<SkImage> grayImg(SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
|
||||
kBottomLeft_GrSurfaceOrigin, kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr,
|
||||
PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker));
|
||||
REPORTER_ASSERT(reporter, grayImg);
|
||||
sk_sp<SkImage> grayImg(SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
|
||||
kBottomLeft_GrSurfaceOrigin, kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr,
|
||||
PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker, delayRelease));
|
||||
REPORTER_ASSERT(reporter, grayImg);
|
||||
|
||||
canvas->drawImage(alphaImg, 0, 0);
|
||||
canvas->drawImage(grayImg, 1, 1);
|
||||
canvas->flush();
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
canvas->drawImage(alphaImg, 0, 0);
|
||||
canvas->drawImage(grayImg, 1, 1);
|
||||
canvas->flush();
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
|
||||
int expectedFulfillCnt = 2;
|
||||
int expectedReleaseCnt = 2;
|
||||
int expectedDoneCnt = 0;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
int expectedFulfillCnt = 2;
|
||||
int expectedReleaseCnt = 0;
|
||||
int expectedDoneCnt = 0;
|
||||
ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kAny;
|
||||
if (delayRelease == SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo) {
|
||||
expectedReleaseCnt = 2;
|
||||
balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
}
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
|
||||
// Because they use different configs, each image should have created a different GrTexture
|
||||
// and they both should still be cached.
|
||||
ctx->contextPriv().getResourceCache()->purgeAsNeeded();
|
||||
// Because they use different configs, each image should have created a different GrTexture
|
||||
// and they both should still be cached.
|
||||
ctx->contextPriv().getResourceCache()->purgeAsNeeded();
|
||||
|
||||
auto keys = promiseChecker.uniqueKeys();
|
||||
REPORTER_ASSERT(reporter, keys.count() == 2);
|
||||
for (const auto& key : keys) {
|
||||
auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key);
|
||||
REPORTER_ASSERT(reporter, surf && surf->asTexture());
|
||||
if (surf && surf->asTexture()) {
|
||||
REPORTER_ASSERT(reporter, !GrBackendTexture::TestingOnly_Equals(
|
||||
backendTex1, surf->asTexture()->getBackendTexture()));
|
||||
auto keys = promiseChecker.uniqueKeys();
|
||||
REPORTER_ASSERT(reporter, keys.count() == 2);
|
||||
for (const auto& key : keys) {
|
||||
auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key);
|
||||
REPORTER_ASSERT(reporter, surf && surf->asTexture());
|
||||
if (surf && surf->asTexture()) {
|
||||
REPORTER_ASSERT(reporter,
|
||||
!GrBackendTexture::TestingOnly_Equals(
|
||||
backendTex1, surf->asTexture()->getBackendTexture()));
|
||||
}
|
||||
}
|
||||
|
||||
// Change the backing texture, this should invalidate the keys.
|
||||
promiseChecker.replaceTexture();
|
||||
ctx->contextPriv().getResourceCache()->purgeAsNeeded();
|
||||
|
||||
for (const auto& key : keys) {
|
||||
auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key);
|
||||
REPORTER_ASSERT(reporter, !surf);
|
||||
}
|
||||
}
|
||||
|
||||
// Change the backing texture, this should invalidate the keys. The cached textures should
|
||||
// get purged after purgeAsNeeded is called.
|
||||
promiseChecker.replaceTexture(backendTex2);
|
||||
ctx->contextPriv().getResourceCache()->purgeAsNeeded();
|
||||
|
||||
for (const auto& key : keys) {
|
||||
auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key);
|
||||
REPORTER_ASSERT(reporter, !surf);
|
||||
}
|
||||
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex1);
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex2);
|
||||
}
|
||||
|
||||
DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
|
||||
@ -670,9 +828,10 @@ DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
|
||||
PromiseTextureChecker promiseChecker(backendTex, reporter, false);
|
||||
sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
|
||||
ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
|
||||
kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType,
|
||||
nullptr, PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker));
|
||||
kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
|
||||
PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
|
||||
REPORTER_ASSERT(reporter, image);
|
||||
|
||||
canvas->drawImage(image, 0, 0);
|
||||
@ -687,8 +846,9 @@ DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
|
||||
int expectedFulfillCnt = 1;
|
||||
int expectedReleaseCnt = 1;
|
||||
int expectedDoneCnt = 1;
|
||||
ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
true,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
@ -719,7 +879,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxIn
|
||||
ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
|
||||
kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
|
||||
PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker));
|
||||
PromiseTextureChecker::Done, &promiseChecker,
|
||||
SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
|
||||
REPORTER_ASSERT(reporter, image);
|
||||
|
||||
// Make the cache full. This tests that we don't preemptively purge cached textures for
|
||||
|
@ -246,7 +246,8 @@ sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
|
||||
DDLPromiseImageHelper::PromiseImageFulfillProc,
|
||||
DDLPromiseImageHelper::PromiseImageReleaseProc,
|
||||
DDLPromiseImageHelper::PromiseImageDoneProc,
|
||||
contexts);
|
||||
contexts,
|
||||
helper->fDelayReleaseCallback);
|
||||
for (int i = 0; i < textureCount; ++i) {
|
||||
curImage.callbackContext(i)->wasAddedToImage();
|
||||
}
|
||||
@ -269,7 +270,8 @@ sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
|
||||
DDLPromiseImageHelper::PromiseImageFulfillProc,
|
||||
DDLPromiseImageHelper::PromiseImageReleaseProc,
|
||||
DDLPromiseImageHelper::PromiseImageDoneProc,
|
||||
(void*) curImage.refCallbackContext(0).release());
|
||||
(void*)curImage.refCallbackContext(0).release(),
|
||||
helper->fDelayReleaseCallback);
|
||||
curImage.callbackContext(0)->wasAddedToImage();
|
||||
}
|
||||
perRecorderContext->fPromiseImages->push_back(image);
|
||||
|
@ -47,7 +47,9 @@ struct SkYUVAIndex;
|
||||
// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
|
||||
class DDLPromiseImageHelper {
|
||||
public:
|
||||
DDLPromiseImageHelper() { }
|
||||
using DelayReleaseCallback = SkDeferredDisplayListRecorder::DelayReleaseCallback;
|
||||
DDLPromiseImageHelper(DelayReleaseCallback delayReleaseCallback = DelayReleaseCallback::kNo)
|
||||
: fDelayReleaseCallback(delayReleaseCallback) {}
|
||||
~DDLPromiseImageHelper();
|
||||
|
||||
// Convert the SkPicture into SkData replacing all the SkImages with an index.
|
||||
@ -251,6 +253,7 @@ private:
|
||||
// returns -1 on failure
|
||||
int findOrDefineImage(SkImage* image);
|
||||
|
||||
DelayReleaseCallback fDelayReleaseCallback;
|
||||
SkTArray<PromiseImageInfo> fImageInfo;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user