OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "LazyDecodeBitmap.h" | 8 #include "LazyDecodeBitmap.h" |
9 #include "CopyTilesRenderer.h" | 9 #include "CopyTilesRenderer.h" |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "PictureRenderer.h" | 24 #include "PictureRenderer.h" |
25 #include "PictureRenderingFlags.h" | 25 #include "PictureRenderingFlags.h" |
26 #include "picture_utils.h" | 26 #include "picture_utils.h" |
27 | 27 |
28 // Flags used by this file, alphabetically: | 28 // Flags used by this file, alphabetically: |
29 DEFINE_int32(clone, 0, "Clone the picture n times before rendering."); | 29 DEFINE_int32(clone, 0, "Clone the picture n times before rendering."); |
30 DECLARE_bool(deferImageDecoding); | 30 DECLARE_bool(deferImageDecoding); |
31 DEFINE_int32(maxComponentDiff, 256, "Maximum diff on a component, 0 - 256. Compo
nents that differ " | 31 DEFINE_int32(maxComponentDiff, 256, "Maximum diff on a component, 0 - 256. Compo
nents that differ " |
32 "by more than this amount are considered errors, though all diffs a
re reported. " | 32 "by more than this amount are considered errors, though all diffs a
re reported. " |
33 "Requires --validate."); | 33 "Requires --validate."); |
| 34 DEFINE_string(mismatchPath, "", "Write images for tests that failed due to " |
| 35 "pixel mismatches into this directory."); |
34 DEFINE_string(readJsonSummaryPath, "", "JSON file to read image expectations fro
m."); | 36 DEFINE_string(readJsonSummaryPath, "", "JSON file to read image expectations fro
m."); |
35 DECLARE_string(readPath); | 37 DECLARE_string(readPath); |
36 DEFINE_bool(writeChecksumBasedFilenames, false, | 38 DEFINE_bool(writeChecksumBasedFilenames, false, |
37 "When writing out images, use checksum-based filenames."); | 39 "When writing out images, use checksum-based filenames."); |
38 DEFINE_bool(writeEncodedImages, false, "Any time the skp contains an encoded ima
ge, write it to a " | 40 DEFINE_bool(writeEncodedImages, false, "Any time the skp contains an encoded ima
ge, write it to a " |
39 "file rather than decoding it. Requires writePath to be set. Skips d
rawing the full " | 41 "file rather than decoding it. Requires writePath to be set. Skips d
rawing the full " |
40 "skp to a file. Not compatible with deferImageDecoding."); | 42 "skp to a file. Not compatible with deferImageDecoding."); |
41 DEFINE_string(writeJsonSummaryPath, "", "File to write a JSON summary of image r
esults to."); | 43 DEFINE_string(writeJsonSummaryPath, "", "File to write a JSON summary of image r
esults to."); |
42 DEFINE_string2(writePath, w, "", "Directory to write the rendered images into.")
; | 44 DEFINE_string2(writePath, w, "", "Directory to write the rendered images into.")
; |
43 DEFINE_bool(writeWholeImage, false, "In tile mode, write the entire rendered ima
ge to a " | 45 DEFINE_bool(writeWholeImage, false, "In tile mode, write the entire rendered ima
ge to a " |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 // Put in a dummy bitmap. | 132 // Put in a dummy bitmap. |
131 return SkImageDecoder::DecodeStream(&memStream, bitmap, SkBitmap::kNo_Config
, | 133 return SkImageDecoder::DecodeStream(&memStream, bitmap, SkBitmap::kNo_Config
, |
132 SkImageDecoder::kDecodeBounds_Mode); | 134 SkImageDecoder::kDecodeBounds_Mode); |
133 } | 135 } |
134 | 136 |
135 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 137 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
136 | 138 |
137 /** | 139 /** |
138 * Called only by render_picture(). | 140 * Called only by render_picture(). |
139 */ | 141 */ |
140 static bool render_picture_internal(const SkString& inputPath, const SkString* o
utputDir, | 142 static bool render_picture_internal(const SkString& inputPath, const SkString* w
ritePath, |
| 143 const SkString* mismatchPath, |
141 sk_tools::PictureRenderer& renderer, | 144 sk_tools::PictureRenderer& renderer, |
142 SkBitmap** out) { | 145 SkBitmap** out) { |
143 SkString inputFilename; | 146 SkString inputFilename; |
144 sk_tools::get_basename(&inputFilename, inputPath); | 147 sk_tools::get_basename(&inputFilename, inputPath); |
145 SkString outputDirString; | 148 SkString writePathString; |
146 if (NULL != outputDir && outputDir->size() > 0 && !FLAGS_writeEncodedImages)
{ | 149 if (NULL != writePath && writePath->size() > 0 && !FLAGS_writeEncodedImages)
{ |
147 outputDirString.set(*outputDir); | 150 writePathString.set(*writePath); |
| 151 } |
| 152 SkString mismatchPathString; |
| 153 if (NULL != mismatchPath && mismatchPath->size() > 0) { |
| 154 mismatchPathString.set(*mismatchPath); |
148 } | 155 } |
149 | 156 |
150 SkFILEStream inputStream; | 157 SkFILEStream inputStream; |
151 inputStream.setPath(inputPath.c_str()); | 158 inputStream.setPath(inputPath.c_str()); |
152 if (!inputStream.isValid()) { | 159 if (!inputStream.isValid()) { |
153 SkDebugf("Could not open file %s\n", inputPath.c_str()); | 160 SkDebugf("Could not open file %s\n", inputPath.c_str()); |
154 return false; | 161 return false; |
155 } | 162 } |
156 | 163 |
157 SkPicture::InstallPixelRefProc proc; | 164 SkPicture::InstallPixelRefProc proc; |
(...skipping 24 matching lines...) Expand all Loading... |
182 | 189 |
183 for (int i = 0; i < FLAGS_clone; ++i) { | 190 for (int i = 0; i < FLAGS_clone; ++i) { |
184 SkPicture* clone = picture->clone(); | 191 SkPicture* clone = picture->clone(); |
185 SkDELETE(picture); | 192 SkDELETE(picture); |
186 picture = clone; | 193 picture = clone; |
187 } | 194 } |
188 | 195 |
189 SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(), | 196 SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(), |
190 inputPath.c_str()); | 197 inputPath.c_str()); |
191 | 198 |
192 renderer.init(picture, &outputDirString, &inputFilename, FLAGS_writeChecksum
BasedFilenames); | 199 renderer.init(picture, &writePathString, &mismatchPathString, &inputFilename
, |
| 200 FLAGS_writeChecksumBasedFilenames); |
193 | 201 |
194 if (FLAGS_preprocess) { | 202 if (FLAGS_preprocess) { |
195 if (NULL != renderer.getCanvas()) { | 203 if (NULL != renderer.getCanvas()) { |
196 renderer.getCanvas()->EXPERIMENTAL_optimize(renderer.getPicture()); | 204 renderer.getCanvas()->EXPERIMENTAL_optimize(renderer.getPicture()); |
197 } | 205 } |
198 } | 206 } |
199 | 207 |
200 renderer.setup(); | 208 renderer.setup(); |
201 | 209 |
202 bool success = renderer.render(out); | 210 bool success = renderer.render(out); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 fRenderer->setBBoxHierarchyType(fSavedBbhType); | 247 fRenderer->setBBoxHierarchyType(fSavedBbhType); |
240 } | 248 } |
241 } | 249 } |
242 | 250 |
243 private: | 251 private: |
244 sk_tools::PictureRenderer* fRenderer; | 252 sk_tools::PictureRenderer* fRenderer; |
245 sk_tools::PictureRenderer::BBoxHierarchyType fSavedBbhType; | 253 sk_tools::PictureRenderer::BBoxHierarchyType fSavedBbhType; |
246 }; | 254 }; |
247 | 255 |
248 /** | 256 /** |
249 * Render the SKP file(s) within inputPath, writing their bitmap images into out
putDir. | 257 * Render the SKP file(s) within inputPath. |
250 * | 258 * |
251 * @param inputPath path to an individual SKP file, or a directory of SKP files | 259 * @param inputPath path to an individual SKP file, or a directory of SKP files |
252 * @param outputDir if not NULL, write the image(s) generated into this director
y | 260 * @param writePath if not NULL, write all image(s) generated into this director
y |
| 261 * @param mismatchPath if not NULL, write any image(s) not matching expectations
into this directory |
253 * @param renderer PictureRenderer to use to render the SKPs | 262 * @param renderer PictureRenderer to use to render the SKPs |
254 * @param jsonSummaryPtr if not NULL, add the image(s) generated to this summary | 263 * @param jsonSummaryPtr if not NULL, add the image(s) generated to this summary |
255 */ | 264 */ |
256 static bool render_picture(const SkString& inputPath, const SkString* outputDir, | 265 static bool render_picture(const SkString& inputPath, const SkString* writePath, |
257 sk_tools::PictureRenderer& renderer, | 266 const SkString* mismatchPath, sk_tools::PictureRender
er& renderer, |
258 sk_tools::ImageResultsAndExpectations *jsonSummaryPtr
) { | 267 sk_tools::ImageResultsAndExpectations *jsonSummaryPtr
) { |
259 int diffs[256] = {0}; | 268 int diffs[256] = {0}; |
260 SkBitmap* bitmap = NULL; | 269 SkBitmap* bitmap = NULL; |
261 renderer.setJsonSummaryPtr(jsonSummaryPtr); | 270 renderer.setJsonSummaryPtr(jsonSummaryPtr); |
262 bool success = render_picture_internal(inputPath, | 271 bool success = render_picture_internal(inputPath, |
263 FLAGS_writeWholeImage ? NULL : outputDir, | 272 FLAGS_writeWholeImage ? NULL : writePath, |
| 273 FLAGS_writeWholeImage ? NULL : mismatchPath, |
264 renderer, | 274 renderer, |
265 FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL); | 275 FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL); |
266 | 276 |
267 if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL
)) { | 277 if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL
)) { |
268 SkDebugf("Failed to draw the picture.\n"); | 278 SkDebugf("Failed to draw the picture.\n"); |
269 SkDELETE(bitmap); | 279 SkDELETE(bitmap); |
270 return false; | 280 return false; |
271 } | 281 } |
272 | 282 |
273 if (FLAGS_validate) { | 283 if (FLAGS_validate) { |
274 SkBitmap* referenceBitmap = NULL; | 284 SkBitmap* referenceBitmap = NULL; |
275 sk_tools::PictureRenderer* referenceRenderer; | 285 sk_tools::PictureRenderer* referenceRenderer; |
276 // If the renderer uses a BBoxHierarchy, then the reference renderer | 286 // If the renderer uses a BBoxHierarchy, then the reference renderer |
277 // will be the same renderer, without the bbh. | 287 // will be the same renderer, without the bbh. |
278 AutoRestoreBbhType arbbh; | 288 AutoRestoreBbhType arbbh; |
279 if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType != | 289 if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType != |
280 renderer.getBBoxHierarchyType()) { | 290 renderer.getBBoxHierarchyType()) { |
281 referenceRenderer = &renderer; | 291 referenceRenderer = &renderer; |
282 referenceRenderer->ref(); // to match auto unref below | 292 referenceRenderer->ref(); // to match auto unref below |
283 arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHi
erarchyType); | 293 arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHi
erarchyType); |
284 } else { | 294 } else { |
285 referenceRenderer = SkNEW(sk_tools::SimplePictureRenderer); | 295 referenceRenderer = SkNEW(sk_tools::SimplePictureRenderer); |
286 } | 296 } |
287 SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRe
nderer); | 297 SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRe
nderer); |
288 | 298 |
289 success = render_picture_internal(inputPath, NULL, *referenceRenderer, | 299 success = render_picture_internal(inputPath, NULL, NULL, *referenceRende
rer, |
290 &referenceBitmap); | 300 &referenceBitmap); |
291 | 301 |
292 if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getP
ixels()) { | 302 if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getP
ixels()) { |
293 SkDebugf("Failed to draw the reference picture.\n"); | 303 SkDebugf("Failed to draw the reference picture.\n"); |
294 SkDELETE(bitmap); | 304 SkDELETE(bitmap); |
295 SkDELETE(referenceBitmap); | 305 SkDELETE(referenceBitmap); |
296 return false; | 306 return false; |
297 } | 307 } |
298 | 308 |
299 if (success && (bitmap->width() != referenceBitmap->width())) { | 309 if (success && (bitmap->width() != referenceBitmap->width())) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 for (int i = 1; i <= 255; ++i) { | 345 for (int i = 1; i <= 255; ++i) { |
336 if(diffs[i] > 0) { | 346 if(diffs[i] > 0) { |
337 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diff
s[i]); | 347 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diff
s[i]); |
338 } | 348 } |
339 } | 349 } |
340 } | 350 } |
341 | 351 |
342 if (FLAGS_writeWholeImage) { | 352 if (FLAGS_writeWholeImage) { |
343 sk_tools::force_all_opaque(*bitmap); | 353 sk_tools::force_all_opaque(*bitmap); |
344 | 354 |
345 SkString inputFilename, outputPath; | 355 SkString inputFilename; |
346 sk_tools::get_basename(&inputFilename, inputPath); | 356 sk_tools::get_basename(&inputFilename, inputPath); |
347 sk_tools::make_filepath(&outputPath, *outputDir, inputFilename); | 357 SkString outputFilename(inputFilename); |
348 sk_tools::replace_char(&outputPath, '.', '_'); | 358 sk_tools::replace_char(&outputFilename, '.', '_'); |
349 outputPath.append(".png"); | 359 outputFilename.append(".png"); |
350 | 360 |
351 if (NULL != jsonSummaryPtr) { | 361 if (NULL != jsonSummaryPtr) { |
352 sk_tools::ImageDigest imageDigest(*bitmap); | 362 sk_tools::ImageDigest imageDigest(*bitmap); |
353 SkString outputFileBasename; | 363 jsonSummaryPtr->add(inputFilename.c_str(), outputFilename.c_str(), i
mageDigest); |
354 sk_tools::get_basename(&outputFileBasename, outputPath); | 364 if ((NULL != mismatchPath) && !mismatchPath->isEmpty() && |
355 jsonSummaryPtr->add(inputFilename.c_str(), outputFileBasename.c_str(
), imageDigest); | 365 !jsonSummaryPtr->matchesExpectation(inputFilename.c_str(), image
Digest)) { |
| 366 success &= sk_tools::write_bitmap_to_disk(*bitmap, *mismatchPath
, NULL, |
| 367 outputFilename); |
| 368 } |
356 } | 369 } |
357 | 370 |
358 if (NULL != outputDir) { | 371 if ((NULL != writePath) && !writePath->isEmpty()) { |
359 if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap, | 372 success &= sk_tools::write_bitmap_to_disk(*bitmap, *writePath, NULL,
outputFilename); |
360 SkImageEncoder::kPNG_Type, 100)) { | |
361 SkDebugf("Failed to draw the picture.\n"); | |
362 success = false; | |
363 } | |
364 } | 373 } |
365 } | 374 } |
366 SkDELETE(bitmap); | 375 SkDELETE(bitmap); |
367 | 376 |
368 return success; | 377 return success; |
369 } | 378 } |
370 | 379 |
371 | 380 |
372 static int process_input(const char* input, const SkString* outputDir, | 381 static int process_input(const char* input, const SkString* writePath, |
373 sk_tools::PictureRenderer& renderer, | 382 const SkString* mismatchPath, sk_tools::PictureRenderer
& renderer, |
374 sk_tools::ImageResultsAndExpectations *jsonSummaryPtr)
{ | 383 sk_tools::ImageResultsAndExpectations *jsonSummaryPtr)
{ |
375 SkOSFile::Iter iter(input, "skp"); | 384 SkOSFile::Iter iter(input, "skp"); |
376 SkString inputFilename; | 385 SkString inputFilename; |
377 int failures = 0; | 386 int failures = 0; |
378 SkDebugf("process_input, %s\n", input); | 387 SkDebugf("process_input, %s\n", input); |
379 if (iter.next(&inputFilename)) { | 388 if (iter.next(&inputFilename)) { |
380 do { | 389 do { |
381 SkString inputPath; | 390 SkString inputPath; |
382 SkString inputAsSkString(input); | 391 SkString inputAsSkString(input); |
383 sk_tools::make_filepath(&inputPath, inputAsSkString, inputFilename); | 392 sk_tools::make_filepath(&inputPath, inputAsSkString, inputFilename); |
384 if (!render_picture(inputPath, outputDir, renderer, jsonSummaryPtr))
{ | 393 if (!render_picture(inputPath, writePath, mismatchPath, renderer, js
onSummaryPtr)) { |
385 ++failures; | 394 ++failures; |
386 } | 395 } |
387 } while(iter.next(&inputFilename)); | 396 } while(iter.next(&inputFilename)); |
388 } else if (SkStrEndsWith(input, ".skp")) { | 397 } else if (SkStrEndsWith(input, ".skp")) { |
389 SkString inputPath(input); | 398 SkString inputPath(input); |
390 if (!render_picture(inputPath, outputDir, renderer, jsonSummaryPtr)) { | 399 if (!render_picture(inputPath, writePath, mismatchPath, renderer, jsonSu
mmaryPtr)) { |
391 ++failures; | 400 ++failures; |
392 } | 401 } |
393 } else { | 402 } else { |
394 SkString warning; | 403 SkString warning; |
395 warning.printf("Warning: skipping %s\n", input); | 404 warning.printf("Warning: skipping %s\n", input); |
396 SkDebugf(warning.c_str()); | 405 SkDebugf(warning.c_str()); |
397 } | 406 } |
398 return failures; | 407 return failures; |
399 } | 408 } |
400 | 409 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 if (errorString.size() > 0) { | 449 if (errorString.size() > 0) { |
441 SkDebugf("%s\n", errorString.c_str()); | 450 SkDebugf("%s\n", errorString.c_str()); |
442 } | 451 } |
443 | 452 |
444 if (renderer.get() == NULL) { | 453 if (renderer.get() == NULL) { |
445 exit(-1); | 454 exit(-1); |
446 } | 455 } |
447 | 456 |
448 SkAutoGraphics ag; | 457 SkAutoGraphics ag; |
449 | 458 |
450 SkString outputDir; | 459 SkString writePath; |
451 if (FLAGS_writePath.count() == 1) { | 460 if (FLAGS_writePath.count() == 1) { |
452 outputDir.set(FLAGS_writePath[0]); | 461 writePath.set(FLAGS_writePath[0]); |
| 462 } |
| 463 SkString mismatchPath; |
| 464 if (FLAGS_mismatchPath.count() == 1) { |
| 465 mismatchPath.set(FLAGS_mismatchPath[0]); |
453 } | 466 } |
454 sk_tools::ImageResultsAndExpectations jsonSummary; | 467 sk_tools::ImageResultsAndExpectations jsonSummary; |
455 sk_tools::ImageResultsAndExpectations* jsonSummaryPtr = NULL; | 468 sk_tools::ImageResultsAndExpectations* jsonSummaryPtr = NULL; |
456 if (FLAGS_writeJsonSummaryPath.count() == 1) { | 469 if (FLAGS_writeJsonSummaryPath.count() == 1) { |
457 jsonSummaryPtr = &jsonSummary; | 470 jsonSummaryPtr = &jsonSummary; |
458 if (FLAGS_readJsonSummaryPath.count() == 1) { | 471 if (FLAGS_readJsonSummaryPath.count() == 1) { |
459 SkASSERT(jsonSummary.readExpectationsFile(FLAGS_readJsonSummaryPath[
0])); | 472 SkASSERT(jsonSummary.readExpectationsFile(FLAGS_readJsonSummaryPath[
0])); |
460 } | 473 } |
461 } | 474 } |
462 | 475 |
463 int failures = 0; | 476 int failures = 0; |
464 for (int i = 0; i < FLAGS_readPath.count(); i ++) { | 477 for (int i = 0; i < FLAGS_readPath.count(); i ++) { |
465 failures += process_input(FLAGS_readPath[i], &outputDir, *renderer.get()
, jsonSummaryPtr); | 478 failures += process_input(FLAGS_readPath[i], &writePath, &mismatchPath,
*renderer.get(), |
| 479 jsonSummaryPtr); |
466 } | 480 } |
467 if (failures != 0) { | 481 if (failures != 0) { |
468 SkDebugf("Failed to render %i pictures.\n", failures); | 482 SkDebugf("Failed to render %i pictures.\n", failures); |
469 return 1; | 483 return 1; |
470 } | 484 } |
471 #if SK_SUPPORT_GPU | 485 #if SK_SUPPORT_GPU |
472 #if GR_CACHE_STATS | 486 #if GR_CACHE_STATS |
473 if (renderer->isUsingGpuDevice()) { | 487 if (renderer->isUsingGpuDevice()) { |
474 GrContext* ctx = renderer->getGrContext(); | 488 GrContext* ctx = renderer->getGrContext(); |
475 ctx->printCacheStats(); | 489 ctx->printCacheStats(); |
476 #ifdef SK_DEVELOPER | 490 #ifdef SK_DEVELOPER |
477 ctx->dumpFontCache(); | 491 ctx->dumpFontCache(); |
478 #endif | 492 #endif |
479 } | 493 } |
480 #endif | 494 #endif |
481 #endif | 495 #endif |
482 if (FLAGS_writeJsonSummaryPath.count() == 1) { | 496 if (FLAGS_writeJsonSummaryPath.count() == 1) { |
483 jsonSummary.writeToFile(FLAGS_writeJsonSummaryPath[0]); | 497 jsonSummary.writeToFile(FLAGS_writeJsonSummaryPath[0]); |
484 } | 498 } |
485 return 0; | 499 return 0; |
486 } | 500 } |
487 | 501 |
488 #if !defined SK_BUILD_FOR_IOS | 502 #if !defined SK_BUILD_FOR_IOS |
489 int main(int argc, char * const argv[]) { | 503 int main(int argc, char * const argv[]) { |
490 return tool_main(argc, (char**) argv); | 504 return tool_main(argc, (char**) argv); |
491 } | 505 } |
492 #endif | 506 #endif |
OLD | NEW |