fix(gfx): send fog CLUT payload inline to end sky flicker#4343
Open
semeaj wants to merge 1 commit into
Open
Conversation
The fog texture animation rewrites its 16x16 CLUT in EE memory every frame (base fill plus the per-entry alpha loop), but the PC texture upload record only carried the CLUT's address. The render thread then memcpy'd it whenever the tex bucket rendered, racing the game thread which was already writing the next frame's values. A torn read draws the fog layer (which tints both sky and terrain) with wrong colors for exactly one frame, producing a random one-frame sky flicker, most visible on the jak3 title screen. Carry the CLUT payload inline in the double-buffered dma buffer right after the upload record (qwc 65) so the renderer always sees a coherent copy. The C++ handler accepts both forms; callers with frame-stable data (bigmap, blit-displays) keep the address form. Applies to jak2 and jak3, which share the fog anim code. (AI-assisted)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Jak 2 and Jak 3 exhibit a random one-frame sky/fog flicker, most visible on the jak3 title screen: the sky's warm haze layer pops or briefly disappears for exactly one frame at random intervals (typically every 1 to 3 seconds), independent of framerate. Framerate only changes how visible each bad frame is.
Root cause
The fog texture animation (
real-fog-texture-anim-funcintexture-anim-funcs.gc) rewrites its 16x16 CLUT in EE memory every frame: a base color fill of all 256 entries followed by the per-entry alpha computation. The PC-port upload record (upload-clut-16-16) only carried the CLUT's EE address. The render thread memcpy's that memory whenever the tex bucket renders, racing the game thread which is concurrently writing the next frame's values. A torn read renders the fog layer (which tints both sky and terrain) with wrong colors for exactly one frame, then self-heals on the next upload.This was isolated with per-frame instrumentation: with the sky bucket's DMA, the generated cloud texture (all mip levels), texture pool bindings, and GL state all hashed bit-identical on flicker frames, fully serializing the game and render threads eliminated the flicker (2 events vs 104-182 per 2.5 min baseline), which narrowed it to a cross-thread read of live EE memory; the fog CLUT is the only such per-frame-rewritten payload in the sky path.
Fix
Carry the CLUT payload inline in the double-buffered DMA buffer, immediately after the upload record (qwc 65 = 1 record + 64 quadwords of CLUT). The buffer is per-frame double-buffered, so the renderer always sees a coherent copy with no synchronization needed.
The C++ handler accepts both forms based on transfer size, so the other
upload-clut-16-16callers (bigmap, blit-displays), whose data is stable while a frame renders, keep the address form unchanged.Test plan
I work off a self-hosted forge, so this GitHub account is quiet; the full investigation telemetry (per-frame DMA and texture content hashes, framebuffer pixel-patch captures, before/after event-rate runs) is available if anyone wants the raw data.
(AI-assisted)