⚠️ 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 Renderizado Python

Fecha: 2025-12-25 Step ID: 0305 Estado: DRAFT

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:

  1. PPU C++ genera framebuffer: El framebuffer contiene índices de color (0-3) en formato 1D (23040 elementos = 160x144)
  2. Renderer Python obtiene framebuffer: Zero-Copy mediante memoryview desde PPU C++
  3. Renderer mapea índices a RGB: Usa una paleta para convertir índices (0-3) a colores RGB
  4. Renderer escribe en PixelArray: Escribe píxeles RGB en una superficie Pygame (160x144)
  5. 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 - ✅ Corregida
  • debug_palette_map (líneas 502, 614, 990): Paleta de debug - ✅ Corregida
  • palette0 y palette1 (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 definir palette
  • 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 en PixelArray
  • 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 definir debug_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 hallazgos
  • debug_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:

  1. Rendimiento: FPS extremadamente bajo (21.8 vs 60 esperado)
  2. 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