blob: de38cc9eb5db9722121eeff6211f347f785515d4 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
bsalomon@google.com971d0c82011-08-19 17:22:05 +00007
mtklein@google.comc2897432013-09-10 19:23:38 +00008#include "BenchTimer.h"
scroggo@google.com9a412522012-09-07 15:21:18 +00009#include "SkBenchLogger.h"
bsalomon@google.com971d0c82011-08-19 17:22:05 +000010#include "SkBenchmark.h"
robertphillips@google.com73672252013-08-29 12:40:26 +000011#include "SkBitmapDevice.h"
reed@android.combd700c32009-01-05 03:34:50 +000012#include "SkCanvas.h"
mtklein@google.com78d03792013-09-10 19:42:07 +000013#include "SkColorPriv.h"
sglez@google.com586db932013-07-24 17:24:23 +000014#include "SkCommandLineFlags.h"
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +000015#include "SkDeferredCanvas.h"
reed@android.com3a859a02009-01-28 00:56:29 +000016#include "SkGraphics.h"
reed@android.comb398fe82009-01-07 11:47:57 +000017#include "SkImageEncoder.h"
mtklein@google.comc2897432013-09-10 19:23:38 +000018#include "SkOSFile.h"
reed@android.com6c924ad2009-03-31 03:48:49 +000019#include "SkPicture.h"
reed@android.combd700c32009-01-05 03:34:50 +000020#include "SkString.h"
reed@android.com29348cb2009-08-04 18:17:15 +000021
djsollen@google.comdb490e92013-11-20 13:15:40 +000022#if SK_SUPPORT_GPU
23#include "GrContext.h"
24#include "GrContextFactory.h"
25#include "GrRenderTarget.h"
26#include "SkGpuDevice.h"
27#include "gl/GrGLDefines.h"
28#else
29class GrContext;
30#endif // SK_SUPPORT_GPU
31
mtklein@google.com9ef1d212013-09-13 20:39:50 +000032#include <limits>
33
mtklein@google.comc2897432013-09-10 19:23:38 +000034enum BenchMode {
35 kNormal_BenchMode,
36 kDeferred_BenchMode,
37 kDeferredSilent_BenchMode,
38 kRecord_BenchMode,
39 kPictureRecord_BenchMode
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000040};
mtklein@google.comdbd41c82013-09-13 20:11:09 +000041const char* BenchMode_Name[] = {
42 "normal", "deferred", "deferredSilent", "record", "picturerecord"
43};
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000044
borenet@google.com4e061d32013-09-16 19:12:19 +000045static const char kDefaultsConfigStr[] = "defaults";
46
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000047///////////////////////////////////////////////////////////////////////////////
48
reed@android.com6c924ad2009-03-31 03:48:49 +000049static void erase(SkBitmap& bm) {
50 if (bm.config() == SkBitmap::kA8_Config) {
junov@google.comdbfac8a2012-12-06 21:47:40 +000051 bm.eraseColor(SK_ColorTRANSPARENT);
reed@android.com6c924ad2009-03-31 03:48:49 +000052 } else {
53 bm.eraseColor(SK_ColorWHITE);
54 }
55}
56
reed@android.combd700c32009-01-05 03:34:50 +000057class Iter {
58public:
mtklein@google.comc2897432013-09-10 19:23:38 +000059 Iter() : fBench(BenchRegistry::Head()) {}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000060
reed@android.combd700c32009-01-05 03:34:50 +000061 SkBenchmark* next() {
62 if (fBench) {
63 BenchRegistry::Factory f = fBench->factory();
64 fBench = fBench->next();
mtklein@google.com410e6e82013-09-13 19:52:27 +000065 return f();
reed@android.combd700c32009-01-05 03:34:50 +000066 }
67 return NULL;
68 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +000069
reed@android.combd700c32009-01-05 03:34:50 +000070private:
71 const BenchRegistry* fBench;
72};
73
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +000074class AutoPrePostDraw {
75public:
76 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) {
77 fBench->preDraw();
78 }
79 ~AutoPrePostDraw() {
80 fBench->postDraw();
81 }
82private:
83 SkBenchmark* fBench;
84};
85
reed@android.combd700c32009-01-05 03:34:50 +000086static void make_filename(const char name[], SkString* path) {
87 path->set(name);
88 for (int i = 0; name[i]; i++) {
89 switch (name[i]) {
90 case '/':
91 case '\\':
92 case ' ':
93 case ':':
94 path->writable_str()[i] = '-';
95 break;
96 default:
97 break;
98 }
99 }
100}
101
reed@android.com4c7d3d62009-01-21 03:15:13 +0000102static void saveFile(const char name[], const char config[], const char dir[],
103 const SkBitmap& bm) {
reed@android.com4c7d3d62009-01-21 03:15:13 +0000104 SkBitmap copy;
105 if (!bm.copyTo(&copy, SkBitmap::kARGB_8888_Config)) {
106 return;
107 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000108
reed@android.comf523e252009-01-26 23:15:37 +0000109 if (bm.config() == SkBitmap::kA8_Config) {
110 // turn alpha into gray-scale
111 size_t size = copy.getSize() >> 2;
112 SkPMColor* p = copy.getAddr32(0, 0);
113 for (size_t i = 0; i < size; i++) {
114 int c = (*p >> SK_A32_SHIFT) & 0xFF;
115 c = 255 - c;
116 c |= (c << 24) | (c << 16) | (c << 8);
117 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT);
118 }
119 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000120
mtklein@google.comc2897432013-09-10 19:23:38 +0000121 SkString filename;
122 make_filename(name, &filename);
123 filename.appendf("_%s.png", config);
124 SkString path = SkOSPath::SkPathJoin(dir, filename.c_str());
125 ::remove(path.c_str());
126 SkImageEncoder::EncodeFile(path.c_str(), copy, SkImageEncoder::kPNG_Type, 100);
reed@android.com4c7d3d62009-01-21 03:15:13 +0000127}
128
129static void performClip(SkCanvas* canvas, int w, int h) {
130 SkRect r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000131
reed@android.com4c7d3d62009-01-21 03:15:13 +0000132 r.set(SkIntToScalar(10), SkIntToScalar(10),
133 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3));
134 canvas->clipRect(r, SkRegion::kIntersect_Op);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000135
reed@android.com4c7d3d62009-01-21 03:15:13 +0000136 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3),
137 SkIntToScalar(w-10), SkIntToScalar(h-10));
138 canvas->clipRect(r, SkRegion::kXOR_Op);
139}
140
141static void performRotate(SkCanvas* canvas, int w, int h) {
142 const SkScalar x = SkIntToScalar(w) / 2;
143 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000144
reed@android.com4c7d3d62009-01-21 03:15:13 +0000145 canvas->translate(x, y);
146 canvas->rotate(SkIntToScalar(35));
147 canvas->translate(-x, -y);
148}
149
reed@android.com387359e2009-08-04 01:51:09 +0000150static void performScale(SkCanvas* canvas, int w, int h) {
151 const SkScalar x = SkIntToScalar(w) / 2;
152 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000153
reed@android.com387359e2009-08-04 01:51:09 +0000154 canvas->translate(x, y);
155 // just enough so we can't take the sprite case
156 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
157 canvas->translate(-x, -y);
158}
159
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000160static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size,
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000161 SkBenchmark::Backend backend, int sampleCount, GrContext* context) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000162 SkBaseDevice* device = NULL;
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000163 SkBitmap bitmap;
164 bitmap.setConfig(config, size.fX, size.fY);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000165
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000166 switch (backend) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000167 case SkBenchmark::kRaster_Backend:
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000168 bitmap.allocPixels();
169 erase(bitmap);
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000170 device = SkNEW_ARGS(SkBitmapDevice, (bitmap));
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000171 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000172#if SK_SUPPORT_GPU
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000173 case SkBenchmark::kGPU_Backend: {
bsalomon@google.comcb265352013-02-22 16:13:16 +0000174 GrTextureDesc desc;
175 desc.fConfig = kSkia8888_GrPixelConfig;
176 desc.fFlags = kRenderTarget_GrTextureFlagBit;
177 desc.fWidth = size.fX;
178 desc.fHeight = size.fY;
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000179 desc.fSampleCnt = sampleCount;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000180 SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
181 if (!texture) {
182 return NULL;
183 }
184 device = SkNEW_ARGS(SkGpuDevice, (context, texture.get()));
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000185 break;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000186 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000187#endif
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000188 case SkBenchmark::kPDF_Backend:
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000189 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000190 SkDEBUGFAIL("unsupported");
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000191 }
192 return device;
193}
194
bsalomon@google.comcb265352013-02-22 16:13:16 +0000195#if SK_SUPPORT_GPU
196GrContextFactory gContextFactory;
197typedef GrContextFactory::GLContextType GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000198static const GLContextType kNative = GrContextFactory::kNative_GLContextType;
199#if SK_ANGLE
200static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000201#endif
202static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType;
203static const GLContextType kNull = GrContextFactory::kNull_GLContextType;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000204#else
205typedef int GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000206static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000207#endif
208
mtklein@google.comc2897432013-09-10 19:23:38 +0000209#ifdef SK_DEBUG
210static const bool kIsDebug = true;
211#else
212static const bool kIsDebug = false;
213#endif
214
215static const struct Config {
216 SkBitmap::Config config;
217 const char* name;
218 int sampleCount;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000219 SkBenchmark::Backend backend;
mtklein@google.comc2897432013-09-10 19:23:38 +0000220 GLContextType contextType;
221 bool runByDefault;
reed@android.com4bc19832009-01-19 20:08:35 +0000222} gConfigs[] = {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000223 { SkBitmap::kNo_Config, "NONRENDERING", 0, SkBenchmark::kNonRendering_Backend, kNative, true},
224 { SkBitmap::kARGB_8888_Config, "8888", 0, SkBenchmark::kRaster_Backend, kNative, true},
225 { SkBitmap::kRGB_565_Config, "565", 0, SkBenchmark::kRaster_Backend, kNative, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000226#if SK_SUPPORT_GPU
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000227 { SkBitmap::kARGB_8888_Config, "GPU", 0, SkBenchmark::kGPU_Backend, kNative, true},
228 { SkBitmap::kARGB_8888_Config, "MSAA4", 4, SkBenchmark::kGPU_Backend, kNative, false},
229 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, SkBenchmark::kGPU_Backend, kNative, false},
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000230#if SK_ANGLE
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000231 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, SkBenchmark::kGPU_Backend, kANGLE, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000232#endif // SK_ANGLE
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000233 { SkBitmap::kARGB_8888_Config, "Debug", 0, SkBenchmark::kGPU_Backend, kDebug, kIsDebug},
234 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, SkBenchmark::kGPU_Backend, kNull, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000235#endif // SK_SUPPORT_GPU
reed@android.com4bc19832009-01-19 20:08:35 +0000236};
237
mtklein@google.comc2897432013-09-10 19:23:38 +0000238DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir.");
239DEFINE_string(timers, "cg", "Timers to display. "
240 "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)");
reed@android.com4c7d3d62009-01-21 03:15:13 +0000241
mtklein@google.comc2897432013-09-10 19:23:38 +0000242DEFINE_bool(rotate, false, "Rotate canvas before bench run?");
243DEFINE_bool(scale, false, "Scale canvas before bench run?");
244DEFINE_bool(clip, false, "Clip canvas before bench run?");
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000245
mtklein@google.comc2897432013-09-10 19:23:38 +0000246DEFINE_bool(forceAA, true, "Force anti-aliasing?");
247DEFINE_bool(forceFilter, false, "Force bitmap filtering?");
248DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?");
249DEFINE_bool(forceBlend, false, "Force alpha blending?");
250
251DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable cache.");
252DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to disable cache.");
253
254DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n"
255 "Multiple matches may be separated by spaces.\n"
256 "~ causes a matching test to always be skipped\n"
257 "^ requires the start of the test to match\n"
258 "$ requires the end of the test to match\n"
259 "^ and $ requires an exact match\n"
260 "If a test does not match any list entry,\n"
261 "it is skipped unless some list entry starts with ~\n");
262DEFINE_string(mode, "normal",
263 "normal: draw to a normal canvas;\n"
264 "deferred: draw to a deferred canvas;\n"
265 "deferredSilent: deferred with silent playback;\n"
266 "record: draw to an SkPicture;\n"
267 "picturerecord: draw from an SkPicture to an SkPicture.\n");
borenet@google.com4e061d32013-09-16 19:12:19 +0000268DEFINE_string(config, kDefaultsConfigStr,
269 "Run configs given. By default, runs the configs marked \"runByDefault\" in gConfigs.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000270DEFINE_string(logFile, "", "Also write stdout here.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000271DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run.");
272DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run.");
273DEFINE_double(error, 0.01,
274 "Ratio of subsequent bench measurements must drop within 1±error to converge.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000275DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000276DEFINE_bool2(verbose, v, false, "Print more.");
scroggo@google.com111fd112013-09-25 21:42:12 +0000277DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000278
279// Has this bench converged? First arguments are milliseconds / loop iteration,
280// last is overall runtime in milliseconds.
281static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw) {
282 if (currRaw < FLAGS_minMs) {
283 return false;
284 }
285 const double low = 1 - FLAGS_error, high = 1 + FLAGS_error;
286 const double ratio = currPerLoop / prevPerLoop;
287 return low < ratio && ratio < high;
288}
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000289
caryclark@google.com5987f582012-10-02 18:33:14 +0000290int tool_main(int argc, char** argv);
291int tool_main(int argc, char** argv) {
bsalomon@google.com4e230682013-01-15 20:37:04 +0000292#if SK_ENABLE_INST_COUNT
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000293 gPrintInstCount = true;
294#endif
reed@android.com3a859a02009-01-28 00:56:29 +0000295 SkAutoGraphics ag;
mtklein@google.comc2897432013-09-10 19:23:38 +0000296 SkCommandLineFlags::Parse(argc, argv);
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000297
mtklein@google.comc2897432013-09-10 19:23:38 +0000298 // First, parse some flags.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000299
scroggo@google.com9a412522012-09-07 15:21:18 +0000300 SkBenchLogger logger;
mtklein@google.comc2897432013-09-10 19:23:38 +0000301 if (FLAGS_logFile.count()) {
302 logger.SetLogFile(FLAGS_logFile[0]);
303 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000304
mtklein@google.comc2897432013-09-10 19:23:38 +0000305 const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF;
306 SkTriState::State dither = SkTriState::kDefault;
307 for (size_t i = 0; i < 3; i++) {
308 if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) {
309 dither = static_cast<SkTriState::State>(i);
reed@android.comb398fe82009-01-07 11:47:57 +0000310 }
311 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000312
313 BenchMode benchMode = kNormal_BenchMode;
314 for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) {
315 if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) {
316 benchMode = static_cast<BenchMode>(i);
317 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000318 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000319
320 SkTDArray<int> configs;
borenet@google.com4e061d32013-09-16 19:12:19 +0000321 bool runDefaultConfigs = false;
mtklein@google.comc2897432013-09-10 19:23:38 +0000322 // Try user-given configs first.
323 for (int i = 0; i < FLAGS_config.count(); i++) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000324 for (int j = 0; j < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++j) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000325 if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) {
326 *configs.append() = j;
borenet@google.com4e061d32013-09-16 19:12:19 +0000327 } else if (0 == strcmp(FLAGS_config[i], kDefaultsConfigStr)) {
328 runDefaultConfigs = true;
mtklein@google.comc2897432013-09-10 19:23:38 +0000329 }
330 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000331 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000332 // If there weren't any, fill in with defaults.
borenet@google.com4e061d32013-09-16 19:12:19 +0000333 if (runDefaultConfigs) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000334 for (int i = 0; i < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000335 if (gConfigs[i].runByDefault) {
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000336 *configs.append() = i;
337 }
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000338 }
339 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000340 // Filter out things we can't run.
341 if (kNormal_BenchMode != benchMode) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000342 // Non-rendering configs only run in normal mode
343 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000344 const Config& config = gConfigs[configs[i]];
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000345 if (SkBenchmark::kNonRendering_Backend == config.backend) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000346 configs.remove(i, 1);
347 --i;
348 }
349 }
350 }
scroggo@google.com111fd112013-09-25 21:42:12 +0000351 // Set the resource path.
352 if (!FLAGS_resourcePath.isEmpty()) {
353 SkBenchmark::SetResourcePath(FLAGS_resourcePath[0]);
354 }
355
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000356#if SK_SUPPORT_GPU
357 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000358 const Config& config = gConfigs[configs[i]];
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000359
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000360 if (SkBenchmark::kGPU_Backend == config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000361 GrContext* context = gContextFactory.get(config.contextType);
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000362 if (NULL == context) {
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000363 logger.logError(SkStringPrintf(
364 "Error creating GrContext for config %s. Config will be skipped.\n",
365 config.name));
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000366 configs.remove(i);
367 --i;
368 continue;
369 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000370 if (config.sampleCount > context->getMaxSampleCount()){
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000371 logger.logError(SkStringPrintf(
372 "Sample count (%d) for config %s is unsupported. Config will be skipped.\n",
373 config.sampleCount, config.name));
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000374 configs.remove(i);
375 --i;
376 continue;
377 }
378 }
379 }
380#endif
381
mtklein@google.comc2897432013-09-10 19:23:38 +0000382 // All flags should be parsed now. Report our settings.
383 if (kIsDebug) {
384 logger.logError("bench was built in Debug mode, so we're going to hide the times."
385 " It's for your own good!\n");
386 }
387 SkString str("skia bench:");
388 str.appendf(" mode=%s", FLAGS_mode[0]);
389 str.appendf(" alpha=0x%02X antialias=%d filter=%d dither=%s",
390 alpha, FLAGS_forceAA, FLAGS_forceFilter, SkTriState::Name[dither]);
391 str.appendf(" rotate=%d scale=%d clip=%d", FLAGS_rotate, FLAGS_scale, FLAGS_clip);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000392
mtklein@google.comc2897432013-09-10 19:23:38 +0000393#if defined(SK_SCALAR_IS_FIXED)
394 str.append(" scalar=fixed");
395#else
396 str.append(" scalar=float");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000397#endif
398
399#if defined(SK_BUILD_FOR_WIN32)
mtklein@google.comc2897432013-09-10 19:23:38 +0000400 str.append(" system=WIN32");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000401#elif defined(SK_BUILD_FOR_MAC)
mtklein@google.comc2897432013-09-10 19:23:38 +0000402 str.append(" system=MAC");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000403#elif defined(SK_BUILD_FOR_ANDROID)
mtklein@google.comc2897432013-09-10 19:23:38 +0000404 str.append(" system=ANDROID");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000405#elif defined(SK_BUILD_FOR_UNIX)
mtklein@google.comc2897432013-09-10 19:23:38 +0000406 str.append(" system=UNIX");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000407#else
mtklein@google.comc2897432013-09-10 19:23:38 +0000408 str.append(" system=other");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000409#endif
410
411#if defined(SK_DEBUG)
mtklein@google.comc2897432013-09-10 19:23:38 +0000412 str.append(" DEBUG");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000413#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000414 str.append("\n");
415 logger.logProgress(str);
bsalomon@google.com508824b2011-12-13 16:49:49 +0000416
mtklein@google.comc2897432013-09-10 19:23:38 +0000417
418 // Set texture cache limits if non-default.
bsalomon@google.com5c90e292013-02-22 19:17:13 +0000419 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) {
bsalomon@google.comcb265352013-02-22 16:13:16 +0000420#if SK_SUPPORT_GPU
mtklein@google.comc2897432013-09-10 19:23:38 +0000421 const Config& config = gConfigs[i];
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000422 if (SkBenchmark::kGPU_Backend != config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000423 continue;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000424 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000425 GrContext* context = gContextFactory.get(config.contextType);
426 if (NULL == context) {
427 continue;
428 }
429
430 size_t bytes;
431 int count;
432 context->getTextureCacheLimits(&count, &bytes);
433 if (-1 != FLAGS_gpuCacheBytes) {
434 bytes = static_cast<size_t>(FLAGS_gpuCacheBytes);
435 }
436 if (-1 != FLAGS_gpuCacheCount) {
437 count = FLAGS_gpuCacheCount;
438 }
439 context->setTextureCacheLimits(count, bytes);
bsalomon@google.comcb265352013-02-22 16:13:16 +0000440#endif
441 }
bsalomon@google.com74913722011-10-27 20:44:19 +0000442
mtklein@google.comc2897432013-09-10 19:23:38 +0000443 // Find the longest name of the benches we're going to run to make the output pretty.
444 Iter names;
reed@android.combd700c32009-01-05 03:34:50 +0000445 SkBenchmark* bench;
robertphillips@google.com8c99c9f2013-11-20 15:56:14 +0000446 int longestName = 0;
mtklein@google.comc2897432013-09-10 19:23:38 +0000447 while ((bench = names.next()) != NULL) {
448 SkAutoTUnref<SkBenchmark> benchUnref(bench);
449 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
450 continue;
451 }
robertphillips@google.com8c99c9f2013-11-20 15:56:14 +0000452 const int length = strlen(bench->getName());
mtklein@google.comc2897432013-09-10 19:23:38 +0000453 longestName = length > longestName ? length : longestName;
454 }
455
456 // Run each bench in each configuration it supports and we asked for.
457 Iter iter;
reed@android.combd700c32009-01-05 03:34:50 +0000458 while ((bench = iter.next()) != NULL) {
bsalomon@google.com7fbc6042012-08-13 22:10:05 +0000459 SkAutoTUnref<SkBenchmark> benchUnref(bench);
mtklein@google.comc2897432013-09-10 19:23:38 +0000460 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
reed@android.comb398fe82009-01-07 11:47:57 +0000461 continue;
462 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000463
mtklein@google.comc2897432013-09-10 19:23:38 +0000464 bench->setForceAlpha(alpha);
465 bench->setForceAA(FLAGS_forceAA);
466 bench->setForceFilter(FLAGS_forceFilter);
467 bench->setDither(dither);
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +0000468 AutoPrePostDraw appd(bench);
469
mtklein@google.comc2897432013-09-10 19:23:38 +0000470 bool loggedBenchName = false;
471 for (int i = 0; i < configs.count(); ++i) {
472 const int configIndex = configs[i];
473 const Config& config = gConfigs[configIndex];
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000474
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000475 if (!bench->isSuitableFor(config.backend)) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000476 continue;
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000477 }
478
bsalomon@google.comcb265352013-02-22 16:13:16 +0000479 GrContext* context = NULL;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000480#if SK_SUPPORT_GPU
sugoi@google.com9c55f802013-03-07 20:52:59 +0000481 SkGLContextHelper* glContext = NULL;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000482 if (SkBenchmark::kGPU_Backend == config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000483 context = gContextFactory.get(config.contextType);
bsalomon@google.comcb265352013-02-22 16:13:16 +0000484 if (NULL == context) {
485 continue;
486 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000487 glContext = gContextFactory.getGLContext(config.contextType);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000488 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000489#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000490 SkAutoTUnref<SkBaseDevice> device;
491 SkAutoTUnref<SkCanvas> canvas;
492 SkPicture recordFrom, recordTo;
493 const SkIPoint dim = bench->getSize();
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000494
mtklein@google.comc2897432013-09-10 19:23:38 +0000495 const SkPicture::RecordingFlags kRecordFlags =
496 SkPicture::kUsePathBoundsForClip_RecordingFlag;
497
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000498 if (SkBenchmark::kNonRendering_Backend != config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000499 device.reset(make_device(config.config,
500 dim,
501 config.backend,
502 config.sampleCount,
503 context));
504 if (!device.get()) {
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000505 logger.logError(SkStringPrintf(
506 "Device creation failure for config %s. Will skip.\n", config.name));
mtklein@google.comc2897432013-09-10 19:23:38 +0000507 continue;
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000508 }
junov@chromium.orgfb103892012-09-20 19:35:43 +0000509
mtklein@google.comc2897432013-09-10 19:23:38 +0000510 switch(benchMode) {
511 case kDeferredSilent_BenchMode:
512 case kDeferred_BenchMode:
513 canvas.reset(SkDeferredCanvas::Create(device.get()));
514 break;
515 case kRecord_BenchMode:
516 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
517 break;
518 case kPictureRecord_BenchMode:
519 bench->draw(recordFrom.beginRecording(dim.fX, dim.fY, kRecordFlags));
520 recordFrom.endRecording();
521 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
522 break;
523 case kNormal_BenchMode:
524 canvas.reset(new SkCanvas(device.get()));
525 break;
526 default:
527 SkASSERT(false);
528 }
529 }
530
531 if (NULL != canvas) {
532 canvas->clear(SK_ColorWHITE);
533 if (FLAGS_clip) { performClip(canvas, dim.fX, dim.fY); }
534 if (FLAGS_scale) { performScale(canvas, dim.fX, dim.fY); }
535 if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); }
536 }
537
538 if (!loggedBenchName) {
539 loggedBenchName = true;
540 SkString str;
541 str.printf("running bench [%3d %3d] %*s ",
542 dim.fX, dim.fY, longestName, bench->getName());
543 logger.logProgress(str);
544 }
545
546#if SK_SUPPORT_GPU
547 SkGLContextHelper* contextHelper = NULL;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000548 if (SkBenchmark::kGPU_Backend == config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000549 contextHelper = gContextFactory.getGLContext(config.contextType);
550 }
551 BenchTimer timer(contextHelper);
552#else
553 BenchTimer timer;
554#endif
555
mtklein@google.com9ef1d212013-09-13 20:39:50 +0000556 double previous = std::numeric_limits<double>::infinity();
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000557 bool converged = false;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000558
559 // variables used to compute loopsPerFrame
560 double frameIntervalTime = 0.0f;
561 int frameIntervalTotalLoops = 0;
562
563 bool frameIntervalComputed = false;
564 int loopsPerFrame = 0;
565 int loopsPerIter = 0;
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000566 if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.name); }
mtklein@google.comc2897432013-09-10 19:23:38 +0000567 do {
djsollen@google.com70de4da2013-10-10 17:33:39 +0000568 // Ramp up 1 -> 2 -> 4 -> 8 -> 16 -> ... -> ~1 billion.
569 loopsPerIter = (loopsPerIter == 0) ? 1 : loopsPerIter * 2;
570 if (loopsPerIter >= (1<<30) || timer.fWall > FLAGS_maxMs) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000571 // If you find it takes more than a billion loops to get up to 20ms of runtime,
572 // you've got a computer clocked at several THz or have a broken benchmark. ;)
573 // "1B ought to be enough for anybody."
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000574 logger.logError(SkStringPrintf(
djsollen@google.com70de4da2013-10-10 17:33:39 +0000575 "\nCan't get %s %s to converge in %dms (%d loops)",
576 bench->getName(), config.name, FLAGS_maxMs, loopsPerIter));
mtklein@google.comc2897432013-09-10 19:23:38 +0000577 break;
578 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000579
580 if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) {
581 // Clear the recorded commands so that they do not accumulate.
582 canvas.reset(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags));
junov@chromium.orgfb103892012-09-20 19:35:43 +0000583 }
robertphillips@google.com91ee3a12012-08-28 12:18:40 +0000584
mtklein@google.comc2897432013-09-10 19:23:38 +0000585 timer.start();
djsollen@google.com70de4da2013-10-10 17:33:39 +0000586 // Inner loop that allows us to break the run into smaller
587 // chunks (e.g. frames). This is especially useful for the GPU
588 // as we can flush and/or swap buffers to keep the GPU from
589 // queuing up too much work.
590 for (int loopCount = loopsPerIter; loopCount > 0; ) {
commit-bot@chromium.org28871192013-10-14 15:28:01 +0000591 // Save and restore around each call to draw() to guarantee a pristine canvas.
592 SkAutoCanvasRestore saveRestore(canvas, true/*also save*/);
593
djsollen@google.com70de4da2013-10-10 17:33:39 +0000594 if (frameIntervalComputed && loopCount > loopsPerFrame) {
595 bench->setLoops(loopsPerFrame);
596 loopCount -= loopsPerFrame;
597 } else {
598 bench->setLoops(loopCount);
599 loopCount = 0;
600 }
601
602 if (benchMode == kPictureRecord_BenchMode) {
603 recordFrom.draw(canvas);
604 } else {
605 bench->draw(canvas);
606 }
607
608 if (kDeferredSilent_BenchMode == benchMode) {
609 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush();
610 } else if (NULL != canvas) {
611 canvas->flush();
612 }
613
614#if SK_SUPPORT_GPU
615 // swap drawing buffers on each frame to prevent the GPU
616 // from queuing up too much work
617 if (NULL != glContext) {
618 glContext->swapBuffers();
619 }
620#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000621 }
622
mtklein@google.comc2897432013-09-10 19:23:38 +0000623
624
625 // Stop truncated timers before GL calls complete, and stop the full timers after.
626 timer.truncatedEnd();
627#if SK_SUPPORT_GPU
628 if (NULL != glContext) {
629 context->flush();
630 SK_GL(*glContext, Finish());
631 }
632#endif
633 timer.end();
djsollen@google.com70de4da2013-10-10 17:33:39 +0000634
djsollen@google.comdcfed6c2013-10-10 18:48:27 +0000635 // setup the frame interval for subsequent iterations
636 if (!frameIntervalComputed) {
djsollen@google.com70de4da2013-10-10 17:33:39 +0000637 frameIntervalTime += timer.fWall;
638 frameIntervalTotalLoops += loopsPerIter;
639 if (frameIntervalTime >= FLAGS_minMs) {
640 frameIntervalComputed = true;
641 loopsPerFrame =
djsollen@google.com4e1d4b32013-10-10 17:50:52 +0000642 (int)(((double)frameIntervalTotalLoops / frameIntervalTime) * FLAGS_minMs);
djsollen@google.com70de4da2013-10-10 17:33:39 +0000643 if (loopsPerFrame < 1) {
644 loopsPerFrame = 1;
645 }
646// SkDebugf(" %s has %d loops in %f ms (normalized to %d)\n",
647// bench->getName(), frameIntervalTotalLoops,
648// timer.fWall, loopsPerFrame);
649 }
650 }
djsollen@google.comdcfed6c2013-10-10 18:48:27 +0000651
djsollen@google.com70de4da2013-10-10 17:33:39 +0000652 const double current = timer.fWall / loopsPerIter;
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000653 if (FLAGS_verbose && current > previous) { SkDebugf("↑"); }
654 if (FLAGS_verbose) { SkDebugf("%.3g ", current); }
655 converged = HasConverged(previous, current, timer.fWall);
656 previous = current;
657 } while (!kIsDebug && !converged);
658 if (FLAGS_verbose) { SkDebugf("\n"); }
mtklein@google.comc2897432013-09-10 19:23:38 +0000659
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000660 if (FLAGS_outDir.count() && SkBenchmark::kNonRendering_Backend != config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000661 saveFile(bench->getName(),
662 config.name,
663 FLAGS_outDir[0],
664 device->accessBitmap(false));
665 }
666
667 if (kIsDebug) {
668 // Let's not mislead ourselves by looking at Debug build bench times!
669 continue;
670 }
671
672 // Normalize to ms per 1000 iterations.
djsollen@google.com70de4da2013-10-10 17:33:39 +0000673 const double normalize = 1000.0 / loopsPerIter;
mtklein@google.comc2897432013-09-10 19:23:38 +0000674 const struct { char shortName; const char* longName; double ms; } times[] = {
675 {'w', "msecs", normalize * timer.fWall},
676 {'W', "Wmsecs", normalize * timer.fTruncatedWall},
677 {'c', "cmsecs", normalize * timer.fCpu},
678 {'C', "Cmsecs", normalize * timer.fTruncatedCpu},
679 {'g', "gmsecs", normalize * timer.fGpu},
680 };
681
682 SkString result;
683 result.appendf(" %s:", config.name);
684 for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) {
685 if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms > 0) {
686 result.appendf(" %s = ", times[i].longName);
687 result.appendf(FLAGS_timeFormat[0], times[i].ms);
commit-bot@chromium.org7495f592013-06-03 19:31:07 +0000688 }
reed@google.com25df8882011-07-14 19:03:58 +0000689 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000690 logger.logProgress(result);
bensong@google.com24ed8d72013-06-12 14:45:03 +0000691 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000692 if (loggedBenchName) {
693 logger.logProgress("\n");
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000694 }
reed@android.combd700c32009-01-05 03:34:50 +0000695 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000696#if SK_SUPPORT_GPU
bsalomon@google.comcb265352013-02-22 16:13:16 +0000697 gContextFactory.destroyContexts();
robertphillips@google.com9d594202012-09-13 14:05:00 +0000698#endif
reed@android.combd700c32009-01-05 03:34:50 +0000699 return 0;
700}
caryclark@google.com5987f582012-10-02 18:33:14 +0000701
borenet@google.com7158e6a2012-11-01 17:43:44 +0000702#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000703int main(int argc, char * const argv[]) {
704 return tool_main(argc, (char**) argv);
705}
706#endif