Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Green Low Bit (grn_lo)

The GBA colour word is often described as 15-bit colour (R5G5B5), but bit 15 is not always inert.

What bit 15 is

Bit:  15      14-10  9-5    4-0
      grn_lo  Blue   Green  Red

grn_lo is the low bit of an internal 6-bit green path used by colour special effects.

  • Without blending effects, grn_lo is not visibly distinguishable.
  • With brighten/darken/alpha effects enabled, the hardware pipeline can use that extra green precision.
  • Some emulators still treat bit 15 as unused, so they render colours as if grn_lo does not exist.

Demo: hidden text using grn_lo

This demo draws two colours that differ only by bit 15, then enables brightness increase. On hardware, the hidden text becomes visible; on many emulators, it stays flat/invisible.

#include <gba/video>

static constexpr unsigned char glyphs[][5] = {
    {0b101, 0b101, 0b111, 0b101, 0b101}, // H
    {0b111, 0b100, 0b111, 0b100, 0b111}, // E
    {0b100, 0b100, 0b100, 0b100, 0b111}, // L
    {0b100, 0b100, 0b100, 0b100, 0b111}, // L
    {0b111, 0b101, 0b101, 0b101, 0b111}, // O
};

static void draw_glyph(int g, int px, int py, int scale, unsigned short color) {
    for (int row = 0; row < 5; ++row) {
        for (int col = 0; col < 3; ++col) {
            if (!(glyphs[g][row] & (4 >> col))) continue;
            for (int sy = 0; sy < scale; ++sy)
                for (int sx = 0; sx < scale; ++sx)
                    gba::mem_vram[(px + col * scale + sx) + (py + row * scale + sy) * 240] = color;
        }
    }
}

int main() {
    gba::reg_dispcnt = {.video_mode = 3, .enable_bg2 = true};

    constexpr short base = 12 << 5;                     // green=12
    constexpr unsigned short hidden = base | (1 << 15); // green=12, grn_lo=1

    for (int i = 0; i < 240 * 160; ++i) gba::mem_vram[i] = base;

    constexpr int scale = 6, ox = (240 - 19 * scale) / 2, oy = (160 - 5 * scale) / 2;
    for (int i = 0; i < 5; ++i) draw_glyph(i, ox + i * 4 * scale, oy, scale, hidden);

    // Brightness increase on BG2 - hardware processes the full 6-bit
    // green channel, revealing the hidden text on real hardware
    gba::reg_bldcnt = {.dest_bg2 = true, .blend_op = gba::blend_op_brighten};
    using namespace gba::literals;
    gba::reg_bldy = 0.25_fx;

    for (;;) {}
}

Comparison screenshots

PlatformResultScreenshot
mGBA (0.11-8996-6a99e17f5)Text is invisiblemGBA screenshot - word is invisible
Analogue Pocket (FPGA)Text is faintly visibleAnalogue Pocket screenshot - word is faintly visible
Real GBA hardwareText is visibleReal GBA hardware - word is visible

Practical guidance

  • For normal palette authoring, treat colours as 15-bit.
  • If you rely on hardware colour effects and exact output parity, test on real hardware (or FPGA implementations that model this behaviour).
  • Keep this behaviour in mind when debugging “looks different on emulator vs hardware” reports.