blob: 016ad2dff61a97d6ffec00fb8ad337e7a786b3b3 [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
tfarinaf168b862014-06-19 12:32:29 -07008#include "BenchLogger.h"
tfarinaf168b862014-06-19 12:32:29 -07009#include "Benchmark.h"
mtklein30e6e2a2014-06-18 11:44:15 -070010#include "CrashHandler.h"
tfarinaf168b862014-06-19 12:32:29 -070011#include "GMBench.h"
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000012#include "ResultsWriter.h"
robertphillips@google.com73672252013-08-29 12:40:26 +000013#include "SkBitmapDevice.h"
reed@android.combd700c32009-01-05 03:34:50 +000014#include "SkCanvas.h"
mtklein@google.com78d03792013-09-10 19:42:07 +000015#include "SkColorPriv.h"
sglez@google.com586db932013-07-24 17:24:23 +000016#include "SkCommandLineFlags.h"
reed@google.com1bc6c6a2014-02-04 14:02:44 +000017#include "SkData.h"
bsalomon@google.com82a7bfc2012-04-16 19:11:17 +000018#include "SkDeferredCanvas.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"
robertphillips@google.com770963f2014-04-18 18:04:41 +000023#include "SkPictureRecorder.h"
reed@android.combd700c32009-01-05 03:34:50 +000024#include "SkString.h"
reed@google.com1bc6c6a2014-02-04 14:02:44 +000025#include "SkSurface.h"
mtklein9ac68ee2014-06-20 11:29:20 -070026#include "Timer.h"
reed@android.com29348cb2009-08-04 18:17:15 +000027
djsollen@google.comdb490e92013-11-20 13:15:40 +000028#if SK_SUPPORT_GPU
29#include "GrContext.h"
30#include "GrContextFactory.h"
31#include "GrRenderTarget.h"
32#include "SkGpuDevice.h"
33#include "gl/GrGLDefines.h"
34#else
35class GrContext;
36#endif // SK_SUPPORT_GPU
37
mtklein@google.com9ef1d212013-09-13 20:39:50 +000038#include <limits>
39
mtklein@google.comc2897432013-09-10 19:23:38 +000040enum BenchMode {
41 kNormal_BenchMode,
42 kDeferred_BenchMode,
43 kDeferredSilent_BenchMode,
44 kRecord_BenchMode,
45 kPictureRecord_BenchMode
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000046};
mtklein@google.comdbd41c82013-09-13 20:11:09 +000047const char* BenchMode_Name[] = {
48 "normal", "deferred", "deferredSilent", "record", "picturerecord"
49};
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000050
borenet@google.com4e061d32013-09-16 19:12:19 +000051static const char kDefaultsConfigStr[] = "defaults";
52
kkinnunen74fc7272014-06-22 22:56:53 -070053#if SK_SUPPORT_GPU
54static const char kGpuAPINameGL[] = "gl";
55static const char kGpuAPINameGLES[] = "gles";
56#endif
57
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +000058///////////////////////////////////////////////////////////////////////////////
59
reed@android.combd700c32009-01-05 03:34:50 +000060class Iter {
61public:
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000062 Iter() : fBenches(BenchRegistry::Head()), fGMs(skiagm::GMRegistry::Head()) {}
rmistry@google.comfbfcd562012-08-23 18:09:54 +000063
tfarinaf168b862014-06-19 12:32:29 -070064 Benchmark* next() {
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000065 if (fBenches) {
66 BenchRegistry::Factory f = fBenches->factory();
67 fBenches = fBenches->next();
commit-bot@chromium.org38aeb0f2014-02-26 23:01:57 +000068 return (*f)(NULL);
reed@android.combd700c32009-01-05 03:34:50 +000069 }
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000070
71 while (fGMs) {
72 SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL));
73 fGMs = fGMs->next();
74 if (gm->getFlags() & skiagm::GM::kAsBench_Flag) {
tfarinaf168b862014-06-19 12:32:29 -070075 return SkNEW_ARGS(GMBench, (gm.detach()));
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000076 }
77 }
78
reed@android.combd700c32009-01-05 03:34:50 +000079 return NULL;
80 }
bungeman@google.comd1a416a2011-05-18 18:37:07 +000081
reed@android.combd700c32009-01-05 03:34:50 +000082private:
commit-bot@chromium.org575d9cd2014-02-24 23:25:49 +000083 const BenchRegistry* fBenches;
84 const skiagm::GMRegistry* fGMs;
reed@android.combd700c32009-01-05 03:34:50 +000085};
86
87static void make_filename(const char name[], SkString* path) {
88 path->set(name);
89 for (int i = 0; name[i]; i++) {
90 switch (name[i]) {
91 case '/':
92 case '\\':
93 case ' ':
94 case ':':
95 path->writable_str()[i] = '-';
96 break;
97 default:
98 break;
99 }
100 }
101}
102
reed@android.com4c7d3d62009-01-21 03:15:13 +0000103static void saveFile(const char name[], const char config[], const char dir[],
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000104 const SkImage* image) {
105 SkAutoTUnref<SkData> data(image->encode(SkImageEncoder::kPNG_Type, 100));
106 if (NULL == data.get()) {
reed@android.com4c7d3d62009-01-21 03:15:13 +0000107 return;
108 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000109
mtklein@google.comc2897432013-09-10 19:23:38 +0000110 SkString filename;
111 make_filename(name, &filename);
112 filename.appendf("_%s.png", config);
113 SkString path = SkOSPath::SkPathJoin(dir, filename.c_str());
114 ::remove(path.c_str());
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000115
reed@google.comace13542014-02-06 22:00:58 +0000116 SkFILEWStream stream(path.c_str());
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000117 stream.write(data->data(), data->size());
reed@android.com4c7d3d62009-01-21 03:15:13 +0000118}
119
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000120static void perform_clip(SkCanvas* canvas, int w, int h) {
reed@android.com4c7d3d62009-01-21 03:15:13 +0000121 SkRect r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000122
reed@android.com4c7d3d62009-01-21 03:15:13 +0000123 r.set(SkIntToScalar(10), SkIntToScalar(10),
124 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3));
125 canvas->clipRect(r, SkRegion::kIntersect_Op);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000126
reed@android.com4c7d3d62009-01-21 03:15:13 +0000127 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3),
128 SkIntToScalar(w-10), SkIntToScalar(h-10));
129 canvas->clipRect(r, SkRegion::kXOR_Op);
130}
131
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000132static void perform_rotate(SkCanvas* canvas, int w, int h) {
reed@android.com4c7d3d62009-01-21 03:15:13 +0000133 const SkScalar x = SkIntToScalar(w) / 2;
134 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000135
reed@android.com4c7d3d62009-01-21 03:15:13 +0000136 canvas->translate(x, y);
137 canvas->rotate(SkIntToScalar(35));
138 canvas->translate(-x, -y);
139}
140
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000141static void perform_scale(SkCanvas* canvas, int w, int h) {
reed@android.com387359e2009-08-04 01:51:09 +0000142 const SkScalar x = SkIntToScalar(w) / 2;
143 const SkScalar y = SkIntToScalar(h) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000144
reed@android.com387359e2009-08-04 01:51:09 +0000145 canvas->translate(x, y);
146 // just enough so we can't take the sprite case
147 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
148 canvas->translate(-x, -y);
149}
150
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000151static SkSurface* make_surface(SkColorType colorType, const SkIPoint& size,
tfarinaf168b862014-06-19 12:32:29 -0700152 Benchmark::Backend backend, int sampleCount,
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000153 GrContext* context) {
154 SkSurface* surface = NULL;
155 SkImageInfo info = SkImageInfo::Make(size.fX, size.fY, colorType,
156 kPremul_SkAlphaType);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000157
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000158 switch (backend) {
tfarinaf168b862014-06-19 12:32:29 -0700159 case Benchmark::kRaster_Backend:
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000160 surface = SkSurface::NewRaster(info);
161 surface->getCanvas()->clear(SK_ColorWHITE);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000162 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000163#if SK_SUPPORT_GPU
tfarinaf168b862014-06-19 12:32:29 -0700164 case Benchmark::kGPU_Backend: {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000165 surface = SkSurface::NewRenderTarget(context, info, sampleCount);
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000166 break;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000167 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000168#endif
tfarinaf168b862014-06-19 12:32:29 -0700169 case Benchmark::kPDF_Backend:
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000170 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000171 SkDEBUGFAIL("unsupported");
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000172 }
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000173 return surface;
mike@reedtribe.orga9015f82011-05-17 02:25:05 +0000174}
175
bsalomon@google.comcb265352013-02-22 16:13:16 +0000176#if SK_SUPPORT_GPU
177GrContextFactory gContextFactory;
178typedef GrContextFactory::GLContextType GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000179static const GLContextType kNative = GrContextFactory::kNative_GLContextType;
commit-bot@chromium.orge8989572014-01-26 20:51:00 +0000180static const GLContextType kNVPR = GrContextFactory::kNVPR_GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000181#if SK_ANGLE
182static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000183#endif
184static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType;
185static const GLContextType kNull = GrContextFactory::kNull_GLContextType;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000186#else
187typedef int GLContextType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000188static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000189#endif
190
mtklein@google.comc2897432013-09-10 19:23:38 +0000191#ifdef SK_DEBUG
192static const bool kIsDebug = true;
193#else
194static const bool kIsDebug = false;
195#endif
196
197static const struct Config {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000198 SkColorType fColorType;
mtklein@google.comc2897432013-09-10 19:23:38 +0000199 const char* name;
200 int sampleCount;
tfarinaf168b862014-06-19 12:32:29 -0700201 Benchmark::Backend backend;
mtklein@google.comc2897432013-09-10 19:23:38 +0000202 GLContextType contextType;
203 bool runByDefault;
reed@android.com4bc19832009-01-19 20:08:35 +0000204} gConfigs[] = {
tfarinaf168b862014-06-19 12:32:29 -0700205 { kN32_SkColorType, "NONRENDERING", 0, Benchmark::kNonRendering_Backend, kNative, true},
206 { kN32_SkColorType, "8888", 0, Benchmark::kRaster_Backend, kNative, true},
207 { kRGB_565_SkColorType, "565", 0, Benchmark::kRaster_Backend, kNative, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000208#if SK_SUPPORT_GPU
tfarinaf168b862014-06-19 12:32:29 -0700209 { kN32_SkColorType, "GPU", 0, Benchmark::kGPU_Backend, kNative, true},
210 { kN32_SkColorType, "MSAA4", 4, Benchmark::kGPU_Backend, kNative, false},
211 { kN32_SkColorType, "MSAA16", 16, Benchmark::kGPU_Backend, kNative, false},
212 { kN32_SkColorType, "NVPRMSAA4", 4, Benchmark::kGPU_Backend, kNVPR, true},
213 { kN32_SkColorType, "NVPRMSAA16", 16, Benchmark::kGPU_Backend, kNVPR, false},
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000214#if SK_ANGLE
tfarinaf168b862014-06-19 12:32:29 -0700215 { kN32_SkColorType, "ANGLE", 0, Benchmark::kGPU_Backend, kANGLE, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000216#endif // SK_ANGLE
tfarinaf168b862014-06-19 12:32:29 -0700217 { kN32_SkColorType, "Debug", 0, Benchmark::kGPU_Backend, kDebug, kIsDebug},
218 { kN32_SkColorType, "NULLGPU", 0, Benchmark::kGPU_Backend, kNull, true},
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000219#endif // SK_SUPPORT_GPU
reed@android.com4bc19832009-01-19 20:08:35 +0000220};
221
mtklein@google.comc2897432013-09-10 19:23:38 +0000222DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir.");
223DEFINE_string(timers, "cg", "Timers to display. "
224 "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)");
reed@android.com4c7d3d62009-01-21 03:15:13 +0000225
mtklein@google.comc2897432013-09-10 19:23:38 +0000226DEFINE_bool(rotate, false, "Rotate canvas before bench run?");
227DEFINE_bool(scale, false, "Scale canvas before bench run?");
228DEFINE_bool(clip, false, "Clip canvas before bench run?");
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000229
mtklein@google.comc2897432013-09-10 19:23:38 +0000230DEFINE_bool(forceAA, true, "Force anti-aliasing?");
231DEFINE_bool(forceFilter, false, "Force bitmap filtering?");
232DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?");
233DEFINE_bool(forceBlend, false, "Force alpha blending?");
234
kkinnunen74fc7272014-06-22 22:56:53 -0700235DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" "
236 "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
237 "Defaults to empty string, which selects the API native to the "
238 "system.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000239DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable cache.");
240DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to disable cache.");
241
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +0000242DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000243DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n"
244 "Multiple matches may be separated by spaces.\n"
245 "~ causes a matching test to always be skipped\n"
246 "^ requires the start of the test to match\n"
247 "$ requires the end of the test to match\n"
248 "^ and $ requires an exact match\n"
249 "If a test does not match any list entry,\n"
250 "it is skipped unless some list entry starts with ~\n");
251DEFINE_string(mode, "normal",
252 "normal: draw to a normal canvas;\n"
253 "deferred: draw to a deferred canvas;\n"
254 "deferredSilent: deferred with silent playback;\n"
255 "record: draw to an SkPicture;\n"
256 "picturerecord: draw from an SkPicture to an SkPicture.\n");
borenet@google.com4e061d32013-09-16 19:12:19 +0000257DEFINE_string(config, kDefaultsConfigStr,
258 "Run configs given. By default, runs the configs marked \"runByDefault\" in gConfigs.");
mtklein@google.comc2897432013-09-10 19:23:38 +0000259DEFINE_string(logFile, "", "Also write stdout here.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000260DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run.");
261DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run.");
commit-bot@chromium.org4bbe2e52014-04-21 21:12:32 +0000262DEFINE_bool(runOnce, kIsDebug, "Run each bench exactly once and don't report timings.");
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000263DEFINE_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.");
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000267DEFINE_string(outResultsFile, "", "If given, the results will be written to the file in JSON format.");
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000268DEFINE_bool(dryRun, false, "Don't actually run the tests, just print what would have been done.");
269
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000270// 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) {
mtklein30e6e2a2014-06-18 11:44:15 -0700283 SetupCrashHandler();
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +0000284 SkCommandLineFlags::Parse(argc, argv);
bsalomon@google.com4e230682013-01-15 20:37:04 +0000285#if SK_ENABLE_INST_COUNT
commit-bot@chromium.org6dda8272014-01-23 17:21:19 +0000286 if (FLAGS_leaks) {
287 gPrintInstCount = true;
288 }
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000289#endif
reed@android.com3a859a02009-01-28 00:56:29 +0000290 SkAutoGraphics ag;
bsalomon@google.com65a87cc2012-08-14 13:15:44 +0000291
mtklein@google.comc2897432013-09-10 19:23:38 +0000292 // First, parse some flags.
tfarinaf168b862014-06-19 12:32:29 -0700293 BenchLogger logger;
mtklein@google.comc2897432013-09-10 19:23:38 +0000294 if (FLAGS_logFile.count()) {
295 logger.SetLogFile(FLAGS_logFile[0]);
296 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000297
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000298 LoggerResultsWriter logWriter(logger, FLAGS_timeFormat[0]);
299 MultiResultsWriter writer;
300 writer.add(&logWriter);
commit-bot@chromium.org61744ec2014-05-16 13:15:41 +0000301
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000302 SkAutoTDelete<JSONResultsWriter> jsonWriter;
303 if (FLAGS_outResultsFile.count()) {
304 jsonWriter.reset(SkNEW(JSONResultsWriter(FLAGS_outResultsFile[0])));
305 writer.add(jsonWriter.get());
306 }
commit-bot@chromium.org61744ec2014-05-16 13:15:41 +0000307
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000308 // Instantiate after all the writers have been added to writer so that we
309 // call close() before their destructors are called on the way out.
310 CallEnd<MultiResultsWriter> ender(writer);
311
mtklein@google.comc2897432013-09-10 19:23:38 +0000312 const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF;
313 SkTriState::State dither = SkTriState::kDefault;
314 for (size_t i = 0; i < 3; i++) {
315 if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) {
316 dither = static_cast<SkTriState::State>(i);
reed@android.comb398fe82009-01-07 11:47:57 +0000317 }
318 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000319
320 BenchMode benchMode = kNormal_BenchMode;
321 for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) {
322 if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) {
323 benchMode = static_cast<BenchMode>(i);
324 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000325 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000326
327 SkTDArray<int> configs;
borenet@google.com4e061d32013-09-16 19:12:19 +0000328 bool runDefaultConfigs = false;
mtklein@google.comc2897432013-09-10 19:23:38 +0000329 // Try user-given configs first.
330 for (int i = 0; i < FLAGS_config.count(); i++) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000331 for (int j = 0; j < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++j) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000332 if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) {
333 *configs.append() = j;
borenet@google.com4e061d32013-09-16 19:12:19 +0000334 } else if (0 == strcmp(FLAGS_config[i], kDefaultsConfigStr)) {
335 runDefaultConfigs = true;
mtklein@google.comc2897432013-09-10 19:23:38 +0000336 }
337 }
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000338 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000339 // If there weren't any, fill in with defaults.
borenet@google.com4e061d32013-09-16 19:12:19 +0000340 if (runDefaultConfigs) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000341 for (int i = 0; i < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000342 if (gConfigs[i].runByDefault) {
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000343 *configs.append() = i;
344 }
tomhudson@google.com13eaaaa2012-04-16 18:00:40 +0000345 }
346 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000347 // Filter out things we can't run.
348 if (kNormal_BenchMode != benchMode) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000349 // Non-rendering configs only run in normal mode
350 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000351 const Config& config = gConfigs[configs[i]];
tfarinaf168b862014-06-19 12:32:29 -0700352 if (Benchmark::kNonRendering_Backend == config.backend) {
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000353 configs.remove(i, 1);
354 --i;
355 }
356 }
357 }
scroggo@google.com111fd112013-09-25 21:42:12 +0000358
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000359#if SK_SUPPORT_GPU
kkinnunen74fc7272014-06-22 22:56:53 -0700360 GrGLStandard gpuAPI = kNone_GrGLStandard;
361 if (1 == FLAGS_gpuAPI.count()) {
362 if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
363 gpuAPI = kGL_GrGLStandard;
364 } else if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
365 gpuAPI = kGLES_GrGLStandard;
366 } else {
367 SkDebugf("Selected gpu API could not be used. Using the default.\n");
368 }
369 } else if (FLAGS_gpuAPI.count() > 1) {
370 SkDebugf("Selected gpu API could not be used. Using the default.\n");
371 }
372
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000373 for (int i = 0; i < configs.count(); ++i) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000374 const Config& config = gConfigs[configs[i]];
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000375
tfarinaf168b862014-06-19 12:32:29 -0700376 if (Benchmark::kGPU_Backend == config.backend) {
kkinnunen74fc7272014-06-22 22:56:53 -0700377 GrContext* context = gContextFactory.get(config.contextType, gpuAPI);
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000378 if (NULL == context) {
commit-bot@chromium.org0f298cc2014-04-30 15:54:29 +0000379 SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n",
380 config.name);
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000381 configs.remove(i);
382 --i;
383 continue;
384 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000385 if (config.sampleCount > context->getMaxSampleCount()){
commit-bot@chromium.org0f298cc2014-04-30 15:54:29 +0000386 SkDebugf(
387 "Sample count (%d) for config %s is not supported. Config will be skipped.\n",
388 config.sampleCount, config.name);
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000389 configs.remove(i);
390 --i;
391 continue;
392 }
393 }
394 }
395#endif
396
mtklein@google.comc2897432013-09-10 19:23:38 +0000397 // All flags should be parsed now. Report our settings.
commit-bot@chromium.org4bbe2e52014-04-21 21:12:32 +0000398 if (FLAGS_runOnce) {
399 logger.logError("bench was run with --runOnce, so we're going to hide the times."
400 " It's for your own good!\n");
mtklein@google.comc2897432013-09-10 19:23:38 +0000401 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000402 writer.option("mode", FLAGS_mode[0]);
403 writer.option("alpha", SkStringPrintf("0x%02X", alpha).c_str());
404 writer.option("antialias", SkStringPrintf("%d", FLAGS_forceAA).c_str());
405 writer.option("filter", SkStringPrintf("%d", FLAGS_forceFilter).c_str());
406 writer.option("dither", SkTriState::Name[dither]);
407
408 writer.option("rotate", SkStringPrintf("%d", FLAGS_rotate).c_str());
409 writer.option("scale", SkStringPrintf("%d", FLAGS_scale).c_str());
410 writer.option("clip", SkStringPrintf("%d", FLAGS_clip).c_str());
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000411
bungeman@google.coma5d48412011-06-15 17:25:46 +0000412#if defined(SK_BUILD_FOR_WIN32)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000413 writer.option("system", "WIN32");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000414#elif defined(SK_BUILD_FOR_MAC)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000415 writer.option("system", "MAC");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000416#elif defined(SK_BUILD_FOR_ANDROID)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000417 writer.option("system", "ANDROID");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000418#elif defined(SK_BUILD_FOR_UNIX)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000419 writer.option("system", "UNIX");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000420#else
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000421 writer.option("system", "other");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000422#endif
423
424#if defined(SK_DEBUG)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000425 writer.option("build", "DEBUG");
426#else
427 writer.option("build", "RELEASE");
bungeman@google.coma5d48412011-06-15 17:25:46 +0000428#endif
mtklein@google.comc2897432013-09-10 19:23:38 +0000429
430 // Set texture cache limits if non-default.
bsalomon@google.com5c90e292013-02-22 19:17:13 +0000431 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) {
bsalomon@google.comcb265352013-02-22 16:13:16 +0000432#if SK_SUPPORT_GPU
mtklein@google.comc2897432013-09-10 19:23:38 +0000433 const Config& config = gConfigs[i];
tfarinaf168b862014-06-19 12:32:29 -0700434 if (Benchmark::kGPU_Backend != config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000435 continue;
bsalomon@google.comcb265352013-02-22 16:13:16 +0000436 }
kkinnunen74fc7272014-06-22 22:56:53 -0700437 GrContext* context = gContextFactory.get(config.contextType, gpuAPI);
mtklein@google.comc2897432013-09-10 19:23:38 +0000438 if (NULL == context) {
439 continue;
440 }
441
442 size_t bytes;
443 int count;
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000444 context->getResourceCacheLimits(&count, &bytes);
mtklein@google.comc2897432013-09-10 19:23:38 +0000445 if (-1 != FLAGS_gpuCacheBytes) {
446 bytes = static_cast<size_t>(FLAGS_gpuCacheBytes);
447 }
448 if (-1 != FLAGS_gpuCacheCount) {
449 count = FLAGS_gpuCacheCount;
450 }
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000451 context->setResourceCacheLimits(count, bytes);
bsalomon@google.comcb265352013-02-22 16:13:16 +0000452#endif
453 }
bsalomon@google.com74913722011-10-27 20:44:19 +0000454
mtklein@google.comc2897432013-09-10 19:23:38 +0000455 // Run each bench in each configuration it supports and we asked for.
456 Iter iter;
tfarinaf168b862014-06-19 12:32:29 -0700457 Benchmark* bench;
reed@android.combd700c32009-01-05 03:34:50 +0000458 while ((bench = iter.next()) != NULL) {
tfarinaf168b862014-06-19 12:32:29 -0700459 SkAutoTUnref<Benchmark> 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);
mtklein683e9062014-06-18 07:15:48 -0700468 bench->preDraw();
bsalomon@google.com30e6d2c2012-08-13 14:03:31 +0000469
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;
tfarinaf168b862014-06-19 12:32:29 -0700482 if (Benchmark::kGPU_Backend == config.backend) {
kkinnunen74fc7272014-06-22 22:56:53 -0700483 context = gContextFactory.get(config.contextType, gpuAPI);
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
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000490
mtklein@google.comc2897432013-09-10 19:23:38 +0000491 SkAutoTUnref<SkCanvas> canvas;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000492 SkAutoTUnref<SkPicture> recordFrom;
493 SkPictureRecorder recorderTo;
mtklein@google.comc2897432013-09-10 19:23:38 +0000494 const SkIPoint dim = bench->getSize();
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000495
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000496 SkAutoTUnref<SkSurface> surface;
tfarinaf168b862014-06-19 12:32:29 -0700497 if (Benchmark::kNonRendering_Backend != config.backend) {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000498 surface.reset(make_surface(config.fColorType,
499 dim,
500 config.backend,
501 config.sampleCount,
502 context));
503 if (!surface.get()) {
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000504 logger.logError(SkStringPrintf(
505 "Device creation failure for config %s. Will skip.\n", config.name));
mtklein@google.comc2897432013-09-10 19:23:38 +0000506 continue;
keyar@chromium.orgfdd909c2012-07-20 23:03:42 +0000507 }
junov@chromium.orgfb103892012-09-20 19:35:43 +0000508
mtklein@google.comc2897432013-09-10 19:23:38 +0000509 switch(benchMode) {
510 case kDeferredSilent_BenchMode:
511 case kDeferred_BenchMode:
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000512 canvas.reset(SkDeferredCanvas::Create(surface.get()));
mtklein@google.comc2897432013-09-10 19:23:38 +0000513 break;
514 case kRecord_BenchMode:
robertphillips9f1c2412014-06-09 06:25:34 -0700515 canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY)));
mtklein@google.comc2897432013-09-10 19:23:38 +0000516 break;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000517 case kPictureRecord_BenchMode: {
518 SkPictureRecorder recorderFrom;
robertphillips9f1c2412014-06-09 06:25:34 -0700519 bench->draw(1, recorderFrom.beginRecording(dim.fX, dim.fY));
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000520 recordFrom.reset(recorderFrom.endRecording());
robertphillips9f1c2412014-06-09 06:25:34 -0700521 canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY)));
mtklein@google.comc2897432013-09-10 19:23:38 +0000522 break;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000523 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000524 case kNormal_BenchMode:
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000525 canvas.reset(SkRef(surface->getCanvas()));
mtklein@google.comc2897432013-09-10 19:23:38 +0000526 break;
527 default:
528 SkASSERT(false);
529 }
530 }
531
532 if (NULL != canvas) {
533 canvas->clear(SK_ColorWHITE);
skia.committer@gmail.com51997012014-04-14 03:04:57 +0000534 if (FLAGS_clip) {
535 perform_clip(canvas, dim.fX, dim.fY);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000536 }
skia.committer@gmail.com51997012014-04-14 03:04:57 +0000537 if (FLAGS_scale) {
538 perform_scale(canvas, dim.fX, dim.fY);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000539 }
skia.committer@gmail.com51997012014-04-14 03:04:57 +0000540 if (FLAGS_rotate) {
541 perform_rotate(canvas, dim.fX, dim.fY);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000542 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000543 }
544
545 if (!loggedBenchName) {
546 loggedBenchName = true;
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000547 writer.bench(bench->getName(), dim.fX, dim.fY);
mtklein@google.comc2897432013-09-10 19:23:38 +0000548 }
549
550#if SK_SUPPORT_GPU
551 SkGLContextHelper* contextHelper = NULL;
tfarinaf168b862014-06-19 12:32:29 -0700552 if (Benchmark::kGPU_Backend == config.backend) {
mtklein@google.comc2897432013-09-10 19:23:38 +0000553 contextHelper = gContextFactory.getGLContext(config.contextType);
554 }
mtklein9ac68ee2014-06-20 11:29:20 -0700555 Timer timer(contextHelper);
mtklein@google.comc2897432013-09-10 19:23:38 +0000556#else
mtklein9ac68ee2014-06-20 11:29:20 -0700557 Timer timer;
mtklein@google.comc2897432013-09-10 19:23:38 +0000558#endif
559
mtklein@google.com9ef1d212013-09-13 20:39:50 +0000560 double previous = std::numeric_limits<double>::infinity();
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000561 bool converged = false;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000562
563 // variables used to compute loopsPerFrame
564 double frameIntervalTime = 0.0f;
565 int frameIntervalTotalLoops = 0;
566
567 bool frameIntervalComputed = false;
568 int loopsPerFrame = 0;
569 int loopsPerIter = 0;
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000570 if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.name); }
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000571 if (!FLAGS_dryRun) {
572 do {
573 // Ramp up 1 -> 2 -> 4 -> 8 -> 16 -> ... -> ~1 billion.
574 loopsPerIter = (loopsPerIter == 0) ? 1 : loopsPerIter * 2;
575 if (loopsPerIter >= (1<<30) || timer.fWall > FLAGS_maxMs) {
576 // If you find it takes more than a billion loops to get up to 20ms of runtime,
577 // you've got a computer clocked at several THz or have a broken benchmark. ;)
578 // "1B ought to be enough for anybody."
579 logger.logError(SkStringPrintf(
580 "\nCan't get %s %s to converge in %dms (%d loops)",
581 bench->getName(), config.name, FLAGS_maxMs, loopsPerIter));
582 break;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000583 }
584
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000585 if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) {
586 // Clear the recorded commands so that they do not accumulate.
robertphillips9f1c2412014-06-09 06:25:34 -0700587 canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY)));
djsollen@google.com70de4da2013-10-10 17:33:39 +0000588 }
589
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000590 timer.start();
591 // Inner loop that allows us to break the run into smaller
592 // chunks (e.g. frames). This is especially useful for the GPU
593 // as we can flush and/or swap buffers to keep the GPU from
594 // queuing up too much work.
595 for (int loopCount = loopsPerIter; loopCount > 0; ) {
596 // Save and restore around each call to draw() to guarantee a pristine canvas.
597 SkAutoCanvasRestore saveRestore(canvas, true/*also save*/);
djsollen@google.com70de4da2013-10-10 17:33:39 +0000598
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000599 int loops;
600 if (frameIntervalComputed && loopCount > loopsPerFrame) {
601 loops = loopsPerFrame;
602 loopCount -= loopsPerFrame;
603 } else {
604 loops = loopCount;
605 loopCount = 0;
djsollen@google.com70de4da2013-10-10 17:33:39 +0000606 }
djsollen@google.comdcfed6c2013-10-10 18:48:27 +0000607
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000608 if (benchMode == kPictureRecord_BenchMode) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000609 recordFrom->draw(canvas);
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000610 } else {
611 bench->draw(loops, canvas);
612 }
613
614 if (kDeferredSilent_BenchMode == benchMode) {
615 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush();
616 } else if (NULL != canvas) {
617 canvas->flush();
618 }
619
620 #if SK_SUPPORT_GPU
621 // swap drawing buffers on each frame to prevent the GPU
622 // from queuing up too much work
623 if (NULL != glContext) {
624 glContext->swapBuffers();
625 }
626 #endif
627 }
628
629
630
631 // Stop truncated timers before GL calls complete, and stop the full timers after.
632 timer.truncatedEnd();
633 #if SK_SUPPORT_GPU
634 if (NULL != glContext) {
635 context->flush();
636 SK_GL(*glContext, Finish());
637 }
638 #endif
639 timer.end();
640
641 // setup the frame interval for subsequent iterations
642 if (!frameIntervalComputed) {
643 frameIntervalTime += timer.fWall;
644 frameIntervalTotalLoops += loopsPerIter;
645 if (frameIntervalTime >= FLAGS_minMs) {
646 frameIntervalComputed = true;
647 loopsPerFrame =
648 (int)(((double)frameIntervalTotalLoops / frameIntervalTime) * FLAGS_minMs);
649 if (loopsPerFrame < 1) {
650 loopsPerFrame = 1;
651 }
652 // SkDebugf(" %s has %d loops in %f ms (normalized to %d)\n",
653 // bench->getName(), frameIntervalTotalLoops,
654 // timer.fWall, loopsPerFrame);
655 }
656 }
657
658 const double current = timer.fWall / loopsPerIter;
659 if (FLAGS_verbose && current > previous) { SkDebugf("↑"); }
660 if (FLAGS_verbose) { SkDebugf("%.3g ", current); }
661 converged = HasConverged(previous, current, timer.fWall);
662 previous = current;
commit-bot@chromium.org4bbe2e52014-04-21 21:12:32 +0000663 } while (!FLAGS_runOnce && !converged);
commit-bot@chromium.org56b7a6d2014-03-13 16:22:00 +0000664 }
mtklein@google.comdbd41c82013-09-13 20:11:09 +0000665 if (FLAGS_verbose) { SkDebugf("\n"); }
mtklein@google.comc2897432013-09-10 19:23:38 +0000666
tfarinaf168b862014-06-19 12:32:29 -0700667 if (!FLAGS_dryRun && FLAGS_outDir.count() && Benchmark::kNonRendering_Backend != config.backend) {
reed@google.com1bc6c6a2014-02-04 14:02:44 +0000668 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
669 if (image.get()) {
670 saveFile(bench->getName(), config.name, FLAGS_outDir[0],
671 image);
672 }
mtklein@google.comc2897432013-09-10 19:23:38 +0000673 }
674
commit-bot@chromium.org4bbe2e52014-04-21 21:12:32 +0000675 if (FLAGS_runOnce) {
676 // Let's not mislead ourselves by looking at Debug build or single iteration bench times!
mtklein@google.comc2897432013-09-10 19:23:38 +0000677 continue;
678 }
679
680 // Normalize to ms per 1000 iterations.
djsollen@google.com70de4da2013-10-10 17:33:39 +0000681 const double normalize = 1000.0 / loopsPerIter;
mtklein@google.comc2897432013-09-10 19:23:38 +0000682 const struct { char shortName; const char* longName; double ms; } times[] = {
683 {'w', "msecs", normalize * timer.fWall},
684 {'W', "Wmsecs", normalize * timer.fTruncatedWall},
685 {'c', "cmsecs", normalize * timer.fCpu},
686 {'C', "Cmsecs", normalize * timer.fTruncatedCpu},
687 {'g', "gmsecs", normalize * timer.fGpu},
688 };
689
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000690 writer.config(config.name);
mtklein@google.comc2897432013-09-10 19:23:38 +0000691 for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) {
692 if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms > 0) {
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000693 writer.timer(times[i].longName, times[i].ms);
commit-bot@chromium.org7495f592013-06-03 19:31:07 +0000694 }
reed@google.com25df8882011-07-14 19:03:58 +0000695 }
bsalomon@google.com604a56a2013-03-15 15:42:15 +0000696 }
reed@android.combd700c32009-01-05 03:34:50 +0000697 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000698#if SK_SUPPORT_GPU
bsalomon@google.comcb265352013-02-22 16:13:16 +0000699 gContextFactory.destroyContexts();
robertphillips@google.com9d594202012-09-13 14:05:00 +0000700#endif
reed@android.combd700c32009-01-05 03:34:50 +0000701 return 0;
702}
caryclark@google.com5987f582012-10-02 18:33:14 +0000703
borenet@google.com7158e6a2012-11-01 17:43:44 +0000704#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +0000705int main(int argc, char * const argv[]) {
706 return tool_main(argc, (char**) argv);
707}
708#endif