mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Test: the window mode refuses render passes
Once the frame-rate stack's render passes land, a pass backs up and restores only s_hr_fbo, at s_hr_scale. In the 8K window mode the presented surfaces are the tiles at s_out_scale, which a pass would not restore, and the queued native-wide replay has no pass clamp, so the backend must refuse passes there (gl_renderer_pass_unavailable: s_hiw returns PSX_MOD_RENDER_PASS_BACKEND). Nothing enforced that but prose. test_gl_internal_scale_guards: where the renderer defines gl_renderer_pass_unavailable, its s_hiw refusal must return PSX_MOD_RENDER_PASS_BACKEND and pass_begin and pass_plan must go through gl_renderer_pass_ready; skipped before render passes exist. The GL fixture gains a passes mode, built only when the renderer has render passes: with the flip-aware blend ready, the full-VRAM surface at 9x offers passes and the window mode at 9x and 18x refuses them and pass_begin opens nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,9 @@ Mask runs (mode mask) change the GP0(E6) mask-check bit after a line, a flat
|
||||
triangle or an opaque textured rect and before its batch is drawn: the draw
|
||||
must keep the check bit it was submitted under, at 1x, above it and in the
|
||||
window mode.
|
||||
Pass runs (mode passes, where the renderer has the frame-rate stack's render
|
||||
passes) check that the window mode refuses them and the full-VRAM surface
|
||||
offers them.
|
||||
|
||||
macOS/Linux: pass the SDL3 include directory and static library (for example
|
||||
from a runtime build tree's _deps/sdl3-src/include and
|
||||
@@ -111,6 +114,11 @@ def main():
|
||||
# drops them (-dead_strip, or per-function sections with --gc-sections).
|
||||
# Anything still unresolved is a link error, not a NULL call at run time.
|
||||
sections = [] if platform.system() == "Darwin" else ["-ffunction-sections", "-fdata-sections"]
|
||||
# Render passes (the frame-rate stack): build the fixture's passes mode.
|
||||
renderer = (framework / "runtime/src/gpu_gl_renderer.c").read_text(encoding="utf-8")
|
||||
passes = "uint32_t gl_renderer_pass_unavailable(void)" in renderer
|
||||
if passes:
|
||||
sections.append("-DPSX_TEST_RENDER_PASSES=1")
|
||||
objs = []
|
||||
for name, src in sources:
|
||||
o = dest / (name + ".o")
|
||||
@@ -247,6 +255,19 @@ def main():
|
||||
r.stderr.strip()[-600:])
|
||||
if r.returncode or not parsed or parsed[1]:
|
||||
ok = False
|
||||
# Render passes: offered on the full-VRAM surface, refused in the window mode.
|
||||
if not passes:
|
||||
print("passes: skipped (this renderer has no render passes)")
|
||||
for label, s, extra in ((("full", 9, {}), ("window", 9, {"PSX_GL_HIRES_WINDOW": "1"}),
|
||||
("window", 18, {"PSX_GL_HIRES_WINDOW": "1"})) if passes else ()):
|
||||
e = dict(env)
|
||||
e.update(extra)
|
||||
r = run([dest / "probe", s, "passes"], env=e)
|
||||
parsed = parse_run(r.stdout)
|
||||
print(f"passes {label} {s}: exit={r.returncode}", r.stdout.strip().splitlines()[-2:],
|
||||
r.stderr.strip()[-600:])
|
||||
if r.returncode or not parsed or parsed[1]:
|
||||
ok = False
|
||||
for label, s, budget in (("over-limit", 32, None), ("budget", 12, "40")):
|
||||
e = dict(env)
|
||||
if budget is not None:
|
||||
|
||||
@@ -275,6 +275,28 @@ class ScaleContractGuards(unittest.TestCase):
|
||||
name + " binds s_hr_fbo at s_out_scale without handling the window")
|
||||
|
||||
|
||||
class RenderPassGuards(unittest.TestCase):
|
||||
"""Render passes (the frame-rate stack) back up and restore only
|
||||
s_hr_fbo, at s_hr_scale. In the window mode the presented surfaces are the
|
||||
tiles at s_out_scale, which a pass would not restore, and the queued wide
|
||||
mirror replay has no pass clamp: the backend must refuse passes there.
|
||||
Skipped where the renderer has no render passes; the GL fixture's passes
|
||||
runs check the same refusal on a real context."""
|
||||
|
||||
def test_window_mode_refuses_passes(self):
|
||||
if "uint32_t gl_renderer_pass_unavailable(void)" not in GL:
|
||||
self.skipTest("no render passes in this tree")
|
||||
refuse = body(GL, "uint32_t gl_renderer_pass_unavailable(void)")
|
||||
self.assertRegex(strip_comments(refuse),
|
||||
r"if \([^;{}]*\bs_hiw\b[^;{}]*\)\s*return PSX_MOD_RENDER_PASS_BACKEND;")
|
||||
# Every way in goes through that refusal.
|
||||
for sig in ("int gl_renderer_pass_begin(", "uint32_t gl_renderer_pass_plan("):
|
||||
if sig in GL:
|
||||
self.assertIn("gl_renderer_pass_ready()", body(GL, sig), sig)
|
||||
self.assertIn("gl_renderer_pass_unavailable() == PSX_MOD_RENDER_PASS_READY",
|
||||
body(GL, "int gl_renderer_pass_ready(void)"))
|
||||
|
||||
|
||||
class InternalResolutionGuards(unittest.TestCase):
|
||||
def test_hidpi_window_only_when_opted_in(self):
|
||||
self.assertIn("win_flags |= PSX_SDL_WINDOW_HIGH_DENSITY;", MAIN)
|
||||
|
||||
@@ -44,6 +44,12 @@
|
||||
* check on (then off) or off (then on) before their batch is drawn: with
|
||||
* the check on the rect's pixels stay, with it off they are overwritten,
|
||||
* in the native VRAM and in the frame at S.
|
||||
* - mode "passes" (built only where the renderer has render passes, the
|
||||
* frame-rate stack; the runner defines PSX_TEST_RENDER_PASSES): with the
|
||||
* flip-aware frame blend ready, the full-VRAM surface offers render passes
|
||||
* and the window mode refuses them (PSX_MOD_RENDER_PASS_BACKEND), and
|
||||
* gl_renderer_pass_begin opens nothing there: a pass backs up and restores
|
||||
* only the authoritative surface, never the window's tiles.
|
||||
* Original source-owned scene; no retail payload. */
|
||||
#include "gpu_gl_renderer.c"
|
||||
#include "mod_texture_banks.c"
|
||||
@@ -375,6 +381,28 @@ static int mask_main(int scale, int window) {
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
|
||||
#if defined(PSX_TEST_RENDER_PASSES)
|
||||
/* Mode "passes": see the header. */
|
||||
static int passes_main(int scale, int window) {
|
||||
(void)scale;
|
||||
gl_renderer_set_interpolation(1, 120.0, 120.0, 60.0, 2);
|
||||
gl_renderer_set_interpolation_source(1);
|
||||
s_interp_valid = 2; /* as after the first presented frame */
|
||||
uint32_t why = gl_renderer_pass_unavailable();
|
||||
printf("passes: unavailable=%u\n", (unsigned)why);
|
||||
if (window) {
|
||||
check(why == PSX_MOD_RENDER_PASS_BACKEND, "window mode refuses render passes");
|
||||
check(!gl_renderer_pass_begin(0, 0, FRAME_W, FRAME_H, 1, 1, 0) && !s_pass_active,
|
||||
"window mode: pass_begin opens nothing");
|
||||
} else {
|
||||
check(why == PSX_MOD_RENDER_PASS_READY, "full-VRAM surface offers render passes");
|
||||
}
|
||||
check(glGetError() == GL_NO_ERROR, "GL error");
|
||||
printf("checks=%d failures=%d\n", checks, failures);
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int capture_main(int scale, int window) {
|
||||
GLuint fbo = s_hr_fbo;
|
||||
int sx = 0;
|
||||
@@ -605,6 +633,14 @@ int main(int argc, char **argv) {
|
||||
gl_renderer_shutdown(); SDL_DestroyWindow(win); SDL_Quit();
|
||||
return rc;
|
||||
}
|
||||
#if defined(PSX_TEST_RENDER_PASSES)
|
||||
if (!strcmp(mode, "passes")) {
|
||||
if (si.windowed) check(si.hr_scale == 1, "window mode engaged");
|
||||
int rc = passes_main(scale, si.windowed);
|
||||
gl_renderer_shutdown(); SDL_DestroyWindow(win); SDL_Quit();
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
if (!strcmp(mode, "mask")) {
|
||||
if (si.windowed) check(si.hr_scale == 1, "window mode engaged");
|
||||
int rc = mask_main(scale, si.windowed);
|
||||
|
||||
Reference in New Issue
Block a user