4. コマンドリスト

コマンドリストは 3DS が独自に導入したもので、3D グラフィックス処理で呼び出される glnngx 関数をコマンドとして記録し、まとめて実行させることができます。コマンドリストへの処理は、コマンドリストオブジェクトを用いて行われます。3DS では、コマンドリストを 3D グラフィックスの描画の実行単位として扱います。

コマンドリストは GPU が直接実行するレジスタ書き込みコマンド(3D コマンド)と、CPU から GPU に命令を伝えるためのコマンドリクエストで構成されます。3D コマンドは、glnngx 関数で描画などが行われると、3D コマンドバッファに蓄積されます。コマンドリクエストは、要因となる特定の glnngx 関数の呼び出しによりキューイングされます。コマンドリクエストの種類と詳細については「4.2. コマンドリクエストの種類」で説明します。

図 4-1. コマンドリスト

コマンドリスト 3Dコマンド 3Dコマンドバッファ コマンドリクエスト

コマンドリクエストにキューイングされた 3D 実行コマンドが処理されると、GPU は 3D コマンドバッファから 3D コマンドを読み込んで実行します。3D コマンドは複数で 1 つのコマンドセットとして扱われ、コマンドセット単位で実行されます。各コマンドセットの最後のコマンドは区切りとなるもので、GPU が 3D バッファの読み込みを終了するコマンドとなります。

図 4-2. コマンドセット

3Dコマンドバッファ コマンドリクエスト 3D実行コマンド コマンドセット

補足:

コマンドリクエストを発行する関数はアプリコア(コア 0)でのみ呼び出しが可能です。

4.1. 使用方法

3DS では、GPU による 3D 描画はコマンドリスト単位で実行されます。そのため、アプリケーションはコマンドリストオブジェクトを生成し、gl 関数などで蓄積された 3D コマンドをまとめて実行することになります。

4.1.1. オブジェクトの生成

最初に、nngxGenCmdlists() でコマンドリストオブジェクトを生成します。

コード 4-1. コマンドリストの生成関数
void nngxGenCmdlists(GLsizei n, GLuint* cmdlists);

n 個のコマンドリストオブジェクトを生成して、cmdlists にその名前(オブジェクト名)を格納します。

コマンドリストは固有の名前空間を持っています。オブジェクト名が 0 のコマンドリストはシステムで予約されています。

表 4-1. nngxGenCmdlists() が生成するエラー

エラー

原因

GL_ERROR_8000_DMP

n に負の値を指定した

GL_ERROR_8001_DMP

管理領域の確保に失敗した

4.1.2. バインド

次に、生成したコマンドリストオブジェクトを nngxBindCmdlist() で GPU に関連付け(バインド)ます。バインドしたコマンドリストの 3D コマンドバッファに 3D コマンドが蓄積されていきます。

コード 4-2. コマンドリストのバインド関数
void nngxBindCmdlist(GLuint cmdlist);

cmdlist に未使用のオブジェクト名が指定された場合はオブジェクトの生成が行われます。

表 4-2. nngxBindCmdlist() が生成するエラー

エラー

原因

GL_ERROR_8004_DMP

管理領域の確保に失敗した

GL_ERROR_8005_DMP

コマンドキャッシュ(詳しくは「3DS プログラミングマニュアル - グラフィックス応用編」を参照してください)を利用して、コマンドリストの保存を行っている状態で呼び出した

4.1.3. メモリ領域の確保

バインドしたコマンドリストに対して、nngxCmdlistStorage() でメモリ領域の確保を行います。

コード 4-3. コマンドリストのメモリ領域の確保
void nngxCmdlistStorage(GLsizei bufsize, GLsizei requestcount);

bufsize に 3D コマンドバッファのサイズを、requestcount にコマンドリクエストをキューイング可能な個数を指定します。

コマンドリストオブジェクトを複数生成している場合は、それぞれに対して nngxBindCmdlist()nngxCmdlistStorage() を呼び出してください。オブジェクト名が 0 のコマンドリストをバインドしている場合、この関数の呼び出しは無視されます。また、すでに領域を確保しているオブジェクトに対して、この関数を再度呼び出した場合は確保していた領域を解放し、再度領域の確保が行われます。

確保した 3D コマンドバッファのサイズを超えて 3D コマンドが蓄積された場合や 3D コマンドバッファが未設定の場合は、該当の関数呼び出しで GL_ERROR_COMMANDBUFFER_FULL_DMP のエラーが生成されます。コマンドリクエストにキューイング可能な個数を超えてキューイングされた場合やバッファが未設定の場合は、該当の関数呼び出しで GL_ERROR_COMMANDREQUEST_FULL_DMP のエラーが生成されます。

表 4-3. nngxCmdlistStorage() が生成するエラー

エラー

原因

GL_ERROR_8006_DMP

メモリ領域の確保に失敗した

GL_ERROR_8007_DMP

実行中のコマンドリストに対して呼び出した

GL_ERROR_8008_DMP

引数に負の値を指定した

4.1.4. 実行

バインドされているコマンドリストにキューイングされたコマンドリクエストの実行を開始させるには、nngxRunCmdlist() を呼び出します。

コード 4-4. コマンドリストの実行関数
void nngxRunCmdlist(void);
void nngxRunCmdlistByID(GLuint cmdlist);

オブジェクト名が 0 のコマンドリストをバインドしている場合、実行は無視されます。また、コマンドリクエストの実行中にほかのコマンドリストをバインドし、この関数を実行しても無視されます。

コマンドリクエストの実行開始後は、続けて同じコマンドリストにコマンドを蓄積することもできますが、別のコマンドリストをバインドしてコマンドを蓄積させることもできます。ただし、コマンドの蓄積順と実行順は同じでなければなりません。

実行中のコマンドリストにコマンドを蓄積する場合はアプリコアで行う必要があります。アプリコア以外で行った場合は不定な動作をすることがあります。

nngxRunCmdlistByID() は、現在バインドされているコマンドリストではなく、cmdlist で指定されたコマンドリストを実行します。指定されたコマンドリストを実行する以外には、nngxRunCmdlist() の動作との違いはありません。

表 4-4. nngxRunCmdlist() および nngxRunCmdlistByID() が生成するエラー

エラー

原因

GL_ERROR_8009_DMP

メモリ領域が確保されていないコマンドリストに対して呼び出した(nngxRuncmdlist()

GL_ERROR_80B1_DMP

メモリ領域が確保されていないコマンドリストに対して呼び出した(nngxRuncmdlistByID()

4.1.4.1. 実行状態の取得

コマンドリストが実行中かどうかは nngxGetIsRunning() で取得することができます。

コード 4-5. コマンドリストの実行状態の取得関数
GLboolean nngxGetIsRunning(void);

この関数は、コマンドリストが現在バインドされているものかどうかに関係なく、実行中のコマンドリストがあれば GL_TRUE を返します。

同様に、コマンドリストが実行中かどうかを nngxGetCmdlistParameteri()pnameNN_GX_CMDLIST_IS_RUNNING を渡して取得できますが、この方法で取得する実行状態は、現在バインドされているコマンドリストが実行中かどうかだけです。nngxGetCmdlistParameteri() については、「4.1.10. パラメータ取得」を参照してください。

4.1.5. 破棄

不要になったコマンドリストオブジェクトは nngxDeleteCmdlists() で破棄することができます。

コード 4-6. コマンドリストの破棄関数
void nngxDeleteCmdlists(GLsizei n, const GLuint* cmdlists);

cmdlists に格納されている、n 個のオブジェクト名で指定されたコマンドリストオブジェクトを破棄します。実行中のコマンドリストが含まれていた場合、GL_ERROR_8003_DMP のエラーが生成されますがコマンドリストの実行に影響はなく、ほかに指定されているコマンドリストオブジェクトが破棄されます。

表 4-5. nngxDeleteCmdlists() が生成するエラー

エラー

原因

GL_ERROR_8002_DMP

n に負の値を指定した

GL_ERROR_8003_DMP

cmdlists に実行中のコマンドリストが含まれていた

4.1.6. 停止

実行中のコマンドリストを停止するには、以下の関数を呼び出します。

コード 4-7. コマンドリストの停止関数
void nngxStopCmdlist(void);
void nngxReserveStopCmdlist(GLint id);

nngxStopCmdlist() は、呼び出し時に実行中だったコマンドリクエストが完了した時点で停止します。すでに実行が開始されているコマンドリクエスト(実行開始待ちを含む)を中止することはできません。

nngxReserveStopCmdlist()id 番目に蓄積したコマンドリクエストの実行完了直後に停止します。

停止したコマンドリストを再開する場合は、nngxRunCmdlist() を呼び出します。ただし、停止を指示してからコマンドの実行が完了するまでに呼び出した場合は無視されてしまうことに注意してください。

表 4-6. nngxReserveStopCmdlist() が生成するエラー

エラー

原因

GL_ERROR_800A_DMP

実行中のコマンドリストに対して呼び出した

GL_ERROR_800B_DMP

id に 0 または負の値、コマンドリクエストの最大数を超える値を指定した

4.1.7. 3D コマンドバッファの区切り

nngxSplitDrawCmdlist() で 3D コマンドバッファにバッファ読み込み終了コマンドを追加し、3D 実行コマンドをキューイングすることができます。コマンドリストが 3D コマンドを蓄積しながら実行している場合は、この関数で区切られた部分までの 3D コマンドが実行されます。

コード 4-8. 3D コマンドバッファを区切る関数
void nngxSplitDrawCmdlist(void);

3D 実行コマンドはバッファ読み込み終了コマンドが追加されるまでキューイングされません。この関数以外にも 3D 実行コマンドをキューイングする関数があります。glClear()glTexImage2D() などは 3D コマンドの実行を停止させなければならないため、バッファ読み込み終了コマンドの追加と 3D 実行コマンドのキューイングを行います。

表 4-7. nngxSplitDrawCmdlist() が生成するエラー

エラー

原因

GL_ERROR_800C_DMP

オブジェクト名が 0 のコマンドリストをバインドしているときに呼び出した

GL_ERROR_800D_DMP

すでにコマンドリクエストの蓄積数が最大数に達していた

GL_ERROR_800E_DMP

この関数が追加するコマンドにより 3D コマンドバッファが一杯になる

この関数を内部で呼び出している関数が、これらのエラーを生成することがあります。

4.1.7.1. 蓄積済み 3D コマンドバッファのフラッシュ

nngxSplitDrawCmdlist() を呼び出すと、3D コマンドバッファに 3D コマンドが蓄積されていない場合でも、バッファ読み込み終了コマンドの追加と 3D 実行コマンドのキューイングが行われます。つまり、意図せず無駄なコマンドが追加されることになりますので、3D コマンドが蓄積されている場合にのみ 3D コマンドバッファを区切るためのコマンドを追加する nngxFlush3DCommand() または nngxFlush3DCommandNoCacheFlush() を呼び出すことを推奨します。キャッシュのフラッシュが複数回発生するような場合はキャッシュをフラッシュしない後者の関数を呼び出し、nngxUpdateBufferLight() でまとめてキャッシュを反映することで CPU コストを抑えられる可能性があります。

コード 4-9. 3D コマンドバッファをフラッシュする関数
void nngxFlush3DCommand(void);
void nngxFlush3DCommandNoCacheFlush(void);

これらの関数は、バインドされているコマンドリストの 3D コマンドバッファが最後に区切られたあと、3D コマンドが蓄積されていなければバッファ読み込み終了コマンドと 3D 実行コマンドの追加を行わず、3D コマンドが蓄積されていればバッファ読み込み終了コマンドと 3D 実行コマンドの追加を行います。3D コマンドを蓄積しながら実行している場合は、この関数で区切られた部分までの 3D コマンドが実行されます。

表 4-8. nngxFlush3DCommand() および nngxFlush3DCommandNoCacheFlush() が生成するエラー

エラー

原因

GL_ERROR_8084_DMP
GL_ERROR_80AE_DMP

オブジェクト名が 0 のコマンドリストをバインドしているときに呼び出した

GL_ERROR_8085_DMP
GL_ERROR_80AF_DMP

すでにコマンドリクエストの蓄積数が最大数に達していた

GL_ERROR_8086_DMP
GL_ERROR_80B0_DMP

この関数が追加するコマンドにより 3D コマンドバッファが一杯になる

4.1.7.2. 蓄積済み 3D コマンドバッファの部分フラッシュ

指定したサイズ分の 3D コマンドを実行する nngxFlush3DCommandPartially() が用意されています。この関数は nngxFlush3DCommand() の機能を拡張したもので、nngxAdd3DCommand() などで追加した、コマンドバッファ実行レジスタのキックコマンドを含む 3D コマンドを正しく実行させるために呼び出します。詳細は「3DS プログラミングマニュアル - グラフィックス応用編」の「コマンドバッファ実行レジスタ(0x0238 ~ 0x023D)」を参照してください。

コード 4-10. 3D コマンドバッファを部分フラッシュする関数
void nngxFlush3DCommandPartially(GLsizei buffersize);

buffersize に、実行するコマンドバッファのサイズをバイト数で指定します。16 の倍数でなければなりません。

buffersize には、前回のコマンドフラッシュ後のアドレスから、最初のキックコマンドまで(キックコマンドを含む)のサイズを正しく指定する必要があります。誤った値を指定した場合、意図しない順序でコマンドが実行される、正しく実行を終了できないなどの動作を起こす可能性があります。

前回のコマンドフラッシュ後から、この関数を呼び出すまでに蓄積された 3D コマンドバッファのキャッシュフラッシュはアプリケーションで確実に行ってください。この関数内でも割り込み発生コマンドなどが生成されるため、キャッシュ全体のフラッシュは関数を呼び出したあとでなければなりません。また、キャッシュがフラッシュされる前に実行されないようにするため、この関数は実行中のコマンドリストに対して呼び出すことができません。なお、glClear()nngxTransferRenderImage()glCopyTexImage2D() などの関数は、関数内で nngxFlush3DCommand() と同じ手法のフラッシュを実行します。これらの関数を呼び出す前に、必ず本関数でフラッシュしてください。

nngxAddJumpCommand()nngxAddSubroutineCommand() を使用してキックコマンドを追加した場合、最初のキックコマンドまでを実行サイズとしてキックするようにドライバ側がサイズを調整します。そのため、これらの関数を使用している場合は、nngxFlush3DCommandPartially() を呼び出す必要はありません。

nngxAddSubroutineCommand() でキックコマンドを追加したコマンドバッファに対して部分フラッシュを行うと、ドライバ側で計算された実行サイズではなく、buffersize で指定されたサイズが実行サイズとして使用されることに注意してください。

表 4-9. nngxFlush3DCommandPartially() が生成するエラー

エラー

原因

GL_ERROR_80A9_DMP

オブジェクト名が 0 のコマンドリストをバインドしているときに呼び出した

GL_ERROR_80AA_DMP

すでにコマンドリクエストの蓄積数が最大数に達していた

GL_ERROR_80AB_DMP

この関数が追加するコマンドにより 3D コマンドバッファが一杯になる

GL_ERROR_80AC_DMP

buffersize に 0 以下の値、または 16 の倍数以外の値を指定した

GL_ERROR_80AD_DMP

実行中のコマンドリストに対して呼び出した

4.1.8. クリア

コマンドリストをクリアして、3D コマンドバッファとコマンドリクエストのキューを未使用状態(メモリ領域確保直後の状態)にします。

コード 4-11. コマンドリストのクリア関数
void nngxClearCmdlist(void);
表 4-10. nngxClearCmdlist() が生成するエラー

エラー

原因

GL_ERROR_800F_DMP

実行中のコマンドリストに対して呼び出した

4.1.8.1. クリアと 3D コマンドバッファのフィル

コマンドリストのクリアとともに、3D コマンドバッファの内容を指定されたデータで初期化します。3D コマンドバッファとコマンドリクエストのキューは未使用状態になります。

コード 4-12. コマンドリストのクリアと 3D コマンドバッファのフィル関数
void nngxClearFillCmdlist(GLuint data);
表 4-11. nngxClearFillCmdlist() が生成するエラー

エラー

原因

GL_ERROR_8065_DMP

実行中のコマンドリストに対して呼び出した

4.1.9. パラメータ設定

nngxSetCmdlistParameteri() を呼び出すことで、コマンドリストの設定パラメータを指定することができます。

コード 4-13. コマンドリストのパラメータ設定関数
void nngxSetCmdlistParameteri(GLenum pname, GLint param);
表 4-12. コマンドリストの設定パラメータ(設定)

pname の値

設定の内容

NN_GX_CMDLIST_GAS_UPDATE

この設定はコマンドリストオブジェクトごとに設定され、以下の値から設定を選択します。

  • GL_TRUE:ガスの密度情報描画の加算ブレンド結果を更新
  • GL_FALSE:通常動作(デフォルト)

この設定が GL_TRUE の状態で、nngxSplitDrawCmdlist()nngxFlush3DCommand() を呼び出すと、蓄積された 3D 実行コマンドの実行終了時にガスの密度情報描画の加算ブレンド結果を更新します。

GL_FALSE の状態では通常動作に戻り、必要なときにのみガスの密度情報が更新されるコマンドが蓄積されます。

この設定は、nngxSplitDrawCmdlist()nngxFlush3DCommand() を呼び出したときに GL_TRUE であるかどうかで機能します。3D 実行コマンドが実行されるときに GL_TRUE であるかどうかは影響しません。また、nngxSplitDrawCmdlist() および nngxFlush3DCommand() 以外を呼び出して蓄積された 3D 実行コマンドには影響しません。

ガス密度情報描画の加算ブレンド結果の更新については、「3DS プログラミングマニュアル - グラフィックス応用編」の「ガス制御設定レジスタ」も併せて参照してください。

表 4-13. nngxSetCmdlistParameteri() が生成するエラー

エラー

原因

GL_ERROR_8015_DMP

実行中のコマンドリストに対して呼び出した

GL_ERROR_8016_DMP

pname または param に無効な値を指定した

4.1.10. パラメータ取得

nngxGetCmdlistParameteri() を呼び出すことで、コマンドリストの設定パラメータを取得することができます。

コード 4-14. コマンドリストのパラメータ取得関数
void nngxGetCmdlistParameteri(GLenum pname, GLint* param);
表 4-14. コマンドリストの設定パラメータ(取得)

pname の値

取得可能な設定の内容

NN_GX_CMDLIST_IS_RUNNING

コマンドリストの実行状態。

GL_TRUE:コマンドリストは実行中です。
GL_FALSE:コマンドリストは実行中ではありません。

NN_GX_CMDLIST_USED_BUFSIZE

蓄積された 3D コマンドバッファのバイトサイズ。

NN_GX_CMDLIST_USED_REQCOUNT

蓄積されたコマンドリクエストの個数。

NN_GX_CMDLIST_MAX_BUFSIZE

3D コマンドバッファの最大サイズ。

nngxCmdlistStorage()bufsize で指定した値です。

NN_GX_CMDLIST_MAX_REQCOUNT

コマンドリクエストの最大個数。

nngxCmdlistStorage()requestcount で指定した値です。

NN_GX_CMDLIST_TOP_BUFADDR

3D コマンドバッファの先頭アドレス。

NN_GX_CMDLIST_BINDING

現在バインドされているコマンドリストのオブジェクト名。

NN_GX_CMDLIST_RUN_BUFSIZE

実行済みの 3D コマンドバッファのバイトサイズ。

NN_GX_CMDLIST_RUN_REQCOUNT

実行済みのコマンドリクエストの個数。

NN_GX_CMDLIST_TOP_REQADDR

コマンドリクエストのリクエストキュー用データ領域の先頭アドレス。

NN_GX_CMDLIST_NEXT_REQTYPE

次に実行されるコマンドリクエストまたは実行中のコマンドリクエストのコマンドの種類。

param に返される値は、現在バインドされているコマンドリストの状態によって変化します。実行停止中のコマンドリストの場合は次に実行されるコマンドリクエストのコマンドの種類が、実行中の場合は実行中のコマンドリクエストのコマンドの種類が返されます。すべてのコマンドリクエストの実行が完了している場合は NULL が返されます。

コマンドの種類は以下のマクロで定義されています。

NN_GX_CMDLIST_REQTYPE_DMA : DMA 転送コマンド
NN_GX_CMDLIST_REQTYPE_RUN3D : 3D 実行コマンド
NN_GX_CMDLIST_REQTYPE_FILLMEM : メモリフィルコマンド
NN_GX_CMDLIST_REQTYPE_POSTTRANS : ポスト転送コマンド
NN_GX_CMDLIST_REQTYPE_COPYTEX : レンダーテクスチャ転送コマンド

NN_GX_CMDLIST_NEXT_REQINFO

コマンドバッファのアドレスとバイトサイズ。

param の第 1 要素にコマンドバッファのアドレスが、第 2 要素にコマンドバッファのバイトサイズが格納されますので、param には要素数が 2 以上の GLint の配列へのポインタを渡す必要があります。

現在バインドされているコマンドリストが実行停止中の場合は、次に実行されるコマンドリクエストのパラメータ情報が返されます。実行中の場合は、現在実行中のコマンドリクエストのパラメータ情報が返されます。すべてのコマンドリクエストの実行が完了している場合は何も返しません。

次に実行される、または実行中のコマンドリクエストが 3D 実行コマンドである場合にのみ対応しています。それ以外のコマンドの場合は何も返しません。

NN_GX_CMDLIST_HW_STATE

ハードウェアの状態を示す 32 ビットのデータ。

以下の状態である場合に対応するビットに 1 がセットされます。

ビット 20 : ポスト転送が実行中
ビット 19 : メモリフィルが実行中
ビット 18 : 下画面 LCD の FIFO でアンダーランエラーが発生
ビット 17 : 上画面 LCD の FIFO でアンダーランエラーが発生
ビット 16 : ポスト頂点キャッシュがビジー
ビット 15 : レジスタ 0x0252 の [ 1 : 0 ] に 1 が設定されている
ビット 14 : 頂点プロセッサ 3 がビジー
ビット 13 : 頂点プロセッサ 2 がビジー
ビット 12 : 頂点プロセッサ 1 がビジー
ビット 11 : 頂点プロセッサ 0(ジオメトリシェーダプロセッサ兼用)がビジー
ビット 10 : レジスタ 0x0229 の [ 1 : 0 ] が 0 以外
ビット 9 : コマンドバッファおよび頂点アレイをロードするモジュールの入力がビジー
ビット 8 : コマンドバッファおよび頂点アレイをロードするモジュールの出力がビジー
ビット 7 : アーリーデプステストモジュールがビジー
ビット 6 : パーフラグメントオペレーションモジュールが前段のモジュールからのデータ処理に関してビジー
ビット 5 : パーフラグメントオペレーションモジュールがフレームバッファアクセスに関してビジー
ビット 4 : テクスチャコンバイナがビジー
ビット 3 : フラグメントライティングがビジー
ビット 2 : テクスチャユニットがビジー
ビット 1 : ラスタライゼーションモジュールがビジー
ビット 0 : トライアングルセットアップがビジー

NN_GX_CMDLIST_CURRENT_BUFADDR

現在バインドされているコマンドリストで、次にコマンドが蓄積される 3D コマンドバッファのアドレス。

表 4-15. nngxGetCmdlistParameteri() が生成するエラー

エラー

原因

GL_ERROR_8017_DMP

pname または param に無効な値を指定した

GL_ERROR_8018_DMP

オブジェクト名が 0 のコマンドリストがバインドされているときに、pnameNN_GX_CMDLIST_BINDING 以外を指定した

4.1.11. コマンド終了割り込み

コマンドリストのコマンドリクエストが終了したタイミングで割り込みを発生させ、割り込みハンドラを呼び出すことができます。割り込みハンドラは nngxSetCmdlistCallback() で登録することができます。

コード 4-15. 割り込みハンドラの登録関数
void nngxSetCmdlistCallback(void (*func)(GLint));

割り込みハンドラはバインドされているコマンドリストに対してのみ有効です。func に 0(NULL)を渡して呼び出した場合はハンドラの登録を解除します。

割り込みハンドラはメインスレッドとは異なるスレッドから呼び出されますので、メインスレッドと共有するデータを参照する場合は排他処理が必要です。ただし、同じグラフィックス関連の nngxSetVSyncCallback() によって登録されたコールバック関数との間では排他処理が不要となっています。

表 4-16. nngxSetCmdlistCallback() が生成するエラー

エラー

原因

GL_ERROR_8010_DMP

実行中のコマンドリストに対して呼び出した

割り込みを発生させるには、nngxEnableCmdlistCallback() で終了時に割り込みを発生させるコマンドリクエストを指定します。nngxDisableCmdlistCallback() は割り込みの発生を無効化することができます。

コード 4-16. 割り込み制御関数
void nngxEnableCmdlistCallback(GLint id);
void nngxDisableCmdlistCallback(GLint id);

id には何番目に蓄積されたコマンドリクエストの終了時に割り込みを発生させるかを指定します。1 つのコマンドリストに対して別々の id で複数回呼び出し、割り込みを複数回発生させることもできます。id 番目に実行されるコマンドリクエストではなく、id 番目に蓄積されたコマンドリクエストであることに注意してください。指定する id の値には、nngxGetCmdlistParameteri()pnameNN_GX_CMDLIST_USED_REQCOUNT で呼び出して取得した結果を利用することができます。id に -1 を指定した場合は、コマンドリストに蓄積されたコマンドリクエストすべてが終了したときに割り込みが発生します。

コマンドリストに蓄積されたコマンドリクエストの最後尾以外への割り込みは、割り込みハンドラが呼び出されたときにまだコマンドリストは実行中です。そのため、コマンドリストの実行中に呼び出すことができない関数は割り込みハンドラ内で呼び出すことはできません。

割り込みハンドラを登録しなくても、nngxGetCmdlistParameteri()pnameNN_GX_CMDLIST_IS_RUNNING で呼び出して取得した結果が GL_FALSE になるまで待つことで、コマンドリクエストの実行終了を判断することができます。

表 4-17. nngxEnableCmdlistCallback() および nngxDisableCmdlistCallback() が生成するエラー

エラー

原因

GL_ERROR_8012_DMP
GL_ERROR_8014_DMP

id に 0 または -1 以外の負値、コマンドリクエストの最大数を指定した

4.1.12. コマンド実行の完了待ち

nngxWaitCmdlistDone() の呼び出しで、コマンドリストに蓄積されたコマンドリクエストの実行がすべて完了するまで待つことができます。

コード 4-17. コマンド完了待ち関数
void nngxWaitCmdlistDone(void);

3D 実行コマンドは区切られた部分まで実行されます。蓄積されている 3D 実行コマンドをすべて実行させるには、この関数を呼び出す前に nngxSplitDrawCmdlist() を呼び出してください。

この関数はコマンドの実行が完了するまで処理を返しませんが、nngxSetTimeout() でタイムアウト時間を設定することができます。

コード 4-18. コマンド完了待ち関数のタイムアウト時間を設定する関数
void nngxSetTimeout(GLint64EXT time, void (*callback)(void));

time には、nngxWaitCmdlistDone() の処理がタイムアウトするまでの時間をチック値で指定します。0 を指定した場合はタイムアウトが発生しません。

callback には、タイムアウト時に呼び出されるコールバック関数を指定します。NULL を指定した場合はタイムアウト発生時にコールバック関数を呼び出しません。

デフォルトは time に 0 を、callbackNULL を指定した状態ですので、タイムアウトは発生しません。

4.1.13. DMA 転送コマンドの追加

nngxAddVramDmaCommand() または nngxAddVramDmaCommandNoCacheFlush() の呼び出しで、VRAM への DMA 転送を行うコマンドがコマンドリストに蓄積されます。前者は転送元のキャッシュフラッシュを行いますが、後者はキャッシュフラッシュを行いません。これらの関数では、メインメモリから VRAM への DMA 転送のみを行うことができます。

コード 4-19. DMA 転送コマンドを追加する関数
void nngxAddVramDmaCommand(
                        const GLvoid* srcaddr, GLvoid* dstaddr, GLsizei size);
void nngxAddVramDmaCommandNoCacheFlush(
                        const GLvoid* srcaddr, GLvoid* dstaddr, GLsizei size);

srcaddr には転送元のアドレス、dstaddr には転送先のアドレスをそれぞれ指定し、size には転送するデータのサイズを指定します。

nngxAddVramDmaCommand() では、有効なコマンドリストがバインドされていない状態で呼び出されたときは GL_ERROR_8062_DMP のエラーを、size に負の値を指定したときは GL_ERROR_8064_DMP のエラーを生成します。

nngxAddVramDmaCommandNoCacheFlush() では、有効なコマンドリストがバインドされていない状態で呼び出されたときは GL_ERROR_8090_DMP のエラーを、size に負の値を指定したときは GL_ERROR_8091_DMP のエラーを生成します。

4.1.14. アンチエイリアスフィルタ転送コマンドの追加

nngxFilterBlockImage() の呼び出しで、アンチエイリアスフィルタを適用したイメージ転送を行うコマンドがコマンドリストに蓄積されます。イメージ転送はブロックフォーマットのまま行われ、フォーマットの変換は行われません。アンチエイリアスの指定は 2x2 にのみ対応しています。

コード 4-20. アンチエイリアスフィルタ転送コマンドを追加する関数
void nngxFilterBlockImage(const GLvoid* srcaddr, GLvoid* dstaddr, 
                          GLsizei width, GLsizei height, GLenum format);

srcaddr には転送元のアドレス、dstaddr には転送先のアドレスをそれぞれ指定し、widthheightformat には転送元のイメージの幅、高さ、フォーマットをそれぞれ指定します。

width heightformat の指定によって以下のように制限されています。

表 4-18. フォーマットによる転送元イメージの幅と高さの制限

format

width

height

GL_RGBA8_OES
GL_RGB8_OES

64 以上かつ、64 の倍数

64 以上かつ、16 の倍数

GL_RGBA4
GL_RGB5_A1
GL_RGB565

128 以上かつ、128 の倍数

128 以上かつ、16 の倍数

転送元の領域と転送先の領域が重なる場合、srcaddrdstaddr が等しい、または srcaddrdstaddr より大きいならば正常に動作します。なお、srcaddrdstaddr より小さい場合は転送結果が壊れる可能性があります。

srcaddr にデバイスメモリ上のアドレスを指定した場合、転送元の領域のキャッシュがフラッシュされていなければ、正しい結果にならない可能性があります。

表 4-19. nngxFilterBlockImage() が生成するエラー

エラー

原因

GL_ERROR_8068_DMP

オブジェクト名が 0 のコマンドリストをバインドしているとき、コマンドリクエストのキューに空きがないときに呼び出した

GL_ERROR_8069_DMP

srcaddr または dstaddr に指定するアドレスが 8 バイトのアライメントでない

GL_ERROR_806A_DMP

制限に抵触する width または height を指定した

GL_ERROR_806B_DMP

制限に表記されている以外のフォーマットを format に指定した

4.1.15. 画像イメージ転送コマンドの追加

nngxTransferLinearImage() の呼び出しで、レンダーバッファまたはテクスチャへの画像イメージ転送を行うコマンドがコマンドリストに蓄積されます。カレントの 3D コマンドバッファに区切られていないコマンドが蓄積されている場合は、区切りのコマンドを追加してから転送コマンドが追加されます。

イメージの転送中にリニアフォーマットからブロックフォーマットへの変換が行われますが、行われるのはアドレッシングの変換のみです。レンダーバッファに対して呼び出した場合、転送時のブロックアドレッシングへの変換はブロックモードの設定によって、自動的に 8 ブロック用と 32 ブロック用のアドレッシング変換が行われます。テクスチャに対して呼び出した場合は 8 ブロック用のアドレッシング変換が行われます。どちらの場合でも、転送元画像に対して V 方向のフリップとバイトオーダーの変換を事前に行う必要があります。

補足:

ブロックモードについては、「3DS プログラミングマニュアル - グラフィックス応用編」の「ブロックモードの設定」を参照してください。

コード 4-21. 画像イメージ転送コマンドを追加する関数
void nngxTransferLinearImage(const GLvoid* srcaddr, GLuint dstid, 
                             GLenum target);

srcaddr には転送元画像の先頭アドレスを指定します。画像は、転送先のレンダーバッファまたはテクスチャと同じフォーマット、同じ幅、高さでなければなりません。ただし、ピクセルフォーマットが 24 ビットフォーマット同士の転送はハードウェアでサポートされていませんので、転送先のピクセルフォーマットが 24 ビットフォーマットの場合、転送元のピクセルデータは 32 ビットフォーマットでなければなりません。このとき、転送元データは 4 バイトごとに最初の 1 バイト(内部フォーマットのアルファ成分)が切り捨てられて転送されます。

dstid には転送先のレンダーバッファまたはテクスチャのオブジェクト ID を、target には転送先オブジェクトの種類を指定します。

表 4-20. target, dstid に指定する値

target の値

dstid に指定する値

GL_RENDERBUFFER

レンダーバッファのオブジェクト ID。

0 を指定した場合は、カレントのフレームバッファにアタッチされているカラーバッファに転送されます。

GL_TEXTURE_2D

2D テクスチャのオブジェクト ID。

GL_TEXTURE_CUBE_MAP_POSITIVE_X{,Y,Z}
GL_TEXTURE_CUBE_MAP_NEGATIVE_X{,Y,Z}

キューブマップテクスチャのオブジェクト ID。

転送先のレンダーバッファの幅および高さは、ブロックモードがブロック 8 モードの場合は 8 の倍数、ブロック 32 モードの場合は 32 の倍数でなければなりません。また、幅および高さは 128 以上でなければなりません。

表 4-21. nngxTransferLinearImage() が生成するエラー

エラー

原因

GL_ERROR_805B_DMP

オブジェクト名が 0 のコマンドリストをバインドしているときに呼び出した

GL_ERROR_805C_DMP

すでにコマンドリクエストの蓄積数が最大値に達していた

GL_ERROR_805D_DMP

この関数が追加するコマンドにより 3D コマンドバッファが一杯になる

GL_ERROR_805E_DMP

dstid に指定したレンダーバッファまたはテクスチャが存在しない、またはメモリ領域が確保されていない

GL_ERROR_805F_DMP

転送先のレンダーバッファの幅および高さの制限に抵触する

GL_ERROR_8060_DMP

target に不正な値を指定した

GL_ERROR_8067_DMP

転送先のレンダーバッファまたはテクスチャのピクセルサイズが 32 ビット、24 ビット、16 ビット以外

4.1.16. ブロックイメージからリニアイメージへの変換転送コマンドの追加

nngxAddB2LTransferCommand() の呼び出しで、ブロックイメージをリニアイメージに変換して転送を行うコマンドがコマンドリストに追加されます。nngxTransferRenderImage() でも同様の機能が提供されていますが、この関数は、より汎用的な機能を提供します。また、3D コマンドの区切りコマンドを追加せず、転送リクエストコマンドのみを追加する点が異なります。

コード 4-22. ブロックイメージからリニアイメージへの変換転送コマンドを追加する関数
void nngxAddB2LTransferCommand(
    const GLvoid* srcaddr, GLsizei srcwidth, GLsizei srcheight, GLenum srcformat,
    GLvoid* dstaddr, GLsizei dstwidth, GLsizei dstheight, GLenum dstformat,
    GLenum aamode, GLboolean yflip, GLsizei blocksize);

srcaddr には転送元(ブロックイメージ)のアドレスを指定します。dstaddr には転送先(リニアイメージ)のアドレスを指定します。srcaddrdstaddr は、ともに 16 バイトアライメントでなければなりません。

srcwidth srcheightdstwidthdstheight には、それぞれ転送元イメージの幅と高さ、転送先イメージの幅と高さをピクセル数で指定します。転送元イメージおよび転送先イメージの幅と高さは、ブロックサイズ(8 または 32)の倍数でなければなりません。さらに、転送先イメージのピクセルサイズが 24 bit、かつブロックサイズが 8 の場合、転送元イメージの幅と転送先イメージの幅は 16 の倍数でなければなりません。srcwidthsrcheightdstwidthdstheight のいずれかに 0 が指定されていると、コマンドは追加されません。転送先イメージの幅と高さのピクセル数は、転送元イメージと同じか小さくなければなりません。

転送元イメージおよび転送先イメージの幅と高さのピクセル数は最小サイズの制限があります。転送元イメージの幅と高さの最小値は128です。転送先イメージの幅と高さの最小値は、アンチエイリアスの設定に依存します。アンチエイリアスが無効の場合は幅と高さともに128、2x1アンチエイリアスが有効な場合は幅が64、高さが128、2x2アンチエイリアスが有効な場合は幅と高さともに64です。

srcformat dstformat には、それぞれ転送元イメージおよび転送先イメージのピクセルフォーマットを指定します。指定可能なピクセルフォーマットは以下の 5 種類です。

表 4-22. ピクセルフォーマットの指定

定義

ビット数

フォーマットの詳細

GL_RGBA4

16

RGBA 各成分とも 4 bit

GL_RGB5_A1

16

RGB 各成分が 5 bit、アルファ成分が 1 bit

GL_RGB565

16

RB 成分が各 5 bit、G 成分が 6 bit。アルファ成分なし

GL_RGB8_OES

24

RGB 各成分とも 8 bit。アルファ成分なし

GL_RGBA8_OES

32

RGBA 各成分とも 8 bit

ピクセルフォーマットのビット数が大きくなる変換はできません。つまり、24 bit のフォーマットから 32 bit のフォーマットへの変換、16 bit のフォーマットから 24 bit または 32 bit のフォーマットへの変換はできません。

aamode にはアンチエイリアスフィルタのモードを指定します。指定可能なモードは以下の 3 種類です。表中の幅と高さは、転送元に必要なサイズが転送先の何倍以上であるかを示したものです。

表 4-23. アンチエイリアスの指定

定義

アンチエイリアス

高さ

NN_GX_ANTIALIASE_NOT_USED

アンチエイリアスなし

等倍

等倍

NN_GX_ANTIALIASE_2x1

2x1 アンチエイリアスで転送

2 倍

等倍

NN_GX_ANTIALIASE_2x2

2x2 アンチエイリアスで転送

2 倍

2 倍

yflip にはイメージを転送するときに縦方向のフリップを有効にするかどうかを指定します。GL_TRUE(または 0 以外の値)を指定した場合はフリップが行われ、GL_FALSE(または 0 )を指定した場合はフリップが行われません。

blocksize には、転送元イメージのブロックサイズを 8 または 32 で指定します。

表 4-24. nngxAddB2LTransferCommand() が生成するエラー

エラー

原因

GL_ERROR_807C_DMP

オブジェクト名が 0 のコマンドリストをバインドしている、またはコマンドリクエストのキューに空きがない

GL_ERROR_807D_DMP

srcaddr または dstaddr が 16 バイトアライメントではない

GL_ERROR_807E_DMP

blocksize に 8 または 32 以外の値を指定している

GL_ERROR_807F_DMP

aamode に不正な値を指定している

GL_ERROR_8080_DMP

srcformat および dstformat に不正な値を指定している

GL_ERROR_8081_DMP

srcformat のピクセルサイズより dstformat のピクセルサイズが大きい

GL_ERROR_8082_DMP

srcwidth srcheightdstwidthdstheight のいずれかに不正な値を指定した

GL_ERROR_8083_DMP

転送先イメージが転送元イメージより幅または高さのピクセル数が大きくなるような指定をした

GL_ERROR_80B7_DMP

転送元イメージの幅または高さのピクセル数に最小値未満の値を指定した

GL_ERROR_80B8_DMP

転送先イメージの幅または高さのピクセル数に最小値未満の値を指定した

4.1.17. リニアイメージからブロックイメージへの変換転送コマンドの追加

nngxAddL2BTransferCommand() の呼び出しで、リニアイメージをブロックイメージに変換して転送を行うコマンドがコマンドリストに追加されます。nngxTransferLinearImage() でも同様の機能が提供されていますが、この関数は、より汎用的な機能を提供します。また、3D コマンドの区切りコマンドを追加せず、転送リクエストコマンドのみを追加する点が異なります。

コード 4-23. リニアイメージからブロックイメージへの変換転送コマンドを追加する関数
void nngxAddL2BTransferCommand(
        const GLvoid* srcaddr, GLvoid* dstaddr,
        GLsizei width, GLsizei height, GLenum format, GLsizei blocksize);

srcaddr には転送元(リニアイメージ)のアドレスを指定します。dstaddr には転送先(ブロックイメージ)のアドレスを指定します。srcaddrdstaddr は、ともに 16 バイトアライメントでなければなりません。

width height には、それぞれ転送元および転送先のイメージの幅と高さをピクセル数で指定します。イメージの幅と高さは、転送元と転送先で同じでなければならず、128 以上かつブロックサイズ(8 または 32)の倍数でなければなりません。さらに、転送先イメージのピクセルサイズが 24 bit の場合は、ブロックサイズが 8 であっても、イメージの幅は 32 の倍数でなければなりません。width または height に 0 が指定されていると、コマンドは追加されません。

format には転送されるイメージのピクセルフォーマットを指定します。指定可能なピクセルフォーマットは nngxAddB2LTransferCommand() と同じです(表 4-22)。転送元と転送先のイメージは同じピクセルフォーマットでなければなりません。ただし、24 bit のフォーマットの場合、ハードウェアによる 24 bit から 24 bit への転送がサポートされていないため、転送元イメージが 32 bit のフォーマットでなければなりません。その場合、転送元データの 4 バイトごとに最初の 1 バイトが切り捨てられて転送されます。

blocksize には変換先イメージのブロックサイズを 8 または 32 から指定します。

表 4-25. nngxAddL2BTransferCommand() が生成するエラー

エラー

原因

GL_ERROR_806F_DMP

オブジェクト名が 0 のコマンドリストをバインドしている、またはコマンドリクエストのキューに空きがない

GL_ERROR_8070_DMP

srcaddr または dstaddr が 16 バイトアライメントではない

GL_ERROR_8071_DMP

blocksize に 8 または 32 以外の値を指定している

GL_ERROR_8072_DMP

width height のいずれかに不正な値を指定した

GL_ERROR_8073_DMP

format に不正な値を指定している

4.1.18. ブロックイメージ転送コマンドの追加

nngxAddBlockImageCopyCommand() の呼び出しで、ブロックイメージの転送を行うコマンドがコマンドリストに追加されます。追加されるコマンドにより、描画されたレンダーバッファやテクスチャ間での画像のコピーを行うことができます。転送サイズとスキップサイズの組を指定した転送を行うため、転送元イメージの部分領域を切り出したり、転送先イメージの部分領域にはめ込んだりすることができます。この関数はブロックフォーマットのイメージを転送することを主な目的としていますが、フォーマットの変換を行わないため、各種データの転送に利用することができます。

コード 4-24. ブロックイメージ転送コマンドを追加する関数
void nngxAddBlockImageCopyCommand(
        const GLvoid* srcaddr, GLsizei srcunit, GLsizei srcinterval,
        GLvoid* dstaddr, GLsizei dstunit, GLsizei dstinterval,
        GLsizei totalsize);

srcaddr には転送元の開始アドレスを指定します。dstaddr には転送先の開始アドレスを指定します。srcaddrdstaddr は、ともに 16 バイトアライメントでなければなりません。

totalsize には転送を行うサイズの合計をバイト単位で指定します。totalsize は 16 の倍数でなければなりません。

srcunit srcinterval には、それぞれ転送元の読み込み単位サイズとスキップサイズをバイト単位で指定します。srcunit バイトのデータ転送と srcinterval バイトの読み込みアドレスのスキップが交互に繰り返し行われ、転送されたサイズが totalsize に達したときに転送が終了します。srcinterval に 0 を指定した場合スキップは行われず、totalsize バイトの連続領域の読み込みが行われることになります。srcinterval に 0 以外を指定した場合は読み込みとスキップを繰り返すため、転送元イメージの部分領域を切り出して転送することができます。

dstunit dstinterval には、それぞれ転送先の書き込み単位サイズとスキップサイズをバイト単位で指定します。dstunit バイトのデータ書き込みと、dstinterval バイトの書き込みアドレスのスキップが交互に繰り返し行われ、転送されたサイズが totalsize に達したときに転送が終了します。dstinterval に 0 を指定した場合スキップは行われず、totalsize バイトの連続領域の書き込みが行われることになります。dstinterval に 0 以外を指定した場合は書き込みとスキップを繰り返すため、転送先イメージの部分領域にイメージをはめ込むような転送を行うことができます。

図 4-3. ブロックイメージ転送の例

srcaddr dstaddr dstunit dstinterval srcunit srcinterval

srcunit srcintervaldstunitdstinterval は 16 の倍数でなければなりません。また、0x100000 以上の値や負の値は指定することができません。

描画結果などのブロックイメージを転送する際は、転送イメージの先頭アドレス(転送元と転送先)が画像の左上(OpenGL ES では左下)である点や、ブロックサイズ 8 のフォーマットであれば 8×8 ピクセルのブロック単位でデータが配置されている点などに注意して、引数を設定してください。ブロックフォーマットの詳細については、「7.10. PICA ネイティブフォーマット」を参照してください。

表 4-26. nngxAddBlockImageCopyCommand() が生成するエラー

エラー

原因

GL_ERROR_8074_DMP

オブジェクト名が 0 のコマンドリストをバインドしている、またはコマンドリクエストのキューに空きがない

GL_ERROR_8075_DMP

srcaddr または dstaddr が 16 バイトアライメントではない

GL_ERROR_8076_DMP

totalsize が 16 の倍数ではない

GL_ERROR_8077_DMP

srcunit srcintervaldstunitdstinterval のいずれかに不正な値を指定した

4.1.19. メモリフィルコマンドの追加

nngxAddMemoryFillCommand() の呼び出しで、指定した領域を指定したデータで埋める(フィルする)コマンドがコマンドリストに追加されます。この関数で追加されるコマンドは、カラーバッファとデプスバッファ(ステンシルバッファ)をクリアする場合などに使用します。glClear() でも同様の機能を提供していますが、この関数は、より汎用的な機能を提供します。独立したパラメータの指定が可能な 2 つのチャンネル設定により、サイズの異なる 2 つの領域を同時にクリアすることができます。

コード 4-25. メモリフィルコマンドを追加する関数
void nngxAddMemoryFillCommand(
        GLvoid* startaddr0, GLsizei size0, GLuint data0, GLsizei width0,
        GLvoid* startaddr1, GLsizei size1, GLuint data1, GLsizei width1);

startaddr0 size0data0width0 がチャンネル 0 の設定、startaddr1size1data1width1 がチャンネル 1 の設定です。チャンネル 0 とチャンネル 1 によるメモリフィルは同時に実行されます。そのため、チャンネル 0 とチャンネル 1 で指定された領域が重なる場合、どちらの結果が最終的に反映されるのかは不定です。

startaddr0 startaddr1 には領域の先頭アドレスを指定します。アドレスは 16 バイトアライメントでなければなりません。アドレスに 0 を指定した場合は、そのチャンネルを使用しません。startaddr0 に 0 を指定した場合、size0data0width0 の指定に関するエラーはチェックされません。startaddr1 に 0 を指定した場合、size1data1width1 の指定に関するエラーはチェックはされません。

size0 size1 には領域のサイズをバイト単位で指定します。サイズは 16 の倍数でなければなりません。

data0 data1 にはフィルパターンのデータを指定します。領域には指定されたデータが繰り返し格納されます。

width0 width1 にはフィルパターンのビット幅を指定します。指定可能なビット幅は 16、24、32 のいずれかです。16 を指定した場合は、データのビット [ 15 : 0 ] を使って 16 bit 単位で埋められます。24 を指定した場合は、データのビット [ 23 : 0 ] を使って 24 bit 単位で埋められます。32 を指定した場合は、データのビット [ 31 : 0 ] を使って 32 bit 単位で埋められます。

下表は、レンダーバッファのフォーマットによるフィルパターンの指定(ビット幅、各成分値)をまとめたものです。

表 4-27. レンダーバッファのフォーマットによるフィルパターン

レンダーバッファのフォーマット

ビット幅

R / D

G / S

B

A

GL_RGBA8_OES

32

[ 31 : 24 ]
0 ~ 255

[ 23 : 16 ]
0 ~ 255

[ 15 : 8 ]
0 ~ 255

[ 7 : 0 ]
0 ~ 255

GL_RGB8_OES

24

[ 23 : 16 ]
0 ~ 255

[ 15 : 8 ]
0 ~ 255

[ 7 : 0 ]
0 ~ 255

-

GL_RGBA4

16

[ 15 : 12 ]
0 ~ 15

[ 11 : 8 ]
0 ~ 15

[ 7 : 4 ]
0 ~ 15

[ 3 : 0 ]
0 ~ 15

GL_RGB5_A1

16

[ 15 : 11 ]
0 ~ 31

[ 10 : 6 ]
0 ~ 31

[ 5 : 1 ]
0 ~ 31

[ 0 : 0 ]
0 ~ 1

GL_RGB565

16

[15 : 11 ]
0 ~ 31

[ 10 : 5 ]
0 ~ 63

[ 4 : 0 ]
0 ~ 31

-

GL_DEPTH24_STENCIL8_EXT

32

[ 23 : 0 ]

[ 31 : 24 ]

-

-

GL_DEPTH_COMPONENT24_OES

24

[ 23 : 0 ]

-

-

-

GL_DEPTH_COMPONENT16

16

[ 15 : 0 ]

-

-

-

表 4-28. nngxAddMemoryFillCommand() が生成するエラー

エラー

原因

GL_ERROR_8078_DMP

オブジェクト名が 0 のコマンドリストをバインドしている、またはコマンドリクエストのキューに空きがない

GL_ERROR_8079_DMP

startaddr0 または startaddr1 が 16 バイトアライメントではない

GL_ERROR_807A_DMP

size0 または size1 が 16 の倍数ではない

GL_ERROR_807B_DMP

width0 または width1 に不正な値を指定した

4.1.20. 3D コマンドバッファのポインタ移動

nngxMoveCommandbufferPointer() の呼び出しで、現在バインドされているコマンドリストの 3D コマンドバッファのポインタ(3D コマンドの実行位置)を移動させることができます。

コード 4-26. 3D コマンドバッファのポインタを移動させる関数
void nngxMoveCommandbufferPointer(GLint offset);

offset にはポインタの移動量をバイト単位で指定します。

コマンドリストがバインドされていない場合や、ポインタが 3D コマンドバッファの領域外に移動してしまう場合は GL_ERROR_8061_DMP のエラーを生成します。

4.1.21. ジャンプコマンドの追加

nngxAddJumpCommand() の呼び出しで、指定された領域にある 3D コマンドを実行するジャンプコマンドが、現在バインドされているコマンドリストに追加されます。ジャンプコマンドを利用すると、割り込みを発生させることなく、別のコマンドリストを続けて実行することができます。

この関数は PICA レジスタのコマンドバッファ実行レジスタを利用しています。チャンネル 0 のみを使用していますので、2 つのレジスタ(0x0238 と 0x023A)の内容が関数の実行時に書き換えられます。動作の詳細については、「3DS プログラミングマニュアル - グラフィックス応用編」の「コマンドバッファ実行レジスタ(0x0238 ~ 0x023D)」と「コマンドバッファの連続実行」を参照してください。

コード 4-27. ジャンプコマンドを追加する関数
void nngxAddJumpCommand(const GLvoid* bufferaddr, GLsizei buffersize);

bufferaddr buffersize には、続けて実行されるコマンドバッファのアドレスとバッファのサイズを指定します。bufferaddrbuffersize は、ともに 16 の倍数である必要があります。

ジャンプ先(bufferaddrbuffersize で指定されたコマンドリスト)のコマンドバッファの内容は、現在バインドされているコマンドリストのコマンドバッファにコピーされません。ジャンプコマンドはコマンドバッファの実行アドレスを変更し、ジャンプ先のコマンドバッファを直接実行します。そのため、ジャンプ先の領域のキャッシュがフラッシュされていることをアプリケーションで保証しなければなりません。

ジャンプ先で最後に実行されるコマンドは、区切りコマンド(nngxSplitDrawCmdlist() で追加される区切りコマンド設定レジスタへの書き込みコマンド)でなければなりません。区切りコマンドの代わりにジャンプコマンドでジャンプを繰り返すことができます。ただし、ジャンプを繰り返した場合は、最終的に実行されるコマンドバッファの最後に区切りコマンドが必要です。

この関数は、3D 実行コマンドのコマンドリクエストを追加します。nngxFlush3DCommand() などでコマンドバッファがフラッシュされた直後に呼び出しても意味がないため、GL_ERROR_809A_DMP のエラーが生成されます。フラッシュされた直後のコマンドバッファに 3D コマンドを追加する場合は nngxAdd3DCommand() を呼び出してください。

表 4-29. nngxAddJumpCommand() が生成するエラー

エラー

原因

GL_ERROR_8096_DMP

オブジェクト名が 0 のコマンドリストをバインドしている

GL_ERROR_8097_DMP

buffersize が 0 以下

GL_ERROR_8098_DMP

buffersize が 16 の倍数ではない

GL_ERROR_8099_DMP

bufferaddr が 16 の倍数ではない

GL_ERROR_809A_DMP

現在バインドされているコマンドリストのコマンドバッファがフラッシュされた直後

GL_ERROR_809B_DMP

この関数で追加されるコマンドリクエストによってキューがあふれる

GL_ERROR_809C_DMP

この関数で追加されるコマンドによってコマンドバッファがあふれる

4.1.22. サブルーチンコマンドの追加

nngxAddSubroutineCommand() の呼び出しで、指定された領域にある 3D コマンドを実行するジャンプコマンドとジャンプ元のコマンドバッファに戻るためのアドレス情報設定用のコマンドが、現在バインドされているコマンドリストに追加されます。サブルーチンコマンドを利用すると、割り込みを発生させることなく、別のコマンドリストをサブルーチンのように実行することができます。

この関数は PICA レジスタのコマンドバッファ実行レジスタを利用しています。すべてのチャンネルを使用していますので、4 つのレジスタ(0x0238 ~ 0x023B)の内容が関数の実行時に書き換えられます。動作の詳細については、「3DS プログラミングマニュアル - グラフィックス応用編」の「コマンドバッファ実行レジスタ(0x0238 ~ 0x023D)」と「同じコマンドバッファの繰り返し実行」 を参照してください。

コード 4-28. サブルーチンコマンドを追加する関数
void nngxAddSubroutineCommand(const GLvoid* bufferaddr, GLsizei buffersize);

bufferaddr buffersize には、続けて実行されるコマンドバッファのアドレスとバッファのサイズを指定します。bufferaddrbuffersize は、ともに 16 の倍数である必要があります。

ジャンプ先(bufferaddrbuffersize で指定されたコマンドリスト)のコマンドバッファの内容は、現在バインドされているコマンドリストのコマンドバッファにコピーされません。ジャンプコマンドはコマンドバッファの実行アドレスを変更し、ジャンプ先のコマンドバッファを直接実行します。そのため、ジャンプ先の領域のキャッシュがフラッシュされていることをアプリケーションで保証しなければなりません。

ジャンプコマンドはチャンネル 0 で実行され、元のコマンドバッファに戻るコマンドはチャンネル 1 で実行されます。そのため、ジャンプ先で最後に実行されるコマンドはチャンネル 1 のキックコマンド(コマンドバッファ実行レジスタ 0x023D への書き込みコマンド)でなければなりません。代わりにジャンプコマンドで別のコマンドバッファへジャンプすることもできますが、ジャンプに使用するチャンネルは 0 でなければならず、最終的に実行されるコマンドバッファの最後にチャンネル 1 のキックコマンドが必要です。また、その途中でチャンネル 1 のアドレス設定(0x0239、0x023B)を書き換えないでください。この関数が追加するのはジャンプコマンド(チャンネル 0)とアドレス設定(チャンネル 1)です。チャンネル 1 のキックコマンドやサブルーチン内でのジャンプコマンドはアプリケーションが配置しなければなりません。

この関数は、3D 実行コマンドのコマンドリクエストを追加しません。この関数を呼び出したあとも続けてコマンドを蓄積し、nngxFlush3DCommand() などでコマンドバッファをフラッシュしてから実行してください。コマンドバッファがフラッシュされるまで、この関数が追加するチャンネル 1 のサイズ設定レジスタ(0x023B)への書き込まれる値は未確定の状態ですので、コマンドバッファをフラッシュする前にコピーした内容を再利用したときの動作は不定です。

表 4-30. nngxAddSubroutineCommand() が生成するエラー

エラー

原因

GL_ERROR_809D_DMP

オブジェクト名が 0 のコマンドリストをバインドしている

GL_ERROR_809E_DMP

buffersize が 0 以下

GL_ERROR_809F_DMP

buffersize が 16 の倍数ではない

GL_ERROR_80A0_DMP

bufferaddr が 16 の倍数ではない

GL_ERROR_80A1_DMP

この関数で追加されるコマンドによってコマンドバッファがあふれる

4.2. コマンドリクエストの種類

コマンドリストにキューイングされるコマンドリクエストには、以下のコマンドがあります。

DMA 転送コマンド

メインメモリから VRAM への、テクスチャイメージや頂点バッファの DMA 転送を行うコマンドです。

glTexImage2D() などのテクスチャ領域確保や glBufferData() などの頂点バッファ領域確保でキューイングされます。

3D 実行コマンド

3D コマンドバッファに蓄積されている 3D コマンドを、コマンドセット 1 つ分実行するコマンドです。

glClear()glTexImage2D() などの呼び出しでバッファ読み込み終了の 3D コマンドが書き込まれ、蓄積していた 3D コマンドバッファを 1 つの 3D 実行コマンドとしてキューイングされます。

nngxSplitDrawCmdlist() により、任意のタイミングで 3D 実行コマンドをキューイングさせることもできます。

メモリフィルコマンド

GPU のメモリフィル機能によって、VRAM 上に確保されている領域を指定したデータパターンでクリアするコマンドです。

レンダーバッファを指定し、glClear() を呼び出したときにキューイングされます。glClear() の実行には、メモリフィル以外にも 3D コマンドの実行が必要となります。つまり glClear() を呼び出すと、3D コマンドバッファに glClear() 用とバッファ読み込み終了の 3D コマンドが書き込まれ、3D 実行コマンドとメモリフィルコマンドが続けてキューイングされます。

ポスト転送コマンド

GPU のポストフィルタ機能によって、PICA ブロックフォーマットで描画されたイメージを LCD が読み込めるリニアフォーマットに変換するコマンドです。

nngxTransferRenderImage() を呼び出したときにキューイングされます。nngxSplitDrawCmdlist() を事前に呼び出して 3D コマンドバッファの読み込みを終了させていなければ、バッファ読み込み終了コマンドの書き込みと 3D 実行コマンドのキューイングのあとに、このコマンドがキューイングされることになります。

レンダーテクスチャ転送コマンド

GPU の描画結果をテクスチャイメージとしてメモリにコピーするコマンドです。

glCopyTexImage2D() または glCopyTexSubImage2D() を呼び出したときにキューイングされます。

nngxSplitDrawCmdlist() を事前に呼び出して 3D コマンドバッファの読み込みを終了させていなければ、バッファ読み込み終了コマンドの書き込みと 3D 実行コマンドのキューイングのあとに、このコマンドがキューイングされることになります。

4.3. 3D コマンドバッファのパフォーマンスを最適化する手法

3D コマンドバッファ実行時のパフォーマンスを最適化する手法を説明します。

4.3.1. アドレスとサイズによるロード速度の変化

3D コマンドバッファのアドレスとサイズが、実行時のロード速度に影響する場合があります。

3D コマンドバッファの実行方法には、コマンドリクエストにキューイングされた 3D 実行コマンドでの実行と、コマンドバッファ実行レジスタでの実行の 2 種類があります。

3D 実行コマンドにより実行される場合は、nngxFlush3DCommand()nngxSplitDrawCmdlist() で区切りコマンドが追加された直後のアドレスから、次に区切りコマンドが追加されるまでのサイズにより影響を受けます。3D コマンドバッファに蓄積中の 3D コマンドのアドレスは、nngxGetCmdlistParameteri()pnameNN_GX_CMDLIST_CURRENT_BUFADDR を渡して取得できます。

コマンドバッファ実行レジスタにより実行される場合は、nngxAddJumpCommand() で追加されるコマンドバッファのアドレスとサイズ、nngxAddSubroutineCommand() で追加されるサブルーチンとしてのコマンドバッファおよびサブルーチンから呼び出し元に戻るために実行されるコマンドバッファのアドレスとサイズにより影響を受けます。

3D コマンドバッファのアドレスが 128 バイトアライメントの場合、サイズが 256 バイト単位(256 バイト、512 バイト、768 バイトなど)ならば転送速度が向上する可能性があります。

3D コマンドバッファのアドレスが 128 バイトアライメントではない場合、直前の 128 バイトアライメントのアドレスから 3D コマンドバッファの終端までのサイズが 256 バイト単位である場合に速度が向上する可能性があります。例えば 3D コマンドバッファのアドレスとサイズがそれぞれ 0x20000010 と 0x1F0 だった場合、直前の 128 バイトアライメントのアドレスは 0x10 だけ手前の 0x20000000 です。そこから終端までは 0x1F0 + 0x10 で 0x200 となり、256 バイト単位であると言えます。

GPU の実装上の理由により、3D コマンドバッファのアドレスとサイズには上記のような特性がありますが、格納場所や 3D コマンドの内容、ほかのモジュールとのメモリアクセスの競合などにより、大きな効果が得られない場合があります。

4.3.2. サブルーチン実行の利用

3D コマンドバッファのサブルーチン実行を利用することで、パフォーマンスが向上する可能性があります。

4.3.2.1. 概要

3D コマンドバッファのサブルーチン実行とは、コマンドバッファ実行レジスタを使用した実行方法です。3D コマンドを一続きの 3D コマンドバッファに格納して実行する通常の手法とは異なり、別の場所に格納してあるコマンドバッファをコマンドバッファのアドレスジャンプ機能を使って連続で実行させる手法です。3D コマンドバッファのアドレスを特定のアドレスへジャンプさせ、ジャンプ先の 3D コマンドバッファを実行したあと、ジャンプ元へ戻るという制御を行うことから、この手法をコマンドバッファのサブルーチン実行と呼びます。

コマンドバッファのサブルーチン実行を行うための具体的な方法については、「4.1.22. サブルーチンコマンドの追加」および「3DS プログラミングマニュアル - グラフィックス応用編」の「コマンドバッファ実行レジスタ(0x0238 ~ 0x023D)」を参照してください。

4.3.2.2. 動作への影響

コマンドバッファをサブルーチン化して実行することには、以下のメリットがあります。

  • サブルーチン化されたコマンドバッファへのジャンプコマンドなどを格納するだけでよいため、3D コマンドのコピーに必要な CPU 処理を削減できます。つまり、参照テーブルのデータやシェーダプログラムのロードなど、ある程度サイズが大きく、頻繁に設定が行われる処理で効果を発揮します。
  • サブルーチン化されたコマンドバッファはカレントの 3D コマンドバッファへコピーされずに GPU から直接参照されるため、コマンドバッファの総サイズを縮小することができます。
  • サブルーチン化されたコマンドバッファを VRAM に格納すれば、GPU からコマンドバッファへのアクセスがメインメモリ(デバイスメモリ)に比べて高速になります。そのため、コマンドバッファへのメモリアクセスがボトルネックとなっている場合に、システム全体の処理速度の向上が期待できます。

一方、以下のデメリットがあります。

  • ジャンプコマンドによるアドレスの切り替えで、メモリアクセスのオーバーヘッドが発生します。そのため、サブルーチン化の粒度を小さくして頻繁に呼び出すような実装では、GPU の処理速度が低下する可能性があります。

サブルーチン化による処理速度への影響は、メモリアクセスの競合などに左右されるため、実際のアプリケーションの実装に強く依存します。

4.3.2.3. 格納場所

コマンドバッファのアクセス速度はメインメモリ(デバイスメモリ)より VRAM の方が高速ですので、サブルーチン化されたコマンドバッファは VRAM に格納することを推奨します。

ジャンプコマンドによるサブルーチン化されたコマンドバッファの実行ではメモリアクセスのオーバーヘッドが発生しますが、実行するコマンドバッファが VRAM に格納されている場合はオーバーヘッドが軽減されます。

コマンドバッファを VRAM に格納するには、デバイスメモリ上に生成したあとに、nngxAddVramDmaCommand() を利用して VRAM に DMA 転送する必要があります。VRAM への DMA 転送については「4.1.13. DMA 転送コマンドの追加」を参照してください。

4.3.2.4. 実行処理とアクセス処理のバランス

サブルーチン化されたコマンドバッファの内容によっては、ボトルネックとなる処理が 3D コマンドのアクセス処理と実行処理の間で移動する場合があります。

3D コマンドがラスタライゼーションモジュール以降のモジュール(ラスタライゼーションモジュールを含む)のレジスタライトコマンドである場合、1 個の 3D コマンドを処理するのに 2 サイクルかかるため、実行処理の比重が大きくなります。3D コマンドがバーストコマンドで構成されている場合は、アクセス処理に対する実行処理の比重はさらに大きくなります。このような場合、実行処理がボトルネックとなり、サブルーチン化で発生するメモリアクセスの処理コストが隠蔽されることになります。

3D コマンドが、ラスタライゼーションモジュールより前のモジュール(ラスタライゼーションモジュールを含まない)のレジスタライトコマンドである場合、1 個の 3D コマンドを処理するのに 1 サイクルかかるため、前者よりも実行処理の比重が小さくなります。この場合、アクセス処理がボトルネックになりやすく、サブルーチン化で発生するメモリアクセスの処理コストが全体のパフォーマンスに影響しやすくなります。

各モジュールの位置関係については「2.2. レンダリングパイプライン」を参照してください。