• 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 "Test.h"
9 #include "RecordTestUtils.h"
10 
11 #include "SkColorFilter.h"
12 #include "SkRecord.h"
13 #include "SkRecordOpts.h"
14 #include "SkRecorder.h"
15 #include "SkRecords.h"
16 #include "SkXfermode.h"
17 #include "SkPictureRecorder.h"
18 #include "SkPictureImageFilter.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 
assert_savelayer_restore(skiatest::Reporter * r,SkRecord * record,int i,bool shouldBeNoOped)103 static void assert_savelayer_restore(skiatest::Reporter* r,
104                                      SkRecord* record,
105                                      int i,
106                                      bool shouldBeNoOped) {
107     SkRecordNoopSaveLayerDrawRestores(record);
108     if (shouldBeNoOped) {
109         assert_type<SkRecords::NoOp>(r, *record, i);
110         assert_type<SkRecords::NoOp>(r, *record, i+1);
111     } else {
112         assert_type<SkRecords::SaveLayer>(r, *record, i);
113         assert_type<SkRecords::Restore>(r, *record, i+1);
114     }
115 }
116 
assert_savelayer_draw_restore(skiatest::Reporter * r,SkRecord * record,int i,bool shouldBeNoOped)117 static void assert_savelayer_draw_restore(skiatest::Reporter* r,
118                                           SkRecord* record,
119                                           int i,
120                                           bool shouldBeNoOped) {
121     SkRecordNoopSaveLayerDrawRestores(record);
122     if (shouldBeNoOped) {
123         assert_type<SkRecords::NoOp>(r, *record, i);
124         assert_type<SkRecords::NoOp>(r, *record, i+2);
125     } else {
126         assert_type<SkRecords::SaveLayer>(r, *record, i);
127         assert_type<SkRecords::Restore>(r, *record, i+2);
128     }
129 }
130 
131 #include "SkBlurImageFilter.h"
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.setXfermodeMode(SkXfermode::kDstIn_Mode);  // 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     SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(3, 3));
192     recorder.saveLayer({ nullptr, nullptr, filter, 0});
193         recorder.drawRect(draw, opaqueDrawPaint);
194     recorder.restore();
195     assert_savelayer_draw_restore(r, &record, 18, false);
196 }
197 
assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter * r,SkRecord * record,int i,bool shouldBeNoOped)198 static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
199                                                        SkRecord* record,
200                                                        int i,
201                                                        bool shouldBeNoOped) {
202     SkRecordMergeSvgOpacityAndFilterLayers(record);
203     if (shouldBeNoOped) {
204         assert_type<SkRecords::NoOp>(r, *record, i);
205         assert_type<SkRecords::NoOp>(r, *record, i + 6);
206     } else {
207         assert_type<SkRecords::SaveLayer>(r, *record, i);
208         assert_type<SkRecords::Restore>(r, *record, i + 6);
209     }
210 }
211 
DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers,r)212 DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
213     SkRecord record;
214     SkRecorder recorder(&record, W, H);
215 
216     SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200));
217     SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60));
218 
219     SkPaint alphaOnlyLayerPaint;
220     alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
221     SkPaint translucentLayerPaint;
222     translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
223     SkPaint xfermodePaint;
224     xfermodePaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
225     SkPaint colorFilterPaint;
226     colorFilterPaint.setColorFilter(
227         SkColorFilter::CreateModeFilter(SK_ColorLTGRAY, SkXfermode::kSrcIn_Mode))->unref();
228 
229     SkPaint opaqueFilterLayerPaint;
230     opaqueFilterLayerPaint.setColor(0xFF020202);  // Opaque.
231     SkPaint translucentFilterLayerPaint;
232     translucentFilterLayerPaint.setColor(0x0F020202);  // Not opaque.
233     SkAutoTUnref<SkPicture> shape;
234     {
235         SkPictureRecorder recorder;
236         SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100));
237         SkPaint shapePaint;
238         shapePaint.setColor(SK_ColorWHITE);
239         canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint);
240         shape.reset(recorder.endRecordingAsPicture());
241     }
242     translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Create(shape))->unref();
243 
244     int index = 0;
245 
246     {
247         SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(3, 3));
248         // first (null) should be optimized, 2nd should not
249         SkImageFilter* filters[] = { nullptr, filter.get() };
250 
251         // Any combination of these should cause the pattern to be optimized.
252         SkRect* firstBounds[] = { nullptr, &bounds };
253         SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint };
254         SkRect* secondBounds[] = { nullptr, &bounds };
255         SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
256 
257         for (auto outerF : filters) {
258             bool outerNoOped = !outerF;
259             for (auto innerF : filters) {
260                 for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
261                     for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
262                         for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
263                             for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
264                                 bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF;
265 
266                                 recorder.saveLayer({firstBounds[i], firstPaints[j], outerF, 0});
267                                 recorder.save();
268                                 recorder.clipRect(clip);
269                                 recorder.saveLayer({secondBounds[k], secondPaints[m], innerF, 0});
270                                 recorder.restore();
271                                 recorder.restore();
272                                 recorder.restore();
273                                 assert_merge_svg_opacity_and_filter_layers(r, &record, index,
274                                                                            outerNoOped);
275                                 assert_savelayer_restore(r, &record, index + 3, innerNoOped);
276                                 index += 7;
277                             }
278                         }
279                     }
280                 }
281             }
282         }
283     }
284 
285     // These should cause the pattern to stay unoptimized:
286     struct {
287         SkPaint* firstPaint;
288         SkPaint* secondPaint;
289     } noChangeTests[] = {
290         // No change: nullptr filter layer paint not implemented.
291         { &alphaOnlyLayerPaint, nullptr },
292         // No change: layer paint is not alpha-only.
293         { &translucentLayerPaint, &opaqueFilterLayerPaint },
294         // No change: layer paint has an xfereffect.
295         { &xfermodePaint, &opaqueFilterLayerPaint },
296         // No change: filter layer paint has an xfereffect.
297         { &alphaOnlyLayerPaint, &xfermodePaint },
298         // No change: layer paint has a color filter.
299         { &colorFilterPaint, &opaqueFilterLayerPaint },
300         // No change: filter layer paint has a color filter (until the optimization accounts for
301         // constant color draws that can filter the color).
302         { &alphaOnlyLayerPaint, &colorFilterPaint }
303     };
304 
305     for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) {
306         recorder.saveLayer(nullptr, noChangeTests[i].firstPaint);
307         recorder.save();
308         recorder.clipRect(clip);
309         recorder.saveLayer(nullptr, noChangeTests[i].secondPaint);
310         recorder.restore();
311         recorder.restore();
312         recorder.restore();
313         assert_merge_svg_opacity_and_filter_layers(r, &record, index, false);
314         index += 7;
315     }
316 
317     // Test the folded alpha value.
318     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
319     recorder.save();
320     recorder.clipRect(clip);
321     recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
322     recorder.restore();
323     recorder.restore();
324     recorder.restore();
325     assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
326 
327     const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3);
328     REPORTER_ASSERT(r, saveLayer != nullptr);
329     REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202);
330 
331     index += 7;
332 
333     // Test that currently we do not fold alphas for patterns without the clip. This is just not
334     // implemented.
335     recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
336     recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
337     recorder.restore();
338     recorder.restore();
339     SkRecordMergeSvgOpacityAndFilterLayers(&record);
340     assert_type<SkRecords::SaveLayer>(r, record, index);
341     assert_type<SkRecords::SaveLayer>(r, record, index + 1);
342     assert_type<SkRecords::Restore>(r, record, index + 2);
343     assert_type<SkRecords::Restore>(r, record, index + 3);
344     index += 4;
345 }
346