我正在尝试在程序集(NASM)中创建一些基本的绘图例程。查看x86 BIOS interrupt table,我发现 10h 中断提供了一些视频处理服务。
使用它,我设法绘制了一个绘制正方形的例程,将中断调用配置为Write a Graphics Pixel (AH = 0Ch)。
正方形被正确绘制但需要太长时间,我可以看到正在填充。顺便说一下,我在QEMU上运行我的代码。
我认为屏幕刷新的速度比执行指令要快。经过一些研究,我没有找到任何有用的内容。主要的解决方案是调整垂直同步并直接写入视频内存。
考虑到我使用的视频模式 12h(640x480 - 16种颜色),我的问题是:
1 - 直接写入视频内存比调用中断要快吗?
2 - 视频内存空间中字节的组织方式如何?每个像素占用一个字节(从地址0xa000开始)?
3 - 如何写入视频内存?只需按顺序写入每个像素颜色?
4 - 一般情况下,当显示屏刷新屏幕时,它只是直接从视频内存中读取?
答案 0 :(得分:4)
1)直接写入视频内存要快得多。
2)对于只有16种颜色(4位)的图形视频模式,我们必须使用端口访问(到3CEh像素掩模寄存器),并在目标位置附加虚拟读取,以便将一个像素设置为帧缓冲区。解释方式并不是那么简单。但我可以使用16种颜色的视频模式为您提供ET4000图形卡像素设置程序的示例:
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
但是没有端口访问,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卡,我更喜欢使用我的28英寸宽屏显示器的原始分辨率,19202x1200,32位色,使用位于第四千兆字节的线性帧缓冲。为了切换到这个分辨率我使用VBE-Bios和VBE-bios中的modenumbers模式表。该文档的文档可以在vesa.org的 vbe3.pdf 中找到(costfree但需要注册/登录)在该页面的公共部分。