端末エミュレータでまだ画面のちらつきが発生するのはなぜですか?

端末エミュレータでまだ画面のちらつきが発生するのはなぜですか?

ターミナルエミュレータがテキストベースのアプリケーションを描画するときにまだ視覚的アーティファクトがあるのはなぜですか?これは、アーティファクトフリーのアンチエイリアシングベクトルフォントを含む3DゲームやGUIウィンドウをレンダリングする最新のコンピュータで機能します。

画面更新プロセスの中間段階を示す次のアーティファクトを頻繁に表示できます。

  • ターミナルカーソルの移動(更新中にカーソルが画面上で点滅またはジャンプします。)
  • (画面の一部には古いコンテンツが表示され、他の部分には新しいコンテンツが表示されます)
  • スクロール(新しいスクロール位置がすぐに表示されず、スクロールが目立つ)

これらの成果物は1秒未満の間隔でのみ表示され、ほとんどの画面更新中は表示されません。しかし、ちらつきのないGUIで育った私はまだそれを防ぐ方法が気になります。より複雑な画面を描画し始めると、上記のすべての成果物(スクロールを除く)を次のASCIInemaビデオで見ることができます。MapSCII - コンソールで世界中に会いましょう!

遅いアップデートについても具体的に言うものではありません。アップデートが常にすぐに行われれば幸いですが、ネットワークと処理の遅延のため、これは必ずしも可能ではありません。ここでいう意味は、部分的に描かれた画面がちょっと見える場合が多いということです。ほとんどの最新のGUIでは、完全に完成した画面のみがユーザーに表示され、部分的に描かれたアーティファクトは非常にまれです。

私の考えでは、ターミナルエミュレーションパイプラインは次のとおりです。

  1. ユーザーがキーボードのキーを押す
  2. カーネルはキーボードドライバからウィンドウシステムにキーストロークを渡します。
  3. ウィンドウシステムはキー押下を端末エミュレータに渡す。
  4. ターミナルエミュレータは、キー押しを疑似ターミナル(pty)カーネルデバイスに渡します。
  5. Ptyはキーストロークを解釈し、結果をテキストベースのアプリケーションに渡します。
  6. アプリケーションはキーの押下に応答してコマンドを実行します。
  7. アプリケーションは内部バッファに新しい画面(文字セルグリッド)をレンダリングします。
  8. curses文字セルグリッドをANSIエスケープコードに変換して端末にその画面をレンダリングするアプリケーション呼び出しまたは他のライブラリ
  9. ライブラリは、これらのANSIエスケープコードをptyデバイスに書き込みます。
  10. Ptyは何らかの方法で記録されたデータを処理します。
  11. 端末エミュレータは、ptyから一部のチャンクの処理済みデータを読み込みます。
  12. ターミナルエミュレータはウィンドウシステムを呼び出して、ターミナルウィンドウにANSIエスケープコードの結果をレンダリングします。

上記の手順のうち、端末エミュレータが最終結果の代わりに中間レンダリングステップを表示するようにプロセスを遅らせることができる手順は何ですか?

  • ハードウェア端末(シリアルポート接続)の速度は、ハードウェアによって決まるようです。ボーレート変更することはできますが、tcsetattr()複数のソースを介して、ボーレート設定がターミナルエミュレータで使用される擬似ターミナル(pty)デバイスに影響を与えないことがわかります。これは、Unixカーネルが意図的にpty通信速度を制限しないことを意味しますか?

  • アプリケーションやレンダリングライブラリ(呪いなど)がテキストとANSIコードを1回の書き込みで送信するのではなく、複数回の書き込みで送信しますかwrite()

  • Unixカーネルには内部I / Oバッファのサイズ制限があり、これはブロックなしでパイプを介して転送できる最大データ量に影響します。これは、多くの詳細(テキスト画面、さまざまな色など)を含む端末画面のレンダリングに影響しますか?結合されたテキストとANSIエスケープコードは、ptyドライバのバッファに収まらないデータを生成しすぎて、画面の更新をアプリケーションへの複数の書き込みと端末エミュレータへの複数の書き込み操作に分けることができると思います。端末エミュレータが次の読み取りを処理する前に各読み取りの結果を表示しようとすると、バッチの最終読み取りが処理されるまでディスプレイが点滅します。

  • ターミナルエミュレータまたはptyドライバは意図的にバッチタイムアウトを設定し、その動作がハードウェアターミナルに似ているように感じたり、より自然に感じたり、表示速度よりも重要であると考えられる他の問題を解決したりしますか?

最近では、より速くレンダリングする新しい端末エミュレータを作成することができました(たとえば、ビデオメモリのOpenGLテクスチャでフォントをプリレンダリングする方法など)。しかし、この努力は、グリッドを計算した後にスクリーンビットマップに文字セルグリッドをレンダリングする速度を高めるように見えるだけです。

非常に高速なコンピュータでも、これらのものが根本的に遅いのには他に理由があるようです。考えてみてください。端末エミュレータが画面ビットマップに何かをレンダリングする前に文字セルグリッドを取得するためにすべてのANSIコードを処理する場合、文字グリッドビットマップレンダリングルーチンがどれほど遅いかは問題ではありません。点滅しないでください。少なくとも、私たちがたくさん見ることができるハードウェア端末のカーソルの動きに明らかに対応する点滅ではありません。端末エミュレータが画面に特定の文字セルグリッドを描画するのに1秒かかっても、ちらつきではなく1秒の非アクティブ時間だけが発生します。

同様の問題は、Unixclearresetコマンドが実行する操作に比べて非常に遅いことです(GUIユーザーの観点からは、ビットマップを再描画するよりも複雑なことはありません)。おそらく、関連する理由によるかもしれません。

答え1

システムを使用するときは、これらの点滅に気づかなかったので、どのようにそのような目立つ点滅が発生するかを詳しく知りたいと思います。

私のシステムでは、VTE(GNOME端末の背後にあるエンジン)は約10 MB / sの受信データを処理できます。他のシミュレータの性能はあまり変わらず、双方向に3〜5倍程度になることがあります。ちらつきのないアップデートにはこれで十分です。

全画面端末には数万文字のセルを含めることができることに注意してください。 UTF-8 文字は複数バイトで構成されます。他のプロパティ(色、太字など)に切り替えるには、エスケープシーケンスが必要です。このシーケンスは、3〜4バイトから10〜20バイト(特に256色およびトゥルーカラー拡張)に簡単に拡張できます。したがって、本当に複雑なレイアウトには10​​0kB以上が必要な場合があります。これは間違いなく一段階でttyラインを渡すことはできません。一部のアプリケーション(またはスクリーン描画ライブラリ)が1つのステップで出力全体をバッファリングすることを意図しているかどうかはわかりません。おそらく彼らはprintf()を使い、stdioが8kB程度毎にフラッシュされるようにします。これが遅い別の理由かもしれません。

私は、2つのプロセスとユーザー/カーネルモードの間を前後に切り替える必要があるのか​​、マルチスレッドCPUで同時に実行できるのかなど、カーネルのスケジューリング動作についてはよくわかりません。最近、ほとんどのCPUのようにマルチコアCPUで同時に実行できたらと思います。

ストーリーには意図的なカットはありません。ただし、エミュレータがデータの読み取りを続行するか画面を更新するかを決定すると、推測が発生する可能性があります。たとえば、端末エミュレータがアプリケーションがエクスポートできるよりも速く入力を処理する場合は、最初のブロックを処理した後に入力が中断されることを確認し、UIを更新することを合理的に決定できます。

カーソルは、コンテンツが更新されると画面に沿って移動するため、点滅するのが最も簡単なようです。同じ場所に滞在することはできません。エミュレータが入力データを受信したときに画面を一度だけ更新し、カーソルが同じ位置に留まると、これらの点滅が表示されることがあります。

あなたはこれに興味があるかもしれませんアトミックアップデートの提案ここで議論してください)、これは、端末エミュレータと内部で実行されているアプリケーションの両方がサポートされている場合、ほとんどの問題を解決します。

キーボードスクロール体験がなぜそんなに良いのかに興味があるかもしれません。すごいです。キーボードの繰り返し速度とモニターのリフレッシュレートの間の干渉により、本質的に点滅しないことは不快な経験を引き起こす可能性があります。

関連情報