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