7. GX ライブラリとの関係

ライブラリの関数内で呼び出している nngx 関数や、nngx 関数との関係で注意が必要となる特殊なケースを説明します。

7.1. nngx 関数の内部使用

GD ライブラリの関数の中には、内部で nngx 関数を呼び出すものが存在します。以下の表に記されている関数は、「条件」欄にある条件が満たされてエラーも発生していないときに、内部で nngx 関数を呼び出します。ただし、同一の関数でも条件によって異なる nngx 関数が呼び出されることがあります。

条件が「常に」と記載されているものは、エラーが発生した場合を除いて、示された nngx 関数が常に呼び出されます。

表 7-1. 内部で nngx 関数を呼び出す GD ライブラリの関数
GD 関数 条件 nngx 関数
System::
StartRecordingPackets()
常に nngxStartCmdlistSave()
System::
StopRecordingPackets()
常に

nngxSplitDrawCmdlist()

nngxStopCmdlistSave()

nngxExportCmdlist()

System::ReplayPackets() 常に nngxImportCmdlist()
System::
Execute3DCommandList()
常に nngxSplitDrawCmdlist()
Resource::
CreateTexture2DResource()
初期データがあり、VRAM に確保したメモリにコピー nngxAddVramDmaCommand()
初期データがあり、デバイスメモリに確保したメモリにコピー nngxUpdateBuffer()
初期データがあり、ミップマップを自動生成 nngxFilterBlockImage()
Memory::GenerateMipMaps() 常に nngxFilterBlockImage()
描画依存関係がある nngxSplitDrawCmdlist()
Resource::
CreateVertexBufferResource()
初期データがあり、VRAM に確保したメモリにコピー nngxAddVramDmaCommand()
初期データがあり、デバイスメモリに確保したメモリにコピー nngxUpdateBuffer()
Memory::
CopyTextureSubResource()
常に nngxAddBlockImageCopyCommand()
描画依存関係がある nngxSplitDrawCmdlist()
Memory::
CopyVertexBufferSubResource()
常に nngxAddBlockImageCopyCommand()
Memory::
CopyTexture2DResource
BlockToLinear()
常に nngxAddB2LTransferCommand()
描画依存関係がある nngxSplitDrawCmdlist()
Memory::
CopyTexture2DResource
LinearToBlock()
常に nngxAddL2BTransferCommand()
描画依存関係がある nngxSplitDrawCmdlist()
Memory::ClearTargets() 常に nngxAddMemoryFillCommand()
描画依存関係がある nngxSplitDrawCmdlist()
Memory::
ClearTexture2DResource()
常に nngxAddMemoryFillCommand()
描画依存関係がある nngxSplitDrawCmdlist()
Resource::
UnmapTexture2DResource
デバイスメモリにあるリソースを書き込みありでマッピング nngxUpdateBuffer()
Resource::
UnmapVertexBufferResource
デバイスメモリにあるリソースを書き込みありでマッピング nngxUpdateBuffer()

7.2. nngx 関数との相互作用

GD ライブラリを利用する上で、nngx 関数との関係に注意が必要となる特殊なケースを示します。

7.2.1. 初期データを持つテクスチャを VRAM 上に作成

初期データを用いて VRAM 上にリソースを作成することになるため、初期データをメインメモリから VRAM に転送する DMA 転送コマンドがコマンドリクエストキューに追加されます。GD ライブラリではコマンドリクエストの実行を管理していないため、初期データを解放する前に DMA 転送の完了をアプリケーションで確認する必要があります。

以下のコード例のように、nngxWaitCmdlistDone() を呼べばすべてのコマンドリクエストの完了を待つことができます。ただしコマンドリストをダブルバッファ化している場合は、現在のコマンドリクエストキューに追加された DMA 転送コマンドが次のフレームまで実行されないことに注意してください。

コード 7-1. 初期データを持つテクスチャを VRAM 上に作成
nn::gd::Texture2DResource* texture2DResource = 0;
nn::gd::Texture2DResourceDescription Text2DResDesc =
{
    width, height, 1, nn::gd::Resource::NATIVE_FORMAT_RGB_888,
    nn::gd::Memory::LAYOUT_BLOCK_8, nn::gd::Memory::VRAMA
};
nn::gd::Resource::CreateTexture2DResource(
        &Text2DResDesc, data, GD_TRUE, &texture2DResource);

// リソースはVRAM上に作成されるため、解放前にDMA転送の完了を確認しなければならない
nngxWaitCmdlistDone();

free(data);

7.2.2. 描画結果へのアクセス

レンダリング後にカラーバッファやデプス(ステンシル)バッファ、テクスチャの内容にアクセスして描画結果を直接書き換えたい場合、CPU から直接 VRAM 上のデータにアクセスすることはできませんので、以下のような手順が必要となります。

  • 一時的なリソースをデバイスメモリに確保する
  • VRAM 上にあるリソースを一時的なリソースにコピーする(VRAM からのデータ転送)
  • 一時的なリソースを書き換える
  • VRAM 上にあるリソースに一時的なリソースの内容を書き戻す(VRAM へのデータ転送)

VRAM からのデータ転送と VRAM へのデータ転送はコマンドリクエストによって実行されます。そのため、リソースを書き換える前や一時的に確保したリソースを解放する前に、コマンドリクエストの実行が完了するのを待たなければなりません。

実際のコードでは以下のような流れになります。

コード 7-2. 描画結果へのアクセス
// デバイスメモリ(FCRAM)上に一時的なリソースを確保
nn::gd::Texture2DResource* tmpResource= 0;
nn::gd::Texture2DResourceDescription tmpResourceDesc =
{
    s_RenderTextureWidth, s_RenderTextureHeight, 1,
    nn::gd::Resource::NATIVE_FORMAT_RGBA_8888,
    nn::gd::Memory::LAYOUT_BLOCK_8,
    nn::gd::Memory::FCRAM
};
res = nn::gd::Resource::CreateTexture2DResource(
        &tmpResourceDesc, 0, GD_FALSE, &tmpResource);

// VRAM 上のリソースを一時的なリソースにコピー
nn::gd::Memory::Rect memRect(0, 0, -1, -1);
res = nn::gd::Memory::CopyTextureSubResource(
        s_texture2DResource_ColorBuffer, 0, memRect, tmpResource, 0, 0, 0);
// アクセスするためにリソースをマップする
u8* data;
nn::gd::Resource::MapTexture2DResource(
        tmpResource, 0, nn::gd::Resource::MAP_READ_WRITE, (void**)&data);
// データにアクセスする前にコマンドの実行完了待ちが必要
nngxWaitCmdlistDone();

// ここでマップしたリソースに書き込む
for (int y=0; y<s_RenderTextureHeight*s_RenderTextureWidth>>1; y++)
{
    data[k+] = 255; data[k] = 255; data[k] = 255; data[k+] = 255;
}

// マッピング解除時に一時的なリソースへの変更が確定される
nn::gd::Resource::UnmapTexture2DResource(tmpResource);

// 一時的なリソースから VRAM 上のリソースにコピー
nn::gd::Memory::CopyTextureSubResource(
        tmpResource, 0, memRect, s_texture2DResource_ColorBuffer, 0, 0, 0);