Author: aandrejevic
Date: Fri Jul 5 01:31:50 2013
New Revision: 59425
URL:
http://svn.reactos.org/svn/reactos?rev=59425&view=rev
Log:
[NTVDM]
Improve vertical refresh performance.
Properly synchronize access to the framebuffer.
Modified:
branches/ntvdm/subsystems/ntvdm/bios.c
branches/ntvdm/subsystems/ntvdm/bios.h
branches/ntvdm/subsystems/ntvdm/emulator.c
branches/ntvdm/subsystems/ntvdm/ntvdm.c
Modified: branches/ntvdm/subsystems/ntvdm/bios.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/bios.c?r…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] Fri Jul 5 01:31:50 2013
@@ -22,11 +22,16 @@
static BOOLEAN BiosKbdBufferEmpty = TRUE;
static DWORD BiosTickCount = 0;
static BOOLEAN BiosPassedMidnight = FALSE;
-static HANDLE BiosConsoleInput, BiosConsoleOutput;
+static HANDLE BiosConsoleInput = INVALID_HANDLE_VALUE;
+static HANDLE BiosConsoleOutput = INVALID_HANDLE_VALUE;
static BYTE CurrentVideoMode = BIOS_DEFAULT_VIDEO_MODE;
static BYTE CurrentVideoPage = 0;
static HANDLE ConsoleBuffers[BIOS_MAX_PAGES] = { NULL };
static LPVOID ConsoleFramebuffers[BIOS_MAX_PAGES] = { NULL };
+static HANDLE ConsoleMutexes[BIOS_MAX_PAGES] = { NULL };
+static BOOLEAN VideoNeedsUpdate = TRUE;
+static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
+static CONSOLE_SCREEN_BUFFER_INFO BiosSavedBufferInfo;
static VIDEO_MODE VideoModes[] =
{
/* Width | Height | Text | Colors | Gray | Pages | Segment */
@@ -54,14 +59,39 @@
/* PRIVATE FUNCTIONS **********************************************************/
+static INT BiosColorNumberToBits(DWORD Colors)
+{
+ INT i;
+
+ /* Find the index of the highest-order bit */
+ for (i = 31; i >= 0; i--) if (Colors & (1 << i)) break;
+
+ /* Special case for zero */
+ if (i == 0) i = 32;
+
+ return i;
+}
+
static COORD BiosVideoAddressToCoord(ULONG Address)
{
COORD Result = {0, 0};
-
- Result.X = ((Address - (VideoModes[CurrentVideoMode].Segment << 4)) >>
1)
- % VideoModes[CurrentVideoMode].Width;
- Result.Y = ((Address - (VideoModes[CurrentVideoMode].Segment << 4)) >>
1)
- / VideoModes[CurrentVideoMode].Width;
+ INT BitsPerPixel;
+ DWORD Offset = Address - (VideoModes[CurrentVideoMode].Segment << 4);
+
+ if (VideoModes[CurrentVideoMode].Text)
+ {
+ Result.X = (Offset / sizeof(WORD)) % VideoModes[CurrentVideoMode].Width;
+ Result.Y = (Offset / sizeof(WORD)) / VideoModes[CurrentVideoMode].Width;
+ }
+ else
+ {
+ BitsPerPixel = BiosColorNumberToBits(VideoModes[CurrentVideoMode].Colors);
+
+ Result.X = ((Offset * 8) / BitsPerPixel)
+ % VideoModes[CurrentVideoMode].Width;
+ Result.Y = ((Offset * 8) / BitsPerPixel)
+ / VideoModes[CurrentVideoMode].Width;
+ }
return Result;
}
@@ -130,6 +160,7 @@
for (i = 0; i < VideoModes[CurrentVideoMode].Pages; i++)
{
if (ConsoleBuffers[i] != NULL) CloseHandle(ConsoleBuffers[i]);
+ if (!VideoModes[CurrentVideoMode].Text) CloseHandle(ConsoleMutexes[i]);
}
if (VideoModes[ModeNumber].Text)
@@ -182,14 +213,7 @@
BitmapInfo->bmiHeader.biHeight = VideoModes[ModeNumber].Height;
BitmapInfo->bmiHeader.biPlanes = 1;
BitmapInfo->bmiHeader.biCompression = BI_RGB;
-
- /* Calculate the number of color bits */
- for (i = 31; i >= 0; i--)
- {
- if (VideoModes[ModeNumber].Colors & (1 << i)) break;
- }
- if (i == 0) i = 32;
- BitmapInfo->bmiHeader.biBitCount = i;
+ BitmapInfo->bmiHeader.biBitCount =
BiosColorNumberToBits(VideoModes[ModeNumber].Colors);
/* Calculate the image size */
BitmapInfo->bmiHeader.biSizeImage = BitmapInfo->bmiHeader.biWidth
@@ -220,8 +244,9 @@
CONSOLE_GRAPHICS_BUFFER,
&GraphicsBufferInfo);
- /* Save the framebuffer address */
+ /* Save the framebuffer address and mutex */
ConsoleFramebuffers[i] = GraphicsBufferInfo.lpBitMap;
+ ConsoleMutexes[i] = GraphicsBufferInfo.hMutex;
}
/* Free the bitmap information */
@@ -244,22 +269,21 @@
inline VOID BiosVerticalRefresh()
{
- SMALL_RECT Region;
-
/* Ignore if we're in text mode */
if (VideoModes[CurrentVideoMode].Text) return;
- /* Fill the rectangle structure */
- Region.Left = Region.Top = 0;
- Region.Right = VideoModes[CurrentVideoMode].Width;
- Region.Bottom = VideoModes[CurrentVideoMode].Height;
+ /* Ignore if there's nothing to update */
+ if (!VideoNeedsUpdate) return;
/* Redraw the screen */
InvalidateConsoleDIBits(ConsoleBuffers[CurrentVideoPage],
- &Region);
-}
-
-BOOLEAN BiosInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
+ &UpdateRectangle);
+
+ /* Clear the update flag */
+ VideoNeedsUpdate = FALSE;
+}
+
+BOOLEAN BiosInitialize()
{
INT i;
WORD Offset = 0;
@@ -290,15 +314,41 @@
BiosCode[Offset++] = 0xCF; // iret
}
- /* Set global console I/O handles */
- BiosConsoleInput = ConsoleInput;
- BiosConsoleOutput = ConsoleOutput;
-
+ /* Get the input and output handles to the real console */
+ BiosConsoleInput = CreateFile(TEXT("CONIN$"),
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ BiosConsoleOutput = CreateFile(TEXT("CONOUT$"),
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ /* Make sure it was successful */
+ if ((BiosConsoleInput == INVALID_HANDLE_VALUE)
+ || (BiosConsoleOutput == INVALID_HANDLE_VALUE))
+ {
+ return FALSE;
+ }
+
+ /* Save the console screen buffer information */
+ if (!GetConsoleScreenBufferInfo(BiosConsoleOutput, &BiosSavedBufferInfo))
+ {
+ return FALSE;
+ }
+
/* Set the default video mode */
BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
/* Set the console input mode */
- SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
+ SetConsoleMode(BiosConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
/* Initialize the PIC */
PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
@@ -325,6 +375,28 @@
PitWriteData(0, 0x00);
return TRUE;
+}
+
+VOID BiosCleanup()
+{
+ INT i;
+
+ /* Restore the old screen buffer */
+ SetConsoleActiveScreenBuffer(BiosConsoleOutput);
+
+ /* Restore the screen buffer size */
+ SetConsoleScreenBufferSize(BiosConsoleOutput, BiosSavedBufferInfo.dwSize);
+
+ /* Free the buffers */
+ for (i = 0; i < VideoModes[CurrentVideoMode].Pages; i++)
+ {
+ if (ConsoleBuffers[i] != NULL) CloseHandle(ConsoleBuffers[i]);
+ if (!VideoModes[CurrentVideoMode].Text) CloseHandle(ConsoleMutexes[i]);
+ }
+
+ /* Close the console handles */
+ if (BiosConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleInput);
+ if (BiosConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleOutput);
}
VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
@@ -367,11 +439,40 @@
}
else
{
+ /* Wait for the mutex object */
+ WaitForSingleObject(ConsoleMutexes[CurrentVideoPage], INFINITE);
+
/* Copy the data to the framebuffer */
RtlCopyMemory((LPVOID)((ULONG_PTR)ConsoleFramebuffers[CurrentVideoPage]
+ StartAddress - BiosGetVideoMemoryStart()),
(LPVOID)((ULONG_PTR)BaseAddress + StartAddress),
EndAddress - StartAddress);
+
+ /* Release the mutex */
+ ReleaseMutex(ConsoleMutexes[CurrentVideoPage]);
+
+ /* Check if this is the first time the rectangle is updated */
+ if (!VideoNeedsUpdate)
+ {
+ UpdateRectangle.Left = UpdateRectangle.Top = (SHORT)0x7FFF;
+ UpdateRectangle.Right = UpdateRectangle.Bottom = (SHORT)0x8000;
+ }
+
+ /* Expand the update rectangle */
+ for (i = StartAddress; i < EndAddress; i++)
+ {
+ /* Get the coordinates */
+ Coordinates = BiosVideoAddressToCoord(i);
+
+ /* Expand the rectangle to include the point */
+ UpdateRectangle.Left = min(UpdateRectangle.Left, Coordinates.X);
+ UpdateRectangle.Right = max(UpdateRectangle.Right, Coordinates.X);
+ UpdateRectangle.Top = min(UpdateRectangle.Top, Coordinates.Y);
+ UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Coordinates.Y);
+ }
+
+ /* Set the update flag */
+ VideoNeedsUpdate = TRUE;
}
}
@@ -415,11 +516,17 @@
}
else
{
+ /* Wait for the mutex object */
+ WaitForSingleObject(ConsoleMutexes[CurrentVideoPage], INFINITE);
+
/* Copy the data to the emulator memory */
RtlCopyMemory((LPVOID)((ULONG_PTR)BaseAddress + StartAddress),
(LPVOID)((ULONG_PTR)ConsoleFramebuffers[CurrentVideoPage]
+ StartAddress - BiosGetVideoMemoryStart()),
EndAddress - StartAddress);
+
+ /* Release the mutex */
+ ReleaseMutex(ConsoleMutexes[CurrentVideoPage]);
}
}
@@ -736,6 +843,12 @@
}
}
+VOID BiosSystemTimerInterrupt()
+{
+ /* Increase the system tick count */
+ BiosTickCount++;
+}
+
VOID BiosEquipmentService()
{
/* Return the equipment list */
@@ -749,11 +862,8 @@
/* PIT IRQ */
case 0:
{
- /* Increase the system tick count */
- BiosTickCount++;
-
/* Perform the system timer interrupt */
- EmulatorInterrupt(0x1C);
+ EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT);
break;
}
Modified: branches/ntvdm/subsystems/ntvdm/bios.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/bios.h?r…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/bios.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/bios.h [iso-8859-1] Fri Jul 5 01:31:50 2013
@@ -25,6 +25,7 @@
#define BIOS_EQUIPMENT_INTERRUPT 0x11
#define BIOS_KBD_INTERRUPT 0x16
#define BIOS_TIME_INTERRUPT 0x1A
+#define BIOS_SYS_TIMER_INTERRUPT 0x1C
#define CONSOLE_FONT_HEIGHT 8
#define BIOS_KBD_BUFFER_SIZE 256
#define BIOS_EQUIPMENT_LIST 0x3C // HACK: Disable FPU for now
@@ -46,6 +47,7 @@
/* FUNCTIONS ******************************************************************/
BOOLEAN BiosInitialize();
+VOID BiosCleanup();
VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress);
VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress);
inline DWORD BiosGetVideoMemoryStart();
@@ -57,5 +59,6 @@
VOID BiosKeyboardService();
VOID BiosTimeService();
VOID BiosHandleIrq(BYTE IrqNumber);
+VOID BiosSystemTimerInterrupt();
#endif
Modified: branches/ntvdm/subsystems/ntvdm/emulator.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/emulator…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] Fri Jul 5 01:31:50 2013
@@ -234,6 +234,12 @@
BiosTimeService();
break;
}
+ case BIOS_SYS_TIMER_INTERRUPT:
+ {
+ /* BIOS timer update */
+ BiosSystemTimerInterrupt();
+ break;
+ }
case 0x20:
{
DosInt20h(CodeSegment);
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.c?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] Fri Jul 5 01:31:50 2013
@@ -76,43 +76,9 @@
DWORD LastVerticalRefresh = GetTickCount();
LARGE_INTEGER Frequency, LastTimerTick, Counter;
LONGLONG TimerTicks;
- HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
- HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
- CONSOLE_SCREEN_BUFFER_INFO SavedBufferInfo;
/* Set the handler routine */
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
-
- /* Get the input and output handles to the real console */
- ConsoleInput = CreateFile(TEXT("CONIN$"),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
-
- ConsoleOutput = CreateFile(TEXT("CONOUT$"),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
-
- if ((ConsoleInput == INVALID_HANDLE_VALUE)
- || (ConsoleOutput == INVALID_HANDLE_VALUE))
- {
- wprintf(L"FATAL: Could not get handles to the console\n");
- goto Cleanup;
- }
-
- /* Save the console screen buffer information */
- if (!GetConsoleScreenBufferInfo(ConsoleOutput, &SavedBufferInfo))
- {
- wprintf(L"FATAL: Could not save the console screen buffer
information\n");
- goto Cleanup;
- }
/* The DOS command line must be ASCII */
WideCharToMultiByte(CP_ACP, 0, GetCommandLine(), -1, CommandLine, 128, NULL, NULL);
@@ -131,7 +97,7 @@
}
/* Initialize the system BIOS */
- if (!BiosInitialize(ConsoleInput, ConsoleOutput))
+ if (!BiosInitialize())
{
wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
goto Cleanup;
@@ -201,17 +167,8 @@
}
Cleanup:
- /* Restore the old screen buffer */
- SetConsoleActiveScreenBuffer(ConsoleOutput);
-
- /* Restore the screen buffer size */
- SetConsoleScreenBufferSize(ConsoleOutput, SavedBufferInfo.dwSize);
-
+ BiosCleanup();
EmulatorCleanup();
-
- /* Close the console handles */
- if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
- if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
return 0;
}