GL: queue the native-wide mirror with the high-resolution window's draws

With lines batched, 8K widescreen still switched to the wide surface and
back for every textured or flat batch that reaches the margins (~29 per
frame at 21:9 in an R4 race; 32:9 flushes ~4x as many textured batches).
At 18x those surfaces are 10080x9216 and 15372x9216, and each switch ends a
render pass: with the mirror drawn into the hr surface instead (no switch,
gl_ws_ablate 3) 32:9 at 8K ran at 57 guest frames/s instead of 12.

In windowed mode a draw's native-wide mirror now rides in its window queue
entry (target surface, x shift, backdrop stretch) and is replayed in the
queue's flush, in order, one pass per wide surface (hiw_replay_wide). The
queue's sync points already cover what the mirror samples (the raw mirror)
and the stencil rebuild; every other write to a wide surface (the clears,
the full-screen overlay rect, reallocation) and every read of one
(present, capture, dumps) now flushes the queue first. Outside windowed
mode, and with the mirror ablated, the immediate mirror runs as before.

- gl_scale_invariance_test: the window runs' native-wide surfaces (the
  scene's and the new lines runs') stay byte-identical to the full-VRAM
  runs, and the lines runs check that the mirrors were queued. Mutations
  fail it: no queueing (the queue check), a wrong x shift or no replay
  (the wide digests).
- R4, same setup as the previous commit: 21:9 at 8K 34.2-37.7 -> 56.1-56.6
  guest frames/s (4:3 at 8K: 59.4), 32:9 12.6-13.8 -> 45.1-45.9; mirror
  passes per frame 29 -> 0.5. With the debug server's per-frame readback on
  (the default debug build): 21:9 43.7, 32:9 40.0.
- test_gl_internal_scale_guards pins the queued path, the replay state and
  the sync points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Shokunin
2026-09-28 16:56:15 -07:00
parent 624fadc14f
commit 9805a00a7e
3 changed files with 208 additions and 30 deletions
+153 -27
View File
@@ -2303,17 +2303,16 @@ static int mirror_geo_center_only(const int *xs, int n) {
}
/* mirror_batch_center_only (textured-batch variant) is defined after s_tb below. */
/* Set / clear the 2D-backdrop x-stretch for a wide-mirror draw, per the current
* gate (s_bd_gate, set by the caller from bd_prim_gate / the batch gate). */
static void wide_set_bd_scale(GLint uScale, GLint uCenter) {
/* The 2D-backdrop x-stretch for a wide-mirror draw under gate `gate`. */
static void wide_bd_scale(int gate, float *out_scale, float *out_center) {
extern int g_ws_tex_edge_pct;
float scale = 1.0f, center = 0.0f;
if (s_bd_gate && g_ws_bd_stretch_on && g_wide_w > 0) {
if (gate && g_ws_bd_stretch_on && g_wide_w > 0) {
int native_w = g_wide_w - 2 * g_wide_off;
if (native_w > 0) {
scale = g_ws_bd_stretch_pct > 0 ? (float)g_ws_bd_stretch_pct / 100.0f
: (float)g_wide_w / (float)native_w;
if (s_bd_gate == 2) {
if (gate == 2) {
scale = g_ws_tex_edge_pct > 0
? (float)g_ws_tex_edge_pct / 100.0f : scale;
scale = -scale; /* shader: expand only beyond canonical edges */
@@ -2322,6 +2321,15 @@ static void wide_set_bd_scale(GLint uScale, GLint uCenter) {
}
}
if (scale != 1.0f) s_bdg_applied++;
*out_scale = scale;
*out_center = center;
}
/* Set / clear the 2D-backdrop x-stretch for a wide-mirror draw, per the current
* gate (s_bd_gate, set by the caller from bd_prim_gate / the batch gate). */
static void wide_set_bd_scale(GLint uScale, GLint uCenter) {
float scale, center;
wide_bd_scale(s_bd_gate, &scale, &center);
p_glUniform1f(uScale, scale);
p_glUniform1f(uCenter, center);
}
@@ -2464,7 +2472,15 @@ static int mirror_batch_center_only(int nverts) {
* uploads, the depth24 clear), any other write to the window (fill, copy,
* upload, stencil rebuild), and every read of it (present, capture, growth).
* Order within the window is preserved; its content equals an immediate
* mirror at every point it is observed. */
* mirror at every point it is observed.
* The native-wide mirror of the same draws switched to the wide surface and
* back per batch as well; at 8K that surface is up to 15372x9216 and the
* switches held a 21:9 race to ~30 frames/s. In windowed mode a draw's wide
* mirror rides in its queue entry (wfbo: target surface, wdx: its x shift,
* wscale/wcenter: its backdrop stretch) and is replayed in the same flush,
* one pass per wide surface. Every other write to a wide surface (clears,
* the full-screen overlay rect, reallocation) and every read of one
* (present, capture, dumps) flushes the queue first. */
enum { HQ_TEX = 1, HQ_GEO = 2 };
typedef struct {
uint8_t kind;
@@ -2477,6 +2493,9 @@ typedef struct {
int ax0, ay0, ax1, ay1; /* draw area, inclusive */
size_t vfirst; /* float offset into s_hq_v */
int vcount; /* vertices */
GLuint wfbo; /* native-wide mirror target, 0: none */
int wdx; /* its x shift (wide_dx()) */
float wscale, wcenter; /* its backdrop stretch (wide_bd_scale) */
} HiCmd;
static HiCmd *s_hq = NULL;
static int s_hq_n = 0, s_hq_cap = 0;
@@ -2520,23 +2539,118 @@ static int hiw_area_touches(void) {
return 0;
}
static void hiw_enqueue_tex(int nverts, int semi) {
if (!hiw_area_touches()) return;
/* A draw's native-wide mirror goes in its queue entry when the window's
* queue is live and the mirror is not being ablated (a perf probe). */
static int hiw_wide_queue_ok(int mirror) {
return mirror && g_wide_cur && s_ws_ablate == 0;
}
static void hiw_wide_set(HiCmd *c, int gate) {
c->wfbo = g_wide_cur;
c->wdx = wide_dx();
wide_bd_scale(gate, &c->wscale, &c->wcenter);
}
/* Queue a textured batch for the window, and its native-wide mirror when
* `mirror` (gate: its backdrop-stretch gate). Returns 1 when the mirror was
* queued (the caller then skips its immediate mirror). */
static int hiw_enqueue_tex(int nverts, int semi, int mirror, int gate) {
int wq = hiw_wide_queue_ok(mirror);
if (!wq && !hiw_area_touches()) return 0;
HiCmd *c = hiw_enqueue(HQ_TEX, s_tb, nverts, TEXV);
if (!c) { hiw_flush_queue(); return; }
if (!c) { hiw_flush_queue(); return 0; }
c->semi = (int8_t)semi;
c->mask = (uint8_t)s_tb_mask;
c->filter = (uint8_t)s_tb_filter;
c->tex = s_tb_bank_tex ? s_tb_bank_tex : s_raw_tex;
memcpy(c->twin, s_tb_twin, sizeof c->twin);
if (wq) hiw_wide_set(c, gate);
return wq;
}
static void hiw_enqueue_geo(const float *verts, int nverts, int semi, int mask) {
if (!hiw_area_touches()) return;
static int hiw_enqueue_geo(const float *verts, int nverts, int semi, int mask,
int mirror, int gate) {
int wq = hiw_wide_queue_ok(mirror);
if (!wq && !hiw_area_touches()) return 0;
HiCmd *c = hiw_enqueue(HQ_GEO, verts, nverts, 6);
if (!c) { hiw_flush_queue(); return; }
if (!c) { hiw_flush_queue(); return 0; }
c->semi = (int8_t)semi;
c->mask = (uint8_t)(mask ? 1 : 0);
if (wq) hiw_wide_set(c, gate);
return wq;
}
/* Replay the queued native-wide mirrors, in order, into their wide surfaces:
* the state wide_target_begin sets (full-width scissor, the draw area's rows,
* the S sample-grid shift) plus each entry's shift and backdrop stretch. */
static void hiw_replay_wide(void) {
int S = s_out_scale, any = 0, cur = 0;
GLuint bound = 0;
for (int i = 0; i < s_hq_n; i++) {
const HiCmd *c = &s_hq[i];
if (!c->wfbo) continue;
if (!any) { gl_perf_mirror_begin(); any = 1; }
if (c->wfbo != bound) {
p_glBindFramebuffer(PSXGL_FRAMEBUFFER, c->wfbo);
glViewport(0, 0, g_wide_w * S, VRAM_H * S);
glEnable(GL_SCISSOR_TEST);
p_glUseProgram(s_geo_prog);
p_glUniform1f(s_geo_uShift, s_shift_hi);
p_glUniform1f(s_geo_uXhalf, (float)g_wide_w / 2.0f);
p_glUseProgram(s_tex_prog);
p_glUniform1f(s_tex_uShift, s_shift_hi);
p_glUniform1f(s_tex_uXhalf, (float)g_wide_w / 2.0f);
p_glUniform1i(s_uVram, 0);
p_glActiveTexture(PSXGL_TEXTURE0);
bound = c->wfbo;
cur = 0;
}
int sy = c->ay0, sh = c->ay1 - c->ay0 + 1;
if (sy < 0) { sh += sy; sy = 0; }
if (sy + sh > VRAM_H) sh = VRAM_H - sy;
if (sh < 0) sh = 0;
glScissor(0, sy * S, g_wide_w * S, sh * S);
if (c->kind == HQ_TEX) {
if (cur != HQ_TEX) {
p_glUseProgram(s_tex_prog);
p_glBindVertexArray(s_tex_vao);
p_glBindBuffer(PSXGL_ARRAY_BUFFER, s_tex_vbo);
cur = HQ_TEX;
}
p_glUniform1f(s_tex_uXoff, (float)c->wdx);
p_glUniform1f(s_tex_uXscale, c->wscale);
p_glUniform1f(s_tex_uXcenter, c->wcenter);
glBindTexture(GL_TEXTURE_2D, c->tex);
p_glUniform4i(s_uTwin, c->twin[0], c->twin[1], c->twin[2], c->twin[3]);
p_glUniform1i(s_uMaskset, c->mask);
p_glUniform1i(s_uFilter, c->filter);
p_glBufferData(PSXGL_ARRAY_BUFFER, (ptrdiff_t)((size_t)c->vcount * TEXV * sizeof(float)),
s_hq_v + c->vfirst, PSXGL_STREAM_DRAW);
tex_draw_passes_ex(c->vcount, c->semi, c->mask, c->check, 0);
} else {
if (cur != HQ_GEO) {
p_glUseProgram(s_geo_prog);
p_glBindVertexArray(s_geo_vao);
p_glBindBuffer(PSXGL_ARRAY_BUFFER, s_geo_vbo);
cur = HQ_GEO;
}
p_glUniform1f(s_geo_uXoff, (float)c->wdx);
p_glUniform1f(s_geo_uXscale, c->wscale);
p_glUniform1f(s_geo_uXcenter, c->wcenter);
if (c->semi >= 0) apply_psx_blend(c->semi); else glDisable(GL_BLEND);
mask_stencil_ex(c->mask, c->check);
p_glBufferData(PSXGL_ARRAY_BUFFER, (ptrdiff_t)((size_t)c->vcount * 6 * sizeof(float)),
s_hq_v + c->vfirst, PSXGL_STREAM_DRAW);
glDrawArrays(GL_TRIANGLES, 0, c->vcount);
}
}
if (!any) return;
p_glUseProgram(s_geo_prog);
p_glUniform1f(s_geo_uXscale, 1.0f);
p_glUniform1f(s_geo_uXcenter, 0.0f);
p_glUseProgram(s_tex_prog);
p_glUniform1f(s_tex_uXscale, 1.0f);
p_glUniform1f(s_tex_uXcenter, 0.0f);
gl_perf_mirror_end();
}
/* Replay the queued draws into every tile they touch: the window projection
@@ -2556,7 +2670,7 @@ static void hiw_flush_queue(void) {
int cx1 = c->ax1 + 1 < T->x1 ? c->ax1 + 1 : T->x1;
int cy0 = c->ay0 < 0 ? 0 : c->ay0;
int cy1 = c->ay1 + 1 > VRAM_H ? VRAM_H : c->ay1 + 1;
if (cx1 <= cx0 || cy1 <= cy0) continue;
if (cx1 <= cx0 || cy1 <= cy0) continue; /* (a wide-only entry) */
if (!bound) {
p_glBindFramebuffer(PSXGL_FRAMEBUFFER, T->fbo);
glViewport(0, 0, ww * S, VRAM_H * S);
@@ -2604,6 +2718,7 @@ static void hiw_flush_queue(void) {
}
}
}
hiw_replay_wide();
/* Canonical projection back on both programs. */
p_glUseProgram(s_geo_prog);
p_glUniform1f(s_geo_uShift, s_shift_hr);
@@ -2639,17 +2754,18 @@ static void flush_tex_batch(void) {
tex_batch_draw_passes(nverts, semi);
/* Windowed high-resolution surface: the same batch at S, queued and
* replayed in one render pass at the next sync point (see s_hq). No-op
* unless that mode is engaged. */
if (hiw_on()) hiw_enqueue_tex(nverts, semi);
/* Native-wide mirror — skipped for a batch fully inside the 4:3 frame (its
* centre content comes from the present-time canonical blit; nothing to add
* to the margins). A backdrop-stretched batch (s_tb_gate) widens past the
* frame, so it is never treated as centre-only. */
if (g_wide_cur && s_ws_ablate != 1 &&
!(s_tb_gate == 0 && mirror_batch_center_only(nverts))) { /* native-wide mirror */
int mirror = g_wide_cur && s_ws_ablate != 1 &&
!(s_tb_gate == 0 && mirror_batch_center_only(nverts));
/* Windowed high-resolution surface: the same batch at S, queued and
* replayed in one render pass at the next sync point (see s_hq), with its
* native-wide mirror. No-op unless that mode is engaged. */
if (hiw_on() && hiw_enqueue_tex(nverts, semi, mirror, s_tb_gate)) mirror = 0;
if (mirror) { /* native-wide mirror */
int dx = wide_dx();
s_bd_gate = s_tb_gate; /* this batch is uniform-gate (flushed on change) */
gl_perf_mirror_begin();
@@ -2732,10 +2848,11 @@ static void flush_flat_batch(void) {
s_fb, PSXGL_STREAM_DRAW);
if (nl) flat_batch_draw_hr_lines(nverts, nl);
else glDrawArrays(GL_TRIANGLES, 0, nverts);
if (hiw_on()) hiw_enqueue_geo(s_fb, nverts, semi, mask);
int mirror = g_wide_cur && !s_wide_suppress && s_ws_ablate != 1 &&
!(!g_ws_bd_stretch_on && mirror_flat_batch_center_only(nverts));
if (hiw_on() && hiw_enqueue_geo(s_fb, nverts, semi, mask, mirror, 0)) mirror = 0;
if (g_wide_cur && !s_wide_suppress && s_ws_ablate != 1 &&
!(!g_ws_bd_stretch_on && mirror_flat_batch_center_only(nverts))) {
if (mirror) {
int dx = wide_dx();
/* Batch may span many prims; use stretch gate off (flat dots/UI). */
s_bd_gate = 0;
@@ -2880,11 +2997,13 @@ static void gpu_geometry(GLenum mode, const int *xs, const int *ys,
quad, PSXGL_STREAM_DRAW);
draw_mode = GL_TRIANGLES; draw_n = 6;
}
if (hiw_on())
int mirror = g_wide_cur && !s_wide_suppress && s_ws_ablate != 1 &&
!(!g_ws_bd_stretch_on && mirror_geo_center_only(xs, n));
if (hiw_on() &&
hiw_enqueue_geo(draw_mode == GL_TRIANGLES && is_line ? quad : verts,
draw_n, semi, s_mask_set);
if (g_wide_cur && !s_wide_suppress && s_ws_ablate != 1 &&
!(!g_ws_bd_stretch_on && mirror_geo_center_only(xs, n))) {
draw_n, semi, s_mask_set, mirror, bd_prim_gate(xs, n, 0)))
mirror = 0;
if (mirror) {
int dx = wide_dx();
s_bd_gate = bd_prim_gate(xs, n, 0);
gl_perf_mirror_begin();
@@ -3109,6 +3228,7 @@ static void gpu_flat_rect(int x,int y,int w,int h,uint16_t c,int semi) {
* for the full-width wide pass so blend/scissor/program state is
* clean. */
if (s_ws_ablate != 1) {
hiw_flush_queue(); /* windowed: queued wide mirrors land first */
hr_begin(0);
gl_perf_mirror_begin();
wide_flat_rect_direct(0, y, g_wide_w, h, c, semi);
@@ -4676,6 +4796,7 @@ static void glb_wide_configure(int wide_w, int offset) {
if (!s_raster_ok) return;
double t0 = cw_ms(); s_cw_wide_cfgs++;
flush_tex_batch(); /* a queued batch's wide mirror targets the CURRENT surfaces */
hiw_flush_queue(); /* ...and so does a windowed-mode queued one */
if (wide_w <= 0) { wide_free_all(); g_wide_w = 0; g_wide_off = 0; s_cw_wide_ms += cw_ms() - t0; return; }
if (wide_w != g_wide_w) { wide_free_all(); s_wide_refused_logged = 0; }
g_wide_w = wide_w;
@@ -4704,6 +4825,7 @@ static void glb_wide_clear(int base_x, int y, int h, uint16_t color) {
if (!s_raster_ok || s_ws_ablate == 1) return;
double t0 = cw_ms(); s_cw_wide_clears++;
flush_tex_batch();
hiw_flush_queue(); /* queued wide mirrors land before the clear */
GLuint fbo = wide_fbo_for(base_x);
if (!fbo) { s_cw_wide_ms += cw_ms() - t0; return; }
gl_perf_mirror_begin();
@@ -4737,6 +4859,7 @@ static void glb_wide_clear_margins(int base_x, int y, int h, uint16_t color, int
double t0 = cw_ms(); s_cw_wide_clears++;
flush_flat_batch();
flush_tex_batch();
hiw_flush_queue(); /* queued wide mirrors land before the clear */
GLuint fbo = wide_fbo_for(base_x);
if (!fbo) { s_cw_wide_ms += cw_ms() - t0; return; }
gl_perf_mirror_begin();
@@ -4801,6 +4924,7 @@ static int glb_render_wide_display(uint32_t *out, int pitch, int base_x,
* make sure all wide-FBO draws have completed before the readback. */
flush_tex_batch();
flush_cpu_upload();
hiw_flush_queue(); /* windowed: queued wide mirrors */
wide_blit_center(fbo, base_x, disp_y, disp_h); /* fast-path: authoritative centre before readback */
glFinish();
@@ -4851,6 +4975,7 @@ static int glb_wide_dump_full(uint32_t *out, int cap_pixels, int *ow, int *oh,
if (!fbo) return 0;
flush_tex_batch();
flush_cpu_upload();
hiw_flush_queue(); /* windowed: queued wide mirrors */
wide_blit_center(fbo, base_x, 0, VRAM_H); /* authoritative centre (full height) */
glFinish();
int W = g_wide_w * s_out_scale;
@@ -5807,6 +5932,7 @@ int gl_renderer_present_wide_fbo(int disp_x, int disp_y, int disp_h, int linear)
flush_flat_batch();
flush_tex_batch();
flush_cpu_upload();
hiw_flush_queue(); /* windowed: queued wide mirrors */
if (s_force_present_remaining <= 0 &&
s_last_present_path == GL_PRES_WIDE &&
s_last_dx == disp_x && s_last_dy == disp_y &&
+45 -2
View File
@@ -102,7 +102,7 @@ class GlScaleGuards(unittest.TestCase):
self.assertIn("(nverts + 2 * nl) * 6 * sizeof(float)", flush)
self.assertRegex(flush, r"if \(nl\) flat_batch_draw_hr_lines\(nverts, nl\);\n"
r"\s*else glDrawArrays\((GL_TRIANGLES|fmode), 0, nverts\);")
self.assertIn("hiw_enqueue_geo(s_fb, nverts, semi, mask);", flush)
self.assertIn("hiw_enqueue_geo(s_fb, nverts, semi, mask, mirror, 0)", flush)
wide = flush[flush.index("wide_target_begin("):]
self.assertRegex(wide, r"glDrawArrays\((GL_TRIANGLES|fmode), 0, nverts\);")
hr = body(GL, "static void flat_batch_draw_hr_lines(int nverts, int nl)")
@@ -133,7 +133,50 @@ class HiresWindowGuards(unittest.TestCase):
# an immediate write into the window lands after every queued draw
self.assertIn("hiw_flush_queue();", body(GL, fn))
for site in ("flush_tex_batch(void)", "flush_flat_batch(void)"):
self.assertIn("if (hiw_on()) hiw_enqueue_", body(GL, "static void " + site))
self.assertIn("if (hiw_on() && hiw_enqueue_", body(GL, "static void " + site))
def test_wide_mirror_queued_in_windowed_mode(self):
# Windowed mode: a draw's native-wide mirror rides in its window queue
# entry and is replayed in the queue's flush (one pass per wide
# surface), not as a surface switch per batch. The immediate mirror
# runs only when the entry did not take it.
for site, call in (("static void flush_tex_batch(void)",
"if (hiw_on() && hiw_enqueue_tex(nverts, semi, mirror, s_tb_gate)) mirror = 0;"),
("static void flush_flat_batch(void)",
"if (hiw_on() && hiw_enqueue_geo(s_fb, nverts, semi, mask, mirror, 0)) mirror = 0;"),
("static void gpu_geometry(", "mirror = 0;")):
fn = body(GL, site)
self.assertIn(call, fn, site)
self.assertLess(fn.index(call), fn.index("if (mirror) {"), site)
self.assertIn("wide_target_begin(", fn[fn.index("if (mirror) {"):], site)
ok = body(GL, "static int hiw_wide_queue_ok(int mirror)")
self.assertIn("return mirror && g_wide_cur && s_ws_ablate == 0;", ok)
for fn in ("static int hiw_enqueue_tex(", "static int hiw_enqueue_geo("):
b = body(GL, fn)
self.assertIn("if (!wq && !hiw_area_touches()) return 0;", b)
self.assertIn("if (wq) hiw_wide_set(c, gate);", b)
flush = body(GL, "static void hiw_flush_queue(void)")
self.assertIn("hiw_replay_wide();", flush)
self.assertLess(flush.index("hiw_replay_wide();"), flush.index("hr_end();"))
replay = body(GL, "static void hiw_replay_wide(void)")
for need in ("if (!c->wfbo) continue;", "p_glBindFramebuffer(PSXGL_FRAMEBUFFER, c->wfbo);",
"glViewport(0, 0, g_wide_w * S, VRAM_H * S);",
"glScissor(0, sy * S, g_wide_w * S, sh * S);",
"p_glUniform1f(s_tex_uXoff, (float)c->wdx);",
"p_glUniform1f(s_geo_uXoff, (float)c->wdx);",
"tex_draw_passes_ex(c->vcount, c->semi, c->mask, c->check, 0);",
"mask_stencil_ex(c->mask, c->check);"):
self.assertIn(need, replay)
# Every other write to a wide surface, and every read of one, lands
# after the queued mirrors.
overlay = body(GL, "static void gpu_flat_rect(")
self.assertLess(overlay.index("hiw_flush_queue();"),
overlay.index("wide_flat_rect_direct(0, y, g_wide_w, h, c, semi);"))
for fn in ("static void glb_wide_configure(",
"static void glb_wide_clear(", "static void glb_wide_clear_margins(",
"static int glb_render_wide_display(", "static int glb_wide_dump_full(",
"int gl_renderer_present_wide_fbo(", "static void rebuild_mask_stencils(void)"):
self.assertIn("hiw_flush_queue();", body(GL, fn), fn)
def test_queue_syncs_before_the_raw_mirror_changes(self):
# Queued window draws sample the raw mirror; it must not change under them.
+10 -1
View File
@@ -28,7 +28,8 @@
* - mode "lines" (with or without the window): lines interleaved with
* triangles that overlap them, over native-wide. Above 1x they share one
* flat batch (checked); in windowed mode each batched line also keeps its
* GL_LINES vertices for the 1x authoritative surface. The runner checks
* GL_LINES vertices for the 1x authoritative surface, and the batches'
* native-wide mirrors wait in the window's queue (checked). The runner checks
* the window runs' native frame (lband) against the 1x run's, so the 1x
* surface draws exactly what 1x draws, in painter order, and their frame
* and wide surface at S against the full-VRAM run at the same scale.
@@ -232,6 +233,14 @@ static int lines_main(int scale, int window) {
glb_draw_flat_triangle(10, 150, 80, 150, 40, 200, 0x5294);
glb_draw_line(5, 160, 90, 190, 0x7fff);
glb_set_draw_area(0, 0, 1023, 511);
{
/* Windowed: the batches' native-wide mirrors wait in the window's
* queue (replayed in one pass per surface at the next sync point). */
int wq = 0;
for (int i = 0; i < s_hq_n; i++) wq += s_hq[i].wfbo != 0;
if (window && wq < 3) fprintf(stderr, "queued wide mirrors=%d\n", wq);
check(window ? wq >= 3 : s_hq_n == 0, "windowed: native-wide mirrors queued");
}
gl_renderer_sync_cpu();
check(gl_renderer_fbo_peek(0, 0, 1024, 512, peek), "native peek");
uint64_t lband = 0xcbf29ce484222325ull; /* the native frame */