Preserve background composite lifetime and park visual validation

This commit is contained in:
Matthew Stanley
2026-09-12 12:01:56 -07:00
parent 4dfc7b9c1c
commit 7b2962efb5
5 changed files with 47 additions and 9 deletions
+21 -6
View File
@@ -18,12 +18,27 @@ the composite remains continuous. Tags expire after two frames and reject
reused packets whose words changed. This method performs no guest writes or
extra guest allocations.
OpenGL preserves the tag across flat and textured batching. While an explicitly
tagged background is active, it renders the full wide composite instead of
copying the canonical center over it, which would create a scale seam. Other
scenes retain the center-copy optimization. Measure performance in the title
and validate the visible sky at the requested aspect before release. Vulkan's
native-wide compositor is not implemented; this API does not add one.
OpenGL preserves the tag across flat and textured batching. Once a valid
background has been tagged, it renders the full wide composite instead of
copying the canonical center over it, which would create a scale seam. Packet
freshness and displayed-pixel lifetime are separate: a slow game or held display
can retain stretched pixels after the two-frame packet guard expires. The
full-composite requirement therefore remains latched until GPU reset or snapshot
restore; packet-address/content freshness is not relaxed. Sessions that have not
tagged a background retain the center-copy optimization. Measure performance in
the title and validate the visible sky at the requested aspect before release.
Vulkan's native-wide compositor is not implemented; this API does not add one.
### Parked validation checkpoint (2026-09-12)
The focused GPU packet/tag regression passes, including expired packets,
changed packet contents, disabled widescreen and retained composite lifetime.
The V8 Windows runtime builds and both game CTests pass. In the oil-field
21:9 playtest the owner reports that terrain looks fine and the background
flickers less badly, but still flickers. This is partial improvement, not visual
acceptance. State replay required the HLE scheduler; repeat the comparison with
matched scheduler settings before attributing the improvement solely to this
change. Work is parked in a draft; no release is approved.
## Earlier projection-and-stretch implementation
+5 -2
View File
@@ -366,9 +366,12 @@ void gpu_ws_tag_hud_prim(uint32_t prim, int anchor);
* Tag the complete background composite before submitting its ordering table.
* The caller proves background identity/coverage; no guest data is modified. */
void gpu_ws_tag_background_prim(uint32_t prim);
/* Renderer policy: tagged background scenes need their full wide composite;
* copying the canonical center over it would introduce a scale discontinuity. */
/* Fresh packet tags are eligible for background classification. */
int gpu_ws_background_stretch_active(void);
/* A tagged background can remain in a wide surface after its packet expires.
* Once used, retain full compositing until GPU reset or snapshot restoration.
* Packet freshness must never re-enable canonical-center overwrites. */
int gpu_ws_background_requires_full_composite(void);
/* Clear synthetic margins to black over an opaque 0x64/65 rectangle's Y band
* immediately before it executes. Packet-guarded; canonical VRAM is untouched. */
void gpu_ws_tag_black_reveal_rect(uint32_t prim);
+9
View File
@@ -1967,6 +1967,15 @@ int gpu_ws_background_stretch_active(void) {
frame - ws_background_tag_frame <= WS_HUD_ANCHOR_FRESH_FRAMES;
}
int gpu_ws_background_requires_full_composite(void) {
/* Freshness governs reuse of a packet address, not the lifetime of the
* pixels it produced. A slow game frame or a held display buffer can keep
* those pixels on screen indefinitely. Conservatively keep full mirroring
* once a composite has been tagged; GPU reset/snapshot restore clears the
* latch together with the tags. Never modify the packet freshness guard. */
return ws_background_tags_used && ws_native_wide_configured();
}
static int ws_nw_explicit_background(void) {
if (!gpu_ws_background_stretch_active() ||
gp0_cmd_source_addr == 0xFFFFFFFFu ||
+1 -1
View File
@@ -1705,7 +1705,7 @@ static int wide_fast_center_valid(void) {
/* An explicitly stretched sky differs inside the canonical viewport too.
* Keep the full composite for those scenes, including later foreground
* draws. Tags are installed before DMA, so no earlier center draws skip. */
return s_wide_fast && !gpu_ws_background_stretch_active();
return s_wide_fast && !gpu_ws_background_requires_full_composite();
}
static void wide_blit_center(GLuint wide_fbo, int base_x, int disp_y, int disp_h); /* def below */
/* True if [lo,hi] (canonical draw-x) lies strictly inside the 4:3 frame, so the
@@ -113,11 +113,13 @@ static void test_background_packet_tags(void) {
memcpy(gp0_cmd_buf, packet, sizeof(packet));
gpu_ws_tag_background_prim(addr - 4u);
assert(!gpu_ws_background_stretch_active());
assert(!gpu_ws_background_requires_full_composite());
assert(!ws_nw_explicit_background());
configure_native_wide_16_9();
gpu_ws_tag_background_prim(0x80000000u | (addr - 4u));
assert(gpu_ws_background_stretch_active());
assert(gpu_ws_background_requires_full_composite());
assert(ws_nw_explicit_background());
/* Explicit proof remains valid after a foreground phase has begun. */
s_bg_phase_frame = (uint32_t)s_frame_count;
@@ -141,11 +143,19 @@ static void test_background_packet_tags(void) {
++s_frame_count;
assert(!gpu_ws_background_stretch_active());
assert(!ws_nw_explicit_background());
/* A held display retains its stretched pixels after packet expiry. The
* compositor must not paste canonical 4:3 scenery over their center. */
assert(gpu_ws_background_requires_full_composite());
s_frame_count += 120;
assert(gpu_ws_background_requires_full_composite());
assert(!ws_nw_explicit_background());
s_frame_count = 99;
assert(!gpu_ws_background_stretch_active());
assert(gpu_ws_background_requires_full_composite());
s_frame_count = 100;
ws_mode = 0;
assert(!gpu_ws_background_stretch_active());
assert(!gpu_ws_background_requires_full_composite());
/* Reject semi-transparent polygons, rectangles, misalignment and RAM
* overflow; a rejected tag must not even enable the full-composite path. */
@@ -153,6 +163,7 @@ static void test_background_packet_tags(void) {
0x1F800000u};
reset_gpu_state_for_test();
configure_native_wide_16_9();
assert(!gpu_ws_background_requires_full_composite());
for (unsigned i = 0; i < sizeof(bad_prim) / sizeof(bad_prim[0]); ++i)
gpu_ws_tag_background_prim(bad_prim[i]);
assert(!gpu_ws_background_stretch_active());