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