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 "SkRecord.h"
     12 #include "SkRecordOpts.h"
     13 #include "SkRecorder.h"
     14 #include "SkRecords.h"
     15 #include "SkXfermode.h"
     16 
     17 static const int W = 1920, H = 1080;
     18 
     19 DEF_TEST(RecordOpts_Culling, r) {
     20     SkRecord record;
     21     SkRecorder recorder(&record, W, H);
     22 
     23     recorder.drawRect(SkRect::MakeWH(1000, 10000), SkPaint());
     24 
     25     recorder.pushCull(SkRect::MakeWH(100, 100));
     26         recorder.drawRect(SkRect::MakeWH(10, 10), SkPaint());
     27         recorder.drawRect(SkRect::MakeWH(30, 30), SkPaint());
     28         recorder.pushCull(SkRect::MakeWH(5, 5));
     29             recorder.drawRect(SkRect::MakeWH(1, 1), SkPaint());
     30         recorder.popCull();
     31     recorder.popCull();
     32 
     33     SkRecordAnnotateCullingPairs(&record);
     34 
     35     REPORTER_ASSERT(r, 6 == assert_type<SkRecords::PairedPushCull>(r, record, 1)->skip);
     36     REPORTER_ASSERT(r, 2 == assert_type<SkRecords::PairedPushCull>(r, record, 4)->skip);
     37 }
     38 
     39 DEF_TEST(RecordOpts_NoopCulls, r) {
     40     SkRecord record;
     41     SkRecorder recorder(&record, W, H);
     42 
     43     // All should be nooped.
     44     recorder.pushCull(SkRect::MakeWH(200, 200));
     45         recorder.pushCull(SkRect::MakeWH(100, 100));
     46         recorder.popCull();
     47     recorder.popCull();
     48 
     49     // Kept for now.  We could peel off a layer of culling.
     50     recorder.pushCull(SkRect::MakeWH(5, 5));
     51         recorder.pushCull(SkRect::MakeWH(5, 5));
     52             recorder.drawRect(SkRect::MakeWH(1, 1), SkPaint());
     53         recorder.popCull();
     54     recorder.popCull();
     55 
     56     SkRecordNoopCulls(&record);
     57 
     58     for (unsigned i = 0; i < 4; i++) {
     59         assert_type<SkRecords::NoOp>(r, record, i);
     60     }
     61     assert_type<SkRecords::PushCull>(r, record, 4);
     62     assert_type<SkRecords::PushCull>(r, record, 5);
     63     assert_type<SkRecords::DrawRect>(r, record, 6);
     64     assert_type<SkRecords::PopCull>(r, record, 7);
     65     assert_type<SkRecords::PopCull>(r, record, 8);
     66 }
     67 
     68 static void draw_pos_text(SkCanvas* canvas, const char* text, bool constantY) {
     69     const size_t len = strlen(text);
     70     SkAutoTMalloc<SkPoint> pos(len);
     71     for (size_t i = 0; i < len; i++) {
     72         pos[i].fX = (SkScalar)i;
     73         pos[i].fY = constantY ? SK_Scalar1 : (SkScalar)i;
     74     }
     75     canvas->drawPosText(text, len, pos, SkPaint());
     76 }
     77 
     78 DEF_TEST(RecordOpts_StrengthReduction, r) {
     79     SkRecord record;
     80     SkRecorder recorder(&record, W, H);
     81 
     82     // We can convert a drawPosText into a drawPosTextH when all the Ys are the same.
     83     draw_pos_text(&recorder, "This will be reduced to drawPosTextH.", true);
     84     draw_pos_text(&recorder, "This cannot be reduced to drawPosTextH.", false);
     85 
     86     SkRecordReduceDrawPosTextStrength(&record);
     87 
     88     assert_type<SkRecords::DrawPosTextH>(r, record, 0);
     89     assert_type<SkRecords::DrawPosText>(r, record, 1);
     90 }
     91 
     92 DEF_TEST(RecordOpts_TextBounding, r) {
     93     SkRecord record;
     94     SkRecorder recorder(&record, W, H);
     95 
     96     // First, get a drawPosTextH.  Here's a handy way.  Its text size will be the default (12).
     97     draw_pos_text(&recorder, "This will be reduced to drawPosTextH.", true);
     98     SkRecordReduceDrawPosTextStrength(&record);
     99 
    100     const SkRecords::DrawPosTextH* original =
    101         assert_type<SkRecords::DrawPosTextH>(r, record, 0);
    102 
    103     // This should wrap the original DrawPosTextH with minY and maxY.
    104     SkRecordBoundDrawPosTextH(&record);
    105 
    106     const SkRecords::BoundedDrawPosTextH* bounded =
    107         assert_type<SkRecords::BoundedDrawPosTextH>(r, record, 0);
    108 
    109     const SkPaint defaults;
    110     REPORTER_ASSERT(r, bounded->base == original);
    111     REPORTER_ASSERT(r, bounded->minY <= SK_Scalar1 - defaults.getTextSize());
    112     REPORTER_ASSERT(r, bounded->maxY >= SK_Scalar1 + defaults.getTextSize());
    113 }
    114 
    115 DEF_TEST(RecordOpts_NoopDrawSaveRestore, r) {
    116     SkRecord record;
    117     SkRecorder recorder(&record, W, H);
    118 
    119     // The save and restore are pointless if there's only draw commands in the middle.
    120     recorder.save();
    121         recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint());
    122         recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint());
    123         recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint());
    124     recorder.restore();
    125 
    126     record.replace<SkRecords::NoOp>(2);  // NoOps should be allowed.
    127 
    128     SkRecordNoopSaveRestores(&record);
    129 
    130     assert_type<SkRecords::NoOp>(r, record, 0);
    131     assert_type<SkRecords::DrawRect>(r, record, 1);
    132     assert_type<SkRecords::NoOp>(r, record, 2);
    133     assert_type<SkRecords::DrawRect>(r, record, 3);
    134     assert_type<SkRecords::NoOp>(r, record, 4);
    135 }
    136 
    137 DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
    138     SkRecord record;
    139     SkRecorder recorder(&record, W, H);
    140 
    141     recorder.save();
    142         recorder.clipRect(SkRect::MakeWH(200, 200));
    143     recorder.restore();
    144 
    145     SkRecordNoopSaveRestores(&record);
    146     for (unsigned i = 0; i < 3; i++) {
    147         assert_type<SkRecords::NoOp>(r, record, i);
    148     }
    149 }
    150 
    151 DEF_TEST(RecordOpts_NoopSaveRestores, r) {
    152     SkRecord record;
    153     SkRecorder recorder(&record, W, H);
    154 
    155     // The second pass will clean up this pair after the first pass noops all the innards.
    156     recorder.save();
    157         // A simple pointless pair of save/restore.
    158         recorder.save();
    159         recorder.restore();
    160 
    161         // As long as we don't draw in there, everything is a noop.
    162         recorder.save();
    163             recorder.clipRect(SkRect::MakeWH(200, 200));
    164             recorder.clipRect(SkRect::MakeWH(100, 100));
    165         recorder.restore();
    166     recorder.restore();
    167 
    168     SkRecordNoopSaveRestores(&record);
    169     for (unsigned index = 0; index < 8; index++) {
    170         assert_type<SkRecords::NoOp>(r, record, index);
    171     }
    172 }
    173 
    174 static void assert_savelayer_restore(skiatest::Reporter* r,
    175                                      SkRecord* record,
    176                                      unsigned i,
    177                                      bool shouldBeNoOped) {
    178     SkRecordNoopSaveLayerDrawRestores(record);
    179     if (shouldBeNoOped) {
    180         assert_type<SkRecords::NoOp>(r, *record, i);
    181         assert_type<SkRecords::NoOp>(r, *record, i+2);
    182     } else {
    183         assert_type<SkRecords::SaveLayer>(r, *record, i);
    184         assert_type<SkRecords::Restore>(r, *record, i+2);
    185     }
    186 }
    187 
    188 DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
    189     SkRecord record;
    190     SkRecorder recorder(&record, W, H);
    191 
    192     SkRect bounds = SkRect::MakeWH(100, 200);
    193     SkRect   draw = SkRect::MakeWH(50, 60);
    194 
    195     SkPaint goodLayerPaint, badLayerPaint, worseLayerPaint;
    196     goodLayerPaint.setColor(0x03000000);  // Only alpha.
    197     badLayerPaint.setColor( 0x03040506);  // Not only alpha.
    198     worseLayerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);  // Any effect will do.
    199 
    200     SkPaint goodDrawPaint, badDrawPaint;
    201     goodDrawPaint.setColor(0xFF020202);  // Opaque.
    202     badDrawPaint.setColor( 0x0F020202);  // Not opaque.
    203 
    204     // No change: optimization can't handle bounds.
    205     recorder.saveLayer(&bounds, NULL);
    206         recorder.drawRect(draw, goodDrawPaint);
    207     recorder.restore();
    208     assert_savelayer_restore(r, &record, 0, false);
    209 
    210     // SaveLayer/Restore removed: no bounds + no paint = no point.
    211     recorder.saveLayer(NULL, NULL);
    212         recorder.drawRect(draw, goodDrawPaint);
    213     recorder.restore();
    214     assert_savelayer_restore(r, &record, 3, true);
    215 
    216     // TODO(mtklein): test case with null draw paint
    217 
    218     // No change: layer paint isn't alpha-only.
    219     recorder.saveLayer(NULL, &badLayerPaint);
    220         recorder.drawRect(draw, goodDrawPaint);
    221     recorder.restore();
    222     assert_savelayer_restore(r, &record, 6, false);
    223 
    224     // No change: layer paint has an effect.
    225     recorder.saveLayer(NULL, &worseLayerPaint);
    226         recorder.drawRect(draw, goodDrawPaint);
    227     recorder.restore();
    228     assert_savelayer_restore(r, &record, 9, false);
    229 
    230     // No change: draw paint isn't opaque.
    231     recorder.saveLayer(NULL, &goodLayerPaint);
    232         recorder.drawRect(draw, badDrawPaint);
    233     recorder.restore();
    234     assert_savelayer_restore(r, &record, 12, false);
    235 
    236     // SaveLayer/Restore removed: we can fold in the alpha!
    237     recorder.saveLayer(NULL, &goodLayerPaint);
    238         recorder.drawRect(draw, goodDrawPaint);
    239     recorder.restore();
    240     assert_savelayer_restore(r, &record, 15, true);
    241 
    242     const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
    243     REPORTER_ASSERT(r, drawRect != NULL);
    244     REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
    245 }
    246