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" |
11 #include "SkBitmapHasher.h" | 11 #include "SkBitmapHasher.h" |
12 #include "SkCanvas.h" | 12 #include "SkCanvas.h" |
13 #include "SkData.h" | 13 #include "SkData.h" |
14 #include "SkDevice.h" | 14 #include "SkDevice.h" |
15 #include "SkDiscardableMemoryPool.h" | 15 #include "SkDiscardableMemoryPool.h" |
16 #include "SkGPipe.h" | 16 #include "SkGPipe.h" |
17 #if SK_SUPPORT_GPU | 17 #if SK_SUPPORT_GPU |
18 #include "gl/GrGLDefines.h" | 18 #include "gl/GrGLDefines.h" |
19 #include "SkGpuDevice.h" | 19 #include "SkGpuDevice.h" |
20 #endif | 20 #endif |
21 #include "SkGraphics.h" | 21 #include "SkGraphics.h" |
22 #include "SkImageEncoder.h" | 22 #include "SkImageEncoder.h" |
23 #include "SkMaskFilter.h" | 23 #include "SkMaskFilter.h" |
24 #include "SkMatrix.h" | 24 #include "SkMatrix.h" |
| 25 #include "SkOSFile.h" |
25 #include "SkPicture.h" | 26 #include "SkPicture.h" |
26 #include "SkPictureUtils.h" | 27 #include "SkPictureUtils.h" |
27 #include "SkPixelRef.h" | 28 #include "SkPixelRef.h" |
28 #include "SkQuadTree.h" | 29 #include "SkQuadTree.h" |
29 #include "SkQuadTreePicture.h" | 30 #include "SkQuadTreePicture.h" |
30 #include "SkRTree.h" | 31 #include "SkRTree.h" |
31 #include "SkScalar.h" | 32 #include "SkScalar.h" |
32 #include "SkStream.h" | 33 #include "SkStream.h" |
33 #include "SkString.h" | 34 #include "SkString.h" |
34 #include "SkTemplates.h" | 35 #include "SkTemplates.h" |
35 #include "SkTileGridPicture.h" | 36 #include "SkTileGridPicture.h" |
36 #include "SkTDArray.h" | 37 #include "SkTDArray.h" |
37 #include "SkThreadUtils.h" | 38 #include "SkThreadUtils.h" |
38 #include "SkTypes.h" | 39 #include "SkTypes.h" |
39 | 40 |
40 static inline SkScalar scalar_log2(SkScalar x) { | 41 static inline SkScalar scalar_log2(SkScalar x) { |
41 static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2)
); | 42 static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2)
); |
42 | 43 |
43 return SkScalarLog(x) * log2_conversion_factor; | 44 return SkScalarLog(x) * log2_conversion_factor; |
44 } | 45 } |
45 | 46 |
46 namespace sk_tools { | 47 namespace sk_tools { |
47 | 48 |
48 enum { | 49 enum { |
49 kDefaultTileWidth = 256, | 50 kDefaultTileWidth = 256, |
50 kDefaultTileHeight = 256 | 51 kDefaultTileHeight = 256 |
51 }; | 52 }; |
52 | 53 |
53 /* TODO(epoger): These constants are already maintained in 2 other places: | 54 /* TODO(epoger): Similar 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
. | 55 * 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. | 56 * Figure out a way to share the definitions instead. |
| 57 * |
| 58 * Note that, as of https://codereview.chromium.org/226293002 , the JSON |
| 59 * schema used here has started to differ from the one in gm_expectations.cpp . |
| 60 * TODO(epoger): Consider getting GM and render_pictures to use the same JSON |
| 61 * output module. |
56 */ | 62 */ |
57 const static char kJsonKey_ActualResults[] = "actual-results"; | 63 const static char kJsonKey_ActualResults[] = "actual-results"; |
58 const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison"; | 64 const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison"; |
59 const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5"; | 65 const static char kJsonKey_Header[] = "header"; |
| 66 const static char kJsonKey_Header_Type[] = "type"; |
| 67 const static char kJsonKey_Header_Revision[] = "revision"; // unique within Typ
e |
60 | 68 |
61 void ImageResultsSummary::add(const char *testName, uint64_t hash) { | 69 const static char kJsonKey_Image_ChecksumAlgorithm[] = "checksumAlgorithm"; |
62 Json::Value jsonTypeValuePair; | 70 const static char kJsonKey_Image_ChecksumValue[] = "checksumValue"; |
63 jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5)); | 71 const static char kJsonKey_Image_Filepath[] = "filepath"; |
64 jsonTypeValuePair.append(Json::UInt64(hash)); | 72 // Values (not keys) that are written out by this JSON generator |
65 fActualResultsNoComparison[testName] = jsonTypeValuePair; | 73 const static char kJsonValue_Header_Type[] = "ChecksummedImages"; |
| 74 const static int kJsonValue_Header_Revision = 1; |
| 75 const static char kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5[] = "bitmap-
64bitMD5"; |
| 76 |
| 77 void ImageResultsSummary::add(const char *testName, const char *fileName, uint64
_t hash) { |
| 78 Json::Value node; |
| 79 node[kJsonKey_Image_ChecksumAlgorithm] = kJsonValue_Image_ChecksumAlgorithm_
Bitmap64bitMD5; |
| 80 node[kJsonKey_Image_ChecksumValue] = Json::UInt64(hash); |
| 81 node[kJsonKey_Image_Filepath] = fileName; |
| 82 fActualResultsNoComparison[testName] = node; |
66 } | 83 } |
67 | 84 |
68 void ImageResultsSummary::add(const char *testName, const SkBitmap& bitmap) { | 85 void ImageResultsSummary::add(const char *testName, const char *fileName, const
SkBitmap& bitmap) { |
69 uint64_t hash; | 86 uint64_t hash; |
70 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); | 87 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); |
71 this->add(testName, hash); | 88 this->add(testName, fileName, hash); |
72 } | 89 } |
73 | 90 |
74 void ImageResultsSummary::writeToFile(const char *filename) { | 91 void ImageResultsSummary::writeToFile(const char *filename) { |
| 92 Json::Value header; |
| 93 header[kJsonKey_Header_Type] = kJsonValue_Header_Type; |
| 94 header[kJsonKey_Header_Revision] = kJsonValue_Header_Revision; |
75 Json::Value actualResults; | 95 Json::Value actualResults; |
76 actualResults[kJsonKey_ActualResults_NoComparison] = fActualResultsNoCompari
son; | 96 actualResults[kJsonKey_ActualResults_NoComparison] = fActualResultsNoCompari
son; |
77 Json::Value root; | 97 Json::Value root; |
| 98 root[kJsonKey_Header] = header; |
78 root[kJsonKey_ActualResults] = actualResults; | 99 root[kJsonKey_ActualResults] = actualResults; |
79 std::string jsonStdString = root.toStyledString(); | 100 std::string jsonStdString = root.toStyledString(); |
80 SkFILEWStream stream(filename); | 101 SkFILEWStream stream(filename); |
81 stream.write(jsonStdString.c_str(), jsonStdString.length()); | 102 stream.write(jsonStdString.c_str(), jsonStdString.length()); |
82 } | 103 } |
83 | 104 |
84 void PictureRenderer::init(SkPicture* pict, const SkString* outputDir, | 105 void PictureRenderer::init(SkPicture* pict, const SkString* outputDir, |
85 const SkString* inputFilename, bool useChecksumBasedF
ilenames) { | 106 const SkString* inputFilename, bool useChecksumBasedF
ilenames) { |
86 this->CopyString(&fOutputDir, outputDir); | 107 this->CopyString(&fOutputDir, outputDir); |
87 this->CopyString(&fInputFilename, inputFilename); | 108 this->CopyString(&fInputFilename, inputFilename); |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 SkISize size = canvas->getDeviceSize(); | 351 SkISize size = canvas->getDeviceSize(); |
331 sk_tools::setup_bitmap(&bitmap, size.width(), size.height()); | 352 sk_tools::setup_bitmap(&bitmap, size.width(), size.height()); |
332 | 353 |
333 // Make sure we only compute the bitmap hash once (at most). | 354 // Make sure we only compute the bitmap hash once (at most). |
334 uint64_t hash; | 355 uint64_t hash; |
335 bool generatedHash = false; | 356 bool generatedHash = false; |
336 | 357 |
337 canvas->readPixels(&bitmap, 0, 0); | 358 canvas->readPixels(&bitmap, 0, 0); |
338 sk_tools::force_all_opaque(bitmap); | 359 sk_tools::force_all_opaque(bitmap); |
339 | 360 |
340 SkString outputFilename(inputFilename); | |
341 outputFilename.remove(outputFilename.size() - 4, 4); | |
342 if (NULL != numberToAppend) { | |
343 outputFilename.appendf("%i", *numberToAppend); | |
344 } | |
345 outputFilename.append(".png"); | |
346 // TODO(epoger): what about including the config type within outputFilename?
That way, | 361 // TODO(epoger): what about including the config type within outputFilename?
That way, |
347 // we could combine results of different config types without conflicting fi
lenames. | 362 // we could combine results of different config types without conflicting fi
lenames. |
| 363 SkString inputFilenameWithTileNumber(inputFilename); |
| 364 if (NULL != numberToAppend) { |
| 365 inputFilenameWithTileNumber.append("-tile"); |
| 366 inputFilenameWithTileNumber.appendS32(*numberToAppend); |
| 367 } |
| 368 SkString escapedInputFilenameWithTileNumber(inputFilenameWithTileNumber); |
| 369 replace_char(&escapedInputFilenameWithTileNumber, '.', '_'); |
348 | 370 |
349 if (NULL != jsonSummaryPtr) { | 371 SkString outputFilename; |
| 372 const char *outputSubdirPtr = NULL; |
| 373 if (useChecksumBasedFilenames) { |
350 SkASSERT(!generatedHash); | 374 SkASSERT(!generatedHash); |
351 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); | 375 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); |
352 generatedHash = true; | 376 generatedHash = true; |
353 | 377 |
354 jsonSummaryPtr->add(outputFilename.c_str(), hash); | 378 outputSubdirPtr = escapedInputFilenameWithTileNumber.c_str(); |
| 379 outputFilename.set(kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5); |
| 380 outputFilename.append("_"); |
| 381 outputFilename.appendU64(hash); |
| 382 } else { |
| 383 outputFilename.set(escapedInputFilenameWithTileNumber); |
355 } | 384 } |
| 385 outputFilename.append(".png"); |
356 | 386 |
357 // Update outputFilename AFTER adding to JSON summary, but BEFORE writing ou
t the image file. | 387 if (NULL != jsonSummaryPtr) { |
358 if (useChecksumBasedFilenames) { | |
359 if (!generatedHash) { | 388 if (!generatedHash) { |
360 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); | 389 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); |
361 generatedHash = true; | 390 generatedHash = true; |
362 } | 391 } |
363 outputFilename.set(kJsonKey_Hashtype_Bitmap_64bitMD5); | 392 |
364 outputFilename.append("_"); | 393 SkString outputRelativePath; |
365 outputFilename.appendU64(hash); | 394 if (outputSubdirPtr) { |
366 outputFilename.append(".png"); | 395 outputRelativePath.set(outputSubdirPtr); |
| 396 outputRelativePath.append("/"); // always use "/", even on Windows |
| 397 outputRelativePath.append(outputFilename); |
| 398 } else { |
| 399 outputRelativePath.set(outputFilename); |
| 400 } |
| 401 jsonSummaryPtr->add(inputFilenameWithTileNumber.c_str(), outputRelativeP
ath.c_str(), hash); |
367 } | 402 } |
368 | 403 |
369 SkASSERT(!outputDir.isEmpty()); // TODO(epoger): we want to remove this cons
traint, | 404 SkASSERT(!outputDir.isEmpty()); // TODO(epoger): we want to remove this cons
traint, |
370 // as noted above | 405 // as noted above |
371 SkString fullPathname; | 406 SkString dirPath; |
372 make_filepath(&fullPathname, outputDir, outputFilename); | 407 if (outputSubdirPtr) { |
373 return SkImageEncoder::EncodeFile(fullPathname.c_str(), bitmap, SkImageEncod
er::kPNG_Type, 100); | 408 dirPath = SkOSPath::SkPathJoin(outputDir.c_str(), outputSubdirPtr); |
| 409 sk_mkdir(dirPath.c_str()); |
| 410 } else { |
| 411 dirPath.set(outputDir); |
| 412 } |
| 413 SkString fullPath = SkOSPath::SkPathJoin(dirPath.c_str(), outputFilename.c_s
tr()); |
| 414 return SkImageEncoder::EncodeFile(fullPath.c_str(), bitmap, SkImageEncoder::
kPNG_Type, 100); |
374 } | 415 } |
375 | 416 |
376 ////////////////////////////////////////////////////////////////////////////////
/////////////// | 417 ////////////////////////////////////////////////////////////////////////////////
/////////////// |
377 | 418 |
378 SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) { | 419 SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) { |
379 // defer the canvas setup until the render step | 420 // defer the canvas setup until the render step |
380 return NULL; | 421 return NULL; |
381 } | 422 } |
382 | 423 |
383 // the size_t* parameter is deprecated, so we ignore it | 424 // the size_t* parameter is deprecated, so we ignore it |
384 static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) { | 425 static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) { |
385 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100); | 426 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100); |
386 } | 427 } |
387 | 428 |
388 bool RecordPictureRenderer::render(SkBitmap** out) { | 429 bool RecordPictureRenderer::render(SkBitmap** out) { |
389 SkAutoTUnref<SkPicture> replayer(this->createPicture()); | 430 SkAutoTUnref<SkPicture> replayer(this->createPicture()); |
390 SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->ge
tViewHeight(), | 431 SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->ge
tViewHeight(), |
391 this->recordFlags()); | 432 this->recordFlags()); |
392 this->scaleToScaleFactor(recorder); | 433 this->scaleToScaleFactor(recorder); |
393 fPicture->draw(recorder); | 434 fPicture->draw(recorder); |
394 replayer->endRecording(); | 435 replayer->endRecording(); |
395 if (!fOutputDir.isEmpty()) { | 436 if (!fOutputDir.isEmpty()) { |
396 // Record the new picture as a new SKP with PNG encoded bitmaps. | 437 // Record the new picture as a new SKP with PNG encoded bitmaps. |
397 SkString skpPath; | 438 SkString skpPath = SkOSPath::SkPathJoin(fOutputDir.c_str(), fInputFilena
me.c_str()); |
398 make_filepath(&skpPath, fOutputDir, fInputFilename); | |
399 SkFILEWStream stream(skpPath.c_str()); | 439 SkFILEWStream stream(skpPath.c_str()); |
400 replayer->serialize(&stream, &encode_bitmap_to_data); | 440 replayer->serialize(&stream, &encode_bitmap_to_data); |
401 return true; | 441 return true; |
402 } | 442 } |
403 return false; | 443 return false; |
404 } | 444 } |
405 | 445 |
406 SkString RecordPictureRenderer::getConfigNameInternal() { | 446 SkString RecordPictureRenderer::getConfigNameInternal() { |
407 return SkString("record"); | 447 return SkString("record"); |
408 } | 448 } |
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
995 virtual SkString getConfigNameInternal() SK_OVERRIDE { | 1035 virtual SkString getConfigNameInternal() SK_OVERRIDE { |
996 return SkString("picture_clone"); | 1036 return SkString("picture_clone"); |
997 } | 1037 } |
998 }; | 1038 }; |
999 | 1039 |
1000 PictureRenderer* CreatePictureCloneRenderer() { | 1040 PictureRenderer* CreatePictureCloneRenderer() { |
1001 return SkNEW(PictureCloneRenderer); | 1041 return SkNEW(PictureCloneRenderer); |
1002 } | 1042 } |
1003 | 1043 |
1004 } // namespace sk_tools | 1044 } // namespace sk_tools |
OLD | NEW |