返回 2026-04-20
⚙️ 工程

在使用 bank-switched 内存的显卡上,代码如何处理每像素24位格式?How did code handle 24-bit-per-pixel formats when using video cards with bank-switched memory?

文章探讨早期显卡因内存分页(bank-switched)架构限制,在处理24bpp图像时面临的内存对齐挑战。尽管像素本身可能未按32位边界对齐,开发者仍需确保内存访问操作满足硬件对齐要求以避免性能损失或错误。解决方案包括手动填充数据至32位对齐或使用分段读取策略绕过bank边界限制。

Raymond Chen

关于访问违规跨越多个页面的情况,Gil-Ad Ben Or 好奇的是,在使用采用 bank-switched 内存的显卡时,代码是如何处理每像素 24 位格式的。“问题在于,64KB 无法被 3 整除,而如果你不使用某种缓冲机制,通常又需要以像素为粒度进行访问。”

这指的是早前一篇关于 Windows 95 VFLATD 视频驱动辅助程序的文章。该程序通过将当前活动的 bank 映射到地址空间中与其模拟的平坦地址相对应的位置,从而在底层显卡使用 bank-switched 内存的情况下模拟出一个平坦的视频地址空间;并在发生页错误时切换 bank,并将映射移动到新 bank 所对应的模拟平坦地址。

但如果某个内存访问操作跨越了两个 bank,这种技巧就会失效,因为它会导致 bank 切换陷入无限循环:CPU 在第一个 bank 上触发访问违规,驱动程序将该 bank 映射进来并使第二个 bank 失效。但由于内存访问跨越了两个 bank,CPU 又会在第二个 bank 上触发访问违规,而重新映射该 bank 的操作又会导致第一个 bank 被解除映射,如此循环往复。

那么,代码是如何处理跨越两个 bank 的像素的呢?

其根本原则是:所有对内存的访问都必须正确对齐。任何正确对齐的内存访问都不会跨越页面边界。

满足这一要求只是开发中的常规成本。编写访问视频内存代码的人都知道,不能使用“读取一个 32 位值然后忽略高 8 位”这类技巧。如果一个像素跨越了边界,就必须将其拆分为三次字节访问,或者至少是一次字节访问加一次字访问(且字访问必须正确对齐)。实际上,为了决定是按“字节+字”还是“字+字节”拆分像素而大费周章并不值得,所以大家通常都直接采用三次字节访问。

不过,如果你要操作一整行像素,就可以使用对齐的 32 位读写来访问整行数据:先复制字节直到地址 32 位对齐,然后对行的主体部分使用 32 位读取,最后再复制末尾剩余的字节。这些 32 位读取会跨越像素边界,但这没关系,因为它们不会跨越页面边界。

换句话说,答案就是:他们通过正确处理这个问题来解决问题。

Category

Topics

Author

Raymond 参与 Windows 的演进已超过 30 年。2003 年,他创办了一个名为 The Old New Thing 的网站,其受欢迎程度远远超出了他最疯狂的想象,这一发展至今仍让他感到心惊肉跳。该网站后来催生了一本书,巧合的是书名也叫 The Old New Thing(Addison Wesley,2007 年)。他偶尔也会出现在 Windows Dev Docs 的 Twitter 账号上,讲述一些毫无实用价值的故事。

需要完整排版与评论请前往来源站点阅读。