NDS/DOCgraphicmodes

From Dev-Scene

< NDS

Contents

[edit] Dual Screen

It should be apparent to all (well, most anyway) that the DS in fact has two screens. To accommodate rendering to these separate screens there exists two separate 2D graphics engines. This document refers to these engines as SUB and MAIN and will make an attempt at documenting the features of both.

In anticipation of misconception I will take a moment to point out an interesting fact: MAIN and SUB have nothing to do with TOP and BOTTOM. In fact you can render to the TOP or BOTTOM screen with either engine. Because the MAIN engine is a bit more capable than the 2D engine you generally assign it to the screen your user is looking at most and this depends on your application.

[edit] Graphic Modes

<center> <table class="dovstable">

     <caption>Graphics Modes</caption>
 
      <tr><th colspan="5" class="innerHeader">Main 2D Engine</th></tr>
      <tr style="bold">
       <td class="dtMode">Mode</td>
       <td class="dtBG0">BG0</td>
       <td class="dtBG1">BG1</td>
       <td class="dtBG2">BG2</td>
       <td class="dtBG3">BG3</td>
      </tr>
    
      <tr >
       <td class="dtMode">Mode 0</td>
       <td class="dtBG0">Text/3D</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Text</td>
       <td class="dtBG3">Text</td>
      </tr>
      
      <tr >
       <td class="dtMode">Mode 1</td>
       <td class="dtBG0">Text/3D</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Text</td>
       <td class="dtBG3">Rotation</td>
      </tr>

<tr >

       <td class="dtMode">Mode 2</td>
       <td class="dtBG0">Text/3D</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Rotation</td>
       <td class="dtBG3">Rotation</td>
      </tr>

<tr >

       <td class="dtMode">Mode 3</td>
       <td class="dtBG0">Text/3D</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Text</td>
       <td class="dtBG3">Extended</td>
      </tr>

<tr >

       <td class="dtMode">Mode 4</td>
       <td class="dtBG0">Text/3D</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Rotation</td>
       <td class="dtBG3">Extended</td>
      </tr>

<tr >

       <td class="dtMode">Mode 5</td>
       <td class="dtBG0">Text/3D</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Extended</td>
       <td class="dtBG3">Extended</td>
      </tr>

<tr >

       <td class="dtMode">Mode 6</td>
       <td class="dtBG0">3D</td>
       <td class="dtBG1">-</td>
       <td class="dtBG2">Large Bitmap</td>
       <td class="dtBG3">-</td>
      </tr>

<tr >

       <td  class="dtMode">Frame Buffer</td>
       <td colspan="4" class="dtBG0">Direct VRAM display as a bitmap</td>
       </tr>
      
      <tr><th colspan="5" class="innerHeader">Sub 2D Engine</th></tr>
      <tr style="bold">
       <td class="dtMode" >Mode</td>
       <td class="dtBG0">BG0</td>
       <td class="dtBG1">BG1</td>
       <td class="dtBG2">BG2</td>
       <td class="dtBG3">BG3</td>
      </tr>
       <tr >
       <td class="dtMode">Mode 0</td>
       <td class="dtBG0">Text</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Text</td>
       <td class="dtBG3">Text</td>
      </tr>
      
      <tr >
       <td class="dtMode">Mode 1</td>
       <td class="dtBG0">Text</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Text</td>
       <td class="dtBG3">Rotation</td>
      </tr>

<tr >

       <td class="dtMode">Mode 2</td>
       <td class="dtBG0">Text</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Rotation</td>
       <td class="dtBG3">Rotation</td>
      </tr>

<tr >

       <td class="dtMode">Mode 3</td>
       <td class="dtBG0">Text</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Text</td>
       <td class="dtBG3">Extended</td>
      </tr>

<tr >

       <td class="dtMode">Mode 4</td>
       <td class="dtBG0">Text</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Rotation</td>
       <td class="dtBG3">Extended</td>
      </tr>

<tr >

       <td class="dtMode">Mode 5</td>
       <td class="dtBG0">Text</td>
       <td class="dtBG1">Text</td>
       <td class="dtBG2">Extended</td>
       <td class="dtBG3">Extended</td>
      </tr>

</table> </center>

There are 8 graphics modes for the MAIN engine and 6 graphics modes for the SUB. Each graphics mode allows you to configure the available background layers as depicted on the above chart. As you can see MAIN has a few more features.

To enable 3D on the MAIN engine you specify MODE_blah_3D. This will allow background 0 to be used as a 3D layer. libnds includes a decent openGLish wrapper for accessing 3D features. Although you can only render 3D with the main engine it is possible to render it off-screen and use that rendered image to drive the SUB display. The effect of this is 3D on both screens at half the frame rate.

Libnds provides a small macro for configuring graphics modes. videoSetMode() and videoSetModeSub() take arguments which determine not only the mode but which backgrounds are turned on.

<cpp> videoSetMode(MODE_5_2D | DISPLAY_BG2_ACTIVE | DISPLAY_BG3_ACTIVE); videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE); </cpp>

The effect of these two calls is to place the MAIN engine into mode 5 2D and enable (turn on, activate, whatever) “Extended Rotation” backgrounds 2 and 3. It then places the SUB engine into mode 0 and activates “Text” background 0.

Recall that MAIN and SUB have nothing to do with TOP and BOTTOM so to ensure you are rendering to the correct screen you must assign the engines appropriately.

<cpp> lcdMainOnTop(); //MAIN renders to top screen SUB to bottom lcdMainOnBottom(); //SUB renders to top screen MAIN to bottom lcdSwap(); //swap the screens the egines were rendering to </cpp>

[edit] Background Types

We have six types of backgrounds:

  • framebuffer - The framebuffer is the simplest background. Here we manipulate every pixel on our own. We have a region of memory which gets printed to the screen directly. It is 256*192 pixels in size and has 16 bit/pixel color (5 bits red, green and blue - bit 15 gets ignored).
  • 3D - We paint to a 3D background with OpenGL like commands so we can not manipulate the pixels of the screen directly.
  • text - A text background (a.k.a. a tile background) is divided into small blocks of 8x8 pixels. We can say what these tiles should look like and what tile should get printed in a block. The largest amount of tiles that this mode supports is 64x64 tiles (512x512 pixels). Maps are arranged in 32x32 blocks(i.e. when using BG_64x64 the first forth of the map defines a 32x32 chunk of the map in the top left).
  • rotation - Similar to text backgrounds but you can also scale and rotate these layers. Rotation backgrounds support up to 128x128 tiles (1024x1024 pixels) and use 8 bit maps instead of 16 bit maps like text backgrounds. Rotation maps are arranged sequentially.
  • extended rotation - Can be used like the framebuffer but also supports 8 bit images. The size of the buffers can be smaller or bigger that the actual resolution, but we can scroll, zoom, rotate etc. these very easily in hardware. If you use 16 bits per pixel, bit 15 will be the alpha bit.
  • large bitmap - A large 512*1024 or 1024*512 pixel image with 8 bit/pixel (this is already 512KB, so we will need VRAM banks A-D!).


Text Variants
Resolution Defined Map Size Layout
256x256 BG_32x32 2 KiB 32x32
256x512 BG_32x64 4 KiB 32x64
512x256 BG_64x32 4 KiB (32x32)+(32x32)
512x512 BG_64x64 8 KiB (32x32)+(32x32)+(32x32)+(32x32)


Rotation Variants
Resolution Defined Map Size Layout
128x128 BG_RS_16x16 256 Bytes 16x16
256x256 BG_RS_32x32 1 KiB 32x32
512x512 BG_RS_64x64 4 KiB 64x64
1024x1024 BG_RS_128x128 16KiB 128x128


Extended Rotation Variants
Resolution Size @ 8bit/pixel Size @ 16bit/pixel
128x128 16 KiB

BG_BMP8_128x128

32 KiB

BG_BMP16_128x128

256x256 64 KiB

BG_BMP8_256x256

128 KiB

BG_BMP16_256x256

512x256 128 KiB

BG_BMP8_512x256

256 KiB

BG_BMP16_512x256

512x512 256 KiB

BG_BMP8_512x512

512 KiB

BG_BMP16_512x512

(How to use these defines (BG_BMP8_512x512, etc.) will be explained later)

[edit] VRAM

VRAM
bank control register size what it can be used for
VRAM

VRAM_A

VRAM_A_CR 128 KiB
VRAM_A_LCD
VRAM_A_MAIN_BG_0x6000000 = VRAM_A_MAIN_BG
VRAM_A_MAIN_BG_0x6020000
VRAM_A_MAIN_BG_0x6040000
VRAM_A_MAIN_BG_0x6060000
VRAM_A_MAIN_SPRITE
VRAM_A_TEXTURE_SLOT0 = VRAM_A_TEXTURE
VRAM_A_TEXTURE_SLOT1
VRAM_A_TEXTURE_SLOT2
VRAM_A_TEXTURE_SLOT3
VRAM_B VRAM_B_CR 128 KiB
VRAM_B_LCD
VRAM_B_MAIN_BG_0x6000000
VRAM_B_MAIN_BG_0x6020000 = VRAM_B_MAIN_BG
VRAM_B_MAIN_BG_0x6040000
VRAM_B_MAIN_BG_0x6060000
VRAM_B_MAIN_SPRITE
VRAM_B_TEXTURE_SLOT0
VRAM_B_TEXTURE_SLOT1 = VRAM_B_TEXTURE
VRAM_B_TEXTURE_SLOT2
VRAM_B_TEXTURE_SLOT3
VRAM_C VRAM_C_CR 128 KiB
VRAM_C_LCD
VRAM_C_MAIN_BG_0x6000000
VRAM_C_MAIN_BG_0x6020000
VRAM_C_MAIN_BG_0x6040000 = VRAM_C_MAIN_BG
VRAM_C_MAIN_BG_0x6060000
VRAM_C_ARM7
VRAM_C_SUB_BG_0x6200000 = VRAM_C_SUB_BG
VRAM_C_SUB_BG_0x6220000
VRAM_C_SUB_BG_0x6240000
VRAM_C_SUB_BG_0x6260000
VRAM_C_TEXTURE_SLOT0
VRAM_C_TEXTURE_SLOT1
VRAM_C_TEXTURE_SLOT2 = VRAM_C_TEXTURE
VRAM_C_TEXTURE_SLOT3
VRAM_D VRAM_D_CR 128 KiB
VRAM_D_LCD
VRAM_D_MAIN_BG_0x6000000
VRAM_D_MAIN_BG_0x6020000
VRAM_D_MAIN_BG_0x6040000
VRAM_D_MAIN_BG_0x6060000 = VRAM_D_MAIN_BG
VRAM_D_ARM7
VRAM_D_SUB_SPRITE
VRAM_D_TEXTURE_SLOT0
VRAM_D_TEXTURE_SLOT1
VRAM_D_TEXTURE_SLOT2
VRAM_D_TEXTURE_SLOT3 = VRAM_D_TEXTURE
VRAM_E VRAM_E_CR 64 KiB
VRAM_E_LCD
VRAM_E_MAIN_BG
VRAM_E_MAIN_SPRITE
VRAM_E_TEX_PALETTE
VRAM_E_BG_EXT_PALETTE
VRAM_E_OBJ_EXT_PALETTE
VRAM_F VRAM_F_CR 16 KiB
VRAM_F_LCD
VRAM_F_MAIN_BG
VRAM_F_MAIN_SPRITE
VRAM_F_TEX_PALETTE
VRAM_F_BG_EXT_PALETTE
VRAM_F_OBJ_EXT_PALETTE
VRAM_G VRAM_G_CR 16 KiB
VRAM_G_LCD
VRAM_G_MAIN_BG
VRAM_G_MAIN_SPRITE
VRAM_G_TEX_PALETTE
VRAM_G_BG_EXT_PALETTE
VRAM_G_OBJ_EXT_PALETTE
VRAM_H VRAM_H_CR 32 KiB
VRAM_H_LCD
VRAM_H_SUB_BG
VRAM_H_SUB_BG_EXT_PALETTE
VRAM_I VRAM_I_CR 16 KiB
VRAM_I_LCD
VRAM_I_SUB_BG
VRAM_I_SUB_SPRITE
VRAM_I_SUB_SPRITE_EXT_PALETTE

Now we have to tell our DS which VRAM banks it should use. The 656 KB VRAM are accessable as nine banks with different sizes and purposes. If we need a bigger block of VRAM we can use multiple banks together. These banks are available.

Note: VRAM is an alias for VRAM_A, not an extra bank. To use VRAM banks, we have to map them to special adresses begining at 0x06000000.

We have ten functions to set VRAM banks:

 void vramSetBankA(VRAM_A_TYPE a);
 (...)
 void vramSetBankI(VRAM_I_TYPE i);
 uint32 vramSetMainBanks(VRAM_A_TYPE a, VRAM_B_TYPE b, VRAM_C_TYPE c, VRAM_D_TYPE d);

vramSetMainBanks(a,b,c,d); does the same as vramSetBankA(a); vramSetBankB(b); vramSetBankC(c); vramSetBankD(d); but gives you the previously used config as a return parameter. This way you can easily restore the first four banks with

 void vramRestoreMainBanks(uint32 vramTemp);

Note: void vramRestorMainBanks(uint32 vramTemp); has been deprecated.

The VRAM_X_TYPE values are printed in the last column of the table. But what do these values mean?

  • VRAM_X_LCD: This is used for 3D and framebuffer mode.
  • VRAM_X_MAIN_BG_0x60n0000: Use this VRAM for the main screen. If we want 256 KiB, we have to map one screen to 0x6000000 and one to 0x6020000.
  • VRAM_X_SUB_BG_0x62n0000: Same with the sub screen.
  • VRAM_X_MAIN_SPRITE: Use this VRAM for sprites. It is mapped to 0x06400000 for bank A, 0x06420000 for bank B etc. up to bank D.
  • VRAM_X_SUB_SPRITE: Same with the sub screen at offset 0x06600000 to 0x06660000 for bank A to D.
  • VRAM_X_TEXTURE_SLOTn:
  • VRAM_X_ARM7:
  • VRAM_X_TEX_PALETTE:
  • VRAM_X_BG_EXT_PALETTE:
  • VRAM_X_SUB_BG_EXT_PALETTE:
  • VRAM_X_OBJ_EXT_PALETTE:
  • VRAM_X_SUB_SPRITE_EXT_PALETTE:

[edit] Background Control Register

[edit] One CR For Each Background

The DS has eight background control registers; one for each background on the main and sub screen. They are called BGn_CR for the main screen and SUB_BGn_CR for the sub screen. BG_CR is an alias for BG0_CR and the same goes with the sub screen: SUB_BG_CR = SUB_BG0_CR. We use these registers to tell the DS where it can find the content of a background and what image format there will be. Let's look at an example:

 videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
 vramSetBankA(VRAM_A_MAIN_BG_0x6000000);
 BG3_CR = BG_BMP16_256x256 | BG_WRAP_ON;

We use MODE_5 on the main screen but we only need background 3 (extended rotation). Then we map VRAM bank A to the adress 0x6000000 so the main screen can use it. In the last line we tell the DS that background 3 is a 16 bit bitmap of size 256*256 pixels and will wrap around.

[edit] Parameters For The CR

Here is a list of parameters for BGn_CR:

  • BG_{32x32|32x64|64x32|64x64}; used for text backgrounds
  • BG_RS_{16x16|32x32|64x64|128x128}; used for rotation backgrounds
  • BG_BMP{8|16}_{128x128|256x256|512x256|512x512}: extended rotation background variants, bit per pixel and resolution
  • BG_BMP8_1024x512 and BG_BMP8_512x1024: is used only for MODE 6
  • BG_WRAP_ON: if you scroll to the end of the image, it will wrap. This way, you can "scroll forever".
  • BG_PRIORITY(n) or BG_PRIORITY_n: the priority of the background: 0 is the highest priority, 3 the lowest. A background with a higher priority will be printed on top of backgrounds with lower priorities. If there is a sprite with the same priority, it will be printed on top of the background.
  • BG_MOSAIC_ON: You have to set this flag if you want to use the mosaic effect (see below).
  • BG_TILE_BASE(n): each tile-block is 16KB. This parameter selects, which block we want to use. For tile-based backgrounds only.
  • BG_MAP_BASE(n): each map-block is 2KB. This parameter selects, which block we want to use. For tile-based backgrounds only.
  • BG_BMP_BASE(n): each bitmap-block is 16KB. This parameter selects, which block we want to use. For bitmap backgrounds only.

Here are defines that give you the addresses of the blocks:

  • BG_TILE_RAM(n): main screen only! We have 16 blocks of RAM for tile data, each 16KB big, starting at 0x6000000. This define gives you the direct address of the block.
  • BG_TILE_RAM_SUB(n): sub screen only! We have 16 blocks of RAM for tile data, each 16KB big, starting at 0x6200000. This define gives you the direct address of the block.
  • BG_MAP_RAM(n): main screen only! We have 32 blocks of RAM for tile data, each 2KB big, starting at 0x6000000. This define gives you the direct address of the block.
  • BG_MAP_RAM_SUB(n): sub screen only! We have 32 blocks of RAM for tile data, each 2KB big, starting at 0x6200000. This define gives you the direct address of the block.
  • BG_BMP_RAM(n): main screen only! We have 16 blocks of RAM for bitmap data, each 16KB big, starting at 0x6000000. This parameter selects, wich block we want to use.
  • BG_BMP_RAM_SUB(n): sub screen only! We have 16 blocks of RAM for bitmap data, each 16KB big, starting at 0x6200000. This define gives you the direct address of the block.

[edit] Additional Register For Each Background

We have some more registers:

  • BGn_X0: this controls where the left origin of the screen maps to the background
  • BGn_Y0: this controls where the top of the screen maps to the background

With n = 0,1,2 or 3. If we use an extended rotation background we have even more registers:

  • BGn_XDX: this controls the x-axis scaling, it's a 0.8.8 fixed point number. If you don't want to scale at all, set it to 1.0 (which is 1 << 8). Increase the value to "zoom out." F0or example, 2.0 (1 << 9) will show the background at half its width.
  • BGn_XDY: this is for rotating and shearing
  • BGn_YDX: this is for rotating and shearing
  • BGn_YDY: this controls the y-axis scaling and works the same as BGn_XDX.
  • BGn_CX: this controls where the left origin of the screen maps to the background (in 0.8.8 fixed point, too).
  • BGn_CY: this controls where the top of the screen maps to the background (in 0.8.8 fixed point, too).

With n = 2 or 3 and the same for the sub screen (SUB_BG2_X0 etc.).

When using a rotation background or extended rotation background the BGn_CX and BGn_CY registers replace BGn_X0 and BGn_Y0.

[edit] Special Registers

We have some more registers which are not specific for one background:

  • MOSAIC_CR / SUB_MOSAIC_CR: This controlls the mosaic effect (looks like bigger pixels). You have to enable the effect first for the background. The lower 4 bit define the mosaic size of the X-axis; bit 4-7 define the mosaic size of the Y-axis.
  • BLEND_CR / SUB_BLEND_CR: This register defines what backgrounds we want to blend or what background we want to fade to white/black (see examples below).
  • BLEND_AB / SUB_BLEND_AB: If we blend two backgrounds, bits 0-4 will define the blending coefficient of background A and bits 8-12 will define the blending coefficient of background B. The rest of this 16 bit register seems to be unused. For a 50/50 blending you will just say: BLEND_AB = 0x0F | (0x0F << 8);
  • BLEND_Y / SUB_BLEND_Y: If we fade a background to white/black, the lowest 5 bits of this register tell the DS how much white/black we want. 0x00 is the background, 0x1F is white/black.

Examples:

 // blend BG2 and BG3 on the main screen
 BLEND_CR = BLEND_ALPHA | BLEND_SRC_BG2 | BLEND_DST_BG3;
 // fade BG2 to black on the sub screen
 SUB_BLEND_CR = BLEND_FADE_BLACK | BLEND_SRC_BG2;

We have the following blending defines:

  • BLEND_NONE: no blending
  • BLEND_ALPHA: blend two backgrounds
  • BLEND_FADE_WHITE: fade to white
  • BLEND_FADE_BLACK: fade to black
  • BLEND_SRC_BGn: (n = 0,1,2,3) which background will be the source
  • BLEND_SRC_SPRITE:
  • BLEND_SRC_BACKDROP:
  • BLEND_DST_BGn: (n = 0,1,2,3) which background will be the destination
  • BLEND_DST_SPRITE:
  • BLEND_DST_BACKDROP:

Back to our registers:

  • WINn_X0 / SUB_WINn_X0: (n = 0,1)
  • WINn_X1 / SUB_WINn_X1: (n = 0,1)
  • WINn_Y0 / SUB_WINn_Y0: (n = 0,1)
  • WINn_Y1 / SUB_WINn_Y1: (n = 0,1)
  • WIN_IN / SUB_WIN_IN:
  • WIN_OUT / SUB_WIN_OUT:

[edit] Display Capture

There is a 32 bit display capture control register DISP_CAPTURE and the following parameters:

  • DCAP_ENABLE BIT(31)
  • DCAP_MODE(n):
  • DCAP_DST(n):
  • DCAP_SRC(n):
  • DCAP_SIZE(n):
  • DCAP_OFFSET(n):
  • DCAP_BANK(n):
  • DCAP_B(n):
  • DCAP_A(n):

Here is an example of setting the capture register with comments

 // Comments taken from http://nocash.emubase.de/gbatek.htm#dsvideocaptureandmainmemorydisplaymode
 DISP_CAPTURE = DCAP_ENABLE |
 	DCAP_MODE(2) |	// Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
 	DCAP_DST(0) |	// VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
 	DCAP_SRC(0) |	// Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
 	DCAP_SIZE(3) |	// Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
 	DCAP_OFFSET(0)|	// VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
 	DCAP_BANK(2) |	// VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
 	DCAP_B(0) |	// EVB (0..16, or 0..31 ?) Blending Factor for Source A (or B ?)
 	DCAP_A(14);	// EVA (0..16, or 0..31 ?) Blending Factor for Source B (or A ?)
Dev-Scene (c) Ashley "MrShlee" Hull.