From c9a4efe11994ca1d6595f1751fe9e814c0e0e5b7 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Wed, 12 Aug 2026 15:58:16 +0300 Subject: [PATCH] =?UTF-8?q?L9-INVERT:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=BE=D1=80=D0=BE=D1=82=20=D1=8D=D0=BA=D1=80=D0=B0=D0=BD=D0=B0?= =?UTF-8?q?=20accel-=D0=BA=D0=BE=D0=BF=D0=B8=D0=B5=D0=B9=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BA=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=B2=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=20+=20UI-SPRITES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Момент переключения зелья переворота делаем не перерисовкой комнаты, а двумя построчными проходами акселератора (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 --- applications/PoP/roomtest/TASKS_OPEN.md | 65 +++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/applications/PoP/roomtest/TASKS_OPEN.md b/applications/PoP/roomtest/TASKS_OPEN.md index a67c073..17fa25f 100644 --- a/applications/PoP/roomtest/TASKS_OPEN.md +++ b/applications/PoP/roomtest/TASKS_OPEN.md @@ -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). + +### 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 (поле, переворачиваются). После переноса обе страницы +становятся чисто «полевыми», и постраничный кэш перевёрнутых кадров получается +однородным, без спрайтов-исключений. + ### MEM-COLD2. Второй шаг разгрузки резидента