blob: 6eea11fc149a0d763df45f0cced79757a8501fbc [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"
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +00009#include "ResultsWriter.h"
scroggo@google.com9a412522012-09-07 15:21:18 +000010#include "SkBenchLogger.h"
bsalomon@google.com971d0c82011-08-19 17:22:05 +000011#include "SkBenchmark.h"
robertphillips@google.com73672252013-08-29 12:40:26 +000012#include "SkBitmapDevice.h"
reed@android.combd700c32009-01-05 03:34:50 +000013#include "SkCanvas.h"
mtklein@google.com78d03792013-09-10 19:42:07 +000014#include "SkColorPriv.h"
sglez@google.com586db932013-07-24 17:24:23 +000015#include "SkCommandLineFlags.h"
reed@google.com1bc6c6a2014-02-04 14:02:44 +000016#include "SkData.h"
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +000017#include "SkDeferredCanvas.h"
commit-bot@chromium.org6adce672014-02-03 14:48:17 +000018#include "SkGMBench.h"
reed@android.com3a859a02009-01-28 00:56:29 +000019#include "SkGraphics.h"
reed@android.comb398fe82009-01-07 11:47:57 +000020#include "SkImageEncoder.h"
mtklein@google.comc2897432013-09-10 19:23:38 +000021#include "SkOSFile.h"
reed@android.com6c924ad2009-03-31 03:48:49 +000022#include "SkPicture.h"
reed@android.combd700c32009-01-05 03:34:50 +000023#include "SkString.h"
reed@google.com1bc6c6a2014-02-04 14:02:44 +000024#include "SkSurface.h"
reed@android.com29348cb2009-08-04 18:17:15 +000025
djsollen@google.comdb490e92013-11-20 13:15:40 +000026#if SK_SUPPORT_GPU
27#include "GrContext.h"
28#include "GrContextFactory.h"
29#include "GrRenderTarget.h"
30#include "SkGpuDevice.h"
31#include "gl/GrGLDefines.h"
32#else
33class GrContext;
34#endif // SK_SUPPORT_GPU
35
mtklein@google.com9ef1d212013-09-13 20:39:50 +000036#include <limits>
37
mtklein@google.comc2897432013-09-10 19:23:38 +000038enum BenchMode {
39 kNormal_BenchMode,
40 kDeferred_BenchMode,
41 kDeferredSilent_BenchMode,
42 kRecord_BenchMode,
43 kPictureRecord_BenchMode
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000044};
mtklein@google.comdbd41c82013-09-13 20:11:09 +000045const char* BenchMode_Name[] = {
46 "normal", "deferred", "deferredSilent", "record", "picturerecord"
47};
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000048
borenet@google.com4e061d32013-09-16 19:12:19 +000049static const char kDefaultsConfigStr[] = "defaults";
50
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000051///////////////////////////////////////////////////////////////////////////////
52
reed@android.combd700c32009-01-05 03:34:50 +000053class Iter {
54public:
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000055 Iter() : fBenches(BenchRegistry::Head()), fGMs(skiagm::GMRegistry::Head()) {}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000056
reed@android.combd700c32009-01-05 03:34:50 +000057 SkBenchmark* next() {
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000058 if (fBenches) {
59 BenchRegistry::Factory f = fBenches->factory();
60 fBenches = fBenches->next();
commit-bot@chromium.org6adce672014-02-03 14:48:17 +000061 return (*f)();
reed@android.combd700c32009-01-05 03:34:50 +000062 }
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000063
64 while (fGMs) {
65 SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL));
66 fGMs = fGMs->next();
67 if (gm->getFlags() & skiagm::GM::kAsBench_Flag) {
68 return SkNEW_ARGS(SkGMBench, (gm.detach()));
69 }
70 }
71
reed@android.combd700c32009-01-05 03:34:50 +000072 return NULL;
73 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +000074
reed@android.combd700c32009-01-05 03:34:50 +000075private:
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000076 const BenchRegistry* fBenches;
77 const skiagm::GMRegistry* fGMs;
reed@android.combd700c32009-01-05 03:34:50 +000078};
79
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +000080class AutoPrePostDraw {
81public:
82 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) {
83 fBench->preDraw();
84 }
85 ~AutoPrePostDraw() {
86 fBench->postDraw();
87 }
88private:
89 SkBenchmark* fBench;
90};
91
reed@android.combd700c32009-01-05 03:34:50 +000092static void make_filename(const char name[], SkString* path) {
93 path->set(name);
94 for (int i = 0; name[i]; i++) {
95 switch (name[i]) {
96 case '/':
97 case '\\':
98 case ' ':
99 case ':':
100 path->writable_str()[i] = '-';
101 break;
102 default:
103 break;
104 }
105 }
106}
107
reed@android.com4c7d3d62009-01-21 03:15:13 +0000108static void saveFile(const char name[], const char config[], const char dir[],
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000109 const SkImage* image) {
110 SkAutoTUnref<SkData> data(image->encode(SkImageEncoder::kPNG_Type, 100));
111 if (NULL == data.get()) {
reed@android.com4c7d3d62009-01-21 03:15:13 +0000112 return;
113 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000114
mtklein@google.comc2897432013-09-10 19:23:38 +0000115 SkString filename;
116 make_filename(name, &filename);
117 filename.appendf("_%s.png", config);
118 SkString path = SkOSPath::SkPathJoin(dir, filename.c_str());
119 ::remove(path.c_str());
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000120
reed@google.comace13542014-02-06 22:00:58 +0000121 SkFILEWStream stream(path.c_str());
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000122 stream.write(data->data(), data->size());
reed@android.com4c7d3d62009-01-21 03:15:13 +0000123}
124
125static void performClip(SkCanvas* canvas, int w, int h) {
126 SkRect r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000127
reed@android.com4c7d3d62009-01-21 03:15:13 +0000128 r.set(SkIntToScalar(10), SkIntToScalar(10),
129 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3));
130 canvas->clipRect(r, SkRegion::kIntersect_Op);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000131
reed@android.com4c7d3d62009-01-21 03:15:13 +0000132 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3),
133 SkIntToScalar(w-10), SkIntToScalar(h-10));
134 canvas->clipRect(r, SkRegion::kXOR_Op);
135}
136
137static void performRotate(SkCanvas* canvas, int w, int h) {
138 const SkScalar x = SkIntToScalar(w) / 2;
139 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000140
reed@android.com4c7d3d62009-01-21 03:15:13 +0000141 canvas->translate(x, y);
142 canvas->rotate(SkIntToScalar(35));
143 canvas->translate(-x, -y);
144}
145
reed@android.com387359e2009-08-04 01:51:09 +0000146static void performScale(SkCanvas* canvas, int w, int h) {
147 const SkScalar x = SkIntToScalar(w) / 2;
148 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000149
reed@android.com387359e2009-08-04 01:51:09 +0000150 canvas->translate(x, y);
151 // just enough so we can't take the sprite case
152 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
153 canvas->translate(-x, -y);
154}
155
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000156static SkSurface* make_surface(SkColorType colorType, const SkIPoint& size,
157 SkBenchmark::Backend backend, int sampleCount,
158 GrContext* context) {
159 SkSurface* surface = NULL;
160 SkImageInfo info = SkImageInfo::Make(size.fX, size.fY, colorType,
161 kPremul_SkAlphaType);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000162
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000163 switch (backend) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000164 case SkBenchmark::kRaster_Backend:
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000165 surface = SkSurface::NewRaster(info);
166 surface->getCanvas()->clear(SK_ColorWHITE);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000167 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000168#if SK_SUPPORT_GPU
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000169 case SkBenchmark::kGPU_Backend: {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000170 surface = SkSurface::NewRenderTarget(context, info, sampleCount);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000171 break;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000172 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000173#endif
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000174 case SkBenchmark::kPDF_Backend:
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000175 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000176 SkDEBUGFAIL("unsupported");
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000177 }
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000178 return surface;
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000179}
180
bsalomon@google.comcb265352013-02-22 16:13:16 +0000181#if SK_SUPPORT_GPU
182GrContextFactory gContextFactory;
183typedef GrContextFactory::GLContextType GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000184static const GLContextType kNative = GrContextFactory::kNative_GLContextType;
commit-bot@chromium.orge8989572014-01-26 20:51:00 +0000185static const GLContextType kNVPR = GrContextFactory::kNVPR_GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000186#if SK_ANGLE
187static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000188#endif
189static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType;
190static const GLContextType kNull = GrContextFactory::kNull_GLContextType;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000191#else
192typedef int GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000193static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000194#endif
195
mtklein@google.comc2897432013-09-10 19:23:38 +0000196#ifdef SK_DEBUG
197static const bool kIsDebug = true;
198#else
199static const bool kIsDebug = false;
200#endif
201
202static const struct Config {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000203 SkColorType fColorType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000204 const char* name;
205 int sampleCount;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000206 SkBenchmark::Backend backend;
mtklein@google.comc2897432013-09-10 19:23:38 +0000207 GLContextType contextType;
208 bool runByDefault;
reed@android.com4bc19832009-01-19 20:08:35 +0000209} gConfigs[] = {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000210 { kPMColor_SkColorType, "NONRENDERING", 0, SkBenchmark::kNonRendering_Backend, kNative, true},
211 { kPMColor_SkColorType, "8888", 0, SkBenchmark::kRaster_Backend, kNative, true},
212 { kRGB_565_SkColorType, "565", 0, SkBenchmark::kRaster_Backend, kNative, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000213#if SK_SUPPORT_GPU
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000214 { kPMColor_SkColorType, "GPU", 0, SkBenchmark::kGPU_Backend, kNative, true},
215 { kPMColor_SkColorType, "MSAA4", 4, SkBenchmark::kGPU_Backend, kNative, false},
216 { kPMColor_SkColorType, "MSAA16", 16, SkBenchmark::kGPU_Backend, kNative, false},
217 { kPMColor_SkColorType, "NVPRMSAA4", 4, SkBenchmark::kGPU_Backend, kNVPR, true},
218 { kPMColor_SkColorType, "NVPRMSAA16", 16, SkBenchmark::kGPU_Backend, kNVPR, false},
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000219#if SK_ANGLE
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000220 { kPMColor_SkColorType, "ANGLE", 0, SkBenchmark::kGPU_Backend, kANGLE, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000221#endif // SK_ANGLE
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000222 { kPMColor_SkColorType, "Debug", 0, SkBenchmark::kGPU_Backend, kDebug, kIsDebug},
223 { kPMColor_SkColorType, "NULLGPU", 0, SkBenchmark::kGPU_Backend, kNull, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000224#endif // SK_SUPPORT_GPU
reed@android.com4bc19832009-01-19 20:08:35 +0000225};
226
mtklein@google.comc2897432013-09-10 19:23:38 +0000227DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir.");
228DEFINE_string(timers, "cg", "Timers to display. "
229 "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)");
reed@android.com4c7d3d62009-01-21 03:15:13 +0000230
mtklein@google.comc2897432013-09-10 19:23:38 +0000231DEFINE_bool(rotate, false, "Rotate canvas before bench run?");
232DEFINE_bool(scale, false, "Scale canvas before bench run?");
233DEFINE_bool(clip, false, "Clip canvas before bench run?");
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000234
mtklein@google.comc2897432013-09-10 19:23:38 +0000235DEFINE_bool(forceAA, true, "Force anti-aliasing?");
236DEFINE_bool(forceFilter, false, "Force bitmap filtering?");
237DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?");
238DEFINE_bool(forceBlend, false, "Force alpha blending?");
239
240DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable cache.");
241DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to disable cache.");
242
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +0000243DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000244DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n"
245 "Multiple matches may be separated by spaces.\n"
246 "~ causes a matching test to always be skipped\n"
247 "^ requires the start of the test to match\n"
248 "$ requires the end of the test to match\n"
249 "^ and $ requires an exact match\n"
250 "If a test does not match any list entry,\n"
251 "it is skipped unless some list entry starts with ~\n");
252DEFINE_string(mode, "normal",
253 "normal: draw to a normal canvas;\n"
254 "deferred: draw to a deferred canvas;\n"
255 "deferredSilent: deferred with silent playback;\n"
256 "record: draw to an SkPicture;\n"
257 "picturerecord: draw from an SkPicture to an SkPicture.\n");
borenet@google.com4e061d32013-09-16 19:12:19 +0000258DEFINE_string(config, kDefaultsConfigStr,
259 "Run configs given. By default, runs the configs marked \"runByDefault\" in gConfigs.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000260DEFINE_string(logFile, "", "Also write stdout here.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000261DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run.");
262DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run.");
263DEFINE_double(error, 0.01,
264 "Ratio of subsequent bench measurements must drop within 1±error to converge.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000265DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000266DEFINE_bool2(verbose, v, false, "Print more.");
tfarina@chromium.org725a64c2013-12-31 14:29:52 +0000267DEFINE_string2(resourcePath, i, "resources", "directory for test resources.");
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000268DEFINE_string(outResultsFile, "", "If given, the results will be written to the file in JSON format.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000269
270// Has this bench converged? First arguments are milliseconds / loop iteration,
271// last is overall runtime in milliseconds.
272static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw) {
273 if (currRaw < FLAGS_minMs) {
274 return false;
275 }
276 const double low = 1 - FLAGS_error, high = 1 + FLAGS_error;
277 const double ratio = currPerLoop / prevPerLoop;
278 return low < ratio && ratio < high;
279}
tomhudson@google.com86bb9b72012-04-03 13:28:57 +0000280
caryclark@google.com5987f582012-10-02 18:33:14 +0000281int tool_main(int argc, char** argv);
282int tool_main(int argc, char** argv) {
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +0000283 SkCommandLineFlags::Parse(argc, argv);
bsalomon@google.com4e230682013-01-15 20:37:04 +0000284#if SK_ENABLE_INST_COUNT
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +0000285 if (FLAGS_leaks) {
286 gPrintInstCount = true;
287 }
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000288#endif
reed@android.com3a859a02009-01-28 00:56:29 +0000289 SkAutoGraphics ag;
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000290
mtklein@google.comc2897432013-09-10 19:23:38 +0000291 // First, parse some flags.
scroggo@google.com9a412522012-09-07 15:21:18 +0000292 SkBenchLogger logger;
mtklein@google.comc2897432013-09-10 19:23:38 +0000293 if (FLAGS_logFile.count()) {
294 logger.SetLogFile(FLAGS_logFile[0]);
295 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000296
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000297 LoggerResultsWriter logWriter(logger, FLAGS_timeFormat[0]);
298 MultiResultsWriter writer;
299 writer.add(&logWriter);
300 SkAutoTDelete<JSONResultsWriter> jsonWriter;
301 if (FLAGS_outResultsFile.count()) {
302 jsonWriter.reset(SkNEW(JSONResultsWriter(FLAGS_outResultsFile[0])));
303 writer.add(jsonWriter.get());
304 }
305 // Instantiate after all the writers have been added to writer so that we
306 // call close() before their destructors are called on the way out.
307 CallEnd<MultiResultsWriter> ender(writer);
308
mtklein@google.comc2897432013-09-10 19:23:38 +0000309 const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF;
310 SkTriState::State dither = SkTriState::kDefault;
311 for (size_t i = 0; i < 3; i++) {
312 if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) {
313 dither = static_cast<SkTriState::State>(i);
reed@android.comb398fe82009-01-07 11:47:57 +0000314 }
315 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000316
317 BenchMode benchMode = kNormal_BenchMode;
318 for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) {
319 if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) {
320 benchMode = static_cast<BenchMode>(i);
321 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000322 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000323
324 SkTDArray<int> configs;
borenet@google.com4e061d32013-09-16 19:12:19 +0000325 bool runDefaultConfigs = false;
mtklein@google.comc2897432013-09-10 19:23:38 +0000326 // Try user-given configs first.
327 for (int i = 0; i < FLAGS_config.count(); i++) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000328 for (int j = 0; j < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++j) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000329 if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) {
330 *configs.append() = j;
borenet@google.com4e061d32013-09-16 19:12:19 +0000331 } else if (0 == strcmp(FLAGS_config[i], kDefaultsConfigStr)) {
332 runDefaultConfigs = true;
mtklein@google.comc2897432013-09-10 19:23:38 +0000333 }
334 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000335 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000336 // If there weren't any, fill in with defaults.
borenet@google.com4e061d32013-09-16 19:12:19 +0000337 if (runDefaultConfigs) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000338 for (int i = 0; i < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000339 if (gConfigs[i].runByDefault) {
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000340 *configs.append() = i;
341 }
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000342 }
343 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000344 // Filter out things we can't run.
345 if (kNormal_BenchMode != benchMode) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000346 // Non-rendering configs only run in normal mode
347 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000348 const Config& config = gConfigs[configs[i]];
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000349 if (SkBenchmark::kNonRendering_Backend == config.backend) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000350 configs.remove(i, 1);
351 --i;
352 }
353 }
354 }
scroggo@google.com111fd112013-09-25 21:42:12 +0000355 // Set the resource path.
356 if (!FLAGS_resourcePath.isEmpty()) {
357 SkBenchmark::SetResourcePath(FLAGS_resourcePath[0]);
358 }
359
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000360#if SK_SUPPORT_GPU
361 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000362 const Config& config = gConfigs[configs[i]];
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000363
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000364 if (SkBenchmark::kGPU_Backend == config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000365 GrContext* context = gContextFactory.get(config.contextType);
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000366 if (NULL == context) {
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000367 logger.logError(SkStringPrintf(
368 "Error creating GrContext for config %s. Config will be skipped.\n",
369 config.name));
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000370 configs.remove(i);
371 --i;
372 continue;
373 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000374 if (config.sampleCount > context->getMaxSampleCount()){
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000375 logger.logError(SkStringPrintf(
376 "Sample count (%d) for config %s is unsupported. Config will be skipped.\n",
377 config.sampleCount, config.name));
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000378 configs.remove(i);
379 --i;
380 continue;
381 }
382 }
383 }
384#endif
385
mtklein@google.comc2897432013-09-10 19:23:38 +0000386 // All flags should be parsed now. Report our settings.
387 if (kIsDebug) {
388 logger.logError("bench was built in Debug mode, so we're going to hide the times."
389 " It's for your own good!\n");
390 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000391 writer.option("mode", FLAGS_mode[0]);
392 writer.option("alpha", SkStringPrintf("0x%02X", alpha).c_str());
393 writer.option("antialias", SkStringPrintf("%d", FLAGS_forceAA).c_str());
394 writer.option("filter", SkStringPrintf("%d", FLAGS_forceFilter).c_str());
395 writer.option("dither", SkTriState::Name[dither]);
396
397 writer.option("rotate", SkStringPrintf("%d", FLAGS_rotate).c_str());
398 writer.option("scale", SkStringPrintf("%d", FLAGS_scale).c_str());
399 writer.option("clip", SkStringPrintf("%d", FLAGS_clip).c_str());
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000400
bungeman@google.coma5d48412011-06-15 17:25:46 +0000401#if defined(SK_BUILD_FOR_WIN32)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000402 writer.option("system", "WIN32");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000403#elif defined(SK_BUILD_FOR_MAC)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000404 writer.option("system", "MAC");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000405#elif defined(SK_BUILD_FOR_ANDROID)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000406 writer.option("system", "ANDROID");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000407#elif defined(SK_BUILD_FOR_UNIX)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000408 writer.option("system", "UNIX");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000409#else
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000410 writer.option("system", "other");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000411#endif
412
413#if defined(SK_DEBUG)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000414 writer.option("build", "DEBUG");
415#else
416 writer.option("build", "RELEASE");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000417#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000418
419 // Set texture cache limits if non-default.
bsalomon@google.com5c90e292013-02-22 19:17:13 +0000420 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) {
bsalomon@google.comcb265352013-02-22 16:13:16 +0000421#if SK_SUPPORT_GPU
mtklein@google.comc2897432013-09-10 19:23:38 +0000422 const Config& config = gConfigs[i];
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000423 if (SkBenchmark::kGPU_Backend != config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000424 continue;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000425 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000426 GrContext* context = gContextFactory.get(config.contextType);
427 if (NULL == context) {
428 continue;
429 }
430
431 size_t bytes;
432 int count;
433 context->getTextureCacheLimits(&count, &bytes);
434 if (-1 != FLAGS_gpuCacheBytes) {
435 bytes = static_cast<size_t>(FLAGS_gpuCacheBytes);
436 }
437 if (-1 != FLAGS_gpuCacheCount) {
438 count = FLAGS_gpuCacheCount;
439 }
440 context->setTextureCacheLimits(count, bytes);
bsalomon@google.comcb265352013-02-22 16:13:16 +0000441#endif
442 }
bsalomon@google.com74913722011-10-27 20:44:19 +0000443
mtklein@google.comc2897432013-09-10 19:23:38 +0000444 // Run each bench in each configuration it supports and we asked for.
445 Iter iter;
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000446 SkBenchmark* bench;
reed@android.combd700c32009-01-05 03:34:50 +0000447 while ((bench = iter.next()) != NULL) {
bsalomon@google.com7fbc6042012-08-13 22:10:05 +0000448 SkAutoTUnref<SkBenchmark> benchUnref(bench);
mtklein@google.comc2897432013-09-10 19:23:38 +0000449 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) {
reed@android.comb398fe82009-01-07 11:47:57 +0000450 continue;
451 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000452
mtklein@google.comc2897432013-09-10 19:23:38 +0000453 bench->setForceAlpha(alpha);
454 bench->setForceAA(FLAGS_forceAA);
455 bench->setForceFilter(FLAGS_forceFilter);
456 bench->setDither(dither);
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +0000457 AutoPrePostDraw appd(bench);
458
mtklein@google.comc2897432013-09-10 19:23:38 +0000459 bool loggedBenchName = false;
460 for (int i = 0; i < configs.count(); ++i) {
461 const int configIndex = configs[i];
462 const Config& config = gConfigs[configIndex];
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000463
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000464 if (!bench->isSuitableFor(config.backend)) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000465 continue;
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000466 }
467
bsalomon@google.comcb265352013-02-22 16:13:16 +0000468 GrContext* context = NULL;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000469#if SK_SUPPORT_GPU
sugoi@google.com9c55f802013-03-07 20:52:59 +0000470 SkGLContextHelper* glContext = NULL;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000471 if (SkBenchmark::kGPU_Backend == config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000472 context = gContextFactory.get(config.contextType);
bsalomon@google.comcb265352013-02-22 16:13:16 +0000473 if (NULL == context) {
474 continue;
475 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000476 glContext = gContextFactory.getGLContext(config.contextType);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000477 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000478#endif
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000479
mtklein@google.comc2897432013-09-10 19:23:38 +0000480 SkAutoTUnref<SkCanvas> canvas;
481 SkPicture recordFrom, recordTo;
482 const SkIPoint dim = bench->getSize();
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000483
mtklein@google.comc2897432013-09-10 19:23:38 +0000484 const SkPicture::RecordingFlags kRecordFlags =
485 SkPicture::kUsePathBoundsForClip_RecordingFlag;
486
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000487 SkAutoTUnref<SkSurface> surface;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000488 if (SkBenchmark::kNonRendering_Backend != config.backend) {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000489 surface.reset(make_surface(config.fColorType,
490 dim,
491 config.backend,
492 config.sampleCount,
493 context));
494 if (!surface.get()) {
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000495 logger.logError(SkStringPrintf(
496 "Device creation failure for config %s. Will skip.\n", config.name));
mtklein@google.comc2897432013-09-10 19:23:38 +0000497 continue;
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000498 }
junov@chromium.orgfb103892012-09-20 19:35:43 +0000499
mtklein@google.comc2897432013-09-10 19:23:38 +0000500 switch(benchMode) {
501 case kDeferredSilent_BenchMode:
502 case kDeferred_BenchMode:
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000503 canvas.reset(SkDeferredCanvas::Create(surface.get()));
mtklein@google.comc2897432013-09-10 19:23:38 +0000504 break;
505 case kRecord_BenchMode:
506 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
507 break;
508 case kPictureRecord_BenchMode:
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000509 bench->draw(1, recordFrom.beginRecording(dim.fX, dim.fY, kRecordFlags));
mtklein@google.comc2897432013-09-10 19:23:38 +0000510 recordFrom.endRecording();
511 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
512 break;
513 case kNormal_BenchMode:
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000514 canvas.reset(SkRef(surface->getCanvas()));
mtklein@google.comc2897432013-09-10 19:23:38 +0000515 break;
516 default:
517 SkASSERT(false);
518 }
519 }
520
521 if (NULL != canvas) {
522 canvas->clear(SK_ColorWHITE);
523 if (FLAGS_clip) { performClip(canvas, dim.fX, dim.fY); }
524 if (FLAGS_scale) { performScale(canvas, dim.fX, dim.fY); }
525 if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); }
526 }
527
528 if (!loggedBenchName) {
529 loggedBenchName = true;
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000530 writer.bench(bench->getName(), dim.fX, dim.fY);
mtklein@google.comc2897432013-09-10 19:23:38 +0000531 }
532
533#if SK_SUPPORT_GPU
534 SkGLContextHelper* contextHelper = NULL;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000535 if (SkBenchmark::kGPU_Backend == config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000536 contextHelper = gContextFactory.getGLContext(config.contextType);
537 }
538 BenchTimer timer(contextHelper);
539#else
540 BenchTimer timer;
541#endif
542
mtklein@google.com9ef1d212013-09-13 20:39:50 +0000543 double previous = std::numeric_limits<double>::infinity();
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000544 bool converged = false;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000545
546 // variables used to compute loopsPerFrame
547 double frameIntervalTime = 0.0f;
548 int frameIntervalTotalLoops = 0;
549
550 bool frameIntervalComputed = false;
551 int loopsPerFrame = 0;
552 int loopsPerIter = 0;
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000553 if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.name); }
mtklein@google.comc2897432013-09-10 19:23:38 +0000554 do {
djsollen@google.com70de4da2013-10-10 17:33:39 +0000555 // Ramp up 1 -> 2 -> 4 -> 8 -> 16 -> ... -> ~1 billion.
556 loopsPerIter = (loopsPerIter == 0) ? 1 : loopsPerIter * 2;
557 if (loopsPerIter >= (1<<30) || timer.fWall > FLAGS_maxMs) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000558 // If you find it takes more than a billion loops to get up to 20ms of runtime,
559 // you've got a computer clocked at several THz or have a broken benchmark. ;)
560 // "1B ought to be enough for anybody."
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000561 logger.logError(SkStringPrintf(
djsollen@google.com70de4da2013-10-10 17:33:39 +0000562 "\nCan't get %s %s to converge in %dms (%d loops)",
563 bench->getName(), config.name, FLAGS_maxMs, loopsPerIter));
mtklein@google.comc2897432013-09-10 19:23:38 +0000564 break;
565 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000566
567 if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) {
568 // Clear the recorded commands so that they do not accumulate.
commit-bot@chromium.org0f531222014-02-04 19:32:37 +0000569 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
junov@chromium.orgfb103892012-09-20 19:35:43 +0000570 }
robertphillips@google.com91ee3a12012-08-28 12:18:40 +0000571
mtklein@google.comc2897432013-09-10 19:23:38 +0000572 timer.start();
djsollen@google.com70de4da2013-10-10 17:33:39 +0000573 // Inner loop that allows us to break the run into smaller
574 // chunks (e.g. frames). This is especially useful for the GPU
575 // as we can flush and/or swap buffers to keep the GPU from
576 // queuing up too much work.
577 for (int loopCount = loopsPerIter; loopCount > 0; ) {
commit-bot@chromium.org28871192013-10-14 15:28:01 +0000578 // Save and restore around each call to draw() to guarantee a pristine canvas.
579 SkAutoCanvasRestore saveRestore(canvas, true/*also save*/);
580
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000581 int loops;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000582 if (frameIntervalComputed && loopCount > loopsPerFrame) {
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000583 loops = loopsPerFrame;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000584 loopCount -= loopsPerFrame;
585 } else {
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000586 loops = loopCount;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000587 loopCount = 0;
588 }
589
590 if (benchMode == kPictureRecord_BenchMode) {
591 recordFrom.draw(canvas);
592 } else {
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000593 bench->draw(loops, canvas);
djsollen@google.com70de4da2013-10-10 17:33:39 +0000594 }
595
596 if (kDeferredSilent_BenchMode == benchMode) {
597 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush();
598 } else if (NULL != canvas) {
599 canvas->flush();
600 }
601
602#if SK_SUPPORT_GPU
603 // swap drawing buffers on each frame to prevent the GPU
604 // from queuing up too much work
605 if (NULL != glContext) {
606 glContext->swapBuffers();
607 }
608#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000609 }
610
mtklein@google.comc2897432013-09-10 19:23:38 +0000611
612
613 // Stop truncated timers before GL calls complete, and stop the full timers after.
614 timer.truncatedEnd();
615#if SK_SUPPORT_GPU
616 if (NULL != glContext) {
617 context->flush();
618 SK_GL(*glContext, Finish());
619 }
620#endif
621 timer.end();
djsollen@google.com70de4da2013-10-10 17:33:39 +0000622
djsollen@google.comdcfed6c2013-10-10 18:48:27 +0000623 // setup the frame interval for subsequent iterations
624 if (!frameIntervalComputed) {
djsollen@google.com70de4da2013-10-10 17:33:39 +0000625 frameIntervalTime += timer.fWall;
626 frameIntervalTotalLoops += loopsPerIter;
627 if (frameIntervalTime >= FLAGS_minMs) {
628 frameIntervalComputed = true;
629 loopsPerFrame =
djsollen@google.com4e1d4b32013-10-10 17:50:52 +0000630 (int)(((double)frameIntervalTotalLoops / frameIntervalTime) * FLAGS_minMs);
djsollen@google.com70de4da2013-10-10 17:33:39 +0000631 if (loopsPerFrame < 1) {
632 loopsPerFrame = 1;
633 }
634// SkDebugf(" %s has %d loops in %f ms (normalized to %d)\n",
635// bench->getName(), frameIntervalTotalLoops,
636// timer.fWall, loopsPerFrame);
637 }
638 }
djsollen@google.comdcfed6c2013-10-10 18:48:27 +0000639
djsollen@google.com70de4da2013-10-10 17:33:39 +0000640 const double current = timer.fWall / loopsPerIter;
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000641 if (FLAGS_verbose && current > previous) { SkDebugf("↑"); }
642 if (FLAGS_verbose) { SkDebugf("%.3g ", current); }
643 converged = HasConverged(previous, current, timer.fWall);
644 previous = current;
645 } while (!kIsDebug && !converged);
646 if (FLAGS_verbose) { SkDebugf("\n"); }
mtklein@google.comc2897432013-09-10 19:23:38 +0000647
commit-bot@chromium.org644629c2013-11-21 06:21:58 +0000648 if (FLAGS_outDir.count() && SkBenchmark::kNonRendering_Backend != config.backend) {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000649 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
650 if (image.get()) {
651 saveFile(bench->getName(), config.name, FLAGS_outDir[0],
652 image);
653 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000654 }
655
656 if (kIsDebug) {
657 // Let's not mislead ourselves by looking at Debug build bench times!
658 continue;
659 }
660
661 // Normalize to ms per 1000 iterations.
djsollen@google.com70de4da2013-10-10 17:33:39 +0000662 const double normalize = 1000.0 / loopsPerIter;
mtklein@google.comc2897432013-09-10 19:23:38 +0000663 const struct { char shortName; const char* longName; double ms; } times[] = {
664 {'w', "msecs", normalize * timer.fWall},
665 {'W', "Wmsecs", normalize * timer.fTruncatedWall},
666 {'c', "cmsecs", normalize * timer.fCpu},
667 {'C', "Cmsecs", normalize * timer.fTruncatedCpu},
668 {'g', "gmsecs", normalize * timer.fGpu},
669 };
670
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000671 writer.config(config.name);
mtklein@google.comc2897432013-09-10 19:23:38 +0000672 for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) {
673 if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms > 0) {
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000674 writer.timer(times[i].longName, times[i].ms);
commit-bot@chromium.org7495f592013-06-03 19:31:07 +0000675 }
reed@google.com25df8882011-07-14 19:03:58 +0000676 }
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000677 }
reed@android.combd700c32009-01-05 03:34:50 +0000678 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000679#if SK_SUPPORT_GPU
bsalomon@google.comcb265352013-02-22 16:13:16 +0000680 gContextFactory.destroyContexts();
robertphillips@google.com9d594202012-09-13 14:05:00 +0000681#endif
reed@android.combd700c32009-01-05 03:34:50 +0000682 return 0;
683}
caryclark@google.com5987f582012-10-02 18:33:14 +0000684
borenet@google.com7158e6a2012-11-01 17:43:44 +0000685#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000686int main(int argc, char * const argv[]) {
687 return tool_main(argc, (char**) argv);
688}
689#endif