Hotdry.

Article

DOS VGA Mode 13h 双缓冲与垂直同步:复古图形编程的硬核实现

深入解析 DOS VGA Mode 13h 256色模式下的软件双缓冲实现与垂直同步技术,提供可落地的端口轮询方案与性能优化参数。

2026-06-09systems

在 1990 年代的 PC 游戏开发中,VGA Mode 13h 是最具代表性的图形模式之一。这个 320×200 分辨率、256 色的线性帧缓冲模式,以其简洁的内存布局和直接的像素访问方式,成为了 Doom、Duke Nukem 3D 等经典游戏的渲染基础。然而,Mode 13h 的一个关键限制是仅提供单一的 64KB 显存页面,这意味着开发者必须在软件层面实现双缓冲和垂直同步,才能避免画面撕裂并保证流畅的动画效果。

Mode 13h 的内存架构与限制

Mode 13h 的帧缓冲固定在物理地址 A000:0000,占用连续的 64KB 内存空间。每个像素由单个字节表示,该字节作为索引指向 VGA 调色板中的 256 种颜色之一。这种设计带来了极大的编程便利性 —— 开发者可以通过简单的内存写入操作绘制像素,无需处理复杂的位平面(planar)内存布局。

然而,这种简洁性也伴随着代价。与 EGA 或后续 VGA Mode X 不同,Mode 13h 不支持硬件级别的页翻转(page flipping)。显存中只有一个可见页面,这意味着任何直接写入显存的操作都会立即反映在屏幕上。如果在屏幕刷新过程中修改显存内容,就会产生画面撕裂(tearing)现象,即一帧图像中同时显示新旧两帧的部分内容。

软件双缓冲的实现策略

为了规避 Mode 13h 的单页面限制,开发者采用了一种经典的软件双缓冲方案:在系统主内存中维护一个与显存大小相同的后缓冲(back buffer),所有绘制操作首先在后缓冲中完成,然后在垂直空白期(VBLANK)将整个后缓冲的内容一次性复制到显存。

具体实现流程如下:

  1. 初始化阶段:分配 64KB 的连续内存作为后缓冲,通常使用 malloc 或编译器的静态数组分配。部分开发者选择将后缓冲放置在特定的内存段以优化复制性能。

  2. 渲染阶段:所有图形绘制操作(像素绘制、位图渲染、精灵绘制等)都针对后缓冲进行。此时显存内容保持不变,用户看到的是上一帧的完整图像。

  3. 同步阶段:通过轮询 VGA 状态端口检测垂直空白期的到来。标准做法是读取端口 0x3DA(CRT 状态寄存器),检查第 3 位(垂直同步位)的状态变化。

  4. 复制阶段:在垂直空白期内,使用优化的内存复制例程将后缓冲的 64KB 数据快速传输到显存地址 A000:0000。常用的优化手段包括使用 rep movsbrep movsw 指令,以及展开循环以减少指令开销。

  5. 交换阶段:逻辑上交换前缓冲和后缓冲的角色,为下一帧的渲染做准备。

垂直同步的端口级实现

垂直同步(VSync)是消除画面撕裂的关键技术。在 DOS 实模式下,开发者需要直接与硬件交互来检测显示器的刷新周期。

VGA 适配器的 CRT 控制器提供了一个状态寄存器,通过 I/O 端口 0x3DA(或 0x3BA 用于单色显示器)可以读取。该寄存器的第 3 位(位掩码 0x08)表示垂直同步信号的状态:当该位为 1 时,表示显示器正处于垂直空白期。

典型的等待垂直空白期的汇编代码如下:

; 等待垂直空白期开始
wait_vblank_start:
    in al, 0x3DA
    test al, 0x08
    jz wait_vblank_start

; 等待垂直空白期结束(可选,用于精确时序控制)
wait_vblank_end:
    in al, 0x3DA
    test al, 0x08
    jnz wait_vblank_end

在实际应用中,开发者通常只需要等待垂直空白期的开始即可进行显存复制操作。垂直空白期的时间窗口约为 1.2 毫秒(以 70Hz 刷新率计算),对于 64KB 的数据传输来说绰绰有余。在 286/386 级别的处理器上,使用优化的复制例程可以在 0.5 毫秒内完成整个帧缓冲的更新。

性能优化与参数调优

双缓冲方案的性能瓶颈主要集中在两个环节:后缓冲的渲染效率和显存复制的带宽消耗。

渲染优化:由于后缓冲位于系统内存,像素写入速度比显存访问更快。但仍需注意避免逐像素计算的开销。对于填充操作,可以使用 memset 或汇编级的块填充指令;对于精灵绘制,建议预先计算好源地址和掩码,减少运行时的地址计算。

复制优化:64KB 的帧缓冲复制是每帧的固定开销。优化策略包括:

  • 字对齐复制:使用 movsw 而非 movsb,每次复制 2 字节,减少指令执行次数
  • 双字复制:在 386 及以上处理器上,使用 movsd 进一步减少循环开销
  • 展开循环:将循环体展开 4-8 次,减少分支预测失败的概率
  • 使用段寄存器:合理设置 DS:SIES:DI,避免不必要的段前缀字节

时序参数:对于 320×200 分辨率、70Hz 刷新率的 Mode 13h,每帧的理论时间约为 14.3 毫秒。建议将渲染时间控制在 10 毫秒以内,留出足够的余量应对系统中断和时钟漂移。

Mode X 的替代方案

对于需要更高性能或真正硬件双缓冲的场景,开发者可以考虑 Mode X(Mode 13h 的非标准变体)。Mode X 将显存组织为四个位平面,支持硬件页翻转和更高的分辨率(如 320×240)。然而,这种方案需要处理更复杂的内存布局,编程复杂度显著增加。

如 Catlantean 3D 项目的开发者所指出,Mode 13h 的 320×200 分辨率在 4:3 显示器上会产生非方形像素,而 Mode X 的 320×240 则能保持像素比例的一致性。这种权衡体现了复古图形编程中常见的取舍:简洁性与功能性之间的平衡。

现代应用与学习价值

尽管 Mode 13h 已成为历史,但理解其双缓冲和垂直同步机制对现代图形编程仍具有重要价值。许多嵌入式系统和复古游戏开发仍在使用类似的软件渲染技术,而现代 GPU 的交换链(swap chain)概念本质上也是双缓冲的硬件加速版本。

对于学习计算机图形学的开发者而言,从零实现一个 Mode 13h 渲染器是理解帧缓冲、调色板、垂直同步等核心概念的绝佳途径。这种底层编程经验能够培养对性能敏感型代码的直觉,这种直觉在处理现代图形 API 时同样适用。


参考来源

  • Marko Stanić, "Catlantean 3D - Making Graphics Like It's 1993", 2026
  • David Brackeen, 256-Color VGA Programming in C, 1996
  • Michael Abrash, Graphics Programming Black Book, 1997

systems

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com