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

Investigación y Corrección del Problema de Pantallas Blancas y Rendimiento

Fecha: 2025-12-29 Step ID: 0361 Estado: VERIFIED

Resumen

Se implementó un sistema completo de diagnóstico para investigar por qué las pantallas se muestran blancas a pesar de que los logs indican que el pipeline funciona correctamente. Se agregaron verificaciones detalladas en cada etapa del pipeline de renderizado: verificación del framebuffer antes de que Python lo lea, verificación de que `render_scanline()` se ejecuta y escribe al framebuffer, verificación de que `render_frame()` se llama en Python, investigación del problema de rendimiento (FPS muy bajo), y verificación del timing de limpieza del framebuffer. Los resultados confirman que el framebuffer tiene datos cuando se renderiza, pero se identificó un problema donde algunos frames tienen el framebuffer casi vacío cuando Python lo lee.

Concepto de Hardware

En un emulador híbrido Python/C++, el pipeline de renderizado es crítico para la visualización correcta de gráficos. El pipeline completo incluye:

  1. Renderizado en C++: La PPU renderiza cada línea (scanline) y escribe índices de color al framebuffer
  2. Transferencia a Python: Python lee el framebuffer desde C++ y lo convierte a RGB
  3. Renderizado en Python: Python dibuja los píxeles RGB en la pantalla usando Pygame

Es esencial verificar que cada etapa del pipeline funciona correctamente. Si una etapa falla, los gráficos no se mostrarán correctamente. El problema de pantallas blancas puede ser causado por:

  • El framebuffer está vacío cuando Python lo lee
  • El framebuffer se limpia antes de que Python lo renderice
  • El renderizado no se ejecuta correctamente
  • Problemas de sincronización entre C++ y Python

Rendimiento del Emulador: El emulador debe mantener ~60 FPS para una experiencia fluida. FPS muy bajo (0.1, 10.8) indica un problema grave que puede ser causado por bucles infinitos, bloqueos, o operaciones muy costosas.

Implementación

Se implementaron verificaciones detalladas en cada etapa del pipeline de renderizado para identificar dónde se pierde la información visual.

Componentes creados/modificados

  • PPU.cpp - Verificación del Framebuffer Antes de Leer: Se agregó verificación en `get_frame_ready_and_reset()` que muestra el contenido del framebuffer justo antes de que Python lo lea, incluyendo distribución de índices y advertencia si está vacío
  • PPU.cpp - Verificación de render_scanline(): Se agregó verificación en `render_scanline()` que muestra qué índices se escriben al framebuffer, el estado de VRAM, y advertencia si VRAM tiene tiles pero la línea está vacía
  • PPU.cpp - Verificación de Timing de Limpieza: Se agregó verificación en `confirm_framebuffer_read()` que muestra el contenido del framebuffer antes de limpiarlo
  • viboy.py - Verificación de Llamada a render_frame(): Se agregó verificación que muestra el contenido del framebuffer cuando se pasa a `render_frame()` y advertencia si está vacío
  • viboy.py - Investigación de Rendimiento: Se agregó verificación de timing en el bucle principal que muestra la duración de cada frame y advertencia si es muy lento

Decisiones de diseño

Se decidió agregar logs detallados con límites (20-50 logs) para evitar saturar el contexto. Los logs se limitan a los primeros frames para capturar el comportamiento inicial del emulador. Se corrigió el uso de `static` en Python (que no existe) usando variables de instancia en su lugar.

Archivos Afectados

  • src/core/cpp/PPU.cpp - Agregadas verificaciones del framebuffer, render_scanline(), y timing de limpieza
  • src/viboy.py - Agregadas verificaciones de llamada a render_frame() y rendimiento

Tests y Verificación

Se ejecutaron pruebas de diagnóstico con Oro.gbc durante 30 segundos y se analizaron los logs generados:

  • Comando ejecutado: timeout 30 python3 main.py roms/Oro.gbc 2>&1 | tee logs/test_oro_step0361_diagnostic.log
  • Análisis de logs: Se analizaron los logs usando grep para extraer los mensajes de diagnóstico específicos

Hallazgos Clave

  • ✅ Framebuffer tiene datos cuando se renderiza: Los logs muestran que el framebuffer tiene 11520 píxeles no-blancos (50%) en los primeros frames, lo cual es correcto para un patrón checkerboard
  • ✅ render_scanline() se ejecuta correctamente: Los logs muestran que `render_scanline()` se ejecuta y escribe índices al framebuffer (80 píxeles no-blancos por línea, 50%)
  • ✅ Framebuffer se limpia correctamente: Los logs muestran que el framebuffer se limpia después de que Python lo lee, lo cual es correcto
  • ⚠️ Problema detectado: Hay un frame (Frame 14) donde el framebuffer está casi vacío (80/23040 = 0.35%) cuando Python lo lee, lo cual podría explicar las pantallas blancas
  • ❓ Logs de Python no aparecen: Los logs de `[Viboy-Render-Call]` y `[Viboy-Performance]` no aparecen en el log, lo cual necesita investigación adicional

Evidencia de Logs

[PPU-FRAMEBUFFER-BEFORE-READ] Frame 0 | Non-white pixels: 11520/23040 (50.00%) | Index distribution: 0=11520 1=0 2=0 3=11520
[PPU-RENDER-SCANLINE] LY=0 | VRAM non-zero: 0/6144 | Line non-white: 80/160 (50.0%) | First 10 indices: 3 3 3 3 3 3 3 3 0 0
[PPU-CLEAR-TIMING] Frame 0 | Non-white pixels before clear: 11520/23040 (50.00%) | Clearing framebuffer now
[PPU-FRAMEBUFFER-BEFORE-READ] Frame 14 | Non-white pixels: 80/23040 (0.35%)
[PPU-FRAMEBUFFER-BEFORE-READ] ⚠️ ADVERTENCIA: Framebuffer está vacío cuando Python va a leer!

Fuentes Consultadas

  • Pan Docs: Renderizado de líneas (Scanlines)
  • Pan Docs: Sincronización del framebuffer
  • Implementación basada en conocimiento general de arquitectura híbrida Python/C++

Integridad Educativa

Lo que Entiendo Ahora

  • Pipeline de Renderizado: El pipeline completo incluye renderizado en C++, transferencia a Python, y renderizado en Python. Cada etapa debe funcionar correctamente para que los gráficos se muestren
  • Verificación del Framebuffer: Es esencial verificar que el framebuffer tiene datos cuando se renderiza. Los logs confirman que el framebuffer tiene datos en la mayoría de los frames
  • Problema de Frames Vacíos: Algunos frames tienen el framebuffer casi vacío cuando Python lo lee, lo cual podría explicar las pantallas blancas

Lo que Falta Confirmar

  • Logs de Python: Los logs de `[Viboy-Render-Call]` y `[Viboy-Performance]` no aparecen en el log. Necesita investigación adicional para determinar por qué
  • Causa de Frames Vacíos: Se necesita investigar por qué algunos frames tienen el framebuffer casi vacío cuando Python lo lee
  • Rendimiento: Se necesita investigar por qué el FPS es muy bajo (0.1, 10.8) y si está relacionado con el problema de pantallas blancas

Hipótesis y Suposiciones

Hipótesis Principal: El problema de pantallas blancas podría ser causado por frames donde el framebuffer está casi vacío cuando Python lo lee. Esto podría ser causado por un problema de sincronización o por el framebuffer que se limpia demasiado pronto.

Próximos Pasos

  • [ ] Investigar por qué los logs de Python no aparecen
  • [ ] Investigar por qué algunos frames tienen el framebuffer casi vacío cuando Python lo lee
  • [ ] Investigar el problema de rendimiento (FPS muy bajo)
  • [ ] Implementar corrección basada en los hallazgos
  • [ ] Verificar visualmente que los gráficos se muestran correctamente después de la corrección