私は最近OpenGLに触れ始め、OpenGLが直接または間接レンダリングにX Window Systemを使用する方法を研究しています。
私が理解したところによると、直接レンダリングにはDRI(Direct Rendering Infrastructure)というものが使われます。その後、DRIはDRM(Direct Render Manager)を利用してハードウェアに直接アクセスします。
OpenGLが必要なのはなぜですか?DRMを使用してハードウェアに直接アクセスできないのはなぜですか?
ベストアンサー1
OpenGLとは何ですか?グラフィックカードとは何ですか?
OpenGLは高度な3Dグラフィックライブラリです。
「グラフィックカード」またはむしろGPUと通信するために使用されますが、多くの3Dサポートカード間の多くの違いをOpenGLのよりシンプルで一貫した「概念空間」に抽象化します。 OpenGLは、コンピュータにPCIがあるか、SoCであるか、カードにいくつかの制御レジスタがあるか、またはその他の重要でないハードウェアの詳細については気にしません。
最新のOpenGL対応GPU(たとえば、nvidia、ati、またはモバイルチップセットのGPU)は、実際には「グラフィックス」カードではありません。
実際、今日の最新のGPUの実際の「グラフィックカード」は回路の0.01%しか占めていません。
実際、最新のGPUは非常に複雑な「3Dグラフィックエンジン」です。 GPUチップの99.99%がこのエンジンであるほどです。
また、ピクセルなどの低レベルの基本要素についても話しません。
たとえば、ほぼすべての過去のGPU(約2000年)には、いわゆる「2Dブリッタ」エンジン、つまりビットマップ転送のための実際の物理回路がありました。「ビットブロック転送」。
SNESなどの古いコンソールには、イメージスプライトをフレームバッファメモリに転送、変換、増やし、回転させることができる同様の回路(転送)がありました。私たちはこの回路を「ロータリースケーラ」と呼ぶ傾向があります。ハードウェアで表現されたため、SNESは8/16ビットコンピュータでも簡単に60fpsの流動グラフィックスを実装できました(当然、スプライト数は特定のチップ設計によって制限されています)。
最新のGPUには、もはや「2Dブリッター」や「ロトズーマー」はありません。特別に構成された直交投影で2つの三角形で構成された3Dクワッドを描画すると、GPUの3Dエンジンは本質的に従来のブリッター/ロトズマー操作のように動作できるためです。しかし、実際の3D回路で処理されるため、フラグメントシェーダ、頂点シェーダ、Zバッファ、ステンシルバッファ、頂点配列など、驚くべき柔軟性を持つようになります。ステロイドのためのスーパースピンスケーラだと思います。
実際、今日のほとんどのGPUは、画面の多数のインスタンスで複雑な3Dモデルを完全に自律的に、テクスチャリングし、シェーディングするのに十分進歩しています。つまり、最新のGPUはシーン全体を自分で描きます!
実際、彼らはコンピュータの中のコンピュータです。考えてみてください。 GPUは実際に(!)モデルデータ(コーナーリスト、ポリゴン/三角形リスト、テクスチャ、変換行列、テンソルまで)、モデル変換、透視投影変換などを理解しています。
さらに、これらすべては「プログラミング可能」です(!)。つまり、「マイクロプログラム」を作成し、それをカードプロセッサコマンドでコンパイルしてから、カード自体に(永続的ではない)「アップロード」することができます。
OpenGLは、これらすべての操作をプログラミング言語に依存しない形式で表現します。たとえば、gccやclang(llvm)とは大きく異なる完全に最適化されたシェーディング言語コンパイラが含まれていますが、フラグメントシェーダのアセンブリガイドラインも表示されません。単に必要ではありません。
ただし、低レベル(システムレベル)では、すべてのモデルデータとシェーダプログラムが何とかカードに入る必要があります。またカードを「駆動」しなければなりません(例: コマンドを送りなさい: これを描きなさい、それを描きなさい、スクリーンを消しなさい)。コンパイルされたシェーダプログラムやモデルデータなど、一部のデータはメモリチャンク単位で提供されます。命令のような他のものは通常、CPUと同様にGPUレジスタを介して動作する。
PCI技術を使用するPCタイプコンピュータでは、このすべての作業は通常、カードのレジスタセットと「メモリウィンドウ」(データ転送穴)をPCI空間からプロセッサメモリ空間にマッピングすることによって行われます。ただし、タブレットや携帯電話では完全に異なる場合があります(多くのSoCにはPCIもありません)。
グラフィックスプログラマーとして、あなたはこれらの詳細に興味を持っていません。
伝統的な「Unix」「グラフィック」
今、伝統的に「unix」(BSD、Linux、Solarisなど)はグラフィックに興味がありませんでした。 X11サーバーはこの目的のために設計されたツールです。
実際、古い「Unix」システムにはディスプレイドライバという概念さえありませんでした。 「Unix」はグラフィックカードが何であるかさえ知らなかった!
それとその核心に関する限り、それはテレタイプやディスクドライブとは異なり、役に立たず、死んで、電力を大量に消費します。 :).
その時、Xはどのように絵を描いたのか聞いてみることもできますね。
と。
したがって、この「穴」を通して実際にカードを話し、直接「駆動」する人はXです。考えてみてください。これはマイクロカーネル/FUSEに似たデザインです。
これはうまくいきます...
… …しばらく… …
...しかし、それは私たちが思ったほど効果的ではないことがわかりました。
当初は適切でしたが、カードとGUIがより複雑になったため、このデザインはロードと使用の要件を満たしていませんでした。
元のデザインは美しかった:
- Xをクラッシュしてもシステムはクラッシュしません。
- プログラムはXに絵を描くように頼み、Xはそれらの間の絵を調停し、ハードウェアを直接駆動します。
- Xとの通信はソケットを介して行われるため、描画はネットワーク経由でも可能です(ネットワークの透明性のため)。
「地上」の状況も簡単です。
- グラフィックカードには、実際にはフレームバッファ、文字ジェネレータ、ディスプレイコントローラ、アドバンストカードの場合はビットバッファなど、いくつかのコンポーネントがあります。
- アプリケーションは、ほとんど単純なベクトル2Dグラフィックを描画するために単純なコマンドを実行します。
- Xはグラフィックアルゴリズムの「知識ポイント」です(これはGPU回路とシェーダコードの組み合わせです。どちらもXの外側にあります)。
私たちはもっと必要またはもっと欲しいことがわかりました…
ユーザーモードの望ましくない効果
まず、ハードウェアを駆動するユーザモードプログラムは、待ち時間とあらゆる種類の奇妙な問題を直接発生させる。
たとえば、グラフィックカードが割り込みを生成する場合があります。カーネルスレーブデバイス(気にしない)からユーザーモードXサーバープロセスに割り込みを伝播するにはどうすればよいですか?
時々この割り込みに対する応答は即時でなければなりませんが、Xorgが現在予約されていて、sshが現在着信トラフィックを処理している場合はどうなりますか?
または別のもの:何でも描くには、プログラムのユーザーモードからカーネルモードに切り替える必要があり、Xのユーザーモードに切り替える必要があります(遅延)。実は、ご覧のようにはるかに悪いです。
同様の質問がたくさん起こり始めました。
第二に、Xはこれらのカードと通信するために独自のドライバを必要とします。これはカーネルドライバではありませんが、ユーザーモードXがハードウェアと通信するためのFUSEに似たXドライバです。ちょっと厄介です。
第三に、遅いですが、人々は関連性を維持するためにカーネルがグラフィックについて知っておくべきことを発見しています(グラフィックブート画面が必要な場合は、カーネルはグラフィックモードやディスプレイなどについて知る必要があります - 一部のデバイス) )はテキストモードグラフィックも認識しません。だからカーネルはとにかく独自のドライバを開発し始めました。だから、ある時点で、すべてのカードの冗長ドライバが起動しました。 1つはX用で、もう1つはカーネル用です。
第四に、最新の「グラフィックカード」はもはやグラフィックカードではありません。フラグメントシェーダ、頂点シェーダ、テクスチャ、頂点バッファ、ディスプレイバッファ、ディスプレイ、モニタなど、あらゆる種類の興味深いオブジェクトを知るインテリジェントエンジンです。
最新のUnixシリーズのマルチタスクオペレーティングシステムには、複数のユーザー、異なるモニターで同時に実行される複数のアプリケーションがあり、多くのアプリケーションが同時にカードのハードウェアオブジェクトを使用します。つまり、アカウント(割り当て/割り当て解除)を実行する必要があります。 、アクセス制御とすぐに。
X は、ユーザー空間のアプリケーション間でこれらすべてのオブジェクトを管理します。しかし、Xがクラッシュした場合、これらのオブジェクトはどうなりますか?カードには引き続き割り当てられていますが、システムはそのカードに関するすべての請求情報を失いました。この問題を解決する唯一の方法は、すべてを忘れて再起動するようにカードを強制的にリセットすることです。
最後に、Xベースのソケット描画がどのように機能するかを考えてみましょう。アプリケーションが10K頂点3Dモデルを描画しようとしているとします。
- アプリケーションはモデルデータを保持するメモリバッファを準備する必要があります。
- モデルデータを正しい形式でフォーマットする必要があります。
- その後、Unixソケット(またはクレイジーな場合はネットワーク)を介してXに送信します。
- Xはデータを受信するためにメモリバッファを準備する必要があります。
- カーネルはデータを混ぜる
- Xはカードとの通信を準備する必要があります。
- Xはデータをカードにマッピングしました(つまり、カードに「転送」)。
- カーネルはデータを混ぜる
- Xはジョブの結果を検索してパッケージ化し、Xソケットを介して返す必要があります。
- カーネルはデータを混ぜる
- アプリケーションはメッセージで結果を受信する必要があります。
- アプリケーションは受信したメッセージを表示し、操作が失敗したことを知らせることができます。
上記のタスクは、提供または実行する必要がある他のタスク(オーディオプレーヤー、SSH、ディスクなど)によってプリエンプトされる可能性があることに注意してください。さらに、これらのプロセスはすべて、最新のOpenGLゲームが何百万もの詳細な木を含むフレームをレンダリングするのにかかる時間よりも長く(遅延)かかることがあります。
現代:カーネルはバルーンガムを噛んで歩くだけでなく、ボブロスのように描く方法も同時に学びました。
したがって、KMSとDRIという2つの新しい技術が導入されました。
KMS - カーネルモードの設定 - カーネルにグラフィックカードとその機能(フレームバッファ、ディスプレイリンク、モニタ/ディスプレイ、解像度)を認識させる。
DRI - Direct Render Infrastructure - DRM(Direct Render Manager)を使用してカーネルを拡張し、一部のカードにオブジェクト(バッファ/さまざまなメモリブロック(フレームバッファ、モデル、テクスチャ、メモリホール))を含めることができる複雑な3Dグラフィックエンジンイムを認識します。 「データ)、シェーダ、その他など。また、これへのアクセスも考慮します。
結局のところ、カーネルはシステムのシステムオブジェクト(プロセス、ファイル、メモリマップ)に関する最高の統計を持っています。 DRMはこれをグラフィックオブジェクトに拡張します。 X(またはそれを使用する他のもの)がクラッシュすると、カーネルはそのイベントを選択し、カード自体からすべてのプロセス関連リソースを消去します。オブジェクトの漏れやハードカードのリセットはなくなりました。
これらのインタフェースはすべてソケット(Xなど)の代わりにシステムコール、ファイル記述子、およびメモリマップを使用して実装され、必要に応じてカーネルに直接移動します。したがって、インメモリマッピング「ホール」の場合、待ち時間が大幅に短縮され、ほぼ即時である。
これは、ソケットを介して送信されるバッファではなくシステムコールや他のカーネルオブジェクトであるため、ハードウェア全体の速度でゼロコピーデータ転送が達成されます。
最後に、DRIの場合、描画アプリケーション自体(Xではない)がカードと直接通信することを理解する必要があります。
だから「直接」と呼びます。
たとえば、Xを実行してDRIアプリケーション(OpenGLベースのアプリケーションなど)を使用している場合、このウィンドウに描かれたコンテンツは通常、XではなくDRIのアプリケーション固有のプライベートコードパスを介してカードに入ります。 Xは、ウィンドウがXディスプレイの対応する位置にマッピングされているかのように偽装します。
最新のOpenGLはDRIに基づいて構築されました。しかし、DRIは絵を描くのではありません...
なぜDRIを使用しないのですか?なぜなら、ポイントは何ですか?
OpenGLを使用している場合は、すでに直接使用しているのです。この場合にのみ、OpenGLライブラリはドライバDRIのプロセスアドレス空間にロードされます。
しかし、グラフィカルアプリケーションプログラマにとっては、DRIは低すぎるので、面倒にする必要はありません。 DRI は、アクセス権、割り当ての追跡とクリーンアップ、描画コンテキストの切り替え、コマンドの多重化、メモリマッピングなどのシステムの問題を処理します。
DRIには「絵」はあまりありません。グラフィックスプログラマがこのサブシステムを操作すると、どのような利点が得られますか?文字通り何もありません。
また、DRIはUnixシステムに特化しているので(すべての主要なBSDはLinuxのDRIインフラストラクチャを使用しています)、Unix用のDirect3Dと少し似ていますが、はるかに低いレベルなので、ここでのDirect3Dの比較は公平ではありません。
たとえば、DRIを直接使用する別の新しいAPIはVulkanです。 Vulkanコードを見ると、同じOpenGLコードよりはるかに複雑です。これは、OpenGLよりはるかに低いレベルに移動できるためです。しかし、DRIは低レベルにあり、これには「写真」は含まれていません。
内部的にはDRIを使用することができますが、3Dグラフィックとは無関係であり、ビデオデコードの完全な直交世界をカバーする別のAPIはVDAPUです。 VDAPUの内部構造はアプリケーションユーザー(メディアプレーヤー)から完全に分離されています。
DRI は特定のカードのハードウェアの詳細と直接関連しており、DRM とグラフィックスメモリマネージャの大部分はアプリケーションやユーザ空間ではなくカーネルにあります。
アプリケーションプログラマでもグラフィックプログラマでも、特定のシステムプログラミングタスク(DRIの変更など)を実行したくない限り、DRIレベルに直接移動することは意味がありません。そうすれば、オープンソースのグラフィックドライバを簡単に使用できます。またはOpenGL、Vulkan、またはVDPAUライブラリ自体から。
OpenGLとVulkanは、グラフィックスプログラマがやりたいことをすべて表現できる「薄い」クロスプラットフォームレイヤーで、カード間の違いを抽象化します。
グラフィカルアプリケーションプログラマは、並列に実行される他のアプリケーションでテクスチャ割り当てがどのように機能するか、またはどのテクスチャが特定のDRMファイル記述子にバインドされているかを気にしません。
彼らが興味を持っているのは、アプリを介して希望の方法でカードを運転することだけです。