⚠️ Clean-Room / Educational

This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.

Big Blit Optimization and Input Debugging

Date:2025-12-18 StepID:0089 State: Verified

Summary

Implemented "Big Blit" optimization to improve rendering performance from 48 FPS to 60 FPS target. Optimization maintains a 256x256 persistent buffer pixels and only rebuilds it when necessary, reducing calls to 360 blit per frame only 1-4. Also added debug logging for keyboard events to Diagnose input problems that caused immediate "Game Over" in Tetris.

Hardware Concept

Background rendering on Game Boy works by drawing a complete tilemap of 32x32 tiles (256x256 pixels) and then cropping the visible window to 160x144 pixels using the SCX and SCY (Scroll X/Y) registers.

Big Blit Optimization:Instead of redrawing all the tiles in the tilemap in each frame (1024 tiles = 1024 blits), we maintain a persistent buffer that is only rebuilds when:

  • VRAM tiles change (marked as dirty)
  • BGP palette changes
  • The base tilemap changes

This drastically reduces the rendering cost because we only do 1-4 blits of the full buffer to the final framebuffer, instead of 360 individual blits per frame.

InputDebug:Keyboard events (KEYDOWN/KEYUP) must be processed correctly so that the joypad buttons activate and deactivate properly. If a KEYUP is not processed, the button becomes "stuck" in the pressed state, causing it to pieces fall instantly in games like Tetris.

Implementation

A change tracking system was implemented in the renderer to determine when the bg_buffer needs rebuilding. The flag was addedbg_buffer_dirtyand the tracking of the last used pallet (_last_bgp).

Components created/modified

  • src/gpu/renderer.py:
    • Addedbg_buffer_dirtyflag for tracking changes
    • Added_last_bgpto detect palette changes
    • Modifiedrender_frame()to rebuild bg_buffer only when necessary
    • Modifiedmark_tile_dirty()to mark bg_buffer as dirty
  • src/viboy.py:
    • Added debug logging for KEYDOWN/KEYUP events in_handle_pygame_events()
    • Logs show which key is pressed/released and which button it maps to

Design decisions

Full vs incremental rebuild:Chosen to rebuild the bg_buffer when there are changes instead of updating only the affected tiles. This is more simple to implement and is still much faster than redrawing each frame, because We only rebuild when there are real changes (modified tiles or changed palette).

Debug logging:Added DEBUG level logging for keyboard events to help diagnose input problems. Logs can be activated by configuring the logging level to DEBUG.

Affected Files

  • src/gpu/renderer.py- Big Blit optimization with change tracking
  • src/viboy.py- Debug logging for keyboard events

Tests and Verification

Performance:Tested with Tetris (user-contributed ROM, not distributed) to verify that performance improves from 48 FPS to 60 FPS target. CPU usage too should be significantly reduced.

Inputs:The debug logs will allow you to verify that the KEYDOWN and KEYUP are processed correctly. If a button is "stuck", the logs will show that it is missing a corresponding KEYUP.

Test command: python main.py tetris.gb

Logging activated:To activate debug logs, configure the level of logging to DEBUG before running:

import logging
logging.basicConfig(level=logging.DEBUG)

Sources consulted

  • Pan Docs: Background Tile Map, Scroll Registers (SCX/SCY)
  • Implementation based on common 2D rendering optimizations: maintaining buffers persistent and only update when there are changes.

Educational Integrity

What I Understand Now

  • Big Blit:Keep a persistent buffer and only rebuild it when there are changes it is a standard optimization in 2D rendering. Drastically reduces the number of graphic operations per frame.
  • Input Handling:Keyboard events must be processed in pairs (KEYDOWN + KEYUP) so that the joypad status is correct. If a KEYUP is missing, The button remains in a permanently pressed state.

What remains to be confirmed

  • Actual performance:Needs to be verified in real execution with Tetris to confirm that 60 FPS is reached.
  • Cause of immediate Game Over:The debug logs will help Identify if the problem is "stuck" inputs or some other cause.

Hypotheses and Assumptions

Hypothesis:The immediate "Game Over" problem in Tetris is due to inputs that remain "stuck" (KEYUP events are missing). The debug logs will confirm or will refute this hypothesis.

Assumption:Big Blit optimization will be enough to achieve 60 FPS on a high-end PC (i7-10700K + RTX 2080 Ti). If it is not enough, it will be necessary migrate to Cython for v0.0.2.

Next Steps

  • [ ] Check real performance with Tetris (goal: 60 FPS)
  • [ ] Analyze debug logs to diagnose input problems
  • [ ] If the inputs continue to fail, implement a multi-key tracking system to handle correctly when multiple keys map to the same button
  • [ ] If performance is still poor, plan to migrate to Cython for v0.0.2
  • [ ] Close v0.0.1 with this optimization