using System.Numerics; namespace XFESystem.NativeRuntime.ConsoleApplication; public readonly record struct ConsoleFramebufferSurface(nuint Address, nuint MappedBytes, int Width, int Height, int PitchBytes, int BitsPerPixel, uint RedMask, uint GreenMask, uint BlueMask); public interface IConsoleFramebuffer { int Width { get; } int Height { get; } void Present(ReadOnlySpan pixels); } /// Console scanout uses only the kernel-provided mapping; it never creates a desktop or a host window. public sealed unsafe class ConsoleMemoryFramebuffer : IConsoleFramebuffer { private readonly ConsoleFramebufferSurface surface; private readonly int bytesPerPixel; private Action? beforeFirstPresent; public int Width => surface.Width; public int Height => surface.Height; public ConsoleMemoryFramebuffer(ConsoleFramebufferSurface surface, Action? beforeFirstPresent = null) { if (surface.Address == 0 || surface.Width is < 320 or > 16384 || surface.Height is < 240 or > 16384 || (long)surface.Width * surface.Height > 33_554_432 || surface.BitsPerPixel is not (16 or 24 or 32)) throw new ArgumentException("A bounded mapped framebuffer is required.", nameof(surface)); bytesPerPixel = surface.BitsPerPixel / 8; ulong required = checked((ulong)(surface.Height - 1) * (uint)surface.PitchBytes + (ulong)surface.Width * (uint)bytesPerPixel); if (surface.PitchBytes < (long)surface.Width * bytesPerPixel || required > surface.MappedBytes || required > nuint.MaxValue - surface.Address || !ValidMask(surface.RedMask, surface.BitsPerPixel) || !ValidMask(surface.GreenMask, surface.BitsPerPixel) || !ValidMask(surface.BlueMask, surface.BitsPerPixel) || (surface.RedMask & surface.GreenMask) != 0 || (surface.RedMask & surface.BlueMask) != 0 || (surface.GreenMask & surface.BlueMask) != 0) throw new ArgumentException("Framebuffer extent, pitch or masks are invalid.", nameof(surface)); this.surface = surface; this.beforeFirstPresent = beforeFirstPresent; } public void Present(ReadOnlySpan pixels) { if (pixels.Length != (long)Width * Height) throw new ArgumentException("Incomplete console frame.", nameof(pixels)); beforeFirstPresent?.Invoke(); beforeFirstPresent = null; // Common UEFI/QEMU RGB32 case: row copies retain firmware pitch padding. if (bytesPerPixel == 4 && surface.RedMask == 0xFF0000 && surface.GreenMask == 0xFF00 && surface.BlueMask == 0xFF) { for (int y = 0; y < Height; y++) pixels.Slice(y * Width, Width).CopyTo(new Span((void*)(surface.Address + (nuint)y * (nuint)surface.PitchBytes), Width)); return; } for (int y = 0; y < Height; y++) { byte* output = (byte*)surface.Address + (nuint)y * (nuint)surface.PitchBytes; for (int x = 0; x < Width; x++) { uint rgb = unchecked((uint)pixels[y * Width + x]); uint packed = Channel((byte)(rgb >> 16), surface.RedMask) | Channel((byte)(rgb >> 8), surface.GreenMask) | Channel((byte)rgb, surface.BlueMask); for (int index = 0; index < bytesPerPixel; index++) *output++ = (byte)(packed >> (index * 8)); } } } private static bool ValidMask(uint mask, int bits) { if (mask == 0 || bits < 32 && mask >> bits != 0) return false; uint range = mask >> BitOperations.TrailingZeroCount(mask); return (range & (range + 1)) == 0; } private static uint Channel(byte value, uint mask) { int shift = BitOperations.TrailingZeroCount(mask); return (uint)(((ulong)value * (mask >> shift) + 127) / 255) << shift; } }