XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using XFESystem.Branding;
namespace XFESystem.NativeKernel;

public static unsafe class Framebuffer
{
    public static byte* Address;
    public static uint Width, Height, Pitch;
    static byte _redShift, _greenShift, _blueShift;
    public static bool Ready;

    public static bool Initialize(LimineFramebuffer* source)
    {
        Ready = false;
        if (source == null || source->Address == null || source->BitsPerPixel != 32 || source->MemoryModel != 1 ||
            source->Width == 0 || source->Height == 0 || source->Width > 16384 || source->Height > 16384 ||
            source->Pitch < source->Width * 4 || source->Pitch > 1024 * 1024 || (source->Pitch & 3) != 0 ||
            source->RedSize != 8 || source->GreenSize != 8 || source->BlueSize != 8 ||
            source->RedShift > 24 || source->GreenShift > 24 || source->BlueShift > 24) return false;
        uint red = 255u << source->RedShift, green = 255u << source->GreenShift, blue = 255u << source->BlueShift;
        if ((red & green) != 0 || (red & blue) != 0 || (green & blue) != 0 ||
            (ulong)source->Address > ~0UL - source->Pitch * source->Height) return false;
        Address = source->Address;
        Width = (uint)source->Width;
        Height = (uint)source->Height;
        Pitch = (uint)source->Pitch;
        _redShift = source->RedShift; _greenShift = source->GreenShift; _blueShift = source->BlueShift;
        Ready = true;
        return true;
    }
    public static uint Pack(uint rgb) => (((rgb >> 16) & 255) << _redShift) |
        (((rgb >> 8) & 255) << _greenShift) | ((rgb & 255) << _blueShift);
    public static void Pixel(int x, int y, uint rgb)
    {
        if (Ready && x >= 0 && y >= 0 && (uint)x < Width && (uint)y < Height)
            *(uint*)(Address + (ulong)(uint)y * Pitch + (ulong)(uint)x * 4) = Pack(rgb);
    }
    public static void Rectangle(int x, int y, int width, int height, uint rgb)
    {
        if (!Ready || width <= 0 || height <= 0) return;
        long right = (long)x + width, bottom = (long)y + height;
        if (right <= 0 || bottom <= 0 || x >= (long)Width || y >= (long)Height) return;
        int left = x < 0 ? 0 : x, top = y < 0 ? 0 : y;
        int r = right > Width ? (int)Width : (int)right, b = bottom > Height ? (int)Height : (int)bottom;
        uint color = Pack(rgb);
        for (int py = top; py < b; py++)
        {
            uint* row = (uint*)(Address + (ulong)(uint)py * Pitch);
            for (int px = left; px < r; px++) row[px] = color;
        }
    }
    public static void Fill(uint rgb) => Rectangle(0, 0, (int)Width, (int)Height, rgb);
    public static void BootStage(uint stage, bool failure = false)
    {
        if (!Ready) return;
        if (failure) BootSplash.Blackout();
        // Boot diagnostics belong to serial. There are no progress strips,
        // stage numbers or error text on the user's display.
        Native.MemoryBarrier();
    }
    public static void PaintBoot(uint* backbuffer, ulong elapsedMilliseconds, bool waiting)
    {
        if (!Ready || backbuffer == null) return;
        BootVisual.Draw(backbuffer, (int)Width, (int)Height, (int)Width, elapsedMilliseconds,
            waiting, _redShift, _greenShift, _blueShift);
        // Never erase the visible logo to construct its next frame. Copy only
        // the complete dirty region; firmware pitch padding remains untouched.
        int size = BootVisual.LogoSize((int)Width, (int)Height), cx = (int)Width / 2;
        int top = BootVisual.CenterY((int)Height) - size - 12;
        int bottom = BootVisual.LoaderY((int)Width, (int)Height) + 32;
        Native.MemoryBarrier();
        for (int y = top < 0 ? 0 : top; y < bottom && y < Height; y++)
        {
            uint* output = (uint*)(Address + (ulong)(uint)y * Pitch);
            uint* input = backbuffer + (ulong)(uint)y * Width;
            for (int x = cx - size - 12; x <= cx + size + 12; x++)
                if (x >= 0 && x < Width) output[x] = input[x];
        }
        Native.MemoryBarrier();
    }
    public static bool SelfTest()
    {
        if (!Ready) return false;
        uint* first = (uint*)Address;
        uint saved = *first;
        Pixel(0, 0, 0x2ea8df);
        Native.MemoryBarrier();
        bool result = *first == Pack(0x2ea8df);
        *first = saved;
        Native.MemoryBarrier();
        return result;
    }
}