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/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkPicture.h"
19 #include "include/core/SkPictureRecorder.h"
20 #include "include/core/SkPoint.h"
21 #include "include/core/SkRect.h"
22 #include "include/core/SkRefCnt.h"
23 #include "include/core/SkSamplingOptions.h"
24 #include "include/core/SkScalar.h"
25 #include "include/core/SkSize.h"
26 #include "include/core/SkStream.h"
27 #include "include/core/SkString.h"
28 #include "include/core/SkSurface.h"
29 #include "include/core/SkTiledImageUtils.h"
30 #include "include/encode/SkPngEncoder.h"
31 #include "include/gpu/GpuTypes.h"
32 #include "include/private/base/SkAssert.h"
33 #include "src/core/SkSamplingPriv.h"
34 #include "tests/Test.h"
35 #include "tests/TestUtils.h"
36 #include "tools/ToolUtils.h"
37
38 #if defined(SK_GANESH)
39 #include "include/gpu/GrDirectContext.h"
40 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
41 #include "src/gpu/ganesh/GrDirectContextPriv.h"
42 #include "src/gpu/ganesh/GrResourceCache.h"
43 #include "src/gpu/ganesh/GrSurface.h"
44 #include "src/gpu/ganesh/GrTexture.h"
45 #include "tests/CtsEnforcement.h"
46 struct GrContextOptions;
47 #endif
48
49 #if defined(SK_GRAPHITE)
50 #include "include/gpu/graphite/Context.h"
51 #include "include/gpu/graphite/Recorder.h"
52 #include "include/gpu/graphite/Surface.h"
53 #include "src/gpu/graphite/Caps.h"
54 #include "src/gpu/graphite/RecorderPriv.h"
55 #include "src/gpu/graphite/Texture.h"
56 #include "tools/GpuToolUtils.h"
57 #else
58 namespace skgpu { namespace graphite { class Recorder; } }
59 #endif
60
61 #include <atomic>
62 #include <functional>
63 #include <initializer_list>
64 #include <string.h>
65 #include <utility>
66
67 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
68 extern int gOverrideMaxTextureSizeGanesh;
69 extern std::atomic<int> gNumTilesDrawnGanesh;
70 #endif
71
72 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
73 extern int gOverrideMaxTextureSizeGraphite;
74 extern std::atomic<int> gNumTilesDrawnGraphite;
75 #endif
76
77 namespace {
78
79 // Draw a white border around the edge (to test strict constraints) and
80 // a Hilbert curve inside of that (so the effects of (mis) sampling are evident).
draw(SkCanvas * canvas,int imgSize,int whiteBandWidth,int desiredLineWidth,int desiredDepth)81 void draw(SkCanvas* canvas, int imgSize, int whiteBandWidth,
82 int desiredLineWidth, int desiredDepth) {
83 const int kPad = desiredLineWidth;
84
85 canvas->clear(SK_ColorWHITE);
86
87 SkPaint innerRect;
88 innerRect.setColor(SK_ColorDKGRAY);
89 canvas->drawRect(SkRect::MakeIWH(imgSize, imgSize).makeInset(whiteBandWidth, whiteBandWidth),
90 innerRect);
91
92 int desiredDrawSize = imgSize - 2 * kPad - 2 * whiteBandWidth;
93 ToolUtils::HilbertGenerator gen(desiredDrawSize, desiredLineWidth, desiredDepth);
94
95 canvas->translate(kPad + whiteBandWidth, imgSize - kPad - whiteBandWidth);
96 gen.draw(canvas);
97 }
98
99
make_big_bitmap_image(int imgSize,int whiteBandWidth,int desiredLineWidth,int desiredDepth)100 sk_sp<SkImage> make_big_bitmap_image(int imgSize, int whiteBandWidth,
101 int desiredLineWidth, int desiredDepth) {
102 SkBitmap bm;
103
104 bm.allocN32Pixels(imgSize, imgSize, /* isOpaque= */ true);
105 SkCanvas canvas(bm);
106
107 draw(&canvas, imgSize, whiteBandWidth, desiredLineWidth, desiredDepth);
108
109 bm.setImmutable();
110 return bm.asImage();
111 }
112
make_big_picture_image(int imgSize,int whiteBandWidth,int desiredLineWidth,int desiredDepth)113 sk_sp<SkImage> make_big_picture_image(int imgSize, int whiteBandWidth,
114 int desiredLineWidth, int desiredDepth) {
115 sk_sp<SkPicture> pic;
116
117 {
118 SkPictureRecorder recorder;
119 SkCanvas* canvas = recorder.beginRecording(SkRect::MakeIWH(imgSize, imgSize));
120 draw(canvas, imgSize, whiteBandWidth, desiredLineWidth, desiredDepth);
121 pic = recorder.finishRecordingAsPicture();
122 }
123
124 return SkImages::DeferredFromPicture(std::move(pic),
125 { imgSize, imgSize },
126 /* matrix= */ nullptr,
127 /* paint= */ nullptr,
128 SkImages::BitDepth::kU8,
129 SkColorSpace::MakeSRGB());
130 }
131
132
get_sampling_str(const SkSamplingOptions & sampling)133 const char* get_sampling_str(const SkSamplingOptions& sampling) {
134 if (sampling.isAniso()) {
135 return "Aniso";
136 } else if (sampling.useCubic) {
137 return "Cubic";
138 } else if (sampling.mipmap != SkMipmapMode::kNone) {
139 return "Mipmap";
140 } else if (sampling.filter == SkFilterMode::kLinear) {
141 return "Linear";
142 } else {
143 return "NN";
144 }
145 }
146
create_label(GrDirectContext * dContext,const char * generator,const SkSamplingOptions & sampling,int scale,int rot,SkCanvas::SrcRectConstraint constraint,int numTiles)147 SkString create_label(GrDirectContext* dContext,
148 const char* generator,
149 const SkSamplingOptions& sampling,
150 int scale,
151 int rot,
152 SkCanvas::SrcRectConstraint constraint,
153 int numTiles) {
154 SkString label;
155 label.appendf("%s-%s-%s-%d-%d-%s-%d",
156 dContext ? "ganesh" : "graphite",
157 generator,
158 get_sampling_str(sampling),
159 scale,
160 rot,
161 constraint == SkCanvas::kFast_SrcRectConstraint ? "fast" : "strict",
162 numTiles);
163 return label;
164 }
165
potentially_write_to_png(const char * directory,const SkString & label,const SkBitmap & bm)166 void potentially_write_to_png(const char* directory,
167 const SkString& label,
168 const SkBitmap& bm) {
169 constexpr bool kWriteOutImages = false;
170
171 if constexpr(kWriteOutImages) {
172 SkString filename;
173 filename.appendf("//%s//%s.png", directory, label.c_str());
174
175 SkFILEWStream file(filename.c_str());
176 SkAssertResult(file.isValid());
177
178 SkAssertResult(SkPngEncoder::Encode(&file, bm.pixmap(), {}));
179 }
180 }
181
check_pixels(skiatest::Reporter * reporter,const SkBitmap & expected,const SkBitmap & actual,const SkString & label,int rot)182 bool check_pixels(skiatest::Reporter* reporter,
183 const SkBitmap& expected,
184 const SkBitmap& actual,
185 const SkString& label,
186 int rot) {
187 static const float kTols[4] = { 0.008f, 0.008f, 0.008f, 0.008f }; // ~ 2/255
188 static const float kRotTols[4] = { 0.024f, 0.024f, 0.024f, 0.024f }; // ~ 6/255
189
190 auto error = std::function<ComparePixmapsErrorReporter>(
191 [&](int x, int y, const float diffs[4]) {
192 SkASSERT(x >= 0 && y >= 0);
193 ERRORF(reporter, "%s: mismatch at %d, %d (%f, %f, %f %f)",
194 label.c_str(), x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
195 });
196
197 return ComparePixels(expected.pixmap(), actual.pixmap(), rot ? kRotTols : kTols, error);
198 }
199
200 // Return a clip rect that will result in the number of desired tiles being used. The trick
201 // is that the clip rect also has to work when rotated.
clip_rect(SkRect dstRect,int numDesiredTiles)202 SkRect clip_rect(SkRect dstRect, int numDesiredTiles) {
203 dstRect.outset(5, 5);
204
205 switch (numDesiredTiles) {
206 case 0:
207 return { dstRect.fLeft-64, dstRect.fTop-64, dstRect.fLeft-63, dstRect.fTop-63 };
208 case 4: {
209 // Upper left 4x4
210 float outset = 0.125f * dstRect.width() * SK_ScalarRoot2Over2;
211 SkPoint center = dstRect.center();
212 return { center.fX - outset, center.fY - outset,
213 center.fX + outset, center.fY + outset };
214 }
215 case 9: {
216 // Upper left 3x3
217 float outset = 0.25f * dstRect.width() * SK_ScalarRoot2Over2;
218 SkPoint center = dstRect.center();
219 center.offset(-dstRect.width()/8.0f, -dstRect.height()/8.0f);
220 return { center.fX - outset, center.fY - outset,
221 center.fX + outset, center.fY + outset };
222 }
223 }
224
225 return dstRect; // all 16 tiles
226 }
227
difficult_case(const SkSamplingOptions & sampling,int scale,int rot,SkCanvas::SrcRectConstraint constraint)228 bool difficult_case(const SkSamplingOptions& sampling,
229 int scale,
230 int rot,
231 SkCanvas::SrcRectConstraint constraint) {
232 if (sampling.useCubic) {
233 return false; // cubic never causes any issues
234 }
235
236 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
237 (sampling.mipmap != SkMipmapMode::kNone || sampling.filter == SkFilterMode::kLinear)) {
238 // linear-filtered strict big image drawing is currently broken (b/286239467). The issue
239 // is that the strict constraint is propagated to the child tiles which breaks the
240 // interpolation expected in the middle of the large image.
241 // Note that strict mipmapping is auto-downgraded to strict linear sampling.
242 return true;
243 }
244
245 if (sampling.mipmap == SkMipmapMode::kLinear) {
246 // Mipmapping is broken for anything other that 1-to-1 draws (b/286256104). The issue
247 // is that the mipmaps are created for each tile individually so the higher levels differ
248 // from what would be generated with the entire image. Mipmapped draws are off by ~20/255
249 // at 4x and ~64/255 at 8x)
250 return scale > 1;
251 }
252
253 if (sampling.filter == SkFilterMode::kNearest) {
254 // Perhaps unsurprisingly, NN only passes on un-rotated 1-to-1 draws (off by ~187/255 at
255 // different scales).
256 return scale > 1 || rot > 0;
257 }
258
259 return false;
260 }
261
262 // compare tiled and untiled draws - varying the parameters (e.g., sampling, rotation, fast vs.
263 // strict, etc).
tiling_comparison_test(GrDirectContext * dContext,skgpu::graphite::Recorder * recorder,skiatest::Reporter * reporter)264 void tiling_comparison_test(GrDirectContext* dContext,
265 skgpu::graphite::Recorder* recorder,
266 skiatest::Reporter* reporter) {
267 // We're using the knowledge that the internal tile size is 1024. By creating kImageSize
268 // sized images we know we'll get a 4x4 tiling regardless of the sampling.
269 static const int kImageSize = 4096 - 4 * 2 * kBicubicFilterTexelPad;
270 static const int kOverrideMaxTextureSize = 1024;
271
272 #if defined(SK_GANESH)
273 if (dContext && dContext->maxTextureSize() < kImageSize) {
274 // For the expected images we need to be able to draw w/o tiling
275 return;
276 }
277 #endif
278
279 #if defined(SK_GRAPHITE)
280 if (recorder) {
281 const skgpu::graphite::Caps* caps = recorder->priv().caps();
282 if (caps->maxTextureSize() < kImageSize) {
283 return;
284 }
285 }
286 #endif
287
288 static const int kWhiteBandWidth = 4;
289 const SkRect srcRect = SkRect::MakeIWH(kImageSize, kImageSize).makeInset(kWhiteBandWidth,
290 kWhiteBandWidth);
291
292 using GeneratorT = sk_sp<SkImage>(*)(int imgSize, int whiteBandWidth,
293 int desiredLineWidth, int desiredDepth);
294
295 static const struct {
296 GeneratorT fGen;
297 const char* fTag;
298 } kGenerators[] = { { make_big_bitmap_image, "BM" },
299 { make_big_picture_image, "Picture" } };
300
301 static const SkSamplingOptions kSamplingOptions[] = {
302 SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone),
303 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
304 // Note that Mipmapping gets auto-disabled with a strict-constraint
305 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
306 SkSamplingOptions(SkCubicResampler::CatmullRom()),
307 };
308
309 int numClippedTiles = 9;
310 for (auto gen : kGenerators) {
311 if (recorder && !strcmp(gen.fTag, "Picture")) {
312 // In the picture-image case, the non-tiled code path draws the picture directly into a
313 // gpu-backed surface while the tiled code path the picture is draws the picture into
314 // a raster-backed surface. For Ganesh this works out, since both Ganesh and Raster
315 // support non-AA rect draws. For Graphite the results are very different (since
316 // Graphite always anti-aliases. Forcing all the rect draws to be AA doesn't work out
317 // since AA introduces too much variance between both of the gpu backends and Raster -
318 // which would obscure any errors introduced by tiling.
319 continue;
320 }
321
322 sk_sp<SkImage> img = (*gen.fGen)(kImageSize,
323 kWhiteBandWidth,
324 /* desiredLineWidth= */ 16,
325 /* desiredDepth= */ 7);
326 numClippedTiles = (numClippedTiles == 9) ? 4 : 9; // alternate to reduce the combinatorics
327
328 for (int scale : { 1, 4, 8 }) {
329 for (int rot : { 0, 45 }) {
330 for (int numDesiredTiles : { numClippedTiles, 16 }) {
331 SkRect destRect = SkRect::MakeWH(srcRect.width()/scale,
332 srcRect.height()/scale);
333
334 SkMatrix m = SkMatrix::RotateDeg(rot, destRect.center());
335 SkIRect rotatedRect = m.mapRect(destRect).roundOut();
336 rotatedRect.outset(2, 2); // outset to capture the constraint's effect
337
338 SkRect clipRect = clip_rect(destRect, numDesiredTiles);
339
340 auto destII = SkImageInfo::Make(rotatedRect.width(),
341 rotatedRect.height(),
342 kRGBA_8888_SkColorType,
343 kPremul_SkAlphaType);
344
345 SkBitmap expected, actual;
346 expected.allocPixels(destII);
347 actual.allocPixels(destII);
348
349 sk_sp<SkSurface> surface;
350
351 #if defined(SK_GANESH)
352 if (dContext) {
353 surface = SkSurfaces::RenderTarget(dContext,
354 skgpu::Budgeted::kNo,
355 destII);
356 }
357 #endif
358
359 #if defined(SK_GRAPHITE)
360 if (recorder) {
361 surface = SkSurfaces::RenderTarget(recorder, destII);
362 }
363 #endif
364
365 for (auto sampling : kSamplingOptions) {
366 for (auto constraint : { SkCanvas::kStrict_SrcRectConstraint,
367 SkCanvas::kFast_SrcRectConstraint }) {
368 if (difficult_case(sampling, scale, rot, constraint)) {
369 continue;
370 }
371
372 SkString label = create_label(dContext, gen.fTag, sampling, scale, rot,
373 constraint, numDesiredTiles);
374
375 SkCanvas* canvas = surface->getCanvas();
376
377 SkAutoCanvasRestore acr(canvas, /* doSave= */ true);
378
379 canvas->translate(-rotatedRect.fLeft, -rotatedRect.fTop);
380 if (sampling.useCubic || sampling.filter != SkFilterMode::kNearest) {
381 // NN sampling doesn't deal well w/ the (0.5, 0.5) offset but the
382 // other sampling modes need it to exercise strict vs. fast
383 // constraint in non-rotated draws
384 canvas->translate(0.5f, 0.5f);
385 }
386 canvas->concat(m);
387
388 // First, draw w/o tiling
389 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
390 gOverrideMaxTextureSizeGanesh = 0;
391 #endif
392 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
393 gOverrideMaxTextureSizeGraphite = 0;
394 #endif
395 canvas->clear(SK_ColorBLACK);
396 canvas->save();
397 canvas->clipRect(clipRect);
398
399 SkTiledImageUtils::DrawImageRect(canvas, img, srcRect, destRect,
400 sampling, /* paint= */ nullptr,
401 constraint);
402 SkAssertResult(surface->readPixels(expected, 0, 0));
403 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
404 int actualNumTiles =
405 gNumTilesDrawnGanesh.load(std::memory_order_acquire);
406 REPORTER_ASSERT(reporter, actualNumTiles == 0);
407 #endif
408 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
409 int actualNumTiles2 =
410 gNumTilesDrawnGraphite.load(std::memory_order_acquire);
411 REPORTER_ASSERT(reporter, actualNumTiles2 == 0);
412 #endif
413 canvas->restore();
414
415 // Then, force 4x4 tiling
416 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
417 gOverrideMaxTextureSizeGanesh = kOverrideMaxTextureSize;
418 #endif
419 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
420 gOverrideMaxTextureSizeGraphite = kOverrideMaxTextureSize;
421 #endif
422
423 canvas->clear(SK_ColorBLACK);
424 canvas->save();
425 canvas->clipRect(clipRect);
426
427 SkTiledImageUtils::DrawImageRect(canvas, img, srcRect, destRect,
428 sampling, /* paint= */ nullptr,
429 constraint);
430 SkAssertResult(surface->readPixels(actual, 0, 0));
431 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
432 if (canvas->recordingContext()) {
433 actualNumTiles =
434 gNumTilesDrawnGanesh.load(std::memory_order_acquire);
435 REPORTER_ASSERT(reporter,
436 numDesiredTiles == actualNumTiles,
437 "mismatch expected: %d actual: %d\n",
438 numDesiredTiles,
439 actualNumTiles);
440 }
441 #endif
442 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
443 if (canvas->recorder()) {
444 actualNumTiles2 =
445 gNumTilesDrawnGraphite.load(std::memory_order_acquire);
446 REPORTER_ASSERT(reporter,
447 numDesiredTiles == actualNumTiles2,
448 "mismatch expected: %d actual: %d\n",
449 numDesiredTiles,
450 actualNumTiles2);
451 }
452 #endif
453
454 canvas->restore();
455
456 REPORTER_ASSERT(reporter, check_pixels(reporter, expected, actual,
457 label, rot));
458
459 potentially_write_to_png("expected", label, expected);
460 potentially_write_to_png("actual", label, actual);
461 }
462 }
463 }
464 }
465 }
466 }
467 // Reset tiling behavior
468 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
469 gOverrideMaxTextureSizeGanesh = 0;
470 #endif
471 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
472 gOverrideMaxTextureSizeGraphite = 0;
473 #endif
474 }
475
476 // In this test we draw the same bitmap-backed image twice and check that we only upload it once.
477 // Everything is set up for the bitmap-backed image to be split into 16 1024x1024 tiles.
tiled_image_caching_test(GrDirectContext * dContext,skgpu::graphite::Recorder * recorder,skiatest::Reporter * reporter)478 void tiled_image_caching_test(GrDirectContext* dContext,
479 skgpu::graphite::Recorder* recorder,
480 skiatest::Reporter* reporter) {
481 static const int kImageSize = 4096;
482 static const int kOverrideMaxTextureSize = 1024;
483 static const SkISize kExpectedTileSize { kOverrideMaxTextureSize, kOverrideMaxTextureSize };
484
485 sk_sp<SkImage> img = make_big_bitmap_image(kImageSize,
486 /* whiteBandWidth= */ 0,
487 /* desiredLineWidth= */ 16,
488 /* desiredDepth= */ 7);
489
490 auto destII = SkImageInfo::Make(kImageSize, kImageSize,
491 kRGBA_8888_SkColorType,
492 kPremul_SkAlphaType);
493
494 SkBitmap readback;
495 readback.allocPixels(destII);
496
497 sk_sp<SkSurface> surface;
498
499 #if defined(SK_GANESH)
500 if (dContext) {
501 surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, destII);
502 }
503 #endif
504
505 #if defined(SK_GRAPHITE)
506 if (recorder) {
507 surface = SkSurfaces::RenderTarget(recorder, destII);
508 }
509 #endif
510
511 if (!surface) {
512 return;
513 }
514
515 SkCanvas* canvas = surface->getCanvas();
516
517 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
518 gOverrideMaxTextureSizeGanesh = kOverrideMaxTextureSize;
519 #endif
520 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
521 gOverrideMaxTextureSizeGraphite = kOverrideMaxTextureSize;
522 #endif
523 for (int i = 0; i < 2; ++i) {
524 canvas->clear(SK_ColorBLACK);
525
526 SkTiledImageUtils::DrawImage(canvas, img,
527 /* x= */ 0, /* y= */ 0,
528 SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone),
529 /* paint= */ nullptr,
530 SkCanvas::kFast_SrcRectConstraint);
531 SkAssertResult(surface->readPixels(readback, 0, 0));
532 }
533
534 int numFound = 0;
535
536 #if defined(SK_GANESH)
537 if (dContext) {
538 GrResourceCache* cache = dContext->priv().getResourceCache();
539
540 cache->visitSurfaces([&](const GrSurface* surf, bool /* purgeable */) {
541 const GrTexture* tex = surf->asTexture();
542 if (tex && tex->dimensions() == kExpectedTileSize) {
543 ++numFound;
544 }
545 });
546 }
547 #endif
548
549 #if defined(SK_GRAPHITE)
550 if (recorder) {
551 skgpu::graphite::ResourceCache* cache = recorder->priv().resourceCache();
552
553 cache->visitTextures([&](const skgpu::graphite::Texture* tex, bool /* purgeable */) {
554 if (tex->dimensions() == kExpectedTileSize) {
555 ++numFound;
556 }
557 });
558 }
559 #endif
560
561 REPORTER_ASSERT(reporter, numFound == 16, "Expected: 16 Actual: %d", numFound);
562
563 // reset to default behavior
564 #if defined(SK_GANESH) && defined(GR_TEST_UTILS)
565 gOverrideMaxTextureSizeGanesh = 0;
566 #endif
567 #if defined(SK_GRAPHITE) && defined(GRAPHITE_TEST_UTILS)
568 gOverrideMaxTextureSizeGraphite = 0;
569 #endif
570 }
571
572 } // anonymous namespace
573
574 #if defined(SK_GANESH)
575
576 // TODO(b/306005622): fix in SkQP and move to CtsEnforcement::kNextRelease
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Ganesh,reporter,ctxInfo,CtsEnforcement::kNever)577 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Ganesh,
578 reporter,
579 ctxInfo,
580 CtsEnforcement::kNever) {
581 auto dContext = ctxInfo.directContext();
582
583 tiling_comparison_test(dContext, /* recorder= */ nullptr, reporter);
584 }
585
586 // TODO(b/306005622): fix in SkQP and move to CtsEnforcement::kNextRelease
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Ganesh,reporter,ctxInfo,CtsEnforcement::kNever)587 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Ganesh,
588 reporter,
589 ctxInfo,
590 CtsEnforcement::kNever) {
591 auto dContext = ctxInfo.directContext();
592
593 tiled_image_caching_test(dContext, /* recorder= */ nullptr, reporter);
594 }
595
596 #endif // SK_GANESH
597
598 #if defined(SK_GRAPHITE)
599
600 // TODO(b/306005622): fix in SkQP and move to CtsEnforcement::kNextRelease
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Graphite,reporter,context,CtsEnforcement::kNever)601 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Graphite,
602 reporter,
603 context,
604 CtsEnforcement::kNever) {
605 std::unique_ptr<skgpu::graphite::Recorder> recorder =
606 context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
607
608 tiling_comparison_test(/* dContext= */ nullptr, recorder.get(), reporter);
609 }
610
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Graphite,reporter,context,CtsEnforcement::kNextRelease)611 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Graphite,
612 reporter,
613 context,
614 CtsEnforcement::kNextRelease) {
615 std::unique_ptr<skgpu::graphite::Recorder> recorder =
616 context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
617
618 tiled_image_caching_test(/* dContext= */ nullptr, recorder.get(), reporter);
619 }
620
621 #endif // SK_GRAPHITE
622