experiment/fiddle
Review URL: https://codereview.chromium.org/1349163003
This commit is contained in:
parent
fd5f6c1b0d
commit
decb21e3ae
3
experimental/fiddle/.gitignore
vendored
Normal file
3
experimental/fiddle/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.gch
|
||||
*.o
|
||||
fiddler
|
30
experimental/fiddle/draw.cpp
Normal file
30
experimental/fiddle/draw.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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);
|
||||
SkAutoTUnref<SkShader> shader(
|
||||
image->newShader(SkShader::kRepeat_TileMode,
|
||||
SkShader::kRepeat_TileMode,
|
||||
&matrix));
|
||||
SkPaint paint;
|
||||
paint.setShader(shader);
|
||||
canvas->drawPaint(paint);
|
||||
}
|
155
experimental/fiddle/fiddle_main.cpp
Normal file
155
experimental/fiddle/fiddle_main.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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;
|
||||
SkImage* image(nullptr);
|
||||
|
||||
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(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(SkSurface* surface) {
|
||||
SkAutoTUnref<SkImage> img(surface->newImageSnapshot());
|
||||
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 GrContext* create_mesa_grcontext() {
|
||||
SkAutoTUnref<const GrGLInterface> mesa(GrGLCreateMesaInterface());
|
||||
intptr_t backend = reinterpret_cast<intptr_t>(mesa.get());
|
||||
return backend ? GrContext::Create(kOpenGL_GrBackend, backend) : nullptr;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
const DrawOptions options = GetDrawOptions();
|
||||
fprintf(stderr, "%s\n", options.source);
|
||||
if (options.source) {
|
||||
SkAutoTUnref<SkData> data(SkData::NewFromFileName(options.source));
|
||||
if (!data) {
|
||||
perror(options.source);
|
||||
return 1;
|
||||
} else {
|
||||
image = SkImage::NewFromEncoded(data);
|
||||
if (!image) {
|
||||
perror("Unable to decode the source image.");
|
||||
return 1;
|
||||
}
|
||||
SkAssertResult(image->asLegacyBitmap(
|
||||
&source, SkImage::kRO_LegacyBitmapMode));
|
||||
}
|
||||
}
|
||||
SkAutoTUnref<SkData> rasterData, gpuData, pdfData, skpData;
|
||||
if (options.raster) {
|
||||
SkAutoTUnref<SkSurface> rasterSurface(
|
||||
SkSurface::NewRaster(SkImageInfo::MakeN32Premul(options.size)));
|
||||
draw(rasterSurface->getCanvas());
|
||||
rasterData.reset(encode_snapshot(rasterSurface));
|
||||
}
|
||||
if (options.gpu) {
|
||||
OSMesaContext osMesaContext = create_osmesa_context();
|
||||
SkAutoTUnref<GrContext> grContext(create_mesa_grcontext());
|
||||
if (!grContext) {
|
||||
fputs("Unable to get Mesa GrContext.\n", stderr);
|
||||
} else {
|
||||
SkAutoTUnref<SkSurface> surface(
|
||||
SkSurface::NewRenderTarget(
|
||||
grContext,
|
||||
SkSurface::kNo_Budgeted,
|
||||
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;
|
||||
SkAutoTUnref<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()));
|
||||
SkAutoTUnref<SkPicture> picture(recorder.endRecordingAsPicture());
|
||||
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");
|
||||
|
||||
SkSafeSetNull(image);
|
||||
return 0;
|
||||
}
|
34
experimental/fiddle/fiddle_main.h
Normal file
34
experimental/fiddle/fiddle_main.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#include "skia.h"
|
||||
|
||||
extern SkBitmap source;
|
||||
extern 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
|
31
experimental/fiddle/fiddle_test
Normal file
31
experimental/fiddle/fiddle_test
Normal file
@ -0,0 +1,31 @@
|
||||
#!/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")/../.."
|
||||
skia_dir="$PWD"
|
||||
cores=32
|
||||
|
||||
echo "Bootstrapping CMake"
|
||||
cmake_dir="${skia_dir}/third_party/externals/cmake"
|
||||
cd "$cmake_dir"
|
||||
./bootstrap --parallel=$cores
|
||||
make -j $cores cmake
|
||||
|
||||
echo "Building fiddle bootstrapped CMake"
|
||||
cd "${skia_dir}/experimental/fiddle"
|
||||
export PATH="${cmake_dir}/bin:${PATH}"
|
||||
go build fiddler.go
|
||||
./fiddler "$skia_dir"
|
||||
./fiddler "$skia_dir" draw.cpp > /dev/null
|
||||
|
||||
echo "cleaning up"
|
||||
cd "$skia_dir"
|
||||
git clean -fxd cmake experimental/fiddle
|
159
experimental/fiddle/fiddler.go
Normal file
159
experimental/fiddle/fiddler.go
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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 experimental/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 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, "experimental", "fiddle")
|
||||
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, "experimental", "fiddle")
|
||||
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)
|
||||
}
|
||||
util.Close(inputFile)
|
||||
if err = fiddler(skiaSrc, inputFile, os.Stdout, tempDir); err != nil {
|
||||
glog.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
experimental/fiddle/parse-fiddle-output
Executable file
21
experimental/fiddle/parse-fiddle-output
Executable file
@ -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
|
Loading…
Reference in New Issue
Block a user