Commit Graph

3 Commits

Author SHA1 Message Date
snark13 65797af44c Ресурсы — в архивы PBA1; тайминги сцены PV — по часам насоса CBL
ТАЙМИНГИ.  Пользователь заметил, что заклинание Джафара не совпадает с
музыкой. Замер в MAME (breakpoint на вспышке + курсор трека): реплика m53
успевала ДОИГРАТЬ до молнии, хотя по шкале оригинала между входом Джафара
и заклинанием ровно 822 тика = 13,7 с.

Причина: пейсинг считал НАШИ ожидания vsync, а не прошедшее время.
Полноэкранная копия страницы стоит больше кадра луча, и разница копилась.
Кадровые прерывания для счёта не годятся (теряются в di-окнах
акселератора), поэтому часами стал насос CBL: он идёт от расхода буфера
железом, 85,4 Гц, и ему безразлично, чем занят главный цикл. Один тик
оригинала = 57/40 тика насоса (0,07 % ошибки, без деления в кадре).
Когда звук выключен, работает прежний путь по кадрам луча.

После фикса замер даёт 229 блоков остатка m53 против расчётных 233 —
расхождение 47 мс.

АРХИВЫ.  Группы ресурсов сложены в PBA1: kid (58 атласов), pv (78),
shadow (32), bg (25), title (20), guard (10), vizier (5), skel (4). Было
232 файла на образе, стало 8 архивов плюс шесть палитр и таблицы уровней.
При цене `open` 51,4 мс против 32,6 мс за чтение 16 КБ это возвращает
секунды на каждой загрузке.

- pop_pack_arc.py печатает индексы элементов константами (ARC_<GRP>_<FILE>),
  порядок задаёт Makefile, а серии код проверяет статически;
- atlas_load разделён: atlas_attach принимает уже прочитанную страницу,
  поэтому чтение из архива не дублирует проверку магии и подготовку W0;
- имена архивов живут в pop_arc.c и адресуются номером. Строковый литерал
  лежит в rodata своего банка, и указатель на него из другого банка после
  переключения W3 показывает на чужие данные — ровно так падала загрузка
  фона (поймано брейкпоинтом на puts).

Проверено в MAME: заставка, интро и уровень 1 собираются из архивов,
Тень грузит все 32 страницы. Host-тесты: 15 наборов.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 21:29:14 +03:00
snark13 5b6664ffce Зеркальные кадры персонажей — готовыми файлами, а не разворотом в рантайме
Замеры в MAME (такты Z80, кадр = 430 000) решили вопрос однозначно:
  загрузка 28 атласов Кида с HDD  — 27 160 092 такта (1.26 с), 970 003 на страницу;
  разворот ОДНОЙ страницы на месте — 12 645 582 такта (0.59 с), т.е. 771 такт/байт.
Даже идеальный вариант (копия accel'ом ~0.25 кадра + asm-реверс ~2.2 кадра)
дал бы ~1.05 млн на страницу — то есть в лучшем случае сравнялся бы с чтением
готового файла.  На 34 страницы: 1.5 с загрузки против 20 с разворота.

* Упаковщики пишут второй набор: vflip_cols/vflip_page в pop_pack_kid.py ->
  kid0_v.atl…kid27_v.atl, sword_v.atl; pop_pack_guard.py -> g0_v.atl…g4_v.atl
  ТОЛЬКО для обычного стража (на уровне 9 tbl_guard_type = 0; тень рисуется
  атласами Кида, скелет/визирь с переворотом не встречаются).
* pop_vflip.c схлопнулся до таблицы «страница -> зеркальная пара»; весь
  побайтовый разворот и аллокация EMM удалены.
* pop_vflip_load_all (банк 8) грузит набор ОДНИМ вызовом и откуда угодно —
  задел под загрузку ресурсов во время интро.  Зовётся при старте и при
  смене уровня, если это POP_UPSIDE_LEVEL; чит U на других уровнях поднимает
  набор лениво (страховка в главном цикле).
* Стартовый уровень стал параметром сборки: make LEVEL=N (-DFIRST_LEVEL).

Проверено в MAME на уровне 9: переворот мгновенный, pop_flip_screen = 897 263
такта (2.1 кадра) — это сама копия экрана, загрузки в кадре больше нет.
tests-host 6/6.
2026-08-12 23:17:22 +03:00
snark13 755190674c L9-INVERT II.4: персонажи рисуются перевёрнутыми (зеркальные страницы атласов)
Спрайты персонажей хранятся column-major (ради бесплатного H-флипа), а
вертикальное зеркало у такой раскладки — разворот байтов ВНУТРИ колонки,
чего accel не умеет.  Поэтому pop_vflip.c готовит зеркальные КОПИИ страниц
атласов: копия побайтово повторяет раскладку .atl (заголовок, каталог,
смещения лент), развёрнуты только пиксели — значит вызывающему достаточно
подменить номер страницы, которую он мапит в W0.

* Кэш ленивый (страница зеркалится при первом обращении в перевёрнутом
  виде) и живёт до смены уровня — зелье переключает состояние туда-обратно,
  перезеркаливать по 16 КБ на каждый переворот незачем.  EMM хватает: 34
  страницы из ~215 свободных.
* pop_cdraw/pop_kdraw: страница + позиция (top = 191 - obj_y для персонажа,
  192 - top - h для клинка).  «Пропустить skip строк сверху» у зеркальной
  ленты = «срезать снизу» у оригинала, поэтому клипы считаются как обычно.
* Модуль резидентный: он маппит W3 (приёмник копии) — банку так нельзя.
* pop_vflip_reset на смене уровня: копии сделаны из старых страниц.

Проверено в MAME: чит U переворачивает всё разом, Кид и факелы вверх ногами,
полоса HP на месте, бег без следов на фоне (heal бьёт в те же координаты).

ОСТАЁТСЯ (L9-CLIPCHAR): clip_char в перевороте должен резать снизу, а не
сверху — пока при pop_upside не режем вовсе.  Тени/брызг это не касается.
2026-08-12 22:25:18 +03:00