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\n\texpected: %f %f %f %f\n\tactual: %f %f %f %f",
91 e.fColor.fR,
92 e.fColor.fG,
93 e.fColor.fB,
94 e.fColor.fA,
95 color.fR,
96 color.fG,
97 color.fB,
98 color.fA);
99 }
100 #endif
101 REPORTER_ASSERT(reporter, color == e.fColor);
102 }
103 }
104
105 // 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_V)106 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestClear, reporter, context,
107 CtsEnforcement::kApiLevel_V) {
108 SkISize surfaceSize = SkISize::Make(8, 4);
109 SkISize recordingSize = SkISize::Make(4, 4);
110
111 auto draw = [](SkCanvas* canvas) { canvas->clear(SkColors::kRed); };
112
113 std::vector<Expectation> expectations = {{0, 0, SkColors::kRed},
114 {4, 0, SkColors::kTransparent}};
115
116 run_test(reporter,
117 context,
118 surfaceSize,
119 recordingSize,
120 kNoOffset,
121 kEmptyClip,
122 skgpu::Mipmapped::kNo,
123 skgpu::Mipmapped::kNo,
124 draw,
125 expectations);
126 }
127
128 // Tests that a draw is translated correctly when replayed with an offset.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestDraw,reporter,context,CtsEnforcement::kNextRelease)129 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestDraw, reporter, context,
130 CtsEnforcement::kNextRelease) {
131 SkISize surfaceSize = SkISize::Make(8, 4);
132 SkISize recordingSize = SkISize::Make(4, 4);
133 SkIVector replayOffset = SkIVector::Make(4, 0);
134
135 auto draw = [](SkCanvas* canvas) {
136 canvas->drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), SkPaint(SkColors::kRed));
137 };
138
139
140 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
141 {4, 0, SkColors::kRed}};
142
143 run_test(reporter,
144 context,
145 surfaceSize,
146 recordingSize,
147 replayOffset,
148 kEmptyClip,
149 skgpu::Mipmapped::kNo,
150 skgpu::Mipmapped::kNo,
151 draw,
152 expectations);
153 }
154
155 // Tests that writePixels is translated correctly when replayed with an offset.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixels,reporter,context,CtsEnforcement::kApiLevel_V)156 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixels, reporter, context,
157 CtsEnforcement::kApiLevel_V) {
158 SkBitmap bitmap;
159 bitmap.allocN32Pixels(4, 4, true);
160 SkCanvas bitmapCanvas(bitmap);
161 SkPaint paint;
162 paint.setColor(SkColors::kRed);
163 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
164
165 SkISize surfaceSize = SkISize::Make(8, 4);
166 SkISize recordingSize = SkISize::Make(4, 4);
167 SkIVector replayOffset = SkIVector::Make(4, 0);
168
169 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
170
171 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
172 {4, 0, SkColors::kRed}};
173
174 run_test(reporter,
175 context,
176 surfaceSize,
177 recordingSize,
178 replayOffset,
179 kEmptyClip,
180 skgpu::Mipmapped::kNo,
181 skgpu::Mipmapped::kNo,
182 draw,
183 expectations);
184 }
185
186 // Tests that the result of writePixels is cropped correctly when offscreen.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsOffscreen,reporter,context,CtsEnforcement::kApiLevel_V)187 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsOffscreen, reporter, context,
188 CtsEnforcement::kApiLevel_V) {
189 SkBitmap bitmap;
190 bitmap.allocN32Pixels(4, 4, true);
191 SkCanvas bitmapCanvas(bitmap);
192 SkPaint paint;
193 paint.setColor(SkColors::kRed);
194 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
195 paint.setColor(SkColors::kGreen);
196 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(2, 2, 2, 2), paint);
197
198 SkISize surfaceSize = SkISize::Make(4, 4);
199 SkISize recordingSize = SkISize::Make(4, 4);
200 SkIVector replayOffset = SkIVector::Make(-2, -2);
201
202 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
203
204 std::vector<Expectation> expectations = {{0, 0, SkColors::kGreen}};
205
206 run_test(reporter,
207 context,
208 surfaceSize,
209 recordingSize,
210 replayOffset,
211 kEmptyClip,
212 skgpu::Mipmapped::kNo,
213 skgpu::Mipmapped::kNo,
214 draw,
215 expectations);
216 }
217
218 // 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::kNextRelease)219 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestDrawWithClip, reporter, context,
220 CtsEnforcement::kNextRelease) {
221 SkISize surfaceSize = SkISize::Make(8, 4);
222 SkISize recordingSize = SkISize::Make(8, 4);
223
224 auto draw = [](SkCanvas* canvas) {
225 canvas->drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), SkPaint(SkColors::kRed));
226 canvas->drawIRect(SkIRect::MakeXYWH(4, 0, 4, 4), SkPaint(SkColors::kGreen));
227 };
228
229 {
230 // Test that the clip applies in translated space.
231 SkIVector replayOffset = SkIVector::Make(4, 0);
232 SkIRect replayClip = SkIRect::MakeXYWH(0, 0, 2, 4);
233
234 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
235 {4, 0, SkColors::kRed},
236 {6, 0, SkColors::kTransparent}};
237
238 run_test(reporter,
239 context,
240 surfaceSize,
241 recordingSize,
242 replayOffset,
243 replayClip,
244 skgpu::Mipmapped::kNo,
245 skgpu::Mipmapped::kNo,
246 draw,
247 expectations);
248 }
249
250 {
251 // Test that the draw is not translated by the clip.
252 SkIRect replayClip = SkIRect::MakeXYWH(4, 0, 2, 4);
253
254 std::vector<Expectation> expectations = {{4, 0, SkColors::kGreen}};
255
256 run_test(reporter,
257 context,
258 surfaceSize,
259 recordingSize,
260 kNoOffset,
261 replayClip,
262 skgpu::Mipmapped::kNo,
263 skgpu::Mipmapped::kNo,
264 draw,
265 expectations);
266 }
267 }
268
269 // 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::kNextRelease)270 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsWithClip, reporter, context,
271 CtsEnforcement::kNextRelease) {
272 SkBitmap bitmap;
273 bitmap.allocN32Pixels(4, 4, true);
274 SkCanvas bitmapCanvas(bitmap);
275 SkPaint paint;
276 paint.setColor(SkColors::kRed);
277 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
278
279 SkISize surfaceSize = SkISize::Make(8, 4);
280 SkISize recordingSize = SkISize::Make(4, 4);
281 SkIVector replayOffset = SkIVector::Make(4, 0);
282 SkIRect replayClip = SkIRect::MakeXYWH(0, 0, 2, 4);
283
284 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
285
286 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
287 {4, 0, SkColors::kRed},
288 {6, 0, SkColors::kTransparent}};
289
290 run_test(reporter,
291 context,
292 surfaceSize,
293 recordingSize,
294 replayOffset,
295 replayClip,
296 skgpu::Mipmapped::kNo,
297 skgpu::Mipmapped::kNo,
298 draw,
299 expectations);
300 }
301
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmapped,reporter,context,CtsEnforcement::kNextRelease)302 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmapped, reporter, context,
303 CtsEnforcement::kNextRelease) {
304 SkISize recordingSize = SkISize::Make(1, 1);
305
306 auto draw = [](SkCanvas* canvas) { canvas->clear(SkColors::kRed); };
307
308 {
309 SkISize surfaceSize = SkISize::Make(1, 1);
310
311 std::vector<Expectation> expectations = {{0, 0, SkColors::kRed}};
312
313 run_test(reporter,
314 context,
315 surfaceSize,
316 recordingSize,
317 kNoOffset,
318 kEmptyClip,
319 skgpu::Mipmapped::kYes,
320 skgpu::Mipmapped::kYes,
321 draw,
322 expectations);
323 }
324
325 {
326 // Test that draw fails if canvas and surface mipmap settings don't match.
327 SkISize surfaceSize = SkISize::Make(1, 1);
328
329 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
330
331 run_test(reporter,
332 context,
333 surfaceSize,
334 recordingSize,
335 kNoOffset,
336 kEmptyClip,
337 skgpu::Mipmapped::kYes,
338 skgpu::Mipmapped::kNo,
339 draw,
340 expectations);
341
342 run_test(reporter,
343 context,
344 surfaceSize,
345 recordingSize,
346 kNoOffset,
347 kEmptyClip,
348 skgpu::Mipmapped::kNo,
349 skgpu::Mipmapped::kYes,
350 draw,
351 expectations);
352 }
353
354 {
355 // Test that draw fails if canvas and surface dimensions don't match.
356 SkISize surfaceSize = SkISize::Make(2, 1);
357
358 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
359
360 run_test(reporter,
361 context,
362 surfaceSize,
363 recordingSize,
364 kNoOffset,
365 kEmptyClip,
366 skgpu::Mipmapped::kYes,
367 skgpu::Mipmapped::kYes,
368 draw,
369 expectations);
370 }
371
372 {
373 // Test that draw fails if offset is provided.
374 SkISize surfaceSize = SkISize::Make(1, 1);
375 SkIVector replayOffset = SkIVector::Make(1, 0);
376
377 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
378
379 run_test(reporter,
380 context,
381 surfaceSize,
382 recordingSize,
383 replayOffset,
384 kEmptyClip,
385 skgpu::Mipmapped::kYes,
386 skgpu::Mipmapped::kYes,
387 draw,
388 expectations);
389 }
390
391 {
392 // Test that draw fails if clip is provided.
393 SkISize surfaceSize = SkISize::Make(1, 1);
394 SkIRect replayClip = SkIRect::MakeXYWH(0, 0, 1, 1);
395
396 std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent}};
397
398 run_test(reporter,
399 context,
400 surfaceSize,
401 recordingSize,
402 kNoOffset,
403 replayClip,
404 skgpu::Mipmapped::kYes,
405 skgpu::Mipmapped::kYes,
406 draw,
407 expectations);
408 }
409 }
410
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmappedWritePixels,reporter,context,CtsEnforcement::kNextRelease)411 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestMipmappedWritePixels, reporter, context,
412 CtsEnforcement::kNextRelease) {
413 SkBitmap bitmap;
414 bitmap.allocN32Pixels(1, 1, true);
415 SkCanvas bitmapCanvas(bitmap);
416 SkPaint paint;
417 paint.setColor(SkColors::kRed);
418 bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 1, 1), paint);
419
420 SkISize recordingSize = SkISize::Make(1, 1);
421 SkISize surfaceSize = SkISize::Make(1, 1);
422
423 auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
424
425 std::vector<Expectation> expectations = {{0, 0, SkColors::kRed}};
426
427 run_test(reporter,
428 context,
429 surfaceSize,
430 recordingSize,
431 kNoOffset,
432 kEmptyClip,
433 skgpu::Mipmapped::kYes,
434 skgpu::Mipmapped::kYes,
435 draw,
436 expectations);
437 }
438
439 // Tests that you can't create two deferred canvases before snapping the first.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestTwoCanvases,reporter,context,CtsEnforcement::kNextRelease)440 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestTwoCanvases, reporter, context,
441 CtsEnforcement::kNextRelease) {
442 const SkImageInfo kImageInfo = SkImageInfo::Make(SkISize::Make(1, 1),
443 SkColorType::kRGBA_8888_SkColorType,
444 SkAlphaType::kPremul_SkAlphaType);
445 std::unique_ptr<Recorder> recorder = context->makeRecorder();
446 sk_sp<SkSurface> surface =
447 SkSurfaces::RenderTarget(recorder.get(), kImageInfo, skgpu::Mipmapped::kNo);
448 const TextureInfo& textureInfo =
449 static_cast<Surface*>(surface.get())->backingTextureProxy()->textureInfo();
450
451 // First canvas is created successfully.
452 REPORTER_ASSERT(reporter, recorder->makeDeferredCanvas(kImageInfo, textureInfo) != nullptr);
453 // Second canvas fails to be created.
454 REPORTER_ASSERT(reporter, recorder->makeDeferredCanvas(kImageInfo, textureInfo) == nullptr);
455 }
456
457 // Tests that inserting a recording with a surface does not crash even if no draws to a deferred
458 // canvas were recorded.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestUnnecessarySurface,reporter,context,CtsEnforcement::kNextRelease)459 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestUnnecessarySurface, reporter, context,
460 CtsEnforcement::kNextRelease) {
461 const SkImageInfo kImageInfo = SkImageInfo::Make(SkISize::Make(1, 1),
462 SkColorType::kRGBA_8888_SkColorType,
463 SkAlphaType::kPremul_SkAlphaType);
464 std::unique_ptr<Recorder> recorder = context->makeRecorder();
465
466 sk_sp<SkSurface> surface =
467 SkSurfaces::RenderTarget(recorder.get(), kImageInfo, skgpu::Mipmapped::kNo);
468 std::unique_ptr<Recording> recording = recorder->snap();
469 REPORTER_ASSERT(reporter, context->insertRecording({recording.get(), surface.get()}));
470 }
471
472 } // namespace skgpu::graphite
473