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

VESA图形模式下绘制像素失败求助:int 10h 0ch函数无效

如何在VESA图形模式下绘制像素?

让我来帮你分析一下代码里的问题,以及如何解决它:

问题根源

你尝试使用传统VGA BIOS的INT 10h AH=0Ch函数来绘制像素,但这个方法在VESA图形模式下几乎行不通,原因有两个:

  1. BIOS函数兼容性问题:传统的INT 10h图形函数是为老旧的VGA模式设计的,绝大多数VESA扩展模式(尤其是线性帧缓冲模式)并不支持通过BIOS中断来操作像素。VESA的设计初衷就是让程序直接访问显存,而非依赖BIOS层的封装。
  2. VESA模式设置的缺失:你的代码中设置VESA模式时,没有启用线性帧缓冲(这是直接操作显存的关键)。即使某些VESA模式支持BIOS像素函数,分段式显存的管理也会带来额外的复杂度,远不如直接操作线性显存高效。

解决方案:直接操作VESA线性帧缓冲

正确的做法是获取VESA模式的显存基地址,然后直接计算像素的显存位置并写入颜色值。下面是修改后的完整代码(NASM语法,可在QEMU中测试):

首先定义VESA模式信息结构,用于获取显存参数:

struc VbeModeInfoBlock
    .ModeAttrs        resw 1
    .WinAAttrs        resb 1
    .WinBAttrs        resb 1
    .WinGranularity   resw 1
    .WinSize          resw 1
    .WinASegment      resw 1
    .WinBSegment      resw 1
    .WinFuncPtr       resd 1
    .BytesPerScanLine resw 1
    .XResolution      resw 1
    .YResolution      resw 1
    .XCharSize        resb 1
    .YCharSize        resb 1
    .NumberOfPlanes   resb 1
    .BitsPerPixel     resb 1
    .NumberOfBanks    resb 1
    .MemoryModel      resb 1
    .BankSize         resb 1
    .NumberOfImagePages resb 1
    .Reserved0        resb 1
    .RedMaskSize      resb 1
    .RedFieldPos      resb 1
    .GreenMaskSize    resb 1
    .GreenFieldPos    resb 1
    .BlueMaskSize     resb 1
    .BlueFieldPos     resb 1
    .RsvdMaskSize     resb 1
    .RsvdFieldPos     resb 1
    .DirectColorModeInfo resb 1
    .PhysBasePtr      resd 1
    .Reserved1        resd 1
    .Reserved2        resw 1
    .Reserved3        resb 1
    .Reserved4        resb 39
endstruc

主引导代码:

org 0x7c00

; 初始化段寄存器和栈
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00

; 获取VESA模式0x105(1024x768 8位色)的信息
mov ax, 0x4F01
mov cx, 0x105
mov di, vbe_mode_info
int 0x10
cmp ax, 0x4F
jne error_handler ; 如果VESA不支持该模式,跳转到错误处理

; 设置VESA模式,启用线性帧缓冲(BX最高位设为0x8000)
mov ax, 0x4F02
mov bx, 0x8105 ; 0x105 | 0x8000,启用线性帧缓冲
int 0x10
cmp ax, 0x4F
jne error_handler

; 计算(2,3)位置像素的显存地址
mov eax, [vbe_mode_info + VbeModeInfoBlock.PhysBasePtr] ; 显存基地址
mov ecx, 3 ; Y坐标(行)
movzx edx, word [vbe_mode_info + VbeModeInfoBlock.BytesPerScanLine] ; 每行字节数
mul edx ; EAX = Y * 每行字节数
add eax, 2 ; 加上X坐标(8位色,每个像素占1字节)
mov byte [eax], 0x05 ; 写入颜色值(对应你之前的00000101b)

; 无限循环
jmp $

; 简单错误处理:显示'E'字符
error_handler:
mov ah, 0x0E
mov al, 'E'
mov bh, 0
int 0x10
jmp $

; 存储VESA模式信息的缓冲区
vbe_mode_info: istruc VbeModeInfoBlock
    iend

; 填充引导扇区到512字节
times 510-($-$$) db 0
dw 0xaa55

关键细节说明

  • 线性帧缓冲启用:设置VESA模式时,BX的最高位(0x8000)必须置1,这样才能获得一个连续的32位显存地址,无需处理分段显存的银行切换。
  • 像素地址计算:必须使用BytesPerScanLine而非屏幕宽度来计算行偏移,因为某些VESA模式会在扫描线末尾添加填充字节,确保每行字节数对齐到特定边界。
  • 颜色值:对于8位色模式(如0x105),颜色值是0-255的索引,对应VESA模式的调色板。你可以通过INT 10h AH=10h系列函数来设置调色板颜色。

内容的提问来源于stack exchange,提问作者Juan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:59:40