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