Разбор draw_tile: модель цены блита + пакетная пометка pop_cd_touch
Замер (MAME, комната 23 ур.13) разложил цену одного gfx_blit_noclip
регрессией по 339 блитам, высоты 3..63:
такты = 8791 + 198.2 * h + 5.96 * (w * h)
Модель ложится на весь диапазон (32x3 -> 9 891, 32x13 -> 13 887,
32x60 -> 32 073), разброс внутри размерной группы — ТРИ такта.
Выводы:
- 5.96 на байт — предел железа: байт идёт через акселератор дважды
(burst src->память акселератора, burst ->экран), по 3 такта на проход
при системном клоке 21 МГц. Ускорять передачу нечем.
- 198 на строку — цикл _bgi_blit_rows_raw; при w=32 это половина
построчной цены.
- 8791 на ВЫЗОВ — крупнейшая статья, НЕ объяснена. Проверено, что это не
W3-скобка (в обеих половинах по 5 инструкций) и не прерывания (разброс
3 такта). Один тайл = 5-6 спрайтов ~ 107 000 тактов, из них ~50 000 —
постоянные накладные вызовов. Это и есть главный резерв.
Заодно: pop_cd_touch собирается в ПАКЕТ на тайл (pop_cd_batch_begin/end,
скобка в draw_tile) вместо вызова на каждый кусок — раньше 2 866 тактов
на спрайт, 15% цены блита. ВНИМАНИЕ: выигрыш замером НЕ подтверждён —
в захваченных кадрах скобка не сработала (блиты шли из холодной отрисовки
комнаты, мимо draw_tile). Правка безопасна по построению: объединение
прямоугольников может пометку только расширить, не сузить.
Снятые сегодня неверные утверждения (чтобы не всплыли):
- «клипованный блит дороже полного» — артефакт сравнения разных выборок
спрайтов; 32x60 с клипом до полосы стоит 7 236, то есть клип работает;
- «блиты идут программным циклом со скоростью ldir» — нет, ядро на
акселераторе, см. модель выше;
- «отложить запекание на кадр» — НЕЛЬЗЯ: запекание пишет ОЗУ-копию фона,
из которой heal восстанавливает; отложенное даёт призрак плиты.
Все 8 наборов tests-host проходят. Оснастка замера временная.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -146,3 +146,19 @@ void pop_dbg_m15(void) { }
|
||||
* его вместе с тактами — так видно цену КАЖДОГО вида, а не число пометок. */
|
||||
void pop_dbg_kind(uint8_t k) { (void)k; }
|
||||
void pop_dbg_m16(void) { }
|
||||
|
||||
/* ВРЕМЕННО (разбор pop_blit_b 2026-08-13): сколько в одном блите занимают
|
||||
* САМИ пиксели, а сколько пооспрайтовые накладные (map/unmap страницы
|
||||
* атласа, чтение заголовка, пометка грязного прямоугольника). */
|
||||
void pop_dbg_b1(void) { } /* вход (спрайт прошёл отсев) */
|
||||
void pop_dbg_b2(void) { } /* atlas_image + gfx_w0_map */
|
||||
void pop_dbg_b3(void) { } /* сам блит */
|
||||
void pop_dbg_b4(void) { } /* pop_cd_touch */
|
||||
void pop_dbg_b5(void) { } /* gfx_w0_unmap (конец) */
|
||||
void pop_dbg_b6(void) { } /* взведён = пошли в gfx_blit_noclip, а не в _part */
|
||||
|
||||
/* ВРЕМЕННО (регрессия цены блита 2026-08-13): w и h упакованы в один
|
||||
* 16-битный аргумент (arg1 -> HL при __sdcccall(1)), брейкпоинт логирует
|
||||
* HL — дальше цена раскладывается как a + b*h + c*w*h, где b и есть
|
||||
* построчные накладные ядра. */
|
||||
void pop_dbg_wh(uint16_t wh) { (void)wh; }
|
||||
|
||||
Reference in New Issue
Block a user