123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- /*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "tests/RecordTestUtils.h"
- #include "tests/Test.h"
- #include "include/core/SkColorFilter.h"
- #include "include/core/SkPictureRecorder.h"
- #include "include/core/SkSurface.h"
- #include "include/effects/SkBlurImageFilter.h"
- #include "include/effects/SkPictureImageFilter.h"
- #include "src/core/SkRecord.h"
- #include "src/core/SkRecordOpts.h"
- #include "src/core/SkRecorder.h"
- #include "src/core/SkRecords.h"
- static const int W = 1920, H = 1080;
- DEF_TEST(RecordOpts_NoopDraw, r) {
- SkRecord record;
- SkRecorder recorder(&record, W, H);
- recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint());
- recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint());
- recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint());
- record.replace<SkRecords::NoOp>(1); // NoOps should be allowed.
- SkRecordNoopSaveRestores(&record);
- REPORTER_ASSERT(r, 2 == count_instances_of_type<SkRecords::DrawRect>(record));
- }
- DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
- SkRecord record;
- SkRecorder recorder(&record, W, H);
- recorder.save();
- recorder.clipRect(SkRect::MakeWH(200, 200));
- recorder.restore();
- SkRecordNoopSaveRestores(&record);
- for (int i = 0; i < 3; i++) {
- assert_type<SkRecords::NoOp>(r, record, i);
- }
- }
- DEF_TEST(RecordOpts_NoopSaveRestores, r) {
- SkRecord record;
- SkRecorder recorder(&record, W, H);
- // The second pass will clean up this pair after the first pass noops all the innards.
- recorder.save();
- // A simple pointless pair of save/restore.
- recorder.save();
- recorder.restore();
- // As long as we don't draw in there, everything is a noop.
- recorder.save();
- recorder.clipRect(SkRect::MakeWH(200, 200));
- recorder.clipRect(SkRect::MakeWH(100, 100));
- recorder.restore();
- recorder.restore();
- SkRecordNoopSaveRestores(&record);
- for (int index = 0; index < record.count(); index++) {
- assert_type<SkRecords::NoOp>(r, record, index);
- }
- }
- DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) {
- SkRecord record;
- SkRecorder recorder(&record, W, H);
- // A previous bug NoOp'd away the first 3 commands.
- recorder.save();
- recorder.saveLayer(nullptr, nullptr);
- recorder.restore();
- recorder.restore();
- SkRecordNoopSaveRestores(&record);
- switch (record.count()) {
- case 4:
- assert_type<SkRecords::Save> (r, record, 0);
- assert_type<SkRecords::SaveLayer>(r, record, 1);
- assert_type<SkRecords::Restore> (r, record, 2);
- assert_type<SkRecords::Restore> (r, record, 3);
- break;
- case 2:
- assert_type<SkRecords::SaveLayer>(r, record, 0);
- assert_type<SkRecords::Restore> (r, record, 1);
- break;
- case 0:
- break;
- default:
- REPORTER_ASSERT(r, false);
- }
- }
- #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
- static void assert_savelayer_restore(skiatest::Reporter* r,
- SkRecord* record,
- int i,
- bool shouldBeNoOped) {
- SkRecordNoopSaveLayerDrawRestores(record);
- if (shouldBeNoOped) {
- assert_type<SkRecords::NoOp>(r, *record, i);
- assert_type<SkRecords::NoOp>(r, *record, i+1);
- } else {
- assert_type<SkRecords::SaveLayer>(r, *record, i);
- assert_type<SkRecords::Restore>(r, *record, i+1);
- }
- }
- static void assert_savelayer_draw_restore(skiatest::Reporter* r,
- SkRecord* record,
- int i,
- bool shouldBeNoOped) {
- SkRecordNoopSaveLayerDrawRestores(record);
- if (shouldBeNoOped) {
- assert_type<SkRecords::NoOp>(r, *record, i);
- assert_type<SkRecords::NoOp>(r, *record, i+2);
- } else {
- assert_type<SkRecords::SaveLayer>(r, *record, i);
- assert_type<SkRecords::Restore>(r, *record, i+2);
- }
- }
- DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
- SkRecord record;
- SkRecorder recorder(&record, W, H);
- SkRect bounds = SkRect::MakeWH(100, 200);
- SkRect draw = SkRect::MakeWH(50, 60);
- SkPaint alphaOnlyLayerPaint, translucentLayerPaint, xfermodeLayerPaint;
- alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha.
- translucentLayerPaint.setColor(0x03040506); // Not only alpha.
- xfermodeLayerPaint.setBlendMode(SkBlendMode::kDstIn); // Any effect will do.
- SkPaint opaqueDrawPaint, translucentDrawPaint;
- opaqueDrawPaint.setColor(0xFF020202); // Opaque.
- translucentDrawPaint.setColor(0x0F020202); // Not opaque.
- // SaveLayer/Restore removed: No paint = no point.
- recorder.saveLayer(nullptr, nullptr);
- recorder.drawRect(draw, opaqueDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 0, true);
- // Bounds don't matter.
- recorder.saveLayer(&bounds, nullptr);
- recorder.drawRect(draw, opaqueDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 3, true);
- // TODO(mtklein): test case with null draw paint
- // No change: layer paint isn't alpha-only.
- recorder.saveLayer(nullptr, &translucentLayerPaint);
- recorder.drawRect(draw, opaqueDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 6, false);
- // No change: layer paint has an effect.
- recorder.saveLayer(nullptr, &xfermodeLayerPaint);
- recorder.drawRect(draw, opaqueDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 9, false);
- // SaveLayer/Restore removed: we can fold in the alpha!
- recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
- recorder.drawRect(draw, translucentDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 12, true);
- // SaveLayer/Restore removed: we can fold in the alpha!
- recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
- recorder.drawRect(draw, opaqueDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 15, true);
- const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
- REPORTER_ASSERT(r, drawRect != nullptr);
- REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
- // saveLayer w/ backdrop should NOT go away
- sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(3, 3, nullptr));
- recorder.saveLayer({ nullptr, nullptr, filter.get(), nullptr, nullptr, 0});
- recorder.drawRect(draw, opaqueDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 18, false);
- // saveLayer w/ clip mask should also NOT go away
- {
- sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(10, 10));
- recorder.saveLayer({ nullptr, nullptr, nullptr, surface->makeImageSnapshot().get(),
- nullptr, 0});
- recorder.drawRect(draw, opaqueDrawPaint);
- recorder.restore();
- assert_savelayer_draw_restore(r, &record, 21, false);
- }
- }
- #endif
- static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
- SkRecord* record,
- int i,
- bool shouldBeNoOped) {
- SkRecordMergeSvgOpacityAndFilterLayers(record);
- if (shouldBeNoOped) {
- assert_type<SkRecords::NoOp>(r, *record, i);
- assert_type<SkRecords::NoOp>(r, *record, i + 6);
- } else {
- assert_type<SkRecords::SaveLayer>(r, *record, i);
- assert_type<SkRecords::Restore>(r, *record, i + 6);
- }
- }
- DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
- SkRecord record;
- SkRecorder recorder(&record, W, H);
- SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200));
- SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60));
- SkPaint alphaOnlyLayerPaint;
- alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha.
- SkPaint translucentLayerPaint;
- translucentLayerPaint.setColor(0x03040506); // Not only alpha.
- SkPaint xfermodePaint;
- xfermodePaint.setBlendMode(SkBlendMode::kDstIn);
- SkPaint colorFilterPaint;
- colorFilterPaint.setColorFilter(
- SkColorFilters::Blend(SK_ColorLTGRAY, SkBlendMode::kSrcIn));
- SkPaint opaqueFilterLayerPaint;
- opaqueFilterLayerPaint.setColor(0xFF020202); // Opaque.
- SkPaint translucentFilterLayerPaint;
- translucentFilterLayerPaint.setColor(0x0F020202); // Not opaque.
- sk_sp<SkPicture> shape;
- {
- SkPictureRecorder recorder;
- SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100));
- SkPaint shapePaint;
- shapePaint.setColor(SK_ColorWHITE);
- canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint);
- shape = recorder.finishRecordingAsPicture();
- }
- translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Make(shape));
- int index = 0;
- {
- sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(3, 3, nullptr));
- // first (null) should be optimized, 2nd should not
- SkImageFilter* filters[] = { nullptr, filter.get() };
- // Any combination of these should cause the pattern to be optimized.
- SkRect* firstBounds[] = { nullptr, &bounds };
- SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint };
- SkRect* secondBounds[] = { nullptr, &bounds };
- SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
- for (auto outerF : filters) {
- bool outerNoOped = !outerF;
- for (auto innerF : filters) {
- for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
- for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
- for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
- for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
- bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF;
- recorder.saveLayer({firstBounds[i], firstPaints[j], outerF,
- nullptr, nullptr, 0});
- recorder.save();
- recorder.clipRect(clip);
- recorder.saveLayer({secondBounds[k], secondPaints[m], innerF,
- nullptr, nullptr, 0});
- recorder.restore();
- recorder.restore();
- recorder.restore();
- assert_merge_svg_opacity_and_filter_layers(r, &record, index,
- outerNoOped);
- #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
- assert_savelayer_restore(r, &record, index + 3, innerNoOped);
- #endif
- index += 7;
- }
- }
- }
- }
- }
- }
- }
- // These should cause the pattern to stay unoptimized:
- struct {
- SkPaint* firstPaint;
- SkPaint* secondPaint;
- } noChangeTests[] = {
- // No change: nullptr filter layer paint not implemented.
- { &alphaOnlyLayerPaint, nullptr },
- // No change: layer paint is not alpha-only.
- { &translucentLayerPaint, &opaqueFilterLayerPaint },
- // No change: layer paint has an xfereffect.
- { &xfermodePaint, &opaqueFilterLayerPaint },
- // No change: filter layer paint has an xfereffect.
- { &alphaOnlyLayerPaint, &xfermodePaint },
- // No change: layer paint has a color filter.
- { &colorFilterPaint, &opaqueFilterLayerPaint },
- // No change: filter layer paint has a color filter (until the optimization accounts for
- // constant color draws that can filter the color).
- { &alphaOnlyLayerPaint, &colorFilterPaint }
- };
- for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) {
- recorder.saveLayer(nullptr, noChangeTests[i].firstPaint);
- recorder.save();
- recorder.clipRect(clip);
- recorder.saveLayer(nullptr, noChangeTests[i].secondPaint);
- recorder.restore();
- recorder.restore();
- recorder.restore();
- assert_merge_svg_opacity_and_filter_layers(r, &record, index, false);
- index += 7;
- }
- // Test the folded alpha value.
- recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
- recorder.save();
- recorder.clipRect(clip);
- recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
- recorder.restore();
- recorder.restore();
- recorder.restore();
- assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
- const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3);
- REPORTER_ASSERT(r, saveLayer != nullptr);
- REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202);
- index += 7;
- // Test that currently we do not fold alphas for patterns without the clip. This is just not
- // implemented.
- recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
- recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
- recorder.restore();
- recorder.restore();
- SkRecordMergeSvgOpacityAndFilterLayers(&record);
- assert_type<SkRecords::SaveLayer>(r, record, index);
- assert_type<SkRecords::SaveLayer>(r, record, index + 1);
- assert_type<SkRecords::Restore>(r, record, index + 2);
- assert_type<SkRecords::Restore>(r, record, index + 3);
- index += 4;
- }
- static void do_draw(SkCanvas* canvas, SkColor color, bool doLayer) {
- canvas->drawColor(SK_ColorWHITE);
- SkPaint p;
- p.setColor(color);
- if (doLayer) {
- canvas->saveLayer(nullptr, nullptr);
- p.setBlendMode(SkBlendMode::kSrc);
- canvas->drawPaint(p);
- canvas->restore();
- } else {
- canvas->drawPaint(p);
- }
- }
- static bool is_equal(SkSurface* a, SkSurface* b) {
- const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
- SkPMColor ca, cb;
- a->readPixels(info, &ca, sizeof(SkPMColor), 0, 0);
- b->readPixels(info, &cb, sizeof(SkPMColor), 0, 0);
- return ca == cb;
- }
- // Test drawing w/ and w/o a simple layer (no bounds or paint), so see that drawing ops
- // that *should* draw the same in fact do.
- //
- // Perform this test twice : once directly, and once via a picture
- //
- static void do_savelayer_srcmode(skiatest::Reporter* r, SkColor color) {
- for (int doPicture = 0; doPicture <= 1; ++doPicture) {
- sk_sp<SkSurface> surf0 = SkSurface::MakeRasterN32Premul(10, 10);
- sk_sp<SkSurface> surf1 = SkSurface::MakeRasterN32Premul(10, 10);
- SkCanvas* c0 = surf0->getCanvas();
- SkCanvas* c1 = surf1->getCanvas();
- SkPictureRecorder rec0, rec1;
- if (doPicture) {
- c0 = rec0.beginRecording(10, 10);
- c1 = rec1.beginRecording(10, 10);
- }
- do_draw(c0, color, false);
- do_draw(c1, color, true);
- if (doPicture) {
- surf0->getCanvas()->drawPicture(rec0.finishRecordingAsPicture());
- surf1->getCanvas()->drawPicture(rec1.finishRecordingAsPicture());
- }
- // we replicate the assert so we can see which line is reported if there is a failure
- if (doPicture) {
- REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
- } else {
- REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
- }
- }
- }
- DEF_TEST(savelayer_srcmode_opaque, r) {
- do_savelayer_srcmode(r, SK_ColorRED);
- }
- DEF_TEST(savelayer_srcmode_alpha, r) {
- do_savelayer_srcmode(r, 0x80FF0000);
- }
|