Архивы ресурсов PBA1: звук одним файлом, музыка потоком; ALLOCS 6000
ЗАМЕР, из которого всё выросло (MAME, 2026-08-25): `open` стоит 51,4 мс, а чтение 16 КБ из уже открытого файла — 32,6 мс. То есть 61 % времени загрузки уходит на ОТКРЫТИЕ, а не на данные, и чистая скорость чтения — 491 КБ/с, а не 260. На диске игры 343 файла; одна только стартовая пачка (kid+shadow+bg+sound+guard, ~142 файла) — это 7,3 секунды чистого open. * toolchain/pop_pack_arc.py + pop_arc.c/h (банк 8) — формат PBA1: заголовок 512 Б, магия, count, записи по 4 байта (offset в СЕКТОРАХ — архив бывает больше 64 КБ; size в байтах — ресурс всегда <= 16 КБ, он обязан лезть в EMM-страницу). Таблицу держит вызывающий на своём стеке: в W2 её класть нельзя, а стека в точке загрузки израсходовано 75 байт из 1279 (замер там же). * libc: bank_read_page — чтение из УЖЕ ОТКРЫТОГО файла в EMM-страницу. bank_load_file переписана через неё, поэтому дублирования работы с W3 не осталось и резидент почти не вырос. * Набор эффектов: 10 файлов -> SND\snd.arc, один open вместо десяти. * Музыка: трек лежит ОДНИМ файлом и читается порциями по странице — нарезка на куски больше не нужна. Этот же путь понадобится финалу `won` (1,2 МБ), который в память целиком не влезает. * Менеджер звука приведён к оригиналу: играющая музыка участвует в таблицах приоритета наравне с эффектами (seg000:1672 + data.h:433). Почти вся музыка НЕперебиваема, поэтому поверх неё эффект не стартует — ровно как в SDLPoP; раньше эффект её перебивал. * ALLOCS 3000 -> 6000 (решение пользователя): сборка +20 с, резидент -161 байт. Куча 87 -> 248 Б. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* pop_arc.c — чтение архива ресурсов PBA1, БАНК 8.
|
||||
*
|
||||
* Контракт и мотивация — в pop_arc.h. Здесь всё сводится к трём вызовам
|
||||
* libc: open один раз на группу, lseek к элементу и bank_read_page прямо в
|
||||
* EMM-страницу (тот резидентен и потому безопасен из банка huge — он же
|
||||
* переключает W3, где живёт наш код).
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sprinter_mem.h>
|
||||
#include "pop_arc.h"
|
||||
|
||||
int8_t pop_arc_open(pop_arc_t *a, const char *path,
|
||||
uint8_t *tbl, uint8_t tbl_max) __banked
|
||||
{
|
||||
uint8_t head[8];
|
||||
int fd;
|
||||
|
||||
a->fd = -1;
|
||||
a->count = 0;
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
if (read(fd, head, sizeof(head)) != (int)sizeof(head) ||
|
||||
memcmp(head, "PBA1", 4) != 0 ||
|
||||
head[4] == 0 || head[4] > tbl_max || head[4] > POP_ARC_MAX) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (read(fd, tbl, (uint16_t)head[4] * POP_ARC_REC) !=
|
||||
(int)((uint16_t)head[4] * POP_ARC_REC)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
a->fd = fd;
|
||||
a->count = head[4];
|
||||
return (int8_t)head[4];
|
||||
}
|
||||
|
||||
uint16_t pop_arc_size(const uint8_t *tbl, uint8_t idx)
|
||||
{
|
||||
const uint8_t *rec = tbl + (uint16_t)idx * POP_ARC_REC;
|
||||
return (uint16_t)(rec[2] | ((uint16_t)rec[3] << 8));
|
||||
}
|
||||
|
||||
int pop_arc_read(pop_arc_t *a, const uint8_t *tbl, uint8_t idx, uint16_t skip,
|
||||
uint8_t page, uint16_t off, uint16_t size) __banked
|
||||
{
|
||||
const uint8_t *rec;
|
||||
uint16_t sec, len;
|
||||
long pos;
|
||||
|
||||
if (a->fd < 0 || idx >= a->count) return -1;
|
||||
rec = tbl + (uint16_t)idx * POP_ARC_REC;
|
||||
sec = (uint16_t)(rec[0] | ((uint16_t)rec[1] << 8));
|
||||
len = (uint16_t)(rec[2] | ((uint16_t)rec[3] << 8));
|
||||
if (skip >= len) return 0;
|
||||
len = (uint16_t)(len - skip);
|
||||
if (size && size < len) len = size;
|
||||
|
||||
/* Сектора в байты — единственное место, где нужна 32-битная величина:
|
||||
* архив может быть больше 64 КБ, и lseek принимает long. Путь холодный
|
||||
* (загрузка ресурсов), в кадре этого нет. */
|
||||
pos = ((long)sec << 9) + (long)skip;
|
||||
if (lseek(a->fd, pos, SEEK_SET) < 0) return -1;
|
||||
return bank_read_page(a->fd, page, off, len);
|
||||
}
|
||||
|
||||
void pop_arc_close(pop_arc_t *a) __banked
|
||||
{
|
||||
if (a->fd >= 0) close(a->fd);
|
||||
a->fd = -1;
|
||||
a->count = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user