Module gpu

Source
Expand description

GPU renderer: the effect chain as OpenGL shaders, using eframe’s existing glow context.

Why: the CPU compositor is fine for cuts but blur/VHS/motion-blur at 1080p+ are not. Every round-3 effect is a fragment shader here; the CPU path (engine/effects.rs) keeps the older, cheap effects so the app still runs (degraded) when no GL context exists.

Threading: GL belongs to the thread that owns the context — the UI thread. So:

  • preview → render_to_texture during App::update, painted straight into the preview pane (no CPU readback at all).
  • export → the export thread posts RenderRequests; the UI thread serves them with render_frame (readback via glReadPixels) so preview and export run the SAME shaders.
  • headless (--selftest, no GL) → callers fall back to engine::compose::Compositor.

Pipeline per frame: decode (CPU, player threads) → upload layer textures (upload) → for each visual clip: build its chain (node graph when present, else the linear effect stack) → ping-pong FBOs → transform+blend into the canvas FBO → adjustment layers re-process the canvas → subtitles/markers. All textures are RGBA8 with straight alpha, matching media::Frame.

What the caller owes us (LayerSet): one decoded frame per visual clip that is on screen at t, keyed by clip id — including both clips of a transition (they are rendered virtually extended past their own bounds), the rendered bitmap of a Text/Shape clip, the rendered canvas of a nested Sequence clip, and, under LayerSet::SUBTITLES, the subtitle bitmap. Anything missing is skipped. Footage is placed from its asset’s native size, so any decode size works; text/shape/subtitle bitmaps are placed 1:1 and must be rasterised for render_size(w, h, quality), not for w×h.

Textures returned by render_to_texture / apply_effect / mask_texture / eval_graph stay valid until the next render_to_texture / render_frame call, which recycles them.

Structs§

Extra 🔒
Per-clip render tweaks used by transitions (mirrors compose::Extra).
GpuRenderer
The renderer. One per app; lives on the UI thread.
LayerSet
Decoded layers for one timeline instant, produced by the player/export thread on the CPU and handed to the renderer: (clip id, decoded frame). Motion-blur effects also get the neighbouring frames.
LayerTex 🔒
A layer texture and the revision of the frame currently in it.
Pool 🔒
Size-keyed target pool. GL objects are created by the renderer when take finds nothing reusable and deleted here when the free list outgrows its budget. Ping-pong falls out of it: composite takes a second canvas-sized target, draws into it and returns the old canvas here, so the two keep swapping.
Prog 🔒
Programs
Compiled shader programs, cached by effect kind (and by source hash for EffectKind::Shader).
Target
One reusable off-screen target (texture + FBO).

Enums§

MaskTex 🔒
Either a mask we rendered (and must recycle) or one the caller owns.

Constants§

COPY_BODY 🔒
vec4 effect(..) bodies that are not per-effect: a pass-through and the two-input matte.
EFFECT_BASE 🔒
K_COMPOSITE 🔒
K_COPY 🔒
K_MASK 🔒
K_MATTE 🔒
MATTE_BODY 🔒
MAX_MASK_POINTS
MASK’s m_points array size.
MOTION_NEXT 🔒
MOTION_PREV 🔒
Texture-cache keys for the neighbouring frames of a motion-blurred clip. Clip ids are small counters (Project::new_id), so the top bits are free to tag a variant of the same clip.
PARAM_NAMES 🔒
One name per parameter any effect can have (Curves has 12, everything else 8 or fewer).
UNIFORMS 🔒
Every uniform any of our programs can declare; looked up once per link.
USER_BIT 🔒
U_B 🔒
U_DST 🔒
U_MASK 🔒
U_NEXT 🔒
U_PREV 🔒
U_TEX 🔒
Texture units.

Functions§

blend_index
The GLSL int mode for a blend mode: its index in BlendMode::ALL, which is the order engine::blend::blend_channel matches.
build 🔒
column_major 🔒
Row-major 3×3 -> the column-major order glUniformMatrix3fv expects.
compile 🔒
driven
An effect node’s parameter ports: a value node wired to port i + 1 computes parameter i for this frame, which is the graph’s only way to drive a knob. Untouched effects are not cloned.
hash_str 🔒
inverse_placement
Canvas pixels -> layer uv for a placement (what COMPOSITE’s u_inv wants).
invert3
Inverse of a 3×3 (adjugate / det); None when singular.
param_values 🔒
An effect’s parameters at time t, in EffectKind::params() order.
placement_quad
The placed layer’s four corners (TL, TR, BR, BL) in canvas pixels, projected through the yaw/pitch tilt with focal length f and depth offset z0. None when a corner is behind the camera. Mirrors compose::draw_layer_perspective (which uses f = canvas width, z0 = 0).
render_size
The canvas size render_to_texture actually renders at for a given preview quality. Callers must rasterise text/shape/subtitle layers at this size (they are placed 1:1, not fitted).
scaler_index
square_to_quad
Homography mapping the unit square (0,0)(1,0)(1,1)(0,1) onto q (Heckbert). ponytail: copied from compose::square_to_quad (private there) so the GPU geometry cannot drift from the CPU one — make that pair pub(crate) and this goes away.
tex_params 🔒
user_key 🔒
Cache key of a user shader body — shared by effect_program, check_shader and shader_error so the editor reads the very program the renderer would build.