From a65da9696048033237456b4163740a900235944e Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Wed, 19 Aug 2026 15:35:54 +0300 Subject: [PATCH] =?UTF-8?q?CHAR-PARTIAL-REDRAW:=20=D0=BE=D0=B1=D1=8F=D0=B7?= =?UTF-8?q?=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D0=B0=D1=8F=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=B4=D0=B0=D1=87=D0=B0=20=D0=BE=20=D0=BD=D0=B5=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=B2=D0=B8=D0=B6=D0=BD=D0=BE=D0=BC=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=81=D0=BE=D0=BD=D0=B0=D0=B6=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Постановка пользователя: проверять, нужна ли отрисовка стража, когда он не двигается. Если движется — лишние ~150 000 тактов приемлемы: в оригинале во время боя число физических кадров на логический тоже растёт на единицу. Замер чтением pop_cd из памяти машины показал, насколько цена несоразмерна поводу: страж x 257..284, y 18..56 28 x 39 пламя (0,7) x 264..279, y 5..22 16 x 18 пересечение x 264..279, y 18..22 16 x 5 То есть пламя задевает страже только макушку — 80 пикселей, — а перерисовывается он целиком за 148 302 такта (85 524 спрайт с клинком и снимком + 62 778 fore-проход), это 23 % работы кадра. Пересечение при этом настоящее: дело не в грубости маски меток, проверено числами. В задаче записаны два варианта: A — частичная перерисовка только пересечения (безопаснее, укладывается в контракт pop_cd), B — не рисовать фон там, где он всё равно перекрыт неподвижным персонажем (дешевле, но обрезанное пламя попадёт в ОЗУ-копию и heal вернёт дыру, когда персонаж сдвинется). Заодно уточнено, чем НЕ является P13 (вопрос пользователя): это не перерисовка комнаты заново каждый кадр — такой вариант стоил бы порядка 3 000 000 тактов, семь растровых кадров, и оригинал так тоже не делает. Разница в цене ПОСЕЩЕНИЯ тайла: у нас fore_tile сразу блитит, у оригинала add_*table только кладёт запись, а рисует один draw_table в конце. Co-Authored-By: Claude Opus 5 --- applications/PoP/docs/perf_registry.md | 38 ++++++++++++++++- applications/PoP/roomtest/TASKS_OPEN.md | 54 +++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/applications/PoP/docs/perf_registry.md b/applications/PoP/docs/perf_registry.md index 0358c3d..7170e06 100644 --- a/applications/PoP/docs/perf_registry.md +++ b/applications/PoP/docs/perf_registry.md @@ -150,6 +150,27 @@ Новое, найдено 2026-08-19. +### P15. Неподвижный персонаж перерисовывается целиком — ОБЯЗАТЕЛЬНО [замер 2026-08-19] + +**Постановка пользователя:** проверять, нужна ли отрисовка стража, когда он +не двигается. Если движется — лишние ~150 000 приемлемы: в оригинале во +время боя число физических кадров на логический тоже растёт на единицу. + +Измерено чтением `pop_cd` из памяти машины: + +| | прямоугольник | размер | +|---|---|---| +| страж | x 257..284, y 18..56 | 28 × 39 | +| пламя факела (0,7) | x 264..279, y 5..22 | 16 × 18 | +| **пересечение** | **x 264..279, y 18..22** | **16 × 5** | + +**148 302 такта (23 % кадра) тратятся из-за 80 задетых пикселей на макушке.** +Пересечение при этом НАСТОЯЩЕЕ — дело не в грубости маски меток. + +Полная постановка с двумя вариантами решения (частичная перерисовка против +обрезки фона под персонажем) — `TASKS_OPEN.md`, якорь `char-partial-redraw`. +Смежное: **P14** — вторая половина той же цены. + ### P14. Fore-проход персонажа — 62 778…89 000 НА ПЕРСОНАЖА [замер 2026-08-19] **Самая дорогая единичная статья кадра: около 152 000 на двоих, 20 % работы.** @@ -312,6 +333,20 @@ BUG-LATTICE-DOORTOP, BUG-SEAM-WEDGE-1) — только отдельным за ### P13. Крупные рефакторинги — брать, только если понадобится ещё запас +**Чем P13 НЕ является (вопрос пользователя 2026-08-19).** Это не «рисовать +комнату заново каждый кадр в скрытый буфер». Такой вариант исключён +арифметикой: 30 тайлов по 5-6 спрайтов при цене блита 16 674 (и 179 914 за +полную запечку одного тайла) дают порядка **3 000 000 тактов — семь +растровых кадров**. Оригинал так тоже не делает: у него та же +инкрементальная схема с пометками (`redraw_frames_full` / `_anim` / +`_fore`), перерисовываются только помеченные тайлы. + +Разница не в объёме отрисовки, а в цене ПОСЕЩЕНИЯ тайла: у нас +`fore_tile(r, c)` сразу блитит (со всеми 6 126 фиксированных накладных), а +у оригинала `add_backtable`/`add_midtable`/`add_foretable` только кладут +запись в массив, и рисует один `draw_table()` в конце. Плюс у него ОДИН +обход тайлов за кадр против наших трёх. + - **C7 / backlog §5-6: objtable + отложенные таблицы back/mid/fore.** У оригинала «посетить тайл» стоит копейки, потому что таблицы только копят записи, а рисует один `draw_table()` в конце. У нас блит идёт сразу из @@ -346,7 +381,8 @@ BUG-LATTICE-DOORTOP, BUG-SEAM-WEDGE-1) — только отдельным за | # | что | ожидание | риск | комментарий | |---|---|---:|---|---| -| **P14** | **fore-проход персонажа** — 62 778 у стража, ~89 000 у Кида | **до −80 000** | высокий | НОВОЕ, самая дорогая статья кадра (20 %). Включает P10 как первый шаг | +| **P15** | **неподвижный персонаж: не перерисовывать целиком** | **до −130 000** | средний | **ОБЯЗАТЕЛЬНАЯ** (пользователь, 2026-08-19). 148 302 из-за пересечения 16×5 | +| **P14** | **fore-проход персонажа** — 62 778 у стража, ~89 000 у Кида | **до −80 000** | высокий | самая дорогая статья кадра (20 %). Включает P10 как первый шаг | | P4 | накладные блита (4 правки) | −28 000 | низкий | 6 126 фиксированных на любой блит | | P11 | мелочи с известной ценой | −26 000 | низкий | `clip_char_top` 8 658 подтверждён замером | | P10 | футпринт персонажа из физики | −23 000 | средний | часть P14 | diff --git a/applications/PoP/roomtest/TASKS_OPEN.md b/applications/PoP/roomtest/TASKS_OPEN.md index 9fbe32a..49ca7a6 100644 --- a/applications/PoP/roomtest/TASKS_OPEN.md +++ b/applications/PoP/roomtest/TASKS_OPEN.md @@ -261,6 +261,60 @@ MEM-BANK2, MEM-BANK5, CLIP-1, KBD-1, DBG-CHEATS. ## P0 — делаем сейчас +### CHAR-PARTIAL-REDRAW. Неподвижный персонаж перерисовывается целиком из-за нескольких пикселей — ОБЯЗАТЕЛЬНО + +**Постановка (пользователь, 2026-08-19).** Проверять, нужна ли отрисовка +стража, когда он НЕ ДВИГАЕТСЯ. Если движется — лишние ~150 000 тактов +приемлемы: в оригинале во время боя число физических кадров на логический +тоже растёт на единицу, и прийти к тому же решению не страшно. + +**Измерено** (сцена 11/15, MAME, чтение `pop_cd` из памяти): + +| | прямоугольник | размер | +|---|---|---| +| страж | x 257..284, y 18..56 | 28 × 39 | +| пламя правого факела (0,7) | x 264..279, y 5..22 | 16 × 18 | +| **пересечение** | **x 264..279, y 18..22** | **16 × 5** | + +То есть пламя задевает страже только макушку — 80 пикселей, — а +перерисовывается он ЦЕЛИКОМ и стоит **148 302 такта** (85 524 сам спрайт с +клинком и снимком, 62 778 fore-проход). Это 23 % работы кадра. + +Механика: `pop_torch_draw` запекает пламя в фон каждый кадр (`TORCH_ANIM_DIV += 1`), `pop_cd_touch` метит область, `cd_quiet` видит пересечение с bbox +слота и снимает «тихий» бит — дальше `pop_char_draw` + `pop_char_fore` +идут полностью. Метка тут ни при чём: пересечение НАСТОЯЩЕЕ (проверено +числами выше, а не по грубой маске колонок). + +**Варианты решения** (оба нуждаются в прототипе и замере): + +- **A. Частичная перерисовка.** Если сигнатура слота не изменилась, но + фон задет — восстановить только пересечение: блит нужных колонок/строк + спрайта (`gfx_blit_cols_part_w` это умеет) и fore-проход только по + задетым тайлам. Ожидание: вместо 148 302 порядка 20 000. + Риск: надо аккуратно с клинком и брызгами (у них свой прямоугольник) и с + порядком слоёв внутри пересечения. +- **B. Не рисовать фон там, где он всё равно перекрыт.** Пламя обрезать по + прямоугольнику неподвижного персонажа — визуально результат тот же (эти + строки под ним и не видны), а персонажа не надо трогать вовсе: + экономия все 148 302. **Опасность:** обрезанное пламя попадает в + ОЗУ-копию, и когда персонаж сдвинется, `heal` вернёт фон С ДЫРОЙ. + Годится, только если запекать в копию полное пламя, а обрезать лишь + запись в видео-ОЗУ — то есть нужен блит с двумя разными масками. + +**Порядок:** сначала A (безопаснее и укладывается в существующий контракт +`pop_cd`), B — только если A не хватит. + +**Проверка:** замер 11/15 в ОБЕИХ позициях Кида (лёгкая x = 99 и тяжёлая +x = 106, разбор в [`../docs/perf_l11_room15.md`](../docs/perf_l11_room15.md) +§7) плюс визуальный прогон боя: персонаж не должен оставлять хвостов и +не должен просвечивать сквозь пламя. + +**Место в очереди — [`../docs/perf_registry.md`](../docs/perf_registry.md), +позиция P15.** Смежное: P14 (fore-проход персонажа — вторая половина той же +цены). + + ### HEAL-WIDTH. Ширина точечных heal'ов не совпадает со следом перерисовки — ОБЯЗАТЕЛЬНО **Постановка (пользователь, 2026-08-18).** Ширины heal'ов взяты «на глаз по