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