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 21static const int W = 1920, H = 1080; 22 23DEF_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 38DEF_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 52DEF_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 75DEF_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 105static 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 119static 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 133DEF_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(), 0}); 194 recorder.drawRect(draw, opaqueDrawPaint); 195 recorder.restore(); 196 assert_savelayer_draw_restore(r, &record, 18, false); 197} 198#endif 199 200static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r, 201 SkRecord* record, 202 int i, 203 bool shouldBeNoOped) { 204 SkRecordMergeSvgOpacityAndFilterLayers(record); 205 if (shouldBeNoOped) { 206 assert_type<SkRecords::NoOp>(r, *record, i); 207 assert_type<SkRecords::NoOp>(r, *record, i + 6); 208 } else { 209 assert_type<SkRecords::SaveLayer>(r, *record, i); 210 assert_type<SkRecords::Restore>(r, *record, i + 6); 211 } 212} 213 214DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) { 215 SkRecord record; 216 SkRecorder recorder(&record, W, H); 217 218 SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200)); 219 SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60)); 220 221 SkPaint alphaOnlyLayerPaint; 222 alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha. 223 SkPaint translucentLayerPaint; 224 translucentLayerPaint.setColor(0x03040506); // Not only alpha. 225 SkPaint xfermodePaint; 226 xfermodePaint.setBlendMode(SkBlendMode::kDstIn); 227 SkPaint colorFilterPaint; 228 colorFilterPaint.setColorFilter( 229 SkColorFilter::MakeModeFilter(SK_ColorLTGRAY, SkBlendMode::kSrcIn)); 230 231 SkPaint opaqueFilterLayerPaint; 232 opaqueFilterLayerPaint.setColor(0xFF020202); // Opaque. 233 SkPaint translucentFilterLayerPaint; 234 translucentFilterLayerPaint.setColor(0x0F020202); // Not opaque. 235 sk_sp<SkPicture> shape; 236 { 237 SkPictureRecorder recorder; 238 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100)); 239 SkPaint shapePaint; 240 shapePaint.setColor(SK_ColorWHITE); 241 canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint); 242 shape = recorder.finishRecordingAsPicture(); 243 } 244 translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Make(shape)); 245 246 int index = 0; 247 248 { 249 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(3, 3, nullptr)); 250 // first (null) should be optimized, 2nd should not 251 SkImageFilter* filters[] = { nullptr, filter.get() }; 252 253 // Any combination of these should cause the pattern to be optimized. 254 SkRect* firstBounds[] = { nullptr, &bounds }; 255 SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint }; 256 SkRect* secondBounds[] = { nullptr, &bounds }; 257 SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint }; 258 259 for (auto outerF : filters) { 260 bool outerNoOped = !outerF; 261 for (auto innerF : filters) { 262 for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) { 263 for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) { 264 for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) { 265 for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) { 266 bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF; 267 268 recorder.saveLayer({firstBounds[i], firstPaints[j], outerF, 0}); 269 recorder.save(); 270 recorder.clipRect(clip); 271 recorder.saveLayer({secondBounds[k], secondPaints[m], innerF, 0}); 272 recorder.restore(); 273 recorder.restore(); 274 recorder.restore(); 275 assert_merge_svg_opacity_and_filter_layers(r, &record, index, 276 outerNoOped); 277 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK 278 assert_savelayer_restore(r, &record, index + 3, innerNoOped); 279 #endif 280 index += 7; 281 } 282 } 283 } 284 } 285 } 286 } 287 } 288 289 // These should cause the pattern to stay unoptimized: 290 struct { 291 SkPaint* firstPaint; 292 SkPaint* secondPaint; 293 } noChangeTests[] = { 294 // No change: nullptr filter layer paint not implemented. 295 { &alphaOnlyLayerPaint, nullptr }, 296 // No change: layer paint is not alpha-only. 297 { &translucentLayerPaint, &opaqueFilterLayerPaint }, 298 // No change: layer paint has an xfereffect. 299 { &xfermodePaint, &opaqueFilterLayerPaint }, 300 // No change: filter layer paint has an xfereffect. 301 { &alphaOnlyLayerPaint, &xfermodePaint }, 302 // No change: layer paint has a color filter. 303 { &colorFilterPaint, &opaqueFilterLayerPaint }, 304 // No change: filter layer paint has a color filter (until the optimization accounts for 305 // constant color draws that can filter the color). 306 { &alphaOnlyLayerPaint, &colorFilterPaint } 307 }; 308 309 for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) { 310 recorder.saveLayer(nullptr, noChangeTests[i].firstPaint); 311 recorder.save(); 312 recorder.clipRect(clip); 313 recorder.saveLayer(nullptr, noChangeTests[i].secondPaint); 314 recorder.restore(); 315 recorder.restore(); 316 recorder.restore(); 317 assert_merge_svg_opacity_and_filter_layers(r, &record, index, false); 318 index += 7; 319 } 320 321 // Test the folded alpha value. 322 recorder.saveLayer(nullptr, &alphaOnlyLayerPaint); 323 recorder.save(); 324 recorder.clipRect(clip); 325 recorder.saveLayer(nullptr, &opaqueFilterLayerPaint); 326 recorder.restore(); 327 recorder.restore(); 328 recorder.restore(); 329 assert_merge_svg_opacity_and_filter_layers(r, &record, index, true); 330 331 const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3); 332 REPORTER_ASSERT(r, saveLayer != nullptr); 333 REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202); 334 335 index += 7; 336 337 // Test that currently we do not fold alphas for patterns without the clip. This is just not 338 // implemented. 339 recorder.saveLayer(nullptr, &alphaOnlyLayerPaint); 340 recorder.saveLayer(nullptr, &opaqueFilterLayerPaint); 341 recorder.restore(); 342 recorder.restore(); 343 SkRecordMergeSvgOpacityAndFilterLayers(&record); 344 assert_type<SkRecords::SaveLayer>(r, record, index); 345 assert_type<SkRecords::SaveLayer>(r, record, index + 1); 346 assert_type<SkRecords::Restore>(r, record, index + 2); 347 assert_type<SkRecords::Restore>(r, record, index + 3); 348 index += 4; 349} 350 351static void do_draw(SkCanvas* canvas, SkColor color, bool doLayer) { 352 canvas->drawColor(SK_ColorWHITE); 353 354 SkPaint p; 355 p.setColor(color); 356 357 if (doLayer) { 358 canvas->saveLayer(nullptr, nullptr); 359 p.setBlendMode(SkBlendMode::kSrc); 360 canvas->drawPaint(p); 361 canvas->restore(); 362 } else { 363 canvas->drawPaint(p); 364 } 365} 366 367static bool is_equal(SkSurface* a, SkSurface* b) { 368 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 369 SkPMColor ca, cb; 370 a->readPixels(info, &ca, sizeof(SkPMColor), 0, 0); 371 b->readPixels(info, &cb, sizeof(SkPMColor), 0, 0); 372 return ca == cb; 373} 374 375// Test drawing w/ and w/o a simple layer (no bounds or paint), so see that drawing ops 376// that *should* draw the same in fact do. 377// 378// Perform this test twice : once directly, and once via a picture 379// 380static void do_savelayer_srcmode(skiatest::Reporter* r, SkColor color) { 381 for (int doPicture = 0; doPicture <= 1; ++doPicture) { 382 sk_sp<SkSurface> surf0 = SkSurface::MakeRasterN32Premul(10, 10); 383 sk_sp<SkSurface> surf1 = SkSurface::MakeRasterN32Premul(10, 10); 384 SkCanvas* c0 = surf0->getCanvas(); 385 SkCanvas* c1 = surf1->getCanvas(); 386 387 SkPictureRecorder rec0, rec1; 388 if (doPicture) { 389 c0 = rec0.beginRecording(10, 10); 390 c1 = rec1.beginRecording(10, 10); 391 } 392 393 do_draw(c0, color, false); 394 do_draw(c1, color, true); 395 396 if (doPicture) { 397 surf0->getCanvas()->drawPicture(rec0.finishRecordingAsPicture()); 398 surf1->getCanvas()->drawPicture(rec1.finishRecordingAsPicture()); 399 } 400 401 // we replicate the assert so we can see which line is reported if there is a failure 402 if (doPicture) { 403 REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get())); 404 } else { 405 REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get())); 406 } 407 } 408} 409 410DEF_TEST(savelayer_srcmode_opaque, r) { 411 do_savelayer_srcmode(r, SK_ColorRED); 412} 413 414DEF_TEST(savelayer_srcmode_alpha, r) { 415 do_savelayer_srcmode(r, 0x80FF0000); 416} 417 418