コンピューターグラフィックスの表示において、CPUとGPUはどのように相互作用しますか?


58

ここでは、OpenGL APIに基づいた回転三角形を備えたTriangle.exeという小さなC ++プログラムのスクリーンショットを見ることができます。

ここに画像の説明を入力してください

確かに非常に基本的な例ですが、他のグラフィックカード操作にも適用できると思います。

私はちょうど興味があり、Windows XPでTriangle.exeをダブルクリックしてから、モニター上で三角形が回転するのを見るまでのプロセス全体を知りたいと思っていました。CPU(最初に.exeを処理する)とGPU(最終的に画面に三角形を出力する)がどのように相互作用しますか?

この回転する三角形の表示に関与するのは、主に以下のハードウェア/ソフトウェアです。

ハードウェア

  • HDD
  • システムメモリ(RAM)
  • CPU
  • ビデオメモリ
  • GPU
  • 液晶ディスプレイ

ソフトウェア

  • オペレーティング・システム
  • DirectX / OpenGL API
  • Nvidiaドライバー

誰かが説明のために、おそらく何らかのフローチャートで説明できますか?

すべての単一のステップ(範囲を超えると思われる)を網羅する複雑な説明ではなく、中間のIT担当者が従うことができる説明であるべきです。

ITの専門家でさえ自分自身と呼ぶ多くの人々は、このプロセスを正しく説明できなかったと確信しています。


GPUをCPUの拡張と見なすことができれば、ジレンマは解消されます。
KawaiKx

回答:


55

プログラミングの側面と、コンポーネントが相互に通信する方法について少し書くことにしました。おそらく、特定の領域に光を当てるでしょう。

プレゼンテーション

質問に投稿した単一の画像を画面に表示するには、何が必要ですか?

画面に三角形を描くには多くの方法があります。簡単にするために、頂点バッファが使用されていないと仮定しましょう。(頂点バッファーは、座標を格納するメモリの領域です。)プログラムが、グラフィック処理パイプラインに、すべての単一の頂点(頂点は単なる空間内の座標)を連続して伝えたと仮定しましょう。

ただし、何かを描画する前に、まず足場を実行する必要があります。理由は後でわかります。

// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

// Reset The Current Modelview Matrix
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();

// Drawing Using Triangles
glBegin(GL_TRIANGLES);

  // Red
  glColor3f(1.0f,0.0f,0.0f);
  // Top Of Triangle (Front)
  glVertex3f( 0.0f, 1.0f, 0.0f);

  // Green
  glColor3f(0.0f,1.0f,0.0f);
  // Left Of Triangle (Front)
  glVertex3f(-1.0f,-1.0f, 1.0f);

  // Blue
  glColor3f(0.0f,0.0f,1.0f);
  // Right Of Triangle (Front)
  glVertex3f( 1.0f,-1.0f, 1.0f);

// Done Drawing
glEnd();

それで、それは何をしましたか?

グラフィックカードを使用するプログラムを作成する場合、通常、ドライバーに対する何らかのインターフェイスを選択します。ドライバーへのよく知られたインターフェースは次のとおりです。

  • OpenGL
  • Direct3D
  • CUDA

この例では、OpenGLを使用します。さて、あなたのドライバへのインターフェイスは、あなたのプログラムにするために必要なすべてのツール与えるものである話をグラフィックカード(または、ドライバーに話しカードにします)。

このインターフェイスは、特定のツールを提供します。これらのツールは、プログラムから呼び出すことができるAPIの形を取ります。

このAPIは、上記の例で使用されているものです。よく見てみましょう。

足場

実際に描画を行う前に、セットアップを実行する必要があります。ビューポート(実際にレンダリングされる領域)、視点(世界へのカメラ)、使用するアンチエイリアス(三角形のエッジを滑らかにするため)を定義する必要があります...

しかし、私たちはそれのどれも見ません。すべてのフレームでやらなければならないことをちょっと見てみましょう。好む:

画面をクリアする

グラフィックパイプラインは、すべてのフレームで画面をクリアするわけではありません。あなたはそれを言わなければなりません。どうして?これが理由です:

ここに画像の説明を入力してください

画面をクリアしない場合は、フレームごとに単純に描画します。それglClearGL_COLOR_BUFFER_BITセットで呼び出す理由です。もう1つのビット(GL_DEPTH_BUFFER_BIT)は、深度バッファーをクリアするようOpenGLに指示します。このバッファーは、他のピクセルの前(または後ろ)にあるピクセルを判別するために使用されます。

変換

ここに画像の説明を入力してください
画像ソース

変換は、すべての入力座標(三角形の頂点)を取得してModelViewマトリックスを適用する部分です。これは、モデル(頂点)がどのように回転、拡大縮小、および移動(移動)されるかを説明するマトリックスです。

次に、射影行列を適用します。これにより、すべての座標が移動し、カメラに正しく向かいます。

次に、ビューポートマトリックスを使用してもう一度変換します。これを行って、モデルをモニターのサイズに合わせます。これで、レンダリングの準備ができた頂点のセットができました!

少し後で変換に戻ります。

三角形を描画するには、定数を使用して呼び出すことにより、三角形の新しいリストを開始するようにOpenGLに指示するだけです。描画できる他のフォームもあります。以下のような三角形ストリップ三角形ファンこれらは、同じ量の三角形を描画するためにCPUとGPU間の通信が少なくて済むため、主に最適化です。glBeginGL_TRIANGLES

その後、各三角形を構成する3つの頂点のセットのリストを提供できます。すべての三角形は3つの座標を使用します(3D空間にいるため)。さらに、を呼び出す前に呼び出すことにより、各頂点のも提供します。glColor3f glVertex3f

3つの頂点(三角形の3つの角)間のシェードは、OpenGLによって自動的に計算されます。ポリゴンの面全体に色を補間します。

インタラクション

さて、ウィンドウをクリックすると。アプリケーションは、クリックを知らせるウィンドウメッセージをキャプチャするだけです。その後、プログラムで任意のアクションを実行できます。

これは、取得たくさんあなたがあなたの3Dシーンとの対話を開始したい、もう一度難しいです。

まず、ユーザーがウィンドウをクリックしたピクセルを明確に知る必要があります。次に、視点を考慮して、マウスクリックのポイントからシーンへの光線の方向を計算できます。その後、シーン内のオブジェクトがその光線と交差するかどうかを計算できます。これで、ユーザーがオブジェクトをクリックしたかどうかがわかりました。

それでは、どのように回転させるのですか?

変換

一般的に適用される2種類の変換を認識しています。

  • マトリックスベースの変換
  • 骨ベースの変換

違いは、骨が単一の頂点に影響することです。行列は常に、描画されたすべての頂点に同じように影響します。例を見てみましょう。

前に、三角形を描く前に単位行列をロードしました。単位行列は、変換をまったく提供しないものです。だから、私が描くものは何でも、私の視点によってのみ影響を受けます。したがって、三角形はまったく回転しません。

今すぐ回転させたい場合は、自分で(CPU上で)計算を行い、単純glVertex3f他の座標(回転している)で呼び出すことができます。または、glRotatef描画する前に呼び出すことで、GPUにすべての作業を任せることができます。

// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);               

amountもちろん、固定値です。あなたがしたい場合はアニメーション、あなたはを追跡する必要がありますamountし、それをフレームごとに増加します。

さて、先ほどの行列の話はどうなりましたか?

この単純な例では、マトリックスを気にする必要はありません。私たちは単に電話をかけるだけでglRotatef、それは私たちのすべての面倒を見てくれます。

glRotateangleベクトルxyzを中心とした度数の回転を生成します。現在の行列(glMatrixModeを参照)は、現在の行列を置き換える積で回転行列を乗算します。これは、glMultMatrixが次の行列を引数として呼び出されたかのようになります。

x 2⁡1-c + cx⁢y⁡1-c-z⁢sx⁢z⁡1-c + y⁢s 0 y⁢x⁡1-c + z⁢sy 2⁡1-c + cy⁢z⁡ 1-c-x⁢s 0 x⁢z⁡1-c-y⁢sy⁢z⁡1-c + x⁢sz 2⁡1-c + c 0 0 0 0 1

まあ、それをありがとう!

結論

明らかになるのは、OpenGL について多くの話があることです。しかし、それは私たちに何も語っいません。コミュニケーションはどこですか?

この例でOpenGLが伝えているの、完了したときだけです。すべての操作には一定の時間がかかります。一部の操作には非常に時間がかかり、他の操作は非常に高速です。

GPUに頂点送信するのは非常に高速で、表現方法もわかりません。CPUからGPUに、1フレームごとに数千の頂点を送信することは、ほとんどの場合、まったく問題ありません。

画面のクリアには、ビューポートの大きさに応じて、ミリ秒以上かかる場合があります(通常、各フレームを描画するのに約16ミリ秒しか時間がないことに注意してください)。それをクリアするために、OpenGLはクリアしたい色ですべてのピクセルを描画する必要があります。

それ以外は、グラフィックアダプターの機能(最大解像度、最大アンチエイリアス、最大色深度など)についてのみOpenGLに問い合わせることができます。

ただし、特定の色のピクセルでテクスチャを塗りつぶすこともできます。したがって、各ピクセルは値を保持し、テクスチャはデータで満たされた巨大な「ファイル」です。(テクスチャバッファを作成して)グラフィックカードにロードし、シェーダをロードして、そのシェーダにテクスチャを入力として使用し、「ファイル」に対して非常に重い計算を実行するように指示できます。

次に、計算の結果を(新しい色の形で)新しいテクスチャに「レンダリング」できます。

これが、GPUを他の方法で動作させる方法です。私はCUDAがその側面と同様に機能すると仮定しますが、私はそれを扱う機会がありませんでした。

私たちは本当に全体をほんの少しだけ触れました。3Dグラフィックプログラミングは、とんでもないことです。

ここに画像の説明を入力してください
画像ソース


38

あなたが理解していないことを正確に理解することは困難です。

GPUには、BIOSがマップする一連のレジスタがあります。これらにより、CPUはGPUのメモリにアクセスし、GPUに操作を実行するよう指示します。CPUはこれらのレジスタに値をプラグインして、CPUがアクセスできるようにGPUのメモリの一部をマップします。次に、そのメモリに命令をロードします。次に、CPUがメモリにロードした命令を実行するようGPUに指示するレジスタに値を書き込みます。

情報は、GPUが実行する必要があるソフトウェアで構成されています。このソフトウェアはドライバーにバンドルされており、ドライバーは(両方のデバイスでコードの一部を実行することにより)CPUとGPUの間で分割された責任を処理します。

次に、ドライバーは、CPUが読み書きできるGPUメモリへの一連の「ウィンドウ」を管理します。一般に、アクセスパターンでは、CPUが命令または情報をマップされたGPUメモリに書き込み、レジスタを介してGPUに命令を実行するか、その情報を処理するよう指示します。情報には、シェーダーロジック、テクスチャなどが含まれます。


1
ご説明ありがとうございます。基本的に私が理解していなかったのは、CPU命令セットがGPU命令セットと通信する方法ですが、明らかにその部分を実行するのはドライバーです。それが抽象化レイヤーの意味です。
JohnnyFromBF

2
関連するCPU命令セットはありません。ドライバーとランタイムは、CUDA、OpenGL、Direct3DなどをネイティブのGPUプログラム/カーネルにコンパイルします。これらはデバイスのメモリにもアップロードされます。コマンドバッファーは、他のリソースのようなものを参照します。
アクセルグナイティング

2
参照しているプログラム(gpuで実行され、ドライバーに含まれているプログラム)がわかりません。gpuは主に固定機能のハードウェアであり、実行するプログラムはシェーダーのみで、ドライバーではなくアプリケーションによって提供されます。ドライバーはこれらのプログラムのみをコンパイルし、それらをgpuのメモリにロードします。
ベンリチャーズ

1
@ sidran32:たとえば、nVidiaのKeplerアーキテクチャでは、カーネル、ストリーム、およびイベントは、(通常)CPUではなくGPUで実行されるソフトウェアによって作成されます。GPU側のソフトウェアもRDMAを管理します。そのソフトウェアはすべて、ドライバーによってGPUメモリに読み込まれ、CPU / GPUの協調ペアのGPU側を処理するGPUで「ミニOS」として実行されます。
デビッドシュワルツ

@DavidSchwartz GPU計算タスクについて忘れていました。ただし、とにかく、それらは実装においてシェーダーと同様に動作します。ただし、通常はOSに関連付けられている機能と同じ機能がないため、「ミニOS」とは呼びません。GPUは(正当な理由で)CPUのように設計されていないため、依然として非常に特殊なソフトウェアです。
ベンリチャーズ

13

私はちょうど興味があり、Windows XPでTriangle.exeをダブルクリックしてから、モニター上で三角形が回転するのを見るまでのプロセス全体を知りたいと思っていました。CPU(最初に.exeを処理する)とGPU(最終的に画面に三角形を出力する)がどのように相互作用しますか?

オペレーティングシステムで実行可能ファイルがどのように実行され、その実行可能ファイルがGPUからモニターにどのように送信されるかを実際に知っていると仮定しますが、その間に何が起こっているかは知りません。それでは、ハードウェアの側面から見て、プログラマーの側面の答えをさらに拡張しましょう...

CPUとGPUの間のインターフェースは何ですか?

ドライバーを使用して、CPUはPCIなどのマザーボード機能を介してグラフィックスカードと通信し、GPU命令の実行、GPUメモリへのアクセス/更新、GPUで実行されるコードのロードなどのコマンドを送信できます...

ただし、コードからハードウェアやドライバーと直接話をすることはできません。そのため、これはOpenGL、Direct3D、CUDA、HLSL、CgなどのAPIを介して発生する必要があります。前者はGPU命令を実行および/またはGPUメモリを更新しますが、後者は物理/シェーダー言語であるため、実際にGPUでコードを実行します。

CPUではなくGPUでコードを実行する理由

CPUは毎日のワークステーションおよびサーバープログラムの実行に優れていますが、最近のゲームで見られるこれらのすべての光沢のあるグラフィックについてはあまり考えられていませんでした。当時、ソフトウェアレンダラーは2Dおよび3Dのことからトリックを実行していましたが、それらは非常に限定的でした。そこで、ここでGPUが登場しました。

GPUは、グラフィックスで最も重要な計算の1つであるマトリックス操作用に最適化されています。CPUは行列操作で各乗算を1つずつ計算する必要がありますが(後で、3DNow!SSEなどが追いつきます)、GPUはそれらの乗算をすべて一度に実行できます!並列処理。

しかし、並列計算が唯一の理由ではありません。別の理由は、GPUがビデオメモリに非常に近いため、CPUなどを往復するよりもはるかに高速になることです。

これらのGPU命令/メモリ/コードはどのようにグラフィックスを表示しますか?

これをすべて機能させるために欠けているものが1つあります。書き込み可能なものが必要で、それを読み取って画面に送信できます。これを行うには、フレームバッファを作成します。どのような操作を行っても、最終的にフレームバッファのピクセルを更新します。場所の他に、色と深度に関する情報も保持します。

血液スプライト(画像)をどこかに描画したい例を挙げましょう。まず、ツリーテクスチャ自体がGPUメモリにロードされるため、必要に応じて簡単に再描画できます。次に、スプ​​ライトを実際にどこかに描画するには、頂点を使用してスプライトを変換し(正しい位置に配置)、ラスタライズ(3Dオブジェクトからピクセルに変換)して、フレームバッファーを更新します。より良いアイデアを得るために、WikipediaのOpenGLパイプラインのフローチャートを以下に示します。

これは、グラフィックス全体のアイデアの主な要点であり、読者にとってより多くの研究が宿題です。


7

物事を簡単にするために、このように説明できます。一部のメモリアドレスは、RAMではなくビデオカード用に予約されています(BIOSやオペレーティングシステムによって)。これらの値(ポインター)で書き込まれたデータはすべてカードに送られます。したがって、理論的には、プログラムはアドレス範囲を知るだけでビデオカードに直接書き込むことができます。これは昔の方法とまったく同じです。最新のOSを使用する場合、これはビデオドライバーやグラフィックライブラリ(DirectX、OpenGLなど)によって管理されます。


1
-1彼は、CPUからのDirectX API呼び出しがどのようにGPUと通信できるのかを尋ねますが、あなたの答えは「ドライバーやDirectXによって管理されていますですか?また、カスタムコード(ala CUDA)を実行する方法についても説明していません。
BlueRaja-ダニーPflughoeft

3
読むことを学んでください。RAMではなくGPU用に予約されている特定のメモリアドレスに書き込むことで言いました。そして、これはすべてを実行する方法を説明します。カードのメモリ範囲が登録されます。その範囲で書くものはすべて、頂点処理、CUDAなどを実行するGPUに送られます。
AZ。

5

GPUは通常、DMAバッファーによって駆動されます。つまり、ドライバーは、ユーザー空間プログラムから受け取ったコマンドを命令のストリーム(状態の切り替え、その方法での描画、コンテキストの切り替えなど)にコンパイルし、デバイスメモリにコピーします。次に、PCIレジスタまたは同様の方法でこのコマンドバッファーを実行するようにGPUに指示します。

したがって、描画呼び出しなどのたびに、ユーザースペースドライバーがコマンドをコンパイルし、その後割り込みを介してカーネルスペースドライバーを呼び出し、最終的にコマンドバッファーをデバイスメモリに送信し、GPUにレンダリングの開始を指示します。

コンソールでは、特にPS3ですべてを自分で行うことができます。


0

CPUがビデオデータをバス経由でGPUに送信し、GPUがそれを表示すると思います。したがって、より高速なGPUはCPUからのより多くのデータを処理できます。このようにして、cpuoffloadからGPUへの処理の一部が行われます。したがって、ゲームの速度が速くなります。

CPUがデータを保存するRAMのようなものなので、すばやくロードして処理できます。どちらもゲームを高速化します。

または、サウンドカードまたはネットカードは同じ原理で動作します。つまり、データを取得し、CPUの負荷を軽減します。


これにより別の回答が複製され、新しいコンテンツは追加されません。実際に何か貢献できるものがない限り、回答を投稿しないでください。
DavidPostill

0

私は、cpuがグラフィックスカードに正確に何を伝えているのか、グラフィックス関連のコマンド(openglやdirect3dコマンドなど)がGPUに直接送信されない理由がわからないと思います。

CPUは何をレンダリングするかをGPUに指示するだけです。すべての命令は最初にCPUを通過し、そこでGPUが実際にレンダリングを行うためにセットアップ/初期化されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.