Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Creating GPU backed Canvas #16

Merged
merged 13 commits into from
Nov 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ jobs:
key: 1-${{ runner.os }}-cmake-build
restore-keys: |
1-${{ runner.os }}-cmake-build

- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: sudo apt-get install xorg-dev

- name: Build Native Library (Unix)
if: runner.os != 'Windows'
Expand Down
9 changes: 9 additions & 0 deletions native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ if (WIN32)
target_compile_options(native_canvas PRIVATE
/MT
/W0)

target_link_libraries(native_canvas
gdi32
user32
kernel32
opengl32)
endif()

# target_compile_options(native_canvas PRIVATE -g)
Expand All @@ -41,6 +47,9 @@ if(APPLE)
target_link_libraries(native_canvas "-framework CoreFoundation")
target_link_libraries(native_canvas "-framework CoreText")
target_link_libraries(native_canvas "-framework CoreGraphics")
target_link_libraries(native_canvas "-framework IOKit")
target_link_libraries(native_canvas "-framework Cocoa")
target_link_libraries(native_canvas "-framework OpenGL")
endif()

set (SKIA_OUT ${CMAKE_CURRENT_SOURCE_DIR}/../skia/out/Release)
Expand Down
8 changes: 8 additions & 0 deletions native/include/canvas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@
#include "include/core/SkImageFilter.h"
#include "include/common.hpp"
#include "include/effects/SkImageFilters.h"
// #include "GLFW/glfw3.h"
#define SK_GL
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/gl/GrGLInterface.h"

typedef struct sk_canvas {
SkSurface* surface;
GrDirectContext* context;
void* pixels;
} sk_canvas;

Expand Down Expand Up @@ -47,10 +53,12 @@ typedef struct sk_context {
extern "C" {
SKIA_EXPORT void sk_init();
SKIA_EXPORT sk_canvas* sk_canvas_create(int width, int height, void* pixels);
SKIA_EXPORT sk_canvas* sk_canvas_create_gl(int width, int height);
SKIA_EXPORT void sk_canvas_destroy(sk_canvas* canvas);
SKIA_EXPORT int sk_canvas_save(sk_canvas* canvas, char* path, int format, int quality);
SKIA_EXPORT void sk_canvas_read_pixels(sk_canvas* canvas, int x, int y, int width, int height, void* pixels, int cs);
SKIA_EXPORT const void* sk_canvas_encode_image(sk_canvas* canvas, int format, int quality, int* size, SkData** data);
SKIA_EXPORT void sk_data_free(SkData* data);
SKIA_EXPORT sk_context* sk_canvas_get_context(sk_canvas* canvas);
SKIA_EXPORT void sk_canvas_flush(sk_canvas* canvas);
}
56 changes: 56 additions & 0 deletions native/src/canvas.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
#include "include/canvas.hpp"
#include "include/context2d.hpp"

void error_callback(int error, const char* description) {
std::cerr << "skia_canvas: glfw error (" << error << "): " << description << std::endl;
}

extern "C" {
void sk_init() {
// if (glfwInit()) {
// glfwSetErrorCallback(error_callback);
// glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
// glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// // glfwWindowHint(GLFW_SRGB_CAPABLE, GL_TRUE);
// glfwWindowHint(GLFW_STENCIL_BITS, 0);
// // glfwWindowHint(GLFW_ALPHA_BITS, 0);
// glfwWindowHint(GLFW_DEPTH_BITS, 0);
// }
SkGraphics::Init();
}

Expand All @@ -16,6 +31,47 @@ extern "C" {
return canvas;
}

sk_canvas* sk_canvas_create_gl(int width, int height) {
sk_canvas* canvas = new sk_canvas();
auto interface = GrGLMakeNativeInterface();

if (interface == nullptr) {
return nullptr;
}

canvas->context = GrDirectContext::MakeGL(interface).release();

if (canvas->context == nullptr) {
return nullptr;
}

GrGLFramebufferInfo framebufferInfo;
framebufferInfo.fFBOID = 0;
framebufferInfo.fFormat = 32856;

SkColorType colorType = kRGBA_8888_SkColorType;
GrBackendRenderTarget backendRenderTarget(width, height, 0, 0, framebufferInfo);

canvas->surface = SkSurface::MakeFromBackendRenderTarget(
canvas->context,
backendRenderTarget,
kBottomLeft_GrSurfaceOrigin,
colorType,
nullptr, // SkColorSpace::MakeSRGB(),
nullptr
).release();

if (canvas->surface == nullptr) {
return nullptr;
}

return canvas;
}

void sk_canvas_flush(sk_canvas* canvas) {
canvas->context->flush();
}

void sk_canvas_destroy(sk_canvas* canvas) {
canvas->surface->unref();
delete canvas;
Expand Down
6 changes: 3 additions & 3 deletions scripts/build_skia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const BUILD_ARGS: Record<string, any> = {
skia_use_piex: false,
is_debug: false,
is_component_build: false,
skia_enable_gpu: false,
skia_use_gl: false,
skia_enable_gpu: true,
skia_use_gl: true,
// skia_use_harfbuzz: true,
skia_use_icu: true,
skia_use_libjpeg_turbo_decode: true,
Expand All @@ -34,7 +34,7 @@ const BUILD_ARGS: Record<string, any> = {
paragraph_gms_enabled: false,
paragraph_tests_enabled: false,
skia_enable_android_utils: false,
skia_enable_discrete_gpu: false,
skia_enable_discrete_gpu: true,
skia_enable_particles: true,
skia_enable_pdf: true,
skia_enable_skshaper: true,
Expand Down
29 changes: 23 additions & 6 deletions src/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { ColorSpace } from "./image.ts";

const {
sk_canvas_create,
sk_canvas_create_gl,
sk_canvas_destroy,
sk_canvas_save,
sk_canvas_read_pixels,
sk_canvas_encode_image,
sk_data_free,
sk_canvas_get_context,
sk_canvas_flush,
} = ffi;

const CANVAS_FINALIZER = new FinalizationRegistry((ptr: Deno.PointerValue) => {
Expand Down Expand Up @@ -49,7 +51,8 @@ export class Canvas {
#ptr: Deno.PointerValue;
#width: number;
#height: number;
#pixels: Uint8Array;
#pixels: Uint8Array | null;
#gpu = false;

get _unsafePointer() {
return this.#ptr;
Expand All @@ -68,9 +71,15 @@ export class Canvas {
return this.#height;
}

constructor(width: number, height: number) {
this.#pixels = new Uint8Array(width * height * 4);
this.#ptr = sk_canvas_create(
/** Whether Canvas is GPU backed */
get gpu() {
return this.#gpu;
}

constructor(width: number, height: number, gpu = false) {
this.#gpu = gpu;
this.#pixels = gpu ? null : new Uint8Array(width * height * 4);
this.#ptr = gpu ? sk_canvas_create_gl(width, height) : sk_canvas_create(
width,
height,
this.#pixels,
Expand Down Expand Up @@ -157,11 +166,19 @@ export class Canvas {
return null;
}
}

/** Only for GPU backed: Flushes all draw calls, call before swap */
flush() {
sk_canvas_flush(this.#ptr);
}
}

/**
* Creates a new canvas with the given dimensions.
*
* Only pass `gpu: true` if you have an OpenGL context initialized
* and made current already.
*/
export function createCanvas(width: number, height: number) {
return new Canvas(width, height);
export function createCanvas(width: number, height: number, gpu?: boolean) {
return new Canvas(width, height, gpu);
}
10 changes: 10 additions & 0 deletions src/ffi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,16 @@ const SYMBOLS = {
parameters: ["pointer", "buffer", "buffer"],
result: "pointer",
},

sk_canvas_create_gl: {
parameters: ["i32", "i32"],
result: "pointer",
},

sk_canvas_flush: {
parameters: ["pointer"],
result: "void",
},
} as const;

const LOCAL_BUILD = Deno.env.get("DENO_SKIA_LOCAL") === "1";
Expand Down
4 changes: 2 additions & 2 deletions test/test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createCanvas, Image, Path2D } from "../mod.ts";
import { Canvas, Image, Path2D } from "../mod.ts";

const canvas = createCanvas(300, 300);
const canvas = new Canvas(300, 300);
const ctx = canvas.getContext("2d");

ctx.filter = "brightness(70%) contrast(160%)";
Expand Down