GD ライブラリを使用してグラフィックスを表示するために最低限必要となる処理を、行うべき順番(多少前後することがあります)で示すと以下のようになります。
- GD ライブラリの初期化
- フレームバッファの確保
- シェーダプログラムのロード
- 頂点データの準備
- ビューポートの設定
- 描画の実行
- 描画結果の表示
- 終了処理
上記以外の処理については「4. 各モジュールの説明」などを参照してください。
この章では関数の詳細については説明しません。関数の詳細な情報については、以降の章や関数リファレンスを参照してください。
2.1. GD ライブラリの初期化
GD ライブラリの初期化は nn::gd::System::Initialize()
を呼び出すことで行われます。初期化は GD ライブラリのほかの関数を呼び出す前に行われている必要があります。
また、nn::gd::System::Initialize()
は内部での作業用メモリ確保のために nngxInitialize()
経由で与えられているアロケータを使用します。このため、GD ライブラリの初期化に先立って nngxInitialize()
による GX ライブラリの初期化と、関数内で実行される 3D コマンドのためにコマンドリストの確保を行う必要があります。
以下は GD ライブラリの初期化に必要な流れの一例です。
nngxInitialize(...); nngxGenCmdlists(1, &cmdListId); nngxBindCmdlist(cmdListId); nngxCmdlistStorage(0x80000, 128); nnResult result = nn::gd::System::Initialize();
GD ライブラリでは、同じコマンドリストを使用した状態でも、ほかのフレームワーク(NintendoWare など)と平行して利用することができます。ただし、すでに GD ライブラリ以外でコマンドリストを確保していた場合は、GD ライブラリの初期化前にコマンドリストの確保を行わないように注意してください。
ディスプレイバッファを確保するための関数は GD ライブラリにはありません。ディスプレイバッファの確保は nngx 関数で行ってください。
2.2. フレームバッファの確保
カラーバッファとデプス(ステンシル)バッファの確保は GD ライブラリで行います。
デスクリプタクラスの設定に違いがあるものの、どちらのバッファも Texture2DResource
オブジェクトを作成しなければならないのは同じです。バッファのクリアや描画の効率から、以下のコード例のようにカラーバッファとデプス(ステンシル)バッファは VRAM-A と VRAM-B に分散して確保することを推奨します。
static nn::gd::Texture2DResource* s_texture2DResource_ColorBuffer = 0; static nn::gd::Texture2DResource* s_texture2DResource_DepthStencilBuffer = 0; //Color buffer nn::gd::Texture2DResourceDescription Text2DResDesc_ColorBuffer = {nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, 1, nn::gd::Resource::NATIVE_FORMAT_RGBA_8888, nn::gd::Memory::LAYOUT_BLOCK_8, nn::gd::Memory::VRAMA}; nnResult res = nn::gd::Resource::CreateTexture2DResource( &Text2DResDesc_ColorBuffer, 0, GD_FALSE, &s_texture2DResource_ColorBuffer); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} //Depth Stencil buffer nn::gd::Texture2DResourceDescription Text2DResDesc_DepthStencilBuffer = {nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT, 1, nn::gd::Resource::NATIVE_FORMAT_DEPTH_24_STENCIL_8, nn::gd::Memory::LAYOUT_BLOCK_8, nn::gd::Memory::VRAMB}; res = nn::gd::Resource::CreateTexture2DResource( &Text2DResDesc_DepthStencilBuffer, 0, GD_FALSE, &s_texture2DResource_DepthStencilBuffer); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");}
作成した Texture2DResource
オブジェクトを使って、カラーバッファならば RenderTarget
オブジェクトを、デプス(ステンシル)バッファならば DepthStencilTarget
オブジェクトをそれぞれ作成します。
static nn::gd::RenderTarget* s_RenderTarget = 0; static nn::gd::DepthStencilTarget* s_DepthStencilTarget = 0; //Color buffer nn::gd::RenderTargetDescription descRenderTarget = {0}; res = nn::gd::OutputStage::CreateRenderTarget( s_texture2DResource_ColorBuffer, &descRenderTarget, &s_RenderTarget); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} //Depth Stencil buffer nn::gd::DepthStencilTargetDescription descDepthStencilTarget = {0}; res = nn::gd::OutputStage::CreateDepthStencilTarget( s_texture2DResource_DepthStencilBuffer, &descDepthStencilTarget, &s_DepthStencilTarget); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");}
パイプラインへの設定はアウトプットステージで行い、RenderTarget
オブジェクトならば SetRenderTarget()
を、DepthStencilTarget
オブジェクトならば SetDepthStencilTarget()
をそれぞれ呼び出します。
//Set the color/depthstencil targets nn::gd::OutputStage::SetRenderTarget(s_RenderTarget); nn::gd::OutputStage::SetDepthStencilTarget(s_DepthStencilTarget);
2.3. シェーダプログラムのロード
描画に使用するシェーダプログラムをパイプラインに反映させるまでには、以下の手順が必要です。
- シェーダバイナリの読み込み
-
ShaderBinary
オブジェクトの作成 -
Shader
オブジェクトの作成 -
ShaderPipeline
オブジェクトの作成 - パイプラインへの反映
以下のコード例では、シェーダバイナリ(rBuf
に rSize
バイトのファイルを読み込み済み)に含まれている頂点シェーダをパイプラインに反映させています。
static nn::gd::ShaderBinary* shaderBinary = 0; static nn::gd::ShaderPipeline* shaderPipeline = 0; static nn::gd::Shader* vertexShader = 0; nnResult res; res = nn::gd::ShaderStage::CreateShaderBinary(rBuf, rSize, &shaderBinary); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} res = nn::gd::ShaderStage::CreateShader(shaderBinary, 0, &vertexShader); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} res = nn::gd::ShaderStage::CreateShaderPipeline( vertexShader, NULL, &shaderPipeline); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} nn::gd::ShaderStage::SetShaderPipeline(shaderPipeline);
シェーダプログラムで使用する各レジスタへの値の設定は、シェーダステージの GetShaderUniformLocation()
の引数に ShaderPipeline
オブジェクトとデータ名を指定して取得した、UniformLocation
オブジェクトを介して行います。
static nn::gd::UniformLocation s_shaderVariable_proj; static nn::gd::UniformLocation s_shaderVariable_view; s_shaderVariable_proj = nn::gd::ShaderStage::GetShaderUniformLocation( shaderPipeline, "uProjection"); s_shaderVariable_view = nn::gd::ShaderStage::GetShaderUniformLocation( shaderPipeline, "uModelView"); NN_ASSERT(s_shaderVariable_proj.IsValid()); NN_ASSERT(s_shaderVariable_view.IsValid()); nn::math::Matrix44 proj, mv; nn::gd::ShaderStage::SetShaderPipelineConstantFloat( shaderPipeline, s_shaderVariable_proj, static_cast<f32*>(proj)); nn::gd::ShaderStage::SetShaderPipelineConstantFloat( shaderPipeline, s_shaderVariable_view, static_cast<f32*>(mv));
2.4. 頂点データの準備
GD ライブラリでは、プリミティブの描画には必ず頂点バッファを使用しなければなりません。
頂点バッファを使用するには、以下の手順が必要となります。
-
InputLayout
オブジェクトの作成 -
VertexBufferResource
オブジェクトの作成 - パイプラインへの反映(入力レイアウトと頂点バッファ)
以下のコード例では、頂点座標と頂点カラーがインターリーブされた頂点データを使用しています。
u16 idxs[] = {0, 1, 2}; nnResult res; float coords_color[] = { 0.5f, 0.0f, 0.f, 1.f, 1.f, 0.0f, 0.0f, -0.5f, 0.5f, 0.f, 1.f, 0.f, 1.0f, 0.0f, -0.5f,-0.5f, 0.f, 1.f, 0.f, 0.0f, 1.0f, }; nn::gd::InputElementDescription descs[] = { { 0, "aPosition", nn::gd::VertexInputStage::STREAM_TYPE_FLOAT, 4, 0}, { 0, "aColor", nn::gd::VertexInputStage::STREAM_TYPE_FLOAT, 3, sizeof(float) * 4}, }; u32 strides[] = { sizeof(float) * 7 }; res = nn::gd::VertexInputStage::CreateInputLayout( descs, 2, strides, vertexShader, &inputLayout); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} nn::gd::VertexBufferResourceDescription desc; desc.m_ByteSize = sizeof(coords_color); desc.m_MemLocation = nn::gd::Memory::FCRAM; res = nn::gd::Resource::CreateVertexBufferResource( &desc, coords_color, &bufferCoord); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} desc.m_ByteSize = sizeof(idxs); res = nn::gd::Resource::CreateVertexBufferResource(&desc, idxs, &bufferIndex); if ( GD_NNRESULT_IS_FAILURE(res) ) {NN_PANIC("\n");} nn::gd::VertexBufferResource* buffers[] = { bufferCoord }; u32 offsets[] = { 0 }; nn::gd::VertexInputStage::SetVertexBuffers(0, 1, buffers, offsets); nn::gd::VertexInputStage::SetInputLayout(inputLayout); nn::gd::VertexInputStage::SetIndexBuffer( bufferIndex, nn::gd::VertexInputStage::INDEX_FORMAT_USHORT, 0);
2.5. ビューポートの設定
ビューポートの設定はラスタライザステージの SetViewport()
で行います。
以下のコード例では、アウトプットステージの GetRenderTargetProperties()
で取得したレンダーターゲットの情報をビューポートの設定に利用しています。
nn::gd::TargetProperties renderTargetProperty; nn::gd::OutputStage::GetRenderTargetProperties( s_RenderTarget, &renderTargetProperty); nn::gd::Viewport viewPort(0, 0, renderTargetProperty.m_Width, renderTargetProperty.m_Height); nn::gd::RasterizerStage::SetViewport(viewPort);
2.6. 描画の実行
描画のために呼び出す関数は頂点インデックスを使用するかどうかで異なります。頂点インデックスを使用する場合は nn::gd::System::DrawIndexed()
を、使用しない場合 nn::gd::System::Draw()
を呼び出します。なお、頂点バッファリソースを使用せずに描画を行う nn::gd::System::DrawImmediate()
と nn::gd::System::DrawImmediateIndexed()
も用意されています。ただし、頂点バッファリソースを使用しない描画は頂点データの取り扱いが柔軟になりますが、描画の実行が遅くなります。
フレームバッファのクリアには nn::gd::Memory::ClearTargets()
を使用してください。
以下のコード例では、フレームバッファのクリアと頂点インデックスを使用した描画を行っています。
//Clear the render buffers u8 clearColor[] = {25, 25, 122, 255}; nn::gd::Memory::ClearTargets(s_RenderTarget, s_DepthStencilTarget, clearColor, 1.f, 0); //Draw nn::gd::System::DrawIndexed(3, 0);
2.7. 描画結果の表示
カラーバッファの内容を nn::gd::Memory::CopyTexture2DResourceBlockToLinear()
でディスプレイバッファにコピーし、描画結果を LCD に表示させます。この関数は nngxTransferRenderImage()
とほぼ同じ機能を有していますが、コピー先のアドレスは nngxGetDisplaybufferParameteri()
などを利用してアプリケーションで取得しなければなりません。
//Transfer framebuffer to display buffer int dstAddr; nngxActiveDisplay(NN_GX_DISPLAY0); nngxGetDisplaybufferParameteri(NN_GX_DISPLAYBUFFER_ADDRESS, &dstAddr); nn::gd::Memory::CopyTexture2DResourceBlockToLinear( s_texture2DResource_ColorBuffer, //source 0, //sourceMipLevelIndex 0, //srcOffsetY (u8*)dstAddr, //dstAddr nn::gx::DISPLAY0_WIDTH, //dstWidth nn::gx::DISPLAY0_HEIGHT, //dstHeight nn::gd::Resource::NATIVE_FORMAT_RGB_888, //dstFormat nn::gd::Memory::DOWNSCALING_NONE, //DownScalingMode GD_FALSE //yFlip ); nngxWaitCmdlistDone(); nngxSwapBuffers(NN_GX_DISPLAY_BOTH);
2.8. 終了処理
GD ライブラリの終了処理は nn::gd::System::Finalize()
を呼び出すことで行われます。この関数の実行が完了したあとは GD ライブラリの関数を呼び出すことができなくなります。
終了処理では、アプリケーションで確保したものを含めて、ライブラリが管理しているリソースなどが自動的に解放されます。しかし、アプリケーションで作成したステートやリソースなどのオブジェクトは、なるべくアプリケーションで明示的に解放することを推奨します。