• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc.
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/RecordTestUtils.h"
9 #include "tests/Test.h"
10 
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkPictureRecorder.h"
13 #include "include/core/SkSurface.h"
14 #include "include/effects/SkImageFilters.h"
15 #include "src/core/SkRecord.h"
16 #include "src/core/SkRecordOpts.h"
17 #include "src/core/SkRecorder.h"
18 #include "src/core/SkRecords.h"
19 
20 static const int W = 1920, H = 1080;
21 
DEF_TEST(RecordOpts_NoopDraw,r)22 DEF_TEST(RecordOpts_NoopDraw, r) {
23     SkRecord record;
24     SkRecorder recorder(&record, W, H);
25 
26     recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint());
27     recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint());
28     recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint());
29 
30     record.replace<SkRecords::NoOp>(1);  // NoOps should be allowed.
31 
32     SkRecordNoopSaveRestores(&record);
33 
34     REPORTER_ASSERT(r, 2 == count_instances_of_type<SkRecords::DrawRect>(record));
35 }
36 
DEF_TEST(RecordOpts_SingleNoopSaveRestore,r)37 DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
38     SkRecord record;
39     SkRecorder recorder(&record, W, H);
40 
41     recorder.save();
42         recorder.clipRect(SkRect::MakeWH(200, 200));
43     recorder.restore();
44 
45     SkRecordNoopSaveRestores(&record);
46     for (int i = 0; i < 3; i++) {
47         assert_type<SkRecords::NoOp>(r, record, i);
48     }
49 }
50 
DEF_TEST(RecordOpts_NoopSaveRestores,r)51 DEF_TEST(RecordOpts_NoopSaveRestores, r) {
52     SkRecord record;
53     SkRecorder recorder(&record, W, H);
54 
55     // The second pass will clean up this pair after the first pass noops all the innards.
56     recorder.save();
57         // A simple pointless pair of save/restore.
58         recorder.save();
59         recorder.restore();
60 
61         // As long as we don't draw in there, everything is a noop.
62         recorder.save();
63             recorder.clipRect(SkRect::MakeWH(200, 200));
64             recorder.clipRect(SkRect::MakeWH(100, 100));
65         recorder.restore();
66     recorder.restore();
67 
68     SkRecordNoopSaveRestores(&record);
69     for (int index = 0; index < record.count(); index++) {
70         assert_type<SkRecords::NoOp>(r, record, index);
71     }
72 }
73 
DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore,r)74 DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) {
75     SkRecord record;
76     SkRecorder recorder(&record, W, H);
77 
78     // A previous bug NoOp'd away the first 3 commands.
79     recorder.save();
80         recorder.saveLayer(nullptr, nullptr);
81         recorder.restore();
82     recorder.restore();
83 
84     SkRecordNoopSaveRestores(&record);
85     switch (record.count()) {
86         case 4:
87             assert_type<SkRecords::Save>     (r, record, 0);
88             assert_type<SkRecords::SaveLayer>(r, record, 1);
89             assert_type<SkRecords::Restore>  (r, record, 2);
90             assert_type<SkRecords::Restore>  (r, record, 3);
91             break;
92         case 2:
93             assert_type<SkRecords::SaveLayer>(r, record, 0);
94             assert_type<SkRecords::Restore>  (r, record, 1);
95             break;
96         case 0:
97             break;
98         default:
99             REPORTER_ASSERT(r, false);
100     }
101 }
102 
103 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
assert_savelayer_restore(skiatest::Reporter * r,SkRecord * record,int i,bool shouldBeNoOped)104 static void assert_savelayer_restore(skiatest::Reporter* r,
105                                      SkRecord* record,
106                                      int i,
107                                      bool shouldBeNoOped) {
108     SkRecordNoopSaveLayerDrawRestores(record);
109     if (shouldBeNoOped) {
110         assert_type<SkRecords::NoOp>(r, *record, i);
111         assert_type<SkRecords::NoOp>(r, *record, i+1);
112     } else {
113         assert_type<SkRecords::SaveLayer>(r, *record, i);
114         assert_type<SkRecords::Restore>(r, *record, i+1);
115     }
116 }
117 
assert_savelayer_draw_restore(skiatest::Reporter * r,SkRecord * record,int i,bool shouldBeNoOped)118 static void assert_savelayer_draw_restore(skiatest::Reporter* r,
119                                           SkRecord* record,
120                                           int i,
121                                           bool shouldBeNoOped) {
122     SkRecordNoopSaveLayerDrawRestores(record);
123     if (shouldBeNoOped) {
124         assert_type<SkRecords::NoOp>(r, *record, i);
125         assert_type<SkRecords::NoOp>(r, *record, i+2);
126     } else {
127         assert_type<SkRecords::SaveLayer>(r, *record, i);
128         assert_type<SkRecords::Restore>(r, *record, i+2);
129     }
130 }
131 
DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore,r)132 DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
133     SkRecord record;
134     SkRecorder recorder(&record, W, H);
135 
136     SkRect bounds = SkRect::MakeWH(100, 200);
137     SkRect   draw = SkRect::MakeWH(50, 60);
138 
139     SkPaint alphaOnlyLayerPaint, translucentLayerPaint, xfermodeLayerPaint;
140     alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
141     translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
142     xfermodeLayerPaint.setBlendMode(SkBlendMode::kDstIn);  // Any effect will do.
143 
144     SkPaint opaqueDrawPaint, translucentDrawPaint;
145     opaqueDrawPaint.setColor(0xFF020202);  // Opaque.
146     translucentDrawPaint.setColor(0x0F020202);  // Not opaque.
147 
148     // SaveLayer/Restore removed: No paint = no point.
149     recorder.saveLayer(nullptr, nullptr);
150         recorder.drawRect(draw, opaqueDrawPaint);
151     recorder.restore();
152     assert_savelayer_draw_restore(r, &record, 0, true);
153 
154     // Bounds don't matter.
155     recorder.saveLayer(&bounds, nullptr);
156         recorder.drawRect(draw, opaqueDrawPaint);
157     recorder.restore();
158     assert_savelayer_draw_restore(r, &record, 3, true);
159 
160     // TODO(mtklein): test case with null draw paint
161 
162     // No change: layer paint isn't alpha-only.
163     recorder.saveLayer(nullptr, &translucentLayerPaint);
164         recorder.drawRect(draw, opaqueDrawPaint);
165     recorder.restore();
166     assert_savelayer_draw_restore(r, &record, 6, false);
167 
168     // No change: layer paint has an effect.
169     recorder.saveLayer(nullptr, &xfermodeLayerPaint);
170         recorder.drawRect(draw, opaqueDrawPaint);
171     recorder.restore();
172     assert_savelayer_draw_restore(r, &record, 9, false);
173 
174     // SaveLayer/Restore removed: we can fold in the alpha!
175     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
176         recorder.drawRect(draw, translucentDrawPaint);
177     recorder.restore();
178     assert_savelayer_draw_restore(r, &record, 12, true);
179 
180     // SaveLayer/Restore removed: we can fold in the alpha!
181     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
182         recorder.drawRect(draw, opaqueDrawPaint);
183     recorder.restore();
184     assert_savelayer_draw_restore(r, &record, 15, true);
185 
186     const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
187     REPORTER_ASSERT(r, drawRect != nullptr);
188     REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
189 
190     // saveLayer w/ backdrop should NOT go away
191     sk_sp<SkImageFilter> filter(SkImageFilters::Blur(3, 3, nullptr));
192     recorder.saveLayer({ nullptr, nullptr, filter.get(), nullptr, nullptr, 0});
193         recorder.drawRect(draw, opaqueDrawPaint);
194     recorder.restore();
195     assert_savelayer_draw_restore(r, &record, 18, false);
196 
197     // saveLayer w/ clip mask should also NOT go away
198     {
199         sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(10, 10));
200         recorder.saveLayer({ nullptr, nullptr, nullptr, surface->makeImageSnapshot().get(),
201                              nullptr, 0});
202             recorder.drawRect(draw, opaqueDrawPaint);
203         recorder.restore();
204         assert_savelayer_draw_restore(r, &record, 21, false);
205     }
206 }
207 #endif
208 
assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter * r,SkRecord * record,int i,bool shouldBeNoOped)209 static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
210                                                        SkRecord* record,
211                                                        int i,
212                                                        bool shouldBeNoOped) {
213     SkRecordMergeSvgOpacityAndFilterLayers(record);
214     if (shouldBeNoOped) {
215         assert_type<SkRecords::NoOp>(r, *record, i);
216         assert_type<SkRecords::NoOp>(r, *record, i + 6);
217     } else {
218         assert_type<SkRecords::SaveLayer>(r, *record, i);
219         assert_type<SkRecords::Restore>(r, *record, i + 6);
220     }
221 }
222 
DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers,r)223 DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
224     SkRecord record;
225     SkRecorder recorder(&record, W, H);
226 
227     SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200));
228     SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60));
229 
230     SkPaint alphaOnlyLayerPaint;
231     alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
232     SkPaint translucentLayerPaint;
233     translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
234     SkPaint xfermodePaint;
235     xfermodePaint.setBlendMode(SkBlendMode::kDstIn);
236     SkPaint colorFilterPaint;
237     colorFilterPaint.setColorFilter(
238         SkColorFilters::Blend(SK_ColorLTGRAY, SkBlendMode::kSrcIn));
239 
240     SkPaint opaqueFilterLayerPaint;
241     opaqueFilterLayerPaint.setColor(0xFF020202);  // Opaque.
242     SkPaint translucentFilterLayerPaint;
243     translucentFilterLayerPaint.setColor(0x0F020202);  // Not opaque.
244     sk_sp<SkPicture> shape;
245     {
246         SkPictureRecorder recorder;
247         SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100));
248         SkPaint shapePaint;
249         shapePaint.setColor(SK_ColorWHITE);
250         canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint);
251         shape = recorder.finishRecordingAsPicture();
252     }
253     translucentFilterLayerPaint.setImageFilter(SkImageFilters::Picture(shape));
254 
255     int index = 0;
256 
257     {
258         sk_sp<SkImageFilter> filter(SkImageFilters::Blur(3, 3, nullptr));
259         // first (null) should be optimized, 2nd should not
260         SkImageFilter* filters[] = { nullptr, filter.get() };
261 
262         // Any combination of these should cause the pattern to be optimized.
263         SkRect* firstBounds[] = { nullptr, &bounds };
264         SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint };
265         SkRect* secondBounds[] = { nullptr, &bounds };
266         SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
267 
268         for (auto outerF : filters) {
269             bool outerNoOped = !outerF;
270             for (auto innerF : filters) {
271                 for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
272                     for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
273                         for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
274                             for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
275                                 bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF;
276 
277                                 recorder.saveLayer({firstBounds[i], firstPaints[j], outerF,
278                                                     nullptr, nullptr, 0});
279                                 recorder.save();
280                                 recorder.clipRect(clip);
281                                 recorder.saveLayer({secondBounds[k], secondPaints[m], innerF,
282                                                     nullptr, nullptr, 0});
283                                 recorder.restore();
284                                 recorder.restore();
285                                 recorder.restore();
286                                 assert_merge_svg_opacity_and_filter_layers(r, &record, index,
287                                                                            outerNoOped);
288                             #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
289                                 assert_savelayer_restore(r, &record, index + 3, innerNoOped);
290                             #endif
291                                 index += 7;
292                             }
293                         }
294                     }
295                 }
296             }
297         }
298     }
299 
300     // These should cause the pattern to stay unoptimized:
301     struct {
302         SkPaint* firstPaint;
303         SkPaint* secondPaint;
304     } noChangeTests[] = {
305         // No change: nullptr filter layer paint not implemented.
306         { &alphaOnlyLayerPaint, nullptr },
307         // No change: layer paint is not alpha-only.
308         { &translucentLayerPaint, &opaqueFilterLayerPaint },
309         // No change: layer paint has an xfereffect.
310         { &xfermodePaint, &opaqueFilterLayerPaint },
311         // No change: filter layer paint has an xfereffect.
312         { &alphaOnlyLayerPaint, &xfermodePaint },
313         // No change: layer paint has a color filter.
314         { &colorFilterPaint, &opaqueFilterLayerPaint },
315         // No change: filter layer paint has a color filter (until the optimization accounts for
316         // constant color draws that can filter the color).
317         { &alphaOnlyLayerPaint, &colorFilterPaint }
318     };
319 
320     for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) {
321         recorder.saveLayer(nullptr, noChangeTests[i].firstPaint);
322         recorder.save();
323         recorder.clipRect(clip);
324         recorder.saveLayer(nullptr, noChangeTests[i].secondPaint);
325         recorder.restore();
326         recorder.restore();
327         recorder.restore();
328         assert_merge_svg_opacity_and_filter_layers(r, &record, index, false);
329         index += 7;
330     }
331 
332     // Test the folded alpha value.
333     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
334     recorder.save();
335     recorder.clipRect(clip);
336     recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
337     recorder.restore();
338     recorder.restore();
339     recorder.restore();
340     assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
341 
342     const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3);
343     REPORTER_ASSERT(r, saveLayer != nullptr);
344     REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202);
345 
346     index += 7;
347 
348     // Test that currently we do not fold alphas for patterns without the clip. This is just not
349     // implemented.
350     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
351     recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
352     recorder.restore();
353     recorder.restore();
354     SkRecordMergeSvgOpacityAndFilterLayers(&record);
355     assert_type<SkRecords::SaveLayer>(r, record, index);
356     assert_type<SkRecords::SaveLayer>(r, record, index + 1);
357     assert_type<SkRecords::Restore>(r, record, index + 2);
358     assert_type<SkRecords::Restore>(r, record, index + 3);
359     index += 4;
360 }
361 
do_draw(SkCanvas * canvas,SkColor color,bool doLayer)362 static void do_draw(SkCanvas* canvas, SkColor color, bool doLayer) {
363     canvas->drawColor(SK_ColorWHITE);
364 
365     SkPaint p;
366     p.setColor(color);
367 
368     if (doLayer) {
369         canvas->saveLayer(nullptr, nullptr);
370         p.setBlendMode(SkBlendMode::kSrc);
371         canvas->drawPaint(p);
372         canvas->restore();
373     } else {
374         canvas->drawPaint(p);
375     }
376 }
377 
is_equal(SkSurface * a,SkSurface * b)378 static bool is_equal(SkSurface* a, SkSurface* b) {
379     const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
380     SkPMColor ca, cb;
381     a->readPixels(info, &ca, sizeof(SkPMColor), 0, 0);
382     b->readPixels(info, &cb, sizeof(SkPMColor), 0, 0);
383     return ca == cb;
384 }
385 
386 // Test drawing w/ and w/o a simple layer (no bounds or paint), so see that drawing ops
387 // that *should* draw the same in fact do.
388 //
389 // Perform this test twice : once directly, and once via a picture
390 //
do_savelayer_srcmode(skiatest::Reporter * r,SkColor color)391 static void do_savelayer_srcmode(skiatest::Reporter* r, SkColor color) {
392     for (int doPicture = 0; doPicture <= 1; ++doPicture) {
393         sk_sp<SkSurface> surf0 = SkSurface::MakeRasterN32Premul(10, 10);
394         sk_sp<SkSurface> surf1 = SkSurface::MakeRasterN32Premul(10, 10);
395         SkCanvas* c0 = surf0->getCanvas();
396         SkCanvas* c1 = surf1->getCanvas();
397 
398         SkPictureRecorder rec0, rec1;
399         if (doPicture) {
400             c0 = rec0.beginRecording(10, 10);
401             c1 = rec1.beginRecording(10, 10);
402         }
403 
404         do_draw(c0, color, false);
405         do_draw(c1, color, true);
406 
407         if (doPicture) {
408             surf0->getCanvas()->drawPicture(rec0.finishRecordingAsPicture());
409             surf1->getCanvas()->drawPicture(rec1.finishRecordingAsPicture());
410         }
411 
412         // we replicate the assert so we can see which line is reported if there is a failure
413         if (doPicture) {
414             REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
415         } else {
416             REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
417         }
418     }
419 }
420 
DEF_TEST(savelayer_srcmode_opaque,r)421 DEF_TEST(savelayer_srcmode_opaque, r) {
422     do_savelayer_srcmode(r, SK_ColorRED);
423 }
424 
DEF_TEST(savelayer_srcmode_alpha,r)425 DEF_TEST(savelayer_srcmode_alpha, r) {
426     do_savelayer_srcmode(r, 0x80FF0000);
427 }
428 
429