首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么终端模拟器还有屏幕闪烁?

为什么终端模拟器还有屏幕闪烁?
EN

Unix & Linux用户
提问于 2018-11-23 21:17:08
回答 1查看 3K关注 0票数 5

为什么终端仿真器绘制基于文本的应用程序时仍然存在视觉伪影?这在最近的电脑,渲染3D游戏和GUI窗口,包括反别名矢量字体,没有工件。

我经常看到以下工件,它们显示屏幕更新过程的中间步骤:

  • 终端光标运动(更新期间光标闪烁或跳过屏幕)
  • 撕裂 (屏幕的一部分显示旧的东西,另一部分显示新的东西)
  • 滚动(滚动是明显的,而不是立即显示新的滚动位置)

这些工件只在亚秒间隔内被看到,而不是在大多数屏幕更新过程中,但是在没有闪烁的GUI上长大后,我仍然想知道如何避免它们。上面所有的工件(滚动除外)都可以在下面的ASCIInema视频中看到,当它开始绘制更复杂的屏幕时:MapSCII -在你的控制台里的整个世界!

我也没有特别提到缓慢的更新。如果更新总是即时的,那就太好了,但由于网络和处理延迟,这并不总是可能的。我在这里的意思是,部分绘制的屏幕通常在短时间内是可见的。在大多数现代GUI中,只有完全完成的屏幕才会显示给用户,部分绘图的工件非常罕见。

我的印象是,终端模拟管道是这样的:

  1. 用户按键盘上的键
  2. 内核将按键从键盘驱动程序传递到窗口系统。
  3. 窗口系统将按键传递给终端模拟器。
  4. 终端模拟器将按键传递给伪终端(pty)内核设备。
  5. Pty解释keypress并将结果传递给基于文本的应用程序。
  6. 应用程序执行命令以响应keypress。
  7. 应用程序将新屏幕(字符单元格)呈现到内部缓冲区。
  8. 应用程序调用curses或其他库将字符单元格转换为ANSI转义代码,这些代码将在终端上呈现一个等效的屏幕。
  9. 库将那些ANSI转义代码写入pty设备
  10. Pty以某种方式处理书面数据
  11. 终端模拟器以某些块从pty读取处理过的数据。
  12. 终端仿真器调用窗口系统在终端窗口中呈现ANSI转义码的结果。

以上哪几个步骤可以减慢进程,使终端模拟器向我们显示中间呈现步骤,而不是只显示最终结果?

  • 硬件终端(串口连接)的速度似乎是由波特率决定的,波特率可以随tcsetattr()的变化而改变,但我从多个来源读取到,波特率设置对终端模拟器使用的伪终端(pty)设备没有影响。这是否意味着Unix内核不刻意限制pty通信?
  • 做应用程序或呈现库(诅咒等)以多次写入方式发送文本和ANSI代码,而不是尝试只使用一个write()
  • Unix内核对其内部I/O缓冲区有大小限制,这会影响到可以通过管道不阻塞地发送的最大数据量。这是否会影响显示终端屏幕的许多细节(大量的文本、颜色等)?我设想合并的文本和ANSI转义代码可能相当于大量的数据,以至于它不适合pty驱动程序缓冲区,这会将屏幕更新拆分为应用程序的几个写操作和终端模拟器的几个读取。如果终端模拟器急于在处理下一次读取之前显示每次读取的结果,这将导致显示闪烁,直到处理完批处理的最终读取为止。
  • 终端仿真器或pty驱动程序是否对批处理进行了深思熟虑的超时,以便它们的行为更接近于硬件终端,感觉更自然,或者解决了其他一些被认为比显示速度更重要的问题?

最近有一些努力使新的终端仿真器呈现得更快(例如,将字体预渲染到视频内存中的OpenGL纹理中)。但是,这些努力似乎只会加速字符单元格的渲染到屏幕位图上,一旦计算出网格。

似乎还有别的事情在发生,甚至在一台非常快的电脑上,也会使这些东西从根本上慢下来。想想看:如果终端模拟器在将任何内容呈现到屏幕位图之前处理所有ANSI代码以获得字符单元格网格,那么字符网格到位图呈现例程的速度有多慢并不重要--不应该有闪烁(至少不应该出现明显对应于硬件终端上光标移动的那种闪烁,这是我们经常看到的)。即使终端模拟器花了整整一秒钟在屏幕上绘制任何给定的字符单元格,我们也只能得到一秒的不活动,而不是一秒的闪烁。

一个类似的问题是,Unix、clearreset命令所做的工作非常慢(从GUI用户的角度来看,它们不会做比重绘位图更复杂的事情)。也许是因为相关的原因。

EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2018-11-24 01:54:01

我希望听到更多的细节,如何准确地触发这样突出的闪烁,因为我没有注意到在使用我的系统。

在我的系统中,VTE ( GNOME终端后面的引擎)可以处理大约10 MB/s的传入数据。其他仿真器的性能也离此不远,在两个方向上可能在3或5的因子范围内。这很多,应该足够闪烁-更少的更新。

不过,请记住,全屏终端可能包含数万个字符单元格。UTF-8字符由多个字节组成.切换到不同的属性(颜色、大胆等)需要转义序列,可以从3-4到简单的10-20字节(特别是256颜色和真彩色扩展)。因此,真正复杂的布局可能需要100 kB,甚至更大的流量。这肯定不能在一个步骤中通过tty行。我甚至不确定某些应用程序(或屏幕绘图库)是否愿意在一步内缓冲整个输出。也许他们只是使用printf(),然后让stdio在大约8 kB之后刷新它们。这可能是他们行动迟缓的另一个原因。

我不太熟悉内核的调度行为,例如,它是否需要在两个进程以及用户/内核模式之间来回切换,或者它们是否可以在多线程CPU上同时运行。不过,我真的希望它们能在多核CPU上同时运行,而现在大多数CPU都是这样。

故事中没有故意节流。不过,当模拟器决定是否继续读取数据或更新其屏幕时,可能会有猜测。例如,如果终端仿真器处理输入的速度比应用程序发出的要快,那么它会在处理第一个块后看到输入延迟,因此可能会合理地决定更新其UI。

光标可能是最突出的闪烁,因为光标沿屏幕移动,因为内容正在被更新。它不能停留在同一个地方。如果模拟器在接收输入数据时只更新其屏幕一次,并且光标最终保持在相同的位置,则此闪烁极有可能变得可见。

您可能对这个原子更新建议 (在这里讨论)感兴趣,如果终端仿真器以及运行在其中的应用程序都支持它,它将主要解决这个问题。

您可能还感兴趣的是,由于键盘重复频率和监视器刷新速率之间的干扰,使用键盘的滚动体验是必干,这本身不是闪烁,而是会导致不愉快的体验。

票数 4
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/483777

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档