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