CHANGELOG 0.3.1.md — Notepad

Added

  • Separate graphics compositor (/bin/compositord). Direct /dev/gpu0 access, display surface import, batched presents, the present timeline and the hardware cursor moved into a userland daemon. desktop starts it with pipes and an inherited framebuffer section and speaks a versioned binary protocol (savanxp/compositor_protocol.h). The shell keeps window policy, chrome and input routing but no longer issues GPU ioctls.

  • GPU HAL: a swappable display backend. namespace display goes from a fixed passthrough to virtio_gpu to a real display::Backend vtable, with /dev/gpu0 registered by a backend-agnostic dispatcher (kernel/gpu_device.cpp). New kernel/fb_gpu.cpp backend: software composition straight onto Limine's linear framebuffer, for when there is no virtio-gpu. kernel_main autodetects.

  • Composited fullscreen for apps (F11 key). A fullscreen-capable app (Doom, Gfx Demo) goes chromeless: the shell scales its 640x400 buffer and presents through compositord, with no mode change and no client scanout flip. It works over virtio-gpu and over the flat framebuffer alike.

  • Native subsystem (Haxe) — Phase 0 kickoff. The chain is proven end to end at compile/link level: Main.hx -> reflaxe.CPP -> C++17 -> freestanding clang++ -> a native ELF. New subsystems/native/ with a seed SDK and a separate build.ps1 that pins reflaxe under toolchain/haxe-libs/.

  • Native subsystem — Phase 1: real native processes. A native binary is marked with e_ident[EI_OSABI]=0x53 and the loader assigns subsystem::Id::native by the binary's ABI, not by inheritance from the parent. Its syscalls enter through dispatch_native_syscall, which delegates the baseline to posix and stands as the point of divergence.

  • Real typefaces baked offline into C tables with tools/font/genfont.py: GNU UniFont 8x16 for the kernel console and the terminal, and proportional antialiased Noto Sans for the desktop chrome. The OS still does not parse TrueType at runtime.

  • A monospace text path in sxgfx (gfx_blit_text_mono, gfx_cell_width/height) and per-pixel alpha blending (gfx_pixel_blend) for Noto's antialiased text.

  • Real interrupts through MSI-X in virtio-gpu, with an ISR/DPC pattern instead of pure polling. The kernel has no IOAPIC and q35 in APIC mode does not deliver legacy INTx, so MSI-X is the only path. Includes pci::find_capability, virtio_pci::enable_msix and IDT vector 49.

  • poll() reports readiness for kernel waitable objects (events, timers), so the compositor can wait for its clients' submit events in the same poll set.

  • An on-screen FPS and present latency overlay in Doom's backend, and a dump of the driver's per-stage stats in gputest --soak.

  • A PIT timer backend (8254, IRQ0) as a fallback when the local APIC does not support x2APIC or calibration fails; previously the scheduler never started there. savanxp_system_info exposes the active backend (SAVANXP_TIMER_LOCAL_APIC / _PIT / _NONE).

Changed

  • The desktop compositor composes by regions with occlusion culling: it builds the layer list in z-order and paints each one once over its visible region, eliminating overdraw under opaque windows. New sx_rect_set_subtract_rect; sx_rect_set capacity goes from 32 to 64.

  • The kernel console moves from the hand-authored 5x7 bitmap font to UniFont 8x16, with ASCII + Latin-1 + box drawing through a sparse table.

  • gfx_blit_text rasterizes Noto Sans from an 8-bit coverage atlas; shellapp uses the UniFont monospace path. The desktop chrome metrics were readjusted for the larger line height.

  • UniFont is baked from unifont.hex (crisp on-grid bitmaps), not from the TTF outline, which rasterized off-grid with artifacts.

  • The kernel timer goes from 200 Hz to 1000 Hz, with the scheduler quantum rescaled to keep ~20 ms of wall clock. Signalling an event now yields to the woken thread on the syscall return instead of waiting for the next tick.

  • The compositor wakes on a client's frame submit instead of exhausting the 16 ms timeout, which remains as a backstop.

  • The virtio-gpu driver becomes interrupt-driven: the present waiters' spin is cut from 50000 to 2000 iterations before halting, and the backstop timeouts are expressed in wall-clock milliseconds to survive the tick rate change.

Removed

  • The hand-generated 8x8 font system (tools/font/genfont.ps1, font8x8.txt, gfx_font8x8.inc), replaced by the genfont.py toolchain.

Fixed

  • release_surface_allocation (virtio-gpu) freed the primary surface's backing without a RESOURCE_UNREF of the host resource, so the first real runtime mode change failed with RESOURCE_CREATE_2D -> INVALID_RESOURCE_ID.

  • decode_bar_size computed ~mask + 1 in 64 bits over a mask holding only the low 32 bits, returning garbage sizes for any 64-bit memory BAR under 4 GiB and preventing them from being mapped — the MSI-X table among them.

  • Inode corruption from rounding in the SVFS2 bitmap. The host-side installer computed the byte index with [int]($Bit / 8), which in PowerShell rounds instead of truncating, desyncing from the kernel's floor indexing and reassigning live inodes (symptom: "expected inode N but read 0"). Now -shr 3.

  • An orderly QEMU shutdown in Run-AutomationQemu: quit over the HMP monitor instead of Stop-Process -Force, so QEMU flushes its block backends and closes the disk file cleanly, with a fallback to the forced kill.

  • The OS hung indefinitely after "Starting welcome" on hypervisors without x2APIC: initialize_local_apic failed silently and the scheduler never started. Resolved by the PIT fallback above.

  • Erratic cursor: PS/2 packet framing corrupted in streaming. process_mouse_byte discarded every 0xFA/0xFE assuming ACK/RESEND, but in streaming those are also legitimate deltas (-6 and -2), and losing the byte desynced the 3-byte framing. The bug was directional — only left/down. A defensive clamp of +-150 per axis clips instead of discarding the packet.

  • reserve_kernel_mmio_window reserved a PML4 entry without installing the corresponding PDPT, so any later map_kernel_mmio over that window failed or corrupted memory.

  • fb_gpu's present timeline always returned submitted_sequence = 0, retired_sequence = 0, so wait_present depended on a lucky coincidence instead of a real counter.

  • Experimental VirtualBox compatibility (VBoxVGA backend). The system now boots stably to a graphical session and the PS/2 mouse responds in all four directions. Open and undiagnosed: the binaries in /disk still do not start under VirtualBox even with the SVFS2 volume attached.

Version 0.3.12026-07-028 changes