Commit Graph
282 Commits
Author SHA1 Message Date
vangel76andClaude Opus 5.5 c7060e2d75 Exposure: gamma 2.2 linear-light conversion, as After Effects
With Bypass Linear Light Conversion off, Exposure decoded and re-encoded
with the piecewise sRGB curve. After Effects 2026 renders (sRGB working
space, 32 bpc) of Offset 0.0005 / 0.002 / 0.02 / 0.1 on black measure
8 / 15 / 43 / 90, which a pure 2.2 power predicts (8.06 / 15.13 / 43.08 /
89.54) and the sRGB curve does not (1.65 / 6.59 / 38.68 / 89.04).

The effect now uses its own 2.2 power curve on the CPU and in the GPU
kernel; the shared colour functions and other effects are unchanged. As
before, the conversion applies whatever the working space, also a
linearised one. Negative values go through both curves mirrored (input
was clamped at 0 before), so defaults are an identity for 32-bpc values
and a negative Offset darkens past black without NaN.

New test against the AE values; existing Exposure tests still hold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:14:26 +02:00
vangel76andClaude Opus 5.5 70c1349cbc Black & White: Tint keeps the gray's luminosity, as After Effects
After Effects tints Black & White's gray like a Color blend: the tint colour's
hue and saturation at the gray's luminosity (weights 0.3 / 0.59 / 0.11, channels
outside 0..1 pulled back toward the gray). EffectCraft used the gray as HSL
lightness. Measured in AE 2026, Tint Color [1, 0.5, 0]: a red solid at Reds 10
(case 717) AE (43, 21, 0), EffectCraft was (51, 26, 0), now (43, 21, 0); a
yellow solid at the default sliders (gray 0.6, case 825) AE (255, 129, 2), now
(255, 129, 3); white stays white. The six sliders already matched AE on eight
colours (cases 816, 817). CPU and GPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:14:21 +02:00
vangel76andClaude Opus 5.5 960f41d50b Tritone: Rec. 601 luminance, as After Effects
After Effects' Tritone weighs the working-space values with Rec. 601 (0.299,
0.587, 0.114), as its Tint does; EffectCraft used Rec. 709. Case 718 (red solid,
Highlights [1,1,0.8], Midtones [0.6,0.2,0.2], Shadows [0,0,0.3], Blend 25):
AE (132, 23, 46), EffectCraft was (113, 16, 49), now (132, 23, 46). On a grey
ramp (case 815) the shadows / midtones / highlights mapping already matched and
still does within 1/255. CPU and GPU (fx_color op 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:13:41 +02:00
vangel76andClaude Opus 5.5 fb16d5573e Tint: Rec. 601 luminance weights, as After Effects
After Effects 2026 (sRGB working space, not linearised) maps red, green,
blue and 50% grey solids at Tint's defaults to 76, 150, 29 and 128/255:
Rec. 601 weights on the working-space values, not Rec. 709. CPU and GPU
kernel changed; tests pin the four greys within 1/255.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:12:50 +02:00
NetterSilverandClaude Haiku 5.5 26636bfb18 Make Fractal Noise evolution progress linearly
Fixes #1816

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 07:00:02 +00:00
sanyamsingh001andCodex 9bcf2e2dfd Use symmetric HexTile cell coordinates on CPU and GPU
Keep the existing regression and tolerance while preserving upstream
WireRemoval and test-service recovery changes.

Co-authored-by: Codex <codex@openai.com>
2026-10-18 21:48:26 +00:00
Anubhav-RaiandClaude Opus 5 3b9d243ac5 Shift Channels: After Effects' Take … From menu order, so 10 is Full Off (#1797)
The menu had an extra "Half On" at position 10, where After Effects has
"Full Off", so a project or script written for After Effects set a channel
to 50 % grey instead of turning it off, with no error: the RGB-split recipe
(three copies, each keeping one channel and setting the other two to Full
Off, blended with Add) rendered pastel instead of pure red, green and blue.

After Effects' ten options now come first, in its order, and "Half On" sits
last as an EffectCraft extra, so values 1 to 10 mean what they mean in After
Effects and nothing is lost. Instances saved with the old order keep the
option they chose: upgrade_instance already remaps popup values by label.

The GPU path keeps its own copy of the table, so it is reordered to match;
a GPU-vs-CPU parity case now covers the constant sources at the end of the
menu, where the two tables could drift apart unnoticed. Both paths clamped
the index to a hardcoded 10 and now use SHIFT_ORDER.len() - 1, so the clamp
cannot go stale if the list changes again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-18 23:34:25 +05:30
Brandon Thomas 681d99c0e7 Merge pull request #1731 2026-10-18 09:35:35 -04:00
Brandon Thomas a01f681551 Merge pull request #1704 2026-10-18 09:35:35 -04:00
Brandon Thomas fc3d228616 Merge pull request #1688 2026-10-18 09:35:34 -04:00
Brandon Thomas f16ef4a6b5 Merge pull request #1265 2026-10-18 09:35:32 -04:00
sanyamsingh001andCodex 2de015fe9f Fix HexTile centerline cell selection
Evaluate the third cube coordinate symmetrically to retain the intended centerline tie. Keep the existing pixel oracle and tolerance.

Scope the Mem fixture mutex unwrap allowance so the original strict CI can validate this base.

Co-authored-by: Codex <codex@openai.com>
2026-10-18 05:52:04 +00:00
MarekSpodBiedry 0e5b366574 Keep CC Simple Wire Removal between points A and B (#1724) 2026-10-17 14:33:06 +02:00
heojunfoandClaude Opus 5.5 ee5c9ac2dd Advanced 3D: Accepts Shadows Only draws just the shadow (#1691)
The Advanced 3D renderer folded Accepts Shadows (Off/On/Only) into a
bool, so a shadow catcher set to Only drew as an ordinary lit surface.
The material now carries shadows_only. Such a fragment draws black at
the strongest shadow a light casts on it, as Classic 3D does, and it
goes in the blended pass so what is behind it shows through. The CPU
shader and advanced3d.wgsl get the same branch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 13:31:08 +09:00
Matej Kozlovský 0fbe76b2bf Cryptomatte: CryptoAux enum instead of a positional bool; GPU test for every display mode (#473)
crypto_aux_image_with takes CryptoAux::{ColorsAndMatte, MatteOnly}, and
CryptoAux::for_display holds the rule for which displays read the ID
colours. A new GPU test checks every display x Matte Only against the CPU,
so the GPU fails the test if the shader starts reading RGB in a mode that
skips it (checked by mutation: forcing MatteOnly fails display 0).
2026-10-17 01:48:48 +02:00
Matej Kozlovský f8bd967861 gpu: honour wgpu env overrides in headless/CLI (with_env, WGPU_ADAPTER_NAME, WGPU_POWER_PREF)
GpuContext::request() now applies InstanceDescriptor::with_env() (WGPU_BACKEND,
WGPU_DX12_COMPILER, WGPU_VALIDATION, WGPU_DEBUG, ...), the same variables the
desktop app honours via egui-wgpu, and requests PowerPreference::from_env(),
defaulting to HighPerformance (an unknown WGPU_POWER_PREF logs a warning).

WGPU_ADAPTER_NAME (CLI/headless only; the desktop ignores it) picks the first
adapter whose name contains the trimmed value, case-insensitively. Empty or
blank counts as unset. Only the name is matched (backend via WGPU_BACKEND). A non-matching name is an
error that says so and lists each distinct adapter once as 'name (backend)', instead of wgpu::util::initialize_adapter_from_env's panic;
no adapters at all gets its own message.
2026-10-16 20:12:35 +02:00
Vikram Bhaskaran 31d74e268d Normalize cardinal Wave Warp directions to preserve CPU and GPU parity. 2026-10-17 03:12:36 +11:00
BFlat 908c946fc1 Merge pull request #1538 from guillehr2/black-white-artifacts-1463
Effects: Black & White no longer turns faint colour noise in shadows into blocks
2026-10-16 19:02:00 +07:00
BFlat c6f6f9b373 Merge pull request #1511 from MatejKozlovsky/fallback-parallel
Export: render in parallel once the GPU stops for good
2026-10-16 19:01:38 +07:00
BFlat 90e68eb6ab Merge pull request #1524 from MatejKozlovsky/require-gpu-tests
GPU tests: say why the GPU didn't start, and fail with EFFECTCRAFT_REQUIRE_GPU=1 instead of skipping
2026-10-16 19:00:52 +07:00
BFlat 1071e57dfd Merge pull request #1520 from MatejKozlovsky/frame0-failfast
GPU: stop drawing a frame once the device has failed
2026-10-16 18:11:16 +07:00
BFlat 0953011664 Merge pull request #1549 from MatejKozlovsky/upload-cache-dead-entries
gpu: upload cache drops textures of freed buffers on every insert
2026-10-16 18:10:41 +07:00
BFlat 74ed4dc423 Merge pull request #1383 from marcoarnulfo/fix/1381-generators-alpha
Effects: 4-Color Gradient keeps the layer's alpha with Blending Mode None (refs #1381)
2026-10-16 18:08:08 +07:00
bflatasticandClaude Opus 5.5 45eacf1b17 GPU: upload_buf keeps its own doc comment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 17:33:50 +07:00
Matej Kozlovský 74517a52da Cryptomatte: the GPU path skips the ID colours unless the Colors display reads them, and the CPU path keys the layer in place instead of copying it (#473)
Output is bit-identical (all displays, CPU and GPU). At 2560x1440 with 3 ranks and 2000 IDs on 8 cores the CPU effect drops from ~87-135 ms to ~44-54 ms and the GPU path's aux reduction from 38 to 8 ms for Matte, Preview and Matte Only.
2026-10-15 23:01:42 +02:00
Matej Kozlovský 77a8d6ae73 gpu: upload cache drops textures of freed buffers on every insert
Entries whose layer buffer was freed were pruned only once the cache went over its budget
(1.5 GiB), so an animated layer, which makes a new buffer every frame, left a dead 4K texture
per frame allocated until the cache filled up.
2026-10-15 10:19:42 +02:00
Guillem Hermida 749e810174 Effects: Black & White keeps faint colour noise in shadows faint (#1463)
Black & White offset each pixel's luminance by (hue weight - 0.5) times
its HSL saturation. HSL saturation is near 1 for any tinted near-black
pixel, so the code or two of colour noise in compressed footage's
shadows came out as bright and black blocks, and a 32-bpc overbright
such as (1.5, 0.5, 0.5) divided by zero and went black.

The gray is now the pixel's smallest channel plus its chroma (largest -
smallest channel) times the same hue-interpolated slider weight. Neutral
pixels keep their value, a pure hue becomes its slider's percentage
(Reds 40% turns pure red into 40% gray), noise moves the gray by no
more than its own size, and nothing divides. The CPU effect and the GPU
kernel change the same way.
2026-10-15 07:24:22 +02:00
Matej Kozlovský 217f0ffd59 GPU tests: print why the GPU didn't start, and fail with EFFECTCRAFT_REQUIRE_GPU=1 instead of skipping 2026-10-15 03:53:00 +02:00
Matej Kozlovský 295e2a3837 GPU: stop drawing a frame once the device has failed 2026-10-15 01:38:36 +02:00
Matej Kozlovský 2603a6f0e0 Export: render in parallel once the GPU stops for good 2026-10-15 01:30:54 +02:00
arnav-hiwarkar 68d928aff3 fix(render): preserve preceding effects in GPU Echo (#1120) 2026-10-14 13:42:59 +05:30
tylerjenningsw 8d00db7d90 GPU: test CC Particle Systems II against the CPU with a keyed Birth Rate (#1373)
The keyed Birth Rate comparison is shared (keyed_agree) and now runs on
CC Particle Systems II too. The same two histories bear 90 particles by
0.9 s at different steps: the GPU's particles match the CPU's, and each
state really came from the GPU.
2026-10-13 22:35:37 -04:00
tylerjenningsw d04f88750e GPU: the keyed Birth Rate test tells birth timing from birth count and checks the GPU ran (#1373)
The two histories now bear the same 180 particles by 0.9 s at different
steps (3/s from 0 to 0.5 s, and from 0.25 to 0.75 s). So a checkpoint
check by birth count alone fails the test, not only no check. A
test-only dispatch counter asserts each GPU state really came from the
GPU rather than the CPU fallback.
2026-10-13 21:59:03 -04:00
Marco Arnulfo 7df16a5e20 Effects: 4-Color Gradient keeps the layer's alpha with Blending Mode None (refs #1381) 2026-10-14 02:56:17 +02:00
tylerjenningsw 1cea7d774f GPU: test GPU particles against the CPU with a keyed Birth Rate (#1373)
With a Birth Rate keyed into a burst, the GPU's particles match the CPU
simulation through the burst and after it. A second history with the
same system key, whose burst starts later (so the same ids are born at
other steps), isn't resumed from the first history's GPU checkpoints.
2026-10-13 20:45:21 -04:00
tylerjenningsw bb0e2b57db CC Particle World: Birth Rate decides the births of its own time, so a burst lives on (#1373)
The simulation runs from layer time 0, but it used the Birth Rate of the
rendered frame for every step. A rate keyed from 3 down to 0 simulated
no births at all once it reached 0, so the burst's particles vanished
that frame although their Longevity had not run out. A ramped rate was
simulated as if its current value had always applied.

Each step now samples Birth Rate at its own layer time through
EffectHost::param_at (with the effect's own index). Without such a host
the current value applies throughout, as before. Particles already alive
keep moving and ageing whatever the rate. The carry and particle ids
continue across rate changes.

Birth Rate is left out of the simulation cache key, so an animated rate
no longer restarts the simulation every frame. In its place:

- The CPU state keeps a hash of the rates it was stepped with (hist). A
  checkpoint is resumed only when that matches the current history, so
  moving an earlier key is never served from a stale checkpoint.
- The GPU gets the birth schedule of the sampled rates (births_at). Its
  checkpoints record which births they hold, and are resumed only when
  the request's births before that step are the same.

A constant Birth Rate gives exactly the particles it did. CC Particle
Systems II and CC Mr. Mercury keep their constant-rate simulation.
2026-10-13 20:45:20 -04:00
tylerjenningsw 3dca185958 GPU: test that the frame after a rejected view composites on the GPU like the CPU (refs #1319) 2026-10-13 14:12:16 -04:00
tylerjenningsw 864b9e4ede GPU: no texture of a failed frame returns to the pool, even one out or waiting on another encoder (refs #1319) 2026-10-13 14:12:15 -04:00
tylerjenningsw 87d28ac6fe GPU: a frame the device rejected isn't reported as out of memory (refs #1319) 2026-10-13 13:43:33 -04:00
tylerjenningsw 1b3a70a7bc GPU: discard_kept is public like clear_uploads, so wasm builds don't flag it unused (refs #1319) 2026-10-13 13:43:33 -04:00
tylerjenningsw babdcd3b9f GPU: the frame guard contains validation errors and drops the failed frame's textures (refs #1319) 2026-10-13 13:36:04 -04:00
tylerjenningsw ec29d78ca2 GPU: working textures are labelled with their size (refs #1319) 2026-10-13 13:25:42 -04:00
Matej Kozlovský 9a202b133a Render: effect stacks keep the cover's pixel-grid phase, only known-margin stacks skip the cover, and displacement and Repeat Edge Pixels get the room the cover gave them (#1205) 2026-10-13 15:53:10 +02:00
Vikram Bhaskaran fb715d9015 Render: drop the blanket layer cover from effect stacks; effects pay only what they need (#1205)
Since #659 every text or shape layer with an enabled video effect grew its
effect buffer to the comp-sized layer rectangle before the stack ran, so
glow and blur — which only need their own margins — allocated a 1920x1080
RGBA32F texture per layer per frame in flight (~5 GB peak VRAM in parallel
export, measured on an RTX 3090).

Effects that actually place pixels outside the painted content already
grow the buffer themselves by exactly what they need (CC Tiler, CC Smear,
CC Mosaic sharp via layer_cover_pad / Buf::pad), on CPU and GPU. The
blanket target.cover(layer_size) in Renderer::run_effects_on, the
FxTarget::cover trait method with its CPU default, and the GPU
GpuTarget::cover texture allocation are removed; Buf::cover/cover_plan
stay as the effects-crate helpers they were designed as.

The #659 regression tests (tiling across the layer region, centred-shape
edge pinning) and the render/effects/gpu suites pass unchanged.
2026-10-14 00:32:56 +11:00
Vikram Bhaskaran 2720ae5fe2 Wave Warp: cover the Top/Bottom edge pinning paths end to end (#1181)
The pinning regression only exercised All Edges (and Left Edge in the CPU
unit test), so the reported 'does not work with Top/Bottom Edge' had no
coverage to catch or clear it. This holds the pinned first/last row in a
CPU test at Direction 90, and adds CPU/GPU parity cases for Top (4),
Bottom (6), diagonal directions, and single-edge pinning on shape layers.
CPU pinning verified correct on main: the guards in dst_wave_pin/wave_pin
agree; the gap was that neither edge path was tested.
2026-10-13 23:40:32 +11:00
Brandon Thomas 9aabb5da4f Merge pull request #688 from MatejKozlovsky/gpu-resident-effects 2026-10-13 04:33:22 -04:00
Brandon Thomas 5281171282 Merge pull request #1204 from marcoarnulfo/fix/adjustment-track-matte 2026-10-13 04:29:49 -04:00
Brandon Thomas 0cfb563764 Merge pull request #1183 from MatejKozlovsky/cryptomatte-rank-speedup 2026-10-13 04:28:58 -04:00
Marco Arnulfo 3095217ce8 Track matte on an adjustment layer limits where its effects show (fixes #1201) 2026-10-13 08:42:14 +02:00
Kristian MyramandClaude Haiku 5.5 98796a29b8 #1063: the gradient ramp matches the CPU on the GPU, including transparent regions
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-13 02:48:46 +02:00