You can use command buffer addresses and sizes and kick commands to make execution jump to command buffers at different addresses.
The libraries provided by the SDK have API functions not only for normal, unidirectional command-buffer jumps, but also for jumping to command buffers in different locations in the form of subroutines that execute and then jump back to resume execution of subsequent commands in the original command buffer.
There are both benefits and drawbacks to the use of command-buffer jumps, and these are both considered below.
nngx API
There is the nngxAddJumpCommand function for unidirectional jumps, and the nngxAddSubroutineCommand function for performing command-buffer jumps as subroutines.
The nngx API functions operate internally and automatically to adjust the byte alignment and size.
The subroutine made for the command-buffer jump must add a Channel 1 kick command to the end of the command buffer. (For this, you can use the nn::gr::MakeChannelKickCommand function, which is described later.)
If you are going to add 3D rendering command requests (to add split commands) including a jump, use the following functions:
nngxFlush3DCommand function. (The nngxSplitDrawCmdlist function is also fine, but not recommended.)nngxFlush3DCommandNoCacheFlush function.nngx API
For unidirectional jumps there is the nn::gr::MakeChannel0JumpCommand function and the nn::gr::MakeChannel1JumpCommand function. For subroutines, there is the nn::gr::MakeChannel0SubroutineCommand function and the nn::gr::MakeChannel1SubroutineCommand function.
In addition, the nn::gr::MakeChannelKickCommand function is supported for adding the kick command itself.
The GR library does not take the command buffer size and alignment into consideration when adding jump-related commands.
You must make adjustments based on the size of commands added by the API functions.
Alternatively, you can select the channels to use and the commands to add. Also, the nn::gr::CommandBufferJumpHelper class helps you to adjust command sizes and create kick commands, but does not allow you to select channels.
| API | Size (in Bytes) of the Added Command |
|---|---|
MakeChannelKickCommand |
8 |
MakeChannel0SubroutineCommand |
24 |
MakeChannel1SubroutineCommand |
32 |
MakeChannel0JumpCommand |
24 |
MakeChannel1JumpCommand |
24 |
To add a split command you must use the nngxFlush3DCommandPartially function.
For the argument, specify the size from the start of the command buffer to the (first) kick command.
If you are using the GR library, you must explicitly flush the CPU cache for the command buffer.
The nngxFlush3DCommandPartially function does not perform this flush internally.
If you use the GD library, you do not need to make direct calls to the nngx functions for command-buffer jumping. The library acts internally to call the necessary functions.
Specify RECORD_3D_COMMAND_BUFFER_FOR_JUMP for the usage parameter of the nn::gd::System::StartRecordingPackets function and create the 3D command buffer you want as a subroutine. After the necessary commands are created, call the nn::gd::System::StopRecordingPackets function. The jump command is added internally when you specify the saved RecordedPacketId to the nn::gd::System::ReplayPackets function.
You can also jump by directly creating commands to send to the GPU. Use registers 0x238 to 0x23d. For more information, see the documentation.
However, there is really no benefit to creating your own commands, so we recommend normally using one of the other methods.
The following supplemental information describes cautions to take when implementing command-buffer jumps, and ways to boost efficiency.
Access to command buffers from the GPU is faster when the subroutines of commands are stored in VRAM rather than in main memory. If access to command buffers in main memory becomes a bottleneck, you can expect an overall boost in processing speed by saving to VRAM.
To place commands in VRAM, use the nngxAddVramDmaCommand function or the nngxAddVramDmaCommandNoCacheFlush function.
nngx API Functions)
If you implement a subroutine using the nngx API functions, calling the nngxFlush3DCommand function when adding a split command increases the load on the CPU because the CPU cache is flushed each time it is called.
For this reason, it is more efficient to keep the 3D rendering command requests together without splitting if they include a subroutine call.
If you need to have 3D rendering command requests containing multiple subroutines, what you can do is use the nngxFlush3DCommandNoCacheFlush function when adding the split command and then later call the nn::gx::UpdateBuffer function for the entire required region so that all flush operations are done together.
If there are no unexecuted command requests in the command list called by the nngxRunCmdlist function, that command list enters the "waiting to run" state.
In this state, if a new command request is added to the list, that request begins to run. During command request processing, the command list is in the "running" state.
When the command list is in the running state, some nngx API functions generate an error and interrupt the processing.
You must be particularly careful with the previously-mentioned nngxFlush3DCommandPartially function.
For implementations similar to the following example, depending on the timing, the intended commands may not be generated and the GPU may hang.
// Bad implementation.
// One command list is used while it remains in the "waiting to run" state.
Draw()
{
// Add a command request to clear the render buffer. ... (A)
nngxAddMemoryFillCommand(...);
// Create some rendering command. (Assume that the GR library is internally applying the jump.)
DrawObjects();
// Add a split command. (Add a 3D rendering command request.)... (B)
nngxFlush3DCommandPartially(buffersize);
// Flush the CPU cache for the command buffer.
nngxUpdateBuffer(...);
// Add a command request to transfer data to the display buffer. ... (C)
nngxTransferRenderImage(...);
// Wait for execution to complete.
nngxWaitCmdlistDone();
// Swap buffers.
Swap();
// Clear the command list.
nngxClearCmdlist();
}
If the command list is in the "waiting to run" state, it transitions to the "running" state when the command list is added (A). nngxFlush3DCommandPartially function generates the error GL_ERROR_80AD_DMP.nngxTransferRenderImage function is called in (C), a split command is added if there is any unprocessed command buffer, and a 3D rendering command request created.There are several possible workarounds.
nngxWaitCmdlistDone function to wait for the command list to finish running.nn::gr::CommandBufferJumpHelper class.CONFIDENTIAL