352. Seleccionar la ruta de máscara opaca temporizada
Seleccionar la composición de máscara de opacidad temporizada solo cuando hay un fotograma completo disponible.
Lección 352 de 356 · tests/chapter_13_scrolling/test_352_select_timed_opaque_mask_path.py
Archivo a actualizar
emulator/rendering/ppu_background_renderer.pyReferencias
https://www.nesdev.org/wiki/PPU_rendering
https://www.nesdev.org/wiki/PPU_scrollingPor qué existe este paso
El paso 351 construyó el mecanismo para componer filas booleanas de opacidad de fondo a partir de los mismos estados temporizados que las filas RGB del framebuffer. El adaptador público de la máscara debe activar ahora ese mecanismo sin romper el comportamiento de inicio ni el de fotogramas incompletos.
Límite de selección
exactly 240 completed states -> timed opacity-mask composition
any other tuple length -> existing t + fine-X snapshot fallbackEsta compuerta exacta coincide con la del adaptador del framebuffer. Una comprobación de veracidad no es suficiente porque una tupla parcial de una o de 239 entradas no está vacía pero no puede describir todas las filas visibles.
¿Por qué mantener la reserva? Una PPU nueva empieza con una tupla completada vacía. La ruta de instantánea ya establecida sigue siendo un mecanismo de compatibilidad determinista hasta que se publique el primer fotograma temporizado completo. También contiene el límite de pares lógicos y de mirroring previamente probado.
Flujo de control
ppu_background_viewport_to_opaque_mask(ppu)
|
v
completed length == 240?
/ yes no
| |
v v
timed mask helper existing snapshot mask
| |
+------ return --+Invariantes importantes
- exactamente 240 entradas seleccionan el helper temporizado
- la rama temporizada retorna inmediatamente
- la construcción de máscara de origen antigua y la composición de fotograma completo no se ejecutan también
- tuplas vacías, parciales o sobredimensionadas seleccionan la reserva antigua
- la reserva sigue leyendo ppu.temp_vram_addr y ppu.fine_x
- la ruta del framebuffer y el código de sprite-zero-hit permanecen sin cambios
Concepto erróneo habitual
No captures errores del helper temporizado ni reintentes silenciosamente la reserva. La compuerta gestiona la disponibilidad de datos esperada. Una vez que un fotograma completo selecciona el helper temporizado, una excepción representa un invariante violado que debe permanecer observable.
¿Qué cambia en la práctica? Console ya usa esta máscara consciente del viewport para la composición de sprites y fondo. El RGB y la prioridad visual de sprites ahora pueden usar coordenadas temporizadas idénticas, corrigiendo casos como una seta apareciendo incorrectamente delante de un tile opaco. El helper independiente de sprite-zero-hit sigue usando su dependencia de máscara más antigua y se alineará en una lección posterior.
Fuera de alcance
- cambiar la composición de filas temporizadas
- cambiar la compuerta del framebuffer
- cambiar el consumo de máscara de sprite-zero-hit
- desplazamiento vertical completo de la fila de origen
Implementación de ejemplo completa
# emulator/rendering/ppu_background_renderer.py
def ppu_background_viewport_to_opaque_mask(
ppu: PPU,
) -> BackgroundOpaqueMask:
# --- NEW BLOCK: USE TIMED DATA ONLY FOR A COMPLETE FRAME ---
if (
len(ppu.completed_scanline_scroll_states)
== NAMETABLE_PIXEL_HEIGHT
):
return _timed_scanlines_to_opaque_mask(ppu)
# Existing temp_vram_addr + fine_x fallback remains unchanged below.
viewport_x, _ = decode_background_viewport_position(
temp_vram_addr=ppu.temp_vram_addr,
fine_x=ppu.fine_x,
)
...Ejecutar esta lección
uv run pytest tests/chapter_13_scrolling/test_352_select_timed_opaque_mask_path.py -v