Commit graph

21 commits

Author SHA1 Message Date
Stephen Hellings
d1c993e295 Whatever bro 2026-03-09 21:59:18 -04:00
Stephen Hellings
42b111410c Again 2026-03-09 21:32:16 -04:00
Stephen Hellings
4fe557c536 fix: register Wayland display/socket fds with calloop to fix DRM rendering stall
The DRM event loop only woke for registered calloop sources (VBlank,
libinput, session). When the VBlank rendering cycle broke (transient
page-flip failure, timing edge), nothing woke the loop to restart it —
only input events (mouse movement) would un-stall rendering.

Three changes:

1. Register the Wayland display poll_fd as a calloop source so client
   surface commits immediately wake the event loop and trigger
   render_frame via the main callback.

2. Register the listening socket fd so new Wayland client connections
   also wake the loop promptly.

3. Add a periodic timer (fires every frame_time ≈ 16ms) as a safety net
   to restart stalled VBlank cycles even with no input or client
   activity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 19:24:33 -04:00
Stephen Hellings
83cdaffd05 Cry 2026-03-09 18:07:07 -04:00
Stephen Hellings
d28e50fcf9 Attempt 5... 2026-03-09 15:54:44 -04:00
Stephen Hellings
d4c8d1c465 Attempt 5... 2026-03-09 15:54:29 -04:00
Stephen Hellings
e245af128c fix: add frame.finish() to flush GL commands, fix IPC write ordering
Two critical fixes:

1. **Flickering (GL frame not finalized)**: render_frame was missing
   the frame.finish() call that nested.rs has (line 688). Without it,
   GL rendering commands are never flushed to the GBM BO, so the DRM
   page flip scans out a buffer with stale/incomplete pixel data,
   alternating between rendered and unrendered content every frame.

2. **IPC protocol corruption (EPIPE/ECONNRESET)**: Node's socket.write()
   is async and buffers data in userspace. The native sendFd() call
   (sendmsg with SCM_RIGHTS) goes directly to the kernel, racing ahead
   of the buffered header+plane bytes. The compositor then reads the
   1-byte SCM_RIGHTS dummy as the next message magic, hits 'unknown
   magic', and the IPC reader thread exits — closing the socket (EPIPE).
   Fix: use fs.writeSync() on the raw fd for header+plane data so it
   reaches the kernel buffer before sendFd's sendmsg.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 14:31:47 -04:00
Stephen Hellings
6c487d6b75 fix: swapchain slot retention to eliminate flickering, add keyboard_key action, align maximize with nested.rs
Three fixes:

1. **Flickering (every-other-frame)**: Swapchain slots were dropped
   immediately after page_flip, setting acquired=false so the next
   acquire() could return the same GBM BO currently being scanned out
   by the CRTC. Added current_slot field to EventLoopData that holds
   the submitted slot until the next frame replaces it, preventing
   buffer reuse during scanout.

2. **Missing keyboard_key action**: The DRM codepath was missing the
   'keyboard_key' custom action handler that nested.rs has. Added it
   with evdev→XKB keycode conversion and keyboard.input() dispatch.

3. **Maximize alignment**: DRM maximize was clamping to size hints and
   centering horizontally, while nested.rs uses full output width.
   Aligned to match nested.rs behavior.

4. **z_order sorting**: Electron window rendering now sorts by z_order
   to match nested.rs's chain+sort approach.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 13:30:45 -04:00
Stephen Hellings
5123aac2d4 fix: merge [[root]] entries into config.windows and force initial modeset
Two critical bugs causing a black/off screen:

1. [[root]] window configs were spawned as Electron processes but never
   added to config.windows. The render loop, window_mapped state, and
   respawn logic all iterate config.windows — so root windows were
   invisible. Fix: merge root entries (with fullscreen geometry and low
   z_order) into config.windows before WoState::new(), so all subsystems
   see them uniformly.

2. When the display manager (Ly) leaves the CRTC in a state Smithay
   considers 'already committed' (matching mode/connectors),
   commit_pending() returns false and only page_flip() is used.
   page_flip without a prior modeset can 'succeed' but produce no
   visible output because the CRTC was never properly activated with
   a framebuffer. Fix: force a full modeset commit (ALLOW_MODESET) on
   the very first frame (total_flips==0) regardless of commit_pending.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 13:16:00 -04:00
Stephen Hellings
b82a9ca9c3 fix: clear IPC socket timeout after handshake, add vblank recovery and render diagnostics
Three bugs addressed:

1. SO_RCVTIMEO(5s) on the IPC socket was never cleared after the HELLO
   handshake. When the web page becomes static (no paint events for >5s),
   the blocking read_exact in recv_message times out, the IPC reader thread
   exits, and the socket is closed — causing ECONNRESET on the Electron
   side and permanently stalling frame delivery. Fix: clear SO_RCVTIMEO
   to zero (infinite) immediately after successful HELLO exchange.

2. If a VBlank event is lost or delayed (e.g. during DRM master transitions),
   vblank_pending stays true and all subsequent render_frame calls bail out
   permanently. Fix: if vblank_pending has been stuck for >500ms, force-clear
   it with a warning so rendering can resume.

   making it impossible to diagnose the black screen from logs. Fix: add
   INFO-level logging for first render, first page flip, first texture
   import, swapchain exhaustion on first frame, and vblank recovery events.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 13:08:59 -04:00
Stephen Hellings
ae528b5132 fix: Electron offscreen rendering and DRM render node propagation
Three root causes prevented Electron frames from reaching the compositor:

1. --disable-gpu killed Chromium's rendering pipeline, preventing the
   'paint' event from firing in offscreen mode. Replaced with
   --use-gl=swiftshader so Chromium can composite internally while the
   native wo_dmabuf module handles GPU buffer allocation separately.

2. DISPLAY=:0 with no X server caused Electron to fail silently on
   pure Wayland sessions (Ly/logind). Replaced with
   --ozone-platform=headless which lets Chromium's OSR pipeline work
   without any display server connection.

3. WO_DRM_RENDER_NODE was never set, so the native wo_dmabuf.node
   module always defaulted to /dev/dri/renderD128 regardless of which
   GPU the compositor actually opened. Now resolved via sysfs
   (card1 -> renderD128, card2 -> renderD129, etc.) and passed through
   to Electron.

Also: retry EACCES/EPERM as transient during DRM device open (logind
session activation can lag behind libseat's is_active() flag on Ly).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 12:31:09 -04:00
Stephen Hellings
eee56bc5f4 Attempt 4... 2026-03-09 11:35:01 -04:00
Stephen Hellings
4dcb10d9f1 Attempt 3 to fix launching permission denied 2026-03-09 11:21:08 -04:00
Stephen Hellings
5e154e19f9 Attempt 2 to fix launching permission denied 2026-03-09 09:45:30 -04:00
Stephen Hellings
d9fa1323c3 More robust retries when page flip fails 2026-03-09 03:22:10 -04:00
Stephen Hellings
cbe2dd43bd Do not use npm for pkg 2026-03-08 23:39:36 -04:00
Stephen Hellings
d184ab69e4 Fix types + build issue 2026-03-08 23:38:12 -04:00
Stephen Hellings
e03fe3739f Commit lockfile 2026-03-08 23:27:48 -04:00
Stephen Hellings
ee5b7f764e Upd PKGBUILD 2026-03-08 23:22:34 -04:00
stephen hellings
e442ad43a0
Create LICENSE 2026-03-08 23:12:27 -04:00
Stephen Hellings
33359b814e Initial commit 2026-03-08 23:04:02 -04:00