• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "SkExchange.h"
9 #include "Test.h"
10 
11 #include "GrBackendSurface.h"
12 #include "GrContextPriv.h"
13 #include "GrGpu.h"
14 #include "GrTexture.h"
15 #include "SkImage_Gpu.h"
16 #include "SkPromiseImageTexture.h"
17 
18 using namespace sk_gpu_test;
19 
20 struct PromiseTextureChecker {
21     // shared indicates whether the backend texture is used to fulfill more than one promise
22     // image.
PromiseTextureCheckerPromiseTextureChecker23     explicit PromiseTextureChecker(const GrBackendTexture& tex, skiatest::Reporter* reporter,
24                                    bool shared)
25             : fTexture(SkPromiseImageTexture::Make(tex))
26             , fReporter(reporter)
27             , fShared(shared)
28             , fFulfillCount(0)
29             , fReleaseCount(0)
30             , fDoneCount(0) {}
31     sk_sp<SkPromiseImageTexture> fTexture;
32     skiatest::Reporter* fReporter;
33     bool fShared;
34     int fFulfillCount;
35     int fReleaseCount;
36     int fDoneCount;
37     GrBackendTexture fLastFulfilledTexture;
38 
39     /**
40      * Replaces the backend texture that this checker will return from fulfill. Also, transfers
41      * ownership of the previous PromiseImageTexture to the caller, if they want to control when
42      * it is deleted. The default argument will remove the existing texture without installing a
43      * valid replacement.
44      */
replaceTexturePromiseTextureChecker45     sk_sp<const SkPromiseImageTexture> replaceTexture(
46             const GrBackendTexture& tex = GrBackendTexture()) {
47         return skstd::exchange(fTexture, SkPromiseImageTexture::Make(tex));
48     }
49 
uniqueKeysPromiseTextureChecker50     SkTArray<GrUniqueKey> uniqueKeys() const {
51         return fTexture->testingOnly_uniqueKeysToInvalidate();
52     }
53 
FulfillPromiseTextureChecker54     static sk_sp<SkPromiseImageTexture> Fulfill(void* self) {
55         auto checker = static_cast<PromiseTextureChecker*>(self);
56         checker->fFulfillCount++;
57         checker->fLastFulfilledTexture = checker->fTexture->backendTexture();
58         return checker->fTexture;
59     }
ReleasePromiseTextureChecker60     static void Release(void* self) {
61         auto checker = static_cast<PromiseTextureChecker*>(self);
62         checker->fReleaseCount++;
63         if (!checker->fShared) {
64             // This is only used in a single threaded fashion with a single promise image. So
65             // every fulfill should be balanced by a release before the next fulfill.
66             REPORTER_ASSERT(checker->fReporter, checker->fReleaseCount == checker->fFulfillCount);
67         }
68     }
DonePromiseTextureChecker69     static void Done(void* self) {
70         static_cast<PromiseTextureChecker*>(self)->fDoneCount++;
71     }
72 };
73 
74 enum class ReleaseBalanceExpecation {
75     kBalanced,
76     kBalancedOrPlusOne,
77     kAny
78 };
79 
check_fulfill_and_release_cnts(const PromiseTextureChecker & promiseChecker,ReleaseBalanceExpecation balanceExpecation,int expectedFulfillCnt,int expectedReleaseCnt,bool expectedRequired,int expectedDoneCnt,skiatest::Reporter * reporter)80 static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker,
81                                            ReleaseBalanceExpecation balanceExpecation,
82                                            int expectedFulfillCnt,
83                                            int expectedReleaseCnt,
84                                            bool expectedRequired,
85                                            int expectedDoneCnt,
86                                            skiatest::Reporter* reporter) {
87     bool result = true;
88     int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
89     // FulfillCount should always equal ReleaseCount or be at most one higher
90     if (countDiff != 0) {
91         if (balanceExpecation == ReleaseBalanceExpecation::kBalanced) {
92             result = false;
93             REPORTER_ASSERT(reporter, 0 == countDiff);
94         } else if (countDiff != 1 &&
95                    balanceExpecation == ReleaseBalanceExpecation::kBalancedOrPlusOne) {
96             result = false;
97             REPORTER_ASSERT(reporter, 0 == countDiff || 1 == countDiff);
98         } else if (countDiff < 0) {
99             result = false;
100             REPORTER_ASSERT(reporter, countDiff >= 0);
101         }
102     }
103 
104     int fulfillDiff = expectedFulfillCnt - promiseChecker.fFulfillCount;
105     REPORTER_ASSERT(reporter, fulfillDiff >= 0);
106     if (fulfillDiff != 0) {
107         if (expectedRequired) {
108             result = false;
109             REPORTER_ASSERT(reporter, expectedFulfillCnt == promiseChecker.fFulfillCount);
110         } else if (fulfillDiff > 1) {
111             result = false;
112             REPORTER_ASSERT(reporter, fulfillDiff <= 1);
113         }
114     }
115 
116     int releaseDiff = expectedReleaseCnt - promiseChecker.fReleaseCount;
117     REPORTER_ASSERT(reporter, releaseDiff >= 0);
118     if (releaseDiff != 0) {
119         if (expectedRequired) {
120             result = false;
121             REPORTER_ASSERT(reporter, expectedReleaseCnt == promiseChecker.fReleaseCount);
122         } else if (releaseDiff > 1) {
123             result = false;
124             REPORTER_ASSERT(reporter, releaseDiff <= 1);
125         }
126     }
127 
128     if (expectedDoneCnt != promiseChecker.fDoneCount) {
129         result = false;
130         REPORTER_ASSERT(reporter, expectedDoneCnt == promiseChecker.fDoneCount);
131     }
132 
133     return result;
134 }
135 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestNoDelayedRelease,reporter,ctxInfo)136 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestNoDelayedRelease, reporter, ctxInfo) {
137     const int kWidth = 10;
138     const int kHeight = 10;
139 
140     GrContext* ctx = ctxInfo.grContext();
141     GrGpu* gpu = ctx->contextPriv().getGpu();
142 
143     for (bool releaseImageEarly : {true, false}) {
144         GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
145                 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo);
146         REPORTER_ASSERT(reporter, backendTex.isValid());
147 
148         GrBackendFormat backendFormat = backendTex.getBackendFormat();
149         REPORTER_ASSERT(reporter, backendFormat.isValid());
150 
151         PromiseTextureChecker promiseChecker(backendTex, reporter, false);
152         GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
153         sk_sp<SkImage> refImg(
154                 SkImage_Gpu::MakePromiseTexture(
155                         ctx, backendFormat, kWidth, kHeight,
156                         GrMipMapped::kNo, texOrigin,
157                         kRGBA_8888_SkColorType, kPremul_SkAlphaType,
158                         nullptr,
159                         PromiseTextureChecker::Fulfill,
160                         PromiseTextureChecker::Release,
161                         PromiseTextureChecker::Done,
162                         &promiseChecker,
163                         SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
164 
165         SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
166         sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
167         SkCanvas* canvas = surface->getCanvas();
168 
169         int expectedFulfillCnt = 0;
170         int expectedReleaseCnt = 0;
171         int expectedDoneCnt = 0;
172         ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
173 
174         canvas->drawImage(refImg, 0, 0);
175         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
176                                                                  balanceExpecation,
177                                                                  expectedFulfillCnt,
178                                                                  expectedReleaseCnt,
179                                                                  true,
180                                                                  expectedDoneCnt,
181                                                                  reporter));
182 
183         bool isVulkan = GrBackendApi::kVulkan == ctx->backend();
184         canvas->flush();
185         expectedFulfillCnt++;
186         expectedReleaseCnt++;
187         if (isVulkan) {
188             balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
189         }
190         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
191                                                                  balanceExpecation,
192                                                                  expectedFulfillCnt,
193                                                                  expectedReleaseCnt,
194                                                                  !isVulkan,
195                                                                  expectedDoneCnt,
196                                                                  reporter));
197 
198         gpu->testingOnly_flushGpuAndSync();
199         balanceExpecation = ReleaseBalanceExpecation::kBalanced;
200         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
201                                                                  balanceExpecation,
202                                                                  expectedFulfillCnt,
203                                                                  expectedReleaseCnt,
204                                                                  true,
205                                                                  expectedDoneCnt,
206                                                                  reporter));
207 
208         canvas->drawImage(refImg, 0, 0);
209         canvas->drawImage(refImg, 0, 0);
210 
211         canvas->flush();
212         expectedFulfillCnt++;
213         expectedReleaseCnt++;
214 
215         gpu->testingOnly_flushGpuAndSync();
216         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
217                                                                  balanceExpecation,
218                                                                  expectedFulfillCnt,
219                                                                  expectedReleaseCnt,
220                                                                  true,
221                                                                  expectedDoneCnt,
222                                                                  reporter));
223 
224         // Now test code path on Vulkan where we released the texture, but the GPU isn't done with
225         // resource yet and we do another draw. We should only call fulfill on the first draw and
226         // use the cached GrBackendTexture on the second. Release should only be called after the
227         // second draw is finished.
228         canvas->drawImage(refImg, 0, 0);
229         canvas->flush();
230         expectedFulfillCnt++;
231         expectedReleaseCnt++;
232         if (isVulkan) {
233             balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
234         }
235         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
236                                                                  balanceExpecation,
237                                                                  expectedFulfillCnt,
238                                                                  expectedReleaseCnt,
239                                                                  !isVulkan,
240                                                                  expectedDoneCnt,
241                                                                  reporter));
242 
243         canvas->drawImage(refImg, 0, 0);
244 
245         if (releaseImageEarly) {
246             refImg.reset();
247         }
248 
249         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
250                                                                  balanceExpecation,
251                                                                  expectedFulfillCnt,
252                                                                  expectedReleaseCnt,
253                                                                  !isVulkan,
254                                                                  expectedDoneCnt,
255                                                                  reporter));
256 
257         canvas->flush();
258         expectedFulfillCnt++;
259 
260         gpu->testingOnly_flushGpuAndSync();
261         expectedReleaseCnt++;
262         if (releaseImageEarly) {
263             expectedDoneCnt++;
264         }
265         balanceExpecation = ReleaseBalanceExpecation::kBalanced;
266         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
267                                                                  balanceExpecation,
268                                                                  expectedFulfillCnt,
269                                                                  expectedReleaseCnt,
270                                                                  !isVulkan,
271                                                                  expectedDoneCnt,
272                                                                  reporter));
273         expectedFulfillCnt = promiseChecker.fFulfillCount;
274         expectedReleaseCnt = promiseChecker.fReleaseCount;
275 
276         if (!releaseImageEarly) {
277             refImg.reset();
278             expectedDoneCnt++;
279         }
280 
281         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
282                                                                  balanceExpecation,
283                                                                  expectedFulfillCnt,
284                                                                  expectedReleaseCnt,
285                                                                  true,
286                                                                  expectedDoneCnt,
287                                                                  reporter));
288 
289         gpu->deleteTestingOnlyBackendTexture(backendTex);
290     }
291 }
292 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestDelayedRelease,reporter,ctxInfo)293 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestDelayedRelease, reporter, ctxInfo) {
294     const int kWidth = 10;
295     const int kHeight = 10;
296 
297     GrContext* ctx = ctxInfo.grContext();
298     GrGpu* gpu = ctx->contextPriv().getGpu();
299 
300     GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
301             nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo);
302     REPORTER_ASSERT(reporter, backendTex.isValid());
303 
304     GrBackendFormat backendFormat = backendTex.getBackendFormat();
305     REPORTER_ASSERT(reporter, backendFormat.isValid());
306 
307     PromiseTextureChecker promiseChecker(backendTex, reporter, false);
308     GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
309     sk_sp<SkImage> refImg(
310             SkImage_Gpu::MakePromiseTexture(
311                     ctx, backendFormat, kWidth, kHeight,
312                     GrMipMapped::kNo, texOrigin,
313                     kRGBA_8888_SkColorType, kPremul_SkAlphaType,
314                     nullptr,
315                     PromiseTextureChecker::Fulfill,
316                     PromiseTextureChecker::Release,
317                     PromiseTextureChecker::Done,
318                     &promiseChecker,
319                     SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes));
320 
321     SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
322     sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
323     SkCanvas* canvas = surface->getCanvas();
324 
325     int expectedFulfillCnt = 0;
326     int expectedReleaseCnt = 0;
327     int expectedDoneCnt = 0;
328     ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
329 
330     canvas->drawImage(refImg, 0, 0);
331     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
332                                                              balanceExpecation,
333                                                              expectedFulfillCnt,
334                                                              expectedReleaseCnt,
335                                                              true,
336                                                              expectedDoneCnt,
337                                                              reporter));
338 
339     bool isVulkan = GrBackendApi::kVulkan == ctx->backend();
340     canvas->flush();
341     expectedFulfillCnt++;
342     // Because we've delayed release, we expect a +1 balance.
343     balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
344     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
345                                                              balanceExpecation,
346                                                              expectedFulfillCnt,
347                                                              expectedReleaseCnt,
348                                                              !isVulkan,
349                                                              expectedDoneCnt,
350                                                              reporter));
351 
352     gpu->testingOnly_flushGpuAndSync();
353     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
354                                                              balanceExpecation,
355                                                              expectedFulfillCnt,
356                                                              expectedReleaseCnt,
357                                                              true,
358                                                              expectedDoneCnt,
359                                                              reporter));
360 
361     canvas->drawImage(refImg, 0, 0);
362     canvas->drawImage(refImg, 0, 0);
363 
364     canvas->flush();
365 
366     gpu->testingOnly_flushGpuAndSync();
367     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
368                                                              balanceExpecation,
369                                                              expectedFulfillCnt,
370                                                              expectedReleaseCnt,
371                                                              true,
372                                                              expectedDoneCnt,
373                                                              reporter));
374 
375     canvas->drawImage(refImg, 0, 0);
376     canvas->flush();
377     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
378                                                              balanceExpecation,
379                                                              expectedFulfillCnt,
380                                                              expectedReleaseCnt,
381                                                              !isVulkan,
382                                                              expectedDoneCnt,
383                                                              reporter));
384 
385     canvas->drawImage(refImg, 0, 0);
386 
387     refImg.reset();
388 
389     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
390                                                              balanceExpecation,
391                                                              expectedFulfillCnt,
392                                                              expectedReleaseCnt,
393                                                              !isVulkan,
394                                                              expectedDoneCnt,
395                                                              reporter));
396 
397     canvas->flush();
398     gpu->testingOnly_flushGpuAndSync();
399     // We released the image already and we flushed and synced.
400     balanceExpecation = ReleaseBalanceExpecation::kBalanced;
401     expectedReleaseCnt++;
402     expectedDoneCnt++;
403     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
404                                                              balanceExpecation,
405                                                              expectedFulfillCnt,
406                                                              expectedReleaseCnt,
407                                                              !isVulkan,
408                                                              expectedDoneCnt,
409                                                              reporter));
410 
411     gpu->deleteTestingOnlyBackendTexture(backendTex);
412 }
413 
414 // Tests replacing the backing texture for a promise image after a release and then refulfilling in
415 // the SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo case.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse,reporter,ctxInfo)416 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo) {
417     const int kWidth = 10;
418     const int kHeight = 10;
419 
420     GrContext* ctx = ctxInfo.grContext();
421     GrGpu* gpu = ctx->contextPriv().getGpu();
422 
423     GrBackendTexture backendTex1 = gpu->createTestingOnlyBackendTexture(
424             nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, false, GrMipMapped::kNo);
425     GrBackendTexture backendTex2 = gpu->createTestingOnlyBackendTexture(
426             nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, false, GrMipMapped::kNo);
427     GrBackendTexture backendTex3 = gpu->createTestingOnlyBackendTexture(
428             nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, false, GrMipMapped::kNo);
429     REPORTER_ASSERT(reporter, backendTex1.isValid());
430     REPORTER_ASSERT(reporter, backendTex2.isValid());
431     REPORTER_ASSERT(reporter, backendTex3.isValid());
432 
433     GrBackendFormat backendFormat = backendTex1.getBackendFormat();
434     REPORTER_ASSERT(reporter, backendFormat.isValid());
435     REPORTER_ASSERT(reporter, backendFormat == backendTex2.getBackendFormat());
436     REPORTER_ASSERT(reporter, backendFormat == backendTex3.getBackendFormat());
437 
438     PromiseTextureChecker promiseChecker(backendTex1, reporter, true);
439     GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
440     sk_sp<SkImage> refImg(
441             SkImage_Gpu::MakePromiseTexture(
442                     ctx, backendFormat, kWidth, kHeight,
443                     GrMipMapped::kNo, texOrigin,
444                     kRGBA_8888_SkColorType, kPremul_SkAlphaType,
445                     nullptr,
446                     PromiseTextureChecker::Fulfill,
447                     PromiseTextureChecker::Release,
448                     PromiseTextureChecker::Done,
449                     &promiseChecker,
450                     SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
451 
452     SkImageInfo info =
453             SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
454     sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
455     SkCanvas* canvas = surface->getCanvas();
456 
457     int expectedFulfillCnt = 0;
458     int expectedReleaseCnt = 0;
459     int expectedDoneCnt = 0;
460 
461     canvas->drawImage(refImg, 0, 0);
462     canvas->drawImage(refImg, 5, 5);
463     ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
464     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
465                                                              balanceExpecation,
466                                                              expectedFulfillCnt,
467                                                              expectedReleaseCnt,
468                                                              true,
469                                                              expectedDoneCnt,
470                                                              reporter));
471 
472     bool isVulkan = GrBackendApi::kVulkan == ctx->backend();
473     canvas->flush();
474     expectedFulfillCnt++;
475     expectedReleaseCnt++;
476     if (isVulkan) {
477         balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
478     }
479     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
480                                                              balanceExpecation,
481                                                              expectedFulfillCnt,
482                                                              expectedReleaseCnt,
483                                                              !isVulkan,
484                                                              expectedDoneCnt,
485                                                              reporter));
486     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(
487                                       promiseChecker.fLastFulfilledTexture, backendTex1));
488     // We should have put a GrTexture for this fulfillment into the cache.
489     auto keys = promiseChecker.uniqueKeys();
490     REPORTER_ASSERT(reporter, keys.count() == 1);
491     GrUniqueKey texKey1;
492     if (keys.count()) {
493         texKey1 = keys[0];
494     }
495     REPORTER_ASSERT(reporter, texKey1.isValid());
496     REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey1));
497 
498     gpu->testingOnly_flushGpuAndSync();
499     balanceExpecation = ReleaseBalanceExpecation::kBalanced;
500     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
501                                                              balanceExpecation,
502                                                              expectedFulfillCnt,
503                                                              expectedReleaseCnt,
504                                                              true,
505                                                              expectedDoneCnt,
506                                                              reporter));
507     REPORTER_ASSERT(reporter,
508                     GrBackendTexture::TestingOnly_Equals(
509                             promiseChecker.replaceTexture()->backendTexture(), backendTex1));
510     gpu->deleteTestingOnlyBackendTexture(backendTex1);
511 
512     ctx->contextPriv().getResourceCache()->purgeAsNeeded();
513     // We should have invalidated the key on the previously cached texture (after ensuring
514     // invalidation messages have been processed by calling purgeAsNeeded.)
515     REPORTER_ASSERT(reporter, !ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey1));
516 
517     promiseChecker.replaceTexture(backendTex2);
518 
519     canvas->drawImage(refImg, 0, 0);
520     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
521                                                              balanceExpecation,
522                                                              expectedFulfillCnt,
523                                                              expectedReleaseCnt,
524                                                              true,
525                                                              expectedDoneCnt,
526                                                              reporter));
527 
528     canvas->flush();
529     expectedFulfillCnt++;
530     expectedReleaseCnt++;
531     if (isVulkan) {
532         balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne;
533     }
534     // Second texture should be in the cache.
535     keys = promiseChecker.uniqueKeys();
536     REPORTER_ASSERT(reporter, keys.count() == 1);
537     GrUniqueKey texKey2;
538     if (keys.count()) {
539         texKey2 = keys[0];
540     }
541     REPORTER_ASSERT(reporter, texKey2.isValid() && texKey2 != texKey1);
542     REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2));
543 
544     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
545                                                              balanceExpecation,
546                                                              expectedFulfillCnt,
547                                                              expectedReleaseCnt,
548                                                              !isVulkan,
549                                                              expectedDoneCnt,
550                                                              reporter));
551     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(
552                                       promiseChecker.fLastFulfilledTexture, backendTex2));
553 
554     gpu->testingOnly_flushGpuAndSync();
555     balanceExpecation = ReleaseBalanceExpecation::kBalanced;
556     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
557                                                              balanceExpecation,
558                                                              expectedFulfillCnt,
559                                                              expectedReleaseCnt,
560                                                              true,
561                                                              expectedDoneCnt,
562                                                              reporter));
563 
564     // Because we have kept the SkPromiseImageTexture alive, we should be able to use it again and
565     // hit the cache.
566     ctx->contextPriv().getResourceCache()->purgeAsNeeded();
567     REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2));
568 
569     canvas->drawImage(refImg, 0, 0);
570 
571     canvas->flush();
572     gpu->testingOnly_flushGpuAndSync();
573     expectedFulfillCnt++;
574     expectedReleaseCnt++;
575     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
576                                                              balanceExpecation,
577                                                              expectedFulfillCnt,
578                                                              expectedReleaseCnt,
579                                                              true,
580                                                              expectedDoneCnt,
581                                                              reporter));
582 
583     // Make sure we didn't add another key and that the second texture is still alive in the cache.
584     keys = promiseChecker.uniqueKeys();
585     REPORTER_ASSERT(reporter, keys.count() == 1);
586     if (keys.count()) {
587         REPORTER_ASSERT(reporter, texKey2 == keys[0]);
588     }
589     ctx->contextPriv().getResourceCache()->purgeAsNeeded();
590     REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2));
591 
592     // Now we test keeping tex2 alive but fulfilling with a new texture.
593     sk_sp<const SkPromiseImageTexture> promiseImageTexture2 =
594             promiseChecker.replaceTexture(backendTex3);
595     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(
596                                       promiseImageTexture2->backendTexture(), backendTex2));
597 
598     canvas->drawImage(refImg, 0, 0);
599 
600     canvas->flush();
601     gpu->testingOnly_flushGpuAndSync();
602     expectedFulfillCnt++;
603     expectedReleaseCnt++;
604     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
605                                                              balanceExpecation,
606                                                              expectedFulfillCnt,
607                                                              expectedReleaseCnt,
608                                                              true,
609                                                              expectedDoneCnt,
610                                                              reporter));
611 
612     keys = promiseChecker.uniqueKeys();
613     REPORTER_ASSERT(reporter, keys.count() == 1);
614     GrUniqueKey texKey3;
615     if (keys.count()) {
616         texKey3 = keys[0];
617     }
618     ctx->contextPriv().getResourceCache()->purgeAsNeeded();
619     REPORTER_ASSERT(reporter, !ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2));
620     REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey3));
621     gpu->deleteTestingOnlyBackendTexture(promiseImageTexture2->backendTexture());
622 
623     // Make a new promise image also backed by texture 3.
624     sk_sp<SkImage> refImg2(
625             SkImage_Gpu::MakePromiseTexture(
626                     ctx, backendFormat, kWidth, kHeight,
627                     GrMipMapped::kNo, texOrigin,
628                     kRGBA_8888_SkColorType, kPremul_SkAlphaType,
629                     nullptr,
630                     PromiseTextureChecker::Fulfill,
631                     PromiseTextureChecker::Release,
632                     PromiseTextureChecker::Done,
633                     &promiseChecker,
634                     SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
635     canvas->drawImage(refImg, 0, 0);
636     canvas->drawImage(refImg2, 1, 1);
637 
638     canvas->flush();
639     gpu->testingOnly_flushGpuAndSync();
640     expectedFulfillCnt += 2;
641     expectedReleaseCnt += 2;
642     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
643                                                              balanceExpecation,
644                                                              expectedFulfillCnt,
645                                                              expectedReleaseCnt,
646                                                              true,
647                                                              expectedDoneCnt,
648                                                              reporter));
649 
650     // The two images should share a single GrTexture by using the same key. The key is only
651     // dependent on the pixel config and the PromiseImageTexture key.
652     keys = promiseChecker.uniqueKeys();
653     REPORTER_ASSERT(reporter, keys.count() == 1);
654     if (keys.count() > 0) {
655         REPORTER_ASSERT(reporter, texKey3 == keys[0]);
656     }
657     ctx->contextPriv().getResourceCache()->purgeAsNeeded();
658 
659     // If we delete the SkPromiseImageTexture we should trigger both key removals.
660     REPORTER_ASSERT(reporter,
661                     GrBackendTexture::TestingOnly_Equals(
662                             promiseChecker.replaceTexture()->backendTexture(), backendTex3));
663 
664     ctx->contextPriv().getResourceCache()->purgeAsNeeded();
665     REPORTER_ASSERT(reporter, !ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey3));
666     gpu->deleteTestingOnlyBackendTexture(backendTex3);
667 
668     // After deleting each image we should get a done call.
669     refImg.reset();
670     ++expectedDoneCnt;
671     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
672                                                              balanceExpecation,
673                                                              expectedFulfillCnt,
674                                                              expectedReleaseCnt,
675                                                              true,
676                                                              expectedDoneCnt,
677                                                              reporter));
678     refImg2.reset();
679     ++expectedDoneCnt;
680     REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
681                                                              balanceExpecation,
682                                                              expectedFulfillCnt,
683                                                              expectedReleaseCnt,
684                                                              true,
685                                                              expectedDoneCnt,
686                                                              reporter));
687 }
688 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig,reporter,ctxInfo)689 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, reporter, ctxInfo) {
690     // Try making two promise SkImages backed by the same texture but with different configs.
691     // This will only be testable on backends where a single texture format (8bit red unorm) can
692     // be used for alpha and gray image color types.
693 
694     const int kWidth = 10;
695     const int kHeight = 10;
696 
697     GrContext* ctx = ctxInfo.grContext();
698     GrGpu* gpu = ctx->contextPriv().getGpu();
699 
700     GrBackendTexture backendTex1 = gpu->createTestingOnlyBackendTexture(
701             nullptr, kWidth, kHeight, GrColorType::kGray_8, false, GrMipMapped::kNo);
702     REPORTER_ASSERT(reporter, backendTex1.isValid());
703 
704     GrBackendTexture backendTex2 = gpu->createTestingOnlyBackendTexture(
705             nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo);
706     REPORTER_ASSERT(reporter, backendTex2.isValid());
707     if (backendTex1.getBackendFormat() != backendTex2.getBackendFormat()) {
708         gpu->deleteTestingOnlyBackendTexture(backendTex1);
709         return;
710     }
711     // We only needed this texture to check that alpha and gray color types use the same format.
712     gpu->deleteTestingOnlyBackendTexture(backendTex2);
713 
714     SkImageInfo info =
715             SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
716     sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
717     SkCanvas* canvas = surface->getCanvas();
718 
719     for (auto delayRelease : {SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo,
720                               SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes}) {
721         PromiseTextureChecker promiseChecker(backendTex1, reporter, true);
722         sk_sp<SkImage> alphaImg(SkImage_Gpu::MakePromiseTexture(
723                 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
724                 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
725                 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
726                 PromiseTextureChecker::Done, &promiseChecker, delayRelease));
727         REPORTER_ASSERT(reporter, alphaImg);
728 
729         sk_sp<SkImage> grayImg(SkImage_Gpu::MakePromiseTexture(
730                 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
731                 kBottomLeft_GrSurfaceOrigin, kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr,
732                 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
733                 PromiseTextureChecker::Done, &promiseChecker, delayRelease));
734         REPORTER_ASSERT(reporter, grayImg);
735 
736         canvas->drawImage(alphaImg, 0, 0);
737         canvas->drawImage(grayImg, 1, 1);
738         canvas->flush();
739         gpu->testingOnly_flushGpuAndSync();
740 
741         int expectedFulfillCnt = 2;
742         int expectedReleaseCnt = 0;
743         int expectedDoneCnt = 0;
744         ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kAny;
745         if (delayRelease == SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo) {
746             expectedReleaseCnt = 2;
747             balanceExpecation = ReleaseBalanceExpecation::kBalanced;
748         }
749         REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
750                                                                  balanceExpecation,
751                                                                  expectedFulfillCnt,
752                                                                  expectedReleaseCnt,
753                                                                  true,
754                                                                  expectedDoneCnt,
755                                                                  reporter));
756 
757         // Because they use different configs, each image should have created a different GrTexture
758         // and they both should still be cached.
759         ctx->contextPriv().getResourceCache()->purgeAsNeeded();
760 
761         auto keys = promiseChecker.uniqueKeys();
762         REPORTER_ASSERT(reporter, keys.count() == 2);
763         for (const auto& key : keys) {
764             auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key);
765             REPORTER_ASSERT(reporter, surf && surf->asTexture());
766             if (surf && surf->asTexture()) {
767                 REPORTER_ASSERT(reporter,
768                                 !GrBackendTexture::TestingOnly_Equals(
769                                         backendTex1, surf->asTexture()->getBackendTexture()));
770             }
771         }
772 
773         // Change the backing texture, this should invalidate the keys.
774         promiseChecker.replaceTexture();
775         ctx->contextPriv().getResourceCache()->purgeAsNeeded();
776 
777         for (const auto& key : keys) {
778             auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key);
779             REPORTER_ASSERT(reporter, !surf);
780         }
781     }
782     gpu->deleteTestingOnlyBackendTexture(backendTex1);
783 }
784 
DEF_GPUTEST(PromiseImageTextureShutdown,reporter,ctxInfo)785 DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
786     const int kWidth = 10;
787     const int kHeight = 10;
788 
789     // Different ways of killing contexts.
790     using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrContext*)>;
791     DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
792         factory->destroyContexts();
793     };
794     DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
795         context->abandonContext();
796     };
797     DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory,
798                                             GrContext* context) {
799         context->releaseResourcesAndAbandonContext();
800     };
801 
802     for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
803         auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
804         // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
805         // and http://skbug.com/8275
806         GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
807         if (api == GrBackendApi::kVulkan) {
808             continue;
809         }
810         DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon};
811         for (auto contextDeath : contextKillers) {
812             sk_gpu_test::GrContextFactory factory;
813             auto ctx = factory.get(contextType);
814             if (!ctx) {
815                 continue;
816             }
817             GrGpu* gpu = ctx->contextPriv().getGpu();
818 
819             GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
820                     nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo);
821             REPORTER_ASSERT(reporter, backendTex.isValid());
822 
823             SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
824                                                  kPremul_SkAlphaType);
825             sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
826             SkCanvas* canvas = surface->getCanvas();
827 
828             PromiseTextureChecker promiseChecker(backendTex, reporter, false);
829             sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
830                     ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
831                     kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
832                     PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
833                     PromiseTextureChecker::Done, &promiseChecker,
834                     SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
835             REPORTER_ASSERT(reporter, image);
836 
837             canvas->drawImage(image, 0, 0);
838             image.reset();
839             // If the surface still holds a ref to the context then the factory will not be able
840             // to destroy the context (and instead will release-all-and-abandon).
841             surface.reset();
842 
843             ctx->flush();
844             contextDeath(&factory, ctx);
845 
846             int expectedFulfillCnt = 1;
847             int expectedReleaseCnt = 1;
848             int expectedDoneCnt = 1;
849             ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced;
850             REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
851                                                                      balanceExpecation,
852                                                                      expectedFulfillCnt,
853                                                                      expectedReleaseCnt,
854                                                                      true,
855                                                                      expectedDoneCnt,
856                                                                      reporter));
857         }
858     }
859 }
860 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache,reporter,ctxInfo)861 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) {
862     const int kWidth = 10;
863     const int kHeight = 10;
864 
865     GrContext* ctx = ctxInfo.grContext();
866     GrGpu* gpu = ctx->contextPriv().getGpu();
867 
868     GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
869             nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo);
870     REPORTER_ASSERT(reporter, backendTex.isValid());
871 
872     SkImageInfo info =
873             SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
874     sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
875     SkCanvas* canvas = surface->getCanvas();
876 
877     PromiseTextureChecker promiseChecker(backendTex, reporter, false);
878     sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
879             ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
880             kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
881             PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
882             PromiseTextureChecker::Done, &promiseChecker,
883             SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo));
884     REPORTER_ASSERT(reporter, image);
885 
886     // Make the cache full. This tests that we don't preemptively purge cached textures for
887     // fulfillment due to cache pressure.
888     static constexpr int kMaxResources = 10;
889     static constexpr int kMaxBytes = 100;
890     ctx->setResourceCacheLimits(kMaxResources, kMaxBytes);
891     sk_sp<GrTexture> textures[2 * kMaxResources];
892     for (int i = 0; i < 2 * kMaxResources; ++i) {
893         GrSurfaceDesc desc;
894         desc.fConfig = kRGBA_8888_GrPixelConfig;
895         desc.fWidth = desc.fHeight = 100;
896         textures[i] = ctx->contextPriv().resourceProvider()->createTexture(desc, SkBudgeted::kYes);
897         REPORTER_ASSERT(reporter, textures[i]);
898     }
899 
900     // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are
901     // properly ordered.
902     canvas->drawImage(image, 0, 0);
903     canvas->flush();
904     canvas->drawImage(image, 1, 0);
905     canvas->flush();
906     canvas->drawImage(image, 2, 0);
907     canvas->flush();
908     canvas->drawImage(image, 3, 0);
909     canvas->flush();
910     canvas->drawImage(image, 4, 0);
911     canvas->flush();
912     canvas->drawImage(image, 5, 0);
913     canvas->flush();
914     // Must call this to ensure that all callbacks are performed before the checker is destroyed.
915     gpu->testingOnly_flushGpuAndSync();
916     gpu->deleteTestingOnlyBackendTexture(backendTex);
917 }
918