roomtest: двойная буферизация (два экрана + флип), тумблер SPACE

Убирает мерцание/тиринг при перерисовке слоёв (Kid/fore/пол-оверлей):
рендер всего кадра в скрытую страницу, tear-free флип на vblank.
Инфра libbgi (gfx_set_draw_page/visible_page/wait_vsync) уже была.

- фон комнаты рисуется в ОБЕ графические страницы (у каждой своя
  ОЗУ-копия — источник heal); палитра 0->1 уже синкалась gfx_pal_sync;
- kid_heal/kid_draw: прямоугольник Kid запоминается ПО СТРАНИЦЕ
  (kid_l*[2]) — при чередовании страниц heal стирает пиксели своей
  страницы (прошлый Kid там был 2 логических кадра назад);
- цикл: draw в back, 3x wait_vsync (пейсинг), gfx_set_visible_page(back);
- SPACE (edge) — тумблер: off = однобуфер (draw==visible==0) для отладки.

Мерцание при подъёме подтверждено устранённым в MAME (пользователь).
План: applications/PoP/docs/double_buffer_plan.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 16:07:03 +03:00
parent fce3e58830
commit 023b45eb85
3 changed files with 129 additions and 21 deletions
+15 -8
View File
@@ -163,9 +163,14 @@ void kid_tick(void)
#define KID_XOFF 0
#define KID_YOFF 0
static int kid_lx, kid_ly;
static uint16_t kid_lw, kid_lh;
static uint8_t kid_lvalid;
/* Прямоугольник последней отрисовки Kid — ПО СТРАНИЦЕ (0/1). У каждой
* графической страницы своя ОЗУ-копия/видео-ОЗУ, поэтому heal должен
* стирать пиксели Kid именно той страницы, в которую сейчас рисуем
* (при дабл-буфере страница чередуется — прошлый Kid на этой странице
* был 2 логических кадра назад). В однобуфере используется только [0]. */
static int kid_lx[2], kid_ly[2];
static uint16_t kid_lw[2], kid_lh[2];
static uint8_t kid_lvalid[2];
/* Метрики последнего kid_draw для футпринта fore-over-Kid (pop_bg):
* obj_x — ЛОГИЧЕСКАЯ X кадра (ДО ×8/7), obj_y — низ, w/h — размер. */
@@ -179,9 +184,10 @@ uint16_t kid_fp_height(void) { return kid_fp_h; }
/* Восстановить фон из теневой копии на месте ПРЕДЫДУЩЕГО кадра Kid. */
void kid_heal(void)
{
if (kid_lvalid)
gfx_heal(kid_lx, kid_ly, kid_lw, kid_lh);
kid_lvalid = 0;
uint8_t p = gfx_get_draw_page();
if (kid_lvalid[p])
gfx_heal(kid_lx[p], kid_ly[p], kid_lw[p], kid_lh[p]);
kid_lvalid[p] = 0;
}
void kid_draw(void)
@@ -221,11 +227,12 @@ void kid_draw(void)
if (flip)
bx -= (int)w; /* seg008: xpos -= image->w */
top = obj_y - (int)h + 1 + KID_YOFF;
uint8_t dp = gfx_get_draw_page(); /* в какую страницу рисуем */
gfx_set_bank(GFX_BANK_SPRITE); /* видео-ОЗУ, без теневой копии */
gfx_blit_cols(bx, top, img, flip);
gfx_set_bank(GFX_BANK_NORMAL);
kid_lx = bx; kid_ly = top;
kid_lw = w; kid_lh = h; kid_lvalid = 1;
kid_lx[dp] = bx; kid_ly[dp] = top;
kid_lw[dp] = w; kid_lh[dp] = h; kid_lvalid[dp] = 1;
kid_fp_w = w; kid_fp_h = h; /* размер кадра для футпринта fore */
}
gfx_w0_unmap();