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