pop_blit_b: быстрый путь без клипа + backlog отложенной оптимизации
Клипованный путь вынесен в отдельную функцию blit_b_clip: под его девять 16-битных локалей SDCC заводит кадр IX, и за этот кадр платили ВСЕ блиты фона, включая те, где клипа нет вовсе (весь фон вне fore-прохода — факелы, зелья, перерисовка тайлов, у них pop_t_fclip_on == 0). Быстрый путь идёт сразу в gfx_blit_noclip. Замер: pop_torch_draw 41 778 -> 31 218 тактов на факел (часть разницы — прошлая правка pop_cd_touch; чистый вклад этой ~6 300 на блит). Поведение не изменилось: клипованная ветка перенесена дословно. docs/perf_backlog.md — отложенные идеи с измеренной ценой (футпринт из физики 11 574, размеры ленты из каталога атласа, один map/unmap на группу блитов, единый проход по тайлам как redraw_needed_tiles, objtable, отложенные таблицы back/mid/fore) плюс раздел «как мерить»: wait-state'ы дают 2,4x к справочным тактам, кадр 430 000, адреса символов меняются после каждой пересборки, сцена между сессиями не воспроизводится. Там же — что уже проверено и НЕ сработало. tests-host: 5/5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -439,6 +439,15 @@ wait-state'ы, и замеренная стоимость выходит **≈ 2
|
||||
|
||||
Синяя полоса (ввод + логика) была ~60 % → стала ~29 %.
|
||||
|
||||
**Оптимизация закрыта по решению пользователя 2026-08-10.** Всё, что
|
||||
осталось неcделанным, вынесено с замерами в
|
||||
[`../docs/perf_backlog.md`](../docs/perf_backlog.md) — там же протокол «как
|
||||
мерить», чтобы не наступать заново на wait-state'ы и на устаревшие адреса
|
||||
символов. Что доделано после таблицы выше: `pop_cd_touch` развёрнут,
|
||||
tp/10 у факелов таблицей, пустой слот соперника считается тихим, ранний
|
||||
выход в fore-проходе (нулевой эффект, оставлен как порт), быстрый путь без
|
||||
клипа в `pop_blit_b` (факел 41 778 -> 31 218 тактов).
|
||||
|
||||
**Что осталось (запас на будущее, срочности больше нет):**
|
||||
|
||||
1. **`pop_char_fore` 113 628.** Внутри: `char_footprint` + расширение окна
|
||||
|
||||
@@ -186,11 +186,45 @@ void pop_cd_touch(int x, int y, int w, int h)
|
||||
}
|
||||
|
||||
/* ---- Блит куска атласа ---------------------------------------------- */
|
||||
/* Клипованный путь — ОТДЕЛЬНОЙ функцией. У него девять 16-битных локалей,
|
||||
* и SDCC заводит под них кадр IX; пока он жил в общем теле, за этот кадр
|
||||
* платили и блиты БЕЗ клипа (`ld -n(ix)` = 19 тактов номинала, у нас ~46).
|
||||
* А блитов без клипа большинство: весь фон вне fore-прохода — факелы, зелья,
|
||||
* перерисовка тайлов — идёт с pop_t_fclip_on == 0. */
|
||||
static void blit_b_clip(const uint8_t *img, int x, int top, int w, int h)
|
||||
{
|
||||
int dx = x, dy = top, dw = w, dh = h, sx = 0, sy = 0;
|
||||
if (pop_t_clip_top && dy < pop_t_clip_top) { /* полоса у потолка */
|
||||
sy = pop_t_clip_top - dy; dy = pop_t_clip_top; dh -= sy;
|
||||
}
|
||||
if (pop_t_fclip_on) { /* окно fore-слоя */
|
||||
if (dx < pop_t_fclip_x0) { int d = pop_t_fclip_x0 - dx; sx += d; dx += d; dw -= d; }
|
||||
if (dy < pop_t_fclip_y0) { int d = pop_t_fclip_y0 - dy; sy += d; dy += d; dh -= d; }
|
||||
if (dx + dw > pop_t_fclip_x1) dw = pop_t_fclip_x1 - dx;
|
||||
if (dy + dh > pop_t_fclip_y1) dh = pop_t_fclip_y1 - dy;
|
||||
}
|
||||
if (dw <= 0 || dh <= 0) return;
|
||||
if (dx >= 0 && dy >= 0 && dw < 256 && dh < 256 &&
|
||||
dx + dw <= 320 && dy + dh <= 256 && w < 256) {
|
||||
if (sx == 0 && sy == 0 && dw == w && dh == h)
|
||||
gfx_blit_noclip(dx, dy, img);
|
||||
else
|
||||
gfx_blit_part_noclip(dx, dy, img, (uint8_t)sx, (uint8_t)sy,
|
||||
(uint8_t)dw, (uint8_t)dh);
|
||||
} else {
|
||||
gfx_blit_part(dx, dy, img, sx, sy, dw, dh); /* край экрана */
|
||||
}
|
||||
/* Кусок ФОНА лёг туда, где может лежать уже нарисованный персонаж —
|
||||
* пометить область (DRAW-COST, pop_cdraw.h). Признак «это не fore-проход
|
||||
* поверх персонажа» — окно клипа: его ставит только он. */
|
||||
if (!pop_t_fclip_on) pop_cd_touch(dx, dy, dw, dh);
|
||||
}
|
||||
|
||||
void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
|
||||
{
|
||||
const uint8_t *img;
|
||||
uint16_t w, h;
|
||||
int top, dx, dy, dw, dh, sx = 0, sy = 0;
|
||||
int top;
|
||||
if (idx >= a->count)
|
||||
return;
|
||||
/* Грубый отсев ДО маппинга страницы: реальные w/h лежат в заголовке
|
||||
@@ -208,37 +242,22 @@ void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
|
||||
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
|
||||
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
|
||||
top = ybottom - (int)h + 1 + POP_YOFF; /* +YOFF: центрирование */
|
||||
dx = x; dy = top; dw = (int)w; dh = (int)h;
|
||||
if (pop_t_clip_top && dy < pop_t_clip_top) { /* полоса у потолка */
|
||||
sy = pop_t_clip_top - dy; dy = pop_t_clip_top; dh -= sy;
|
||||
}
|
||||
if (pop_t_fclip_on) { /* окно fore-слоя */
|
||||
if (dx < pop_t_fclip_x0) { int d = pop_t_fclip_x0 - dx; sx += d; dx += d; dw -= d; }
|
||||
if (dy < pop_t_fclip_y0) { int d = pop_t_fclip_y0 - dy; sy += d; dy += d; dh -= d; }
|
||||
if (dx + dw > pop_t_fclip_x1) dw = pop_t_fclip_x1 - dx;
|
||||
if (dy + dh > pop_t_fclip_y1) dh = pop_t_fclip_y1 - dy;
|
||||
}
|
||||
if (w && h && dw > 0 && dh > 0) {
|
||||
/* Целиком на экране — линейное ядро без клипа: ~2.9× быстрее
|
||||
* (замер: 4617 против 13288 тактов на спрайт 32×3; общее ядро
|
||||
* gfx_blit платит за клип/16-бит/split, а не за пиксели).
|
||||
* W3-скобку ставит сама libbgi: из кода, собранного с --w3, её
|
||||
* вызывать нельзя (окно W3 уходит под видеобанк). */
|
||||
if (dx >= 0 && dy >= 0 && dw < 256 && dh < 256 &&
|
||||
dx + dw <= 320 && dy + dh <= 256 && w < 256) {
|
||||
if (sx == 0 && sy == 0 && dw == (int)w && dh == (int)h)
|
||||
gfx_blit_noclip(dx, dy, img);
|
||||
if (w && h) {
|
||||
if (!pop_t_fclip_on && !pop_t_clip_top) {
|
||||
/* БЫСТРЫЙ путь: клипа нет вовсе. Так идут все блиты фона вне
|
||||
* fore-прохода. Линейное ядро без клипа — ~2.9× быстрее общего
|
||||
* (замер: 4617 против 13288 тактов на спрайт 32×3; gfx_blit
|
||||
* платит за клип/16-бит/split, а не за пиксели). W3-скобку
|
||||
* ставит сама libbgi: из кода с --w3 её вызывать нельзя. */
|
||||
if (x >= 0 && top >= 0 && w < 256 && h < 256 &&
|
||||
x + (int)w <= 320 && top + (int)h <= 256)
|
||||
gfx_blit_noclip(x, top, img);
|
||||
else
|
||||
gfx_blit_part_noclip(dx, dy, img, (uint8_t)sx, (uint8_t)sy,
|
||||
(uint8_t)dw, (uint8_t)dh);
|
||||
gfx_blit_part(x, top, img, 0, 0, (int)w, (int)h);
|
||||
pop_cd_touch(x, top, (int)w, (int)h);
|
||||
} else {
|
||||
gfx_blit_part(dx, dy, img, sx, sy, dw, dh); /* край экрана — с клипом */
|
||||
blit_b_clip(img, x, top, (int)w, (int)h);
|
||||
}
|
||||
/* Кусок ФОНА лёг туда, где может лежать уже нарисованный персонаж —
|
||||
* пометить область, чтобы его перерисовали (DRAW-COST, pop_cdraw.h).
|
||||
* Признак «это не fore-проход поверх персонажа» — окно клипа: его
|
||||
* ставит только он. */
|
||||
if (!pop_t_fclip_on) pop_cd_touch(dx, dy, dw, dh);
|
||||
}
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user