Implement framebuffer double buffering
All checks were successful
All checks were successful
This commit is contained in:
@@ -25,10 +25,9 @@ XTAPI
|
||||
VOID
|
||||
HL::FrameBuffer::ClearScreen(IN ULONG Color)
|
||||
{
|
||||
ULONG PositionX, PositionY;
|
||||
ULONG BackgroundColor;
|
||||
PCHAR CurrentLine;
|
||||
PULONG Pixel;
|
||||
ULONG BackgroundColor, PositionY;
|
||||
PCHAR CurrentLine, TargetBuffer;
|
||||
UCHAR FillByte;
|
||||
|
||||
/* Make sure frame buffer is already initialized */
|
||||
if(FrameBufferData.Initialized == FALSE)
|
||||
@@ -37,20 +36,29 @@ HL::FrameBuffer::ClearScreen(IN ULONG Color)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert background color and get pointer to frame buffer */
|
||||
/* Convert background color */
|
||||
BackgroundColor = GetRGBColor(Color);
|
||||
CurrentLine = (PCHAR)FrameBufferData.Address;
|
||||
|
||||
/* Extract the lower byte for SetMemory */
|
||||
FillByte = (UCHAR)(BackgroundColor & 0xFF);
|
||||
|
||||
/* Determine target buffer */
|
||||
TargetBuffer = (ScreenShadowBuffer != NULLPTR) ? (PCHAR)ScreenShadowBuffer : (PCHAR)FrameBufferData.Address;
|
||||
CurrentLine = TargetBuffer;
|
||||
|
||||
/* Fill the screen with the specified color */
|
||||
for(PositionY = 0; PositionY < FrameBufferData.Height; PositionY++, CurrentLine += FrameBufferData.Pitch)
|
||||
{
|
||||
/* Fill the current line with the specified color */
|
||||
Pixel = (PULONG)CurrentLine;
|
||||
for(PositionX = 0; PositionX < FrameBufferData.Width; PositionX++)
|
||||
{
|
||||
/* Set the color of the pixel */
|
||||
Pixel[PositionX] = BackgroundColor;
|
||||
}
|
||||
/* Fill the current scanline with the background color byte */
|
||||
RTL::Memory::SetMemory(CurrentLine, FillByte, FrameBufferData.Width * FrameBufferData.BytesPerPixel);
|
||||
}
|
||||
|
||||
/* Check if Shadow Buffer is active */
|
||||
if(ScreenShadowBuffer != NULLPTR)
|
||||
{
|
||||
/* Flush changes to VRAM */
|
||||
RTL::Memory::CopyMemory(FrameBufferData.Address, ScreenShadowBuffer,
|
||||
FrameBufferData.Pitch * FrameBufferData.Height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +76,9 @@ XTCDECL
|
||||
XTSTATUS
|
||||
HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
||||
{
|
||||
ULONG CharacterX, CharacterY;
|
||||
PSSFN_FONT_HEADER FbFont;
|
||||
BOOLEAN VisibleCharacter;
|
||||
|
||||
/* Make sure frame buffer is already initialized */
|
||||
if(FrameBufferData.Initialized == FALSE)
|
||||
@@ -80,6 +90,9 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
||||
/* Get font information */
|
||||
FbFont = (PSSFN_FONT_HEADER)FrameBufferData.Font;
|
||||
|
||||
/* Assume invisible character */
|
||||
VisibleCharacter = FALSE;
|
||||
|
||||
/* Handle special characters */
|
||||
switch(Character)
|
||||
{
|
||||
@@ -91,15 +104,20 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
||||
case L'\t':
|
||||
/* Move cursor to the next tab stop */
|
||||
ScrollRegionData.CursorX += (8 - (ScrollRegionData.CursorX - ScrollRegionData.Left) / FbFont->Width % 8) * FbFont->Width;
|
||||
if (ScrollRegionData.CursorX >= ScrollRegionData.Right)
|
||||
if(ScrollRegionData.CursorX >= ScrollRegionData.Right)
|
||||
{
|
||||
ScrollRegionData.CursorX = ScrollRegionData.Left;
|
||||
ScrollRegionData.CursorY += FbFont->Height;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Draw the character */
|
||||
DrawCharacter(ScrollRegionData.CursorX, ScrollRegionData.CursorY, ScrollRegionData.TextColor, Character);
|
||||
/* Save cursor position */
|
||||
CharacterX = ScrollRegionData.CursorX;
|
||||
CharacterY = ScrollRegionData.CursorY;
|
||||
|
||||
/* Draw the character to RAM and mark it as visible */
|
||||
DrawCharacter(CharacterX, CharacterY, ScrollRegionData.TextColor, Character);
|
||||
VisibleCharacter = TRUE;
|
||||
|
||||
/* Advance cursor */
|
||||
ScrollRegionData.CursorX += FbFont->Width;
|
||||
@@ -107,6 +125,7 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
||||
/* Check if cursor reached end of line */
|
||||
if(ScrollRegionData.CursorX >= ScrollRegionData.Right)
|
||||
{
|
||||
/* Reset cursor to the left margin and advance to the next line */
|
||||
ScrollRegionData.CursorX = ScrollRegionData.Left;
|
||||
ScrollRegionData.CursorY += FbFont->Height;
|
||||
}
|
||||
@@ -120,6 +139,13 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
||||
ScrollRegion();
|
||||
ScrollRegionData.CursorY = ScrollRegionData.Bottom - FbFont->Height;
|
||||
}
|
||||
else if(VisibleCharacter == TRUE)
|
||||
{
|
||||
/* Flush visible character to VRAM */
|
||||
UpdateScreenRegion(CharacterX, CharacterY,
|
||||
CharacterX + FbFont->Width,
|
||||
CharacterY + FbFont->Height);
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
@@ -153,9 +179,8 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
||||
{
|
||||
UINT CurrentFragment, Glyph, GlyphLimit, Index, Line, Mapping;
|
||||
PUCHAR Character, CharacterMapping, Fragment;
|
||||
UINT_PTR GlyphPixel, Pixel;
|
||||
ULONG FontColor, GlyphOffset, PixelOffset;
|
||||
PSSFN_FONT_HEADER FbFont;
|
||||
ULONG FontColor;
|
||||
|
||||
/* Make sure frame buffer is already initialized */
|
||||
if(FrameBufferData.Initialized == FALSE)
|
||||
@@ -192,7 +217,7 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There's a glyph for this character, check if it matches */
|
||||
/* There is a glyph for this character, check if it matches */
|
||||
if(Index == WideCharacter)
|
||||
{
|
||||
/* Found the character, break loop */
|
||||
@@ -213,8 +238,7 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
||||
}
|
||||
|
||||
/* Find the glyph position on the frame buffer and set font color */
|
||||
GlyphPixel = (UINT_PTR)FrameBufferData.Address + PositionY * FrameBufferData.Pitch +
|
||||
PositionX * FrameBufferData.BytesPerPixel;
|
||||
GlyphOffset = (PositionY * FrameBufferData.Pitch) + (PositionX * FrameBufferData.BytesPerPixel);
|
||||
FontColor = GetRGBColor(Color);
|
||||
|
||||
/* Check all kerning fragments */
|
||||
@@ -243,7 +267,7 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
||||
}
|
||||
|
||||
/* Get initial glyph line */
|
||||
GlyphPixel += (CharacterMapping[1] - Mapping) * FrameBufferData.Pitch;
|
||||
GlyphOffset += (CharacterMapping[1] - Mapping) * FrameBufferData.Pitch;
|
||||
Mapping = CharacterMapping[1];
|
||||
|
||||
/* Extract glyph data from fragments table and advance */
|
||||
@@ -255,7 +279,8 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
||||
CurrentFragment = 1;
|
||||
while(GlyphLimit--)
|
||||
{
|
||||
Pixel = GlyphPixel;
|
||||
/* Set the initial pixel offset for the current glyph fragment */
|
||||
PixelOffset = GlyphOffset;
|
||||
for(Line = 0; Line < Glyph; Line++)
|
||||
{
|
||||
/* Decode compressed offsets */
|
||||
@@ -269,17 +294,26 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
||||
/* Check if pixel should be drawn */
|
||||
if(*Fragment & CurrentFragment)
|
||||
{
|
||||
/* Draw glyph pixel */
|
||||
*((PULONG)Pixel) = FontColor;
|
||||
/* Route the pixel draw operation to the active buffer */
|
||||
if(ScreenShadowBuffer != NULLPTR)
|
||||
{
|
||||
/* Draw glyph pixel to Shadow Buffer */
|
||||
*((PULONG)((PCHAR)ScreenShadowBuffer + PixelOffset)) = FontColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Draw glyph pixel directly to VRAM */
|
||||
*((PULONG)((PCHAR)FrameBufferData.Address + PixelOffset)) = FontColor;
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance pixel pointer */
|
||||
Pixel += FrameBufferData.BytesPerPixel;
|
||||
PixelOffset += FrameBufferData.BytesPerPixel;
|
||||
CurrentFragment <<= 1;
|
||||
}
|
||||
|
||||
/* Advance to next line and increase mapping */
|
||||
GlyphPixel += FrameBufferData.Pitch;
|
||||
GlyphOffset += FrameBufferData.Pitch;
|
||||
Mapping++;
|
||||
}
|
||||
|
||||
@@ -310,7 +344,7 @@ HL::FrameBuffer::DrawPixel(IN ULONG PositionX,
|
||||
IN ULONG PositionY,
|
||||
IN ULONG Color)
|
||||
{
|
||||
PCHAR PixelAddress;
|
||||
ULONG Offset;
|
||||
|
||||
/* Make sure frame buffer is already initialized */
|
||||
if(FrameBufferData.Initialized == FALSE)
|
||||
@@ -327,11 +361,67 @@ HL::FrameBuffer::DrawPixel(IN ULONG PositionX,
|
||||
}
|
||||
|
||||
/* Calculate the address of the pixel in the frame buffer memory */
|
||||
PixelAddress = (PCHAR)FrameBufferData.Address + (PositionY * FrameBufferData.Pitch) +
|
||||
(PositionX * FrameBufferData.BytesPerPixel);
|
||||
Offset = (PositionY * FrameBufferData.Pitch) + (PositionX * FrameBufferData.BytesPerPixel);
|
||||
|
||||
/* Set the color of the pixel by writing to the corresponding memory location */
|
||||
*((PULONG)PixelAddress) = GetRGBColor(Color);
|
||||
/* Route the pixel draw operation to the active buffer */
|
||||
if(ScreenShadowBuffer != NULLPTR)
|
||||
{
|
||||
/* Set the color of the pixel by writing to the corresponding memory location (RAM) */
|
||||
*((PULONG)((PCHAR)ScreenShadowBuffer + Offset)) = GetRGBColor(Color);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set the color of the pixel by writing to the corresponding memory location (VRAM) */
|
||||
*((PULONG)((PCHAR)FrameBufferData.Address + Offset)) = GetRGBColor(Color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the Shadow Buffer (Double Buffering) for high-performance rendering.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
XTSTATUS
|
||||
HL::FrameBuffer::EnableShadowBuffer(VOID)
|
||||
{
|
||||
ULONG FrameBufferSize;
|
||||
XTSTATUS Status;
|
||||
|
||||
/* Check if the shadow buffer is already enabled */
|
||||
if(ScreenShadowBuffer != NULLPTR)
|
||||
{
|
||||
/* Nothing to do, return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Make sure frame buffer is already initialized */
|
||||
if(FrameBufferData.Initialized == FALSE)
|
||||
{
|
||||
/* Unable to operate on non-initialized frame buffer */
|
||||
return STATUS_DEVICE_NOT_READY;
|
||||
}
|
||||
|
||||
/* Calculate the total size of the framebuffer */
|
||||
FrameBufferSize = FrameBufferData.Pitch * FrameBufferData.Height;
|
||||
|
||||
/* Allocate non-paged memory for the shadow buffer */
|
||||
Status = MM::Allocator::AllocatePool(NonPagedPool, FrameBufferSize,
|
||||
&ScreenShadowBuffer, SIGNATURE32('F', 'B', 'U', 'F'));
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Allocation failed, return status code */
|
||||
ScreenShadowBuffer = NULLPTR;
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Synchronize the newly allocated shadow buffer with the current on-screen contents */
|
||||
RTL::Memory::CopyMemory(ScreenShadowBuffer, FrameBufferData.Address, FrameBufferSize);
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,10 +634,9 @@ XTAPI
|
||||
VOID
|
||||
HL::FrameBuffer::ScrollRegion(VOID)
|
||||
{
|
||||
PCHAR Destination, Source;
|
||||
PCHAR TargetBuffer, Destination, Source;
|
||||
ULONG Line, PositionX, LineBytes;
|
||||
PSSFN_FONT_HEADER FbFont;
|
||||
ULONG Line, PositionX;
|
||||
ULONG LineBytes;
|
||||
PULONG Pixel;
|
||||
|
||||
/* Make sure frame buffer is already initialized */
|
||||
@@ -557,37 +646,132 @@ HL::FrameBuffer::ScrollRegion(VOID)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get font information */
|
||||
/* Retrieve font metrics and calculate line properties for the scroll operation */
|
||||
FbFont = (PSSFN_FONT_HEADER)FrameBufferData.Font;
|
||||
|
||||
/* Calculate bytes per line in the scroll region */
|
||||
LineBytes = (ScrollRegionData.Right - ScrollRegionData.Left) * FrameBufferData.BytesPerPixel;
|
||||
TargetBuffer = (ScreenShadowBuffer != NULLPTR) ? (PCHAR)ScreenShadowBuffer : (PCHAR)FrameBufferData.Address;
|
||||
|
||||
/* Scroll up each scan line in the scroll region */
|
||||
for(Line = ScrollRegionData.Top; Line < ScrollRegionData.Bottom - FbFont->Height; Line++)
|
||||
/* Process every line in the scroll region */
|
||||
for(Line = ScrollRegionData.Top; Line < ScrollRegionData.Bottom; Line++)
|
||||
{
|
||||
Destination = (PCHAR)FrameBufferData.Address + Line * FrameBufferData.Pitch +
|
||||
ScrollRegionData.Left * FrameBufferData.BytesPerPixel;
|
||||
/* Calculate destination address for the current line */
|
||||
Destination = TargetBuffer + (Line * FrameBufferData.Pitch) +
|
||||
(ScrollRegionData.Left * FrameBufferData.BytesPerPixel);
|
||||
|
||||
/* The source is one full text line (FbFont->Height) below the destination */
|
||||
Source = (PCHAR)FrameBufferData.Address + (Line + FbFont->Height) * FrameBufferData.Pitch +
|
||||
ScrollRegionData.Left * FrameBufferData.BytesPerPixel;
|
||||
|
||||
/* Move each scan line in the scroll region up */
|
||||
RTL::Memory::MoveMemory(Destination, Source, LineBytes);
|
||||
}
|
||||
|
||||
/* Clear the last text line */
|
||||
for(Line = ScrollRegionData.Bottom - FbFont->Height; Line < ScrollRegionData.Bottom; Line++)
|
||||
{
|
||||
/* Get pointer to the start of the scan line to clear */
|
||||
Pixel = (PULONG)((PCHAR)FrameBufferData.Address + Line * FrameBufferData.Pitch +
|
||||
ScrollRegionData.Left * FrameBufferData.BytesPerPixel);
|
||||
|
||||
/* Clear each pixel in the scan line with the background color */
|
||||
for(PositionX = 0; PositionX < (ScrollRegionData.Right - ScrollRegionData.Left); PositionX++)
|
||||
/* Check if the current line needs to be copied from below or cleared */
|
||||
if(Line < ScrollRegionData.Bottom - FbFont->Height)
|
||||
{
|
||||
Pixel[PositionX] = ScrollRegionData.BackgroundColor;
|
||||
/* Copy the line from below */
|
||||
Source = Destination + (FbFont->Height * FrameBufferData.Pitch);
|
||||
RTL::Memory::CopyMemory(Destination, Source, LineBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fill the bottom line(s) with the background color */
|
||||
Pixel = (PULONG)Destination;
|
||||
for(PositionX = 0; PositionX < (ScrollRegionData.Right - ScrollRegionData.Left); PositionX++)
|
||||
{
|
||||
/* Overwrite the pixel with the background color */
|
||||
Pixel[PositionX] = ScrollRegionData.BackgroundColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush changes to VRAM if Shadow Buffer was used */
|
||||
if(ScreenShadowBuffer != NULLPTR)
|
||||
{
|
||||
/* Flush the updated scroll region to VRAM */
|
||||
UpdateScreenRegion(ScrollRegionData.Left,
|
||||
ScrollRegionData.Top,
|
||||
ScrollRegionData.Right,
|
||||
ScrollRegionData.Bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the current content of the Shadow Buffer to the visible FrameBuffer (VRAM).
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
HL::FrameBuffer::UpdateScreen(VOID)
|
||||
{
|
||||
/* Make sure framebuffer is already initialized and shadow buffer is ready */
|
||||
if(FrameBufferData.Initialized == FALSE || ScreenShadowBuffer == NULLPTR)
|
||||
{
|
||||
/* Unable to operate on non-initialized frame buffer */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Flush RAM to VRAM */
|
||||
RTL::Memory::CopyMemory(FrameBufferData.Address,
|
||||
ScreenShadowBuffer,
|
||||
FrameBufferData.Pitch * FrameBufferData.Height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes a specific rectangular region from the Shadow Buffer to the visible FrameBuffer (VRAM).
|
||||
*
|
||||
* @param Left
|
||||
* Supplies the left pixel coordinate of the region to update.
|
||||
*
|
||||
* @param Top
|
||||
* Supplies the top pixel coordinate of the region to update.
|
||||
*
|
||||
* @param Right
|
||||
* Supplies the right pixel coordinate of the region to update.
|
||||
*
|
||||
* @param Bottom
|
||||
* Supplies the bottom pixel coordinate of the region to update.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
HL::FrameBuffer::UpdateScreenRegion(IN ULONG Left,
|
||||
IN ULONG Top,
|
||||
IN ULONG Right,
|
||||
IN ULONG Bottom)
|
||||
{
|
||||
ULONG Line, LineBytes;
|
||||
PCHAR Source, Destination;
|
||||
|
||||
/* Make sure framebuffer is already initialized and shadow buffer is ready */
|
||||
if(FrameBufferData.Initialized == FALSE || ScreenShadowBuffer == NULLPTR)
|
||||
{
|
||||
/* Unable to operate on non-initialized frame buffer */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure parameters are valid to prevent memory corruption */
|
||||
if(Left >= Right || Top >= Bottom || Right > FrameBufferData.Width || Bottom > FrameBufferData.Height)
|
||||
{
|
||||
/* Invalid region coordinates provided */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate the width of the region */
|
||||
LineBytes = (Right - Left) * FrameBufferData.BytesPerPixel;
|
||||
|
||||
/* Copy the specified region line by line */
|
||||
for(Line = Top; Line < Bottom; Line++)
|
||||
{
|
||||
/* Calculate the source address in the shadow buffer */
|
||||
Source = (PCHAR)ScreenShadowBuffer +
|
||||
(Line * FrameBufferData.Pitch) +
|
||||
(Left * FrameBufferData.BytesPerPixel);
|
||||
|
||||
/* Calculate the destination address in the VRAM */
|
||||
Destination = (PCHAR)FrameBufferData.Address +
|
||||
(Line * FrameBufferData.Pitch) +
|
||||
(Left * FrameBufferData.BytesPerPixel);
|
||||
|
||||
/* Flush RAM to VRAM */
|
||||
RTL::Memory::CopyMemory(Destination, Source, LineBytes);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user