add -r to DM
$ out/Debug/dm -w good
$ out/Debug/dm -r good -w bad && echo "hooray no diffs!"
BUG=skia:
Review URL: https://codereview.chromium.org/863093003
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 708d855..5b99a4c 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -4,11 +4,13 @@
#include "OverwriteLine.h"
#include "ProcStats.h"
#include "SkBBHFactory.h"
+#include "SkChecksum.h"
#include "SkCommonFlags.h"
#include "SkForceLinking.h"
#include "SkGraphics.h"
#include "SkMD5.h"
#include "SkOSFile.h"
+#include "SkTDynamicHash.h"
#include "SkTaskGroup.h"
#include "Test.h"
#include "Timer.h"
@@ -28,6 +30,8 @@
"'--blacklist gpu skp _' will blacklist all SKPs drawn into the gpu config.\n"
"'--blacklist gpu skp _ 8888 gm aarects' will also blacklist the aarects GM on 8888.");
+DEFINE_string2(readPath, r, "", "If set check for equality with golden results in this directory.");
+
__SK_FORCE_IMAGE_DECODER_LINKING;
using namespace DM;
@@ -62,6 +66,40 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+struct Gold : public SkString {
+ Gold(ImplicitString sink, ImplicitString src, ImplicitString name, ImplicitString md5)
+ : SkString("") {
+ this->append(sink);
+ this->append(src);
+ this->append(name);
+ this->append(md5);
+ while (this->size() % 4) {
+ this->append("!"); // Pad out if needed so we can pass this to Murmur3.
+ }
+ }
+ static const Gold& GetKey(const Gold& g) { return g; }
+ static uint32_t Hash(const Gold& g) {
+ return SkChecksum::Murmur3((const uint32_t*)g.c_str(), g.size());
+ }
+};
+static SkTDynamicHash<Gold, Gold> gGold;
+
+static void add_gold(JsonWriter::BitmapResult r) {
+ gGold.add(new Gold(r.config, r.sourceType, r.name, r.md5)); // We'll let these leak. Lazybones.
+}
+
+static void gather_gold() {
+ if (!FLAGS_readPath.isEmpty()) {
+ SkString path(FLAGS_readPath[0]);
+ path.append("/dm.json");
+ if (!JsonWriter::ReadJson(path.c_str(), add_gold)) {
+ fail(SkStringPrintf("Couldn't read %s for golden results.", path.c_str()));
+ }
+ }
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
template <typename T>
struct Tagged : public SkAutoTDelete<T> { const char* tag; };
@@ -256,14 +294,40 @@
name.c_str(),
err.c_str()));
}
+ SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream());
+
+ SkString md5;
+ if (!FLAGS_writePath.isEmpty() || !FLAGS_readPath.isEmpty()) {
+ SkMD5 hash;
+ if (data->getLength()) {
+ hash.writeStream(data, data->getLength());
+ data->rewind();
+ } else {
+ hash.write(bitmap.getPixels(), bitmap.getSize());
+ }
+ SkMD5::Digest digest;
+ hash.finish(digest);
+ for (int i = 0; i < 16; i++) {
+ md5.appendf("%02x", digest.data[i]);
+ }
+ }
+
+ if (!FLAGS_readPath.isEmpty() &&
+ !gGold.find(Gold(task->sink.tag, task->src.tag, name, md5))) {
+ fail(SkStringPrintf("%s not found for %s %s %s in %s",
+ md5.c_str(),
+ task->sink.tag,
+ task->src.tag,
+ name.c_str(),
+ FLAGS_readPath[0]));
+ }
+
if (!FLAGS_writePath.isEmpty()) {
const char* ext = task->sink->fileExtension();
- if (stream.bytesWritten() == 0) {
- SkMemoryStream pixels(bitmap.getPixels(), bitmap.getSize());
- WriteToDisk(*task, &pixels, bitmap.getSize(), &bitmap, ext);
+ if (data->getLength()) {
+ WriteToDisk(*task, md5, ext, data, data->getLength(), NULL);
} else {
- SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream());
- WriteToDisk(*task, data, data->getLength(), NULL, ext);
+ WriteToDisk(*task, md5, ext, NULL, 0, &bitmap);
}
}
}
@@ -275,22 +339,16 @@
}
static void WriteToDisk(const Task& task,
+ SkString md5,
+ const char* ext,
SkStream* data, size_t len,
- const SkBitmap* bitmap,
- const char* ext) {
- SkMD5 hash;
- hash.writeStream(data, len);
- SkMD5::Digest digest;
- hash.finish(digest);
-
+ const SkBitmap* bitmap) {
JsonWriter::BitmapResult result;
result.name = task.src->name();
result.config = task.sink.tag;
result.sourceType = task.src.tag;
result.ext = ext;
- for (int i = 0; i < 16; i++) {
- result.md5.appendf("%02x", digest.data[i]);
- }
+ result.md5 = md5;
JsonWriter::AddBitmapResult(result);
const char* dir = FLAGS_writePath[0];
@@ -323,7 +381,6 @@
return;
}
- data->rewind();
if (bitmap) {
// We can't encode A8 bitmaps as PNGs. Convert them to 8888 first.
SkBitmap converted;
@@ -418,6 +475,8 @@
SkAutoGraphics ag;
SkTaskGroup::Enabler enabled(FLAGS_threads);
+ gather_gold();
+
gather_srcs();
gather_sinks();
gather_tests();
diff --git a/dm/DMJsonWriter.cpp b/dm/DMJsonWriter.cpp
index 8aea814..56c1301 100644
--- a/dm/DMJsonWriter.cpp
+++ b/dm/DMJsonWriter.cpp
@@ -8,6 +8,7 @@
#include "DMJsonWriter.h"
#include "SkCommonFlags.h"
+#include "SkData.h"
#include "SkJSONCPP.h"
#include "SkOSFile.h"
#include "SkStream.h"
@@ -79,4 +80,31 @@
stream.flush();
}
+bool JsonWriter::ReadJson(const char* path, void(*callback)(BitmapResult)) {
+ SkAutoTUnref<SkData> json(SkData::NewFromFileName(path));
+ if (!json) {
+ return false;
+ }
+
+ Json::Reader reader;
+ Json::Value root;
+ const char* data = (const char*)json->data();
+ if (!reader.parse(data, data+json->size(), root)) {
+ return false;
+ }
+
+ const Json::Value& results = root["results"];
+ BitmapResult br;
+ for (unsigned i = 0; i < results.size(); i++) {
+ const Json::Value& r = results[i];
+ br.name = r["key"]["name"].asCString();
+ br.config = r["key"]["config"].asCString();
+ br.sourceType = r["key"]["source_type"].asCString();
+ br.ext = r["ext"].asCString();
+ br.md5 = r["md5"].asCString();
+ callback(br);
+ }
+ return true;
+}
+
} // namespace DM
diff --git a/dm/DMJsonWriter.h b/dm/DMJsonWriter.h
index 58d85d3..5934846 100644
--- a/dm/DMJsonWriter.h
+++ b/dm/DMJsonWriter.h
@@ -44,7 +44,14 @@
* Write all collected results to the file FLAGS_writePath[0]/dm.json.
*/
static void DumpJson();
+
+ /**
+ * Read JSON file at path written by DumpJson, calling callback for each
+ * BitmapResult recorded in the file. Return success.
+ */
+ static bool ReadJson(const char* path, void(*callback)(BitmapResult));
};
+
} // namespace DM
#endif // DMJsonWriter_DEFINED