CLIP-1: heal Кида и стража — линейным ядром, когда клип не нужен

kid_heal/pop_guard_heal звали gfx_heal всегда, хотя рисуют ровно тот
прямоугольник, который блит в большинстве кадров кладёт noclip-ядром.
Все три места heal (+ heal_off фона) сведены к общему pop_heal_fast.

Замер в MAME, счётчики totalcycles на входах kid_heal и kid_tick (вся
группа heal за кадр), комната 1, Кид стоит:
  клипающее ядро  26 200 тактов/кадр (149 кадров)
  noclip          15 848 тактов/кадр (239 кадров)
−10 352 такта, −39.5 %.  A/B в одном прогоне: вторая половина снята с
пропатченным в памяти условием (jr nz → jr), то есть на той же геометрии.

Размер СУММАРНО −362 Б: _CODE +17, BANK2 −116 (свободно 2708 — это тесный
банк из рисков levels_plan §5), BANK3 −263, BANK4 без изменений.

Грабли по дороге: первым заходом хелпер был static inline в pop_bg.h —
SDCC 4.5 И встраивает тело (181 Б) в каждый вызов, И оставляет копию в
каждом TU, который видит заголовок.  pop_guard_heal раздулся с ~60 до
663 Б, итого +1091 Б в _CODE и +636 Б в банке стража.  Отсюда pop_draw.c:
обычная функция в резиденте W1, из банков это прямой call без трамплина.

pop_room_clip_borders оставлен клипающим осознанно (320 не лезет в 8 бит,
гейт border_dirty редкий) — причина записана в коде.

Проверено визуально: ходьба, прыжок, спуск, позиция за решёткой шва
(straddle — там работает клипающий фолбэк) — артефактов нет.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Александр Петров
2026-08-01 21:53:30 +03:00
parent d552cbaca9
commit 1146c57544
11 changed files with 277 additions and 139 deletions
+10 -10
View File
@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <unistd.h>
#include "pop_bg.h"
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
#include "pop_state.h"
#include "pop_geom.h"
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
@@ -135,18 +136,12 @@ static void blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
gfx_w0_unmap();
}
/* heal в room-space (со сдвигом POP_YOFF) — все heal слоя фона/loose. */
/* heal в room-space (со сдвигом POP_YOFF) — все heal слоя фона/loose.
* Выбор ядра (noclip / клипающее) — общий с Кидом и стражем, pop_heal_fast
* в pop_bg.h. */
static void heal_off(int x, int y, int w, int h)
{
int sy = y + POP_YOFF;
/* Без клипа — линейным ядром (~2.9×, как gfx_blit_noclip): общий
* gfx_heal платит за клип/16-бит/split, а не за пиксели (замер:
* 11 658 тактов на heal 22×22). */
if (x >= 0 && sy >= 0 && w > 0 && h > 0 && w < 256 && h < 256 &&
x + w <= 320 && sy + h <= 256)
gfx_heal_noclip(x, sy, (uint8_t)w, (uint8_t)h);
else
gfx_heal(x, sy, w, h);
pop_heal_fast(x, y + POP_YOFF, w, h);
}
/* Область, куда в этом кадре рисовался ОВЕРЛЕЙ (не футпринт fore, а
@@ -1190,6 +1185,11 @@ void pop_room_clip_borders(void) __banked
{
if (!border_dirty) return;
border_dirty--;
/* ОСТАЁТСЯ клипающим осознанно (CLIP-1, 2026-08-01): полоса шириной 320
* не лезет в 8-битный параметр noclip-ядра, а разбивать её на два куска
* по 160 нет смысла — гейт border_dirty пускает сюда только в кадрах
* падения/выхода за поле, и выигрыш (~2×5.6 К тактов подготовки) там
* тонет в цене самих 320×28 пикселей. Не «оптимизировать» повторно. */
gfx_heal(0, 0, 320, POP_YOFF); /* верхний борт */
gfx_heal(0, POP_CLIP_BOTTOM, 320, 256 - POP_CLIP_BOTTOM);/* статус-полоса + нижний борт */
}