⚠️ 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 de Desaparición del Checkerboard

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

Resumen

Este step investiga por qué el checkerboard temporal desaparece después de algunos frames. Se implementaron logs de diagnóstico para verificar el estado del framebuffer, cuándo se limpia, cambios en vram_is_empty_, y el estado del renderizador. Los logs revelaron que el problema era que la verificación periódica del framebuffer se hacía cuando ly_ == 0, justo después de limpiarlo, mostrando siempre un framebuffer vacío. Se corrigió moviendo la verificación a VBLANK_START (144), después de renderizar todo el frame.

Concepto de Hardware

Persistencia del Framebuffer

El framebuffer debe mantener sus datos hasta que se renderice el siguiente frame. Si el framebuffer se limpia prematuramente, la pantalla se vuelve blanca. El framebuffer solo debe limpiarse al inicio del siguiente frame, después de que Python lo haya leído.

Checkerboard Temporal

El checkerboard temporal se activa cuando VRAM está vacía (vram_is_empty_ == true). Debe mantenerse activo mientras VRAM esté vacía. Si vram_is_empty_ cambia incorrectamente, el checkerboard puede desaparecer.

Ciclo de Renderizado

El ciclo de renderizado de la PPU funciona así:

  • Líneas 0-143: Renderizado de scanlines (render_scanline())
  • Línea 144 (VBLANK_START): V-Blank, frame listo para leer
  • Líneas 145-153: V-Blank continuado
  • Línea > 153: Reset a ly_ = 0, limpieza del framebuffer para el siguiente frame

Por lo tanto, el framebuffer debe verificarse en VBLANK_START (144), después de renderizar todo el frame, pero antes de que se limpie para el siguiente frame.

Implementación

Logs de Diagnóstico Agregados

Se agregaron los siguientes logs de diagnóstico para investigar la desaparición del checkerboard:

  • [PPU-FRAMEBUFFER-PERIODIC]: Verificación periódica del estado del framebuffer cada 100 frames
  • [PPU-CLEAR-FRAMEBUFFER]: Log cada vez que se limpia el framebuffer
  • [PPU-VRAM-EMPTY-CHANGE]: Log cuando vram_is_empty_ cambia de estado
  • [Renderer-Periodic]: Verificación periódica del renderizador cada 100 frames

Corrección Crítica

Se identificó que la verificación periódica del framebuffer se hacía cuando ly_ == 0, justo después de limpiarlo. Esto causaba que siempre se mostrara un framebuffer vacío, aunque el checkerboard se estuviera dibujando correctamente.

Solución: Mover la verificación periódica a VBLANK_START (144), después de renderizar todo el frame, pero antes de que se limpie para el siguiente frame.

Componentes Modificados

  • src/core/cpp/PPU.cpp: Agregados logs de diagnóstico y corrección de verificación periódica
  • src/gpu/renderer.py: Agregados logs periódicos del renderizador

Archivos Afectados

  • src/core/cpp/PPU.cpp - Agregados logs de diagnóstico y corrección de verificación periódica
  • src/gpu/renderer.py - Agregados logs periódicos del renderizador

Tests y Verificación

Se ejecutaron pruebas con las 5 ROMs (Pokémon Red, TETRIS, Mario, Pokémon Yellow, Pokémon Gold) durante 2.5 minutos cada una para recopilar logs de diagnóstico.

Resultados de los Logs

Antes de la corrección: Los logs mostraban que el framebuffer estaba completamente vacío (0 píxeles no-blancos) aunque VRAM estaba vacía y debería tener checkerboard.

Después de la corrección: Los logs muestran que el framebuffer tiene datos correctos (11520 píxeles con índice 0 y 11520 con índice 3), indicando que el checkerboard se está dibujando correctamente.

Ejemplo de Log Corregido

[PPU-FRAMEBUFFER-PERIODIC] Frame 1 | Non-zero pixels: 11520/23040 | 
Distribution: 0=11520 1=0 2=0 3=11520 | VRAM empty: YES
[PPU-FRAMEBUFFER-PERIODIC] Frame 101 | Non-zero pixels: 11520/23040 | 
Distribution: 0=11520 1=0 2=0 3=11520 | VRAM empty: YES

Verificación de Otras Llamadas a clear_framebuffer()

Se verificó que solo hay 3 llamadas a clear_framebuffer():

  • En el constructor (línea 25) - Correcto
  • Cuando ly_ > 153 (línea 292) - Correcto
  • La definición de la función (línea 500) - Correcto

Fuentes Consultadas

  • Pan Docs: LCD Display, V-Blank, Framebuffer
  • Implementación basada en conocimiento general de arquitectura LR35902

Integridad Educativa

Lo que Entiendo Ahora

  • Ciclo de Renderizado: El framebuffer se limpia al inicio del frame (ly_ == 0), se renderiza durante las líneas 0-143, y se marca como listo en VBLANK_START (144).
  • Verificación del Framebuffer: La verificación del framebuffer debe hacerse después de renderizar todo el frame (VBLANK_START), no al inicio cuando se limpia.
  • Checkerboard Temporal: El checkerboard se dibuja correctamente cuando VRAM está vacía, pero la verificación prematura mostraba un framebuffer vacío.

Lo que Falta Confirmar

  • Desaparición del Checkerboard: Aunque los logs muestran que el checkerboard se dibuja correctamente, aún falta verificar visualmente si el checkerboard desaparece después de algunos frames en la pantalla.
  • Cambios en vram_is_empty_: Los logs muestran que vram_is_empty_ cambia después de algunos frames (ej: frame 4723, 4732), lo cual es normal cuando el juego carga tiles. Necesitamos verificar si esto causa la desaparición del checkerboard.

Hipótesis y Suposiciones

Hipótesis Principal: El problema de la desaparición del checkerboard puede estar relacionado con cambios en vram_is_empty_ después de algunos frames. Cuando VRAM se llena con tiles, vram_is_empty_ cambia a false, lo que desactiva el checkerboard. Esto es comportamiento esperado, pero puede causar confusión visual si el juego carga tiles y luego los borra.

Próximos Pasos

  • [ ] Verificar visualmente si el checkerboard desaparece después de algunos frames
  • [ ] Analizar si los cambios en vram_is_empty_ causan la desaparición del checkerboard
  • [ ] Si el problema persiste, implementar corrección basada en los hallazgos de los logs
  • [ ] Verificación final de renderizado con todas las ROMs