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" | 28 #include "SkOSFile.h" |
32 #include "SkPicture.h" | 29 #include "SkPicture.h" |
33 #include "SkString.h" | 30 #include "SkString.h" |
34 #include "SkTArray.h" | |
35 #include "TimerData.h" | |
epoger
2013/09/04 14:36:40
Now that benchmain doesn't use TimerData.h anymore
mtklein
2013/09/04 19:06:51
Yeah, deleting TimerData is coming. I haven't don
| |
36 | 31 |
37 enum benchModes { | 32 enum BenchMode { |
38 kNormal_benchModes, | 33 kNormal_BenchMode, |
39 kDeferred_benchModes, | 34 kDeferred_BenchMode, |
40 kDeferredSilent_benchModes, | 35 kDeferredSilent_BenchMode, |
41 kRecord_benchModes, | 36 kRecord_BenchMode, |
42 kPictureRecord_benchModes | 37 kPictureRecord_BenchMode |
43 }; | 38 }; |
39 const char* BenchMode_Name[] = { "normal", "deferred", "deferredSilent", "record ", "picturerecord" }; | |
44 | 40 |
45 #ifdef SK_DEBUG | 41 enum TimerTypes { |
46 static const bool kDebugOnly = true; | 42 kWall_TimerType, |
47 #else | 43 kTruncWall_TimerType, |
48 static const bool kDebugOnly = false; | 44 kCpu_TimerType, |
49 #endif | 45 kTruncCpu_TimerType, |
46 kGpu_TimerType, | |
47 }; | |
48 const char TimerType_Short[] = { 'w', 'W', 'c', 'C', 'g' }; | |
49 const char* TimerType_Name[] = { "msecs", "Wmsecs", "cmsecs", "Cmsecs", "gmsecs" }; | |
50 | 50 |
51 /////////////////////////////////////////////////////////////////////////////// | 51 /////////////////////////////////////////////////////////////////////////////// |
52 | 52 |
53 static void erase(SkBitmap& bm) { | 53 static void erase(SkBitmap& bm) { |
54 if (bm.config() == SkBitmap::kA8_Config) { | 54 if (bm.config() == SkBitmap::kA8_Config) { |
55 bm.eraseColor(SK_ColorTRANSPARENT); | 55 bm.eraseColor(SK_ColorTRANSPARENT); |
56 } else { | 56 } else { |
57 bm.eraseColor(SK_ColorWHITE); | 57 bm.eraseColor(SK_ColorWHITE); |
58 } | 58 } |
59 } | 59 } |
60 | 60 |
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 { | 61 class Iter { |
80 public: | 62 public: |
81 Iter(void* param) { | 63 Iter() : fBench(BenchRegistry::Head()) {} |
82 fBench = BenchRegistry::Head(); | |
83 fParam = param; | |
84 } | |
85 | 64 |
86 SkBenchmark* next() { | 65 SkBenchmark* next() { |
87 if (fBench) { | 66 if (fBench) { |
88 BenchRegistry::Factory f = fBench->factory(); | 67 BenchRegistry::Factory f = fBench->factory(); |
89 fBench = fBench->next(); | 68 fBench = fBench->next(); |
90 return f(fParam); | 69 return f(NULL); |
91 } | 70 } |
92 return NULL; | 71 return NULL; |
93 } | 72 } |
94 | 73 |
95 private: | 74 private: |
96 const BenchRegistry* fBench; | 75 const BenchRegistry* fBench; |
97 void* fParam; | |
98 }; | 76 }; |
99 | 77 |
100 class AutoPrePostDraw { | 78 class AutoPrePostDraw { |
101 public: | 79 public: |
102 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) { | 80 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) { |
103 fBench->preDraw(); | 81 fBench->preDraw(); |
104 } | 82 } |
105 ~AutoPrePostDraw() { | 83 ~AutoPrePostDraw() { |
106 fBench->postDraw(); | 84 fBench->postDraw(); |
107 } | 85 } |
(...skipping 29 matching lines...) Expand all Loading... | |
137 size_t size = copy.getSize() >> 2; | 115 size_t size = copy.getSize() >> 2; |
138 SkPMColor* p = copy.getAddr32(0, 0); | 116 SkPMColor* p = copy.getAddr32(0, 0); |
139 for (size_t i = 0; i < size; i++) { | 117 for (size_t i = 0; i < size; i++) { |
140 int c = (*p >> SK_A32_SHIFT) & 0xFF; | 118 int c = (*p >> SK_A32_SHIFT) & 0xFF; |
141 c = 255 - c; | 119 c = 255 - c; |
142 c |= (c << 24) | (c << 16) | (c << 8); | 120 c |= (c << 24) | (c << 16) | (c << 8); |
143 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); | 121 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); |
144 } | 122 } |
145 } | 123 } |
146 | 124 |
147 SkString str; | 125 SkString filename; |
148 make_filename(name, &str); | 126 make_filename(name, &filename); |
149 str.appendf("_%s.png", config); | 127 filename.appendf("_%s.png", config); |
150 str.prepend(dir); | 128 SkString path = SkOSPath::SkPathJoin(dir, filename.c_str()); |
151 ::remove(str.c_str()); | 129 ::remove(path.c_str()); |
152 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, | 130 SkImageEncoder::EncodeFile(path.c_str(), copy, SkImageEncoder::kPNG_Type, 10 0); |
153 100); | |
154 } | 131 } |
155 | 132 |
156 static void performClip(SkCanvas* canvas, int w, int h) { | 133 static void performClip(SkCanvas* canvas, int w, int h) { |
157 SkRect r; | 134 SkRect r; |
158 | 135 |
159 r.set(SkIntToScalar(10), SkIntToScalar(10), | 136 r.set(SkIntToScalar(10), SkIntToScalar(10), |
160 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); | 137 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); |
161 canvas->clipRect(r, SkRegion::kIntersect_Op); | 138 canvas->clipRect(r, SkRegion::kIntersect_Op); |
162 | 139 |
163 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), | 140 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), |
(...skipping 13 matching lines...) Expand all Loading... | |
177 static void performScale(SkCanvas* canvas, int w, int h) { | 154 static void performScale(SkCanvas* canvas, int w, int h) { |
178 const SkScalar x = SkIntToScalar(w) / 2; | 155 const SkScalar x = SkIntToScalar(w) / 2; |
179 const SkScalar y = SkIntToScalar(h) / 2; | 156 const SkScalar y = SkIntToScalar(h) / 2; |
180 | 157 |
181 canvas->translate(x, y); | 158 canvas->translate(x, y); |
182 // just enough so we can't take the sprite case | 159 // just enough so we can't take the sprite case |
183 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); | 160 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); |
184 canvas->translate(-x, -y); | 161 canvas->translate(-x, -y); |
185 } | 162 } |
186 | 163 |
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 { | 164 enum Backend { |
196 kNonRendering_Backend, | 165 kNonRendering_Backend, |
197 kRaster_Backend, | 166 kRaster_Backend, |
198 kGPU_Backend, | 167 kGPU_Backend, |
199 kPDF_Backend, | 168 kPDF_Backend, |
200 }; | 169 }; |
201 | 170 |
202 static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size, | 171 static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size, |
203 Backend backend, int sampleCount, GrContext* co ntext) { | 172 Backend backend, int sampleCount, GrContext* co ntext) { |
204 SkBaseDevice* device = NULL; | 173 SkBaseDevice* device = NULL; |
(...skipping 25 matching lines...) Expand all Loading... | |
230 case kPDF_Backend: | 199 case kPDF_Backend: |
231 default: | 200 default: |
232 SkDEBUGFAIL("unsupported"); | 201 SkDEBUGFAIL("unsupported"); |
233 } | 202 } |
234 return device; | 203 return device; |
235 } | 204 } |
236 | 205 |
237 #if SK_SUPPORT_GPU | 206 #if SK_SUPPORT_GPU |
238 GrContextFactory gContextFactory; | 207 GrContextFactory gContextFactory; |
239 typedef GrContextFactory::GLContextType GLContextType; | 208 typedef GrContextFactory::GLContextType GLContextType; |
240 static const GLContextType kDontCareGLCtxType = GrContextFactory::kNative_GLCont extType; | 209 static const GLContextType kNative = GrContextFactory::kNative_GLContextType; |
210 #if SK_ANGLE | |
211 static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType; | |
212 #else | |
213 static const GLContextType kANGLE = kNative; | |
214 #endif | |
215 static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType; | |
216 static const GLContextType kNull = GrContextFactory::kNull_GLContextType; | |
241 #else | 217 #else |
242 typedef int GLContextType; | 218 typedef int GLContextType; |
243 static const GLContextType kDontCareGLCtxType = 0; | 219 static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0; |
244 #endif | 220 #endif |
245 | 221 |
246 static const struct { | 222 #ifdef SK_DEBUG |
247 SkBitmap::Config fConfig; | 223 static const bool kIsDebug = true; |
248 const char* fName; | 224 #else |
249 int fSampleCnt; | 225 static const bool kIsDebug = false; |
250 Backend fBackend; | 226 #endif |
251 GLContextType fContextType; | 227 |
252 bool fRunByDefault; | 228 static const struct Config { |
229 SkBitmap::Config config; | |
230 const char* name; | |
231 int sampleCount; | |
232 Backend backend; | |
233 GLContextType contextType; | |
234 bool runByDefault; | |
253 } gConfigs[] = { | 235 } gConfigs[] = { |
254 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kD ontCareGLCtxType, true }, | 236 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kNa tive, true}, |
255 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kD ontCareGLCtxType, true }, | 237 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kNa tive, true}, |
256 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kD ontCareGLCtxType, true }, | 238 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kNa tive, true}, |
257 #if SK_SUPPORT_GPU | 239 #if SK_SUPPORT_GPU |
258 { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, Gr ContextFactory::kNative_GLContextType, true }, | 240 { 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 }, | 241 { 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 }, | 242 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, kNa tive, false}, |
261 #if SK_ANGLE | 243 #if SK_ANGLE |
262 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, Gr ContextFactory::kANGLE_GLContextType, true }, | 244 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, kAN GLE, true}, |
263 #endif // SK_ANGLE | 245 #endif // SK_ANGLE |
264 { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, Gr ContextFactory::kDebug_GLContextType, kDebugOnly }, | 246 { 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 }, | 247 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, kNu ll, true}, |
266 #endif // SK_SUPPORT_GPU | 248 #endif // SK_SUPPORT_GPU |
267 }; | 249 }; |
268 | 250 |
269 static int findConfig(const char config[]) { | 251 DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir." ); |
epoger
2013/09/04 14:36:40
In future CLs (I'm not asking you to back out any
mtklein
2013/09/04 19:06:51
Yeah, this was a case where the code was such that
| |
270 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) { | 252 DEFINE_string(timers, "cg", "Timers to display. " |
271 if (!strcmp(config, gConfigs[i].fName)) { | 253 "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)"); |
272 return i; | |
273 } | |
274 } | |
275 return -1; | |
276 } | |
277 | 254 |
278 static void help() { | 255 DEFINE_bool(rotate, false, "Rotate canvas before bench run?"); |
279 SkString configsStr; | 256 DEFINE_bool(scale, false, "Scale canvas before bench run?"); |
280 static const size_t kConfigCount = SK_ARRAY_COUNT(gConfigs); | 257 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 | 258 |
285 SkDebugf("Usage: bench [-o outDir] [--repeat nr] [--logPerIter] " | 259 DEFINE_bool(forceAA, true, "Force anti-aliasing?"); |
286 "[--timers [wcgWC]*] [--rotate]\n" | 260 DEFINE_bool(forceFilter, false, "Force bitmap filtering?"); |
287 " [--scale] [--clip] [--min] [--forceAA 1|0] [--forceFilter 1|0] \n" | 261 DEFINE_string(forceDither, "default", "Force dithering: true, false, or default? "); |
288 " [--forceDither 1|0] [--forceBlend 1|0]" | 262 DEFINE_bool(forceBlend, false, "Force alpha blending?"); |
289 #if SK_SUPPORT_GPU | 263 |
290 " [--gpuCacheSize <bytes> <count>]" | 264 DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable ca che."); |
291 #endif | 265 DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to dis able cache."); |
292 "\n" | 266 |
293 " [--strokeWidth width] [--match name]\n" | 267 DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n" |
294 " [--mode normal|deferred|deferredSilent|record|picturerecord]\n " | 268 "Multiple matches may be separated by spaces.\n" |
295 " [--config "); | 269 "~ causes a matching test to always be skipped\n" |
296 SkDebugf("%s]\n", configsStr.c_str()); | 270 "^ requires the start of the test to match\n" |
297 SkDebugf(" [-Dfoo bar] [--logFile filename] [-h|--help]"); | 271 "$ requires the end of the test to match\n" |
298 SkDebugf("\n\n"); | 272 "^ and $ requires an exact match\n" |
299 SkDebugf(" -o outDir : Image of each bench will be put in outDir.\n"); | 273 "If a test does not match any list entry,\n" |
300 SkDebugf(" --repeat nr : Each bench repeats for nr times.\n"); | 274 "it is skipped unless some list entry starts with ~\n" ); |
301 SkDebugf(" --logPerIter : " | 275 DEFINE_string(mode, "normal", |
302 "Log each repeat timer instead of mean, default is disabled.\n"); | 276 "normal: draw to a normal canvas;\n" |
303 SkDebugf(" --timers [wcgWC]* : " | 277 "deferred: draw to a deferred canvas;\n" |
304 "Display wall, cpu, gpu, truncated wall or truncated cpu time for e ach bench.\n"); | 278 "deferredSilent: deferred with silent playback;\n" |
305 SkDebugf(" --rotate : Rotate before each bench runs.\n"); | 279 "record: draw to an SkPicture;\n" |
306 SkDebugf(" --scale : Scale before each bench runs.\n"); | 280 "picturerecord: draw from an SkPicture to an SkPicture.\n"); |
307 SkDebugf(" --clip : Clip before each bench runs.\n"); | 281 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"); | 282 DEFINE_string(logFile, "", "Also write stdout here."); |
309 SkDebugf(" --forceAA 1|0 : " | 283 DEFINE_int32(benchMs, 20, "Target time in ms to run each benchmark config."); |
310 "Enable/disable anti-aliased, default is enabled.\n"); | 284 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 | 285 |
346 int tool_main(int argc, char** argv); | 286 int tool_main(int argc, char** argv); |
347 int tool_main(int argc, char** argv) { | 287 int tool_main(int argc, char** argv) { |
348 #if SK_ENABLE_INST_COUNT | 288 #if SK_ENABLE_INST_COUNT |
349 gPrintInstCount = true; | 289 gPrintInstCount = true; |
350 #endif | 290 #endif |
351 SkAutoGraphics ag; | 291 SkAutoGraphics ag; |
292 SkCommandLineFlags::Parse(argc, argv); | |
352 | 293 |
353 SkTDict<const char*> defineDict(1024); | 294 // First, parse some flags. |
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 | 295 |
392 SkBenchLogger logger; | 296 SkBenchLogger logger; |
297 if (FLAGS_logFile.count()) { | |
298 logger.SetLogFile(FLAGS_logFile[0]); | |
299 } | |
393 | 300 |
394 char* const* stop = argv + argc; | 301 const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF; |
395 for (++argv; argv < stop; ++argv) { | 302 SkTriState::State dither = SkTriState::kDefault; |
396 if (strcmp(*argv, "-o") == 0) { | 303 for (size_t i = 0; i < 3; i++) { |
397 argv++; | 304 if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) { |
398 if (argv < stop && **argv) { | 305 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 } | 306 } |
584 } | 307 } |
585 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchMod es) | 308 |
586 && !outDir.isEmpty()) { | 309 uint32_t timerTypes = 0; |
587 logger.logError("'--mode record' and '--mode picturerecord' are not" | 310 for (const char* c = FLAGS_timers[0]; *c; ++c) { |
epoger
2013/09/04 14:36:40
I think code like this would be much easier to und
mtklein
2013/09/04 19:06:51
Agreed. I took a closer look at this and realized
| |
588 " compatible with -o.\n"); | 311 for (size_t i = 0; i < SK_ARRAY_COUNT(TimerType_Short); i++) { |
589 return -1; | 312 if (*c == TimerType_Short[i]) { |
313 timerTypes |= (1<<i); | |
314 } | |
315 } | |
590 } | 316 } |
591 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchMod es)) { | 317 |
592 perIterTimeformat.set("%.4f"); | 318 BenchMode benchMode = kNormal_BenchMode; |
593 normalTimeFormat.set("%6.4f"); | 319 for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) { |
320 if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) { | |
321 benchMode = static_cast<BenchMode>(i); | |
322 } | |
594 } | 323 } |
595 if (!userConfig) { | 324 |
596 // if no config is specified by user, add the default configs | 325 SkTDArray<int> configs; |
597 for (unsigned int i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | 326 // Try user-given configs first. |
598 if (gConfigs[i].fRunByDefault) { | 327 for (int i = 0; i < FLAGS_config.count(); i++) { |
328 for (size_t j = 0; j < SK_ARRAY_COUNT(gConfigs); j++) { | |
329 if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) { | |
330 *configs.append() = j; | |
331 } | |
332 } | |
333 } | |
334 // If there weren't any, fill in with defaults. | |
335 if (configs.count() == 0) { | |
336 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | |
337 if (gConfigs[i].runByDefault) { | |
599 *configs.append() = i; | 338 *configs.append() = i; |
600 } | 339 } |
601 } | 340 } |
602 } | 341 } |
603 if (kNormal_benchModes != benchMode) { | 342 // Filter out things we can't run. |
343 if (kNormal_BenchMode != benchMode) { | |
604 // Non-rendering configs only run in normal mode | 344 // Non-rendering configs only run in normal mode |
605 for (int i = 0; i < configs.count(); ++i) { | 345 for (int i = 0; i < configs.count(); ++i) { |
606 int configIdx = configs[i]; | 346 const Config& config = gConfigs[configs[i]]; |
607 if (kNonRendering_Backend == gConfigs[configIdx].fBackend) { | 347 if (kNonRendering_Backend == config.backend) { |
608 configs.remove(i, 1); | 348 configs.remove(i, 1); |
609 --i; | 349 --i; |
610 } | 350 } |
611 } | 351 } |
612 } | 352 } |
613 | |
614 #if SK_SUPPORT_GPU | 353 #if SK_SUPPORT_GPU |
615 for (int i = 0; i < configs.count(); ++i) { | 354 for (int i = 0; i < configs.count(); ++i) { |
616 int configIdx = configs[i]; | 355 const Config& config = gConfigs[configs[i]]; |
617 | 356 |
618 if (kGPU_Backend == gConfigs[configIdx].fBackend && gConfigs[configIdx]. fSampleCnt > 0) { | 357 if (kGPU_Backend == config.backend) { |
619 GrContext* context = gContextFactory.get(gConfigs[configIdx].fContex tType); | 358 GrContext* context = gContextFactory.get(config.contextType); |
620 if (NULL == context) { | 359 if (NULL == context) { |
621 SkString error; | 360 SkString error; |
622 error.printf("Error creating GrContext for config %s. Config wil l be skipped.\n", | 361 error.printf("Error creating GrContext for config %s. Config wil l be skipped.\n", |
623 gConfigs[configIdx].fName); | 362 config.name); |
624 logger.logError(error.c_str()); | 363 logger.logError(error); |
625 configs.remove(i); | 364 configs.remove(i); |
626 --i; | 365 --i; |
627 continue; | 366 continue; |
628 } | 367 } |
629 if (gConfigs[configIdx].fSampleCnt > context->getMaxSampleCount()){ | 368 if (config.sampleCount > context->getMaxSampleCount()){ |
630 SkString error; | 369 SkString error; |
631 error.printf("Sample count (%d) for config %s is unsupported. " | 370 error.printf("Sample count (%d) for config %s is unsupported. " |
632 "Config will be skipped.\n", | 371 "Config will be skipped.\n", |
633 gConfigs[configIdx].fSampleCnt, gConfigs[configIdx] .fName); | 372 config.sampleCount, config.name); |
634 logger.logError(error.c_str()); | 373 logger.logError(error); |
635 configs.remove(i); | 374 configs.remove(i); |
636 --i; | 375 --i; |
637 continue; | 376 continue; |
638 } | 377 } |
639 } | 378 } |
640 } | 379 } |
641 #endif | 380 #endif |
642 | 381 |
643 // report our current settings | 382 // All flags should be parsed now. Report our settings. |
644 { | 383 SkString str("skia bench:"); |
645 SkString str; | 384 str.appendf(" mode=%s", FLAGS_mode[0]); |
646 const char* deferredMode = benchMode == kDeferred_benchModes ? "yes" : | 385 str.appendf(" alpha=0x%02X antialias=%d filter=%d dither=%s", |
647 (benchMode == kDeferredSilent_benchModes ? "silent" : "no"); | 386 alpha, FLAGS_forceAA, FLAGS_forceFilter, SkTriState::Name[dither ]); |
648 str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d " | 387 str.appendf(" rotate=%d scale=%d clip=%d", FLAGS_rotate, FLAGS_scale, FLAGS_ clip); |
649 "deferred=%s logperiter=%d", | 388 |
650 forceAlpha, forceAA, forceFilter, deferredMode, | 389 #if defined(SK_SCALAR_IS_FIXED) |
651 TimerData::kPerIter_Result == timerResult); | 390 str.append(" scalar=fixed"); |
652 str.appendf(" rotate=%d scale=%d clip=%d min=%d", | 391 #else |
653 doRotate, doScale, doClip, TimerData::kMin_Result == timerRes ult); | 392 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 | 393 #endif |
677 | 394 |
678 #if defined(SK_BUILD_FOR_WIN32) | 395 #if defined(SK_BUILD_FOR_WIN32) |
679 str.append(" system=WIN32"); | 396 str.append(" system=WIN32"); |
680 #elif defined(SK_BUILD_FOR_MAC) | 397 #elif defined(SK_BUILD_FOR_MAC) |
681 str.append(" system=MAC"); | 398 str.append(" system=MAC"); |
682 #elif defined(SK_BUILD_FOR_ANDROID) | 399 #elif defined(SK_BUILD_FOR_ANDROID) |
683 str.append(" system=ANDROID"); | 400 str.append(" system=ANDROID"); |
684 #elif defined(SK_BUILD_FOR_UNIX) | 401 #elif defined(SK_BUILD_FOR_UNIX) |
685 str.append(" system=UNIX"); | 402 str.append(" system=UNIX"); |
686 #else | 403 #else |
687 str.append(" system=other"); | 404 str.append(" system=other"); |
688 #endif | 405 #endif |
689 | 406 |
690 #if defined(SK_DEBUG) | 407 #if defined(SK_DEBUG) |
691 str.append(" DEBUG"); | 408 str.append(" DEBUG"); |
692 #endif | 409 #endif |
693 str.append("\n"); | 410 str.append("\n"); |
694 logger.logProgress(str); | 411 logger.logProgress(str); |
695 } | 412 |
696 | 413 |
697 SkTArray<BenchTimer*> timers(SK_ARRAY_COUNT(gConfigs)); | 414 // Set texture cache limits and get timers suitable for each config. |
415 SkTDArray<BenchTimer*> timers; | |
698 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | 416 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { |
699 #if SK_SUPPORT_GPU | 417 #if SK_SUPPORT_GPU |
418 const Config& config = gConfigs[i]; | |
700 SkGLContextHelper* glCtx = NULL; | 419 SkGLContextHelper* glCtx = NULL; |
701 if (kGPU_Backend == gConfigs[i].fBackend) { | 420 if (kGPU_Backend == config.backend) { |
702 GrContext* context = gContextFactory.get(gConfigs[i].fContextType); | 421 GrContext* context = gContextFactory.get(config.contextType); |
703 if (NULL != context) { | 422 if (NULL != context) { |
704 // Set the user specified cache limits if non-default. | 423 // Set the user specified cache limits if non-default. |
705 size_t bytes; | 424 size_t bytes; |
706 int count; | 425 int count; |
707 context->getTextureCacheLimits(&count, &bytes); | 426 context->getTextureCacheLimits(&count, &bytes); |
708 if (-1 != gpuCacheSize.fBytes) { | 427 if (-1 != FLAGS_gpuCacheBytes) { |
709 bytes = static_cast<size_t>(gpuCacheSize.fBytes); | 428 bytes = static_cast<size_t>(FLAGS_gpuCacheBytes); |
710 } | 429 } |
711 if (-1 != gpuCacheSize.fCount) { | 430 if (-1 != FLAGS_gpuCacheCount) { |
712 count = gpuCacheSize.fCount; | 431 count = FLAGS_gpuCacheCount; |
713 } | 432 } |
714 context->setTextureCacheLimits(count, bytes); | 433 context->setTextureCacheLimits(count, bytes); |
715 } | 434 } |
716 glCtx = gContextFactory.getGLContext(gConfigs[i].fContextType); | 435 glCtx = gContextFactory.getGLContext(config.contextType); |
717 } | 436 } |
718 timers.push_back(SkNEW_ARGS(BenchTimer, (glCtx))); | 437 *timers.append() = SkNEW_ARGS(BenchTimer, (glCtx)); |
719 #else | 438 #else |
720 timers.push_back(SkNEW(BenchTimer)); | 439 *timers.append() = SkNEW(BenchTimer); |
721 #endif | 440 #endif |
722 } | 441 } |
723 | 442 |
724 Iter iter(&defineDict); | 443 // Find the longest name of the benches we're going to run to make the outpu t pretty. |
444 Iter names; | |
725 SkBenchmark* bench; | 445 SkBenchmark* bench; |
446 int longestName = 0; | |
447 while ((bench = names.next()) != NULL) { | |
448 SkAutoTUnref<SkBenchmark> benchUnref(bench); | |
449 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { | |
450 continue; | |
451 } | |
452 const int length = strlen(bench->getName()); | |
453 longestName = length > longestName ? length : longestName; | |
454 } | |
455 | |
456 // Run each bench in each configuration it supports and we asked for. | |
epoger
2013/09/04 14:36:40
Where is (was) the outer repeat loop that you dele
mtklein
2013/09/04 19:06:51
Yeah, exactly. Hard to read. It was everything i
| |
457 Iter iter; | |
726 while ((bench = iter.next()) != NULL) { | 458 while ((bench = iter.next()) != NULL) { |
727 SkAutoTUnref<SkBenchmark> benchUnref(bench); | 459 SkAutoTUnref<SkBenchmark> benchUnref(bench); |
728 | 460 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { |
729 SkIPoint dim = bench->getSize(); | |
730 if (dim.fX <= 0 || dim.fY <= 0) { | |
731 continue; | 461 continue; |
732 } | 462 } |
733 | 463 |
734 bench->setForceAlpha(forceAlpha); | 464 bench->setForceAlpha(alpha); |
735 bench->setForceAA(forceAA); | 465 bench->setForceAA(FLAGS_forceAA); |
736 bench->setForceFilter(forceFilter); | 466 bench->setForceFilter(FLAGS_forceFilter); |
737 bench->setDither(forceDither); | 467 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); | 468 AutoPrePostDraw appd(bench); |
750 | 469 |
751 for (int x = 0; x < configs.count(); ++x) { | 470 bool loggedBenchName = false; |
752 int configIndex = configs[x]; | 471 for (int i = 0; i < configs.count(); ++i) { |
753 | 472 const int configIndex = configs[i]; |
754 bool setupFailed = false; | 473 const Config& config = gConfigs[configIndex]; |
755 | 474 |
756 if (kNonRendering_Backend == gConfigs[configIndex].fBackend) { | 475 if ((kNonRendering_Backend == config.backend) == bench->isRendering( )) { |
757 if (bench->isRendering()) { | 476 continue; |
758 continue; | 477 } |
759 } | 478 |
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; | 479 GrContext* context = NULL; |
771 BenchTimer* timer = timers[configIndex]; | |
772 | |
773 #if SK_SUPPORT_GPU | 480 #if SK_SUPPORT_GPU |
774 SkGLContextHelper* glContext = NULL; | 481 SkGLContextHelper* glContext = NULL; |
775 if (kGPU_Backend == backend) { | 482 if (kGPU_Backend == config.backend) { |
776 context = gContextFactory.get(gConfigs[configIndex].fContextType ); | 483 context = gContextFactory.get(config.contextType); |
777 if (NULL == context) { | 484 if (NULL == context) { |
778 continue; | 485 continue; |
779 } | 486 } |
780 glContext = gContextFactory.getGLContext(gConfigs[configIndex].f ContextType); | 487 glContext = gContextFactory.getGLContext(config.contextType); |
781 } | 488 } |
782 #endif | 489 #endif |
783 SkBaseDevice* device = NULL; | 490 SkAutoTUnref<SkBaseDevice> device; |
784 SkCanvas* canvas = NULL; | 491 SkAutoTUnref<SkCanvas> canvas; |
785 SkPicture pictureRecordFrom; | 492 SkPicture recordFrom, recordTo; |
786 SkPicture pictureRecordTo; | 493 const SkIPoint dim = bench->getSize(); |
787 | 494 |
788 if (kNonRendering_Backend != backend) { | 495 const SkPicture::RecordingFlags kRecordFlags = |
789 device = make_device(outConfig, dim, backend, sampleCount, conte xt); | 496 SkPicture::kUsePathBoundsForClip_RecordingFlag; |
790 if (NULL == device) { | 497 |
498 if (kNonRendering_Backend != config.backend) { | |
499 device.reset(make_device(config.config, | |
500 dim, | |
501 config.backend, | |
502 config.sampleCount, | |
503 context)); | |
504 if (!device.get()) { | |
791 SkString error; | 505 SkString error; |
792 error.printf("Device creation failure for config %s. Will sk ip.\n", configName); | 506 error.printf("Device creation failure for config %s. Will sk ip.\n", config.name); |
793 logger.logError(error.c_str()); | 507 logger.logError(error); |
794 setupFailed = true; | 508 continue; |
509 } | |
510 | |
511 switch(benchMode) { | |
512 case kDeferredSilent_BenchMode: | |
513 case kDeferred_BenchMode: | |
514 canvas.reset(SkDeferredCanvas::Create(device.get())); | |
515 break; | |
516 case kRecord_BenchMode: | |
517 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.f Y, kRecordFlags))); | |
518 break; | |
519 case kPictureRecord_BenchMode: | |
520 bench->draw(recordFrom.beginRecording(dim.fX, dim.fY, kR ecordFlags)); | |
521 recordFrom.endRecording(); | |
522 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.f Y, kRecordFlags))); | |
523 break; | |
524 case kNormal_BenchMode: | |
525 canvas.reset(new SkCanvas(device.get())); | |
526 break; | |
527 default: | |
528 SkASSERT(false); | |
529 } | |
530 } | |
531 | |
532 if (NULL != canvas) { | |
533 canvas->clear(SK_ColorWHITE); | |
534 if (FLAGS_clip) { performClip(canvas, dim.fX, dim.fY); } | |
535 if (FLAGS_scale) { performScale(canvas, dim.fX, dim.fY); } | |
536 if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); } | |
537 } | |
538 | |
539 if (!loggedBenchName) { | |
540 loggedBenchName = true; | |
541 SkString str; | |
542 str.printf("running bench [%3d %3d] %*s ", | |
543 dim.fX, dim.fY, longestName, bench->getName()); | |
544 logger.logProgress(str); | |
545 } | |
546 | |
547 BenchTimer* const timer = timers[configIndex]; | |
548 bench->setLoops(0); | |
549 do { | |
550 // Ramp up 1 -> 4 -> 16 -> ... -> ~1 billion. | |
551 const int loops = bench->getLoops(); | |
552 if (loops >= (1<<30)) { | |
epoger
2013/09/04 14:36:40
What's with the magic "30" here? I take it you ar
mtklein
2013/09/04 19:06:51
1<<30 is about a billion, which is a somewhat arbi
epoger
2013/09/04 19:18:26
That all sounds fine, please just paste your expla
mtklein
2013/09/04 19:25:15
Done.
| |
553 SkString str; | |
554 str.printf("Can't ramp %s to %dms.\n", bench->getName(), FLA GS_benchMs); | |
555 logger.logError(str); | |
556 break; | |
557 } | |
558 bench->setLoops(loops == 0 ? 1 : loops * 4); | |
559 | |
560 if ((benchMode == kRecord_BenchMode || benchMode == kPictureReco rd_BenchMode)) { | |
561 // Clear the recorded commands so that they do not accumulat e. | |
562 canvas.reset(recordTo.beginRecording(dim.fX, dim.fY, kRecord Flags)); | |
563 } | |
564 | |
565 timer->start(); | |
566 if (NULL != canvas) { | |
567 canvas->save(); | |
568 } | |
569 if (benchMode == kPictureRecord_BenchMode) { | |
570 recordFrom.draw(canvas); | |
795 } else { | 571 } else { |
796 switch(benchMode) { | 572 bench->draw(canvas); |
797 case kDeferredSilent_benchModes: | 573 } |
798 case kDeferred_benchModes: | 574 |
799 canvas = SkDeferredCanvas::Create(device); | 575 if (kDeferredSilent_BenchMode == benchMode) { |
800 break; | 576 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush(); |
801 case kRecord_benchModes: | 577 } else if (NULL != canvas) { |
802 canvas = pictureRecordTo.beginRecording(dim.fX, dim. fY, | 578 canvas->flush(); |
803 SkPicture::kUsePathBoundsForClip_RecordingFlag); | 579 } |
804 canvas->ref(); | 580 |
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) { | 581 if (NULL != canvas) { |
834 if (doClip) { | 582 canvas->restore(); |
835 performClip(canvas, dim.fX, dim.fY); | 583 } |
836 } | 584 |
837 if (doScale) { | 585 |
838 performScale(canvas, dim.fX, dim.fY); | 586 // Stop truncated timers before GL calls complete, and stop the full timers after. |
839 } | 587 timer->truncatedEnd(); |
840 if (doRotate) { | 588 #if SK_SUPPORT_GPU |
841 performRotate(canvas, dim.fX, dim.fY); | 589 if (NULL != glContext) { |
842 } | 590 context->flush(); |
843 } | 591 SK_GL(*glContext, Finish()); |
844 | 592 } |
845 if (!loggedBenchStart) { | 593 #endif |
846 loggedBenchStart = true; | 594 timer->end(); |
847 SkString str; | 595 } while (!kIsDebug && timer->fWall < FLAGS_benchMs); |
848 str.printf("running bench [%d %d] %28s", dim.fX, dim.fY, ben ch->getName()); | 596 |
849 logger.logProgress(str); | 597 if (kIsDebug) { |
850 } | 598 // Lets not mislead ourselves by looking at Debug build bench ti mes! |
epoger
2013/09/04 14:36:40
I think it would be better to print a warning here
mtklein
2013/09/04 19:06:51
Added one up front.
| |
851 | 599 continue; |
852 // warm up caches if needed | 600 } |
853 if (repeatDraw > 1 && NULL != canvas) { | 601 |
854 #if SK_SUPPORT_GPU | 602 // In same order as TimerTypes, multiplied to normalize times to ms per 1000 iterations. |
epoger
2013/09/04 14:36:40
Does something bad happen if the TimerTypes enum i
mtklein
2013/09/04 19:06:51
now moot
| |
855 // purge the GPU resources to reduce variance | 603 const double normalize = 1000.0 / bench->getLoops(); |
856 if (NULL != context) { | 604 const double times[] = { |
857 context->freeGpuResources(); | 605 normalize * timer->fWall, |
858 } | 606 normalize * timer->fTruncatedWall, |
859 #endif | 607 normalize * timer->fCpu, |
860 SkAutoCanvasRestore acr(canvas, true); | 608 normalize * timer->fTruncatedCpu, |
861 if (benchMode == kPictureRecord_benchModes) { | 609 normalize * timer->fGpu, |
862 pictureRecordFrom.draw(canvas); | 610 }; |
863 } else { | 611 |
864 bench->draw(canvas); | 612 uint32_t filteredTimerTypes = timerTypes; |
865 } | 613 if (NULL == context) { |
866 | 614 filteredTimerTypes &= ~(1<<kGpu_TimerType); |
epoger
2013/09/04 14:36:40
In my fantasy world, this becomes the easier-to-fo
mtklein
2013/09/04 19:06:51
this turned out to be a complete no-op. removed i
| |
867 if (kDeferredSilent_benchModes == benchMode) { | 615 |
868 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); | 616 } |
869 } else { | 617 |
870 canvas->flush(); | 618 SkString result; |
871 } | 619 result.appendf(" %s:", config.name); |
872 #if SK_SUPPORT_GPU | 620 for (size_t i = 0; i < SK_ARRAY_COUNT(TimerType_Name); i++) { |
epoger
2013/09/04 14:36:40
In my fantasy world, this becomes:
for (int typ
mtklein
2013/09/04 19:06:51
Should be moot now. Just out of curiosity, what c
| |
873 if (NULL != context) { | 621 if (filteredTimerTypes & (1<<i) && times[i] > 0) { |
epoger
2013/09/04 14:36:40
Why don't we report this timer if times[i] == 0?
mtklein
2013/09/04 19:06:51
I don't have a opinion on whether we want to print
| |
874 context->flush(); | 622 result.appendf(" %s = ", TimerType_Name[i]); |
875 SK_GL(*glContext, Finish()); | 623 result.appendf(FLAGS_timeFormat[0], times[i]); |
876 } | 624 } |
877 #endif | 625 } |
878 } | 626 logger.logProgress(result); |
879 | 627 |
880 // record timer values for each repeat, and their sum | 628 if (FLAGS_outDir.count() && kNonRendering_Backend != config.backend) { |
881 TimerData timerData(repeatDraw); | 629 saveFile(bench->getName(), |
882 for (int i = 0; i < repeatDraw; i++) { | 630 config.name, |
883 if ((benchMode == kRecord_benchModes || benchMode == kPictur eRecord_benchModes)) { | 631 FLAGS_outDir[0], |
884 // This will clear the recorded commands so that they do not | 632 device->accessBitmap(false)); |
885 // accumulate. | 633 } |
886 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, | 634 } |
887 SkPicture::kUsePathBoundsForClip_RecordingFlag); | 635 if (loggedBenchName) { |
888 } | 636 logger.logProgress("\n"); |
889 | 637 } |
890 timer->start(bench->getDurationScale()); | 638 } |
891 if (NULL != canvas) { | 639 timers.deleteAll(); |
892 canvas->save(); | 640 #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(); | 641 gContextFactory.destroyContexts(); |
967 #endif | 642 #endif |
968 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | |
969 SkDELETE(timers[i]); | |
970 } | |
971 | |
972 return 0; | 643 return 0; |
973 } | 644 } |
974 | 645 |
975 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 646 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
976 int main(int argc, char * const argv[]) { | 647 int main(int argc, char * const argv[]) { |
977 return tool_main(argc, (char**) argv); | 648 return tool_main(argc, (char**) argv); |
978 } | 649 } |
979 #endif | 650 #endif |
OLD | NEW |