diff options
author | halcanary <halcanary@google.com> | 2016-04-18 11:50:07 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-04-18 11:50:07 -0700 |
commit | f0da138c9500bab765a6ef59d97759d1466c1965 (patch) | |
tree | 1431756e9a33d8d04048e760d66e521b7dde21c3 /tools/fiddle | |
parent | 382949db14cb38ffbc5b1e15a0f56bb7d4e8f7d0 (diff) |
experimental/fiddle -> tools/fiddle
also, test building fiddle_main.cpp & draw.cpp
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1895143002
Review URL: https://codereview.chromium.org/1895143002
Diffstat (limited to 'tools/fiddle')
-rw-r--r-- | tools/fiddle/.gitignore | 3 | ||||
-rw-r--r-- | tools/fiddle/draw.cpp | 28 | ||||
-rw-r--r-- | tools/fiddle/fiddle_main.cpp | 164 | ||||
-rw-r--r-- | tools/fiddle/fiddle_main.h | 45 | ||||
-rwxr-xr-x | tools/fiddle/fiddle_test | 35 | ||||
-rw-r--r-- | tools/fiddle/fiddler.go | 162 | ||||
-rwxr-xr-x | tools/fiddle/parse-fiddle-output | 21 |
7 files changed, 458 insertions, 0 deletions
diff --git a/tools/fiddle/.gitignore b/tools/fiddle/.gitignore new file mode 100644 index 0000000000..dd6cc4fbbb --- /dev/null +++ b/tools/fiddle/.gitignore @@ -0,0 +1,3 @@ +*.gch +*.o +fiddler
\ No newline at end of file diff --git a/tools/fiddle/draw.cpp b/tools/fiddle/draw.cpp new file mode 100644 index 0000000000..78f428da2a --- /dev/null +++ b/tools/fiddle/draw.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// This is an example of the translation unit that needs to be +// assembled by the fiddler program to compile into a fiddle: an +// implementation of the GetDrawOptions() and draw() functions. + +#include "fiddle_main.h" +DrawOptions GetDrawOptions() { + // path *should* be absolute. + static const char path[] = "../../resources/color_wheel.png"; + return DrawOptions(256, 256, true, true, true, true, path); +} +void draw(SkCanvas* canvas) { + canvas->clear(SK_ColorWHITE); + SkMatrix matrix; + matrix.setScale(0.75f, 0.75f); + matrix.preRotate(30.0f); + SkPaint paint; + paint.setShader(image->makeShader(SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode, + &matrix)); + canvas->drawPaint(paint); +} diff --git a/tools/fiddle/fiddle_main.cpp b/tools/fiddle/fiddle_main.cpp new file mode 100644 index 0000000000..3e1570813d --- /dev/null +++ b/tools/fiddle/fiddle_main.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <stdio.h> + +#include <GL/osmesa.h> + +#include "fiddle_main.h" + +// Globals externed in fiddle_main.h +SkBitmap source; +sk_sp<SkImage> image; + +static void encode_to_base64(const void* data, size_t size, FILE* out) { + const uint8_t* input = reinterpret_cast<const uint8_t*>(data); + const uint8_t* end = &input[size]; + static const char codes[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789+/"; + while (input != end) { + uint8_t b = (*input & 0xFC) >> 2; + fputc(codes[b], out); + b = (*input & 0x03) << 4; + ++input; + if (input == end) { + fputc(codes[b], out); + fputs("==", out); + return; + } + b |= (*input & 0xF0) >> 4; + fputc(codes[b], out); + b = (*input & 0x0F) << 2; + ++input; + if (input == end) { + fputc(codes[b], out); + fputc('=', out); + return; + } + b |= (*input & 0xC0) >> 6; + fputc(codes[b], out); + b = *input & 0x3F; + fputc(codes[b], out); + ++input; + } +} + +static void dump_output(const sk_sp<SkData>& data, + const char* name, bool last = true) { + if (data) { + printf("\t\"%s\": \"", name); + encode_to_base64(data->data(), data->size(), stdout); + fputs(last ? "\"\n" : "\",\n", stdout); + } +} + +static SkData* encode_snapshot(const sk_sp<SkSurface>& surface) { + sk_sp<SkImage> img(surface->makeImageSnapshot()); + return img ? img->encode() : nullptr; +} + +static OSMesaContext create_osmesa_context() { + OSMesaContext osMesaContext = + OSMesaCreateContextExt(OSMESA_BGRA, 0, 0, 0, nullptr); + if (osMesaContext != nullptr) { + static uint32_t buffer[16 * 16]; + OSMesaMakeCurrent(osMesaContext, &buffer, GL_UNSIGNED_BYTE, 16, 16); + } + return osMesaContext; +} + +static sk_sp<GrContext> create_mesa_grcontext() { + if (nullptr == OSMesaGetCurrentContext()) { + return nullptr; + } + auto osmesa_get = [](void* ctx, const char name[]) { + SkASSERT(nullptr == ctx); + SkASSERT(OSMesaGetCurrentContext()); + return OSMesaGetProcAddress(name); + }; + sk_sp<const GrGLInterface> mesa(GrGLAssembleInterface(nullptr, osmesa_get)); + if (!mesa) { + return nullptr; + } + return sk_sp<GrContext>(GrContext::Create( + kOpenGL_GrBackend, + reinterpret_cast<intptr_t>(mesa.get()))); +} + +int main() { + const DrawOptions options = GetDrawOptions(); + if (options.source) { + sk_sp<SkData> data(SkData::NewFromFileName(options.source)); + if (!data) { + perror(options.source); + return 1; + } else { + image = SkImage::MakeFromEncoded(std::move(data)); + if (!image) { + perror("Unable to decode the source image."); + return 1; + } + SkAssertResult(image->asLegacyBitmap( + &source, SkImage::kRO_LegacyBitmapMode)); + } + } + sk_sp<SkData> rasterData, gpuData, pdfData, skpData; + if (options.raster) { + auto rasterSurface = + SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(options.size)); + draw(rasterSurface->getCanvas()); + rasterData.reset(encode_snapshot(rasterSurface)); + } + if (options.gpu) { + OSMesaContext osMesaContext = create_osmesa_context(); + auto grContext = create_mesa_grcontext(); + if (!grContext) { + fputs("Unable to get Mesa GrContext.\n", stderr); + } else { + auto surface = SkSurface::MakeRenderTarget( + grContext.get(), + SkBudgeted::kNo, + SkImageInfo::MakeN32Premul(options.size)); + if (!surface) { + fputs("Unable to get render surface.\n", stderr); + exit(1); + } + draw(surface->getCanvas()); + gpuData.reset(encode_snapshot(surface)); + } + if (osMesaContext) { + OSMesaDestroyContext(osMesaContext); + } + } + if (options.pdf) { + SkDynamicMemoryWStream pdfStream; + sk_sp<SkDocument> document(SkDocument::CreatePDF(&pdfStream)); + draw(document->beginPage(options.size.width(), options.size.height())); + document->close(); + pdfData.reset(pdfStream.copyToData()); + } + if (options.skp) { + SkSize size; + size = options.size; + SkPictureRecorder recorder; + draw(recorder.beginRecording(size.width(), size.height())); + auto picture = recorder.finishRecordingAsPicture(); + SkDynamicMemoryWStream skpStream; + picture->serialize(&skpStream); + skpData.reset(skpStream.copyToData()); + } + + printf("{\n"); + dump_output(rasterData, "Raster", !gpuData && !pdfData && !skpData); + dump_output(gpuData, "Gpu", !pdfData && !skpData); + dump_output(pdfData, "Pdf", !skpData); + dump_output(skpData, "Skp"); + printf("}\n"); + + return 0; +} diff --git a/tools/fiddle/fiddle_main.h b/tools/fiddle/fiddle_main.h new file mode 100644 index 0000000000..0f36ad7804 --- /dev/null +++ b/tools/fiddle/fiddle_main.h @@ -0,0 +1,45 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef fiddle_main_DEFINED +#define fiddle_main_DEFINED + +#ifdef FIDDLE_BUILD_TEST + #include "GrContext.h" + #include "SkCanvas.h" + #include "SkDocument.h" + #include "SkPictureRecorder.h" + #include "SkStream.h" + #include "SkSurface.h" + #include "gl/GrGLAssembleInterface.h" + #include "gl/GrGLInterface.h" +#else + #include "skia.h" +#endif + +extern SkBitmap source; +extern sk_sp<SkImage> image; + +struct DrawOptions { + DrawOptions(int w, int h, bool r, bool g, bool p, bool k, const char* s) + : size(SkISize::Make(w, h)) + , raster(r) + , gpu(g) + , pdf(p) + , skp(k) + , source(s) {} + SkISize size; + bool raster; + bool gpu; + bool pdf; + bool skp; + const char* source; +}; + +extern DrawOptions GetDrawOptions(); +extern void draw(SkCanvas*); + +#endif // fiddle_main_DEFINED diff --git a/tools/fiddle/fiddle_test b/tools/fiddle/fiddle_test new file mode 100755 index 0000000000..2b5349583f --- /dev/null +++ b/tools/fiddle/fiddle_test @@ -0,0 +1,35 @@ +#!/bin/sh +# Copyright 2015 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Script for building Fiddle build bots. + +set -e +set -x + +cd "$(dirname "$0")" +fiddle_dir="$PWD" +cd "../.." +skia_dir="$PWD" + +if ! command -v cmake > /dev/null 2>&1 ; then + cores=32 + echo "Bootstrapping CMake" + cmake_dir="${skia_dir}/third_party/externals/cmake" + cd "$cmake_dir" + ./bootstrap --parallel=$cores + make -j $cores cmake + export PATH="${cmake_dir}/bin:${PATH}" +fi + +echo "Building Skia and Fiddle" +cd "$fiddle_dir" +git clean -fxd . +go build fiddler.go +./fiddler "$skia_dir" +./fiddler "$skia_dir" draw.cpp > /dev/null + +echo "cleaning up" +git clean -fxd . diff --git a/tools/fiddle/fiddler.go b/tools/fiddle/fiddler.go new file mode 100644 index 0000000000..31ea286d0f --- /dev/null +++ b/tools/fiddle/fiddler.go @@ -0,0 +1,162 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +package main + +// Example use: +// git clone https://skia.googlesource.com/skia.git +// cd skia +// SKIA=$PWD +// cd tools/fiddle +// go get github.com/skia-dev/glog +// go get go.skia.org/infra/go/util +// go build fiddler.go +// # compile prerequisites +// ./fiddler "$SKIA" +// # compile and run a fiddle +// ./fiddler "$SKIA" draw.cpp | ./parse-fiddle-output +// # compile and run a different fiddle +// ./fiddler "$SKIA" ANOTHER_FIDDLE.cpp | ./parse-fiddle-output + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path" + "syscall" + + "github.com/skia-dev/glog" + "go.skia.org/infra/go/util" +) + +func fiddlePath() string { + return path.Join("tools", "fiddle") +} +func setResourceLimits() error { + const maximumTimeInSeconds = 5 + limit := syscall.Rlimit{maximumTimeInSeconds, maximumTimeInSeconds} + if err := syscall.Setrlimit(syscall.RLIMIT_CPU, &limit); err != nil { + return err + } + const maximumMemoryInBytes = 1 << 28 + limit = syscall.Rlimit{maximumMemoryInBytes, maximumMemoryInBytes} + return syscall.Setrlimit(syscall.RLIMIT_AS, &limit) +} + +// execCommand runs command and returns an error if it fails. If there is no +// error, all output is discarded. +func execCommand(input io.Reader, dir string, name string, arg ...string) error { + var buffer bytes.Buffer + cmd := exec.Command(name, arg...) + cmd.Dir = dir + cmd.Stdout = &buffer + cmd.Stderr = &buffer + cmd.Stdin = input + if err := cmd.Run(); err != nil { + return fmt.Errorf("execution failed:\n\n%s\n[%v]", buffer.String(), err) + } + return nil +} + +func compileArgs(skiaSrc string) string { + return "@" + path.Join(skiaSrc, "cmake", "skia_compile_arguments.txt") +} + +func linkArgs(skiaSrc string) string { + return "@" + path.Join(skiaSrc, "cmake", "skia_link_arguments.txt") +} + +// fiddler compiles the input, links against skia, and runs the executable. +// @param skiaSrc: the base directory of the Skia repository +// @param inputReader: C++ fiddle source +// @param output: stdout of executable sent here +// @param tempDir: where to place the compiled executable +func fiddler(skiaSrc string, inputReader io.Reader, output io.Writer, tempDir string) error { + binarypath := path.Join(tempDir, "fiddle") + fiddle_dir := path.Join(skiaSrc, fiddlePath()) + if err := execCommand(inputReader, fiddle_dir, + "c++", + compileArgs(skiaSrc), + "-I", fiddle_dir, + "-o", binarypath, + "-x", "c++", "-", "-x", "none", + "fiddle_main.o", + "-lOSMesa", + linkArgs(skiaSrc), + ); err != nil { + return err + } + var buffer bytes.Buffer + runCmd := exec.Cmd{Path: binarypath, Stdout: output, Stderr: &buffer} + if err := runCmd.Run(); err != nil { + return fmt.Errorf("execution failed:\n\n%s\n[%v]", buffer.String(), err) + } + return nil +} + +// Compile Skia library and fiddle_main.cpp +// @param skiaSrc: the base directory of the Skia repository. +func fiddlerPrerequisites(skiaSrc string) error { + cmakeDir := path.Join(skiaSrc, "cmake") + if err := execCommand(nil, cmakeDir, "cmake", "-G", "Ninja", "."); err != nil { + return err + } + if err := execCommand(nil, cmakeDir, "ninja", "skia"); err != nil { + return err + } + fiddle_dir := path.Join(skiaSrc, fiddlePath()) + if err := execCommand(nil, fiddle_dir, "c++", compileArgs(skiaSrc), + "fiddle_main.h"); err != nil { + return err + } + return execCommand(nil, fiddle_dir, "c++", compileArgs(skiaSrc), + "-c", "-o", "fiddle_main.o", "fiddle_main.cpp") +} + +func main() { + if len(os.Args) < 2 { + glog.Fatalf("usage: %s SKIA_SRC_PATH [PATH_TO_DRAW.CPP]", os.Args[0]) + } + skiaSrc := os.Args[1] + if len(os.Args) < 3 { + // execCommand(nil, skiaSrc, "git", "fetch") + // execCommand(nil, skiaSrc, "git", "checkout", "origin/master") + if err := fiddlerPrerequisites(skiaSrc); err != nil { + glog.Fatal(err) + } + } else { + if err := setResourceLimits(); err != nil { + glog.Fatal(err) + } + tempDir, err := ioutil.TempDir("", "fiddle_") + if err != nil { + glog.Fatal(err) + } + defer func() { + err = os.RemoveAll(tempDir) + if err != nil { + glog.Fatalf("os.RemoveAll(tempDir) failed: %v", err) + } + }() + if os.Args[2] == "-" { + if err := fiddler(skiaSrc, os.Stdin, os.Stdout, tempDir); err != nil { + glog.Fatal(err) + } + } else { + inputFile, err := os.Open(os.Args[2]) + if err != nil { + glog.Fatalf("unable to open \"%s\": %v", os.Args[2], err) + } + defer util.Close(inputFile) + if err = fiddler(skiaSrc, inputFile, os.Stdout, tempDir); err != nil { + glog.Fatal(err) + } + } + } +} diff --git a/tools/fiddle/parse-fiddle-output b/tools/fiddle/parse-fiddle-output new file mode 100755 index 0000000000..f9a2fac6d6 --- /dev/null +++ b/tools/fiddle/parse-fiddle-output @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright 2015 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Parse the output of fiddle_main, for use in testing +while IFS= read -r line; do + type=$(echo $line | sed -n 's/[^"]*"\([^"]*\)":.*/\1/p') + if [ "$type" ]; then + case "$type" in + Raster|Gpu) ext='.png';; + Pdf) ext='.pdf';; + Skp) ext='.skp';; + esac + dst="${TMPDIR:-/tmp}/fiddle_${type}${ext}" + echo $line | sed 's/[^"]*"[^"]*": "//; s/"\(,\|\)$//' \ + | base64 -d > "$dst" + echo $dst + fi +done |