1 /*
2  * Copyright 2022 Google LLC
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 "include/gpu/graphite/BackendTexture.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkSurface.h"
14 #include "include/gpu/graphite/Context.h"
15 #include "include/gpu/graphite/Recording.h"
16 #include "src/gpu/graphite/Caps.h"
17 #include "src/gpu/graphite/ContextPriv.h"
18 #include "src/gpu/graphite/RecordingPriv.h"
19 #include "tests/Test.h"
20 
21 using namespace skgpu::graphite;
22 
23 namespace {
24 
25 struct PromiseTextureChecker {
26     PromiseTextureChecker() = default;
27 
PromiseTextureChecker__anonfa97a8590111::PromiseTextureChecker28     explicit PromiseTextureChecker(const BackendTexture& backendTex,
29                                    skiatest::Reporter* reporter)
30             : fReporter(reporter) {
31         fBackendTextures[0] = backendTex;
32     }
33 
PromiseTextureChecker__anonfa97a8590111::PromiseTextureChecker34     explicit PromiseTextureChecker(const BackendTexture& backendTex0,
35                                    const BackendTexture& backendTex1,
36                                    skiatest::Reporter* reporter)
37             : fReporter(reporter)
38             , fHasTwoBackendTextures(true) {
39         fBackendTextures[0] = backendTex0;
40         fBackendTextures[1] = backendTex1;
41     }
42 
checkImageReleased__anonfa97a8590111::PromiseTextureChecker43     void checkImageReleased(skiatest::Reporter* reporter, int expectedReleaseCnt) {
44         REPORTER_ASSERT(reporter, expectedReleaseCnt == fImageReleaseCount);
45     }
46 
totalReleaseCount__anonfa97a8590111::PromiseTextureChecker47     int totalReleaseCount() const { return fTextureReleaseCounts[0] + fTextureReleaseCounts[1]; }
48 
49     skiatest::Reporter* fReporter = nullptr;
50     bool fHasTwoBackendTextures = false;
51     BackendTexture fBackendTextures[2];
52     int fFulfillCount = 0;
53     int fImageReleaseCount = 0;
54     int fTextureReleaseCounts[2] = { 0, 0 };
55 
Fulfill__anonfa97a8590111::PromiseTextureChecker56     static std::tuple<BackendTexture, void*> Fulfill(void* self) {
57         auto checker = reinterpret_cast<PromiseTextureChecker*>(self);
58 
59         checker->fFulfillCount++;
60 
61         if (checker->fHasTwoBackendTextures) {
62             int whichToUse = checker->fFulfillCount % 2;
63             return { checker->fBackendTextures[whichToUse],
64                      &checker->fTextureReleaseCounts[whichToUse] };
65         } else {
66             return { checker->fBackendTextures[0], &checker->fTextureReleaseCounts[0] };
67         }
68     }
69 
ImageRelease__anonfa97a8590111::PromiseTextureChecker70     static void ImageRelease(void* self) {
71         auto checker = reinterpret_cast<PromiseTextureChecker*>(self);
72 
73         checker->fImageReleaseCount++;
74     }
75 
TextureRelease__anonfa97a8590111::PromiseTextureChecker76     static void TextureRelease(void* context) {
77         int* releaseCount = reinterpret_cast<int*>(context);
78 
79         (*releaseCount)++;
80     }
81 };
82 
83 enum class ReleaseBalanceExpectation {
84     kBalanced,
85     kOffByOne,     // fulfill calls ahead of release calls by 1
86     kOffByTwo,     // fulfill calls ahead of release calls by 2
87     kFulfillsOnly, // 'n' fulfill calls, 0 release calls
88 };
89 
check_fulfill_and_release_cnts(skiatest::Reporter * reporter,const PromiseTextureChecker & promiseChecker,int expectedFulfillCnt,ReleaseBalanceExpectation releaseBalanceExpectation)90 void check_fulfill_and_release_cnts(skiatest::Reporter* reporter,
91                                     const PromiseTextureChecker& promiseChecker,
92                                     int expectedFulfillCnt,
93                                     ReleaseBalanceExpectation releaseBalanceExpectation) {
94     SkASSERT(promiseChecker.fFulfillCount == expectedFulfillCnt);
95     REPORTER_ASSERT(reporter, promiseChecker.fFulfillCount == expectedFulfillCnt);
96     if (!expectedFulfillCnt) {
97         // Release should only ever be called after Fulfill.
98         REPORTER_ASSERT(reporter, !promiseChecker.fImageReleaseCount);
99         REPORTER_ASSERT(reporter, !promiseChecker.totalReleaseCount());
100         return;
101     }
102 
103     int releaseDiff = promiseChecker.fFulfillCount - promiseChecker.totalReleaseCount();
104     switch (releaseBalanceExpectation) {
105         case ReleaseBalanceExpectation::kBalanced:
106             SkASSERT(!releaseDiff);
107             REPORTER_ASSERT(reporter, !releaseDiff);
108             break;
109         case ReleaseBalanceExpectation::kOffByOne:
110             SkASSERT(releaseDiff == 1);
111             REPORTER_ASSERT(reporter, releaseDiff == 1);
112             break;
113         case ReleaseBalanceExpectation::kOffByTwo:
114             SkASSERT(releaseDiff == 2);
115             REPORTER_ASSERT(reporter, releaseDiff == 2);
116             break;
117         case ReleaseBalanceExpectation::kFulfillsOnly:
118             REPORTER_ASSERT(reporter, promiseChecker.totalReleaseCount() == 0);
119             break;
120     }
121 }
122 
check_unfulfilled(const PromiseTextureChecker & promiseChecker,skiatest::Reporter * reporter)123 void check_unfulfilled(const PromiseTextureChecker& promiseChecker,
124                        skiatest::Reporter* reporter) {
125     check_fulfill_and_release_cnts(reporter, promiseChecker, /* expectedFulfillCnt= */ 0,
126                                    ReleaseBalanceExpectation::kBalanced);
127 }
128 
check_fulfilled_ahead_by_one(skiatest::Reporter * reporter,const PromiseTextureChecker & promiseChecker,int expectedFulfillCnt)129 void check_fulfilled_ahead_by_one(skiatest::Reporter* reporter,
130                                   const PromiseTextureChecker& promiseChecker,
131                                   int expectedFulfillCnt) {
132     check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
133                                    ReleaseBalanceExpectation::kOffByOne);
134 }
135 
check_fulfilled_ahead_by_two(skiatest::Reporter * reporter,const PromiseTextureChecker & promiseChecker,int expectedFulfillCnt)136 void check_fulfilled_ahead_by_two(skiatest::Reporter* reporter,
137                                   const PromiseTextureChecker& promiseChecker,
138                                   int expectedFulfillCnt) {
139     check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
140                                    ReleaseBalanceExpectation::kOffByTwo);
141 }
142 
check_all_done(skiatest::Reporter * reporter,const PromiseTextureChecker & promiseChecker,int expectedFulfillCnt)143 void check_all_done(skiatest::Reporter* reporter,
144                     const PromiseTextureChecker& promiseChecker,
145                     int expectedFulfillCnt) {
146     check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
147                                    ReleaseBalanceExpectation::kBalanced);
148 }
149 
check_fulfills_only(skiatest::Reporter * reporter,const PromiseTextureChecker & promiseChecker,int expectedFulfillCnt)150 void check_fulfills_only(skiatest::Reporter* reporter,
151                          const PromiseTextureChecker& promiseChecker,
152                          int expectedFulfillCnt) {
153     check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
154                                    ReleaseBalanceExpectation::kFulfillsOnly);
155 }
156 
157 struct TestCtx {
TestCtx__anonfa97a8590111::TestCtx158     TestCtx() {}
159 
~TestCtx__anonfa97a8590111::TestCtx160     ~TestCtx() {
161         for (int i = 0; i < 2; ++i) {
162             if (fBackendTextures[i].isValid()) {
163                 fContext->deleteBackendTexture(fBackendTextures[i]);
164             }
165         }
166     }
167 
168     Context* fContext;
169     std::unique_ptr<Recorder> fRecorder;
170     BackendTexture fBackendTextures[2];
171     PromiseTextureChecker fPromiseChecker;
172     sk_sp<SkImage> fImg;
173     sk_sp<SkSurface> fSurface;
174 };
175 
setup_test_context(Context * context,skiatest::Reporter * reporter,TestCtx * testCtx,SkISize dimensions,Volatile isVolatile,bool invalidBackendTex)176 void setup_test_context(Context* context,
177                         skiatest::Reporter* reporter,
178                         TestCtx* testCtx,
179                         SkISize dimensions,
180                         Volatile isVolatile,
181                         bool invalidBackendTex) {
182     testCtx->fContext = context;
183 
184     const Caps* caps = context->priv().caps();
185     testCtx->fRecorder = context->makeRecorder();
186 
187     TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(kRGBA_8888_SkColorType,
188                                                                  skgpu::Mipmapped::kNo,
189                                                                  skgpu::Protected::kNo,
190                                                                  Renderable::kYes);
191 
192     if (invalidBackendTex) {
193         // Having invalid backend textures will invalidate all the fulfill calls
194         REPORTER_ASSERT(reporter, !testCtx->fBackendTextures[0].isValid());
195         REPORTER_ASSERT(reporter, !testCtx->fBackendTextures[1].isValid());
196     } else {
197         testCtx->fBackendTextures[0] = testCtx->fRecorder->createBackendTexture(dimensions,
198                                                                                 textureInfo);
199         REPORTER_ASSERT(reporter, testCtx->fBackendTextures[0].isValid());
200 
201         if (isVolatile == Volatile::kYes) {
202             testCtx->fBackendTextures[1] = testCtx->fRecorder->createBackendTexture(dimensions,
203                                                                                     textureInfo);
204             REPORTER_ASSERT(reporter, testCtx->fBackendTextures[1].isValid());
205         }
206     }
207 
208     if (isVolatile == Volatile::kYes) {
209         testCtx->fPromiseChecker = PromiseTextureChecker(testCtx->fBackendTextures[0],
210                                                          testCtx->fBackendTextures[1],
211                                                          reporter);
212     } else {
213         testCtx->fPromiseChecker = PromiseTextureChecker(testCtx->fBackendTextures[0],
214                                                          reporter);
215     }
216 
217     SkImageInfo ii = SkImageInfo::Make(dimensions.fWidth,
218                                        dimensions.fHeight,
219                                        kRGBA_8888_SkColorType,
220                                        kPremul_SkAlphaType);
221 
222     testCtx->fImg = SkImage::MakeGraphitePromiseTexture(testCtx->fRecorder.get(),
223                                                         dimensions,
224                                                         textureInfo,
225                                                         ii.colorInfo(),
226                                                         isVolatile,
227                                                         PromiseTextureChecker::Fulfill,
228                                                         PromiseTextureChecker::ImageRelease,
229                                                         PromiseTextureChecker::TextureRelease,
230                                                         &testCtx->fPromiseChecker);
231 
232     testCtx->fSurface = SkSurface::MakeGraphite(testCtx->fRecorder.get(), ii);
233 }
234 
235 } // anonymous namespace
236 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageTest,reporter,context)237 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageTest,
238                                          reporter,
239                                          context) {
240     constexpr SkISize kDimensions { 16, 16 };
241 
242     TestCtx testContext;
243     setup_test_context(context, reporter, &testContext,
244                        kDimensions, Volatile::kNo, /* invalidBackendTex= */ false);
245 
246     {
247         SkCanvas* canvas = testContext.fSurface->getCanvas();
248 
249         canvas->drawImage(testContext.fImg, 0, 0);
250         check_unfulfilled(testContext.fPromiseChecker, reporter);
251 
252         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
253         check_unfulfilled(testContext.fPromiseChecker, reporter); // NVPIs not fulfilled at snap
254 
255         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
256         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
257                                      /* expectedFulfillCnt= */ 1); // NVPIs fulfilled at insert
258     }
259 
260     context->submit(SyncToCpu::kNo);
261     // testContext.fImg still has a ref so we should not have called TextureRelease.
262     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
263                                  /* expectedFulfillCnt= */ 1);
264 
265     context->submit(SyncToCpu::kYes);
266     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
267                                  /* expectedFulfillCnt= */ 1);
268 
269     // Test that more draws and insertions don't refulfill the NVPI
270     {
271         SkCanvas* canvas = testContext.fSurface->getCanvas();
272 
273         canvas->drawImage(testContext.fImg, 0, 0);
274         canvas->drawImage(testContext.fImg, 0, 0);
275 
276         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
277         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
278                                      /* expectedFulfillCnt= */ 1); // No new fulfill
279 
280         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
281         // testContext.fImg should still be fulfilled from the first time we inserted a Recording.
282         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
283                                      /* expectedFulfillCnt= */ 1);
284     }
285 
286     context->submit(SyncToCpu::kYes);
287     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
288                                  /* expectedFulfillCnt= */ 1);
289 
290     // Test that dropping the SkImage's ref doesn't change anything
291     {
292         SkCanvas* canvas = testContext.fSurface->getCanvas();
293 
294         canvas->drawImage(testContext.fImg, 0, 0);
295         testContext.fImg.reset();
296 
297         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
298         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
299                                      /* expectedFulfillCnt= */ 1);
300 
301         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
302         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
303                                      /* expectedFulfillCnt= */ 1);
304     }
305 
306     // fImg's proxy is reffed by the recording so, despite fImg being reset earlier,
307     // the imageRelease callback doesn't occur until the recording is deleted.
308     testContext.fPromiseChecker.checkImageReleased(reporter, /* expectedReleaseCnt= */ 1);
309 
310     // testContext.fImg no longer holds a ref but the last recording is still not submitted.
311     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
312                                  /* expectedFulfillCnt= */ 1);
313 
314     context->submit(SyncToCpu::kYes);
315 
316     // Now TextureRelease should definitely have been called.
317     check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
318 }
319 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageFulfillFailureTest,reporter,context)320 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageFulfillFailureTest,
321                                          reporter,
322                                          context) {
323     constexpr SkISize kDimensions { 16, 16 };
324 
325     TestCtx testContext;
326     setup_test_context(context, reporter, &testContext,
327                        kDimensions, Volatile::kNo, /* invalidBackendTex= */ true);
328 
329     // Draw the image a few different ways.
330     {
331         SkCanvas* canvas = testContext.fSurface->getCanvas();
332 
333         canvas->drawImage(testContext.fImg, 0, 0);
334         check_unfulfilled(testContext.fPromiseChecker, reporter);
335 
336         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
337         check_unfulfilled(testContext.fPromiseChecker, reporter);
338 
339         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
340         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
341                                      /* expectedFulfillCnt= */ 1);
342 
343         // Test that reinserting gives uninstantiated PromiseImages a second chance
344         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
345         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
346     }
347 
348     {
349         SkCanvas* canvas = testContext.fSurface->getCanvas();
350 
351         SkPaint paint;
352         paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
353         canvas->drawImage(testContext.fImg, 0, 0, SkSamplingOptions(), &paint);
354 
355         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
356         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
357 
358         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
359         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 3);
360     }
361 
362     {
363         SkCanvas* canvas = testContext.fSurface->getCanvas();
364 
365         sk_sp<SkShader> shader = testContext.fImg->makeShader(SkSamplingOptions());
366         REPORTER_ASSERT(reporter, shader);
367 
368         SkPaint paint;
369         paint.setShader(std::move(shader));
370         canvas->drawRect(SkRect::MakeWH(1, 1), paint);
371 
372         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
373         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 3);
374 
375         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
376         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
377     }
378 
379     testContext.fSurface.reset();
380     testContext.fImg.reset();
381 
382     // Despite fulfill failing 4x, the imageRelease callback still fires
383     testContext.fPromiseChecker.checkImageReleased(reporter, /* expectedReleaseCnt= */ 1);
384 
385     context->submit(SyncToCpu::kYes);
386     // fulfill should've been called 4x while release should never have been called
387     check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
388 }
389 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageCreationFailureTest,reporter,context)390 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageCreationFailureTest,
391                                          reporter,
392                                          context) {
393     // Note: these dimensions are invalid and will cause MakeGraphitePromiseTexture to fail
394     constexpr SkISize kDimensions { 0, 0 };
395 
396     TestCtx testContext;
397     setup_test_context(context, reporter, &testContext,
398                        kDimensions, Volatile::kNo, /* invalidBackendTex= */ true);
399 
400     SkASSERT(!testContext.fImg);
401 
402     // Despite MakeGraphitePromiseTexture failing, ImageRelease is called
403     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fFulfillCount == 0);
404     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fImageReleaseCount == 1);
405     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.totalReleaseCount() == 0);
406 }
407 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphitePromiseImageTest,reporter,context)408 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphitePromiseImageTest,
409                                          reporter,
410                                          context) {
411     constexpr SkISize kDimensions { 16, 16 };
412 
413     TestCtx testContext;
414     setup_test_context(context, reporter, &testContext,
415                        kDimensions, Volatile::kYes, /* invalidBackendTex= */ false);
416 
417     {
418         SkCanvas* canvas = testContext.fSurface->getCanvas();
419 
420         canvas->drawImage(testContext.fImg, 0, 0);
421         check_unfulfilled(testContext.fPromiseChecker, reporter);
422 
423         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
424         // Nothing happens at snap time for VPIs
425         check_unfulfilled(testContext.fPromiseChecker, reporter);
426 
427         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
428         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
429                                      /* expectedFulfillCnt= */ 1);  // VPIs fulfilled on insert
430 
431         // Test that multiple insertions will clobber prior fulfills
432         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
433         check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
434                                      /* expectedFulfillCnt= */ 2);
435     }
436 
437     context->submit(SyncToCpu::kYes);
438     check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
439 
440     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[0] == 1);
441     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[1] == 1);
442 
443     {
444         SkCanvas* canvas = testContext.fSurface->getCanvas();
445 
446         canvas->drawImage(testContext.fImg, 0, 0);
447         canvas->drawImage(testContext.fImg, 0, 0);
448 
449         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
450         // Nothing happens at snap time for volatile images
451         check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
452 
453         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
454         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
455                                      /* expectedFulfillCnt= */ 3);
456 
457         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
458         check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
459                                      /* expectedFulfillCnt= */ 4);
460     }
461 
462     context->submit(SyncToCpu::kYes);
463     check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
464 
465     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[0] == 2);
466     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[1] == 2);
467 
468     {
469         SkCanvas* canvas = testContext.fSurface->getCanvas();
470 
471         canvas->drawImage(testContext.fImg, 0, 0);
472         testContext.fImg.reset();
473 
474         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
475         // Nothing happens at snap time for volatile images
476         check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
477 
478         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
479         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
480                                      /* expectedFulfillCnt= */ 5);
481 
482         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
483         check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
484                                      /* expectedFulfillCnt= */ 6);
485     }
486 
487     // testContext.fImg no longer holds a ref but the last recordings are still not submitted.
488     check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
489                                  /* expectedFulfillCnt= */ 6);
490 
491     context->submit(SyncToCpu::kYes);
492 
493     // Now all Releases should definitely have been called.
494     check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 6);
495 
496     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[0] == 3);
497     REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[1] == 3);
498 }
499 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphitePromiseImageFulfillFailureTest,reporter,context)500 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphitePromiseImageFulfillFailureTest,
501                                          reporter,
502                                          context) {
503     constexpr SkISize kDimensions { 16, 16 };
504 
505     TestCtx testContext;
506     setup_test_context(context, reporter, &testContext,
507                        kDimensions, Volatile::kYes, /* invalidBackendTex= */ true);
508 
509     // Draw the image a few different ways.
510     {
511         SkCanvas* canvas = testContext.fSurface->getCanvas();
512 
513         canvas->drawImage(testContext.fImg, 0, 0);
514         check_unfulfilled(testContext.fPromiseChecker, reporter);
515 
516         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
517         check_unfulfilled(testContext.fPromiseChecker, reporter);
518 
519         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
520         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
521 
522         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
523         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
524     }
525 
526     {
527         SkCanvas* canvas = testContext.fSurface->getCanvas();
528 
529         SkPaint paint;
530         paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
531         canvas->drawImage(testContext.fImg, 0, 0, SkSamplingOptions(), &paint);
532 
533         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
534         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
535 
536         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
537         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 3);
538 
539         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
540         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
541     }
542 
543     {
544         SkCanvas* canvas = testContext.fSurface->getCanvas();
545 
546         sk_sp<SkShader> shader = testContext.fImg->makeShader(SkSamplingOptions());
547         REPORTER_ASSERT(reporter, shader);
548 
549         SkPaint paint;
550         paint.setShader(std::move(shader));
551         canvas->drawRect(SkRect::MakeWH(1, 1), paint);
552 
553         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
554         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
555 
556         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
557         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 5);
558 
559         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
560         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 6);
561     }
562 
563     testContext.fSurface.reset();
564     testContext.fImg.reset();
565 
566     context->submit(SyncToCpu::kYes);
567     check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 6);
568 }
569 
570 // Test out dropping the Recorder prior to inserting the Recording
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphitePromiseImageRecorderLoss,reporter,context)571 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphitePromiseImageRecorderLoss,
572                                          reporter,
573                                          context) {
574     constexpr SkISize kDimensions{ 16, 16 };
575 
576     for (Volatile isVolatile : { Volatile::kNo, Volatile::kYes }) {
577         TestCtx testContext;
578         setup_test_context(context, reporter, &testContext,
579                            kDimensions, isVolatile, /* invalidBackendTex= */ false);
580 
581         SkCanvas* canvas = testContext.fSurface->getCanvas();
582 
583         canvas->drawImage(testContext.fImg, 0, 0);
584         check_unfulfilled(testContext.fPromiseChecker, reporter);
585 
586         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
587         check_unfulfilled(testContext.fPromiseChecker, reporter);
588 
589         testContext.fRecorder.reset();  // Recorder drop
590 
591         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
592         check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
593 
594         context->submit(SyncToCpu::kYes);
595 
596         testContext.fSurface.reset();
597         testContext.fImg.reset();
598         recording.reset();
599 
600         check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
601     }
602 }
603 
604 // Test out PromiseImages appearing in multiple Recordings. In particular, test that
605 // previous instantiations don't impact the Recording's collection of PromiseImages.
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphitePromiseImageMultipleImgUses,reporter,context)606 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphitePromiseImageMultipleImgUses,
607                                          reporter,
608                                          context) {
609     constexpr SkISize kDimensions{ 16, 16 };
610 
611     static constexpr int kNumRecordings = 3;
612 
613     for (Volatile isVolatile : { Volatile::kNo, Volatile::kYes }) {
614         int expectedVolatile = (isVolatile == Volatile::kYes) ? 1 : 0;
615         int expectedNonVolatile = 1 - expectedVolatile;
616 
617         TestCtx testContext;
618         setup_test_context(context, reporter, &testContext,
619                            kDimensions, isVolatile, /* invalidBackendTex= */ false);
620 
621         std::unique_ptr<Recording> recordings[kNumRecordings];
622 
623         SkCanvas* canvas = testContext.fSurface->getCanvas();
624 
625         for (int i = 0; i < kNumRecordings; ++i) {
626             canvas->drawImage(testContext.fImg, 0, 0);
627 
628             recordings[i] = testContext.fRecorder->snap();
629 
630             if (isVolatile == Volatile::kYes) {
631                 check_fulfills_only(reporter, testContext.fPromiseChecker,
632                                     /* expectedFulfillCnt= */ i);
633             } else {
634                 check_fulfills_only(reporter, testContext.fPromiseChecker,
635                                     /* expectedFulfillCnt= */ i > 0 ? 1 : 0);
636             }
637 
638             REPORTER_ASSERT(reporter,
639                             recordings[i]->priv().numVolatilePromiseImages() == expectedVolatile);
640             REPORTER_ASSERT(reporter,
641                             recordings[i]->priv().numNonVolatilePromiseImages() ==
642                             expectedNonVolatile);
643 
644             REPORTER_ASSERT(reporter, context->insertRecording({ recordings[i].get() }));
645 
646             if (isVolatile == Volatile::kYes) {
647                 check_fulfills_only(reporter, testContext.fPromiseChecker,
648                                     /* expectedFulfillCnt= */ i+1);
649             } else {
650                 check_fulfills_only(reporter, testContext.fPromiseChecker,
651                                     /* expectedFulfillCnt= */ 1);
652             }
653 
654             // Non-volatiles are cleared out after a successful insertion
655             REPORTER_ASSERT(reporter, recordings[i]->priv().numNonVolatilePromiseImages() == 0);
656         }
657 
658         context->submit(SyncToCpu::kYes);
659 
660         testContext.fSurface.reset();
661         testContext.fImg.reset();
662         for (int i = 0; i < kNumRecordings; ++i) {
663             recordings[i].reset();
664         }
665 
666         if (isVolatile == Volatile::kYes) {
667             check_all_done(reporter, testContext.fPromiseChecker,
668                            /* expectedFulfillCnt= */ kNumRecordings);
669         } else {
670             check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
671         }
672     }
673 }
674