aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--dm/DMSrcSink.cpp5
-rw-r--r--include/core/SkDeferredDisplayListRecorder.h9
-rw-r--r--src/core/SkDeferredDisplayListRecorder.cpp3
-rw-r--r--src/image/SkImage_Gpu.cpp59
-rw-r--r--src/image/SkImage_Gpu.h8
-rw-r--r--tests/DeferredDisplayListTest.cpp2
-rw-r--r--tests/PromiseImageTest.cpp257
7 files changed, 230 insertions, 113 deletions
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 9b68dc99cf..43992a8ff8 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -1248,6 +1248,10 @@ static void promise_image_release_proc(void* textureContext) {
// Do nothing. We free all the backend textures at the end.
}
+static void promise_image_done_proc(void* textureContext) {
+ // Do nothing.
+}
+
class PromiseImageCallbackContext {
public:
const SkTArray<PromiseImageInfo>* fImageInfo;
@@ -1283,6 +1287,7 @@ static sk_sp<SkImage> promise_image_creator(const void* rawData, size_t length,
curImage.fBitmap.refColorSpace(),
promise_image_fulfill_proc,
promise_image_release_proc,
+ promise_image_done_proc,
(void*) &curImage);
SkASSERT(image);
return image;
diff --git a/include/core/SkDeferredDisplayListRecorder.h b/include/core/SkDeferredDisplayListRecorder.h
index d7743e6b8c..0acf598f96 100644
--- a/include/core/SkDeferredDisplayListRecorder.h
+++ b/include/core/SkDeferredDisplayListRecorder.h
@@ -55,6 +55,7 @@ public:
typedef void* TextureContext;
typedef void (*TextureReleaseProc)(TextureContext textureContext);
typedef void (*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
+ typedef void (*PromiseDoneProc)(TextureContext textureContext);
/**
Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The main
@@ -75,6 +76,12 @@ public:
In other words we will never call textureFulfillProc or textureReleaseProc multiple times
for the same textureContext before calling the other.
+ We we call the promiseDoneProc when we will no longer call the textureFulfillProc again. We
+ 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.
@param backendFormat format of promised gpu texture
@@ -91,6 +98,7 @@ 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 textureContext state passed to textureFulfillProc and textureReleaseProc
@return created SkImage, or nullptr
*/
@@ -104,6 +112,7 @@ public:
sk_sp<SkColorSpace> colorSpace,
TextureFulfillProc textureFulfillProc,
TextureReleaseProc textureReleaseProc,
+ PromiseDoneProc promiseDoneProc,
TextureContext textureContext);
private:
diff --git a/src/core/SkDeferredDisplayListRecorder.cpp b/src/core/SkDeferredDisplayListRecorder.cpp
index 3d84aeb7bb..a0f6c01563 100644
--- a/src/core/SkDeferredDisplayListRecorder.cpp
+++ b/src/core/SkDeferredDisplayListRecorder.cpp
@@ -33,6 +33,7 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
sk_sp<SkColorSpace> colorSpace,
TextureFulfillProc textureFulfillProc,
TextureReleaseProc textureReleaseProc,
+ PromiseDoneProc promiseDoneProc,
TextureContext textureContext) {
return nullptr;
}
@@ -155,6 +156,7 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
sk_sp<SkColorSpace> colorSpace,
TextureFulfillProc textureFulfillProc,
TextureReleaseProc textureReleaseProc,
+ PromiseDoneProc promiseDoneProc,
TextureContext textureContext) {
if (!fContext) {
return nullptr;
@@ -171,6 +173,7 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
std::move(colorSpace),
textureFulfillProc,
textureReleaseProc,
+ promiseDoneProc,
textureContext);
}
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 6ab2ddc0b8..5a2b25106f 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -529,17 +529,58 @@ sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstCo
return nullptr;
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This helper holds the normal hard ref for the Release proc as well as a hard ref on the DoneProc.
+ * Thus when a GrTexture is being released, it will unref both the ReleaseProc and DoneProc.
+ */
+class PromiseReleaseProcHelper : public GrReleaseProcHelper {
+public:
+ PromiseReleaseProcHelper(SkImage_Gpu::TextureReleaseProc releaseProc,
+ SkImage_Gpu::TextureContext context,
+ sk_sp<GrReleaseProcHelper> doneHelper)
+ : INHERITED(releaseProc, context)
+ , fDoneProcHelper(std::move(doneHelper)) {}
+
+ void weak_dispose() const override {
+ // Call the inherited weak_dispose first so that we call the ReleaseProc before the DoneProc
+ // if we hold the last ref to the DoneProc.
+ INHERITED::weak_dispose();
+ fDoneProcHelper.reset();
+ }
+
+private:
+ mutable sk_sp<GrReleaseProcHelper> fDoneProcHelper;
+
+ typedef GrReleaseProcHelper INHERITED;
+};
+
+/**
+ * This helper class manages the ref counting for the the ReleaseProc and DoneProc for promise
+ * images. It holds a weak ref on the ReleaseProc (hard refs are owned by GrTextures). The weak ref
+ * allows us to reuse an outstanding ReleaseProc (because we dropped our GrTexture but the GrTexture
+ * isn't done on the GPU) without needing to call FulfillProc again. It also holds a hard ref on the
+ * DoneProc. The idea is that after every flush we may call the ReleaseProc so that the client can
+ * free up their GPU memory if they want to. The life time of the DoneProc matches that of any
+ * outstanding ReleaseProc as well as the PromiseImageHelper. Thus we won't call the DoneProc until
+ * all ReleaseProcs are finished and we are finished with the PromiseImageHelper (i.e. won't call
+ * FulfillProc again).
+ */
class PromiseImageHelper {
public:
PromiseImageHelper(SkImage_Gpu::TextureFulfillProc fulFillProc,
SkImage_Gpu::TextureReleaseProc releaseProc,
+ SkImage_Gpu::PromiseDoneProc doneProc,
SkImage_Gpu::TextureContext context)
: fFulfillProc(fulFillProc)
, fReleaseProc(releaseProc)
- , fContext(context) {}
+ , fContext(context)
+ , fDoneHelper(new GrReleaseProcHelper(doneProc, context)) {}
void reset() {
this->resetReleaseHelper();
+ fDoneHelper.reset();
}
sk_sp<GrTexture> getTexture(GrResourceProvider* resourceProvider, GrPixelConfig config) {
@@ -567,7 +608,7 @@ public:
fReleaseProc(fContext);
return sk_sp<GrTexture>();
}
- fReleaseHelper = new GrReleaseProcHelper(fReleaseProc, fContext);
+ fReleaseHelper = new PromiseReleaseProcHelper(fReleaseProc, fContext, fDoneHelper);
// Take a weak ref
fReleaseHelper->weak_ref();
} else {
@@ -608,7 +649,11 @@ private:
GrBackendTexture fBackendTex;
// The fReleaseHelper is used to track a weak ref on the release proc. This helps us make sure
// we are always pairing fulfill and release proc calls correctly.
- GrReleaseProcHelper* fReleaseHelper = nullptr;
+ PromiseReleaseProcHelper* fReleaseHelper = nullptr;
+ // We don't want to call the fDoneHelper until we are done with the PromiseImageHelper and all
+ // ReleaseHelpers are finished. Thus we hold a hard ref here and we will pass a hard ref to each
+ // fReleaseHelper we make.
+ sk_sp<GrReleaseProcHelper> fDoneHelper;
};
sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
@@ -622,6 +667,7 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
sk_sp<SkColorSpace> colorSpace,
TextureFulfillProc textureFulfillProc,
TextureReleaseProc textureReleaseProc,
+ PromiseDoneProc promiseDoneProc,
TextureContext textureContext) {
if (!context) {
return nullptr;
@@ -631,7 +677,7 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
return nullptr;
}
- if (!textureFulfillProc || !textureReleaseProc) {
+ if (!textureFulfillProc || !textureReleaseProc || !promiseDoneProc) {
return nullptr;
}
@@ -651,7 +697,8 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
desc.fHeight = height;
desc.fConfig = config;
- PromiseImageHelper promiseHelper(textureFulfillProc, textureReleaseProc, textureContext);
+ PromiseImageHelper promiseHelper(textureFulfillProc, textureReleaseProc, promiseDoneProc,
+ textureContext);
sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
[promiseHelper, config] (GrResourceProvider* resourceProvider) mutable {
@@ -672,6 +719,8 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
std::move(colorSpace), SkBudgeted::kNo);
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
bool buildMips, SkColorSpace* dstColorSpace) {
sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index e1fd35a766..7a4fa9751a 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -63,6 +63,7 @@ public:
typedef ReleaseContext TextureContext;
typedef void (*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
+ typedef void (*PromiseDoneProc)(TextureContext textureContext);
/**
Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The main
@@ -83,6 +84,11 @@ public:
In other words we will never call textureFulfillProc or textureReleaseProc multiple times
for the same textureContext before calling the other.
+ We we call the promiseDoneProc when we will no longer call the textureFulfillProc again. We
+ 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
@@ -98,6 +104,7 @@ 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 textureContext state passed to textureFulfillProc and textureReleaseProc
@return created SkImage, or nullptr
*/
@@ -112,6 +119,7 @@ public:
sk_sp<SkColorSpace> colorSpace,
TextureFulfillProc textureFulfillProc,
TextureReleaseProc textureReleaseProc,
+ PromiseDoneProc promiseDoneProc,
TextureContext textureContext);
/** Implementation of MakeFromYUVTexturesCopy and MakeFromNV12TexturesCopy */
diff --git a/tests/DeferredDisplayListTest.cpp b/tests/DeferredDisplayListTest.cpp
index f17957c9c8..9abe5f9ff4 100644
--- a/tests/DeferredDisplayListTest.cpp
+++ b/tests/DeferredDisplayListTest.cpp
@@ -406,6 +406,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
static void dummy_fulfill_proc(void*, GrBackendTexture*) { SkASSERT(0); }
static void dummy_release_proc(void*) { SkASSERT(0); }
+static void dummy_done_proc(void*) { SkASSERT(0); }
// Test out the behavior of an invalid DDLRecorder
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
@@ -439,6 +440,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
kPremul_SkAlphaType, nullptr,
dummy_fulfill_proc,
dummy_release_proc,
+ dummy_done_proc,
nullptr);
REPORTER_ASSERT(reporter, !image);
}
diff --git a/tests/PromiseImageTest.cpp b/tests/PromiseImageTest.cpp
index c5bd9cd268..ef4a299850 100644
--- a/tests/PromiseImageTest.cpp
+++ b/tests/PromiseImageTest.cpp
@@ -22,10 +22,12 @@ struct PromiseTextureChecker {
explicit PromiseTextureChecker(const GrBackendTexture& tex)
: fTexture(tex)
, fFulfillCount(0)
- , fReleaseCount(0) {}
+ , fReleaseCount(0)
+ , fDoneCount(0) {}
GrBackendTexture fTexture;
int fFulfillCount;
int fReleaseCount;
+ int fDoneCount;
static void Fulfill(void* self, GrBackendTexture* outTexture) {
static_cast<PromiseTextureChecker*>(self)->fFulfillCount++;
*outTexture = static_cast<PromiseTextureChecker*>(self)->fTexture;
@@ -33,6 +35,9 @@ struct PromiseTextureChecker {
static void Release(void* self) {
static_cast<PromiseTextureChecker*>(self)->fReleaseCount++;
}
+ static void Done(void* self) {
+ static_cast<PromiseTextureChecker*>(self)->fDoneCount++;
+ }
};
// Because Vulkan may delay when it actually calls the ReleaseProcs depending on when command
@@ -43,6 +48,7 @@ static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseC
int expectedFulfillCnt,
int expectedReleaseCnt,
bool expectedRequired,
+ int expectedDoneCnt,
skiatest::Reporter* reporter) {
bool result = true;
int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
@@ -81,123 +87,158 @@ static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseC
}
}
+ if (expectedDoneCnt != promiseChecker.fDoneCount) {
+ result = false;
+ REPORTER_ASSERT(reporter, expectedDoneCnt == promiseChecker.fDoneCount);
+ }
+
return result;
}
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
const int kWidth = 10;
const int kHeight = 10;
- std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]);
GrContext* ctx = ctxInfo.grContext();
GrGpu* gpu = ctx->contextPriv().getGpu();
- GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
- pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
- REPORTER_ASSERT(reporter, backendTex.isValid());
-
- GrBackendFormat backendFormat = backendTex.format();
- REPORTER_ASSERT(reporter, backendFormat.isValid());
-
- PromiseTextureChecker promiseChecker(backendTex);
- 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,
- &promiseChecker));
-
- 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;
-
- canvas->drawImage(refImg, 0, 0);
- REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
- true,
- expectedFulfillCnt,
- expectedReleaseCnt,
- true,
- reporter));
-
- bool isVulkan = kVulkan_GrBackend == ctx->contextPriv().getBackend();
- canvas->flush();
- expectedFulfillCnt++;
- expectedReleaseCnt++;
- REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
- !isVulkan,
- expectedFulfillCnt,
- expectedReleaseCnt,
- !isVulkan,
- reporter));
-
- gpu->testingOnly_flushGpuAndSync();
- REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
- true,
- expectedFulfillCnt,
- expectedReleaseCnt,
- true,
- reporter));
-
- canvas->drawImage(refImg, 0, 0);
- canvas->drawImage(refImg, 0, 0);
-
- canvas->flush();
- expectedFulfillCnt++;
- expectedReleaseCnt++;
-
- gpu->testingOnly_flushGpuAndSync();
- REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
- true,
- expectedFulfillCnt,
- expectedReleaseCnt,
- true,
- reporter));
-
- // Now test code path on Vulkan where we released the texture, but the GPU isn't done with
- // resource yet and we do another draw. We should only call fulfill on the first draw and
- // use the cached GrBackendTexture on the second. Release should only be called after the second
- // draw is finished.
- canvas->drawImage(refImg, 0, 0);
- canvas->flush();
- expectedFulfillCnt++;
- expectedReleaseCnt++;
- REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
- !isVulkan,
- expectedFulfillCnt,
- expectedReleaseCnt,
- !isVulkan,
- reporter));
-
- canvas->drawImage(refImg, 0, 0);
- canvas->flush();
- expectedFulfillCnt++;
-
- gpu->testingOnly_flushGpuAndSync();
- expectedReleaseCnt++;
- REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
- true,
- expectedFulfillCnt,
- expectedReleaseCnt,
- !isVulkan,
- reporter));
- expectedFulfillCnt = promiseChecker.fFulfillCount;
- expectedReleaseCnt = promiseChecker.fReleaseCount;
-
- refImg.reset();
-
- REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
- true,
- expectedFulfillCnt,
- expectedReleaseCnt,
- true,
- reporter));
-
- gpu->deleteTestingOnlyBackendTexture(backendTex);
+ for (bool releaseImageEarly : {true, false}) {
+ GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
+ nullptr, kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
+ REPORTER_ASSERT(reporter, backendTex.isValid());
+
+ GrBackendFormat backendFormat = backendTex.format();
+ REPORTER_ASSERT(reporter, backendFormat.isValid());
+
+ PromiseTextureChecker promiseChecker(backendTex);
+ 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));
+
+ 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;
+
+ canvas->drawImage(refImg, 0, 0);
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ true,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ true,
+ expectedDoneCnt,
+ reporter));
+
+ bool isVulkan = kVulkan_GrBackend == ctx->contextPriv().getBackend();
+ canvas->flush();
+ expectedFulfillCnt++;
+ expectedReleaseCnt++;
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ !isVulkan,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ !isVulkan,
+ expectedDoneCnt,
+ reporter));
+
+ gpu->testingOnly_flushGpuAndSync();
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ true,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ true,
+ expectedDoneCnt,
+ reporter));
+
+ canvas->drawImage(refImg, 0, 0);
+ canvas->drawImage(refImg, 0, 0);
+
+ canvas->flush();
+ expectedFulfillCnt++;
+ expectedReleaseCnt++;
+
+ gpu->testingOnly_flushGpuAndSync();
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ true,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ true,
+ expectedDoneCnt,
+ reporter));
+
+ // Now test code path on Vulkan where we released the texture, but the GPU isn't done with
+ // resource yet and we do another draw. We should only call fulfill on the first draw and
+ // use the cached GrBackendTexture on the second. Release should only be called after the
+ // second draw is finished.
+ canvas->drawImage(refImg, 0, 0);
+ canvas->flush();
+ expectedFulfillCnt++;
+ expectedReleaseCnt++;
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ !isVulkan,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ !isVulkan,
+ expectedDoneCnt,
+ reporter));
+
+ canvas->drawImage(refImg, 0, 0);
+
+ if (releaseImageEarly) {
+ refImg.reset();
+ }
+
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ !isVulkan,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ !isVulkan,
+ expectedDoneCnt,
+ reporter));
+
+ canvas->flush();
+ expectedFulfillCnt++;
+
+ gpu->testingOnly_flushGpuAndSync();
+ expectedReleaseCnt++;
+ if (releaseImageEarly) {
+ expectedDoneCnt++;
+ }
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ true,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ !isVulkan,
+ expectedDoneCnt,
+ reporter));
+ expectedFulfillCnt = promiseChecker.fFulfillCount;
+ expectedReleaseCnt = promiseChecker.fReleaseCount;
+
+ if (!releaseImageEarly) {
+ refImg.reset();
+ expectedDoneCnt++;
+ }
+
+ REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
+ true,
+ expectedFulfillCnt,
+ expectedReleaseCnt,
+ true,
+ expectedDoneCnt,
+ reporter));
+
+ gpu->deleteTestingOnlyBackendTexture(backendTex);
+ }
}
#endif