Разбор 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:
2026-08-13 23:36:48 +03:00
parent f89b7dd0d2
commit b27b31318a
5 changed files with 79 additions and 1 deletions
+6
View File
@@ -298,6 +298,11 @@ static void draw_tile(int row, int col)
rbl_mod = pop_tile_mod(row + 1, col - 1);
}
/* Пометка «фон трогали» — ОДНА на весь тайл, а не на каждый его кусок
* (pop_cd_batch_begin/end). Досрочных выходов у draw_tile нет, так что
* скобка гарантированно закрывается. */
pop_cd_batch_begin();
/* --- draw_tile_anim_topright (seg008:0568): верх ВОРОТ снизу-слева.
* Условие дословно: свой тайл пуст / верх большой колонны / верх двери,
* а снизу-слева — ворота. --- */
@@ -472,6 +477,7 @@ static void draw_tile(int row, int col)
} else if (t->fore_id) {
pop_fore_b(t->fore_id, t->fore_x * 8 + x, t->fore_y + dmy);
}
pop_cd_batch_end(); /* одна пометка на весь тайл */
}