This document describes programming using the CTR-SDK's GD library. It assumes that the reader is already familiar with basic graphics concepts and how to use some of the libraries (such as the GX library), and focuses specifically on the GD library.
This document also assumes that the reader has an understanding of the content in the 3DS Programming Manual: Basic Graphics and the CTR Programming Manual: Advanced Graphics. Please read those documents first.
1.1. The GD Library
The GD library is one of the CTR-SDK graphics libraries. It is mainly used to generate 3D commands.
The library generates only the 3D commands necessary to synchronize its internal state with the GPU state, allowing you to implement graphics processing without keeping track of the GPU state. The API is structured in a way that is tightly linked with the 3DS graphics hardware. It has been designed to achieve high performance while at the same time making it easy for applications to use.
The GD library is incompatible with DMPGL (gl()
functions). You must use the GX library (nngx()
functions) for command list management and some other system-related features. In addition, only a C++ interface is provided.
1.1.1. Command Lists
As already mentioned, the GD library does not manage command list operations; the features provided by the GX library are used for that. In other words, applications are solely responsible for implementing ways of preparing, using, and synchronizing command lists.
1.1.2. Immediate and Non-Immediate Functions
GD library functions are classified as either immediate or non-immediate functions, depending on when they write 3D commands to the 3D command buffer specified by the current command list object.
Immediate functions write data directly to the 3D command buffer when they are called. This has the advantage of allowing you to directly edit recorded packets when you use the packet recording feature (see 6. Packet Recording).
Non-immediate functions update the internal state of the GD library without writing to the 3D command buffer. These internal states are loaded when rendering functions (nn::gd::System::Draw
or nn::gd::System::DrawIndexed
) are called and data is written to the 3D command buffer as necessary.
Some functions have the characteristics of both immediate and non-immediate functions and update the GD library's internal state while continuing to write to the 3D command buffer.
1.1.3. Error Handling
Functions that may fail internally are implemented to return an nnResult
object. In other words, when an error occurs a corresponding error value is returned.
There are two ways to handle errors with the GD library. The first is to always check the return values from GD functions. The second is to call the nn::gd::System::SetCallbackFunctionError()
function to register a callback function for handling errors. You can use both of these methods at the same time, getting errors from the return values of the GD functions after the callback is invoked.
typedef void (*nn::gd::System::gdCallbackfunctionErrorPtr)( nnResult result, const char* functionName); static void nn::gd::System::SetCallbackFunctionError( nn::gd::System::gdCallbackfunctionErrorPtr callbackFunctionError);
The build type (Debug/Development/Release) determines the granularity of error checking within GD functions.
You can also use the nn::gd::System::GetErrorStringFromResult()
function for debugging purposes to get a message that corresponds to the error for a given nnResult
object.
static char* nn::gd::System::GetErrorStringFromResult(nnResult result);
1.2. Module
Modules bundle related processing within the 3DS rendering pipeline.
The following modules are defined by the GD library.
Module | Definition Name |
---|---|
Vertex Input Stage | nn::gd::System::MODULE_VERTEX_INPUT |
Shader Stage | nn::gd::System::MODULE_SHADER |
Rasterizer Stage | nn::gd::System::MODULE_RASTERIZER |
Texture Stage | nn::gd::System::MODULE_TEXTURE |
Procedural Texture Stage | nn::gd::System::MODULE_TEXTURE_PROCEDURAL |
Lighting Stage | nn::gd::System::MODULE_LIGHTING |
Combiner Stage | nn::gd::System::MODULE_TEXTURE_COMBINER |
Fog Stage | nn::gd::System::MODULE_GAS_FOG |
Output Stage | nn::gd::System::MODULE_OUTPUT |
Pipeline processing is sometimes split into stages. Modules are also sometimes called stages.
1.2.1. Static Class Definitions
Most GD library functions are accessed through static
classes defined in each module. These stateless classes only have static()
functions and are never instantiated. In other words, these classes are simply used to group function definitions for each feature.
Each module has one or more classes, as shown in the following table.
Module | Classes | Processing |
---|---|---|
Vertex Input Stage | VertexInputStage |
Vertex buffer input. |
Shader Stage | ShaderStage |
Attaching shader programs. |
Rasterizer Stage | RasterizerStage |
Culling, clipping, viewport settings, scissoring, and early depth tests. |
Texture Stage | TextureStage |
Texture unit settings. |
Procedural Texture Stage | ProceduralTextureStage |
Procedural texture settings. |
Lighting Stage | LightingStage |
Fragment lighting settings. |
Combiner Stage | CombinerStage |
Texture combiner settings. |
Fog Stage | FogStage |
Fog and gas settings. |
Output Stage | OutputStage |
Depth tests, stencil tests, alpha tests, logical operations, blending, write masks, render target settings, and fragment operation settings. |
1.2.2. Managing Module States
The library manages its internal state in several modules. If the internal state does not change for two rendering passes, commands related to those modules are not resent. This prevents unnecessary command packets from being generated and can improve performance. If, however, some GD function call has modified the internal state, the corresponding module is considered to be "dirty" (in other words, the module contains changes). Commands that reference the internal state of any module considered to be dirty are sent the next time rendering occurs.
The library tracks whether modules are dirty and automatically processes them. Accordingly, applications that use the GD library normally do not need to track which modules are dirty. However, sometimes it is advantageous to ensure that all the commands related to a module are re-sent. To that end, the GD library provides the following function to explicitly mark modules as dirty.
void nn::gd::System::ForceDirty(u32 moduleFlag);
Specify the modules to mark as dirty to moduleFlag
using a bitwise OR of the definitions in Table 1-1.
This function is useful when the hardware state has been updated (after prepared command packets are executed, for example) or when another graphics library (such as NintendoWare, DMPGL, and GR) is used, and you want to ensure that the entire GD library state is applied.
1.3. State Objects and Resource Objects
State objects are immutable objects that are never modified after they are created. They are typically created during initialization and then used to set a state when necessary at run time. Although the act of creating an object involves memory allocation and data processing time, after a state is created it can be simply output to the 3D command buffer, to minimize later processing. There is no way to directly access the content of these state objects.
When the GD library receives a request to create a state object, it first determines whether it has already created an object that has the exact same settings. If it finds an object with the same settings, it simply returns a pointer to that object rather than creating a new one.
The following are defined as state objects.
State Object | Stage Used | Bundled Settings |
---|---|---|
CombinerState |
Combiner Stage | Combiner and combiner buffer. |
BlendState |
Output Stage | Logical operations and blending. |
DepthStencilState |
Output Stage | Depth and stencil tests. |
InputLayout |
Vertex Input Stage | Vertex buffers. |
SamplerState |
Texture Stage | Texture parameters. |
Apart from state objects, there are also the following resource objects. These are used in the same way in the sense that the necessary processing is almost entirely finished when the objects are created.
Resource Objects | Description |
---|---|
ShaderBinary |
Saves and loads shader binaries. |
Shader |
Loads floating-point constants into the GPU and sets input and output registers. |
ShaderPipeline |
Attaches shader programs to the shader pipeline. |
VertexBufferResource |
Maintains vertex buffer data. |
Texture2DResource |
Maintains resources that have a width and height, such as textures and color buffers. |
Texture2D |
Handles a Texture2DResource object as a 2D texture. |
TextureCube |
Handles six Texture2DResource objects as a cube-map texture. |
RenderTarget |
Handles a Texture2DResource object as a color buffer. |
DepthStencilTarget |
Handles a Texture2DResource object as a depth (stencil) buffer. |
The memory required to create state and resource objects is allocated as a system buffer (NN_GX_MEM_SYSTEM
) from device memory (NN_GX_MEM_FCRAM
) through the allocator specified when the GX library was initialized. We recommend that you consider how much memory is used by this library and leave extra space in device memory.
For more information about how much memory is allocated, see 9.2. Size of Memory Allocated Within Functions.
1.3.1. Descriptor Classes
Pass a descriptor class that defines the necessary settings to functions that create objects, such as state and resource objects, which are used to configure the pipeline.
All of a descriptor class's member variables are defined to be public
. Descriptor classes also sometimes define member functions for easily setting multiple member variables.