Video summary

Gameboy Emulator Development - Part 14

Main summary

Key takeaways

Technology

Summary of the video (Game Boy Emulator Dev – Part 14)

This installment continues the low-level Game Boy PPU/GPU pipeline work. After building the pixel FIFO background rendering in the previous part, the author now adds sprite support by:

  • implementing OAM (sprite attribute memory) scanning per scanline
  • building a small linked-list of sprites visible on the current line
  • extending the pixel FIFO to fetch sprite pixels (with priority, palettes, transparency, and x/y flipping)
  • loading sprite tile indices and pattern data for up to a limited number of sprites per FIFO window

1) OAM scan changes: build “sprites on this line”

The PPU switches into an OAM scan mode (described as mode 2) that reads sprite data for the current scanline. Key constraints noted:

  • Up to 10 sprites can be on a given line (hardware behavior).
  • OAM has 40 entries, but only visible ones are stored for the current line.

A new structure is created:

  • oam line entry: a linked-list node containing the sprite entry and a next pointer
  • stored inside the PPU context
  • includes:
    • line_sprite_count (0–10)
    • line_sprites (head pointer for linked list)
    • an line entry array[10] used as preallocated storage (avoids repeated malloc/free)
    • fetched_entry_count to manage how many sprites are currently being fetched into the FIFO for the next pixel chunk

2) load_line_sprites: scan OAM for sprites on current Y

The author adds a function like load_line_sprites that:

  • reads each OAM entry (looping through 40)
  • ignores non-visible sprites (checks an x-value condition; subtitles imply x==0 used as not visible)
  • checks Y overlap using sprite height and the current scanline:
    • if sprite lies within the current 8-bit scanline region, it is considered “on this line”
  • inserts the sprite entry into the linked list sorted by X order
    • ordering matters for correct game behavior

This scan happens when line_ticks == 1 (a simplified timing approximation rather than exact cycle-accurate emulation).


3) FIFO integration: fetching sprite pixels per 8-pixel chunk

The pixel FIFO is extended to blend sprites over the background.

New helper: fetch_sprite_pixels

A function is added conceptually to:

  • return a sprite-derived color for a given pixel bit position and sprite data
  • output includes:
    • color (U32)
    • uses bg_color as the fallback when sprite pixel is transparent

It handles:

  • x-offset + scroll x adjustment
  • bounds checking (only affects the current 8-pixel FIFO window)
  • x flipping:
    • chooses bit index reversed if flipped
  • extracts sprite pattern bytes:
    • high/low bits from two consecutive bytes (data0/data1 behavior)
  • transparency:
    • sprite pixel value 0 means “transparent”, so background shows through
  • priority vs background:
    • checks the “background priority” bit
    • if priority rules allow, sprite overwrites; otherwise may keep background
  • palette selection:
    • chooses between sprite palettes (subtitles mention correcting palette1 vs palette2)

Where it plugs in

In the FIFO “pixel rendering” stage:

  • color selection becomes conditional:
    • if background disabled → use background_color[0]
    • if sprites enabled → call fetch_sprite_pixels(...) to possibly override color

4) FIFO sprite data loading: pipeline_load_sprite_tile + pipeline_load_sprite_data

Before sprite pixel bits can be fetched, the FIFO needs to load the relevant sprite patterns.

pipeline_load_sprite_tile

  • iterates over the line_sprites linked list
  • computes sprite X for the current FIFO window:

    • spx = sprite_x - 8 + (scrollx % 8)
  • checks whether the sprite intersects the FIFO’s current 8-pixel section:

    • ensures spx and spx+8 overlap with [fetch_x, fetch_x+8)
  • adds matching sprites into a fetched_entries[] array-like region
  • enforces a maximum of 3 sprites per FIFO window:
    • stops when fetched_entry_count >= 3

pipeline_load_sprite_data

  • loads pattern bytes for each fetched sprite:
    • uses current LY and sprite height from LCDC
    • computes the correct tY for the scanline within the sprite
    • applies y-flip via reversing logic (subtitles describe reversing within sprite height)
    • computes tile index adjustments:
      • mentions a “trick” for 8x16/16px cases by masking bits
  • reads sprite tile pattern bytes from VRAM:
    • index * 16 + tY + offset for the two bitplanes (data0/data1)

5) Build fixes and correctness notes

The author notes build/setup fixes (e.g., includes string.h, forward declarations). Then small correctness fixes are made:

  • a missing continue in sprite loading logic (referred to as causing problems)
  • palette correction:
    • “palette one” vs “palette two” swap

6) Visual results and remaining work

After these changes:

  • sprites start appearing, including examples like:
    • Mario preview
    • hearts
    • jumping/pills
    • a spaceship/asteroids
  • however, some sprite sections are missing, attributed to the Game Boy Window feature:
    • the “window” rendering region isn’t implemented yet
    • expectation: once window handling is added, sprite rendering should fully match

Future steps mentioned

  • implement window
  • possibly implement gamepad/controller input
  • then support larger ROMs / different ROM types beyond ROM-only/simple cases

Main sources / speakers

  • Primary speaker/source: the channel host from “Low Level Devil” (narrating and writing the emulator code / implementing PPU + FIFO sprite support).

Original video