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