This document aims to outline and summarize the functionality of the Nintendo DS’s 2D rendering system and the wrapping APIs around that system as used in Pokemon Platinum.
Much of the underlying systems from the Game Boy Advance still applies to the DS. Thus, this document will aim to only highlight the differences.
Backgrounds are rendered in layers; the SDK provides support for 8 total layers
evenly split across the Main and Sub screens. For simplicity, this document will
refer to layers by the indices 0
, 1
, 2
, and 3
to refer to the set of
layers accessible to each of the displays.
Like its predecessors, the DS makes use of a basic tiling system with access to 656 KB of VRAM. This VRAM chunk is split into 9 total banks of varying sizes:
Both the 2D and 3D processing engines can access any of these banks, but are not permitted to access the same bank concurrently. The 2D processing engine will access these banks to render each of the various backgrounds, while the 3D processing engine will fetch textures from these banks during rendering.
Some restrictions apply to accessing each of these banks:
The console’s 2D engine can generate various types of backgrounds, each with different supported functions. There are, effectively, three groups of these types.
These background types utilize a traditional tiling system, rendering frames by mapping them from VRAM to simple indexing buffer.
This is the most ordinary background type. It supports screen resolutions up to 512x512, 256 on-screen colors, and 16 total palettes (of 16 colors each). It also supports all the usual effects:
The VRAM buffer supports up to 1024 total tiles for each background of this type.
This background type supports screen resolutions up to 1024x1024, as well as the usual set of basic affine transformations:
However, to support these transformations, the flipping flags are disabled, and the VRAM buffer supports up to 256 tiles rather than 1024.
This background type is an extension of the Affine type; it supports the same screen resolutions and set of affine transformations, but restores support for flipping flags and 1024 tiles.
Rather than rendering frames from tiles mapped onto an indexing buffer, types in this group treat VRAM as a true bitmap frame buffer.
Functionally, this type is identical to a Static with Affine background, but effects are applied on the full 512x512 bitmap.
This type is similar to the 256 color extension, but the frame buffer now supports direct 15-bit color, permitting up to 32,768 total on-screen colors.
This type treats a single 128KB chunk of VRAM as a frame-buffer of size 1024x512.
Backgrounds of this type (which is the only member of its group) treat the rendering result of the 3D graphics engine as a background layer. Thus, backgrounds of this type do not support most of the previous 2D effects, but do retain support for horizontal scrolling and alpha blending. In addition, backgrounds of this type support direct 18-bit color, permitting up to 262,144 total on-screen colors.
Background types are restricted to various “modes”, as controlled by the SDK. The SDK supports 7 total modes:
Mode | Layer 0 Type | Layer 1 Type | Layer 2 Type | Layer 3 Type |
---|---|---|---|---|
0 | Static / 3D | Static | Static | Static |
1 | Static / 3D | Static | Static | Affine |
2 | Static / 3D | Static | Affine | Affine |
3 | Static / 3D | Static | Static | Affine Extended |
4 | Static / 3D | Static | Affine | Affine Extended |
5 | Static / 3D | Static | Affine Extended | Affine Extended |
6 | 3D Background | N/A | Large Screen | N/A |
Each of the displays can be set to its own background mode; this permits, for example, having affine transformations apply to the main screen, but showing a simple static HUD on the sub screen.
Game Freak built a minimal wrapping API around the SDK’s internals, much of which is identical to the similar wrapping API built for the Advance generation. This wrapping API restricts the available background types to the following:
enum BgType {
BG_TYPE_STATIC = 0,
BG_TYPE_AFFINE,
BG_TYPE_STATIC_WITH_AFFINE,
};
Backgrounds can be quickly constructed via a simple template system, which allows storing common properties in ROM:
typedef struct BgTemplate {
u32 x;
u32 y;
u32 bufferSize;
u32 baseTile;
u8 screenSize;
u8 colorMode;
u8 screenBase;
u8 charBase;
u8 bgExtPltt;
u8 priority;
u8 areaOver;
u8 dummy;
BOOL mosaic;
} BgTemplate;
The wrapping API’s primary feature is support for scheduling scroll and VRAM
transfer operations for future bulk transformation. Most background update
operations provide Schedule
alternative, which will perform the operation,
but delay committing the result to VRAM until the next invocation of
Bg_RunScheduledUpdates
. To illustrate, consider the following functions:
void Bg_FillTilemap(BgConfig *bgConfig, u8 bgLayer, u16 fillVal)
{
if (bgConfig->bgs[bgLayer].tilemapBuffer == NULL) {
return;
}
MI_CpuFill16(bgConfig->bgs[bgLayer].tilemapBuffer, fillVal, bgConfig->bgs[bgLayer].bufferSize);
Bg_CopyTilemapBufferToVRAM(bgConfig, bgLayer);
}
void Bg_ScheduleFillTilemap(BgConfig *bgConfig, u8 bgLayer, u16 fillVal)
{
if (bgConfig->bgs[bgLayer].tilemapBuffer == NULL) {
return;
}
MI_CpuFill16(bgConfig->bgs[bgLayer].tilemapBuffer, fillVal, bgConfig->bgs[bgLayer].bufferSize);
Bg_ScheduleTilemapTransfer(bgConfig, bgLayer);
}
Note that each of these operations perform the same MI_CpuFill16
operation,
but the latter invokes Bg_ScheduleTilemapTransfer
, which flags the background
layer for VRAM transfer, usually on the next VBlank callback.