From a4f5ce0c9879ebce8d46e2823311c193a514d93b Mon Sep 17 00:00:00 2001 From: Chris Dalton Date: Tue, 26 Jun 2018 10:13:06 -0600 Subject: skpbench: Support .svg files Bug: skia: Change-Id: I0337757f635c631870c02a65f8784fc190d1435e Reviewed-on: https://skia-review.googlesource.com/137540 Commit-Queue: Chris Dalton Reviewed-by: Robert Phillips --- tools/skpbench/skpbench.cpp | 74 +++++++++++++++++++++++++++++++++------------ tools/skpbench/skpbench.py | 30 +++++++++--------- 2 files changed, 70 insertions(+), 34 deletions(-) (limited to 'tools') diff --git a/tools/skpbench/skpbench.cpp b/tools/skpbench/skpbench.cpp index 399bf6cdb2..55fbc00980 100644 --- a/tools/skpbench/skpbench.cpp +++ b/tools/skpbench/skpbench.cpp @@ -37,10 +37,17 @@ #include "picture_utils.h" #include "sk_tool_utils.h" +#ifdef SK_XML +#include "SkDOM.h" +#include "../experimental/svg/model/SkSVGDOM.h" +#endif + + /** - * This is a minimalist program whose sole purpose is to open an skp file, benchmark it on a single - * config, and exit. It is intended to be used through skpbench.py rather than invoked directly. - * Limiting the entire process to a single config/skp pair helps to keep the results repeatable. + * This is a minimalist program whose sole purpose is to open a .skp or .svg file, benchmark it on a + * single config, and exit. It is intended to be used through skpbench.py rather than invoked + * directly. Limiting the entire process to a single config/skp pair helps to keep the results + * repeatable. * * No tiling, looping, or other fanciness is used; it just draws the skp whole into a size-matched * render target and syncs the GPU after each draw. @@ -57,7 +64,7 @@ DEFINE_int32(duration, 5000, "number of milliseconds to run the benchmark"); DEFINE_int32(sampleMs, 50, "minimum duration of a sample"); DEFINE_bool(gpuClock, false, "time on the gpu clock (gpu work only)"); DEFINE_bool(fps, false, "use fps instead of ms"); -DEFINE_string(skp, "", "path to a single .skp file, or 'warmup' for a builtin warmup run"); +DEFINE_string(src, "", "path to a single .skp or .svg file, or 'warmup' for a builtin warmup run"); DEFINE_string(png, "", "if set, save a .png proof to disk at this file location"); DEFINE_int32(verbosity, 4, "level of verbosity (0=none to 5=debug)"); DEFINE_bool(suppressHeader, false, "don't print a header row before the results"); @@ -108,6 +115,7 @@ enum class ExitErr { static void draw_skp_and_flush(SkCanvas*, const SkPicture*); static sk_sp create_warmup_skp(); +static sk_sp create_skp_from_svg(SkStream*, const char* filename); static bool mkdir_p(const SkString& name); static SkString join(const SkCommandLineFlags::StringArray&); static void exitf(ExitErr, const char* format, ...); @@ -337,36 +345,41 @@ int main(int argc, char** argv) { } // Parse the skp. - if (FLAGS_skp.count() != 1) { - exitf(ExitErr::kUsage, "invalid skp '%s': must specify a single skp file, or 'warmup'", - join(FLAGS_skp).c_str()); + if (FLAGS_src.count() != 1) { + exitf(ExitErr::kUsage, + "invalid input '%s': must specify a single .skp or .svg file, or 'warmup'", + join(FLAGS_src).c_str()); } SkGraphics::Init(); sk_sp skp; - SkString skpname; - if (0 == strcmp(FLAGS_skp[0], "warmup")) { + SkString srcname; + if (0 == strcmp(FLAGS_src[0], "warmup")) { skp = create_warmup_skp(); - skpname = "warmup"; + srcname = "warmup"; } else { - const char* skpfile = FLAGS_skp[0]; - std::unique_ptr skpstream(SkStream::MakeFromFile(skpfile)); - if (!skpstream) { - exitf(ExitErr::kIO, "failed to open skp file %s", skpfile); + SkString srcfile(FLAGS_src[0]); + std::unique_ptr srcstream(SkStream::MakeFromFile(srcfile.c_str())); + if (!srcstream) { + exitf(ExitErr::kIO, "failed to open file %s", srcfile.c_str()); + } + if (srcfile.endsWith(".svg")) { + skp = create_skp_from_svg(srcstream.get(), srcfile.c_str()); + } else { + skp = SkPicture::MakeFromStream(srcstream.get()); } - skp = SkPicture::MakeFromStream(skpstream.get()); if (!skp) { - exitf(ExitErr::kData, "failed to parse skp file %s", skpfile); + exitf(ExitErr::kData, "failed to parse file %s", srcfile.c_str()); } - skpname = SkOSPath::Basename(skpfile); + srcname = SkOSPath::Basename(srcfile.c_str()); } int width = SkTMin(SkScalarCeilToInt(skp->cullRect().width()), 2048), height = SkTMin(SkScalarCeilToInt(skp->cullRect().height()), 2048); if (FLAGS_verbosity >= 3 && (width != skp->cullRect().width() || height != skp->cullRect().height())) { fprintf(stderr, "%s is too large (%ix%i), cropping to %ix%i.\n", - skpname.c_str(), SkScalarCeilToInt(skp->cullRect().width()), + srcname.c_str(), SkScalarCeilToInt(skp->cullRect().width()), SkScalarCeilToInt(skp->cullRect().height()), width, height); } @@ -448,7 +461,7 @@ int main(int argc, char** argv) { run_gpu_time_benchmark(testCtx->gpuTimer(), testCtx->fenceSync(), canvas, skp.get(), &samples); } - print_result(samples, config->getTag().c_str(), skpname.c_str()); + print_result(samples, config->getTag().c_str(), srcname.c_str()); // Save a proof (if one was requested). if (!FLAGS_png.isEmpty()) { @@ -499,6 +512,29 @@ static sk_sp create_warmup_skp() { return recorder.finishRecordingAsPicture(); } +static sk_sp create_skp_from_svg(SkStream* stream, const char* filename) { +#ifdef SK_XML + SkDOM xml; + if (!xml.build(*stream)) { + exitf(ExitErr::kData, "failed to parse xml in file %s", filename); + } + sk_sp svg = SkSVGDOM::MakeFromDOM(xml); + if (!svg) { + exitf(ExitErr::kData, "failed to build svg dom from file %s", filename); + } + + static constexpr SkRect bounds{0, 0, 1200, 1200}; + SkPictureRecorder recorder; + SkCanvas* recording = recorder.beginRecording(bounds); + + svg->setContainerSize(SkSize::Make(recording->getBaseLayerSize())); + svg->render(recording); + + return recorder.finishRecordingAsPicture(); +#endif + exitf(ExitErr::kData, "SK_XML is disabled; cannot open svg file %s", filename); +} + bool mkdir_p(const SkString& dirname) { if (dirname.isEmpty()) { return true; diff --git a/tools/skpbench/skpbench.py b/tools/skpbench/skpbench.py index 0477db2227..9d111f0ff0 100755 --- a/tools/skpbench/skpbench.py +++ b/tools/skpbench/skpbench.py @@ -79,9 +79,9 @@ __argparse.add_argument('--gpuThreads', type=int, default=-1, help="Create this many extra threads to assist with GPU work, including" " software path rendering. Defaults to two.") -__argparse.add_argument('skps', +__argparse.add_argument('srcs', nargs='+', - help=".skp files or directories to expand for .skp files") + help=".skp files or directories to expand for .skp files, and/or .svg files") FLAGS = __argparse.parse_args() if FLAGS.adb: @@ -167,7 +167,7 @@ class SKPBench: print('running %i second warmup...' % warmup_time, file=sys.stderr) commandline = cls.ARGV + ['--duration', str(warmup_time * 1000), '--config', config, - '--skp', 'warmup'] + '--src', 'warmup'] dump_commandline_if_verbose(commandline) output = subprocess.check_output(commandline, stderr=subprocess.STDOUT) @@ -178,8 +178,8 @@ class SKPBench: return raise Exception('Invalid warmup output:\n%s' % output) - def __init__(self, skp, config, max_stddev, best_result=None): - self.skp = skp + def __init__(self, src, config, max_stddev, best_result=None): + self.src = src self.config = config self.max_stddev = max_stddev self.best_result = best_result @@ -202,11 +202,11 @@ class SKPBench: self._schedule_hardware_poll() commandline = self.ARGV + ['--config', self.config, - '--skp', self.skp, + '--src', self.src, '--suppressHeader', 'true'] if FLAGS.write_path: pngfile = _path.join(FLAGS.write_path, self.config, - _path.basename(self.skp) + '.png') + _path.basename(self.src) + '.png') commandline.extend(['--png', pngfile]) dump_commandline_if_verbose(commandline) self._proc = subprocess.Popen(commandline, stdout=subprocess.PIPE, @@ -269,10 +269,10 @@ def emit_result(line, resultsfile=None): print(line, file=resultsfile) resultsfile.flush() -def run_benchmarks(configs, skps, hardware, resultsfile=None): +def run_benchmarks(configs, srcs, hardware, resultsfile=None): hasheader = False - benches = collections.deque([(skp, config, FLAGS.max_stddev) - for skp in skps + benches = collections.deque([(src, config, FLAGS.max_stddev) + for src in srcs for config in configs]) while benches: try: @@ -291,7 +291,7 @@ def run_benchmarks(configs, skps, hardware, resultsfile=None): resultsfile) else: print("WARNING: no result for %s with config %s" % - (skpbench.skp, skpbench.config), file=sys.stderr) + (skpbench.src, skpbench.config), file=sys.stderr) except StddevException: retry_max_stddev = skpbench.max_stddev * math.sqrt(2) @@ -302,7 +302,7 @@ def run_benchmarks(configs, skps, hardware, resultsfile=None): skpbench.best_result.stddev, skpbench.max_stddev, retry_max_stddev), file=sys.stderr) - benches.append((skpbench.skp, skpbench.config, retry_max_stddev, + benches.append((skpbench.src, skpbench.config, retry_max_stddev, skpbench.best_result)) except HardwareException as exception: @@ -322,7 +322,7 @@ def main(): # Delimiter is ',' or ' ', skip if nested inside parens (e.g. gpu(a=b,c=d)). DELIMITER = r'[, ](?!(?:[^(]*\([^)]*\))*[^()]*\))' configs = re.split(DELIMITER, FLAGS.config) - skps = _path.find_skps(FLAGS.skps) + srcs = _path.find_skps(FLAGS.srcs) if FLAGS.adb: adb = Adb(FLAGS.device_serial, FLAGS.adb_binary, @@ -350,9 +350,9 @@ def main(): if FLAGS.resultsfile: with open(FLAGS.resultsfile, mode='a+') as resultsfile: - run_benchmarks(configs, skps, hardware, resultsfile=resultsfile) + run_benchmarks(configs, srcs, hardware, resultsfile=resultsfile) else: - run_benchmarks(configs, skps, hardware) + run_benchmarks(configs, srcs, hardware) if __name__ == '__main__': -- cgit v1.2.3