mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Reuse desktop GL storage across dynamic-resolution steps
This commit is contained in:
@@ -213,6 +213,8 @@ on a fixed region -> next.
|
||||
|
||||
## 5. Status / Log (update every session)
|
||||
|
||||
- **2026-10-21 (BRIEF-4 storage reuse):** Desktop GL retains ceiling storage and rescales in place, preserving cleared depth/stencil and unwritten wide regions. Apple keeps level-sized allocations by default. Windows old/new output controls and forced-reuse Mac fixtures pass. With corrected presenter accounting, R4 60s fullscreen quiet/loaded runs have zero completion gaps >25ms, p99 busy 44.6/48.8%, 17x..18x scales. R4 final pin/default checks remain in progress.
|
||||
|
||||
- **2026-10-21 (BRIEF-4 presenter accounting):** Publish composer swap/slot wait separately and exclude that pacing from dynamic-resolution work backpressure. Windows and Mac real-context checks pass. Quiet fullscreen route: 60.020 Hz, four completion gaps >25ms, p99 busy 48.0%; allocation stalls remain. Raw completion and queue-wait metrics are unchanged.
|
||||
|
||||
- **2026-10-21 (BRIEF-4 GPU timing):** Split TIME_ELAPSED brackets around command starvation and presentation waits. Real-context 30ms producer-idle control reports 35.141ms with the old bracket / 5.620ms active GPU work; Windows and Mac GL fixtures and render-thread unit checks pass. Completion stalls remain; dynamic-resolution reallocations are the next target. No guest or completion-clock changes.
|
||||
|
||||
@@ -10809,6 +10809,49 @@ static void dyn_stats_lock(void) { while (atomic_flag_test_and_set_explicit(&s_d
|
||||
static void dyn_stats_unlock(void) { atomic_flag_clear_explicit(&s_dyn_stats_lock, memory_order_release); }
|
||||
static int s_rthm_scale = 1; /* emulation-side level (recording) */
|
||||
|
||||
/* Desktop immediate-mode GL can reuse the ceiling allocation. On Apple's
|
||||
* GL-on-Metal, attachment load/store bandwidth scales with allocation size,
|
||||
* so keep allocating at the active level there. The control retains the old
|
||||
* allocation path for exact image comparisons on either backend. */
|
||||
static int dyn_reuse_storage(void) {
|
||||
static int enabled = -1;
|
||||
if (enabled < 0) {
|
||||
const char *e = getenv("PSX_GL_DYNRES_REUSE_STORAGE");
|
||||
#ifdef __APPLE__
|
||||
enabled = e && e[0] == '1';
|
||||
#else
|
||||
enabled = !(e && e[0] == '0');
|
||||
#endif
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
static void dyn_clear_wide_rest(GLuint fbo, const int (*cols)[2], int ncols,
|
||||
int y0, int y1, int scale) {
|
||||
p_glBindFramebuffer(PSXGL_FRAMEBUFFER, fbo);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
if (y0 > 0) {
|
||||
glScissor(0, 0, g_wide_w * scale, y0 * scale); glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
if (y1 < VRAM_H) {
|
||||
glScissor(0, y1 * scale, g_wide_w * scale, (VRAM_H - y1) * scale);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
int x = 0;
|
||||
for (int c = 0; c <= ncols; ++c) {
|
||||
int end = c < ncols ? cols[c][0] : g_wide_w;
|
||||
if (end > x) {
|
||||
glScissor(x * scale, y0 * scale, (end - x) * scale, (y1 - y0) * scale);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
if (c < ncols) x = cols[c][1];
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glStencilMask(0xFF); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT);
|
||||
p_glBindFramebuffer(PSXGL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
static int dyn_apply(int snew) {
|
||||
/* Never in the windowed high-resolution mode (s_hiw): dyn_eligible keeps
|
||||
* s_alloc_scale 0 there; refuse here too rather than step its tiles. */
|
||||
@@ -10904,7 +10947,14 @@ static int dyn_apply(int snew) {
|
||||
* step down reseeds the old surface's corner in place; a step up past
|
||||
* the old allocation is refused. */
|
||||
GLuint ntex = 0, nrb = 0, nfbo = 0;
|
||||
if (!hr_alloc_surface(snew, &ntex, &nrb, &nfbo)) {
|
||||
if (dyn_reuse_storage() && snew <= s_hr_alloc) {
|
||||
p_glBindFramebuffer(PSXGL_FRAMEBUFFER, s_hr_fbo);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_TRUE); glClearDepth(1.0);
|
||||
glStencilMask(0xFF); glClearStencil(0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
p_glBindFramebuffer(PSXGL_FRAMEBUFFER, 0);
|
||||
} else if (!hr_alloc_surface(snew, &ntex, &nrb, &nfbo)) {
|
||||
if (snew > s_hr_alloc) {
|
||||
s_dyn_stats.refused++;
|
||||
fprintf(stdout, "psxrecomp: dynamic resolution %dx -> %dx refused (the "
|
||||
@@ -10960,7 +11010,11 @@ static int dyn_apply(int snew) {
|
||||
* before and the surface keeps its larger allocation; a step up
|
||||
* past it drops the surface (recreated at the next target). */
|
||||
GLuint ntex = 0, nrb = 0, nfbo = 0;
|
||||
if (wide_alloc_surface(snew, &ntex, &nrb, &nfbo)) {
|
||||
if (dyn_reuse_storage() && snew <= s_wide_as[i]) {
|
||||
dyn_rescale_in_place(s_wide_fbo[i], g_wide_w, (const int (*)[2])cols, nc,
|
||||
y0, y1, sold, snew);
|
||||
dyn_clear_wide_rest(s_wide_fbo[i], (const int (*)[2])cols, nc, y0, y1, snew);
|
||||
} else if (wide_alloc_surface(snew, &ntex, &nrb, &nfbo)) {
|
||||
for (int c = 0; c < nc; c++)
|
||||
if (cols[c][1] > cols[c][0])
|
||||
dyn_rescale_rect(s_wide_tex[i], cols[c][0] * sold, y0 * sold, sold,
|
||||
@@ -10993,7 +11047,7 @@ static int dyn_apply(int snew) {
|
||||
int hw = VRAM_W * snew, hh = VRAM_H * snew;
|
||||
int sw = snew <= 2 ? hw : (hw < GL_SCRATCH_TILE ? hw : GL_SCRATCH_TILE);
|
||||
int sh = snew <= 2 ? hh : (hh < GL_SCRATCH_TILE ? hh : GL_SCRATCH_TILE);
|
||||
if (s_scratch_w > sw || s_scratch_h > sh) {
|
||||
if (!dyn_reuse_storage() && (s_scratch_w > sw || s_scratch_h > sh)) {
|
||||
p_glActiveTexture(PSXGL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, s_scratch_tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sw, sh, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
@@ -341,6 +341,11 @@ int main(int argc, char **argv) {
|
||||
gl_renderer_dynres_stats(&ds);
|
||||
printf("dyn_steps=%llu asked=%d\n", (unsigned long long)ds.steps, nsteps);
|
||||
check(ds.steps == (uint64_t)nsteps && ds.level == scale, "every step applied");
|
||||
printf("dyn_allocs hr=%llu wide=%llu\n", (unsigned long long)ds.hr_reallocs,
|
||||
(unsigned long long)ds.wide_reallocs);
|
||||
if (dyn_reuse_storage())
|
||||
check(ds.hr_reallocs == 0 && ds.wide_reallocs == 0,
|
||||
"ceiling storage reused at every level");
|
||||
if (threaded) {
|
||||
GlRthCosts co;
|
||||
gl_renderer_render_thread_costs(&co);
|
||||
|
||||
Reference in New Issue
Block a user