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 Renderizado Python
Resumen
Investigación exhaustiva del código de renderizado en Python para identificar por qué aparecen rayas verdes cuando el framebuffer de PPU C++ solo contiene índices 0. Se implementaron 3 monitores adicionales para rastrear la paleta, el PixelArray y las modificaciones de paleta durante la ejecución.
Objetivo: Identificar la causa raíz de las rayas verdes que aparecen después de ~2 minutos de ejecución, cuando el framebuffer PPU C++ solo contiene índices 0. El problema NO está en PPU C++, sino en el renderizado Python.
Hipótesis evaluadas:
- Hipótesis A: La paleta se modifica durante la ejecución
- Hipótesis B: Hay otro código que renderiza usando una paleta incorrecta
- Hipótesis C: Problema con PixelArray o scaling que causa artefactos visuales
- Hipótesis D: Hay alguna paleta que no se corrigió en los steps anteriores
Concepto de Hardware
Flujo de Renderizado
El flujo de renderizado en el emulador sigue estos pasos:
- PPU C++ genera framebuffer: El framebuffer contiene índices de color (0-3) en formato 1D (23040 elementos = 160x144)
- Renderer Python obtiene framebuffer: Zero-Copy mediante memoryview desde PPU C++
- Renderer mapea índices a RGB: Usa una paleta para convertir índices (0-3) a colores RGB
- Renderer escribe en PixelArray: Escribe píxeles RGB en una superficie Pygame (160x144)
- PixelArray se escala y blit: La superficie se escala a la ventana (480x432) y se blit a la pantalla
Posibles Problemas en el Flujo
Si el framebuffer PPU C++ solo contiene índices 0 (blanco), pero aparecen rayas verdes, el problema debe estar en uno de estos puntos:
- Paleta modificada: La paleta se cambia durante la ejecución, causando que índices 0 se mapeen a verde
- Múltiples paletas: Hay otra paleta en uso que no se corrigió
- Problemas con PixelArray: El PixelArray o el scaling causan artefactos visuales
- Código adicional: Hay otro código que renderiza usando una paleta incorrecta
Fuente: Pan Docs - "Framebuffer", "Palette", "Pixel Mapping"
Implementación
Búsqueda Exhaustiva de Paletas
Se realizó una búsqueda exhaustiva de todas las paletas en el código:
- Búsqueda de valores verdes: No se encontraron valores verdes (224, 248, 208), (136, 192, 112), (52, 104, 86)
- Búsqueda de definiciones de paleta: Se encontraron 40 coincidencias, todas verificadas y corregidas
Paletas encontradas:
self.COLORS(línea 191): Paleta base del renderer - ✅ Corregidadebug_palette_map(líneas 502, 614, 990): Paleta de debug - ✅ Corregidapalette0ypalette1(líneas 999, 1005): Paletas para sprites - ✅ Corregidas
Búsqueda de Código de Renderizado
Se buscaron todas las funciones y operaciones de renderizado:
- Funciones de renderizado: 4 funciones encontradas (update_tile_cache, render_vram_debug, render_frame, render_sprites)
- Operaciones de renderizado: 17 operaciones encontradas (blit, fill, set_at)
- Conclusión: No hay código adicional que renderice. El flujo es claro y único.
Monitores Implementados
Se implementaron 3 monitores adicionales para rastrear el renderizado:
Monitor 1: [PALETTE-VERIFY]
Verifica la paleta usada en cada frame:
- Ubicación:
render_frame()después de definirpalette - Frecuencia: Cada 1000 frames o primeros 100 frames
- Funcionalidad: Imprime los valores RGB de la paleta (Palette[0], Palette[1], Palette[2], Palette[3])
if self._palette_verify_count % 1000 == 0 or self._palette_verify_count < 10:
if self._palette_verify_count < 100:
print(f"[PALETTE-VERIFY] Frame {self._palette_verify_count} | "
f"Palette[0]={palette[0]} Palette[1]={palette[1]} "
f"Palette[2]={palette[2]} Palette[3]={palette[3]}")
self._palette_verify_count += 1
Monitor 2: [PIXEL-VERIFY]
Verifica el píxel central antes del mapeo en PixelArray:
- Ubicación:
render_frame()antes de escribir enPixelArray - Frecuencia: Primeros 10 frames
- Funcionalidad: Verifica el píxel central (línea 72, columna 80) antes y después del mapeo
if self._pixel_verify_count < 10:
center_idx = (72 * 160 + 80) # Línea 72, columna 80
center_color_idx = frame_indices[center_idx] & 0x03
center_color_rgb = palette[center_color_idx]
print(f"[PIXEL-VERIFY] Frame {self._pixel_verify_count} | "
f"Center pixel: idx={center_idx} color_idx={center_color_idx} "
f"rgb={center_color_rgb}")
self._pixel_verify_count += 1
Monitor 3: [PALETTE-MODIFIED]
Detecta si la paleta se modifica durante la ejecución:
- Ubicación:
render_frame()después de definirdebug_palette_map - Funcionalidad: Compara la paleta actual con la última paleta verificada y muestra stack trace si cambia
if self._last_palette_checked is not None:
if self._last_palette_checked != debug_palette_map:
print(f"[PALETTE-MODIFIED] Paleta modificada detectada!")
print(f" Original: {self._original_debug_palette}")
print(f" Actual: {debug_palette_map}")
import traceback
traceback.print_stack(limit=10)
self._last_palette_checked = dict(debug_palette_map)
Archivos Afectados
src/gpu/renderer.py- Implementación de 3 monitores adicionales ([PALETTE-VERIFY], [PIXEL-VERIFY], [PALETTE-MODIFIED])ANALISIS_STEP_0305_RENDERER.md- Documento de análisis con todos los hallazgosdebug_step_0305_renderer.log- Logs de ejecución (en progreso)
Tests y Verificación
Ejecución del Emulador: El emulador se ejecutó en segundo plano durante 2-3 minutos para capturar logs.
Comandos de Análisis:
# Analizar [PALETTE-VERIFY]
Select-String -Path debug_step_0305_renderer.log -Pattern "\[PALETTE-VERIFY\]" | Select-Object -First 20 -Last 20
# Analizar [PIXEL-VERIFY]
Select-String -Path debug_step_0305_renderer.log -Pattern "\[PIXEL-VERIFY\]" | Select-Object -First 10
# Buscar modificaciones de paleta
Select-String -Path debug_step_0305_renderer.log -Pattern "\[PALETTE-MODIFIED\]" | Select-Object -First 10
# Buscar patrones antes de rayas verdes
Select-String -Path debug_step_0305_renderer.log -Pattern "\[PALETTE-VERIFY\]" | Select-Object -Skip 50 -First 20
Validación de Módulo Compilado C++: Los monitores se ejecutan en Python y verifican el framebuffer obtenido desde PPU C++.
Hallazgos
Búsqueda de Paletas
- ✅ No se encontraron valores verdes en el código
- ✅ Todas las paletas están corregidas: self.COLORS, debug_palette_map, palette0, palette1
- ✅ Hipótesis D rechazada: No hay paletas pendientes de corrección
Búsqueda de Código de Renderizado
- ✅ No hay código adicional que renderice: Solo hay un flujo de renderizado principal
- ✅ Hipótesis B rechazada: No hay otro código usando paleta incorrecta
Monitores Implementados
- ✅ [PALETTE-VERIFY]: Implementado y activo
- ✅ [PIXEL-VERIFY]: Implementado y activo
- ✅ [PALETTE-MODIFIED]: Implementado y activo
Análisis de Ejecución y Captura de Pantalla
Observaciones de la captura de pantalla:
- ✅ Sprites visibles: Se pueden ver sprites de Pokémon (aunque fragmentados) y texto "RED"
- ✅ Problema de rayas verdes: No se observaron rayas verdes en la captura (posiblemente resuelto)
- ⚠️ Rendimiento crítico: FPS 21.8 (debería ser ~60 FPS) - problema nuevo identificado
- ⚠️ Corrupción gráfica: Patrón de tablero de ajedrez en sección inferior, líneas verticales en superior, sprites fragmentados
Conclusión: El problema original de rayas verdes parece estar resuelto, pero se identificaron dos nuevos problemas críticos:
- Rendimiento: FPS extremadamente bajo (21.8 vs 60 esperado)
- Corrupción gráfica: Patrones anómalos y sprites fragmentados
Fuentes Consultadas
- Pan Docs: "Framebuffer", "Palette", "Pixel Mapping"
- Step 0304: Verificación Extendida y Monitor de Framebuffer
- Step 0303: Corrección de Paleta Debug Índices 1 y 2
Integridad Educativa
Lo que Entiendo Ahora
- Flujo de renderizado: El framebuffer PPU C++ contiene índices (0-3), que se mapean a RGB usando una paleta en Python, luego se escriben en PixelArray y se escalan.
- Búsqueda exhaustiva: Es importante buscar todas las paletas y código de renderizado para asegurar que no se pierda nada.
- Monitores múltiples: Implementar varios monitores permite capturar diferentes aspectos del problema (paleta, píxeles, modificaciones).
- Control de contexto: Los logs deben redirigirse a archivos y analizarse con muestras, no leer completos para evitar saturar el contexto.
Lo que Falta Confirmar
- Análisis de logs: Pendiente de análisis completo cuando los logs estén disponibles.
- Causa raíz: Si los monitores no detectan modificaciones de paleta, el problema puede estar en PixelArray, scaling, o en cómo Pygame renderiza los colores.
Hipótesis y Suposiciones
Hipótesis actual: Si el framebuffer PPU C++ solo contiene índices 0, pero aparecen rayas verdes, el problema debe estar en:
- El mapeo de índices a RGB (paleta incorrecta en algún momento)
- El PixelArray o el scaling causando artefactos
- Pygame renderizando colores incorrectamente
Los monitores implementados ayudarán a identificar cuál de estas hipótesis es correcta.
Próximos Pasos
Prioridad Alta
- [ ] Investigar Rendimiento (FPS 21.8):
- Profilar el bucle de renderizado
- Verificar si hay bloqueos en el código Python
- Optimizar operaciones costosas (PixelArray, scaling)
- Verificar sincronización CPU-PPU
- [ ] Investigar Corrupción Gráfica:
- Verificar integridad del framebuffer
- Investigar el patrón de tablero de ajedrez (posible problema con tiles o VRAM)
- Verificar sincronización de tiles y sprites
- Revisar el código de renderizado de sprites
Prioridad Media
- [ ] Verificar Problema de Rayas Verdes:
- Ejecutar sesión extendida (10-15 minutos) para confirmar que las rayas verdes no aparecen
- Si aparecen, usar los monitores implementados para diagnosticar
- [ ] Mejorar Monitores:
- Asegurar que los logs se generen correctamente
- Agregar monitores de rendimiento (FPS, tiempo de frame)
- Agregar monitores de corrupción gráfica