• 検索結果がありません。

0以降、頂点シェーダは、現在バインドされているテクスチャユニットを読み込めるようになり ました。この技法により、頂点処理の際、より大容量のメモリバッファにアクセスできるので、高度

ドキュメント内 iOS用OpenGL ESプログラミングガイド (TP ) (ページ 113-154)

Important: 精度ヒントで定義されている範囲制限は強制ではありません。そのため、データがこ の範囲に収まっていると想定することはできません。

iOS 7. 0以降、頂点シェーダは、現在バインドされているテクスチャユニットを読み込めるようになり ました。この技法により、頂点処理の際、より大容量のメモリバッファにアクセスできるので、高度

なレンダリング技法を高性能で実行できます。適用可能な技法として、たとえば次のようなものがあ ります。

変位マッピング。既定の頂点位置でメッシュを描画した後、頂点シェーダのテクスチャから各頂 点を読み込んで位置を変えます。リスト 10-10に、この技法を使って、グレースケールの高さマッ プテクスチャから3次元ジオメトリを生成する例を示します。

インスタンス描画法。“インスタンス描画法により描画関数の呼び出し回数を減らす” (76 ペー ジ)で説明したように、よく似たオブジェクトが多数並んだシーンをレンダリングする際、CPU のオーバーヘッドを大幅に削減できます。しかし、インスタンスごとに異なる情報を頂点シェー ダに供給する方法は、判断が難しいかも知れません。テクスチャには多くのインスタンスに関す るさまざまな情報を格納できます。たとえば広大な都市景観を、単なる立方体を記述するだけの

頂点シェーダで、より大容量のメモリバッファとしてテクスチャを使う

頂点データから、数百ものインスタンスを描画する、という方法でレンダリングできます。頂点 シェーダは

gl_InstanceID

変数を使い、テクスチャからサンプリングして、それぞれのインスタ ンス(建物)に適用する変換行列、色、テクスチャ座標オフセット、高さなどを求めます。

リスト 10-10

高さマップからレンダリングする頂点シェーダ

attribute vec2 xzPos;

uniform mat4 modelViewProjectionMatrix;

uniform sampler2D heightMap;

void main() {

// Use the vertex X and Z values to look up a Y value in the texture.

vec4 position = texture2D(heightMap, xzPos);

// Put the X and Z values into their places in the position vector.

position.xz = xzPos;

// Transform the position vector from model to clip space.

gl_Position = modelViewProjectionMatrix * position;

}

(OpenGL ES 3.0で導入された)ユニフォーム配列やユニフォームバッファオブジェクトを使って、大 量のデータを頂点シェーダに供給することもできますが、頂点テクスチャを使う方法にも状況によっ ては長所があります。テクスチャには、ユニフォーム配列やユニフォームバッファオブジェクトより も多くのデータを格納でき、また、ラッピングやフィルタリングの機能により、データを補間するこ とも可能です。さらに、テクスチャにレンダリングすることにより、この後の頂点処理ステージで使 うデータをGPUで生成できる、という利点があります。

デバイス上で、頂点テクスチャのサンプリングが可能かどうか(可能な場合は頂点シェーダが使える テクスチャユニット数)、実行時に

MAX_VERTEX_TEXTURE_IMAGE_UNITS

の制限値を確認してくださ い(詳しくは“OpenGL ESの機能の検証” (16 ページ)を参照)。

頂点シェーダで、より大容量のメモリバッファとしてテクスチャを使う

並列処理とは、コンピューティングにおいては通常、複数のプロセッサ上で同時にタスクを実行する ことを指します。作業を並行して実行することで、タスクがより短時間で完了し、ユーザから見たア プリケーションの応答性が高まります。しっかりした設計のOpenGL ESアプリケーションには、具体 的な形の並列処理、すなわちCPU上でのアプリケーションの処理とGPU上でのOpenGL ESの処理の並列 処理が見られます。“OpenGL ES設計ガイドライン” (52 ページ)で紹介する技法の多くは、特に、

CPUとGPUの間での優れた並列処理を実現するOpenGLアプリケーションの作成を狙いとしています。

並列処理アプリケーションを設計するということは、作業をサブタスクに分解し、並行して安全に実 行できるタスクと、順番に実行しなければならないタスクを特定することを意味します。つまり、ほ かのタスクが使用するリソース、またはほかのタスクから返された結果のどちらかに依存するタスク を特定することを意味します。

iOSにおける各プロセスは、1つ以上のスレッドで構成されています。スレッドとは、プロセスのため

のコードを実行する、実行の流れのことです。Appleは、従来のスレッドと、Grand Central Dispatch

(GCD)と呼ばれる機能の両方を提供します。Grand Central Dispatchを使用すると、スレッドを手動 で管理せずにタスクをサブタスクに分解することができます。Grand Central Dispatchは、デバイス上 で利用可能なコア数に基づいてスレッドを割り当て、それらのスレッドに対して自動的にタスクのス ケジューリングを行います。

より高いレベルでは、Cocoa Touchが

NSOperation

NSOperationQueue

を提供して、作業単位の作成 とスケジューリングのためのObjective-C抽象化を可能にしています。

この章ではこれらのテクノロジーは詳しく取り上げません。OpenGL ESアプリケーションに並列処理 を追加する方法を検討する前に、『Concurrency Programming Guide』をお読みください。スレッドを 手動で管理する場合は、『Threading Programming Guide』もお読みください。使用するテクニックに 関係なく、マルチスレッドシステム上でOpenGL ESを呼び出す場合に追加の制限があります。この章 は、マルチスレッドによってOpenGL ESアプリケーションのパフォーマンスが向上する場合、OpenGL ES がマルチスレッドアプリケーション課す制限、そしてOpenGL ESアプリケーションに並列処理を実装 するために使用できる一般的な設計方法を理解するのに役立ちます。

並列処理のメリットがあるかどうか判断する

マルチスレッドアプリケーションの作成では、アプリケーションの設計、実装、テストにおいてかな りの労力が必要です。スレッドもアプリケーションに複雑さとオーバーヘッドを追加する要素です。

アプリケーションはワーカースレッドに渡すことができるようデータをコピーする必要のある場合が

並列処理と OpenGL ES

あり、複数のスレッドは同一リソースへのアクセスを同期する必要の生じる場合があります。OpenGL

ESアプリケーションに並列処理を実装しようとする前に、“OpenGL ES設計ガイドライン” (52 ペー

ジ)で説明するテクニックを使用して、まず単一スレッド環境でOpenGL ESコードを最適化します。

最初は、CPUとGPUの効率的な並列処理の達成に焦点を合わせ、その後で並列プログラミングによっ てパフォーマンスを向上できるかどうかについて評価します。

並列処理に適した候補には、次に示す特性のどちらか、またはその両方が備わっています。

アプリケーションが、OpenGL ESのレンダリングに依存しない多くのタスクをCPU上で実行する。

たとえば、ゲームは、ゲームの世界をシミュレートし、コンピュータに操られる敵の人工知能を 計算し、サウンドを再生します。このシナリオでは、タスクの多くがOpenGL ESの描画コードに 依存していないため、並列処理を活用できます。

アプリケーションのプロファイルを調べた結果、OpenGL ESのレンダリングコードがCPUで多くの 時間を費やしていることがわかった。このシナリオでは、アプリケーションがGPUに十分な速さ でコマンドを送信できていないため、GPUはアイドル状態です。CPUに結び付けられているコー ドがすでに最適化されている場合は、並行して実行されるタスクへと作業内容を分割することに より、アプリケーションのパフォーマンスを向上できる可能性があります。

アプリケーションがGPUを待機してブロックされている場合で、OpenGL ESによる描画と並行して実 行可能な作業がない場合、そのアプリケーションは並列処理に適した候補ではありません。CPUとGPU の両方がアイドル状態の場合、OpenGL ESのニーズはおそらく、それ以上のチューニングの必要がな いほどシンプルです。

OpenGL ES は各コンテキストを単一スレッドに制限

iOSにおけるスレッドにはそれぞれ、単一で現在のOpenGL ESレンダリングコンテキストがあります。

アプリケーションがOpenGL ES関数を呼び出すごとに、OpenGL ESは現在のスレッドに関連付けられて いるコンテキストを暗黙的に参照し、そのコンテキストに関連付けられている状態またはオブジェク トを修正します。

OpenGL ESは再入可能ではありません。複数のスレッドに関連付けられている同じコンテキストを同

時に修正する場合、結果は予測できません。アプリケーションがクラッシュする可能性もあれば、レ ンダリングが正常に行われない可能性もあります。何らかの理由で複数のスレッドが同じコンテキス トをターゲットとするよう設定することにした場合は、そのコンテキストに対するすべてのOpenGL ES 呼び出しにミューテックスを配置して、スレッドを同期させなければなりません。ブロック状態にな るOpenGL ESコマンド(

glFinish

など)は、スレッドを同期しません。

OpenGL ESは各コンテキストを単一スレッドに制限

Grand Central Dispatch

および

NSOperationQueue

オブジェクトは、選択したスレッド上でタスクを実 行することができます。これらは、そのタスク専用のスレッドを作成する場合もあれば、既存のス レッドを再利用する場合もあります。しかし、どちらの場合でも、どのスレッドがタスクを実行する か保証できません。これは、OpenGL ESアプリケーションにとっては、次の意味を持ちます。

各タスクは、OpenGL ESコマンドを実行する前にコンテキストを設定しなければならない。

同じコンテキストを評価する2つのタスクを自動に実行することはできない。

各タスクは、終了する前にスレッドのコンテキストを消去する必要がある。

OpenGL ES アプリケーションに並列処理を実装する方法

並列処理が可能なOpenGL ESアプリケーションは、OpenGL ESがより多くの作業をGPUに提供できるよ う、CPUの並列処理に焦点を合わせるべきです。OpenGL ESアプリケーションに並列処理を実装する ときの推奨事項を次に示します。

アプリケーションを、同時に実行可能なOpenGL ESのタスクとOpenGL ES以外のタスクに分解す る。OpenGL ESの描画コードは単一のタスクとして実行されます。そのため、OpenGL ESの描画 コードは単一のスレッドで実行されます。この方法は、アプリケーションに大量のCPU処理を必 要とするほかのタスクがある場合に最も有効です。

処理性能のプロファイリングにより、OpenGL内でかなりのCPU時間を費やしていることが分かっ た場合は、OpenGL ESコンテキストのマルチスレッド処理を有効にして、処理の一部を別のスレッ ドに移動してください。この方法には簡単であるという利点があります。マルチスレッドを有効 にするコードは1行だけで済みます。“マルチスレッド化したOpenGL ES” (118 ページ)を参照し てください。

アプリケーションがOpenGL ESに送るデータの準備に大量のCPU時間を費やす場合は、レンダリン グデータを準備するタスクと、レンダリングコマンドをOpenGL ESに送信するタスクとに作業を 分割することができます。“ワーカータスクにおけるOpenGL ES演算の実行” (118 ページ)を参照 してください。

同時にレンダリング可能な複数のシーンがある場合、または複数のコンテキストで実行可能な作 業がある場合、アプリケーションは複数のタスクを作成し、1つのタスクに1つのOpenGL ESコン テキストを設定します。複数のコンテキストが同じアートアセットにアクセスする場合は、

sharegroupを使用して、コンテキスト間でOpenGL ESオブジェクトを共有します。“複数のOpenGL ES

コンテキストの使用” (119 ページ)を参照してください。

OpenGL ESアプリケーションに並列処理を実装する方法

ドキュメント内 iOS用OpenGL ESプログラミングガイド (TP ) (ページ 113-154)