diff --git a/applications/PoP/docs/perf_backlog.md b/applications/PoP/docs/perf_backlog.md index e8f338f..c309974 100644 --- a/applications/PoP/docs/perf_backlog.md +++ b/applications/PoP/docs/perf_backlog.md @@ -44,6 +44,88 @@ MAME (`z80_profiling_method`) на роомтесте, уровень 1 комн Одна перерисовка персонажа = **~137 000 тактов = 32 % растрового кадра**, из них полезной работы (heal 20×19 + спрайт 12×41) — меньше трети. +## Профиль дворца (уровень 4) на 2026-08-10 + +Сцена: уровень 4, Кид НЕПОДВИЖНО стоит на (1,7) (комната с решёткой), +стража нет. Разбивка одного логического кадра брейкпоинтами на границах +фаз (адреса `PROF()` из `roomtest.lst` + базы `_CODE = 0x42AD`): + +| фаза | тактов | доля работы | +|---|---:|---:| +| ввод + читы + heal | 59 340 | 11 % | +| логика (kid_tick, phys_tick, страж, боёвка) | 85 356 | 16 % | +| `pop_loose_tick` | 27 396 | 5 % | +| `pop_process_trobs` | 106 107 | 21 % | +| `pop_redraw_needed` | 447 | — | +| шов / смена уровня / вспышка | 5 448 | 1 % | +| `guard_over_kid` + `pop_char_skip_mask` | 4 788 | 1 % | +| `pop_char_draw(KID)` | 52 206 | 10 % | +| соперник + `loose_mob_draw_over` + `hp_draw` | 4 086 | 1 % | +| **`pop_char_fore(KID)`** | **171 693** | **33 %** | +| `pop_room_clip_borders` + прочее | 742 | — | +| **ИТОГО работа** | **517 609** | 120 % растрового кадра → период **4 кадра** | + +По цветам бордюра: синий (`PROF(2)`) 144 696 (28 %), зелёный (`PROF(4)`) +139 398 (27 %), циан (`PROF(6)`) 233 515 (45 % работы = 54 % растрового +кадра, начинается на 74 % первого кадра и кончается на 123 %). + +## 0. Дворцовая кладка в fore-проходе — 27 % кадра НА НОЛЬ ПИКСЕЛЕЙ + +**Цена: 139 863 такта за кадр (32 % растрового кадра), полезных пикселей — +ровно ноль.** Самая дорогая известная позиция; снятие её одной уводит +работу с 517 609 до ~378 000, то есть период с **4 растровых кадров на 3**. + +Замер (уровень 4, Кид на (1,7)). Окно fore-клипа в этот момент — +`x 229..241, y 106..147` (прочитано из `pop_t_fclip_*` брейкпоинтом). +`pop_fore_over_char` обходит 6 тайлов: + +| тайл | тактов | +|---|---:| +| (0,6) (0,7) (1,6) (1,7) | 2 800 – 4 600 каждый | +| **(2,6) — стена** | **74 310** | +| **(2,7) — стена** | **65 553** | + +Ряд 2 этой комнаты — стена, и он лежит ПОД ногами Кида, то есть попадает в +его fore-окно всегда. Внутри одного тайла стены `wall_pattern_palace` +делает 6 × `wpp_fill` (≈ 3 100 каждый) + 5 × `pop_wall_b` (≈ 9 760 каждый) +≈ 60 000 тактов. + +Ни один кусок в окно не попадает: +- верхняя заливка стоит на `dmy - 59 = 157`, окно кончается на `y = 147`; + все остальные куски ещё ниже; +- тайл (2,6) занимает `x 192..223`, окно начинается с `x = 229` — он + промахивается и по горизонтали тоже. + +Тайл всё равно проходит, потому что предфильтр в `fore_tile` (pop_bg.c, +`x0 < fclip_x1 && x0 + 40 > fclip_x0 && y0 - 8 < fclip_y1 && y0 + 70 > +fclip_y0`) намеренно грубый — габарит 40×78 на тайл. Дальше `wpp_fill` +честно режет по окну и выходит с пустым прямоугольником, но 3 100 тактов на +арифметику клипа уже потрачены, а `pop_wall_b` о существовании окна не знает +вовсе: он идёт в `atlas_image` + `gfx_w0_map`, читает `w`/`h` и только там +обнаруживает, что рисовать нечего. + +Что делать (по возрастанию объёма): +1. **Ранний выход из `wall_pattern_palace`**: самый верхний пиксель узора — + `dmy - 59`, самый нижний — `dby + высота нижнего декаля`. Один + `if (pop_t_fclip_on && (fclip_y1 <= dmy - 59 || fclip_y0 > dby + h)) + return;` плюс такая же проверка по `x` убивает оба тайла целиком почти + даром. +2. Прогнать `pop_wall_b` в этом узоре через ту же проверку окна, что уже + есть у `wpp_fill` (нужны размеры кусков — см. п. 2 ниже, «размеры из + каталога атласа»). +3. Сузить сам предфильтр `fore_tile` до реального габарита узора вместо + 40×78 — тогда лечится не только дворец. + +Порядок в подземелье тот же, но дешевле: `wall_pattern` в подземелье делает +до 3 блитов и ни одной заливки (~29 000 на тайл против ~60 000). Это же +объясняет, почему после перехода на дворцовый тайлсет период вырос. + +Сверено с SDLPoP (`seg008.c:1943 wall_pattern`, ветка +`!is_dungeon && GRAPHICS_VGA`): состав узора у нас дословный — 5 +`add_wipetable` + 4 декаля + нижняя заливка + нижний декаль. Расходимся не +составом, а тем, что оригинал складывает всё в `foretable` и рисует одним +`draw_table()`, у которого «посетить тайл» стоит копейки (см. п. 6). + --- ## 1. Футпринт персонажа — брать из физики, а не считать заново