Keep native redraw VRAM journals bounded with an exact spill backup

This commit is contained in:
Matthew Stanley
2026-10-07 00:47:24 -07:00
parent bebf2d08dc
commit b8cf0aa8b6
2 changed files with 22 additions and 6 deletions
+12 -2
View File
@@ -279,8 +279,18 @@ int render_pass_vram_policy(const RenderPassJournal *j, int px, int py,
if (*x >= j->x[i] && *y >= j->y[i] && *x + *w <= j->x[i] + j->w[i] &&
*y + *h <= j->y[i] + j->h[i])
return RENDER_PASS_VRAM_ALLOW; /* already covered */
return j->n < RENDER_PASS_JOURNAL_MAX ? RENDER_PASS_VRAM_JOURNAL
: RENDER_PASS_VRAM_REFUSE;
if (j->n >= RENDER_PASS_JOURNAL_MAX) return RENDER_PASS_VRAM_REFUSE;
/* Reserve the last entry for a whole-VRAM spill. A sprite scene can
* upload more than 64 disjoint animation/CLUT rectangles in one redraw.
* Back up the current contents once, including earlier temporary writes;
* reverse-order rollback restores this spill FIRST and then restores
* those earlier rectangles to their original contents. Subsequent writes
* are covered by the spill, so capacity remains bounded without dropping
* legitimate texture uploads or disabling native interpolation. */
if (j->n == RENDER_PASS_JOURNAL_MAX - 1) {
*x = *y = 0; *w = vram_w; *h = vram_h;
}
return RENDER_PASS_VRAM_JOURNAL;
}
int render_pass_journal_add(RenderPassJournal *j, const uint16_t *vram,
+10 -4
View File
@@ -17,8 +17,8 @@
* 3. VRAM journal (render_pass_vram_policy / _journal_add / _rollback, the
* CPU side of gpu_gl_renderer.c's out-of-rect journal): writes inside the
* pass rect are allowed, writes outside are backed up first and rolled
* back exactly, covered writes are not journaled twice, a full journal or
* a renderer mode that cannot journal refuses.
* back exactly, covered writes are not journaled twice, the last slot spills
* to a whole-VRAM backup, and a mode that cannot journal refuses.
*
* The GPU, presenter and remaining devices are mocks. Build/run:
* ctest -R render_pass_sandbox_test */
@@ -648,10 +648,16 @@ static void test_journal(void) {
int k = j.n;
CHECK(POLICY(400 + 8 * k, 100, 4, 4, 1) == RENDER_PASS_VRAM_JOURNAL, "fill journal");
render_pass_journal_add(&j, s_vram, VW, x, y, w, h);
paint(x, y, w, h, (uint16_t)(0x8000 + k));
/* Policy can enlarge the BACKUP, never the actual GPU write. */
paint(400 + 8 * k, 100, 4, 4, (uint16_t)(0x8000 + k));
}
CHECK(j.n == RENDER_PASS_JOURNAL_MAX && n == 5, "journal full");
CHECK(POLICY(900, 400, 4, 4, 1) == RENDER_PASS_VRAM_REFUSE, "full journal refuses");
CHECK(j.x[j.n-1] == 0 && j.y[j.n-1] == 0 &&
j.w[j.n-1] == VW && j.h[j.n-1] == VH, "last slot protects all VRAM");
CHECK(POLICY(900, 400, 4, 4, 1) == RENDER_PASS_VRAM_ALLOW, "spill covers later writes");
paint(900, 400, 4, 4, 0x9999);
CHECK(POLICY(650, 4, 16, 16, 1) == RENDER_PASS_VRAM_ALLOW, "spill permits overlapping rewrites");
paint(650, 4, 16, 16, 0xAAAA);
CHECK(render_pass_journal_add(&j, s_vram, VW, 900, 400, 4, 4) == -1,
"add refuses past the limit");