314. Console passes background opaque mask

Wire Console.render_framebuffer() to pass the background opacity mask.

Lesson 314 of 356 · tests/chapter_09_sprite_rendering/test_314_console_passes_background_opaque_mask.py

File to update

emulator/console.py

Why this step exists

The sprite renderer can now apply sprite priority bit 5 when it receives a BackgroundOpaqueMask. Step 313 added the PPU-level helper:

ppu_background_to_opaque_mask(ppu)

This step connects that helper to the full-frame render path.

Required behavior

Console.render_framebuffer()
    -> render background framebuffer
    -> call ppu_background_to_opaque_mask(self.ppu)
    -> build sprite palettes
    -> select sprite pattern table with PPUCTRL bit 3
    -> call composite_background_and_sprites(..., background_opaque_mask=mask)

Example implementation fragment

from emulator.rendering.ppu_background_renderer import (
    ppu_background_to_framebuffer,
    # --- ADD THIS NEW IMPORT ---
    ppu_background_to_opaque_mask,
    PATTERN_TABLE_0_ADDR,
    PATTERN_TABLE_1_ADDR,
)


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

    # --- ADD THIS NEW LINE ---
    background_opaque_mask = ppu_background_to_opaque_mask(self.ppu)

    ...

    return composite_background_and_sprites(
        background=background,
        oam=self.ppu.oam,
        pattern_table=pattern_table,
        sprite_palettes=sprite_palettes,
        # --- ADD THIS NEW LINE ---
        background_opaque_mask=background_opaque_mask,
    )

Important boundary

Console should orchestrate helpers. It should not duplicate the background nametable/pattern-table extraction that belongs to ppu_background_renderer.py.

Out of scope

  • adding another background mask algorithm
  • changing ppu_background_to_opaque_mask()
  • sprite 0 hit
  • sprite overflow
  • pygame

Run this lesson

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