Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkImage.h"
      9 #include "SkOSFile.h"
     10 #include "SkPictureRecorder.h"
     11 #include "SkPngEncoder.h"
     12 #include "ProcStats.h"
     13 #include "Timer.h"
     14 #include "ok.h"
     15 #include <chrono>
     16 #include <regex>
     17 
     18 static std::unique_ptr<Src> proxy(Src* original, std::function<Status(SkCanvas*)> fn) {
     19     struct : Src {
     20         Src*                             original;
     21         std::function<Status(SkCanvas*)> fn;
     22 
     23         std::string name() override { return original->name(); }
     24         SkISize     size() override { return original->size(); }
     25         Status draw(SkCanvas* canvas) override { return fn(canvas); }
     26     } src;
     27     src.original = original;
     28     src.fn       = fn;
     29     return move_unique(src);
     30 }
     31 
     32 struct ViaPic : Dst {
     33     std::unique_ptr<Dst> target;
     34     bool                 rtree = false;
     35 
     36     static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
     37         ViaPic via;
     38         via.target = std::move(dst);
     39         if (options("bbh") == "rtree") { via.rtree = true; }
     40         return move_unique(via);
     41     }
     42 
     43     Status draw(Src* src) override {
     44         SkRTreeFactory factory;
     45         SkPictureRecorder rec;
     46         rec.beginRecording(SkRect::MakeSize(SkSize::Make(src->size())),
     47                            rtree ? &factory : nullptr);
     48 
     49         for (auto status = src->draw(rec.getRecordingCanvas()); status != Status::OK; ) {
     50             return status;
     51         }
     52         auto pic = rec.finishRecordingAsPicture();
     53 
     54         return target->draw(proxy(src, [=](SkCanvas* canvas) {
     55             pic->playback(canvas);
     56             return Status::OK;
     57         }).get());
     58     }
     59 
     60     sk_sp<SkImage> image() override {
     61         return target->image();
     62     }
     63 };
     64 static Register via_pic{"via_pic", "record then play back an SkPicture", ViaPic::Create};
     65 
     66 struct Png : Dst {
     67     std::unique_ptr<Dst> target;
     68     std::string          dir;
     69 
     70     static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
     71         Png via;
     72         via.target = std::move(dst);
     73         via.dir    = options("dir", "ok");
     74         return move_unique(via);
     75     }
     76 
     77     Status draw(Src* src) override {
     78         for (auto status = target->draw(src); status != Status::OK; ) {
     79             return status;
     80         }
     81 
     82         SkBitmap bm;
     83         SkPixmap pm;
     84         if (!target->image()->asLegacyBitmap(&bm, SkImage::kRO_LegacyBitmapMode) ||
     85             !bm.peekPixels(&pm)) {
     86             return Status::Failed;
     87         }
     88 
     89         sk_mkdir(dir.c_str());
     90         SkFILEWStream dst{(dir + "/" + src->name() + ".png").c_str()};
     91 
     92         SkPngEncoder::Options options;
     93         options.fFilterFlags      = SkPngEncoder::FilterFlag::kNone;
     94         options.fZLibLevel        = 1;
     95         options.fUnpremulBehavior = pm.colorSpace() ? SkTransferFunctionBehavior::kRespect
     96                                                     : SkTransferFunctionBehavior::kIgnore;
     97         return SkPngEncoder::Encode(&dst, pm, options) ? Status::OK
     98                                                        : Status::Failed;
     99     }
    100 
    101     sk_sp<SkImage> image() override {
    102         return target->image();
    103     }
    104 };
    105 static Register png{"png", "dump PNGs to dir=ok" , Png::Create};
    106 
    107 struct Filter : Dst {
    108     std::unique_ptr<Dst> target;
    109     std::regex match, search;
    110 
    111     static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
    112         Filter via;
    113         via.target = std::move(dst);
    114         via.match  = options("match",  ".*");
    115         via.search = options("search", ".*");
    116         return move_unique(via);
    117     }
    118 
    119     Status draw(Src* src) override {
    120         auto name = src->name();
    121         if (!std::regex_match (name, match) ||
    122             !std::regex_search(name, search)) {
    123             return Status::Skipped;
    124         }
    125         return target->draw(src);
    126     }
    127 
    128     sk_sp<SkImage> image() override {
    129         return target->image();
    130     }
    131 };
    132 static Register filter{"filter",
    133                        "run only srcs matching match=.* exactly and search=.* somewhere",
    134                        Filter::Create};
    135 
    136 struct Time : Dst {
    137     std::unique_ptr<Dst> target;
    138 
    139     static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
    140         Time via;
    141         via.target = std::move(dst);
    142         return move_unique(via);
    143     }
    144 
    145     Status draw(Src* src) override {
    146         auto start = std::chrono::steady_clock::now();
    147             Status status = target->draw(src);
    148         std::chrono::duration<double, std::milli> elapsed = std::chrono::steady_clock::now()
    149                                                           - start;
    150 
    151         auto msg = HumanizeMs(elapsed.count());
    152         ok_log(msg.c_str());
    153         return status;
    154     }
    155 
    156     sk_sp<SkImage> image() override {
    157         return target->image();
    158     }
    159 };
    160 static Register _time{"time", "print wall run time", Time::Create};
    161 
    162 struct Memory : Dst {
    163     std::unique_ptr<Dst> target;
    164 
    165     static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
    166         Memory via;
    167         via.target = std::move(dst);
    168         return move_unique(via);
    169     }
    170 
    171     Status draw(Src* src) override {
    172         Status status = target->draw(src);
    173 
    174         auto msg = SkStringPrintf("%dMB", sk_tools::getMaxResidentSetSizeMB());
    175         ok_log(msg.c_str());
    176 
    177         return status;
    178     }
    179 
    180     sk_sp<SkImage> image() override {
    181         return target->image();
    182     }
    183 };
    184 static Register memory{"memory", "print process maximum memory usage", Memory::Create};
    185