停止屏幕刷新 - INT 0x10(视频服务)- 装配中

Stop screen refreshing - INT 0x10 (Video Services) - In Assembly

我的编程环境是 MS-DOS 模拟器,我正在用 16 位汇编程序编程。

我正在使用常规文本模式,我可以在其中打印字符和使用属性。

在屏幕的一部分上,我每秒画很多字符,数千个,这创建了一个不错的动画。

问题是,为了创建动画,首先我必须删除旧的,我基本上打印 space 字符大约 1000 次。 (!) 现在,因为我正在这样做,所以每次我重绘动画时都会出现轻微的闪烁问题,这个问题很明显,非常 烦人。

我正在使用视频服务来完成所有的输出和动画工作。所以我的第一个想法就是想办法阻止屏幕刷新,全部重绘,让屏幕自己继续刷新。

因为这个过程每秒发生很多次,而且它必须发生很多次,所以我发现任何其他清洁方法都不是很有帮助。

基本问题是,即使只是一瞬间,您也会向用户展示他们不想看到的东西,一个充满空格的空白屏幕。这就是造成闪烁的原因。您可以通过使用单个 BIOS 调用(例如 INT 10h AX=0600h)更快地擦除屏幕来改进这一点,但更好的解决方案是只向用户显示他们想要看到的内容。

从上到下覆盖所有内容

一种方法是更改​​您的代码,以便在绘制新框架时完全覆盖旧框架。这样就不需要擦除屏幕。因此,例如,不要在屏幕上的不同位置跳来跳去地绘制文本,而是从左上角开始,从左到右、从上到下绘制文本。打印空格以将光标从一个位置移动到另一个位置。假设你只有两个函数可以使用,一个是将光标移动到屏幕的左上角,另一个是打印一个字符并使光标前进。

在用户看不到的地方绘制

如果这太难了,您可以使用屏幕外缓冲区来完成您现在正在做的事情。擦除屏幕外缓冲区,在上面绘制文本,然后显示它。这样用户就永远不会看到他们本不想看到的已擦除屏幕。您可以在内存中创建一个屏幕外缓冲区,然后将其复制到屏幕,或者您可以在显存中的页面之间翻转。

绘制到内存中的屏幕外缓冲区

在内存中使用缓冲区意味着您不能使用BIOS功能在其上绘制,但根据情况,这会方便很多。您将使用正常的内存写入来擦除缓冲区并绘制文本,然后将整个缓冲区复制到屏幕上。本质上,这是一种从上到下完全覆盖所有内容的方法,如上所述。

绘制到非活动视频页面

在视频页面之间翻动可能会让您使用与现在相同的 BIOS 功能来绘制文本。也就是说,假设他们在 BH 中使用一个参数来指定要使用的页面。并不是所有的 BIOS 函数都有这个,特别是我前面提到的 BIOS 函数 INT 10h, AH=06h 没有。您将使用两个视频页面,0 和 1,并且您需要跟踪哪个页面当前处于活动状态并显示给用户。然后,您将在非活动页面上擦除并绘制文本,完成后翻页,使非活动页面成为活动页面。为此,您可以使用 INT 10h AX=05XX,其中 XX 是要激活的页码。

直接写入显存

更高级的技术是直接写入显存。当 MS-DOS 流行时,PC 的速度非常慢,以至于使用 BIOS 绘制文本对于任何类型的实用动画来说通常都太慢了。相反,大多数执行此类操作的应用程序都直接写入视频内存,绕过缓慢的 BIOS 例程。您可以将上述任何技术与此结合使用。例如,您可以绘制到普通内存中的屏幕外缓冲区,然后使用 REP MOVS 指令将其复制 ("blit") 到显存。

绕过 BIOS 的缺点是它会降低您的代码的可移植性。例如,最初的 IBM PC 单色显示适配器 (MDA) 和彩色图形适配器 (CGA) 的视频内存位于不同的位置(分别为 B000:0000 和 B800:0000)。其他第三方不是 100% PC 兼容的计算机甚至更奇怪。有些不支持文本模式,BIOS会使用位图图形模式绘制文本。

直接写入显存:

  • 找出视频模式如下:

    1. 将 AH 设置为 0x0F
    2. 呼叫中断 0x10(视频服务)
    3. 在 AL 中查找视频模式
  • 如果视频模式为7,屏幕内存从B000:0000

  • 开始
  • 否则,屏幕内存从B800:0000
  • 开始

内存在字符的一个字节和"attributes"(粗体、下划线、反转、闪烁)的一个字节之间交替

如果您使用的是物理硬件,最好在写入物理屏幕内存之前等待垂直回扫以避免 "snow"。这可以通过在写入之前等待端口 0x3DA 变为奇数来完成。

请参阅此 old Usenet thread 讨论此技术的局限性和可能的​​改进。