Revert "Revert "Change promise image contract to for when Release and Done are called.""
This reverts commit d716d4402a
.
Bug: skia:8800
Change-Id: Ic16cd4e960be2c3d2462bdf2b54b2e32abbd9f78
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/199081
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
d25070bd0d
commit
0cc575488f
@ -58,31 +58,45 @@ public:
|
||||
using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext);
|
||||
using PromiseImageTextureDoneProc = void (*)(PromiseImageTextureContext);
|
||||
|
||||
/**
|
||||
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.
|
||||
enum class PromiseImageApiVersion { kLegacy, kNew };
|
||||
|
||||
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.
|
||||
/**
|
||||
Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The
|
||||
difference is that the caller need not have created the texture nor populated it with the
|
||||
image pixel data. Moreover, the SkImage may be created on a thread as the creation of the
|
||||
image does not require access to the backend API or GrContext. Instead of passing a
|
||||
GrBackendTexture the client supplies a description of the texture consisting of
|
||||
GrBackendFormat, width, height, and GrMipMapped state. The resulting SkImage can be drawn
|
||||
to a SkDeferredDisplayListRecorder or directly to a GPU-backed SkSurface.
|
||||
|
||||
When the actual texture is required to perform a backend API draw, textureFulfillProc will
|
||||
be called to receive a GrBackendTexture. The properties of the GrBackendTexture must match
|
||||
those set during the SkImage creation, and it must refer to a valid existing texture in the
|
||||
backend API context/device, and be populated with the image pixel data. The texture contents
|
||||
cannot be modified until textureReleaseProc is called. The texture cannot be deleted until
|
||||
textureDoneProc is called.
|
||||
|
||||
When all the following are true:
|
||||
* the promise image is deleted,
|
||||
* the promise SkImage 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. There is at most one call to each of
|
||||
textureFulfillProc, textureReleaseProc, and textureDoneProc. textureDoneProc is always
|
||||
called even if image creation fails or if the image is never fulfilled (e.g. it is never
|
||||
drawn). If textureFulfillProc is called then textureReleaseProc will always be called even
|
||||
if textureFulfillProc fails.
|
||||
* and all draws referencing the texture have been flushed (via GrContext::flush or
|
||||
SkSurface::flush)
|
||||
the textureReleaseProc is called. When the following additional constraint is met
|
||||
* the texture is safe to delete in the underlying API
|
||||
the textureDoneProc is called. For some APIs (e.g. GL) the two states are equivalent.
|
||||
However, for others (e.g. Vulkan) they are not as it is not legal to delete a texture until
|
||||
the GPU work referencing it has completed.
|
||||
|
||||
There is at most one call to each of textureFulfillProc, textureReleaseProc, and
|
||||
textureDoneProc. textureDoneProc is always called even if image creation fails or if the
|
||||
image is never fulfilled (e.g. it is never drawn or all draws are clipped out). If
|
||||
textureFulfillProc is called then textureReleaseProc will always be called even if
|
||||
textureFulfillProc failed.
|
||||
|
||||
This call is only valid if the SkDeferredDisplayListRecorder is backed by a gpu context.
|
||||
If 'version' is set to kLegacy then the textureReleaseProc call is delayed until the
|
||||
conditions for textureDoneProc are met and then they are both called.
|
||||
|
||||
This call is only valid if the SkDeferredDisplayListRecorder is backed by a GPU context.
|
||||
|
||||
@param backendFormat format of promised gpu texture
|
||||
@param width width of promised gpu texture
|
||||
@ -98,42 +112,51 @@ public:
|
||||
@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 promiseDoneProc function called when we will no longer call textureFulfillProc
|
||||
@param textureDoneProc function called when we will no longer call textureFulfillProc
|
||||
@param textureContext state passed to textureFulfillProc and textureReleaseProc
|
||||
@param version controls when textureReleaseProc is called
|
||||
@return created SkImage, or nullptr
|
||||
*/
|
||||
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);
|
||||
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,
|
||||
PromiseImageApiVersion version = PromiseImageApiVersion::kLegacy);
|
||||
|
||||
/**
|
||||
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'.
|
||||
This entry point operates like 'makePromiseTexture' but it is used to construct a SkImage
|
||||
from YUV[A] data. The source data may be planar (i.e. spread across multiple textures). In
|
||||
the extreme Y, U, V, and A are all in different planes and thus the image is specified by
|
||||
four textures. 'yuvaIndices' specifies the mapping from texture color channels to Y, U, V,
|
||||
and possibly A components. It therefore indicates how many unique textures compose the full
|
||||
image. Separate textureFulfillProc, textureReleaseProc, and textureDoneProc calls are made
|
||||
for each texture and each texture has its own PromiseImageTextureContext. 'yuvFormats',
|
||||
'yuvaSizes', and 'textureContexts' have one entry for each of the up to four textures, as
|
||||
indicated by 'yuvaIndices'.
|
||||
*/
|
||||
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[]);
|
||||
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[],
|
||||
PromiseImageApiVersion version = PromiseImageApiVersion::kLegacy);
|
||||
|
||||
private:
|
||||
bool init();
|
||||
|
@ -49,7 +49,7 @@ struct SK_API SkYUVAIndex {
|
||||
};
|
||||
static constexpr int kIndexCount = kLast_Index + 1;
|
||||
|
||||
/** The index is a number between -1..3 which definies which image source to read from, where -1
|
||||
/** The index is a number between -1..3 which defines which image source to read from, where -1
|
||||
* means the image source doesn't exist. The assumption is we will always have image sources for
|
||||
* each of YUV planes, but optionally have image source for A plane. */
|
||||
int fIndex;
|
||||
|
@ -34,7 +34,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureContext textureContext,
|
||||
PromiseImageApiVersion) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -50,7 +51,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]) {
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
PromiseImageApiVersion) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -233,7 +235,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureContext textureContext,
|
||||
PromiseImageApiVersion version) {
|
||||
if (!fContext) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -250,7 +253,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
|
||||
textureFulfillProc,
|
||||
textureReleaseProc,
|
||||
textureDoneProc,
|
||||
textureContext);
|
||||
textureContext,
|
||||
version);
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
@ -265,7 +269,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]) {
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
PromiseImageApiVersion version) {
|
||||
if (!fContext) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -282,7 +287,8 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
|
||||
textureFulfillProc,
|
||||
textureReleaseProc,
|
||||
textureDoneProc,
|
||||
textureContexts);
|
||||
textureContexts,
|
||||
version);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -405,7 +405,8 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureContext textureContext,
|
||||
PromiseImageApiVersion version) {
|
||||
// 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.
|
||||
@ -436,7 +437,7 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
|
||||
callDone.clear();
|
||||
auto proxy = MakePromiseImageLazyProxy(context, width, height, origin, config, backendFormat,
|
||||
mipMapped, textureFulfillProc, textureReleaseProc,
|
||||
textureDoneProc, textureContext);
|
||||
textureDoneProc, textureContext, version);
|
||||
if (!proxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -55,7 +55,8 @@ public:
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContext);
|
||||
PromiseImageTextureContext textureContext,
|
||||
PromiseImageApiVersion);
|
||||
|
||||
static sk_sp<SkImage> ConvertYUVATexturesToRGB(GrContext*, SkYUVColorSpace yuvColorSpace,
|
||||
const GrBackendTexture yuvaTextures[],
|
||||
|
@ -386,7 +386,8 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
PromiseImageTextureFulfillProc fulfillProc,
|
||||
PromiseImageTextureReleaseProc releaseProc,
|
||||
PromiseImageTextureDoneProc doneProc,
|
||||
PromiseImageTextureContext textureContext) {
|
||||
PromiseImageTextureContext textureContext,
|
||||
PromiseImageApiVersion version) {
|
||||
SkASSERT(context);
|
||||
SkASSERT(width > 0 && height > 0);
|
||||
SkASSERT(doneProc);
|
||||
@ -425,8 +426,12 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
PromiseImageTextureReleaseProc releaseProc,
|
||||
PromiseImageTextureDoneProc doneProc,
|
||||
PromiseImageTextureContext context,
|
||||
GrPixelConfig config)
|
||||
: fFulfillProc(fulfillProc), fReleaseProc(releaseProc), fConfig(config) {
|
||||
GrPixelConfig config,
|
||||
PromiseImageApiVersion version)
|
||||
: fFulfillProc(fulfillProc)
|
||||
, fReleaseProc(releaseProc)
|
||||
, fConfig(config)
|
||||
, fVersion(version) {
|
||||
fDoneCallback = sk_make_sp<GrRefCntedCallback>(doneProc, context);
|
||||
}
|
||||
PromiseLazyInstantiateCallback(PromiseLazyInstantiateCallback&&) = default;
|
||||
@ -492,7 +497,10 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
return sk_sp<GrTexture>();
|
||||
}
|
||||
}
|
||||
tex->addIdleProc(std::move(releaseCallback), GrTexture::IdleState::kFinished);
|
||||
auto releaseIdleState = fVersion == PromiseImageApiVersion::kLegacy
|
||||
? GrTexture::IdleState::kFinished
|
||||
: GrTexture::IdleState::kFlushed;
|
||||
tex->addIdleProc(std::move(releaseCallback), releaseIdleState);
|
||||
tex->addIdleProc(std::move(fDoneCallback), GrTexture::IdleState::kFinished);
|
||||
promiseTexture->addKeyToInvalidate(tex->getContext()->priv().contextID(), key);
|
||||
fTexture = tex.get();
|
||||
@ -513,7 +521,8 @@ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
|
||||
GrTexture* fTexture = nullptr;
|
||||
uint32_t fTextureContextID = SK_InvalidUniqueID;
|
||||
GrPixelConfig fConfig;
|
||||
} callback(fulfillProc, releaseProc, doneProc, textureContext, config);
|
||||
PromiseImageApiVersion fVersion;
|
||||
} callback(fulfillProc, releaseProc, doneProc, textureContext, config, version);
|
||||
|
||||
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
|
||||
|
||||
|
@ -78,6 +78,7 @@ public:
|
||||
using PromiseImageTextureDoneProc = SkDeferredDisplayListRecorder::PromiseImageTextureDoneProc;
|
||||
|
||||
protected:
|
||||
using PromiseImageApiVersion = SkDeferredDisplayListRecorder::PromiseImageApiVersion;
|
||||
// Helper for making a lazy proxy for a promise image. The PromiseDoneProc we be called,
|
||||
// if not null, immediately if this function fails. Othwerwise, it is installed in the
|
||||
// proxy along with the TextureFulfillProc and TextureReleaseProc. PromiseDoneProc must not
|
||||
@ -85,7 +86,7 @@ protected:
|
||||
static sk_sp<GrTextureProxy> MakePromiseImageLazyProxy(
|
||||
GrContext*, int width, int height, GrSurfaceOrigin, GrPixelConfig, GrBackendFormat,
|
||||
GrMipMapped, PromiseImageTextureFulfillProc, PromiseImageTextureReleaseProc,
|
||||
PromiseImageTextureDoneProc, PromiseImageTextureContext);
|
||||
PromiseImageTextureDoneProc, PromiseImageTextureContext, PromiseImageApiVersion);
|
||||
|
||||
static bool RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* renderTargetContext,
|
||||
const SkRect& rect, SkYUVColorSpace yuvColorSpace,
|
||||
|
@ -282,7 +282,8 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc promiseDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]) {
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
PromiseImageApiVersion version) {
|
||||
int numTextures;
|
||||
bool valid = SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures);
|
||||
|
||||
@ -342,7 +343,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], version);
|
||||
++proxiesCreated;
|
||||
if (!proxies[texIdx]) {
|
||||
return nullptr;
|
||||
|
@ -73,7 +73,8 @@ public:
|
||||
PromiseImageTextureFulfillProc textureFulfillProc,
|
||||
PromiseImageTextureReleaseProc textureReleaseProc,
|
||||
PromiseImageTextureDoneProc textureDoneProc,
|
||||
PromiseImageTextureContext textureContexts[]);
|
||||
PromiseImageTextureContext textureContexts[],
|
||||
PromiseImageApiVersion);
|
||||
|
||||
private:
|
||||
SkImage_GpuYUVA(const SkImage_GpuYUVA* image, sk_sp<SkColorSpace>);
|
||||
|
@ -675,7 +675,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
|
||||
dummy_fulfill_proc,
|
||||
dummy_release_proc,
|
||||
dummy_done_proc,
|
||||
nullptr);
|
||||
nullptr,
|
||||
SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
|
||||
REPORTER_ASSERT(reporter, !image);
|
||||
}
|
||||
|
||||
@ -779,7 +780,8 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLTextureFlagsTest, reporter, ctxInfo) {
|
||||
dummy_fulfill_proc,
|
||||
dummy_release_proc,
|
||||
dummy_done_proc,
|
||||
nullptr);
|
||||
nullptr,
|
||||
SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
|
||||
if (GR_GL_TEXTURE_2D != target && mipMapped == GrMipMapped::kYes) {
|
||||
REPORTER_ASSERT(reporter, !image);
|
||||
continue;
|
||||
|
@ -63,66 +63,100 @@ struct PromiseTextureChecker {
|
||||
}
|
||||
};
|
||||
|
||||
enum class ReleaseBalanceExpecation {
|
||||
enum class ReleaseBalanceExpectation {
|
||||
kBalanced,
|
||||
kBalancedOrPlusOne,
|
||||
kAny
|
||||
kAllUnbalanced,
|
||||
kUnbalancedByOne,
|
||||
};
|
||||
|
||||
static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker,
|
||||
ReleaseBalanceExpecation balanceExpecation,
|
||||
enum class DoneBalanceExpectation {
|
||||
kBalanced,
|
||||
kAllUnbalanced,
|
||||
kUnknown,
|
||||
kUnbalancedByOne,
|
||||
kBalancedOrOffByOne,
|
||||
};
|
||||
|
||||
static void check_fulfill_and_release_cnts(skiatest::Reporter* reporter,
|
||||
const PromiseTextureChecker& promiseChecker,
|
||||
int expectedFulfillCnt,
|
||||
int expectedReleaseCnt,
|
||||
bool expectedRequired,
|
||||
int expectedDoneCnt,
|
||||
skiatest::Reporter* reporter) {
|
||||
bool result = true;
|
||||
int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
|
||||
// FulfillCount should always equal ReleaseCount or be at most one higher
|
||||
if (countDiff != 0) {
|
||||
if (balanceExpecation == ReleaseBalanceExpecation::kBalanced) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, 0 == countDiff);
|
||||
} 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);
|
||||
}
|
||||
ReleaseBalanceExpectation releaseBalanceExpecation,
|
||||
DoneBalanceExpectation doneBalanceExpecation) {
|
||||
REPORTER_ASSERT(reporter, promiseChecker.fFulfillCount == expectedFulfillCnt);
|
||||
if (!expectedFulfillCnt) {
|
||||
// Release and Done should only ever be called after Fulfill.
|
||||
REPORTER_ASSERT(reporter, !promiseChecker.fReleaseCount);
|
||||
REPORTER_ASSERT(reporter, !promiseChecker.fDoneCount);
|
||||
return;
|
||||
}
|
||||
|
||||
int fulfillDiff = expectedFulfillCnt - promiseChecker.fFulfillCount;
|
||||
REPORTER_ASSERT(reporter, fulfillDiff >= 0);
|
||||
if (fulfillDiff != 0) {
|
||||
if (expectedRequired) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, expectedFulfillCnt == promiseChecker.fFulfillCount);
|
||||
} else if (fulfillDiff > 1) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, fulfillDiff <= 1);
|
||||
}
|
||||
int releaseDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
|
||||
switch (releaseBalanceExpecation) {
|
||||
case ReleaseBalanceExpectation::kBalanced:
|
||||
REPORTER_ASSERT(reporter, !releaseDiff);
|
||||
break;
|
||||
case ReleaseBalanceExpectation::kAllUnbalanced:
|
||||
REPORTER_ASSERT(reporter, releaseDiff == promiseChecker.fFulfillCount);
|
||||
break;
|
||||
case ReleaseBalanceExpectation::kUnbalancedByOne:
|
||||
REPORTER_ASSERT(reporter, releaseDiff == 1);
|
||||
break;
|
||||
}
|
||||
|
||||
int releaseDiff = expectedReleaseCnt - promiseChecker.fReleaseCount;
|
||||
REPORTER_ASSERT(reporter, releaseDiff >= 0);
|
||||
if (releaseDiff != 0) {
|
||||
if (expectedRequired) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, expectedReleaseCnt == promiseChecker.fReleaseCount);
|
||||
} else if (releaseDiff > 1) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, releaseDiff <= 1);
|
||||
}
|
||||
int doneDiff = promiseChecker.fFulfillCount - promiseChecker.fDoneCount;
|
||||
switch (doneBalanceExpecation) {
|
||||
case DoneBalanceExpectation::kBalanced:
|
||||
REPORTER_ASSERT(reporter, !doneDiff);
|
||||
break;
|
||||
case DoneBalanceExpectation::kAllUnbalanced:
|
||||
REPORTER_ASSERT(reporter, doneDiff == promiseChecker.fFulfillCount);
|
||||
break;
|
||||
case DoneBalanceExpectation::kUnknown:
|
||||
REPORTER_ASSERT(reporter, doneDiff >= 0 && doneDiff <= promiseChecker.fFulfillCount);
|
||||
break;
|
||||
case DoneBalanceExpectation::kUnbalancedByOne:
|
||||
REPORTER_ASSERT(reporter, doneDiff == 1);
|
||||
break;
|
||||
case DoneBalanceExpectation::kBalancedOrOffByOne:
|
||||
REPORTER_ASSERT(reporter, doneDiff == 0 || doneDiff == 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (expectedDoneCnt != promiseChecker.fDoneCount) {
|
||||
result = false;
|
||||
REPORTER_ASSERT(reporter, expectedDoneCnt == promiseChecker.fDoneCount);
|
||||
static void check_unfulfilled(const PromiseTextureChecker& promiseChecker,
|
||||
skiatest::Reporter* reporter) {
|
||||
check_fulfill_and_release_cnts(reporter, promiseChecker, 0,
|
||||
ReleaseBalanceExpectation::kBalanced,
|
||||
DoneBalanceExpectation::kBalanced);
|
||||
}
|
||||
|
||||
static void check_only_fulfilled(skiatest::Reporter* reporter,
|
||||
const PromiseTextureChecker& promiseChecker,
|
||||
int expectedFulfillCnt = 1) {
|
||||
check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
|
||||
ReleaseBalanceExpectation::kAllUnbalanced,
|
||||
DoneBalanceExpectation::kAllUnbalanced);
|
||||
}
|
||||
|
||||
static void check_all_flushed_but_not_synced(skiatest::Reporter* reporter,
|
||||
const PromiseTextureChecker& promiseChecker,
|
||||
GrBackendApi api,
|
||||
int expectedFulfillCnt = 1) {
|
||||
DoneBalanceExpectation doneBalanceExpectation = DoneBalanceExpectation::kBalanced;
|
||||
// On Vulkan Done isn't guaranteed to be called until a sync has occurred.
|
||||
if (api == GrBackendApi::kVulkan) {
|
||||
doneBalanceExpectation = expectedFulfillCnt == 1
|
||||
? DoneBalanceExpectation::kBalancedOrOffByOne
|
||||
: DoneBalanceExpectation::kUnknown;
|
||||
}
|
||||
check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
|
||||
ReleaseBalanceExpectation::kBalanced, doneBalanceExpectation);
|
||||
}
|
||||
|
||||
return result;
|
||||
static void check_all_done(skiatest::Reporter* reporter,
|
||||
const PromiseTextureChecker& promiseChecker,
|
||||
int expectedFulfillCnt = 1) {
|
||||
check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
|
||||
ReleaseBalanceExpectation::kBalanced,
|
||||
DoneBalanceExpectation::kBalanced);
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
@ -150,47 +184,22 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
PromiseTextureChecker::Fulfill,
|
||||
PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done,
|
||||
&promiseChecker));
|
||||
&promiseChecker,
|
||||
SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
|
||||
|
||||
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));
|
||||
check_unfulfilled(promiseChecker, reporter);
|
||||
|
||||
bool isVulkan = GrBackendApi::kVulkan == ctx->backend();
|
||||
surface->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));
|
||||
// We still own the image so we should not have called Release or Done.
|
||||
check_only_fulfilled(reporter, promiseChecker);
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
check_only_fulfilled(reporter, promiseChecker);
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
@ -198,49 +207,25 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
|
||||
surface->flush();
|
||||
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
// Image should still be fulfilled from the first time we drew/flushed it.
|
||||
check_only_fulfilled(reporter, promiseChecker);
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
surface->flush();
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
check_only_fulfilled(reporter, promiseChecker);
|
||||
|
||||
canvas->drawImage(refImg, 0, 0);
|
||||
|
||||
refImg.reset();
|
||||
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
!isVulkan,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
// We no longer own the image but the last draw is still unflushed.
|
||||
check_only_fulfilled(reporter, promiseChecker);
|
||||
|
||||
surface->flush();
|
||||
// Flushing should have called Release. Depending on the backend and timing it may have called
|
||||
// done.
|
||||
check_all_flushed_but_not_synced(reporter, promiseChecker, ctx->backend());
|
||||
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));
|
||||
// Now Done should definitely have been called.
|
||||
check_all_done(reporter, promiseChecker);
|
||||
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex);
|
||||
}
|
||||
@ -280,32 +265,23 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, repo
|
||||
ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
|
||||
kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
|
||||
PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
|
||||
PromiseTextureChecker::Done, &promiseChecker));
|
||||
PromiseTextureChecker::Done, &promiseChecker,
|
||||
SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
|
||||
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));
|
||||
PromiseTextureChecker::Done, &promiseChecker,
|
||||
SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
|
||||
REPORTER_ASSERT(reporter, grayImg);
|
||||
|
||||
canvas->drawImage(alphaImg, 0, 0);
|
||||
canvas->drawImage(grayImg, 1, 1);
|
||||
surface->flush();
|
||||
gpu->testingOnly_flushGpuAndSync();
|
||||
|
||||
int expectedFulfillCnt = 2;
|
||||
int expectedReleaseCnt = 0;
|
||||
int expectedDoneCnt = 0;
|
||||
ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kAny;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
check_only_fulfilled(reporter, promiseChecker, 2);
|
||||
|
||||
// Because they use different configs, each image should have created a different GrTexture
|
||||
// and they both should still be cached.
|
||||
@ -323,7 +299,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, repo
|
||||
}
|
||||
}
|
||||
|
||||
// Change the backing texture, this should invalidate the keys.
|
||||
// Invalidate the backing texture, this should invalidate the keys.
|
||||
promiseChecker.releaseTexture();
|
||||
ctx->priv().getResourceCache()->purgeAsNeeded();
|
||||
|
||||
@ -331,13 +307,14 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, repo
|
||||
auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
|
||||
REPORTER_ASSERT(reporter, !surf);
|
||||
}
|
||||
|
||||
// Must do this to ensure all callbacks occur before the PromiseImageChecker goes out of scope.
|
||||
alphaImg.reset();
|
||||
ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
|
||||
check_fulfill_and_release_cnts(reporter, promiseChecker, 2,
|
||||
ReleaseBalanceExpectation::kUnbalancedByOne,
|
||||
DoneBalanceExpectation::kUnbalancedByOne);
|
||||
grayImg.reset();
|
||||
ctx->flush();
|
||||
ctx->priv().getGpu()->testingOnly_flushGpuAndSync();
|
||||
|
||||
ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
|
||||
check_all_done(reporter, promiseChecker, 2);
|
||||
gpu->deleteTestingOnlyBackendTexture(backendTex1);
|
||||
}
|
||||
|
||||
@ -389,7 +366,8 @@ DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
|
||||
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::PromiseImageApiVersion::kNew));
|
||||
REPORTER_ASSERT(reporter, image);
|
||||
|
||||
canvas->drawImage(image, 0, 0);
|
||||
@ -401,17 +379,7 @@ DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
|
||||
ctx->flush();
|
||||
contextDeath(&factory, ctx);
|
||||
|
||||
int expectedFulfillCnt = 1;
|
||||
int expectedReleaseCnt = 1;
|
||||
int expectedDoneCnt = 1;
|
||||
ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
|
||||
REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
|
||||
balanceExpecation,
|
||||
expectedFulfillCnt,
|
||||
expectedReleaseCnt,
|
||||
true,
|
||||
expectedDoneCnt,
|
||||
reporter));
|
||||
check_all_done(reporter, promiseChecker);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -437,7 +405,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::PromiseImageApiVersion::kNew));
|
||||
REPORTER_ASSERT(reporter, image);
|
||||
|
||||
// Make the cache full. This tests that we don't preemptively purge cached textures for
|
||||
|
@ -202,18 +202,20 @@ sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
|
||||
sizes[i] = SkISize::MakeEmpty();
|
||||
}
|
||||
|
||||
image = recorder->makeYUVAPromiseTexture(curImage.yuvColorSpace(),
|
||||
backendFormats,
|
||||
sizes,
|
||||
curImage.yuvaIndices(),
|
||||
curImage.overallWidth(),
|
||||
curImage.overallHeight(),
|
||||
GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
|
||||
curImage.refOverallColorSpace(),
|
||||
DDLPromiseImageHelper::PromiseImageFulfillProc,
|
||||
DDLPromiseImageHelper::PromiseImageReleaseProc,
|
||||
DDLPromiseImageHelper::PromiseImageDoneProc,
|
||||
contexts);
|
||||
image = recorder->makeYUVAPromiseTexture(
|
||||
curImage.yuvColorSpace(),
|
||||
backendFormats,
|
||||
sizes,
|
||||
curImage.yuvaIndices(),
|
||||
curImage.overallWidth(),
|
||||
curImage.overallHeight(),
|
||||
GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
|
||||
curImage.refOverallColorSpace(),
|
||||
DDLPromiseImageHelper::PromiseImageFulfillProc,
|
||||
DDLPromiseImageHelper::PromiseImageReleaseProc,
|
||||
DDLPromiseImageHelper::PromiseImageDoneProc,
|
||||
contexts,
|
||||
SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
|
||||
for (int i = 0; i < textureCount; ++i) {
|
||||
curImage.callbackContext(i)->wasAddedToImage();
|
||||
}
|
||||
@ -235,18 +237,20 @@ sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
|
||||
// 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());
|
||||
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(),
|
||||
SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
|
||||
curImage.callbackContext(0)->wasAddedToImage();
|
||||
}
|
||||
perRecorderContext->fPromiseImages->push_back(image);
|
||||
|
Loading…
Reference in New Issue
Block a user