xref: /aosp_15_r20/external/skia/tests/graphite/RecordingSurfacesTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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