blob: 87643137365db92a84c40bf46e10e584083c3aa9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 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 */
bsalomon@google.com971d0c82011-08-19 17:22:05 +00008
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00009#if SK_SUPPORT_GPU
bsalomon@google.com971d0c82011-08-19 17:22:05 +000010#include "GrContext.h"
bsalomon@google.comcb265352013-02-22 16:13:16 +000011#include "GrContextFactory.h"
bsalomon@google.com971d0c82011-08-19 17:22:05 +000012#include "GrRenderTarget.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000013#include "SkGpuDevice.h"
mtklein@google.comc2897432013-09-10 19:23:38 +000014#include "gl/GrGLDefines.h"
bsalomon@google.com41809932013-02-22 16:25:28 +000015#else
16class GrContext;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000017#endif // SK_SUPPORT_GPU
bsalomon@google.com971d0c82011-08-19 17:22:05 +000018
mtklein@google.comc2897432013-09-10 19:23:38 +000019#include "BenchTimer.h"
scroggo@google.com9a412522012-09-07 15:21:18 +000020#include "SkBenchLogger.h"
bsalomon@google.com971d0c82011-08-19 17:22:05 +000021#include "SkBenchmark.h"
robertphillips@google.com73672252013-08-29 12:40:26 +000022#include "SkBitmapDevice.h"
reed@android.combd700c32009-01-05 03:34:50 +000023#include "SkCanvas.h"
mtklein@google.com78d03792013-09-10 19:42:07 +000024#include "SkColorPriv.h"
sglez@google.com586db932013-07-24 17:24:23 +000025#include "SkCommandLineFlags.h"
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +000026#include "SkDeferredCanvas.h"
reed@android.com3a859a02009-01-28 00:56:29 +000027#include "SkGraphics.h"
reed@android.comb398fe82009-01-07 11:47:57 +000028#include "SkImageEncoder.h"
mtklein@google.comc2897432013-09-10 19:23:38 +000029#include "SkOSFile.h"
reed@android.com6c924ad2009-03-31 03:48:49 +000030#include "SkPicture.h"
reed@android.combd700c32009-01-05 03:34:50 +000031#include "SkString.h"
reed@android.com29348cb2009-08-04 18:17:15 +000032
mtklein@google.com9ef1d212013-09-13 20:39:50 +000033#include <limits>
34
mtklein@google.comc2897432013-09-10 19:23:38 +000035enum BenchMode {
36 kNormal_BenchMode,
37 kDeferred_BenchMode,
38 kDeferredSilent_BenchMode,
39 kRecord_BenchMode,
40 kPictureRecord_BenchMode
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000041};
mtklein@google.comdbd41c82013-09-13 20:11:09 +000042const char* BenchMode_Name[] = {
43 "normal", "deferred", "deferredSilent", "record", "picturerecord"
44};
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000045
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000046///////////////////////////////////////////////////////////////////////////////
47
reed@android.com6c924ad2009-03-31 03:48:49 +000048static void erase(SkBitmap& bm) {
49 if (bm.config() == SkBitmap::kA8_Config) {
junov@google.comdbfac8a2012-12-06 21:47:40 +000050 bm.eraseColor(SK_ColorTRANSPARENT);
reed@android.com6c924ad2009-03-31 03:48:49 +000051 } else {
52 bm.eraseColor(SK_ColorWHITE);
53 }
54}
55
reed@android.combd700c32009-01-05 03:34:50 +000056class Iter {
57public:
mtklein@google.comc2897432013-09-10 19:23:38 +000058 Iter() : fBench(BenchRegistry::Head()) {}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000059
reed@android.combd700c32009-01-05 03:34:50 +000060 SkBenchmark* next() {
61 if (fBench) {
62 BenchRegistry::Factory f = fBench->factory();
63 fBench = fBench->next();
mtklein@google.com410e6e82013-09-13 19:52:27 +000064 return f();
reed@android.combd700c32009-01-05 03:34:50 +000065 }
66 return NULL;
67 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +000068
reed@android.combd700c32009-01-05 03:34:50 +000069private:
70 const BenchRegistry* fBench;
71};
72
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +000073class AutoPrePostDraw {
74public:
75 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) {
76 fBench->preDraw();
77 }
78 ~AutoPrePostDraw() {
79 fBench->postDraw();
80 }
81private:
82 SkBenchmark* fBench;
83};
84
reed@android.combd700c32009-01-05 03:34:50 +000085static void make_filename(const char name[], SkString* path) {
86 path->set(name);
87 for (int i = 0; name[i]; i++) {
88 switch (name[i]) {
89 case '/':
90 case '\\':
91 case ' ':
92 case ':':
93 path->writable_str()[i] = '-';
94 break;
95 default:
96 break;
97 }
98 }
99}
100
reed@android.com4c7d3d62009-01-21 03:15:13 +0000101static void saveFile(const char name[], const char config[], const char dir[],
102 const SkBitmap& bm) {
reed@android.com4c7d3d62009-01-21 03:15:13 +0000103 SkBitmap copy;
104 if (!bm.copyTo(&copy, SkBitmap::kARGB_8888_Config)) {
105 return;
106 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000107
reed@android.comf523e252009-01-26 23:15:37 +0000108 if (bm.config() == SkBitmap::kA8_Config) {
109 // turn alpha into gray-scale
110 size_t size = copy.getSize() >> 2;
111 SkPMColor* p = copy.getAddr32(0, 0);
112 for (size_t i = 0; i < size; i++) {
113 int c = (*p >> SK_A32_SHIFT) & 0xFF;
114 c = 255 - c;
115 c |= (c << 24) | (c << 16) | (c << 8);
116 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT);
117 }
118 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000119
mtklein@google.comc2897432013-09-10 19:23:38 +0000120 SkString filename;
121 make_filename(name, &filename);
122 filename.appendf("_%s.png", config);
123 SkString path = SkOSPath::SkPathJoin(dir, filename.c_str());
124 ::remove(path.c_str());
125 SkImageEncoder::EncodeFile(path.c_str(), copy, SkImageEncoder::kPNG_Type, 100);
reed@android.com4c7d3d62009-01-21 03:15:13 +0000126}
127
128static void performClip(SkCanvas* canvas, int w, int h) {
129 SkRect r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000130
reed@android.com4c7d3d62009-01-21 03:15:13 +0000131 r.set(SkIntToScalar(10), SkIntToScalar(10),
132 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3));
133 canvas->clipRect(r, SkRegion::kIntersect_Op);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000134
reed@android.com4c7d3d62009-01-21 03:15:13 +0000135 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3),
136 SkIntToScalar(w-10), SkIntToScalar(h-10));
137 canvas->clipRect(r, SkRegion::kXOR_Op);
138}
139
140static void performRotate(SkCanvas* canvas, int w, int h) {
141 const SkScalar x = SkIntToScalar(w) / 2;
142 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000143
reed@android.com4c7d3d62009-01-21 03:15:13 +0000144 canvas->translate(x, y);
145 canvas->rotate(SkIntToScalar(35));
146 canvas->translate(-x, -y);
147}
148
reed@android.com387359e2009-08-04 01:51:09 +0000149static void performScale(SkCanvas* canvas, int w, int h) {
150 const SkScalar x = SkIntToScalar(w) / 2;
151 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000152
reed@android.com387359e2009-08-04 01:51:09 +0000153 canvas->translate(x, y);
154 // just enough so we can't take the sprite case
155 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
156 canvas->translate(-x, -y);
157}
158
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000159enum Backend {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000160 kNonRendering_Backend,
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000161 kRaster_Backend,
162 kGPU_Backend,
163 kPDF_Backend,
164};
165
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000166static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size,
167 Backend backend, int sampleCount, GrContext* context) {
168 SkBaseDevice* device = NULL;
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000169 SkBitmap bitmap;
170 bitmap.setConfig(config, size.fX, size.fY);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000171
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000172 switch (backend) {
173 case kRaster_Backend:
174 bitmap.allocPixels();
175 erase(bitmap);
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000176 device = SkNEW_ARGS(SkBitmapDevice, (bitmap));
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000177 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000178#if SK_SUPPORT_GPU
bsalomon@google.comcb265352013-02-22 16:13:16 +0000179 case kGPU_Backend: {
180 GrTextureDesc desc;
181 desc.fConfig = kSkia8888_GrPixelConfig;
182 desc.fFlags = kRenderTarget_GrTextureFlagBit;
183 desc.fWidth = size.fX;
184 desc.fHeight = size.fY;
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000185 desc.fSampleCnt = sampleCount;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000186 SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
187 if (!texture) {
188 return NULL;
189 }
190 device = SkNEW_ARGS(SkGpuDevice, (context, texture.get()));
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000191 break;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000192 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000193#endif
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000194 case kPDF_Backend:
195 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000196 SkDEBUGFAIL("unsupported");
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000197 }
198 return device;
199}
200
bsalomon@google.comcb265352013-02-22 16:13:16 +0000201#if SK_SUPPORT_GPU
202GrContextFactory gContextFactory;
203typedef GrContextFactory::GLContextType GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000204static const GLContextType kNative = GrContextFactory::kNative_GLContextType;
205#if SK_ANGLE
206static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType;
207#else
208static const GLContextType kANGLE = kNative;
209#endif
210static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType;
211static const GLContextType kNull = GrContextFactory::kNull_GLContextType;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000212#else
213typedef int GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000214static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000215#endif
216
mtklein@google.comc2897432013-09-10 19:23:38 +0000217#ifdef SK_DEBUG
218static const bool kIsDebug = true;
219#else
220static const bool kIsDebug = false;
221#endif
222
223static const struct Config {
224 SkBitmap::Config config;
225 const char* name;
226 int sampleCount;
227 Backend backend;
228 GLContextType contextType;
229 bool runByDefault;
reed@android.com4bc19832009-01-19 20:08:35 +0000230} gConfigs[] = {
mtklein@google.comc2897432013-09-10 19:23:38 +0000231 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kNative, true},
232 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kNative, true},
233 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kNative, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000234#if SK_SUPPORT_GPU
mtklein@google.comc2897432013-09-10 19:23:38 +0000235 { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, kNative, true},
236 { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, kNative, false},
237 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, kNative, false},
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000238#if SK_ANGLE
mtklein@google.comc2897432013-09-10 19:23:38 +0000239 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, kANGLE, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000240#endif // SK_ANGLE
mtklein@google.comc2897432013-09-10 19:23:38 +0000241 { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, kDebug, kIsDebug},
242 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, kNull, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000243#endif // SK_SUPPORT_GPU
reed@android.com4bc19832009-01-19 20:08:35 +0000244};
245
mtklein@google.comc2897432013-09-10 19:23:38 +0000246DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir.");
247DEFINE_string(timers, "cg", "Timers to display. "
248 "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)");
reed@android.com4c7d3d62009-01-21 03:15:13 +0000249
mtklein@google.comc2897432013-09-10 19:23:38 +0000250DEFINE_bool(rotate, false, "Rotate canvas before bench run?");
251DEFINE_bool(scale, false, "Scale canvas before bench run?");
252DEFINE_bool(clip, false, "Clip canvas before bench run?");
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000253
mtklein@google.comc2897432013-09-10 19:23:38 +0000254DEFINE_bool(forceAA, true, "Force anti-aliasing?");
255DEFINE_bool(forceFilter, false, "Force bitmap filtering?");
256DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?");
257DEFINE_bool(forceBlend, false, "Force alpha blending?");
258
259DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable cache.");
260DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to disable cache.");
261
262DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n"
263 "Multiple matches may be separated by spaces.\n"
264 "~ causes a matching test to always be skipped\n"
265 "^ requires the start of the test to match\n"
266 "$ requires the end of the test to match\n"
267 "^ and $ requires an exact match\n"
268 "If a test does not match any list entry,\n"
269 "it is skipped unless some list entry starts with ~\n");
270DEFINE_string(mode, "normal",
271 "normal: draw to a normal canvas;\n"
272 "deferred: draw to a deferred canvas;\n"
273 "deferredSilent: deferred with silent playback;\n"
274 "record: draw to an SkPicture;\n"
275 "picturerecord: draw from an SkPicture to an SkPicture.\n");
276DEFINE_string(config, "", "Run configs given. If empty, runs the defaults set in gConfigs.");
277DEFINE_string(logFile, "", "Also write stdout here.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000278DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run.");
279DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run.");
280DEFINE_double(error, 0.01,
281 "Ratio of subsequent bench measurements must drop within 1±error to converge.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000282DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000283DEFINE_bool2(verbose, v, false, "Print more.");
284
285// Has this bench converged? First arguments are milliseconds / loop iteration,
286// last is overall runtime in milliseconds.
287static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw) {
288 if (currRaw < FLAGS_minMs) {
289 return false;
290 }
291 const double low = 1 - FLAGS_error, high = 1 + FLAGS_error;
292 const double ratio = currPerLoop / prevPerLoop;
293 return low < ratio && ratio < high;
294}
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000295
caryclark@google.com5987f582012-10-02 18:33:14 +0000296int tool_main(int argc, char** argv);
297int tool_main(int argc, char** argv) {
bsalomon@google.com4e230682013-01-15 20:37:04 +0000298#if SK_ENABLE_INST_COUNT
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000299 gPrintInstCount = true;
300#endif
reed@android.com3a859a02009-01-28 00:56:29 +0000301 SkAutoGraphics ag;
mtklein@google.comc2897432013-09-10 19:23:38 +0000302 SkCommandLineFlags::Parse(argc, argv);
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000303
mtklein@google.comc2897432013-09-10 19:23:38 +0000304 // First, parse some flags.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000305
scroggo@google.com9a412522012-09-07 15:21:18 +0000306 SkBenchLogger logger;
mtklein@google.comc2897432013-09-10 19:23:38 +0000307 if (FLAGS_logFile.count()) {
308 logger.SetLogFile(FLAGS_logFile[0]);
309 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000310
mtklein@google.comc2897432013-09-10 19:23:38 +0000311 const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF;
312 SkTriState::State dither = SkTriState::kDefault;
313 for (size_t i = 0; i < 3; i++) {
314 if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) {
315 dither = static_cast<SkTriState::State>(i);
reed@android.comb398fe82009-01-07 11:47:57 +0000316 }
317 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000318
319 BenchMode benchMode = kNormal_BenchMode;
320 for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) {
321 if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) {
322 benchMode = static_cast<BenchMode>(i);
323 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000324 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000325
326 SkTDArray<int> configs;
327 // Try user-given configs first.
328 for (int i = 0; i < FLAGS_config.count(); i++) {
329 for (size_t j = 0; j < SK_ARRAY_COUNT(gConfigs); j++) {
330 if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) {
331 *configs.append() = j;
332 }
333 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000334 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000335 // If there weren't any, fill in with defaults.
336 if (configs.count() == 0) {
337 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) {
338 if (gConfigs[i].runByDefault) {
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000339 *configs.append() = i;
340 }
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000341 }
342 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000343 // Filter out things we can't run.
344 if (kNormal_BenchMode != benchMode) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000345 // Non-rendering configs only run in normal mode
346 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000347 const Config& config = gConfigs[configs[i]];
348 if (kNonRendering_Backend == config.backend) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000349 configs.remove(i, 1);
350 --i;
351 }
352 }
353 }
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000354#if SK_SUPPORT_GPU
355 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000356 const Config& config = gConfigs[configs[i]];
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000357
mtklein@google.comc2897432013-09-10 19:23:38 +0000358 if (kGPU_Backend == config.backend) {
359 GrContext* context = gContextFactory.get(config.contextType);
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000360 if (NULL == context) {
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000361 logger.logError(SkStringPrintf(
362 "Error creating GrContext for config %s. Config will be skipped.\n",
363 config.name));
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000364 configs.remove(i);
365 --i;
366 continue;
367 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000368 if (config.sampleCount > context->getMaxSampleCount()){
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000369 logger.logError(SkStringPrintf(
370 "Sample count (%d) for config %s is unsupported. Config will be skipped.\n",
371 config.sampleCount, config.name));
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000372 configs.remove(i);
373 --i;
374 continue;
375 }
376 }
377 }
378#endif
379
mtklein@google.comc2897432013-09-10 19:23:38 +0000380 // All flags should be parsed now. Report our settings.
381 if (kIsDebug) {
382 logger.logError("bench was built in Debug mode, so we're going to hide the times."
383 " It's for your own good!\n");
384 }
385 SkString str("skia bench:");
386 str.appendf(" mode=%s", FLAGS_mode[0]);
387 str.appendf(" alpha=0x%02X antialias=%d filter=%d dither=%s",
388 alpha, FLAGS_forceAA, FLAGS_forceFilter, SkTriState::Name[dither]);
389 str.appendf(" rotate=%d scale=%d clip=%d", FLAGS_rotate, FLAGS_scale, FLAGS_clip);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000390
mtklein@google.comc2897432013-09-10 19:23:38 +0000391#if defined(SK_SCALAR_IS_FIXED)
392 str.append(" scalar=fixed");
393#else
394 str.append(" scalar=float");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000395#endif
396
397#if defined(SK_BUILD_FOR_WIN32)
mtklein@google.comc2897432013-09-10 19:23:38 +0000398 str.append(" system=WIN32");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000399#elif defined(SK_BUILD_FOR_MAC)
mtklein@google.comc2897432013-09-10 19:23:38 +0000400 str.append(" system=MAC");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000401#elif defined(SK_BUILD_FOR_ANDROID)
mtklein@google.comc2897432013-09-10 19:23:38 +0000402 str.append(" system=ANDROID");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000403#elif defined(SK_BUILD_FOR_UNIX)
mtklein@google.comc2897432013-09-10 19:23:38 +0000404 str.append(" system=UNIX");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000405#else
mtklein@google.comc2897432013-09-10 19:23:38 +0000406 str.append(" system=other");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000407#endif
408
409#if defined(SK_DEBUG)
mtklein@google.comc2897432013-09-10 19:23:38 +0000410 str.append(" DEBUG");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000411#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000412 str.append("\n");
413 logger.logProgress(str);
bsalomon@google.com508824b2011-12-13 16:49:49 +0000414
mtklein@google.comc2897432013-09-10 19:23:38 +0000415
416 // Set texture cache limits if non-default.
bsalomon@google.com5c90e292013-02-22 19:17:13 +0000417 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) {
bsalomon@google.comcb265352013-02-22 16:13:16 +0000418#if SK_SUPPORT_GPU
mtklein@google.comc2897432013-09-10 19:23:38 +0000419 const Config& config = gConfigs[i];
420 if (kGPU_Backend != config.backend) {
421 continue;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000422 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000423 GrContext* context = gContextFactory.get(config.contextType);
424 if (NULL == context) {
425 continue;
426 }
427
428 size_t bytes;
429 int count;
430 context->getTextureCacheLimits(&count, &bytes);
431 if (-1 != FLAGS_gpuCacheBytes) {
432 bytes = static_cast<size_t>(FLAGS_gpuCacheBytes);
433 }
434 if (-1 != FLAGS_gpuCacheCount) {
435 count = FLAGS_gpuCacheCount;
436 }
437 context->setTextureCacheLimits(count, bytes);
bsalomon@google.comcb265352013-02-22 16:13:16 +0000438#endif
439 }
bsalomon@google.com74913722011-10-27 20:44:19 +0000440
mtklein@google.comc2897432013-09-10 19:23:38 +0000441 // Find the longest name of the benches we're going to run to make the output pretty.
442 Iter names;
reed@android.combd700c32009-01-05 03:34:50 +0000443 SkBenchmark* bench;
mtklein@google.comc2897432013-09-10 19:23:38 +0000444 int longestName = 0;
445 while ((bench = names.next()) != NULL) {
446 SkAutoTUnref<SkBenchmark> benchUnref(bench);
447 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
448 continue;
449 }
450 const int length = strlen(bench->getName());
451 longestName = length > longestName ? length : longestName;
452 }
453
454 // Run each bench in each configuration it supports and we asked for.
455 Iter iter;
reed@android.combd700c32009-01-05 03:34:50 +0000456 while ((bench = iter.next()) != NULL) {
bsalomon@google.com7fbc6042012-08-13 22:10:05 +0000457 SkAutoTUnref<SkBenchmark> benchUnref(bench);
mtklein@google.comc2897432013-09-10 19:23:38 +0000458 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
reed@android.comb398fe82009-01-07 11:47:57 +0000459 continue;
460 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000461
mtklein@google.comc2897432013-09-10 19:23:38 +0000462 bench->setForceAlpha(alpha);
463 bench->setForceAA(FLAGS_forceAA);
464 bench->setForceFilter(FLAGS_forceFilter);
465 bench->setDither(dither);
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +0000466 AutoPrePostDraw appd(bench);
467
mtklein@google.comc2897432013-09-10 19:23:38 +0000468 bool loggedBenchName = false;
469 for (int i = 0; i < configs.count(); ++i) {
470 const int configIndex = configs[i];
471 const Config& config = gConfigs[configIndex];
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000472
mtklein@google.comc2897432013-09-10 19:23:38 +0000473 if ((kNonRendering_Backend == config.backend) == bench->isRendering()) {
474 continue;
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000475 }
476
bsalomon@google.comcb265352013-02-22 16:13:16 +0000477 GrContext* context = NULL;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000478#if SK_SUPPORT_GPU
sugoi@google.com9c55f802013-03-07 20:52:59 +0000479 SkGLContextHelper* glContext = NULL;
mtklein@google.comc2897432013-09-10 19:23:38 +0000480 if (kGPU_Backend == config.backend) {
481 context = gContextFactory.get(config.contextType);
bsalomon@google.comcb265352013-02-22 16:13:16 +0000482 if (NULL == context) {
483 continue;
484 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000485 glContext = gContextFactory.getGLContext(config.contextType);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000486 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000487#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000488 SkAutoTUnref<SkBaseDevice> device;
489 SkAutoTUnref<SkCanvas> canvas;
490 SkPicture recordFrom, recordTo;
491 const SkIPoint dim = bench->getSize();
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000492
mtklein@google.comc2897432013-09-10 19:23:38 +0000493 const SkPicture::RecordingFlags kRecordFlags =
494 SkPicture::kUsePathBoundsForClip_RecordingFlag;
495
496 if (kNonRendering_Backend != config.backend) {
497 device.reset(make_device(config.config,
498 dim,
499 config.backend,
500 config.sampleCount,
501 context));
502 if (!device.get()) {
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000503 logger.logError(SkStringPrintf(
504 "Device creation failure for config %s. Will skip.\n", config.name));
mtklein@google.comc2897432013-09-10 19:23:38 +0000505 continue;
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000506 }
junov@chromium.orgfb103892012-09-20 19:35:43 +0000507
mtklein@google.comc2897432013-09-10 19:23:38 +0000508 switch(benchMode) {
509 case kDeferredSilent_BenchMode:
510 case kDeferred_BenchMode:
511 canvas.reset(SkDeferredCanvas::Create(device.get()));
512 break;
513 case kRecord_BenchMode:
514 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
515 break;
516 case kPictureRecord_BenchMode:
517 bench->draw(recordFrom.beginRecording(dim.fX, dim.fY, kRecordFlags));
518 recordFrom.endRecording();
519 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
520 break;
521 case kNormal_BenchMode:
522 canvas.reset(new SkCanvas(device.get()));
523 break;
524 default:
525 SkASSERT(false);
526 }
527 }
528
529 if (NULL != canvas) {
530 canvas->clear(SK_ColorWHITE);
531 if (FLAGS_clip) { performClip(canvas, dim.fX, dim.fY); }
532 if (FLAGS_scale) { performScale(canvas, dim.fX, dim.fY); }
533 if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); }
534 }
535
536 if (!loggedBenchName) {
537 loggedBenchName = true;
538 SkString str;
539 str.printf("running bench [%3d %3d] %*s ",
540 dim.fX, dim.fY, longestName, bench->getName());
541 logger.logProgress(str);
542 }
543
544#if SK_SUPPORT_GPU
545 SkGLContextHelper* contextHelper = NULL;
546 if (kGPU_Backend == config.backend) {
547 contextHelper = gContextFactory.getGLContext(config.contextType);
548 }
549 BenchTimer timer(contextHelper);
550#else
551 BenchTimer timer;
552#endif
553
mtklein@google.com9ef1d212013-09-13 20:39:50 +0000554 double previous = std::numeric_limits<double>::infinity();
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000555 bool converged = false;
mtklein@google.comc2897432013-09-10 19:23:38 +0000556 bench->setLoops(0);
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000557 if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.name); }
mtklein@google.comc2897432013-09-10 19:23:38 +0000558 do {
559 // Ramp up 1 -> 4 -> 16 -> ... -> ~1 billion.
560 const int loops = bench->getLoops();
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000561 if (loops >= (1<<30) || timer.fWall > FLAGS_maxMs) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000562 // If you find it takes more than a billion loops to get up to 20ms of runtime,
563 // you've got a computer clocked at several THz or have a broken benchmark. ;)
564 // "1B ought to be enough for anybody."
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000565 logger.logError(SkStringPrintf(
566 "Can't get %s %s to converge in %dms.\n",
567 bench->getName(), config.name, FLAGS_maxMs));
mtklein@google.comc2897432013-09-10 19:23:38 +0000568 break;
569 }
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000570 bench->setLoops(loops == 0 ? 1 : loops * 2);
mtklein@google.comc2897432013-09-10 19:23:38 +0000571
572 if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) {
573 // Clear the recorded commands so that they do not accumulate.
574 canvas.reset(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags));
junov@chromium.orgfb103892012-09-20 19:35:43 +0000575 }
robertphillips@google.com91ee3a12012-08-28 12:18:40 +0000576
mtklein@google.comc2897432013-09-10 19:23:38 +0000577 timer.start();
578 if (NULL != canvas) {
579 canvas->save();
commit-bot@chromium.org7495f592013-06-03 19:31:07 +0000580 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000581 if (benchMode == kPictureRecord_BenchMode) {
582 recordFrom.draw(canvas);
borenet@google.com8ad29ce2013-09-10 17:22:43 +0000583 } else {
mtklein@google.comc2897432013-09-10 19:23:38 +0000584 bench->draw(canvas);
commit-bot@chromium.org7495f592013-06-03 19:31:07 +0000585 }
borenet@google.com8ad29ce2013-09-10 17:22:43 +0000586
mtklein@google.comc2897432013-09-10 19:23:38 +0000587 if (kDeferredSilent_BenchMode == benchMode) {
588 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush();
589 } else if (NULL != canvas) {
590 canvas->flush();
591 }
592
593 if (NULL != canvas) {
594 canvas->restore();
595 }
596
597
598 // Stop truncated timers before GL calls complete, and stop the full timers after.
599 timer.truncatedEnd();
600#if SK_SUPPORT_GPU
601 if (NULL != glContext) {
602 context->flush();
603 SK_GL(*glContext, Finish());
604 }
605#endif
606 timer.end();
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000607 const double current = timer.fWall / bench->getLoops();
608 if (FLAGS_verbose && current > previous) { SkDebugf("↑"); }
609 if (FLAGS_verbose) { SkDebugf("%.3g ", current); }
610 converged = HasConverged(previous, current, timer.fWall);
611 previous = current;
612 } while (!kIsDebug && !converged);
613 if (FLAGS_verbose) { SkDebugf("\n"); }
mtklein@google.comc2897432013-09-10 19:23:38 +0000614
615 if (FLAGS_outDir.count() && kNonRendering_Backend != config.backend) {
616 saveFile(bench->getName(),
617 config.name,
618 FLAGS_outDir[0],
619 device->accessBitmap(false));
620 }
621
622 if (kIsDebug) {
623 // Let's not mislead ourselves by looking at Debug build bench times!
624 continue;
625 }
626
627 // Normalize to ms per 1000 iterations.
628 const double normalize = 1000.0 / bench->getLoops();
629 const struct { char shortName; const char* longName; double ms; } times[] = {
630 {'w', "msecs", normalize * timer.fWall},
631 {'W', "Wmsecs", normalize * timer.fTruncatedWall},
632 {'c', "cmsecs", normalize * timer.fCpu},
633 {'C', "Cmsecs", normalize * timer.fTruncatedCpu},
634 {'g', "gmsecs", normalize * timer.fGpu},
635 };
636
637 SkString result;
638 result.appendf(" %s:", config.name);
639 for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) {
640 if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms > 0) {
641 result.appendf(" %s = ", times[i].longName);
642 result.appendf(FLAGS_timeFormat[0], times[i].ms);
commit-bot@chromium.org7495f592013-06-03 19:31:07 +0000643 }
reed@google.com25df8882011-07-14 19:03:58 +0000644 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000645 logger.logProgress(result);
bensong@google.com24ed8d72013-06-12 14:45:03 +0000646 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000647 if (loggedBenchName) {
648 logger.logProgress("\n");
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000649 }
reed@android.combd700c32009-01-05 03:34:50 +0000650 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000651#if SK_SUPPORT_GPU
bsalomon@google.comcb265352013-02-22 16:13:16 +0000652 gContextFactory.destroyContexts();
robertphillips@google.com9d594202012-09-13 14:05:00 +0000653#endif
reed@android.combd700c32009-01-05 03:34:50 +0000654 return 0;
655}
caryclark@google.com5987f582012-10-02 18:33:14 +0000656
borenet@google.com7158e6a2012-11-01 17:43:44 +0000657#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000658int main(int argc, char * const argv[]) {
659 return tool_main(argc, (char**) argv);
660}
661#endif