xref: /aosp_15_r20/external/skia/tests/graphite/GraphiteYUVAPromiseImageTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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__anon59cb78cf0111::PromiseImageChecker32     void checkImageReleased(skiatest::Reporter* reporter, int expectedReleaseCnt) {
33         REPORTER_ASSERT(reporter, expectedReleaseCnt == fImageReleaseCount);
34     }
35 
36     int fImageReleaseCount = 0;
37 
ImageRelease__anon59cb78cf0111::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__anon59cb78cf0111::PromiseTextureChecker48     explicit PromiseTextureChecker(const BackendTexture& backendTex) {
49         fBackendTextures[0] = backendTex;
50     }
51 
PromiseTextureChecker__anon59cb78cf0111::PromiseTextureChecker52     explicit PromiseTextureChecker(const BackendTexture& backendTex0,
53                                    const BackendTexture& backendTex1)
54             : fHasTwoBackendTextures(true) {
55         fBackendTextures[0] = backendTex0;
56         fBackendTextures[1] = backendTex1;
57     }
58 
totalReleaseCount__anon59cb78cf0111::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__anon59cb78cf0111::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__anon59cb78cf0111::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__anon59cb78cf0111::TestCtx177     TestCtx() {}
178 
~TestCtx__anon59cb78cf0111::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(testCtx->fRecorder.get(),
257                                            yuvaInfo,
258                                            textureInfo,
259                                            skgpu::Mipmapped::kNo);
260 
261     testCtx->fImg = SkImages::PromiseTextureFromYUVA(testCtx->fRecorder.get(),
262                                                      yuvaBackendInfo,
263                                                      SkColorSpace::MakeSRGBLinear(),
264                                                      isVolatile,
265                                                      PromiseTextureChecker::Fulfill,
266                                                      PromiseImageChecker::ImageRelease,
267                                                      PromiseTextureChecker::TextureRelease,
268                                                      testCtx->fImageContext,
269                                                      testCtx->fTextureContexts);
270 
271     SkImageInfo ii = SkImageInfo::Make(dimensions.fWidth,
272                                        dimensions.fHeight,
273                                        kRGBA_8888_SkColorType,
274                                        kPremul_SkAlphaType);
275     testCtx->fSurface = SkSurfaces::RenderTarget(testCtx->fRecorder.get(), ii);
276 }
277 
278 } // anonymous namespace
279 
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageTest,reporter,context,testGpuContext,true,CtsEnforcement::kApiLevel_V)280 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageTest,
281                                                      reporter,
282                                                      context,
283                                                      testGpuContext,
284                                                      true,
285                                                      CtsEnforcement::kApiLevel_V) {
286     constexpr SkISize kDimensions { 16, 16 };
287 
288     TestCtx testContext;
289     setup_test_context(context, reporter, &testContext,
290                        kDimensions, Volatile::kNo, /* invalidBackendTex= */ false);
291 
292     {
293         SkCanvas* canvas = testContext.fSurface->getCanvas();
294 
295         canvas->drawImage(testContext.fImg, 0, 0);
296         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
297                           reporter);
298 
299         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
300         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
301                           reporter); // NVPIs not fulfilled at snap
302 
303         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
304         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
305                                      testContext.fPromiseTextureCheckers,
306                                      /* expectedFulfillCnt= */ 1); // NVPIs fulfilled at insert
307     }
308 
309     context->submit(SyncToCpu::kNo);
310     // testContext.fImg still has a ref so we should not have called TextureRelease.
311     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
312                                  testContext.fPromiseTextureCheckers,
313                                  /* expectedFulfillCnt= */ 1);
314 
315     testGpuContext->syncedSubmit(context);
316 
317     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
318                                  testContext.fPromiseTextureCheckers,
319                                  /* expectedFulfillCnt= */ 1);
320 
321     // Test that more draws and insertions don't refulfill the NVPI
322     {
323         SkCanvas* canvas = testContext.fSurface->getCanvas();
324 
325         canvas->drawImage(testContext.fImg, 0, 0);
326         canvas->drawImage(testContext.fImg, 0, 0);
327 
328         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
329         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
330                                      testContext.fPromiseTextureCheckers,
331                                      /* expectedFulfillCnt= */ 1); // No new fulfill
332 
333         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
334         // testContext.fImg should still be fulfilled from the first time we inserted a Recording.
335         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
336                                      testContext.fPromiseTextureCheckers,
337                                      /* expectedFulfillCnt= */ 1);
338     }
339 
340     testGpuContext->syncedSubmit(context);
341 
342     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
343                                  testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 1);
344 
345     // Test that dropping the SkImage's ref doesn't change anything
346     {
347         SkCanvas* canvas = testContext.fSurface->getCanvas();
348 
349         canvas->drawImage(testContext.fImg, 0, 0);
350         testContext.fImg.reset();
351 
352         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
353         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
354                                      testContext.fPromiseTextureCheckers,
355                                      /* expectedFulfillCnt= */ 1);
356 
357         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
358         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
359                                      testContext.fPromiseTextureCheckers,
360                                      /* expectedFulfillCnt= */ 1);
361     }
362 
363     // fImg's proxy is reffed by the recording so, despite fImg being reset earlier,
364     // the imageRelease callback doesn't occur until the recording is deleted.
365     testContext.fPromiseImageChecker.checkImageReleased(reporter, /* expectedReleaseCnt= */ 1);
366 
367     // testContext.fImg no longer holds a ref but the last recording is still not submitted.
368     check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
369                                  testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 1);
370 
371     testGpuContext->syncedSubmit(context);
372 
373     // Now TextureRelease should definitely have been called.
374     check_all_done(reporter, testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
375                    /* expectedFulfillCnt= */ 1);
376 }
377 
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageFulfillFailureTest,reporter,context,testGpuContext,true,CtsEnforcement::kApiLevel_V)378 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(
379         NonVolatileGraphiteYUVAPromiseImageFulfillFailureTest,
380         reporter,
381         context,
382         testGpuContext,
383         true,
384         CtsEnforcement::kApiLevel_V) {
385     constexpr SkISize kDimensions { 16, 16 };
386 
387     TestCtx testContext;
388     setup_test_context(context, reporter, &testContext,
389                        kDimensions, Volatile::kNo, /* invalidBackendTex= */ true);
390 
391     // Draw the image a few different ways.
392     {
393         SkCanvas* canvas = testContext.fSurface->getCanvas();
394 
395         canvas->drawImage(testContext.fImg, 0, 0);
396         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
397                           reporter);
398 
399         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
400         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
401                           reporter);
402 
403         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
404         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
405                                      testContext.fPromiseTextureCheckers,
406                                      /* expectedFulfillCnt= */ 1);
407 
408         // Test that reinserting gives uninstantiated PromiseImages a second chance
409         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
410         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
411                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 2);
412     }
413 
414     {
415         SkCanvas* canvas = testContext.fSurface->getCanvas();
416 
417         SkPaint paint;
418         paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
419         canvas->drawImage(testContext.fImg, 0, 0, SkSamplingOptions(), &paint);
420 
421         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
422         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
423                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 2);
424 
425         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
426         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
427                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 3);
428     }
429 
430     {
431         SkCanvas* canvas = testContext.fSurface->getCanvas();
432 
433         sk_sp<SkShader> shader = testContext.fImg->makeShader(SkSamplingOptions());
434         REPORTER_ASSERT(reporter, shader);
435 
436         SkPaint paint;
437         paint.setShader(std::move(shader));
438         canvas->drawRect(SkRect::MakeWH(1, 1), paint);
439 
440         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
441         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
442                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 3);
443 
444         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
445         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
446                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 4);
447     }
448 
449     testContext.fSurface.reset();
450     testContext.fImg.reset();
451 
452     // Despite fulfill failing 4x, the imageRelease callback still fires
453     testContext.fPromiseImageChecker.checkImageReleased(reporter, /* expectedReleaseCnt= */ 1);
454 
455     testGpuContext->syncedSubmit(context);
456     // fulfill should've been called 4x while release should never have been called
457     check_fulfills_only(reporter, testContext.fPromiseImageChecker,
458                         testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 4);
459 }
460 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageCreationFailureTest,reporter,context,CtsEnforcement::kApiLevel_V)461 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageCreationFailureTest,
462                                          reporter,
463                                          context,
464                                          CtsEnforcement::kApiLevel_V) {
465     // Note: these dimensions are invalid and will cause MakeGraphitePromiseTexture to fail
466     constexpr SkISize kDimensions { 0, 0 };
467 
468     TestCtx testContext;
469     setup_test_context(context, reporter, &testContext,
470                        kDimensions, Volatile::kNo, /* invalidBackendTex= */ true);
471 
472     SkASSERT(!testContext.fImg);
473 
474     // Despite MakeGraphitePromiseTexture failing, ImageRelease is called
475     REPORTER_ASSERT(reporter, testContext.fPromiseImageChecker.fImageReleaseCount == 1);
476     for (int i = 0; i < 4; ++i) {
477         REPORTER_ASSERT(reporter, testContext.fPromiseTextureCheckers[i].fFulfillCount == 0);
478         REPORTER_ASSERT(reporter, testContext.fPromiseTextureCheckers[i].totalReleaseCount() == 0);
479     }
480 }
481 
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphiteYUVAPromiseImageTest,reporter,context,testGpuContext,true,CtsEnforcement::kApiLevel_V)482 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphiteYUVAPromiseImageTest,
483                                                      reporter,
484                                                      context,
485                                                      testGpuContext,
486                                                      true,
487                                                      CtsEnforcement::kApiLevel_V) {
488     constexpr SkISize kDimensions { 16, 16 };
489 
490     TestCtx testContext;
491     setup_test_context(context, reporter, &testContext,
492                        kDimensions, Volatile::kYes, /* invalidBackendTex= */ false);
493 
494     {
495         SkCanvas* canvas = testContext.fSurface->getCanvas();
496 
497         canvas->drawImage(testContext.fImg, 0, 0);
498         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
499                           reporter);
500 
501         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
502         // Nothing happens at snap time for VPIs
503         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
504                           reporter);
505 
506         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
507         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
508                                      testContext.fPromiseTextureCheckers,
509                                      /* expectedFulfillCnt= */ 1);  // VPIs fulfilled on insert
510 
511         // Test that multiple insertions will clobber prior fulfills
512         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
513         check_fulfilled_ahead_by_two(reporter, testContext.fPromiseImageChecker,
514                                      testContext.fPromiseTextureCheckers,
515                                      /* expectedFulfillCnt= */ 2);
516     }
517 
518     testGpuContext->syncedSubmit(context);
519     check_all_done(reporter, testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
520                    /* expectedFulfillCnt= */ 2);
521 
522     for (int i = 0; i < 4; ++i) {
523         REPORTER_ASSERT(reporter,
524                         testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[0] == 1);
525         REPORTER_ASSERT(reporter,
526                         testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[1] == 1);
527     }
528 
529     {
530         SkCanvas* canvas = testContext.fSurface->getCanvas();
531 
532         canvas->drawImage(testContext.fImg, 0, 0);
533         canvas->drawImage(testContext.fImg, 0, 0);
534 
535         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
536         // Nothing happens at snap time for volatile images
537         check_all_done(reporter, testContext.fPromiseImageChecker,
538                        testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 2);
539 
540         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
541         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
542                                      testContext.fPromiseTextureCheckers,
543                                      /* expectedFulfillCnt= */ 3);
544 
545         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
546         check_fulfilled_ahead_by_two(reporter, testContext.fPromiseImageChecker,
547                                      testContext.fPromiseTextureCheckers,
548                                      /* expectedFulfillCnt= */ 4);
549     }
550 
551     testGpuContext->syncedSubmit(context);
552     check_all_done(reporter, testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
553                    /* expectedFulfillCnt= */ 4);
554 
555     for (int i = 0; i < 4; ++i) {
556         REPORTER_ASSERT(reporter,
557                         testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[0] == 2);
558         REPORTER_ASSERT(reporter,
559                         testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[1] == 2);
560     }
561 
562     {
563         SkCanvas* canvas = testContext.fSurface->getCanvas();
564 
565         canvas->drawImage(testContext.fImg, 0, 0);
566         testContext.fImg.reset();
567 
568         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
569         // Nothing happens at snap time for volatile images
570         check_all_done(reporter, testContext.fPromiseImageChecker,
571                        testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 4);
572 
573         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
574         check_fulfilled_ahead_by_one(reporter, testContext.fPromiseImageChecker,
575                                      testContext.fPromiseTextureCheckers,
576                                      /* expectedFulfillCnt= */ 5);
577 
578         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
579         check_fulfilled_ahead_by_two(reporter, testContext.fPromiseImageChecker,
580                                      testContext.fPromiseTextureCheckers,
581                                      /* expectedFulfillCnt= */ 6);
582     }
583 
584     // testContext.fImg no longer holds a ref but the last recordings are still not submitted.
585     check_fulfilled_ahead_by_two(reporter, testContext.fPromiseImageChecker,
586                                  testContext.fPromiseTextureCheckers,
587                                  /* expectedFulfillCnt= */ 6);
588 
589     testGpuContext->syncedSubmit(context);
590 
591     // Now all Releases should definitely have been called.
592     check_all_done(reporter, testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
593                    /* expectedFulfillCnt= */ 6);
594 
595     for (int i = 0; i < 4; ++i) {
596         REPORTER_ASSERT(reporter,
597                         testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[0] == 3);
598         REPORTER_ASSERT(reporter,
599                         testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[1] == 3);
600     }
601 }
602 
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphiteYUVAPromiseImageFulfillFailureTest,reporter,context,testGpuContext,true,CtsEnforcement::kApiLevel_V)603 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(
604         VolatileGraphiteYUVAPromiseImageFulfillFailureTest,
605         reporter,
606         context,
607         testGpuContext,
608         true,
609         CtsEnforcement::kApiLevel_V) {
610     constexpr SkISize kDimensions { 16, 16 };
611 
612     TestCtx testContext;
613     setup_test_context(context, reporter, &testContext,
614                        kDimensions, Volatile::kYes, /* invalidBackendTex= */ true);
615 
616     // Draw the image a few different ways.
617     {
618         SkCanvas* canvas = testContext.fSurface->getCanvas();
619 
620         canvas->drawImage(testContext.fImg, 0, 0);
621         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
622                           reporter);
623 
624         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
625         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
626                           reporter);
627 
628         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
629         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
630                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 1);
631 
632         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
633         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
634                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 2);
635     }
636 
637     {
638         SkCanvas* canvas = testContext.fSurface->getCanvas();
639 
640         SkPaint paint;
641         paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
642         canvas->drawImage(testContext.fImg, 0, 0, SkSamplingOptions(), &paint);
643 
644         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
645         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
646                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 2);
647 
648         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
649         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
650                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 3);
651 
652         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
653         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
654                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 4);
655     }
656 
657     {
658         SkCanvas* canvas = testContext.fSurface->getCanvas();
659 
660         sk_sp<SkShader> shader = testContext.fImg->makeShader(SkSamplingOptions());
661         REPORTER_ASSERT(reporter, shader);
662 
663         SkPaint paint;
664         paint.setShader(std::move(shader));
665         canvas->drawRect(SkRect::MakeWH(1, 1), paint);
666 
667         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
668         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
669                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 4);
670 
671         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
672         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
673                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 5);
674 
675         REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
676         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
677                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 6);
678     }
679 
680     testContext.fSurface.reset();
681     testContext.fImg.reset();
682 
683     testGpuContext->syncedSubmit(context);
684     check_fulfills_only(reporter, testContext.fPromiseImageChecker,
685                         testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 6);
686 }
687 
688 // Test out dropping the Recorder prior to inserting the Recording
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphiteYUVAPromiseImageRecorderLoss,reporter,context,testGpuContext,true,CtsEnforcement::kApiLevel_V)689 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphiteYUVAPromiseImageRecorderLoss,
690                                                      reporter,
691                                                      context,
692                                                      testGpuContext,
693                                                      true,
694                                                      CtsEnforcement::kApiLevel_V) {
695     constexpr SkISize kDimensions{ 16, 16 };
696 
697     for (Volatile isVolatile : { Volatile::kNo, Volatile::kYes }) {
698         TestCtx testContext;
699         setup_test_context(context, reporter, &testContext,
700                            kDimensions, isVolatile, /* invalidBackendTex= */ false);
701 
702         SkCanvas* canvas = testContext.fSurface->getCanvas();
703 
704         canvas->drawImage(testContext.fImg, 0, 0);
705         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
706                           reporter);
707 
708         std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
709         check_unfulfilled(testContext.fPromiseImageChecker, testContext.fPromiseTextureCheckers,
710                           reporter);
711 
712         testContext.fRecorder.reset();  // Recorder drop
713 
714         REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
715         check_fulfills_only(reporter, testContext.fPromiseImageChecker,
716                             testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 1);
717 
718         testGpuContext->syncedSubmit(context);
719 
720         testContext.fSurface.reset();
721         testContext.fImg.reset();
722         recording.reset();
723 
724         check_all_done(reporter, testContext.fPromiseImageChecker,
725                        testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 1);
726     }
727 }
728 
729 // Test out PromiseImages appearing in multiple Recordings. In particular, test that
730 // 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_V)731 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphiteYUVAPromiseImageMultipleImgUses,
732                                                      reporter,
733                                                      context,
734                                                      testGpuContext,
735                                                      true,
736                                                      CtsEnforcement::kApiLevel_V) {
737     constexpr SkISize kDimensions{ 16, 16 };
738 
739     static constexpr int kNumRecordings = 3;
740 
741     for (Volatile isVolatile : { Volatile::kNo, Volatile::kYes }) {
742         int expectedVolatile = (isVolatile == Volatile::kYes) ? 4 : 0;
743         int expectedNonVolatile = 4 - expectedVolatile;
744 
745         TestCtx testContext;
746         setup_test_context(context, reporter, &testContext,
747                            kDimensions, isVolatile, /* invalidBackendTex= */ false);
748 
749         std::unique_ptr<Recording> recordings[kNumRecordings];
750 
751         SkCanvas* canvas = testContext.fSurface->getCanvas();
752 
753         for (int i = 0; i < kNumRecordings; ++i) {
754             canvas->drawImage(testContext.fImg, 0, 0);
755 
756             recordings[i] = testContext.fRecorder->snap();
757 
758             if (isVolatile == Volatile::kYes) {
759                 check_fulfills_only(reporter, testContext.fPromiseImageChecker,
760                                     testContext.fPromiseTextureCheckers,
761                                     /* expectedFulfillCnt= */ i);
762             } else {
763                 check_fulfills_only(reporter, testContext.fPromiseImageChecker,
764                                     testContext.fPromiseTextureCheckers,
765                                     /* expectedFulfillCnt= */ i > 0 ? 1 : 0);
766             }
767 
768             REPORTER_ASSERT(reporter,
769                             recordings[i]->priv().numVolatilePromiseImages() == expectedVolatile);
770             REPORTER_ASSERT(reporter,
771                             recordings[i]->priv().numNonVolatilePromiseImages() ==
772                             expectedNonVolatile);
773 
774             REPORTER_ASSERT(reporter, context->insertRecording({ recordings[i].get() }));
775 
776             if (isVolatile == Volatile::kYes) {
777                 check_fulfills_only(reporter, testContext.fPromiseImageChecker,
778                                     testContext.fPromiseTextureCheckers,
779                                     /* expectedFulfillCnt= */ i+1);
780             } else {
781                 check_fulfills_only(reporter, testContext.fPromiseImageChecker,
782                                     testContext.fPromiseTextureCheckers,
783                                     /* expectedFulfillCnt= */ 1);
784             }
785 
786             // Non-volatiles are cleared out after a successful insertion
787             REPORTER_ASSERT(reporter, recordings[i]->priv().numNonVolatilePromiseImages() == 0);
788         }
789 
790         testGpuContext->syncedSubmit(context);
791 
792         testContext.fSurface.reset();
793         testContext.fImg.reset();
794         for (int i = 0; i < kNumRecordings; ++i) {
795             recordings[i].reset();
796         }
797 
798         if (isVolatile == Volatile::kYes) {
799             check_all_done(reporter, testContext.fPromiseImageChecker,
800                            testContext.fPromiseTextureCheckers,
801                            /* expectedFulfillCnt= */ kNumRecordings);
802         } else {
803             check_all_done(reporter, testContext.fPromiseImageChecker,
804                            testContext.fPromiseTextureCheckers, /* expectedFulfillCnt= */ 1);
805         }
806     }
807 }
808