blob: 2cff880baf0a0c1b766fe1c490ffeba6052595b6 [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
9
10#include "BenchTimer.h"
11
12#include "GrContext.h"
13#include "GrRenderTarget.h"
14
15#include "SkBenchmark.h"
reed@android.combd700c32009-01-05 03:34:50 +000016#include "SkCanvas.h"
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +000017#include "SkDeferredCanvas.h"
reed@android.comf523e252009-01-26 23:15:37 +000018#include "SkColorPriv.h"
bsalomon@google.com971d0c82011-08-19 17:22:05 +000019#include "SkGpuDevice.h"
reed@android.com3a859a02009-01-28 00:56:29 +000020#include "SkGraphics.h"
reed@android.comb398fe82009-01-07 11:47:57 +000021#include "SkImageEncoder.h"
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +000022#if SK_ANGLE
23#include "gl/SkANGLEGLContext.h"
24#endif
tomhudson@google.com6bf38b52012-02-14 15:11:59 +000025#include "gl/SkNativeGLContext.h"
26#include "gl/SkNullGLContext.h"
robertphillips@google.com0da37192012-03-19 14:42:13 +000027#include "gl/SkDebugGLContext.h"
reed@android.com6c924ad2009-03-31 03:48:49 +000028#include "SkNWayCanvas.h"
29#include "SkPicture.h"
reed@android.combd700c32009-01-05 03:34:50 +000030#include "SkString.h"
reed@android.combd700c32009-01-05 03:34:50 +000031
djsollen@google.com56c69772011-11-08 19:00:26 +000032#ifdef SK_BUILD_FOR_ANDROID
reed@android.com29348cb2009-08-04 18:17:15 +000033static void log_error(const char msg[]) { SkDebugf("%s", msg); }
34static void log_progress(const char msg[]) { SkDebugf("%s", msg); }
35#else
36static void log_error(const char msg[]) { fprintf(stderr, "%s", msg); }
37static void log_progress(const char msg[]) { printf("%s", msg); }
38#endif
39
40static void log_error(const SkString& str) { log_error(str.c_str()); }
41static void log_progress(const SkString& str) { log_progress(str.c_str()); }
42
43///////////////////////////////////////////////////////////////////////////////
44
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000045enum benchModes {
46 kNormal_benchModes,
47 kDeferred_benchModes,
48 kRecord_benchModes,
49 kPictureRecord_benchModes
50};
51
52///////////////////////////////////////////////////////////////////////////////
53
reed@android.com6c924ad2009-03-31 03:48:49 +000054static void erase(SkBitmap& bm) {
55 if (bm.config() == SkBitmap::kA8_Config) {
56 bm.eraseColor(0);
57 } else {
58 bm.eraseColor(SK_ColorWHITE);
59 }
60}
61
mike@reedtribe.orga9015f82011-05-17 02:25:05 +000062#if 0
reed@android.com6c924ad2009-03-31 03:48:49 +000063static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) {
64 if (bm1.width() != bm2.width() ||
65 bm1.height() != bm2.height() ||
66 bm1.config() != bm2.config()) {
67 return false;
68 }
69
70 size_t pixelBytes = bm1.width() * bm1.bytesPerPixel();
71 for (int y = 0; y < bm1.height(); y++) {
72 if (memcmp(bm1.getAddr(0, y), bm2.getAddr(0, y), pixelBytes)) {
73 return false;
74 }
75 }
reed@android.com6c924ad2009-03-31 03:48:49 +000076 return true;
77}
mike@reedtribe.orga9015f82011-05-17 02:25:05 +000078#endif
reed@android.com6c924ad2009-03-31 03:48:49 +000079
reed@android.combd700c32009-01-05 03:34:50 +000080class Iter {
81public:
reed@android.come9d00602009-09-02 21:12:42 +000082 Iter(void* param) {
reed@android.combd700c32009-01-05 03:34:50 +000083 fBench = BenchRegistry::Head();
reed@android.come9d00602009-09-02 21:12:42 +000084 fParam = param;
reed@android.combd700c32009-01-05 03:34:50 +000085 }
86
87 SkBenchmark* next() {
88 if (fBench) {
89 BenchRegistry::Factory f = fBench->factory();
90 fBench = fBench->next();
reed@android.come9d00602009-09-02 21:12:42 +000091 return f(fParam);
reed@android.combd700c32009-01-05 03:34:50 +000092 }
93 return NULL;
94 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +000095
reed@android.combd700c32009-01-05 03:34:50 +000096private:
97 const BenchRegistry* fBench;
reed@android.come9d00602009-09-02 21:12:42 +000098 void* fParam;
reed@android.combd700c32009-01-05 03:34:50 +000099};
100
101static void make_filename(const char name[], SkString* path) {
102 path->set(name);
103 for (int i = 0; name[i]; i++) {
104 switch (name[i]) {
105 case '/':
106 case '\\':
107 case ' ':
108 case ':':
109 path->writable_str()[i] = '-';
110 break;
111 default:
112 break;
113 }
114 }
115}
116
reed@android.com4c7d3d62009-01-21 03:15:13 +0000117static void saveFile(const char name[], const char config[], const char dir[],
118 const SkBitmap& bm) {
reed@android.com4c7d3d62009-01-21 03:15:13 +0000119 SkBitmap copy;
120 if (!bm.copyTo(&copy, SkBitmap::kARGB_8888_Config)) {
121 return;
122 }
reed@android.comf523e252009-01-26 23:15:37 +0000123
124 if (bm.config() == SkBitmap::kA8_Config) {
125 // turn alpha into gray-scale
126 size_t size = copy.getSize() >> 2;
127 SkPMColor* p = copy.getAddr32(0, 0);
128 for (size_t i = 0; i < size; i++) {
129 int c = (*p >> SK_A32_SHIFT) & 0xFF;
130 c = 255 - c;
131 c |= (c << 24) | (c << 16) | (c << 8);
132 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT);
133 }
134 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000135
reed@android.com4c7d3d62009-01-21 03:15:13 +0000136 SkString str;
137 make_filename(name, &str);
138 str.appendf("_%s.png", config);
139 str.prepend(dir);
140 ::remove(str.c_str());
141 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type,
142 100);
reed@android.com4c7d3d62009-01-21 03:15:13 +0000143}
144
145static void performClip(SkCanvas* canvas, int w, int h) {
146 SkRect r;
147
148 r.set(SkIntToScalar(10), SkIntToScalar(10),
149 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3));
150 canvas->clipRect(r, SkRegion::kIntersect_Op);
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000151
reed@android.com4c7d3d62009-01-21 03:15:13 +0000152 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3),
153 SkIntToScalar(w-10), SkIntToScalar(h-10));
154 canvas->clipRect(r, SkRegion::kXOR_Op);
155}
156
157static void performRotate(SkCanvas* canvas, int w, int h) {
158 const SkScalar x = SkIntToScalar(w) / 2;
159 const SkScalar y = SkIntToScalar(h) / 2;
160
161 canvas->translate(x, y);
162 canvas->rotate(SkIntToScalar(35));
163 canvas->translate(-x, -y);
164}
165
reed@android.com387359e2009-08-04 01:51:09 +0000166static void performScale(SkCanvas* canvas, int w, int h) {
167 const SkScalar x = SkIntToScalar(w) / 2;
168 const SkScalar y = SkIntToScalar(h) / 2;
169
170 canvas->translate(x, y);
171 // just enough so we can't take the sprite case
172 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
173 canvas->translate(-x, -y);
174}
175
reed@android.com29348cb2009-08-04 18:17:15 +0000176static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) {
177 if (argv < stop) {
178 *var = atoi(*argv) != 0;
179 return true;
180 }
181 return false;
182}
183
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000184enum Backend {
185 kRaster_Backend,
186 kGPU_Backend,
187 kPDF_Backend,
188};
189
bsalomon@google.com508824b2011-12-13 16:49:49 +0000190class GLHelper {
191public:
192 GLHelper() {
193 }
194
195 bool init(SkGLContext* glCtx, int width, int height) {
196 GrContext* grCtx;
197 GrRenderTarget* rt;
198 if (glCtx->init(width, height)) {
199 GrPlatform3DContext ctx =
200 reinterpret_cast<GrPlatform3DContext>(glCtx->gl());
201 grCtx = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx);
202 if (NULL != grCtx) {
203 GrPlatformRenderTargetDesc desc;
204 desc.fConfig = kSkia8888_PM_GrPixelConfig;
205 desc.fWidth = width;
206 desc.fHeight = height;
207 desc.fStencilBits = 8;
208 desc.fRenderTargetHandle = glCtx->getFBOID();
209 rt = grCtx->createPlatformRenderTarget(desc);
210 if (NULL == rt) {
211 grCtx->unref();
212 return false;
213 }
214 }
215 } else {
216 return false;
217 }
218 glCtx->ref();
219 fGLContext.reset(glCtx);
220 fGrContext.reset(grCtx);
221 fRenderTarget.reset(rt);
222 return true;
223 }
224
robertphillips@google.com0da37192012-03-19 14:42:13 +0000225 void cleanup() {
226 fGLContext.reset(NULL);
227 fGrContext.reset(NULL);
228 fRenderTarget.reset(NULL);
229 }
230
bsalomon@google.com508824b2011-12-13 16:49:49 +0000231 bool isValid() {
232 return NULL != fGLContext.get();
233 }
234
235 SkGLContext* glContext() {
236 return fGLContext.get();
237 }
238
239 GrRenderTarget* renderTarget() {
240 return fRenderTarget.get();
241 }
242
243 GrContext* grContext() {
244 return fGrContext.get();
245 }
246private:
247 SkAutoTUnref<SkGLContext> fGLContext;
248 SkAutoTUnref<GrContext> fGrContext;
249 SkAutoTUnref<GrRenderTarget> fRenderTarget;
250};
251
252static GLHelper gRealGLHelper;
253static GLHelper gNullGLHelper;
robertphillips@google.com0da37192012-03-19 14:42:13 +0000254static GLHelper gDebugGLHelper;
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000255#if SK_ANGLE
256static GLHelper gANGLEGLHelper;
257#endif
bsalomon@google.com508824b2011-12-13 16:49:49 +0000258
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000259static SkDevice* make_device(SkBitmap::Config config, const SkIPoint& size,
bsalomon@google.com508824b2011-12-13 16:49:49 +0000260 Backend backend, GLHelper* glHelper) {
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000261 SkDevice* device = NULL;
262 SkBitmap bitmap;
263 bitmap.setConfig(config, size.fX, size.fY);
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000264
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000265 switch (backend) {
266 case kRaster_Backend:
267 bitmap.allocPixels();
268 erase(bitmap);
reed@google.comaf951c92011-06-16 19:10:39 +0000269 device = new SkDevice(bitmap);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000270 break;
271 case kGPU_Backend:
bsalomon@google.com508824b2011-12-13 16:49:49 +0000272 device = new SkGpuDevice(glHelper->grContext(),
273 glHelper->renderTarget());
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000274 break;
275 case kPDF_Backend:
276 default:
277 SkASSERT(!"unsupported");
278 }
279 return device;
280}
281
reed@android.com4bc19832009-01-19 20:08:35 +0000282static const struct {
283 SkBitmap::Config fConfig;
284 const char* fName;
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000285 Backend fBackend;
bsalomon@google.com508824b2011-12-13 16:49:49 +0000286 GLHelper* fGLHelper;
reed@android.com4bc19832009-01-19 20:08:35 +0000287} gConfigs[] = {
bsalomon@google.com508824b2011-12-13 16:49:49 +0000288 { SkBitmap::kARGB_8888_Config, "8888", kRaster_Backend, NULL },
289 { SkBitmap::kRGB_565_Config, "565", kRaster_Backend, NULL },
290 { SkBitmap::kARGB_8888_Config, "GPU", kGPU_Backend, &gRealGLHelper },
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000291#if SK_ANGLE
292 { SkBitmap::kARGB_8888_Config, "ANGLE", kGPU_Backend, &gANGLEGLHelper },
293#endif
robertphillips@google.coma0b63b82012-03-30 12:23:56 +0000294#ifdef SK_DEBUG
295 { SkBitmap::kARGB_8888_Config, "Debug", kGPU_Backend, &gDebugGLHelper },
296#endif
bsalomon@google.com508824b2011-12-13 16:49:49 +0000297 { SkBitmap::kARGB_8888_Config, "NULLGPU", kGPU_Backend, &gNullGLHelper },
reed@android.com4bc19832009-01-19 20:08:35 +0000298};
299
reed@android.com4c7d3d62009-01-21 03:15:13 +0000300static int findConfig(const char config[]) {
301 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
302 if (!strcmp(config, gConfigs[i].fName)) {
303 return i;
304 }
305 }
306 return -1;
307}
308
tomhudson@google.com83823942011-10-28 14:59:07 +0000309static void determine_gpu_context_size(SkTDict<const char*>& defineDict,
310 int* contextWidth,
311 int* contextHeight) {
312 Iter iter(&defineDict);
313 SkBenchmark* bench;
314 while ((bench = iter.next()) != NULL) {
315 SkIPoint dim = bench->getSize();
316 if (*contextWidth < dim.fX) {
317 *contextWidth = dim.fX;
318 }
319 if (*contextHeight < dim.fY) {
320 *contextHeight = dim.fY;
321 }
322 }
323}
324
reed@google.com1a7eabc2011-10-31 16:33:52 +0000325static bool skip_name(const SkTDArray<const char*> array, const char name[]) {
326 if (0 == array.count()) {
327 // no names, so don't skip anything
328 return false;
329 }
330 for (int i = 0; i < array.count(); ++i) {
331 if (strstr(name, array[i])) {
332 // found the name, so don't skip
333 return false;
334 }
335 }
336 return true;
337}
338
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000339static void help() {
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000340 SkDebugf("Usage: bench [-o outDir] [-repeat nr] [-logPerIter 1|0] "
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000341 "[-timers [wcg]*] [-rotate]\n"
342 " [-scale] [-clip] [-forceAA 1|0] [-forceFilter 1|0]\n"
343 " [-forceDither 1|0] [-forceBlend 1|0] [-strokeWidth width]\n"
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000344 " [-match name] [-mode normal|deferred|record|picturerecord]\n"
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000345 " [-config 8888|565|GPU|ANGLE|NULLGPU] [-Dfoo bar]\n"
346 " [-h|--help]");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000347 SkDebugf("\n\n");
348 SkDebugf(" -o outDir : Image of each bench will be put in outDir.\n");
349 SkDebugf(" -repeat nr : Each bench repeats for nr times.\n");
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000350 SkDebugf(" -logPerIter 1|0 : "
351 "Log each repeat timer instead of mean, default is disabled.\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000352 SkDebugf(" -timers [wcg]* : "
353 "Display wall time, cpu time or gpu time for each bench.\n");
354 SkDebugf(" -rotate : Rotate before each bench runs.\n");
355 SkDebugf(" -scale : Scale before each bench runs.\n");
356 SkDebugf(" -clip : Clip before each bench runs.\n");
357 SkDebugf(" -forceAA 1|0 : "
358 "Enable/disable anti-aliased, default is enabled.\n");
359 SkDebugf(" -forceFilter 1|0 : "
360 "Enable/disable bitmap filtering, default is disabled.\n");
361 SkDebugf(" -forceDither 1|0 : "
362 "Enable/disable dithering, default is disabled.\n");
363 SkDebugf(" -forceBlend 1|0 : "
364 "Enable/disable dithering, default is disabled.\n");
365 SkDebugf(" -strokeWidth width : The width for path stroke.\n");
366 SkDebugf(" -match name : Only run bench whose name is matched.\n");
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000367 SkDebugf(" -mode normal|deferred|record|picturerecord : Run in the corresponding mode\n"
368 " normal, Use a normal canvas to draw to;\n"
369 " deferred, Use a deferrred canvas when drawing;\n"
370 " record, Benchmark the time to record to an SkPicture;\n"
371 " picturerecord, Benchmark the time to do record from a \n"
372 " SkPicture to a SkPicture.\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000373 SkDebugf(" -config 8888|565|GPU|ANGLE|NULLGPU : "
374 "Run bench in corresponding config mode.\n");
375 SkDebugf(" -Dfoo bar : Add extra definition to bench.\n");
376 SkDebugf(" -h|--help : Show this help message.\n");
377}
378
reed@android.combd700c32009-01-05 03:34:50 +0000379int main (int argc, char * const argv[]) {
reed@android.com3a859a02009-01-28 00:56:29 +0000380 SkAutoGraphics ag;
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000381
reed@android.come9d00602009-09-02 21:12:42 +0000382 SkTDict<const char*> defineDict(1024);
reed@android.com4bc19832009-01-19 20:08:35 +0000383 int repeatDraw = 1;
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000384 bool logPerIter = false;
reed@android.com4bc19832009-01-19 20:08:35 +0000385 int forceAlpha = 0xFF;
386 bool forceAA = true;
reed@android.com29348cb2009-08-04 18:17:15 +0000387 bool forceFilter = false;
reed@android.com4e635f92009-10-19 17:39:46 +0000388 SkTriState::State forceDither = SkTriState::kDefault;
bungeman@google.combe9ad4e2011-06-07 19:16:02 +0000389 bool timerWall = false;
390 bool timerCpu = true;
391 bool timerGpu = true;
reed@android.com387359e2009-08-04 01:51:09 +0000392 bool doScale = false;
reed@android.com4c7d3d62009-01-21 03:15:13 +0000393 bool doRotate = false;
394 bool doClip = false;
agl@chromium.org652807b2010-04-27 15:47:34 +0000395 bool hasStrokeWidth = false;
396 float strokeWidth;
reed@google.com1a7eabc2011-10-31 16:33:52 +0000397 SkTDArray<const char*> fMatches;
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000398 benchModes benchMode = kNormal_benchModes;
399 SkString perIterTimeformat("%.2f");
400 SkString normalTimeFormat("%6.2f");
401
reed@android.comb398fe82009-01-07 11:47:57 +0000402 SkString outDir;
reed@android.com387359e2009-08-04 01:51:09 +0000403 SkBitmap::Config outConfig = SkBitmap::kNo_Config;
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000404 GLHelper* glHelper = NULL;
reed@android.com387359e2009-08-04 01:51:09 +0000405 const char* configName = "";
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000406 Backend backend = kRaster_Backend; // for warning
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000407 SkTDArray<int> configs;
408 bool userConfig = false;
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000409
reed@android.comb398fe82009-01-07 11:47:57 +0000410 char* const* stop = argv + argc;
411 for (++argv; argv < stop; ++argv) {
412 if (strcmp(*argv, "-o") == 0) {
413 argv++;
414 if (argv < stop && **argv) {
415 outDir.set(*argv);
416 if (outDir.c_str()[outDir.size() - 1] != '/') {
417 outDir.append("/");
418 }
419 }
reed@android.com4bc19832009-01-19 20:08:35 +0000420 } else if (strcmp(*argv, "-repeat") == 0) {
421 argv++;
422 if (argv < stop) {
423 repeatDraw = atoi(*argv);
424 if (repeatDraw < 1) {
425 repeatDraw = 1;
426 }
427 } else {
reed@android.com29348cb2009-08-04 18:17:15 +0000428 log_error("missing arg for -repeat\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000429 help();
reed@android.com4bc19832009-01-19 20:08:35 +0000430 return -1;
431 }
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000432 } else if (strcmp(*argv, "-logPerIter") == 0) {
433 if (!parse_bool_arg(++argv, stop, &logPerIter)) {
434 log_error("missing arg for -logPerIter\n");
435 help();
436 return -1;
437 }
bungeman@google.combe9ad4e2011-06-07 19:16:02 +0000438 } else if (strcmp(*argv, "-timers") == 0) {
439 argv++;
440 if (argv < stop) {
441 timerWall = false;
442 timerCpu = false;
443 timerGpu = false;
444 for (char* t = *argv; *t; ++t) {
445 switch (*t) {
446 case 'w': timerWall = true; break;
447 case 'c': timerCpu = true; break;
448 case 'g': timerGpu = true; break;
449 }
450 }
451 } else {
452 log_error("missing arg for -timers\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000453 help();
bungeman@google.combe9ad4e2011-06-07 19:16:02 +0000454 return -1;
455 }
reed@android.com4c7d3d62009-01-21 03:15:13 +0000456 } else if (!strcmp(*argv, "-rotate")) {
457 doRotate = true;
reed@android.com387359e2009-08-04 01:51:09 +0000458 } else if (!strcmp(*argv, "-scale")) {
459 doScale = true;
reed@android.com4c7d3d62009-01-21 03:15:13 +0000460 } else if (!strcmp(*argv, "-clip")) {
461 doClip = true;
reed@android.com4bc19832009-01-19 20:08:35 +0000462 } else if (strcmp(*argv, "-forceAA") == 0) {
reed@android.com29348cb2009-08-04 18:17:15 +0000463 if (!parse_bool_arg(++argv, stop, &forceAA)) {
464 log_error("missing arg for -forceAA\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000465 help();
reed@android.com29348cb2009-08-04 18:17:15 +0000466 return -1;
467 }
468 } else if (strcmp(*argv, "-forceFilter") == 0) {
469 if (!parse_bool_arg(++argv, stop, &forceFilter)) {
470 log_error("missing arg for -forceFilter\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000471 help();
reed@android.com29348cb2009-08-04 18:17:15 +0000472 return -1;
473 }
reed@android.com4e635f92009-10-19 17:39:46 +0000474 } else if (strcmp(*argv, "-forceDither") == 0) {
475 bool tmp;
476 if (!parse_bool_arg(++argv, stop, &tmp)) {
477 log_error("missing arg for -forceDither\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000478 help();
reed@android.com4e635f92009-10-19 17:39:46 +0000479 return -1;
480 }
481 forceDither = tmp ? SkTriState::kTrue : SkTriState::kFalse;
reed@android.com4bc19832009-01-19 20:08:35 +0000482 } else if (strcmp(*argv, "-forceBlend") == 0) {
reed@android.com29348cb2009-08-04 18:17:15 +0000483 bool wantAlpha = false;
484 if (!parse_bool_arg(++argv, stop, &wantAlpha)) {
485 log_error("missing arg for -forceBlend\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000486 help();
reed@android.com29348cb2009-08-04 18:17:15 +0000487 return -1;
488 }
489 forceAlpha = wantAlpha ? 0x80 : 0xFF;
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000490 } else if (strcmp(*argv, "-mode") == 0) {
491 argv++;
492 if (argv < stop) {
493 if (strcmp(*argv, "normal") == 0) {
494 benchMode = kNormal_benchModes;
495 } else if (strcmp(*argv, "deferred") == 0) {
496 benchMode = kDeferred_benchModes;
497 } else if (strcmp(*argv, "record") == 0) {
498 benchMode = kRecord_benchModes;
499 } else if (strcmp(*argv, "picturerecord") == 0) {
500 benchMode = kPictureRecord_benchModes;
501 } else {
502 log_error("bad arg for -mode\n");
503 help();
504 return -1;
505 }
506 } else {
507 log_error("missing arg for -mode\n");
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000508 help();
509 return -1;
510 }
agl@chromium.org652807b2010-04-27 15:47:34 +0000511 } else if (strcmp(*argv, "-strokeWidth") == 0) {
512 argv++;
513 if (argv < stop) {
514 const char *strokeWidthStr = *argv;
515 if (sscanf(strokeWidthStr, "%f", &strokeWidth) != 1) {
516 log_error("bad arg for -strokeWidth\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000517 help();
agl@chromium.org652807b2010-04-27 15:47:34 +0000518 return -1;
519 }
520 hasStrokeWidth = true;
521 } else {
522 log_error("missing arg for -strokeWidth\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000523 help();
agl@chromium.org652807b2010-04-27 15:47:34 +0000524 return -1;
525 }
reed@android.com387359e2009-08-04 01:51:09 +0000526 } else if (strcmp(*argv, "-match") == 0) {
527 argv++;
528 if (argv < stop) {
reed@google.com1a7eabc2011-10-31 16:33:52 +0000529 *fMatches.append() = *argv;
reed@android.com387359e2009-08-04 01:51:09 +0000530 } else {
reed@android.com29348cb2009-08-04 18:17:15 +0000531 log_error("missing arg for -match\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000532 help();
reed@android.com387359e2009-08-04 01:51:09 +0000533 return -1;
reed@android.com4c7d3d62009-01-21 03:15:13 +0000534 }
reed@android.com387359e2009-08-04 01:51:09 +0000535 } else if (strcmp(*argv, "-config") == 0) {
536 argv++;
537 if (argv < stop) {
538 int index = findConfig(*argv);
539 if (index >= 0) {
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000540 *configs.append() = index;
541 userConfig = true;
reed@android.com387359e2009-08-04 01:51:09 +0000542 } else {
reed@android.com29348cb2009-08-04 18:17:15 +0000543 SkString str;
544 str.printf("unrecognized config %s\n", *argv);
545 log_error(str);
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000546 help();
reed@android.com387359e2009-08-04 01:51:09 +0000547 return -1;
548 }
549 } else {
reed@android.com29348cb2009-08-04 18:17:15 +0000550 log_error("missing arg for -config\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000551 help();
reed@android.com387359e2009-08-04 01:51:09 +0000552 return -1;
553 }
reed@android.com0c9da392010-02-22 19:50:13 +0000554 } else if (strlen(*argv) > 2 && strncmp(*argv, "-D", 2) == 0) {
reed@android.come9d00602009-09-02 21:12:42 +0000555 argv++;
reed@android.com0c9da392010-02-22 19:50:13 +0000556 if (argv < stop) {
reed@android.come9d00602009-09-02 21:12:42 +0000557 defineDict.set(argv[-1] + 2, *argv);
558 } else {
559 log_error("incomplete '-Dfoo bar' definition\n");
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000560 help();
reed@android.come9d00602009-09-02 21:12:42 +0000561 return -1;
562 }
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000563 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
564 help();
565 return 0;
reed@android.com387359e2009-08-04 01:51:09 +0000566 } else {
reed@android.com29348cb2009-08-04 18:17:15 +0000567 SkString str;
568 str.printf("unrecognized arg %s\n", *argv);
569 log_error(str);
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000570 help();
reed@android.com387359e2009-08-04 01:51:09 +0000571 return -1;
reed@android.comb398fe82009-01-07 11:47:57 +0000572 }
573 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000574 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes)
575 && !outDir.isEmpty()) {
576 log_error("'-mode record' and '-mode picturerecord' are not"
577 " compatible with -o.\n");
578 return -1;
579 }
580 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes)) {
581 perIterTimeformat.set("%.4f");
582 normalTimeFormat.set("%6.4f");
583 }
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000584 if (!userConfig) {
585 // if no config is specified by user, we add them all.
586 for (unsigned int i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) {
587 *configs.append() = i;
588 }
589 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000590
reed@google.com3b14dc12011-04-04 14:31:36 +0000591 // report our current settings
592 {
593 SkString str;
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000594 str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d "
595 "deferred=%d logperiter=%d",
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000596 forceAlpha, forceAA, forceFilter, benchMode == kDeferred_benchModes,
597 logPerIter);
bungeman@google.coma5d48412011-06-15 17:25:46 +0000598 str.appendf(" rotate=%d scale=%d clip=%d",
599 doRotate, doScale, doClip);
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000600 str.appendf(" record=%d picturerecord=%d",
601 benchMode == kRecord_benchModes,
602 benchMode == kPictureRecord_benchModes);
bungeman@google.coma5d48412011-06-15 17:25:46 +0000603 const char * ditherName;
604 switch (forceDither) {
605 case SkTriState::kDefault: ditherName = "default"; break;
606 case SkTriState::kTrue: ditherName = "true"; break;
607 case SkTriState::kFalse: ditherName = "false"; break;
608 default: ditherName = "<invalid>"; break;
609 }
610 str.appendf(" dither=%s", ditherName);
611
612 if (hasStrokeWidth) {
613 str.appendf(" strokeWidth=%f", strokeWidth);
614 } else {
615 str.append(" strokeWidth=none");
616 }
617
618#if defined(SK_SCALAR_IS_FLOAT)
619 str.append(" scalar=float");
620#elif defined(SK_SCALAR_IS_FIXED)
621 str.append(" scalar=fixed");
622#endif
623
624#if defined(SK_BUILD_FOR_WIN32)
625 str.append(" system=WIN32");
626#elif defined(SK_BUILD_FOR_MAC)
627 str.append(" system=MAC");
628#elif defined(SK_BUILD_FOR_ANDROID)
629 str.append(" system=ANDROID");
630#elif defined(SK_BUILD_FOR_UNIX)
631 str.append(" system=UNIX");
632#else
633 str.append(" system=other");
634#endif
635
636#if defined(SK_DEBUG)
637 str.append(" DEBUG");
638#endif
639 str.append("\n");
reed@google.com3b14dc12011-04-04 14:31:36 +0000640 log_progress(str);
641 }
bsalomon@google.com508824b2011-12-13 16:49:49 +0000642
bungeman@google.coma5d48412011-06-15 17:25:46 +0000643 //Don't do GL when fixed.
644#if !defined(SK_SCALAR_IS_FIXED)
tomhudson@google.com83823942011-10-28 14:59:07 +0000645 int contextWidth = 1024;
646 int contextHeight = 1024;
647 determine_gpu_context_size(defineDict, &contextWidth, &contextHeight);
bsalomon@google.com508824b2011-12-13 16:49:49 +0000648 SkAutoTUnref<SkGLContext> realGLCtx(new SkNativeGLContext);
649 SkAutoTUnref<SkGLContext> nullGLCtx(new SkNullGLContext);
robertphillips@google.com0da37192012-03-19 14:42:13 +0000650 SkAutoTUnref<SkGLContext> debugGLCtx(new SkDebugGLContext);
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000651#if SK_ANGLE
652 SkAutoTUnref<SkGLContext> angleGLCtx(new SkANGLEGLContext);
653#endif
bsalomon@google.com508824b2011-12-13 16:49:49 +0000654 gRealGLHelper.init(realGLCtx.get(), contextWidth, contextHeight);
655 gNullGLHelper.init(nullGLCtx.get(), contextWidth, contextHeight);
robertphillips@google.com0da37192012-03-19 14:42:13 +0000656 gDebugGLHelper.init(debugGLCtx.get(), contextWidth, contextHeight);
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000657#if SK_ANGLE
658 gANGLEGLHelper.init(angleGLCtx.get(), contextWidth, contextHeight);
659#endif
bungeman@google.coma5d48412011-06-15 17:25:46 +0000660#endif
bsalomon@google.com74913722011-10-27 20:44:19 +0000661
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000662 BenchTimer timer = BenchTimer(gRealGLHelper.glContext());
reed@android.come9d00602009-09-02 21:12:42 +0000663 Iter iter(&defineDict);
reed@android.combd700c32009-01-05 03:34:50 +0000664 SkBenchmark* bench;
665 while ((bench = iter.next()) != NULL) {
reed@android.comb398fe82009-01-07 11:47:57 +0000666 SkIPoint dim = bench->getSize();
667 if (dim.fX <= 0 || dim.fY <= 0) {
668 continue;
669 }
reed@android.comb398fe82009-01-07 11:47:57 +0000670
reed@android.com4bc19832009-01-19 20:08:35 +0000671 bench->setForceAlpha(forceAlpha);
672 bench->setForceAA(forceAA);
reed@android.com29348cb2009-08-04 18:17:15 +0000673 bench->setForceFilter(forceFilter);
reed@android.com4e635f92009-10-19 17:39:46 +0000674 bench->setDither(forceDither);
agl@chromium.org652807b2010-04-27 15:47:34 +0000675 if (hasStrokeWidth) {
676 bench->setStrokeWidth(strokeWidth);
677 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000678
reed@android.com387359e2009-08-04 01:51:09 +0000679 // only run benchmarks if their name contains matchStr
reed@google.com1a7eabc2011-10-31 16:33:52 +0000680 if (skip_name(fMatches, bench->getName())) {
reed@android.com387359e2009-08-04 01:51:09 +0000681 continue;
682 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000683
reed@android.com29348cb2009-08-04 18:17:15 +0000684 {
685 SkString str;
reed@google.comd34658a2011-04-11 13:12:51 +0000686 str.printf("running bench [%d %d] %28s", dim.fX, dim.fY,
reed@android.com0c9da392010-02-22 19:50:13 +0000687 bench->getName());
reed@android.com29348cb2009-08-04 18:17:15 +0000688 log_progress(str);
689 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000690
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000691 for (int x = 0; x < configs.count(); ++x) {
692 int configIndex = configs[x];
693
694 outConfig = gConfigs[configIndex].fConfig;
695 configName = gConfigs[configIndex].fName;
696 backend = gConfigs[configIndex].fBackend;
697 glHelper = gConfigs[configIndex].fGLHelper;
bsalomon@google.com508824b2011-12-13 16:49:49 +0000698
699 if (kGPU_Backend == backend &&
700 (NULL == glHelper || !glHelper->isValid())) {
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000701 continue;
702 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000703
bsalomon@google.com508824b2011-12-13 16:49:49 +0000704 SkDevice* device = make_device(outConfig, dim, backend, glHelper);
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000705 SkCanvas* canvas = NULL;
706 SkPicture pictureRecordFrom;
707 SkPicture pictureRecordTo;
708 switch(benchMode) {
709 case kDeferred_benchModes:
710 canvas = new SkDeferredCanvas(device);
711 break;
712 case kRecord_benchModes:
713 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY);
714 canvas->ref();
715 break;
716 case kPictureRecord_benchModes: {
717 // This sets up picture-to-picture recording.
718 // The C++ drawing calls for the benchmark are recorded into
719 // pictureRecordFrom. As the benchmark, we will time how
720 // long it takes to playback pictureRecordFrom into
721 // pictureRecordTo.
722 SkCanvas* tempCanvas = pictureRecordFrom.beginRecording(dim.fX, dim.fY);
723 bench->draw(tempCanvas);
724 pictureRecordFrom.endRecording();
725 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY);
726 canvas->ref();
727 break;
728 }
729 case kNormal_benchModes:
730 canvas = new SkCanvas(device);
731 break;
732 default:
733 SkASSERT(0);
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000734 }
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000735 device->unref();
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000736 SkAutoUnref canvasUnref(canvas);
737
reed@android.com4c7d3d62009-01-21 03:15:13 +0000738 if (doClip) {
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000739 performClip(canvas, dim.fX, dim.fY);
reed@android.com4c7d3d62009-01-21 03:15:13 +0000740 }
reed@android.com387359e2009-08-04 01:51:09 +0000741 if (doScale) {
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000742 performScale(canvas, dim.fX, dim.fY);
reed@android.com387359e2009-08-04 01:51:09 +0000743 }
reed@android.com4c7d3d62009-01-21 03:15:13 +0000744 if (doRotate) {
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000745 performRotate(canvas, dim.fX, dim.fY);
reed@android.com4c7d3d62009-01-21 03:15:13 +0000746 }
bsalomon@google.com508824b2011-12-13 16:49:49 +0000747
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000748 // warm up caches if needed
reed@android.comeca48362010-12-20 18:34:17 +0000749 if (repeatDraw > 1) {
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000750 SkAutoCanvasRestore acr(canvas, true);
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000751 if (benchMode == kPictureRecord_benchModes) {
752 pictureRecordFrom.draw(canvas);
753 } else {
754 bench->draw(canvas);
755 }
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000756 canvas->flush();
bsalomon@google.com508824b2011-12-13 16:49:49 +0000757 if (glHelper) {
758 glHelper->grContext()->flush();
759 SK_GL(*glHelper->glContext(), Finish());
bungeman@google.comd1a416a2011-05-18 18:37:07 +0000760 }
reed@android.comeca48362010-12-20 18:34:17 +0000761 }
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000762
763 // record timer values for each repeat, and their sum
764 SkString fWallStr(" msecs = ");
765 SkString fCpuStr(" cmsecs = ");
766 SkString fGpuStr(" gmsecs = ");
767 double fWallSum = 0.0;
768 double fCpuSum = 0.0;
769 double fGpuSum = 0.0;
reed@android.com4bc19832009-01-19 20:08:35 +0000770 for (int i = 0; i < repeatDraw; i++) {
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000771 if ((benchMode == kRecord_benchModes
772 || benchMode == kPictureRecord_benchModes)) {
773 // This will clear the recorded commands so that they do not
774 // acculmulate.
775 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY);
776 }
777
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000778 timer.start();
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000779 SkAutoCanvasRestore acr(canvas, true);
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000780 if (benchMode == kPictureRecord_benchModes) {
781 pictureRecordFrom.draw(canvas);
782 } else {
783 bench->draw(canvas);
784 }
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +0000785 canvas->flush();
bsalomon@google.com508824b2011-12-13 16:49:49 +0000786 if (glHelper) {
787 glHelper->grContext()->flush();
reed@google.com25df8882011-07-14 19:03:58 +0000788 }
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000789 timer.end();
790
791 if (i == repeatDraw - 1) {
792 // no comma after the last value
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000793 fWallStr.appendf(perIterTimeformat.c_str(), timer.fWall);
794 fCpuStr.appendf(perIterTimeformat.c_str(), timer.fCpu);
795 fGpuStr.appendf(perIterTimeformat.c_str(), timer.fGpu);
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000796 } else {
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000797 fWallStr.appendf(perIterTimeformat.c_str(), timer.fWall);
798 fWallStr.appendf(",");
799 fCpuStr.appendf(perIterTimeformat.c_str(), timer.fCpu);
800 fCpuStr.appendf(",");
801 fGpuStr.appendf(perIterTimeformat.c_str(), timer.fGpu);
802 fGpuStr.appendf(",");
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000803 }
804 fWallSum += timer.fWall;
805 fCpuSum += timer.fCpu;
806 fGpuSum += timer.fGpu;
reed@google.com25df8882011-07-14 19:03:58 +0000807 }
bsalomon@google.com508824b2011-12-13 16:49:49 +0000808 if (glHelper) {
809 SK_GL(*glHelper->glContext(), Finish());
bsalomon@google.com788e2472011-10-19 20:56:30 +0000810 }
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000811
reed@android.com4bc19832009-01-19 20:08:35 +0000812 if (repeatDraw > 1) {
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000813 // output each repeat (no average) if logPerIter is set,
814 // otherwise output only the average
815 if (!logPerIter) {
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000816 fWallStr.set(" msecs = ");
817 fWallStr.appendf(normalTimeFormat.c_str(), fWallSum / repeatDraw);
818 fCpuStr.set(" cmsecs = ");
819 fCpuStr.appendf(normalTimeFormat.c_str(), fCpuSum / repeatDraw);
820 fGpuStr.set(" gmsecs = ");
821 fGpuStr.appendf(normalTimeFormat.c_str(), fGpuSum / repeatDraw);
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000822 }
reed@android.com29348cb2009-08-04 18:17:15 +0000823 SkString str;
bungeman@google.combe9ad4e2011-06-07 19:16:02 +0000824 str.printf(" %4s:", configName);
825 if (timerWall) {
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000826 str += fWallStr;
bungeman@google.combe9ad4e2011-06-07 19:16:02 +0000827 }
828 if (timerCpu) {
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000829 str += fCpuStr;
bungeman@google.combe9ad4e2011-06-07 19:16:02 +0000830 }
bensong@google.comaf3d79a2012-07-02 20:48:51 +0000831 if (timerGpu && glHelper && fGpuSum > 0) {
832 str += fGpuStr;
bungeman@google.combe9ad4e2011-06-07 19:16:02 +0000833 }
reed@android.com29348cb2009-08-04 18:17:15 +0000834 log_progress(str);
reed@android.com4bc19832009-01-19 20:08:35 +0000835 }
reed@android.com4c7d3d62009-01-21 03:15:13 +0000836 if (outDir.size() > 0) {
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000837 saveFile(bench->getName(), configName, outDir.c_str(),
838 device->accessBitmap(false));
reed@android.com4c7d3d62009-01-21 03:15:13 +0000839 }
reed@android.com4bc19832009-01-19 20:08:35 +0000840 }
reed@android.com29348cb2009-08-04 18:17:15 +0000841 log_progress("\n");
reed@android.combd700c32009-01-05 03:34:50 +0000842 }
bsalomon@google.com971d0c82011-08-19 17:22:05 +0000843
robertphillips@google.com0da37192012-03-19 14:42:13 +0000844 // need to clean up here rather than post-main to allow leak detection to work
845 gDebugGLHelper.cleanup();
846
reed@android.combd700c32009-01-05 03:34:50 +0000847 return 0;
848}