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