summaryrefslogtreecommitdiff
path: root/rust/wasm
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-19 07:42:52 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-19 07:42:52 +0200
commit729d10592f4e802f91c555c309ff3ba4b119f843 (patch)
treea547a6d1ba90ca9cc03f406e0160df0af987644d /rust/wasm
parent9da365bc01fc54f6d3f0ca9c3212eee4c0cee7cd (diff)
downloadopencut-729d10592f4e802f91c555c309ff3ba4b119f843.tar.gz
fix: WebGL frame rendering and opencut-wasm 0.2.8
Diffstat (limited to 'rust/wasm')
-rw-r--r--rust/wasm/Cargo.toml2
-rw-r--r--rust/wasm/src/compositor.rs50
-rw-r--r--rust/wasm/src/gpu.rs20
3 files changed, 54 insertions, 18 deletions
diff --git a/rust/wasm/Cargo.toml b/rust/wasm/Cargo.toml
index 98e9ed30..d8bda107 100644
--- a/rust/wasm/Cargo.toml
+++ b/rust/wasm/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "opencut-wasm"
-version = "0.2.5"
+version = "0.2.8"
edition = "2024"
description = "Shared video editor logic compiled to WebAssembly"
repository = "https://github.com/opencut/opencut"
diff --git a/rust/wasm/src/compositor.rs b/rust/wasm/src/compositor.rs
index 55756a21..126c7468 100644
--- a/rust/wasm/src/compositor.rs
+++ b/rust/wasm/src/compositor.rs
@@ -131,22 +131,41 @@ pub fn render_frame(options: JsValue) -> Result<(), JsValue> {
));
};
- let surface = gpu_runtime
- .context
- .instance()
- .create_surface(wgpu::SurfaceTarget::Canvas(runtime.canvas.clone()))
- .map_err(|error| JsValue::from_str(&error.to_string()))?;
+ if gpu_runtime.context.supports_surface_rendering() {
+ let surface = gpu_runtime
+ .context
+ .instance()
+ .create_surface(wgpu::SurfaceTarget::Canvas(runtime.canvas.clone()))
+ .map_err(|error| JsValue::from_str(&error.to_string()))?;
- runtime
- .compositor
- .render_frame(
- &gpu_runtime.context,
- RenderFrameOptions {
- frame: &frame,
- surface: &surface,
- },
- )
- .map_err(|error| JsValue::from_str(&error.to_string()))
+ runtime
+ .compositor
+ .render_frame(
+ &gpu_runtime.context,
+ RenderFrameOptions {
+ frame: &frame,
+ surface: &surface,
+ },
+ )
+ .map_err(|error| JsValue::from_str(&error.to_string()))
+ } else {
+ // WebGL cannot surface-render to an arbitrary canvas element.
+ // Composite to a texture, then blit to the canvas via the 2D context.
+ let texture = runtime
+ .compositor
+ .render_frame_to_texture(&gpu_runtime.context, &frame)
+ .map_err(|error| JsValue::from_str(&error.to_string()))?;
+
+ gpu_runtime
+ .context
+ .render_texture_via_gl_canvas(
+ &texture,
+ &runtime.canvas,
+ frame.width,
+ frame.height,
+ )
+ .map_err(|error| JsValue::from_str(&error.to_string()))
+ }
})
})
}
@@ -171,4 +190,3 @@ fn parse_upload_texture_options(value: JsValue) -> Result<UploadTextureOptions,
height: read_u32_property(&object, "height")?,
})
}
-
diff --git a/rust/wasm/src/gpu.rs b/rust/wasm/src/gpu.rs
index 4e65978c..52c051f0 100644
--- a/rust/wasm/src/gpu.rs
+++ b/rust/wasm/src/gpu.rs
@@ -19,9 +19,27 @@ thread_local! {
static GPU_RUNTIME: RefCell<Option<GpuRuntime>> = const { RefCell::new(None) };
}
+fn set_panic_hook() {
+ static SET_HOOK: std::sync::Once = std::sync::Once::new();
+ SET_HOOK.call_once(|| {
+ std::panic::set_hook(Box::new(|info| {
+ // Store the full panic message in window.__wasmPanic so the JS catch block
+ // can surface it instead of the opaque "Unreachable" WASM trap message.
+ if let Some(window) = web_sys::window() {
+ let _ = Reflect::set(
+ &window,
+ &JsValue::from_str("__wasmPanic"),
+ &JsValue::from_str(&info.to_string()),
+ );
+ }
+ console_error_panic_hook::hook(info);
+ }));
+ });
+}
+
#[wasm_bindgen(js_name = initializeGpu)]
pub async fn initialize_gpu() -> Result<(), JsValue> {
- console_error_panic_hook::set_once();
+ set_panic_hook();
if GPU_RUNTIME.with(|runtime| runtime.borrow().is_some()) {
return Ok(());