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 <mtklein@chromium.org> Commit-Queue: Mike Klein <mtklein@chromium.org>
This commit is contained in:
parent
e0ff6ab272
commit
e15a7b528e
133
tools/ok.cpp
133
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 <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;
|
||||
}
|
||||
std::string name = src->name();
|
||||
tls_currently_running = name.c_str();
|
||||
|
||||
auto dst = dst_factory();
|
||||
if (!dst->draw(src.get())) {
|
||||
return Status::Failed;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
17
tools/ok.h
17
tools/ok.h
@ -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
|
||||
|
@ -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);
|
||||
}};
|
||||
|
@ -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};
|
||||
|
@ -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 {
|
||||
|
@ -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};
|
||||
|
Loading…
Reference in New Issue
Block a user