fore-проход: ранний выход по коду тайла + контекст тайла один раз (эффект нулевой)

Сближение с SDLPoP, замером НЕ подтвердилось — фиксирую как есть.

- FORE_ANY[32]: есть ли у кода тайла хоть что-то в переднем слое.  Порт
  ранней проверки оригинала `if (tile_table[curr_tile].fore_id == 0) return;`
  из начала ветки default в draw_tile_fore (seg008:0D15), расширенной нашими
  спецслучаями (стена 20, пики 2, чомпер 0x12, нижняя грань loose 11 — они
  рисуются мимо fore_id).  Была в самом конце цепочки сравнений.
- ft_code/ft_x/ft_dmy: контекст тайла считается один раз на тайл, как глобалы
  curr_tile/draw_xh/draw_main_y у load_curr_and_left_tile.  Код тайла читался
  дважды (fore_tile и снова fore_only_tile), координаты — в каждом листе.

Замер (Кид на 2,4 в щебне, MAME): pop_fore_over_char 58 764 -> 58 866, то
есть в пределах шума.  Ранний выход не срабатывает — в футпринте Кида тайлы
почти всегда С передним слоем; снятое второе чтение кода съедено проверкой
FORE_ANY и записью контекста.  Отрисовка не изменилась: щебёнка блитится теми
же параметрами (x=150 y=208 sx=22 w=10 h=2).

Где время на самом деле: ~16 000 тактов фиксированных накладных на КАЖДЫЙ
блит фона независимо от размера (atlas_image + gfx_w0_map + чтение w/h через
окно 0 + арифметика клипа + unmap).  Блит щебёнки 10×2 обходится в 21 168,
факел 16×22 — в 31 000 при самом gfx_blit_noclip 8 706.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 10:55:01 +03:00
parent b0524b9ad0
commit a9f4521ffd
+44 -7
View File
@@ -318,15 +318,46 @@ static int8_t col_from_x(int xpos) /* get_tile_div_mod: колонка (
#define y_to_row(y) pop_y_to_row((int16_t)(y)) /* общий (pop_geom) */
/* Контекст ТЕКУЩЕГО тайла прохода: код, левый край, база Y. Порт глобалов
* оригинала (curr_tile / draw_xh / draw_main_y, которые load_curr_and_left_tile
* ставит ОДИН раз на тайл, seg008 redraw_needed_tiles) — все рисовальщики
* читают их, а не считают заново. У нас код тайла читался дважды за тайл
* (в fore_tile и снова тут), а координаты — в каждом листе. */
static uint8_t ft_code;
static int ft_x, ft_dmy;
/* Есть ли у кода тайла ХОТЬ ЧТО-ТО в переднем слое. Порт ранней проверки
* оригинала — `id = tile_table[curr_tile].fore_id; if (id == 0) return;`
* в начале ветки default у draw_tile_fore (seg008:0D15), — расширенной
* нашими спецслучаями: стена (20), пики (2), чомпер (0x12) и нижняя грань
* loose (11) рисуются мимо fore_id.
*
* Была в самом КОНЦЕ цепочки: до неё успевали отработать чтение кода тайла
* и все сравнения спецслучаев. Замер в MAME: fore-проход стоил 58 764 такта
* ради одного блита 10×2, а в позиции без переднего слоя — 112 758 тактов
* и ноль блитов. */
static const uint8_t FORE_ANY[32] = {
/* 00 empty */ 0, /* 01 floor */ 0, /* 02 spike */ 1, /* 03 pillar */ 1,
/* 04 gate */ 1, /* 05 stuck */ 0, /* 06 closebtn */ 0, /* 07 doortopf */ 1,
/* 08 bpbot */ 1, /* 09 bptop */ 1, /* 0A potion */ 1, /* 0B loose */ 1,
/* 0C dtop */ 1, /* 0D mirror */ 1, /* 0E debris */ 1, /* 0F openbtn */ 0,
/* 10 ldL */ 0, /* 11 ldR */ 0, /* 12 chomper */ 1, /* 13 torch */ 0,
/* 14 wall */ 1, /* 15 skeleton */ 0, /* 16 sword */ 0, /* 17 balcL */ 0,
/* 18 balcR */ 0, /* 19 lattpil */ 1, /* 1A lattdown */ 1, /* 1B lattsm */ 1,
/* 1C lattl */ 1, /* 1D lattr */ 1, /* 1E debristo */ 1, /* 1F — */ 0
};
/* Контекст ft_* обязан быть проставлен вызывающим. */
static void fore_only_tile(int row, int col)
{
/* Нажатая кнопка → пол/stuck (get_tile_to_draw), иначе поверх Kid лезет
* передняя грань КНОПКИ. */
uint8_t code = pop_tile_code_drawn(row, col);
/* Нажатая кнопка → пол/stuck (get_tile_to_draw) — это уже учтено в ft_code
* (его ставит pop_tile_code_drawn), иначе поверх Kid лезет передняя грань
* КНОПКИ. */
uint8_t code = ft_code;
const piece *t;
int x = ft_x, dmy = ft_dmy;
if (!FORE_ANY[code]) return; /* ранний выход, как в оригинале */
t = &pop_tile_table[code];
int x = POP_COL_XH[col] * 8;
int dmy = 63 * row + 62;
if (code == 20) {
pop_wall_b(POP_WALL_FRAM_MAIN[pop_wall_modifier(row, col)], x, dmy);
wall_pattern(row, col, 1);
@@ -375,6 +406,8 @@ static void ceil_over_kid_tile(int col)
}
if (code == 11) /* draw_loose(1): плита-потолок */
pop_env_b(POP_LOOSE_FRAM_BOTTOM[pop_loose_frame(pop_ceil_modif[col])], x, dby);
ft_code = pop_tile_code_drawn(-1, col); /* контекст тайла для листа */
ft_x = x; ft_dmy = 63 * (-1) + 62;
fore_only_tile(-1, col); /* draw_tile_fore */
}
@@ -405,9 +438,13 @@ static void fore_tile(int row, int col) /* передний слой одно
* висящего/подтягивающегося Kid видны НАД плитой, а тело уходит ЗА неё.
* Без этого Kid лез на плиту «с переднего края» (комната 12: вис на
* кромке loose над дырой от соседней упавшей плиты). */
if (row >= 0 && pop_tile_code_drawn(row, col) == 11)
ft_code = pop_tile_code_drawn(row, col); /* код тайла — ОДИН раз на тайл */
if (!FORE_ANY[ft_code]) return; /* нечего класть в передний слой */
ft_x = POP_COL_XH[col] * 8;
ft_dmy = 63 * row + 62;
if (row >= 0 && ft_code == 11)
pop_env_b(POP_LOOSE_FRAM_BOTTOM[pop_loose_frame(pop_loose_modif[row * 10 + col])],
POP_COL_XH[col] * 8, 63 * row + 65);
ft_x, ft_dmy + 3);
/* draw_tile_fore (seg008:690) — ТОЛЬКО add_foretable-часть. Раньше здесь
* рисовалась ещё и передняя кромка пола (bottom_id) «чтобы перекрывала
* Kid», но в оригинале bottom идёт через draw_tile_bottom в backtable