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