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