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/ganesh/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/graphite/GraphiteToolUtils.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(GPU_TEST_UTILS)
68 extern int gOverrideMaxTextureSizeGanesh;
69 extern std::atomic<int> gNumTilesDrawnGanesh;
70 #endif
71
72 #if defined(SK_GRAPHITE) && defined(GPU_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 // Max size of created images accounting for 45 degree rotation.
273 static const int kMaxRotatedImageSize = std::ceil(kImageSize * std::sqrt(2.0));
274
275 #if defined(SK_GANESH)
276 if (dContext && dContext->maxTextureSize() < kMaxRotatedImageSize) {
277 // For the expected images we need to be able to draw w/o tiling
278 return;
279 }
280 #endif
281
282 #if defined(SK_GRAPHITE)
283 if (recorder) {
284 const skgpu::graphite::Caps* caps = recorder->priv().caps();
285 if (caps->maxTextureSize() < kMaxRotatedImageSize) {
286 return;
287 }
288 }
289 #endif
290
291 static const int kWhiteBandWidth = 4;
292 const SkRect srcRect = SkRect::MakeIWH(kImageSize, kImageSize).makeInset(kWhiteBandWidth,
293 kWhiteBandWidth);
294
295 using GeneratorT = sk_sp<SkImage>(*)(int imgSize, int whiteBandWidth,
296 int desiredLineWidth, int desiredDepth);
297
298 static const struct {
299 GeneratorT fGen;
300 const char* fTag;
301 } kGenerators[] = { { make_big_bitmap_image, "BM" },
302 { make_big_picture_image, "Picture" } };
303
304 static const SkSamplingOptions kSamplingOptions[] = {
305 SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone),
306 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
307 // Note that Mipmapping gets auto-disabled with a strict-constraint
308 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
309 SkSamplingOptions(SkCubicResampler::CatmullRom()),
310 };
311
312 int numClippedTiles = 9;
313 for (auto gen : kGenerators) {
314 sk_sp<SkImage> img = (*gen.fGen)(kImageSize,
315 kWhiteBandWidth,
316 /* desiredLineWidth= */ 16,
317 /* desiredDepth= */ 7);
318 numClippedTiles = (numClippedTiles == 9) ? 4 : 9; // alternate to reduce the combinatorics
319
320 for (int scale : { 1, 4, 8 }) {
321 for (int rot : { 0, 45 }) {
322 for (int numDesiredTiles : { numClippedTiles, 16 }) {
323 SkRect destRect = SkRect::MakeWH(srcRect.width()/scale,
324 srcRect.height()/scale);
325
326 SkMatrix m = SkMatrix::RotateDeg(rot, destRect.center());
327 SkIRect rotatedRect = m.mapRect(destRect).roundOut();
328 rotatedRect.outset(2, 2); // outset to capture the constraint's effect
329
330 SkRect clipRect = clip_rect(destRect, numDesiredTiles);
331
332 auto destII = SkImageInfo::Make(rotatedRect.width(),
333 rotatedRect.height(),
334 kRGBA_8888_SkColorType,
335 kPremul_SkAlphaType);
336
337 SkBitmap expected, actual;
338 expected.allocPixels(destII);
339 actual.allocPixels(destII);
340
341 sk_sp<SkSurface> surface;
342
343 #if defined(SK_GANESH)
344 if (dContext) {
345 surface = SkSurfaces::RenderTarget(dContext,
346 skgpu::Budgeted::kNo,
347 destII);
348 }
349 #endif
350
351 #if defined(SK_GRAPHITE)
352 if (recorder) {
353 surface = SkSurfaces::RenderTarget(recorder, destII);
354 }
355 #endif
356
357 if (!surface) {
358 ERRORF(reporter, "Failed to create surface");
359 return;
360 }
361
362 for (auto sampling : kSamplingOptions) {
363 for (auto constraint : { SkCanvas::kStrict_SrcRectConstraint,
364 SkCanvas::kFast_SrcRectConstraint }) {
365 if (difficult_case(sampling, scale, rot, constraint)) {
366 continue;
367 }
368
369 SkString label = create_label(dContext, gen.fTag, sampling, scale, rot,
370 constraint, numDesiredTiles);
371
372 SkCanvas* canvas = surface->getCanvas();
373
374 SkAutoCanvasRestore acr(canvas, /* doSave= */ true);
375
376 canvas->translate(-rotatedRect.fLeft, -rotatedRect.fTop);
377 if (sampling.useCubic || sampling.filter != SkFilterMode::kNearest) {
378 // NN sampling doesn't deal well w/ the (0.5, 0.5) offset but the
379 // other sampling modes need it to exercise strict vs. fast
380 // constraint in non-rotated draws
381 canvas->translate(0.5f, 0.5f);
382 }
383 canvas->concat(m);
384
385 // First, draw w/o tiling
386 #if defined(SK_GANESH) && defined(GPU_TEST_UTILS)
387 gOverrideMaxTextureSizeGanesh = 0;
388 #endif
389 #if defined(SK_GRAPHITE) && defined(GPU_TEST_UTILS)
390 gOverrideMaxTextureSizeGraphite = 0;
391 #endif
392 canvas->clear(SK_ColorBLACK);
393 canvas->save();
394 canvas->clipRect(clipRect);
395
396 SkTiledImageUtils::DrawImageRect(canvas, img, srcRect, destRect,
397 sampling, /* paint= */ nullptr,
398 constraint);
399 SkAssertResult(surface->readPixels(expected, 0, 0));
400 #if defined(SK_GANESH) && defined(GPU_TEST_UTILS)
401 if (canvas->recordingContext()) {
402 int actualNumTiles =
403 gNumTilesDrawnGanesh.load(std::memory_order_acquire);
404 REPORTER_ASSERT(reporter, actualNumTiles == 0);
405 }
406 #endif
407 #if defined(SK_GRAPHITE) && defined(GPU_TEST_UTILS)
408 if (canvas->recorder()) {
409 int actualNumTiles =
410 gNumTilesDrawnGraphite.load(std::memory_order_acquire);
411 REPORTER_ASSERT(reporter, actualNumTiles == 0);
412 }
413 #endif
414 canvas->restore();
415
416 // Then, force 4x4 tiling
417 #if defined(SK_GANESH) && defined(GPU_TEST_UTILS)
418 gOverrideMaxTextureSizeGanesh = kOverrideMaxTextureSize;
419 #endif
420 #if defined(SK_GRAPHITE) && defined(GPU_TEST_UTILS)
421 gOverrideMaxTextureSizeGraphite = kOverrideMaxTextureSize;
422 #endif
423
424 canvas->clear(SK_ColorBLACK);
425 canvas->save();
426 canvas->clipRect(clipRect);
427
428 SkTiledImageUtils::DrawImageRect(canvas, img, srcRect, destRect,
429 sampling, /* paint= */ nullptr,
430 constraint);
431 SkAssertResult(surface->readPixels(actual, 0, 0));
432 #if defined(SK_GANESH) && defined(GPU_TEST_UTILS)
433 if (canvas->recordingContext()) {
434 int actualNumTiles =
435 gNumTilesDrawnGanesh.load(std::memory_order_acquire);
436 REPORTER_ASSERT(reporter,
437 numDesiredTiles == actualNumTiles,
438 "mismatch expected: %d actual: %d\n",
439 numDesiredTiles,
440 actualNumTiles);
441 }
442 #endif
443 #if defined(SK_GRAPHITE) && defined(GPU_TEST_UTILS)
444 if (canvas->recorder()) {
445 int actualNumTiles =
446 gNumTilesDrawnGraphite.load(std::memory_order_acquire);
447 REPORTER_ASSERT(reporter,
448 numDesiredTiles == actualNumTiles,
449 "mismatch expected: %d actual: %d\n",
450 numDesiredTiles,
451 actualNumTiles);
452 }
453 #endif
454
455 canvas->restore();
456
457 REPORTER_ASSERT(reporter, check_pixels(reporter, expected, actual,
458 label, rot));
459
460 potentially_write_to_png("expected", label, expected);
461 potentially_write_to_png("actual", label, actual);
462 }
463 }
464 }
465 }
466 }
467 }
468 // Reset tiling behavior
469 #if defined(SK_GANESH) && defined(GPU_TEST_UTILS)
470 gOverrideMaxTextureSizeGanesh = 0;
471 #endif
472 #if defined(SK_GRAPHITE) && defined(GPU_TEST_UTILS)
473 gOverrideMaxTextureSizeGraphite = 0;
474 #endif
475 }
476
477 // In this test we draw the same bitmap-backed image twice and check that we only upload it once.
478 // 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)479 void tiled_image_caching_test(GrDirectContext* dContext,
480 skgpu::graphite::Recorder* recorder,
481 skiatest::Reporter* reporter) {
482 static const int kImageSize = 4096;
483 static const int kOverrideMaxTextureSize = 1024;
484 static const SkISize kExpectedTileSize { kOverrideMaxTextureSize, kOverrideMaxTextureSize };
485
486 sk_sp<SkImage> img = make_big_bitmap_image(kImageSize,
487 /* whiteBandWidth= */ 0,
488 /* desiredLineWidth= */ 16,
489 /* desiredDepth= */ 7);
490
491 auto destII = SkImageInfo::Make(kImageSize, kImageSize,
492 kRGBA_8888_SkColorType,
493 kPremul_SkAlphaType);
494
495 SkBitmap readback;
496 readback.allocPixels(destII);
497
498 sk_sp<SkSurface> surface;
499
500 #if defined(SK_GANESH)
501 if (dContext) {
502 surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, destII);
503 }
504 #endif
505
506 #if defined(SK_GRAPHITE)
507 if (recorder) {
508 surface = SkSurfaces::RenderTarget(recorder, destII);
509 }
510 #endif
511
512 if (!surface) {
513 return;
514 }
515
516 SkCanvas* canvas = surface->getCanvas();
517
518 #if defined(SK_GANESH) && defined(GPU_TEST_UTILS)
519 gOverrideMaxTextureSizeGanesh = kOverrideMaxTextureSize;
520 #endif
521 #if defined(SK_GRAPHITE) && defined(GPU_TEST_UTILS)
522 gOverrideMaxTextureSizeGraphite = kOverrideMaxTextureSize;
523 #endif
524 for (int i = 0; i < 2; ++i) {
525 canvas->clear(SK_ColorBLACK);
526
527 SkTiledImageUtils::DrawImage(canvas, img,
528 /* x= */ 0, /* y= */ 0,
529 SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone),
530 /* paint= */ nullptr,
531 SkCanvas::kFast_SrcRectConstraint);
532 SkAssertResult(surface->readPixels(readback, 0, 0));
533 }
534
535 int numFound = 0;
536
537 #if defined(SK_GANESH)
538 if (dContext) {
539 GrResourceCache* cache = dContext->priv().getResourceCache();
540
541 cache->visitSurfaces([&](const GrSurface* surf, bool /* purgeable */) {
542 const GrTexture* tex = surf->asTexture();
543 if (tex && tex->dimensions() == kExpectedTileSize) {
544 ++numFound;
545 }
546 });
547 }
548 #endif
549
550 #if defined(SK_GRAPHITE)
551 if (recorder) {
552 skgpu::graphite::ResourceCache* cache = recorder->priv().resourceCache();
553
554 cache->visitTextures([&](const skgpu::graphite::Texture* tex, bool /* purgeable */) {
555 if (tex->dimensions() == kExpectedTileSize) {
556 ++numFound;
557 }
558 });
559 }
560 #endif
561
562 REPORTER_ASSERT(reporter, numFound == 16, "Expected: 16 Actual: %d", numFound);
563
564 // reset to default behavior
565 #if defined(SK_GANESH) && defined(GPU_TEST_UTILS)
566 gOverrideMaxTextureSizeGanesh = 0;
567 #endif
568 #if defined(SK_GRAPHITE) && defined(GPU_TEST_UTILS)
569 gOverrideMaxTextureSizeGraphite = 0;
570 #endif
571 }
572
573 } // anonymous namespace
574
575 #if defined(SK_GANESH)
576
577 // TODO(b/306005622): fix in SkQP and move to CtsEnforcement::kNextRelease
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Ganesh,reporter,ctxInfo,CtsEnforcement::kNever)578 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Ganesh,
579 reporter,
580 ctxInfo,
581 CtsEnforcement::kNever) {
582 auto dContext = ctxInfo.directContext();
583
584 tiling_comparison_test(dContext, /* recorder= */ nullptr, reporter);
585 }
586
587 // TODO(b/306005622): fix in SkQP and move to CtsEnforcement::kNextRelease
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Ganesh,reporter,ctxInfo,CtsEnforcement::kNever)588 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Ganesh,
589 reporter,
590 ctxInfo,
591 CtsEnforcement::kNever) {
592 auto dContext = ctxInfo.directContext();
593
594 tiled_image_caching_test(dContext, /* recorder= */ nullptr, reporter);
595 }
596
597 #endif // SK_GANESH
598
599 #if defined(SK_GRAPHITE)
600
601 // TODO(b/306005622): fix in SkQP and move to CtsEnforcement::kNextRelease
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Graphite,reporter,context,CtsEnforcement::kNever)602 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(BigImageTest_Graphite,
603 reporter,
604 context,
605 CtsEnforcement::kNever) {
606 std::unique_ptr<skgpu::graphite::Recorder> recorder =
607 context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
608
609 tiling_comparison_test(/* dContext= */ nullptr, recorder.get(), reporter);
610 }
611
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Graphite,reporter,context,CtsEnforcement::kApiLevel_V)612 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(TiledDrawCacheTest_Graphite,
613 reporter,
614 context,
615 CtsEnforcement::kApiLevel_V) {
616 std::unique_ptr<skgpu::graphite::Recorder> recorder =
617 context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
618
619 tiled_image_caching_test(/* dContext= */ nullptr, recorder.get(), reporter);
620 }
621
622 #endif // SK_GRAPHITE
623