Оптимизация: логический кадр уложился в бюджет, цикл 4 растровых кадра -> 3
Главный цикл спейсится тремя gfx_wait_vsync, поэтому работа сверх 430 000 тактов стоит сразу целый лишний растровый кадр. Было 470 964, стало ~425 600 — игра быстрее на треть (16,7 логических кадров/с против 12,5). - pop_y_to_row: цепочка сравнений вместо (y+60)/63%4-1. ВАЖНО: медленный хвост вынесен в ОТДЕЛЬНУЮ функцию — SDCC видит одинаковое выражение в двух ветках и поднимает деление в вершину, быстрые возвраты не спасают. - col_from_x (pop_bg) и get_tile_div_mod (pop_map) — общие резидентные таблицы POP_TILE_DIV/POP_TILE_MOD в pop_tile.c (const банка из чужого банка не читается). - pop_fore_over_char: расширение окна считается арифметикой, а не перебором 10 колонок и 3 рядов (условие монотонно -> границы). Формулы сверены с прежним перебором перебором значений, расхождений нет. - pop_cd_touch: цикл по страницам развёрнут, x+w/y+h считаются один раз. Зовётся с каждого блита фона, стоил 6 846 тактов. - process_trobs: tp/10 и tp%10 у факелов — таблицей. - Пустой слот соперника (стража на сцене нет, на странице ничего не нарисовано) считается «тихим»: ни heal, ни вход в pop_char_draw, ни fore-проход. Приём для поиска делений: брейкпоинт на __divsint/__divuint/__divuchar с печатью адреса возврата (printf "%04X", w@(sp)). Профиль остатка — TASKS_OPEN.md#draw-cost. tests-host: 5/5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -304,10 +304,16 @@ void pop_gate_back_b(uint8_t modl, int xh, int dby, int dmy) __banked
|
||||
* X кадра Kid (до ×8/7), obj_y — низ спрайта, w/h — размер, dir — направление. */
|
||||
static int8_t col_from_x(int xpos) /* get_tile_div_mod: колонка (58/14) */
|
||||
{
|
||||
int x = xpos - 58;
|
||||
int xh = x / 14;
|
||||
if (x % 14 < 0) xh--; /* округление вниз для отрицательных */
|
||||
return (int8_t)xh;
|
||||
/* Таблицей (резидентная POP_TILE_DIV, см. pop_tile.h) — как в оригинале.
|
||||
* Было `/14` и `%14`: два полноценных 16-битных деления SDCC на вызов,
|
||||
* а зовётся это дважды на каждый футпринт персонажа. */
|
||||
if ((unsigned int)xpos < 256u) return POP_TILE_DIV[xpos];
|
||||
{
|
||||
int x = xpos - 58;
|
||||
int xh = x / 14;
|
||||
if (x % 14 < 0) xh--; /* округление вниз для отрицательных */
|
||||
return (int8_t)xh;
|
||||
}
|
||||
}
|
||||
|
||||
#define y_to_row(y) pop_y_to_row((int16_t)(y)) /* общий (pop_geom) */
|
||||
@@ -626,20 +632,37 @@ void pop_fore_over_char(const pop_char_t *ch, int obj_x, int obj_y,
|
||||
* ради скорости (см. pop_fore_layer_cost). Поэтому перебор расширяется
|
||||
* САМИМ ОКНОМ fore-клипа — оно и есть объединение «персонаж + клинок +
|
||||
* брызги», считать его второй раз не надо. */
|
||||
/* Границы считаются АРИФМЕТИКОЙ, а не перебором всех колонок и рядов.
|
||||
* Условие монотонно по номеру (x0 растёт), значит принятые номера идут
|
||||
* подряд — хватает первого и последнего. Перебор стоил 38 970 тактов на
|
||||
* кадр (замер MAME): тринадцать итераций, в каждой пара 16-битных
|
||||
* ЗНАКОВЫХ сверок, а SDCC пишет их через `jp PO / xor 0x80 / jp P`. */
|
||||
if (pop_t_fclip_x1 > pop_t_fclip_x0 && pop_t_fclip_y1 > pop_t_fclip_y0) {
|
||||
int8_t c2, r2;
|
||||
for (c2 = 0; c2 <= 9; c2++) {
|
||||
int x0 = POP_COL_XH[c2] * 8;
|
||||
if (x0 + 40 > pop_t_fclip_x0 && x0 < pop_t_fclip_x1) {
|
||||
if (c2 < fp_cL) fp_cL = c2;
|
||||
if (c2 > fp_cR) fp_cR = c2;
|
||||
}
|
||||
int8_t lo, hi;
|
||||
/* Колонки: x0 = POP_COL_XH[c]*8 = 32*c (таблица линейна, шаг 4).
|
||||
* 32c + 40 > x0 -> c >= floor((x0−40)/32) + 1
|
||||
* 32c < x1 -> c <= ceil(x1/32) − 1
|
||||
* Сдвиг вправо у SDCC z80 для int — арифметический, то есть floor и
|
||||
* для отрицательных; на это здесь и рассчитано. */
|
||||
lo = (int8_t)(((pop_t_fclip_x0 - 40) >> 5) + 1);
|
||||
hi = (int8_t)((((pop_t_fclip_x1 + 31) >> 5)) - 1);
|
||||
if (lo < 0) lo = 0;
|
||||
if (hi > 9) hi = 9;
|
||||
if (lo <= hi) {
|
||||
if (lo < fp_cL) fp_cL = lo;
|
||||
if (hi > fp_cR) fp_cR = hi;
|
||||
}
|
||||
for (r2 = 0; r2 <= 2; r2++) {
|
||||
int y0 = POP_YOFF + 63 * r2;
|
||||
if (y0 + 70 > pop_t_fclip_y0 && y0 - 8 < pop_t_fclip_y1) {
|
||||
if (r2 < fp_rT) fp_rT = r2;
|
||||
if (r2 > fp_rB) fp_rB = r2;
|
||||
/* Ряды: y0 = POP_YOFF + 63*r, r только 0..2 — деления на 63 не надо,
|
||||
* достаточно сравнить с границами полос.
|
||||
* 63r > y0 − POP_YOFF − 70 и 63r < y1 − POP_YOFF + 8 */
|
||||
{
|
||||
int a = pop_t_fclip_y0 - POP_YOFF - 70;
|
||||
int b = pop_t_fclip_y1 - POP_YOFF + 8;
|
||||
lo = a < 0 ? 0 : (a < 63 ? 1 : 2);
|
||||
hi = b > 126 ? 2 : (b > 63 ? 1 : 0);
|
||||
if (a < 126 && b > 0 && lo <= hi) {
|
||||
if (lo < fp_rT) fp_rT = lo;
|
||||
if (hi > fp_rB) fp_rB = hi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user