VGA显卡垂直回扫位清除时是否读取像素缓冲区?DOS游戏技术问询
Understanding VGA Vertical Retrace & Your Screen Tear Fix
Great question—let’s break this down step by step, since VGA timing is one of those old-school details that’s easy to misremember, especially when working with mode 13h (320x200 256-color).
Why Waiting for Vertical Retrace Works
First, let’s clarify what that bit 3 in port 0x3DA actually does:
- Bit 3 set (1): The VGA is in the vertical retrace period. This is the short window where the electron beam in the DOS-era CRT monitor has finished drawing the entire screen and is moving back up to the top-left corner to start the next frame. During this time, the VGA does not read from the video memory (A000:0000)—it’s busy resetting its position, so writing to video RAM here won’t interfere with the current frame being displayed.
- Bit 3 clear (0): The VGA is actively drawing the screen (the vertical display period). During this time, it’s continuously reading pixels from A000:0000 via DMA to send to the monitor. If you write to video RAM while this is happening, you risk overwriting pixels that the VGA is in the middle of reading—this causes the screen tear you saw originally.
Your fix works because:
- You first wait for any ongoing vertical retrace to finish (wait for bit 3 to clear)
- Then you wait until the next vertical retrace starts (bit 3 to set again)
- You perform the
rep movswto copy your frame buffer to video RAM only during this safe window
Addressing Your Guesses
Let’s correct a couple of small misconceptions in your reasoning:
- Your core idea that writing during vertical retrace is safe is spot-on, but the timing details are slightly off:
- When bit 3 is set, the VGA is not reading pixels to output—it’s in the retrace phase (beam moving back up).
- When bit 3 is clear, the VGA is actively reading from A000:0000 via DMA to draw the screen line by line. Writing during this period is risky because you might overwrite data the VGA hasn’t sent to the monitor yet, leading to tear.
- The VGA doesn’t "load pixels into local memory" during retrace—CRT-based VGA is a real-time device: it reads pixels directly from video RAM as it draws each scanline. There’s no dedicated frame buffer in the VGA itself (mode 13h uses a planar frame buffer in system RAM at A000:0000).
Why You’re Still Seeing Minor Sprite/Jitter Issues
The small remaining jitter when scrolling sprites/backgrounds is likely due to one of two things:
- Your frame copy takes longer than the vertical retrace period: Vertical retrace in VGA mode 13h is only about 1ms (depending on the monitor’s 60Hz refresh rate). If your
rep movsw(copying 32,000 words) takes longer than that, you’ll start writing into the active display period again, causing partial tear/jitter. Optimize this by:- Using faster memory copy methods (e.g., unrolling the loop instead of
rep movsw, or using 32-bit registers if you’re on a 386+ system) - Only updating changed parts of the screen instead of copying the entire frame buffer every time (dirty rectangles)
- Using faster memory copy methods (e.g., unrolling the loop instead of
- Sprite drawing timing: If you’re drawing sprites directly to the frame buffer after waiting for retrace but before copying, or if sprite drawing spills into the active display period, that can cause jitter. Make sure all off-screen rendering (frame buffer updates) happen before you wait for retrace and copy to video RAM.
Your Original vs. Fixed Code
Original (Tear-Prone) Code
WRITE_FRAME PROC ;WRITES ALL 64,000 PIXELS (32,000 WORDS) IN THE FRAME BUFFER TO VIDEO MEMORY push es push di push ds push si push cx mov cx, frame mov ds, cx xor si, si ;ds:si -> frame buffer (source) mov cx, vidMemSeg mov es, cx xor di, di ;es:di -> video memory (destination) mov cx, (scrArea)/2 ;writing 32,000 words of pixels rep movsw ;write the frame pop cx pop si pop ds pop di pop es ret WRITE_FRAME ENDP
Fixed (Retrace-Synced) Code
WRITE_FRAME PROC ;WRITES ALL 64,000 PIXELS (32,000 WORDS) IN THE FRAME BUFFER TO VIDEO MEMORY push es push di push ds push si push ax push cx push dx mov cx, frame mov ds, cx xor si, si ;ds:si -> frame buffer (source) mov cx, vidMemSeg mov es, cx xor di, di ;es:di -> video memory (destination) mov cx, (scrArea)/2 ;writing 32,000 words of pixels ;If vert. retrace bit is set, wait for it to clear mov dx, 3dah ;dx <- VGA status register VRET_SET: in al, dx ;al <- status byte and al, 8 ;is bit 3 (vertical retrace bit) set jnz VRET_SET ;If so, wait for it to clear VRET_CLR: ;When it's cleared, wait for it to be set in al, dx and al, 8 jz VRET_CLR ;loop back till vert. retrace bit is newly set rep movsw ;write the frame pop dx pop cx pop ax pop si pop ds pop di pop es ret WRITE_FRAME ENDP
内容的提问来源于stack exchange,提问作者bad
相关产品推荐
相关产品推荐

