Регресс тактов после четырёх фиксов: убран +130 000 в heal и +130 000 в циане
Замер на сцене каскада (ур.13 к.23) ПОСЛЕ багфиксов показал регресс, причём
в том числе в СИНЕЙ фазе, которую фиксы не трогали:
до фиксов после фиксов после этой правки
работа 783 798 1 038 528 873 930
синяя 142 830 275 538 142 830
зелёная 414 456 415 284 417 630
циан 269 538 479 628 379 482
период (растр.) 4 5 4 (один кадр 5)
Разбор синей зондом L (граница «ввод+heal» / «логика») сразу указал место:
логика 88 020 не изменилась, а «ввод+heal» вырос 55 000 -> 187 500. Это
pop_fore_heal чистит ОБЪЕДИНЁННЫЙ ov_mark: кромка потолка (полоса y 0..8) и
оверлеи соседей (64x64 на тайл) от шести кусков сливались в прямоугольник на
полкомнаты.
Правки, каждая с замером:
1. Оверлей соседа рисуется в ОКНЕ = прямоугольник самого куска. Смысл
оверлея — перекрыть кусок, а что лежит вне него, и так нарисовано
правильным фоном. Даёт три вещи разом: пикселей в разы меньше; куски
тайла, не задевающие кусок, отсеиваются предфильтром pop_blit_b даром (это
и есть вертикальный гейт, отдельного не надо); ov_mark становится НЕ НУЖЕН
— всё нарисованное лежит внутри heal-коридора куска, а он чистится каждый
кадр. Для этого заведён ov_suppress.
2. Кромка потолка — тоже без ov_mark: её куски рисуются от dby = 2, то есть
занимают строки 0..2, а помечает её только кусок и только пока достаёт
(mob_y <= 18) — значит она внутри его же коридора.
3. Предусловия перенесены в РЕЗИДЕНТ, до вызова в банк 2: pop_mob_overlay_tile
и разбор пометок живут в других банках, и каждый вызов платит межбанковый
трамплин (~8 900), а условий всего два дешёвых чтения тайла
(pop_tile_code — резидент, ~1 100). Гейты: тайл соседа не пуст и его
габарит пересекается с габаритом куска; для полосы потолка — тайл полосы
не пуст (а он там чаще всего пуст: кусок существует ровно потому, что
плита из своей клетки выпала, и пустой тайл в переднем слое не рисует
ничего).
ОТРИЦАТЕЛЬНЫЙ РЕЗУЛЬТАТ, откачен: сдавать пометки ряда −1 одной МАСКОЙ
вместо до двенадцати отдельных вызовов (один трамплин вместо двенадцати) —
873 930 -> 879 276, то есть хуже. Пометки ставятся редко, а цена копилки и
разбора маски платится всегда.
Итог: все три секции в бюджете 400 000 (синяя 158 880, циан 379 482), зелёная
417 630 — она была такой и ДО фиксов, это не регресс. Период вернулся к 4
растровым кадрам; ровно один логический кадр из 54 идёт за 5 (работа 873 930
при пороге 860 000).
Цена четырёх багфиксов по итогу: +90 000 работы за кадр (+11 %), из них весь
рост в циане.
Тестовый образ теперь всегда собирается LEVEL=1 (решение пользователя:
переход на нужный уровень он делает сам).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,9 +34,17 @@
|
|||||||
* восстанавливаем фон на ОБЕИХ страницах (pop_fore_heal). */
|
* восстанавливаем фон на ОБЕИХ страницах (pop_fore_heal). */
|
||||||
static int ov_x0, ov_y0, ov_x1, ov_y1;
|
static int ov_x0, ov_y0, ov_x1, ov_y1;
|
||||||
static uint8_t ov_pending; /* биты страниц, где надо восстановить фон */
|
static uint8_t ov_pending; /* биты страниц, где надо восстановить фон */
|
||||||
|
/* Подавить ov_mark на время серии — для вызывающего, который САМ чистит эту
|
||||||
|
* область каждый кадр. Так работает падающий кусок: его heal-коридор
|
||||||
|
* прочёсывается всегда, а оверлей соседа и кромка потолка рисуются ВНУТРИ
|
||||||
|
* коридора (окно клипа = прямоугольник куска). Без этого объединение ov_mark
|
||||||
|
* по шести кускам растягивалось на полкомнаты, и pop_fore_heal стоил 187 500
|
||||||
|
* такта в фазе «ввод+heal» против 55 000 (замер 2026-08-17). */
|
||||||
|
static uint8_t ov_suppress;
|
||||||
|
|
||||||
static void ov_mark(int x, int y, int w, int h)
|
static void ov_mark(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
|
if (ov_suppress) return;
|
||||||
if (!ov_pending) { ov_x0 = x; ov_y0 = y; ov_x1 = x + w; ov_y1 = y + h; }
|
if (!ov_pending) { ov_x0 = x; ov_y0 = y; ov_x1 = x + w; ov_y1 = y + h; }
|
||||||
else {
|
else {
|
||||||
if (x < ov_x0) ov_x0 = x;
|
if (x < ov_x0) ov_x0 = x;
|
||||||
@@ -837,14 +845,30 @@ static void other_overlay_tile(int row, int col)
|
|||||||
*
|
*
|
||||||
* Ориентир сохраняем и возвращаем: pop_bg_obj_* принадлежит текущему
|
* Ориентир сохраняем и возвращаем: pop_bg_obj_* принадлежит текущему
|
||||||
* персонажу, и его читает ещё и mob_tick_one (решение defer). */
|
* персонажу, и его читает ещё и mob_tick_one (решение defer). */
|
||||||
void pop_mob_overlay_tile(int row, int col, int8_t oref_row, int8_t oref_col) __banked
|
void pop_mob_overlay_tile(int row, int col, int8_t oref_row, int8_t oref_col,
|
||||||
|
int mx, int my, uint8_t mh) __banked
|
||||||
{
|
{
|
||||||
int8_t saved_row = pop_bg_obj_row, saved_col = pop_bg_obj_col;
|
int8_t saved_row = pop_bg_obj_row, saved_col = pop_bg_obj_col;
|
||||||
pop_bg_obj_row = oref_row;
|
pop_bg_obj_row = oref_row;
|
||||||
pop_bg_obj_col = oref_col;
|
pop_bg_obj_col = oref_col;
|
||||||
|
/* ОКНО = прямоугольник самого КУСКА. Смысл оверлея — перекрыть кусок, а
|
||||||
|
* то, что лежит вне него, и так нарисовано правильным фоном. Даёт сразу
|
||||||
|
* три вещи:
|
||||||
|
* - рисуем в разы меньше пикселей (тайл соседа шириной 32 обрезается до
|
||||||
|
* перекрытия с куском);
|
||||||
|
* - куски тайла, вовсе не задевающие кусок, отсеиваются предфильтром
|
||||||
|
* pop_blit_b даром — это и есть вертикальный гейт, отдельного не надо;
|
||||||
|
* - ov_mark становится НЕ НУЖЕН: всё нарисованное внутри heal-коридора
|
||||||
|
* куска, а он чистится каждый кадр.
|
||||||
|
* Замер 2026-08-17: без окна оверлеи шести кусков давали +210 000 в циане
|
||||||
|
* и +130 000 в «ввод+heal» (объединение ov_mark на полкомнаты). */
|
||||||
|
ov_suppress = 1;
|
||||||
|
pop_t_win_set(mx, my - (int)mh + 1 + POP_YOFF, 64, (uint8_t)(mh + 1));
|
||||||
gfx_set_bank(GFX_BANK_SPRITE);
|
gfx_set_bank(GFX_BANK_SPRITE);
|
||||||
other_overlay_tile(row, col);
|
other_overlay_tile(row, col);
|
||||||
gfx_set_bank(GFX_BANK_NORMAL);
|
gfx_set_bank(GFX_BANK_NORMAL);
|
||||||
|
pop_t_win_clear();
|
||||||
|
ov_suppress = 0;
|
||||||
pop_bg_obj_row = saved_row;
|
pop_bg_obj_row = saved_row;
|
||||||
pop_bg_obj_col = saved_col;
|
pop_bg_obj_col = saved_col;
|
||||||
}
|
}
|
||||||
@@ -946,7 +970,14 @@ void pop_fore_tile_b(int row, int col) __banked
|
|||||||
void pop_ceil_fore_tile_b(int col) __banked
|
void pop_ceil_fore_tile_b(int col) __banked
|
||||||
{
|
{
|
||||||
int x = POP_COL_XH[col] * 8;
|
int x = POP_COL_XH[col] * 8;
|
||||||
ov_mark(x, 0, 64, CEIL_BAND_H);
|
/* ov_mark ЗДЕСЬ НЕ НУЖЕН, и это важно для бюджета. Передние куски потолка
|
||||||
|
* рисуются от dby = 2, то есть занимают строки 0..2 поля, а пометку ставит
|
||||||
|
* ТОЛЬКО падающий кусок, и только пока он до этих строк достаёт
|
||||||
|
* (mob_y <= 18) — значит нарисованное целиком лежит в его heal-коридоре
|
||||||
|
* (mob_y−18 .. mob_y+1), который чистится каждый кадр на своей странице.
|
||||||
|
* Пока ov_mark тут стоял, его объединение с оверлеями соседей
|
||||||
|
* растягивалось на полкомнаты и pop_fore_heal стоил 187 500 такта вместо
|
||||||
|
* 55 000 (замер 2026-08-17). */
|
||||||
pop_t_clip_top = POP_YOFF;
|
pop_t_clip_top = POP_YOFF;
|
||||||
pop_t_win_set(x, POP_YOFF, 64, CEIL_BAND_H);
|
pop_t_win_set(x, POP_YOFF, 64, CEIL_BAND_H);
|
||||||
ceil_over_kid_tile(col);
|
ceil_over_kid_tile(col);
|
||||||
|
|||||||
@@ -181,7 +181,8 @@ void pop_ceil_fore_tile_b(int col) __banked;
|
|||||||
/* Оверлей тайла (row,col) ПОВЕРХ падающего куска, чей тайл — (oref_row,
|
/* Оверлей тайла (row,col) ПОВЕРХ падающего куска, чей тайл — (oref_row,
|
||||||
* oref_col): порт set_redraw2 из draw_mob (seg007:1149). Порядок обхода
|
* oref_col): порт set_redraw2 из draw_mob (seg007:1149). Порядок обхода
|
||||||
* проверяется внутри. */
|
* проверяется внутри. */
|
||||||
void pop_mob_overlay_tile(int row, int col, int8_t oref_row, int8_t oref_col) __banked;
|
void pop_mob_overlay_tile(int row, int col, int8_t oref_row, int8_t oref_col,
|
||||||
|
int mx, int my, uint8_t mh) __banked;
|
||||||
|
|
||||||
/* Смена комнаты: куски продолжают падать в СВОИХ комнатах (do_mobs крутит
|
/* Смена комнаты: куски продолжают падать в СВОИХ комнатах (do_mobs крутит
|
||||||
* mobs[] независимо от drawn_room), сбрасывается только heal-история. */
|
* mobs[] независимо от drawn_room), сбрасывается только heal-история. */
|
||||||
|
|||||||
@@ -1463,8 +1463,16 @@ static void mob_mark_neighbour(const mob_t *m)
|
|||||||
* сама структура таблиц: кусок идёт в midtable (draw_mobs), а полоса
|
* сама структура таблиц: кусок идёт в midtable (draw_mobs), а полоса
|
||||||
* потолка — в foretable, и та рисуется позже (draw_tables, seg008:1373). */
|
* потолка — в foretable, и та рисуется позже (draw_tables, seg008:1373). */
|
||||||
if (m->y <= 18) {
|
if (m->y <= 18) {
|
||||||
pop_set_redraw_fore_above((uint8_t)m->col);
|
/* Пустой тайл полосы потолка не рисует В ПЕРЕДНЕМ СЛОЕ ничего
|
||||||
if (m->col + 1 <= 9) pop_set_redraw_fore_above((uint8_t)(m->col + 1));
|
* (bottom_id = 0, FORE_ANY = 0), а пометка стоит потом двух трамплинов
|
||||||
|
* — в банк 7 за разбором пометок и в банк 2 за самой отрисовкой,
|
||||||
|
* ~8 900 такта каждый. А пустой он тут как раз чаще всего: кусок
|
||||||
|
* существует ровно потому, что плита из своей клетки уже выпала.
|
||||||
|
* Проверяем pop_tile_code — он резидентный, ~1 100 такта. */
|
||||||
|
if (pop_tile_code(-1, m->col))
|
||||||
|
pop_set_redraw_fore_above((uint8_t)m->col);
|
||||||
|
if (m->col + 1 <= 9 && pop_tile_code(-1, m->col + 1))
|
||||||
|
pop_set_redraw_fore_above((uint8_t)(m->col + 1));
|
||||||
}
|
}
|
||||||
if (c > 9) return;
|
if (c > 9) return;
|
||||||
if (r >= 0 && r <= 2) pop_set_redraw_fore((uint8_t)(r * 10 + c));
|
if (r >= 0 && r <= 2) pop_set_redraw_fore((uint8_t)(r * 10 + c));
|
||||||
@@ -1481,11 +1489,27 @@ static void mob_overlay_neighbour(const mob_t *m)
|
|||||||
int8_t r = pop_y_to_row((int16_t)m->y);
|
int8_t r = pop_y_to_row((int16_t)m->y);
|
||||||
int8_t rt = pop_y_to_row((int16_t)(m->y - 18));
|
int8_t rt = pop_y_to_row((int16_t)(m->y - 18));
|
||||||
int8_t c = (int8_t)(m->col + 1);
|
int8_t c = (int8_t)(m->col + 1);
|
||||||
|
int ytop, ybot;
|
||||||
if (c > 9) return;
|
if (c > 9) return;
|
||||||
if (r >= 0 && r <= 2)
|
ytop = m->y - (int)mob_spr[2] + 1; /* верх спрайта куска */
|
||||||
pop_mob_overlay_tile(r, c, r, (int8_t)m->col);
|
ybot = m->y;
|
||||||
if (rt != r && rt >= 0 && rt <= 2)
|
/* ПРЕДУСЛОВИЯ ПРОВЕРЯЕМ ЗДЕСЬ, до вызова в банк 2. pop_mob_overlay_tile
|
||||||
pop_mob_overlay_tile(rt, c, r, (int8_t)m->col);
|
* живёт в банке 2, то есть каждый вызов из банка 7 платит межбанковый
|
||||||
|
* трамплин (~8 900 такта); а условий всего два — тайл не пуст и габарит
|
||||||
|
* тайла пересекается с габаритом куска. Оба дешёвые: pop_tile_code —
|
||||||
|
* резидент (~1 100). Замер 2026-08-17: без этого гейта двенадцать
|
||||||
|
* вызовов на шесть кусков стоили ~130 000 в циане, причём большинство
|
||||||
|
* ничего не рисовало.
|
||||||
|
*
|
||||||
|
* Габарит тайла берём ПОЛНЫМ (63*row+2 .. +66) — какая именно часть
|
||||||
|
* соседа окажется поверх куска, решит уже окно клипа внутри. Сужать по
|
||||||
|
* реальной высоте кусков нельзя: у колонн и зеркала база высокая. */
|
||||||
|
if (r >= 0 && r <= 2 && pop_tile_code(r, c) &&
|
||||||
|
ybot >= 63 * r + 2 && ytop <= 63 * r + 66)
|
||||||
|
pop_mob_overlay_tile(r, c, r, (int8_t)m->col, m->x, m->y, mob_spr[2]);
|
||||||
|
if (rt != r && rt >= 0 && rt <= 2 && pop_tile_code(rt, c) &&
|
||||||
|
ybot >= 63 * rt + 2 && ytop <= 63 * rt + 66)
|
||||||
|
pop_mob_overlay_tile(rt, c, r, (int8_t)m->col, m->x, m->y, mob_spr[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
||||||
|
|||||||
Reference in New Issue
Block a user