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 y Diagnóstico Visual
Resumen
Implementación de 4 monitores de diagnóstico visual para investigar por qué el emulador muestra rayas verticales verdes en lugar de gráficos. Los monitores capturan el contenido real del framebuffer, los tile IDs del tilemap, los datos de tiles leídos de VRAM, y la aplicación de la paleta durante el renderizado de la línea central (LY=72).
Objetivo: Identificar la causa raíz del patrón de rayas verdes mediante análisis de los datos reales que se están procesando durante el renderizado.
Concepto de Hardware
Patrones Visuales en Game Boy
Las rayas verticales en el Game Boy suelen aparecer cuando:
- Tilemap con valores repetidos: El tilemap contiene el mismo tile ID repetido en columnas, generando un patrón vertical
- Tiles vacíos con paleta visible: Los tiles están vacíos (0x00) pero la paleta genera colores visibles (verde)
- Cálculo incorrecto de direcciones: El cálculo de direcciones de tiles es incorrecto, generando lecturas repetitivas del mismo tile
- Scroll generando patrón: El scroll (SCX/SCY) está generando un patrón repetitivo en las direcciones calculadas
Fuente: Pan Docs - "Tile Data", "Background", "Palette"
Framebuffer y Paleta
El framebuffer contiene índices de color (0-3), no colores RGB directamente. La paleta BGP (Background Palette) mapea estos índices a colores finales:
- Índice 0 → Color 0 (Blanco por defecto)
- Índice 1 → Color 1 (Gris claro por defecto)
- Índice 2 → Color 2 (Gris oscuro por defecto)
- Índice 3 → Color 3 (Negro por defecto)
El renderer de Python aplica una paleta debug que mapea estos índices a RGB. Si el framebuffer contiene índices repetitivos, se verán rayas del color correspondiente.
Fuente: Pan Docs - "Background Palette (BGP)", "LCD Display"
Renderizado de Tiles
Cada tile tiene 8x8 píxeles. Cada píxel se codifica con 2 bits (4 colores posibles: 0, 1, 2, 3). Dos bytes consecutivos en VRAM representan una línea de 8 píxeles:
- Byte 1: Bit bajo de cada píxel (LSB)
- Byte 2: Bit alto de cada píxel (MSB)
Si un tile está vacío (0x00 en ambos bytes), todos los píxeles serán color_index 0, que con la paleta estándar se mapea a blanco. Sin embargo, si la paleta está configurada de manera diferente, podría generar colores verdes.
Fuente: Pan Docs - "Tile Data", "Tile Format"
Implementación
Monitores de Diagnóstico Visual
Se implementaron 4 monitores de diagnóstico visual en src/core/cpp/PPU.cpp dentro de la función
render_scanline(). Todos los monitores se activan durante el renderizado de la línea central (LY=72)
y capturan datos de los primeros 32 píxeles/tiles para no saturar los logs.
1. Monitor de Framebuffer Real ([FRAMEBUFFER-DUMP])
Captura el contenido real del framebuffer después de renderizar la línea central. Muestra los índices de color (0-3) que se escribieron en el framebuffer para los primeros 32 píxeles.
// Al final del renderizado de la línea 72
static int framebuffer_dump_count = 0;
if (ly_ == 72 && framebuffer_dump_count < 3) {
printf("[FRAMEBUFFER-DUMP] Frame %d, LY:72 | First 32 pixels (indices 0-31):\n",
framebuffer_dump_count + 1);
for(int x_dump = 0; x_dump < 32; x_dump++) {
printf("%02X ", framebuffer_[line_start_index + x_dump]);
if ((x_dump + 1) % 16 == 0) printf("\n");
}
printf("\n");
framebuffer_dump_count++;
}
2. Monitor de Tilemap Real ([TILEMAP-DUMP-VISUAL])
Captura los tile IDs reales que se están leyendo del tilemap durante el renderizado de la línea central. Muestra los primeros 32 tile IDs leídos del tilemap.
// Antes del loop de renderizado, cuando ly_ == 72
static int tilemap_dump_count = 0;
if (ly_ == 72 && tilemap_dump_count < 3) {
printf("[TILEMAP-DUMP-VISUAL] Frame %d, LY:72 | First 32 tile IDs:\n",
tilemap_dump_count + 1);
for(int x_dump = 0; x_dump < 32; x_dump++) {
uint8_t map_x_dump = (x_dump + scx) & 0xFF;
uint8_t map_y_dump = (ly_ + scy) & 0xFF;
uint16_t tile_map_addr_dump = tile_map_base + (map_y_dump / 8) * 32 + (map_x_dump / 8);
uint8_t tile_id_dump = mmu_->read(tile_map_addr_dump);
printf("%02X ", tile_id_dump);
if ((x_dump + 1) % 16 == 0) printf("\n");
}
printf("\n");
tilemap_dump_count++;
}
3. Monitor de Datos de Tiles Reales ([TILEDATA-DUMP-VISUAL])
Captura los datos reales de los tiles que se están leyendo de VRAM durante el renderizado. Muestra los bytes de los primeros 4 tiles (cada 8 píxeles) leídos de VRAM.
// Dentro del loop de renderizado, cuando se lee de VRAM
static int tiledata_dump_count = 0;
if (ly_ == 72 && x < 32 && tiledata_dump_count < 3) {
if (x % 8 == 0) { // Cada 8 píxeles (un tile completo)
uint8_t tile_index = x / 8;
if (tile_index < 4) {
printf("[TILEDATA-DUMP-VISUAL] Frame %d | Tile %d (ID:%02X) | Addr:%04X | Line:%d | Bytes: %02X %02X\n",
tiledata_dump_count + 1, tile_index, tile_id, tile_line_addr, line_in_tile, byte1, byte2);
}
}
}
if (ly_ == 72 && x == 31) tiledata_dump_count++;
4. Monitor de Paleta Aplicada ([PALETTE-DUMP-VISUAL])
Captura la aplicación de la paleta BGP para ver qué colores finales se generan. Muestra el mapeo color_index → final_color para los primeros 32 píxeles.
// Dentro del loop de renderizado, después de aplicar la paleta
static int palette_dump_count = 0;
if (ly_ == 72 && x < 32 && palette_dump_count < 3) {
if (x == 0) {
printf("[PALETTE-DUMP-VISUAL] Frame %d, LY:72 | BGP:0x%02X | First 32 pixels (ColorIndex -> FinalColor):\n",
palette_dump_count + 1, bgp);
}
printf("(%d->%d) ", color_index, final_color);
if ((x + 1) % 16 == 0) printf("\n");
}
if (ly_ == 72 && x == 31) palette_dump_count++;
Decisiones de Diseño
- Línea central (LY=72): Se eligió la línea central porque es representativa del contenido visible y evita bordes que podrían tener comportamientos especiales
- Primeros 32 píxeles/tiles: Se limita a 32 para no saturar los logs, pero es suficiente para identificar patrones repetitivos
- Límite de 3 frames: Cada monitor solo se activa en los primeros 3 frames para evitar saturación de logs
- Formato hexadecimal: Los datos se muestran en hexadecimal para facilitar la identificación de patrones
Archivos Afectados
src/core/cpp/PPU.cpp- Añadidos 4 monitores de diagnóstico visual enrender_scanline()ANALISIS_RAYAS_VERDES_STEP_0299.md- Documento de análisis (nuevo, template para completar después de ejecución)docs/bitacora/entries/2025-12-25__0299__investigacion-rayas-verdes-diagnostico-visual.html- Entrada HTML de bitácoradocs/bitacora/index.html- Actualizado con entrada 0299INFORME_FASE_2.md- Actualizado con Step 0299
Tests y Verificación
Los monitores se validarán ejecutando el emulador y analizando los logs generados:
- Compilación: Los monitores se compilaron sin errores con C++17
- Ejecución: Pendiente de ejecutar el emulador para capturar logs
- Análisis: Pendiente de analizar los logs para identificar patrones
Comando para ejecutar y capturar logs:
python main.py --rom roms/pokemon_red.gb > logs/diagnostico_rayas_0299.log 2>&1
Análisis de logs: Se analizarán los logs usando el documento ANALISIS_RAYAS_VERDES_STEP_0299.md
para identificar la causa raíz del patrón de rayas verdes.
Fuentes Consultadas
- Pan Docs: Tile Data
- Pan Docs: Background
- Pan Docs: Palette
- Pan Docs: LCD Display
Integridad Educativa
Lo que Entiendo Ahora
- Patrones visuales: Las rayas verticales pueden originarse en diferentes puntos del pipeline de renderizado (tilemap, tiles, paleta)
- Framebuffer: Contiene índices de color, no colores RGB directamente. La paleta mapea estos índices a colores finales
- Diagnóstico visual: Capturar datos en múltiples puntos del pipeline permite identificar dónde se origina un patrón visual
- Límites de logs: Es crítico limitar la cantidad de logs para no saturar el contexto y mantener el rendimiento
Lo que Falta Confirmar
- Patrón real: Qué índice de color genera el verde oscuro y cuál el verde claro
- Origen del patrón: Si viene del tilemap, los tiles, o la paleta
- Causa raíz: Por qué se genera el patrón repetitivo
Hipótesis y Suposiciones
Se han formulado 4 hipótesis sobre el origen de las rayas verdes:
- Hipótesis A: Tilemap con valores repetidos
- Hipótesis B: Tiles vacíos con paleta verde
- Hipótesis C: Cálculo incorrecto de direcciones
- Hipótesis D: Scroll generando patrón
Los monitores implementados permitirán confirmar o rechazar estas hipótesis después de ejecutar el emulador y analizar los logs.
Próximos Pasos
- [ ] Ejecutar el emulador y capturar logs de los 4 monitores
- [ ] Analizar los logs para identificar patrones en framebuffer, tilemap, tiles y paleta
- [ ] Confirmar o rechazar las 4 hipótesis sobre el origen de las rayas verdes
- [ ] Identificar la causa raíz del patrón
- [ ] Implementar corrección basada en los hallazgos (si aplica)
- [ ] Completar el documento
ANALISIS_RAYAS_VERDES_STEP_0299.mdcon los resultados