blob: 333a69db68276e7eb6c1b39257c0cfdddabcf250 [file] [log] [blame]
Greg Daniela8d92112018-03-09 12:05:04 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tests/Test.h"
Greg Daniela8d92112018-03-09 12:05:04 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkColorFilter.h"
11#include "include/core/SkPromiseImageTexture.h"
12#include "include/gpu/GrBackendSurface.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrContextPriv.h"
14#include "src/gpu/GrGpu.h"
Greg Daniel456f9b52020-03-05 19:14:18 +000015#include "src/gpu/GrTexture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/image/SkImage_Gpu.h"
Greg Danielc1ad77c2020-05-06 11:40:03 -040017#include "tests/TestUtils.h"
Greg Daniela8d92112018-03-09 12:05:04 -050018
19using namespace sk_gpu_test;
20
21struct PromiseTextureChecker {
Brian Salomon9bc76d92019-01-24 12:18:33 -050022 // shared indicates whether the backend texture is used to fulfill more than one promise
23 // image.
24 explicit PromiseTextureChecker(const GrBackendTexture& tex, skiatest::Reporter* reporter,
25 bool shared)
Brian Salomon3f4cd772019-01-11 16:03:19 -050026 : fTexture(SkPromiseImageTexture::Make(tex))
Brian Salomon9bc76d92019-01-24 12:18:33 -050027 , fReporter(reporter)
28 , fShared(shared)
Greg Daniela8d92112018-03-09 12:05:04 -050029 , fFulfillCount(0)
Greg Daniel7278d682018-03-16 14:57:21 -040030 , fReleaseCount(0)
31 , fDoneCount(0) {}
Brian Salomon3f4cd772019-01-11 16:03:19 -050032 sk_sp<SkPromiseImageTexture> fTexture;
Brian Salomon9bc76d92019-01-24 12:18:33 -050033 skiatest::Reporter* fReporter;
34 bool fShared;
Greg Daniela8d92112018-03-09 12:05:04 -050035 int fFulfillCount;
36 int fReleaseCount;
Greg Daniel7278d682018-03-16 14:57:21 -040037 int fDoneCount;
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050038
39 /**
Brian Salomon7d88f312019-02-28 10:03:03 -050040 * Releases the SkPromiseImageTexture. Used to test that cached GrTexture representations
41 * in the cache are freed.
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050042 */
Brian Salomon7d88f312019-02-28 10:03:03 -050043 void releaseTexture() { fTexture.reset(); }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050044
45 SkTArray<GrUniqueKey> uniqueKeys() const {
Brian Salomon3f4cd772019-01-11 16:03:19 -050046 return fTexture->testingOnly_uniqueKeysToInvalidate();
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050047 }
48
Brian Salomon3f4cd772019-01-11 16:03:19 -050049 static sk_sp<SkPromiseImageTexture> Fulfill(void* self) {
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050050 auto checker = static_cast<PromiseTextureChecker*>(self);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050051 checker->fFulfillCount++;
Brian Salomon3f4cd772019-01-11 16:03:19 -050052 return checker->fTexture;
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050053 }
Brian Salomon9bc76d92019-01-24 12:18:33 -050054 static void Release(void* self) {
55 auto checker = static_cast<PromiseTextureChecker*>(self);
56 checker->fReleaseCount++;
57 if (!checker->fShared) {
58 // This is only used in a single threaded fashion with a single promise image. So
59 // every fulfill should be balanced by a release before the next fulfill.
60 REPORTER_ASSERT(checker->fReporter, checker->fReleaseCount == checker->fFulfillCount);
61 }
62 }
Greg Daniel7278d682018-03-16 14:57:21 -040063 static void Done(void* self) {
64 static_cast<PromiseTextureChecker*>(self)->fDoneCount++;
65 }
Greg Daniela8d92112018-03-09 12:05:04 -050066};
67
Brian Salomon0cc57542019-03-08 13:28:46 -050068enum class ReleaseBalanceExpectation {
Brian Salomonf55e8d52019-01-30 17:28:20 -050069 kBalanced,
Brian Salomon0cc57542019-03-08 13:28:46 -050070 kAllUnbalanced,
71 kUnbalancedByOne,
Brian Salomonf55e8d52019-01-30 17:28:20 -050072};
73
Brian Salomon0cc57542019-03-08 13:28:46 -050074enum class DoneBalanceExpectation {
75 kBalanced,
76 kAllUnbalanced,
77 kUnknown,
78 kUnbalancedByOne,
79 kBalancedOrOffByOne,
80};
81
82static void check_fulfill_and_release_cnts(skiatest::Reporter* reporter,
83 const PromiseTextureChecker& promiseChecker,
Greg Daniela8d92112018-03-09 12:05:04 -050084 int expectedFulfillCnt,
Brian Salomon0cc57542019-03-08 13:28:46 -050085 ReleaseBalanceExpectation releaseBalanceExpecation,
86 DoneBalanceExpectation doneBalanceExpecation) {
87 REPORTER_ASSERT(reporter, promiseChecker.fFulfillCount == expectedFulfillCnt);
88 if (!expectedFulfillCnt) {
89 // Release and Done should only ever be called after Fulfill.
90 REPORTER_ASSERT(reporter, !promiseChecker.fReleaseCount);
91 REPORTER_ASSERT(reporter, !promiseChecker.fDoneCount);
92 return;
Greg Daniela8d92112018-03-09 12:05:04 -050093 }
Brian Salomon0cc57542019-03-08 13:28:46 -050094 int releaseDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
95 switch (releaseBalanceExpecation) {
96 case ReleaseBalanceExpectation::kBalanced:
97 REPORTER_ASSERT(reporter, !releaseDiff);
98 break;
99 case ReleaseBalanceExpectation::kAllUnbalanced:
100 REPORTER_ASSERT(reporter, releaseDiff == promiseChecker.fFulfillCount);
101 break;
102 case ReleaseBalanceExpectation::kUnbalancedByOne:
103 REPORTER_ASSERT(reporter, releaseDiff == 1);
104 break;
Greg Daniela8d92112018-03-09 12:05:04 -0500105 }
Brian Salomon0cc57542019-03-08 13:28:46 -0500106 int doneDiff = promiseChecker.fFulfillCount - promiseChecker.fDoneCount;
107 switch (doneBalanceExpecation) {
108 case DoneBalanceExpectation::kBalanced:
109 REPORTER_ASSERT(reporter, !doneDiff);
110 break;
111 case DoneBalanceExpectation::kAllUnbalanced:
112 REPORTER_ASSERT(reporter, doneDiff == promiseChecker.fFulfillCount);
113 break;
114 case DoneBalanceExpectation::kUnknown:
115 REPORTER_ASSERT(reporter, doneDiff >= 0 && doneDiff <= promiseChecker.fFulfillCount);
116 break;
117 case DoneBalanceExpectation::kUnbalancedByOne:
118 REPORTER_ASSERT(reporter, doneDiff == 1);
119 break;
120 case DoneBalanceExpectation::kBalancedOrOffByOne:
121 REPORTER_ASSERT(reporter, doneDiff == 0 || doneDiff == 1);
122 break;
Greg Daniela8d92112018-03-09 12:05:04 -0500123 }
Brian Salomon0cc57542019-03-08 13:28:46 -0500124}
Greg Daniela8d92112018-03-09 12:05:04 -0500125
Brian Salomon0cc57542019-03-08 13:28:46 -0500126static void check_unfulfilled(const PromiseTextureChecker& promiseChecker,
127 skiatest::Reporter* reporter) {
128 check_fulfill_and_release_cnts(reporter, promiseChecker, 0,
129 ReleaseBalanceExpectation::kBalanced,
130 DoneBalanceExpectation::kBalanced);
131}
132
133static void check_only_fulfilled(skiatest::Reporter* reporter,
134 const PromiseTextureChecker& promiseChecker,
135 int expectedFulfillCnt = 1) {
136 check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
137 ReleaseBalanceExpectation::kAllUnbalanced,
138 DoneBalanceExpectation::kAllUnbalanced);
139}
140
141static void check_all_flushed_but_not_synced(skiatest::Reporter* reporter,
142 const PromiseTextureChecker& promiseChecker,
143 GrBackendApi api,
144 int expectedFulfillCnt = 1) {
145 DoneBalanceExpectation doneBalanceExpectation = DoneBalanceExpectation::kBalanced;
146 // On Vulkan Done isn't guaranteed to be called until a sync has occurred.
147 if (api == GrBackendApi::kVulkan) {
148 doneBalanceExpectation = expectedFulfillCnt == 1
149 ? DoneBalanceExpectation::kBalancedOrOffByOne
150 : DoneBalanceExpectation::kUnknown;
Greg Daniel7278d682018-03-16 14:57:21 -0400151 }
Brian Salomon0cc57542019-03-08 13:28:46 -0500152 check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
153 ReleaseBalanceExpectation::kBalanced, doneBalanceExpectation);
154}
Greg Daniel7278d682018-03-16 14:57:21 -0400155
Brian Salomon0cc57542019-03-08 13:28:46 -0500156static void check_all_done(skiatest::Reporter* reporter,
157 const PromiseTextureChecker& promiseChecker,
158 int expectedFulfillCnt = 1) {
159 check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
160 ReleaseBalanceExpectation::kBalanced,
161 DoneBalanceExpectation::kBalanced);
Greg Daniela8d92112018-03-09 12:05:04 -0500162}
163
Brian Salomon7d88f312019-02-28 10:03:03 -0500164DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
Brian Salomonf55e8d52019-01-30 17:28:20 -0500165 const int kWidth = 10;
166 const int kHeight = 10;
167
168 GrContext* ctx = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500169 GrGpu* gpu = ctx->priv().getGpu();
Brian Salomonf55e8d52019-01-30 17:28:20 -0500170
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400171 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400172 kWidth, kHeight, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400173 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes, GrProtected::kNo);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500174 REPORTER_ASSERT(reporter, backendTex.isValid());
175
176 GrBackendFormat backendFormat = backendTex.getBackendFormat();
177 REPORTER_ASSERT(reporter, backendFormat.isValid());
178
179 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
180 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
181 sk_sp<SkImage> refImg(
182 SkImage_Gpu::MakePromiseTexture(
183 ctx, backendFormat, kWidth, kHeight,
184 GrMipMapped::kNo, texOrigin,
185 kRGBA_8888_SkColorType, kPremul_SkAlphaType,
186 nullptr,
187 PromiseTextureChecker::Fulfill,
188 PromiseTextureChecker::Release,
189 PromiseTextureChecker::Done,
Brian Salomon0cc57542019-03-08 13:28:46 -0500190 &promiseChecker,
191 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomonf55e8d52019-01-30 17:28:20 -0500192
193 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
194 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
195 SkCanvas* canvas = surface->getCanvas();
196
Brian Salomond716d442019-03-07 15:23:30 +0000197 canvas->drawImage(refImg, 0, 0);
Brian Salomon0cc57542019-03-08 13:28:46 -0500198 check_unfulfilled(promiseChecker, reporter);
Brian Salomond716d442019-03-07 15:23:30 +0000199
Robert Phillips9882dae2019-03-04 11:00:10 -0500200 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500201 // We still own the image so we should not have called Release or Done.
202 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500203
204 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500205 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500206
207 canvas->drawImage(refImg, 0, 0);
208 canvas->drawImage(refImg, 0, 0);
209
Robert Phillips9882dae2019-03-04 11:00:10 -0500210 surface->flush();
Brian Salomonf55e8d52019-01-30 17:28:20 -0500211
212 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500213 // Image should still be fulfilled from the first time we drew/flushed it.
214 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500215
216 canvas->drawImage(refImg, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500217 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500218 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500219
220 canvas->drawImage(refImg, 0, 0);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500221 refImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500222 // We no longer own the image but the last draw is still unflushed.
223 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500224
Robert Phillips9882dae2019-03-04 11:00:10 -0500225 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500226 // Flushing should have called Release. Depending on the backend and timing it may have called
227 // done.
228 check_all_flushed_but_not_synced(reporter, promiseChecker, ctx->backend());
Brian Salomonf55e8d52019-01-30 17:28:20 -0500229 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500230 // Now Done should definitely have been called.
231 check_all_done(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500232
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400233 ctx->deleteBackendTexture(backendTex);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500234}
235
Brian Salomon9bc76d92019-01-24 12:18:33 -0500236DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
237 const int kWidth = 10;
238 const int kHeight = 10;
239
240 // Different ways of killing contexts.
241 using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrContext*)>;
242 DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
243 factory->destroyContexts();
244 };
245 DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
246 context->abandonContext();
247 };
248 DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory,
249 GrContext* context) {
250 context->releaseResourcesAndAbandonContext();
251 };
252
253 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
254 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
255 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
256 // and http://skbug.com/8275
257 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
258 if (api == GrBackendApi::kVulkan) {
259 continue;
260 }
261 DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon};
262 for (auto contextDeath : contextKillers) {
263 sk_gpu_test::GrContextFactory factory;
264 auto ctx = factory.get(contextType);
265 if (!ctx) {
266 continue;
267 }
Brian Salomon9bc76d92019-01-24 12:18:33 -0500268
Greg Danielc1ad77c2020-05-06 11:40:03 -0400269 GrBackendTexture backendTex;
270 CreateBackendTexture(ctx, &backendTex, kWidth, kHeight, kAlpha_8_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400271 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500272 REPORTER_ASSERT(reporter, backendTex.isValid());
273
274 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
275 kPremul_SkAlphaType);
276 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
277 SkCanvas* canvas = surface->getCanvas();
278
279 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
280 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
281 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
Brian Salomonf55e8d52019-01-30 17:28:20 -0500282 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
283 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500284 PromiseTextureChecker::Done, &promiseChecker,
285 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500286 REPORTER_ASSERT(reporter, image);
287
288 canvas->drawImage(image, 0, 0);
289 image.reset();
290 // If the surface still holds a ref to the context then the factory will not be able
291 // to destroy the context (and instead will release-all-and-abandon).
292 surface.reset();
293
294 ctx->flush();
295 contextDeath(&factory, ctx);
296
Brian Salomon0cc57542019-03-08 13:28:46 -0500297 check_all_done(reporter, promiseChecker);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500298 }
299 }
300}
301
302DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) {
303 const int kWidth = 10;
304 const int kHeight = 10;
305
306 GrContext* ctx = ctxInfo.grContext();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500307
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400308 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400309 kWidth, kHeight, kAlpha_8_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400310 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500311 REPORTER_ASSERT(reporter, backendTex.isValid());
312
313 SkImageInfo info =
314 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
315 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
316 SkCanvas* canvas = surface->getCanvas();
317
318 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
319 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
320 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
321 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
322 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500323 PromiseTextureChecker::Done, &promiseChecker,
324 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500325 REPORTER_ASSERT(reporter, image);
326
327 // Make the cache full. This tests that we don't preemptively purge cached textures for
328 // fulfillment due to cache pressure.
Robert Phillipscf39f372019-09-03 10:29:20 -0400329 static constexpr int kMaxBytes = 1;
330 ctx->setResourceCacheLimit(kMaxBytes);
331 SkTArray<sk_sp<GrTexture>> textures;
332 for (int i = 0; i < 5; ++i) {
Brian Salomon4eb38b72019-08-05 12:58:39 -0400333 auto format = ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
334 GrRenderable::kNo);
Robert Phillipscf39f372019-09-03 10:29:20 -0400335 textures.emplace_back(ctx->priv().resourceProvider()->createTexture(
Brian Salomona56a7462020-02-07 14:17:25 -0500336 {100, 100}, format, GrRenderable::kNo, 1, GrMipMapped::kNo, SkBudgeted::kYes,
Brian Salomona90382f2019-09-17 09:01:56 -0400337 GrProtected::kNo));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500338 REPORTER_ASSERT(reporter, textures[i]);
339 }
340
Robert Phillipscf39f372019-09-03 10:29:20 -0400341 size_t bytesUsed;
342
343 ctx->getResourceCacheUsage(nullptr, &bytesUsed);
344 REPORTER_ASSERT(reporter, bytesUsed > kMaxBytes);
345
Brian Salomon9bc76d92019-01-24 12:18:33 -0500346 // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are
347 // properly ordered.
348 canvas->drawImage(image, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500349 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500350 canvas->drawImage(image, 1, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500351 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500352 canvas->drawImage(image, 2, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500353 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500354 canvas->drawImage(image, 3, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500355 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500356 canvas->drawImage(image, 4, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500357 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500358 canvas->drawImage(image, 5, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500359 surface->flush();
Brian Salomon876a0172019-03-08 11:12:14 -0500360 // Must call these to ensure that all callbacks are performed before the checker is destroyed.
361 image.reset();
362 ctx->flush();
Robert Phillips9b16f812019-05-17 10:01:21 -0400363 ctx->priv().getGpu()->testingOnly_flushGpuAndSync();
Brian Salomon876a0172019-03-08 11:12:14 -0500364
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400365 ctx->deleteBackendTexture(backendTex);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500366}
Brian Salomond538d3d2019-04-04 12:18:17 -0400367
368// Test case where promise image fulfill returns nullptr.
369DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageNullFulfill, reporter, ctxInfo) {
370 const int kWidth = 10;
371 const int kHeight = 10;
372
373 GrContext* ctx = ctxInfo.grContext();
Brian Salomond538d3d2019-04-04 12:18:17 -0400374
375 // Do all this just to get a valid backend format for the image.
Greg Danielc1ad77c2020-05-06 11:40:03 -0400376 GrBackendTexture backendTex;
377 CreateBackendTexture(ctx, &backendTex, kWidth, kHeight, kRGBA_8888_SkColorType,
378 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes,
379 GrProtected::kNo);
Brian Salomond538d3d2019-04-04 12:18:17 -0400380 REPORTER_ASSERT(reporter, backendTex.isValid());
381 GrBackendFormat backendFormat = backendTex.getBackendFormat();
382 REPORTER_ASSERT(reporter, backendFormat.isValid());
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400383 ctx->deleteBackendTexture(backendTex);
Brian Salomond538d3d2019-04-04 12:18:17 -0400384
385 struct Counts {
386 int fFulfillCount = 0;
387 int fReleaseCount = 0;
388 int fDoneCount = 0;
389 } counts;
390 auto fulfill = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
391 ++static_cast<Counts*>(ctx)->fFulfillCount;
392 return sk_sp<SkPromiseImageTexture>();
393 };
394 auto release = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
395 ++static_cast<Counts*>(ctx)->fReleaseCount;
396 };
397 auto done = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
398 ++static_cast<Counts*>(ctx)->fDoneCount;
399 };
400 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
401 sk_sp<SkImage> refImg(SkImage_Gpu::MakePromiseTexture(
402 ctx, backendFormat, kWidth, kHeight, GrMipMapped::kNo, texOrigin,
403 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, fulfill, release, done, &counts,
404 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
405
406 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
407 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
408 SkCanvas* canvas = surface->getCanvas();
409 // Draw the image a few different ways.
410 canvas->drawImage(refImg, 0, 0);
411 SkPaint paint;
Mike Reedb286bc22019-04-08 16:23:20 -0400412 paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
Brian Salomond538d3d2019-04-04 12:18:17 -0400413 canvas->drawImage(refImg, 0, 0, &paint);
414 auto shader = refImg->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
415 REPORTER_ASSERT(reporter, shader);
416 paint.setShader(std::move(shader));
417 canvas->drawRect(SkRect::MakeWH(1,1), paint);
418 paint.setShader(nullptr);
419 refImg.reset();
420 surface->flush();
421 // We should only call each callback once and we should have made all the calls by this point.
422 REPORTER_ASSERT(reporter, counts.fFulfillCount == 1);
423 REPORTER_ASSERT(reporter, counts.fReleaseCount == 1);
424 REPORTER_ASSERT(reporter, counts.fDoneCount == 1);
425}