* render, gpu: adjustment layers composited on the GPU An adjustment layer anywhere at a time sent the whole frame to the CPU renderer, so GPU rendering did nothing for the frames under one. A full-frame adjustment layer at 100 % opacity, Normal, unmasked and with only effects the GPU stage runs is now a PlanStep::Adjust: its effects run in the effect stage on the accumulator (the composite of the tracks below) and the result replaces it before the tracks above are drawn. Every other adjustment layer keeps the whole-frame CPU fallback. The export renderer takes Composite plans without transitions; frames with a Push still go to the CPU there, as before. perf.stats gpu gains adjustments / cpuAdjustments. * docs: adjustment layers on the GPU compositor in parity and performance hardware-parity.md gains an Adjustment layers row; performance.md gains the main-against-branch export timings with an adjustment layer. * render, gpu: adjustment layer review fixes - is_cpu_frame and plan_frame now ask the same adjustment_ops (evaluated at the render scale, which is_cpu_frame takes from the RenderOptions): a Transform that shrinks the frame no longer takes a pooled export renderer only to be rendered on the CPU and counted as a GPU frame. - FxOp::eval leaves a Transform with its shutter angle on (motion blur) to the CPU; the GPU drew it sharp, on clips and adjustment layers. - The effect stage's texture pool spans the whole composite frame, so an adjustment step's working textures are reused instead of made again every frame. Composite plans honour resolve = false (export). - ExportRenderer::render hands frames with an adjustment layer back to the CPU when the device has no effect stage, instead of compositing them on the CPU and uploading the result to read it back. - adjustment_covers_output checks the full-frame geometry without building the coverage image. - The GPU adjustment test also runs without an effect stage. * render, gpu, export, ui: plan adjustment layers for the device's caps plan_frame and is_cpu_frame take plan::DeviceCaps (how large a frame the device runs adjustment layers on; none without an effect stage), so a frame the compositing device can't adjust becomes a CPU image on the thread that plans it, never on the UI thread or inside a renderer slot. - Monitor: the caps are part of the frame key (Target::SequencePlan(seq, caps)), so a plan made for another device is never reused. - Export: FrameRenderer::caps is required; the renderer pool plans with the smallest caps of its renderers before it takes one. - The compositor's own CPU fallback stays as a safety net for a plan made for other caps; the tests check that nothing reaches it. - Main's own-shutter Transform check replaces the duplicate guard in gpufx. Tests: a Push under an adjustment layer exported on the GPU against render_sequence (forward and reversed, scales 1 and 0.5); routing without an effect stage in the export pipeline and in the monitor's frame server; GPU parity against render_sequence with colour and alpha for a partly transparent canvas, stacked adjustment layers, an empty canvas, a nested sequence below and one inside a nest, at scales 1 and 0.5; caps boundaries and is_cpu_frame agreeing with plan_frame. * gpu: end a refused effect image's frame; count steps once drawn effect_image began an effect stage frame and returned without ending it when the stage refused the job, so the stage stayed mid-frame and kept its working images. The compositor's step counters are added once the whole frame is drawn on the GPU, so a frame that falls back half way no longer counts the steps it threw away.
6.4 KiB
Hardware parity
Last reviewed: 2026-10-10 · Last updated: 2026-10-23 · Change: minor (adjustment layers on the GPU compositor) · Target: Adobe Premiere Pro 2026 (26.5.2)
Each hardware feature Premiere uses, per platform, against ours. Implementation detail lives in
crates/platform/README.md (decode / encode backends, the one
crate allowed unsafe, ADR 0001), the GPU compositor in
architecture.md, and timings in performance.md.
Hardware paths are always optional: our software codecs are the tested fallback, and a hardware
decoder that fails mid-stream hands over to software (HybridDecoder).
Premiere's side is from Adobe's published GPU and hardware-acceleration documentation and release notes (Premiere does not run on Linux).
Hardware decode
| Codec / profile | Premiere macOS | Ours macOS (VideoToolbox) | Premiere Windows | Ours Windows (Media Foundation / D3D11) | Ours Linux (NVDEC, VA-API) |
|---|---|---|---|---|---|
| H.264 8-bit 4:2:0 | yes | yes | Intel, NVIDIA, AMD | yes (Baseline / Main / High) | yes (NVDEC; VA-API Intel / AMD / Mesa) |
| H.264 10-bit / 4:2:2 | Apple silicon | yes where the chip decodes it | Intel; NVIDIA Blackwell (MXF too) | no (declined; no software fallback, G3) | no |
| HEVC Main / Main 10 4:2:0 | yes | yes | yes | yes | yes (NVDEC 8/10; VA-API Main / Main 10) |
| HEVC 4:2:2 10-bit | Apple silicon | yes where supported | Intel; NVIDIA Blackwell | no | no |
| VP9 profile 0 / 2 | — | software | — | yes | software (VA-API VP9 not yet) |
| AV1 main 8 / 10 | — | software | yes | yes | software |
| ProRes | Apple silicon (M1 Pro / Max and later) | software (fast: 318 fps) | software | software | software |
| Field-coded H.264 | yes | no | yes | no | no |
Measured (cargo xtask bench --hw off|auto): M4 Pro, CPU per 2160p frame H.264 119 → 4.2 ms,
HEVC 86 → 3.7 ms, 4K plays with no dropped frames at Full; Intel Iris Xe VA-API H.264 2160p
417 → 11.4 ms, HEVC Main 10 2160p 212 → 18.4 ms. Every decoded picture is read back to the CPU
and re-uploaded to wgpu (no zero-copy yet), which Premiere avoids.
Hardware encode
| Codec | Premiere macOS | Ours macOS | Premiere Windows | Ours Windows | Ours Linux |
|---|---|---|---|---|---|
| H.264 8-bit | yes | yes (VideoToolbox, opt-in, no B-frames; takes the RGBA pictures and converts them itself) | Intel QSV, NVENC, AMD | NVENC only (opt-in) | NVENC only |
| H.264 10-bit / 4:2:2 | yes (Apple silicon) | no | Intel | no | no |
| HEVC Main 8-bit | yes | yes (hardware-only format) | QSV, NVENC, AMD | NVENC only | no |
| HEVC Main 10 / HDR (PQ, HLG) | yes | no (tone-mapped to 8-bit SDR) | yes | NVENC yes (HDR10 SEI, mdcv / clli) |
no |
| ProRes | Apple silicon | software only | software | software | software |
| AV1 | — | no | via plug-ins / newer GPUs | no | no |
Measured: VideoToolbox H.264 1080p25 encode 200 fps on M1; a 9:29 timeline exported in 311 s against 793 s with our software encoder (SSIM 0.990). NVENC HEVC round trip 48.9 dB luma PSNR (8-bit), 71.1 dB (10-bit) on an RTX 5060.
GPU rendering
| Feature | Premiere (Mercury Playback Engine: Metal, CUDA, OpenCL) | Ours (wgpu: Metal, D3D12, Vulkan) | % |
|---|---|---|---|
| Compositing, blend modes, transforms | GPU | GPU (#32), CPU compositor is the oracle | 90% |
| Accelerated video effects | ~82 of ~92 effects marked Accelerated (reference list plan/premiere/10-effects-list.md) |
35 effect ids (render::gpufx::GPU_EFFECTS): colour, levels, blurs (Bokeh Blur included), sharpen, crop, transform, flips, vignette, video limiter, ASC CDL, channel mix, Lumetri basic / creative / vignette |
~40% |
| Lumetri curves, wheels, HSL secondary | GPU | CPU | 0% |
| Keys (Ultra Key), masks, distortions, transitions | GPU | CPU (masks have WGSL parity tests, not in the live path) | 10% |
| Adjustment layers | GPU when every effect on them is accelerated | GPU for a full-frame one at 100 % opacity, Normal, unmasked, with only GPU effects (PlanStep::Adjust): 4.0–5.0× faster GPU exports under one; any other one renders the whole frame on the CPU |
60% |
| Export rendering on the GPU | yes | yes (#421; Export ▸ GPU Rendering, Auto): 2.4× (1080p) to 3.2× (4K) faster on effects-heavy timelines | 80% |
| Thumbnails on the GPU (26.0) | yes | CPU | 0% |
| Software adapter fallback | warns | silently renders everything on the CPU (#632) | — |
| Intel integrated graphics | supported | start-up crash on Intel UHD (#512) | — |
Devices and I/O
| Hardware | Premiere | Ours | % |
|---|---|---|---|
| Audio interfaces | CoreAudio, ASIO, WASAPI; multichannel mapping | cpal (CoreAudio, WASAPI, ALSA); no ASIO; device reports #605, #602 | 60% |
| Voice-over microphone | yes | yes (punch-in); macOS privacy declaration missing (#659) | 80% |
| External video monitoring (Mercury Transmit, Blackmagic DeckLink, AJA) | yes | no | 0% |
| Second computer monitor full-screen playback | yes | full screen inside the app window; no separate-display output or floating windows on other screens (#466) | 40% |
| HDR / EDR display | macOS EDR, Windows HDR | no (SDR display of HDR sequences) | 0% |
| Control surfaces (EUCON, Mackie HUI / MCU) | yes | no | 0% |
| LTC timecode input | yes | no | 0% |
| Tape / deck control | legacy | no | n/a |
Summary
Hardware dimension: ~45%, 120–200 h. Ahead of Premiere: hardware decode on Linux (VA-API, NVDEC) and FreeBSD builds. Behind, by user impact: zero-copy upload; GPU effects beyond 35 (Lumetri curves / wheels / HSL, keys, masks, transitions); Quick Sync and AMD encoders on Windows; VideoToolbox Main 10 HDR encode; 10-bit / 4:2:2 decode off macOS; HDR display; external video I/O and control surfaces (need hardware we don't own). Calibration: one decode backend ~3–5 h, one encoder ~4–8 h (target-app-parity.md).
Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-23 | minor | Adjustment layers row: full-frame, opaque, Normal ones with GPU effects run on the GPU compositor |
| 2026-10-10 | major | Created from ROADMAP.md's performance-and-hardware row and crates/platform/README.md; added Linux NVDEC (#549), GPU export and Lumetri on the GPU (#421), Premiere's per-platform hardware list, devices and I/O |