perf(gui): scene-dirty compositor + cursor overlay + 60 FPS pacer + animations

Rework the compositor so it stops repainting the whole screen every frame,
tripling the frame rate (17 -> 54 FPS at HD) and adding smooth animation.

- Scene-dirty skipping (gui/gui_desktop.c): the full scene is recomposited only
  when something other than the bare pointer changed -- input, an open animation,
  or a ~10 Hz heartbeat for live content (clock, graphs). Idle and pointer-only
  frames skip the recomposite entirely.
- Cursor save-under (gui/gui_cursor.c): the pointer is an overlay that stashes
  and restores the pixels beneath it, so moving the mouse never forces a full
  repaint -- pointer motion runs at the frame cap.
- 60 FPS frame pacer: each iteration is timed against the monotonic clock and
  padded to a 16.666 ms budget with the new ktime_delay_us() (HPET-precise
  busy-wait), giving consistent pacing instead of a free-running spin.
- Window open animation (gui/gui_wm.c): new windows grow from 60% to full size
  with a cubic ease-out over ~160 ms; gui_wm_update() drives it and reports
  while any window is still animating so the compositor keeps redrawing.
- Default display mode set to 1280x720 (HD) -- the sweet spot where the
  software compositor sustains a near-60 FPS cursor with headroom for effects.

Kernel: kernel/time/ktime.c gains ktime_delay_us(), a precise HPET-based delay
(bounded PIT fallback) used by the pacer.

Verified live (screenshotted): boots to 1280x720, logs in, tray reads ~54 FPS
(green) while the pointer moves, no cursor ghosting, windows render cleanly.
Clean build on x86_64/aarch64/armv8i; 0 panics / 0 OOM.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
This commit is contained in:
subhobhai943andClaude Opus 4.8 committed 2026-08-25 23:05:44 +05:30
1 parent 4ecf119377
commit 2c2e2d536e
8 files changed
+200 -13

No files matched your search

+1 -1
View File
@@ -332,7 +332,7 @@ void kernel_main(void* memory_map, uint64_t memory_map_count) {
printk(ANSI_BRIGHT_CYAN " SUB-OS 64-Bit [%s] Modular Monolithic Kernel %s\n" ANSI_RESET, arch_get_name(), kernel_get_version());
printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET);
init_early("root=/dev/sda console=tty1 init=/bin/lazybox video=1920x1080 quiet");
init_early("root=/dev/sda console=tty1 init=/bin/lazybox video=1280x720 quiet");
rtc_init();
printk(KERN_INFO "[1/14] Initializing 64-Bit GDT, IDT, PIC & PIT Timer... ");
+19
View File
@@ -37,3 +37,22 @@ uint64_t ktime_ms(void) { return ktime_ns() / 1000000ULL; }
const char* ktime_source(void) { return g_use_hpet ? "HPET" : "PIT"; }
bool ktime_is_highres(void) { return g_use_hpet; }
void ktime_delay_us(uint64_t us) {
if (us == 0) return;
// With the HPET we can spin precisely; on the PIT the 10 ms tick is far
// coarser than a microsecond, so cap the spin so we never wedge the CPU.
if (!g_use_hpet) {
uint64_t deadline_ms = ktime_ms() + (us + 999) / 1000;
uint64_t guard = 0;
while (ktime_ms() < deadline_ms && guard++ < 100000000ULL) {
/* spin */
}
return;
}
uint64_t start = ktime_ns();
uint64_t target = start + us * 1000ULL;
while (ktime_ns() < target) {
/* spin on the HPET counter */
}
}