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 "tests/Test.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkPixmap.h"
13 #include "include/core/SkPoint.h"
14 #include "include/gpu/graphite/Context.h"
15 #include "include/gpu/graphite/Recorder.h"
16 #include "include/gpu/graphite/Recording.h"
17 #include "include/gpu/graphite/Surface.h"
18 #include "src/gpu/graphite/RecordingPriv.h"
19 #include "src/gpu/graphite/Surface_Graphite.h"
20
21 namespace skgpu::graphite {
22
23 constexpr SkIVector kNoOffset = SkIVector::Make(0, 0);
24 constexpr SkIRect kEmptyClip = SkIRect::MakeEmpty();
25
26 using DrawCallback = std::function<void(SkCanvas*)>;
27
28 struct Expectation {
29 int fX;
30 int fY;
31 SkColor4f fColor;
32 };
33
run_test(skiatest::Reporter * reporter,Context * context,SkISize surfaceSize,SkISize recordingSize,SkIVector replayOffset,SkIRect replayClip,skgpu::Mipmapped canvasMipmapped,skgpu::Mipmapped targetMipmapped,DrawCallback draw,const std::vector<Expectation> & expectations)34 void run_test(skiatest::Reporter* reporter,
35 Context* context,
36 SkISize surfaceSize,
37 SkISize recordingSize,
38 SkIVector replayOffset,
39 SkIRect replayClip,
40 skgpu::Mipmapped canvasMipmapped,
41 skgpu::Mipmapped targetMipmapped,
42 DrawCallback draw,
43 const std::vector<Expectation>& expectations) {
44 const SkImageInfo surfaceImageInfo = SkImageInfo::Make(
45 surfaceSize, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType);
46
47 std::unique_ptr<Recorder> surfaceRecorder = context->makeRecorder();
48 sk_sp<SkSurface> surface =
49 SkSurfaces::RenderTarget(surfaceRecorder.get(), surfaceImageInfo, canvasMipmapped);
50 Surface* graphiteSurface = static_cast<Surface*>(surface.get());
51 const TextureInfo& textureInfo = graphiteSurface->backingTextureProxy()->textureInfo();
52
53 // Flush the initial clear added by MakeGraphite.
54 std::unique_ptr<skgpu::graphite::Recording> surfaceRecording = surfaceRecorder->snap();
55 context->insertRecording({surfaceRecording.get()});
56
57 // Snap a recording without a bound target.
58 const SkImageInfo recordingImageInfo = surfaceImageInfo.makeDimensions(recordingSize);
59 std::unique_ptr<Recorder> recorder = context->makeRecorder();
60 SkCanvas* canvas = recorder->makeDeferredCanvas(recordingImageInfo, textureInfo);
61 draw(canvas);
62 std::unique_ptr<Recording> recording = recorder->snap();
63
64 // Play back recording. If the mipmap settings don't match, we have to create a new surface.
65 if (canvasMipmapped != targetMipmapped) {
66 surface =
67 SkSurfaces::RenderTarget(surfaceRecorder.get(), surfaceImageInfo, targetMipmapped);
68 // Flush the initial clear for this new surface.
69 surfaceRecording = surfaceRecorder->snap();
70 context->insertRecording({surfaceRecording.get()});
71 }
72 context->insertRecording({recording.get(), surface.get(), replayOffset, replayClip});
73
74 // Read pixels.
75 SkBitmap bitmap;
76 SkPixmap pixmap;
77 bitmap.allocPixels(surfaceImageInfo);
78 SkAssertResult(bitmap.peekPixels(&pixmap));
79 if (!surface->readPixels(pixmap, 0, 0)) {
80 ERRORF(reporter, "readPixels failed");
81 return;
82 }
83
84 // Veryify expectations are met and recording is uninstantiated.
85 REPORTER_ASSERT(reporter, !recording->priv().isTargetProxyInstantiated());
86 for (const Expectation& e : expectations) {
87 SkColor4f color = pixmap.getColor4f(e.fX, e.fY);
88 #ifdef SK_DEBUG
89 if (color != e.fColor) {
90 SkDebugf("Wrong color at %d, %d\n\texpected: %f %f %f %f\n\tactual: %f %f %f %f",
91 e.fX,
92 e.fY,
93 e.fColor.fR,
94 e.fColor.fG,
95 e.fColor.fB,
96 e.fColor.fA,
97 color.fR,
98 color.fG,
99 color.fB,
100 color.fA);
101 }
102 #endif
103 REPORTER_ASSERT(reporter, color == e.fColor);
104 }
105 }
106
107 // Tests that clear does not clear an entire replayed-to surface if recorded onto a smaller surface.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestClear,reporter,context,CtsEnforcement::kApiLevel_202404)108 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestClear, reporter, context,
109 CtsEnforcement::kApiLevel_202404) {
110 SkISize surfaceSize = SkISize::Make(8, 4);
111 SkISize recordingSize = SkISize::Make(4, 4);
112
113 auto draw = [](SkCanvas* canvas) { canvas->clear(SkColors::kRed); };
114
115 std::vector<Expectation> expectations = {{0, 0, SkColors::kRed},
116 {4, 0, SkColors::kTransparent}};
117
118 run_test(reporter,
119 context,
120 surfaceSize,
121 recordingSize,
122 kNoOffset,
123 kEmptyClip,
124 skgpu::Mipmapped::kNo,
125 skgpu::Mipmapped::kNo,
126 draw,
127 expectations);
128 }
129
130 // Tests that a draw is translated correctly when replayed with an offset.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestDraw,reporter,context,CtsEnforcement::kApiLevel_202504)131 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestDraw, reporter, context,
132 CtsEnforcement::kApiLevel_202504) {
133 SkISize surfaceSize = SkISize::Make(8, 4);
134 SkISize recordingSize = SkISize::Make(4, 4);
135 SkIVector replayOffset = SkIVector::Make(4, 0);
136
137 auto draw = [](SkCanvas* canvas) {
138 canvas->drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), SkPaint(SkColors::kRed));
139 };
140
141
142 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
143 {4, 0, SkColors::kRed}};
144
145 run_test(reporter,
146 context,
147 surfaceSize,
148 recordingSize,
149 replayOffset,
150 kEmptyClip,
151 skgpu::Mipmapped::kNo,
152 skgpu::Mipmapped::kNo,
153 draw,
154 expectations);
155 }
156
157 // Tests that writePixels is translated correctly when replayed with an offset.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixels,reporter,context,CtsEnforcement::kApiLevel_202404)158 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixels, reporter, context,
159 CtsEnforcement::kApiLevel_202404) {
160 SkBitmap bitmap;
161 bitmap.allocN32Pixels(4, 4, true);
162 SkCanvas bitmapCanvas(bitmap);
163 SkPaint paint;
164 paint.setColor(SkColors::kRed);
165 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
166
167 SkISize surfaceSize = SkISize::Make(8, 4);
168 SkISize recordingSize = SkISize::Make(4, 4);
169 SkIVector replayOffset = SkIVector::Make(4, 0);
170
171 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
172
173 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
174 {4, 0, SkColors::kRed}};
175
176 run_test(reporter,
177 context,
178 surfaceSize,
179 recordingSize,
180 replayOffset,
181 kEmptyClip,
182 skgpu::Mipmapped::kNo,
183 skgpu::Mipmapped::kNo,
184 draw,
185 expectations);
186 }
187
188 // Tests that the result of writePixels is cropped correctly when offscreen.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsOffscreen,reporter,context,CtsEnforcement::kApiLevel_202404)189 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsOffscreen, reporter, context,
190 CtsEnforcement::kApiLevel_202404) {
191 SkBitmap bitmap;
192 bitmap.allocN32Pixels(4, 4, true);
193 SkCanvas bitmapCanvas(bitmap);
194 SkPaint paint;
195 paint.setColor(SkColors::kRed);
196 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
197 paint.setColor(SkColors::kGreen);
198 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(2, 2, 2, 2), paint);
199
200 SkISize surfaceSize = SkISize::Make(4, 4);
201 SkISize recordingSize = SkISize::Make(4, 4);
202 SkIVector replayOffset = SkIVector::Make(-2, -2);
203
204 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
205
206 std::vector<Expectation> expectations = {{0, 0, SkColors::kGreen}};
207
208 run_test(reporter,
209 context,
210 surfaceSize,
211 recordingSize,
212 replayOffset,
213 kEmptyClip,
214 skgpu::Mipmapped::kNo,
215 skgpu::Mipmapped::kNo,
216 draw,
217 expectations);
218 }
219
220 // Tests that the result of a draw is cropped correctly with a provided clip on replay.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestDrawWithClip,reporter,context,CtsEnforcement::kApiLevel_202504)221 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestDrawWithClip, reporter, context,
222 CtsEnforcement::kApiLevel_202504) {
223 SkISize surfaceSize = SkISize::Make(8, 4);
224 SkISize recordingSize = SkISize::Make(8, 4);
225
226 auto draw = [](SkCanvas* canvas) {
227 canvas->drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), SkPaint(SkColors::kRed));
228 canvas->drawIRect(SkIRect::MakeXYWH(4, 0, 4, 4), SkPaint(SkColors::kGreen));
229 };
230
231 {
232 // Test that the clip applies in translated space.
233 SkIVector replayOffset = SkIVector::Make(4, 0);
234 SkIRect replayClip = SkIRect::MakeXYWH(0, 0, 2, 4);
235
236 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
237 {4, 0, SkColors::kRed},
238 {6, 0, SkColors::kTransparent}};
239
240 run_test(reporter,
241 context,
242 surfaceSize,
243 recordingSize,
244 replayOffset,
245 replayClip,
246 skgpu::Mipmapped::kNo,
247 skgpu::Mipmapped::kNo,
248 draw,
249 expectations);
250 }
251
252 {
253 // Test that the draw is not translated by the clip.
254 SkIRect replayClip = SkIRect::MakeXYWH(4, 0, 2, 4);
255
256 std::vector<Expectation> expectations = {{4, 0, SkColors::kGreen}};
257
258 run_test(reporter,
259 context,
260 surfaceSize,
261 recordingSize,
262 kNoOffset,
263 replayClip,
264 skgpu::Mipmapped::kNo,
265 skgpu::Mipmapped::kNo,
266 draw,
267 expectations);
268 }
269 }
270
271 // Tests that a scissor translated to negative coordinates is applied correctly.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestNegativeClip,reporter,context,CtsEnforcement::kNextRelease)272 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestNegativeClip, reporter, context,
273 CtsEnforcement::kNextRelease) {
274 SkISize surfaceSize = SkISize::Make(4, 4);
275 SkISize recordingSize = SkISize::Make(4, 4);
276
277 auto draw = [](SkCanvas* canvas) {
278 canvas->clipIRect(SkIRect::MakeWH(4, 4));
279 canvas->drawIRect(SkIRect::MakeWH(4, 4), SkPaint(SkColors::kRed));
280 };
281
282 SkIVector replayOffset = SkIVector::Make(-2, 0);
283
284 std::vector<Expectation> expectations = {{0, 0, SkColors::kRed},
285 {2, 0, SkColors::kTransparent}};
286
287 run_test(reporter,
288 context,
289 surfaceSize,
290 recordingSize,
291 replayOffset,
292 kEmptyClip,
293 skgpu::Mipmapped::kNo,
294 skgpu::Mipmapped::kNo,
295 draw,
296 expectations);
297 }
298
299 // Tests that the result of writePixels is cropped correctly with a provided clip on replay.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsWithClip,reporter,context,CtsEnforcement::kApiLevel_202504)300 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsWithClip, reporter, context,
301 CtsEnforcement::kApiLevel_202504) {
302 SkBitmap bitmap;
303 bitmap.allocN32Pixels(4, 4, true);
304 SkCanvas bitmapCanvas(bitmap);
305 SkPaint paint;
306 paint.setColor(SkColors::kRed);
307 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
308
309 SkISize surfaceSize = SkISize::Make(8, 4);
310 SkISize recordingSize = SkISize::Make(4, 4);
311 SkIVector replayOffset = SkIVector::Make(4, 0);
312 SkIRect replayClip = SkIRect::MakeXYWH(0, 0, 2, 4);
313
314 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
315
316 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
317 {4, 0, SkColors::kRed},
318 {6, 0, SkColors::kTransparent}};
319
320 run_test(reporter,
321 context,
322 surfaceSize,
323 recordingSize,
324 replayOffset,
325 replayClip,
326 skgpu::Mipmapped::kNo,
327 skgpu::Mipmapped::kNo,
328 draw,
329 expectations);
330 }
331
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmapped,reporter,context,CtsEnforcement::kApiLevel_202504)332 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmapped, reporter, context,
333 CtsEnforcement::kApiLevel_202504) {
334 SkISize recordingSize = SkISize::Make(1, 1);
335
336 auto draw = [](SkCanvas* canvas) { canvas->clear(SkColors::kRed); };
337
338 {
339 SkISize surfaceSize = SkISize::Make(1, 1);
340
341 std::vector<Expectation> expectations = {{0, 0, SkColors::kRed}};
342
343 run_test(reporter,
344 context,
345 surfaceSize,
346 recordingSize,
347 kNoOffset,
348 kEmptyClip,
349 skgpu::Mipmapped::kYes,
350 skgpu::Mipmapped::kYes,
351 draw,
352 expectations);
353 }
354
355 {
356 // Test that draw fails if canvas and surface mipmap settings don't match.
357 SkISize surfaceSize = SkISize::Make(1, 1);
358
359 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
360
361 run_test(reporter,
362 context,
363 surfaceSize,
364 recordingSize,
365 kNoOffset,
366 kEmptyClip,
367 skgpu::Mipmapped::kYes,
368 skgpu::Mipmapped::kNo,
369 draw,
370 expectations);
371
372 run_test(reporter,
373 context,
374 surfaceSize,
375 recordingSize,
376 kNoOffset,
377 kEmptyClip,
378 skgpu::Mipmapped::kNo,
379 skgpu::Mipmapped::kYes,
380 draw,
381 expectations);
382 }
383
384 {
385 // Test that draw fails if canvas and surface dimensions don't match.
386 SkISize surfaceSize = SkISize::Make(2, 1);
387
388 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
389
390 run_test(reporter,
391 context,
392 surfaceSize,
393 recordingSize,
394 kNoOffset,
395 kEmptyClip,
396 skgpu::Mipmapped::kYes,
397 skgpu::Mipmapped::kYes,
398 draw,
399 expectations);
400 }
401
402 {
403 // Test that draw fails if offset is provided.
404 SkISize surfaceSize = SkISize::Make(1, 1);
405 SkIVector replayOffset = SkIVector::Make(1, 0);
406
407 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
408
409 run_test(reporter,
410 context,
411 surfaceSize,
412 recordingSize,
413 replayOffset,
414 kEmptyClip,
415 skgpu::Mipmapped::kYes,
416 skgpu::Mipmapped::kYes,
417 draw,
418 expectations);
419 }
420
421 {
422 // Test that draw fails if clip is provided.
423 SkISize surfaceSize = SkISize::Make(1, 1);
424 SkIRect replayClip = SkIRect::MakeXYWH(0, 0, 1, 1);
425
426 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
427
428 run_test(reporter,
429 context,
430 surfaceSize,
431 recordingSize,
432 kNoOffset,
433 replayClip,
434 skgpu::Mipmapped::kYes,
435 skgpu::Mipmapped::kYes,
436 draw,
437 expectations);
438 }
439 }
440
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmappedWritePixels,reporter,context,CtsEnforcement::kApiLevel_202504)441 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmappedWritePixels, reporter, context,
442 CtsEnforcement::kApiLevel_202504) {
443 SkBitmap bitmap;
444 bitmap.allocN32Pixels(1, 1, true);
445 SkCanvas bitmapCanvas(bitmap);
446 SkPaint paint;
447 paint.setColor(SkColors::kRed);
448 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 1, 1), paint);
449
450 SkISize recordingSize = SkISize::Make(1, 1);
451 SkISize surfaceSize = SkISize::Make(1, 1);
452
453 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
454
455 std::vector<Expectation> expectations = {{0, 0, SkColors::kRed}};
456
457 run_test(reporter,
458 context,
459 surfaceSize,
460 recordingSize,
461 kNoOffset,
462 kEmptyClip,
463 skgpu::Mipmapped::kYes,
464 skgpu::Mipmapped::kYes,
465 draw,
466 expectations);
467 }
468
469 // Tests that you can't create two deferred canvases before snapping the first.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestTwoCanvases,reporter,context,CtsEnforcement::kApiLevel_202504)470 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestTwoCanvases, reporter, context,
471 CtsEnforcement::kApiLevel_202504) {
472 const SkImageInfo kImageInfo = SkImageInfo::Make(SkISize::Make(1, 1),
473 SkColorType::kRGBA_8888_SkColorType,
474 SkAlphaType::kPremul_SkAlphaType);
475 std::unique_ptr<Recorder> recorder = context->makeRecorder();
476 sk_sp<SkSurface> surface =
477 SkSurfaces::RenderTarget(recorder.get(), kImageInfo, skgpu::Mipmapped::kNo);
478 const TextureInfo& textureInfo =
479 static_cast<Surface*>(surface.get())->backingTextureProxy()->textureInfo();
480
481 // First canvas is created successfully.
482 REPORTER_ASSERT(reporter, recorder->makeDeferredCanvas(kImageInfo, textureInfo) != nullptr);
483 // Second canvas fails to be created.
484 REPORTER_ASSERT(reporter, recorder->makeDeferredCanvas(kImageInfo, textureInfo) == nullptr);
485 }
486
487 // Tests that inserting a recording with a surface does not crash even if no draws to a deferred
488 // canvas were recorded.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestUnnecessarySurface,reporter,context,CtsEnforcement::kApiLevel_202504)489 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestUnnecessarySurface, reporter, context,
490 CtsEnforcement::kApiLevel_202504) {
491 const SkImageInfo kImageInfo = SkImageInfo::Make(SkISize::Make(1, 1),
492 SkColorType::kRGBA_8888_SkColorType,
493 SkAlphaType::kPremul_SkAlphaType);
494 std::unique_ptr<Recorder> recorder = context->makeRecorder();
495
496 sk_sp<SkSurface> surface =
497 SkSurfaces::RenderTarget(recorder.get(), kImageInfo, skgpu::Mipmapped::kNo);
498 std::unique_ptr<Recording> recording = recorder->snap();
499 REPORTER_ASSERT(reporter, context->insertRecording({recording.get(), surface.get()}));
500 }
501
502 } // namespace skgpu::graphite
503