libbgi: sy*img_w умножением вместо O(sy)-цикла — rpgwalk 24 → стабильные 48 fps

Профилирование rpgwalk в dev-MAME (watchpoint на OUT-маркеры +
totalcycles) показало: blit 8 спрайтов ел 17 мс из 20.5 — 85% в цикле
`while (sy--) src += img_w;` blit-обёрток (писался под «обычно sy==0»,
а вертикальные ленты атласов дают sy до 176 → до 64К тактов на кадр).

Фикс: src += sy*img_w через __mulint (O(1); __mul16 адаптивен — при
sy < 256 крутит 8 итераций, ~500Т) + if (sy): горизонтальные ленты и
одиночные спрайты не платят и за умножение.  Blit: 45К → 11.8К
тактов/спрайт.

Замерен бюджет кадра (docs/sprite-api-design.md §9д): кадр 48.83 Гц =
430080 тактов @21МГц; спрайт 16×16 ≈ 26К (тик 7.3К + heal 6.4К +
blit 11.8К) → лимит стабильных 48 fps = 14 спрайтов (15 — 94% кадров,
16 — на грани).  FPS-плашка bar+outtextxy стоит ~210К (полкадра!) —
HUD рисовать putimage-заготовкой.

examples/rpgwalk/rpgprof.c — профилировочная копия демо: визуальный
профайлер (цвет бордера по секциям кадра) + маркеры для тактового
профайла через wpiset дебаггера (рецепт в шапке и §9д).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 21:54:37 +03:00
parent 02f7afe765
commit 0eec977630
5 changed files with 342 additions and 10 deletions
+32
View File
@@ -775,6 +775,38 @@ callback НЕ делаем — опрос проще и дешевле).
медленное движение «1 пиксель в 1.5 кадра»); цепочки целей
(waypoints) — приложение ставит новую цель по sprite_moving()==0.
## 9д. Тактовый бюджет кадра (профиль rpgwalk в dev-MAME, 2026-07-13)
Кадр Sprinter = 48.83 Гц (растр 896×320 @14МГц) = **430080 тактов**
@21МГц (такты «эффективные», с wait-state'ами ОЗУ). Метод замера —
watchpoint на OUT-маркеры + printf/g + clog (memory/mame_mcp_bridge).
Цена анимированного спрайта 16×16 в sprite_update (heal+blit на
кадр, W0-атлас, noclip):
| фаза | тактов/спрайт |
|--------------------|---------------|
| тик (anim+tween) | ~7.3К (4.3-9.2К) |
| heal (банк 0x50) | ~6.4К |
| blit (банк 0x5C) | ~11.8К |
| **итого** | **~26К** |
Фикс-часть цикла демо (kbhit+getdatetime+свопы страниц) ~14-19К.
Отсюда лимит на стабильные 48 fps (КАЖДЫЙ кадр в один интервал):
**14 спрайтов** (замерено: все обычные кадры ≤406К, 10/232 двойных —
только кадры с FPS-плашкой); 15 — 94% кадров, 16 — на грани (50%).
Уроки профиля:
- O(sy)-цикл `src += img_w` в blit-обёртках стоил до 64К тактов на
кадр 11 вертикальной ленты (~85% времени блита!) — заменён на
__mulint 2026-07-13 (O(1) ~300Т): blit упал 45К → 11.8К/спрайт,
rpgwalk 24 fps → стабильные 48.
- bar()+outtextxy() FPS-плашки = ~210К тактов (~10 мс, полкадра!) —
текст BGI дорогой; на 14 спрайтах кадры с плашкой уходят в два
интервала. Для HUD в бюджете рисовать заготовленным putimage.
- Резерв: тик в C ~7.3К/спрайт — asm/упрощение подняло бы лимит к
~17-18 спрайтам.
## 10. Риски / что проверить артефактом (Фаза 0)
Статус 2026-07-11: пп. 13 закрыты для MAME 0.283 (tests/gfxbanks,