Commit Graph

21 Commits

Author SHA1 Message Date
Skyler Lehmkuhl aa7d3a3bf4 export: cache the static background + bilinear video, add render profiling
The export render bucket was dominated by re-rendering the static document
background through Vello every frame and by nearest-sampling the video on
upscale.

- Background cache: render the (static) background through Vello once, snapshot
  the composited HDR accumulator, and restore it with a single texture copy on
  every later frame instead of a Vello render + sRGB-convert + composite (+2
  submits). Invalidated on resize. background-render 3.6ms -> 0.56ms (1080p),
  7.5ms -> ~0.5ms (4K).
- blit_straight now uses the bilinear sampler — video frames are scaled to the
  output size, and nearest made that blocky. Fixes export and live preview.
- LB_RENDER_PROFILE: gated per-frame timing split (build/decode vs composite/
  upload vs srgb, and background vs layers) used to find all of the above. Kept
  as a debug aid for the remaining decode stages.

Net: export render ~12.8ms -> ~7.4ms/frame on a 1080p video clip.
2026-06-25 23:30:51 -04:00
Skyler Lehmkuhl 5844a0f070 Composite grouped/nested video on the GPU path
Imported video is a Group[Video, Audio] that rendered as a Vello-baked
Vector layer, re-uploading the full frame to Vello's image atlas every
frame (~17ms/frame at 1080p, hitting playback and export alike). Extract
video frames out of the Group/clip scene recursion into
VideoRenderInstances so they composite via the GPU Video path; mixed
video+vector containers fall back to Vello (correct, unaccelerated).

Also route video through hardware sRGB decode: upload raw sRGB bytes to an
Rgba8UnormSrgb texture and blit with a non-unpremultiplying shader variant
(blit_straight), removing the per-frame per-pixel CPU sRGB->linear pass.
Add an F3 GPU-timestamp timer and a per-frame video texture cache.

Drops the live composite of a 1080p video from ~17ms to ~2-3ms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:38:30 -04:00
Skyler Lehmkuhl 83057b754a Clean up build warnings
Resolve all compiler warnings across daw-backend, lightningbeam-core, and
lightningbeam-editor:

- Delete dead code: the superseded CPU raster tools in raster_tool.rs
  (EffectBrush/Smudge/Gradient/Transform/Warp/Liquify/Selection — replaced by
  the GPU path), plus orphaned helpers and never-read struct fields.
- Mechanical fixes: drop unused imports/variables/mut, underscore unused params,
  `drop(&x)` -> `let _ = x`, deprecated egui::Rounding -> CornerRadius, snake_case
  rename, elided-lifetime Cow<'_, [u8]>.
- Keep the WIP CSS theming system (theme.rs/theme_render.rs) under
  #[allow(dead_code)] rather than deleting it.

Editor checks warning-free; 293 core tests pass.
2026-06-21 16:48:59 -04:00
Skyler Lehmkuhl 4dc937f9c0 Onion tint: screen-blend instead of multiply (so outlines tint too)
Multiplicative tint left blacks black, so outlines (the main thing to ghost in line
art) never picked up the warm/cool color. Switched the canvas-blit tint to a screen
blend (out = base + tint - base*tint): black → tint color, white unchanged, and a
clean no-op at tint=(0,0,0) for all normal blits. Reverted the default .w slots to 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 23:06:05 -04:00
Skyler Lehmkuhl 53cae1bfe5 Onion skinning (raster): toggle + tinted ghosts of the active layer
- OnionSkinSettings (editor view state): enabled, frames_before/after (default 2/2),
  opacity (0.35), warm past / cool future tints, linear falloff. Threaded App →
  SharedPaneState (gated off during playback) → VelloRenderContext.
- Toggle: View ▸ Onion Skinning + the `O` shortcut (AppAction::ToggleOnionSkin).
- Tint: packed an RGB multiply into the canvas-blit matrix uniform's unused .w slots
  (1,1,1 = no tint for all normal blits); BlitTransform::with_tint. Shader multiplies.
- Render: for the ACTIVE raster layer only, blit the N neighbouring keyframes (full
  texture if resident, else the low-res proxy — uploaded on demand) tinted + faint,
  composited behind the current frame. Off during playback.

Next: a settings panel (frame count/opacity) and vector-layer ghosts.
2026-06-20 23:05:57 -04:00
Skyler Lehmkuhl a35cc6fa9f Bilinear-sample upscaled raster proxies (smooth, not blocky)
The canvas blit used a nearest sampler, so the upscaled low-res proxy looked
blocky. Added a Linear sampler + `CanvasBlitPipeline::blit_smooth`; the raster
render uses it only for the proxy path (full-res canvas stays nearest/crisp). The
bind-group layout already declares the canvas texture filterable, so no layout
change was needed.
2026-06-20 21:14:47 -04:00
Skyler Lehmkuhl 1bfd09f151 Phase 3a-3: low-res image proxy for cold-scrub raster frames
Scrubbing onto a paged-out raster keyframe flashed blank for the 1-2 frames its
full pixels took to page in. Now a low-res proxy is shown in that gap.

- core: `MediaKind::RasterProxy` (id derived from the keyframe id via
  `raster_proxy_media_id`); `brush_engine::encode_raster_proxy_png` downscales a full
  RGBA buffer to a ≤192px-long-edge PNG. Save writes a proxy beside each resident
  frame's full PNG (paged-out frames keep their existing proxy row, like the full).
  Load eagerly decodes proxies (small) into `RasterKeyframe::proxy`.
- editor: a separate `proxy_layer_cache` in the GPU brush (own recency LRU, budget 64
  since each is ~1/100th a full frame) + `ensure_proxy_texture`/`get_proxy_texture`.
  The raster render, when the full texture isn't resident, blits the proxy mapped to
  the keyframe's FULL logical dims so it upscales via the sampler. F3 VRAM figure now
  includes proxy textures.

When the full pixels land (async fault-in), the full path takes over automatically.
Proxies only exist after a save+reload; freshly-painted unsaved frames stay resident
so they need none.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:05:46 -04:00
Skyler Lehmkuhl 17d7395229 Phase 3c: bound the raster-layer GPU texture cache + show VRAM in F3
`raster_layer_cache` (one ~w·h·16-byte Rgba16Float CanvasPair per keyframe) had no
size cap — scrubbing a long timeline grew VRAM without bound (~33 MB/frame at 1080p),
the largest unbounded consumer. Added a recency LRU (RASTER_LAYER_CACHE_MAX = 12):
`ensure_layer_texture` bumps the frame to most-recent and evicts the oldest past the
budget; the shown frame (and any rendered this pass) is always most-recent so it's
never the victim. Evicted textures re-upload cheaply from the resident/faulted-in
pixels on revisit. `remove_layer_texture` keeps the LRU in sync.

F3 debug overlay now reports the tracked VRAM (raster cache MB + frame count), pushed
from the GPU brush whenever the cache changes (wgpu exposes no allocator query).
2026-06-20 19:15:16 -04:00
Skyler Lehmkuhl 318720f89d Fix gamma handling and improve brush canvas performance
Color correctness:
- Unpremultiply before the sRGB OETF on the display and export blits;
  encoding premultiplied color corrupted antialiased/transparent edges.
- Tag exported video as full-range BT.709 (matrix/primaries/transfer).
- Run perception effects (invert, brightness/contrast, hue/saturation)
  in gamma space to match standard editors.
- Interpolate gradients in gamma space across the raster and vector paths.
- Render effect thumbnails in the same linear space as the live pipeline.

Brush performance:
- Store the raster canvas as Rgba16Float (no shadow banding from 8-bit
  linear), with an incremental per-tile ping-pong sync replacing the
  per-frame full-canvas copy.
- Do the linear->sRGB readback conversion on the GPU and reuse a cached
  scratch texture, dropping a ~110ms-per-stroke CPU decode.

Cleanup:
- Single COLOR_WGSL prelude and shared CPU sRGB scalars instead of ~8
  duplicated copies of the transfer functions.
- Shared compute-pipeline builder; smudge folded onto the tile-sync path.
2026-06-16 08:32:39 -04:00
Skyler Lehmkuhl 78e296ffde Improve export performance 2026-03-09 13:39:56 -04:00
Skyler Lehmkuhl 09856ab52c Refactor tools and fix bugs 2026-03-08 18:44:32 -04:00
Skyler Lehmkuhl 0d2609c064 work on raster tools 2026-03-07 16:55:38 -05:00
Skyler Lehmkuhl a628d8af37 Shape tools 2026-03-07 07:27:45 -05:00
Skyler Lehmkuhl 4386917fc2 Implement transform tool for raster 2026-03-07 02:12:55 -05:00
Skyler Lehmkuhl bff3d660d6 Improve smudge tool 2026-03-06 06:03:33 -05:00
Skyler Lehmkuhl f2c15d7f0d brush fixes and improvements 2026-03-05 20:24:38 -05:00
Skyler Lehmkuhl 63a8080e60 improve painting performance 2026-03-04 15:20:39 -05:00
Skyler Lehmkuhl 16b0d822e3 painting fixes 2026-03-04 14:40:08 -05:00
Skyler Lehmkuhl 759e41d84a fix color space for raster editing 2026-03-04 11:25:15 -05:00
Skyler Lehmkuhl 885c52c02a organize raster buffers better 2026-03-02 11:24:12 -05:00
Skyler Lehmkuhl da02edb9f5 Move raster editing to GPU 2026-03-01 15:41:28 -05:00