aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/fiddle
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2016-04-18 11:50:07 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-04-18 11:50:07 -0700
commitf0da138c9500bab765a6ef59d97759d1466c1965 (patch)
tree1431756e9a33d8d04048e760d66e521b7dde21c3 /tools/fiddle
parent382949db14cb38ffbc5b1e15a0f56bb7d4e8f7d0 (diff)
experimental/fiddle -> tools/fiddle
Diffstat (limited to 'tools/fiddle')
-rw-r--r--tools/fiddle/.gitignore3
-rw-r--r--tools/fiddle/draw.cpp28
-rw-r--r--tools/fiddle/fiddle_main.cpp164
-rw-r--r--tools/fiddle/fiddle_main.h45
-rwxr-xr-xtools/fiddle/fiddle_test35
-rw-r--r--tools/fiddle/fiddler.go162
-rwxr-xr-xtools/fiddle/parse-fiddle-output21
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