【发布时间】:2019-08-28 20:48:19
【问题描述】:
我正在尝试在控制台中制作图形引擎。我不使用任何 GL,但很快希望开始。它是用 C 编写的,就目前而言,它能够构建彩色半 3D 环境,但我发现 win cmd 支持 True color scheme,使用 ANSI 转义序列。
在我对这个主题的研究过程中,我发现了WriteFile(),所有的 printfs 和 putcs 都基于 Win10。但是对于它不提供的所有商品,它仍然很慢。如内部代码所示,writefile本质上是基于这段代码的:
NtWriteFile:
mov r10,rcx
mov eax,8
test byte ptr [7FFE0308h],1
jne NtWriteFile+15h (07FFBA80CAAA5h)
syscall
ret
这很好,但速度慢且效率低。 我的意思是:我将控制台的输出句柄传递给WriteFile() 和缓冲区,但是对于 160*60 的屏幕(考虑到每个字符都有自己的 ESC[48;2;r;g; bm,20 字节长)我们得到 192000 字节。系统调用的执行时间为 84ms。
然后我用WriteConsoleOutputW() 回到我之前的设置。它使用与控制台相同的输出 ptr,但这次是 320*84 的缓冲区(它使用 CHAR_INFO ptr 作为缓冲区,所以每个 4 字节)-107 520 字节它只持续 1ms !
WriteConsoleOutputW() 基于相似的系统调用代码:
NtDeviceIoControlFile:
mov r10,rcx
mov eax,7 ; notice here is the 7 instead of 8
test byte ptr [7FFE0308h],1
jne NtDeviceIoControlFile+15h (07FFBA80CAAA5h)
syscall
ret
但这次它输出的信息量大致相同,但速度快了 80 倍!我的假设,它只是重新分配一个指向控制台缓冲区的指针,因为当我用单个字符的缓冲区启动它时,它会输出一些带有颜色的奇怪符号
我尝试将 ESC 序列输出为CHAR_INFO,但它会将它们输出为文本。所以问题是:我可以使用 WriteConsoleOutput 或NtDeviceIoControlFile() 以某种方式输出转义序列吗?
另外:我的帧缓冲区将仅包含转义序列和其后的空格符号。定义了缓冲区的宽度和高度,以及一个矩形,我需要做的就是在每个空间上输出正确的前景色。(所以长度将是 20 * 高度 * 宽度)
【问题讨论】:
-
As internal code shows, writefile is essentially based on this code:和WriteConsoleOutputW() is based on similar looking syscall code::看这段代码毫无意义。 “魔法”发生在syscall被命中时,它会跳转到真正代码所在的内核。 -
@tkausl 我知道,但是所有这些函数都可以从代码中调用并有它们的文档,但是如果读取了 writefile esc,那么第二个 bun 就不会了。我想展示的是缓慢在哪里
-
您是如何衡量这些时间的?你怎么知道操作系统没有偷窥你的任务?
-
@PaulOgilvie 有 2 个测量值:1) Visual Studio 2015 的内部调试工具,2) 包装函数上的 QueryPerformanceCounter(它们看起来很相似)
-
据记录,VT 支持仅针对高级流函数
WriteFile(即 Windows 8+ 中的NtWriteFile)实现,但系统调用是实现细节;在 Windows 7 中有所不同) 和WriteConsole(即Windows 8+ 中的NtDeviceIoControlFile,用于屏幕缓冲区文件,使用未记录的IOCTL 代码)。低级控制台 API 是基于字符单元的而不是流式的,因此它与虚拟终端接口不兼容。字符单元 API 性能更好,但代价是失去了高级处理。
标签: c windows cmd system-calls ansi-escape