Skip to content

Instantly share code, notes, and snippets.

@rsms
Last active Apr 19, 2022
Embed
What would you like to do?
Demonstrates a method for remote rendering with Skia. First run build-skia-macos.sh, then make and finally ./remote-render
#!/bin/sh
cd "$(dirname "$0")"
if [ ! -d depot_tools ]; then
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
fi
export PATH="$PWD/depot_tools:$PATH"
if [ ! -d skia ]; then
git clone https://skia.googlesource.com/skia.git
fi
_begin() {
echo
echo ">> $@"
}
cd skia
python2 tools/git-sync-deps
_begin "bin/gn gen out/Release"
rm -rf out/Release
bin/gn gen out/Release --args="\
is_official_build=true \
skia_use_libjpeg_turbo_decode=false \
skia_use_libjpeg_turbo_encode=false \
skia_use_system_libpng=false \
skia_use_system_zlib=false \
skia_use_system_harfbuzz=false \
skia_use_system_icu=false \
skia_use_libwebp_decode=false \
skia_use_libwebp_encode=false \
skia_use_metal=true"
_begin "ninja -C out/Release"
ninja -C out/Release
SRCROOT := $(shell pwd)
SYSTEM := $(shell uname -s)
OBJDIR := .build
SKIA_DIR := skia
SOURCES := remote-render.cc
# skia-compatible config sourced from skia/out/Release/obj/remote_demo.ninja
# via temporarily configuring Skia with skia_enable_tools=true
CFLAGS := -g -ffile-prefix-map=$(SRCROOT)/= -MMD \
-fstrict-aliasing \
-fPIC \
-fvisibility=hidden \
-DDEBUG
CXXFLAGS := \
-std=c++17 \
-fvisibility-inlines-hidden \
-fno-exceptions \
-fno-rtti
LDFLAGS := -Wl,-rpath,@loader_path/. -Wl,-w -dead_strip
SKIA_LIB_CFLAGS := -I$(SKIA_DIR) \
-DSK_ASSUME_GL=1 \
-DSK_CODEC_DECODES_PNG \
-DSK_ENABLE_API_AVAILABLE \
-DSK_ENCODE_PNG \
-DSK_GAMMA_APPLY_TO_A8 \
-DSK_GL \
-DSK_SUPPORT_PDF \
-DSK_USE_LIBGIFCODEC \
-DSK_XML
SKIA_LIB_LDFLAGS := $(SKIA_DIR)/out/Release/libskia.a -ldl -lexpat
ifeq ($(SYSTEM),Darwin)
SKIA_LIB_CFLAGS += -DSK_METAL
SKIA_LIB_LDFLAGS += \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk \
-framework ApplicationServices \
-framework OpenGL \
-framework AppKit \
-framework Quartz \
-framework Metal \
-framework Foundation
endif
CFLAGS += $(SKIA_LIB_CFLAGS)
OBJS := $(patsubst %,$(OBJDIR)/%.o,$(subst $(SKIA_DIR)/,skia/,$(SOURCES)))
DEPS := ${OBJS:.o=.d}
-include $(DEPS)
all: remote-render
remote-render: $(OBJS)
@echo "link $@ ($(foreach fn,$^,$(notdir ${fn:.o=})))"
$(CXX) $(LDFLAGS) $(SKIA_LIB_LDFLAGS) -o $@ $^
$(OBJDIR)/%.cc.o: %.cc
@echo "cc $<"
@mkdir -p $(dir $@)
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $<
clean:
rm -rfv $(OBJDIR) remote-render
.PHONY: all clean
#include <stdio.h>
#include "include/core/SkCanvas.h"
#include "include/core/SkSurface.h"
#include "include/core/SkPicture.h"
#include "include/core/SkPictureRecorder.h"
void save_png_file(sk_sp<SkSurface> surface, const char* filename) {
sk_sp<SkData> imageData =
surface->makeImageSnapshot()->encodeToData(SkEncodedImageFormat::kPNG, /*quality*/100);
FILE* fp = fopen(filename, "w");
fwrite(imageData->data(), imageData->size(), 1, fp);
fclose(fp);
}
void draw(SkCanvas* canvas) {
canvas->save();
canvas->clear(SK_ColorWHITE);
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(SK_ColorRED);
canvas->drawCircle(200, 200, 64, paint);
canvas->restore();
}
sk_sp<SkData> simulate_client(int w, int h) {
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(SkRect::MakeWH(w, h), /*bbh*/nullptr);
draw(canvas);
sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
return pic->serialize();
}
void simulate_renderer(sk_sp<SkData> data) {
sk_sp<SkPicture> pic = SkPicture::MakeFromData(data.get());
SkRect bounds = pic->cullRect();
// setup a render surface, play back the draw commands from SkPicture and write to PNG
sk_sp<SkColorSpace> colorSpace;
SkAlphaType alphaType = SkAlphaType::kPremul_SkAlphaType;
SkColorType colorType = SkColorType::kRGBA_8888_SkColorType;
SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), colorType, alphaType, colorSpace);
sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
SkCanvas* canvas = surface->getCanvas();
pic->playback(canvas, /*callback*/nullptr);
save_png_file(surface, "recorder1.png");
}
int main(int argc, const char* argv[argc]) {
sk_sp<SkData> data = simulate_client(400, 400);
// in a real implementation, data would be transmitted over a socket or something here
simulate_renderer(data);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment