# Double buffer (два экрана + флип) — план Цель: убрать мерцание/тиринг при перерисовке слоёв (Kid ↔ fore/пол-оверлей) и гарантировать, что на экране ВСЕГДА готовый кадр с правильным порядком слоёв. Нужно для отладки fore-слоя (видно момент композиции, а не промежуточные состояния heal-рендера). **Тумблер обязателен** — однобуферный режим удобнее для отладки багов рисования. ## Что уже готово (libbgi — трогать НЕ нужно) - Две графических страницы 0/1: `gfx_set_draw_page(p)` (двигает `_gfx_addr_base` 0xC000/0xC140 — рисуют все примитивы), `gfx_set_visible_page(p)` (ESTEX $54 SELPAGE — display-учёт DSS). - `gfx_wait_vsync()` — луч (bit5 порта 0xFE), момент без разрывов. - Паттерн из gfx.h: `set_draw_page(hidden); draw(); wait_vsync(); set_visible_page(hidden);` - Замечание gfx.h: у каждой страницы СВОЯ плоскость палитры (page0→pal0, page1→pal1) — для seamless грузить одну палитру в ОБЕ. ## Текущая модель рендера roomtest (однобуфер) `roomtest.c`: `draw_page=0`, `visible_page=0` фиксированы. Фон комнаты рисуется ОДИН раз в видео-ОЗУ + теневую копию (GFX_BANK_TRANSPARENT). Цикл: 3× `gfx_wait_vsync` (пейсинг) → `pop_ctrl_tick` → `kid_heal()` (восстановить прямоугольник Кида из тени) → `kid_tick`/`pop_phys_tick` → `kid_draw` → `pop_fore_over_kid`. Мерцание = heal+draw+fore длиннее бланка, луч ловит промежуток. ## Работа на стороне PoP 1. **Инициализация обеих страниц**: `pop_room_draw` в page 0 И page 1 (теневая копия одна — общая, из неё heal'ит любая страница). 2. **Палитра в обе плоскости**: сейчас `gfx_pal_fload(0,...)` + sync. Продублировать в plane 1 (проверить сигнатуру gfx_pal_fload/sync — plane-параметр). 3. **Per-page heal-история** (ядро): вынести `kid_lx/ly/lw/lh` в массивы `[2]`, индекс = страница, в которую рисуем. `kid_heal(page)` восстанавливает СВОЙ прошлый прямоугольник (кадр -2, т.к. рисуем через страницу). То же для fore/пол-оверлея, если они рисуют вне футпринта Кида. 4. **Ping-pong в цикле**: ``` uint8_t back = dbuf ? (front ^ 1) : 0; gfx_set_draw_page(back); kid_heal(back); kid_tick; phys; kid_draw; fore; gfx_wait_vsync(); if (dbuf) { gfx_set_visible_page(back); front = back; } ``` 5. **Тумблер** `dbuf`: off → draw==visible==0, без флипа, heal[0] — бит-в-бит текущее поведение. Управление — клавишей (напр. F2) или compile-флагом. 6. **Пейсинг**: сейчас 3× vsync/лог.кадр. При флипе — один vsync перед свопом; недостающий пейсинг добрать `gfx_set_fps_div(3)` или ручным счётом кадров, чтобы скорость игры не изменилась. ## Порядок - D1: обе страницы + палитра в обе плоскости; ping-pong без per-page heal (проверить, что флип работает, фон корректен на обеих). - D2: per-page heal-история (kid_l*[2]) — убрать «хвост» Кида. - D3: тумблер dbuf + сверка однобуферного пути с текущим (регресс-нет). - D4: пейсинг (fps_div) — вернуть исходную скорость. ## Связанные Рендер-модель — [[pop_fore_layer]], [[pop_background_strategy]]; heal — kid_heal/gfx_heal. Будущие динамические слои (loose-floors [[двойной буфер требует их per-page перерисовки]]) должны рисоваться в обе страницы по той же дисциплине.