From e15a7b528ee1a630639f7a69b970237c8d97d308 Mon Sep 17 00:00:00 2001 From: Mike Klein Date: Wed, 29 Mar 2017 12:41:13 -0400 Subject: [PATCH] ok, most features can be vias This refactors most features out of ok's core into vias: -w --> a .png dumping via, "png", opening the door to other types -m/-s --> a filtering via "filter" Everything now can print a brief help message too. Change-Id: I9e653aab98fd57182a6d458c7a80052130980284 Reviewed-on: https://skia-review.googlesource.com/10509 Reviewed-by: Mike Klein Commit-Queue: Mike Klein --- tools/ok.cpp | 133 ++++++++++++++++++++---------------------------------- tools/ok.h | 17 ++++--- tools/ok_dsts.cpp | 6 +-- tools/ok_srcs.cpp | 12 ++--- tools/ok_test.cpp | 10 ++-- tools/ok_vias.cpp | 82 +++++++++++++++++++++++++++++---- 6 files changed, 144 insertions(+), 116 deletions(-) diff --git a/tools/ok.cpp b/tools/ok.cpp index 2d4a5df..de5727b 100644 --- a/tools/ok.cpp +++ b/tools/ok.cpp @@ -10,21 +10,20 @@ // * ok is entirely opt-in. No more maintaining huge --blacklists. #include "SkGraphics.h" -#include "SkOSFile.h" #include "ok.h" #include #include #include -#include #include #include #include +#include #if !defined(__has_include) #define __has_include(x) 0 #endif -static thread_local const char* tls_name = ""; +static thread_local const char* tls_currently_running = ""; #if __has_include() && __has_include() && __has_include() #include @@ -53,7 +52,7 @@ static thread_local const char* tls_name = ""; #undef CASE } log(" while running '"); - log(tls_name); + log(tls_currently_running); log("'\n"); void* stack[128]; @@ -81,7 +80,7 @@ static thread_local const char* tls_name = ""; void ok_log(const char* msg) { lockf(log_fd, F_LOCK, 0); log("["); - log(tls_name); + log(tls_currently_running); log("]\t"); log(msg); log("\n"); @@ -97,8 +96,6 @@ static thread_local const char* tls_name = ""; } #endif -enum class Status { OK, Failed, Crashed, Skipped, None }; - struct Engine { virtual ~Engine() {} virtual bool spawn(std::function) = 0; @@ -174,55 +171,54 @@ struct ThreadEngine : Engine { #endif struct StreamType { - const char* name; + const char *name, *help; std::unique_ptr (*factory)(Options); }; static std::vector stream_types; struct DstType { - const char* name; + const char *name, *help; std::unique_ptr (*factory)(Options); }; static std::vector dst_types; struct ViaType { - const char* name; + const char *name, *help; std::unique_ptr (*factory)(Options, std::unique_ptr); }; static std::vector via_types; +template +static std::string help_for(std::vector registered) { + std::string help; + for (auto r : registered) { + help += "\n "; + help += r.name; + help += ": "; + help += r.help; + } + return help; +} + int main(int argc, char** argv) { SkGraphics::Init(); setup_crash_handler(); - int jobs {1}; - std::regex match {".*"}; - std::regex search {".*"}; - std::string write_dir {""}; - + int jobs{1}; std::unique_ptr stream; - std::function(void)> dst_factory; + std::function(void)> dst_factory = []{ + // A default Dst that's enough for unit tests and not much else. + struct : Dst { + Status draw(Src* src) override { return src->draw(nullptr); } + sk_sp image() override { return nullptr; } + } dst; + return move_unique(dst); + }; auto help = [&] { - std::string stream_names, dst_names, via_names; - for (auto s : stream_types) { - if (!stream_names.empty()) { - stream_names += ", "; - } - stream_names += s.name; - } - for (auto d : dst_types) { - if (!dst_names.empty()) { - dst_names += ", "; - } - dst_names += d.name; - } - for (auto v : via_types) { - if (!via_names.empty()) { - via_names += ", "; - } - via_names += v.name; - } + std::string stream_help = help_for(stream_types), + dst_help = help_for( dst_types), + via_help = help_for( via_types); printf("%s [-j N] [-m regex] [-s regex] [-w dir] [-h] \n" " src[:k=v,...] dst[:k=v,...] [via[:k=v,...] ...] \n" @@ -230,23 +226,17 @@ int main(int argc, char** argv) { " If <0, use -N threads instead. \n" " If 0, use one thread in one process. \n" " If 1 (default) or -1, auto-detect N. \n" - " -m: Run only names matching regex exactly. \n" - " -s: Run only names matching regex anywhere. \n" - " -w: If set, write .pngs into dir. \n" " -h: Print this message and exit. \n" - " src: content to draw: %s \n" - " dst: how to draw that content: %s \n" - " via: front-patches to the dst: %s \n" - " Some srcs, dsts and vias have options, e.g. skp:dir=skps sw:ct=565 \n", - argv[0], stream_names.c_str(), dst_names.c_str(), via_names.c_str()); + " src: content to draw%s \n" + " dst: how to draw that content%s \n" + " via: wrappers around dst%s \n" + " Most srcs, dsts and vias have options, e.g. skp:dir=skps sw:ct=565 \n", + argv[0], stream_help.c_str(), dst_help.c_str(), via_help.c_str()); return 1; }; for (int i = 1; i < argc; i++) { - if (0 == strcmp("-j", argv[i])) { jobs = atoi(argv[++i]); } - if (0 == strcmp("-m", argv[i])) { match = argv[++i] ; } - if (0 == strcmp("-s", argv[i])) { search = argv[++i] ; } - if (0 == strcmp("-w", argv[i])) { write_dir = argv[++i] ; } + if (0 == strcmp("-j", argv[i])) { jobs = atoi(argv[++i]); } if (0 == strcmp("-h", argv[i])) { return help(); } for (auto s : stream_types) { @@ -283,16 +273,6 @@ int main(int argc, char** argv) { } } if (!stream) { return help(); } - if (!dst_factory) { - // A default Dst that's enough for unit tests and not much else. - dst_factory = []{ - struct : Dst { - bool draw(Src* src) override { return src->draw(nullptr); } - sk_sp image() override { return nullptr; } - } dst; - return move_unique(dst); - }; - } std::unique_ptr engine; if (jobs == 0) { engine.reset(new SerialEngine); } @@ -301,10 +281,6 @@ int main(int argc, char** argv) { if (jobs == 1) { jobs = std::thread::hardware_concurrency(); } - if (!write_dir.empty()) { - sk_mkdir(write_dir.c_str()); - } - int ok = 0, failed = 0, crashed = 0, skipped = 0; auto update_stats = [&](Status s) { @@ -343,25 +319,10 @@ int main(int argc, char** argv) { spawn([=] { std::unique_ptr src{raw}; - auto name = src->name(); - tls_name = name.c_str(); - if (!std::regex_match (name, match) || - !std::regex_search(name, search)) { - return Status::Skipped; - } - - auto dst = dst_factory(); - if (!dst->draw(src.get())) { - return Status::Failed; - } + std::string name = src->name(); + tls_currently_running = name.c_str(); - if (!write_dir.empty()) { - auto image = dst->image(); - sk_sp png{image->encode()}; - SkFILEWStream{(write_dir + "/" + name + ".png").c_str()} - .write(png->data(), png->size()); - } - return Status::OK; + return dst_factory()->draw(src.get()); }); } @@ -374,15 +335,17 @@ int main(int argc, char** argv) { } -Register::Register(const char* name, std::unique_ptr (*factory)(Options)) { - stream_types.push_back(StreamType{name, factory}); +Register::Register(const char* name, const char* help, + std::unique_ptr (*factory)(Options)) { + stream_types.push_back(StreamType{name, help, factory}); } -Register::Register(const char* name, std::unique_ptr (*factory)(Options)) { - dst_types.push_back(DstType{name, factory}); +Register::Register(const char* name, const char* help, + std::unique_ptr (*factory)(Options)) { + dst_types.push_back(DstType{name, help, factory}); } -Register::Register(const char* name, +Register::Register(const char* name, const char* help, std::unique_ptr (*factory)(Options, std::unique_ptr)) { - via_types.push_back(ViaType{name, factory}); + via_types.push_back(ViaType{name, help, factory}); } Options::Options(std::string str) { diff --git a/tools/ok.h b/tools/ok.h index 345465b..f55842b 100644 --- a/tools/ok.h +++ b/tools/ok.h @@ -22,11 +22,13 @@ static std::unique_ptr move_unique(T& v) { void ok_log(const char*); +enum class Status { OK, Failed, Crashed, Skipped, None }; + struct Src { virtual ~Src() {} - virtual std::string name() = 0; - virtual SkISize size() = 0; - virtual bool draw(SkCanvas*) = 0; + virtual std::string name() = 0; + virtual SkISize size() = 0; + virtual Status draw(SkCanvas*) = 0; }; struct Stream { @@ -36,7 +38,7 @@ struct Stream { struct Dst { virtual ~Dst() {} - virtual bool draw(Src*) = 0; + virtual Status draw(Src*) = 0; virtual sk_sp image() = 0; }; @@ -50,9 +52,10 @@ public: // Create globals to register your new type of Stream or Dst. struct Register { - Register(const char* name, std::unique_ptr (*factory)(Options)); - Register(const char* name, std::unique_ptr (*factory)(Options)); - Register(const char* name, std::unique_ptr (*factory)(Options, std::unique_ptr)); + Register(const char* name, const char* help, std::unique_ptr (*factory)(Options)); + Register(const char* name, const char* help, std::unique_ptr (*factory)(Options)); + Register(const char* name, const char* help, + std::unique_ptr(*factory)(Options, std::unique_ptr)); }; #endif//ok_DEFINED diff --git a/tools/ok_dsts.cpp b/tools/ok_dsts.cpp index 034ca45..20b66d5 100644 --- a/tools/ok_dsts.cpp +++ b/tools/ok_dsts.cpp @@ -22,7 +22,7 @@ struct SWDst : Dst { return move_unique(dst); } - bool draw(Src* src) override { + Status draw(Src* src) override { auto size = src->size(); surface = SkSurface::MakeRaster(info.makeWH(size.width(), size.height())); return src->draw(surface->getCanvas()); @@ -32,9 +32,9 @@ struct SWDst : Dst { return surface->makeImageSnapshot(); } }; -static Register sw{"sw", SWDst::Create}; +static Register sw{"sw", "draw with the software backend", SWDst::Create}; -static Register _565{"565", [](Options options) { +static Register _565{"565", "alias for sw:ct=565", [](Options options) { options["ct"] = "565"; return SWDst::Create(options); }}; diff --git a/tools/ok_srcs.cpp b/tools/ok_srcs.cpp index a7d262c..fd5f201 100644 --- a/tools/ok_srcs.cpp +++ b/tools/ok_srcs.cpp @@ -38,12 +38,12 @@ struct GMStream : Stream { return gm->getISize(); } - bool draw(SkCanvas* canvas) override { + Status draw(SkCanvas* canvas) override { this->init(); canvas->clear(0xffffffff); canvas->concat(gm->getInitialTransform()); gm->draw(canvas); - return true; + return Status::OK; } }; @@ -57,7 +57,7 @@ struct GMStream : Stream { return move_unique(src); } }; -static Register gm{"gm", GMStream::Create}; +static Register gm{"gm", "draw GMs linked into this binary", GMStream::Create}; struct SKPStream : Stream { std::string dir; @@ -92,11 +92,11 @@ struct SKPStream : Stream { return pic->cullRect().roundOut().size(); } - bool draw(SkCanvas* canvas) override { + Status draw(SkCanvas* canvas) override { this->init(); canvas->clear(0xffffffff); pic->playback(canvas); - return true; + return Status::OK; } }; @@ -111,4 +111,4 @@ struct SKPStream : Stream { return move_unique(src); } }; -static Register skp{"skp", SKPStream::Create}; +static Register skp{"skp", "draw SKPs from dir=skps", SKPStream::Create}; diff --git a/tools/ok_test.cpp b/tools/ok_test.cpp index 5e7f032..f5c4f22 100644 --- a/tools/ok_test.cpp +++ b/tools/ok_test.cpp @@ -31,15 +31,15 @@ struct TestStream : Stream { std::string name() override { return test.name; } SkISize size() override { return {0,0}; } - bool draw(SkCanvas*) override { + Status draw(SkCanvas*) override { struct : public skiatest::Reporter { - bool ok = true; + Status status = Status::OK; bool extended, verbose_; void reportFailed(const skiatest::Failure& failure) override { ok_log(failure.toString().c_str()); - ok = false; + status = Status::Failed; } bool allowExtendedTest() const override { return extended; } bool verbose() const override { return verbose_; } @@ -55,7 +55,7 @@ struct TestStream : Stream { #endif test.proc(&reporter, factory); - return reporter.ok; + return reporter.status; } }; @@ -71,7 +71,7 @@ struct TestStream : Stream { return move_unique(src); } }; -static Register test{"test", TestStream::Create}; +static Register test{"test", "run unit tests linked into this binary", TestStream::Create}; // Hey, now why were these defined in DM.cpp? That's kind of weird. namespace skiatest { diff --git a/tools/ok_vias.cpp b/tools/ok_vias.cpp index b273d3c..17e117a 100644 --- a/tools/ok_vias.cpp +++ b/tools/ok_vias.cpp @@ -5,17 +5,19 @@ * found in the LICENSE file. */ -#include "ok.h" +#include "SkOSFile.h" #include "SkPictureRecorder.h" +#include "ok.h" +#include -static std::unique_ptr proxy(Src* original, std::function fn) { +static std::unique_ptr proxy(Src* original, std::function fn) { struct : Src { - Src* original; - std::function fn; + Src* original; + std::function fn; std::string name() override { return original->name(); } SkISize size() override { return original->size(); } - bool draw(SkCanvas* canvas) override { return fn(canvas); } + Status draw(SkCanvas* canvas) override { return fn(canvas); } } src; src.original = original; src.fn = fn; @@ -33,20 +35,20 @@ struct ViaPic : Dst { return move_unique(via); } - bool draw(Src* src) override { + Status draw(Src* src) override { SkRTreeFactory factory; SkPictureRecorder rec; rec.beginRecording(SkRect::MakeSize(SkSize::Make(src->size())), rtree ? &factory : nullptr); - if (!src->draw(rec.getRecordingCanvas())) { - return false; + for (auto status = src->draw(rec.getRecordingCanvas()); status != Status::OK; ) { + return status; } auto pic = rec.finishRecordingAsPicture(); return target->draw(proxy(src, [=](SkCanvas* canvas) { pic->playback(canvas); - return true; + return Status::OK; }).get()); } @@ -54,4 +56,64 @@ struct ViaPic : Dst { return target->image(); } }; -static Register via_pic{"via_pic", ViaPic::Create}; +static Register via_pic{"via_pic", "record then play back an SkPicture", ViaPic::Create}; + +struct Png : Dst { + std::unique_ptr target; + std::string dir; + + static std::unique_ptr Create(Options options, std::unique_ptr dst) { + Png via; + via.target = std::move(dst); + via.dir = options("dir", "ok"); + return move_unique(via); + } + + Status draw(Src* src) override { + for (auto status = target->draw(src); status != Status::OK; ) { + return status; + } + + auto image = target->image(); + sk_sp png{image->encode()}; + + sk_mkdir(dir.c_str()); + SkFILEWStream{(dir + "/" + src->name() + ".png").c_str()} + .write(png->data(), png->size()); + return Status::OK; + } + + sk_sp image() override { + return target->image(); + } +}; +static Register png{"png", "dump PNGs to dir=ok" , Png::Create}; + +struct Filter : Dst { + std::unique_ptr target; + std::regex match, search; + + static std::unique_ptr Create(Options options, std::unique_ptr dst) { + Filter via; + via.target = std::move(dst); + via.match = options("match", ".*"); + via.search = options("search", ".*"); + return move_unique(via); + } + + Status draw(Src* src) override { + auto name = src->name(); + if (!std::regex_match (name, match) || + !std::regex_search(name, search)) { + return Status::Skipped; + } + return target->draw(src); + } + + sk_sp image() override { + return target->image(); + } +}; +struct Register filter{"filter", + "run only srcs matching match=.* exactly and search=.* somewhere", + Filter::Create}; -- 2.7.4