0eec977630
Профилирование 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>
38 lines
2.3 KiB
C
38 lines
2.3 KiB
C
/*
|
||
* _gfx_blit_sprite_noclip — блит спрайта БЕЗ клипа по экрану. Как
|
||
* _gfx_blit_sprite, но клип-математики нет ВООБЩЕ (не скип проверки —
|
||
* кода нет физически): приложение ГАРАНТИРУЕТ, что спрайт целиком на
|
||
* экране (флаг gfx_sprite_clip(0)). Отдельная функция, а не ветка в
|
||
* _gfx_blit_sprite: без клип-кода SDCC тесней раскладывает регистры
|
||
* (меньше спиллов) — отсюда полный выигрыш ~+19% на анимации (замер
|
||
* A/B на examples/balls 2026-07-12), а не только скип сравнений.
|
||
*
|
||
* ВНИМАНИЕ: запись за край экрана портит соседнюю память (Port_Y за 256
|
||
* заворачивается наверх, x за 320 — в соседнюю строку/страницу; см.
|
||
* tests/spriteclip). Вызывать только когда спрайт заведомо в пределах.
|
||
*
|
||
* Формат img/img_w/sx/sy — как в _gfx_blit_sprite (getimage-заголовок +
|
||
* лента-атлас). БЕЗ _bgi_begin/_bgi_end и смены банка (держит вызывающий).
|
||
*/
|
||
#include "../_bgi.h"
|
||
|
||
void _gfx_blit_sprite_noclip(int x, int y, const void *img,
|
||
int sx, int sy, uint8_t w, uint8_t h)
|
||
{
|
||
const uint8_t *p = (const uint8_t *)img;
|
||
const uint8_t *src;
|
||
int img_w = p[0] | (p[1] << 8); /* ширина картинки/ленты = sstride */
|
||
|
||
/* sy*img_w умножением (__mulint, O(1) ~300Т): вертикальные ленты
|
||
* атласов сделали sy != 0 нормой — старый цикл сложений был O(sy),
|
||
* до ~64К тактов на блит кадра 11 (профиль rpgwalk 2026-07-13).
|
||
* if (sy): горизонтальные ленты/одиночные спрайты (sy == 0) не
|
||
* платят и за умножение. */
|
||
src = p + 4 + sx;
|
||
if (sy)
|
||
src += (uint16_t)sy * (uint16_t)img_w;
|
||
|
||
_bgi_blit_rows_raw(src, (uint8_t *)(_gfx_addr_base + x),
|
||
w, h, img_w, (uint8_t)y);
|
||
}
|