⚠️ 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.

Activación de Renderizado Real (Background C++)

Fecha: 2025-12-19 Step ID: 0119 Estado: Verified

Resumen

El enlace de video C++ → Python funciona correctamente (se confirmó con la pantalla gris y el punto rojo a 60 FPS). Se eliminó el código de diagnóstico (pantalla gris y píxel rojo) del constructor de la PPU C++ y se activó el renderizado real del Background. El framebuffer ahora se inicializa a blanco (0xFFFFFFFF) y el método `render_scanline()` renderiza los tiles del juego real desde VRAM cuando la PPU entra en H-Blank (Mode 0).

Concepto de Hardware

Renderizado Scanline en Game Boy: La PPU renderiza la pantalla línea por línea (scanline rendering). Cada línea visible (0-143) pasa por 4 modos:

  • Mode 2 (OAM Search): 0-79 ciclos - La PPU busca sprites que intersectan con la línea actual
  • Mode 3 (Pixel Transfer): 80-251 ciclos - La PPU transfiere datos de tiles desde VRAM
  • Mode 0 (H-Blank): 252-455 ciclos - La PPU renderiza la línea completa en el framebuffer
  • Mode 1 (V-Blank): Líneas 144-153 - Período de retrazo vertical, no se renderiza

Renderizado de Background: Durante el H-Blank (Mode 0), la PPU lee el tilemap desde VRAM (0x9800-0x9BFF o 0x9C00-0x9FFF), decodifica los tiles desde Tile Data (0x8000-0x8FFF o 0x8800-0x97FF), aplica el scroll (SCX/SCY) y la paleta BGP, y escribe los 160 píxeles de la línea actual en el framebuffer.

Inicialización del Framebuffer: El framebuffer debe inicializarse a un color por defecto (blanco) antes de que la PPU comience a renderizar. Si se deja sin inicializar o se inicializa a un color de diagnóstico (gris), los juegos mostrarán colores incorrectos o pantallas de prueba en lugar del contenido real.

Fuente: Pan Docs - LCD Timing, Background, Tile Data, 2bpp Format

Implementación

Se realizaron los siguientes cambios en `src/core/cpp/PPU.cpp`:

1. Limpieza del Código de Diagnóstico

Se eliminó el código de diagnóstico que pintaba la pantalla de gris y un píxel rojo:

  • Constructor: Cambió la inicialización del framebuffer de gris (`0xFF808080`) a blanco (`0xFFFFFFFF`)
  • Constructor: Eliminó la línea que pintaba el píxel rojo de diagnóstico (`framebuffer_[0] = 0xFFFF0000`)

2. Verificación de Lógica de Renderizado

Se verificó que la lógica de renderizado funciona correctamente:

  • Método `step()`: Llama a `render_scanline()` cuando la PPU entra en Mode 0 (H-Blank) y la línea es visible (LY < 144)
  • Método `render_scanline()`: Renderiza Background, Window y Sprites en el orden correcto
  • Método `render_bg()`: Lee VRAM, aplica scroll (SCX/SCY), decodifica tiles 2bpp y aplica paleta BGP

Componentes modificados

  • src/core/cpp/PPU.cpp - Constructor: Inicialización del framebuffer a blanco, eliminación de código de diagnóstico

Decisiones de diseño

Color de inicialización: Se eligió blanco (0xFFFFFFFF) como color por defecto porque es el color 0 de la paleta BGP estándar (0xE4), que corresponde a "transparente" o "blanco" en la mayoría de juegos. Si un tile no se renderiza correctamente, aparecerá blanco en lugar de gris, lo que facilita la depuración.

Sin cambios en la lógica de renderizado: La lógica de renderizado ya estaba implementada correctamente en pasos anteriores. Solo se necesitaba eliminar el código de diagnóstico para activar el renderizado real.

Archivos Afectados

  • src/core/cpp/PPU.cpp - Limpieza de código de diagnóstico, inicialización del framebuffer a blanco

Tests y Verificación

Se ejecutaron los tests de renderizado para asegurar que la limpieza del código de diagnóstico no rompió la funcionalidad:

$ python -m pytest tests/test_core_ppu_rendering.py -v

============================= test session starts =============================
platform win32 -- Python 3.13.5, pytest-9.0.2, pluggy-1.6.0
collected 4 items

tests/test_core_ppu_rendering.py::TestCorePPURendering::test_bg_rendering_simple_tile PASSED [ 25%]
tests/test_core_ppu_rendering.py::TestCorePPURendering::test_bg_rendering_scroll PASSED [ 50%]
tests/test_core_ppu_rendering.py::TestCorePPURendering::test_window_rendering PASSED [ 75%]
tests/test_core_ppu_rendering.py::TestCorePPURendering::test_framebuffer_memoryview PASSED [100%]

============================== 4 passed in 0.12s ==============================

Validación de módulo compilado C++: Todos los tests pasaron, confirmando que:

  • El renderizado de Background funciona correctamente
  • El scroll (SCX/SCY) se aplica correctamente
  • La Window se renderiza encima del Background
  • El framebuffer se expone correctamente como memoryview (Zero-Copy)

Test clave: `test_bg_rendering_simple_tile` verifica que un tile negro se renderiza correctamente en el framebuffer cuando se configura en VRAM y tilemap. Este test confirma que el renderizado real funciona.

Fuentes Consultadas

Integridad Educativa

Lo que Entiendo Ahora

  • Renderizado Scanline: La PPU renderiza línea por línea durante el H-Blank (Mode 0), no frame por frame. Esto es crítico para la sincronización con la CPU.
  • Inicialización del Framebuffer: El framebuffer debe inicializarse a un color por defecto (blanco) antes de que la PPU comience a renderizar. Los colores de diagnóstico (gris, rojo) deben eliminarse antes de activar el renderizado real.
  • Orden de Renderizado: Background → Window → Sprites. Este orden determina qué capa se dibuja encima de otra.

Lo que Falta Confirmar

  • Renderizado de Sprites: Los sprites se renderizan pero la lógica de prioridad puede necesitar ajustes. Verificar con juegos reales.
  • Window: La Window puede tener problemas de timing o posicionamiento en algunos juegos. Verificar con Tetris y otros juegos.

Hipótesis y Suposiciones

Color de inicialización: Se asume que blanco (0xFFFFFFFF) es un color seguro para inicializar el framebuffer. Si un juego muestra colores incorrectos, puede ser necesario inicializar a otro color o verificar la paleta BGP.

Próximos Pasos

  • [ ] Probar con ROMs reales (Tetris, Mario) para verificar que el renderizado funciona correctamente
  • [ ] Verificar que los sprites se renderizan correctamente (prioridad, transparencia, flip)
  • [ ] Optimizar el renderizado si es necesario (cacheo de tiles, optimización de bucles)
  • [ ] Implementar soporte para Game Boy Color (paletas CGB, VRAM Banks)