组装 x86 视频模式

Mat*_*eus 5 video x86 assembly nasm vga

我正在尝试在装配 (NASM) 中创建一些基本的绘图程序。查看x86 BIOS 中断表,我发现提供一些视频操作服务的10h中断。

使用它,我设法想出了一个绘制正方形的例程,将中断调用配置为Write a Graphics Pixel (AH = 0Ch)

正方形被正确绘制,但时间太长,我可以看到它被填满。顺便说一句,我在 QEMU 上运行我的代码。

我假设屏幕刷新速度比指令执行速度快。经过一番研究,我没有找到任何有用的内容。主要可能的解决方案是调整垂直同步并直接写入视频内存。

考虑到我使用的是视频模式12h (640x480 - 16 colours),我的问题是:

1 - 直接写入视频内存比调用中断更快?

2 - 视频内存空间中的字节是如何组织的?每个像素占用一个字节(从地址 0xa000 开始)?

3 - 如何写入视频内存?简单地按顺序写入每个像素颜色?

4 - 一般来说,当显示器刷新屏幕时,它只是不时直接从显存中读取?

小智 5


1) 直接写入显存要快得多。

2) 对于只有 16 色(4 位)的图形视频模式,我们必须使用端口访问(到 3CEh Pixel-Mask-Register)并在目标位置额外进行一次虚拟读取,以便将一个像素设置到帧缓冲区。说明方法没那么简单。但我可以给你一个例子,说明我的 ET4000 显卡使用 16 色视频模式的像素设置例程:

PIXEL:    pusha
          add    bp, XMIN
          add    bx, YMIN
          mov    cx, bp              ; Screen-Offset
          shr    cx, 3
          mov    ax, PS              ; Pixel of a line
          mul    bx                  ;    * Y
          add    ax, cx              ;        + (X/8)
          mov    di, ax              ;                = address
          cmp   BYTE PTR[FLAG_2], 5  ; SVGA ?
          jb  VGA
          mov    al, dl              ; Bank switch ET4000
          shl    al, 4               ; for SVGA: 1024x768 and 1280x1024
          add    al, dl              ; overflow 64K border
          mov    dx, 3CDh            ; Port address for bank switching ET4000
          out    dx, al
VGA:      inc    cx                  ; calculate Pixel
          shl    cx, 3
          sub    cx, bp
          dec    cx
          mov    ah, 1               ; 2 ^ (((X/8) + 1) * 8 - X) - 1
          shl    ah, cl              ;                      = Pixel pos.
          mov    dx, 3CEh            ; Pixel-Mask-Register
          mov    al, 8
          out    dx, ax
          mov    al, fs:[di]         ; Dummy-READ (get the address)
EBENE:    mov   BYTE PTR fs:[di], 1  ; set Pixel
          popa
          ret
Run Code Online (Sandbox Code Playgroud)

但是具有 8,15/16,24/32 位颜色的视频模式在没有端口访问的情况下更易于使用。使用 8 位颜色的示例很容易计算像素的地址。像素地址=(Y_coordinate * 水平分辨率)+ X_coordinate

使用 8 位颜色,每个地址代表屏幕上的一个像素。但另外我们有一个调色板(查找表)用于确定每个颜色编号的红色、绿色和蓝色部分。仅对于具有 15/16 和 24/32 色的视频模式,颜色在像素地址中完全编码为两个字节,或三个字节的颜色。

3) 是的,对于具有 8,15/16,24/32 位颜色的视频模式,很容易用颜色填充屏幕。

4)我们不需要告诉显卡刷新屏幕内容。但是如果阴极射线在屏幕的末端,我们可以检查端口3DAh的状态寄存器,以尽量减少闪烁的影响和屏幕内容的撕裂。

第一次我也尝试使用具有 4 位颜色的视频模式,但它不像其他具有更多颜色的图形模式那样使用起来那么简单。今天使用我的 Radeon 7950 卡,我更喜欢使用 19202x1200 的 28" 宽屏显示器的原始分辨率和 32 位颜色,使用位于第四 GB 某处的线性帧缓冲区。为了切换到这个分辨率,我使用 VBE-Bios 和VBE-bios 中的modenumbers 的modetable。可以在vesa.org(成本免费但需要注册/登录)的vbe3.pdf 中找到该页面的公共部分中的文档。