3. メインメモリに置かれたデータの使用

頂点バッファとテクスチャイメージは VRAM だけでなく、メインメモリに確保した領域にも置くことができます。ただし、ここでいう「メインメモリ」とは、その中でも周辺デバイスからのアクセスに対してアドレスの整合性が保証されている領域である「デバイスメモリ」のことを指しています。ライブラリでメインメモリにコピーを作成しない場合は、データを格納している領域がデバイスメモリ上になければならないことに注意してください。

注意:

アドレスのアライメントは、バッファの種別(メモリ領域の使用目的)によって異なります。詳細は「3DS プログラミングマニュアル - グラフィックス基本編」の「アロケータ」にある表「バッファ種別によるアライメントの違い」を参照してください。また、デバイスメモリについての詳細は「3DS プログラミングマニュアル - システム編」を参照してください。

GPU はメインメモリに置かれたデータを直接参照することができますが、領域を確保する際の指定によって動作が異なります。また、メインメモリは VRAM に比べてアクセス速度が劣るため、パフォーマンスに影響を与える可能性があります。例えば、頂点バッファを VRAM とメインメモリに分散して確保した場合、VRAM 上の頂点バッファへのアクセス速度はメインメモリへのアクセス速度まで低下してしまいます。

glTexImage2D()glCompressedTexImage2D()glCopyTexImage2D()glBufferData()target 引数の指定時に特別なフラグを論理和で渡すことで、GPU のアクセス先の設定や、領域確保時にメインメモリにコピーを作成するかどうかの設定を行うことができます。

表 3-1. GPU のアクセス先指定フラグ
フラグ アクセス先
NN_GX_MEM_VRAMA GPU は VRAM-A にアクセス
NN_GX_MEM_VRAMB GPU は VRAM-B にアクセス
NN_GX_MEM_FCRAM GPU はメインメモリにアクセス
表 3-2. コピー作成指定フラグ
フラグ コピーの作成
GL_COPY_FCRAM_DMP メインメモリにコピーを作成する
GL_NO_COPY_FCRAM_DMP メインメモリにコピーを作成しない


設定の組み合わせとしては以下の 4 つに分かれます。

  1. メインメモリにアクセスし、メインメモリにコピーを作成する
  2. メインメモリにアクセスし、メインメモリにコピーを作成しない
  3. VRAM-A(B) にアクセスし、メインメモリにコピーを作成する
  4. VRAM-A(B) にアクセスし、メインメモリにコピーを作成しない

glTexImage2D()glCompressedTexImage2D()glBufferData() のデフォルトは(1)の設定です。

glTexImage2D() のみ、pixels 引数に NULL を渡した場合には 4. の設定で VRAM-B がアクセス先となります。

glCopyTexImage2D() には GPU のアクセス先指定のみが可能です。関数内で指定されたメモリ上に領域を確保し、カラーバッファの内容を DMA 転送します。デフォルトは NN_GX_MEM_FCRAM(メインメモリにアクセス)です。

glBufferSubData() は GPU のアクセス先指定とコピー作成指定フラグの設定を glBufferData() から引き継ぎます。

3.1. メインメモリにアクセスし、メインメモリにコピーを作成する

NN_GX_MEM_FCRAMGL_COPY_FCRAM_DMP との論理和を指定して関数を呼び出した場合です。

以下のような動作をします。

  • 関数内でメインメモリ上に領域を確保する
  • 確保した領域に CPU がデータをコピーする
  • GPU は直接メインメモリ(コピーした領域)にアクセスする

データを格納している領域は関数の終了直後(CPU によるコピー直後)に破棄することができます。データのアドレスに NULL を指定した場合は領域の確保のみが行われ、データのコピーは行われません。

3.2. メインメモリにアクセスし、メインメモリにコピーを作成しない

NN_GX_MEM_FCRAMGL_NO_COPY_FCRAM_DMP との論理和を指定して関数を呼び出した場合です。

以下のような動作をします。

  • GPU は直接メインメモリ(アプリケーションで確保している領域)にアクセスする

データを格納している領域は、描画が完了するまで破棄することができません。データのアドレスに NULL を指定した場合や PICA ネイティブフォーマット以外のテクスチャをロードした場合は GL_INVALID_OPERATION のエラーを生成します。

この設定で glBufferData() が確保する頂点バッファの領域はアプリケーションが管理するメモリであるため、glBufferSubData() は部分領域のデータの更新を行いません。部分領域の更新はアプリケーションで行ってください。また、glBufferSubData()data に、glBufferData() で指定された元のバッファアドレスに offset を加算した値が指定されていない場合は GL_INVALID_VALUE のエラーを生成します。

また、GL 関数を呼び出さずに、メインメモリの内容を CPU で動的に更新したデータを GPU に描画させる場合は nngxUpdateBufferLight() を呼び出す必要があります。

3.3. VRAM-A(B) にアクセスし、メインメモリにコピーを作成する

NN_GX_MEM_VRAMA または NN_GX_MEM_VRAMB と、GL_COPY_FCRAM_DMP との論理和を指定して関数を呼び出した場合です。

以下のような動作をします。

  • 関数内でメインメモリ上と VRAM 上にそれぞれ領域を確保する
  • 確保した領域に CPU がデータをコピーする
  • メインメモリ(コピーした領域)から VRAM にデータを DMA 転送する
  • GPU は VRAM にアクセスする

データを格納している領域は関数の終了直後(CPU によるコピー直後)に破棄することができます。データのアドレスに NULL を指定した場合は GL_INVALID_OPERATION のエラーを生成します。

3.4. VRAM-A(B) にアクセスし、メインメモリにコピーを作成しない

NN_GX_MEM_VRAMA または NN_GX_MEM_VRAMB と、GL_NO_COPY_FCRAM_DMP との論理和を指定して関数を呼び出した場合です。

以下のような動作をします。

  • 関数内で VRAM 上に領域を確保する
  • メインメモリ(アプリケーションで確保している領域)から VRAM にデータを DMA 転送する
  • GPU は VRAM にアクセスする

データを格納している領域は DMA 転送によるコピーが完了(DMA 転送のコマンドリクエスト完了を確認)するまで破棄することができません。データのアドレスに NULL を指定した場合は領域の確保のみが行われ、DMA 転送は行われません。PICA ネイティブフォーマット以外のテクスチャをロードした場合は GL_INVALID_OPERATION のエラーを生成します。

この設定でロードされた頂点バッファに対して glBufferSubData() を呼び出した場合、アプリケーションは DMA 転送が完了するまで data で指定した領域の内容を保証しなければなりません。

3.5. VRAM を有効に利用するには

VRAM-A と VRAM-B へのアクセスは、それぞれ別のチャンネルで行われます。同じタイミングで書き込みや読み込みが発生するバッファは、それぞれを別の VRAM に分けて確保することを推奨します。

アクセスが競合する組み合わせは以下のとおりです。

表 3-3. アクセスが競合する組み合わせ
競合する組み合わせ 発生するタイミング
カラーバッファとデプス(ステンシル)バッファ レンダリング時全般
カラーバッファとディスプレイバッファ nngxTransferRenderImage() の実行時
頂点バッファとインデックスバッファ glDrawElements() の実行時

レンダリング全般でアクセスの発生するカラーバッファとデプス(ステンシル)バッファは別々の VRAM に確保することを強く推奨します。