ok, most features can be vias
authorMike Klein <mtklein@chromium.org>
Wed, 29 Mar 2017 16:41:13 +0000 (12:41 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Fri, 31 Mar 2017 03:03:18 +0000 (03:03 +0000)
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 <mtklein@chromium.org>
Commit-Queue: Mike Klein <mtklein@chromium.org>

tools/ok.cpp
tools/ok.h
tools/ok_dsts.cpp
tools/ok_srcs.cpp
tools/ok_test.cpp
tools/ok_vias.cpp

index 2d4a5df..de5727b 100644 (file)
 //   * ok is entirely opt-in.  No more maintaining huge --blacklists.
 
 #include "SkGraphics.h"
-#include "SkOSFile.h"
 #include "ok.h"
 #include <chrono>
 #include <future>
 #include <list>
-#include <regex>
 #include <stdio.h>
 #include <stdlib.h>
 #include <thread>
+#include <vector>
 
 #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(<execinfo.h>) && __has_include(<fcntl.h>) && __has_include(<signal.h>)
     #include <execinfo.h>
@@ -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<Status(void)>) = 0;
@@ -174,55 +171,54 @@ struct ThreadEngine : Engine {
 #endif
 
 struct StreamType {
-    const char* name;
+    const char *name, *help;
     std::unique_ptr<Stream> (*factory)(Options);
 };
 static std::vector<StreamType> stream_types;
 
 struct DstType {
-    const char* name;
+    const char *name, *help;
     std::unique_ptr<Dst> (*factory)(Options);
 };
 static std::vector<DstType> dst_types;
 
 struct ViaType {
-    const char* name;
+    const char *name, *help;
     std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>);
 };
 static std::vector<ViaType> via_types;
 
+template <typename T>
+static std::string help_for(std::vector<T> 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>                   stream;
-    std::function<std::unique_ptr<Dst>(void)> dst_factory;
+    std::function<std::unique_ptr<Dst>(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<SkImage> 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<SkImage> image() override { return nullptr; }
-            } dst;
-            return move_unique(dst);
-        };
-    }
 
     std::unique_ptr<Engine> 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> 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<SkData> 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<Stream> (*factory)(Options)) {
-    stream_types.push_back(StreamType{name, factory});
+Register::Register(const char* name, const char* help,
+                   std::unique_ptr<Stream> (*factory)(Options)) {
+    stream_types.push_back(StreamType{name, help, factory});
 }
-Register::Register(const char* name, std::unique_ptr<Dst> (*factory)(Options)) {
-    dst_types.push_back(DstType{name, factory});
+Register::Register(const char* name, const char* help,
+                   std::unique_ptr<Dst> (*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<Dst> (*factory)(Options, std::unique_ptr<Dst>)) {
-    via_types.push_back(ViaType{name, factory});
+    via_types.push_back(ViaType{name, help, factory});
 }
 
 Options::Options(std::string str) {
index 345465b..f55842b 100644 (file)
@@ -22,11 +22,13 @@ static std::unique_ptr<T> 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<SkImage> 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<Stream> (*factory)(Options));
-    Register(const char* name, std::unique_ptr<Dst>    (*factory)(Options));
-    Register(const char* name, std::unique_ptr<Dst>    (*factory)(Options, std::unique_ptr<Dst>));
+    Register(const char* name, const char* help, std::unique_ptr<Stream> (*factory)(Options));
+    Register(const char* name, const char* help, std::unique_ptr<Dst>    (*factory)(Options));
+    Register(const char* name, const char* help,
+             std::unique_ptr<Dst>(*factory)(Options, std::unique_ptr<Dst>));
 };
 
 #endif//ok_DEFINED
index 034ca45..20b66d5 100644 (file)
@@ -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);
 }};
index a7d262c..fd5f201 100644 (file)
@@ -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};
index 5e7f032..f5c4f22 100644 (file)
@@ -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 {
index b273d3c..17e117a 100644 (file)
@@ -5,17 +5,19 @@
  * found in the LICENSE file.
  */
 
-#include "ok.h"
+#include "SkOSFile.h"
 #include "SkPictureRecorder.h"
+#include "ok.h"
+#include <regex>
 
-static std::unique_ptr<Src> proxy(Src* original, std::function<bool(SkCanvas*)> fn) {
+static std::unique_ptr<Src> proxy(Src* original, std::function<Status(SkCanvas*)> fn) {
     struct : Src {
-        Src*                           original;
-        std::function<bool(SkCanvas*)> fn;
+        Src*                             original;
+        std::function<Status(SkCanvas*)> 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<Dst> target;
+    std::string          dir;
+
+    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> 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<SkData> 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<SkImage> image() override {
+        return target->image();
+    }
+};
+static Register png{"png", "dump PNGs to dir=ok" , Png::Create};
+
+struct Filter : Dst {
+    std::unique_ptr<Dst> target;
+    std::regex match, search;
+
+    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> 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<SkImage> image() override {
+        return target->image();
+    }
+};
+struct Register filter{"filter",
+                       "run only srcs matching match=.* exactly and search=.* somewhere",
+                       Filter::Create};