• 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(), 0});
193         recorder.drawRect(draw, opaqueDrawPaint);
194     recorder.restore();
195     assert_savelayer_draw_restore(r, &record, 18, false);
196 }
197 #endif
198 
assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter * r,SkRecord * record,int i,bool shouldBeNoOped)199 static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
200                                                        SkRecord* record,
201                                                        int i,
202                                                        bool shouldBeNoOped) {
203     SkRecordMergeSvgOpacityAndFilterLayers(record);
204     if (shouldBeNoOped) {
205         assert_type<SkRecords::NoOp>(r, *record, i);
206         assert_type<SkRecords::NoOp>(r, *record, i + 6);
207     } else {
208         assert_type<SkRecords::SaveLayer>(r, *record, i);
209         assert_type<SkRecords::Restore>(r, *record, i + 6);
210     }
211 }
212 
DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers,r)213 DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
214     SkRecord record;
215     SkRecorder recorder(&record, W, H);
216 
217     SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200));
218     SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60));
219 
220     SkPaint alphaOnlyLayerPaint;
221     alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
222     SkPaint translucentLayerPaint;
223     translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
224     SkPaint xfermodePaint;
225     xfermodePaint.setBlendMode(SkBlendMode::kDstIn);
226     SkPaint colorFilterPaint;
227     colorFilterPaint.setColorFilter(
228         SkColorFilters::Blend(SK_ColorLTGRAY, SkBlendMode::kSrcIn));
229 
230     SkPaint opaqueFilterLayerPaint;
231     opaqueFilterLayerPaint.setColor(0xFF020202);  // Opaque.
232     SkPaint translucentFilterLayerPaint;
233     translucentFilterLayerPaint.setColor(0x0F020202);  // Not opaque.
234     sk_sp<SkPicture> shape;
235     {
236         SkPictureRecorder picRecorder;
237         SkCanvas* canvas = picRecorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100));
238         SkPaint shapePaint;
239         shapePaint.setColor(SK_ColorWHITE);
240         canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint);
241         shape = picRecorder.finishRecordingAsPicture();
242     }
243     translucentFilterLayerPaint.setImageFilter(SkImageFilters::Picture(shape));
244 
245     int index = 0;
246 
247     {
248         sk_sp<SkImageFilter> filter(SkImageFilters::Blur(3, 3, nullptr));
249         // first (null) should be optimized, 2nd should not
250         SkImageFilter* filters[] = { nullptr, filter.get() };
251 
252         // Any combination of these should cause the pattern to be optimized.
253         SkRect* firstBounds[] = { nullptr, &bounds };
254         SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint };
255         SkRect* secondBounds[] = { nullptr, &bounds };
256         SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
257 
258         for (auto outerF : filters) {
259             bool outerNoOped = !outerF;
260             for (auto innerF : filters) {
261                 for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
262                     for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
263                         for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
264                             for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
265                                 bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF;
266 
267                                 recorder.saveLayer({firstBounds[i], firstPaints[j], outerF, 0});
268                                 recorder.save();
269                                 recorder.clipRect(clip);
270                                 recorder.saveLayer({secondBounds[k], secondPaints[m], innerF, 0});
271                                 recorder.restore();
272                                 recorder.restore();
273                                 recorder.restore();
274                                 assert_merge_svg_opacity_and_filter_layers(r, &record, index,
275                                                                            outerNoOped);
276                             #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
277                                 assert_savelayer_restore(r, &record, index + 3, innerNoOped);
278                             #endif
279                                 index += 7;
280                             }
281                         }
282                     }
283                 }
284             }
285         }
286     }
287 
288     // These should cause the pattern to stay unoptimized:
289     struct {
290         SkPaint* firstPaint;
291         SkPaint* secondPaint;
292     } noChangeTests[] = {
293         // No change: nullptr filter layer paint not implemented.
294         { &alphaOnlyLayerPaint, nullptr },
295         // No change: layer paint is not alpha-only.
296         { &translucentLayerPaint, &opaqueFilterLayerPaint },
297         // No change: layer paint has an xfereffect.
298         { &xfermodePaint, &opaqueFilterLayerPaint },
299         // No change: filter layer paint has an xfereffect.
300         { &alphaOnlyLayerPaint, &xfermodePaint },
301         // No change: layer paint has a color filter.
302         { &colorFilterPaint, &opaqueFilterLayerPaint },
303         // No change: filter layer paint has a color filter (until the optimization accounts for
304         // constant color draws that can filter the color).
305         { &alphaOnlyLayerPaint, &colorFilterPaint }
306     };
307 
308     for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) {
309         recorder.saveLayer(nullptr, noChangeTests[i].firstPaint);
310         recorder.save();
311         recorder.clipRect(clip);
312         recorder.saveLayer(nullptr, noChangeTests[i].secondPaint);
313         recorder.restore();
314         recorder.restore();
315         recorder.restore();
316         assert_merge_svg_opacity_and_filter_layers(r, &record, index, false);
317         index += 7;
318     }
319 
320     // Test the folded alpha value.
321     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
322     recorder.save();
323     recorder.clipRect(clip);
324     recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
325     recorder.restore();
326     recorder.restore();
327     recorder.restore();
328     assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
329 
330     const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3);
331     REPORTER_ASSERT(r, saveLayer != nullptr);
332     REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202);
333 
334     index += 7;
335 
336     // Test that currently we do not fold alphas for patterns without the clip. This is just not
337     // implemented.
338     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
339     recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
340     recorder.restore();
341     recorder.restore();
342     SkRecordMergeSvgOpacityAndFilterLayers(&record);
343     assert_type<SkRecords::SaveLayer>(r, record, index);
344     assert_type<SkRecords::SaveLayer>(r, record, index + 1);
345     assert_type<SkRecords::Restore>(r, record, index + 2);
346     assert_type<SkRecords::Restore>(r, record, index + 3);
347     index += 4;
348 }
349 
do_draw(SkCanvas * canvas,SkColor color,bool doLayer)350 static void do_draw(SkCanvas* canvas, SkColor color, bool doLayer) {
351     canvas->drawColor(SK_ColorWHITE);
352 
353     SkPaint p;
354     p.setColor(color);
355 
356     if (doLayer) {
357         canvas->saveLayer(nullptr, nullptr);
358         p.setBlendMode(SkBlendMode::kSrc);
359         canvas->drawPaint(p);
360         canvas->restore();
361     } else {
362         canvas->drawPaint(p);
363     }
364 }
365 
is_equal(SkSurface * a,SkSurface * b)366 static bool is_equal(SkSurface* a, SkSurface* b) {
367     const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
368     SkPMColor ca, cb;
369     a->readPixels(info, &ca, sizeof(SkPMColor), 0, 0);
370     b->readPixels(info, &cb, sizeof(SkPMColor), 0, 0);
371     return ca == cb;
372 }
373 
374 // Test drawing w/ and w/o a simple layer (no bounds or paint), so see that drawing ops
375 // that *should* draw the same in fact do.
376 //
377 // Perform this test twice : once directly, and once via a picture
378 //
do_savelayer_srcmode(skiatest::Reporter * r,SkColor color)379 static void do_savelayer_srcmode(skiatest::Reporter* r, SkColor color) {
380     for (int doPicture = 0; doPicture <= 1; ++doPicture) {
381         sk_sp<SkSurface> surf0 = SkSurface::MakeRasterN32Premul(10, 10);
382         sk_sp<SkSurface> surf1 = SkSurface::MakeRasterN32Premul(10, 10);
383         SkCanvas* c0 = surf0->getCanvas();
384         SkCanvas* c1 = surf1->getCanvas();
385 
386         SkPictureRecorder rec0, rec1;
387         if (doPicture) {
388             c0 = rec0.beginRecording(10, 10);
389             c1 = rec1.beginRecording(10, 10);
390         }
391 
392         do_draw(c0, color, false);
393         do_draw(c1, color, true);
394 
395         if (doPicture) {
396             surf0->getCanvas()->drawPicture(rec0.finishRecordingAsPicture());
397             surf1->getCanvas()->drawPicture(rec1.finishRecordingAsPicture());
398         }
399 
400         // we replicate the assert so we can see which line is reported if there is a failure
401         if (doPicture) {
402             REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
403         } else {
404             REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
405         }
406     }
407 }
408 
DEF_TEST(savelayer_srcmode_opaque,r)409 DEF_TEST(savelayer_srcmode_opaque, r) {
410     do_savelayer_srcmode(r, SK_ColorRED);
411 }
412 
DEF_TEST(savelayer_srcmode_alpha,r)413 DEF_TEST(savelayer_srcmode_alpha, r) {
414     do_savelayer_srcmode(r, 0x80FF0000);
415 }
416 
417