// SPDX-License-Identifier: LCL-1.0 // Copyright (c) 2026 Markus Maiwald // Stewardship: Self Sovereign Society Foundation // // This file is part of the Nexus Commonwealth. // See legal/LICENSE_COMMONWEALTH.md for license terms. //! Rumpk Layer 0: Surface Allocator //! //! Manages contiguous memory chunks for window buffers (compositor). //! Provides a simple pool-based allocation for up to 16 surfaces. //! //! DECISION(Graphics): Fixed pool size of 32MB for surfaces. //! Bump-style allocation; reclamation requires system reset. const std = @import("std"); const uart = @import("uart.zig"); pub const MAX_SURFACES = 16; pub const SURFACE_POOL_SIZE = 1 * 1024 * 1024; // 1MB for surfaces (temporary reduction) // Surface Descriptor pub const Surface = struct { id: i32, ptr: [*]u32, width: u32, height: u32, active: bool, }; // Global Surface Pool // SAFETY(Surfaces): Array is initialized by hal_surface_init before use. var surfaces: [MAX_SURFACES]Surface = undefined; var next_surface_id: i32 = 1; // Backing memory for surfaces (in BSS) // SAFETY(SurfaceHeap): Memory written by alloc before any read. // Initialized to `undefined` to avoid zeroing 32MB at boot. var surface_heap: [SURFACE_POOL_SIZE]u8 align(4096) = undefined; var heap_offset: usize = 0; export fn hal_surface_init() void { for (&surfaces) |*s| { s.id = -1; s.active = false; // SAFETY(Surfaces): Pointer reset to `undefined`. Populated during allocation. s.ptr = undefined; s.width = 0; s.height = 0; } heap_offset = 0; uart.print("[Surface] Allocator Initialized. Pool: 32MB\n"); } pub fn alloc(width: u32, height: u32) ?i32 { const size = width * height * 4; // Alignment to 4096 const aligned_size = (size + 4095) & ~@as(u32, 4095); if (heap_offset + aligned_size > SURFACE_POOL_SIZE) { uart.print("[Surface] ERROR: Out of Memory in Surface Pool!\n"); return null; } // Find free slot var slot: ?*Surface = null; for (&surfaces) |*s| { if (!s.active) { slot = s; break; } } if (slot) |s| { s.id = next_surface_id; next_surface_id += 1; s.width = width; s.height = height; s.ptr = @ptrCast(@alignCast(&surface_heap[heap_offset])); s.active = true; heap_offset += aligned_size; uart.print("[Surface] Allocated ID="); uart.print_hex(@intCast(s.id)); uart.print(" Size="); uart.print_hex(size); uart.print("\n"); return s.id; } uart.print("[Surface] ERROR: Max Surfaces Reached!\n"); return null; } pub fn get_surface(id: i32) ?*Surface { for (&surfaces) |*s| { if (s.active and s.id == id) return s; } return null; } pub fn free(id: i32) bool { for (&surfaces) |*s| { if (s.active and s.id == id) { s.active = false; // Note: In our simple bump-style allocator, we don't reclaim heap space // unless we implement a real allocator. For now, we assume surfaces are // mostly permanent or the system reboots. return true; } } return false; } // Exported for Nim export fn hal_surface_alloc(w: u32, h: u32) i32 { return alloc(w, h) orelse -1; } export fn hal_surface_get_ptr(id: i32) ?[*]u32 { if (get_surface(id)) |s| return s.ptr; return null; }