[BOOTVID]
[reactos.git] / reactos / drivers / base / bootvid / i386 / vga.c
index 1c80994..71754c5 100644 (file)
@@ -63,13 +63,19 @@ ULONG lookup[16] =
     0x1111,
 };
 
-ULONG TextColor = 0xF;
+ULONG VidTextColor = 0xF;
 ULONG curr_x = 0;
 ULONG curr_y = 0;
-BOOLEAN NextLine = FALSE;
+BOOLEAN CarriageReturn = FALSE;
 ULONG_PTR VgaRegisterBase = 0;
 ULONG_PTR VgaBase = 0;
 
+#define __outpb(Port, Value) \
+    WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + Port, (UCHAR)Value)
+
+#define __outpw(Port, Value) \
+    WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase + Port), (USHORT)Value)
+
 /* PRIVATE FUNCTIONS *********************************************************/
 
 VOID
@@ -79,35 +85,18 @@ ReadWriteMode(UCHAR Mode)
     UCHAR Value;
 
     /* Switch to graphics mode register */
-    WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 5);
+    __outpb(0x3CE, 5);
 
     /* Get the current register value, minus the current mode */
     Value = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) & 0xF4;
 
     /* Set the new mode */
-    WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, Mode | Value);
-}
-
-VOID
-NTAPI
-__outpb(IN ULONG Port,
-        IN ULONG Value)
-{
-    /* Write to the VGA Register */
-    WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + Port, (UCHAR)Value);
+    __outpb(0x3CF, Mode | Value);
 }
 
-VOID
-NTAPI
-__outpw(IN ULONG Port,
-        IN ULONG Value)
-{
-    /* Write to the VGA Register */
-    WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase + Port), (USHORT)Value);
-}
 
+FORCEINLINE
 VOID
-NTAPI
 SetPixel(IN ULONG Left,
          IN ULONG Top,
          IN UCHAR Color)
@@ -117,15 +106,6 @@ SetPixel(IN ULONG Left,
     /* Calculate the pixel position. */
     PixelPosition = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80);
 
-    /* Switch to mode 10 */
-    ReadWriteMode(10);
-
-    /* Clear the 4 planes (we're already in unchained mode here) */
-    __outpw(0x3C4, 0xF02);
-
-    /* Select the color don't care register */
-    __outpw(0x3CE, 7);
-
     /* Select the bitmask register and write the mask */
     __outpw(0x3CE, (PixelMask[Left & 7] << 8) | 8);
 
@@ -134,54 +114,120 @@ SetPixel(IN ULONG Left,
                          READ_REGISTER_UCHAR(PixelPosition) & Color);
 }
 
+#ifdef CHAR_GEN_UPSIDE_DOWN
+# define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1;
+# define FONT_PTR_DELTA (-1)
+#else
+# define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT];
+# define FONT_PTR_DELTA (1)
+#endif
+
+#define SET_PIXELS(_PixelPtr, _PixelMask, _TextColor) \
+    /* Select the bitmask register and write the mask */ \
+    __outpw(0x3CE, (_PixelMask << 8) | 8); \
+\
+    /* Set the new color */ \
+    WRITE_REGISTER_UCHAR(_PixelPtr, (UCHAR)_TextColor);\
+
 VOID
 NTAPI
 DisplayCharacter(CHAR Character,
                  ULONG Left,
                  ULONG Top,
                  ULONG TextColor,
-                 ULONG BackTextColor)
+                 ULONG BackColor)
 {
-    PUCHAR FontChar;
-    ULONG i, j, XOffset;
+    PUCHAR FontChar, PixelPtr;
+    ULONG Height;
+    UCHAR Shift;
+
+    /* Switch to mode 10 */
+    ReadWriteMode(10);
+
+    /* Clear the 4 planes (we're already in unchained mode here) */
+    __outpw(0x3C4, 0xF02);
+
+    /* Select the color don't care register */
+    __outpw(0x3CE, 7);
 
-    /* Get the font line for this character */
-    FontChar = &FontData[Character * BOOTCHAR_HEIGHT];
+    /* Calculate shift */
+    Shift = Left & 7;
 
-    /* Loop each pixel height */
-    i = BOOTCHAR_HEIGHT;
+    /* Get the font and pixel pointer */
+    FontChar = GetFontPtr(Character);
+    PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80);
+
+    /* Loop all pixel rows */
+    Height = BOOTCHAR_HEIGHT;
     do
     {
-        /* Loop each pixel width */
-        j = 128;
-        XOffset = Left;
+        SET_PIXELS(PixelPtr, *FontChar >> Shift, TextColor);
+        PixelPtr += 80;
+        FontChar += FONT_PTR_DELTA;
+    } while (--Height);
+
+    /* Check if we need to update neighbor bytes */
+    if (Shift)
+    {
+        /* Calculate shift for 2nd byte */
+        Shift = 8 - Shift;
+
+        /* Get the font and pixel pointer (2nd byte) */
+        FontChar = GetFontPtr(Character);
+        PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80) + 1;
+
+        /* Loop all pixel rows */
+        Height = BOOTCHAR_HEIGHT;
         do
         {
-            /* Check if we should draw this pixel */
-#ifdef CHAR_GEN_UPSIDE_DOWN
-            if (FontChar[i] & (UCHAR)j)
-#else
-            /* Normal character generator (top of char is first element) */
-            if (FontChar[BOOTCHAR_HEIGHT - i] & (UCHAR)j)
-#endif
-            {
-                /* We do, use the given Text Color */
-                SetPixel(XOffset, Top, (UCHAR)TextColor);
-            }
-            else if (BackTextColor < 16)
-            {
-                /* This is a background pixel. */
-                /* We're drawing it unless it's transparent. */
-                SetPixel(XOffset, Top, (UCHAR)BackTextColor);
-            }
+            SET_PIXELS(PixelPtr, *FontChar << Shift, TextColor);
+            PixelPtr += 80;
+            FontChar += FONT_PTR_DELTA;
+        } while (--Height);
+    }
+
+    /* Check if the background color is transparent */
+    if (BackColor >= 16)
+    {
+        /* We are done */
+        return;
+    }
+
+    /* Calculate shift */
+    Shift = Left & 7;
 
-            /* Increase X Offset */
-            XOffset++;
-        } while (j >>= 1);
+    /* Get the font and pixel pointer */
+    FontChar = GetFontPtr(Character);
+    PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80);
+
+    /* Loop all pixel rows */
+    Height = BOOTCHAR_HEIGHT;
+    do
+    {
+        SET_PIXELS(PixelPtr, ~*FontChar >> Shift, BackColor);
+        PixelPtr += 80;
+        FontChar += FONT_PTR_DELTA;
+    } while (--Height);
 
-        /* Move to the next Y ordinate */
-        Top++;
-    } while (--i);
+    /* Check if we need to update neighbor bytes */
+    if (Shift)
+    {
+        /* Calculate shift for 2nd byte */
+        Shift = 8 - Shift;
+
+        /* Get the font and pixel pointer (2nd byte) */
+        FontChar = GetFontPtr(Character);
+        PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80) + 1;
+
+        /* Loop all pixel rows */
+        Height = BOOTCHAR_HEIGHT;
+        do
+        {
+            SET_PIXELS(PixelPtr, ~*FontChar << Shift, BackColor);
+            PixelPtr += 80;
+            FontChar += FONT_PTR_DELTA;
+        } while (--Height);
+    }
 }
 
 VOID
@@ -280,14 +326,8 @@ VOID
 NTAPI
 VgaScroll(ULONG Scroll)
 {
-    ULONG Top;
-    ULONG SourceOffset, DestOffset;
-    ULONG Offset;
-    ULONG i, j;
-
-    /* Set memory positions of the scroll */
-    SourceOffset = VgaBase + (ScrollRegion[1] * 80) + (ScrollRegion[0] >> 3);
-    DestOffset = SourceOffset + (Scroll * 80);
+    ULONG Top, RowSize;
+    PUCHAR OldPosition, NewPosition;
 
     /* Clear the 4 planes */
     __outpw(0x3C4, 0xF02);
@@ -298,49 +338,27 @@ VgaScroll(ULONG Scroll)
     /* Set Mode 1 */
     ReadWriteMode(1);
 
-    /* Save top and check if it's above the bottom */
-    Top = ScrollRegion[1];
-    if (Top > ScrollRegion[3]) return;
+    RowSize = (ScrollRegion[2] - ScrollRegion[0] + 1) / 8;
+
+    /* Calculate the position in memory for the row */
+    OldPosition = (PUCHAR)VgaBase + (ScrollRegion[1] + Scroll) * 80 + ScrollRegion[0] / 8;
+    NewPosition = (PUCHAR)VgaBase + ScrollRegion[1] * 80 + ScrollRegion[0] / 8;
 
     /* Start loop */
-    do
+    for(Top = ScrollRegion[1]; Top <= ScrollRegion[3]; ++Top)
     {
-        /* Set number of bytes to loop and start offset */
-        Offset = ScrollRegion[0] >> 3;
-        j = SourceOffset;
-
-        /* Check if this is part of the scroll region */
-        if (Offset <= (ScrollRegion[2] >> 3))
-        {
-            /* Update position */
-            i = DestOffset - SourceOffset;
-
-            /* Loop the X axis */
-            do
-            {
-                /* Write value in the new position so that we can do the scroll */
-                WRITE_REGISTER_UCHAR(UlongToPtr(j),
-                                     READ_REGISTER_UCHAR(UlongToPtr(j + i)));
-
-                /* Move to the next memory location to write to */
-                j++;
-
-                /* Move to the next byte in the region */
-                Offset++;
-
-                /* Make sure we don't go past the scroll region */
-            } while (Offset <= (ScrollRegion[2] >> 3));
-        }
-
-        /* Move to the next line */
-        SourceOffset += 80;
-        DestOffset += 80;
-
-        /* Increase top */
-        Top++;
+#if defined(_M_IX86) || defined(_M_AMD64)
+        __movsb(NewPosition, OldPosition, RowSize);
+#else
+        ULONG i;
 
-        /* Make sure we don't go past the scroll region */
-    } while (Top <= ScrollRegion[3]);
+        /* Scroll the row */
+        for(i = 0; i < RowSize; ++i)
+            WRITE_REGISTER_UCHAR(NewPosition + i, READ_REGISTER_UCHAR(OldPosition + i));
+#endif
+        OldPosition += 80;
+        NewPosition += 80;
+    }
 }
 
 VOID
@@ -377,19 +395,21 @@ PreserveRow(IN ULONG CurrentTop,
 
     /* Set the count and make sure it's above 0 */
     Count = TopDelta * 80;
-    if (Count)
+
+#if defined(_M_IX86) || defined(_M_AMD64)
+    __movsb(Position1, Position2, Count);
+#else
+    /* Loop every pixel */
+    while (Count--)
     {
-        /* Loop every pixel */
-        do
-        {
-            /* Write the data back on the other position */
-            WRITE_REGISTER_UCHAR(Position1, READ_REGISTER_UCHAR(Position2));
+        /* Write the data back on the other position */
+        WRITE_REGISTER_UCHAR(Position1, READ_REGISTER_UCHAR(Position2));
 
-            /* Increase both positions */
-            Position2++;
-            Position1++;
-        } while (--Count);
+        /* Increase both positions */
+        Position2++;
+        Position1++;
     }
+#endif
 }
 
 VOID
@@ -426,6 +446,15 @@ BitBlt(IN ULONG Left,
         return;
     }
 
+    /* Switch to mode 10 */
+    ReadWriteMode(10);
+
+    /* Clear the 4 planes (we're already in unchained mode here) */
+    __outpw(0x3C4, 0xF02);
+
+    /* Select the color don't care register */
+    __outpw(0x3CE, 7);
+
     /* 4bpp blitting */
     dy = Top;
     do
@@ -465,6 +494,15 @@ RleBitBlt(IN ULONG Left,
     ULONG i, j;
     ULONG Code;
 
+    /* Switch to mode 10 */
+    ReadWriteMode(10);
+
+    /* Clear the 4 planes (we're already in unchained mode here) */
+    __outpw(0x3C4, 0xF02);
+
+    /* Select the color don't care register */
+    __outpw(0x3CE, 7);
+
     /* Set Y height and current X value and start loop */
     YDelta = Top + Height - 1;
     x = Left;
@@ -651,8 +689,8 @@ VidSetTextColor(ULONG Color)
     ULONG OldColor;
 
     /* Save the old color and set the new one */
-    OldColor = TextColor;
-    TextColor = Color;
+    OldColor = VidTextColor;
+    VidTextColor = Color;
     return OldColor;
 }
 
@@ -739,7 +777,7 @@ VOID
 NTAPI
 VidDisplayString(PUCHAR String)
 {
-    ULONG TopDelta = 14;
+    ULONG TopDelta = BOOTCHAR_HEIGHT + 1;
 
     /* Start looping the string */
     while (*String)
@@ -749,21 +787,23 @@ VidDisplayString(PUCHAR String)
         {
             /* Modify Y position */
             curr_y += TopDelta;
-            if (curr_y >= ScrollRegion[3])
+            if (curr_y + TopDelta >= ScrollRegion[3])
             {
                 /* Scroll the view */
                 VgaScroll(TopDelta);
                 curr_y -= TopDelta;
-
+            }
+            else
+            {
                 /* Preserve row */
-                PreserveRow(curr_y, TopDelta, TRUE);
+                PreserveRow(curr_y, TopDelta, FALSE);
             }
 
             /* Update current X */
             curr_x = ScrollRegion[0];
 
-            /* Preseve the current row */
-            PreserveRow(curr_y, TopDelta, FALSE);
+            /* Do not clear line if "\r\n" is given */
+            CarriageReturn = FALSE;
         }
         else if (*String == '\r')
         {
@@ -771,35 +811,37 @@ VidDisplayString(PUCHAR String)
             curr_x = ScrollRegion[0];
 
             /* Check if we're being followed by a new line */
-            if (String[1] != '\n') NextLine = TRUE;
+            CarriageReturn = TRUE;
         }
         else
         {
-            /* Check if we had a \n\r last time */
-            if (NextLine)
+            /* check if we had a '\r' last time */
+            if (CarriageReturn)
             {
-                /* We did, preserve the current row */
+                /* We did, clear the current row */
                 PreserveRow(curr_y, TopDelta, TRUE);
-                NextLine = FALSE;
+                CarriageReturn = FALSE;
             }
 
             /* Display this character */
-            DisplayCharacter(*String, curr_x, curr_y, TextColor, 16);
+            DisplayCharacter(*String, curr_x, curr_y, VidTextColor, 16);
             curr_x += 8;
 
             /* Check if we should scroll */
-            if (curr_x > ScrollRegion[2])
+            if (curr_x + 8 > ScrollRegion[2])
             {
                 /* Update Y position and check if we should scroll it */
                 curr_y += TopDelta;
-                if (curr_y > ScrollRegion[3])
+                if (curr_y + TopDelta > ScrollRegion[3])
                 {
                     /* Do the scroll */
                     VgaScroll(TopDelta);
                     curr_y -= TopDelta;
-
-                    /* Save the row */
-                    PreserveRow(curr_y, TopDelta, TRUE);
+                }
+                else
+                {
+                    /* Preserve the current row */
+                    PreserveRow(curr_y, TopDelta, FALSE);
                 }
 
                 /* Update X */
@@ -1110,4 +1152,3 @@ VidSolidColorFill(IN ULONG Left,
         }
     }
 }
-