L9-INVERT: переворот экрана accel-копией как основной вариант + UI-SPRITES
Момент переключения зелья переворота делаем не перерисовкой комнаты, а двумя построчными проходами акселератора (A->B с реверсом Y, B->A без): accel читает ОЗУ-копию, поэтому копируется чистый фон и ложится и в видео, и в копию приёмника — heal остаётся без изменений. Бюджет 768 burst-строк (0.2-0.3 логического кадра) против почти миллиона тактов у перерисовки. Отдельным пунктом: деления HP переезжают из column-major атласов в const-массивы резидента, что убирает pop_kid_img_blit (334 Б) и делает страницы kid27/g0 однородными для кэша перевёрнутых кадров. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -62,11 +62,47 @@
|
||||
после (seg000:939/946); полоса HP рисуется прямо на экран (y = 194) и НЕ
|
||||
переворачивается.
|
||||
|
||||
**Приём оригинала нам не подходит:** мы рисуем инкрементально прямо в
|
||||
видеостраницу (heal + спрайты), готового offscreen-кадра нет, и «перевернуть
|
||||
буфер на вывод» означало бы полный кадровый блит 61 440 Б. Значит
|
||||
переворачиваем НА ОТРИСОВКЕ: `y' = POP_YOFF + POP_PLAYFIELD_H - (y - POP_YOFF) - h`
|
||||
плюс вертикальное зеркало самого спрайта.
|
||||
**Приём оригинала — переворачивать буфер на выводе КАЖДЫЙ кадр — нам не
|
||||
подходит:** страниц ровно две (`gfx_set_visible_page` → ESTEX $54 SELPAGE,
|
||||
бит 0), рабочей третьей нет, а переворот в видимую страницу порвёт картинку
|
||||
(проход не влезает в vblank). Значит переворачиваем ОДИН РАЗ в момент смены
|
||||
флага, а дальше рисуем зеркально:
|
||||
`y' = POP_YOFF + POP_PLAYFIELD_H - (y - POP_YOFF) - h` плюс вертикальное
|
||||
зеркало самого спрайта.
|
||||
|
||||
#### Момент переключения — accel-копия экрана (ОСНОВНОЙ ВАРИАНТ)
|
||||
|
||||
Решение пользователя 2026-08-12. Уже нарисованное переворачиваем не
|
||||
перерисовкой комнаты, а построчной копией акселератора:
|
||||
|
||||
1. **проход A → B с реверсом Y**: строка `y` читается, пишется в `191-y`
|
||||
(смена Port_Y между burst-чтением и burst-записью). 320 байт в один burst
|
||||
не лезут — две скобки на строку;
|
||||
2. **проход B → A без реверса**: вторая страница дабл-буфера получает то же
|
||||
изображение.
|
||||
|
||||
Почему это работает на нашем железе, а не только на бумаге: **accel читает
|
||||
ОЗУ-КОПИЮ, а не VRAM** (memory `accel_block_ops`), то есть копируется ЧИСТЫЙ
|
||||
фон без персонажей, а запись банком `GFX_BANK_NORMAL` идёт и в видео, и в
|
||||
ОЗУ-копию приёмника. После двух проходов обе страницы имеют перевёрнутый фон
|
||||
в обеих плоскостях — **heal не меняется ни на строку**, он и дальше
|
||||
восстанавливает правильный фон по фактическим координатам отрисовки.
|
||||
|
||||
Бюджет: 192 строки × 2 burst'а × 2 прохода = 768 burst-строк. По нашим
|
||||
замерам строка-burst стоит ~300-530Т (`gfx_heal_noclip` 22×22 = 11 658Т →
|
||||
530Т/строку; у заливки линия 51-53Т, но там нет данных) — итого
|
||||
**230-410 К тактов, то есть 0.2-0.3 логического кадра** (логический = 3
|
||||
растровых ≈ 1.29 млн). Перерисовка комнаты в обе страницы стоила бы под
|
||||
миллион тактов И требовала бы vflip-версии тайлового блита — здесь она не
|
||||
нужна вовсе.
|
||||
|
||||
Что дописать в libbgi: `_bgi_copy_rows_raw` умеет только ИНКРЕМЕНТ Port_Y на
|
||||
строку (`y0` + шаг вперёд, страйды патчатся SMC) — нужен вариант с
|
||||
декрементом одной стороны (параметр «шаг Y» либо отдельное ядро
|
||||
`_bgi_flip_rows_raw`). Перед реализацией подтвердить ДАМПОМ, что обе
|
||||
страницы одновременно адресуемы в W3: `gfx.h` говорит, что страница 1
|
||||
начинается на 320 байт дальше (0xC140), но это комментарий, а не проверка
|
||||
(memory `defer_unexplained_quirks`).
|
||||
|
||||
Зеркало по вертикали стоит по-разному в зависимости от раскладки спрайта:
|
||||
|
||||
@@ -96,6 +132,25 @@
|
||||
fore-слоя, и клип (`clip_char`), и брызги; полоса HP и лейбл комнаты остаются
|
||||
как есть (они вне поля 192).
|
||||
|
||||
<a id="ui-sprites"></a>
|
||||
### UI-SPRITES. Деления HP — из атласов персонажей в константы резидента
|
||||
|
||||
`pop_kid_img_blit` (**334 Б в W1/W2**) существует ради двух картинок 6×5:
|
||||
полосе HP нужен блит по image id из кидовских атласов, а те column-major, и
|
||||
обычным `gfx_blit_noclip` их не нарисовать. Деления Кида (images 216/217,
|
||||
`kid27.atl`) и стража (idx 0 в `g0.atl`) — по 30 байт каждое.
|
||||
|
||||
**Решение пользователя 2026-08-12: положить их const-массивами в РЕЗИДЕНТ**
|
||||
(~68 Б данных), а не подселять в фоновый атлас: резидент всегда ниже
|
||||
0xC000, значит `gfx_blit*` их видит (буфер обязан быть вне W3), EMM-страница
|
||||
не тратится, упаковщики не трогаются. Чистая экономия ~266 Б.
|
||||
|
||||
Побочный плюс для [L9-INVERT](#l9-invert): страницы `kid27` и `g0` сейчас
|
||||
смешанные — деления HP (борт, не переворачиваются) лежат рядом с брызгами
|
||||
крови 28×26 (поле, переворачиваются). После переноса обе страницы
|
||||
становятся чисто «полевыми», и постраничный кэш перевёрнутых кадров получается
|
||||
однородным, без спрайтов-исключений.
|
||||
|
||||
<a id="mem-cold2"></a>
|
||||
### MEM-COLD2. Второй шаг разгрузки резидента
|
||||
|
||||
|
||||
Reference in New Issue
Block a user