[NTVDM]: Implement double-width and double-height separately; used when eg. an app...
[reactos.git] / reactos / subsystems / ntvdm / hardware / vga.c
index 4593a5d..1e33af5 100644 (file)
 static CONST DWORD MemoryBase[]  = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
 static CONST DWORD MemoryLimit[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
 
+/*
+ * Activate this line if you want to use the real
+ * RegisterConsoleVDM API of ReactOS/Windows.
+ */
+// #define USE_REAL_REGISTERCONSOLEVDM
+
 #define USE_REACTOS_COLORS
 // #define USE_DOSBOX_COLORS
 
@@ -234,7 +240,9 @@ static HANDLE TextConsoleBuffer = NULL;
 /* Graphics mode */
 static HANDLE GraphicsConsoleBuffer = NULL;
 static HANDLE ConsoleMutex = NULL;
-static BOOLEAN DoubleVision = FALSE;
+/* DoubleVision support */
+static BOOLEAN DoubleWidth  = FALSE;
+static BOOLEAN DoubleHeight = FALSE;
 
 /*
  * VGA Hardware
@@ -288,44 +296,12 @@ static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
 
 #include <ntddvdeo.h>
 
-typedef
-BOOL
-(WINAPI *pRegisterConsoleVDM)
-(
-    BOOL IsDosVDM_flag,
-    HANDLE EventHandle_1,
-    HANDLE EventHandle_2,
-    HANDLE EventHandle_3,
-    int Unused1,
-    PVOID returned_val_1,
-    PVOID *returned_val_2,
-    PVOID lpUnknownBuffer,
-    DWORD theUnknownBufferLength,
-    COORD theVDMBufferSize,
-    PCHAR *lpVDMBuffer
-);
-
-#if 0
-BOOL
-WINAPI
-RegisterConsoleVDM
-(
-    BOOL IsDosVDM_flag,
-    HANDLE EventHandle_1,
-    HANDLE EventHandle_2,
-    HANDLE EventHandle_3,
-    int Unused1,
-    PVOID returned_val_1,
-    PVOID *returned_val_2,
-    PVOID lpUnknownBuffer,
-    DWORD theUnknownBufferLength,
-    COORD theVDMBufferSize,
-    PVOID *lpVDMBuffer
-);
-
-HMODULE hKernel32 = NULL;
-pRegisterConsoleVDM RegisterConsoleVDM = NULL;
-#endif
+#ifdef USE_REAL_REGISTERCONSOLEVDM
+
+#define __RegisterConsoleVDM        RegisterConsoleVDM
+#define __InvalidateConsoleDIBits   InvalidateConsoleDIBits
+
+#else
 
 /*
  * This private buffer, per-console, is used by
@@ -340,49 +316,49 @@ static PCHAR_INFO CharBuff  = NULL; // This is a hack, which is unneeded
 
 BOOL
 WINAPI
-__RegisterConsoleVDM(BOOL IsDosVDM_flag,
-                     HANDLE EventHandle_1,
-                     HANDLE EventHandle_2,
-                     HANDLE EventHandle_3,
-                     int Unused1,
-                     PVOID returned_val_1,
-                     PVOID *returned_val_2,
-                     PVOID lpUnknownBuffer,
-                     DWORD theUnknownBufferLength,
-                     COORD theVDMBufferSize,
-                     PCHAR *lpVDMBuffer)
+__RegisterConsoleVDM(IN DWORD dwRegisterFlags,
+                     IN HANDLE hStartHardwareEvent,
+                     IN HANDLE hEndHardwareEvent,
+                     IN HANDLE hErrorHardwareEvent,
+                     IN DWORD dwUnusedVar,
+                     OUT LPDWORD lpVideoStateLength,
+                     OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
+                     IN PVOID lpUnusedBuffer,
+                     IN DWORD dwUnusedBufferLength,
+                     IN COORD dwVDMBufferSize,
+                     OUT PVOID* lpVDMBuffer)
 {
-    UNREFERENCED_PARAMETER(EventHandle_3);
-    UNREFERENCED_PARAMETER(Unused1);
-    UNREFERENCED_PARAMETER(returned_val_1);
-    UNREFERENCED_PARAMETER(returned_val_2);
-    UNREFERENCED_PARAMETER(lpUnknownBuffer);
-    UNREFERENCED_PARAMETER(theUnknownBufferLength);
+    UNREFERENCED_PARAMETER(hErrorHardwareEvent);
+    UNREFERENCED_PARAMETER(dwUnusedVar);
+    UNREFERENCED_PARAMETER(lpVideoStateLength);
+    UNREFERENCED_PARAMETER(lpVideoState);
+    UNREFERENCED_PARAMETER(lpUnusedBuffer);
+    UNREFERENCED_PARAMETER(dwUnusedBufferLength);
 
     SetLastError(0);
-    DPRINT1("__RegisterConsoleVDM(%d)\n", IsDosVDM_flag);
+    DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags);
 
     if (lpVDMBuffer == NULL) return FALSE;
 
-    if (IsDosVDM_flag)
+    if (dwRegisterFlags != 0)
     {
-        // if (EventHandle_1 == NULL || EventHandle_2 == NULL) return FALSE;
+        // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
         if (VDMBuffer != NULL) return FALSE;
 
-        VDMBufferSize = theVDMBufferSize;
+        VDMBufferSize = dwVDMBufferSize;
 
         /* HACK: Cache -- to be removed in the real implementation */
         CharBuff = HeapAlloc(GetProcessHeap(),
                              HEAP_ZERO_MEMORY,
-                             theVDMBufferSize.X * theVDMBufferSize.Y
-                                                * sizeof(CHAR_INFO));
+                             VDMBufferSize.X * VDMBufferSize.Y
+                                             * sizeof(CHAR_INFO));
         ASSERT(CharBuff);
 
         VDMBuffer = HeapAlloc(GetProcessHeap(),
                               HEAP_ZERO_MEMORY,
-                              theVDMBufferSize.X * theVDMBufferSize.Y
-                                                 * sizeof(CHAR_CELL));
-        *lpVDMBuffer = (PCHAR)VDMBuffer;
+                              VDMBufferSize.X * VDMBufferSize.Y
+                                              * sizeof(CHAR_CELL));
+        *lpVDMBuffer = VDMBuffer;
         return (VDMBuffer != NULL);
     }
     else
@@ -432,6 +408,8 @@ __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
     return InvalidateConsoleDIBits(hConsoleOutput, lpRect);
 }
 
+#endif
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
 static inline DWORD VgaGetAddressSize(VOID);
@@ -458,6 +436,9 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
     ULONG Length = 0;
     PVIDEO_HARDWARE_STATE_HEADER State;
 
+#ifdef USE_REAL_REGISTERCONSOLEVDM
+    PCHAR_INFO CharBuff = NULL;
+#endif
     SHORT i, j;
     DWORD AddressSize, ScanlineSize;
     DWORD Address = 0;
@@ -472,7 +453,7 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
     /*
      * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
      * in the two following APIs:
-     * SrvRegisterConsoleVDM  (corresponding win32 API: RegisterConsoleVDM)
+     * SrvRegisterConsoleVDM  (corresponding Win32 API: RegisterConsoleVDM)
      * SrvVDMConsoleOperation (corresponding Win32 API: )
      * to check whether the current process is a VDM process, and fails otherwise with the
      * error 0xC0000022 ().
@@ -492,7 +473,7 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
                          NULL,
                          0,
                          TextResolution,
-                         (PCHAR*)&TextFramebuffer);
+                         (PVOID*)&TextFramebuffer);
     if (!Success)
     {
         DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
@@ -500,6 +481,14 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
         return FALSE;
     }
 
+#ifdef USE_REAL_REGISTERCONSOLEVDM
+    CharBuff = HeapAlloc(GetProcessHeap(),
+                         HEAP_ZERO_MEMORY,
+                         TextResolution.X * TextResolution.Y
+                                          * sizeof(CHAR_INFO));
+    ASSERT(CharBuff);
+#endif
+
     /*
      * Resize the console
      */
@@ -560,6 +549,10 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
         Address += ScanlineSize;
     }
 
+#ifdef USE_REAL_REGISTERCONSOLEVDM
+    if (CharBuff) HeapFree(GetProcessHeap(), 0, CharBuff);
+#endif
+
     VgaUpdateCursorPosition();
 
     return TRUE;
@@ -951,6 +944,16 @@ Cleanup:
     return Result;
 }
 
+static VOID VgaSetActiveScreenBuffer(HANDLE ScreenBuffer)
+{
+    /* Set the active buffer */
+    SetConsoleActiveScreenBuffer(ScreenBuffer);
+
+    /* Reinitialize the VDM menu */
+    DestroyVdmMenu();
+    CreateVdmMenu(ScreenBuffer);
+}
+
 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
 {
     DWORD i;
@@ -963,20 +966,14 @@ static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
     LONG Height = Resolution->Y;
 
     /* Use DoubleVision mode if the resolution is too small */
-    if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT)
-    {
-        DoubleVision = TRUE;
-        Width  *= 2;
-        Height *= 2;
-    }
-    else
-    {
-        DoubleVision = FALSE;
-    }
+    DoubleWidth = (Width < VGA_MINIMUM_WIDTH);
+    if (DoubleWidth) Width *= 2;
+    DoubleHeight = (Height < VGA_MINIMUM_HEIGHT);
+    if (DoubleHeight) Height *= 2;
 
     /* Fill the bitmap info header */
-    ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
-    BitmapInfo->bmiHeader.biSize   = sizeof(BITMAPINFOHEADER);
+    RtlZeroMemory(&BitmapInfo->bmiHeader, sizeof(BitmapInfo->bmiHeader));
+    BitmapInfo->bmiHeader.biSize   = sizeof(BitmapInfo->bmiHeader);
     BitmapInfo->bmiHeader.biWidth  = Width;
     BitmapInfo->bmiHeader.biHeight = Height;
     BitmapInfo->bmiHeader.biBitCount = 8;
@@ -1005,10 +1002,10 @@ static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
     ConsoleMutex = GraphicsBufferInfo.hMutex;
 
     /* Clear the framebuffer */
-    ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
+    RtlZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
 
     /* Set the active buffer */
-    SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer);
+    VgaSetActiveScreenBuffer(GraphicsConsoleBuffer);
 
     /* Set the graphics mode palette */
     SetConsolePalette(GraphicsConsoleBuffer,
@@ -1027,7 +1024,7 @@ static VOID VgaLeaveGraphicsMode(VOID)
     ReleaseMutex(ConsoleMutex);
 
     /* Switch back to the default console text buffer */
-    // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
+    // VgaSetActiveScreenBuffer(TextConsoleBuffer);
 
     /* Cleanup the video data */
     CloseHandle(ConsoleMutex);
@@ -1035,7 +1032,9 @@ static VOID VgaLeaveGraphicsMode(VOID)
     ConsoleFramebuffer = NULL;
     CloseHandle(GraphicsConsoleBuffer);
     GraphicsConsoleBuffer = NULL;
-    DoubleVision = FALSE;
+
+    DoubleWidth  = FALSE;
+    DoubleHeight = FALSE;
 }
 
 static BOOL VgaEnterTextMode(PCOORD Resolution)
@@ -1043,7 +1042,7 @@ static BOOL VgaEnterTextMode(PCOORD Resolution)
     DPRINT1("VgaEnterTextMode\n");
 
     /* Switch to the text buffer */
-    SetConsoleActiveScreenBuffer(TextConsoleBuffer);
+    VgaSetActiveScreenBuffer(TextConsoleBuffer);
 
     /* Adjust the text framebuffer if we changed the resolution */
     if (TextResolution.X != Resolution->X ||
@@ -1116,7 +1115,7 @@ static VOID VgaChangeMode(VOID)
         /* Enter new text mode */
         if (!VgaEnterTextMode(&Resolution))
         {
-            DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
+            DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
             EmulatorTerminate();
             return;
         }
@@ -1126,7 +1125,7 @@ static VOID VgaChangeMode(VOID)
         /* Enter graphics mode */
         if (!VgaEnterGraphicsMode(&Resolution))
         {
-            DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
+            DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
             EmulatorTerminate();
             return;
         }
@@ -1306,14 +1305,14 @@ static VOID VgaUpdateFramebuffer(VOID)
                 }
 
                 /* Take into account DoubleVision mode when checking for pixel updates */
-                if (DoubleVision)
+                if (DoubleWidth && DoubleHeight)
                 {
                     /* Now check if the resulting pixel data has changed */
-                    if (GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] != PixelData)
+                    if (GraphicsBuffer[(i * 2 * Resolution.X * 2) + (j * 2)] != PixelData)
                     {
                         /* Yes, write the new value */
-                        GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] = PixelData;
-                        GraphicsBuffer[(i * Resolution.X * 4) + (j * 2 + 1)] = PixelData;
+                        GraphicsBuffer[(i * 2 * Resolution.X * 2) + (j * 2)] = PixelData;
+                        GraphicsBuffer[(i * 2 * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
                         GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
                         GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
 
@@ -1321,7 +1320,33 @@ static VOID VgaUpdateFramebuffer(VOID)
                         VgaMarkForUpdate(i, j);
                     }
                 }
-                else
+                else if (DoubleWidth && !DoubleHeight)
+                {
+                    /* Now check if the resulting pixel data has changed */
+                    if (GraphicsBuffer[(i * Resolution.X * 2) + (j * 2)] != PixelData)
+                    {
+                        /* Yes, write the new value */
+                        GraphicsBuffer[(i * Resolution.X * 2) + (j * 2)] = PixelData;
+                        GraphicsBuffer[(i * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
+
+                        /* Mark the specified pixel as changed */
+                        VgaMarkForUpdate(i, j);
+                    }
+                }
+                else if (!DoubleWidth && DoubleHeight)
+                {
+                    /* Now check if the resulting pixel data has changed */
+                    if (GraphicsBuffer[(i * 2 * Resolution.X) + j] != PixelData)
+                    {
+                        /* Yes, write the new value */
+                        GraphicsBuffer[(i * 2 * Resolution.X) + j] = PixelData;
+                        GraphicsBuffer[((i * 2 + 1) * Resolution.X) + j] = PixelData;
+
+                        /* Mark the specified pixel as changed */
+                        VgaMarkForUpdate(i, j);
+                    }
+                }
+                else // if (!DoubleWidth && !DoubleHeight)
                 {
                     /* Now check if the resulting pixel data has changed */
                     if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
@@ -1796,11 +1821,14 @@ VOID VgaRefreshDisplay(VOID)
         ConsoleBufferHandle = GraphicsConsoleBuffer;
 
         /* In DoubleVision mode, scale the update rectangle */
-        if (DoubleVision)
+        if (DoubleWidth)
         {
             UpdateRectangle.Left *= 2;
-            UpdateRectangle.Top  *= 2;
-            UpdateRectangle.Right  = UpdateRectangle.Right  * 2 + 1;
+            UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
+        }
+        if (DoubleHeight)
+        {
+            UpdateRectangle.Top *= 2;
             UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
         }
     }
@@ -1900,7 +1928,7 @@ VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
 
 VOID VgaClearMemory(VOID)
 {
-    ZeroMemory(VgaMemory, sizeof(VgaMemory));
+    RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
 }
 
 VOID VgaResetPalette(VOID)
@@ -1913,8 +1941,33 @@ VOID VgaResetPalette(VOID)
     PaletteChanged = TRUE;
 }
 
+VOID VgaWriteFont(UINT FontNumber, CONST UCHAR *FontData, UINT Height)
+{
+    UINT i, j;
+    PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)];
 
+    ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
 
+    for (i = 0 ; i < VGA_FONT_CHARACTERS; i++)
+    {
+        /* Write the character */
+        for (j = 0; j < Height; j++)
+        {
+            FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j];
+        }
+
+        /* Clear the unused part */
+        for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
+        {
+            FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0;
+        }
+    }
+}
+
+VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
+{
+    DPRINT1("Screen events not handled\n");
+}
 
 BOOL VgaAttachToConsole(VOID)
 {
@@ -1950,7 +2003,7 @@ VOID VgaDetachFromConsole(BOOL ChangingMode)
                          NULL,
                          0,
                          dummySize,
-                         (PCHAR*)&dummyPtr);
+                         &dummyPtr);
 
     TextFramebuffer = NULL;
 
@@ -1959,7 +2012,7 @@ VOID VgaDetachFromConsole(BOOL ChangingMode)
         SMALL_RECT ConRect;
 
         /* Restore the old screen buffer */
-        SetConsoleActiveScreenBuffer(TextConsoleBuffer);
+        VgaSetActiveScreenBuffer(TextConsoleBuffer);
 
         /* Restore the original console size */
         ConRect.Left   = 0;
@@ -1997,7 +2050,7 @@ BOOLEAN VgaInitialize(HANDLE TextHandle)
     /***/ VgaResetPalette(); /***/
 
     /* Switch to the text buffer */
-    SetConsoleActiveScreenBuffer(TextConsoleBuffer);
+    VgaSetActiveScreenBuffer(TextConsoleBuffer);
 
     /* Clear the VGA memory */
     VgaClearMemory();
@@ -2039,11 +2092,6 @@ VOID VgaCleanup(VOID)
     CloseHandle(AnotherEvent);
     CloseHandle(EndEvent);
     CloseHandle(StartEvent);
-
-#if 0
-    RegisterConsoleVDM = NULL;
-    FreeLibrary(hKernel32);
-#endif
 }
 
 /* EOF */