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:
@@ -464,6 +464,7 @@ int main(void)
|
||||
* по умолчанию (без мерцания); SPACE переключает в однобуфер для
|
||||
* отладки багов рисования (edge по sp_prev, чтоб не дёргать). */
|
||||
uint8_t front = 0, back, dbuf = 1, sp_prev = 0, frozen = 0;
|
||||
uint8_t skip = 0; /* маска «слот перерисовывать не надо» */
|
||||
uint16_t dead_frames = 0;
|
||||
#ifdef ROOMNAV
|
||||
uint8_t nav_prev = 0;
|
||||
@@ -645,8 +646,13 @@ int main(void)
|
||||
pop_check_skel(); /* спецсобытие ур.3: скелет встаёт */
|
||||
pop_check_can_guard_see_kid(); /* луч видимости — ДО логики персонажей */
|
||||
pop_ctrl_tick(); /* ввод -> control(): смена seq */
|
||||
pop_char_heal(POP_CH_KID); /* стереть прошлый кадр ЭТОЙ страницы */
|
||||
pop_char_heal(POP_CH_OPP); /* и прошлый кадр соперника */
|
||||
/* Кто в этом кадре не изменился с прошлой отрисовки ЭТОЙ страницы —
|
||||
* тот на ней уже нарисован правильно: ни стирать, ни рисовать заново
|
||||
* не надо (DRAW-COST, контракт в pop_cdraw.h). Решение
|
||||
* перепроверяется перед самой отрисовкой — тик ещё впереди. */
|
||||
skip = pop_char_skip_mask();
|
||||
if (!(skip & 1)) pop_char_heal(POP_CH_KID); /* стереть прошлый кадр ЭТОЙ страницы */
|
||||
if (!(skip & 2)) pop_char_heal(POP_CH_OPP); /* и прошлый кадр соперника */
|
||||
pop_fore_heal(); /* + следы оверлея (шире прямоугольника Kid) */
|
||||
PROF(2); /* логика (тот же синий) */
|
||||
kid_tick(); /* play_seq: следующий кадр */
|
||||
@@ -819,10 +825,14 @@ int main(void)
|
||||
* персонажа (см. guard_over_kid). Отрисовка одна на всех Char
|
||||
* (pop_cdraw.c), различает их только слот. */
|
||||
uint8_t g_after = guard_over_kid();
|
||||
if (!g_after) { pop_char_draw(POP_CH_OPP); pop_char_fore(POP_CH_OPP); }
|
||||
/* Пересчёт после тика: слот, за который heal не платили, мог
|
||||
* всё-таки сдвинуться — тогда бит снимется, а прошлый кадр
|
||||
* сотрёт сам pop_char_draw (страховка cd_heal). */
|
||||
skip = pop_char_skip_mask();
|
||||
if (!g_after && !(skip & 2)) { pop_char_draw(POP_CH_OPP); pop_char_fore(POP_CH_OPP); }
|
||||
PROF(6); /* кадр Кида (тот же циан) */
|
||||
pop_char_draw(POP_CH_KID); /* спрайт + брызги + клинок */
|
||||
if (g_after) { pop_char_draw(POP_CH_OPP); pop_char_fore(POP_CH_OPP); }
|
||||
if (!(skip & 1)) pop_char_draw(POP_CH_KID); /* спрайт + брызги + клинок */
|
||||
if (g_after && !(skip & 2)) { pop_char_draw(POP_CH_OPP); pop_char_fore(POP_CH_OPP); }
|
||||
/* Брызги урона рисует сама отрисовка персонажа (порядок objtable:
|
||||
* сразу после него и до клинка), а флаги снимаем здесь: соперника
|
||||
* могло не оказаться в отрисованной комнате — тогда брызги просто
|
||||
@@ -840,7 +850,12 @@ int main(void)
|
||||
* pop_char_fore(KID) заодно возвращает окно Кида (при «соперник
|
||||
* поверх» в нём остался бы соперник, и передние грани у Кида
|
||||
* отсеклись бы целиком — он рисовался бы поверх столбов). */
|
||||
pop_char_fore(POP_CH_KID);
|
||||
if (!(skip & 1)) pop_char_fore(POP_CH_KID);
|
||||
/* Персонажи на этой странице приведены в порядок — след «фон трогали»
|
||||
* для неё снят. ПОСЛЕ отрисовки, а не до: слой фона этого же кадра
|
||||
* взводит бит и обязан быть учтён. Всё, что рисуется ниже
|
||||
* (mob поверх Кида, борта), взводит его заново само. */
|
||||
pop_cd_dirty = (uint8_t)(pop_cd_dirty & ~(1 << back));
|
||||
pop_room_clip_borders(); /* почистить борта — только в кадрах падения (гейт) */
|
||||
|
||||
/* Пейсинг 3 кадра, затем tear-free флип на vblank: draw уже
|
||||
|
||||
Reference in New Issue
Block a user