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>
59 lines
2.8 KiB
C
59 lines
2.8 KiB
C
/*
|
||
* _gfx_blit_full — bracket-free ядро блита под-прямоугольника картинки
|
||
* getimage-формата (см. gfx_blit_part). Клип по экрану + нарезка на
|
||
* полосы ≤256 + вызов accel-leaf'а _bgi_copy_rows_raw. БЕЗ _bgi_begin/
|
||
* _bgi_end и БЕЗ смены банка — вызывающий обязан замапить W3 (_bgi_begin)
|
||
* и выставить нужный _gfx_bank ДО вызова.
|
||
*
|
||
* Вынесено из gfx_blit_part (2026-07-12) ради batch-пасса спрайтового
|
||
* движка v2: sprite_update держит одну W3-скобку и один банк на ВЕСЬ
|
||
* проход, вызывая это ядро в цикле по спрайтам (амортизация обвязки —
|
||
* см. docs/sprite-api-design.md §9.1). gfx_blit_part теперь = _bgi_begin
|
||
* + это ядро + _bgi_end.
|
||
*
|
||
* Clip fast-path: если прямоугольник целиком на экране — 4 сравнения
|
||
* вместо полного пути коррекции краёв (TODO «клип fast-path»).
|
||
*/
|
||
#include "../_bgi.h"
|
||
|
||
void _gfx_blit_full(int x, int y, const void *img,
|
||
int sx, int sy, int w, int h)
|
||
{
|
||
const uint8_t *p = (const uint8_t *)img;
|
||
const uint8_t *src;
|
||
uint16_t dst;
|
||
int img_w;
|
||
|
||
/* img_w — ПОЛНАЯ ширина картинки/ленты из заголовка getimage
|
||
* (p[0]=lo, p[1]=hi); это шаг между строками источника (sstride).
|
||
* sx/sy — смещение кадра внутри картинки (атлас). Подробный разбор
|
||
* формата и sx/sy — в common/_gfx_blit_sprite.c. */
|
||
img_w = p[0] | (p[1] << 8);
|
||
|
||
/* Клип по экрану — только если хоть один край вылезает. */
|
||
if (x < 0 || y < 0 || x + w > _bgi_maxx + 1 || y + h > _bgi_maxy + 1) {
|
||
if (x < 0) { sx -= x; w += x; x = 0; }
|
||
if (y < 0) { sy -= y; h += y; y = 0; }
|
||
if (x + w > _bgi_maxx + 1) w = _bgi_maxx + 1 - x;
|
||
if (y + h > _bgi_maxy + 1) h = _bgi_maxy + 1 - y;
|
||
if (w <= 0 || h <= 0) return;
|
||
}
|
||
|
||
/* src = img + 4 + sy*img_w + sx; sy*img_w умножением (__mulint,
|
||
* O(1)) — цикл сложений был O(sy), см. _gfx_blit_sprite.c. */
|
||
src = p + 4 + sx;
|
||
if (sy)
|
||
src += (uint16_t)sy * (uint16_t)img_w;
|
||
|
||
dst = _gfx_addr_base + x;
|
||
while (w > 256) {
|
||
_bgi_blit_rows_raw(src, (uint8_t *)dst, 0 /* =256 */, (uint8_t)h,
|
||
img_w, (uint8_t)y);
|
||
src += 256;
|
||
dst += 256;
|
||
w -= 256;
|
||
}
|
||
_bgi_blit_rows_raw(src, (uint8_t *)dst, (uint8_t)w, (uint8_t)h,
|
||
img_w, (uint8_t)y);
|
||
}
|