Commit Graph
15 Commits
Author SHA1 Message Date
vicrodh d99419f22d fix(renderer+ux): frame-liveness watchdog (#558), dup-add button (#655)
- #558: a backend can be alive yet wedged (zero presented frames forever
  on legacy stacks). Vendored femtovg counts presented frames; a watchdog
  8s after window-ready re-arms the renderer sentinel and restarts, so
  the existing ladder degrades wgpu -> alt adapter -> GL -> software on
  its own instead of stranding the user on a blank window.
- #655: 'Add only new tracks' stays enabled with all-dupes (adds zero
  and closes) instead of disappearing as the primary action.

km
2026-07-25 12:05:27 -06:00
vicrodh 2d747368bf fix(renderer): invalidate layer/image caches on canvas reset
After a Wayland surface re-creation (tray hide/show, miniplayer cycle),
reset_canvas swapped in a fresh canvas but kept graphics_cache and
texture_cache entries whose textures belong to the OLD canvas's image
store. A cache-rendering-hint layer (Sidebar/HeaderBar/NowPlayingBar
since e3257631) then blits a dangling image id: the subtree goes
invisible while layout and hit-testing keep working — exactly the
reported 'sidebar content does not render' after a
miniplayer->theme->sidebar journey. set_window_adapter and
clear_graphics_context already clear both caches; reset_canvas now does
too (layers re-render, images re-upload once per re-creation).

km
2026-07-19 19:11:51 -06:00
vicrodh 1adf4e6f9d fix(renderer): partial-render blockers from adversarial review (#617)
B1: femtovg Canvas::set_size queues SetRenderTarget(Screen) without
updating current_render_target — the scene set_render_target() was
silently undone and the Copy blit overwrote the frame with the empty
persistent texture (black window on the first env-gated frame).
Root-fixed in vendored femtovg (keep the field in sync with the queued
command — upstream-able) + re-assert the scene target after the
notifier block's set_size.

B2: BoxShadow/Transform/Opacity/Layer/Clip bypass the proxy's
filter_item and re-render every frame (core item_rendering.rs:209-217)
— with a multi-rect dirty region they re-blended over uncleared pixels
in the gaps between rects (progressive smear). Collapse the dirty
region to its single bounding rect so filter, scissor and clears all
agree on one rect.

M1: visualize outline now strokes on the swapchain after the blit
(drawn into the persistent texture it accumulated).

Also: case-insensitive env parsing; stale-comment corrections.

km
2026-07-19 16:08:02 -06:00
vicrodh ed897d8c14 feat(renderer): femtovg partial rendering, stages 2-4 (#617)
Stage 2 (frozen-blit): render the scene into a persistent femtovg image
target (image passes use LoadOp::Load — the buffer-age-infinite backing
store the wgpu swapchain cannot provide) and blit it whole to the
swapchain with CompositeOperation::Copy (no prior clear; exact alpha for
the transparent miniplayer). GLItemRenderer::new now takes the initial
render target so layer passes restore to the scene texture, not Screen.
Env-gated via SLINT_FEMTOVG_PARTIAL_RENDERING (default off = current
behavior; "frozen-blit" = this stage only).

Stage 3 (dirty regions): wrap GLItemRenderer in the core PartialRenderer
proxy and repaint only the dirty bounding rect of the persistent texture
(ReusedBuffer semantics). Canvas-level scissor on the main pass only,
set after the canvas reset — never a wgpu-pass-level scissor (it would
clip persistent layer/shadow clears and smear stale texels). Per-dirty-
rect clear_rect as the scoped clear (it ignores canvas scissor by
design). "visualize"/"log" modes, mirroring SLINT_SKIA_PARTIAL_RENDERING.

Stage 4 (lifecycle): mark_dirty_region override (popup-close repaints;
core default is a no-op), free_graphics_resources forwarding,
partial-cache clear on set_window_adapter/reset_canvas,
force_screen_refresh on texture recreate (resize/DPR/UI-scale), on
transformed frames that bypass the persistent texture, and on the
metrics collector's FullSpeed mode.

cargo check clean. Full behavior unchanged when the env gate is off.

km
2026-07-19 15:18:48 -06:00
vicrodh efc2db6dbb feat(renderer): femtovg partial-render scaffold (stage 1)
Inert scaffold for #617 partial rendering in the vendored femtovg-wgpu
renderer. Mirrors the Skia renderer: add an ItemTransform to the render
State (logical space), accumulate it in translate/rotate/scale
(pre_translate/pre_rotate/pre_scale), implement current_transform() (the
core ItemRenderer trait default is todo!()), and add
impl ItemRendererFeatures { SUPPORTS_TRANSFORMATIONS = true }.

Nothing consumes current_transform() yet — the core PartialRenderer proxy
is wired in a later stage — so this is behavior-neutral. Not yet compiled;
validates at the stage-2 build.

cc
2026-07-19 13:39:35 -06:00
vicrodh 80088b6a0b fix(renderer): keep the app alive when the wgpu surface goes Outdated (#558)
At a non-default UI scale, SLINT_SCALE_FACTOR changes the physical surface
size and the first frames race the winit resize/scale-factor event that
reconfigures the swapchain, so get_current_texture() returns Outdated. The
vendored femtovg-wgpu backend reconfigured and retried once, then propagated a
second Outdated via `?`, which killed the event loop and left the app unable
to start at any interface size other than default. Treat a persistent Outdated
like the #540 timeout: skip the frame and back off briefly; the next
resize/redraw reconfigures cleanly. wgpu now survives the scale race without
depending on the degradation ladder falling back to GL.

cc
2026-07-13 13:11:12 -06:00
vicrodh 99cf738a4c fix(scroll): boost Wayland trackpad scroll speed in the vendored Flickable
Trackpad PixelDelta events arrive divided by the HiDPI scale factor, making trackpad scrolling far slower than other apps on scaled Wayland desktops. In FlickableData::scroll_delta, distinguish line-based wheel deltas (always exact multiples of 60) from pixel-precise trackpad deltas and apply a 2.75x factor to the latter only; wheel and fling scrolling are unchanged. Resolves #588.

cc
2026-07-13 04:44:08 -06:00
vicrodh 39304dbef5 Merge bugfix/hyprland-wgpu-surface-timeout into pre-release
cc
2026-07-07 09:36:08 -06:00
vicrodh e5fcb9d1af fix(text): load Korean TTC faces the macOS Skia renderer refused
Vendor i-slint-renderer-skia 1.16.1 with a second-chance typeface
workaround: skia bug 310510989 makes new_from_data fail for TTC faces
at index > 0 on macOS, and for AppleSDGothicNeo.ttc — which packs
every weight at index > 0 — the upstream read/write-fonts rebuild is
ALSO rejected by CoreText, so draw_glyph_run silently dropped every
Korean glyph run at non-regular weights (Japanese survived because
Hiragino ships one file per weight, always index 0). Resolve the same
face through CoreText by family name (typographic name preferred,
localized names resolve too) + OS/2 weight; the match points at the
same installed file so parley's glyph ids stay valid, enforced by cmap
spot checks that reject a mismatching face rather than draw wrong
glyphs. Probe-verified on the Mac Mini: matched face returns identical
glyph ids for U+C0AC across w500/600/700.

cc
2026-07-05 22:36:48 -06:00
vicrodh 7401d2c3fd fix(text): always draw the first line under overflow: elide
Vendor i-slint-core 1.16.1 with a one-rule patch in sharedparley's
line culling: with overflow: elide, every line whose bottom edge
exceeded max_height was dropped — INCLUDING the first one, eliding the
text to literally nothing. CJK fallback fonts report line metrics
taller than snug fixed-height boxes (Hiragino at 14px measures ~21px
inside TrackRow's 20px title line), so on macOS every CJK track title
rendered blank while Latin titles fit; Linux survived because Noto's
metrics fit the box. Root-caused with a headless render matrix on the
Mac Mini: the verbatim TrackRow structure reproduced the blank title,
removing elide rendered it, and the patched core renders all variants.
The first line still receives the ellipsis treatment as the last
visible line.

This is the real #543 mechanism. The earlier femtovg render_glyph
retry (3a1c367d) addressed a different, hypothesized layer and stays
as harmless defense in depth.

Fixes #543

cc
2026-07-05 18:53:02 -06:00
vicrodh 3a1c367d1a fix(text): render CJK glyphs at non-regular weights on macOS
Vendor femtovg 0.23.2 with a targeted patch: the swash raster path can
fail to scale some variable fonts at a non-default variation instance
(the CFF2-based CJK system fonts on modern macOS), and femtovg cached
those glyphs as permanently missing — so track titles and any other
text at medium/semibold/bold weight rendered blank for CJK while
regular weight (empty coords) worked. render_glyph now retries the
glyph at the font's default instance before giving up: worst case the
glyph draws at regular weight instead of not at all. Fonts and
instances that already render are untouched.

Fixes #543

cc
2026-07-05 08:23:17 -06:00
vicrodh 6bf4bb2414 fix(renderer): treat wgpu surface-acquire timeout as a skipped frame
Issue #540: under Hyprland VFR a static screen or hidden workspace
stops compositor frame callbacks, wgpu's get_current_texture() times
out, and the vendored femtovg-wgpu backend retried once then
propagated the error — killing the event loop and the app mid-
playback.

A surface-acquire timeout is transient by definition: return a
FrameSkipped sentinel instead, which the renderer treats as nothing-
to-render, and back off exponentially (250 ms to 2 s) so repeated
redraw requests do not keep blocking the UI thread on a parked
compositor. The first successful acquire resets the cooldown. A
one-time stderr notice aids field diagnosis. Also give the vendored
crate an empty [workspace] table so it can be cargo-checked
standalone.

cc
2026-07-04 17:26:04 -06:00
vicrodh fa3ee1e410 fix(fonts): pre-register macOS CJK fallback families in vendored i-slint-common
fontique's CoreText-based Han-script fallback fails to resolve a family on
modern macOS (the suggested PingFang is not always in the scanned family
map), so Japanese kanji rendered blank while kana worked. Vendor
i-slint-common 1.16.1 and pre-register Hiragino / PingFang / Apple SD
Gothic Neo / Arial Unicode MS in the fallback map at collection creation
(Japanese-biased default; the map takes priority over the CoreText query).
macOS-only cfg; Linux keeps its working fontconfig fallback. Type-checked
against aarch64-apple-darwin.

cc
2026-07-03 10:00:31 -06:00
vicrodh fe111c3ff6 feat: renderer tier auto-detect with Settings override and auto-revert
Weak-GPU hardware (Raspberry Pi 4 / v3dv, Haswell / hasvk) exposes a
real Vulkan adapter, so the old binary wgpu-or-software detection handed
it the slowest possible path: femtovg-wgpu over an immature Vulkan
driver. Mesa's GL path is the fast one on that class of hardware.

- Three-tier chain: wgpu -> femtovg GL -> software. Auto-detect
  classifies adapters (weak-driver markers incl. hasvk, integrated-on-arm,
  tiny texture limits); adapters only reachable through wgpu's GL backend
  never select the wgpu tier (the renderer masks Backends::GL out, so
  detection must too). renderer-femtovg (GL) feature now compiled on
  Linux.
- wgpu tier requests PowerPreference::LowPower (WGPU_POWER_PREF still
  wins).
- Per-window swapchain alpha in the vendored femtovg renderer: only the
  miniplayer gets a transparent (blended) swapchain; the main window
  keeps an Opaque one, sparing a full-window compositor blend per frame.
- Settings > Appearance gains a Renderer row (Linux only): Auto
  (default) / GPU / GPU compatibility / Software, persisted in
  ui_prefs.json, applied on restart. QBZ_RENDERER env still overrides
  (now also accepts gl|gles|femtovg).
- Auto-revert sentinel: a non-auto choice is armed before backend init
  and disarmed after the window survives 5s; if the previous start died
  before that, the setting reverts to Auto with an explanatory toast, so
  a bad renderer pick can never lock the user out of Settings.
- Developer tools > Diagnostics now reports the active renderer, why it
  was chosen, and the enumerated GPU adapters (panel + markdown report).

cc
2026-07-01 18:05:28 -06:00
vicrodh 5fc1beb869 fix(slint): vendor femtovg-wgpu renderer for transparent window surface
Slint 1.16's femtovg-wgpu renderer configures the wgpu surface via
get_default_config() and leaves the composite alpha mode at Auto, which
resolves to an opaque surface on KWin/Wayland — a borderless transparent
window then shows a black rectangular backing behind the rounded card.
WGPUConfiguration exposes no surface/alpha hook, so the only fix is a
renderer patch.

Vendor i-slint-renderer-femtovg-1.16.1 with a preferred_alpha_mode() that
picks a supported non-opaque mode (PreMultiplied / PostMultiplied /
Inherit, guarded by the surface's advertised alpha_modes, else Auto) and
wire it into set_surface(). Pulled in via [patch.crates-io]; Slint stays
pinned =1.16.1. The main window is unaffected (it paints opaque).

cx
2026-06-17 18:35:03 -06:00