From 1bfb13f4fb306c2312b9bb3028537c8d14b61251 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Sat, 27 Aug 2016 17:10:08 +0000 Subject: [PATCH] [NTVDM:SVGA] Properly implement the vertical retrace interval. The starting address and the scanline size are calculated at the start, and the actual update is performed at the end. This allows software to change the pixel panning and some other parameters during the vertical retrace. Also, normalize the CRTC register names. svn path=/trunk/; revision=72474 --- .../subsystems/mvdm/ntvdm/bios/bios32/vbe.c | 6 +- reactos/subsystems/mvdm/ntvdm/bios/vidbios.c | 4 +- .../mvdm/ntvdm/hardware/video/svga.c | 117 +++++++++++------- .../mvdm/ntvdm/hardware/video/svga.h | 4 +- 4 files changed, 80 insertions(+), 51 deletions(-) diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c index a006850b47e..d2f979a67b7 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c @@ -210,11 +210,11 @@ static VOID VbeSetExtendedRegisters(PSVGA_REGISTERS Registers) /* Unlock CRTC registers 0-7 */ IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_HORZ_BLANKING_REG); IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) | 0x80); - IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_VERT_RETRACE_END_REG); + IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_VERT_RETRACE_REG); IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) & ~0x80); // Make sure they remain unlocked Registers->CRT[VGA_CRTC_END_HORZ_BLANKING_REG] |= 0x80; - Registers->CRT[VGA_CRTC_VERT_RETRACE_END_REG] &= ~0x80; + Registers->CRT[VGA_CRTC_END_VERT_RETRACE_REG] &= ~0x80; /* Write the CRTC registers */ for (i = 0; i < SVGA_CRTC_MAX_REG; i++) @@ -564,7 +564,7 @@ VOID WINAPI VbeService(LPWORD Stack) default: { - DPRINT("VESA INT 0x10, AH = 0x05, Unknown subfunction: %02X", getBH()); + DPRINT("VESA INT 0x10, AL = 0x05, Unknown subfunction: %02X", getBH()); } } diff --git a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c index b880197a4d4..052906dbe3e 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c @@ -2195,11 +2195,11 @@ static BOOLEAN VgaSetRegisters(PVGA_REGISTERS Registers) /* Unlock CRTC registers 0-7 */ IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_HORZ_BLANKING_REG); IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) | 0x80); - IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_VERT_RETRACE_END_REG); + IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_VERT_RETRACE_REG); IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) & ~0x80); // Make sure they remain unlocked Registers->CRT[VGA_CRTC_END_HORZ_BLANKING_REG] |= 0x80; - Registers->CRT[VGA_CRTC_VERT_RETRACE_END_REG] &= ~0x80; + Registers->CRT[VGA_CRTC_END_VERT_RETRACE_REG] &= ~0x80; /* Write the CRTC registers */ for (i = 0; i < VGA_CRTC_MAX_REG; i++) diff --git a/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.c b/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.c index 55c6ea5c617..754de9e9744 100644 --- a/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.c +++ b/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.c @@ -272,10 +272,11 @@ static BYTE VgaDacRegisters[VGA_PALETTE_SIZE]; // static VGA_REGISTERS VgaRegisters; -static ULONGLONG VerticalRetraceCycle = 0ULL; static ULONGLONG HorizontalRetraceCycle = 0ULL; -static PHARDWARE_TIMER VSyncTimer; static PHARDWARE_TIMER HSyncTimer; +static DWORD ScanlineCounter = 0; +static DWORD StartAddressLatch = 0; +static DWORD ScanlineSizeLatch = 0; static BOOLEAN NeedsUpdate = FALSE; static BOOLEAN ModeChanged = FALSE; @@ -731,17 +732,8 @@ static VOID VgaUpdateFramebuffer(VOID) { SHORT i, j, k; DWORD AddressSize = VgaGetAddressSize(); - DWORD ScanlineSize = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] - + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2; - BYTE PresetRowScan = VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F; + DWORD Address = StartAddressLatch; 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]) - + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16) - + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15) - + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12) - + PresetRowScan * ScanlineSize - + 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; @@ -816,11 +808,11 @@ static VOID VgaUpdateFramebuffer(VOID) /* Apply horizontal pixel panning */ if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) { - X = j + (PixelShift >> 1); + X = j + ((PixelShift >> 1) & 0x03); } else { - X = j + PixelShift; + X = j + ((PixelShift < 8) ? PixelShift : -1); } /* Check the shifting mode */ @@ -1014,7 +1006,7 @@ static VOID VgaUpdateFramebuffer(VOID) if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1)) { /* Move to the next scanline */ - Address += ScanlineSize; + Address += ScanlineSizeLatch; } } @@ -1064,7 +1056,7 @@ static VOID VgaUpdateFramebuffer(VOID) } /* Move to the next scanline */ - Address += ScanlineSize; + Address += ScanlineSizeLatch; } } } @@ -1116,16 +1108,15 @@ static BYTE WINAPI VgaReadPort(USHORT Port) ULONG CyclesPerMicrosecond = (ULONG)((GetCycleSpeed() + 500000ULL) / 1000000ULL); ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8; ULONG Clock = VgaGetClockFrequency() / 1000000; - ULONG HorizTotalDots = ((ULONG)VgaCrtcRegisters[VGA_CRTC_HORZ_TOTAL_REG] + 5) * Dots; - ULONG VblankStart, VblankEnd, HblankStart, HblankEnd; - ULONG HblankDuration, VblankDuration; + ULONG HblankStart, HblankEnd; + ULONG HblankDuration; + ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG]; + ULONG VerticalRetraceEnd; + + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6; + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2; - /* Calculate the vertical blanking duration in cycles */ - VblankStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_BLANKING_REG] & 0x7F; - VblankEnd = VgaCrtcRegisters[VGA_CRTC_END_VERT_BLANKING_REG] & 0x7F; - if (VblankEnd < VblankStart) VblankEnd |= 0x80; - VblankDuration = ((VblankEnd - VblankStart) * HorizTotalDots - * CyclesPerMicrosecond + (Clock >> 1)) / Clock; + VerticalRetraceEnd = VerticalRetraceStart + (VgaCrtcRegisters[VGA_CRTC_END_VERT_RETRACE_REG] & 0x0F); /* Calculate the horizontal blanking duration in cycles */ HblankStart = VgaCrtcRegisters[VGA_CRTC_START_HORZ_BLANKING_REG] & 0x1F; @@ -1134,16 +1125,12 @@ static BYTE WINAPI VgaReadPort(USHORT Port) HblankDuration = ((HblankEnd - HblankStart) * Dots * CyclesPerMicrosecond + (Clock >> 1)) / Clock; - Vsync = (Cycles - VerticalRetraceCycle) < (ULONGLONG)VblankDuration; + Vsync = ScanlineCounter >= VerticalRetraceStart && ScanlineCounter <= VerticalRetraceEnd; Hsync = (Cycles - HorizontalRetraceCycle) < (ULONGLONG)HblankDuration; /* Reset the AC latch */ VgaAcLatch = FALSE; - /* Reverse the polarity, if needed */ - if (VgaMiscRegister & VGA_MISC_VSYNCP) Vsync = !Vsync; - if (VgaMiscRegister & VGA_MISC_HSYNCP) Hsync = !Hsync; - /* Set a flag if there is a vertical or horizontal retrace */ if (Vsync || Hsync) Result |= VGA_STAT_DD; @@ -1591,13 +1578,8 @@ static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data) SvgaHdrCounter = 0; } -static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime) +static inline VOID VgaVerticalRetrace(VOID) { - UNREFERENCED_PARAMETER(ElapsedTime); - - /* Set the vertical retrace cycle */ - VerticalRetraceCycle = GetCycleCount(); - /* If nothing has changed, just return */ // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate) // return; @@ -1640,10 +1622,61 @@ static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime) static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime) { + ULONG VerticalTotal = VgaCrtcRegisters[VGA_CRTC_VERT_TOTAL_REG]; + ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG]; + ULONG VerticalRetraceEnd; + BOOLEAN BeforeVSyncStart, BeforeVSyncEnd; + ULONG CurrentCycleCount = GetCycleCount(); + ULONG ElapsedCycles = CurrentCycleCount - HorizontalRetraceCycle; + ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8; + ULONG HorizTotalDots = ((ULONG)VgaCrtcRegisters[VGA_CRTC_HORZ_TOTAL_REG] + 5) * Dots; + ULONG HSyncsPerSecond = VgaGetClockFrequency() / HorizTotalDots; + ULONG HSyncs = (ElapsedCycles * HSyncsPerSecond) / GetCycleSpeed(); + UNREFERENCED_PARAMETER(ElapsedTime); + if (HSyncs == 0) HSyncs = 1; + + VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT8) << 8; + VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT9) << 4; + + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6; + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2; + + VerticalRetraceEnd = VerticalRetraceStart + (VgaCrtcRegisters[VGA_CRTC_END_VERT_RETRACE_REG] & 0x0F); /* Set the cycle */ - HorizontalRetraceCycle = GetCycleCount(); + HorizontalRetraceCycle = CurrentCycleCount; + + /* Increment the scanline counter, but make sure we don't skip any part of the vertical retrace */ + BeforeVSyncStart = (ScanlineCounter < VerticalRetraceStart); + BeforeVSyncEnd = (ScanlineCounter < VerticalRetraceEnd); + ScanlineCounter += HSyncs; + if (BeforeVSyncStart && ScanlineCounter >= VerticalRetraceStart) ScanlineCounter = VerticalRetraceStart; + else if (BeforeVSyncEnd && ScanlineCounter >= VerticalRetraceEnd) ScanlineCounter = VerticalRetraceEnd; + + /* The scanline counter wraps around */ + ScanlineCounter %= VerticalTotal; + + if (ScanlineCounter == VerticalRetraceStart) + { + /* Save the scanline size */ + ScanlineSizeLatch = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] + + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2; + + /* Save the starting address */ + StartAddressLatch = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG], + VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]) + + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16) + + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15) + + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12) + + (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F) * ScanlineSizeLatch + + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3); + } + + if (ScanlineCounter == VerticalRetraceEnd) + { + VgaVerticalRetrace(); + } } /* PUBLIC FUNCTIONS ***********************************************************/ @@ -1706,7 +1739,7 @@ COORD VgaGetDisplayResolution(VOID) VOID VgaRefreshDisplay(VOID) { - VgaVerticalRetrace(0); + VgaVerticalRetrace(); } VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size) @@ -1803,13 +1836,11 @@ VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size) /* * These values can also be computed in the following way, but using the table seems to be faster: * - * ColorCompareBytes = VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG]; - * ColorCompareBytes |= (ColorCompareBytes << 7) | (ColorCompareBytes << 14) | (ColorCompareBytes << 21); + * ColorCompareBytes = VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] * 0x000204081; * ColorCompareBytes &= 0x01010101; * ColorCompareBytes = (ColorCompareBytes << 8) - ColorCompareBytes; * - * ColorIgnoreBytes = VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG]; - * ColorIgnoreBytes |= (ColorIgnoreBytes << 7) | (ColorIgnoreBytes << 14) | (ColorIgnoreBytes << 21); + * ColorIgnoreBytes = VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] * 0x000204081; * ColorIgnoreBytes &= 0x01010101; * ColorIgnoreBytes = (ColorIgnoreBytes << 8) - ColorIgnoreBytes; */ @@ -1959,7 +1990,6 @@ BOOLEAN VgaInitialize(HANDLE TextHandle) RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace); - VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(60), VgaVerticalRetrace); /* Return success */ return TRUE; @@ -1970,7 +2000,6 @@ VOID VgaCleanup(VOID) /* Do a final display refresh */ VgaRefreshDisplay(); - DestroyHardwareTimer(VSyncTimer); DestroyHardwareTimer(HSyncTimer); /* Leave the current video mode */ diff --git a/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.h b/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.h index 888d48594fe..8ce564703cf 100644 --- a/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.h +++ b/reactos/subsystems/mvdm/ntvdm/hardware/video/svga.h @@ -215,8 +215,8 @@ enum VGA_CRTC_START_ADDR_LOW_REG, VGA_CRTC_CURSOR_LOC_HIGH_REG, VGA_CRTC_CURSOR_LOC_LOW_REG, - VGA_CRTC_VERT_RETRACE_START_REG, - VGA_CRTC_VERT_RETRACE_END_REG, + VGA_CRTC_START_VERT_RETRACE_REG, + VGA_CRTC_END_VERT_RETRACE_REG, VGA_CRTC_VERT_DISP_END_REG, VGA_CRTC_OFFSET_REG, VGA_CRTC_UNDERLINE_REG,