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.
Fix PPU: framebuffer blanco con TileData alta (render_bg/render_window/swap)
📋 Resumen Ejecutivo
⚠️ INTENTO REVERTIDO
Este Step intentó corregir el criterio de gating vram_has_tiles_ que era demasiado estricto para juegos CGB con tiledata alta pero baja diversidad de tile IDs únicos. Los cambios fueron revertidos porque no resolvieron completamente el problema del framebuffer blanco.
Problema Identificado:
- Juegos como
tetris_dx.gbcyzelda-dx.gbcreportabantiledata_effectivealta (56.6% y 79.0%) perofb_nonzero=0/23040(framebuffer completamente blanco). - El criterio de
vram_has_tiles_requería diversidad >= 5 tile IDs únicos, perozelda-dx.gbcsolo tenía 1 tile ID único.
Solución Intentada:
- Relajar el criterio para permitir render cuando
tiledata_effective >= 200aunqueunique_tile_idssea bajo (>= 1) en modo CGB. - Override condicional:
cgb_high_tiledata_override = (tiledata_effective >= 200) && (unique_tile_ids >= 1).
Resultado:
- ✅
tetris_dx.gbc: Mejora significativa -vram_has_tiles_se activa correctamente (Frame 676). - ⚠️
zelda-dx.gbc:vram_has_tiles_se activa (Frame 13) pero framebuffer sigue blanco. - ❌ Los cambios fueron revertidos porque el problema persiste (requiere investigación más profunda).
🔧 Concepto de Hardware
Criterio de Detección de Tiles en VRAM
Fuente: Pan Docs - "Video RAM", "Tile Data", "Background Tile Map"
La PPU necesita determinar cuándo hay tiles válidos en VRAM para decidir si renderizar el fondo o mostrar un patrón de prueba (checkerboard). En juegos reales, especialmente durante inicialización o transiciones de pantalla, puede haber situaciones donde hay datos de tiles cargados pero con baja diversidad de tile IDs únicos en el tilemap.
Problema Original:
El criterio anterior requería tanto datos de tiles (tiledata_nonzero >= 200 o complete_tiles >= 10) Y diversidad en el tilemap (unique_tile_ids >= 5). Esto causaba falsos negativos en juegos CGB como zelda-dx.gbc que tienen tiledata alta pero solo 1 tile ID único.
Solución Intentada (Revertida):
Relajar el criterio para modo CGB: si tiledata_effective >= 200 y unique_tile_ids >= 1, permitir render aunque la diversidad sea baja.
// Criterio original (estricto)
vram_has_tiles_ = has_tiles_data && has_tilemap_diversity;
// Criterio intentado (relajado para CGB) - REVERTIDO
bool cgb_high_tiledata_override = (tiledata_effective >= 200) && (unique_tile_ids >= 1);
vram_has_tiles_ = has_tiles_data && (has_tilemap_diversity || cgb_high_tiledata_override);
Por qué fue Revertido:
Aunque el cambio mejoró la activación de vram_has_tiles_, el framebuffer seguía quedando blanco en zelda-dx.gbc. Esto sugiere que el problema no es solo el gating sino que hay otro problema en el pipeline de renderizado (posiblemente en el direccionamiento de tiles, swap de framebuffers, o limpieza incorrecta).
💻 Implementación
Archivos Modificados (Cambios Revertidos):
src/core/cpp/PPU.cpp- Líneas ~1559-1578 (funciónrender_scanline())
Cambio Intentado:
// Cálculo de tiledata_effective para CGB
int tiledata_bank1 = count_vram_nonzero_bank1_tiledata();
int tiledata_effective = (tiledata_nonzero > tiledata_bank1) ? tiledata_nonzero : tiledata_bank1;
// Override para CGB con tiledata alta
bool cgb_high_tiledata_override = (tiledata_effective >= 200) && (unique_tile_ids >= 1);
// Nuevo criterio
vram_has_tiles_ = has_tiles_data && (has_tilemap_diversity || cgb_high_tiledata_override);
🧪 Tests y Verificación
Compilación:
$ python3 setup.py build_ext --inplace
✅ Compilación exitosa (exit code: 0)
Suite Paralela (2 minutos, todas las ROMs):
$ export VBC_SUITE=1
$ # Ejecución paralela de 8 ROMs
✅ Suite completada (exit code: 0)
Evidencia de los Logs:
tetris_dx.gbc:
[VRAM-STATE-CHANGE] Frame 676 | has_tiles: 0 -> 1 | tiledata: 4032/4032 | tiles: 252/384 | unique_ids: 185
[VIDEO-SUMMARY] Frame 700 | tiledata=56.6% | tiles: 252/384 | unique_ids: 185 | fb_nonzero: 15360/23040 (66.7%)
[CGB-RGB-CHECK] Frame 700 | Non-white pixels: YES (66.7%)
✅ Mejora significativa: vram_has_tiles_ se activa correctamente, framebuffer tiene píxeles no-blancos.
zelda-dx.gbc:
[VRAM-STATE-CHANGE] Frame 13 | has_tiles: 0 -> 1 | tiledata: 5632/5632 | tiles: 352/384 | unique_ids: 1
[VIDEO-SUMMARY] Frame 700 | tiledata=79.0% | tiles: 352/384 | unique_ids: 1 | fb_nonzero: 0/23040 (0.0%)
[CGB-RGB-CHECK] Frame 700 | Non-white pixels: NO (all white or black)
⚠️ Problema persiste: vram_has_tiles_ se activa pero framebuffer sigue completamente blanco (0%).
🔍 Análisis Post-Mortem
Hallazgos Clave:
- El gating no es el único problema: Aunque
vram_has_tiles_se activa correctamente enzelda-dx.gbc, el framebuffer sigue blanco. - Diversidad baja puede ser válida:
zelda-dx.gbctiene 352 tiles completos pero solo 1 tile ID único (posiblemente carga el mismo tile en toda la pantalla durante inicialización). - Problema más profundo: El renderizado inline no usa
vram_has_tiles_como gating (el bucle for enrender_scanline()no verifica este flag), por lo que debe haber otro problema:- Direccionamiento de tiles incorrecto
- Swap de framebuffers no funciona correctamente
- Limpieza incorrecta del framebuffer
- Problema en
get_tile_color_for_bg()
Por qué se Revirtió:
- El cambio mejora el comportamiento de
tetris_dx.gbcpero no resuelvezelda-dx.gbc. - El criterio relajado podría causar falsos positivos en otros juegos.
- Se necesita una investigación más profunda del pipeline de renderizado antes de modificar el gating.
Próximos Pasos Sugeridos (para Steps futuros):
- Instrumentar el bucle de renderizado inline en
render_scanline()para verificar qué valores de color se escriben al framebuffer. - Verificar que
swap_framebuffers()intercambia correctamente los punteros front/back. - Auditar
get_tile_color_for_bg()con datos reales dezelda-dx.gbc. - Considerar si el problema es específico de CGB (bancos de VRAM, paletas CGB).
🎯 Conclusión
Este Step documentó un intento de corrección del criterio de vram_has_tiles_ que fue revertido porque no resolvió completamente el problema del framebuffer blanco. Los cambios fueron beneficiosos para tetris_dx.gbc pero insuficientes para zelda-dx.gbc.
El análisis reveló que el problema del framebuffer blanco no es solo el gating de vram_has_tiles_ sino que hay un problema más profundo en el pipeline de renderizado que requiere investigación adicional.
Estado Final: DRAFT/REVERTIDO - Los cambios de código fueron revertidos pero la documentación se mantiene para trazabilidad.