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