mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
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
59 lines
1.8 KiB
C
59 lines
1.8 KiB
C
// Unified monotonic high-resolution clock for SUB-OS.
|
|
//
|
|
// When the HPET is available it provides true nanosecond timing; otherwise the
|
|
// clock degrades gracefully to the 100 Hz kernel timer tick (10 ms resolution).
|
|
// Either way the epoch is the moment ktime_init() ran.
|
|
|
|
#include <kernel/ktime.h>
|
|
#include <drivers/hpet.h>
|
|
#include <arch/arch.h>
|
|
#include <kernel/printk.h>
|
|
|
|
#define TICK_HZ 100ULL
|
|
#define NS_PER_TICK (1000000000ULL / TICK_HZ) // 10,000,000 ns at 100 Hz
|
|
|
|
static bool g_use_hpet = false;
|
|
static uint64_t g_base_tick = 0;
|
|
|
|
void ktime_init(void) {
|
|
g_use_hpet = hpet_available();
|
|
g_base_tick = pit_get_ticks();
|
|
printk(ANSI_BRIGHT_GREEN "KTIME: " ANSI_RESET
|
|
"Monotonic clock online (source: %s%s)\n",
|
|
g_use_hpet ? "HPET" : "PIT 100 Hz",
|
|
g_use_hpet ? ", nanosecond resolution" : "");
|
|
}
|
|
|
|
uint64_t ktime_ns(void) {
|
|
if (g_use_hpet) {
|
|
return hpet_get_ns();
|
|
}
|
|
uint64_t ticks = pit_get_ticks() - g_base_tick;
|
|
return ticks * NS_PER_TICK;
|
|
}
|
|
|
|
uint64_t ktime_us(void) { return ktime_ns() / 1000ULL; }
|
|
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 */
|
|
}
|
|
}
|