/* INCLUDES *******************************************************************/
+#include "ntvdm.h"
+
#define NDEBUG
+#include <debug.h>
-#include "ntvdm.h"
#include "emulator.h"
#include "svga.h"
#include <bios/vidbios.h>
#include "io.h"
#include "clock.h"
+#include "../../console/video.h"
+
/* PRIVATE VARIABLES **********************************************************/
static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
static CONST DWORD MemorySize[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
-/*
- * 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
RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
};
-/*
- * Console interface -- VGA-mode-agnostic
- */
-// WARNING! This structure *MUST BE* in sync with the one in consrv/include/conio_winsrv.h
-typedef struct _CHAR_CELL
-{
- CHAR Char;
- BYTE Attributes;
-} CHAR_CELL, *PCHAR_CELL;
-C_ASSERT(sizeof(CHAR_CELL) == 2);
-
-static PVOID ConsoleFramebuffer = NULL; // Active framebuffer, points to
- // either TextFramebuffer or a
- // valid graphics framebuffer.
+/// ConsoleFramebuffer
+static PVOID ActiveFramebuffer = NULL; // Active framebuffer, points to
+ // either TextFramebuffer or a
+ // valid graphics framebuffer.
static HPALETTE TextPaletteHandle = NULL;
static HPALETTE PaletteHandle = NULL;
-static HANDLE StartEvent = NULL;
-static HANDLE EndEvent = NULL;
-static HANDLE AnotherEvent = NULL;
-
-static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
-static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
-
-
-static HANDLE ScreenBufferHandle = NULL;
-static PVOID OldConsoleFramebuffer = NULL;
-
-
/*
* Text mode -- we always keep a valid text mode framebuffer
* even if we are in graphics mode. This is needed in order
* detaches from the console (and reattaches to it later on),
* this text mode framebuffer is recreated.
*/
-static HANDLE TextConsoleBuffer = NULL;
-static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
-static COORD TextResolution = {0};
static PCHAR_CELL TextFramebuffer = NULL;
/*
* Graphics mode
*/
-static HANDLE GraphicsConsoleBuffer = NULL;
-static PVOID GraphicsFramebuffer = NULL;
-static HANDLE ConsoleMutex = NULL;
-/* DoubleVision support */
-static BOOLEAN DoubleWidth = FALSE;
-static BOOLEAN DoubleHeight = FALSE;
+static PBYTE GraphicsFramebuffer = NULL;
+
+
+// static HANDLE ConsoleMutex = NULL;
+// /* DoubleVision support */
+// static BOOLEAN DoubleWidth = FALSE;
+// static BOOLEAN DoubleHeight = FALSE;
+
+
+
/*
static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
-/* RegisterConsoleVDM EMULATION ***********************************************/
-#include <ntddvdeo.h>
-#ifdef USE_REAL_REGISTERCONSOLEVDM
-#define __RegisterConsoleVDM RegisterConsoleVDM
-#define __InvalidateConsoleDIBits InvalidateConsoleDIBits
+/** HACK!! **/
+#include "../../console/video.c"
+/** HACK!! **/
-#else
-/*
- * This private buffer, per-console, is used by
- * RegisterConsoleVDM and InvalidateConsoleDIBits.
- */
-static COORD VDMBufferSize = {0};
-static PCHAR_CELL VDMBuffer = NULL;
-
-static PCHAR_INFO CharBuff = NULL; // This is a hack, which is unneeded
- // for the real RegisterConsoleVDM and
- // InvalidateConsoleDIBits
-
-BOOL
-WINAPI
-__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(hErrorHardwareEvent);
- UNREFERENCED_PARAMETER(dwUnusedVar);
- UNREFERENCED_PARAMETER(lpVideoStateLength);
- UNREFERENCED_PARAMETER(lpVideoState);
- UNREFERENCED_PARAMETER(lpUnusedBuffer);
- UNREFERENCED_PARAMETER(dwUnusedBufferLength);
-
- SetLastError(0);
- DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags);
-
- if (lpVDMBuffer == NULL) return FALSE;
-
- if (dwRegisterFlags != 0)
- {
- // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
- if (VDMBuffer != NULL) return FALSE;
-
- VDMBufferSize = dwVDMBufferSize;
-
- /* HACK: Cache -- to be removed in the real implementation */
- CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- VDMBufferSize.X * VDMBufferSize.Y
- * sizeof(*CharBuff));
- ASSERT(CharBuff);
-
- VDMBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- VDMBufferSize.X * VDMBufferSize.Y
- * sizeof(*VDMBuffer));
- *lpVDMBuffer = VDMBuffer;
- return (VDMBuffer != NULL);
- }
- else
- {
- /* HACK: Cache -- to be removed in the real implementation */
- if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
- CharBuff = NULL;
-
- if (VDMBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer);
- VDMBuffer = NULL;
-
- VDMBufferSize.X = VDMBufferSize.Y = 0;
-
- return TRUE;
- }
-}
-
-BOOL
-__InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
- IN PSMALL_RECT lpRect)
-{
- if ((hConsoleOutput == TextConsoleBuffer) && (VDMBuffer != NULL))
- {
- /* HACK: Write the cached data to the console */
- COORD Origin = { lpRect->Left, lpRect->Top };
- SHORT i, j;
- ASSERT(CharBuff);
-
- for (i = 0; i < VDMBufferSize.Y; i++)
- {
- for (j = 0; j < VDMBufferSize.X; j++)
- {
- CharBuff[i * VDMBufferSize.X + j].Char.AsciiChar = VDMBuffer[i * VDMBufferSize.X + j].Char;
- CharBuff[i * VDMBufferSize.X + j].Attributes = VDMBuffer[i * VDMBufferSize.X + j].Attributes;
- }
- }
-
- WriteConsoleOutputA(hConsoleOutput,
- CharBuff,
- VDMBufferSize,
- Origin,
- lpRect);
- }
-
- return InvalidateConsoleDIBits(hConsoleOutput, lpRect);
-}
-
-#endif
/* PRIVATE FUNCTIONS **********************************************************/
-static inline DWORD VgaGetAddressSize(VOID);
-static VOID VgaUpdateTextCursor(VOID);
-
static inline DWORD VgaGetVideoBaseAddress(VOID)
{
return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
}
-static VOID VgaUpdateCursorPosition(VOID)
-{
- /*
- * Update the cursor position in the VGA registers.
- */
- WORD Offset = ConsoleInfo.dwCursorPosition.Y * TextResolution.X +
- ConsoleInfo.dwCursorPosition.X;
-
- VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
- VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
-
- VgaUpdateTextCursor();
-}
-
-static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
-{
- BOOL Success;
- 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;
- DWORD CurrentAddr;
- SMALL_RECT ConRect;
- COORD Origin = { 0, 0 };
-
- ASSERT(TextFramebuffer == NULL);
-
- TextResolution = *Resolution;
-
- /*
- * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
- * in the two following APIs:
- * 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 (STATUS_ACCESS_DENIED).
- *
- * It is worth it to notice that also basesrv.dll does the same only for the
- * BaseSrvIsFirstVDM API...
- */
-
- /* Register with the console server */
- Success =
- __RegisterConsoleVDM(1,
- StartEvent,
- EndEvent,
- AnotherEvent, // NULL,
- 0,
- &Length, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
- (PVOID*)&State, // NULL,
- NULL,
- 0,
- TextResolution,
- (PVOID*)&TextFramebuffer);
- if (!Success)
- {
- DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
- EmulatorTerminate();
- return FALSE;
- }
-
-#ifdef USE_REAL_REGISTERCONSOLEVDM
- CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- TextResolution.X * TextResolution.Y
- * sizeof(*CharBuff));
- ASSERT(CharBuff);
-#endif
-
- /* Retrieve the latest console information */
- GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
-
- /* Resize the console */
- ConRect.Left = 0;
- ConRect.Right = ConRect.Left + Resolution->X - 1;
- ConRect.Bottom = max(ConsoleInfo.dwCursorPosition.Y, Resolution->Y - 1);
- ConRect.Top = ConRect.Bottom - Resolution->Y + 1;
- /*
- * Use this trick to effectively resize the console buffer and window,
- * because:
- * - SetConsoleScreenBufferSize fails if the new console screen buffer size
- * is smaller than the current console window size, and:
- * - SetConsoleWindowInfo fails if the new console window size is larger
- * than the current console screen buffer size.
- */
- Success = SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
- DPRINT1("(attach) SetConsoleScreenBufferSize(1) %s with error %d\n", Success ? "succeeded" : "failed", GetLastError());
- Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
- DPRINT1("(attach) SetConsoleWindowInfo %s with error %d\n", Success ? "succeeded" : "failed", GetLastError());
- Success = SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
- DPRINT1("(attach) SetConsoleScreenBufferSize(2) %s with error %d\n", Success ? "succeeded" : "failed", GetLastError());
-
- /* Update the saved console information */
- GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
-
- /*
- * Copy console data into VGA memory
- */
-
- /* Read the data from the console into the framebuffer... */
- ConRect.Left = ConRect.Top = 0;
- ConRect.Right = TextResolution.X;
- ConRect.Bottom = TextResolution.Y;
-
- ReadConsoleOutputA(TextConsoleBuffer,
- CharBuff,
- TextResolution,
- Origin,
- &ConRect);
-
- /* ... and copy the framebuffer into the VGA memory */
- AddressSize = VgaGetAddressSize();
- ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
-
- /* Loop through the scanlines */
- for (i = 0; i < TextResolution.Y; i++)
- {
- /* Loop through the characters */
- for (j = 0; j < TextResolution.X; j++)
- {
- CurrentAddr = LOWORD((Address + j) * AddressSize);
-
- /* Store the character in plane 0 */
- VgaMemory[CurrentAddr] = CharBuff[i * TextResolution.X + j].Char.AsciiChar;
-
- /* Store the attribute in plane 1 */
- VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes;
- }
-
- /* Move to the next scanline */
- Address += ScanlineSize;
- }
-
-#ifdef USE_REAL_REGISTERCONSOLEVDM
- if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
-#endif
-
- VgaUpdateCursorPosition();
-
- return TRUE;
-}
-
-static VOID VgaDetachFromConsoleInternal(VOID)
-{
- ULONG dummyLength;
- PVOID dummyPtr;
- COORD dummySize = {0};
-
- /* Deregister with the console server */
- __RegisterConsoleVDM(0,
- NULL,
- NULL,
- NULL,
- 0,
- &dummyLength,
- &dummyPtr,
- NULL,
- 0,
- dummySize,
- &dummyPtr);
-
- TextFramebuffer = NULL;
-}
-
-static BOOL IsConsoleHandle(HANDLE hHandle)
-{
- DWORD dwMode;
-
- /* Check whether the handle may be that of a console... */
- if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
- return FALSE;
-
- /*
- * It may be. Perform another test... The idea comes from the
- * MSDN description of the WriteConsole API:
- *
- * "WriteConsole fails if it is used with a standard handle
- * that is redirected to a file. If an application processes
- * multilingual output that can be redirected, determine whether
- * the output handle is a console handle (one method is to call
- * the GetConsoleMode function and check whether it succeeds).
- * If the handle is a console handle, call WriteConsole. If the
- * handle is not a console handle, the output is redirected and
- * you should call WriteFile to perform the I/O."
- */
- return GetConsoleMode(hHandle, &dwMode);
-}
-
static inline DWORD VgaGetAddressSize(VOID)
{
if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
return Data;
}
-static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
-{
- /* Check if this is the first time the rectangle is updated */
- if (!NeedsUpdate)
- {
- UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
- UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
- }
-
- /* Expand the rectangle to include the point */
- UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
- UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
- UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
- UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
-
- /* Set the update request flag */
- NeedsUpdate = TRUE;
-}
-
static inline ULONG VgaGetClockFrequency(VOID)
{
BYTE Numerator, Denominator;
PaletteChanged = TRUE;
}
-static VOID VgaSetActiveScreenBuffer(HANDLE ScreenBuffer)
+static BOOL VgaEnterNewMode(SCREEN_MODE NewScreenMode, PCOORD Resolution)
{
- ASSERT(ScreenBuffer);
+ /* Check if the new mode is alphanumeric */
+ if (NewScreenMode == TEXT_MODE)
+ {
+ /* Enter new text mode */
- /* Set the active buffer and reattach the VDM UI to it */
- SetConsoleActiveScreenBuffer(ScreenBuffer);
- ConsoleReattach(ScreenBuffer);
-}
+ if (!VgaConsoleCreateTextScreen(// &TextFramebuffer,
+ Resolution,
+ TextPaletteHandle))
+ {
+ DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
+ EmulatorTerminate();
+ return FALSE;
+ }
-static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
-{
- DWORD i;
- CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
- BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
- LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
- LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
-
- LONG Width = Resolution->X;
- LONG Height = Resolution->Y;
-
- /* Use DoubleVision mode if the resolution is too small */
- DoubleWidth = (Width < VGA_MINIMUM_WIDTH);
- if (DoubleWidth) Width *= 2;
- DoubleHeight = (Height < VGA_MINIMUM_HEIGHT);
- if (DoubleHeight) Height *= 2;
-
- /* Fill the bitmap info header */
- RtlZeroMemory(&BitmapInfo->bmiHeader, sizeof(BitmapInfo->bmiHeader));
- BitmapInfo->bmiHeader.biSize = sizeof(BitmapInfo->bmiHeader);
- BitmapInfo->bmiHeader.biWidth = Width;
- BitmapInfo->bmiHeader.biHeight = Height;
- BitmapInfo->bmiHeader.biBitCount = 8;
- BitmapInfo->bmiHeader.biPlanes = 1;
- BitmapInfo->bmiHeader.biCompression = BI_RGB;
- BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
-
- /* Fill the palette data */
- for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
-
- /* Fill the console graphics buffer info */
- GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
- GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
- GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
-
- /* Create the buffer */
- GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- CONSOLE_GRAPHICS_BUFFER,
- &GraphicsBufferInfo);
- if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
-
- /* Save the framebuffer address and mutex */
- GraphicsFramebuffer = GraphicsBufferInfo.lpBitMap;
- ConsoleMutex = GraphicsBufferInfo.hMutex;
-
- /* Clear the framebuffer */
- RtlZeroMemory(GraphicsFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
-
- /* Set the active buffer */
- VgaSetActiveScreenBuffer(GraphicsConsoleBuffer);
-
- /* The active framebuffer is now the graphics framebuffer */
- ConsoleFramebuffer = GraphicsFramebuffer;
-
- /* Set the graphics mode palette */
- SetConsolePalette(GraphicsConsoleBuffer,
- PaletteHandle,
- SYSPAL_NOSTATIC256);
-
- /* Set the screen mode flag */
- ScreenMode = GRAPHICS_MODE;
+ /* The active framebuffer is now the text framebuffer */
+ ActiveFramebuffer = TextFramebuffer;
- return TRUE;
-}
+ /* Set the screen mode flag */
+ ScreenMode = TEXT_MODE;
-static VOID VgaLeaveGraphicsMode(VOID)
-{
- /* Release the console framebuffer mutex */
- ReleaseMutex(ConsoleMutex);
+ return TRUE;
+ }
+ else
+ {
+ /* Enter graphics mode */
- /* Switch back to the default console text buffer */
- // VgaSetActiveScreenBuffer(TextConsoleBuffer);
+ if (!VgaConsoleCreateGraphicsScreen(// &GraphicsFramebuffer,
+ Resolution,
+ PaletteHandle))
+ {
+ DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
+ EmulatorTerminate();
+ return FALSE;
+ }
- /* Cleanup the video data */
- CloseHandle(ConsoleMutex);
- ConsoleMutex = NULL;
- GraphicsFramebuffer = NULL;
- CloseHandle(GraphicsConsoleBuffer);
- GraphicsConsoleBuffer = NULL;
+ /* The active framebuffer is now the graphics framebuffer */
+ ActiveFramebuffer = GraphicsFramebuffer;
- /* Reset the active framebuffer */
- ConsoleFramebuffer = NULL;
+ /* Set the screen mode flag */
+ ScreenMode = GRAPHICS_MODE;
- DoubleWidth = FALSE;
- DoubleHeight = FALSE;
+ return TRUE;
+ }
}
-static BOOL VgaEnterTextMode(PCOORD Resolution)
+static VOID VgaLeaveCurrentMode(VOID)
{
- /* Switch to the text buffer */
- // FIXME: Wouldn't it be preferrable to switch to it AFTER we reset everything??
- VgaSetActiveScreenBuffer(TextConsoleBuffer);
-
- /* Adjust the text framebuffer if we changed the resolution */
- if (TextResolution.X != Resolution->X ||
- TextResolution.Y != Resolution->Y)
+ /* Leave the current video mode */
+ if (ScreenMode == GRAPHICS_MODE)
{
- VgaDetachFromConsoleInternal();
+ VgaConsoleDestroyGraphicsScreen();
- /*
- * VgaAttachToConsoleInternal sets TextResolution
- * to the new resolution and updates ConsoleInfo.
- */
- if (!VgaAttachToConsoleInternal(Resolution))
- {
- DisplayMessage(L"An unexpected error occurred!\n");
- EmulatorTerminate();
- return FALSE;
- }
+ /* Cleanup the video data */
+ GraphicsFramebuffer = NULL;
}
else
{
- VgaUpdateCursorPosition();
- }
+ VgaConsoleDestroyTextScreen();
- /* The active framebuffer is now the text framebuffer */
- ConsoleFramebuffer = TextFramebuffer;
-
- /*
- * Set the text mode palette.
- *
- * INFORMATION: This call should fail on Windows (and therefore
- * we get the default palette and our external behaviour is
- * just like Windows' one), but it should success on ReactOS
- * (so that we get console palette changes even for text-mode
- * screen-buffers, which is a new feature on ReactOS).
- */
- SetConsolePalette(TextConsoleBuffer,
- TextPaletteHandle,
- SYSPAL_NOSTATIC256);
-
- /* Set the screen mode flag */
- ScreenMode = TEXT_MODE;
-
- return TRUE;
-}
+ /* Cleanup the video data */
+ // TextFramebuffer = NULL;
+ // NEVER SET the ALWAYS-SET TextFramebuffer pointer to NULL!!
+ }
-static VOID VgaLeaveTextMode(VOID)
-{
/* Reset the active framebuffer */
- ConsoleFramebuffer = NULL;
+ ActiveFramebuffer = NULL;
}
static VOID VgaChangeMode(VOID)
// *ONLY* if we succeeded in setting the new mode??
/* Leave the current video mode */
- if (ScreenMode == GRAPHICS_MODE)
- VgaLeaveGraphicsMode();
- else
- VgaLeaveTextMode();
+ VgaLeaveCurrentMode(); // ScreenMode
/* Update the current resolution */
CurrResolution = NewResolution;
- /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
-
- /* Check if the new mode is alphanumeric */
- if (NewScreenMode == TEXT_MODE)
- {
- /* Enter new text mode */
- if (!VgaEnterTextMode(&CurrResolution))
- {
- DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
- EmulatorTerminate();
- return;
- }
- }
- else
- {
- /* Enter graphics mode */
- if (!VgaEnterGraphicsMode(&CurrResolution))
- {
- DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
- EmulatorTerminate();
- return;
- }
- }
+ /* Change the screen mode */
+ if (!VgaEnterNewMode(NewScreenMode, &CurrResolution))
+ return;
Quit:
ModeChanged = FALSE;
}
+static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
+{
+ /* Check if this is the first time the rectangle is updated */
+ if (!NeedsUpdate)
+ {
+ UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
+ UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
+ }
+
+ /* Expand the rectangle to include the point */
+ UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
+ UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
+ UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
+ UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
+
+ /* Set the update request flag */
+ NeedsUpdate = TRUE;
+}
+
static VOID VgaUpdateFramebuffer(VOID)
{
SHORT i, j, k;
DWORD AddressSize = VgaGetAddressSize();
DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
BYTE PresetRowScan = VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F;
+ BYTE BytePanning = (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3;
DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG])
+ PresetRowScan * ScanlineSize
- + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3);
+ + BytePanning;
+ WORD LineCompare = VgaCrtcRegisters[VGA_CRTC_LINE_COMPARE_REG]
+ | ((VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_LC8) << 4);
+ BYTE PixelShift = VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F;
/*
* If the console framebuffer is NULL, that means something
* went wrong earlier and this is the final display refresh.
*/
- if (ConsoleFramebuffer == NULL) return;
+ if (ActiveFramebuffer == NULL) return;
/* Check if we are in text or graphics mode */
if (ScreenMode == GRAPHICS_MODE)
{
/* Graphics mode */
- PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
+ PBYTE GraphicsBuffer = (PBYTE)ActiveFramebuffer;
DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
SHORT X;
InterlaceHighBit >>= 1;
}
+ if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
+ {
+ /* Halve the line compare value */
+ LineCompare >>= 1;
+ }
+ else
+ {
+ /* Divide the line compare value by the maximum scan line */
+ LineCompare /= 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
+ }
+
/* Loop through the scanlines */
for (i = 0; i < CurrResolution.Y; i++)
{
+ if (i == LineCompare)
+ {
+ if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_PPM)
+ {
+ /*
+ * Disable the pixel shift count and byte panning
+ * for the rest of the display cycle
+ */
+ PixelShift = 0;
+ BytePanning = 0;
+ }
+
+ /* Reset the address, but assume the preset row scan is 0 */
+ Address = BytePanning;
+ }
+
if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
{
/* Odd-numbered line in interlaced mode - set the high bit */
/* Apply horizontal pixel panning */
if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
{
- X = j + ((VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F) >> 1);
+ X = j + (PixelShift >> 1);
}
else
{
- X = j + (VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F);
+ X = j + PixelShift;
}
/* Check the shifting mode */
* if external palette access is disabled, otherwise (in case
* of palette loading) it is a blank pixel.
*/
- PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
- : 0);
+
+ if (VgaAcPalDisable)
+ {
+ if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_P54S))
+ {
+ /* Bits 4 and 5 are taken from the palette register */
+ PixelData = ((VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4) & 0xC0)
+ | (VgaAcRegisters[PixelData & 0x0F] & 0x3F);
+ }
+ else
+ {
+ /* Bits 4 and 5 are taken from the color select register */
+ PixelData = (VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4)
+ | (VgaAcRegisters[PixelData & 0x0F] & 0x0F);
+ }
+ }
+ else
+ {
+ PixelData = 0;
+ }
}
/* Take into account DoubleVision mode when checking for pixel updates */
{
/* Text mode */
DWORD CurrentAddr;
- PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
+ PCHAR_CELL CharBuffer = (PCHAR_CELL)ActiveFramebuffer;
CHAR_CELL CharInfo;
/*
static VOID VgaUpdateTextCursor(VOID)
{
- COORD Position;
- CONSOLE_CURSOR_INFO CursorInfo;
-
BOOL CursorVisible = !(VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x20);
BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x1F;
BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
/* Just return if we are not in text mode */
if (ScreenMode != TEXT_MODE) return;
- if (CursorStart < CursorEnd)
- {
- /* Visible cursor */
- CursorInfo.bVisible = CursorVisible;
- CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
- }
- else
- {
- /* Hidden cursor */
- CursorInfo.bVisible = FALSE;
- CursorInfo.dwSize = 1; // The size needs to be non-zero for SetConsoleCursorInfo to succeed.
- }
-
/* Add the cursor skew to the location */
Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03;
- /* Find the coordinates of the new position */
- Position.X = (SHORT)(Location % ScanlineSize);
- Position.Y = (SHORT)(Location / ScanlineSize);
-
- DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position.X, Position.Y);
-
- /* Update the physical cursor */
- SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
- SetConsoleCursorPosition(TextConsoleBuffer, Position);
+ VgaConsoleUpdateTextCursor(CursorVisible, CursorStart, CursorEnd,
+ TextSize, ScanlineSize, Location);
/* Reset the cursor changed flag */
CursorChanged = FALSE;
static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
{
- HANDLE ConsoleBufferHandle = NULL;
-
UNREFERENCED_PARAMETER(ElapsedTime);
/* Set the vertical retrace cycle */
UpdateRectangle.Right,
UpdateRectangle.Bottom);
- /* Check if we are in text or graphics mode */
- if (ScreenMode == GRAPHICS_MODE)
- {
- /* Graphics mode */
- ConsoleBufferHandle = GraphicsConsoleBuffer;
-
- /* In DoubleVision mode, scale the update rectangle */
- if (DoubleWidth)
- {
- UpdateRectangle.Left *= 2;
- UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
- }
- if (DoubleHeight)
- {
- UpdateRectangle.Top *= 2;
- UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
- }
- }
- else
- {
- /* Text mode */
- ConsoleBufferHandle = TextConsoleBuffer;
- }
-
- /* Redraw the screen */
- __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
+ VgaConsoleRepaintScreen(&UpdateRectangle);
/* Clear the update flag */
NeedsUpdate = FALSE;
if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
{
- /* Multiply the horizontal resolution by the 9/8 dot mode */
- Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
- ? 8 : 9;
+ /* In "High Resolution" mode, the width of a character is always 8 pixels */
+ if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES)
+ {
+ Resolution.X *= 8;
+ }
+ else
+ {
+ /* Multiply the horizontal resolution by the 9/8 dot mode */
+ Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
+ ? 8 : 9;
- /* The horizontal resolution is halved in 8-bit mode */
- if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
+ /* The horizontal resolution is halved in 8-bit mode */
+ if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
+ }
}
if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
return Resolution;
}
-BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Horizontal, PBOOLEAN Vertical)
-{
- if (GraphicsConsoleBuffer == NULL) return FALSE;
- if (Horizontal) *Horizontal = DoubleWidth;
- if (Vertical) *Vertical = DoubleHeight;
- return TRUE;
-}
-
VOID VgaRefreshDisplay(VOID)
{
VgaVerticalRetrace(0);
}
}
-VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
-{
- DPRINT1("Screen events not handled\n");
-}
-
-BOOL VgaAttachToConsole(VOID)
-{
- if (TextResolution.X == 0 || TextResolution.Y == 0)
- DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
-
- if (TextResolution.X == 0) TextResolution.X = 80;
- if (TextResolution.Y == 0) TextResolution.Y = 25;
-
- // VgaDetachFromConsoleInternal();
-
- /*
- * VgaAttachToConsoleInternal sets TextResolution
- * to the new resolution and updates ConsoleInfo.
- */
- if (!VgaAttachToConsoleInternal(&TextResolution))
- {
- DisplayMessage(L"An unexpected error occurred!\n");
- EmulatorTerminate();
- return FALSE;
- }
-
- /* Restore the original screen buffer */
- VgaSetActiveScreenBuffer(ScreenBufferHandle);
- ScreenBufferHandle = NULL;
-
- /* Restore the screen state */
- if (ScreenMode == TEXT_MODE)
- {
- /* The text mode framebuffer was recreated */
- ConsoleFramebuffer = TextFramebuffer;
- }
- else
- {
- /* The graphics mode framebuffer is unchanged */
- ConsoleFramebuffer = OldConsoleFramebuffer;
- }
- OldConsoleFramebuffer = NULL;
-
- return TRUE;
-}
-
-VOID VgaDetachFromConsole(VOID)
-{
- BOOL Success;
-
- SMALL_RECT ConRect;
-
- VgaDetachFromConsoleInternal();
-
- /* Save the screen state */
- if (ScreenMode == TEXT_MODE)
- ScreenBufferHandle = TextConsoleBuffer;
- else
- ScreenBufferHandle = GraphicsConsoleBuffer;
-
- /* Reset the active framebuffer */
- OldConsoleFramebuffer = ConsoleFramebuffer;
- ConsoleFramebuffer = NULL;
-
- /* Restore the original console size */
- ConRect.Left = ConRect.Top = 0;
- ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
- ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
- /* See the following trick explanation in VgaAttachToConsoleInternal */
- Success = SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
- DPRINT1("(detach) SetConsoleScreenBufferSize(1) %s with error %d\n", Success ? "succeeded" : "failed", GetLastError());
- Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
- DPRINT1("(detach) SetConsoleWindowInfo %s with error %d\n", Success ? "succeeded" : "failed", GetLastError());
- Success = SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
- DPRINT1("(detach) SetConsoleScreenBufferSize(2) %s with error %d\n", Success ? "succeeded" : "failed", GetLastError());
-
- /* Restore the original cursor shape */
- SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
-
- // FIXME: Should we copy back the screen data to the screen buffer??
- // WriteConsoleOutputA(...);
-
- // FIXME: Should we change cursor POSITION??
- // VgaUpdateTextCursor();
-
- ///* Update the physical cursor */
- //SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
- //SetConsoleCursorPosition(TextConsoleBuffer, Position /*OrgConsoleBufferInfo.dwCursorPosition*/);
-
- /* Restore the old text-mode screen buffer */
- VgaSetActiveScreenBuffer(TextConsoleBuffer);
-}
-
BOOLEAN VgaInitialize(HANDLE TextHandle)
{
- /* Save the default text-mode console output handle */
- if (!IsConsoleHandle(TextHandle)) return FALSE;
- TextConsoleBuffer = TextHandle;
-
- /* Save the original cursor and console screen buffer information */
- if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
- !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
- {
- return FALSE;
- }
- ConsoleInfo = OrgConsoleBufferInfo;
+ if (!VgaConsoleInitialize(TextHandle)) return FALSE;
/* Clear the SEQ, GC, CRTC and AC registers */
RtlZeroMemory(VgaSeqRegisters , sizeof(VgaSeqRegisters ));
if (!VgaInitializePalette()) return FALSE;
/***/ VgaResetPalette(); /***/
- /* Switch to the text buffer, but do not enter into a text mode */
- VgaSetActiveScreenBuffer(TextConsoleBuffer);
-
/* Reset the sequencer */
VgaResetSequencer();
DestroyHardwareTimer(HSyncTimer);
/* Leave the current video mode */
- if (ScreenMode == GRAPHICS_MODE)
- VgaLeaveGraphicsMode();
- else
- VgaLeaveTextMode();
+ VgaLeaveCurrentMode(); // ScreenMode
- VgaDetachFromConsole();
MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
- CloseHandle(AnotherEvent);
- CloseHandle(EndEvent);
- CloseHandle(StartEvent);
+ VgaConsoleCleanup();
}
/* EOF */