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<int> pixels);
}
/// <summary>Console scanout uses only the kernel-provided mapping; it never creates a desktop or a host window.</summary>
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<int> 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<int>((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;
}
}
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<int> pixels);
}
/// <summary>Console scanout uses only the kernel-provided mapping; it never creates a desktop or a host window.</summary>
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<int> 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<int>((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;
}
}