| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2012 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #include "LazyDecodeBitmap.h" | |
| 9 #include "CopyTilesRenderer.h" | |
| 10 #include "SkBitmap.h" | |
| 11 #include "SkDevice.h" | |
| 12 #include "SkCommandLineFlags.h" | |
| 13 #include "SkGraphics.h" | |
| 14 #include "SkImageDecoder.h" | |
| 15 #include "SkImageEncoder.h" | |
| 16 #include "SkMath.h" | |
| 17 #include "SkOSFile.h" | |
| 18 #include "SkPicture.h" | |
| 19 #include "SkPictureRecorder.h" | |
| 20 #include "SkStream.h" | |
| 21 #include "SkString.h" | |
| 22 | |
| 23 #include "image_expectations.h" | |
| 24 #include "PictureRenderer.h" | |
| 25 #include "PictureRenderingFlags.h" | |
| 26 #include "picture_utils.h" | |
| 27 | |
| 28 #include <stdlib.h> | |
| 29 | |
| 30 // Flags used by this file, alphabetically: | |
| 31 DEFINE_bool(bench_record, false, "If true, drop into an infinite loop of recordi
ng the picture."); | |
| 32 DECLARE_bool(deferImageDecoding); | |
| 33 DEFINE_string(descriptions, "", "one or more key=value pairs to add to the descr
iptions section " | |
| 34 "of the JSON summary."); | |
| 35 DEFINE_string(imageBaseGSUrl, "", "The Google Storage image base URL the images
are stored in."); | |
| 36 DEFINE_int32(maxComponentDiff, 256, "Maximum diff on a component, 0 - 256. Compo
nents that differ " | |
| 37 "by more than this amount are considered errors, though all diffs a
re reported. " | |
| 38 "Requires --validate."); | |
| 39 DEFINE_string(mismatchPath, "", "Write images for tests that failed due to " | |
| 40 "pixel mismatches into this directory."); | |
| 41 #if GR_GPU_STATS | |
| 42 DEFINE_bool(gpuStats, false, "Only meaningful with gpu configurations. " | |
| 43 "Report some GPU call statistics."); | |
| 44 #endif | |
| 45 DEFINE_bool(mpd, false, "If true, use MultiPictureDraw for rendering."); | |
| 46 DEFINE_string(readJsonSummaryPath, "", "JSON file to read image expectations fro
m."); | |
| 47 DECLARE_string(readPath); | |
| 48 DEFINE_bool(writeChecksumBasedFilenames, false, | |
| 49 "When writing out images, use checksum-based filenames."); | |
| 50 DEFINE_bool(writeEncodedImages, false, "Any time the skp contains an encoded ima
ge, write it to a " | |
| 51 "file rather than decoding it. Requires writePath to be set. Skips d
rawing the full " | |
| 52 "skp to a file. Not compatible with deferImageDecoding."); | |
| 53 DEFINE_string(writeJsonSummaryPath, "", "File to write a JSON summary of image r
esults to."); | |
| 54 DEFINE_string2(writePath, w, "", "Directory to write the rendered images into.")
; | |
| 55 DEFINE_bool(writeWholeImage, false, "In tile mode, write the entire rendered ima
ge to a " | |
| 56 "file, instead of an image for each tile."); | |
| 57 DEFINE_bool(validate, false, "Verify that the rendered image contains the same p
ixels as " | |
| 58 "the picture rendered in simple mode. When used in conjunction with
--bbh, results " | |
| 59 "are validated against the picture rendered in the same mode, but wi
thout the bbh."); | |
| 60 | |
| 61 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
| 62 | |
| 63 /** | |
| 64 * Table for translating from format of data to a suffix. | |
| 65 */ | |
| 66 struct Format { | |
| 67 SkImageDecoder::Format fFormat; | |
| 68 const char* fSuffix; | |
| 69 }; | |
| 70 static const Format gFormats[] = { | |
| 71 { SkImageDecoder::kBMP_Format, ".bmp" }, | |
| 72 { SkImageDecoder::kGIF_Format, ".gif" }, | |
| 73 { SkImageDecoder::kICO_Format, ".ico" }, | |
| 74 { SkImageDecoder::kJPEG_Format, ".jpg" }, | |
| 75 { SkImageDecoder::kPNG_Format, ".png" }, | |
| 76 { SkImageDecoder::kWBMP_Format, ".wbmp" }, | |
| 77 { SkImageDecoder::kWEBP_Format, ".webp" }, | |
| 78 { SkImageDecoder::kUnknown_Format, "" }, | |
| 79 }; | |
| 80 | |
| 81 /** | |
| 82 * Get an appropriate suffix for an image format. | |
| 83 */ | |
| 84 static const char* get_suffix_from_format(SkImageDecoder::Format format) { | |
| 85 for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) { | |
| 86 if (gFormats[i].fFormat == format) { | |
| 87 return gFormats[i].fSuffix; | |
| 88 } | |
| 89 } | |
| 90 return ""; | |
| 91 } | |
| 92 | |
| 93 /** | |
| 94 * Base name for an image file created from the encoded data in an skp. | |
| 95 */ | |
| 96 static SkString gInputFileName; | |
| 97 | |
| 98 /** | |
| 99 * Number to be appended to the image file name so that it is unique. | |
| 100 */ | |
| 101 static uint32_t gImageNo; | |
| 102 | |
| 103 /** | |
| 104 * Set up the name for writing encoded data to a file. | |
| 105 * Sets gInputFileName to name, minus any extension ".*" | |
| 106 * Sets gImageNo to 0, so images from file "X.skp" will | |
| 107 * look like "X_<gImageNo>.<suffix>", beginning with 0 | |
| 108 * for each new skp. | |
| 109 */ | |
| 110 static void reset_image_file_base_name(const SkString& name) { | |
| 111 gImageNo = 0; | |
| 112 // Remove ".skp" | |
| 113 const char* cName = name.c_str(); | |
| 114 const char* dot = strrchr(cName, '.'); | |
| 115 if (dot != nullptr) { | |
| 116 gInputFileName.set(cName, dot - cName); | |
| 117 } else { | |
| 118 gInputFileName.set(name); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * Write the raw encoded bitmap data to a file. | |
| 124 */ | |
| 125 static bool write_image_to_file(const void* buffer, size_t size, SkBitmap* bitma
p) { | |
| 126 SkASSERT(!FLAGS_writePath.isEmpty()); | |
| 127 SkMemoryStream memStream(buffer, size); | |
| 128 SkString outPath; | |
| 129 SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&memStream); | |
| 130 SkString name = SkStringPrintf("%s_%d%s", gInputFileName.c_str(), gImageNo++
, | |
| 131 get_suffix_from_format(format)); | |
| 132 SkString dir(FLAGS_writePath[0]); | |
| 133 outPath = SkOSPath::Join(dir.c_str(), name.c_str()); | |
| 134 SkFILEWStream fileStream(outPath.c_str()); | |
| 135 if (!(fileStream.isValid() && fileStream.write(buffer, size))) { | |
| 136 SkDebugf("Failed to write encoded data to \"%s\"\n", outPath.c_str()); | |
| 137 } | |
| 138 // Put in a dummy bitmap. | |
| 139 return SkImageDecoder::DecodeStream(&memStream, bitmap, kUnknown_SkColorType
, | |
| 140 SkImageDecoder::kDecodeBounds_Mode); | |
| 141 } | |
| 142 | |
| 143 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
| 144 | |
| 145 /** | |
| 146 * Called only by render_picture(). | |
| 147 */ | |
| 148 static bool render_picture_internal(const SkString& inputPath, const SkString* w
ritePath, | |
| 149 const SkString* mismatchPath, | |
| 150 sk_tools::PictureRenderer& renderer, | |
| 151 SkBitmap** out) { | |
| 152 SkString inputFilename = SkOSPath::Basename(inputPath.c_str()); | |
| 153 SkString writePathString; | |
| 154 if (writePath && writePath->size() > 0 && !FLAGS_writeEncodedImages) { | |
| 155 writePathString.set(*writePath); | |
| 156 } | |
| 157 SkString mismatchPathString; | |
| 158 if (mismatchPath && mismatchPath->size() > 0) { | |
| 159 mismatchPathString.set(*mismatchPath); | |
| 160 } | |
| 161 | |
| 162 SkFILEStream inputStream; | |
| 163 inputStream.setPath(inputPath.c_str()); | |
| 164 if (!inputStream.isValid()) { | |
| 165 SkDebugf("Could not open file %s\n", inputPath.c_str()); | |
| 166 return false; | |
| 167 } | |
| 168 | |
| 169 SkPicture::InstallPixelRefProc proc; | |
| 170 if (FLAGS_deferImageDecoding) { | |
| 171 proc = &sk_tools::LazyDecodeBitmap; | |
| 172 } else if (FLAGS_writeEncodedImages) { | |
| 173 SkASSERT(!FLAGS_writePath.isEmpty()); | |
| 174 reset_image_file_base_name(inputFilename); | |
| 175 proc = &write_image_to_file; | |
| 176 } else { | |
| 177 proc = &SkImageDecoder::DecodeMemory; | |
| 178 } | |
| 179 | |
| 180 SkDebugf("deserializing... %s\n", inputPath.c_str()); | |
| 181 | |
| 182 SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&inputStream, pr
oc)); | |
| 183 | |
| 184 if (nullptr == picture) { | |
| 185 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); | |
| 186 return false; | |
| 187 } | |
| 188 | |
| 189 while (FLAGS_bench_record) { | |
| 190 SkPictureRecorder recorder; | |
| 191 picture->playback(recorder.beginRecording(picture->cullRect().width(), | |
| 192 picture->cullRect().height(), | |
| 193 nullptr, 0)); | |
| 194 SkAutoTUnref<SkPicture> other(recorder.endRecording()); | |
| 195 } | |
| 196 | |
| 197 SkDebugf("drawing... [%f %f %f %f] %s\n", | |
| 198 picture->cullRect().fLeft, picture->cullRect().fTop, | |
| 199 picture->cullRect().fRight, picture->cullRect().fBottom, | |
| 200 inputPath.c_str()); | |
| 201 | |
| 202 renderer.init(picture, &writePathString, &mismatchPathString, &inputFilename
, | |
| 203 FLAGS_writeChecksumBasedFilenames, FLAGS_mpd); | |
| 204 | |
| 205 renderer.setup(); | |
| 206 renderer.enableWrites(); | |
| 207 | |
| 208 bool success = renderer.render(out); | |
| 209 if (!success) { | |
| 210 SkDebugf("Failed to render %s\n", inputFilename.c_str()); | |
| 211 } | |
| 212 | |
| 213 renderer.end(); | |
| 214 | |
| 215 return success; | |
| 216 } | |
| 217 | |
| 218 static inline int getByte(uint32_t value, int index) { | |
| 219 SkASSERT(0 <= index && index < 4); | |
| 220 return (value >> (index * 8)) & 0xFF; | |
| 221 } | |
| 222 | |
| 223 static int MaxByteDiff(uint32_t v1, uint32_t v2) { | |
| 224 return SkMax32(SkMax32(SkTAbs(getByte(v1, 0) - getByte(v2, 0)), SkTAbs(getBy
te(v1, 1) - getByte(v2, 1))), | |
| 225 SkMax32(SkTAbs(getByte(v1, 2) - getByte(v2, 2)), SkTAbs(getBy
te(v1, 3) - getByte(v2, 3)))); | |
| 226 } | |
| 227 | |
| 228 class AutoRestoreBbhType { | |
| 229 public: | |
| 230 AutoRestoreBbhType() { | |
| 231 fRenderer = nullptr; | |
| 232 fSavedBbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType; | |
| 233 } | |
| 234 | |
| 235 void set(sk_tools::PictureRenderer* renderer, | |
| 236 sk_tools::PictureRenderer::BBoxHierarchyType bbhType) { | |
| 237 fRenderer = renderer; | |
| 238 fSavedBbhType = renderer->getBBoxHierarchyType(); | |
| 239 renderer->setBBoxHierarchyType(bbhType); | |
| 240 } | |
| 241 | |
| 242 ~AutoRestoreBbhType() { | |
| 243 if (fRenderer) { | |
| 244 fRenderer->setBBoxHierarchyType(fSavedBbhType); | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 private: | |
| 249 sk_tools::PictureRenderer* fRenderer; | |
| 250 sk_tools::PictureRenderer::BBoxHierarchyType fSavedBbhType; | |
| 251 }; | |
| 252 | |
| 253 /** | |
| 254 * Render the SKP file(s) within inputPath. | |
| 255 * | |
| 256 * @param inputPath path to an individual SKP file, or a directory of SKP files | |
| 257 * @param writePath if not nullptr, write all image(s) generated into this direc
tory | |
| 258 * @param mismatchPath if not nullptr, write any image(s) not matching expectati
ons into this directory | |
| 259 * @param renderer PictureRenderer to use to render the SKPs | |
| 260 * @param jsonSummaryPtr if not nullptr, add the image(s) generated to this summ
ary | |
| 261 */ | |
| 262 static bool render_picture(const SkString& inputPath, const SkString* writePath, | |
| 263 const SkString* mismatchPath, sk_tools::PictureRender
er& renderer, | |
| 264 sk_tools::ImageResultsAndExpectations *jsonSummaryPtr
) { | |
| 265 int diffs[256] = {0}; | |
| 266 SkBitmap* bitmap = nullptr; | |
| 267 renderer.setJsonSummaryPtr(jsonSummaryPtr); | |
| 268 bool success = render_picture_internal(inputPath, | |
| 269 FLAGS_writeWholeImage ? nullptr : writePath, | |
| 270 FLAGS_writeWholeImage ? nullptr : mismatchPath, | |
| 271 renderer, | |
| 272 FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : nullptr); | |
| 273 | |
| 274 if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == null
ptr)) { | |
| 275 SkDebugf("Failed to draw the picture.\n"); | |
| 276 delete bitmap; | |
| 277 return false; | |
| 278 } | |
| 279 | |
| 280 if (FLAGS_validate) { | |
| 281 SkBitmap* referenceBitmap = nullptr; | |
| 282 sk_tools::PictureRenderer* referenceRenderer; | |
| 283 // If the renderer uses a BBoxHierarchy, then the reference renderer | |
| 284 // will be the same renderer, without the bbh. | |
| 285 AutoRestoreBbhType arbbh; | |
| 286 if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType != | |
| 287 renderer.getBBoxHierarchyType()) { | |
| 288 referenceRenderer = &renderer; | |
| 289 referenceRenderer->ref(); // to match auto unref below | |
| 290 arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHi
erarchyType); | |
| 291 } else { | |
| 292 #if SK_SUPPORT_GPU | |
| 293 referenceRenderer = new sk_tools::SimplePictureRenderer(renderer.get
GrContextOptions()); | |
| 294 #else | |
| 295 referenceRenderer = new sk_tools::SimplePictureRenderer; | |
| 296 #endif | |
| 297 } | |
| 298 SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRe
nderer); | |
| 299 | |
| 300 success = render_picture_internal(inputPath, nullptr, nullptr, *referenc
eRenderer, | |
| 301 &referenceBitmap); | |
| 302 | |
| 303 if (!success || nullptr == referenceBitmap || nullptr == referenceBitmap
->getPixels()) { | |
| 304 SkDebugf("Failed to draw the reference picture.\n"); | |
| 305 delete bitmap; | |
| 306 delete referenceBitmap; | |
| 307 return false; | |
| 308 } | |
| 309 | |
| 310 if (success && (bitmap->width() != referenceBitmap->width())) { | |
| 311 SkDebugf("Expected image width: %i, actual image width %i.\n", | |
| 312 referenceBitmap->width(), bitmap->width()); | |
| 313 delete bitmap; | |
| 314 delete referenceBitmap; | |
| 315 return false; | |
| 316 } | |
| 317 if (success && (bitmap->height() != referenceBitmap->height())) { | |
| 318 SkDebugf("Expected image height: %i, actual image height %i", | |
| 319 referenceBitmap->height(), bitmap->height()); | |
| 320 delete bitmap; | |
| 321 delete referenceBitmap; | |
| 322 return false; | |
| 323 } | |
| 324 | |
| 325 for (int y = 0; success && y < bitmap->height(); y++) { | |
| 326 for (int x = 0; success && x < bitmap->width(); x++) { | |
| 327 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y), | |
| 328 *bitmap->getAddr32(x, y)); | |
| 329 SkASSERT(diff >= 0 && diff <= 255); | |
| 330 diffs[diff]++; | |
| 331 | |
| 332 if (diff > FLAGS_maxComponentDiff) { | |
| 333 SkDebugf("Expected pixel at (%i %i) exceedds maximum " | |
| 334 "component diff of %i: 0x%x, actual 0x%x\n", | |
| 335 x, y, FLAGS_maxComponentDiff, | |
| 336 *referenceBitmap->getAddr32(x, y), | |
| 337 *bitmap->getAddr32(x, y)); | |
| 338 delete bitmap; | |
| 339 delete referenceBitmap; | |
| 340 return false; | |
| 341 } | |
| 342 } | |
| 343 } | |
| 344 delete referenceBitmap; | |
| 345 | |
| 346 for (int i = 1; i <= 255; ++i) { | |
| 347 if(diffs[i] > 0) { | |
| 348 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diff
s[i]); | |
| 349 } | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 if (FLAGS_writeWholeImage) { | |
| 354 sk_tools::force_all_opaque(*bitmap); | |
| 355 | |
| 356 SkString inputFilename = SkOSPath::Basename(inputPath.c_str()); | |
| 357 SkString outputFilename(inputFilename); | |
| 358 sk_tools::replace_char(&outputFilename, '.', '_'); | |
| 359 outputFilename.append(".png"); | |
| 360 | |
| 361 if (jsonSummaryPtr) { | |
| 362 sk_tools::ImageDigest imageDigest(*bitmap); | |
| 363 jsonSummaryPtr->add(inputFilename.c_str(), outputFilename.c_str(), i
mageDigest); | |
| 364 if ((mismatchPath) && !mismatchPath->isEmpty() && | |
| 365 !jsonSummaryPtr->getExpectation(inputFilename.c_str()).matches(i
mageDigest)) { | |
| 366 success &= sk_tools::write_bitmap_to_disk(*bitmap, *mismatchPath
, nullptr, | |
| 367 outputFilename); | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 if ((writePath) && !writePath->isEmpty()) { | |
| 372 success &= sk_tools::write_bitmap_to_disk(*bitmap, *writePath, nullp
tr, outputFilename); | |
| 373 } | |
| 374 } | |
| 375 delete bitmap; | |
| 376 | |
| 377 return success; | |
| 378 } | |
| 379 | |
| 380 | |
| 381 static int process_input(const char* input, const SkString* writePath, | |
| 382 const SkString* mismatchPath, sk_tools::PictureRenderer
& renderer, | |
| 383 sk_tools::ImageResultsAndExpectations *jsonSummaryPtr)
{ | |
| 384 SkOSFile::Iter iter(input, "skp"); | |
| 385 SkString inputFilename; | |
| 386 int failures = 0; | |
| 387 SkDebugf("process_input, %s\n", input); | |
| 388 if (iter.next(&inputFilename)) { | |
| 389 do { | |
| 390 SkString inputPath = SkOSPath::Join(input, inputFilename.c_str()); | |
| 391 if (!render_picture(inputPath, writePath, mismatchPath, renderer, js
onSummaryPtr)) { | |
| 392 ++failures; | |
| 393 } | |
| 394 } while(iter.next(&inputFilename)); | |
| 395 } else if (SkStrEndsWith(input, ".skp")) { | |
| 396 SkString inputPath(input); | |
| 397 if (!render_picture(inputPath, writePath, mismatchPath, renderer, jsonSu
mmaryPtr)) { | |
| 398 ++failures; | |
| 399 } | |
| 400 } else { | |
| 401 SkString warning; | |
| 402 warning.printf("Warning: skipping %s\n", input); | |
| 403 SkDebugf("%s", warning.c_str()); | |
| 404 } | |
| 405 return failures; | |
| 406 } | |
| 407 | |
| 408 int tool_main(int argc, char** argv); | |
| 409 int tool_main(int argc, char** argv) { | |
| 410 SkCommandLineFlags::SetUsage("Render .skp files."); | |
| 411 SkCommandLineFlags::Parse(argc, argv); | |
| 412 | |
| 413 if (FLAGS_readPath.isEmpty()) { | |
| 414 SkDebugf(".skp files or directories are required.\n"); | |
| 415 exit(-1); | |
| 416 } | |
| 417 | |
| 418 if (FLAGS_maxComponentDiff < 0 || FLAGS_maxComponentDiff > 256) { | |
| 419 SkDebugf("--maxComponentDiff must be between 0 and 256\n"); | |
| 420 exit(-1); | |
| 421 } | |
| 422 | |
| 423 if (FLAGS_maxComponentDiff != 256 && !FLAGS_validate) { | |
| 424 SkDebugf("--maxComponentDiff requires --validate\n"); | |
| 425 exit(-1); | |
| 426 } | |
| 427 | |
| 428 if (FLAGS_writeEncodedImages) { | |
| 429 if (FLAGS_writePath.isEmpty()) { | |
| 430 SkDebugf("--writeEncodedImages requires --writePath\n"); | |
| 431 exit(-1); | |
| 432 } | |
| 433 if (FLAGS_deferImageDecoding) { | |
| 434 SkDebugf("--writeEncodedImages is not compatible with --deferImageDe
coding\n"); | |
| 435 exit(-1); | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 SkString errorString; | |
| 440 SkAutoTUnref<sk_tools::PictureRenderer> renderer(parseRenderer(errorString, | |
| 441 kRender_Pictu
reTool)); | |
| 442 if (errorString.size() > 0) { | |
| 443 SkDebugf("%s\n", errorString.c_str()); | |
| 444 } | |
| 445 | |
| 446 if (renderer.get() == nullptr) { | |
| 447 exit(-1); | |
| 448 } | |
| 449 | |
| 450 SkAutoGraphics ag; | |
| 451 | |
| 452 SkString writePath; | |
| 453 if (FLAGS_writePath.count() == 1) { | |
| 454 writePath.set(FLAGS_writePath[0]); | |
| 455 } | |
| 456 SkString mismatchPath; | |
| 457 if (FLAGS_mismatchPath.count() == 1) { | |
| 458 mismatchPath.set(FLAGS_mismatchPath[0]); | |
| 459 } | |
| 460 sk_tools::ImageResultsAndExpectations jsonSummary; | |
| 461 sk_tools::ImageResultsAndExpectations* jsonSummaryPtr = nullptr; | |
| 462 if (FLAGS_writeJsonSummaryPath.count() == 1) { | |
| 463 jsonSummaryPtr = &jsonSummary; | |
| 464 if (FLAGS_readJsonSummaryPath.count() == 1) { | |
| 465 SkASSERT(jsonSummary.readExpectationsFile(FLAGS_readJsonSummaryPath[
0])); | |
| 466 } | |
| 467 } | |
| 468 | |
| 469 int failures = 0; | |
| 470 for (int i = 0; i < FLAGS_readPath.count(); i ++) { | |
| 471 failures += process_input(FLAGS_readPath[i], &writePath, &mismatchPath,
*renderer.get(), | |
| 472 jsonSummaryPtr); | |
| 473 } | |
| 474 if (failures != 0) { | |
| 475 SkDebugf("Failed to render %i pictures.\n", failures); | |
| 476 return 1; | |
| 477 } | |
| 478 #if GR_CACHE_STATS && SK_SUPPORT_GPU | |
| 479 if (renderer->isUsingGpuDevice()) { | |
| 480 GrContext* ctx = renderer->getGrContext(); | |
| 481 ctx->printCacheStats(); | |
| 482 } | |
| 483 #endif | |
| 484 | |
| 485 #if GR_GPU_STATS && SK_SUPPORT_GPU | |
| 486 if (FLAGS_gpuStats && renderer->isUsingGpuDevice()) { | |
| 487 renderer->getGrContext()->printGpuStats(); | |
| 488 } | |
| 489 #endif | |
| 490 | |
| 491 if (FLAGS_writeJsonSummaryPath.count() == 1) { | |
| 492 // If there were any descriptions on the command line, insert them now. | |
| 493 for (int i=0; i<FLAGS_descriptions.count(); i++) { | |
| 494 SkTArray<SkString> tokens; | |
| 495 SkStrSplit(FLAGS_descriptions[i], "=", &tokens); | |
| 496 SkASSERT(tokens.count() == 2); | |
| 497 jsonSummary.addDescription(tokens[0].c_str(), tokens[1].c_str()); | |
| 498 } | |
| 499 if (FLAGS_imageBaseGSUrl.count() == 1) { | |
| 500 jsonSummary.setImageBaseGSUrl(FLAGS_imageBaseGSUrl[0]); | |
| 501 } | |
| 502 jsonSummary.writeToFile(FLAGS_writeJsonSummaryPath[0]); | |
| 503 } | |
| 504 return 0; | |
| 505 } | |
| 506 | |
| 507 #if !defined SK_BUILD_FOR_IOS | |
| 508 int main(int argc, char * const argv[]) { | |
| 509 return tool_main(argc, (char**) argv); | |
| 510 } | |
| 511 #endif | |
| OLD | NEW |