OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | |
10 #include "BenchTimer.h" | |
11 | |
12 #if SK_SUPPORT_GPU | 9 #if SK_SUPPORT_GPU |
13 #include "GrContext.h" | 10 #include "GrContext.h" |
14 #include "GrContextFactory.h" | 11 #include "GrContextFactory.h" |
15 #include "gl/GrGLDefines.h" | |
16 #include "GrRenderTarget.h" | 12 #include "GrRenderTarget.h" |
17 #include "SkGpuDevice.h" | 13 #include "SkGpuDevice.h" |
14 #include "gl/GrGLDefines.h" | |
18 #else | 15 #else |
19 class GrContext; | 16 class GrContext; |
20 #endif // SK_SUPPORT_GPU | 17 #endif // SK_SUPPORT_GPU |
21 | 18 |
19 #include "BenchTimer.h" | |
22 #include "SkBenchLogger.h" | 20 #include "SkBenchLogger.h" |
23 #include "SkBenchmark.h" | 21 #include "SkBenchmark.h" |
24 #include "SkBitmapDevice.h" | 22 #include "SkBitmapDevice.h" |
25 #include "SkCanvas.h" | 23 #include "SkCanvas.h" |
26 #include "SkCommandLineFlags.h" | 24 #include "SkCommandLineFlags.h" |
27 #include "SkDeferredCanvas.h" | 25 #include "SkDeferredCanvas.h" |
28 #include "SkColorPriv.h" | |
29 #include "SkGraphics.h" | 26 #include "SkGraphics.h" |
30 #include "SkImageEncoder.h" | 27 #include "SkImageEncoder.h" |
31 #include "SkNWayCanvas.h" | |
32 #include "SkPicture.h" | 28 #include "SkPicture.h" |
33 #include "SkString.h" | 29 #include "SkString.h" |
34 #include "SkTArray.h" | |
35 #include "TimerData.h" | |
36 | 30 |
37 enum benchModes { | 31 enum BenchMode { |
scroggo
2013/09/03 19:36:43
Officially I think we're supposed to make the enum
mtklein
2013/09/03 20:04:43
Updated the style guide so that BenchMode and Back
| |
38 kNormal_benchModes, | 32 kNormal_BenchMode, |
39 kDeferred_benchModes, | 33 kDeferred_BenchMode, |
40 kDeferredSilent_benchModes, | 34 kDeferredSilent_BenchMode, |
41 kRecord_benchModes, | 35 kRecord_BenchMode, |
42 kPictureRecord_benchModes | 36 kPictureRecord_BenchMode |
43 }; | 37 }; |
38 const char* BenchMode_Name[] = { "normal", "deferred", "deferredSilent", "record ", "picturerecord" }; | |
44 | 39 |
45 #ifdef SK_DEBUG | 40 enum TimerType { |
scroggo
2013/09/03 19:36:43
Would be nice to consolidate this with bench_pictu
mtklein
2013/09/03 20:04:43
I was thinking maybe I'd go whole-hog and follow u
scroggo
2013/09/03 20:13:53
+1
| |
46 static const bool kDebugOnly = true; | 41 kWall_TimerType, |
47 #else | 42 kTruncWall_TimerType, |
48 static const bool kDebugOnly = false; | 43 kCpu_TimerType, |
49 #endif | 44 kTruncCpu_TimerType, |
45 kGpu_TimerType, | |
46 }; | |
47 const char TimerType_Short[] = { 'w', 'W', 'c', 'C', 'g' }; | |
48 const char* TimerType_Name[] = { "msecs", "Wmsecs", "cmsecs", "Cmsecs", "gmsecs" }; | |
50 | 49 |
51 /////////////////////////////////////////////////////////////////////////////// | 50 /////////////////////////////////////////////////////////////////////////////// |
52 | 51 |
53 static void erase(SkBitmap& bm) { | 52 static void erase(SkBitmap& bm) { |
54 if (bm.config() == SkBitmap::kA8_Config) { | 53 if (bm.config() == SkBitmap::kA8_Config) { |
55 bm.eraseColor(SK_ColorTRANSPARENT); | 54 bm.eraseColor(SK_ColorTRANSPARENT); |
56 } else { | 55 } else { |
57 bm.eraseColor(SK_ColorWHITE); | 56 bm.eraseColor(SK_ColorWHITE); |
58 } | 57 } |
59 } | 58 } |
60 | 59 |
61 #if 0 | |
62 static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { | |
63 if (bm1.width() != bm2.width() || | |
64 bm1.height() != bm2.height() || | |
65 bm1.config() != bm2.config()) { | |
66 return false; | |
67 } | |
68 | |
69 size_t pixelBytes = bm1.width() * bm1.bytesPerPixel(); | |
70 for (int y = 0; y < bm1.height(); y++) { | |
71 if (memcmp(bm1.getAddr(0, y), bm2.getAddr(0, y), pixelBytes)) { | |
72 return false; | |
73 } | |
74 } | |
75 return true; | |
76 } | |
77 #endif | |
78 | |
79 class Iter { | 60 class Iter { |
80 public: | 61 public: |
81 Iter(void* param) { | 62 Iter() : fBench(BenchRegistry::Head()) {} |
82 fBench = BenchRegistry::Head(); | |
83 fParam = param; | |
84 } | |
85 | 63 |
86 SkBenchmark* next() { | 64 SkBenchmark* next() { |
87 if (fBench) { | 65 if (fBench) { |
88 BenchRegistry::Factory f = fBench->factory(); | 66 BenchRegistry::Factory f = fBench->factory(); |
89 fBench = fBench->next(); | 67 fBench = fBench->next(); |
90 return f(fParam); | 68 return f(NULL); |
91 } | 69 } |
92 return NULL; | 70 return NULL; |
93 } | 71 } |
94 | 72 |
95 private: | 73 private: |
96 const BenchRegistry* fBench; | 74 const BenchRegistry* fBench; |
97 void* fParam; | |
98 }; | 75 }; |
99 | 76 |
100 class AutoPrePostDraw { | 77 class AutoPrePostDraw { |
101 public: | 78 public: |
102 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) { | 79 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) { |
103 fBench->preDraw(); | 80 fBench->preDraw(); |
104 } | 81 } |
105 ~AutoPrePostDraw() { | 82 ~AutoPrePostDraw() { |
106 fBench->postDraw(); | 83 fBench->postDraw(); |
107 } | 84 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
140 int c = (*p >> SK_A32_SHIFT) & 0xFF; | 117 int c = (*p >> SK_A32_SHIFT) & 0xFF; |
141 c = 255 - c; | 118 c = 255 - c; |
142 c |= (c << 24) | (c << 16) | (c << 8); | 119 c |= (c << 24) | (c << 16) | (c << 8); |
143 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); | 120 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); |
144 } | 121 } |
145 } | 122 } |
146 | 123 |
147 SkString str; | 124 SkString str; |
148 make_filename(name, &str); | 125 make_filename(name, &str); |
149 str.appendf("_%s.png", config); | 126 str.appendf("_%s.png", config); |
127 str.prepend("/"); | |
scroggo
2013/09/03 19:36:43
SkOSFile now has a function for modifying path nam
mtklein
2013/09/03 20:04:43
Done.
| |
150 str.prepend(dir); | 128 str.prepend(dir); |
151 ::remove(str.c_str()); | 129 ::remove(str.c_str()); |
152 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, | 130 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, |
153 100); | 131 100); |
154 } | 132 } |
155 | 133 |
156 static void performClip(SkCanvas* canvas, int w, int h) { | 134 static void performClip(SkCanvas* canvas, int w, int h) { |
157 SkRect r; | 135 SkRect r; |
158 | 136 |
159 r.set(SkIntToScalar(10), SkIntToScalar(10), | 137 r.set(SkIntToScalar(10), SkIntToScalar(10), |
(...skipping 17 matching lines...) Expand all Loading... | |
177 static void performScale(SkCanvas* canvas, int w, int h) { | 155 static void performScale(SkCanvas* canvas, int w, int h) { |
178 const SkScalar x = SkIntToScalar(w) / 2; | 156 const SkScalar x = SkIntToScalar(w) / 2; |
179 const SkScalar y = SkIntToScalar(h) / 2; | 157 const SkScalar y = SkIntToScalar(h) / 2; |
180 | 158 |
181 canvas->translate(x, y); | 159 canvas->translate(x, y); |
182 // just enough so we can't take the sprite case | 160 // just enough so we can't take the sprite case |
183 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); | 161 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); |
184 canvas->translate(-x, -y); | 162 canvas->translate(-x, -y); |
185 } | 163 } |
186 | 164 |
187 static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { | |
188 if (argv < stop) { | |
189 *var = atoi(*argv) != 0; | |
190 return true; | |
191 } | |
192 return false; | |
193 } | |
194 | |
195 enum Backend { | 165 enum Backend { |
196 kNonRendering_Backend, | 166 kNonRendering_Backend, |
197 kRaster_Backend, | 167 kRaster_Backend, |
198 kGPU_Backend, | 168 kGPU_Backend, |
199 kPDF_Backend, | 169 kPDF_Backend, |
200 }; | 170 }; |
201 | 171 |
202 static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size, | 172 static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size, |
203 Backend backend, int sampleCount, GrContext* co ntext) { | 173 Backend backend, int sampleCount, GrContext* co ntext) { |
204 SkBaseDevice* device = NULL; | 174 SkBaseDevice* device = NULL; |
(...skipping 25 matching lines...) Expand all Loading... | |
230 case kPDF_Backend: | 200 case kPDF_Backend: |
231 default: | 201 default: |
232 SkDEBUGFAIL("unsupported"); | 202 SkDEBUGFAIL("unsupported"); |
233 } | 203 } |
234 return device; | 204 return device; |
235 } | 205 } |
236 | 206 |
237 #if SK_SUPPORT_GPU | 207 #if SK_SUPPORT_GPU |
238 GrContextFactory gContextFactory; | 208 GrContextFactory gContextFactory; |
239 typedef GrContextFactory::GLContextType GLContextType; | 209 typedef GrContextFactory::GLContextType GLContextType; |
240 static const GLContextType kDontCareGLCtxType = GrContextFactory::kNative_GLCont extType; | 210 static const GLContextType kNative = GrContextFactory::kNative_GLContextType; |
211 #if SK_ANGLE | |
212 static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType; | |
213 #else | |
214 static const GLContextType kANGLE = kNative; | |
215 #endif | |
216 static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType; | |
217 static const GLContextType kNull = GrContextFactory::kNull_GLContextType; | |
241 #else | 218 #else |
242 typedef int GLContextType; | 219 typedef int GLContextType; |
243 static const GLContextType kDontCareGLCtxType = 0; | 220 static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0; |
244 #endif | 221 #endif |
245 | 222 |
246 static const struct { | 223 #ifdef SK_DEBUG |
247 SkBitmap::Config fConfig; | 224 static const bool kIsDebug = true; |
248 const char* fName; | 225 #else |
249 int fSampleCnt; | 226 static const bool kIsDebug = false; |
250 Backend fBackend; | 227 #endif |
251 GLContextType fContextType; | 228 |
252 bool fRunByDefault; | 229 static const struct Config { |
230 SkBitmap::Config config; | |
231 const char* name; | |
232 int sampleCount; | |
233 Backend backend; | |
234 GLContextType contextType; | |
235 bool runByDefault; | |
253 } gConfigs[] = { | 236 } gConfigs[] = { |
254 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kD ontCareGLCtxType, true }, | 237 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kNa tive, true}, |
255 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kD ontCareGLCtxType, true }, | 238 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kNa tive, true}, |
256 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kD ontCareGLCtxType, true }, | 239 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kNa tive, true}, |
257 #if SK_SUPPORT_GPU | 240 #if SK_SUPPORT_GPU |
258 { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, Gr ContextFactory::kNative_GLContextType, true }, | 241 { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, kNa tive, true}, |
259 { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, Gr ContextFactory::kNative_GLContextType, false }, | 242 { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, kNa tive, false}, |
260 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, Gr ContextFactory::kNative_GLContextType, false }, | 243 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, kNa tive, false}, |
261 #if SK_ANGLE | 244 #if SK_ANGLE |
262 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, Gr ContextFactory::kANGLE_GLContextType, true }, | 245 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, kAN GLE, true}, |
263 #endif // SK_ANGLE | 246 #endif // SK_ANGLE |
264 { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, Gr ContextFactory::kDebug_GLContextType, kDebugOnly }, | 247 { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, kDe bug, kIsDebug}, |
265 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, Gr ContextFactory::kNull_GLContextType, true }, | 248 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, kNu ll, true}, |
266 #endif // SK_SUPPORT_GPU | 249 #endif // SK_SUPPORT_GPU |
267 }; | 250 }; |
268 | 251 |
269 static int findConfig(const char config[]) { | 252 DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir." ); |
270 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) { | 253 DEFINE_string(timers, "cg", "Timers to display. " |
scroggo
2013/09/03 19:36:43
It would be nice to combine this with bench_pictur
mtklein
2013/09/03 20:04:43
+1
| |
271 if (!strcmp(config, gConfigs[i].fName)) { | 254 "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)"); |
272 return i; | |
273 } | |
274 } | |
275 return -1; | |
276 } | |
277 | 255 |
278 static void help() { | 256 DEFINE_bool(rotate, false, "Rotate canvas before bench run?"); |
279 SkString configsStr; | 257 DEFINE_bool(scale, false, "Scale canvas before bench run?"); |
280 static const size_t kConfigCount = SK_ARRAY_COUNT(gConfigs); | 258 DEFINE_bool(clip, false, "Clip canvas before bench run?"); |
281 for (size_t i = 0; i < kConfigCount; ++i) { | |
282 configsStr.appendf("%s%s", gConfigs[i].fName, ((i == kConfigCount - 1) ? "" : "|")); | |
283 } | |
284 | 259 |
285 SkDebugf("Usage: bench [-o outDir] [--repeat nr] [--logPerIter] " | 260 DEFINE_bool(forceAA, true, "Force anti-aliasing?"); |
286 "[--timers [wcgWC]*] [--rotate]\n" | 261 DEFINE_bool(forceFilter, false, "Force bitmap filtering?"); |
287 " [--scale] [--clip] [--min] [--forceAA 1|0] [--forceFilter 1|0] \n" | 262 DEFINE_string(forceDither, "default", "Force dithering: true, false, or default? "); |
288 " [--forceDither 1|0] [--forceBlend 1|0]" | 263 DEFINE_bool(forceBlend, false, "Force alpha blending?"); |
289 #if SK_SUPPORT_GPU | 264 |
290 " [--gpuCacheSize <bytes> <count>]" | 265 DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable ca che."); |
291 #endif | 266 DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to dis able cache."); |
292 "\n" | 267 |
293 " [--strokeWidth width] [--match name]\n" | 268 DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n" |
scroggo
2013/09/03 19:36:43
Isn't this now built in to SkCommandLineFlags?
mtklein
2013/09/03 20:04:43
Sort of. We can now parse FLAGS_match directly ra
scroggo
2013/09/03 20:13:53
What if SkCommandLineFlags defined it optionally?
| |
294 " [--mode normal|deferred|deferredSilent|record|picturerecord]\n " | 269 "Multiple matches may be separated by spaces.\n" |
295 " [--config "); | 270 "~ causes a matching test to always be skipped\n" |
296 SkDebugf("%s]\n", configsStr.c_str()); | 271 "^ requires the start of the test to match\n" |
297 SkDebugf(" [-Dfoo bar] [--logFile filename] [-h|--help]"); | 272 "$ requires the end of the test to match\n" |
298 SkDebugf("\n\n"); | 273 "^ and $ requires an exact match\n" |
299 SkDebugf(" -o outDir : Image of each bench will be put in outDir.\n"); | 274 "If a test does not match any list entry,\n" |
300 SkDebugf(" --repeat nr : Each bench repeats for nr times.\n"); | 275 "it is skipped unless some list entry starts with ~\n" ); |
301 SkDebugf(" --logPerIter : " | 276 DEFINE_string(mode, "normal", |
302 "Log each repeat timer instead of mean, default is disabled.\n"); | 277 "normal: draw to a normal canvas;\n" |
303 SkDebugf(" --timers [wcgWC]* : " | 278 "deferred: draw to a deferred canvas;\n" |
304 "Display wall, cpu, gpu, truncated wall or truncated cpu time for e ach bench.\n"); | 279 "deferredSilent: deferred with silent playback;\n" |
305 SkDebugf(" --rotate : Rotate before each bench runs.\n"); | 280 "record: draw to an SkPicture;\n" |
306 SkDebugf(" --scale : Scale before each bench runs.\n"); | 281 "picturerecord: draw from an SkPicture to an SkPicture.\n"); |
307 SkDebugf(" --clip : Clip before each bench runs.\n"); | 282 DEFINE_string(config, "", "Run configs given. If empty, runs the defaults set i n gConfigs."); |
308 SkDebugf(" --min : Print the minimum times (instead of average).\n"); | 283 DEFINE_string(logFile, "", "Also write stdout here."); |
309 SkDebugf(" --forceAA 1|0 : " | 284 DEFINE_int32(benchMs, 20, "Target time in ms to run each benchmark config."); |
310 "Enable/disable anti-aliased, default is enabled.\n"); | 285 DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops."); |
311 SkDebugf(" --forceFilter 1|0 : " | |
312 "Enable/disable bitmap filtering, default is disabled.\n"); | |
313 SkDebugf(" --forceDither 1|0 : " | |
314 "Enable/disable dithering, default is disabled.\n"); | |
315 SkDebugf(" --forceBlend 1|0 : " | |
316 "Enable/disable dithering, default is disabled.\n"); | |
317 #if SK_SUPPORT_GPU | |
318 SkDebugf(" --gpuCacheSize <bytes> <count>: " | |
319 "limits gpu cache to bytes size or object count.\n"); | |
320 SkDebugf(" -1 for either value means use the default. 0 for either disa bles the cache.\n"); | |
321 #endif | |
322 SkDebugf(" --strokeWidth width : The width for path stroke.\n"); | |
323 SkDebugf(" --match [~][^]substring[$] [...] of test name to run.\n" | |
324 " Multiple matches may be separated by spaces.\n" | |
325 " ~ causes a matching test to always be skipped\n" | |
326 " ^ requires the start of the test to match\n" | |
327 " $ requires the end of the test to match\n" | |
328 " ^ and $ requires an exact match\n" | |
329 " If a test does not match any list entry,\n" | |
330 " it is skipped unless some list entry starts with ~\n" ); | |
331 SkDebugf(" --mode normal|deferred|deferredSilent|record|picturerecord :\n " | |
332 " Run in the corresponding mode\n" | |
333 " normal, Use a normal canvas to draw to;\n" | |
334 " deferred, Use a deferrred canvas when drawing;\n" | |
335 " deferredSilent, deferred with silent playback;\n" | |
336 " record, Benchmark the time to record to an SkPict ure;\n" | |
337 " picturerecord, Benchmark the time to do record fr om a \n" | |
338 " SkPicture to a SkPicture.\n"); | |
339 SkDebugf(" --logFile filename : destination for writing log output, in ad dition to stdout.\n"); | |
340 SkDebugf(" --config %s:\n", configsStr.c_str()); | |
341 SkDebugf(" Run bench in corresponding config mode.\n"); | |
342 SkDebugf(" -Dfoo bar : Add extra definition to bench.\n"); | |
343 SkDebugf(" -h|--help : Show this help message.\n"); | |
344 } | |
345 | 286 |
346 int tool_main(int argc, char** argv); | 287 int tool_main(int argc, char** argv); |
347 int tool_main(int argc, char** argv) { | 288 int tool_main(int argc, char** argv) { |
348 #if SK_ENABLE_INST_COUNT | 289 #if SK_ENABLE_INST_COUNT |
349 gPrintInstCount = true; | 290 gPrintInstCount = true; |
350 #endif | 291 #endif |
351 SkAutoGraphics ag; | 292 SkAutoGraphics ag; |
293 SkCommandLineFlags::Parse(argc, argv); | |
352 | 294 |
353 SkTDict<const char*> defineDict(1024); | 295 // First, parse some flags. |
scroggo
2013/09/03 19:36:43
It seems this functionality (supplying defines on
mtklein
2013/09/03 20:04:43
Yes. Only DecodeBench.cpp was using it for one po
| |
354 int repeatDraw = 1; | |
355 | |
356 int forceAlpha = 0xFF; | |
357 bool forceAA = true; | |
358 bool forceFilter = false; | |
359 SkTriState::State forceDither = SkTriState::kDefault; | |
360 | |
361 static const uint32_t kDefaultTimerTypes = TimerData::kCpu_Flag | TimerData: :kGpu_Flag; | |
362 static const TimerData::Result kDefaultTimerResult = TimerData::kAvg_Result; | |
363 uint32_t timerTypes = kDefaultTimerTypes; | |
364 TimerData::Result timerResult = kDefaultTimerResult; | |
365 | |
366 bool doScale = false; | |
367 bool doRotate = false; | |
368 bool doClip = false; | |
369 bool hasStrokeWidth = false; | |
370 | |
371 #if SK_SUPPORT_GPU | |
372 struct { | |
373 int fBytes; | |
374 int fCount; | |
375 } gpuCacheSize = { -1, -1 }; // -1s mean use the default | |
376 #endif | |
377 | |
378 float strokeWidth; | |
379 SkTDArray<const char*> fMatches; | |
380 benchModes benchMode = kNormal_benchModes; | |
381 SkString perIterTimeformat("%.2f"); | |
382 SkString normalTimeFormat("%6.2f"); | |
383 | |
384 SkString outDir; | |
385 SkBitmap::Config outConfig = SkBitmap::kNo_Config; | |
386 const char* configName = ""; | |
387 Backend backend = kRaster_Backend; // for warning | |
388 int sampleCount = 0; | |
389 SkTDArray<int> configs; | |
390 bool userConfig = false; | |
391 | 296 |
392 SkBenchLogger logger; | 297 SkBenchLogger logger; |
298 if (FLAGS_logFile.count()) { | |
299 logger.SetLogFile(FLAGS_logFile[0]); | |
300 } | |
393 | 301 |
394 char* const* stop = argv + argc; | 302 const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF; |
395 for (++argv; argv < stop; ++argv) { | 303 SkTriState::State dither = SkTriState::kDefault; |
396 if (strcmp(*argv, "-o") == 0) { | 304 for (size_t i = 0; i < 3; i++) { |
397 argv++; | 305 if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) { |
398 if (argv < stop && **argv) { | 306 dither = static_cast<SkTriState::State>(i); |
399 outDir.set(*argv); | |
400 if (outDir.c_str()[outDir.size() - 1] != '/') { | |
401 outDir.append("/"); | |
402 } | |
403 } | |
404 } else if (strcmp(*argv, "--repeat") == 0) { | |
405 argv++; | |
406 if (argv < stop) { | |
407 repeatDraw = atoi(*argv); | |
408 if (repeatDraw < 1) { | |
409 repeatDraw = 1; | |
410 } | |
411 } else { | |
412 logger.logError("missing arg for --repeat\n"); | |
413 help(); | |
414 return -1; | |
415 } | |
416 } else if (strcmp(*argv, "--logPerIter") == 0) { | |
417 timerResult = TimerData::kPerIter_Result; | |
418 } else if (strcmp(*argv, "--timers") == 0) { | |
419 argv++; | |
420 if (argv < stop) { | |
421 timerTypes = 0; | |
422 for (char* t = *argv; *t; ++t) { | |
423 switch (*t) { | |
424 case 'w': timerTypes |= TimerData::kWall_Flag; break; | |
425 case 'c': timerTypes |= TimerData::kCpu_Flag; break; | |
426 case 'W': timerTypes |= TimerData::kTruncatedWall_Flag; brea k; | |
427 case 'C': timerTypes |= TimerData::kTruncatedCpu_Flag; break ; | |
428 case 'g': timerTypes |= TimerData::kGpu_Flag; break; | |
429 } | |
430 } | |
431 } else { | |
432 logger.logError("missing arg for --timers\n"); | |
433 help(); | |
434 return -1; | |
435 } | |
436 } else if (!strcmp(*argv, "--rotate")) { | |
437 doRotate = true; | |
438 } else if (!strcmp(*argv, "--scale")) { | |
439 doScale = true; | |
440 } else if (!strcmp(*argv, "--clip")) { | |
441 doClip = true; | |
442 } else if (!strcmp(*argv, "--min")) { | |
443 timerResult = TimerData::kMin_Result; | |
444 } else if (strcmp(*argv, "--forceAA") == 0) { | |
445 if (!parse_bool_arg(++argv, stop, &forceAA)) { | |
446 logger.logError("missing arg for --forceAA\n"); | |
447 help(); | |
448 return -1; | |
449 } | |
450 } else if (strcmp(*argv, "--forceFilter") == 0) { | |
451 if (!parse_bool_arg(++argv, stop, &forceFilter)) { | |
452 logger.logError("missing arg for --forceFilter\n"); | |
453 help(); | |
454 return -1; | |
455 } | |
456 } else if (strcmp(*argv, "--forceDither") == 0) { | |
457 bool tmp; | |
458 if (!parse_bool_arg(++argv, stop, &tmp)) { | |
459 logger.logError("missing arg for --forceDither\n"); | |
460 help(); | |
461 return -1; | |
462 } | |
463 forceDither = tmp ? SkTriState::kTrue : SkTriState::kFalse; | |
464 } else if (strcmp(*argv, "--forceBlend") == 0) { | |
465 bool wantAlpha = false; | |
466 if (!parse_bool_arg(++argv, stop, &wantAlpha)) { | |
467 logger.logError("missing arg for --forceBlend\n"); | |
468 help(); | |
469 return -1; | |
470 } | |
471 forceAlpha = wantAlpha ? 0x80 : 0xFF; | |
472 #if SK_SUPPORT_GPU | |
473 } else if (strcmp(*argv, "--gpuCacheSize") == 0) { | |
474 if (stop - argv > 2) { | |
475 gpuCacheSize.fBytes = atoi(*++argv); | |
476 gpuCacheSize.fCount = atoi(*++argv); | |
477 } else { | |
478 SkDebugf("missing arg for --gpuCacheSize\n"); | |
479 help(); | |
480 return -1; | |
481 } | |
482 #endif | |
483 } else if (strcmp(*argv, "--mode") == 0) { | |
484 argv++; | |
485 if (argv < stop) { | |
486 if (strcmp(*argv, "normal") == 0) { | |
487 benchMode = kNormal_benchModes; | |
488 } else if (strcmp(*argv, "deferred") == 0) { | |
489 benchMode = kDeferred_benchModes; | |
490 } else if (strcmp(*argv, "deferredSilent") == 0) { | |
491 benchMode = kDeferredSilent_benchModes; | |
492 } else if (strcmp(*argv, "record") == 0) { | |
493 benchMode = kRecord_benchModes; | |
494 } else if (strcmp(*argv, "picturerecord") == 0) { | |
495 benchMode = kPictureRecord_benchModes; | |
496 } else { | |
497 logger.logError("bad arg for --mode\n"); | |
498 help(); | |
499 return -1; | |
500 } | |
501 } else { | |
502 logger.logError("missing arg for --mode\n"); | |
503 help(); | |
504 return -1; | |
505 } | |
506 } else if (strcmp(*argv, "--strokeWidth") == 0) { | |
507 argv++; | |
508 if (argv < stop) { | |
509 const char *strokeWidthStr = *argv; | |
510 if (sscanf(strokeWidthStr, "%f", &strokeWidth) != 1) { | |
511 logger.logError("bad arg for --strokeWidth\n"); | |
512 help(); | |
513 return -1; | |
514 } | |
515 hasStrokeWidth = true; | |
516 } else { | |
517 logger.logError("missing arg for --strokeWidth\n"); | |
518 help(); | |
519 return -1; | |
520 } | |
521 } else if (strcmp(*argv, "--match") == 0) { | |
522 argv++; | |
523 while (argv < stop && (*argv)[0] != '-') { | |
524 *fMatches.append() = *argv++; | |
525 } | |
526 argv--; | |
527 if (!fMatches.count()) { | |
528 logger.logError("missing arg for --match\n"); | |
529 help(); | |
530 return -1; | |
531 } | |
532 } else if (strcmp(*argv, "--config") == 0) { | |
533 argv++; | |
534 if (argv < stop) { | |
535 int index = findConfig(*argv); | |
536 if (index >= 0) { | |
537 *configs.append() = index; | |
538 userConfig = true; | |
539 } else { | |
540 SkString str; | |
541 str.printf("unrecognized config %s\n", *argv); | |
542 logger.logError(str); | |
543 help(); | |
544 return -1; | |
545 } | |
546 } else { | |
547 logger.logError("missing arg for --config\n"); | |
548 help(); | |
549 return -1; | |
550 } | |
551 } else if (strcmp(*argv, "--logFile") == 0) { | |
552 argv++; | |
553 if (argv < stop) { | |
554 if (!logger.SetLogFile(*argv)) { | |
555 SkString str; | |
556 str.printf("Could not open %s for writing.", *argv); | |
557 logger.logError(str); | |
558 return -1; | |
559 } | |
560 } else { | |
561 logger.logError("missing arg for --logFile\n"); | |
562 help(); | |
563 return -1; | |
564 } | |
565 } else if (strlen(*argv) > 2 && strncmp(*argv, "-D", 2) == 0) { | |
566 argv++; | |
567 if (argv < stop) { | |
568 defineDict.set(argv[-1] + 2, *argv); | |
569 } else { | |
570 logger.logError("incomplete '-Dfoo bar' definition\n"); | |
571 help(); | |
572 return -1; | |
573 } | |
574 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { | |
575 help(); | |
576 return 0; | |
577 } else { | |
578 SkString str; | |
579 str.printf("unrecognized arg %s\n", *argv); | |
580 logger.logError(str); | |
581 help(); | |
582 return -1; | |
583 } | 307 } |
584 } | 308 } |
585 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchMod es) | 309 |
586 && !outDir.isEmpty()) { | 310 uint32_t timerTypes = 0; |
587 logger.logError("'--mode record' and '--mode picturerecord' are not" | 311 for (const char* c = FLAGS_timers[0]; *c; ++c) { |
588 " compatible with -o.\n"); | 312 for (size_t i = 0; i < SK_ARRAY_COUNT(TimerType_Short); i++) { |
589 return -1; | 313 if (*c == TimerType_Short[i]) { |
314 timerTypes |= (1<<i); | |
315 } | |
316 } | |
590 } | 317 } |
591 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchMod es)) { | 318 |
592 perIterTimeformat.set("%.4f"); | 319 BenchMode benchMode = kNormal_BenchMode; |
593 normalTimeFormat.set("%6.4f"); | 320 for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) { |
321 if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) { | |
322 benchMode = static_cast<BenchMode>(i); | |
323 } | |
594 } | 324 } |
595 if (!userConfig) { | 325 |
596 // if no config is specified by user, add the default configs | 326 SkTDArray<int> configs; |
597 for (unsigned int i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | 327 // Try user-given configs first. |
598 if (gConfigs[i].fRunByDefault) { | 328 for (int i = 0; i < FLAGS_config.count(); i++) { |
329 for (size_t j = 0; j < SK_ARRAY_COUNT(gConfigs); j++) { | |
330 if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) { | |
331 *configs.append() = j; | |
332 } | |
333 } | |
334 } | |
335 // If there weren't any, fill in with defaults. | |
336 if (configs.count() == 0) { | |
337 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | |
338 if (gConfigs[i].runByDefault) { | |
599 *configs.append() = i; | 339 *configs.append() = i; |
600 } | 340 } |
601 } | 341 } |
602 } | 342 } |
603 if (kNormal_benchModes != benchMode) { | 343 // Filter out things we can't run. |
344 if (kNormal_BenchMode != benchMode) { | |
604 // Non-rendering configs only run in normal mode | 345 // Non-rendering configs only run in normal mode |
605 for (int i = 0; i < configs.count(); ++i) { | 346 for (int i = 0; i < configs.count(); ++i) { |
606 int configIdx = configs[i]; | 347 const Config& config = gConfigs[configs[i]]; |
607 if (kNonRendering_Backend == gConfigs[configIdx].fBackend) { | 348 if (kNonRendering_Backend == config.backend) { |
608 configs.remove(i, 1); | 349 configs.remove(i, 1); |
609 --i; | 350 --i; |
610 } | 351 } |
611 } | 352 } |
612 } | 353 } |
613 | |
614 #if SK_SUPPORT_GPU | 354 #if SK_SUPPORT_GPU |
615 for (int i = 0; i < configs.count(); ++i) { | 355 for (int i = 0; i < configs.count(); ++i) { |
616 int configIdx = configs[i]; | 356 const Config& config = gConfigs[configs[i]]; |
617 | 357 |
618 if (kGPU_Backend == gConfigs[configIdx].fBackend && gConfigs[configIdx]. fSampleCnt > 0) { | 358 if (kGPU_Backend == config.backend) { |
619 GrContext* context = gContextFactory.get(gConfigs[configIdx].fContex tType); | 359 GrContext* context = gContextFactory.get(config.contextType); |
620 if (NULL == context) { | 360 if (NULL == context) { |
621 SkString error; | 361 SkString error; |
622 error.printf("Error creating GrContext for config %s. Config wil l be skipped.\n", | 362 error.printf("Error creating GrContext for config %s. Config wil l be skipped.\n", |
623 gConfigs[configIdx].fName); | 363 config.name); |
624 logger.logError(error.c_str()); | 364 logger.logError(error); |
625 configs.remove(i); | 365 configs.remove(i); |
626 --i; | 366 --i; |
627 continue; | 367 continue; |
628 } | 368 } |
629 if (gConfigs[configIdx].fSampleCnt > context->getMaxSampleCount()){ | 369 if (config.sampleCount > context->getMaxSampleCount()){ |
630 SkString error; | 370 SkString error; |
631 error.printf("Sample count (%d) for config %s is unsupported. " | 371 error.printf("Sample count (%d) for config %s is unsupported. " |
632 "Config will be skipped.\n", | 372 "Config will be skipped.\n", |
633 gConfigs[configIdx].fSampleCnt, gConfigs[configIdx] .fName); | 373 config.sampleCount, config.name); |
634 logger.logError(error.c_str()); | 374 logger.logError(error); |
635 configs.remove(i); | 375 configs.remove(i); |
636 --i; | 376 --i; |
637 continue; | 377 continue; |
638 } | 378 } |
639 } | 379 } |
640 } | 380 } |
641 #endif | 381 #endif |
642 | 382 |
643 // report our current settings | 383 // All flags should be parsed now. Report our settings. |
644 { | 384 SkString str("skia bench:"); |
645 SkString str; | 385 str.appendf(" mode=%s", FLAGS_mode[0]); |
646 const char* deferredMode = benchMode == kDeferred_benchModes ? "yes" : | 386 str.appendf(" alpha=0x%02X antialias=%d filter=%d dither=%s", |
647 (benchMode == kDeferredSilent_benchModes ? "silent" : "no"); | 387 alpha, FLAGS_forceAA, FLAGS_forceFilter, SkTriState::Name[dither ]); |
648 str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d " | 388 str.appendf(" rotate=%d scale=%d clip=%d", FLAGS_rotate, FLAGS_scale, FLAGS_ clip); |
649 "deferred=%s logperiter=%d", | 389 |
650 forceAlpha, forceAA, forceFilter, deferredMode, | 390 #if defined(SK_SCALAR_IS_FIXED) |
651 TimerData::kPerIter_Result == timerResult); | 391 str.append(" scalar=fixed"); |
652 str.appendf(" rotate=%d scale=%d clip=%d min=%d", | 392 #else |
653 doRotate, doScale, doClip, TimerData::kMin_Result == timerRes ult); | 393 str.append(" scalar=float"); |
654 str.appendf(" record=%d picturerecord=%d", | |
655 benchMode == kRecord_benchModes, | |
656 benchMode == kPictureRecord_benchModes); | |
657 const char * ditherName; | |
658 switch (forceDither) { | |
659 case SkTriState::kDefault: ditherName = "default"; break; | |
660 case SkTriState::kTrue: ditherName = "true"; break; | |
661 case SkTriState::kFalse: ditherName = "false"; break; | |
662 default: ditherName = "<invalid>"; break; | |
663 } | |
664 str.appendf(" dither=%s", ditherName); | |
665 | |
666 if (hasStrokeWidth) { | |
667 str.appendf(" strokeWidth=%f", strokeWidth); | |
668 } else { | |
669 str.append(" strokeWidth=none"); | |
670 } | |
671 | |
672 #if defined(SK_SCALAR_IS_FLOAT) | |
673 str.append(" scalar=float"); | |
674 #elif defined(SK_SCALAR_IS_FIXED) | |
675 str.append(" scalar=fixed"); | |
676 #endif | 394 #endif |
677 | 395 |
678 #if defined(SK_BUILD_FOR_WIN32) | 396 #if defined(SK_BUILD_FOR_WIN32) |
679 str.append(" system=WIN32"); | 397 str.append(" system=WIN32"); |
680 #elif defined(SK_BUILD_FOR_MAC) | 398 #elif defined(SK_BUILD_FOR_MAC) |
681 str.append(" system=MAC"); | 399 str.append(" system=MAC"); |
682 #elif defined(SK_BUILD_FOR_ANDROID) | 400 #elif defined(SK_BUILD_FOR_ANDROID) |
683 str.append(" system=ANDROID"); | 401 str.append(" system=ANDROID"); |
684 #elif defined(SK_BUILD_FOR_UNIX) | 402 #elif defined(SK_BUILD_FOR_UNIX) |
685 str.append(" system=UNIX"); | 403 str.append(" system=UNIX"); |
686 #else | 404 #else |
687 str.append(" system=other"); | 405 str.append(" system=other"); |
688 #endif | 406 #endif |
689 | 407 |
690 #if defined(SK_DEBUG) | 408 #if defined(SK_DEBUG) |
691 str.append(" DEBUG"); | 409 str.append(" DEBUG"); |
692 #endif | 410 #endif |
693 str.append("\n"); | 411 str.append("\n"); |
694 logger.logProgress(str); | 412 logger.logProgress(str); |
695 } | 413 |
696 | 414 |
697 SkTArray<BenchTimer*> timers(SK_ARRAY_COUNT(gConfigs)); | 415 // Set texture cache limits and get timers suitable for each config. |
416 SkTDArray<BenchTimer*> timers; | |
698 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | 417 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { |
699 #if SK_SUPPORT_GPU | 418 #if SK_SUPPORT_GPU |
419 const Config& config = gConfigs[i]; | |
700 SkGLContextHelper* glCtx = NULL; | 420 SkGLContextHelper* glCtx = NULL; |
701 if (kGPU_Backend == gConfigs[i].fBackend) { | 421 if (kGPU_Backend == config.backend) { |
702 GrContext* context = gContextFactory.get(gConfigs[i].fContextType); | 422 GrContext* context = gContextFactory.get(config.contextType); |
703 if (NULL != context) { | 423 if (NULL != context) { |
704 // Set the user specified cache limits if non-default. | 424 // Set the user specified cache limits if non-default. |
705 size_t bytes; | 425 size_t bytes; |
706 int count; | 426 int count; |
707 context->getTextureCacheLimits(&count, &bytes); | 427 context->getTextureCacheLimits(&count, &bytes); |
708 if (-1 != gpuCacheSize.fBytes) { | 428 if (-1 != FLAGS_gpuCacheBytes) { |
709 bytes = static_cast<size_t>(gpuCacheSize.fBytes); | 429 bytes = static_cast<size_t>(FLAGS_gpuCacheBytes); |
710 } | 430 } |
711 if (-1 != gpuCacheSize.fCount) { | 431 if (-1 != FLAGS_gpuCacheCount) { |
712 count = gpuCacheSize.fCount; | 432 count = FLAGS_gpuCacheCount; |
713 } | 433 } |
714 context->setTextureCacheLimits(count, bytes); | 434 context->setTextureCacheLimits(count, bytes); |
715 } | 435 } |
716 glCtx = gContextFactory.getGLContext(gConfigs[i].fContextType); | 436 glCtx = gContextFactory.getGLContext(config.contextType); |
717 } | 437 } |
718 timers.push_back(SkNEW_ARGS(BenchTimer, (glCtx))); | 438 *timers.append() = SkNEW_ARGS(BenchTimer, (glCtx)); |
719 #else | 439 #else |
720 timers.push_back(SkNEW(BenchTimer)); | 440 *timers.append() = SkNEW(BenchTimer); |
721 #endif | 441 #endif |
722 } | 442 } |
723 | 443 |
724 Iter iter(&defineDict); | 444 // Find the longest name of the benches we're going to run to make the outpu t pretty. |
scroggo
2013/09/03 19:36:43
I suppose no benches ever use the dictionary?
mtklein
2013/09/03 20:04:43
Yup. I've just been too lazy to un-plumb the void
mtklein
2013/09/04 19:06:51
Turns out unplumbing the void* here is another CL
| |
445 Iter names; | |
725 SkBenchmark* bench; | 446 SkBenchmark* bench; |
447 int longestName = 0; | |
448 while ((bench = names.next()) != NULL) { | |
449 SkAutoTUnref<SkBenchmark> benchUnref(bench); | |
450 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { | |
451 continue; | |
452 } | |
453 const int length = strlen(bench->getName()); | |
454 longestName = length > longestName ? length : longestName; | |
455 } | |
456 | |
457 // Run each bench in each configuration it supports and we asked for. | |
458 Iter iter; | |
726 while ((bench = iter.next()) != NULL) { | 459 while ((bench = iter.next()) != NULL) { |
727 SkAutoTUnref<SkBenchmark> benchUnref(bench); | 460 SkAutoTUnref<SkBenchmark> benchUnref(bench); |
728 | 461 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { |
729 SkIPoint dim = bench->getSize(); | |
730 if (dim.fX <= 0 || dim.fY <= 0) { | |
731 continue; | 462 continue; |
732 } | 463 } |
733 | 464 |
734 bench->setForceAlpha(forceAlpha); | 465 bench->setForceAlpha(alpha); |
735 bench->setForceAA(forceAA); | 466 bench->setForceAA(FLAGS_forceAA); |
736 bench->setForceFilter(forceFilter); | 467 bench->setForceFilter(FLAGS_forceFilter); |
737 bench->setDither(forceDither); | 468 bench->setDither(dither); |
738 if (hasStrokeWidth) { | |
739 bench->setStrokeWidth(strokeWidth); | |
740 } | |
741 | |
742 // only run benchmarks if their name contains matchStr | |
743 if (SkCommandLineFlags::ShouldSkip(fMatches, bench->getName())) { | |
744 continue; | |
745 } | |
746 | |
747 bool loggedBenchStart = false; | |
748 | |
749 AutoPrePostDraw appd(bench); | 469 AutoPrePostDraw appd(bench); |
750 | 470 |
751 for (int x = 0; x < configs.count(); ++x) { | 471 bool loggedBenchName = false; |
752 int configIndex = configs[x]; | 472 for (int i = 0; i < configs.count(); ++i) { |
753 | 473 const int configIndex = configs[i]; |
754 bool setupFailed = false; | 474 const Config& config = gConfigs[configIndex]; |
755 | 475 |
756 if (kNonRendering_Backend == gConfigs[configIndex].fBackend) { | 476 if ((kNonRendering_Backend == config.backend) == bench->isRendering( )) { |
757 if (bench->isRendering()) { | 477 continue; |
758 continue; | 478 } |
759 } | 479 |
760 } else { | |
761 if (!bench->isRendering()) { | |
762 continue; | |
763 } | |
764 } | |
765 | |
766 outConfig = gConfigs[configIndex].fConfig; | |
767 configName = gConfigs[configIndex].fName; | |
768 backend = gConfigs[configIndex].fBackend; | |
769 sampleCount = gConfigs[configIndex].fSampleCnt; | |
770 GrContext* context = NULL; | 480 GrContext* context = NULL; |
771 BenchTimer* timer = timers[configIndex]; | |
772 | |
773 #if SK_SUPPORT_GPU | 481 #if SK_SUPPORT_GPU |
774 SkGLContextHelper* glContext = NULL; | 482 SkGLContextHelper* glContext = NULL; |
775 if (kGPU_Backend == backend) { | 483 if (kGPU_Backend == config.backend) { |
776 context = gContextFactory.get(gConfigs[configIndex].fContextType ); | 484 context = gContextFactory.get(config.contextType); |
777 if (NULL == context) { | 485 if (NULL == context) { |
778 continue; | 486 continue; |
779 } | 487 } |
780 glContext = gContextFactory.getGLContext(gConfigs[configIndex].f ContextType); | 488 glContext = gContextFactory.getGLContext(config.contextType); |
781 } | 489 } |
782 #endif | 490 #endif |
783 SkBaseDevice* device = NULL; | 491 SkAutoTUnref<SkBaseDevice> device; |
784 SkCanvas* canvas = NULL; | 492 SkAutoTUnref<SkCanvas> canvas; |
785 SkPicture pictureRecordFrom; | 493 SkPicture recordFrom, recordTo; |
786 SkPicture pictureRecordTo; | 494 const SkIPoint dim = bench->getSize(); |
787 | 495 |
788 if (kNonRendering_Backend != backend) { | 496 const SkPicture::RecordingFlags kRecordFlags = |
789 device = make_device(outConfig, dim, backend, sampleCount, conte xt); | 497 SkPicture::kUsePathBoundsForClip_RecordingFlag; |
790 if (NULL == device) { | 498 |
499 if (kNonRendering_Backend != config.backend) { | |
500 device.reset(make_device(config.config, dim, config.backend, con fig.sampleCount, context)); | |
scroggo
2013/09/03 19:36:43
100 chars
mtklein
2013/09/03 20:04:43
Done.
| |
501 if (!device.get()) { | |
791 SkString error; | 502 SkString error; |
792 error.printf("Device creation failure for config %s. Will sk ip.\n", configName); | 503 error.printf("Device creation failure for config %s. Will sk ip.\n", config.name); |
793 logger.logError(error.c_str()); | 504 logger.logError(error); |
794 setupFailed = true; | 505 continue; |
506 } | |
507 | |
508 switch(benchMode) { | |
509 case kDeferredSilent_BenchMode: | |
510 case kDeferred_BenchMode: | |
511 canvas.reset(SkDeferredCanvas::Create(device.get())); | |
512 break; | |
513 case kRecord_BenchMode: | |
514 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.f Y, kRecordFlags))); | |
515 break; | |
516 case kPictureRecord_BenchMode: | |
517 bench->draw(recordFrom.beginRecording(dim.fX, dim.fY, kR ecordFlags)); | |
518 recordFrom.endRecording(); | |
519 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.f Y, kRecordFlags))); | |
520 break; | |
521 case kNormal_BenchMode: | |
522 canvas.reset(new SkCanvas(device.get())); | |
523 break; | |
524 default: | |
525 SkASSERT(false); | |
526 } | |
527 } | |
528 | |
529 if (NULL != canvas) { | |
530 canvas->clear(SK_ColorWHITE); | |
531 if (FLAGS_clip) { performClip(canvas, dim.fX, dim.fY); } | |
532 if (FLAGS_scale) { performScale(canvas, dim.fX, dim.fY); } | |
533 if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); } | |
534 } | |
535 | |
536 if (!loggedBenchName) { | |
537 loggedBenchName = true; | |
538 SkString str; | |
539 str.printf("running bench [%3d %3d] %*s ", | |
540 dim.fX, dim.fY, longestName, bench->getName()); | |
541 logger.logProgress(str); | |
542 } | |
543 | |
544 BenchTimer* const timer = timers[configIndex]; | |
545 bench->setLoops(0); | |
546 do { | |
547 // Ramp up 1 -> 4 -> 16 -> ... -> ~1 billion. | |
548 const int loops = bench->getLoops(); | |
549 if (loops >= (1<<30)) { | |
550 SkString str; | |
551 str.printf("Can't ramp %s to %dms.\n", bench->getName(), FLA GS_benchMs); | |
552 logger.logError(str); | |
553 break; | |
554 } | |
555 bench->setLoops(loops == 0 ? 1 : loops * 4); | |
556 | |
557 if ((benchMode == kRecord_BenchMode || benchMode == kPictureReco rd_BenchMode)) { | |
558 // Clear the recorded commands so that they do not accumulat e. | |
559 canvas.reset(recordTo.beginRecording(dim.fX, dim.fY, kRecord Flags)); | |
560 } | |
561 | |
562 timer->start(); | |
563 if (NULL != canvas) { | |
564 canvas->save(); | |
565 } | |
566 if (benchMode == kPictureRecord_BenchMode) { | |
567 recordFrom.draw(canvas); | |
795 } else { | 568 } else { |
796 switch(benchMode) { | 569 bench->draw(canvas); |
797 case kDeferredSilent_benchModes: | 570 } |
798 case kDeferred_benchModes: | 571 |
799 canvas = SkDeferredCanvas::Create(device); | 572 if (kDeferredSilent_BenchMode == benchMode) { |
800 break; | 573 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush(); |
801 case kRecord_benchModes: | 574 } else if (NULL != canvas) { |
802 canvas = pictureRecordTo.beginRecording(dim.fX, dim. fY, | 575 canvas->flush(); |
803 SkPicture::kUsePathBoundsForClip_RecordingFlag); | 576 } |
804 canvas->ref(); | 577 |
805 break; | |
806 case kPictureRecord_benchModes: { | |
807 // This sets up picture-to-picture recording. | |
808 // The C++ drawing calls for the benchmark are recor ded into | |
809 // pictureRecordFrom. As the benchmark, we will time how | |
810 // long it takes to playback pictureRecordFrom into | |
811 // pictureRecordTo. | |
812 SkCanvas* tempCanvas = pictureRecordFrom.beginRecord ing(dim.fX, dim.fY, | |
813 SkPicture::kUsePathBoundsForClip_RecordingFlag); | |
814 bench->draw(tempCanvas); | |
815 pictureRecordFrom.endRecording(); | |
816 canvas = pictureRecordTo.beginRecording(dim.fX, dim. fY, | |
817 SkPicture::kUsePathBoundsForClip_RecordingFlag); | |
818 canvas->ref(); | |
819 break; | |
820 } | |
821 case kNormal_benchModes: | |
822 canvas = new SkCanvas(device); | |
823 break; | |
824 default: | |
825 SkASSERT(0); | |
826 } | |
827 device->unref(); | |
828 canvas->clear(SK_ColorWHITE); | |
829 } | |
830 } | |
831 SkAutoUnref canvasUnref(canvas); | |
832 if (!setupFailed) { | |
833 if (NULL != canvas) { | 578 if (NULL != canvas) { |
834 if (doClip) { | 579 canvas->restore(); |
835 performClip(canvas, dim.fX, dim.fY); | 580 } |
836 } | 581 |
837 if (doScale) { | 582 |
838 performScale(canvas, dim.fX, dim.fY); | 583 // Stop truncated timers before GL calls complete, and stop the full timers after. |
839 } | 584 timer->truncatedEnd(); |
840 if (doRotate) { | 585 #if SK_SUPPORT_GPU |
841 performRotate(canvas, dim.fX, dim.fY); | 586 if (NULL != glContext) { |
842 } | 587 context->flush(); |
843 } | 588 SK_GL(*glContext, Finish()); |
844 | 589 } |
845 if (!loggedBenchStart) { | 590 #endif |
846 loggedBenchStart = true; | 591 timer->end(); |
847 SkString str; | 592 } while (!kIsDebug && timer->fWall < FLAGS_benchMs); |
848 str.printf("running bench [%d %d] %28s", dim.fX, dim.fY, ben ch->getName()); | 593 |
849 logger.logProgress(str); | 594 if (kIsDebug) { |
850 } | 595 // Lets not mislead ourselves by looking at Debug build bench ti mes! |
scroggo
2013/09/03 19:36:43
+1
Should this print out an error message as well
mtklein
2013/09/03 20:04:43
Nah, it's not really an error to run bench in Debu
| |
851 | 596 continue; |
852 // warm up caches if needed | 597 } |
853 if (repeatDraw > 1 && NULL != canvas) { | 598 |
854 #if SK_SUPPORT_GPU | 599 // In same order as TimerType, multiplied to normalize times to ms p er 1000 iterations. |
855 // purge the GPU resources to reduce variance | 600 const double normalize = 1000.0 / bench->getLoops(); |
856 if (NULL != context) { | 601 const double times[] = { |
857 context->freeGpuResources(); | 602 normalize * timer->fWall, |
858 } | 603 normalize * timer->fTruncatedWall, |
859 #endif | 604 normalize * timer->fCpu, |
860 SkAutoCanvasRestore acr(canvas, true); | 605 normalize * timer->fTruncatedCpu, |
861 if (benchMode == kPictureRecord_benchModes) { | 606 normalize * timer->fGpu, |
862 pictureRecordFrom.draw(canvas); | 607 }; |
863 } else { | 608 |
864 bench->draw(canvas); | 609 uint32_t filteredTimerTypes = timerTypes; |
865 } | 610 if (NULL == context) { |
866 | 611 filteredTimerTypes &= ~(1<<kGpu_TimerType); |
867 if (kDeferredSilent_benchModes == benchMode) { | 612 |
868 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); | 613 } |
869 } else { | 614 |
870 canvas->flush(); | 615 SkString result; |
871 } | 616 result.appendf(" %s:", config.name); |
872 #if SK_SUPPORT_GPU | 617 for (size_t i = 0; i < SK_ARRAY_COUNT(TimerType_Name); i++) { |
873 if (NULL != context) { | 618 if (filteredTimerTypes & (1<<i) && times[i] > 0) { |
874 context->flush(); | 619 result.appendf(" %s = ", TimerType_Name[i]); |
875 SK_GL(*glContext, Finish()); | 620 result.appendf(FLAGS_timeFormat[0], times[i]); |
876 } | 621 } |
877 #endif | 622 } |
878 } | 623 logger.logProgress(result); |
879 | 624 |
880 // record timer values for each repeat, and their sum | 625 if (FLAGS_outDir.count() && kNonRendering_Backend != config.backend) { |
881 TimerData timerData(repeatDraw); | 626 saveFile(bench->getName(), |
882 for (int i = 0; i < repeatDraw; i++) { | 627 config.name, |
883 if ((benchMode == kRecord_benchModes || benchMode == kPictur eRecord_benchModes)) { | 628 FLAGS_outDir[0], |
884 // This will clear the recorded commands so that they do not | 629 device->accessBitmap(false)); |
885 // accumulate. | 630 } |
886 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, | 631 } |
887 SkPicture::kUsePathBoundsForClip_RecordingFlag); | 632 if (loggedBenchName) { |
888 } | 633 logger.logProgress("\n"); |
889 | 634 } |
890 timer->start(bench->getDurationScale()); | 635 } |
891 if (NULL != canvas) { | 636 timers.deleteAll(); |
892 canvas->save(); | 637 #if SK_SUPPORT_GPU |
893 } | |
894 if (benchMode == kPictureRecord_benchModes) { | |
895 pictureRecordFrom.draw(canvas); | |
896 } else { | |
897 bench->draw(canvas); | |
898 } | |
899 | |
900 if (kDeferredSilent_benchModes == benchMode) { | |
901 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); | |
902 } else if (NULL != canvas) { | |
903 canvas->flush(); | |
904 } | |
905 | |
906 if (NULL != canvas) { | |
907 canvas->restore(); | |
908 } | |
909 | |
910 // stop the truncated timer after the last canvas call but | |
911 // don't wait for all the GL calls to complete | |
912 timer->truncatedEnd(); | |
913 #if SK_SUPPORT_GPU | |
914 if (NULL != glContext) { | |
915 context->flush(); | |
916 SK_GL(*glContext, Finish()); | |
917 } | |
918 #endif | |
919 // stop the inclusive and gpu timers once all the GL calls | |
920 // have completed | |
921 timer->end(); | |
922 | |
923 SkAssertResult(timerData.appendTimes(timer)); | |
924 | |
925 } | |
926 if (repeatDraw > 1) { | |
927 const char* timeFormat; | |
928 if (TimerData::kPerIter_Result == timerResult) { | |
929 timeFormat = perIterTimeformat.c_str(); | |
930 } else { | |
931 timeFormat = normalTimeFormat.c_str(); | |
932 } | |
933 uint32_t filteredTimerTypes = timerTypes; | |
934 if (NULL == context) { | |
935 filteredTimerTypes &= ~TimerData::kGpu_Flag; | |
936 } | |
937 SkString result = timerData.getResult(timeFormat, | |
938 timerResult, | |
939 configName, | |
940 filteredTimerTypes); | |
941 logger.logProgress(result); | |
942 } | |
943 if (outDir.size() > 0 && kNonRendering_Backend != backend) { | |
944 saveFile(bench->getName(), configName, outDir.c_str(), | |
945 device->accessBitmap(false)); | |
946 } | |
947 } | |
948 } | |
949 if (loggedBenchStart) { | |
950 logger.logProgress(SkString("\n")); | |
951 } | |
952 } | |
953 #if SK_SUPPORT_GPU | |
954 #if GR_CACHE_STATS | |
955 for (int i = 0; i <= GrContextFactory::kLastGLContextType; ++i) { | |
956 GrContextFactory::GLContextType ctxType = (GrContextFactory::GLContextTy pe)i; | |
957 GrContext* context = gContextFactory.get(ctxType); | |
958 if (NULL != context) { | |
959 SkDebugf("Cache Stats for %s context:\n", GrContextFactory::GLContex tTypeName(ctxType)); | |
960 context->printCacheStats(); | |
961 SkDebugf("\n"); | |
962 } | |
963 } | |
964 #endif | |
965 // Destroy the GrContext before the inst tracking printing at main() exit oc curs. | |
966 gContextFactory.destroyContexts(); | 638 gContextFactory.destroyContexts(); |
967 #endif | 639 #endif |
968 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | |
969 SkDELETE(timers[i]); | |
970 } | |
971 | |
972 return 0; | 640 return 0; |
973 } | 641 } |
974 | 642 |
975 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 643 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
976 int main(int argc, char * const argv[]) { | 644 int main(int argc, char * const argv[]) { |
977 return tool_main(argc, (char**) argv); | 645 return tool_main(argc, (char**) argv); |
978 } | 646 } |
979 #endif | 647 #endif |
OLD | NEW |