You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. You first wait for any ongoing vertical retrace to finish (wait for bit 3 to clear)
  2. Then you wait until the next vertical retrace starts (bit 3 to set again)
  3. You perform the rep movsw to 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)
  • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:25:48