Home | History | Annotate | Download | only in tests
      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 
     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 
     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 
     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 
     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 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 
    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"
    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 
    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 
    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