Flutter Engine
The Flutter Engine
GraphiteYUVAPromiseImageTest.cpp
Go to the documentation of this file.
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
9
22#include "tests/Test.h"
24
25using namespace skgpu::graphite;
26
27namespace {
28
29struct PromiseImageChecker {
30 PromiseImageChecker() = default;
31
32 void checkImageReleased(skiatest::Reporter* reporter, int expectedReleaseCnt) {
33 REPORTER_ASSERT(reporter, expectedReleaseCnt == fImageReleaseCount);
34 }
35
36 int fImageReleaseCount = 0;
37
38 static void ImageRelease(void* self) {
39 auto checker = reinterpret_cast<PromiseImageChecker*>(self);
40
41 checker->fImageReleaseCount++;
42 }
43};
44
46 PromiseTextureChecker() = default;
47
48 explicit PromiseTextureChecker(const BackendTexture& backendTex) {
49 fBackendTextures[0] = backendTex;
50 }
51
52 explicit PromiseTextureChecker(const BackendTexture& backendTex0,
53 const BackendTexture& backendTex1)
54 : fHasTwoBackendTextures(true) {
55 fBackendTextures[0] = backendTex0;
56 fBackendTextures[1] = backendTex1;
57 }
58
59 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
66 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
80 static void TextureRelease(void* context) {
81 int* releaseCount = reinterpret_cast<int*>(context);
82
83 (*releaseCount)++;
84 }
85};
86
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
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) {
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
136void check_unfulfilled(const PromiseImageChecker& promiseImageChecker,
137 const PromiseTextureChecker* promiseTextureCheckers,
139 check_fulfill_and_release_cnts(reporter, promiseImageChecker, promiseTextureCheckers,
140 /* expectedFulfillCnt= */ 0,
142}
143
144void 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
152void 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
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
168void 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
176struct TestCtx {
177 TestCtx() {}
178
179 ~TestCtx() {
180 for (int i = 0; i < 8; ++i) {
181 if (fBackendTextures[i].isValid()) {
182 fContext->deleteBackendTexture(fBackendTextures[i]);
183 }
184 }
185 }
186
188 std::unique_ptr<Recorder> fRecorder;
189 BackendTexture fBackendTextures[8];
190 PromiseImageChecker fPromiseImageChecker;
191 SkImages::GraphitePromiseImageContext fImageContext = &fPromiseImageChecker;
192 PromiseTextureChecker fPromiseTextureCheckers[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
203void setup_test_context(Context* context,
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
214
215 testCtx->fRecorder = context->makeRecorder();
216
217 testCtx->fPromiseImageChecker = PromiseImageChecker();
218
219 TextureInfo textureInfo[4];
220 for (int i = 0; i < 4; ++i) {
223 isProtected,
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,
256 YUVABackendTextureInfo yuvaBackendInfo(testCtx->fRecorder.get(),
257 yuvaInfo,
258 textureInfo,
260
261 testCtx->fImg = SkImages::PromiseTextureFromYUVA(testCtx->fRecorder.get(),
262 yuvaBackendInfo,
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,
275 testCtx->fSurface = SkSurfaces::RenderTarget(testCtx->fRecorder.get(), ii);
276}
277
278} // anonymous namespace
279
280DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageTest,
281 reporter,
282 context,
283 testGpuContext,
284 true,
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
379 NonVolatileGraphiteYUVAPromiseImageFulfillFailureTest,
380 reporter,
381 context,
382 testGpuContext,
383 true,
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
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
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
461DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageCreationFailureTest,
462 reporter,
463 context,
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
482DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphiteYUVAPromiseImageTest,
483 reporter,
484 context,
485 testGpuContext,
486 true,
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) {
524 testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[0] == 1);
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) {
557 testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[0] == 2);
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) {
597 testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[0] == 3);
599 testContext.fPromiseTextureCheckers[i].fTextureReleaseCounts[1] == 3);
600 }
601}
602
604 VolatileGraphiteYUVAPromiseImageFulfillFailureTest,
605 reporter,
606 context,
607 testGpuContext,
608 true,
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
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
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
689DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphiteYUVAPromiseImageRecorderLoss,
690 reporter,
691 context,
692 testGpuContext,
693 true,
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.
731DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphiteYUVAPromiseImageMultipleImgUses,
732 reporter,
733 context,
734 testGpuContext,
735 true,
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
769 recordings[i]->priv().numVolatilePromiseImages() == expectedVolatile);
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}
reporter
Definition: FontMgrTest.cpp:39
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageCreationFailureTest, reporter, context, CtsEnforcement::kNextRelease)
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphiteYUVAPromiseImageTest, reporter, context, testGpuContext, true, CtsEnforcement::kNextRelease)
ReleaseBalanceExpectation
static void check_fulfill_and_release_cnts(skiatest::Reporter *reporter, const PromiseTextureChecker &promiseChecker, int expectedFulfillCnt, ReleaseBalanceExpectation releaseBalanceExpecation)
static void check_unfulfilled(const PromiseTextureChecker &promiseChecker, skiatest::Reporter *reporter)
static void check_all_done(skiatest::Reporter *reporter, const PromiseTextureChecker &promiseChecker, int expectedFulfillCnt=1)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kJPEG_Full_SkYUVColorSpace
describes full range
Definition: SkImageInfo.h:69
const Context & fContext
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
static sk_sp< SkColorFilter > LinearToSRGBGamma()
static sk_sp< SkColorSpace > MakeSRGBLinear()
@ kY_U_V_A
Plane 0: Y, Plane 1: U, Plane 2: V, Plane 3: A.
@ k444
No subsampling. UV values for each Y.
bool protectedSupport() const
Definition: Caps.h:226
virtual TextureInfo getDefaultSampledTextureInfo(SkColorType, Mipmapped mipmapped, Protected, Renderable) const =0
const Caps * caps() const
Definition: ContextPriv.h:32
std::unique_ptr< Recorder > makeRecorder(const RecorderOptions &={})
Definition: Context.cpp:132
bool submit(SyncToCpu=SyncToCpu::kNo)
Definition: Context.cpp:162
void deleteBackendTexture(const BackendTexture &)
Definition: Context.cpp:750
bool insertRecording(const InsertRecordingInfo &)
Definition: Context.cpp:156
const Paint & paint
Definition: color_source.cc:38
FlPixelBufferTexturePrivate * priv
static float max(float r, float g, float b)
Definition: hsl.cpp:49
void * GraphitePromiseTextureFulfillContext
Definition: Image.h:41
void * GraphitePromiseImageContext
Definition: Image.h:38
SK_API sk_sp< SkImage > PromiseTextureFromYUVA(skgpu::graphite::Recorder *, const skgpu::graphite::YUVABackendTextureInfo &, sk_sp< SkColorSpace > imageColorSpace, skgpu::graphite::Volatile, GraphitePromiseTextureFulfillProc, GraphitePromiseImageReleaseProc, GraphitePromiseTextureReleaseProc, GraphitePromiseImageContext imageContext, GraphitePromiseTextureFulfillContext planeContexts[], std::string_view label={})
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
Protected
Definition: GpuTypes.h:61
SkSamplingOptions(SkFilterMode::kLinear))
static sk_sp< GrPromiseImageTexture > Fulfill(void *self)
Definition: SkSize.h:16
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609