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