P1: чомпер перерисовывался неизменной позой — минус 110 802 такта

Позиция заводилась с НЕПОЛНЫМ диагнозом.  Я приписал 190 260 тактов
пометке от факела (пламя лежит в ячейке правого соседа, то есть поверх
чомпера, и запекается каждый кадр).  Правка по этому диагнозу не дала
ничего: 769 002 против 768 684.

Зонд pop_dbg_kind показал факт: все 312 перерисовок прогона — вид
POP_RD_CHOMP, полная, и ни одной от факела.  Собственная пометка чомпера
просто перебивала пометку соседа.

Настоящая причина нашлась сверкой с animate_chomper (seg007:0448).
Оригинал заканчивает её так:

    if ((curr_modifier & 0x7F) < 6) redraw_at_trob();

то есть перерисовывает чомпер только пока фаза меньше 6 — пять кадров из
пятнадцати.  Это не оптимизация оригинала, а следствие таблицы поз:
chomper_fram1 = {3,2,0,1,4,3,3}, и с фазы 5 до конца круга поза одна и та
же.  Мы метили тайл каждый кадр, пока trob жив, а живёт он всё время, пока
Кид в том же ряду — то есть платили полный draw_tile плюс heal 32x64 за
неизменную картинку в двух третях кадров.

Сделано:

  1. пометка только при фазе < 6; на фазе 5 — обе страницы дабл-буфера
     (она последняя рисуемая, её поза обязана лечь на обе; вторую страницу
     пометка догоняет в кадре фазы 6, где поза та же — CHOMP_FRAM1[6] == 3);
  2. новый вид POP_RD_CHOMP_ANIM -> pop_chomp_anim_draw: три блита графики
     чомпера поверх свежего пламени, без heal и без остальных слоёв — порт
     ветки redraw_frames_anim (seg008:0211), где оригинал делает ровно
     draw_tile_anim_topright / draw_tile_anim_right / draw_tile_anim и
     никакого wipe;
  3. приоритет полной перерисовки над anim в pop_set_redraw: у оригинала
     это два независимых счётчика и full побеждает, а у нас вид один на
     тайл, и без проверки исход решал бы порядок trob'ов в списке.

Обе половины работают — замер даёт 40 % полных перерисовок и 60 % лёгких.
Работа 768 684 -> 657 882 (медиана), зелёная 294 510 -> 183 420.  В 40 %
кадров цена прежняя: там поза реально меняется, это честная работа.

Циан не сдвинулся ни на такт, то есть надежда P3 (Кид перестанет будиться
каждый кадр) пока не оправдалась — метки продолжают его будить.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 11:30:01 +03:00
parent f81b30eb68
commit de68eb5cec
7 changed files with 198 additions and 20 deletions
+45 -13
View File
@@ -72,7 +72,30 @@
## 3. Список приёмов, отсортированный по эффекту
### P1. Чомпер под факелом — возвращать только слой anim [модель: 160 000, 20 % работы]
### P1. Чомпер: перерисовка неизменной позы ✅ СДЕЛАНО 2026-08-19 — 110 802
**Диагноз, с которым позиция заводилась, оказался неполным.** Я приписал
190 260 тактов пометке от факела; зонд `pop_dbg_kind` показал, что все 312
перерисовок прогона — вид `POP_RD_CHOMP` (полная), а пометку соседа она
просто перебивала. Настоящая причина нашлась сверкой с `animate_chomper`
(seg007:0448): оригинал перерисовывает чомпер **только при фазе < 6**, пять
кадров из пятнадцати, потому что с фазы 5 поза не меняется
(`chomper_fram1 = {3,2,0,1,4,3,3}`). Мы метили тайл каждый кадр.
Сделано три вещи: условие фазы (с пометкой обеих страниц на фазе 5), новый
вид `POP_RD_CHOMP_ANIM``pop_chomp_anim_draw` (три блита поверх огня, порт
ветки `redraw_frames_anim`) и приоритет полной перерисовки над anim в
`pop_set_redraw`. Обе половины работают: замер даёт 40 % полных
перерисовок и 60 % лёгких.
Работа 768 684 → **657 882** (медиана), зелёная 294 510 → **183 420**.
В 40 % кадров цена осталась прежней — там поза действительно меняется, и это
уже честная работа; резать её дальше только через P7 (раскол `draw_tile`)
или P8 (ширина heal).
Полный разбор — [`perf_l11_room15.md`](perf_l11_room15.md) §6.
<details><summary>Исходная (неполная) постановка</summary>
Разбор в [`perf_l11_room15.md`](perf_l11_room15.md) §3. Сейчас пометка от
факела обрабатывается как `heal 32×64 + полный draw_tile` (190 260 тактов на
@@ -83,7 +106,7 @@
сближение с оригиналом, а не отход от него. Побочно снимает широкую пометку
«фон трогали» вокруг тайла чомпера — см. P3.
Новое, найдено 2026-08-19.
</details>
### P2. Синяя фаза разложена [ЗАМЕР 2026-08-19] — гипотеза не подтвердилась
@@ -279,7 +302,7 @@ BUG-LATTICE-DOORTOP, BUG-SEAM-WEDGE-1) — только отдельным за
| P5 | `loose_tick`: гейты холостого хода | ✅ **сделано** 2026-08-19 | 33 840 на кадре (ждали −28 000) |
| P2 | замер синей фазы | ✅ замерено 2026-08-19 | гипотеза «трамплины» отвергнута |
| P6 | замер `process_trobs` | ✅ замерено 2026-08-19 | 11 058 префетч + ~43 000 цикл |
| P1 | чомпер под факелом: только слой anim | **следующее** | ждём 160 000 |
| P1 | чомпер: перерисовка только при фазе < 6 | **сделано** 2026-08-19 | 110 802 (ждали 160 000) |
| P2b | гейт луча видимости стража | ⬜ | ждём −30 000, риск низкий |
| P4 | накладные блита (4 правки) | ⬜ | ждём −28 000 |
| P11 | мелочи с известной ценой | ⬜ | ждём −26 000 |
@@ -297,30 +320,39 @@ BUG-LATTICE-DOORTOP, BUG-SEAM-WEDGE-1) — только отдельным за
| источник | ожидание |
|---|---:|
| P1 (чомпер: только слой anim) | 160 000 |
| P3 (Кид перестанет будиться, следствие P1) | 70 000 |
| ~~P1 (чомпер)~~ | ~~160 000~~**сделано, 110 802** |
| P3 (Кид перестанет будиться) | −70 000**под вопросом**, см. ниже |
| P2b (гейт луча видимости) | −30 000 |
| P4 (накладные блита) | −28 000 |
| P11 (мелочи) | 26 000 |
| P10 (футпринт из физики) | −23 000 |
| P6a+P6b | 20 000 |
| **сумма** | **357 000** |
| **сумма оставшегося** | **197 000** |
То есть цель достижима, но **впритык и только если сделать ВСЁ перечисленное**,
причём половина суммы держится на одной позиции (P1). Запаса нет, и любая
позиция, давшая меньше ожидаемого, возвращает нас к разбору `pop_phys_tick`
(P2a) — 105 246 тактов на физику двух НЕПОДВИЖНЫХ персонажей, где цена
измерена, а причина ещё не найдена.
**После P1 картина изменилась к худшему.** Снять с дорогого кадра надо
336 000, а всё оставшееся в списке даёт 197 000 — и это при оптимистичных
оценках. Вдобавок P3 (Кид перестанет будиться) теперь под вопросом: циан
после P1 не сдвинулся ни на такт (187 761), то есть метки от чомпера и
факелов продолжают будить обоих персонажей в каждом кадре.
Значит без **P2a — разбора `pop_phys_tick`** (105 246 тактов на физику двух
НЕПОДВИЖНЫХ персонажей, цена измерена, причина не найдена) период 3 растра
не берётся. Это и есть следующая крупная позиция.
**Текущее состояние бюджета 11/15:**
| | работа | синяя | зелёная | циан | период |
|---|---:|---:|---:|---:|---:|
| до оптимизации | 801 768 | 293 238 | 320 916 | 187 758 | 4 растра |
| после P5 | **767 928** | 285 864 | 294 384 | 187 764 | 4 растра |
| после P5 | 767 928 | 285 864 | 294 384 | 187 764 | 4 растра |
| после P1 (медиана) | **657 882** | 286 503 | 183 420 | 187 761 | 4 растра |
| после P1 (дорогой кадр, 40 %) | 765 936 | 286 503 | 291 888 | 187 761 | 4 растра |
Цель — уложить РАБОТУ в 430 000 (тогда период станет 3 растра вместо 4;
хвост кадра — три `gfx_wait_vsync`). Осталось снять **338 000**.
хвост кадра — три `gfx_wait_vsync`). Осталось снять **228 000** с медианы
и **336 000** с дорогого кадра. Считать надо по ДОРОГОМУ: период задаётся
каждым кадром отдельно, и пока дорогие кадры не влезут, 40 % кадров будут
идти по 4 растра.
### Как воспроизвести сцену (важно для следующей сессии)