blob: 0693f49da0a3cad7d73aa162467abd9d5f699e8a [file] [log] [blame]
bsalomon@google.com4a719972013-02-22 15:10:36 +00001
2/*
3 * Copyright 2013 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "SkBenchmark.h"
10#include "SkCanvas.h"
11#include "SkPaint.h"
12#include "SkRandom.h"
13
14/**
15 * This is a conversion of samplecode/SampleChart.cpp into a bench. It sure would be nice to be able
16 * to write one subclass that can be a GM, bench, and/or Sample.
17 */
18
19namespace {
20
21// Generates y values for the chart plots.
22void gen_data(SkScalar yAvg, SkScalar ySpread, int count, SkTDArray<SkScalar>* dataPts) {
23 dataPts->setCount(count);
24 static SkMWCRandom gRandom;
25 for (int i = 0; i < count; ++i) {
26 (*dataPts)[i] = gRandom.nextRangeScalar(yAvg - SkScalarHalf(ySpread),
27 yAvg + SkScalarHalf(ySpread));
28 }
29}
30
31// Generates a path to stroke along the top of each plot and a fill path for the area below each
32// plot. The fill path is bounded below by the bottomData plot points or a horizontal line at
33// yBase if bottomData == NULL.
34// The plots are animated by rotating the data points by leftShift.
35void gen_paths(const SkTDArray<SkScalar>& topData,
36 const SkTDArray<SkScalar>* bottomData,
37 SkScalar yBase,
38 SkScalar xLeft, SkScalar xDelta,
39 int leftShift,
40 SkPath* plot, SkPath* fill) {
41 plot->rewind();
42 fill->rewind();
43 plot->incReserve(topData.count());
44 if (NULL == bottomData) {
45 fill->incReserve(topData.count() + 2);
46 } else {
47 fill->incReserve(2 * topData.count());
48 }
49
50 leftShift %= topData.count();
51 SkScalar x = xLeft;
52
53 // Account for the leftShift using two loops
54 int shiftToEndCount = topData.count() - leftShift;
55 plot->moveTo(x, topData[leftShift]);
56 fill->moveTo(x, topData[leftShift]);
57
58 for (int i = 1; i < shiftToEndCount; ++i) {
59 plot->lineTo(x, topData[i + leftShift]);
60 fill->lineTo(x, topData[i + leftShift]);
61 x += xDelta;
62 }
63
64 for (int i = 0; i < leftShift; ++i) {
65 plot->lineTo(x, topData[i]);
66 fill->lineTo(x, topData[i]);
67 x += xDelta;
68 }
69
70 if (NULL != bottomData) {
71 SkASSERT(bottomData->count() == topData.count());
72 // iterate backwards over the previous graph's data to generate the bottom of the filled
73 // area (and account for leftShift).
74 for (int i = 0; i < leftShift; ++i) {
75 x -= xDelta;
76 fill->lineTo(x, (*bottomData)[leftShift - 1 - i]);
77 }
78 for (int i = 0; i < shiftToEndCount; ++i) {
79 x -= xDelta;
80 fill->lineTo(x, (*bottomData)[bottomData->count() - 1 - i]);
81 }
82 } else {
83 fill->lineTo(x - xDelta, yBase);
84 fill->lineTo(xLeft, yBase);
85 }
86}
87
88}
89
90// A set of scrolling line plots with the area between each plot filled. Stresses out GPU path
91// filling
92class ChartBench : public SkBenchmark {
93public:
94 ChartBench(void* param, bool aa) : SkBenchmark(param) {
95 fShift = 0;
96 fAA = aa;
97 }
98
99protected:
100 virtual const char* onGetName() SK_OVERRIDE {
101 if (fAA) {
102 return "chart_aa";
103 } else {
104 return "chart_bw";
105 }
106 }
107
108 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
109 bool sizeChanged = false;
110 if (canvas->getDeviceSize() != fSize) {
111 fSize = canvas->getDeviceSize();
112 sizeChanged = true;
113 }
114
115 SkScalar ySpread = SkIntToScalar(fSize.fHeight / 20);
116
117 SkScalar height = SkIntToScalar(fSize.fHeight);
118
119 for (int frame = 0; frame < kFramesPerRun; ++frame) {
120 if (sizeChanged) {
121 int dataPointCount = SkMax32(fSize.fWidth / kPixelsPerTick + 1, 2);
122
123 for (int i = 0; i < kNumGraphs; ++i) {
124 SkScalar y = (kNumGraphs - i) * (height - ySpread) / (kNumGraphs + 1);
125 fData[i].reset();
126 gen_data(y, ySpread, dataPointCount, fData + i);
127 }
128 sizeChanged = false;
129 }
130
131 canvas->clear(0xFFE0F0E0);
132
133 static SkMWCRandom colorRand;
134 static SkColor gColors[kNumGraphs] = { 0x0 };
135 if (0 == gColors[0]) {
136 for (int i = 0; i < kNumGraphs; ++i) {
137 gColors[i] = colorRand.nextU() | 0xff000000;
138 }
139 }
140
141 SkPath plotPath;
142 SkPath fillPath;
143
144 static const SkScalar kStrokeWidth = SkIntToScalar(2);
145 SkPaint plotPaint;
146 SkPaint fillPaint;
147 plotPaint.setAntiAlias(fAA);
148 plotPaint.setStyle(SkPaint::kStroke_Style);
149 plotPaint.setStrokeWidth(kStrokeWidth);
150 plotPaint.setStrokeCap(SkPaint::kRound_Cap);
151 plotPaint.setStrokeJoin(SkPaint::kRound_Join);
152 fillPaint.setAntiAlias(fAA);
153 fillPaint.setStyle(SkPaint::kFill_Style);
154
155 SkTDArray<SkScalar>* prevData = NULL;
156 for (int i = 0; i < kNumGraphs; ++i) {
157 gen_paths(fData[i],
158 prevData,
159 height,
160 0,
161 SkIntToScalar(kPixelsPerTick),
162 fShift,
163 &plotPath,
164 &fillPath);
165
166 // Make the fills partially transparent
167 fillPaint.setColor((gColors[i] & 0x00ffffff) | 0x80000000);
168 canvas->drawPath(fillPath, fillPaint);
169
170 plotPaint.setColor(gColors[i]);
171 canvas->drawPath(plotPath, plotPaint);
172
173 prevData = fData + i;
174 }
175
176 fShift += kShiftPerFrame;
177 }
178 }
179
180private:
181 enum {
182 kNumGraphs = 5,
183 kPixelsPerTick = 3,
184 kShiftPerFrame = 1,
185
186 kFramesPerRun = SkBENCHLOOP(5),
187 };
188 int fShift;
189 SkISize fSize;
190 SkTDArray<SkScalar> fData[kNumGraphs];
191 bool fAA;
192
193 typedef SkBenchmark INHERITED;
194};
195
196//////////////////////////////////////////////////////////////////////////////
197
198static SkBenchmark* Fact0(void* p) { return new ChartBench(p, true); }
199static SkBenchmark* Fact1(void* p) { return new ChartBench(p, false); }
200
201static BenchRegistry gReg0(Fact0);
202static BenchRegistry gReg1(Fact1);