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