| 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"); |
| 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 // If you find it takes more than a billion loops to get up
to 20ms of runtime, |
| 544 // you've got a computer clocked at several THz or have a br
oken benchmark. ;) |
| 545 // "1B ought to be enough for anybody." |
| 546 SkString str; |
| 547 str.printf("Can't ramp %s to %dms.\n", bench->getName(), FLA
GS_benchMs); |
| 548 logger.logError(str); |
| 549 break; |
| 550 } |
| 551 bench->setLoops(loops == 0 ? 1 : loops * 4); |
| 552 |
| 553 if ((benchMode == kRecord_BenchMode || benchMode == kPictureReco
rd_BenchMode)) { |
| 554 // Clear the recorded commands so that they do not accumulat
e. |
| 555 canvas.reset(recordTo.beginRecording(dim.fX, dim.fY, kRecord
Flags)); |
| 556 } |
| 557 |
| 558 timer.start(); |
| 559 if (NULL != canvas) { |
| 560 canvas->save(); |
| 561 } |
| 562 if (benchMode == kPictureRecord_BenchMode) { |
| 563 recordFrom.draw(canvas); |
| 795 } else { | 564 } else { |
| 796 switch(benchMode) { | 565 bench->draw(canvas); |
| 797 case kDeferredSilent_benchModes: | 566 } |
| 798 case kDeferred_benchModes: | 567 |
| 799 canvas = SkDeferredCanvas::Create(device); | 568 if (kDeferredSilent_BenchMode == benchMode) { |
| 800 break; | 569 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush(); |
| 801 case kRecord_benchModes: | 570 } else if (NULL != canvas) { |
| 802 canvas = pictureRecordTo.beginRecording(dim.fX, dim.
fY, | 571 canvas->flush(); |
| 803 SkPicture::kUsePathBoundsForClip_RecordingFlag); | 572 } |
| 804 canvas->ref(); | 573 |
| 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) { | 574 if (NULL != canvas) { |
| 834 if (doClip) { | 575 canvas->restore(); |
| 835 performClip(canvas, dim.fX, dim.fY); | 576 } |
| 836 } | 577 |
| 837 if (doScale) { | 578 |
| 838 performScale(canvas, dim.fX, dim.fY); | 579 // Stop truncated timers before GL calls complete, and stop the
full timers after. |
| 839 } | 580 timer.truncatedEnd(); |
| 840 if (doRotate) { | 581 #if SK_SUPPORT_GPU |
| 841 performRotate(canvas, dim.fX, dim.fY); | 582 if (NULL != glContext) { |
| 842 } | 583 context->flush(); |
| 843 } | 584 SK_GL(*glContext, Finish()); |
| 844 | 585 } |
| 845 if (!loggedBenchStart) { | 586 #endif |
| 846 loggedBenchStart = true; | 587 timer.end(); |
| 847 SkString str; | 588 } 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()); | 589 |
| 849 logger.logProgress(str); | 590 if (FLAGS_outDir.count() && kNonRendering_Backend != config.backend)
{ |
| 850 } | 591 saveFile(bench->getName(), |
| 851 | 592 config.name, |
| 852 // warm up caches if needed | 593 FLAGS_outDir[0], |
| 853 if (repeatDraw > 1 && NULL != canvas) { | 594 device->accessBitmap(false)); |
| 854 #if SK_SUPPORT_GPU | 595 } |
| 855 // purge the GPU resources to reduce variance | 596 |
| 856 if (NULL != context) { | 597 if (kIsDebug) { |
| 857 context->freeGpuResources(); | 598 // Let's not mislead ourselves by looking at Debug build bench t
imes! |
| 858 } | 599 continue; |
| 859 #endif | 600 } |
| 860 SkAutoCanvasRestore acr(canvas, true); | 601 |
| 861 if (benchMode == kPictureRecord_benchModes) { | 602 // Normalize to ms per 1000 iterations. |
| 862 pictureRecordFrom.draw(canvas); | 603 const double normalize = 1000.0 / bench->getLoops(); |
| 863 } else { | 604 const struct { char shortName; const char* longName; double ms; } ti
mes[] = { |
| 864 bench->draw(canvas); | 605 {'w', "msecs", normalize * timer.fWall}, |
| 865 } | 606 {'W', "Wmsecs", normalize * timer.fTruncatedWall}, |
| 866 | 607 {'c', "cmsecs", normalize * timer.fCpu}, |
| 867 if (kDeferredSilent_benchModes == benchMode) { | 608 {'C', "Cmsecs", normalize * timer.fTruncatedCpu}, |
| 868 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); | 609 {'g', "gmsecs", normalize * timer.fGpu}, |
| 869 } else { | 610 }; |
| 870 canvas->flush(); | 611 |
| 871 } | 612 SkString result; |
| 872 #if SK_SUPPORT_GPU | 613 result.appendf(" %s:", config.name); |
| 873 if (NULL != context) { | 614 for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) { |
| 874 context->flush(); | 615 if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms >
0) { |
| 875 SK_GL(*glContext, Finish()); | 616 result.appendf(" %s = ", times[i].longName); |
| 876 } | 617 result.appendf(FLAGS_timeFormat[0], times[i].ms); |
| 877 #endif | 618 } |
| 878 } | 619 } |
| 879 | 620 logger.logProgress(result); |
| 880 // record timer values for each repeat, and their sum | 621 } |
| 881 TimerData timerData(repeatDraw); | 622 if (loggedBenchName) { |
| 882 for (int i = 0; i < repeatDraw; i++) { | 623 logger.logProgress("\n"); |
| 883 if ((benchMode == kRecord_benchModes || benchMode == kPictur
eRecord_benchModes)) { | 624 } |
| 884 // This will clear the recorded commands so that they do
not | 625 } |
| 885 // accumulate. | 626 #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 const char* timeFormat; | |
| 927 if (repeatDraw > 1 && TimerData::kPerIter_Result == timerResult)
{ | |
| 928 timeFormat = perIterTimeformat.c_str(); | |
| 929 } else { | |
| 930 timeFormat = normalTimeFormat.c_str(); | |
| 931 } | |
| 932 uint32_t filteredTimerTypes = timerTypes; | |
| 933 if (NULL == context) { | |
| 934 filteredTimerTypes &= ~TimerData::kGpu_Flag; | |
| 935 } | |
| 936 SkString result = timerData.getResult(timeFormat, | |
| 937 timerResult, | |
| 938 configName, | |
| 939 filteredTimerTypes); | |
| 940 logger.logProgress(result); | |
| 941 | |
| 942 if (outDir.size() > 0 && kNonRendering_Backend != backend) { | |
| 943 saveFile(bench->getName(), configName, outDir.c_str(), | |
| 944 device->accessBitmap(false)); | |
| 945 } | |
| 946 } | |
| 947 } | |
| 948 if (loggedBenchStart) { | |
| 949 logger.logProgress(SkString("\n")); | |
| 950 } | |
| 951 } | |
| 952 #if SK_SUPPORT_GPU | |
| 953 #if GR_CACHE_STATS | |
| 954 for (int i = 0; i <= GrContextFactory::kLastGLContextType; ++i) { | |
| 955 GrContextFactory::GLContextType ctxType = (GrContextFactory::GLContextTy
pe)i; | |
| 956 GrContext* context = gContextFactory.get(ctxType); | |
| 957 if (NULL != context) { | |
| 958 SkDebugf("Cache Stats for %s context:\n", GrContextFactory::GLContex
tTypeName(ctxType)); | |
| 959 context->printCacheStats(); | |
| 960 SkDebugf("\n"); | |
| 961 } | |
| 962 } | |
| 963 #endif | |
| 964 // Destroy the GrContext before the inst tracking printing at main() exit oc
curs. | |
| 965 gContextFactory.destroyContexts(); | 627 gContextFactory.destroyContexts(); |
| 966 #endif | 628 #endif |
| 967 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { | |
| 968 SkDELETE(timers[i]); | |
| 969 } | |
| 970 | |
| 971 return 0; | 629 return 0; |
| 972 } | 630 } |
| 973 | 631 |
| 974 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 632 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
| 975 int main(int argc, char * const argv[]) { | 633 int main(int argc, char * const argv[]) { |
| 976 return tool_main(argc, (char**) argv); | 634 return tool_main(argc, (char**) argv); |
| 977 } | 635 } |
| 978 #endif | 636 #endif |
| OLD | NEW |