Ресурсы — в архивы 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>
This commit is contained in:
2026-08-25 21:29:14 +03:00
parent d86adc54c4
commit 65797af44c
40 changed files with 997 additions and 244 deletions
+27 -10
View File
@@ -10,6 +10,8 @@
#include <stdint.h>
#include <gfx.h>
#include <sprite.h>
#include "pop_arc.h"
#include "shadow_arc.h"
#include "pop_shadow.h"
#include "pop_shadow_atlas.h"
@@ -37,19 +39,34 @@ int pop_shadow_load(void) __banked
uint8_t i;
if (pop_shadow_kid_n || pop_shadow_fgt_n) return 0; /* уже загружен */
for (i = 0; i < POP_SHADOW_KID_PAGES; i++) {
if (atlas_load(&pop_shadow_kid[i], pop_shadow_kid_atl[i]) != 0) {
pop_shadow_free();
{
uint8_t tbl[ARC_SHADOW_COUNT * POP_ARC_REC];
pop_arc_t arc;
/* Тридцать два атласа — из одного архива: раньше это были тридцать
* два `open` по 51,4 мс, то есть полторы секунды на ровном месте. */
if (pop_arc_open_id(&arc, POP_ARC_SHADOW, tbl,
ARC_SHADOW_COUNT) < 0)
return -1;
for (i = 0; i < POP_SHADOW_KID_PAGES; i++) {
if (pop_arc_atlas(&arc, tbl, (uint8_t)(ARC_SHADOW_SK0 + i),
&pop_shadow_kid[i]) != 0) {
pop_arc_close(&arc);
pop_shadow_free();
return -1;
}
pop_shadow_kid_n = (uint8_t)(i + 1);
}
pop_shadow_kid_n = (uint8_t)(i + 1);
}
for (i = 0; i < POP_SHADOW_FGT_PAGES; i++) {
if (atlas_load(&pop_shadow_fgt[i], pop_shadow_fgt_atl[i]) != 0) {
pop_shadow_free();
return -1;
for (i = 0; i < POP_SHADOW_FGT_PAGES; i++) {
if (pop_arc_atlas(&arc, tbl, (uint8_t)(ARC_SHADOW_SF0 + i),
&pop_shadow_fgt[i]) != 0) {
pop_arc_close(&arc);
pop_shadow_free();
return -1;
}
pop_shadow_fgt_n = (uint8_t)(i + 1);
}
pop_shadow_fgt_n = (uint8_t)(i + 1);
pop_arc_close(&arc);
}
pop_shadow_pal_apply();