blob: 0a692cfc80ed549da8e72a5953ddffd38abbb221 [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;
bsalomon@google.comcd7421b2013-02-22 16:07:59 +000097 fSize.fWidth = -1;
98 fSize.fHeight = -1;
bsalomon@google.com4a719972013-02-22 15:10:36 +000099 }
100
101protected:
102 virtual const char* onGetName() SK_OVERRIDE {
103 if (fAA) {
104 return "chart_aa";
105 } else {
106 return "chart_bw";
107 }
108 }
109
110 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
111 bool sizeChanged = false;
112 if (canvas->getDeviceSize() != fSize) {
113 fSize = canvas->getDeviceSize();
114 sizeChanged = true;
115 }
116
117 SkScalar ySpread = SkIntToScalar(fSize.fHeight / 20);
118
119 SkScalar height = SkIntToScalar(fSize.fHeight);
bsalomon@google.comcd7421b2013-02-22 16:07:59 +0000120 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 }
bsalomon@google.com4a719972013-02-22 15:10:36 +0000129
130 for (int frame = 0; frame < kFramesPerRun; ++frame) {
bsalomon@google.com4a719972013-02-22 15:10:36 +0000131
132 canvas->clear(0xFFE0F0E0);
133
134 static SkMWCRandom colorRand;
135 static SkColor gColors[kNumGraphs] = { 0x0 };
136 if (0 == gColors[0]) {
137 for (int i = 0; i < kNumGraphs; ++i) {
138 gColors[i] = colorRand.nextU() | 0xff000000;
139 }
140 }
141
142 SkPath plotPath;
143 SkPath fillPath;
144
145 static const SkScalar kStrokeWidth = SkIntToScalar(2);
146 SkPaint plotPaint;
147 SkPaint fillPaint;
148 plotPaint.setAntiAlias(fAA);
149 plotPaint.setStyle(SkPaint::kStroke_Style);
150 plotPaint.setStrokeWidth(kStrokeWidth);
151 plotPaint.setStrokeCap(SkPaint::kRound_Cap);
152 plotPaint.setStrokeJoin(SkPaint::kRound_Join);
153 fillPaint.setAntiAlias(fAA);
154 fillPaint.setStyle(SkPaint::kFill_Style);
155
156 SkTDArray<SkScalar>* prevData = NULL;
157 for (int i = 0; i < kNumGraphs; ++i) {
158 gen_paths(fData[i],
159 prevData,
160 height,
161 0,
162 SkIntToScalar(kPixelsPerTick),
163 fShift,
164 &plotPath,
165 &fillPath);
166
167 // Make the fills partially transparent
168 fillPaint.setColor((gColors[i] & 0x00ffffff) | 0x80000000);
169 canvas->drawPath(fillPath, fillPaint);
170
171 plotPaint.setColor(gColors[i]);
172 canvas->drawPath(plotPath, plotPaint);
173
174 prevData = fData + i;
175 }
176
177 fShift += kShiftPerFrame;
178 }
179 }
180
181private:
182 enum {
183 kNumGraphs = 5,
184 kPixelsPerTick = 3,
185 kShiftPerFrame = 1,
186
187 kFramesPerRun = SkBENCHLOOP(5),
188 };
189 int fShift;
190 SkISize fSize;
191 SkTDArray<SkScalar> fData[kNumGraphs];
192 bool fAA;
193
194 typedef SkBenchmark INHERITED;
195};
196
197//////////////////////////////////////////////////////////////////////////////
198
199static SkBenchmark* Fact0(void* p) { return new ChartBench(p, true); }
200static SkBenchmark* Fact1(void* p) { return new ChartBench(p, false); }
201
202static BenchRegistry gReg0(Fact0);
203static BenchRegistry gReg1(Fact1);