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.
Investigación de Rayas Verdes Recurrentes
Resumen
Investigación de por qué las rayas verdes vuelven a aparecer después de unos minutos de ejecución,
a pesar de la corrección implementada en el Step 0300. Se implementaron 3 monitores de diagnóstico
para rastrear el uso de paletas y cambios en el modo de renderizado, y se corrigió self.COLORS
que aún tenía valores verdes para el índice 0.
Objetivo: Identificar la causa raíz de las rayas verdes recurrentes y corregir cualquier código que use paletas con valores verdes en lugar de la paleta debug corregida.
Concepto de Hardware
Múltiples Fuentes de Paleta en el Renderer
El renderer puede usar múltiples fuentes de paleta durante la ejecución:
- Paleta debug (local): Variable local
palettedefinida enrender_frame()con valores corregidos (blanco para índice 0). - Paleta de clase (
self.palette): Atributo de instancia inicializado desdeself.COLORSque puede ser modificado durante la ejecución. - Paleta del hardware (BGP): Registro 0xFF47 que mapea índices a colores según la configuración del juego.
Si el renderer cambia entre diferentes fuentes de paleta, los colores pueden cambiar dinámicamente.
El problema identificado es que self.COLORS y self.palette aún tenían valores
verdes para el índice 0, lo que podría causar que algún código los use en lugar de la paleta debug local.
Fuente: Pan Docs - "Background Palette (BGP)", "Palette"
Modo C++ vs Modo Python
El renderer puede operar en dos modos:
use_cpp_ppu=True: Usa el framebuffer de C++ directamente (más rápido). La paleta debug se aplica al mapear índices del framebuffer a colores RGB.use_cpp_ppu=False: Calcula tiles desde VRAM en Python (más lento pero más flexible). Usa la paleta debug local para decodificar tiles.
Si el renderer cambia de modo durante la ejecución, puede usar diferentes rutas de código que tienen diferentes paletas. Los monitores implementados detectan estos cambios para identificar si hay una relación con la aparición de rayas verdes.
Fuente: Pan Docs - "LCD Control Register", "PPU Rendering"
Implementación
Se implementaron correcciones preventivas y 3 monitores de diagnóstico para rastrear el uso de paletas y cambios en el modo de renderizado.
Corrección de self.COLORS
Se corrigió self.COLORS en __init__() para que el índice 0 sea blanco
en lugar de verde:
# Antes (Step 0300):
self.COLORS = [
(224, 248, 208), # 0: Blanco/Verde claro (VERDE)
...
]
# Después (Step 0301):
self.COLORS = [
(255, 255, 255), # 0: White (Color 0) - Corregido Step 0301
...
]
Esta corrección asegura que si algún código usa self.COLORS o self.palette
(que se inicializa desde self.COLORS), los valores sean correctos.
Monitor [PALETTE-USE-TRACE]
Monitor que rastrea qué paleta se usa en cada frame. Se implementa en ambas rutas de renderizado (C++ y Python) y registra:
- Número de frame
- Estado de
use_cpp_ppu - Color del índice 0 en la paleta debug local
- Color del índice 0 en
self.palette
# Monitor implementado en render_frame()
if self._palette_trace_count < 100 or (self._palette_trace_count % 1000 == 0):
use_cpp = self.use_cpp_ppu
palette_0_debug = palette[0] # Paleta debug local
palette_0_self = self._palette[0] # self.palette
print(f"[PALETTE-USE-TRACE] Frame {self._palette_trace_count} | use_cpp_ppu={use_cpp} | debug_palette[0]={palette_0_debug} | self.palette[0]={palette_0_self}")
self._palette_trace_count += 1
El monitor registra los primeros 100 frames y luego cada 1000 frames para no saturar los logs.
Monitor [PALETTE-SELF-CHANGE]
Monitor que detecta cambios en self.palette usando una propiedad con setter.
Si algún código modifica self.palette, el monitor registra el cambio y un stack trace:
@property
def palette(self):
"""Getter para self.palette (usado por monitores Step 0301)."""
return self._palette
@palette.setter
def palette(self, value):
"""Setter para self.palette con monitor de cambios (Step 0301)."""
old_0 = self._palette[0] if self._palette else None
self._palette = value
new_0 = value[0] if value else None
if old_0 != new_0:
import traceback
print(f"[PALETTE-SELF-CHANGE] self.palette[0] cambió: {old_0} -> {new_0}")
print(f"[PALETTE-SELF-CHANGE] Stack trace:")
traceback.print_stack(limit=5)
Este monitor requiere cambiar self.palette a self._palette en __init__()
para usar la propiedad.
Monitor [CPP-PPU-TOGGLE]
Monitor que detecta cambios en use_cpp_ppu durante la ejecución:
# Monitor implementado en render_frame()
if self._last_use_cpp_ppu is None:
self._last_use_cpp_ppu = self.use_cpp_ppu
elif self._last_use_cpp_ppu != self.use_cpp_ppu:
print(f"[CPP-PPU-TOGGLE] use_cpp_ppu cambió: {self._last_use_cpp_ppu} -> {self.use_cpp_ppu}")
self._last_use_cpp_ppu = self.use_cpp_ppu
Este monitor ayuda a identificar si el renderer cambia entre modo C++ y modo Python, lo que podría causar que se use una paleta diferente.
Búsqueda de Código que Use self.palette
Se realizó una búsqueda exhaustiva en src/gpu/renderer.py para identificar todos los
lugares donde se usa self.palette o self.COLORS:
- Línea 198:
self._palette = list(self.COLORS)- Inicialización (corregida) - Líneas 349-387:
update_tile_cache(palette)- Usa paleta como parámetro (variable local) - Líneas 701, 705, 791, 867: Uso de
palettecomo variable local enrender_frame()
Conclusión: No se encontró ningún código que use self.palette directamente
durante el renderizado. Todas las referencias a palette son variables locales definidas
en render_frame() con la paleta debug corregida. La corrección de self.COLORS
es preventiva para asegurar que si algún código futuro usa self.palette, los valores sean correctos.
Archivos Afectados
src/gpu/renderer.py- Corrección deself.COLORSe implementación de 3 monitores de diagnóstico
Tests y Verificación
La implementación se verificó mediante:
- Análisis estático de código: Búsqueda exhaustiva de usos de
self.paletteyself.COLORS - Linter: Sin errores de sintaxis o tipo
- Validación de monitores: Los 3 monitores están implementados y listos para capturar logs durante ejecución extendida
Próximo paso: Ejecutar el emulador durante varios minutos y analizar los logs generados por los monitores para identificar cuándo y por qué vuelven las rayas verdes.
Fuentes Consultadas
- Pan Docs: "Background Palette (BGP)" - Gestión de paletas en Game Boy
- Pan Docs: "LCD Control Register" - Modos de renderizado
- Pan Docs: "PPU Rendering" - Renderizado de gráficos
Integridad Educativa
Lo que Entiendo Ahora
- Múltiples fuentes de paleta: El renderer puede usar diferentes paletas según el contexto.
La paleta debug local es la que se usa durante el renderizado, pero
self.palettepodría ser usada en otros lugares. - Monitores de diagnóstico: Los monitores permiten rastrear cambios dinámicos en el estado del renderer que podrían causar problemas visuales. Son herramientas esenciales para debugging.
- Corrección preventiva: Aunque no se encontró código que use
self.palettedurante el renderizado, corregirself.COLORSasegura que cualquier código futuro use valores correctos.
Lo que Falta Confirmar
- Causa raíz de rayas recurrentes: Los monitores deben ejecutarse durante varios minutos
para identificar cuándo y por qué vuelven las rayas verdes. Posibles causas:
- Cambio en
use_cpp_ppudurante la ejecución - Modificación de
self.palettepor código externo - Uso de una paleta diferente en algún código no identificado
- Cambio en
- Análisis de logs: Los logs generados por los monitores deben analizarse para identificar patrones que coincidan con la aparición de rayas verdes.
Hipótesis y Suposiciones
Hipótesis principal: Las rayas verdes recurrentes podrían deberse a que algún código
modifica self.palette o cambia el modo de renderizado después de unos minutos. Los monitores
implementados deberían capturar estos cambios.
Suposición: Si la corrección de self.COLORS no resuelve el problema, el análisis
de logs de los monitores debería revelar la causa raíz.
Próximos Pasos
- [ ] Ejecutar el emulador durante varios minutos con los monitores activos
- [ ] Analizar logs generados por los monitores para identificar patrones
- [ ] Si se identifica la causa raíz, implementar corrección específica
- [ ] Si las rayas desaparecen, verificar que no vuelvan con pruebas extendidas
- [ ] Si persisten, investigar más a fondo otros posibles lugares donde se use paleta verde