⚠️ Clean-Room / Educativo

Este proyecto es educativo y Open Source. No se copia código de otros emuladores. Implementación basada únicamente en documentación técnica y tests permitidas.

Optimización Big Blit y Depuración de Inputs

Fecha: 2025-12-18 Step ID: 0089 Estado: Verified

Resumen

Implementación de la optimización "Big Blit" para mejorar el rendimiento del renderizado desde 48 FPS a 60 FPS objetivo. La optimización mantiene un buffer persistente de 256x256 píxeles y solo lo reconstruye cuando es necesario, reduciendo las llamadas a blit de 360 por frame a solo 1-4. También se añadió logging de debug para eventos de teclado para diagnosticar problemas de inputs que causaban "Game Over" inmediato en Tetris.

Concepto de Hardware

El renderizado del Background en Game Boy funciona dibujando un tilemap completo de 32x32 tiles (256x256 píxeles) y luego recortando la ventana visible de 160x144 píxeles usando los registros SCX y SCY (Scroll X/Y).

Optimización Big Blit: En lugar de redibujar todos los tiles del tilemap en cada frame (1024 tiles = 1024 blits), mantenemos un buffer persistente que solo se reconstruye cuando:

  • Los tiles de VRAM cambian (marcados como dirty)
  • La paleta BGP cambia
  • El tilemap base cambia

Esto reduce drásticamente el coste de renderizado porque solo hacemos 1-4 blits del buffer completo al framebuffer final, en lugar de 360 blits individuales por frame.

Input Debug: Los eventos de teclado (KEYDOWN/KEYUP) deben procesarse correctamente para que los botones del joypad se activen y desactiven adecuadamente. Si un KEYUP no se procesa, el botón queda "pegado" en estado pulsado, causando que las piezas caigan instantáneamente en juegos como Tetris.

Implementación

Se implementó un sistema de tracking de cambios en el renderer para determinar cuándo el bg_buffer necesita reconstrucción. Se añadió el flag bg_buffer_dirty y el tracking de la última paleta usada (_last_bgp).

Componentes creados/modificados

  • src/gpu/renderer.py:
    • Añadido bg_buffer_dirty flag para tracking de cambios
    • Añadido _last_bgp para detectar cambios de paleta
    • Modificado render_frame() para reconstruir bg_buffer solo cuando es necesario
    • Modificado mark_tile_dirty() para marcar bg_buffer como dirty
  • src/viboy.py:
    • Añadido logging de debug para eventos KEYDOWN/KEYUP en _handle_pygame_events()
    • Los logs muestran qué tecla se presiona/suelta y a qué botón se mapea

Decisiones de diseño

Reconstrucción completa vs incremental: Se eligió reconstruir el bg_buffer completo cuando hay cambios en lugar de actualizar solo los tiles afectados. Esto es más simple de implementar y sigue siendo mucho más rápido que redibujar cada frame, porque solo reconstruimos cuando hay cambios reales (tiles modificados o paleta cambiada).

Logging de debug: Se añadió logging a nivel DEBUG para eventos de teclado para ayudar a diagnosticar problemas de inputs. Los logs se pueden activar configurando el nivel de logging a DEBUG.

Archivos Afectados

  • src/gpu/renderer.py - Optimización Big Blit con tracking de cambios
  • src/viboy.py - Logging de debug para eventos de teclado

Tests y Verificación

Rendimiento: Se probó con Tetris (ROM aportada por el usuario, no distribuida) para verificar que el rendimiento mejora de 48 FPS a 60 FPS objetivo. El uso de CPU también debería reducirse significativamente.

Inputs: Los logs de debug permitirán verificar que los eventos KEYDOWN y KEYUP se procesan correctamente. Si un botón queda "pegado", los logs mostrarán que falta un KEYUP correspondiente.

Comando de prueba: python main.py tetris.gb

Logging activado: Para activar los logs de debug, configurar el nivel de logging a DEBUG antes de ejecutar:

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

Fuentes Consultadas

  • Pan Docs: Background Tile Map, Scroll Registers (SCX/SCY)
  • Implementación basada en optimizaciones comunes de renderizado 2D: mantener buffers persistentes y solo actualizar cuando hay cambios.

Integridad Educativa

Lo que Entiendo Ahora

  • Big Blit: Mantener un buffer persistente y solo reconstruirlo cuando hay cambios es una optimización estándar en renderizado 2D. Reduce drásticamente el número de operaciones gráficas por frame.
  • Input Handling: Los eventos de teclado deben procesarse en parejas (KEYDOWN + KEYUP) para que el estado del joypad sea correcto. Si falta un KEYUP, el botón queda en estado pulsado permanentemente.

Lo que Falta Confirmar

  • Rendimiento real: Necesita verificarse en ejecución real con Tetris para confirmar que se alcanza 60 FPS.
  • Causa del Game Over inmediato: Los logs de debug ayudarán a identificar si el problema es inputs "pegados" o alguna otra causa.

Hipótesis y Suposiciones

Hipótesis: El problema de "Game Over" inmediato en Tetris se debe a inputs que quedan "pegados" (faltan eventos KEYUP). Los logs de debug confirmarán o refutarán esta hipótesis.

Suposición: La optimización Big Blit será suficiente para alcanzar 60 FPS en un PC high-end (i7-10700K + RTX 2080 Ti). Si no es suficiente, será necesario migrar a Cython para v0.0.2.

Próximos Pasos

  • [ ] Verificar rendimiento real con Tetris (objetivo: 60 FPS)
  • [ ] Analizar logs de debug para diagnosticar problemas de inputs
  • [ ] Si los inputs siguen fallando, implementar sistema de tracking de teclas múltiples para manejar correctamente cuando múltiples teclas mapean al mismo botón
  • [ ] Si el rendimiento sigue siendo insuficiente, planificar migración a Cython para v0.0.2
  • [ ] Cerrar v0.0.1 con esta optimización