Документы по фазам: результаты дня и оставшийся план
Зелёная и циан — раскладка ПОСЛЕ правок, журнал правок с коммитами, отрицательные результаты с объяснением причины (окно клипа в pop_floor_bake — три попытки), и что осталось: раскол draw_tile на девять узких частей по образцу seg008:01C7. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
Рабочий документ: живёт между сессиями. Внизу **журнал правок** — каждая
|
||||
запись с замером до/после. Сцена, рецепт воспроизведения и зонды —
|
||||
[`perf_l13_room23.md`](perf_l13_room23.md); там же ответ про 8-битные
|
||||
габариты. Парная фаза — [`perf_cyan_phase.md`](perf_cyan_phase.md).
|
||||
габариты. Парная фаза — [`perf_cyan_phase.md`](perf_cyan_phase.md) (её цель
|
||||
достигнута).
|
||||
|
||||
Границы фазы в `roomtest.c`: от `PROF(4)` (строка 450) до `PROF(6)`
|
||||
(строка 620). Содержимое: `pop_loose_tick`, `pop_process_trobs`,
|
||||
@@ -11,209 +12,224 @@
|
||||
|
||||
**Бюджет: ≤ 400 000 тактов (растровый кадр = 430 000).**
|
||||
|
||||
| состояние | зелёная |
|
||||
|---|---:|
|
||||
| покой в комнате 23 | 35 760 |
|
||||
| дрожат 6 плит-потолков | 366 000 |
|
||||
| **пик каскада (провалы + посадки)** | **805 000 (2,0× бюджета)** |
|
||||
| состояние | было (`c312e4a`) | стало (`af189a1`) |
|
||||
|---|---:|---:|
|
||||
| покой в комнате 23 | 35 760 | 35 760 |
|
||||
| дрожат 6 плит-потолков | 366 000 | 335 400 |
|
||||
| **пик каскада** | **805 000** | **546 900** |
|
||||
|
||||
**ЦЕЛЬ ФАЗЫ НЕ ДОСТИГНУТА: 546 900 против 400 000 (1,37×).** Что осталось
|
||||
сделать и почему это именно раскол `draw_tile` — §3.
|
||||
|
||||
---
|
||||
|
||||
## 1. Раскладка (замер 2026-08-17, `c312e4a`, зонды m5/m6/m7 + kind/m16)
|
||||
## 1. Раскладка ПОСЛЕ правок (замер `af189a1`)
|
||||
|
||||
### 1.1 Верхний уровень
|
||||
Пик — кадры 24-28 (посадки плит), больше не кадры провалов.
|
||||
|
||||
| участок | покой | дрожь | пик |
|
||||
|---|---:|---:|---:|
|
||||
| `pop_loose_tick` | 25 602 | 35 646 | **196 152** |
|
||||
| `pop_loose_tick` | 36 234 | 36 234 | **156 762** |
|
||||
| `pop_process_trobs` | 1 050 | 1 050 | 1 050 |
|
||||
| **`pop_redraw_needed`** | 924 | **319 944** | **737 322** |
|
||||
| хвост (шов, смена уровня, сигналы, вспышка) | 9 336 | 9 336 | 11 964 |
|
||||
| **`pop_redraw_needed`** | 924 | 288 800 | **380 568** |
|
||||
| хвост (шов, смена уровня, сигналы, вспышка) | 9 336 | 9 336 | 10 776 |
|
||||
|
||||
**`pop_redraw_needed` — 91 % фазы на пике.**
|
||||
`pop_loose_tick` изнутри на пике: два цикла по тайлам 9 852,
|
||||
**`pop_loose_mob_tick` 154 074** (heal шести летящих кусков), остальное мелочь.
|
||||
|
||||
### 1.2 `pop_loose_tick` изнутри (зонды m9..m12)
|
||||
### Цена одной перерисовки: было → стало
|
||||
|
||||
| участок | покой | пик |
|
||||
|---|---:|---:|
|
||||
| два цикла по тайлам (30 + 10 позиций) | 11 004 | 9 852 |
|
||||
| **`pop_loose_mob_tick`** (heal летящих кусков) | 7 416 | **178 494** |
|
||||
| `check_loose_fall_on_kid` | 6 120 | 3 480 |
|
||||
| хвост | 324 | 3 252 |
|
||||
| вид | было | стало | чем |
|
||||
|---|---:|---:|---|
|
||||
| `RDA_CEIL` — дрожащая плита-потолок | 48 785 | **43 536** | G2 + G3 |
|
||||
| `RDA_CEIL_GONE` — запечь колодец | 251 335 | **138 318** | **G1** (клип полосы) + G2 + G3 |
|
||||
| `RD_FLOOR` — щебень на месте посадки | 198 805 | **179 914** | G2 + G3 + снятая двойная пометка |
|
||||
|
||||
`pop_loose_mob_tick` при шести кусках в воздухе — **≈29 700 такта на кусок**.
|
||||
Это heal прошлой позиции (коридор `MOB_W × 64`) плюс `pop_cd_touch` на
|
||||
коридор плюс `mob_tick_one`.
|
||||
Штук за кадр: `RDA_CEIL` до 6, `RDA_CEIL_GONE` до 2, `RD_FLOOR` до 2.
|
||||
|
||||
### 1.3 Цена ОДНОЙ перерисовки по видам (66 + 12 + 12 замеров)
|
||||
### Детальный профиль `RD_FLOOR` (179 914) — главная оставшаяся статья
|
||||
|
||||
| вид | штук замерено | средняя цена | сколько за кадр | Σ за кадр |
|
||||
|---|---:|---:|---:|---:|
|
||||
| `RDA_CEIL` — дрожащая плита-потолок | 66 | **48 658** | до 6 | 292 000 |
|
||||
| `RDA_CEIL_GONE` — запечь колодец | 12 | **251 023** | до 2 | 619 000 |
|
||||
| `RD_FLOOR` — щебень на месте посадки | 12 | **198 259** | до 2 | 397 000 |
|
||||
|
||||
Для масштаба: ОДНА запечка колодца = 58 % растрового кадра, две = 144 %.
|
||||
`pop_dbg_rdmax` подтверждает состав пика: шесть пометок, все `RDA_CEIL`.
|
||||
|
||||
### 1.4 `RDA_CEIL` = 48 658 изнутри (зонды m13/m14/m15)
|
||||
Снят зондами по каждому блиту (`pop_dbg_b1/b5`) и по рамкам
|
||||
(`pop_bar_black`, `pop_cd_batch_begin/end`):
|
||||
|
||||
| участок | такты |
|
||||
|---|---:|
|
||||
| `pop_heal_off(x, 0, 64, CEIL_BAND_H=8)` | 8 491 |
|
||||
| `draw_tile(-1, col)` | **39 029** |
|
||||
| вход `pop_floor_bake` + `gfx_set_bank` | 2 382 |
|
||||
| `pop_bar_black` 60×39 (включая `pop_cd_touch` 4 502) | ~15 500 |
|
||||
| **контекст `draw_tile` #1** (5 чтений тайлов, `63*row`, индексация таблицы) | **13 584** |
|
||||
| 4 блита тайла #1 | 50 718 |
|
||||
| **диспетчер между блитами #1** (все `if (code == …)`) | **11 388** |
|
||||
| **контекст `draw_tile` #2** | **13 584** |
|
||||
| 4 блита тайла #2 | ~54 000 |
|
||||
| **диспетчер между блитами #2** | **11 388** |
|
||||
| хвост | 6 474 |
|
||||
|
||||
Блитов внутри этого `draw_tile` — **1,17 на тайл** (7 вызовов `pop_blit_b`
|
||||
на 6 тайлов), то есть 15–16 тыс. тактов.
|
||||
**Остальные ~23 700 такта — накладные `draw_tile`, ни одного пикселя.**
|
||||
|
||||
### 1.5 `RDA_CEIL_GONE` = 251 023 и `RD_FLOOR` = 198 259
|
||||
|
||||
- `pop_ceil_bake_empty(col)` — бар + **шесть** `draw_tile`
|
||||
(ряд −1 и ряд 0, колонки col−1..col+1): 6 × 39 000 ≈ 234 000.
|
||||
- `pop_floor_bake(row,col)` — бар 60×39 от `yb+26` + **два** `draw_tile`
|
||||
НИЖНЕГО ряда; там стена, то есть `wall_pattern` — ≈**99 000 на тайл**.
|
||||
|
||||
### 1.6 Почему `draw_tile` стоит 39 000 при одном блите
|
||||
|
||||
Кодоген. Подсчёт в `bank7_pop_room.asm` и совпадение с замером до процентов
|
||||
(одно `-N(ix)` ≈ 19 номинальных тактов ≈ 46 замеренных):
|
||||
|
||||
| функция | стековый кадр | обращений `(ix)` | ожидаемо | замерено |
|
||||
|---|---:|---:|---:|---:|
|
||||
| `draw_tile` | **26 Б** | **513** | ~23 600 | **~23 700** |
|
||||
| `pop_ceil_bake_empty` | — | 8 | ~370 | |
|
||||
| `pop_floor_bake` | — | 12 | ~550 | |
|
||||
| `mob_tick_one` | 16 Б | 99 | ~4 550 | из ~29 700/кусок |
|
||||
| `mob_draw_pass` | 18 Б | 20 | ~900 | |
|
||||
|
||||
У `draw_tile` пятнадцать локалей, объявленных `int`
|
||||
(`code`/`lcode`/`lmod`/`xh`/`x`/`dby`/`dmy`/`t`/`lt`/`rbl_code`/`rbl_mod`/
|
||||
`wmod`/`base_id`/`base_yb`), — в регистры они не влезли, и функция целиком
|
||||
уехала в стековый кадр. Байтовые по природе из них все, кроме `x`/`dby`/`dmy`
|
||||
(экранные координаты, бывают отрицательными).
|
||||
Итого: **105 500 — сами блиты (реальные пиксели), 74 400 — накладные**, из
|
||||
которых 27 168 контекст двух `draw_tile` и 22 776 их диспетчер.
|
||||
|
||||
---
|
||||
|
||||
## 2. Способы ускорения
|
||||
## 2. Что сделано (с чем сравнивать)
|
||||
|
||||
По убыванию отдачи. Оценки — от замеров выше; каждая позиция сверена с
|
||||
`SDLPoP/src/seg008.c` (правило проекта: механику сверять с оригиналом ДО
|
||||
кодинга).
|
||||
### G1. Окно клипа для точечной перерисовки — −90 000
|
||||
|
||||
### G1. Окно клипа для ЗАПЕЧКИ — самый крупный кусок
|
||||
`pop_t_win_set(x, ytop, w, h)` / `pop_t_win_clear()` в `pop_tile.c`: ставит
|
||||
уже существующее окно `pop_t_fclip_*` на прямоугольник, который перерисовка
|
||||
восстанавливает. Работает в обе стороны — и предфильтр `pop_blit_b`
|
||||
отсеивает куски мимо окна ДО `atlas_image`/`gfx_w0_map`, и `blit_b_clip`
|
||||
режет остальные по нему.
|
||||
|
||||
**Отдача: −250 000 … −400 000 на пиковый кадр.**
|
||||
Где сработало: `pop_ceil_bake_empty` — куски ряда 0 высотой 63 px рисовались
|
||||
целиком, хотя восстановить надо девять строк полосы. **Блит 21 447 → 7 619**,
|
||||
вся перерисовка 251 335 → 138 318.
|
||||
|
||||
`pop_ceil_bake_empty` и `pop_floor_bake` восстанавливают ИЗВЕСТНЫЙ
|
||||
прямоугольник (тот, который сами же залили баром), а зовут полный
|
||||
`draw_tile`, который честно рисует и то, что в этот прямоугольник не попадает.
|
||||
У `pop_floor_bake` бар — 60×39 от `yb+26`, а тело дворцовой кладки рисуется
|
||||
НИЖЕ `yb+64`, то есть **вся стена рисуется мимо цели**.
|
||||
Где НЕ сработало — см. §4, отрицательные результаты.
|
||||
|
||||
В `pop_blit_b` уже есть дешёвый предфильтр по окну `pop_t_fclip_*` — он режет
|
||||
кусок ДО `atlas_image` и `gfx_w0_map`, то есть почти даром. Достаточно
|
||||
выставлять это окно на время запечки.
|
||||
Побочно: пока окно стоит, `pop_blit_b` не ставит пометку «фон трогали»
|
||||
(признак fore-прохода), поэтому вызывающий обязан пометить прямоугольник сам.
|
||||
В `pop_ceil_shake_draw` добавлен явный `pop_cd_touch` на область heal'а; в
|
||||
`pop_ceil_bake_empty` и `pop_floor_bake` метит `pop_bar_black`, а лишний
|
||||
второй вызов на ту же область снят.
|
||||
|
||||
Грабли, которые надо обойти: `pop_t_fclip_on` в `pop_blit_b` заодно подавляет
|
||||
`pop_cd_touch` (признак «это fore-проход поверх персонажа»). Для запечки это
|
||||
как раз правильно — она помечает область сама, — но проверить обязательно;
|
||||
если понадобится, ввести отдельный флаг «окно только для отсева».
|
||||
### G2. Контекст тайла — file-scope, а не локали `draw_tile` — −55 000
|
||||
|
||||
Сверка с оригиналом: у него та же идея, только через `wipetable` —
|
||||
`draw_tile_wipe(height)` кладёт прямоугольник в таблицу, а `draw_table`
|
||||
рисует уже с известным клипом (seg008:1368, 1373).
|
||||
Порт `load_curr_and_left_tile` (seg008:0339): у оригинала это
|
||||
`curr_tile`/`curr_modifier`/`draw_xh`/`draw_main_y`/`draw_bottom_y` —
|
||||
переменные модуля, а не локали.
|
||||
|
||||
### G2. Расколоть `draw_tile` + отдельный лист для ряда −1
|
||||
Причина в кодогене: в `draw_tile` **57 вызовов**, и каждое живое через вызов
|
||||
значение SDCC спиливал в стековый кадр — 26 байт кадра и **513 обращений
|
||||
`-N(ix)`** (при ~46 замеренных тактах на обращение это ~23 600, что и
|
||||
намерено). Стало **33 обращения**, кадра нет, банк 7 −703 Б.
|
||||
|
||||
**Отдача: 39 029 → 18 000–20 000 на тайл полосы, то есть −140 000 на кадр
|
||||
дрожания; и она умножается на G1 (шесть вызовов в запечке).**
|
||||
### G3. `blit_b_clip` — байтовый габарит + file-scope
|
||||
|
||||
Два шага:
|
||||
Два шага, и важен порядок наблюдений:
|
||||
|
||||
1. **Отдельный `draw_tile_aboveroom(col)`** — дословный порт seg008:01F2.
|
||||
Оригинал для ряда −1 делает РОВНО шесть вещей: `draw_tile_floorright`,
|
||||
`draw_tile_anim_topright`, `draw_tile_right`, `draw_tile_bottom(1)`,
|
||||
`draw_loose(1)`, `draw_tile_fore`. Ни базы, ни `draw_tile_anim`, ни
|
||||
`draw_tile_anim_right`, ни `wall_pattern`, ни вычисления `rbl_*` через
|
||||
`row+1 > 2`. У нас всё это отсекается ветками `if (row >= 0)` уже ВНУТРИ
|
||||
общего `draw_tile` — то есть кадр IX, пролог и вся арифметика оплачиваются
|
||||
всегда.
|
||||
2. **Расколоть общий `draw_tile` по образцу оригинала** (seg008:01C7 —
|
||||
девять узких листьев). Каждый лист получает `xh`/`dby`/`dmy` параметрами
|
||||
(в регистрах), локалей у него единицы, кадра IX нет.
|
||||
1. **Байтового габарита ОДНОГО НЕ ХВАТИЛО.** `sx/sy/dw/dh` → `uint8_t`
|
||||
(корректно: кадры атласов ≤ 56×63) дало 211 → 173 обращения, а
|
||||
22-байтовый кадр остался: значений, живых через шесть вызовов ядер libbgi,
|
||||
всё равно больше, чем регистров у Z80.
|
||||
2. **Решило вынесение из локалей** (`bc_*`): 51 обращение, кадр 22 → 12 Б.
|
||||
|
||||
Заодно проверить `redraw_needed_above` (seg008:02C1): оригинал делает
|
||||
`draw_tile_wipe(3)` — стирает **32×3**, а мы `pop_heal_off(x,0,64,8)` =
|
||||
64×8. Площадь в 5 раз больше нужной (8 491 такта), хотя основная цена там —
|
||||
накладные вызова.
|
||||
Клипованный блит 14 088 → 11 848. Заодно `blit_b_oversize` больше не ходит
|
||||
через `blit_b_clip` (там теперь байтовый габарит) — рисует напрямую
|
||||
`gfx_blit_part`; это путь под полноэкранные подложки интро/финала.
|
||||
|
||||
### G3. `blit_b_clip` — 22 Б кадра, 211 `(ix)`
|
||||
### G4. Мелочи
|
||||
|
||||
**Отдача: 14 088 → ~10 500 на блит. В зелёной фазе ВСЕ блиты клипованные
|
||||
(полоса у потолка выставляет `pop_t_clip_top`) — при 7–17 блитах это
|
||||
−25 000 … −60 000; в циане и fore-проходе больше.**
|
||||
|
||||
`dx/dy/dw/dh/sx/sy` объявлены `int`. По построению `sx/sy/dw/dh ≤ 255`
|
||||
(габарит любого спрайта ≤ 56×63, см. `perf_l13_room23.md` §5) — их можно
|
||||
сделать `uint8_t`, оставив 16-битными только экранные `dx/dy`.
|
||||
Прецедент: тот же приём в `pop_blit_b` (коммит `c312e4a`) дал −19 % на
|
||||
клипованном пути и −16 % на быстром, `_CODE` −42 Б.
|
||||
|
||||
Проверка по правилу OPT-BLIT: после правки смотреть пролог в
|
||||
`.sprinter-cc-roomtest/pop_tile.asm` — исчез ли `ld iy,#-22`, сколько
|
||||
осталось `-N(ix)`.
|
||||
|
||||
### G4. `mob_tick_one` / `pop_loose_mob_tick` — 29 700 на кусок
|
||||
|
||||
**Отдача: −30 000 … −48 000 на кадр при шести кусках.**
|
||||
|
||||
16-байтовый кадр, 99 `(ix)`. Байтовыми могут быть габарит heal-коридора и
|
||||
разность `prev_y`; `x`/`y` — 16-битные. Плюс `pop_cd_touch` на коридор — один
|
||||
на кусок, 4 502 такта (см. `perf_cyan_phase.md` §1.3 про его цену).
|
||||
|
||||
### G5. `LOOSE-SHAKE-RUNS` — пометки по сменам кадра
|
||||
|
||||
**Отдача: ~20 % работы фазы, и только на дрожащих плитах. Оценка старая
|
||||
(2026-08-13), не перемерена.**
|
||||
|
||||
Подробности и арифметика — в `roomtest/TASKS_OPEN.md#loose-shake-runs`.
|
||||
Коротко: наивный вариант «помечать только на смене кадра» выигрыша НЕ даёт
|
||||
(пять смен × две страницы = те же десять перерисовок); работает только версия
|
||||
«пары и тройки» — две пометки с `pages = 2` на фазах 5 и 8. Тот же приём
|
||||
применим к плитам-ПОТОЛКАМ (`pop_set_redraw_above`), где сейчас идёт пометка
|
||||
каждый кадр отсчёта.
|
||||
|
||||
Вопрос открытый: стоит ли неочевидный код такого узкого выигрыша. Браться
|
||||
после G1–G4.
|
||||
|
||||
### G6. `BG-ONCE` — heal вместо чёрного бара
|
||||
|
||||
Предложение пользователя, см. `roomtest/TASKS_OPEN.md#bg-once`. Сейчас
|
||||
запечка = «залить чёрным + перерисовать фон», то есть двойная работа; heal по
|
||||
координатам бара делает то же за один проход. Прямо дополняет G1.
|
||||
- `pop_blit_b`: аргументы в file-scope (третий и дальше SDCC передаёт стеком,
|
||||
каждое чтение шло через `-N(ix)`) — 76 → 11 обращений.
|
||||
- `pop_loose_mob_tick`: пометки всех кусков ОДНИМ пакетом
|
||||
(`pop_cd_batch_begin/end`) — было по 4 502 такта на кусок.
|
||||
176 772 → 168 600.
|
||||
- Коридор heal куска — по фактической высоте СОБРАННОГО композита (было 24
|
||||
строки константой, стало 20). 168 600 → 156 762.
|
||||
|
||||
---
|
||||
|
||||
## 3. Что НЕ делать (проверено, отрицательный результат)
|
||||
## 3. Что осталось: раскол `draw_tile` (позиция G5)
|
||||
|
||||
**Оставшийся разрыв: −147 000.** Он весь в двух местах.
|
||||
|
||||
### G5. Расколоть `draw_tile` на узкие части, как в оригинале
|
||||
|
||||
**Ожидание: −50 000 … −60 000.**
|
||||
|
||||
У оригинала `draw_tile` (seg008:01C7) — это девять независимых вызовов:
|
||||
`draw_tile_floorright`, `draw_tile_anim_topright`, `draw_tile_right`,
|
||||
`draw_tile_anim_right`, `draw_tile_bottom`, `draw_loose`, `draw_tile_base`,
|
||||
`draw_tile_anim`, `draw_tile_fore`. Для ряда −1 он зовёт шесть из них
|
||||
(`draw_tile_aboveroom`, seg008:01F2), для полосы у потолка — те же шесть плюс
|
||||
`draw_tile_wipe(3)` (`redraw_needed_above`, seg008:02C1).
|
||||
|
||||
У нас всё это — ветки `if (row >= 0)` ВНУТРИ одной функции, то есть контекст
|
||||
(13 584) и диспетчер (11 388) оплачиваются целиком всегда. Расколов, каждая
|
||||
точечная перерисовка сможет звать только нужные части:
|
||||
|
||||
- `pop_floor_bake`: вместо второго полного `draw_tile(row, col+1)` — только
|
||||
его правую грань и базу;
|
||||
- `pop_ceil_shake_draw` / `pop_ceil_bake_empty`: дословный
|
||||
`draw_tile_aboveroom`;
|
||||
- `pop_loose_shake_draw`, `pop_spike_redraw`, `pop_gate_redraw` — то же.
|
||||
|
||||
Риск средний: у `draw_tile` собрано много инвариантов (BUG-LOOSE-3,
|
||||
BUG-LATTICE-DOORTOP, BUG-SEAM-WEDGE-1), проверять придётся прогонами всех
|
||||
уровней. Поэтому делать отдельным заходом, а не хвостом другой правки.
|
||||
|
||||
### G6. Меньше блитов в `RD_FLOOR`
|
||||
|
||||
**Ожидание: неизвестно, надо мерить.** 105 500 из 179 914 — это 7,6 блита,
|
||||
и они рисуют настоящие пиксели. Сократить можно только сократив то, что
|
||||
восстанавливается: бар сейчас 60×39 от `yb+26`, а плита занимает по вертикали
|
||||
меньше (её куски: левая грань `POP_LOOSE_FRAM_LEFT` 32×13 на `dmy = yb+62`,
|
||||
низ `POP_LOOSE_FRAM_BOTTOM` 32×3 на `dby = yb+65`, правая грань в соседе
|
||||
26×16 на `dby−1`). То есть плита живёт в `yb+47 .. yb+65`, а бар начинается с
|
||||
`yb+26` — **21 лишняя строка сверху**.
|
||||
|
||||
Проверять осторожно: бар заодно стирает и то, что рисует ДРУГИЕ куски тайла
|
||||
(орнаментная лента `stripe_id` на `dmy−27 = yb+35` попадает как раз в
|
||||
«лишнюю» часть). Сузишь бар — надо убедиться, что ничего не осталось.
|
||||
|
||||
### G7. heal летящих кусков — 154 074 (28 % фазы)
|
||||
|
||||
Шесть кусков × ~25 700: сам heal 64×20 (по модели ~19 700) + пакетная
|
||||
пометка + накладные `mob_tick_one` (16-байтовый кадр, 99 обращений `(ix)`).
|
||||
**Сам heal у предела железа** — это 1 280 пикселей на кусок, оптимизировать
|
||||
нечего, кроме площади. Площадь уже подрезана до габарита композита.
|
||||
|
||||
Остаётся `mob_tick_one` (~4 500 на кусок = 27 000 на кадр) — то же лечение
|
||||
file-scope, что у `draw_tile`.
|
||||
|
||||
### G8. Снять временную оснастку
|
||||
|
||||
Шесть `pop_dbg_b1..b6` внутри `pop_blit_b` — ~400 такта на блит; при 15
|
||||
блитах зелёной это 6 000 на кадр. Плюс `pop_dbg_kind`/`m16` (2 вызова на
|
||||
перерисовку) и `pop_dbg_m5..m15`. Снимать ПОСЛЕ окончания оптимизации: без
|
||||
них не мерить.
|
||||
|
||||
---
|
||||
|
||||
## 4. Отрицательные результаты — НЕ повторять
|
||||
|
||||
### Окно клипа в `pop_floor_bake` — проверено ТРИ раза, каждый раз хуже
|
||||
|
||||
| попытка | было | стало |
|
||||
|---|---:|---:|
|
||||
| до G3 | 187 266 | 198 279 |
|
||||
| после G3 | 182 124 | 188 460 |
|
||||
| после `pop_blit_b` file-scope, с детальным зондом | 179 914 | 188 417 |
|
||||
|
||||
Третья попытка объяснила причину: клипованный путь стоит **+1 500 такта на
|
||||
КАЖДОМ** из 7,6 блитов (+11 400), а режет он только редкие высокие куски — в
|
||||
трассе такие нашлись (34 878 → 25 872 и 28 818 → 24 090, всего −13 700), но в
|
||||
среднем по 12 перерисовкам их нет. Запись стоит в коде.
|
||||
|
||||
### Прочее (проверено раньше)
|
||||
|
||||
- **Не ускорять передачу пикселей** — она на пределе железа (3+3 такта на
|
||||
байт через акселератор), memory `blit_cost_model`. В пиковом кадре
|
||||
«железный» минимум всех блитов ≈150 000 из 1 437 150.
|
||||
- **Не откладывать запекание на другой кадр** — запечка пишет ОЗУ-копию, из
|
||||
которой восстанавливает heal; отложенная даёт призрак плиты на месте дыры
|
||||
(проверено 2026-08-13).
|
||||
- **Не батчить смежные колонки в `pop_ceil_shake_draw`** — пробовалось и
|
||||
убрано: плиты стартуют со случайными задержками, в кадре дрожат разрозненные
|
||||
колонки, пробег почти всегда длиной в одну.
|
||||
- **Не искать проблему в W3-скобке** (`_bgi_begin`/`_bgi_end` — пять
|
||||
инструкций) и не списывать разброс на прерывания (внутри размерной группы
|
||||
разброс три такта).
|
||||
которой восстанавливает heal; отложенная даёт призрак плиты на месте дыры.
|
||||
- **Не батчить смежные колонки в `pop_ceil_shake_draw`** — плиты стартуют со
|
||||
случайными задержками, в кадре дрожат разрозненные колонки, пробег почти
|
||||
всегда длиной в одну.
|
||||
- **Не ускорять передачу пикселей** — предел железа (3+3 такта на байт,
|
||||
memory `blit_cost_model`). В пиковом кадре «железный» минимум всех блитов
|
||||
≈150 000 из 916 458.
|
||||
- **`LOOSE-SHAKE-RUNS`** (пометки по сменам кадра): наивный вариант выигрыша
|
||||
НЕ даёт — пять смен × две страницы = те же десять перерисовок. Работает
|
||||
только версия «пары и тройки», ~20 % и только на дрожащих плитах; оценка
|
||||
2026-08-13, не перемерена. Подробности —
|
||||
`roomtest/TASKS_OPEN.md#loose-shake-runs`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Журнал правок
|
||||
## 5. Журнал правок
|
||||
|
||||
| дата | что сделано | зелёная: покой / дрожь / пик | коммит |
|
||||
|---|---|---|---|
|
||||
| 2026-08-17 | базовый замер (до правок этой серии) | 35 760 / 366 000 / **805 000** | `c312e4a` |
|
||||
| 2026-08-17 | базовый замер | 35 760 / 366 000 / **805 000** | `c312e4a` |
|
||||
| 2026-08-17 | G2 контекст тайла в file-scope | — / — / **747 954** | `a3c473d` |
|
||||
| 2026-08-17 | G1 окно клипа в `pop_ceil_bake_empty` | — / — / **663 250** | `a3c473d` |
|
||||
| 2026-08-17 | G3 `blit_b_clip` байты + file-scope | — / 335 400 / **575 730** | `a3c473d` |
|
||||
| 2026-08-17 | `pop_blit_b` file-scope; пакетная пометка кусков | — / — / **557 706** | `b2da0b8` |
|
||||
| 2026-08-17 | коридор heal по высоте композита | 35 760 / 335 400 / **546 900** | `9a50ab2` |
|
||||
|
||||
Reference in New Issue
Block a user