mirror of
https://github.com/reactos/reactos.git
synced 2026-05-22 23:30:07 +08:00
[BOOTVID] Implement a generic linear framebuffer boot video driver (#8618)
Its purpose is to offer an out-of-the-box generic framebuffer video (a video miniport driver for win32k will be introduced in a future PR) to ease ReactOS porting to other possibly non-PC-compatible systems, where no VGA-compatible video is present and only linear framebuffers are available; for example: XBOX, UEFI with GOP only, AppleTV, etc. Of course, once ReactOS is ported, one can then (and should) write, or use existing video drivers tailored to the system of interest. Together with our FreeLoader, this driver could also be employed for of porting/modding Windows 2000/XP/2003 attempts to other platforms, as this has been done by external contributors. Current limitations: - Only supports 32 bits-per-pixel ARGB format. This limitation will be removed in subsequent PR(s). - May be slow during rendering (region color filling and scrolling); I will try to improve this as time goes. This driver's code is loosely based upon preliminary code by Justin Miller and on the existing XBOX bootvid implementation. Tested by Justin Miller (@TheDarkFire) for UEFI, and by Sylas Hollander (@DistroHopper39B) with his AppleTV port. It has also been tested with VESA linear modes on PC by myself.
This commit is contained in:
@@ -68,3 +68,4 @@ if((ARCH STREQUAL "i386") OR (ARCH STREQUAL "amd64"))
|
||||
elseif(ARCH STREQUAL "arm")
|
||||
add_bootvid(bootvid arm/armbvid.cmake)
|
||||
endif()
|
||||
add_bootvid(lfbbvid framebuf/lfbbvid.cmake)
|
||||
|
||||
538
drivers/base/bootvid/framebuf/bootvid.c
Normal file
538
drivers/base/bootvid/framebuf/bootvid.c
Normal file
@@ -0,0 +1,538 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Generic Framebuffer Boot Video Driver
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* or MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Main file
|
||||
* COPYRIGHT: Copyright 2023-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* Include the Boot-time (POST) display discovery helper functions */
|
||||
#include <drivers/bootvid/framebuf.c>
|
||||
|
||||
/* Scaling of the bootvid 640x480 default virtual screen to the larger video framebuffer */
|
||||
#define SCALING_SUPPORT
|
||||
#define SCALING_PROPORTIONAL
|
||||
|
||||
/* Keep borders black or controlled with palette */
|
||||
// #define COLORED_BORDERS
|
||||
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define BB_PIXEL(x, y) \
|
||||
((PUCHAR)BackBuffer + (y) * SCREEN_WIDTH + (x))
|
||||
|
||||
#define FB_PIXEL(x, y) \
|
||||
((PUCHAR)FrameBufferStart + (PanV + VidpYScale * (y)) * BytesPerScanLine \
|
||||
+ (PanH + VidpXScale * (x)) * BytesPerPixel)
|
||||
|
||||
static ULONG_PTR FrameBufferStart = 0;
|
||||
static ULONG FrameBufferSize;
|
||||
static ULONG ScreenWidth, ScreenHeight, BytesPerScanLine;
|
||||
static UCHAR BytesPerPixel;
|
||||
static PUCHAR BackBuffer = NULL;
|
||||
static SIZE_T BackBufferSize;
|
||||
|
||||
#ifdef SCALING_SUPPORT
|
||||
static USHORT VidpXScale = 1;
|
||||
static USHORT VidpYScale = 1;
|
||||
#else
|
||||
#define VidpXScale 1
|
||||
#define VidpYScale 1
|
||||
#endif
|
||||
static ULONG PanH, PanV;
|
||||
|
||||
static RGBQUAD CachedPalette[BV_MAX_COLORS];
|
||||
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
static VOID
|
||||
ApplyPalette(VOID)
|
||||
{
|
||||
PULONG Frame = (PULONG)FrameBufferStart;
|
||||
ULONG x, y;
|
||||
|
||||
#ifdef COLORED_BORDERS
|
||||
/* Top border */
|
||||
for (x = 0; x < PanV * ScreenWidth; ++x)
|
||||
{
|
||||
*Frame++ = CachedPalette[BV_COLOR_BLACK];
|
||||
}
|
||||
|
||||
/* Left border */
|
||||
for (y = 0; y < VidpYScale * SCREEN_HEIGHT; ++y)
|
||||
{
|
||||
// Frame = (PULONG)(FrameBufferStart + FB_OFFSET(-(LONG)PanH, y));
|
||||
Frame = (PULONG)(FrameBufferStart + (PanV + y) * BytesPerScanLine);
|
||||
for (x = 0; x < PanH; ++x)
|
||||
{
|
||||
*Frame++ = CachedPalette[BV_COLOR_BLACK];
|
||||
}
|
||||
}
|
||||
#endif // COLORED_BORDERS
|
||||
|
||||
/* Screen redraw */
|
||||
PUCHAR Back = BackBuffer;
|
||||
for (y = 0; y < SCREEN_HEIGHT; ++y)
|
||||
{
|
||||
Frame = (PULONG)FB_PIXEL(0, y);
|
||||
PULONG Pixel = Frame;
|
||||
for (x = 0; x < SCREEN_WIDTH; ++x)
|
||||
{
|
||||
for (ULONG j = VidpXScale; j > 0; --j)
|
||||
*Pixel++ = CachedPalette[*Back];
|
||||
Back++;
|
||||
}
|
||||
Pixel = Frame;
|
||||
for (ULONG i = VidpYScale-1; i > 0; --i)
|
||||
{
|
||||
Pixel = (PULONG)((ULONG_PTR)Pixel + BytesPerScanLine);
|
||||
RtlCopyMemory(Pixel, Frame, VidpXScale * SCREEN_WIDTH * BytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COLORED_BORDERS
|
||||
/* Right border */
|
||||
for (y = 0; y < VidpYScale * SCREEN_HEIGHT; ++y)
|
||||
{
|
||||
// Frame = (PULONG)(FrameBufferStart + FB_OFFSET(SCREEN_WIDTH, y));
|
||||
Frame = (PULONG)(FrameBufferStart + (PanV + y) * BytesPerScanLine + (PanH + VidpXScale * SCREEN_WIDTH) * BytesPerPixel);
|
||||
for (x = 0; x < PanH; ++x)
|
||||
{
|
||||
*Frame++ = CachedPalette[BV_COLOR_BLACK];
|
||||
}
|
||||
}
|
||||
|
||||
/* Bottom border */
|
||||
// Frame = (PULONG)(FrameBufferStart + FB_OFFSET(-(LONG)PanH, SCREEN_HEIGHT));
|
||||
Frame = (PULONG)(FrameBufferStart + (PanV + VidpYScale * SCREEN_HEIGHT) * BytesPerScanLine);
|
||||
for (x = 0; x < PanV * ScreenWidth; ++x)
|
||||
{
|
||||
*Frame++ = CachedPalette[BV_COLOR_BLACK];
|
||||
}
|
||||
#endif // COLORED_BORDERS
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
VidInitialize(
|
||||
_In_ BOOLEAN SetMode)
|
||||
{
|
||||
PHYSICAL_ADDRESS FrameBuffer;
|
||||
PHYSICAL_ADDRESS VramAddress;
|
||||
ULONG VramSize;
|
||||
CM_FRAMEBUF_DEVICE_DATA VideoConfigData; /* Configuration data from hardware tree */
|
||||
INTERFACE_TYPE Interface;
|
||||
ULONG BusNumber;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Find boot-time framebuffer display information from the LoaderBlock */
|
||||
Status = FindBootDisplay(&VramAddress,
|
||||
&VramSize,
|
||||
&VideoConfigData,
|
||||
NULL, // MonitorConfigData
|
||||
&Interface,
|
||||
&BusNumber);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Boot framebuffer does not exist!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The VRAM address must be page-aligned */
|
||||
if (VramAddress.QuadPart % PAGE_SIZE != 0) // DPRINTed for diagnostics on some systems
|
||||
DPRINT1("** VramAddress 0x%I64X isn't PAGE_SIZE aligned\n", VramAddress.QuadPart);
|
||||
ASSERT(VramAddress.QuadPart % PAGE_SIZE == 0);
|
||||
if (VramSize % PAGE_SIZE != 0)
|
||||
DPRINT1("** VramSize %lu (0x%lx) isn't multiple of PAGE_SIZE\n", VramSize, VramSize);
|
||||
// ASSERT(VramSize % PAGE_SIZE == 0); // This assert may fail, e.g. 800x600@32bpp UEFI GOP display
|
||||
|
||||
/* Retrieve the framebuffer address, its visible screen dimensions, and its attributes */
|
||||
FrameBuffer.QuadPart = VramAddress.QuadPart + VideoConfigData.FrameBufferOffset;
|
||||
ScreenWidth = VideoConfigData.ScreenWidth;
|
||||
ScreenHeight = VideoConfigData.ScreenHeight;
|
||||
if (ScreenWidth < SCREEN_WIDTH || ScreenHeight < SCREEN_HEIGHT)
|
||||
{
|
||||
DPRINT1("Unsupported screen resolution!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BytesPerPixel = (VideoConfigData.BitsPerPixel + 7) / 8; // Round up to nearest byte.
|
||||
ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
|
||||
if (BytesPerPixel != 4)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
DPRINT1("Unsupported BytesPerPixel = %u\n", BytesPerPixel);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT(ScreenWidth <= VideoConfigData.PixelsPerScanLine);
|
||||
BytesPerScanLine = VideoConfigData.PixelsPerScanLine * BytesPerPixel;
|
||||
if (BytesPerScanLine < 1)
|
||||
{
|
||||
DPRINT1("Invalid BytesPerScanLine = %lu\n", BytesPerScanLine);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Compute the visible framebuffer size */
|
||||
FrameBufferSize = ScreenHeight * BytesPerScanLine;
|
||||
|
||||
/* Verify that the framebuffer actually fits inside the video RAM */
|
||||
if (FrameBuffer.QuadPart + FrameBufferSize > VramAddress.QuadPart + VramSize)
|
||||
{
|
||||
DPRINT1("The framebuffer exceeds video memory bounds!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Translate the framebuffer from bus-relative to physical address */
|
||||
PHYSICAL_ADDRESS TranslatedAddress;
|
||||
ULONG AddressSpace = 0; /* MMIO space */
|
||||
if (!BootTranslateBusAddress(Interface,
|
||||
BusNumber,
|
||||
FrameBuffer,
|
||||
&AddressSpace,
|
||||
&TranslatedAddress))
|
||||
{
|
||||
DPRINT1("Could not translate framebuffer bus address 0x%I64X\n", FrameBuffer.QuadPart);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Map it into system space if necessary */
|
||||
ULONG MappedSize = 0;
|
||||
PVOID FrameBufferBase = NULL;
|
||||
if (AddressSpace == 0)
|
||||
{
|
||||
/* Calculate page-aligned address and size for MmMapIoSpace() */
|
||||
FrameBuffer.HighPart = TranslatedAddress.HighPart;
|
||||
FrameBuffer.LowPart = ALIGN_DOWN_BY(TranslatedAddress.LowPart, PAGE_SIZE);
|
||||
MappedSize = FrameBufferSize;
|
||||
MappedSize += (ULONG)(TranslatedAddress.QuadPart - FrameBuffer.QuadPart); // BYTE_OFFSET()
|
||||
MappedSize = ROUND_TO_PAGES(MappedSize);
|
||||
/* Essentially MmMapVideoDisplay() */
|
||||
FrameBufferBase = MmMapIoSpace(FrameBuffer, MappedSize, MmFrameBufferCached);
|
||||
if (!FrameBufferBase)
|
||||
FrameBufferBase = MmMapIoSpace(FrameBuffer, MappedSize, MmNonCached);
|
||||
if (!FrameBufferBase)
|
||||
{
|
||||
DPRINT1("Could not map framebuffer 0x%I64X (%lu bytes)\n",
|
||||
FrameBuffer.QuadPart, MappedSize);
|
||||
goto Failure;
|
||||
}
|
||||
FrameBufferStart = (ULONG_PTR)FrameBufferBase;
|
||||
FrameBufferStart += (TranslatedAddress.QuadPart - FrameBuffer.QuadPart); // BYTE_OFFSET()
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The base is the translated address, no need to map */
|
||||
FrameBufferStart = (ULONG_PTR)TranslatedAddress.QuadPart;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reserve off-screen area for the backbuffer that contains
|
||||
* 8-bit indexed color screen image, plus preserved row data.
|
||||
*/
|
||||
BackBufferSize = SCREEN_WIDTH * (SCREEN_HEIGHT + (BOOTCHAR_HEIGHT + 1));
|
||||
|
||||
/* If there is enough video memory in the physical framebuffer,
|
||||
* place the backbuffer in the hidden part of the framebuffer,
|
||||
* otherwise allocate a zone for the backbuffer. */
|
||||
if (VideoConfigData.FrameBufferOffset + FrameBufferSize + BackBufferSize
|
||||
<= ((AddressSpace == 0) ? MappedSize : VramSize))
|
||||
{
|
||||
/* Backbuffer placed following the framebuffer in the hidden part */
|
||||
BackBuffer = (PUCHAR)(FrameBufferStart + FrameBufferSize);
|
||||
// BackBuffer = (PUCHAR)(VramAddress + VramSize - BackBufferSize); // Or at the end of VRAM.
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Allocate the backbuffer */
|
||||
PHYSICAL_ADDRESS NullAddress = {{0, 0}};
|
||||
PHYSICAL_ADDRESS HighestAddress = {{-1, -1}};
|
||||
BackBuffer = MmAllocateContiguousMemorySpecifyCache(
|
||||
BackBufferSize, NullAddress, HighestAddress,
|
||||
NullAddress, MmNonCached);
|
||||
if (!BackBuffer)
|
||||
{
|
||||
DPRINT1("Could not allocate backbuffer (size: %lu)\n", (ULONG)BackBufferSize);
|
||||
goto Failure;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SCALING_SUPPORT
|
||||
/* Compute autoscaling; only integer (not fractional) scaling is supported */
|
||||
VidpXScale = ScreenWidth / SCREEN_WIDTH;
|
||||
VidpYScale = ScreenHeight / SCREEN_HEIGHT;
|
||||
ASSERT(VidpXScale >= 1);
|
||||
ASSERT(VidpYScale >= 1);
|
||||
#ifdef SCALING_PROPORTIONAL
|
||||
VidpXScale = min(VidpXScale, VidpYScale);
|
||||
VidpYScale = VidpXScale;
|
||||
#endif
|
||||
DPRINT1("Scaling X = %hu, Y = %hu\n", VidpXScale, VidpYScale);
|
||||
#endif // SCALING_SUPPORT
|
||||
|
||||
/* Calculate left/right and top/bottom border values
|
||||
* to keep the displayed area centered on the screen */
|
||||
PanH = (ScreenWidth - VidpXScale * SCREEN_WIDTH) / 2;
|
||||
PanV = (ScreenHeight - VidpYScale * SCREEN_HEIGHT) / 2;
|
||||
DPRINT1("Borders X = %lu, Y = %lu\n", PanH, PanV);
|
||||
|
||||
/* Reset the video mode if requested */
|
||||
if (SetMode)
|
||||
VidResetDisplay(TRUE);
|
||||
|
||||
return TRUE;
|
||||
|
||||
Failure:
|
||||
/* We failed somewhere; unmap the framebuffer if we mapped it */
|
||||
if (FrameBufferBase && (AddressSpace == 0))
|
||||
MmUnmapIoSpace(FrameBufferBase, MappedSize);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
VidCleanUp(VOID)
|
||||
{
|
||||
/* Just fill the screen black */
|
||||
VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
|
||||
}
|
||||
|
||||
VOID
|
||||
ResetDisplay(
|
||||
_In_ BOOLEAN SetMode)
|
||||
{
|
||||
RtlZeroMemory(BackBuffer, BackBufferSize);
|
||||
RtlZeroMemory((PVOID)FrameBufferStart, FrameBufferSize);
|
||||
|
||||
/* Re-initialize the palette and fill the screen black */
|
||||
InitializePalette();
|
||||
VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
|
||||
}
|
||||
|
||||
VOID
|
||||
InitPaletteWithTable(
|
||||
_In_reads_(Count) const ULONG* Table,
|
||||
_In_ ULONG Count)
|
||||
{
|
||||
const ULONG* Entry = Table;
|
||||
ULONG i;
|
||||
BOOLEAN HasChanged = FALSE;
|
||||
|
||||
for (i = 0; i < Count; i++, Entry++)
|
||||
{
|
||||
HasChanged |= !!((CachedPalette[i] ^ *Entry) & 0x00FFFFFF);
|
||||
CachedPalette[i] = *Entry | 0xFF000000;
|
||||
}
|
||||
|
||||
/* Re-apply the palette if it has changed */
|
||||
if (HasChanged)
|
||||
ApplyPalette();
|
||||
}
|
||||
|
||||
VOID
|
||||
SetPixel(
|
||||
_In_ ULONG Left,
|
||||
_In_ ULONG Top,
|
||||
_In_ UCHAR Color)
|
||||
{
|
||||
PUCHAR Back = BB_PIXEL(Left, Top);
|
||||
PULONG Frame = (PULONG)FB_PIXEL(Left, Top);
|
||||
|
||||
*Back = Color;
|
||||
for (ULONG i = VidpYScale; i > 0; --i)
|
||||
{
|
||||
PULONG Pixel = Frame;
|
||||
for (ULONG j = VidpXScale; j > 0; --j)
|
||||
*Pixel++ = CachedPalette[Color];
|
||||
Frame = (PULONG)((ULONG_PTR)Frame + BytesPerScanLine);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
PreserveRow(
|
||||
_In_ ULONG CurrentTop,
|
||||
_In_ ULONG TopDelta,
|
||||
_In_ BOOLEAN Restore)
|
||||
{
|
||||
PUCHAR NewPosition, OldPosition;
|
||||
|
||||
/* Calculate the position in memory for the row */
|
||||
if (Restore)
|
||||
{
|
||||
/* Restore the row by copying back the contents saved off-screen */
|
||||
NewPosition = BB_PIXEL(0, CurrentTop);
|
||||
OldPosition = BB_PIXEL(0, SCREEN_HEIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Preserve the row by saving its contents off-screen */
|
||||
NewPosition = BB_PIXEL(0, SCREEN_HEIGHT);
|
||||
OldPosition = BB_PIXEL(0, CurrentTop);
|
||||
}
|
||||
|
||||
/* Set the count and copy the pixel data back to the other position in the backbuffer */
|
||||
ULONG Count = TopDelta * SCREEN_WIDTH;
|
||||
RtlCopyMemory(NewPosition, OldPosition, Count);
|
||||
|
||||
/* On restore, mirror the backbuffer changes to the framebuffer */
|
||||
if (Restore)
|
||||
{
|
||||
NewPosition = BB_PIXEL(0, CurrentTop);
|
||||
for (ULONG y = 0; y < TopDelta; ++y)
|
||||
{
|
||||
PULONG Frame = (PULONG)FB_PIXEL(0, CurrentTop + y);
|
||||
PULONG Pixel = Frame;
|
||||
for (Count = 0; Count < SCREEN_WIDTH; ++Count)
|
||||
{
|
||||
for (ULONG j = VidpXScale; j > 0; --j)
|
||||
*Pixel++ = CachedPalette[*NewPosition];
|
||||
NewPosition++;
|
||||
}
|
||||
Pixel = Frame;
|
||||
for (ULONG i = VidpYScale-1; i > 0; --i)
|
||||
{
|
||||
Pixel = (PULONG)((ULONG_PTR)Pixel + BytesPerScanLine);
|
||||
RtlCopyMemory(Pixel, Frame, VidpXScale * SCREEN_WIDTH * BytesPerPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
DoScroll(
|
||||
_In_ ULONG Scroll)
|
||||
{
|
||||
ULONG RowSize = VidpScrollRegion.Right - VidpScrollRegion.Left + 1;
|
||||
|
||||
/* Calculate the position in memory for the row */
|
||||
PUCHAR OldPosition = BB_PIXEL(VidpScrollRegion.Left, VidpScrollRegion.Top + Scroll);
|
||||
PUCHAR NewPosition = BB_PIXEL(VidpScrollRegion.Left, VidpScrollRegion.Top);
|
||||
|
||||
/* Start loop */
|
||||
for (ULONG Top = VidpScrollRegion.Top; Top <= VidpScrollRegion.Bottom; ++Top)
|
||||
{
|
||||
/* Scroll the row */
|
||||
RtlCopyMemory(NewPosition, OldPosition, RowSize);
|
||||
|
||||
PULONG Frame = (PULONG)FB_PIXEL(VidpScrollRegion.Left, Top);
|
||||
PULONG Pixel = Frame;
|
||||
for (ULONG Count = 0; Count < RowSize; ++Count)
|
||||
{
|
||||
for (ULONG j = VidpXScale; j > 0; --j)
|
||||
*Pixel++ = CachedPalette[NewPosition[Count]];
|
||||
}
|
||||
Pixel = Frame;
|
||||
for (ULONG i = VidpYScale-1; i > 0; --i)
|
||||
{
|
||||
Pixel = (PULONG)((ULONG_PTR)Pixel + BytesPerScanLine);
|
||||
RtlCopyMemory(Pixel, Frame, VidpXScale * RowSize * BytesPerPixel);
|
||||
}
|
||||
|
||||
OldPosition += SCREEN_WIDTH;
|
||||
NewPosition += SCREEN_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
DisplayCharacter(
|
||||
_In_ CHAR Character,
|
||||
_In_ ULONG Left,
|
||||
_In_ ULONG Top,
|
||||
_In_ ULONG TextColor,
|
||||
_In_ ULONG BackColor)
|
||||
{
|
||||
/* Get the font line for this character */
|
||||
const UCHAR* FontChar = GetFontPtr(Character);
|
||||
|
||||
/* Loop each pixel height */
|
||||
for (ULONG y = Top; y < Top + BOOTCHAR_HEIGHT; ++y, FontChar += FONT_PTR_DELTA)
|
||||
{
|
||||
/* Loop each pixel width */
|
||||
ULONG x = Left;
|
||||
for (UCHAR bit = 1 << (BOOTCHAR_WIDTH - 1); bit > 0; bit >>= 1, ++x)
|
||||
{
|
||||
/* If we should draw this pixel, use the text color. Otherwise
|
||||
* this is a background pixel, draw it unless it's transparent. */
|
||||
if (*FontChar & bit)
|
||||
SetPixel(x, y, (UCHAR)TextColor);
|
||||
else if (BackColor < BV_COLOR_NONE)
|
||||
SetPixel(x, y, (UCHAR)BackColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
VidSolidColorFill(
|
||||
_In_ ULONG Left,
|
||||
_In_ ULONG Top,
|
||||
_In_ ULONG Right,
|
||||
_In_ ULONG Bottom,
|
||||
_In_ UCHAR Color)
|
||||
{
|
||||
for (; Top <= Bottom; ++Top)
|
||||
{
|
||||
PUCHAR Back = BB_PIXEL(Left, Top);
|
||||
// NOTE: Assumes 32bpp
|
||||
PULONG Frame = (PULONG)FB_PIXEL(Left, Top);
|
||||
PULONG Pixel = Frame;
|
||||
for (ULONG L = Left; L <= Right; ++L)
|
||||
{
|
||||
*Back++ = Color;
|
||||
for (ULONG j = VidpXScale; j > 0; --j)
|
||||
*Pixel++ = CachedPalette[Color];
|
||||
}
|
||||
Pixel = Frame;
|
||||
for (ULONG i = VidpYScale-1; i > 0; --i)
|
||||
{
|
||||
Pixel = (PULONG)((ULONG_PTR)Pixel + BytesPerScanLine);
|
||||
RtlCopyMemory(Pixel, Frame, VidpXScale * (Right - Left + 1) * BytesPerPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
VidScreenToBufferBlt(
|
||||
_Out_writes_bytes_all_(Delta * Height) PUCHAR Buffer,
|
||||
_In_ ULONG Left,
|
||||
_In_ ULONG Top,
|
||||
_In_ ULONG Width,
|
||||
_In_ ULONG Height,
|
||||
_In_ ULONG Delta)
|
||||
{
|
||||
ULONG x, y;
|
||||
|
||||
/* Clear the destination buffer */
|
||||
RtlZeroMemory(Buffer, Delta * Height);
|
||||
|
||||
/* Start the outer Y height loop */
|
||||
for (y = 0; y < Height; ++y)
|
||||
{
|
||||
/* Set current scanline */
|
||||
PUCHAR Back = BB_PIXEL(Left, Top + y);
|
||||
PUCHAR Buf = Buffer + y * Delta;
|
||||
|
||||
/* Start the X inner loop */
|
||||
for (x = 0; x < Width; x += sizeof(USHORT))
|
||||
{
|
||||
/* Read the current value */
|
||||
*Buf = (*Back++ & 0xF) << 4;
|
||||
*Buf |= *Back++ & 0xF;
|
||||
Buf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
22
drivers/base/bootvid/framebuf/framebuf.h
Normal file
22
drivers/base/bootvid/framebuf/framebuf.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Generic Framebuffer Boot Video Driver
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* or MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Arch-specific header file
|
||||
* COPYRIGHT: Copyright 2023-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
VOID
|
||||
InitPaletteWithTable(
|
||||
_In_reads_(Count) const ULONG* Table,
|
||||
_In_ ULONG Count);
|
||||
|
||||
#define PrepareForSetPixel()
|
||||
|
||||
VOID
|
||||
SetPixel(
|
||||
_In_ ULONG Left,
|
||||
_In_ ULONG Top,
|
||||
_In_ UCHAR Color);
|
||||
7
drivers/base/bootvid/framebuf/lfbbvid.cmake
Normal file
7
drivers/base/bootvid/framebuf/lfbbvid.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
set(MODULE_HEADER ${CMAKE_CURRENT_LIST_DIR}/framebuf.h) # For precomp.h
|
||||
list(APPEND SOURCE
|
||||
${MODULE_HEADER}
|
||||
${CMAKE_CURRENT_LIST_DIR}/bootvid.c)
|
||||
|
||||
set(REACTOS_STR_FILE_DESCRIPTION "Generic Linear FrameBuffer Boot Driver")
|
||||
Reference in New Issue
Block a user