308. Console render framebuffer

Expose a full background+sprites framebuffer from Console.

Lesson 308 of 356 · tests/chapter_09_sprite_rendering/test_308_console_render_framebuffer.py

File to update

emulator/console.py

Why this step exists

Frontends should not know how to extract background memory, sprite OAM, sprite palette RAM, or sprite pattern tables separately. Console coordinates CPU/PPU systems, so it should expose one frontend-facing method:

console.render_framebuffer()

This method returns the current visible framebuffer using

background renderer
PPU.oam sprites
sprite palette RAM $3F10-$3F1F
sprite pattern table selected by PPUCTRL bit 3

Suggested implementation example

# Add this constant to the existing ppu_background_renderer import.
from emulator.rendering.ppu_background_renderer import PALETTE_RAM_ADDR


def render_framebuffer(self) -> Framebuffer:
    background = self.render_background_framebuffer()

    sprite_palette_start = PALETTE_RAM_ADDR + 16
    sprite_palette_ram = bytes(
        self.ppu.ppu_bus.read(sprite_palette_start + offset)
        for offset in range(16)
    )
    sprite_palettes = build_sprite_palettes_from_palette_ram(sprite_palette_ram)

    pattern_table_base = (
        PATTERN_TABLE_1_ADDR
        if self.ppu.ctrl & CTRL_SPRITE_PATTERN_TABLE
        else PATTERN_TABLE_0_ADDR
    )

    pattern_table = bytes(
        self.ppu.ppu_bus.read(pattern_table_base + offset)
        for offset in range(0x1000)
    )

    return composite_background_and_sprites(
        background=background,
        oam=self.ppu.oam,
        pattern_table=pattern_table,
        sprite_palettes=sprite_palettes,
    )

Important boundary

Console may call pure rendering helpers. Console must not import pygame.

Out of scope

  • sprite 0 hit
  • sprite overflow
  • 8x16 sprites
  • sprite/background priority bit behavior
  • pygame display

Run this lesson

uv run pytest tests/chapter_09_sprite_rendering/test_308_console_render_framebuffer.py -v