mirror of
https://github.com/penpot/penpot.git
synced 2025-04-05 11:31:35 -05:00
Pass struct to wasm (rust)
This commit is contained in:
parent
c7f801dd44
commit
fa9004d12c
5 changed files with 122 additions and 80 deletions
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
EMCC_CFLAGS="--no-entry -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s MAX_WEBGL_VERSION=2 -s MODULARIZE=1 -s EXPORT_NAME=createRustSkiaModule -s EXPORTED_RUNTIME_METHODS=GL -s ENVIRONMENT=webgl" cargo build --target=wasm32-unknown-emscripten
|
||||
|
6
frontend/render_v2/rs/build.sh
Executable file
6
frontend/render_v2/rs/build.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
EMSDK_QUIET=1 . "/usr/local/emsdk/emsdk_env.sh"
|
||||
|
||||
EMCC_CFLAGS="--no-entry -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s MAX_WEBGL_VERSION=2 -s MODULARIZE=1 -s EXPORT_NAME=createRustSkiaModule -s EXPORTED_RUNTIME_METHODS=GL -s ENVIRONMENT=web" cargo build --target=wasm32-unknown-emscripten
|
||||
|
|
@ -2,9 +2,11 @@ use std::boxed::Box;
|
|||
|
||||
use skia_safe::{
|
||||
gpu::{self, gl::FramebufferInfo, DirectContext},
|
||||
Color, Paint, PaintStyle, Rect, Surface,
|
||||
// Color, Paint, PaintStyle, Rect, Surface,
|
||||
};
|
||||
|
||||
use skia_safe as skia;
|
||||
|
||||
extern "C" {
|
||||
pub fn emscripten_GetProcAddress(
|
||||
name: *const ::std::os::raw::c_char,
|
||||
|
@ -22,15 +24,15 @@ struct GpuState {
|
|||
/// structures are not thread safe, so a state must not be shared between different Web Workers.
|
||||
pub struct State {
|
||||
gpu_state: GpuState,
|
||||
surface: Surface,
|
||||
surface: skia::Surface,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn new(gpu_state: GpuState, surface: Surface) -> Self {
|
||||
fn new(gpu_state: GpuState, surface: skia::Surface) -> Self {
|
||||
State { gpu_state, surface }
|
||||
}
|
||||
|
||||
fn set_surface(&mut self, surface: Surface) {
|
||||
fn set_surface(&mut self, surface: skia::Surface) {
|
||||
self.surface = surface;
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +68,7 @@ fn create_gpu_state() -> GpuState {
|
|||
}
|
||||
|
||||
/// Create the Skia surface that will be used for rendering.
|
||||
fn create_surface(gpu_state: &mut GpuState, width: i32, height: i32) -> Surface {
|
||||
fn create_surface(gpu_state: &mut GpuState, width: i32, height: i32) -> skia::Surface {
|
||||
let backend_render_target =
|
||||
gpu::backend_render_targets::make_gl((width, height), 1, 8, gpu_state.framebuffer_info);
|
||||
|
||||
|
@ -81,9 +83,9 @@ fn create_surface(gpu_state: &mut GpuState, width: i32, height: i32) -> Surface
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
fn render_rect(surface: &mut Surface, rect: Rect, color: Color) {
|
||||
let mut paint = Paint::default();
|
||||
paint.set_style(PaintStyle::Fill);
|
||||
fn render_rect(surface: &mut skia::Surface, rect: skia::Rect, color: skia::Color) {
|
||||
let mut paint = skia::Paint::default();
|
||||
paint.set_style(skia::PaintStyle::Fill);
|
||||
paint.set_color(color);
|
||||
paint.set_anti_alias(true);
|
||||
surface.canvas().draw_rect(rect, &paint);
|
||||
|
@ -107,24 +109,51 @@ pub unsafe extern "C" fn resize_surface(state: *mut State, width: i32, height: i
|
|||
state.set_surface(surface);
|
||||
}
|
||||
|
||||
/// Draw a black rect at the specified coordinates.
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn draw_rect(
|
||||
state: *mut State,
|
||||
left: i32,
|
||||
top: i32,
|
||||
right: i32,
|
||||
bottom: i32,
|
||||
pub extern "C" fn make_color(r: i32, g: i32, b: i32, a: f32) -> Box<Color> {
|
||||
Box::new(Color {
|
||||
r: r as u8,
|
||||
g: g as u8,
|
||||
b: b as u8,
|
||||
a,
|
||||
})
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Color {
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
) {
|
||||
let state = unsafe { state.as_mut() }.expect("got an invalid state pointer");
|
||||
let rect = Rect::new(left as f32, top as f32, right as f32, bottom as f32);
|
||||
let color = Color::from_rgb(r, g, b);
|
||||
a: f32,
|
||||
}
|
||||
|
||||
render_rect(&mut state.surface, rect, color);
|
||||
#[repr(C)]
|
||||
pub struct Rect {
|
||||
left: f32,
|
||||
top: f32,
|
||||
right: f32,
|
||||
bottom: f32,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn make_rect(left: f32, top: f32, right: f32, bottom: f32) -> Box<Rect> {
|
||||
Box::new(Rect {
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
})
|
||||
}
|
||||
|
||||
/// Draws a rect at the specified coordinates with the give ncolor
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn draw_rect(state: *mut State, rect: &Rect, color: &Color) {
|
||||
let state = unsafe { state.as_mut() }.expect("got an invalid state pointer");
|
||||
let r = skia::Rect::new(rect.left, rect.top, rect.right, rect.bottom);
|
||||
let color = skia::Color::from_argb((color.a * 255.0) as u8, color.r, color.g, color.b);
|
||||
|
||||
render_rect(&mut state.surface, r, color);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
reset-canvas (gobj/get ^js internal-module "_reset_canvas")
|
||||
scale (gobj/get ^js internal-module "_scale")
|
||||
flush (gobj/get ^js internal-module "_flush")
|
||||
make-color (gobj/get ^js internal-module "_make_color")
|
||||
make-rect (gobj/get ^js internal-module "_make_rect")
|
||||
supported-shapes (filter (fn [shape] (not= (:type shape) :frame)) (vals objects))]
|
||||
|
||||
(js/requestAnimationFrame (fn []
|
||||
|
@ -31,9 +33,11 @@
|
|||
(translate gpu-state (- (:x vbox)) (- (:y vbox)))
|
||||
(doseq [shape supported-shapes]
|
||||
(let [sr (:selrect shape)
|
||||
[r g b] (cc/hex->rgb (-> shape :fills first :fill-color))]
|
||||
;; (js/console.log (clj->js shape))
|
||||
(draw-rect gpu-state (:x1 sr) (:y1 sr) (:x2 sr) (:y2 sr) r g b)))
|
||||
[r g b] (cc/hex->rgb (-> shape :fills first :fill-color))
|
||||
alpha (-> shape :fills first :fill-opacity)
|
||||
color (make-color r g b alpha)
|
||||
rect (make-rect (:x1 sr) (:y1 sr) (:x2 sr) (:y2 sr))]
|
||||
(draw-rect gpu-state rect color)))
|
||||
(flush gpu-state)))))
|
||||
|
||||
(defn set-canvas
|
||||
|
|
|
@ -28,7 +28,7 @@ var readyPromise = new Promise((resolve, reject) => {
|
|||
readyPromiseResolve = resolve;
|
||||
readyPromiseReject = reject;
|
||||
});
|
||||
["_draw_rect","_flush","_init","_main","_reset_canvas","_resize_surface","_scale","_translate","getExceptionMessage","incrementExceptionRefcount","decrementExceptionRefcount","_memory","___indirect_function_table","onRuntimeInitialized"].forEach((prop) => {
|
||||
["_draw_rect","_flush","_init","_main","_make_color","_make_rect","_reset_canvas","_resize_surface","_scale","_translate","getExceptionMessage","incrementExceptionRefcount","decrementExceptionRefcount","_memory","___indirect_function_table","onRuntimeInitialized"].forEach((prop) => {
|
||||
if (!Object.getOwnPropertyDescriptor(readyPromise, prop)) {
|
||||
Object.defineProperty(readyPromise, prop, {
|
||||
get: () => abort('You are getting ' + prop + ' on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js'),
|
||||
|
@ -700,7 +700,7 @@ function createWasm() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!wasmBinaryFile) wasmBinaryFile = findWasmBinary();
|
||||
wasmBinaryFile ??= findWasmBinary();
|
||||
|
||||
// If instantiation fails, reject the module ready promise.
|
||||
instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject);
|
||||
|
@ -752,45 +752,51 @@ function isExportedByForceFilesystem(name) {
|
|||
name === 'removeRunDependency';
|
||||
}
|
||||
|
||||
function missingGlobal(sym, msg) {
|
||||
if (typeof globalThis != 'undefined') {
|
||||
/**
|
||||
* Intercept access to a global symbol. This enables us to give informative
|
||||
* warnings/errors when folks attempt to use symbols they did not include in
|
||||
* their build, or no symbols that no longer exist.
|
||||
*/
|
||||
function hookGlobalSymbolAccess(sym, func) {
|
||||
if (typeof globalThis != 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) {
|
||||
Object.defineProperty(globalThis, sym, {
|
||||
configurable: true,
|
||||
get() {
|
||||
warnOnce(`\`${sym}\` is not longer defined by emscripten. ${msg}`);
|
||||
func();
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function missingGlobal(sym, msg) {
|
||||
hookGlobalSymbolAccess(sym, () => {
|
||||
warnOnce(`\`${sym}\` is not longer defined by emscripten. ${msg}`);
|
||||
});
|
||||
}
|
||||
|
||||
missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer');
|
||||
missingGlobal('asm', 'Please use wasmExports instead');
|
||||
|
||||
function missingLibrarySymbol(sym) {
|
||||
if (typeof globalThis != 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) {
|
||||
Object.defineProperty(globalThis, sym, {
|
||||
configurable: true,
|
||||
get() {
|
||||
// Can't `abort()` here because it would break code that does runtime
|
||||
// checks. e.g. `if (typeof SDL === 'undefined')`.
|
||||
var msg = `\`${sym}\` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line`;
|
||||
// DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in
|
||||
// library.js, which means $name for a JS name with no prefix, or name
|
||||
// for a JS name like _name.
|
||||
var librarySymbol = sym;
|
||||
if (!librarySymbol.startsWith('_')) {
|
||||
librarySymbol = '$' + sym;
|
||||
}
|
||||
msg += ` (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='${librarySymbol}')`;
|
||||
if (isExportedByForceFilesystem(sym)) {
|
||||
msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
|
||||
}
|
||||
warnOnce(msg);
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
hookGlobalSymbolAccess(sym, () => {
|
||||
// Can't `abort()` here because it would break code that does runtime
|
||||
// checks. e.g. `if (typeof SDL === 'undefined')`.
|
||||
var msg = `\`${sym}\` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line`;
|
||||
// DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in
|
||||
// library.js, which means $name for a JS name with no prefix, or name
|
||||
// for a JS name like _name.
|
||||
var librarySymbol = sym;
|
||||
if (!librarySymbol.startsWith('_')) {
|
||||
librarySymbol = '$' + sym;
|
||||
}
|
||||
msg += ` (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='${librarySymbol}')`;
|
||||
if (isExportedByForceFilesystem(sym)) {
|
||||
msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
|
||||
}
|
||||
warnOnce(msg);
|
||||
});
|
||||
|
||||
// Any symbol that is not included from the JS library is also (by definition)
|
||||
// not exported on the Module object.
|
||||
unexportedRuntimeSymbol(sym);
|
||||
|
@ -1305,12 +1311,7 @@ function dbg(...args) {
|
|||
|
||||
var _emscripten_date_now = () => Date.now();
|
||||
|
||||
var _emscripten_get_now;
|
||||
// Modern environment where performance.now() is supported:
|
||||
// N.B. a shorter form "_emscripten_get_now = performance.now;" is
|
||||
// unfortunately not allowed even in current browsers (e.g. FF Nightly 75).
|
||||
_emscripten_get_now = () => performance.now();
|
||||
;
|
||||
var _emscripten_get_now = () => performance.now();
|
||||
|
||||
var GLctx;
|
||||
|
||||
|
@ -5641,6 +5642,8 @@ function dbg(...args) {
|
|||
},
|
||||
filesystems:null,
|
||||
syncFSRequests:0,
|
||||
readFiles:{
|
||||
},
|
||||
FSStream:class {
|
||||
constructor() {
|
||||
// TODO(https://github.com/emscripten-core/emscripten/issues/21414):
|
||||
|
@ -6540,7 +6543,6 @@ function dbg(...args) {
|
|||
stream.stream_ops.open(stream);
|
||||
}
|
||||
if (Module['logReadFiles'] && !(flags & 1)) {
|
||||
if (!FS.readFiles) FS.readFiles = {};
|
||||
if (!(path in FS.readFiles)) {
|
||||
FS.readFiles[path] = 1;
|
||||
}
|
||||
|
@ -6961,7 +6963,7 @@ function dbg(...args) {
|
|||
createDevice(parent, name, input, output) {
|
||||
var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name);
|
||||
var mode = FS_getMode(!!input, !!output);
|
||||
if (!FS.createDevice.major) FS.createDevice.major = 64;
|
||||
FS.createDevice.major ??= 64;
|
||||
var dev = FS.makedev(FS.createDevice.major++, 0);
|
||||
// Create a fake device that a set of stream ops to emulate
|
||||
// the old behavior.
|
||||
|
@ -8563,7 +8565,9 @@ var wasmExports = createWasm();
|
|||
var ___wasm_call_ctors = createExportWrapper('__wasm_call_ctors', 0);
|
||||
var _init = Module['_init'] = createExportWrapper('init', 2);
|
||||
var _resize_surface = Module['_resize_surface'] = createExportWrapper('resize_surface', 3);
|
||||
var _draw_rect = Module['_draw_rect'] = createExportWrapper('draw_rect', 8);
|
||||
var _make_color = Module['_make_color'] = createExportWrapper('make_color', 4);
|
||||
var _make_rect = Module['_make_rect'] = createExportWrapper('make_rect', 4);
|
||||
var _draw_rect = Module['_draw_rect'] = createExportWrapper('draw_rect', 3);
|
||||
var _flush = Module['_flush'] = createExportWrapper('flush', 1);
|
||||
var _translate = Module['_translate'] = createExportWrapper('translate', 3);
|
||||
var _scale = Module['_scale'] = createExportWrapper('scale', 3);
|
||||
|
@ -8613,10 +8617,10 @@ var dynCall_iiiiij = Module['dynCall_iiiiij'] = createExportWrapper('dynCall_iii
|
|||
var dynCall_iiiiijj = Module['dynCall_iiiiijj'] = createExportWrapper('dynCall_iiiiijj', 9);
|
||||
var dynCall_iiiiiijj = Module['dynCall_iiiiiijj'] = createExportWrapper('dynCall_iiiiiijj', 10);
|
||||
|
||||
function invoke_vii(index,a1,a2) {
|
||||
function invoke_iii(index,a1,a2) {
|
||||
var sp = stackSave();
|
||||
try {
|
||||
getWasmTableEntry(index)(a1,a2);
|
||||
return getWasmTableEntry(index)(a1,a2);
|
||||
} catch(e) {
|
||||
stackRestore(sp);
|
||||
if (!(e instanceof EmscriptenEH)) throw e;
|
||||
|
@ -8635,6 +8639,17 @@ function invoke_ii(index,a1) {
|
|||
}
|
||||
}
|
||||
|
||||
function invoke_vii(index,a1,a2) {
|
||||
var sp = stackSave();
|
||||
try {
|
||||
getWasmTableEntry(index)(a1,a2);
|
||||
} catch(e) {
|
||||
stackRestore(sp);
|
||||
if (!(e instanceof EmscriptenEH)) throw e;
|
||||
_setThrew(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function invoke_viii(index,a1,a2,a3) {
|
||||
var sp = stackSave();
|
||||
try {
|
||||
|
@ -8657,10 +8672,10 @@ function invoke_vi(index,a1) {
|
|||
}
|
||||
}
|
||||
|
||||
function invoke_iii(index,a1,a2) {
|
||||
function invoke_iiii(index,a1,a2,a3) {
|
||||
var sp = stackSave();
|
||||
try {
|
||||
return getWasmTableEntry(index)(a1,a2);
|
||||
return getWasmTableEntry(index)(a1,a2,a3);
|
||||
} catch(e) {
|
||||
stackRestore(sp);
|
||||
if (!(e instanceof EmscriptenEH)) throw e;
|
||||
|
@ -8690,17 +8705,6 @@ function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6) {
|
|||
}
|
||||
}
|
||||
|
||||
function invoke_iiii(index,a1,a2,a3) {
|
||||
var sp = stackSave();
|
||||
try {
|
||||
return getWasmTableEntry(index)(a1,a2,a3);
|
||||
} catch(e) {
|
||||
stackRestore(sp);
|
||||
if (!(e instanceof EmscriptenEH)) throw e;
|
||||
_setThrew(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function invoke_iiiii(index,a1,a2,a3,a4) {
|
||||
var sp = stackSave();
|
||||
try {
|
||||
|
@ -9048,12 +9052,14 @@ var missingLibrarySymbols = [
|
|||
'setImmediateWrapped',
|
||||
'clearImmediateWrapped',
|
||||
'polyfillSetImmediate',
|
||||
'registerPostMainLoop',
|
||||
'registerPreMainLoop',
|
||||
'getPromise',
|
||||
'makePromise',
|
||||
'idsToPromises',
|
||||
'makePromiseCallback',
|
||||
'Browser_asyncPrepareDataCounter',
|
||||
'setMainLoop',
|
||||
'safeRequestAnimationFrame',
|
||||
'isLeapYear',
|
||||
'ydayFromDate',
|
||||
'arraySum',
|
||||
|
|
Loading…
Add table
Reference in a new issue