d2596979a2
Signed-off-by: Chloe M. <chloe@mensia.org>
248 lines
5.0 KiB
C
248 lines
5.0 KiB
C
/*
|
|
* Copyright (c) 2026, Chloe M.
|
|
* Provided under the BSD-3 clause.
|
|
*
|
|
* Description: Bootvid driver
|
|
* Author: Chloe M.
|
|
*/
|
|
|
|
#include <drivers/bootvid/fbio.h>
|
|
#include <ke/bpal.h>
|
|
#include <ex/trace.h>
|
|
#include <ex/pbi.h>
|
|
#include <stdef.h>
|
|
#include "flanterm.h"
|
|
#include "flanterm_backends/fb.h"
|
|
|
|
#define DTRACE(Fmt, ...) \
|
|
TRACE("[ BOOTVID ]: " Fmt, ##__VA_ARGS__)
|
|
|
|
/* Bootcons attributes */
|
|
#define DEFAULT_BG 0x000000
|
|
#define DEFAULT_FG 0xFFB000
|
|
|
|
static BPAL_FRAMEBUFFER Framebuffer;
|
|
static struct flanterm_context *FtCtx = NULL;
|
|
static BOOLEAN BootConsEnabled = false;
|
|
static BOOTCONS_ATTR DefaultConsAttr = {
|
|
.Foreground = DEFAULT_FG,
|
|
.Background = DEFAULT_BG
|
|
};
|
|
|
|
/*
|
|
* Splash screen header
|
|
*
|
|
* @Width: Width of splash
|
|
* @Height: Height of splash
|
|
*/
|
|
typedef PACKED struct {
|
|
ULONG Width;
|
|
ULONG Height;
|
|
} SPLASH_HEADER;
|
|
|
|
/*
|
|
* Pack RGB bits so it fits the framebuffer format
|
|
*
|
|
* @Red: Red value
|
|
* @Green: Green value
|
|
* @Blue: Blue value
|
|
*/
|
|
static inline ULONG
|
|
BootVidPackRgb(UCHAR Red, UCHAR Green, UCHAR Blue)
|
|
{
|
|
return ((ULONG)Red << Framebuffer.RedMaskShift)
|
|
| ((ULONG)Green << Framebuffer.GreenMaskShift)
|
|
| ((ULONG)Blue << Framebuffer.BlueMaskShift);
|
|
}
|
|
|
|
/*
|
|
* Blit the splash onto the screen
|
|
*
|
|
* @Fb: Framebuffer descriptor
|
|
* @Hdr: Splash header
|
|
* @FileSize: Splash file size
|
|
*/
|
|
static BOOLEAN
|
|
BlitSplash(BPAL_FRAMEBUFFER *Fb, SPLASH_HEADER *Hdr, USIZE FileSize)
|
|
{
|
|
volatile ULONG *Row;
|
|
UCHAR *Pixels, *Base;
|
|
USIZE StartX, StartY;
|
|
USIZE SrcX, SrcY;
|
|
USIZE DrawW, DrawH;
|
|
USIZE PixelBytes;
|
|
ULONG Background;
|
|
USIZE ImgX, ImgY;
|
|
USIZE Off, Red;
|
|
UCHAR Green, Blue;
|
|
UCHAR Alpha;
|
|
|
|
if (Hdr->Width == 0 || Hdr->Height == 0) {
|
|
return false;
|
|
}
|
|
|
|
PixelBytes = (USIZE)Hdr->Width * (USIZE)Hdr->Height * 4;
|
|
if (FileSize < sizeof(SPLASH_HEADER) + PixelBytes) {
|
|
return false;
|
|
}
|
|
|
|
if (Fb->Address == NULL || Fb->Pitch == 0) {
|
|
return false;
|
|
}
|
|
|
|
Pixels = (UCHAR *)Hdr + sizeof(SPLASH_HEADER);
|
|
Base = Fb->Address;
|
|
|
|
DrawW = Hdr->Width;
|
|
DrawH = Hdr->Height;
|
|
StartX = 0;
|
|
StartY = 0;
|
|
SrcX = 0;
|
|
SrcY = 0;
|
|
|
|
if (DrawW < Fb->Width) {
|
|
StartX = (Fb->Width - DrawW) / 2;
|
|
} else if (DrawW > Fb->Width) {
|
|
SrcX = (DrawW - Fb->Width) / 2;
|
|
DrawW = Fb->Width;
|
|
}
|
|
|
|
if (DrawH < Fb->Height) {
|
|
StartY = (Fb->Height - DrawH) / 2;
|
|
} else if (DrawH > Fb->Height) {
|
|
SrcY = (DrawH - Fb->Height) / 2;
|
|
DrawH = Fb->Height;
|
|
}
|
|
|
|
/* Actually blit the splash */
|
|
for (USIZE Y = 0; Y < DrawH; Y++) {
|
|
Row = (volatile ULONG *)(Base + ((StartY + Y) * Fb->Pitch));
|
|
for (USIZE X = 0; X < DrawW; X++) {
|
|
ImgX = SrcX + X;
|
|
ImgY = SrcY + Y;
|
|
Off = (ImgY * Hdr->Width + ImgX) * 4;
|
|
Red = Pixels[Off + 0];
|
|
Green = Pixels[Off + 1];
|
|
Blue = Pixels[Off + 2];
|
|
Alpha = Pixels[Off + 3];
|
|
Row[StartX + X] = BootVidPackRgb(Red, Green, Blue);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
VOID
|
|
BootVidInitCons(BOOTCONS_ATTR *Attr)
|
|
{
|
|
if (BootConsEnabled) {
|
|
BootVidDeInitCons();
|
|
}
|
|
|
|
if (Attr == NULL) {
|
|
Attr = &DefaultConsAttr;
|
|
}
|
|
|
|
FtCtx = flanterm_fb_init(
|
|
NULL,
|
|
NULL,
|
|
Framebuffer.Address,
|
|
Framebuffer.Width,
|
|
Framebuffer.Height,
|
|
Framebuffer.Pitch,
|
|
Framebuffer.RedMaskSize,
|
|
Framebuffer.RedMaskShift,
|
|
Framebuffer.GreenMaskSize,
|
|
Framebuffer.GreenMaskShift,
|
|
Framebuffer.BlueMaskSize,
|
|
Framebuffer.BlueMaskShift,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Attr->Background,
|
|
&Attr->Foreground,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0, 0, 0,
|
|
0, 0, 0, 0
|
|
);
|
|
|
|
BootConsEnabled = true;
|
|
DTRACE("bootcons enabled\n");
|
|
}
|
|
|
|
VOID
|
|
BootVidInit(VOID)
|
|
{
|
|
BPAL_HANDLE BpalHandle;
|
|
|
|
KeBpalGetHandle(&BpalHandle);
|
|
Framebuffer = BpalHandle.Framebuffer;
|
|
|
|
DTRACE("framebuffer width: %d\n", Framebuffer.Width);
|
|
DTRACE("framebuffer height: %d\n", Framebuffer.Height);
|
|
}
|
|
|
|
VOID
|
|
BootVidConsWrite(const CHAR *String, USIZE Length)
|
|
{
|
|
if (String == NULL || Length == 0) {
|
|
return;
|
|
}
|
|
|
|
if (!BootConsEnabled) {
|
|
return;
|
|
}
|
|
|
|
flanterm_write(FtCtx, String, Length);
|
|
}
|
|
|
|
VOID
|
|
BootVidDeInitCons(VOID)
|
|
{
|
|
if (!BootConsEnabled) {
|
|
return;
|
|
}
|
|
|
|
flanterm_deinit(FtCtx, NULL);
|
|
FtCtx = NULL;
|
|
BootConsEnabled = false;
|
|
}
|
|
|
|
VOID
|
|
BootVidSplash(VOID)
|
|
{
|
|
ST_STATUS Status;
|
|
EX_BPI_FILE File;
|
|
SPLASH_HEADER *Hdr;
|
|
|
|
Status = ExPbiLookup("/boot/splash.rgba", &File);
|
|
if (Status != STATUS_SUCCESS) {
|
|
BootVidClear(DEFAULT_BG);
|
|
return;
|
|
}
|
|
|
|
Hdr = File.Data;
|
|
if (!BlitSplash(&Framebuffer, Hdr, File.Size)) {
|
|
BootVidClear(DEFAULT_BG);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
BootVidClear(ULONG Color)
|
|
{
|
|
ULONG *Ptr;
|
|
|
|
Ptr = Framebuffer.Address;
|
|
for (USIZE Idx = 0; Idx < Framebuffer.Height * Framebuffer.Pitch; ++Idx) {
|
|
Ptr[Idx] = Color;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
BootVidConsEn(VOID)
|
|
{
|
|
return BootConsEnabled;
|
|
}
|