0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-07 15:39:42 -05:00

♻️ Refactor rust/wasm code organization

This commit is contained in:
Belén Albeza 2024-10-25 12:10:59 +02:00 committed by Andrey Antukh
parent 043c23899a
commit 29e0964ebc
2 changed files with 94 additions and 91 deletions

View file

@ -1,97 +1,14 @@
use skia_safe::gpu::{self, gl::FramebufferInfo, DirectContext};
use std::boxed::Box;
pub mod render;
use skia_safe as skia;
extern "C" {
pub fn emscripten_GetProcAddress(
name: *const ::std::os::raw::c_char,
) -> *const ::std::os::raw::c_void;
}
struct GpuState {
context: DirectContext,
framebuffer_info: FramebufferInfo,
}
/// This struct holds the state of the Rust application between JS calls.
///
/// It is created by [init] and passed to the other exported functions. Note that rust-skia data
/// structures are not thread safe, so a state must not be shared between different Web Workers.
pub struct State {
gpu_state: GpuState,
surface: skia::Surface,
}
impl State {
fn new(gpu_state: GpuState, surface: skia::Surface) -> Self {
State { gpu_state, surface }
}
fn set_surface(&mut self, surface: skia::Surface) {
self.surface = surface;
}
}
fn init_gl() {
unsafe {
gl::load_with(|addr| {
let addr = std::ffi::CString::new(addr).unwrap();
emscripten_GetProcAddress(addr.into_raw() as *const _) as *const _
});
}
}
/// This needs to be done once per WebGL context.
fn create_gpu_state() -> GpuState {
let interface = skia_safe::gpu::gl::Interface::new_native().unwrap();
let context = skia_safe::gpu::direct_contexts::make_gl(interface, None).unwrap();
let framebuffer_info = {
let mut fboid: gl::types::GLint = 0;
unsafe { gl::GetIntegerv(gl::FRAMEBUFFER_BINDING, &mut fboid) };
FramebufferInfo {
fboid: fboid.try_into().unwrap(),
format: skia_safe::gpu::gl::Format::RGBA8.into(),
protected: skia_safe::gpu::Protected::No,
}
};
GpuState {
context,
framebuffer_info,
}
}
/// Create the Skia surface that will be used for rendering.
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);
gpu::surfaces::wrap_backend_render_target(
&mut gpu_state.context,
&backend_render_target,
skia_safe::gpu::SurfaceOrigin::BottomLeft,
skia_safe::ColorType::RGBA8888,
None,
None,
)
.unwrap()
}
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);
}
use render::State;
/// This is called from JS after the WebGL context has been created.
#[no_mangle]
pub extern "C" fn init(width: i32, height: i32) -> Box<State> {
let mut gpu_state = create_gpu_state();
let surface = create_surface(&mut gpu_state, width, height);
pub extern "C" fn init(width: i32, height: i32) -> Box<render::State> {
let mut gpu_state = render::create_gpu_state();
let surface = render::create_surface(&mut gpu_state, width, height);
let state = State::new(gpu_state, surface);
@ -103,7 +20,7 @@ pub extern "C" fn init(width: i32, height: i32) -> Box<State> {
#[no_mangle]
pub unsafe extern "C" fn resize_surface(state: *mut State, width: i32, height: i32) {
let state = unsafe { state.as_mut() }.expect("got an invalid state pointer");
let surface = create_surface(&mut state.gpu_state, width, height);
let surface = render::create_surface(&mut state.gpu_state, width, height);
state.set_surface(surface);
}
@ -113,7 +30,7 @@ pub unsafe extern "C" fn resize_surface(state: *mut State, width: i32, height: i
pub unsafe extern "C" fn draw_rect(state: *mut State, x1: f32, y1: f32, x2: f32, y2: f32) {
let state = unsafe { state.as_mut() }.expect("got an invalid state pointer");
let r = skia::Rect::new(x1, y1, x2, y2);
render_rect(&mut state.surface, r, skia::Color::RED);
render::render_rect(&mut state.surface, r, skia::Color::RED);
}
#[no_mangle]
@ -144,5 +61,5 @@ pub unsafe extern "C" fn reset_canvas(state: *mut State) {
}
fn main() {
init_gl();
render::init_gl();
}

86
render-wasm/src/render.rs Normal file
View file

@ -0,0 +1,86 @@
use skia_safe as skia;
use skia_safe::gpu::{self, gl::FramebufferInfo, DirectContext};
extern "C" {
pub fn emscripten_GetProcAddress(
name: *const ::std::os::raw::c_char,
) -> *const ::std::os::raw::c_void;
}
pub struct GpuState {
pub context: DirectContext,
framebuffer_info: FramebufferInfo,
}
/// This struct holds the state of the Rust application between JS calls.
///
/// It is created by [init] and passed to the other exported functions. Note that rust-skia data
/// structures are not thread safe, so a state must not be shared between different Web Workers.
pub struct State {
pub gpu_state: GpuState,
pub surface: skia::Surface,
}
impl State {
pub fn new(gpu_state: GpuState, surface: skia::Surface) -> Self {
State { gpu_state, surface }
}
pub fn set_surface(&mut self, surface: skia::Surface) {
self.surface = surface;
}
}
pub(crate) fn init_gl() {
unsafe {
gl::load_with(|addr| {
let addr = std::ffi::CString::new(addr).unwrap();
emscripten_GetProcAddress(addr.into_raw() as *const _) as *const _
});
}
}
/// This needs to be done once per WebGL context.
pub(crate) fn create_gpu_state() -> GpuState {
let interface = skia_safe::gpu::gl::Interface::new_native().unwrap();
let context = skia_safe::gpu::direct_contexts::make_gl(interface, None).unwrap();
let framebuffer_info = {
let mut fboid: gl::types::GLint = 0;
unsafe { gl::GetIntegerv(gl::FRAMEBUFFER_BINDING, &mut fboid) };
FramebufferInfo {
fboid: fboid.try_into().unwrap(),
format: skia_safe::gpu::gl::Format::RGBA8.into(),
protected: skia_safe::gpu::Protected::No,
}
};
GpuState {
context,
framebuffer_info,
}
}
/// Create the Skia surface that will be used for rendering.
pub(crate) 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);
gpu::surfaces::wrap_backend_render_target(
&mut gpu_state.context,
&backend_render_target,
skia_safe::gpu::SurfaceOrigin::BottomLeft,
skia_safe::ColorType::RGBA8888,
None,
None,
)
.unwrap()
}
pub(crate) 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);
}