OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "CrashHandler.h" | 8 #include "CrashHandler.h" |
9 #include "DMJsonWriter.h" | 9 #include "DMJsonWriter.h" |
10 #include "DMSrcSink.h" | 10 #include "DMSrcSink.h" |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 SkStrSplit((const char*)data->data(), "\n", &hashes); | 168 SkStrSplit((const char*)data->data(), "\n", &hashes); |
169 for (const SkString& hash : hashes) { | 169 for (const SkString& hash : hashes) { |
170 gUninterestingHashes.add(hash); | 170 gUninterestingHashes.add(hash); |
171 } | 171 } |
172 } | 172 } |
173 } | 173 } |
174 | 174 |
175 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ | 175 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~*/ |
176 | 176 |
177 struct TaggedSrc : public SkAutoTDelete<Src> { | 177 struct TaggedSrc : public SkAutoTDelete<Src> { |
178 const char* tag; | 178 ImplicitString tag; |
179 const char* options; | 179 ImplicitString options; |
180 }; | 180 }; |
181 | 181 |
182 struct TaggedSink : public SkAutoTDelete<Sink> { | 182 struct TaggedSink : public SkAutoTDelete<Sink> { |
183 const char* tag; | 183 const char* tag; |
184 }; | 184 }; |
185 | 185 |
186 static const bool kMemcpyOK = true; | 186 static const bool kMemcpyOK = true; |
187 | 187 |
188 static SkTArray<TaggedSrc, kMemcpyOK> gSrcs; | 188 static SkTArray<TaggedSrc, kMemcpyOK> gSrcs; |
189 static SkTArray<TaggedSink, kMemcpyOK> gSinks; | 189 static SkTArray<TaggedSink, kMemcpyOK> gSinks; |
190 | 190 |
191 static bool in_shard() { | 191 static bool in_shard() { |
192 static int N = 0; | 192 static int N = 0; |
193 return N++ % FLAGS_shards == FLAGS_shard; | 193 return N++ % FLAGS_shards == FLAGS_shard; |
194 } | 194 } |
195 | 195 |
196 static void push_src(const char* tag, const char* options, Src* s) { | 196 static void push_src(ImplicitString tag, ImplicitString options, Src* s) { |
197 SkAutoTDelete<Src> src(s); | 197 SkAutoTDelete<Src> src(s); |
198 if (in_shard() && | 198 if (in_shard() && |
199 FLAGS_src.contains(tag) && | 199 FLAGS_src.contains(tag.c_str()) && |
200 !SkCommandLineFlags::ShouldSkip(FLAGS_match, src->name().c_str())) { | 200 !SkCommandLineFlags::ShouldSkip(FLAGS_match, src->name().c_str())) { |
201 TaggedSrc& s = gSrcs.push_back(); | 201 TaggedSrc& s = gSrcs.push_back(); |
202 s.reset(src.detach()); | 202 s.reset(src.detach()); |
203 s.tag = tag; | 203 s.tag = tag; |
204 s.options = options; | 204 s.options = options; |
205 } | 205 } |
206 } | 206 } |
207 | 207 |
| 208 static void push_codec_src(Path path, CodecSrc::Mode mode, CodecSrc::DstColorTyp
e dstColorType, |
| 209 float scale) { |
| 210 SkString folder; |
| 211 switch (mode) { |
| 212 case CodecSrc::kCodec_Mode: |
| 213 folder.append("codec"); |
| 214 break; |
| 215 case CodecSrc::kScaledCodec_Mode: |
| 216 folder.append("scaled_codec"); |
| 217 break; |
| 218 case CodecSrc::kScanline_Mode: |
| 219 folder.append("scanline"); |
| 220 break; |
| 221 case CodecSrc::kScanline_Subset_Mode: |
| 222 folder.append("scanline_subset"); |
| 223 break; |
| 224 case CodecSrc::kStripe_Mode: |
| 225 folder.append("stripe"); |
| 226 break; |
| 227 case CodecSrc::kSubset_Mode: |
| 228 folder.append("subset"); |
| 229 break; |
| 230 } |
| 231 |
| 232 switch (dstColorType) { |
| 233 case CodecSrc::kGrayscale_Always_DstColorType: |
| 234 folder.append("_kGray8"); |
| 235 break; |
| 236 case CodecSrc::kIndex8_Always_DstColorType: |
| 237 folder.append("_kIndex8"); |
| 238 break; |
| 239 default: |
| 240 break; |
| 241 } |
| 242 |
| 243 if (1.0f != scale) { |
| 244 folder.appendf("_%.3f", scale); |
| 245 } |
| 246 |
| 247 CodecSrc* src = new CodecSrc(path, mode, dstColorType, scale); |
| 248 push_src("image", folder, src); |
| 249 } |
| 250 |
208 static void push_codec_srcs(Path path) { | 251 static void push_codec_srcs(Path path) { |
209 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str())); | 252 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str())); |
210 if (!encoded) { | 253 if (!encoded) { |
211 SkDebugf("Couldn't read %s.", path.c_str()); | 254 SkDebugf("Couldn't read %s.", path.c_str()); |
212 return; | 255 return; |
213 } | 256 } |
214 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); | 257 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); |
215 if (nullptr == codec.get()) { | 258 if (nullptr == codec.get()) { |
216 SkDebugf("Couldn't create codec for %s.", path.c_str()); | 259 SkDebugf("Couldn't create codec for %s.", path.c_str()); |
217 return; | 260 return; |
218 } | 261 } |
219 | 262 |
220 // Choose scales for scaling tests. | 263 // Choose scales for scaling tests. |
221 // TODO (msarett): Add more scaling tests as we implement more flexible scal
ing. | |
222 // TODO (msarett): Implement scaling tests for SkImageDecoder in order to co
mpare with these | 264 // TODO (msarett): Implement scaling tests for SkImageDecoder in order to co
mpare with these |
223 // tests. SkImageDecoder supports downscales by integer fac
tors. | 265 // tests. SkImageDecoder supports downscales by integer fac
tors. |
224 // SkJpegCodec natively supports scaling to: 0.125, 0.25, 0.375, 0.5, 0.625,
0.75, 0.875 | 266 // SkJpegCodec natively supports scaling to: 0.125, 0.25, 0.375, 0.5, 0.625,
0.75, 0.875 |
225 // 0.1, 0.16, 0.2 etc allow us to test SkScaledCodec with sampleSize 10, 6,
5, etc | 267 // 0.1, 0.16, 0.2 etc allow us to test SkScaledCodec with sampleSize 10, 6,
5, etc |
226 // 0.4, 0.7 etc allow to test what happens when the client requests a scale
that | 268 // 0.4, 0.7 etc allow to test what happens when the client requests a scale
that |
227 // does not exactly match a sampleSize or native scaling capability | 269 // does not exactly match a sampleSize or native scaling capability |
228 const float scales[] = { 0.1f, 0.125f, 0.166f, 0.2f, 0.25f, 0.333f, 0.375f,
0.4f, 0.5f, 0.6f, | 270 const float scales[] = { 0.1f, 0.125f, 0.166f, 0.2f, 0.25f, 0.333f, 0.375f,
0.4f, 0.5f, 0.6f, |
229 0.625f, 0.750f, 0.8f, 0.875f, 1.0f }; | 271 0.625f, 0.750f, 0.8f, 0.875f, 1.0f }; |
230 | 272 |
| 273 const CodecSrc::Mode modes[] = { CodecSrc::kCodec_Mode, CodecSrc::kScaledCod
ec_Mode, |
| 274 CodecSrc::kScanline_Mode, CodecSrc::kScanline_Subset_Mode, CodecSrc:
:kStripe_Mode, |
| 275 CodecSrc::kSubset_Mode }; |
| 276 |
| 277 const CodecSrc::DstColorType colorTypes[] = { CodecSrc::kGetFromCanvas_DstCo
lorType, |
| 278 CodecSrc::kGrayscale_Always_DstColorType, CodecSrc::kIndex8_Always_D
stColorType }; |
| 279 |
231 for (float scale : scales) { | 280 for (float scale : scales) { |
232 if (scale != 1.0f && (path.endsWith(".webp") || path.endsWith(".WEBP")))
{ | 281 if (scale != 1.0f && (path.endsWith(".webp") || path.endsWith(".WEBP")))
{ |
233 // FIXME: skbug.com/4038 Scaling webp seems to leave some pixels uni
nitialized/ | 282 // FIXME: skbug.com/4038 Scaling webp seems to leave some pixels uni
nitialized/ |
234 // compute their colors based on uninitialized values. | 283 // compute their colors based on uninitialized values. |
235 continue; | 284 continue; |
236 } | 285 } |
237 // Build additional test cases for images that decode natively to non-ca
nvas types | 286 |
238 switch(codec->getInfo().colorType()) { | 287 for (CodecSrc::Mode mode : modes) { |
239 case kGray_8_SkColorType: | 288 for (CodecSrc::DstColorType colorType : colorTypes) { |
240 push_src("image", "codec_kGray8", new CodecSrc(path, CodecSrc::k
Normal_Mode, | 289 push_codec_src(path, mode, colorType, scale); |
241 CodecSrc::kGrayscale_Always_DstColorType, scale)); | 290 } |
242 push_src("image", "scanline_kGray8", new CodecSrc(path, CodecSrc
::kScanline_Mode, | |
243 CodecSrc::kGrayscale_Always_DstColorType, scale)); | |
244 push_src("image", "scanline_subset_kGray8", new CodecSrc(path, | |
245 CodecSrc::kScanline_Subset_Mode, CodecSrc::kGrayscale_Al
ways_DstColorType, | |
246 scale)); | |
247 push_src("image", "stripe_kGray8", new CodecSrc(path, CodecSrc::
kStripe_Mode, | |
248 CodecSrc::kGrayscale_Always_DstColorType, scale)); | |
249 // Intentional fall through | |
250 // FIXME: Is this a long term solution for testing wbmps decodes
to kIndex8? | |
251 // Further discussion on this topic is at skbug.com/3683 | |
252 case kIndex_8_SkColorType: | |
253 push_src("image", "codec_kIndex8", new CodecSrc(path, CodecSrc::
kNormal_Mode, | |
254 CodecSrc::kIndex8_Always_DstColorType, scale)); | |
255 push_src("image", "scanline_kIndex8", new CodecSrc(path, CodecSr
c::kScanline_Mode, | |
256 CodecSrc::kIndex8_Always_DstColorType, scale)); | |
257 push_src("image", "scanline_subset_kIndex8", new CodecSrc(path, | |
258 CodecSrc::kScanline_Subset_Mode, CodecSrc::kIndex8_Alway
s_DstColorType, | |
259 scale)); | |
260 push_src("image", "stripe_kIndex8", new CodecSrc(path, CodecSrc:
:kStripe_Mode, | |
261 CodecSrc::kIndex8_Always_DstColorType, scale)); | |
262 break; | |
263 default: | |
264 // Do nothing | |
265 break; | |
266 } | 291 } |
267 | |
268 // Decode all images to the canvas color type | |
269 push_src("image", "codec", new CodecSrc(path, CodecSrc::kNormal_Mode, | |
270 CodecSrc::kGetFromCanvas_DstColorType, scale)); | |
271 push_src("image", "scanline", new CodecSrc(path, CodecSrc::kScanline_Mod
e, | |
272 CodecSrc::kGetFromCanvas_DstColorType, scale)); | |
273 push_src("image", "scanline_subset", new CodecSrc(path, CodecSrc::kScanl
ine_Subset_Mode, | |
274 CodecSrc::kGetFromCanvas_DstColorType, scale)); | |
275 push_src("image", "stripe", new CodecSrc(path, CodecSrc::kStripe_Mode, | |
276 CodecSrc::kGetFromCanvas_DstColorType, scale)); | |
277 // Note: The only codec which supports subsets natively is SkWebpCodec,
which will never | |
278 // report kIndex_8 or kGray_8, so there is no need to test kSubset_mode
with those color | |
279 // types specifically requested. | |
280 push_src("image", "codec_subset", new CodecSrc(path, CodecSrc::kSubset_M
ode, | |
281 CodecSrc::kGetFromCanvas_DstColorType, scale)); | |
282 } | 292 } |
283 } | 293 } |
284 | 294 |
285 static bool codec_supported(const char* ext) { | 295 static bool codec_supported(const char* ext) { |
286 // FIXME: Once other versions of SkCodec are available, we can add them to t
his | 296 // FIXME: Once other versions of SkCodec are available, we can add them to t
his |
287 // list (and eventually we can remove this check once they are all supported
). | 297 // list (and eventually we can remove this check once they are all supported
). |
288 static const char* const exts[] = { | 298 static const char* const exts[] = { |
289 "bmp", "gif", "jpg", "jpeg", "png", "ico", "wbmp", "webp", | 299 "bmp", "gif", "jpg", "jpeg", "png", "ico", "wbmp", "webp", |
290 "BMP", "GIF", "JPG", "JPEG", "PNG", "ICO", "WBMP", "WEBP", | 300 "BMP", "GIF", "JPG", "JPEG", "PNG", "ICO", "WBMP", "WEBP", |
291 }; | 301 }; |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 const TaggedSink& sink; | 578 const TaggedSink& sink; |
569 | 579 |
570 static void Run(Task* task) { | 580 static void Run(Task* task) { |
571 SkString name = task->src->name(); | 581 SkString name = task->src->name(); |
572 | 582 |
573 // We'll skip drawing this Src/Sink pair if: | 583 // We'll skip drawing this Src/Sink pair if: |
574 // - the Src vetoes the Sink; | 584 // - the Src vetoes the Sink; |
575 // - this Src / Sink combination is on the blacklist; | 585 // - this Src / Sink combination is on the blacklist; |
576 // - it's a dry run. | 586 // - it's a dry run. |
577 SkString note(task->src->veto(task->sink->flags()) ? " (veto)" : ""); | 587 SkString note(task->src->veto(task->sink->flags()) ? " (veto)" : ""); |
578 SkString whyBlacklisted = is_blacklisted(task->sink.tag, task->src.tag, | 588 SkString whyBlacklisted = is_blacklisted(task->sink.tag, task->src.tag.c
_str(), |
579 task->src.options, name.c_str()
); | 589 task->src.options.c_str(), name
.c_str()); |
580 if (!whyBlacklisted.isEmpty()) { | 590 if (!whyBlacklisted.isEmpty()) { |
581 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); | 591 note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); |
582 } | 592 } |
583 | 593 |
584 SkString log; | 594 SkString log; |
585 WallTimer timer; | 595 WallTimer timer; |
586 timer.start(); | 596 timer.start(); |
587 if (!FLAGS_dryRun && note.isEmpty()) { | 597 if (!FLAGS_dryRun && note.isEmpty()) { |
588 SkBitmap bitmap; | 598 SkBitmap bitmap; |
589 SkDynamicMemoryWStream stream; | 599 SkDynamicMemoryWStream stream; |
590 if (FLAGS_pre_log) { | 600 if (FLAGS_pre_log) { |
591 SkDebugf("\nRunning %s->%s", name.c_str(), task->sink.tag); | 601 SkDebugf("\nRunning %s->%s", name.c_str(), task->sink.tag); |
592 } | 602 } |
593 start(task->sink.tag, task->src.tag, task->src.options, name.c_str()
); | 603 start(task->sink.tag, task->src.tag, task->src.options, name.c_str()
); |
594 Error err = task->sink->draw(*task->src, &bitmap, &stream, &log); | 604 Error err = task->sink->draw(*task->src, &bitmap, &stream, &log); |
595 if (!err.isEmpty()) { | 605 if (!err.isEmpty()) { |
596 timer.end(); | 606 timer.end(); |
597 if (err.isFatal()) { | 607 if (err.isFatal()) { |
598 fail(SkStringPrintf("%s %s %s %s: %s", | 608 fail(SkStringPrintf("%s %s %s %s: %s", |
599 task->sink.tag, | 609 task->sink.tag, |
600 task->src.tag, | 610 task->src.tag.c_str(), |
601 task->src.options, | 611 task->src.options.c_str(), |
602 name.c_str(), | 612 name.c_str(), |
603 err.c_str())); | 613 err.c_str())); |
604 } else { | 614 } else { |
605 note.appendf(" (skipped: %s)", err.c_str()); | 615 note.appendf(" (skipped: %s)", err.c_str()); |
606 } | 616 } |
607 done(timer.fWall, task->sink.tag, task->src.tag, task->src.optio
ns, | 617 done(timer.fWall, task->sink.tag, task->src.tag, task->src.optio
ns, |
608 name, note, log); | 618 name, note, log); |
609 return; | 619 return; |
610 } | 620 } |
611 SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream()); | 621 SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream()); |
(...skipping 18 matching lines...) Expand all Loading... |
630 } | 640 } |
631 } | 641 } |
632 SkMD5::Digest digest; | 642 SkMD5::Digest digest; |
633 hash.finish(digest); | 643 hash.finish(digest); |
634 for (int i = 0; i < 16; i++) { | 644 for (int i = 0; i < 16; i++) { |
635 md5.appendf("%02x", digest.data[i]); | 645 md5.appendf("%02x", digest.data[i]); |
636 } | 646 } |
637 } | 647 } |
638 | 648 |
639 if (!FLAGS_readPath.isEmpty() && | 649 if (!FLAGS_readPath.isEmpty() && |
640 !gGold.contains(Gold(task->sink.tag, task->src.tag, | 650 !gGold.contains(Gold(task->sink.tag, task->src.tag.c_str(), |
641 task->src.options, name, md5))) { | 651 task->src.options.c_str(), name, md5))) { |
642 fail(SkStringPrintf("%s not found for %s %s %s %s in %s", | 652 fail(SkStringPrintf("%s not found for %s %s %s %s in %s", |
643 md5.c_str(), | 653 md5.c_str(), |
644 task->sink.tag, | 654 task->sink.tag, |
645 task->src.tag, | 655 task->src.tag.c_str(), |
646 task->src.options, | 656 task->src.options.c_str(), |
647 name.c_str(), | 657 name.c_str(), |
648 FLAGS_readPath[0])); | 658 FLAGS_readPath[0])); |
649 } | 659 } |
650 | 660 |
651 if (!FLAGS_writePath.isEmpty()) { | 661 if (!FLAGS_writePath.isEmpty()) { |
652 const char* ext = task->sink->fileExtension(); | 662 const char* ext = task->sink->fileExtension(); |
653 if (data->getLength()) { | 663 if (data->getLength()) { |
654 WriteToDisk(*task, md5, ext, data, data->getLength(), nullpt
r); | 664 WriteToDisk(*task, md5, ext, data, data->getLength(), nullpt
r); |
655 SkASSERT(bitmap.drawsNothing()); | 665 SkASSERT(bitmap.drawsNothing()); |
656 } else if (!bitmap.drawsNothing()) { | 666 } else if (!bitmap.drawsNothing()) { |
657 WriteToDisk(*task, md5, ext, nullptr, 0, &bitmap); | 667 WriteToDisk(*task, md5, ext, nullptr, 0, &bitmap); |
658 } | 668 } |
659 } | 669 } |
660 } | 670 } |
661 timer.end(); | 671 timer.end(); |
662 done(timer.fWall, task->sink.tag, task->src.tag, task->src.options, name
, note, log); | 672 done(timer.fWall, task->sink.tag, task->src.tag.c_str(), task->src.optio
ns.c_str(), name, |
| 673 note, log); |
663 } | 674 } |
664 | 675 |
665 static void WriteToDisk(const Task& task, | 676 static void WriteToDisk(const Task& task, |
666 SkString md5, | 677 SkString md5, |
667 const char* ext, | 678 const char* ext, |
668 SkStream* data, size_t len, | 679 SkStream* data, size_t len, |
669 const SkBitmap* bitmap) { | 680 const SkBitmap* bitmap) { |
670 JsonWriter::BitmapResult result; | 681 JsonWriter::BitmapResult result; |
671 result.name = task.src->name(); | 682 result.name = task.src->name(); |
672 result.config = task.sink.tag; | 683 result.config = task.sink.tag; |
(...skipping 19 matching lines...) Expand all Loading... |
692 if (FLAGS_nameByHash) { | 703 if (FLAGS_nameByHash) { |
693 path = SkOSPath::Join(dir, result.md5.c_str()); | 704 path = SkOSPath::Join(dir, result.md5.c_str()); |
694 path.append("."); | 705 path.append("."); |
695 path.append(ext); | 706 path.append(ext); |
696 if (sk_exists(path.c_str())) { | 707 if (sk_exists(path.c_str())) { |
697 return; // Content-addressed. If it exists already, we're done
. | 708 return; // Content-addressed. If it exists already, we're done
. |
698 } | 709 } |
699 } else { | 710 } else { |
700 path = SkOSPath::Join(dir, task.sink.tag); | 711 path = SkOSPath::Join(dir, task.sink.tag); |
701 sk_mkdir(path.c_str()); | 712 sk_mkdir(path.c_str()); |
702 path = SkOSPath::Join(path.c_str(), task.src.tag); | 713 path = SkOSPath::Join(path.c_str(), task.src.tag.c_str()); |
703 sk_mkdir(path.c_str()); | 714 sk_mkdir(path.c_str()); |
704 if (strcmp(task.src.options, "") != 0) { | 715 if (strcmp(task.src.options.c_str(), "") != 0) { |
705 path = SkOSPath::Join(path.c_str(), task.src.options); | 716 path = SkOSPath::Join(path.c_str(), task.src.options.c_str()); |
706 sk_mkdir(path.c_str()); | 717 sk_mkdir(path.c_str()); |
707 } | 718 } |
708 path = SkOSPath::Join(path.c_str(), task.src->name().c_str()); | 719 path = SkOSPath::Join(path.c_str(), task.src->name().c_str()); |
709 path.append("."); | 720 path.append("."); |
710 path.append(ext); | 721 path.append(ext); |
711 } | 722 } |
712 | 723 |
713 if (bitmap) { | 724 if (bitmap) { |
714 if (!dump_png(*bitmap, path.c_str(), result.md5.c_str())) { | 725 if (!dump_png(*bitmap, path.c_str(), result.md5.c_str())) { |
715 fail(SkStringPrintf("Can't encode PNG to %s.\n", path.c_str())); | 726 fail(SkStringPrintf("Can't encode PNG to %s.\n", path.c_str())); |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 } | 924 } |
914 return 0; | 925 return 0; |
915 } | 926 } |
916 | 927 |
917 #if !defined(SK_BUILD_FOR_IOS) | 928 #if !defined(SK_BUILD_FOR_IOS) |
918 int main(int argc, char** argv) { | 929 int main(int argc, char** argv) { |
919 SkCommandLineFlags::Parse(argc, argv); | 930 SkCommandLineFlags::Parse(argc, argv); |
920 return dm_main(); | 931 return dm_main(); |
921 } | 932 } |
922 #endif | 933 #endif |
OLD | NEW |