v0.25.3
Experimental Linux fbdev backend — feature = "linux-fb" runs mirui directly against /dev/fb0 and /dev/input/event* on Linux, bypassing X11 / Wayland for SBCs and embedded panels. Ships with full input (keyboard / mouse / wheel / SIGINT-as-Quit), auto DPI scale from physical-mm hints, and an opt-in HDMI overscan inset. Two long-standing per-frame allocation leaks in the perf-instrumentation path are also fixed.
Added
feature = "linux-fb"— opt-in Linux backend onmemmap20.9,evdev0.13,libc0.2, andsignal-hook0.3. Fbdev resolution and pixel format come fromFBIOGET_VSCREENINFO; the renderer writes through&mut self.mmap[..]directly and respectsline_lengthso padded scanlines on driver-aligned panels render correctly.- Input — USB tablet / touchscreen (
EV_ABS+ multi-touch slot tracking), USB mouse (EV_RELaccumulated into a clamped cursor position), scroll wheel (REL_WHEEL/REL_HWHEELcoalesced perSYN_REPORT), and a keyboard fd that maps eight editing keys (KEY_BACKSPACE/KEY_LEFT/KEY_RETURN/ ...) to mirui's SDL-style codes; unmapped scancodes pass through raw. - Quit signal —
signal-hookregisters a flag forSIGINT/SIGTERM;poll_eventturns the next tick intoInputEvent::Quitso demos exit cleanly withoutSIGKILL. - Auto DPI scale —
LinuxConfig::scaledefaults toScaleMode::AutoDpi { baseline_dpi: 96 }. Readsvar.width/var.height(mm), computes panel DPI, divides bybaseline_dpi, quantises to quarter-steps, and clamps to[1.0, 4.0]. Drivers reporting 0 mm (qemu ramfb, EFI fb, simple-framebuffer) fall back toFixed::ONE.ScaleMode::Fixed(Fixed)overrides for known-broken drivers. - HDMI overscan inset —
LinuxConfig::overscan_inset_percent(capped at 25%) letsgallery::runshrink the rendered view symmetrically when an HDMI panel eats the panel's outer rim.framebuffer()exposes a sub-slice withtex.stride = line_lengthso the renderer never touches the unsafe border.
- Input — USB tablet / touchscreen (
gallery::demos::hello— minimal LinuxFb-friendly scene (single card + text). Hoisted out oflinux_fb_demoso other backends can run the same body.gallery::demos::widgets— port of the ESP32-C3 widgets showcase (LazyList+Slider+Switch+TabBar+ theme cycling) scaled for desktop / fb-class panels.mirui::plugins::FrameRateCapPlugin— sleeps inpost_renderto a target FPS read fromMonoClock. Native backends ingallery::runinstall it at default 120 Hz (override viaMIRUI_FPS_CAP=<n>,0opts out for benchmarks). Needed because every native backend skipspresent/flushon idle frames, which is also where vsync would have waited — the tick loop otherwise runs at 60 000+ fps and tears against the host compositor.FpsSummary::wall_ns— wall-clock span over the reporting window (MonoClock-based) so sinks can compute the visible FPS (frames * 1e9 / wall_ns) separately from the per-frame work rate (1e9 / avg_frame_ns). Mixed idle / active frames inside a window made the latter swing wildly without context.
Fixed
App::snapshot_system_perfno longer allocates per frame when no plugin reads it. Each tick used to build a freshVec<SystemStat>+Box<SystemPerfSnapshot>regardless of consumer. WithPerfReportPluginabsent the snapshot was thrown away every frame, but musl / glibc returned the freed memory to size-class arenas rather than the OS. Vsync-free backends (linux-fb, headless benches) hit OOM in 3-4 minutes.PerfReportPlugin::buildnow inserts the resource as an opt-in flag;snapshot_system_perfearly-returns without it, and reuses the resource'sVecviaclear() + push()when present.trace_span!/#[trace_fn]no longer leakPerfEvents when no plugin drains them.Guard::droppushed aPerfEventinto a thread-localVecregardless of whether anyone calleddrain_events. WithoutPerfReportPlugintheVecgrew via doubling (40 → 80 → 160 → 320 MB allocations confirmed via backtrace sampling) until OOM.perf::set_enabled(bool)now gates bothenter()andGuard::drop;PerfReportPlugin::buildflips it on. Theno_stdring-buffer path is unchanged.- Text widgets without an explicit size now contribute a fallback intrinsic measurement to layout. A flex parent could otherwise hand
Textwidth = 0, which the render walker culled via strict-less-thanrects_intersect, and a covering parentfill_rectthen erased the previous frame's glyphs — visible as text disappearing where the cursor passed.build_layout_treeandbuild_rectsapply a localLayoutNodemeasurement (Px(text.bytes.len × CHAR_W + 4, CHAR_H + 4)) when both axes areAuto/Contentandflex_grow == 0. ECS state is untouched. - Web-canvas backend — perspective-warped quads now draw rounded corners through
Path::rounded_quad's cubic-bezier approximation. Canvas 2D has no homography, so the affinesetTransform + roundRectfast path does not apply.
Changed
mirui::surface::linux::LinuxFbSurfacewrites directly to mmap — the previous stagingVec<u8>+ per-bandmemcpywas the source of partial-flush coherence bugs.framebuffer()now hands the renderer&mut self.mmap[..]straight, withtex.stride = line_length.flush()becomes a no-op. Side-effect: the R↔B byte swap path is also gone, so BGRX fbdev drivers (qemu ramfb, most modern PC fbs) render with reversed colour until the plannedBGRA8888ColorFormatlands. RGB565 drivers (Pi 4 HDMI) are unaffected.
Internal
gallery/gallery-web/xtask/.cha/plugin-srcworkspace members bumped from 0.25.1 to 0.25.2 (the 0.25.2 release commit had only touchedmirui+mirui-macros), then to 0.25.3 alongside the rest of the workspace.