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 (unsigned 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 (unsigned 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(NULL, NULL);
     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                                      unsigned 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+2);
    111     } else {
    112         assert_type<SkRecords::SaveLayer>(r, *record, i);
    113         assert_type<SkRecords::Restore>(r, *record, i+2);
    114     }
    115 }
    116 
    117 DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
    118     SkRecord record;
    119     SkRecorder recorder(&record, W, H);
    120 
    121     SkRect bounds = SkRect::MakeWH(100, 200);
    122     SkRect   draw = SkRect::MakeWH(50, 60);
    123 
    124     SkPaint alphaOnlyLayerPaint, translucentLayerPaint, xfermodeLayerPaint;
    125     alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
    126     translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
    127     xfermodeLayerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);  // Any effect will do.
    128 
    129     SkPaint opaqueDrawPaint, translucentDrawPaint;
    130     opaqueDrawPaint.setColor(0xFF020202);  // Opaque.
    131     translucentDrawPaint.setColor(0x0F020202);  // Not opaque.
    132 
    133     // SaveLayer/Restore removed: No paint = no point.
    134     recorder.saveLayer(NULL, NULL);
    135         recorder.drawRect(draw, opaqueDrawPaint);
    136     recorder.restore();
    137     assert_savelayer_restore(r, &record, 0, true);
    138 
    139     // Bounds don't matter.
    140     recorder.saveLayer(&bounds, NULL);
    141         recorder.drawRect(draw, opaqueDrawPaint);
    142     recorder.restore();
    143     assert_savelayer_restore(r, &record, 3, true);
    144 
    145     // TODO(mtklein): test case with null draw paint
    146 
    147     // No change: layer paint isn't alpha-only.
    148     recorder.saveLayer(NULL, &translucentLayerPaint);
    149         recorder.drawRect(draw, opaqueDrawPaint);
    150     recorder.restore();
    151     assert_savelayer_restore(r, &record, 6, false);
    152 
    153     // No change: layer paint has an effect.
    154     recorder.saveLayer(NULL, &xfermodeLayerPaint);
    155         recorder.drawRect(draw, opaqueDrawPaint);
    156     recorder.restore();
    157     assert_savelayer_restore(r, &record, 9, false);
    158 
    159     // SaveLayer/Restore removed: we can fold in the alpha!
    160     recorder.saveLayer(NULL, &alphaOnlyLayerPaint);
    161         recorder.drawRect(draw, translucentDrawPaint);
    162     recorder.restore();
    163     assert_savelayer_restore(r, &record, 12, true);
    164 
    165     // SaveLayer/Restore removed: we can fold in the alpha!
    166     recorder.saveLayer(NULL, &alphaOnlyLayerPaint);
    167         recorder.drawRect(draw, opaqueDrawPaint);
    168     recorder.restore();
    169     assert_savelayer_restore(r, &record, 15, true);
    170 
    171     const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
    172     REPORTER_ASSERT(r, drawRect != NULL);
    173     REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
    174 }
    175 
    176 static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
    177                                                        SkRecord* record,
    178                                                        unsigned i,
    179                                                        bool shouldBeNoOped) {
    180     SkRecordMergeSvgOpacityAndFilterLayers(record);
    181     if (shouldBeNoOped) {
    182         assert_type<SkRecords::NoOp>(r, *record, i);
    183         assert_type<SkRecords::NoOp>(r, *record, i + 6);
    184     } else {
    185         assert_type<SkRecords::SaveLayer>(r, *record, i);
    186         assert_type<SkRecords::Restore>(r, *record, i + 6);
    187     }
    188 }
    189 
    190 DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
    191     SkRecord record;
    192     SkRecorder recorder(&record, W, H);
    193 
    194     SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200));
    195     SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60));
    196 
    197     SkPaint alphaOnlyLayerPaint;
    198     alphaOnlyLayerPaint.setColor(0x03000000);  // Only alpha.
    199     SkPaint translucentLayerPaint;
    200     translucentLayerPaint.setColor(0x03040506);  // Not only alpha.
    201     SkPaint xfermodePaint;
    202     xfermodePaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
    203     SkPaint colorFilterPaint;
    204     colorFilterPaint.setColorFilter(
    205         SkColorFilter::CreateModeFilter(SK_ColorLTGRAY, SkXfermode::kSrcIn_Mode))->unref();
    206 
    207     SkPaint opaqueFilterLayerPaint;
    208     opaqueFilterLayerPaint.setColor(0xFF020202);  // Opaque.
    209     SkPaint translucentFilterLayerPaint;
    210     translucentFilterLayerPaint.setColor(0x0F020202);  // Not opaque.
    211     SkAutoTUnref<SkPicture> shape;
    212     {
    213         SkPictureRecorder recorder;
    214         SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100));
    215         SkPaint shapePaint;
    216         shapePaint.setColor(SK_ColorWHITE);
    217         canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint);
    218         shape.reset(recorder.endRecordingAsPicture());
    219     }
    220     translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Create(shape))->unref();
    221 
    222     int index = 0;
    223 
    224     {
    225         // Any combination of these should cause the pattern to be optimized.
    226         SkRect* firstBounds[] = { NULL, &bounds };
    227         SkPaint* firstPaints[] = { NULL, &alphaOnlyLayerPaint };
    228         SkRect* secondBounds[] = { NULL, &bounds };
    229         SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
    230 
    231         for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
    232             for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
    233                 for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
    234                     for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
    235                         recorder.saveLayer(firstBounds[i], firstPaints[j]);
    236                         recorder.save();
    237                         recorder.clipRect(clip);
    238                         recorder.saveLayer(secondBounds[k], secondPaints[m]);
    239                         recorder.restore();
    240                         recorder.restore();
    241                         recorder.restore();
    242                         assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
    243                         index += 7;
    244                     }
    245                 }
    246             }
    247         }
    248     }
    249 
    250     // These should cause the pattern to stay unoptimized:
    251     struct {
    252         SkPaint* firstPaint;
    253         SkPaint* secondPaint;
    254     } noChangeTests[] = {
    255         // No change: NULL filter layer paint not implemented.
    256         { &alphaOnlyLayerPaint, NULL },
    257         // No change: layer paint is not alpha-only.
    258         { &translucentLayerPaint, &opaqueFilterLayerPaint },
    259         // No change: layer paint has an xfereffect.
    260         { &xfermodePaint, &opaqueFilterLayerPaint },
    261         // No change: filter layer paint has an xfereffect.
    262         { &alphaOnlyLayerPaint, &xfermodePaint },
    263         // No change: layer paint has a color filter.
    264         { &colorFilterPaint, &opaqueFilterLayerPaint },
    265         // No change: filter layer paint has a color filter (until the optimization accounts for
    266         // constant color draws that can filter the color).
    267         { &alphaOnlyLayerPaint, &colorFilterPaint }
    268     };
    269 
    270     for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) {
    271         recorder.saveLayer(NULL, noChangeTests[i].firstPaint);
    272         recorder.save();
    273         recorder.clipRect(clip);
    274         recorder.saveLayer(NULL, noChangeTests[i].secondPaint);
    275         recorder.restore();
    276         recorder.restore();
    277         recorder.restore();
    278         assert_merge_svg_opacity_and_filter_layers(r, &record, index, false);
    279         index += 7;
    280     }
    281 
    282     // Test the folded alpha value.
    283     recorder.saveLayer(NULL, &alphaOnlyLayerPaint);
    284     recorder.save();
    285     recorder.clipRect(clip);
    286     recorder.saveLayer(NULL, &opaqueFilterLayerPaint);
    287     recorder.restore();
    288     recorder.restore();
    289     recorder.restore();
    290     assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
    291 
    292     const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3);
    293     REPORTER_ASSERT(r, saveLayer != NULL);
    294     REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202);
    295 
    296     index += 7;
    297 
    298     // Test that currently we do not fold alphas for patterns without the clip. This is just not
    299     // implemented.
    300     recorder.saveLayer(NULL, &alphaOnlyLayerPaint);
    301     recorder.saveLayer(NULL, &opaqueFilterLayerPaint);
    302     recorder.restore();
    303     recorder.restore();
    304     SkRecordMergeSvgOpacityAndFilterLayers(&record);
    305     assert_type<SkRecords::SaveLayer>(r, record, index);
    306     assert_type<SkRecords::SaveLayer>(r, record, index + 1);
    307     assert_type<SkRecords::Restore>(r, record, index + 2);
    308     assert_type<SkRecords::Restore>(r, record, index + 3);
    309     index += 4;
    310 }
    311