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