You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Lost Soul Aside (PPSA26358): flashing green artifacts on the title screen #4387
Lost Soul Aside (PPSA26358) reaches the title screen, but the animated background intermittently renders white polygon fragments surrounded by intense green glow. The fragments flash and move across the scene; the screenshot below captures them in the upper-right corner. The flashes continue with the performance overlay hidden.
This was tested with a local integration build based on main d146ec1b667c3e34bebf817efcc094bdac393423, with additional fixes needed to reach the title screen. These include #3739, #3763, #3831, #4150, #4271 and #4281, together with rendering changes from #1077, #3878 and #3952. This is not a clean-main reproduction.
Relink and launch the game's dump with the integration build.
Let the startup sequence reach the title screen.
Leave the title screen running for several seconds. No input is required to reproduce the flashes.
Expected: the title-screen background renders consistently.
Actual: intermittent bright green flashes and white polygon fragments appear over the background.
The screenshot was taken with the sampled-texture and CPU-read indirect-draw paths enabled. Integrating the zero-position vertex/tessellation clipping fix from #3878 also did not eliminate the flashes. These comparisons have not isolated the responsible rendering path yet.
The workaround matrix helps rule out several host-side paths. To distinguish a real vertex/render-target alias from a stale binding or range calculation, could you capture the failing draw’s vertex-buffer guest address and byte range, the bound color target address and byte range (including format/extent), plus the draw/shader identifier? The rejection is in Draw.cpp at the overlap check, so those values would show whether the ranges truly overlap and let us trace which descriptor or binding supplied them. If available, please include the corresponding request/trace artifact or a minimal replay.
I captured a fresh green-flash interval with probes at the range checks. One correction: I have not reproduced a vertex buffer aliases the render target rejection alongside these flashes. The green corruption is visible while drawing continues, and the alias guard stayed intact.
The probe immediately before that Require records the exact vertex address and calculated bytes after VertexBufferExtent/VertexBufferReadSize and max-index resolution. Additional records capture guest shader-buffer bindings and bound color-target ranges on both normal and recipe draws, with shader variant/source-address mappings.
Download the range trace and screenshot bundle (5.23 MB; SHA-256 e0311fc627ca0158c0761ca7d77c6c8c7969b26023a2afe249f1d2641319bea5). It includes compressed complete JSONL, a ±150 ms screenshot window, deduplicated vertex-range CSV, raw descriptor dwords, binding/fetch indices, target format/extent, draw identifiers, shader addresses and a field/limitations README. This is a numerical range trace, not a standalone replay; shader ISA and guest memory payload are not included.
The 12-second interval contains 25,807 draw calls, 74,222 vertex rows (44,618 against active, nonempty color targets) and 376,840 shader-buffer/target rows (210,307 with both ranges nonempty). Zero recorded overlaps, zero range-calculation exceptions, and no vertex/shader/index alias rejection in the run log. The screenshot operation is timestamped 1791800349389 ms / 2026-10-12 10:19:09.389 UTC:
Examples recorded at that same millisecond, using exclusive-end ranges:
Draw / VS variant
VS guest code
Vertex range / bytes
Color slot 0 range / bytes
Target format / extent
8206 / 0xae5
0x12c183b000
[0x10610caa40, 0x10610caa78) / 56
[0x2094150000, 0x2094570000) / 4,325,376
VK_FORMAT_R8_UNORM (9), 2688×1512
8207 / 0xec9
0x12c1846400
[0x1120ebfe40, 0x1120ebfef0) / 176
[0x2094150000, 0x2094570000) / 4,325,376
VK_FORMAT_R8_UNORM (9), 2688×1512
8208 / 0xc39
0x12c1833c00
[0x1120ebfe40, 0x1120ebfee8) / 168
[0x209f310000, 0x20a1290000) / 33,030,144
VK_FORMAT_R16G16B16A16_SFLOAT (97), 2688×1512
Draw 8206 uses attribute/fetch index 0, descriptor [610caa40, 00100010, 00000004, 2004dfac], stride 16 and max index 3. Draws 8207/8208 use attribute/fetch index 0, descriptor [20ebfe40, 00200011, 00000006, 2004dfac], stride 32 and max index 5. Their VS pipeline variants are 0x105f, 0x103d, 0x1060. The corresponding fragment code/variants are 0x1160e7ff00 / 0x3a2, 0x1420fa6000 / 0x106d, and 0x1220e6c800 / 0x9d7.
These are nearby bound draws, not an isolated offending draw: screenshot time does not identify a GPU submission, and presentation can lag recording. The trace does not establish a causal alias, or exclude a stale/wrong descriptor or too-small calculated range. If the rejection refers to another log/build, these reproduced flashes have not reached that rejection yet.
Build context: integration 20c0a0733 with main 9aa5fd290 merged, the title bring-up fixes listed in #4401, scoped #4150 refolding, #4404 preparation scheduling, and an unproven local mesh zero-position guard. Not clean main. APS5_EXPERIMENTAL_RECLAIM_IR=1, APS5_NO_SAMPLED_FROM_STORAGE=1, fresh shader cache; overlay hidden. Temporary range probes were removed afterward. After capture, two X presses reached level loading; the memory guard stopped the game with about 1.8 GiB commit headroom. Gameplay and the green flashes remain unresolved.
The look of it, bright green with white fragments and a glow on a frame that renders into R16G16B16A16_SFLOAT targets, usually means NaN or infinity pixels reaching the post-processing. Bloom spreads a NaN or inf into a white glow, and Unreal's temporal AA works in YCoCg, where bad values show up green. If that's what is happening, the range trace won't show it, since nothing overlaps; the question is which pass first writes the bad values.
Two things would narrow it down:
A capture of a flashing frame. RenderDoc captures the Vulkan stream, and its texture viewer has a "NaN/INF/-ve" overlay. Nsight Graphics works too. On the HDR scene-colour target (the 2688×1512 R16G16B16A16_SFLOAT in your trace), pixel history for one of the green pixels would show the first draw or dispatch that writes a NaN or inf into it. That pass is where the bad value is created, rather than where it's spread.
That pass's shader addresses. The capture gives you the pipeline, and your probes already map pipelines to guest shader addresses. With the addresses, the shader can be recompiled offline and its float semantics checked instruction by instruction. You don't need to share the shader code: the instruction mix around the output would be enough to see whether it's a NaN rule, a denormal flush, an f16 conversion or uninitialized data.
One thing I checked that this is not: v_cvt_pkrtz_f16_f32, the usual way HDR colour is packed to f16, clamps a large finite value to ±65504 the way AMD's round-toward-zero does. So that conversion doesn't create infinities.
Looking again at the run 68 screenshot, I'd narrow that down. The green objects aren't scattered bad pixels: they're coherent shards and streaks with white cores and a green bloom halo, they move across the scene, and the rest of the frame is right: the logo, the blue background crystals, the small cyan motes and the UI. That looks like one particle effect drawn far too bright, with its colour or intensity off by a large factor, possibly an infinity in one channel, rather than a NaN smeared by TAA.
Unreal simulates GPU particles (Niagara) in compute dispatches, wave64 on PS5, and the particle draw reads each particle's colour, size and alpha from buffers those dispatches write. So in a capture of a flashing frame, I'd go:
Pixel history on one green shard, which should lead to the particle draw.
That draw's per-particle attribute buffer, in RenderDoc's buffer or mesh view: colour, scale, alpha.
If those values are already huge or NaN, the problem is in the simulation dispatch that wrote them, and its compute shader address is the useful one.
If they look sane, it's in the particle's vertex or pixel shader.
Either way, the address of the first shader that produces the bad value is what lets it be recompiled offline and checked.
A data point from another UE title that may help isolate this: Beast of Reincarnation (PPSA29343) at 1080p output showed 64x64-pixel blocks of stale scene content plus small bright fragments in the upper-right corner of its title screen. Like here, APS5_NO_SAMPLED_FROM_STORAGE, synchronous draws, APS5_NO_GPL, disabled barrier elision and the DCC/clear switches did not change it.
Turning off UE's render graph transient allocator removed all of it, with the same frame rate. In the title's saved/ps5/engine.ini:
[SystemSettings]r.RDG.TransientAllocator=0
With the allocator on, APS5_TRACE_DCC_KEYS showed the 960x540 scene color target (format 36), a 4 MiB surface and a 1920x1080 target sharing address ranges within one frame, so the artifacts look like the driver not ordering aliased transient memory the way the console does. If Lost Soul Aside ships the same cvar (it is in Beast's executable as the UTF-16 string r.RDG.TransientAllocator), setting it to 0 would show whether the green flashes have the same cause. Linux, RTX 3050 Laptop, NVIDIA 615.78.08.
Follow-up to my earlier comment: the green flashes turned out to have a different cause, the array-slice XOR that #4551 fixes, so the r.RDG.TransientAllocator suggestion does not apply here. Beast of Reincarnation's blocks were transient aliasing, between a tile image with pending results and a buffer written later over the same memory; the fix is #4654, in case another UE title shows something similar.
Activity
MarcZX10 commentedon Oct 12, 2026
The workaround matrix helps rule out several host-side paths. To distinguish a real vertex/render-target alias from a stale binding or range calculation, could you capture the failing draw’s vertex-buffer guest address and byte range, the bound color target address and byte range (including format/extent), plus the draw/shader identifier? The rejection is in
Draw.cppat the overlap check, so those values would show whether the ranges truly overlap and let us trace which descriptor or binding supplied them. If available, please include the corresponding request/trace artifact or a minimal replay.eljackjoestar-cmd commentedon Oct 12, 2026
I captured a fresh green-flash interval with probes at the range checks. One correction: I have not reproduced a
vertex buffer aliases the render targetrejection alongside these flashes. The green corruption is visible while drawing continues, and the alias guard stayed intact.The probe immediately before that
Requirerecords the exact vertex address and calculatedbytesafterVertexBufferExtent/VertexBufferReadSizeand max-index resolution. Additional records capture guest shader-buffer bindings and bound color-target ranges on both normal and recipe draws, with shader variant/source-address mappings.Download the range trace and screenshot bundle (5.23 MB; SHA-256
e0311fc627ca0158c0761ca7d77c6c8c7969b26023a2afe249f1d2641319bea5). It includes compressed complete JSONL, a ±150 ms screenshot window, deduplicated vertex-range CSV, raw descriptor dwords, binding/fetch indices, target format/extent, draw identifiers, shader addresses and a field/limitations README. This is a numerical range trace, not a standalone replay; shader ISA and guest memory payload are not included.The 12-second interval contains 25,807 draw calls, 74,222 vertex rows (44,618 against active, nonempty color targets) and 376,840 shader-buffer/target rows (210,307 with both ranges nonempty). Zero recorded overlaps, zero range-calculation exceptions, and no vertex/shader/index alias rejection in the run log. The screenshot operation is timestamped
1791800349389ms /2026-10-12 10:19:09.389 UTC:Examples recorded at that same millisecond, using exclusive-end ranges:
0xae50x12c183b000[0x10610caa40, 0x10610caa78)/ 56[0x2094150000, 0x2094570000)/ 4,325,376VK_FORMAT_R8_UNORM(9), 2688×15120xec90x12c1846400[0x1120ebfe40, 0x1120ebfef0)/ 176[0x2094150000, 0x2094570000)/ 4,325,376VK_FORMAT_R8_UNORM(9), 2688×15120xc390x12c1833c00[0x1120ebfe40, 0x1120ebfee8)/ 168[0x209f310000, 0x20a1290000)/ 33,030,144VK_FORMAT_R16G16B16A16_SFLOAT(97), 2688×1512Draw 8206 uses attribute/fetch index 0, descriptor
[610caa40, 00100010, 00000004, 2004dfac], stride 16 and max index 3. Draws 8207/8208 use attribute/fetch index 0, descriptor[20ebfe40, 00200011, 00000006, 2004dfac], stride 32 and max index 5. Their VS pipeline variants are0x105f,0x103d,0x1060. The corresponding fragment code/variants are0x1160e7ff00/0x3a2,0x1420fa6000/0x106d, and0x1220e6c800/0x9d7.These are nearby bound draws, not an isolated offending draw: screenshot time does not identify a GPU submission, and presentation can lag recording. The trace does not establish a causal alias, or exclude a stale/wrong descriptor or too-small calculated range. If the rejection refers to another log/build, these reproduced flashes have not reached that rejection yet.
Build context: integration
20c0a0733with main9aa5fd290merged, the title bring-up fixes listed in #4401, scoped #4150 refolding, #4404 preparation scheduling, and an unproven local mesh zero-position guard. Not clean main.APS5_EXPERIMENTAL_RECLAIM_IR=1,APS5_NO_SAMPLED_FROM_STORAGE=1, fresh shader cache; overlay hidden. Temporary range probes were removed afterward. After capture, two X presses reached level loading; the memory guard stopped the game with about 1.8 GiB commit headroom. Gameplay and the green flashes remain unresolved.karanvora2599 commentedon Oct 12, 2026
The look of it, bright green with white fragments and a glow on a frame that renders into
R16G16B16A16_SFLOATtargets, usually means NaN or infinity pixels reaching the post-processing. Bloom spreads a NaN or inf into a white glow, and Unreal's temporal AA works in YCoCg, where bad values show up green. If that's what is happening, the range trace won't show it, since nothing overlaps; the question is which pass first writes the bad values.Two things would narrow it down:
R16G16B16A16_SFLOATin your trace), pixel history for one of the green pixels would show the first draw or dispatch that writes a NaN or inf into it. That pass is where the bad value is created, rather than where it's spread.One thing I checked that this is not:
v_cvt_pkrtz_f16_f32, the usual way HDR colour is packed to f16, clamps a large finite value to ±65504 the way AMD's round-toward-zero does. So that conversion doesn't create infinities.karanvora2599 commentedon Oct 12, 2026
Looking again at the run 68 screenshot, I'd narrow that down. The green objects aren't scattered bad pixels: they're coherent shards and streaks with white cores and a green bloom halo, they move across the scene, and the rest of the frame is right: the logo, the blue background crystals, the small cyan motes and the UI. That looks like one particle effect drawn far too bright, with its colour or intensity off by a large factor, possibly an infinity in one channel, rather than a NaN smeared by TAA.
Unreal simulates GPU particles (Niagara) in compute dispatches, wave64 on PS5, and the particle draw reads each particle's colour, size and alpha from buffers those dispatches write. So in a capture of a flashing frame, I'd go:
Either way, the address of the first shader that produces the bad value is what lets it be recompiled offline and checked.
GustavoGamarra95 commentedon Oct 12, 2026
A data point from another UE title that may help isolate this: Beast of Reincarnation (PPSA29343) at 1080p output showed 64x64-pixel blocks of stale scene content plus small bright fragments in the upper-right corner of its title screen. Like here,
APS5_NO_SAMPLED_FROM_STORAGE, synchronous draws,APS5_NO_GPL, disabled barrier elision and the DCC/clear switches did not change it.Turning off UE's render graph transient allocator removed all of it, with the same frame rate. In the title's
saved/ps5/engine.ini:With the allocator on,
APS5_TRACE_DCC_KEYSshowed the 960x540 scene color target (format 36), a 4 MiB surface and a 1920x1080 target sharing address ranges within one frame, so the artifacts look like the driver not ordering aliased transient memory the way the console does. If Lost Soul Aside ships the same cvar (it is in Beast's executable as the UTF-16 stringr.RDG.TransientAllocator), setting it to 0 would show whether the green flashes have the same cause. Linux, RTX 3050 Laptop, NVIDIA 615.78.08.eljackjoestar-cmd commentedon Oct 12, 2026
The issue has been resolved and the PR pushed. Thank you for the comments and suggestions they truly helped.
GustavoGamarra95 commentedon Oct 12, 2026
Follow-up to my earlier comment: the green flashes turned out to have a different cause, the array-slice XOR that #4551 fixes, so the
r.RDG.TransientAllocatorsuggestion does not apply here. Beast of Reincarnation's blocks were transient aliasing, between a tile image with pending results and a buffer written later over the same memory; the fix is #4654, in case another UE title shows something similar.