1 /* 2 * Copyright 2016 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 "gm.h" 9 #include "SkAnimTimer.h" 10 #include "SkBlurMask.h" 11 #include "SkBlurMaskFilter.h" 12 #include "SkCanvas.h" 13 #include "SkPaint.h" 14 #include "SkPath.h" 15 #include "SkString.h" 16 #include "SkRandom.h" 17 18 /** 19 * In GM mode this draws an array of circles with different radii and different blur radii. Below 20 * each circle an almost-circle path is drawn with the same blur filter for comparison. 21 * 22 * In Sample mode this draws a single circle and almost-circle with animating radius and blur 23 * radius. 24 * 25 * Bench mode draws the same as GM mode but without the comparison almost-circle paths. It also 26 * slightly perturbs the blur and circle radii to stress caching of blurred profiles in GPU mode. 27 */ 28 class BlurCircles2GM : public skiagm::GM { 29 public: BlurCircles2GM()30 BlurCircles2GM() { 31 fAnimRadius = SkAnimTimer::PingPong(0, kRadiusPingPoingPeriod, kRadiusPingPoingShift, 32 kMinRadius, kMaxRadius); 33 fAnimBlurRadius = SkAnimTimer::PingPong(0, kBlurRadiusPingPoingPeriod, 34 kBlurRadiusPingPoingShift, kMinBlurRadius, 35 kMaxBlurRadius); 36 } 37 38 protected: runAsBench() const39 bool runAsBench() const override { return true; } 40 onShortName()41 SkString onShortName() override { return SkString("blurcircles2"); } 42 onISize()43 SkISize onISize() override { 44 return SkISize::Make(730, 1350); 45 } 46 onDraw(SkCanvas * canvas)47 void onDraw(SkCanvas* canvas) override { 48 constexpr SkScalar kMaxR = kMaxRadius + kMaxBlurRadius; 49 50 auto almostCircleMaker = [] (SkScalar radius, SkPath* dst) { 51 dst->reset(); 52 dst->addArc(SkRect::MakeXYWH(-radius, -radius, 2 * radius, 2 * radius), 0, 355); 53 dst->setIsVolatile(true); 54 dst->close(); 55 }; 56 57 auto blurMaker = [] (SkScalar radius) ->sk_sp<SkMaskFilter> { 58 return SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 59 SkBlurMask::ConvertRadiusToSigma(radius)); 60 }; 61 62 SkPaint paint; 63 paint.setColor(SK_ColorBLACK); 64 65 if (this->getMode() == kSample_Mode) { 66 paint.setMaskFilter(blurMaker(fAnimBlurRadius)); 67 SkISize size = canvas->getBaseLayerSize(); 68 SkPath almostCircle; 69 almostCircleMaker(fAnimRadius, &almostCircle); 70 canvas->save(); 71 canvas->translate(size.fWidth / 2.f, size.fHeight / 4.f); 72 canvas->drawCircle(0, 0, fAnimRadius, paint); 73 canvas->translate(0, 2 * kMaxR); 74 canvas->drawPath(almostCircle, paint); 75 canvas->restore(); 76 } else { 77 bool benchMode = this->getMode() == kBench_Mode; 78 canvas->save(); 79 constexpr SkScalar kPad = 5; 80 constexpr SkScalar kRadiusSteps = 5; 81 constexpr SkScalar kBlurRadiusSteps = 5; 82 canvas->translate(kPad + kMinRadius + kMaxBlurRadius, 83 kPad + kMinRadius + kMaxBlurRadius); 84 constexpr SkScalar kDeltaRadius = (kMaxRadius - kMinRadius) / kRadiusSteps; 85 constexpr SkScalar kDeltaBlurRadius = (kMaxBlurRadius - kMinBlurRadius) / 86 kBlurRadiusSteps; 87 SkScalar lineWidth = 0; 88 if (!benchMode) { 89 for (int r = 0; r < kRadiusSteps - 1; ++r) { 90 const SkScalar radius = r * kDeltaRadius + kMinRadius; 91 lineWidth += 2 * (radius + kMaxBlurRadius) + kPad; 92 } 93 } 94 for (int br = 0; br < kBlurRadiusSteps; ++br) { 95 SkScalar blurRadius = br * kDeltaBlurRadius + kMinBlurRadius; 96 if (benchMode) { 97 blurRadius += fRandom.nextSScalar1() * kDeltaBlurRadius; 98 } 99 const SkScalar maxRowR = blurRadius + kMaxRadius; 100 paint.setMaskFilter(blurMaker(blurRadius)); 101 canvas->save(); 102 for (int r = 0; r < kRadiusSteps; ++r) { 103 SkScalar radius = r * kDeltaRadius + kMinRadius; 104 if (benchMode) { 105 radius += fRandom.nextSScalar1() * kDeltaRadius; 106 } 107 SkPath almostCircle; 108 if (!benchMode) { 109 almostCircleMaker(radius, &almostCircle); 110 } 111 canvas->save(); 112 canvas->drawCircle(0, 0, radius, paint); 113 canvas->translate(0, 2 * maxRowR + kPad); 114 if (!benchMode) { 115 canvas->drawPath(almostCircle, paint); 116 } 117 canvas->restore(); 118 const SkScalar maxColR = radius + kMaxBlurRadius; 119 canvas->translate(maxColR * 2 + kPad, 0); 120 } 121 canvas->restore(); 122 if (!benchMode) { 123 SkPaint blackPaint; 124 blackPaint.setColor(SK_ColorBLACK); 125 const SkScalar lineY = 3 * maxRowR + 1.5f * kPad; 126 if (br != kBlurRadiusSteps - 1) { 127 canvas->drawLine(0, lineY, lineWidth, lineY, blackPaint); 128 } 129 } 130 canvas->translate(0, maxRowR * 4 + 2 * kPad); 131 } 132 canvas->restore(); 133 } 134 } 135 onAnimate(const SkAnimTimer & timer)136 bool onAnimate(const SkAnimTimer& timer) override { 137 fAnimRadius = timer.pingPong(kRadiusPingPoingPeriod, kRadiusPingPoingShift, kMinRadius, 138 kMaxRadius); 139 fAnimBlurRadius = timer.pingPong(kBlurRadiusPingPoingPeriod, kBlurRadiusPingPoingShift, 140 kMinBlurRadius, kMaxBlurRadius); 141 return true; 142 } 143 144 private: 145 static constexpr SkScalar kMinRadius = 15; 146 static constexpr SkScalar kMaxRadius = 45; 147 static constexpr SkScalar kRadiusPingPoingPeriod = 8; 148 static constexpr SkScalar kRadiusPingPoingShift = 3; 149 150 static constexpr SkScalar kMinBlurRadius = 5; 151 static constexpr SkScalar kMaxBlurRadius = 45; 152 static constexpr SkScalar kBlurRadiusPingPoingPeriod = 3; 153 static constexpr SkScalar kBlurRadiusPingPoingShift = 1.5; 154 155 SkScalar fAnimRadius; 156 SkScalar fAnimBlurRadius; 157 158 SkRandom fRandom; 159 160 typedef skiagm::GM INHERITED; 161 }; 162 163 DEF_GM(return new BlurCircles2GM();) 164