• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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