模拟简单的显卡

发布于 2024-12-11 02:39:10 字数 471 浏览 3 评论 0原文

好的。我可以找到简单架构的模拟设计。(编辑:绝对不像x86)

例如使用int 作为程序计数器,使用字节数组作为内存等等。

但是我如何模拟显卡(可以想象的最简单的显卡)功能?

就像使用数组来表示每个像素并逐个“绘制”每个像素。
但是什么时候与 CPU 同步绘制还是异步绘制?谁在该数组中存储图形数据?是否有存储像素和绘制像素的指令?

请考虑所有问号('?')并不意味着“你问了很多问题”,而是解释了问题本身 - 如何模拟显卡?

编辑:链接到CPU+内存的基本实现设计模拟

Ok.I can find simulation designs for simple architectures.(Edit :definitely like not x86)

For example use an int as the program counter , use a byte array as the Memory and so on.

But how can I simulate the graphic card's(the simplest graphic card imaginable) functionality ?

like use an array to represent each pixel and "paint" each pixel one by one.
But when to paint- synchronized with CPU or asynchronously ? Who stores graphic data in that array ? Is there an instruction for storing a pixel and painting a pixel ?

Please consider all the question marks ('?') doesn't mean "you are asking a lot of questions" but explains the problem itself - How to simulate a Graphic Card ?

Edit : LINK to a basic implementation design for CPU+Memory simulation

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月亮是我掰弯的 2024-12-18 02:39:10

显卡通常带有大量 KB 或 MB 的内存,用于存储随后显示在屏幕上的各个像素的颜色。该卡每秒扫描该内存多次,将像素颜色的数字表示转换为显示器可以理解和可视化的视频信号(模拟或数字)。

CPU 可以访问该内存,并且无论何时更改它,该卡最终都会将新的颜色数据转换为适当的视频信号,并且显示器会显示更新的图片。该卡异步完成所有处理,不需要 CPU 的太多帮助。从CPU的角度来看,这很像将新的像素颜色写入显卡内存中与像素坐标相对应的位置,然后就忘记它了。现实中它可能会更复杂一些(由于较差的同步伪影,例如撕裂、雪花等),但这就是它的要点。

当您模拟显卡时,您需要以某种方式将模拟卡的内存镜像到物理显卡的内存中。如果在操作系统中您可以直接访问物理显卡的内存,那么这是一个简单的任务。只需实现对模拟计算机内存的写入,如下所示:

void MemoryWrite(unsigned long Address, unsigned char Value)
{
  if ((Address >= SimulatedCardVideoMemoryStart) &&
      (Address - SimulatedCardVideoMemoryStart < SimulatedCardVideoMemorySize))
  {
    PhysicalCard[Address - SimulatedCardVideoMemoryStart] = Value;
  }

  EmulatedComputerMemory[Address] = Value;
}

当然,上面假设模拟卡具有完全相同的分辨率(例如,1024x768)和像素表示(例如,每个像素 3 个字节,第一个字节为红色) ,第二个为绿色,第三个为蓝色)作为实体卡。在现实生活中,事情可能会稍微复杂一些,但同样,这就是总体思路。

如果您使代码可通过 PC BIOS 启动并将其限制为仅使用 BIOS 服务功能(中断),则您可以直接在 MSDOS 中或在没有任何操作系统的裸 x86 PC 上访问物理卡的内存。所有其他 PC 设备的直接硬件访问。

顺便说一句,将模拟器实现为 DOS 程序并直接在 Windows XP 中运行它可能会非常容易(Vista 和 7 对 32 位版本的 DOS 应用程序的支持极其有限,并且在64 位版本;但是,您可以安装 XP 模式, XP 位于7) 中的虚拟机,或者更好的类似 DOSBox 的东西,它似乎可用于多个操作系统。

如果您将其实现为 Windows 程序,则必须使用 GDI 或 DirectX 才能在屏幕上绘制内容。除非我弄错了,否则这两个选项都不允许您直接访问物理卡的内存,从而自动显示其中的更改。

如果有大量渲染,使用 GDI 或 DirectX 在屏幕上绘制单个像素可能会很昂贵。每次当其中一个像素发生变化时,重新绘制所有模拟卡的像素都会导致相同的性能问题。最好的解决方案可能是每秒更新屏幕 25-50 次,并且仅更新自上次重绘以来发生更改的部分。将模拟卡的缓冲区细分为较小的缓冲区,表示 64x64 像素的矩形区域,每当模拟器写入这些缓冲区时将这些缓冲区标记为“脏”,并在将它们绘制在屏幕上时将它们标记为“干净”。您可以设置一个定期计时器驱动屏幕重绘并在单独的线程中执行它们。你应该能够在 Linux 中做类似的事情,但我对那里的图形编程不太了解。

Graphic cards typically carry a number of KBs or MBs of memory that stores colors of individual pixels that are then displayed on the screen. The card scans this memory a number of times per second turning the numeric representation of pixel colors into video signals (analog or digital) that the display understands and visualizes.

The CPU has access to this memory and whenever it changes it, the card eventually translates the new color data into appropriate video signals and the display shows the updated picture. The card does all the processing asynchronously and doesn't need much help from the CPU. From the CPU's point of view it's pretty much like write the new pixel color into the graphic card's memory at the location corresponding to the coordinates of the pixel and forget about it. It may be a little more complex in reality (due to poor synchronization artifacts such as tearing, snow and the like), but that's the gist of it.

When you simulate a graphic card, you need to somehow mirror the memory of the simulated card in the physical graphic card's memory. If in the OS you can have direct access to the physical graphic card's memory, it's an easy task. Simply implement writing to the memory of your emulated computer something like this:

void MemoryWrite(unsigned long Address, unsigned char Value)
{
  if ((Address >= SimulatedCardVideoMemoryStart) &&
      (Address - SimulatedCardVideoMemoryStart < SimulatedCardVideoMemorySize))
  {
    PhysicalCard[Address - SimulatedCardVideoMemoryStart] = Value;
  }

  EmulatedComputerMemory[Address] = Value;
}

The above, of course, assumes that the simulated card has exactly the same resolution (say, 1024x768) and pixel representation (say, 3 bytes per pixel, first byte for red, second for green and third for blue) as the physical card. In real life things can be slightly more complex, but again, that's the general idea.

You can access the physical card's memory directly in MSDOS or on a bare x86 PC without any OS if you make your code bootable by the PC BIOS and limit it to using only the BIOS service functions (interrupts) and direct hardware access for all the other PC devices.

Btw, it will probably be very easy to implement your emulator as a DOS program and run it either directly in Windows XP (Vista and 7 have extremely limited support for DOS apps in 32-bit editions and none in 64-bit editions; you may, however, install XP Mode, which is XP in a VM in 7) or better yet in something like DOSBox, which appears to be available for multiple OSes.

If you implement the thing as a Windows program, you will have to use either GDI or DirectX in order to draw something on the screen. Unless I'm mistaken, neither of these two options lets you access the physical card's memory directly such that changes in it would be automatically displayed.

Drawing individual pixels on the screen using GDI or DirectX may be expensive if there's a lot of rendering. Redrawing all simulated card's pixels every time when one of them gets changed amounts to the same performance problem. The best solution is probably to update the screen 25-50 times a second and update only the parts that have changed since the last redraw. Subdivide the simulated card's buffer into smaller buffers representing rectangular areas of, say, 64x64 pixels, mark these buffers as "dirty" whenever the emulator writes to them and mark them as "clean" when they've been drawn on the screen. You may set up a periodic timer driving screen redraws and do them in a separate thread. You should be able to do something similar to this in Linux, but I don't know much about graphics programming there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文