Skip to content

Commit 729d105

Browse files
committed
fix: WebGL frame rendering and opencut-wasm 0.2.8
1 parent 9da365b commit 729d105

14 files changed

Lines changed: 331 additions & 120 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/desktop/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use gpui::{
2-
App, Application, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, div,
3-
prelude::*, px, rgb, size,
2+
div, prelude::*, px, rgb, size, App, Application, Bounds, Context, SharedString, Window,
3+
WindowBounds, WindowOptions,
44
};
55

66
struct AppWindow {

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"nanoid": "^5.1.5",
5353
"next": "16.1.3",
5454
"next-themes": "^0.4.4",
55-
"opencut-wasm": "^0.2.6",
55+
"opencut-wasm": "^0.2.8",
5656
"pg": "^8.16.2",
5757
"postgres": "^3.4.5",
5858
"radix-ui": "^1.4.3",

apps/web/src/components/providers/editor-provider.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import { useKeybindingsStore } from "@/stores/keybindings-store";
1010
import { useTimelineStore } from "@/stores/timeline-store";
1111
import { useEditorActions } from "@/hooks/actions/use-editor-actions";
1212
import { loadFontAtlas } from "@/lib/fonts/google-fonts";
13-
import { initializeGpuRenderer, isGpuAvailable } from "@/services/renderer/gpu-renderer";
13+
import {
14+
initializeGpuRenderer,
15+
isGpuAvailable,
16+
} from "@/services/renderer/gpu-renderer";
1417

1518
interface EditorProviderProps {
1619
projectId: string;
@@ -62,9 +65,16 @@ export function EditorProvider({ projectId, children }: EditorProviderProps) {
6265
setIsLoading(false);
6366
}
6467
} else {
65-
setError(
66-
err instanceof Error ? err.message : "Failed to load project",
67-
);
68+
const wasmPanic = (window as Window & { __wasmPanic?: string })
69+
.__wasmPanic;
70+
if (wasmPanic) {
71+
delete (window as Window & { __wasmPanic?: string }).__wasmPanic;
72+
setError(wasmPanic);
73+
} else {
74+
setError(
75+
err instanceof Error ? err.message : "Failed to load project",
76+
);
77+
}
6878
setIsLoading(false);
6979
}
7080
}

apps/web/src/core/managers/project-manager.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,13 @@ export class ProjectManager {
167167
});
168168

169169
if (!project.metadata.thumbnail) {
170-
const didUpdateThumbnail = await this.updateThumbnailFromTimeline();
171-
if (didUpdateThumbnail) {
172-
await this.saveCurrentProject();
170+
try {
171+
const didUpdateThumbnail = await this.updateThumbnailFromTimeline();
172+
if (didUpdateThumbnail) {
173+
await this.saveCurrentProject();
174+
}
175+
} catch (error) {
176+
console.error("Failed to generate project thumbnail:", error);
173177
}
174178
}
175179
} catch (error) {

apps/web/src/services/renderer/effect-preview.ts

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ class EffectPreviewService {
1818
this.loadPreviewImage();
1919
}
2020

21-
onPreviewImageReady({
22-
callback,
23-
}: {
24-
callback: () => void;
25-
}): () => void {
21+
onPreviewImageReady({ callback }: { callback: () => void }): () => void {
2622
this.onReadyCallbacks.add(callback);
2723
return () => this.onReadyCallbacks.delete(callback);
2824
}
@@ -39,35 +35,47 @@ class EffectPreviewService {
3935
uniformDimensions?: { width: number; height: number };
4036
}): void {
4137
const size = PREVIEW_SIZE;
42-
const source = this.getTestSource({ width: size, height: size });
43-
if (!source) return;
44-
45-
const definition = effectsRegistry.get(effectType);
46-
const resolvedParams =
47-
Object.keys(params).length > 0
48-
? params
49-
: buildDefaultParamValues(definition.params);
50-
51-
const passes = resolveEffectPasses({
52-
definition,
53-
effectParams: resolvedParams,
54-
width: uniformDimensions?.width ?? size,
55-
height: uniformDimensions?.height ?? size,
56-
});
57-
const result = this.applyGpuEffect({
58-
source,
59-
width: size,
60-
height: size,
61-
passes,
62-
});
63-
6438
const targetCtx = targetCanvas.getContext(
6539
"2d",
6640
) as CanvasRenderingContext2D | null;
67-
if (targetCtx) {
68-
targetCanvas.width = size;
69-
targetCanvas.height = size;
41+
if (!targetCtx) {
42+
return;
43+
}
44+
45+
targetCanvas.width = size;
46+
targetCanvas.height = size;
47+
48+
const source = this.getTestSource({ width: size, height: size });
49+
if (!source) {
50+
targetCtx.clearRect(0, 0, size, size);
51+
return;
52+
}
53+
54+
try {
55+
const definition = effectsRegistry.get(effectType);
56+
const resolvedParams =
57+
Object.keys(params).length > 0
58+
? params
59+
: buildDefaultParamValues(definition.params);
60+
61+
const passes = resolveEffectPasses({
62+
definition,
63+
effectParams: resolvedParams,
64+
width: uniformDimensions?.width ?? size,
65+
height: uniformDimensions?.height ?? size,
66+
});
67+
const result = this.applyGpuEffect({
68+
source,
69+
width: size,
70+
height: size,
71+
passes,
72+
});
73+
7074
targetCtx.drawImage(result, 0, 0, size, size);
75+
} catch (error) {
76+
console.warn("Failed to render effect preview", { effectType, error });
77+
targetCtx.clearRect(0, 0, size, size);
78+
targetCtx.drawImage(source, 0, 0, size, size);
7179
}
7280
}
7381

bun.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/crates/compositor/src/compositor.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,59 @@ impl Compositor {
288288
self.textures.remove(id);
289289
}
290290

291+
/// Composites all frame items into a texture and returns it.
292+
/// Used on backends that cannot surface-render to an arbitrary canvas (e.g. WebGL).
293+
pub fn render_frame_to_texture(
294+
&mut self,
295+
context: &GpuContext,
296+
frame: &FrameDescriptor,
297+
) -> Result<wgpu::Texture, CompositorError> {
298+
self.texture_pool.recycle_frame();
299+
let mut encoder =
300+
context
301+
.device()
302+
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
303+
label: Some("compositor-frame-encoder"),
304+
});
305+
let mut scene = self.create_cleared_texture(
306+
context,
307+
&mut encoder,
308+
frame.width,
309+
frame.height,
310+
frame.clear.color,
311+
);
312+
313+
for item in &frame.items {
314+
match item {
315+
FrameItemDescriptor::Layer(layer) => {
316+
let layer_texture = self.render_layer(context, &mut encoder, frame, layer)?;
317+
scene = self.blend_texture(
318+
context,
319+
&mut encoder,
320+
&scene,
321+
&layer_texture,
322+
layer.blend_mode,
323+
frame.width,
324+
frame.height,
325+
)?;
326+
}
327+
FrameItemDescriptor::SceneEffect { effect_pass_groups } => {
328+
scene = self.apply_effect_groups(
329+
context,
330+
&mut encoder,
331+
&scene,
332+
frame.width,
333+
frame.height,
334+
effect_pass_groups,
335+
)?;
336+
}
337+
}
338+
}
339+
340+
context.queue().submit([encoder.finish()]);
341+
Ok(scene)
342+
}
343+
291344
pub fn render_frame(
292345
&mut self,
293346
context: &GpuContext,

rust/crates/compositor/src/shaders/layer.wgsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct LayerUniforms {
1111
opacity: f32,
1212
flip_x: f32,
1313
flip_y: f32,
14+
_padding: vec2f,
1415
}
1516

1617
@group(0) @binding(0) var source_texture: texture_2d<f32>;

rust/crates/gpu/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ wgpu = "29.0.1"
1010

1111
[target.'cfg(target_arch = "wasm32")'.dependencies]
1212
wasm-bindgen = "0.2.116"
13-
web-sys = { version = "0.3.93", features = ["Document", "Window", "HtmlCanvasElement", "OffscreenCanvasRenderingContext2d", "ImageData"] }
13+
web-sys = { version = "0.3.93", features = ["Document", "Window", "HtmlCanvasElement", "CanvasRenderingContext2d", "OffscreenCanvasRenderingContext2d", "ImageData"] }
1414

1515
[features]
1616
default = []

0 commit comments

Comments
 (0)