aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Greg Daniel <egdaniel@google.com>2018-03-16 14:57:21 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-16 19:27:46 +0000
commit7278d68cac9e39970144909df449113d43fff480 (patch)
tree95c86e6c9676d59e99549ddcd3fa5d727b71ec98
parent7ba427ef40301d199bcd5c0f9a9d41244c495bd6 (diff)
Add DoneProc to Promise Images
This proc will notify the client when we will no longer call fulfill on their promise image so that can delete any meta data they needed to store to be able to complete the fulfill requests. Bug: skia: Change-Id: Ife1e6845f221c31ce1ae2c0d2ba5e4c8f0203b74 Reviewed-on: https://skia-review.googlesource.com/114092 Commit-Queue: Greg Daniel <egdaniel@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
-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