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 "PictureRenderer.h" | 8 #include "PictureRenderer.h" |
9 #include "picture_utils.h" | 9 #include "picture_utils.h" |
10 #include "SamplePipeControllers.h" | 10 #include "SamplePipeControllers.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 }; | 51 }; |
52 | 52 |
53 /* TODO(epoger): These constants are already maintained in 2 other places: | 53 /* TODO(epoger): These constants are already maintained in 2 other places: |
54 * gm/gm_json.py and gm/gm_expectations.cpp. We shouldn't add yet a third place
. | 54 * gm/gm_json.py and gm/gm_expectations.cpp. We shouldn't add yet a third place
. |
55 * Figure out a way to share the definitions instead. | 55 * Figure out a way to share the definitions instead. |
56 */ | 56 */ |
57 const static char kJsonKey_ActualResults[] = "actual-results"; | 57 const static char kJsonKey_ActualResults[] = "actual-results"; |
58 const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison"; | 58 const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison"; |
59 const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5"; | 59 const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5"; |
60 | 60 |
61 void ImageResultsSummary::add(const char *testName, const SkBitmap& bitmap) { | 61 void ImageResultsSummary::add(const char *testName, uint64_t hash) { |
62 uint64_t hash; | |
63 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); | |
64 Json::Value jsonTypeValuePair; | 62 Json::Value jsonTypeValuePair; |
65 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5)); | 63 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5)); |
66 jsonTypeValuePair.append(Json::UInt64(hash)); | 64 jsonTypeValuePair.append(Json::UInt64(hash)); |
67 fActualResultsNoComparison[testName] = jsonTypeValuePair; | 65 fActualResultsNoComparison[testName] = jsonTypeValuePair; |
68 } | 66 } |
69 | 67 |
| 68 void ImageResultsSummary::add(const char *testName, const SkBitmap& bitmap) { |
| 69 uint64_t hash; |
| 70 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); |
| 71 add(testName, hash); |
| 72 } |
| 73 |
70 void ImageResultsSummary::writeToFile(const char *filename) { | 74 void ImageResultsSummary::writeToFile(const char *filename) { |
71 Json::Value actualResults; | 75 Json::Value actualResults; |
72 actualResults[kJsonKey_ActualResults_NoComparison] = fActualResultsNoCompari
son; | 76 actualResults[kJsonKey_ActualResults_NoComparison] = fActualResultsNoCompari
son; |
73 Json::Value root; | 77 Json::Value root; |
74 root[kJsonKey_ActualResults] = actualResults; | 78 root[kJsonKey_ActualResults] = actualResults; |
75 std::string jsonStdString = root.toStyledString(); | 79 std::string jsonStdString = root.toStyledString(); |
76 SkFILEWStream stream(filename); | 80 SkFILEWStream stream(filename); |
77 stream.write(jsonStdString.c_str(), jsonStdString.length()); | 81 stream.write(jsonStdString.c_str(), jsonStdString.length()); |
78 } | 82 } |
79 | 83 |
80 void PictureRenderer::init(SkPicture* pict) { | 84 void PictureRenderer::init(SkPicture* pict, const SkString& outputDir, |
| 85 const SkString& inputFilename, bool useChecksumBasedF
ilenames) { |
| 86 fOutputDir.set(outputDir); |
| 87 fInputFilename.set(inputFilename); |
| 88 fUseChecksumBasedFilenames = useChecksumBasedFilenames; |
| 89 |
81 SkASSERT(NULL == fPicture); | 90 SkASSERT(NULL == fPicture); |
82 SkASSERT(NULL == fCanvas.get()); | 91 SkASSERT(NULL == fCanvas.get()); |
83 if (fPicture != NULL || NULL != fCanvas.get()) { | 92 if (fPicture != NULL || NULL != fCanvas.get()) { |
84 return; | 93 return; |
85 } | 94 } |
86 | 95 |
87 SkASSERT(pict != NULL); | 96 SkASSERT(pict != NULL); |
88 if (NULL == pict) { | 97 if (NULL == pict) { |
89 return; | 98 return; |
90 } | 99 } |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 } | 283 } |
275 | 284 |
276 uint32_t PictureRenderer::recordFlags() { | 285 uint32_t PictureRenderer::recordFlags() { |
277 return ((kNone_BBoxHierarchyType == fBBoxHierarchyType) ? 0 : | 286 return ((kNone_BBoxHierarchyType == fBBoxHierarchyType) ? 0 : |
278 SkPicture::kOptimizeForClippedPlayback_RecordingFlag) | | 287 SkPicture::kOptimizeForClippedPlayback_RecordingFlag) | |
279 SkPicture::kUsePathBoundsForClip_RecordingFlag; | 288 SkPicture::kUsePathBoundsForClip_RecordingFlag; |
280 } | 289 } |
281 | 290 |
282 /** | 291 /** |
283 * Write the canvas to the specified path. | 292 * Write the canvas to the specified path. |
| 293 * |
284 * @param canvas Must be non-null. Canvas to be written to a file. | 294 * @param canvas Must be non-null. Canvas to be written to a file. |
285 * @param path Path for the file to be written. Should have no extension; write(
) will append | 295 * @param outputDir If nonempty, write the binary image to a file within this di
rectory. |
286 * an appropriate one. Passed in by value so it can be modified. | 296 * @param inputFilename If we are writing out a binary image, use this to build
its filename. |
287 * @param jsonSummaryPtr If not null, add image results to this summary. | 297 * @param jsonSummaryPtr If not null, add image results to this summary. |
| 298 * @param useChecksumBasedFilenames If true, use checksum-based filenames when w
riting to disk. |
| 299 * @param numberToAppend If not null, append this number to the filename. |
288 * @return bool True if the Canvas is written to a file. | 300 * @return bool True if the Canvas is written to a file. |
289 * | 301 * |
290 * TODO(epoger): Right now, all canvases must pass through this function in orde
r to be appended | 302 * TODO(epoger): Right now, all canvases must pass through this function in orde
r to be appended |
291 * to the ImageResultsSummary. We need some way to add bitmaps to the ImageResu
ltsSummary | 303 * to the ImageResultsSummary. We need some way to add bitmaps to the ImageResu
ltsSummary |
292 * even if --writePath has not been specified (and thus this function is not cal
led). | 304 * even if --writePath has not been specified (and thus this function is not cal
led). |
293 * | 305 * |
294 * One fix would be to pass in these path elements separately, and allow this fu
nction to be | 306 * One fix would be to pass in these path elements separately, and allow this fu
nction to be |
295 * called even if --writePath was not specified... | 307 * called even if --writePath was not specified... |
296 * const char *outputDir // NULL if we don't want to write image files to dis
k | 308 * const char *outputDir // NULL if we don't want to write image files to dis
k |
297 * const char *filename // name we use within JSON summary, and as the filen
ame within outputDir | 309 * const char *filename // name we use within JSON summary, and as the filen
ame within outputDir |
| 310 * |
| 311 * UPDATE: Now that outputDir and inputFilename are passed separately, we should
be able to do that. |
298 */ | 312 */ |
299 static bool write(SkCanvas* canvas, const SkString* path, ImageResultsSummary *j
sonSummaryPtr) { | 313 static bool write(SkCanvas* canvas, const SkString& outputDir, const SkString& i
nputFilename, |
| 314 ImageResultsSummary *jsonSummaryPtr, bool useChecksumBasedFile
names, |
| 315 const int* numberToAppend=NULL) { |
300 SkASSERT(canvas != NULL); | 316 SkASSERT(canvas != NULL); |
301 if (NULL == canvas) { | 317 if (NULL == canvas) { |
302 return false; | 318 return false; |
303 } | 319 } |
304 | 320 |
305 SkASSERT(path != NULL); // TODO(epoger): we want to remove this constraint,
as noted above | |
306 SkString fullPathname(*path); | |
307 fullPathname.append(".png"); | |
308 | |
309 SkBitmap bitmap; | 321 SkBitmap bitmap; |
310 SkISize size = canvas->getDeviceSize(); | 322 SkISize size = canvas->getDeviceSize(); |
311 sk_tools::setup_bitmap(&bitmap, size.width(), size.height()); | 323 sk_tools::setup_bitmap(&bitmap, size.width(), size.height()); |
312 | 324 |
| 325 // Make sure we only compute the bitmap hash once (at most). |
| 326 uint64_t hash; |
| 327 bool generatedHash = false; |
| 328 |
313 canvas->readPixels(&bitmap, 0, 0); | 329 canvas->readPixels(&bitmap, 0, 0); |
314 sk_tools::force_all_opaque(bitmap); | 330 sk_tools::force_all_opaque(bitmap); |
315 | 331 |
| 332 SkString outputFilename(inputFilename); |
| 333 outputFilename.remove(outputFilename.size() - 4, 4); |
| 334 if (NULL != numberToAppend) { |
| 335 outputFilename.appendf("%i", *numberToAppend); |
| 336 } |
| 337 outputFilename.append(".png"); |
| 338 // TODO(epoger): what about including the config type within outputFilename?
That way, |
| 339 // we could combine results of different config types without conflicting fi
lenames. |
| 340 |
316 if (NULL != jsonSummaryPtr) { | 341 if (NULL != jsonSummaryPtr) { |
317 // EPOGER: This is a hacky way of constructing the filename associated w
ith the | 342 if (!generatedHash) { |
318 // image checksum; we assume that outputDir is not NULL, and we remove o
utputDir | 343 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); |
319 // from fullPathname. | 344 generatedHash = true; |
320 // | 345 } |
321 // EPOGER: what about including the config type within hashFilename? Th
at way, | 346 jsonSummaryPtr->add(outputFilename.c_str(), hash); |
322 // we could combine results of different config types without conflictin
g filenames. | |
323 SkString hashFilename; | |
324 sk_tools::get_basename(&hashFilename, fullPathname); | |
325 jsonSummaryPtr->add(hashFilename.c_str(), bitmap); | |
326 } | 347 } |
327 | 348 |
| 349 // Update outputFilename AFTER adding to JSON summary, but BEFORE writing ou
t the image file. |
| 350 if (useChecksumBasedFilenames) { |
| 351 if (!generatedHash) { |
| 352 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); |
| 353 generatedHash = true; |
| 354 } |
| 355 outputFilename.set(kJsonKey_Hashtype_Bitmap_64bitMD5); |
| 356 outputFilename.append("_"); |
| 357 outputFilename.appendU64(hash); |
| 358 outputFilename.append(".png"); |
| 359 } |
| 360 |
| 361 SkASSERT(!outputDir.isEmpty()); // TODO(epoger): we want to remove this cons
traint, |
| 362 // as noted above |
| 363 SkString fullPathname; |
| 364 make_filepath(&fullPathname, outputDir, outputFilename); |
328 return SkImageEncoder::EncodeFile(fullPathname.c_str(), bitmap, SkImageEncod
er::kPNG_Type, 100); | 365 return SkImageEncoder::EncodeFile(fullPathname.c_str(), bitmap, SkImageEncod
er::kPNG_Type, 100); |
329 } | 366 } |
330 | 367 |
331 /** | |
332 * If path is non NULL, append number to it, and call write() to write the | |
333 * provided canvas to a file. Returns true if path is NULL or if write() succeed
s. | |
334 */ | |
335 static bool writeAppendNumber(SkCanvas* canvas, const SkString* path, int number
, | |
336 ImageResultsSummary *jsonSummaryPtr) { | |
337 if (NULL == path) { | |
338 return true; | |
339 } | |
340 SkString pathWithNumber(*path); | |
341 pathWithNumber.appendf("%i", number); | |
342 return write(canvas, &pathWithNumber, jsonSummaryPtr); | |
343 } | |
344 | |
345 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 368 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
346 | 369 |
347 SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) { | 370 SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) { |
348 // defer the canvas setup until the render step | 371 // defer the canvas setup until the render step |
349 return NULL; | 372 return NULL; |
350 } | 373 } |
351 | 374 |
352 // the size_t* parameter is deprecated, so we ignore it | 375 // the size_t* parameter is deprecated, so we ignore it |
353 static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) { | 376 static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) { |
354 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100); | 377 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100); |
355 } | 378 } |
356 | 379 |
357 bool RecordPictureRenderer::render(const SkString* path, SkBitmap** out) { | 380 bool RecordPictureRenderer::render(SkBitmap** out) { |
358 SkAutoTUnref<SkPicture> replayer(this->createPicture()); | 381 SkAutoTUnref<SkPicture> replayer(this->createPicture()); |
359 SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->ge
tViewHeight(), | 382 SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->ge
tViewHeight(), |
360 this->recordFlags()); | 383 this->recordFlags()); |
361 this->scaleToScaleFactor(recorder); | 384 this->scaleToScaleFactor(recorder); |
362 fPicture->draw(recorder); | 385 fPicture->draw(recorder); |
363 replayer->endRecording(); | 386 replayer->endRecording(); |
364 if (path != NULL) { | 387 if (!fOutputDir.isEmpty()) { |
365 // Record the new picture as a new SKP with PNG encoded bitmaps. | 388 // Record the new picture as a new SKP with PNG encoded bitmaps. |
366 SkString skpPath(*path); | 389 SkString skpPath; |
367 // ".skp" was removed from 'path' before being passed in here. | 390 make_filepath(&skpPath, fOutputDir, fInputFilename); |
368 skpPath.append(".skp"); | |
369 SkFILEWStream stream(skpPath.c_str()); | 391 SkFILEWStream stream(skpPath.c_str()); |
370 replayer->serialize(&stream, &encode_bitmap_to_data); | 392 replayer->serialize(&stream, &encode_bitmap_to_data); |
371 return true; | 393 return true; |
372 } | 394 } |
373 return false; | 395 return false; |
374 } | 396 } |
375 | 397 |
376 SkString RecordPictureRenderer::getConfigNameInternal() { | 398 SkString RecordPictureRenderer::getConfigNameInternal() { |
377 return SkString("record"); | 399 return SkString("record"); |
378 } | 400 } |
379 | 401 |
380 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 402 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
381 | 403 |
382 bool PipePictureRenderer::render(const SkString* path, SkBitmap** out) { | 404 bool PipePictureRenderer::render(SkBitmap** out) { |
383 SkASSERT(fCanvas.get() != NULL); | 405 SkASSERT(fCanvas.get() != NULL); |
384 SkASSERT(fPicture != NULL); | 406 SkASSERT(fPicture != NULL); |
385 if (NULL == fCanvas.get() || NULL == fPicture) { | 407 if (NULL == fCanvas.get() || NULL == fPicture) { |
386 return false; | 408 return false; |
387 } | 409 } |
388 | 410 |
389 PipeController pipeController(fCanvas.get()); | 411 PipeController pipeController(fCanvas.get()); |
390 SkGPipeWriter writer; | 412 SkGPipeWriter writer; |
391 SkCanvas* pipeCanvas = writer.startRecording(&pipeController); | 413 SkCanvas* pipeCanvas = writer.startRecording(&pipeController); |
392 pipeCanvas->drawPicture(*fPicture); | 414 pipeCanvas->drawPicture(*fPicture); |
393 writer.endRecording(); | 415 writer.endRecording(); |
394 fCanvas->flush(); | 416 fCanvas->flush(); |
395 if (NULL != path) { | 417 if (!fOutputDir.isEmpty()) { |
396 return write(fCanvas, path, fJsonSummaryPtr); | 418 return write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPtr, |
| 419 fUseChecksumBasedFilenames); |
397 } | 420 } |
398 if (NULL != out) { | 421 if (NULL != out) { |
399 *out = SkNEW(SkBitmap); | 422 *out = SkNEW(SkBitmap); |
400 setup_bitmap(*out, fPicture->width(), fPicture->height()); | 423 setup_bitmap(*out, fPicture->width(), fPicture->height()); |
401 fCanvas->readPixels(*out, 0, 0); | 424 fCanvas->readPixels(*out, 0, 0); |
402 } | 425 } |
403 return true; | 426 return true; |
404 } | 427 } |
405 | 428 |
406 SkString PipePictureRenderer::getConfigNameInternal() { | 429 SkString PipePictureRenderer::getConfigNameInternal() { |
407 return SkString("pipe"); | 430 return SkString("pipe"); |
408 } | 431 } |
409 | 432 |
410 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 433 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
411 | 434 |
412 void SimplePictureRenderer::init(SkPicture* picture) { | 435 void SimplePictureRenderer::init(SkPicture* picture, const SkString& outputDir, |
413 INHERITED::init(picture); | 436 const SkString& inputFilename, bool useChecksum
BasedFilenames) { |
| 437 INHERITED::init(picture, outputDir, inputFilename, useChecksumBasedFilenames
); |
414 this->buildBBoxHierarchy(); | 438 this->buildBBoxHierarchy(); |
415 } | 439 } |
416 | 440 |
417 bool SimplePictureRenderer::render(const SkString* path, SkBitmap** out) { | 441 bool SimplePictureRenderer::render(SkBitmap** out) { |
418 SkASSERT(fCanvas.get() != NULL); | 442 SkASSERT(fCanvas.get() != NULL); |
419 SkASSERT(fPicture != NULL); | 443 SkASSERT(fPicture != NULL); |
420 if (NULL == fCanvas.get() || NULL == fPicture) { | 444 if (NULL == fCanvas.get() || NULL == fPicture) { |
421 return false; | 445 return false; |
422 } | 446 } |
423 | 447 |
424 fCanvas->drawPicture(*fPicture); | 448 fCanvas->drawPicture(*fPicture); |
425 fCanvas->flush(); | 449 fCanvas->flush(); |
426 if (NULL != path) { | 450 if (!fOutputDir.isEmpty()) { |
427 return write(fCanvas, path, fJsonSummaryPtr); | 451 return write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPtr, |
| 452 fUseChecksumBasedFilenames); |
428 } | 453 } |
429 | 454 |
430 if (NULL != out) { | 455 if (NULL != out) { |
431 *out = SkNEW(SkBitmap); | 456 *out = SkNEW(SkBitmap); |
432 setup_bitmap(*out, fPicture->width(), fPicture->height()); | 457 setup_bitmap(*out, fPicture->width(), fPicture->height()); |
433 fCanvas->readPixels(*out, 0, 0); | 458 fCanvas->readPixels(*out, 0, 0); |
434 } | 459 } |
435 | 460 |
436 return true; | 461 return true; |
437 } | 462 } |
438 | 463 |
439 SkString SimplePictureRenderer::getConfigNameInternal() { | 464 SkString SimplePictureRenderer::getConfigNameInternal() { |
440 return SkString("simple"); | 465 return SkString("simple"); |
441 } | 466 } |
442 | 467 |
443 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 468 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
444 | 469 |
445 TiledPictureRenderer::TiledPictureRenderer() | 470 TiledPictureRenderer::TiledPictureRenderer() |
446 : fTileWidth(kDefaultTileWidth) | 471 : fTileWidth(kDefaultTileWidth) |
447 , fTileHeight(kDefaultTileHeight) | 472 , fTileHeight(kDefaultTileHeight) |
448 , fTileWidthPercentage(0.0) | 473 , fTileWidthPercentage(0.0) |
449 , fTileHeightPercentage(0.0) | 474 , fTileHeightPercentage(0.0) |
450 , fTileMinPowerOf2Width(0) | 475 , fTileMinPowerOf2Width(0) |
451 , fCurrentTileOffset(-1) | 476 , fCurrentTileOffset(-1) |
452 , fTilesX(0) | 477 , fTilesX(0) |
453 , fTilesY(0) { } | 478 , fTilesY(0) { } |
454 | 479 |
455 void TiledPictureRenderer::init(SkPicture* pict) { | 480 void TiledPictureRenderer::init(SkPicture* pict, const SkString& outputDir, |
| 481 const SkString& inputFilename, bool useChecksumB
asedFilenames) { |
456 SkASSERT(pict != NULL); | 482 SkASSERT(pict != NULL); |
457 SkASSERT(0 == fTileRects.count()); | 483 SkASSERT(0 == fTileRects.count()); |
458 if (NULL == pict || fTileRects.count() != 0) { | 484 if (NULL == pict || fTileRects.count() != 0) { |
459 return; | 485 return; |
460 } | 486 } |
461 | 487 |
462 // Do not call INHERITED::init(), which would create a (potentially large) c
anvas which is not | 488 // Do not call INHERITED::init(), which would create a (potentially large) c
anvas which is not |
463 // used by bench_pictures. | 489 // used by bench_pictures. |
464 fPicture = pict; | 490 fPicture = pict; |
| 491 fOutputDir.set(outputDir); |
| 492 fInputFilename.set(inputFilename); |
| 493 fUseChecksumBasedFilenames = useChecksumBasedFilenames; |
465 fPicture->ref(); | 494 fPicture->ref(); |
466 this->buildBBoxHierarchy(); | 495 this->buildBBoxHierarchy(); |
467 | 496 |
468 if (fTileWidthPercentage > 0) { | 497 if (fTileWidthPercentage > 0) { |
469 fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->wi
dth() / 100)); | 498 fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->wi
dth() / 100)); |
470 } | 499 } |
471 if (fTileHeightPercentage > 0) { | 500 if (fTileHeightPercentage > 0) { |
472 fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->
height() / 100)); | 501 fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->
height() / 100)); |
473 } | 502 } |
474 | 503 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 return true; | 645 return true; |
617 } | 646 } |
618 return false; | 647 return false; |
619 } | 648 } |
620 | 649 |
621 void TiledPictureRenderer::drawCurrentTile() { | 650 void TiledPictureRenderer::drawCurrentTile() { |
622 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count())
; | 651 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count())
; |
623 draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture); | 652 draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture); |
624 } | 653 } |
625 | 654 |
626 bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) { | 655 bool TiledPictureRenderer::render(SkBitmap** out) { |
627 SkASSERT(fPicture != NULL); | 656 SkASSERT(fPicture != NULL); |
628 if (NULL == fPicture) { | 657 if (NULL == fPicture) { |
629 return false; | 658 return false; |
630 } | 659 } |
631 | 660 |
632 SkBitmap bitmap; | 661 SkBitmap bitmap; |
633 if (out){ | 662 if (out){ |
634 *out = SkNEW(SkBitmap); | 663 *out = SkNEW(SkBitmap); |
635 setup_bitmap(*out, fPicture->width(), fPicture->height()); | 664 setup_bitmap(*out, fPicture->width(), fPicture->height()); |
636 setup_bitmap(&bitmap, fTileWidth, fTileHeight); | 665 setup_bitmap(&bitmap, fTileWidth, fTileHeight); |
637 } | 666 } |
638 bool success = true; | 667 bool success = true; |
639 for (int i = 0; i < fTileRects.count(); ++i) { | 668 for (int i = 0; i < fTileRects.count(); ++i) { |
640 draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture); | 669 draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture); |
641 if (NULL != path) { | 670 if (!fOutputDir.isEmpty()) { |
642 success &= writeAppendNumber(fCanvas, path, i, fJsonSummaryPtr); | 671 success &= write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPt
r, |
| 672 fUseChecksumBasedFilenames, &i); |
643 } | 673 } |
644 if (NULL != out) { | 674 if (NULL != out) { |
645 if (fCanvas->readPixels(&bitmap, 0, 0)) { | 675 if (fCanvas->readPixels(&bitmap, 0, 0)) { |
646 // Add this tile to the entire bitmap. | 676 // Add this tile to the entire bitmap. |
647 bitmapCopyAtOffset(bitmap, *out, SkScalarFloorToInt(fTileRects[i
].left()), | 677 bitmapCopyAtOffset(bitmap, *out, SkScalarFloorToInt(fTileRects[i
].left()), |
648 SkScalarFloorToInt(fTileRects[i].top())); | 678 SkScalarFloorToInt(fTileRects[i].top())); |
649 } else { | 679 } else { |
650 success = false; | 680 success = false; |
651 } | 681 } |
652 } | 682 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 return name; | 721 return name; |
692 } | 722 } |
693 | 723 |
694 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 724 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
695 | 725 |
696 // Holds all of the information needed to draw a set of tiles. | 726 // Holds all of the information needed to draw a set of tiles. |
697 class CloneData : public SkRunnable { | 727 class CloneData : public SkRunnable { |
698 | 728 |
699 public: | 729 public: |
700 CloneData(SkPicture* clone, SkCanvas* canvas, SkTDArray<SkRect>& rects, int
start, int end, | 730 CloneData(SkPicture* clone, SkCanvas* canvas, SkTDArray<SkRect>& rects, int
start, int end, |
701 SkRunnable* done, ImageResultsSummary* jsonSummaryPtr) | 731 SkRunnable* done, ImageResultsSummary* jsonSummaryPtr, bool useChe
cksumBasedFilenames) |
702 : fClone(clone) | 732 : fClone(clone) |
703 , fCanvas(canvas) | 733 , fCanvas(canvas) |
704 , fPath(NULL) | |
705 , fRects(rects) | 734 , fRects(rects) |
706 , fStart(start) | 735 , fStart(start) |
707 , fEnd(end) | 736 , fEnd(end) |
708 , fSuccess(NULL) | 737 , fSuccess(NULL) |
709 , fDone(done) | 738 , fDone(done) |
710 , fJsonSummaryPtr(jsonSummaryPtr) { | 739 , fJsonSummaryPtr(jsonSummaryPtr) |
| 740 , fUseChecksumBasedFilenames(useChecksumBasedFilenames) { |
711 SkASSERT(fDone != NULL); | 741 SkASSERT(fDone != NULL); |
712 } | 742 } |
713 | 743 |
714 virtual void run() SK_OVERRIDE { | 744 virtual void run() SK_OVERRIDE { |
715 SkGraphics::SetTLSFontCacheLimit(1024 * 1024); | 745 SkGraphics::SetTLSFontCacheLimit(1024 * 1024); |
716 | 746 |
717 SkBitmap bitmap; | 747 SkBitmap bitmap; |
718 if (fBitmap != NULL) { | 748 if (fBitmap != NULL) { |
719 // All tiles are the same size. | 749 // All tiles are the same size. |
720 setup_bitmap(&bitmap, SkScalarFloorToInt(fRects[0].width()), SkScala
rFloorToInt(fRects[0].height())); | 750 setup_bitmap(&bitmap, SkScalarFloorToInt(fRects[0].width()), SkScala
rFloorToInt(fRects[0].height())); |
721 } | 751 } |
722 | 752 |
723 for (int i = fStart; i < fEnd; i++) { | 753 for (int i = fStart; i < fEnd; i++) { |
724 draw_tile_to_canvas(fCanvas, fRects[i], fClone); | 754 draw_tile_to_canvas(fCanvas, fRects[i], fClone); |
725 if ((fPath != NULL) && !writeAppendNumber(fCanvas, fPath, i, fJsonSu
mmaryPtr) | 755 if ((!fOutputDir.isEmpty()) |
| 756 && !write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPtr, |
| 757 fUseChecksumBasedFilenames, &i) |
726 && fSuccess != NULL) { | 758 && fSuccess != NULL) { |
727 *fSuccess = false; | 759 *fSuccess = false; |
728 // If one tile fails to write to a file, do not continue drawing
the rest. | 760 // If one tile fails to write to a file, do not continue drawing
the rest. |
729 break; | 761 break; |
730 } | 762 } |
731 if (fBitmap != NULL) { | 763 if (fBitmap != NULL) { |
732 if (fCanvas->readPixels(&bitmap, 0, 0)) { | 764 if (fCanvas->readPixels(&bitmap, 0, 0)) { |
733 SkAutoLockPixels alp(*fBitmap); | 765 SkAutoLockPixels alp(*fBitmap); |
734 bitmapCopyAtOffset(bitmap, fBitmap, SkScalarFloorToInt(fRect
s[i].left()), | 766 bitmapCopyAtOffset(bitmap, fBitmap, SkScalarFloorToInt(fRect
s[i].left()), |
735 SkScalarFloorToInt(fRects[i].top())); | 767 SkScalarFloorToInt(fRects[i].top())); |
736 } else { | 768 } else { |
737 *fSuccess = false; | 769 *fSuccess = false; |
738 // If one tile fails to read pixels, do not continue drawing
the rest. | 770 // If one tile fails to read pixels, do not continue drawing
the rest. |
739 break; | 771 break; |
740 } | 772 } |
741 } | 773 } |
742 } | 774 } |
743 fDone->run(); | 775 fDone->run(); |
744 } | 776 } |
745 | 777 |
746 void setPathAndSuccess(const SkString* path, bool* success) { | 778 void setPathsAndSuccess(const SkString& outputDir, const SkString& inputFile
name, |
747 fPath = path; | 779 bool* success) { |
| 780 fOutputDir.set(outputDir); |
| 781 fInputFilename.set(inputFilename); |
748 fSuccess = success; | 782 fSuccess = success; |
749 } | 783 } |
750 | 784 |
751 void setBitmap(SkBitmap* bitmap) { | 785 void setBitmap(SkBitmap* bitmap) { |
752 fBitmap = bitmap; | 786 fBitmap = bitmap; |
753 } | 787 } |
754 | 788 |
755 private: | 789 private: |
756 // All pointers unowned. | 790 // All pointers unowned. |
757 SkPicture* fClone; // Picture to draw from. Each CloneData has
a unique one which | 791 SkPicture* fClone; // Picture to draw from. Each CloneData has
a unique one which |
758 // is threadsafe. | 792 // is threadsafe. |
759 SkCanvas* fCanvas; // Canvas to draw to. Reused for each tile. | 793 SkCanvas* fCanvas; // Canvas to draw to. Reused for each tile. |
760 const SkString* fPath; // If non-null, path to write the result to
as a PNG. | 794 SkString fOutputDir; // If not empty, write results into this dir
ectory. |
| 795 SkString fInputFilename; // Filename of input SkPicture file. |
761 SkTDArray<SkRect>& fRects; // All tiles of the picture. | 796 SkTDArray<SkRect>& fRects; // All tiles of the picture. |
762 const int fStart; // Range of tiles drawn by this thread. | 797 const int fStart; // Range of tiles drawn by this thread. |
763 const int fEnd; | 798 const int fEnd; |
764 bool* fSuccess; // Only meaningful if path is non-null. Shar
ed by all threads, | 799 bool* fSuccess; // Only meaningful if path is non-null. Shar
ed by all threads, |
765 // and only set to false upon failure to wri
te to a PNG. | 800 // and only set to false upon failure to wri
te to a PNG. |
766 SkRunnable* fDone; | 801 SkRunnable* fDone; |
767 SkBitmap* fBitmap; | 802 SkBitmap* fBitmap; |
768 ImageResultsSummary* fJsonSummaryPtr; | 803 ImageResultsSummary* fJsonSummaryPtr; |
| 804 bool fUseChecksumBasedFilenames; |
769 }; | 805 }; |
770 | 806 |
771 MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount) | 807 MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount) |
772 : fNumThreads(threadCount) | 808 : fNumThreads(threadCount) |
773 , fThreadPool(threadCount) | 809 , fThreadPool(threadCount) |
774 , fCountdown(threadCount) { | 810 , fCountdown(threadCount) { |
775 // Only need to create fNumThreads - 1 clones, since one thread will use the
base | 811 // Only need to create fNumThreads - 1 clones, since one thread will use the
base |
776 // picture. | 812 // picture. |
777 fPictureClones = SkNEW_ARRAY(SkPicture, fNumThreads - 1); | 813 fPictureClones = SkNEW_ARRAY(SkPicture, fNumThreads - 1); |
778 fCloneData = SkNEW_ARRAY(CloneData*, fNumThreads); | 814 fCloneData = SkNEW_ARRAY(CloneData*, fNumThreads); |
779 } | 815 } |
780 | 816 |
781 void MultiCorePictureRenderer::init(SkPicture *pict) { | 817 void MultiCorePictureRenderer::init(SkPicture *pict, const SkString& outputDir, |
| 818 const SkString& inputFilename, bool useCheck
sumBasedFilenames) { |
782 // Set fPicture and the tiles. | 819 // Set fPicture and the tiles. |
783 this->INHERITED::init(pict); | 820 this->INHERITED::init(pict, outputDir, inputFilename, useChecksumBasedFilena
mes); |
784 for (int i = 0; i < fNumThreads; ++i) { | 821 for (int i = 0; i < fNumThreads; ++i) { |
785 *fCanvasPool.append() = this->setupCanvas(this->getTileWidth(), this->ge
tTileHeight()); | 822 *fCanvasPool.append() = this->setupCanvas(this->getTileWidth(), this->ge
tTileHeight()); |
786 } | 823 } |
787 // Only need to create fNumThreads - 1 clones, since one thread will use the
base picture. | 824 // Only need to create fNumThreads - 1 clones, since one thread will use the
base picture. |
788 fPicture->clone(fPictureClones, fNumThreads - 1); | 825 fPicture->clone(fPictureClones, fNumThreads - 1); |
789 // Populate each thread with the appropriate data. | 826 // Populate each thread with the appropriate data. |
790 // Group the tiles into nearly equal size chunks, rounding up so we're sure
to cover them all. | 827 // Group the tiles into nearly equal size chunks, rounding up so we're sure
to cover them all. |
791 const int chunkSize = (fTileRects.count() + fNumThreads - 1) / fNumThreads; | 828 const int chunkSize = (fTileRects.count() + fNumThreads - 1) / fNumThreads; |
792 | 829 |
793 for (int i = 0; i < fNumThreads; i++) { | 830 for (int i = 0; i < fNumThreads; i++) { |
794 SkPicture* pic; | 831 SkPicture* pic; |
795 if (i == fNumThreads-1) { | 832 if (i == fNumThreads-1) { |
796 // The last set will use the original SkPicture. | 833 // The last set will use the original SkPicture. |
797 pic = fPicture; | 834 pic = fPicture; |
798 } else { | 835 } else { |
799 pic = &fPictureClones[i]; | 836 pic = &fPictureClones[i]; |
800 } | 837 } |
801 const int start = i * chunkSize; | 838 const int start = i * chunkSize; |
802 const int end = SkMin32(start + chunkSize, fTileRects.count()); | 839 const int end = SkMin32(start + chunkSize, fTileRects.count()); |
803 fCloneData[i] = SkNEW_ARGS(CloneData, | 840 fCloneData[i] = SkNEW_ARGS(CloneData, |
804 (pic, fCanvasPool[i], fTileRects, start, end,
&fCountdown, | 841 (pic, fCanvasPool[i], fTileRects, start, end,
&fCountdown, |
805 fJsonSummaryPtr)); | 842 fJsonSummaryPtr, useChecksumBasedFilenames))
; |
806 } | 843 } |
807 } | 844 } |
808 | 845 |
809 bool MultiCorePictureRenderer::render(const SkString *path, SkBitmap** out) { | 846 bool MultiCorePictureRenderer::render(SkBitmap** out) { |
810 bool success = true; | 847 bool success = true; |
811 if (path != NULL) { | 848 if (!fOutputDir.isEmpty()) { |
812 for (int i = 0; i < fNumThreads-1; i++) { | 849 for (int i = 0; i < fNumThreads-1; i++) { |
813 fCloneData[i]->setPathAndSuccess(path, &success); | 850 fCloneData[i]->setPathsAndSuccess(fOutputDir, fInputFilename, &succe
ss); |
814 } | 851 } |
815 } | 852 } |
816 | 853 |
817 if (NULL != out) { | 854 if (NULL != out) { |
818 *out = SkNEW(SkBitmap); | 855 *out = SkNEW(SkBitmap); |
819 setup_bitmap(*out, fPicture->width(), fPicture->height()); | 856 setup_bitmap(*out, fPicture->width(), fPicture->height()); |
820 for (int i = 0; i < fNumThreads; i++) { | 857 for (int i = 0; i < fNumThreads; i++) { |
821 fCloneData[i]->setBitmap(*out); | 858 fCloneData[i]->setBitmap(*out); |
822 } | 859 } |
823 } else { | 860 } else { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
861 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 898 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
862 | 899 |
863 void PlaybackCreationRenderer::setup() { | 900 void PlaybackCreationRenderer::setup() { |
864 fReplayer.reset(this->createPicture()); | 901 fReplayer.reset(this->createPicture()); |
865 SkCanvas* recorder = fReplayer->beginRecording(this->getViewWidth(), this->g
etViewHeight(), | 902 SkCanvas* recorder = fReplayer->beginRecording(this->getViewWidth(), this->g
etViewHeight(), |
866 this->recordFlags()); | 903 this->recordFlags()); |
867 this->scaleToScaleFactor(recorder); | 904 this->scaleToScaleFactor(recorder); |
868 fPicture->draw(recorder); | 905 fPicture->draw(recorder); |
869 } | 906 } |
870 | 907 |
871 bool PlaybackCreationRenderer::render(const SkString*, SkBitmap** out) { | 908 bool PlaybackCreationRenderer::render(SkBitmap** out) { |
872 fReplayer->endRecording(); | 909 fReplayer->endRecording(); |
873 // Since this class does not actually render, return false. | 910 // Since this class does not actually render, return false. |
874 return false; | 911 return false; |
875 } | 912 } |
876 | 913 |
877 SkString PlaybackCreationRenderer::getConfigNameInternal() { | 914 SkString PlaybackCreationRenderer::getConfigNameInternal() { |
878 return SkString("playback_creation"); | 915 return SkString("playback_creation"); |
879 } | 916 } |
880 | 917 |
881 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 918 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
(...skipping 26 matching lines...) Expand all Loading... |
908 fPicture->height(), fGridInfo)); | 945 fPicture->height(), fGridInfo)); |
909 } | 946 } |
910 SkASSERT(0); // invalid bbhType | 947 SkASSERT(0); // invalid bbhType |
911 return NULL; | 948 return NULL; |
912 } | 949 } |
913 | 950 |
914 /////////////////////////////////////////////////////////////////////////////// | 951 /////////////////////////////////////////////////////////////////////////////// |
915 | 952 |
916 class GatherRenderer : public PictureRenderer { | 953 class GatherRenderer : public PictureRenderer { |
917 public: | 954 public: |
918 virtual bool render(const SkString* path, SkBitmap** out = NULL) | 955 virtual bool render(SkBitmap** out = NULL) |
919 SK_OVERRIDE { | 956 SK_OVERRIDE { |
920 SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->width()), | 957 SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->width()), |
921 SkIntToScalar(fPicture->height())); | 958 SkIntToScalar(fPicture->height())); |
922 SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds); | 959 SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds); |
923 SkSafeUnref(data); | 960 SkSafeUnref(data); |
924 | 961 |
925 return NULL == path; // we don't have anything to write | 962 return (fOutputDir.isEmpty()); // we don't have anything to write |
926 } | 963 } |
927 | 964 |
928 private: | 965 private: |
929 virtual SkString getConfigNameInternal() SK_OVERRIDE { | 966 virtual SkString getConfigNameInternal() SK_OVERRIDE { |
930 return SkString("gather_pixelrefs"); | 967 return SkString("gather_pixelrefs"); |
931 } | 968 } |
932 }; | 969 }; |
933 | 970 |
934 PictureRenderer* CreateGatherPixelRefsRenderer() { | 971 PictureRenderer* CreateGatherPixelRefsRenderer() { |
935 return SkNEW(GatherRenderer); | 972 return SkNEW(GatherRenderer); |
936 } | 973 } |
937 | 974 |
938 /////////////////////////////////////////////////////////////////////////////// | 975 /////////////////////////////////////////////////////////////////////////////// |
939 | 976 |
940 class PictureCloneRenderer : public PictureRenderer { | 977 class PictureCloneRenderer : public PictureRenderer { |
941 public: | 978 public: |
942 virtual bool render(const SkString* path, SkBitmap** out = NULL) | 979 virtual bool render(SkBitmap** out = NULL) |
943 SK_OVERRIDE { | 980 SK_OVERRIDE { |
944 for (int i = 0; i < 100; ++i) { | 981 for (int i = 0; i < 100; ++i) { |
945 SkPicture* clone = fPicture->clone(); | 982 SkPicture* clone = fPicture->clone(); |
946 SkSafeUnref(clone); | 983 SkSafeUnref(clone); |
947 } | 984 } |
948 | 985 |
949 return NULL == path; // we don't have anything to write | 986 return (fOutputDir.isEmpty()); // we don't have anything to write |
950 } | 987 } |
951 | 988 |
952 private: | 989 private: |
953 virtual SkString getConfigNameInternal() SK_OVERRIDE { | 990 virtual SkString getConfigNameInternal() SK_OVERRIDE { |
954 return SkString("picture_clone"); | 991 return SkString("picture_clone"); |
955 } | 992 } |
956 }; | 993 }; |
957 | 994 |
958 PictureRenderer* CreatePictureCloneRenderer() { | 995 PictureRenderer* CreatePictureCloneRenderer() { |
959 return SkNEW(PictureCloneRenderer); | 996 return SkNEW(PictureCloneRenderer); |
960 } | 997 } |
961 | 998 |
962 } // namespace sk_tools | 999 } // namespace sk_tools |
OLD | NEW |