1c67bb575d0393bef8517810c8f7c578804403c61bsalomon/* 2c67bb575d0393bef8517810c8f7c578804403c61bsalomon* Copyright 2016 Google Inc. 3c67bb575d0393bef8517810c8f7c578804403c61bsalomon* 4c67bb575d0393bef8517810c8f7c578804403c61bsalomon* Use of this source code is governed by a BSD-style license that can be 5c67bb575d0393bef8517810c8f7c578804403c61bsalomon* found in the LICENSE file. 6c67bb575d0393bef8517810c8f7c578804403c61bsalomon*/ 7c67bb575d0393bef8517810c8f7c578804403c61bsalomon 8c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "gm.h" 9c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "SkAnimTimer.h" 10c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "SkBlurMask.h" 11c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "SkBlurMaskFilter.h" 12c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "SkCanvas.h" 13c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "SkPaint.h" 14c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "SkPath.h" 15c67bb575d0393bef8517810c8f7c578804403c61bsalomon#include "SkString.h" 1633d2055e594177b27360f84e0631b26d74a55a9bMike Klein#include "SkRandom.h" 17c67bb575d0393bef8517810c8f7c578804403c61bsalomon 18c67bb575d0393bef8517810c8f7c578804403c61bsalomon/** 19c67bb575d0393bef8517810c8f7c578804403c61bsalomon * In GM mode this draws an array of circles with different radii and different blur radii. Below 20c67bb575d0393bef8517810c8f7c578804403c61bsalomon * each circle an almost-circle path is drawn with the same blur filter for comparison. 21c67bb575d0393bef8517810c8f7c578804403c61bsalomon * 22c67bb575d0393bef8517810c8f7c578804403c61bsalomon * In Sample mode this draws a single circle and almost-circle with animating radius and blur 23c67bb575d0393bef8517810c8f7c578804403c61bsalomon * radius. 242996553ba23212e345ba611772fcc6ee1574cb7ebsalomon * 252996553ba23212e345ba611772fcc6ee1574cb7ebsalomon * Bench mode draws the same as GM mode but without the comparison almost-circle paths. It also 262996553ba23212e345ba611772fcc6ee1574cb7ebsalomon * slightly perturbs the blur and circle radii to stress caching of blurred profiles in GPU mode. 27c67bb575d0393bef8517810c8f7c578804403c61bsalomon */ 28c67bb575d0393bef8517810c8f7c578804403c61bsalomonclass BlurCircles2GM : public skiagm::GM { 29c67bb575d0393bef8517810c8f7c578804403c61bsalomonpublic: 30c67bb575d0393bef8517810c8f7c578804403c61bsalomon BlurCircles2GM() { 31c67bb575d0393bef8517810c8f7c578804403c61bsalomon fAnimRadius = SkAnimTimer::PingPong(0, kRadiusPingPoingPeriod, kRadiusPingPoingShift, 32c67bb575d0393bef8517810c8f7c578804403c61bsalomon kMinRadius, kMaxRadius); 33c67bb575d0393bef8517810c8f7c578804403c61bsalomon fAnimBlurRadius = SkAnimTimer::PingPong(0, kBlurRadiusPingPoingPeriod, 34c67bb575d0393bef8517810c8f7c578804403c61bsalomon kBlurRadiusPingPoingShift, kMinBlurRadius, 35c67bb575d0393bef8517810c8f7c578804403c61bsalomon kMaxBlurRadius); 36c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 37c67bb575d0393bef8517810c8f7c578804403c61bsalomon 38c67bb575d0393bef8517810c8f7c578804403c61bsalomonprotected: 392996553ba23212e345ba611772fcc6ee1574cb7ebsalomon bool runAsBench() const override { return true; } 402996553ba23212e345ba611772fcc6ee1574cb7ebsalomon 41c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkString onShortName() override { return SkString("blurcircles2"); } 42c67bb575d0393bef8517810c8f7c578804403c61bsalomon 43c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkISize onISize() override { 44c67bb575d0393bef8517810c8f7c578804403c61bsalomon return SkISize::Make(730, 1350); 45c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 46c67bb575d0393bef8517810c8f7c578804403c61bsalomon 47c67bb575d0393bef8517810c8f7c578804403c61bsalomon void onDraw(SkCanvas* canvas) override { 48dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr SkScalar kMaxR = kMaxRadius + kMaxBlurRadius; 49c67bb575d0393bef8517810c8f7c578804403c61bsalomon 50c67bb575d0393bef8517810c8f7c578804403c61bsalomon auto almostCircleMaker = [] (SkScalar radius, SkPath* dst) { 51c67bb575d0393bef8517810c8f7c578804403c61bsalomon dst->reset(); 52c67bb575d0393bef8517810c8f7c578804403c61bsalomon dst->addArc(SkRect::MakeXYWH(-radius, -radius, 2 * radius, 2 * radius), 0, 355); 53c67bb575d0393bef8517810c8f7c578804403c61bsalomon dst->setIsVolatile(true); 54c67bb575d0393bef8517810c8f7c578804403c61bsalomon dst->close(); 55c67bb575d0393bef8517810c8f7c578804403c61bsalomon }; 56c67bb575d0393bef8517810c8f7c578804403c61bsalomon 57c67bb575d0393bef8517810c8f7c578804403c61bsalomon auto blurMaker = [] (SkScalar radius) ->sk_sp<SkMaskFilter> { 58c67bb575d0393bef8517810c8f7c578804403c61bsalomon return SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 59c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkBlurMask::ConvertRadiusToSigma(radius), 60c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkBlurMaskFilter::kHighQuality_BlurFlag); 61c67bb575d0393bef8517810c8f7c578804403c61bsalomon }; 62c67bb575d0393bef8517810c8f7c578804403c61bsalomon 63c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkPaint paint; 64c67bb575d0393bef8517810c8f7c578804403c61bsalomon paint.setColor(SK_ColorBLACK); 65c67bb575d0393bef8517810c8f7c578804403c61bsalomon 66c67bb575d0393bef8517810c8f7c578804403c61bsalomon if (this->getMode() == kSample_Mode) { 67c67bb575d0393bef8517810c8f7c578804403c61bsalomon paint.setMaskFilter(blurMaker(fAnimBlurRadius)); 68c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkISize size = canvas->getBaseLayerSize(); 69c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkPath almostCircle; 70c67bb575d0393bef8517810c8f7c578804403c61bsalomon almostCircleMaker(fAnimRadius, &almostCircle); 71c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->save(); 72c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->translate(size.fWidth / 2.f, size.fHeight / 4.f); 73c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->drawCircle(0, 0, fAnimRadius, paint); 74c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->translate(0, 2 * kMaxR); 75c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->drawPath(almostCircle, paint); 76c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->restore(); 77c67bb575d0393bef8517810c8f7c578804403c61bsalomon } else { 782996553ba23212e345ba611772fcc6ee1574cb7ebsalomon bool benchMode = this->getMode() == kBench_Mode; 79c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->save(); 80dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr SkScalar kPad = 5; 81dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr SkScalar kRadiusSteps = 5; 82dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr SkScalar kBlurRadiusSteps = 5; 83c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->translate(kPad + kMinRadius + kMaxBlurRadius, 84c67bb575d0393bef8517810c8f7c578804403c61bsalomon kPad + kMinRadius + kMaxBlurRadius); 85dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr SkScalar kDeltaRadius = (kMaxRadius - kMinRadius) / kRadiusSteps; 86dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr SkScalar kDeltaBlurRadius = (kMaxBlurRadius - kMinBlurRadius) / 872996553ba23212e345ba611772fcc6ee1574cb7ebsalomon kBlurRadiusSteps; 88c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkScalar lineWidth = 0; 892996553ba23212e345ba611772fcc6ee1574cb7ebsalomon if (!benchMode) { 902996553ba23212e345ba611772fcc6ee1574cb7ebsalomon for (int r = 0; r < kRadiusSteps - 1; ++r) { 912996553ba23212e345ba611772fcc6ee1574cb7ebsalomon const SkScalar radius = r * kDeltaRadius + kMinRadius; 922996553ba23212e345ba611772fcc6ee1574cb7ebsalomon lineWidth += 2 * (radius + kMaxBlurRadius) + kPad; 932996553ba23212e345ba611772fcc6ee1574cb7ebsalomon } 94c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 95c67bb575d0393bef8517810c8f7c578804403c61bsalomon for (int br = 0; br < kBlurRadiusSteps; ++br) { 962996553ba23212e345ba611772fcc6ee1574cb7ebsalomon SkScalar blurRadius = br * kDeltaBlurRadius + kMinBlurRadius; 972996553ba23212e345ba611772fcc6ee1574cb7ebsalomon if (benchMode) { 982996553ba23212e345ba611772fcc6ee1574cb7ebsalomon blurRadius += fRandom.nextSScalar1() * kDeltaBlurRadius; 992996553ba23212e345ba611772fcc6ee1574cb7ebsalomon } 100c67bb575d0393bef8517810c8f7c578804403c61bsalomon const SkScalar maxRowR = blurRadius + kMaxRadius; 101c67bb575d0393bef8517810c8f7c578804403c61bsalomon paint.setMaskFilter(blurMaker(blurRadius)); 102c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->save(); 103c67bb575d0393bef8517810c8f7c578804403c61bsalomon for (int r = 0; r < kRadiusSteps; ++r) { 1042996553ba23212e345ba611772fcc6ee1574cb7ebsalomon SkScalar radius = r * kDeltaRadius + kMinRadius; 1052996553ba23212e345ba611772fcc6ee1574cb7ebsalomon if (benchMode) { 1062996553ba23212e345ba611772fcc6ee1574cb7ebsalomon radius += fRandom.nextSScalar1() * kDeltaRadius; 1072996553ba23212e345ba611772fcc6ee1574cb7ebsalomon } 108c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkPath almostCircle; 1092996553ba23212e345ba611772fcc6ee1574cb7ebsalomon if (!benchMode) { 1102996553ba23212e345ba611772fcc6ee1574cb7ebsalomon almostCircleMaker(radius, &almostCircle); 1112996553ba23212e345ba611772fcc6ee1574cb7ebsalomon } 112c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->save(); 113c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->drawCircle(0, 0, radius, paint); 114c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->translate(0, 2 * maxRowR + kPad); 1152996553ba23212e345ba611772fcc6ee1574cb7ebsalomon if (!benchMode) { 116c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->drawPath(almostCircle, paint); 1172996553ba23212e345ba611772fcc6ee1574cb7ebsalomon } 118c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->restore(); 119c67bb575d0393bef8517810c8f7c578804403c61bsalomon const SkScalar maxColR = radius + kMaxBlurRadius; 120c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->translate(maxColR * 2 + kPad, 0); 121c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 122c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->restore(); 1232996553ba23212e345ba611772fcc6ee1574cb7ebsalomon if (!benchMode) { 1242996553ba23212e345ba611772fcc6ee1574cb7ebsalomon SkPaint blackPaint; 1252996553ba23212e345ba611772fcc6ee1574cb7ebsalomon blackPaint.setColor(SK_ColorBLACK); 1262996553ba23212e345ba611772fcc6ee1574cb7ebsalomon const SkScalar lineY = 3 * maxRowR + 1.5f * kPad; 1272996553ba23212e345ba611772fcc6ee1574cb7ebsalomon if (br != kBlurRadiusSteps - 1) { 1282996553ba23212e345ba611772fcc6ee1574cb7ebsalomon canvas->drawLine(0, lineY, lineWidth, lineY, blackPaint); 1292996553ba23212e345ba611772fcc6ee1574cb7ebsalomon } 130c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 131c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->translate(0, maxRowR * 4 + 2 * kPad); 132c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 133c67bb575d0393bef8517810c8f7c578804403c61bsalomon canvas->restore(); 134c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 135c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 136c67bb575d0393bef8517810c8f7c578804403c61bsalomon 137c67bb575d0393bef8517810c8f7c578804403c61bsalomon bool onAnimate(const SkAnimTimer& timer) override { 138c67bb575d0393bef8517810c8f7c578804403c61bsalomon fAnimRadius = timer.pingPong(kRadiusPingPoingPeriod, kRadiusPingPoingShift, kMinRadius, 139c67bb575d0393bef8517810c8f7c578804403c61bsalomon kMaxRadius); 140c67bb575d0393bef8517810c8f7c578804403c61bsalomon fAnimBlurRadius = timer.pingPong(kBlurRadiusPingPoingPeriod, kBlurRadiusPingPoingShift, 141c67bb575d0393bef8517810c8f7c578804403c61bsalomon kMinBlurRadius, kMaxBlurRadius); 142c67bb575d0393bef8517810c8f7c578804403c61bsalomon return true; 143c67bb575d0393bef8517810c8f7c578804403c61bsalomon } 144c67bb575d0393bef8517810c8f7c578804403c61bsalomon 145c67bb575d0393bef8517810c8f7c578804403c61bsalomonprivate: 146c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kMinRadius = 15; 147c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kMaxRadius = 45; 148c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kRadiusPingPoingPeriod = 8; 149c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kRadiusPingPoingShift = 3; 150c67bb575d0393bef8517810c8f7c578804403c61bsalomon 151c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kMinBlurRadius = 5; 152c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kMaxBlurRadius = 45; 153c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kBlurRadiusPingPoingPeriod = 3; 154c67bb575d0393bef8517810c8f7c578804403c61bsalomon static constexpr SkScalar kBlurRadiusPingPoingShift = 1.5; 155c67bb575d0393bef8517810c8f7c578804403c61bsalomon 156c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkScalar fAnimRadius; 157c67bb575d0393bef8517810c8f7c578804403c61bsalomon SkScalar fAnimBlurRadius; 158c67bb575d0393bef8517810c8f7c578804403c61bsalomon 1592996553ba23212e345ba611772fcc6ee1574cb7ebsalomon SkRandom fRandom; 1602996553ba23212e345ba611772fcc6ee1574cb7ebsalomon 161c67bb575d0393bef8517810c8f7c578804403c61bsalomon typedef skiagm::GM INHERITED; 162c67bb575d0393bef8517810c8f7c578804403c61bsalomon}; 163c67bb575d0393bef8517810c8f7c578804403c61bsalomon 164c67bb575d0393bef8517810c8f7c578804403c61bsalomonDEF_GM(return new BlurCircles2GM();) 165