DRAW-COST шаг 1: пропуск неизменившегося персонажа — 210% -> 116% кадра
Персонаж, у которого с прошлой отрисовки ЭТОЙ страницы дабл-буфера не изменился ни один вход отрисовки, а фон в его прямоугольнике не трогали, уже нарисован правильно: heal, блит и fore-проход пропускаются целиком. Не спецкейс «мёртвый страж», а общее правило — покрывает и труп, и стоящего Кида, и ждущего стража. Механизм: снимок входов по страницам (pop_cdraw.c, cd_sig/cd_quiet) + позиционная метка «фон трогали вот здесь» (pop_cd_touch в резидентном pop_tile.c, зовёт сам pop_blit_b). Решение перепроверяется перед отрисовкой, а pop_char_draw страхуется собственным heal — если тик всё-таки сдвинул персонажа, прошлый кадр стирается там. Слоты рядом (32 px) — перерисовываем оба, иначе heal соседа выест кусок из «тихого». Метка обязана быть ПОЗИЦИОННОЙ: с флагом «фон трогали хоть где-то» выигрыш был ровно нулевым — факелы анимируются каждый кадр и гасили пропуск для всех сразу (597 684 такта, как без оптимизации). Замеры (MAME, брейкпоинты по totalcycles, бюджет кадра 430 000): комн. 1.3, труп стража, Кид стоит: 210 % -> 116 % (500 772 такта), ноль вызовов pop_heal_fast за кадр, весь фон — 2 блита (44 136); комн. 1.1, Кид стоит вдали от факелов: 404 112 (94 %), цикл 4 -> 3 кадра. Узкое место сместилось на ЛОГИКУ: 60 % кадра уходит на тик персонажей, которые СТОЯТ, ещё 28 % — на loose_tick + process_trobs в комнате без единой ловушки. Разбивка и план — TASKS_OPEN.md#draw-cost.
This commit is contained in:
@@ -90,4 +90,45 @@ void pop_char_fore(uint8_t who) __banked;
|
||||
/* Straddle-смещение спрайта (см. render_dx). */
|
||||
void pop_char_set_render_dx(uint8_t who, int dx) __banked;
|
||||
|
||||
/* ---- Пропуск НЕИЗМЕНИВШЕГОСЯ кадра (DRAW-COST) ---------------------- *
|
||||
* heal + спрайт + fore-проход стоят ~50 % кадрового периода НА ПЕРСОНАЖА
|
||||
* (замер пользователя 2026-08-08: комната 1.3 с телом убитого стража — 210 %
|
||||
* кадра, соседняя 1.2 без тела — 140 %). Платили мы это и за то, что не
|
||||
* менялось: труп лежит неподвижно до выхода из комнаты, стоящий Кид — пока
|
||||
* игрок не нажал клавишу, а перерисовывались они каждый кадр.
|
||||
*
|
||||
* Оптимизация: у каждой страницы дабл-буфера свой снимок ВХОДОВ отрисовки
|
||||
* слота (поза, координаты, направление, меч, брызги, straddle). Если снимок
|
||||
* совпал, спрайт этой страницы не стёрт и фона под ним никто не трогал —
|
||||
* нужный кадр на странице УЖЕ нарисован, и heal/draw/fore пропускаются
|
||||
* целиком.
|
||||
*
|
||||
* `pop_cd_touch` — «фон трогали ВОТ ЗДЕСЬ»: слой фона копит ПРЯМОУГОЛЬНИК
|
||||
* своих правок по страницам дабл-буфера, и слот перерисовывается, только
|
||||
* если тот задел его самого. Флага «трогали хоть что-то» не хватило:
|
||||
* факелы анимируются КАЖДЫЙ кадр, и один факел в комнате обнулял пропуск
|
||||
* для всех персонажей сразу (замер 2026-08-08: комната 1.1, Кид стоит —
|
||||
* 597 684 такта, то есть ровно как без оптимизации).
|
||||
*
|
||||
* Метку ставит сам блит фона (`pop_blit_b`, по признаку «идёт не
|
||||
* fore-проход») плюс те немногие места, что стирают фон голым `bar` или
|
||||
* своим heal (падающий кусок, оверлей fore-heal). Координаты — ЭКРАННЫЕ
|
||||
* (с POP_YOFF). Прямоугольник копится сразу для ОБЕИХ страниц: правку фона
|
||||
* почти всегда повторяют на второй, а лишняя перерисовка персонажа дешевле
|
||||
* лишнего состояния. Снимает метку главный цикл — после того, как
|
||||
* персонажи на этой странице отрисованы.
|
||||
*
|
||||
* Резидент (pop_tile.c): зовёт и банковый слой фона, и резидентные листья,
|
||||
* а трамплин на КАЖДЫЙ кусок фона стоил бы дороже самой метки. */
|
||||
extern uint8_t pop_cd_dirty; /* биты страниц: прямоугольник взведён */
|
||||
extern int pop_cd_dx0[2], pop_cd_dy0[2], pop_cd_dx1[2], pop_cd_dy1[2];
|
||||
void pop_cd_touch(int x, int y, int w, int h);
|
||||
#define POP_CD_TOUCH_ALL() pop_cd_touch(0, 0, 320, 256)
|
||||
|
||||
/* Кого в этом кадре можно НЕ перерисовывать: бит 0 — Кид, бит 1 — соперник.
|
||||
* Звать ДВАЖДЫ: перед heal (стирать нечего) и перед отрисовкой (тик мог
|
||||
* персонажа всё-таки сдвинуть — тогда бит снимется сам, а pop_char_draw
|
||||
* сотрёт прошлый кадр за нас). */
|
||||
uint8_t pop_char_skip_mask(void) __banked;
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user