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 "SkBlurImageFilter.h" 12 #include "SkColorFilter.h" 13 #include "SkRecord.h" 14 #include "SkRecordOpts.h" 15 #include "SkRecorder.h" 16 #include "SkRecords.h" 17 #include "SkPictureRecorder.h" 18 #include "SkPictureImageFilter.h" 19 #include "SkSurface.h" 20 21 static const int W = 1920, H = 1080; 22 23 DEF_TEST(RecordOpts_NoopDraw, r) { 24 SkRecord record; 25 SkRecorder recorder(&record, W, H); 26 27 recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint()); 28 recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint()); 29 recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint()); 30 31 record.replace<SkRecords::NoOp>(1); // NoOps should be allowed. 32 33 SkRecordNoopSaveRestores(&record); 34 35 REPORTER_ASSERT(r, 2 == count_instances_of_type<SkRecords::DrawRect>(record)); 36 } 37 38 DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) { 39 SkRecord record; 40 SkRecorder recorder(&record, W, H); 41 42 recorder.save(); 43 recorder.clipRect(SkRect::MakeWH(200, 200)); 44 recorder.restore(); 45 46 SkRecordNoopSaveRestores(&record); 47 for (int i = 0; i < 3; i++) { 48 assert_type<SkRecords::NoOp>(r, record, i); 49 } 50 } 51 52 DEF_TEST(RecordOpts_NoopSaveRestores, r) { 53 SkRecord record; 54 SkRecorder recorder(&record, W, H); 55 56 // The second pass will clean up this pair after the first pass noops all the innards. 57 recorder.save(); 58 // A simple pointless pair of save/restore. 59 recorder.save(); 60 recorder.restore(); 61 62 // As long as we don't draw in there, everything is a noop. 63 recorder.save(); 64 recorder.clipRect(SkRect::MakeWH(200, 200)); 65 recorder.clipRect(SkRect::MakeWH(100, 100)); 66 recorder.restore(); 67 recorder.restore(); 68 69 SkRecordNoopSaveRestores(&record); 70 for (int index = 0; index < record.count(); index++) { 71 assert_type<SkRecords::NoOp>(r, record, index); 72 } 73 } 74 75 DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) { 76 SkRecord record; 77 SkRecorder recorder(&record, W, H); 78 79 // A previous bug NoOp'd away the first 3 commands. 80 recorder.save(); 81 recorder.saveLayer(nullptr, nullptr); 82 recorder.restore(); 83 recorder.restore(); 84 85 SkRecordNoopSaveRestores(&record); 86 switch (record.count()) { 87 case 4: 88 assert_type<SkRecords::Save> (r, record, 0); 89 assert_type<SkRecords::SaveLayer>(r, record, 1); 90 assert_type<SkRecords::Restore> (r, record, 2); 91 assert_type<SkRecords::Restore> (r, record, 3); 92 break; 93 case 2: 94 assert_type<SkRecords::SaveLayer>(r, record, 0); 95 assert_type<SkRecords::Restore> (r, record, 1); 96 break; 97 case 0: 98 break; 99 default: 100 REPORTER_ASSERT(r, false); 101 } 102 } 103 104 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK 105 static void assert_savelayer_restore(skiatest::Reporter* r, 106 SkRecord* record, 107 int i, 108 bool shouldBeNoOped) { 109 SkRecordNoopSaveLayerDrawRestores(record); 110 if (shouldBeNoOped) { 111 assert_type<SkRecords::NoOp>(r, *record, i); 112 assert_type<SkRecords::NoOp>(r, *record, i+1); 113 } else { 114 assert_type<SkRecords::SaveLayer>(r, *record, i); 115 assert_type<SkRecords::Restore>(r, *record, i+1); 116 } 117 } 118 119 static void assert_savelayer_draw_restore(skiatest::Reporter* r, 120 SkRecord* record, 121 int i, 122 bool shouldBeNoOped) { 123 SkRecordNoopSaveLayerDrawRestores(record); 124 if (shouldBeNoOped) { 125 assert_type<SkRecords::NoOp>(r, *record, i); 126 assert_type<SkRecords::NoOp>(r, *record, i+2); 127 } else { 128 assert_type<SkRecords::SaveLayer>(r, *record, i); 129 assert_type<SkRecords::Restore>(r, *record, i+2); 130 } 131 } 132 133 DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) { 134 SkRecord record; 135 SkRecorder recorder(&record, W, H); 136 137 SkRect bounds = SkRect::MakeWH(100, 200); 138 SkRect draw = SkRect::MakeWH(50, 60); 139 140 SkPaint alphaOnlyLayerPaint, translucentLayerPaint, xfermodeLayerPaint; 141 alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha. 142 translucentLayerPaint.setColor(0x03040506); // Not only alpha. 143 xfermodeLayerPaint.setBlendMode(SkBlendMode::kDstIn); // Any effect will do. 144 145 SkPaint opaqueDrawPaint, translucentDrawPaint; 146 opaqueDrawPaint.setColor(0xFF020202); // Opaque. 147 translucentDrawPaint.setColor(0x0F020202); // Not opaque. 148 149 // SaveLayer/Restore removed: No paint = no point. 150 recorder.saveLayer(nullptr, nullptr); 151 recorder.drawRect(draw, opaqueDrawPaint); 152 recorder.restore(); 153 assert_savelayer_draw_restore(r, &record, 0, true); 154 155 // Bounds don't matter. 156 recorder.saveLayer(&bounds, nullptr); 157 recorder.drawRect(draw, opaqueDrawPaint); 158 recorder.restore(); 159 assert_savelayer_draw_restore(r, &record, 3, true); 160 161 // TODO(mtklein): test case with null draw paint 162 163 // No change: layer paint isn't alpha-only. 164 recorder.saveLayer(nullptr, &translucentLayerPaint); 165 recorder.drawRect(draw, opaqueDrawPaint); 166 recorder.restore(); 167 assert_savelayer_draw_restore(r, &record, 6, false); 168 169 // No change: layer paint has an effect. 170 recorder.saveLayer(nullptr, &xfermodeLayerPaint); 171 recorder.drawRect(draw, opaqueDrawPaint); 172 recorder.restore(); 173 assert_savelayer_draw_restore(r, &record, 9, false); 174 175 // SaveLayer/Restore removed: we can fold in the alpha! 176 recorder.saveLayer(nullptr, &alphaOnlyLayerPaint); 177 recorder.drawRect(draw, translucentDrawPaint); 178 recorder.restore(); 179 assert_savelayer_draw_restore(r, &record, 12, true); 180 181 // SaveLayer/Restore removed: we can fold in the alpha! 182 recorder.saveLayer(nullptr, &alphaOnlyLayerPaint); 183 recorder.drawRect(draw, opaqueDrawPaint); 184 recorder.restore(); 185 assert_savelayer_draw_restore(r, &record, 15, true); 186 187 const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16); 188 REPORTER_ASSERT(r, drawRect != nullptr); 189 REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202); 190 191 // saveLayer w/ backdrop should NOT go away 192 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(3, 3, nullptr)); 193 recorder.saveLayer({ nullptr, nullptr, filter.get(), nullptr, nullptr, 0}); 194 recorder.drawRect(draw, opaqueDrawPaint); 195 recorder.restore(); 196 assert_savelayer_draw_restore(r, &record, 18, false); 197 198 // saveLayer w/ clip mask should also NOT go away 199 { 200 sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(10, 10)); 201 recorder.saveLayer({ nullptr, nullptr, nullptr, surface->makeImageSnapshot().get(), 202 nullptr, 0}); 203 recorder.drawRect(draw, opaqueDrawPaint); 204 recorder.restore(); 205 assert_savelayer_draw_restore(r, &record, 21, false); 206 } 207 } 208 #endif 209 210 static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r, 211 SkRecord* record, 212 int i, 213 bool shouldBeNoOped) { 214 SkRecordMergeSvgOpacityAndFilterLayers(record); 215 if (shouldBeNoOped) { 216 assert_type<SkRecords::NoOp>(r, *record, i); 217 assert_type<SkRecords::NoOp>(r, *record, i + 6); 218 } else { 219 assert_type<SkRecords::SaveLayer>(r, *record, i); 220 assert_type<SkRecords::Restore>(r, *record, i + 6); 221 } 222 } 223 224 DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) { 225 SkRecord record; 226 SkRecorder recorder(&record, W, H); 227 228 SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200)); 229 SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60)); 230 231 SkPaint alphaOnlyLayerPaint; 232 alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha. 233 SkPaint translucentLayerPaint; 234 translucentLayerPaint.setColor(0x03040506); // Not only alpha. 235 SkPaint xfermodePaint; 236 xfermodePaint.setBlendMode(SkBlendMode::kDstIn); 237 SkPaint colorFilterPaint; 238 colorFilterPaint.setColorFilter( 239 SkColorFilter::MakeModeFilter(SK_ColorLTGRAY, SkBlendMode::kSrcIn)); 240 241 SkPaint opaqueFilterLayerPaint; 242 opaqueFilterLayerPaint.setColor(0xFF020202); // Opaque. 243 SkPaint translucentFilterLayerPaint; 244 translucentFilterLayerPaint.setColor(0x0F020202); // Not opaque. 245 sk_sp<SkPicture> shape; 246 { 247 SkPictureRecorder recorder; 248 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100)); 249 SkPaint shapePaint; 250 shapePaint.setColor(SK_ColorWHITE); 251 canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint); 252 shape = recorder.finishRecordingAsPicture(); 253 } 254 translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Make(shape)); 255 256 int index = 0; 257 258 { 259 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(3, 3, nullptr)); 260 // first (null) should be optimized, 2nd should not 261 SkImageFilter* filters[] = { nullptr, filter.get() }; 262 263 // Any combination of these should cause the pattern to be optimized. 264 SkRect* firstBounds[] = { nullptr, &bounds }; 265 SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint }; 266 SkRect* secondBounds[] = { nullptr, &bounds }; 267 SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint }; 268 269 for (auto outerF : filters) { 270 bool outerNoOped = !outerF; 271 for (auto innerF : filters) { 272 for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) { 273 for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) { 274 for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) { 275 for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) { 276 bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF; 277 278 recorder.saveLayer({firstBounds[i], firstPaints[j], outerF, 279 nullptr, nullptr, 0}); 280 recorder.save(); 281 recorder.clipRect(clip); 282 recorder.saveLayer({secondBounds[k], secondPaints[m], innerF, 283 nullptr, nullptr, 0}); 284 recorder.restore(); 285 recorder.restore(); 286 recorder.restore(); 287 assert_merge_svg_opacity_and_filter_layers(r, &record, index, 288 outerNoOped); 289 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK 290 assert_savelayer_restore(r, &record, index + 3, innerNoOped); 291 #endif 292 index += 7; 293 } 294 } 295 } 296 } 297 } 298 } 299 } 300 301 // These should cause the pattern to stay unoptimized: 302 struct { 303 SkPaint* firstPaint; 304 SkPaint* secondPaint; 305 } noChangeTests[] = { 306 // No change: nullptr filter layer paint not implemented. 307 { &alphaOnlyLayerPaint, nullptr }, 308 // No change: layer paint is not alpha-only. 309 { &translucentLayerPaint, &opaqueFilterLayerPaint }, 310 // No change: layer paint has an xfereffect. 311 { &xfermodePaint, &opaqueFilterLayerPaint }, 312 // No change: filter layer paint has an xfereffect. 313 { &alphaOnlyLayerPaint, &xfermodePaint }, 314 // No change: layer paint has a color filter. 315 { &colorFilterPaint, &opaqueFilterLayerPaint }, 316 // No change: filter layer paint has a color filter (until the optimization accounts for 317 // constant color draws that can filter the color). 318 { &alphaOnlyLayerPaint, &colorFilterPaint } 319 }; 320 321 for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) { 322 recorder.saveLayer(nullptr, noChangeTests[i].firstPaint); 323 recorder.save(); 324 recorder.clipRect(clip); 325 recorder.saveLayer(nullptr, noChangeTests[i].secondPaint); 326 recorder.restore(); 327 recorder.restore(); 328 recorder.restore(); 329 assert_merge_svg_opacity_and_filter_layers(r, &record, index, false); 330 index += 7; 331 } 332 333 // Test the folded alpha value. 334 recorder.saveLayer(nullptr, &alphaOnlyLayerPaint); 335 recorder.save(); 336 recorder.clipRect(clip); 337 recorder.saveLayer(nullptr, &opaqueFilterLayerPaint); 338 recorder.restore(); 339 recorder.restore(); 340 recorder.restore(); 341 assert_merge_svg_opacity_and_filter_layers(r, &record, index, true); 342 343 const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3); 344 REPORTER_ASSERT(r, saveLayer != nullptr); 345 REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202); 346 347 index += 7; 348 349 // Test that currently we do not fold alphas for patterns without the clip. This is just not 350 // implemented. 351 recorder.saveLayer(nullptr, &alphaOnlyLayerPaint); 352 recorder.saveLayer(nullptr, &opaqueFilterLayerPaint); 353 recorder.restore(); 354 recorder.restore(); 355 SkRecordMergeSvgOpacityAndFilterLayers(&record); 356 assert_type<SkRecords::SaveLayer>(r, record, index); 357 assert_type<SkRecords::SaveLayer>(r, record, index + 1); 358 assert_type<SkRecords::Restore>(r, record, index + 2); 359 assert_type<SkRecords::Restore>(r, record, index + 3); 360 index += 4; 361 } 362 363 static void do_draw(SkCanvas* canvas, SkColor color, bool doLayer) { 364 canvas->drawColor(SK_ColorWHITE); 365 366 SkPaint p; 367 p.setColor(color); 368 369 if (doLayer) { 370 canvas->saveLayer(nullptr, nullptr); 371 p.setBlendMode(SkBlendMode::kSrc); 372 canvas->drawPaint(p); 373 canvas->restore(); 374 } else { 375 canvas->drawPaint(p); 376 } 377 } 378 379 static bool is_equal(SkSurface* a, SkSurface* b) { 380 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 381 SkPMColor ca, cb; 382 a->readPixels(info, &ca, sizeof(SkPMColor), 0, 0); 383 b->readPixels(info, &cb, sizeof(SkPMColor), 0, 0); 384 return ca == cb; 385 } 386 387 // Test drawing w/ and w/o a simple layer (no bounds or paint), so see that drawing ops 388 // that *should* draw the same in fact do. 389 // 390 // Perform this test twice : once directly, and once via a picture 391 // 392 static void do_savelayer_srcmode(skiatest::Reporter* r, SkColor color) { 393 for (int doPicture = 0; doPicture <= 1; ++doPicture) { 394 sk_sp<SkSurface> surf0 = SkSurface::MakeRasterN32Premul(10, 10); 395 sk_sp<SkSurface> surf1 = SkSurface::MakeRasterN32Premul(10, 10); 396 SkCanvas* c0 = surf0->getCanvas(); 397 SkCanvas* c1 = surf1->getCanvas(); 398 399 SkPictureRecorder rec0, rec1; 400 if (doPicture) { 401 c0 = rec0.beginRecording(10, 10); 402 c1 = rec1.beginRecording(10, 10); 403 } 404 405 do_draw(c0, color, false); 406 do_draw(c1, color, true); 407 408 if (doPicture) { 409 surf0->getCanvas()->drawPicture(rec0.finishRecordingAsPicture()); 410 surf1->getCanvas()->drawPicture(rec1.finishRecordingAsPicture()); 411 } 412 413 // we replicate the assert so we can see which line is reported if there is a failure 414 if (doPicture) { 415 REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get())); 416 } else { 417 REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get())); 418 } 419 } 420 } 421 422 DEF_TEST(savelayer_srcmode_opaque, r) { 423 do_savelayer_srcmode(r, SK_ColorRED); 424 } 425 426 DEF_TEST(savelayer_srcmode_alpha, r) { 427 do_savelayer_srcmode(r, 0x80FF0000); 428 } 429 430