348. Viewport x scanline
Декодировать горизонтальный viewport X из одного записанного состояния scanline.
Урок 348 из 356 · tests/chapter_13_scrolling/test_348_scanline_viewport_x.py
Файл для обновления
emulator/rendering/ppu_background_renderer.pyСсылка
https://www.nesdev.org/wiki/PPU_scrollingЗачем нужен этот шаг
Шаг 347 выбрал две логические nametable, которые образуют горизонтальную исходную пару. Позже композитор строк также нуждается в точном пикселе, где этот scanline начинается внутри этой 512-пиксельной пары.
Записанный адрес использует тот же упакованный макет полей прокрутки, что и t
yyy NN YYYYY XXXXXГоризонтальный viewport X использует
XXXXX coarse X tile column
low N bit horizontal nametable selection, vram_addr bit 10
state.fine_x pixel offset inside the first tileПреобразование пикселей
viewport_x = nametable_x * 256 + coarse_x * 8 + fine_xПример
nametable X = 1
coarse X = 5
fine X = 3
viewport X = 1 * 256 + 5 * 8 + 3 = 299Почему переиспользовать decode_background_viewport_position? Существующий чистый декодер уже владеет преобразованием упакованного поля прокрутки. И t, и записанный v имеют одинаковый макет битов, поэтому повторение масок и размеров в этом рендерере создаст две реализации, которые могут расходиться.
Важные инварианты
- горизонтальный бит nametable 10 вносит 256 пикселей
- coarse X вносит восемь пикселей на плитку
- fine X вносит финальное смещение пикселя 0-7
- вертикальный nametable, coarse Y и fine Y не влияют на viewport X
- результат остаётся внутри логического горизонтального диапазона 0-511
- записанный адрес не отмотан снова
- вспомогательная функция не выполняет рендеринг или доступ к памяти
Распространённое заблуждение
Записанный адрес не нуждается в другой двухплиточной коррекции. Шаг 345 уже отмотал копию v дважды перед построением BackgroundScanlineState. Повторение отмотки здесь неправильно сдвинет каждую отрендеренную строку на шестнадцать пикселей влево.
Вне области действия
- выбор логических адресов nametable
- композиция строк framebuffer
- применение горизонтального переноса к пикселям назначения
- композиция opacity-mask
- выбор синхронизированных данных в сравнении со старым fallback уровня кадра
Полный пример реализации
# emulator/rendering/ppu_background_renderer.py
# --- NEW BLOCK: DECODE ONE SCANLINE'S HORIZONTAL VIEWPORT ---
def _scanline_viewport_x(state: BackgroundScanlineState) -> int:
viewport_x, _ = decode_background_viewport_position(
temp_vram_addr=state.vram_addr,
fine_x=state.fine_x,
)
return viewport_xЗапустить этот урок
uv run pytest tests/chapter_13_scrolling/test_348_scanline_viewport_x.py -v