diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-01 13:57:32 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-01 13:57:32 +0200 |
| commit | e579ae120290329fd697b50ea9138ffccb65a805 (patch) | |
| tree | 12a63ee60b00e5004a1806ddf3ebd70c012e3e28 /apps/web/src/services/renderer/nodes | |
| parent | b048b739bd598f9d9ff97166f29bcb6e37c40607 (diff) | |
| download | opencut-e579ae120290329fd697b50ea9138ffccb65a805.tar.gz | |
feat: migrate GPU renderer from WebGL to wgpu/WASM
Diffstat (limited to 'apps/web/src/services/renderer/nodes')
4 files changed, 87 insertions, 87 deletions
diff --git a/apps/web/src/services/renderer/nodes/blur-background-node.ts b/apps/web/src/services/renderer/nodes/blur-background-node.ts index 7f4d06fc..f790ebb4 100644 --- a/apps/web/src/services/renderer/nodes/blur-background-node.ts +++ b/apps/web/src/services/renderer/nodes/blur-background-node.ts @@ -5,7 +5,7 @@ import { videoCache } from "@/services/video-cache/service"; import type { RetimeConfig } from "@/lib/timeline"; import type { CanvasRenderer } from "../canvas-renderer"; import { createOffscreenCanvas } from "../canvas-utils"; -import { webglEffectRenderer } from "../webgl/webgl-effect-renderer"; +import { gpuRenderer } from "../gpu-renderer"; import { BaseNode } from "./base-node"; import { loadImageSource, type CachedImageSource } from "./image-node"; @@ -131,7 +131,7 @@ export class BlurBackgroundNode extends BaseNode<BlurBackgroundNodeParams> { sigmaX: this.params.blurIntensity * (renderer.width / 1920), sigmaY: this.params.blurIntensity * (renderer.height / 1080), }); - const effectResult = webglEffectRenderer.applyEffect({ + const effectResult = gpuRenderer.applyEffect({ source: offscreen as CanvasImageSource, width: renderer.width, height: renderer.height, diff --git a/apps/web/src/services/renderer/nodes/effect-layer-node.ts b/apps/web/src/services/renderer/nodes/effect-layer-node.ts index 51de2398..d8389fb5 100644 --- a/apps/web/src/services/renderer/nodes/effect-layer-node.ts +++ b/apps/web/src/services/renderer/nodes/effect-layer-node.ts @@ -1,81 +1,81 @@ -import type { CanvasRenderer } from "../canvas-renderer";
-import { effectsRegistry, resolveEffectPasses } from "@/lib/effects";
-import type { ParamValues } from "@/lib/params";
-import { BaseNode } from "./base-node";
-import { webglEffectRenderer } from "../webgl/webgl-effect-renderer";
-
-const TIME_EPSILON = 1e-6;
-
-export type EffectLayerNodeParams = {
- effectType: string;
- effectParams: ParamValues;
- timeOffset: number;
- duration: number;
-};
-
-function isInRange({
- time,
- timeOffset,
- duration,
-}: {
- time: number;
- timeOffset: number;
- duration: number;
-}): boolean {
- return (
- time >= timeOffset - TIME_EPSILON &&
- time < timeOffset + duration + TIME_EPSILON
- );
-}
-
-// snapshots whatever is currently on the canvas, applies the effect, draws it back
-export class EffectLayerNode extends BaseNode<EffectLayerNodeParams> {
- async render({
- renderer,
- time,
- }: {
- renderer: CanvasRenderer;
- time: number;
- }): Promise<void> {
- if (
- !isInRange({
- time,
- timeOffset: this.params.timeOffset,
- duration: this.params.duration,
- })
- ) {
- return;
- }
-
- const source = renderer.context.canvas as CanvasImageSource;
-
- const effectDefinition = effectsRegistry.get(this.params.effectType);
-
- const passes = resolveEffectPasses({
- definition: effectDefinition,
- effectParams: this.params.effectParams,
- width: renderer.width,
- height: renderer.height,
- });
- if (passes.length === 0) {
- return;
- }
- const effectResult = webglEffectRenderer.applyEffect({
- source,
- width: renderer.width,
- height: renderer.height,
- passes,
- });
-
- renderer.context.save();
- renderer.context.clearRect(0, 0, renderer.width, renderer.height);
- renderer.context.drawImage(
- effectResult,
- 0,
- 0,
- renderer.width,
- renderer.height,
- );
- renderer.context.restore();
- }
-}
+import type { CanvasRenderer } from "../canvas-renderer"; +import { effectsRegistry, resolveEffectPasses } from "@/lib/effects"; +import type { ParamValues } from "@/lib/params"; +import { BaseNode } from "./base-node"; +import { gpuRenderer } from "../gpu-renderer"; + +const TIME_EPSILON = 1e-6; + +export type EffectLayerNodeParams = { + effectType: string; + effectParams: ParamValues; + timeOffset: number; + duration: number; +}; + +function isInRange({ + time, + timeOffset, + duration, +}: { + time: number; + timeOffset: number; + duration: number; +}): boolean { + return ( + time >= timeOffset - TIME_EPSILON && + time < timeOffset + duration + TIME_EPSILON + ); +} + +// snapshots whatever is currently on the canvas, applies the effect, draws it back +export class EffectLayerNode extends BaseNode<EffectLayerNodeParams> { + async render({ + renderer, + time, + }: { + renderer: CanvasRenderer; + time: number; + }): Promise<void> { + if ( + !isInRange({ + time, + timeOffset: this.params.timeOffset, + duration: this.params.duration, + }) + ) { + return; + } + + const source = renderer.context.canvas as CanvasImageSource; + + const effectDefinition = effectsRegistry.get(this.params.effectType); + + const passes = resolveEffectPasses({ + definition: effectDefinition, + effectParams: this.params.effectParams, + width: renderer.width, + height: renderer.height, + }); + if (passes.length === 0) { + return; + } + const effectResult = gpuRenderer.applyEffect({ + source, + width: renderer.width, + height: renderer.height, + passes, + }); + + renderer.context.save(); + renderer.context.clearRect(0, 0, renderer.width, renderer.height); + renderer.context.drawImage( + effectResult, + 0, + 0, + renderer.width, + renderer.height, + ); + renderer.context.restore(); + } +} diff --git a/apps/web/src/services/renderer/nodes/text-node.ts b/apps/web/src/services/renderer/nodes/text-node.ts index 031c43b3..643e538a 100644 --- a/apps/web/src/services/renderer/nodes/text-node.ts +++ b/apps/web/src/services/renderer/nodes/text-node.ts @@ -21,7 +21,7 @@ import { } from "@/lib/animation"; import { resolveEffectParamsAtTime } from "@/lib/animation/effect-param-channel"; import { effectsRegistry, resolveEffectPasses } from "@/lib/effects"; -import { webglEffectRenderer } from "../webgl/webgl-effect-renderer"; +import { gpuRenderer } from "../gpu-renderer"; import { clamp } from "@/utils/math"; const TEXT_DECORATION_THICKNESS_RATIO = 0.07; @@ -272,7 +272,7 @@ export class TextNode extends BaseNode<TextNodeParams> { width: renderer.width, height: renderer.height, }); - currentSource = webglEffectRenderer.applyEffect({ + currentSource = gpuRenderer.applyEffect({ source: currentSource, width: renderer.width, height: renderer.height, diff --git a/apps/web/src/services/renderer/nodes/visual-node.ts b/apps/web/src/services/renderer/nodes/visual-node.ts index e0f87c52..82093da4 100644 --- a/apps/web/src/services/renderer/nodes/visual-node.ts +++ b/apps/web/src/services/renderer/nodes/visual-node.ts @@ -16,7 +16,7 @@ import { TIME_EPSILON_SECONDS } from "@/constants/animation-constants"; import { effectsRegistry, resolveEffectPasses } from "@/lib/effects"; import { masksRegistry } from "@/lib/masks"; import { getSourceTimeAtClipTime } from "@/lib/retime"; -import { webglEffectRenderer } from "../webgl/webgl-effect-renderer"; +import { gpuRenderer } from "../gpu-renderer"; import { applyMaskFeather } from "../mask-feather"; export interface VisualNodeParams { @@ -205,7 +205,7 @@ export abstract class VisualNode< width, height, }); - current = webglEffectRenderer.applyEffect({ + current = gpuRenderer.applyEffect({ source: current, width: Math.round(width), height: Math.round(height), |
