我正在编写一个操作系统,并希望具有GUI。我找不到在屏幕上绘制像素的良好教程。
我想要一些汇编+ C示例,可以在某些仿真器(如BOCHS或v86)上构建并运行
答案 0 :(得分:3)
基本思想是:
1)引导程序使用固件(BIOS上的VBE,UEFI上的GOP或UGA)设置显示器,视频卡和OS支持的图形模式;在执行此操作时,它会从固件中获取有关帧缓冲区的相关信息(帧缓冲区的物理地址,水平和垂直分辨率,像素格式,水平行之间的字节),并将其传递给操作系统;这样,操作系统就可以在“早期初始化”(启动本机视频驱动程序之前)期间使用此信息,并在没有合适的本机视频驱动程序的情况下继续使用它(作为一种“渐进模式”)。
2)OS使用该信息来确定如何写入帧缓冲区。这可能是类似physical_address = base_address + y * bytes_between_lines + x * bytes_per_pixel
的计算(其中bytes_per_pixel
是根据像素格式确定的。)
“早期初始化”注意事项:
“中间初始化”注意事项:
“初始化后”的注意事项:
对于传统的“ 2D GUI”;通常,您为背景/桌面有一个缓冲区(或“画布”或“纹理”或其他东西),为每个窗口或对话框有更多的缓冲区/画布,对于较小的东西(例如,鼠标指针,拖放)可能有更多的缓冲区/画布。下拉菜单,“小部件”等);这样,应用程序就可以修改其缓冲区/画布(但出于安全原因而被阻止直接或间接访问任何其他缓冲区/画布)。然后,GUI告知视频驱动程序应在何处绘制这些缓冲区/画布中的每一个;视频驱动程序(如果是本地视频驱动程序,则使用硬件加速)将这些片段组合在一起(“合成”)以获取整个帧的像素数据,然后进行像素格式转换(希望使用GPU)以获取原始像素数据到显示/发送到显示器。这意味着在存在本机视频驱动程序时,各种操作(在屏幕上移动窗口,在窗口之间“ alt切换”,在鼠标之间移动等)变得非常快,因为CPU不执行任何操作,而视频卡本身也可以完成所有工作
理想情况下,应用程序会有一种方法(例如OpenGL)要求视频驱动程序在应用程序的缓冲区/画布中绘制内容;这样,视频卡就可以完成更多工作(而CPU无法完成)。这对于3D游戏尤为重要,但是没有理由为什么普通的2D应用程序无法从对2D图形使用相同的方法中受益。
请注意,大多数初学者会做错所有事情(没有设计良好的本机视频驱动程序界面),因此永远不会有任何本机视频驱动程序,因为他们的所有软件始终无法使用本机视频驱动程序。这些人可能会试图说服您这不值得麻烦(因为在他们的经验中,原生视频驱动程序将永远不存在)。现实情况是,大多数本机视频驱动程序极难编写,但其中一些(对于虚拟机)并不难编写。而您的目标应该是允许其他人(通过设计合适的界面并提供足够的文档)最终编写驱动程序,而不是自己编写所有驱动程序。
答案 1 :(得分:3)
最佳答案在解释方面做得很好。您确实要求提供一些示例代码,所以这是我的GitHub上的代码段,下面将进行详细说明。
1. bios_setup:
2. mov ah, 00h ; tell the bios we'll be in graphics mode
3. mov al, 13h
4. int 10h ; call the BIOS
5. mov ah, 0Ch ; set video mode
6. mov bh, 0 ; set output vga
7. mov al, 0 ; set initial color
8. mov cx, 0 ; x = 0
9. mov dx, 0 ; y = 0
10. int 10h ; BIOS interrupt
第2行是乐趣的起点。首先,我们将值0移到ah寄存器中。在第3行,我们将13进制数移入al -现在我们可以进行BIOS调用了。 第4行调用中断向量为10 hex的bios。 BIOS现在检查ah和al。
AH:
- tells BIOS to set video mode
AL:
- tells BIOS to enter write string mode.
现在我们在第4行调用了中断,现在可以将新值移入某些寄存器了。 在第5行,我们将0C hex放入ah寄存器。 这告诉BIOS我们要写入图形像素。 在第6行,我们将0放入bh寄存器,这告诉BIOS我们将使用CGA,EGA,MCGA或VGA适配器进行输出。所以输出模式基本上是0。 接下来,我们要做的就是设置颜色。因此,让我们从0开始,它是黑色的。 都很好,但是我们要将黑色像素实际绘制到哪里呢? 那是第8-9行进入的地方,寄存器cx和dx分别存储要绘制的像素的x,y坐标。 设置好后,我们将以中断10进制的形式调用BIOS。然后画出像素。
在阅读了布伦丹详尽而翔实的答案后,这段代码将使 更有意义。某些值必须在某些寄存器中才能调用 BIOS仅仅因为这些是相应中断所位于的寄存器 会检查。其他一切都非常简单。如果你想要另一个 颜色,只需更改al中的值即可。您想在其他地方像素化吗? 混乱在cx和dx中的x和y值。再次,这不是很 对于图形密集型程序非常有效,因为它相当慢。 但是,出于教育目的,它胜过编写自己的图形驱动程序;)
通过将所有内容绘制到RAM中的缓冲区之前,您仍然可以获得一些效率 就像布兰登所说的那样在屏幕上闪烁,但我宁愿保持简单 我的例子。
在my GitHub上查看完整的免费示例。我还提供了自述文件和Makefile,但它们是Linux独有的。如果您在Windows上运行,则进行一些谷歌搜索会生成将OS组装到可引导软盘上所需的任何信息,几乎任何虚拟机主机都可以。另外,请随时问我任何不清楚的问题。干杯!
Ps:我没有写工具,只是在NASM中写了一个小脚本,打算将其组装到软盘上并作为内核(如果需要,可以在VM中运行)