127 lines
3.4 KiB
Zig
127 lines
3.4 KiB
Zig
// 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;
|
|
}
|