diff --git a/ROADMAP.md b/ROADMAP.md index 29c0409f..8eaf78ff 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -36,7 +36,7 @@ before choosing work. | **Correctness in depth** | not tracked | **~60–70%** | A first-time contributor found four real bugs in core paths within hours (#5–#8: AIFF import failed, Slide left linked audio behind, transitions didn't follow ripple trims, export ignored start/end times). User reports: Color Matte always grey with no picker (#29); ALSA audio error on Linux (#23). Settings are "most wired", not all. | | **Codecs and media** | ~90% | **~75%** | Our decoders are bit-exact on conformance streams. Real camera and phone media (variable frame rate, damaged files, unusual containers) is far less tested. No camera RAW (RED, BRAW, ARRIRAW), no E-AC-3. | | **Export** | ~92% | **~70%** | Delivery: H.264 only (ProRes, DNxHR and image sequences cover mastering). No HEVC or AV1 export. AAF and OMF have never been validated in Avid Media Composer or Pro Tools. Export renders and encodes on the CPU only. | -| **Performance and hardware** | ~62% | **~35–40%** | Premiere runs effects, decoding and encoding on the GPU and the hardware media engines. Here, hardware decode works on macOS (VideoToolbox, #33; active in the desktop app only since #41, so releases up to 0.2.1 decoded in software) and Windows (Media Foundation / Direct3D 11 DXVA, H.264, HEVC Main / Main 10, VP9 and AV1 4:2:0 8/10-bit, #30). The GPU does compositing, blend modes (#32) and 31 common effects (GPU2): colour adjustments, crop/flip/transform, blurs, sharpen. Lumetri, keys, masks, the remaining effects and export rendering are CPU; H.264 encoding can use VideoToolbox on macOS (opt-in per export, no B-frames) and NVENC on Windows with an NVIDIA GPU (opt-in per export), and H.265 (HEVC) export exists there only, through the same hardware encoder. Linux has no hardware path. 8K isn't real-time (AV1 is on Windows with a hardware decoder). The effect list shows Premiere's "GPU accelerated" badge, but only 31 effect ids run on the GPU here; the rest, Lumetri included, run on the CPU. | +| **Performance and hardware** | ~62% | **~35–40%** | Premiere runs effects, decoding and encoding on the GPU and the hardware media engines. Here, hardware decode works on macOS (VideoToolbox, #33; active in the desktop app only since #41, so releases up to 0.2.1 decoded in software) and Windows (Media Foundation / Direct3D 11 DXVA, H.264, HEVC Main / Main 10, VP9 and AV1 4:2:0 8/10-bit, #30). The GPU does compositing, blend modes (#32) and 32 common effects (GPU2, GPU4): colour adjustments, crop/flip/transform, blurs, sharpen, vignette. Lumetri, keys, masks, the remaining effects and export rendering are CPU; H.264 encoding can use VideoToolbox on macOS (opt-in per export, no B-frames) and NVENC on Windows with an NVIDIA GPU (opt-in per export), and H.265 (HEVC) export exists there only, through the same hardware encoder. Linux has no hardware path. 8K isn't real-time (AV1 is on Windows with a hardware decoder). The effect list shows Premiere's "GPU accelerated" badge, but only 32 effect ids run on the GPU here; the rest, Lumetri included, run on the CPU. | | **Stability** | not tracked | **improving, unproven** | The never-crash pass (no panics in product code, last-resort guards) landed on 2026-10-04. There's no field record from real users' projects yet. | | **Plugins and pro ecosystem** | not tracked | **~0–10%** | No audio plugin hosting (VST3 / Audio Units) and no third-party video effects (OpenFX). For many professional editors this alone rules FilmCraft out. Team Projects and Productions are out of scope by design. | | **AI features** | partial | **~25–35%** | Speech to text exists but is off in default builds (the `whisper` feature). Enhance Speech is a DSP chain, not a model. Auto Reframe is approximate. No Generative Extend, and no media-intelligence search or auto colour. | @@ -50,7 +50,7 @@ In priority order. Agents should prefer this work over adding more checklist ite 1. **Hardware acceleration** (#30), the most visible gap to users: - hardware decode on Linux (VA-API); - zero-copy decoded frames into wgpu; - - the remaining effects on the GPU: Lumetri, keys, Vignette, Video Limiter, masks (31 common effects are done); + - the remaining effects on the GPU: Lumetri, keys, Video Limiter, masks (32 common effects are done); - GPU export, then hardware encode: H.264 and H.265 on macOS are in (H.264 opt-in; H.265 has no other encoder), H.264 on NVENC (Windows, opt-in); HEVC on Windows and Linux remain. 2. **A measured parity number.** Add `cargo xtask parity`, run in CI. It should cover menus, commands, effects, transitions, panels, preferences and formats against the Premiere snapshot in @@ -143,7 +143,7 @@ Status: ✅ done · 🟡 in progress · ⬜ not started. Estimates are remaining | M2 | H.264 decoder | ✅ | Own decoder, bit-exact on 37+ streams, 500–600 fps 1080p | — | — | | M3 | Editing core | 🟡 | Edit algebra (insert/overwrite/razor/lift/extract/ripple/roll/slip/slide/rate-stretch/nest/paste), tools, markers, trim mode + Trim Monitor + dynamic J/K/L trimming, Keyboard Shortcuts editor with FilmCraft/Premiere/FCP/Avid presets; Edit/Clip/File menu commands (Label colours and Select Label Group, Paste/Remove Attributes, Select All Matching, Remove Unused, Consolidate Duplicates, Sequence From Clip, Bin From Selection, Offline File, Close Project, Make/Edit Subclip, Modify Audio Channels/Timecode, Frame Hold Options/Add Frame Hold/Insert Frame Hold Segment, Time Interpolation with frame blending, Fit/Fill frame, Breakout to Mono, Extract Audio, Replace With Clip; M3.11: Scene Edit Detection (pure-Rust cut detection, background job), Normalize Mix Track, Simplify Sequence, Transcribe Sequence, Find/Find Next and search bins, Automate to Sequence, Edit Original, Edit Offline, Source Settings, Update Metadata (XMP), Generate Audio Waveform, Project Settings General/Scratch Disks, Get Media File Properties, Save as Template, Selection as FilmCraft Project, Avid Log Exchange export, Flash Cue markers, Dynamic Audio Waveforms, Reveal Log Files, System Compatibility Report); M3.12 keyboard parity: Premiere's default keyboard (~115 keyboard-only commands: edit-point navigation on targeted/any track, select clip at playhead/next/previous, extend edit to playhead, nudge/slip/slide selection, target and source-patch toggles, clip volume ±1 dB/many, frame maximize/full screen/panel cycling, monitor zoom, track heights, Project and Text panel keyboard navigation, text size/leading/alignment, Export Frame, poster frames; see docs/keyboard.md); multicam (Create Multi-Camera Source Sequence, Multi-Camera view with live switching on 1–9, angle switching, Enable/Flatten, Edit Cameras) and sync (Synchronize, Merge Clips; In/Out/timecode/marker/audio — GCC-PHAT, sample-accurate) | Multicam paging >16 angles and grid thumbnails, optical flow (renders as frame blending), 39 Premiere default shortcuts skipped with reasons in docs/keyboard.md (Productions, AI/cloud tools, work area bar, Production/Search panels) | 6–10 | | M4 | Playback | 🟡 | Audio-clock master, prefetch with cancellation, J/K/L, correct dropped-frame stats, playback resolution, render bar + content-hashed render previews, App Nap opt-out; 1080p H.264 and 3 stacked 1080p streams play with 0 dropped frames | 4K under load, 8K, frame-threaded AV1 decode, reduced-resolution decode for multicam grids | 6–10 | -| M5 | Effects, keyframes, GPU | 🟡 | All 93 Premiere 26 video effects and 84 transitions (CPU), blend modes and 31 common effects on the GPU (#32, GPU2), keyframes + value/velocity graphs, wgpu compositor, effect + opacity masks (ellipse/polygon/pen, feather, expansion, modes; CPU/WGSL parity), mask tracking (Lucas–Kanade + RANSAC), adjustment layers, effect presets (built-in + user, JSON import/export) | Effects on the GPU (in progress, #30), GPU masks in the live path, GPU export, exact Warp Stabilizer (3-D) and Morph Cut | 20–30 | +| M5 | Effects, keyframes, GPU | 🟡 | All 93 Premiere 26 video effects and 84 transitions (CPU), blend modes and 32 common effects on the GPU (#32, GPU2, GPU4), keyframes + value/velocity graphs, wgpu compositor, effect + opacity masks (ellipse/polygon/pen, feather, expansion, modes; CPU/WGSL parity), mask tracking (Lucas–Kanade + RANSAC), adjustment layers, effect presets (built-in + user, JSON import/export) | Effects on the GPU (in progress, #30), GPU masks in the live path, GPU export, exact Warp Stabilizer (3-D) and Morph Cut | 20–30 | | M6 | Export | ✅ | Own H.264 encoder (High/Main/Baseline, B-frames, VBR/CBR/2-pass) → MP4 or QuickTime + own AAC; ProRes, DNxHR, MJPEG, PNG/TIFF/BMP sequences (Premiere-style numbering), GIF, WAV, AIFF; background jobs; M6.5: Export mode parity (frame size / rate / scaling / pixel aspect, profile / level, CBR / VBR 1- and 2-pass, keyframe distance, audio codec / rate / channels / bitrate / sample size, multiplexer, burn-in or sidecar captions, image / name / timecode overlays, video limiter, loudness normalization with true-peak limiter, metadata, ranges, estimated size, summary), 24 built-in presets + user presets with favourites and import/export (Preset Manager), export queue (reorder, cancel, retry, several sequences / ranges), Quick Export; `export.*` commands and `filmcraft-cli export --preset` | Interlaced encoding, 5.1 audio, smart render, publishing destinations | 6–8 | | M7 | Audio | 🟡 | Mixer graph (tracks → submixes → Mix, pre/post-fader inserts and sends, latency-compensated, sample-accurate, ~6× realtime for 24 tracks × 3 effects on one core), Audio Track Mixer + Audio Clip Mixer panels, track automation (Off/Read/Latch/Touch/Write, recorded live while playing, thinned to keyframes, timeline lanes with pen editing), solo/solo-safe, channel mapping basics, peak + BS.1770 loudness meters (match ffmpeg), DSP crate with 16 clip/track effects, Audio Gain (set/adjust/normalize), Constant Power / Constant Gain / Exponential Fade, Essential Sound (types, Loudness auto-match, Repair incl. DeEss/DeReverb, Clarity, Creative, Ducking keyframes, presets; full Dialogue chain 22× realtime) | Music duration remix, ML speech enhancement, 5.1 panner and multichannel buses, voice-over record, effect editor windows (EQ curve), remaining effects (multiband, convolution reverb), clip-mixer automation recording | 6–9 | | M8 | Colour | 🟡 | Lumetri: basic, creative + looks, RGB & hue curves, wheels, HSL secondary, vignette, section bypass; Input LUT / Look LUT (.cube 1D/3D/shaper, .3dl; tetrahedral CPU + WGSL; project LUT library; built-in camera conversions); Colour Match (Oklab tonal-range statistics, skin protection, solved in Lumetri wheels); colour management: Rec. 709 / Rec. 2100 PQ / HLG working spaces + wide gamut, Interpret Footage colour space (S-Log3, V-Log, Canon Log 2/3, LogC3/4, Apple Log, D-Log from published specs), metadata auto-detect, BT.2390 tone mapping, gamut mapping, HDR export signalling (VUI/colr/mdcv/clli/SEI, ffprobe-verified); Lumetri Scopes: Vectorscope YUV (75/100 % targets, skin-tone line) and HLS, Histogram, Parade (RGB/YUV/RGB-White), Waveform (RGB/Luma/YC/YC no Chroma), presets, Rec. 601/709/2100, 8-bit/float/HDR (cd/m²) scales, multi-scope grid, `scopes.read` | HDR-aware Lumetri maths, macOS EDR monitors, mastering metadata → tone-map peak, D-Log M (no published formula), HSL Secondary refine | 3–5 | @@ -154,7 +154,7 @@ Status: ✅ done · 🟡 in progress · ⬜ not started. Estimates are remaining ## Running now -- **Hardware acceleration (#30):** landed: blend modes on the GPU (#32); VideoToolbox hardware decode + the `platform` FFI crate (#33); 31 common effects on the GPU (GPU2). Windows: Media Foundation / Direct3D 11 H.264 + HEVC decode (HW2) and VP9 + AV1 (HW3), NVENC H.264 export (HW4, opt-in). Next: VA-API (Linux) decode, zero-copy upload, Lumetri on the GPU. +- **Hardware acceleration (#30):** landed: blend modes on the GPU (#32); VideoToolbox hardware decode + the `platform` FFI crate (#33); 32 common effects on the GPU (GPU2, GPU4). Windows: Media Foundation / Direct3D 11 H.264 + HEVC decode (HW2) and VP9 + AV1 (HW3), NVENC H.264 export (HW4, opt-in). Next: VA-API (Linux) decode, zero-copy upload, Lumetri on the GPU. - **Next:** [Where we are lacking](#where-we-are-lacking) items 1–5. GPU export waits for the export-crate work (#19 and the never-crash follow-up) to land. ## Log diff --git a/crates/gpu/src/fx.rs b/crates/gpu/src/fx.rs index 930a43d8..96c386c7 100644 --- a/crates/gpu/src/fx.rs +++ b/crates/gpu/src/fx.rs @@ -40,6 +40,7 @@ const OP_ASC_CDL: u32 = 15; const OP_CHANNEL_MIX: u32 = 16; const OP_COLOR_REPLACE: u32 = 17; const OP_ALPHA_ADJUST: u32 = 18; +const OP_VIGNETTE: u32 = 19; const OP_BOX: u32 = 20; const OP_DIRECTIONAL: u32 = 22; const OP_UNSHARP: u32 = 23; @@ -175,6 +176,11 @@ fn steps(op: &FxOp) -> Vec { FxOp::AlphaAdjust { opacity, ignore, invert, mask_only } => { out.push(step(OP_ALPHA_ADJUST, [*ignore as u32, *invert as u32, *mask_only as u32, 0], &[*opacity])); } + FxOp::Vignette { amount, midpoint, roundness, feather, target } => { + if amount.abs() >= 1e-5 { + out.push(step(OP_VIGNETTE, [0; 4], &[*amount, *midpoint, *roundness, *feather, target[0], target[1], target[2]])); + } + } } out } diff --git a/crates/gpu/src/fx.wgsl b/crates/gpu/src/fx.wgsl index ee5d0248..80c8e520 100644 --- a/crates/gpu/src/fx.wgsl +++ b/crates/gpu/src/fx.wgsl @@ -36,6 +36,7 @@ const OP_ASC_CDL: u32 = 15u; const OP_CHANNEL_MIX: u32 = 16u; const OP_COLOR_REPLACE: u32 = 17u; const OP_ALPHA_ADJUST: u32 = 18u; +const OP_VIGNETTE: u32 = 19u; const OP_BOX: u32 = 20u; const OP_DIRECTIONAL: u32 = 22u; const OP_UNSHARP: u32 = 23u; @@ -467,6 +468,36 @@ fn pixel(op: u32, p: vec2) -> vec4 { let o = ld(p); return q + (o - q) * u.p0.z; } + case OP_VIGNETTE: { + let o = ld(p); + let a = o.a; + if a <= 1e-6 { + return o; + } + let amt = u.p0.x; + if abs(amt) < 1e-5 { + return o; + } + let mid = u.p0.y; + let round = u.p0.z; + let feather = u.p0.w; + let tgt = u.p1.xyz; + let w = f32(s.x); + let h = f32(s.y); + let aspect = w / h; + var nx = pc.x / w * 2.0 - 1.0; + let ny = pc.y / h * 2.0 - 1.0; + if round > 0.0 { + nx *= 1.0 + (aspect - 1.0) * round; + } + let p_exp = select(2.0, 2.0 + (-round) * 6.0, round < 0.0); + let d = powf(powf(abs(nx), p_exp) + powf(abs(ny), p_exp), 1.0 / p_exp) / powf(2.0, 1.0 / p_exp); + let edge = smoothstep_fx(mid - feather * 0.5, mid + feather * 0.5, d); + let c = o.rgb / a; + let ec = enc(c); + let res = dec(ec + (tgt - ec) * (edge * abs(amt))); + return vec4(res * a, a); + } default: { let o = ld(p); let a = o.a; diff --git a/crates/gpu/src/fx_tests.rs b/crates/gpu/src/fx_tests.rs index 5e201d11..37da6f04 100644 --- a/crates/gpu/src/fx_tests.rs +++ b/crates/gpu/src/fx_tests.rs @@ -187,6 +187,14 @@ fn cases() -> Vec<(&'static str, Vec<(&'static str, ParamValue)>, bool)> { ("alpha_adjust", vec![("opacity", fl(60.0))], false), ("alpha_adjust", vec![("ignore", ParamValue::Bool(true)), ("invert", ParamValue::Bool(true))], false), ("alpha_adjust", vec![("invert", ParamValue::Bool(true)), ("mask_only", ParamValue::Bool(true)), ("opacity", fl(150.0))], false), + ("vignette", vec![], false), + ("vignette", vec![("amount", fl(-100.0)), ("midpoint", fl(50.0)), ("roundness", fl(0.0)), ("feather", fl(50.0))], false), + ( + "vignette", + vec![("amount", fl(-30.0)), ("midpoint", fl(20.0)), ("roundness", fl(-100.0)), ("feather", fl(0.0)), ("color", col(0.1, 0.4, 0.7))], + false, + ), + ("vignette", vec![("amount", fl(40.0)), ("midpoint", fl(90.0)), ("roundness", fl(100.0)), ("feather", fl(100.0))], false), ] } @@ -319,6 +327,10 @@ fn hostile_parameters_are_bounded() { // minifying resamples (the CPU's mip path) stay on the CPU effect("transform", &[("scale_height", fl(20.0))]), effect("crop", &[("left", fl(-300.0)), ("zoom", ParamValue::Bool(true))]), + effect("vignette", &[("amount", fl(f64::NAN))]), + effect("vignette", &[("midpoint", fl(f64::INFINITY))]), + effect("vignette", &[("roundness", fl(f64::NAN))]), + effect("vignette", &[("feather", fl(f64::NAN))]), ]; for e in &nan { let op = FxOp::eval(e, &cx(Tick::ZERO, 1.0), w, h); diff --git a/crates/render/src/gpufx.rs b/crates/render/src/gpufx.rs index 1dd0edfd..cc5b6afc 100644 --- a/crates/render/src/gpufx.rs +++ b/crates/render/src/gpufx.rs @@ -161,6 +161,13 @@ pub enum FxOp { invert: bool, mask_only: bool, }, + Vignette { + amount: f32, + midpoint: f32, + roundness: f32, + feather: f32, + target: [f32; 3], + }, } /// Effect ids [`FxOp::eval`] understands (the GPU-capable standard effects). @@ -196,6 +203,7 @@ pub const GPU_EFFECTS: &[&str] = &[ "channel_mix", "color_replace", "alpha_adjust", + "vignette", ]; /// `Image::transformed` without the mip path: the destination rectangle it writes and the inverse. @@ -415,6 +423,17 @@ impl FxOp { use crate::vfx::{bv, fv}; FxOp::AlphaAdjust { opacity: fv(e, "opacity", cx) / 100.0, ignore: bv(e, "ignore"), invert: bv(e, "invert"), mask_only: bv(e, "mask_only") } } + "vignette" => { + use crate::vfx::{cv, fv}; + let amt = fv(e, "amount", cx) / 100.0; + let mid = fv(e, "midpoint", cx) / 100.0; + let round = fv(e, "roundness", cx) / 100.0; + let raw_feather = fv(e, "feather", cx); + let feather = if raw_feather.is_finite() { (raw_feather / 100.0).max(0.01) } else { raw_feather }; + let col = cv(e, "color", cx); + let target = if amt < 0.0 { [col[0], col[1], col[2]] } else { [1.0; 3] }; + FxOp::Vignette { amount: amt, midpoint: mid, roundness: round, feather, target } + } _ => return None, }) } @@ -458,6 +477,7 @@ impl FxOp { FxOp::ChannelMix { m } => m.iter().all(|r| fin(r)), FxOp::ColorReplace { sim, target, replace, replace_hsl, .. } => sim.is_finite() && fin(target) && fin(replace) && fin(replace_hsl), FxOp::AlphaAdjust { opacity, .. } => opacity.is_finite(), + FxOp::Vignette { amount, midpoint, roundness, feather, target } => fin(&[*amount, *midpoint, *roundness, *feather]) && fin(target), } } @@ -709,6 +729,30 @@ impl FxOp { } }); } + FxOp::Vignette { amount, midpoint, roundness, feather, target } => { + let (amt, mid, round, feather, target) = (*amount, *midpoint, *roundness, *feather, *target); + if !amt.is_finite() || !mid.is_finite() || !round.is_finite() || !feather.is_finite() || !target.iter().all(|c| c.is_finite()) { + return; + } + if amt.abs() < 1e-5 { + return; + } + let (w, h) = (img.w as f32, img.h as f32); + let aspect = w / h; + img.map_rgb(|c, x, y| { + let mut nx = (x as f32 + 0.5) / w * 2.0 - 1.0; + let ny = (y as f32 + 0.5) / h * 2.0 - 1.0; + // roundness 100 = circle; 0 = an ellipse following the frame; −100 = squarer + if round > 0.0 { + nx *= 1.0 + (aspect - 1.0) * round; + } + let p = if round < 0.0 { 2.0 + (-round) * 6.0 } else { 2.0 }; + // 0 at the centre, 1 at the corners + let d = (nx.abs().powf(p) + ny.abs().powf(p)).powf(1.0 / p) / 2f32.powf(1.0 / p); + let edge = crate::vfx::smoothstep(mid - feather * 0.5, mid + feather * 0.5, d); + dec(crate::vfx::lerp3(enc(c), target, edge * amt.abs())) + }); + } } } } diff --git a/crates/render/src/vfx/color.rs b/crates/render/src/vfx/color.rs index 9b0469d7..b6bfb1ea 100644 --- a/crates/render/src/vfx/color.rs +++ b/crates/render/src/vfx/color.rs @@ -189,34 +189,6 @@ pub(crate) fn limit(v: [f32; 3], max: f32, comp: f32, axis: u32) -> [f32; 3] { to_rgb(y, cb, cr).map(|q| q.clamp(0.0, max)) } -/// Vignette: darkens (negative Amount, towards Color) or lightens the frame edges. -pub fn vignette(img: &mut Image, e: &EffectInstance, cx: &FxCtx) { - let amt = fv(e, "amount", cx) / 100.0; - if amt.abs() < 1e-5 { - return; - } - let mid = fv(e, "midpoint", cx) / 100.0; - let round = fv(e, "roundness", cx) / 100.0; - let feather = (fv(e, "feather", cx) / 100.0).max(0.01); - let col = cv(e, "color", cx); - let target = if amt < 0.0 { [col[0], col[1], col[2]] } else { [1.0; 3] }; - let (w, h) = (img.w as f32, img.h as f32); - let aspect = w / h; - img.map_rgb(|c, x, y| { - let mut nx = (x as f32 + 0.5) / w * 2.0 - 1.0; - let ny = (y as f32 + 0.5) / h * 2.0 - 1.0; - // roundness 100 = circle; 0 = an ellipse following the frame; −100 = squarer - if round > 0.0 { - nx *= 1.0 + (aspect - 1.0) * round; - } - let p = if round < 0.0 { 2.0 + (-round) * 6.0 } else { 2.0 }; - // 0 at the centre, 1 at the corners - let d = (nx.abs().powf(p) + ny.abs().powf(p)).powf(1.0 / p) / 2f32.powf(1.0 / p); - let edge = smoothstep(mid - feather * 0.5, mid + feather * 0.5, d); - dec(lerp3(enc(c), target, edge * amt.abs())) - }); -} - /// Logo Cutout: removes a flat white/black/custom background by un-multiplying it — the alpha of /// a pixel is how far it is from the background towards the gamut edge, and the colour is /// recovered as if it had been composited over that background. diff --git a/crates/render/src/vfx/mod.rs b/crates/render/src/vfx/mod.rs index f6d88fc7..70c69ce2 100644 --- a/crates/render/src/vfx/mod.rs +++ b/crates/render/src/vfx/mod.rs @@ -461,7 +461,6 @@ pub fn apply(img: &mut Image, e: &EffectInstance, cx: &FxCtx) -> bool { // Adjust / Color / Image Control / Keying / Utility colour "lighting_effects" => color::lighting(img, e, cx), "video_limiter" => color::video_limiter(img, e, cx), - "vignette" => color::vignette(img, e, cx), "logo_cutout" => color::logo_cutout(img, e, cx), "ultra_key" => color::ultra_key(img, e, cx), "track_matte" => color::track_matte(img, e, cx), diff --git a/docs/architecture.md b/docs/architecture.md index e0a7885c..72e351db 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -283,7 +283,7 @@ file ──► codecs (MP4/MOV, MKV, audio) demux + decode, GOP-aware see Balance, Leave Color, Change to Color, Color Pass, Color Replace, Channel Mix, ASC CDL, Gamma Correction, Levels, Extract, Invert, Posterize, Alpha Adjust, Gaussian Blur and Directional Blur (and their legacy aliases), Camera Blur, Sharpen, Unsharp Mask, Crop, Edge Feather, Transform, - Horizontal / Vertical Flip, Mirror and Offset. When every enabled effect of a media clip is in + Horizontal / Vertical Flip, Mirror, Offset and Vignette. When every enabled effect of a media clip is in that set (unmasked, with finite parameters, and no Transform shrinking the picture below half size, which the CPU pre-filters), the plan hands the GPU the clip's source with the effects' parameters evaluated at that time: the source is drawn into an `Rgba32Float`