Description
One Path of Building instance can enter a severe, focus-gated GPU/UI stutter state on Windows. The displayed frame remains pixel-identical, but a focused 3840x1600 window repeatedly redraws and saturates the ANGLE/D3D11 path.
This was reproduced live with PoB 2.66.2 and SimpleGraphic 2.5-3b1a346 on an RTX 3080 Ti.
Measured behavior
| State |
PoB GPU 3D |
PoB CPU |
| affected instance, focused, maximized (3856x1568) |
80.5% avg / 89.7% max |
89.4% avg |
| affected instance, unfocused |
no measurable PoB GPU engine |
4.0% avg |
| affected instance, minimized |
no measurable PoB GPU engine |
negligible |
| affected instance, focused, windowed (1296x759) |
1.26% avg |
24.9% avg |
| affected instance, near-fullscreen windowed (3800x1500) |
79.4% avg |
99.4% avg |
| affected instance, focused at temporary 60 Hz |
81.8% avg |
83.6% avg |
| second PoB instance, same executable/runtime, focused/maximized |
2.57% avg |
33.1% avg |
Two consecutive captures of the affected window were byte-for-byte identical. Changing PoB tabs did not reduce load while focused. The workload stops when the window loses focus and scales strongly with framebuffer size.
The NVIDIA per-application profile correctly targets the exact executable and disables G-SYNC for it. DWM remained light during the bad sample, and there were no display-driver resets or relevant application errors. Both PoB instances had the same RTSS hook loaded, so the overlay is not the primary discriminator.
Confirmed renderer state
SimpleGraphic's built-in Layers diagnostic showed:
122 out of 122 frames drawn
Elide identical frames enabled
Elision inhibited continuously true
This rules out a changing command-buffer hash as the immediate trigger. A first candidate that stabilized raw command padding also passed the Windows build but made no performance difference in a portable A/B test.
Root cause
r_shaderHnd_c::~r_shaderHnd_c() aborts an asynchronous texture load when its shader's reference count reaches zero. Cancellation can leave the texture in a non-DONE state (INIT or PENDING_UPLOAD), and PurgeShaders() retains non-DONE shader slots.
r_renderer_c::PumpShaders() currently scans every retained slot. It therefore treats an already released, unusable shader as an active incomplete texture and sets inhibitElision on every frame. EndFrame() then clears lastFrameHash, forcing the full draw queue to replay continuously while PoB is focused.
Proposed fix
Only active shader slots (refCount > 0) should inhibit frame elision while their textures load. Released shaders cannot be used for rendering and must not globally disable elision.
PR #109 contains the one-line correction. The Windows CI build passed, and portable A/B validation on the reproducing build reduced focused/maximized GPU 3D load from 80.7% average to 6.27% while clearing the renderer's inhibition flag (22 out of 1020 frames drawn).
Environment
- Windows build 26100
- NVIDIA RTX 3080 Ti, driver 610.47
- Active display: 3840x1600 at 144 Hz
- PoB 2.66.2
- SimpleGraphic 2.5-3b1a346
- Loaded path: SimpleGraphic -> GLFW 3.4 -> EGL/GLES (ANGLE) -> D3D11/DXGI
Description
One Path of Building instance can enter a severe, focus-gated GPU/UI stutter state on Windows. The displayed frame remains pixel-identical, but a focused 3840x1600 window repeatedly redraws and saturates the ANGLE/D3D11 path.
This was reproduced live with PoB 2.66.2 and SimpleGraphic 2.5-3b1a346 on an RTX 3080 Ti.
Measured behavior
Two consecutive captures of the affected window were byte-for-byte identical. Changing PoB tabs did not reduce load while focused. The workload stops when the window loses focus and scales strongly with framebuffer size.
The NVIDIA per-application profile correctly targets the exact executable and disables G-SYNC for it. DWM remained light during the bad sample, and there were no display-driver resets or relevant application errors. Both PoB instances had the same RTSS hook loaded, so the overlay is not the primary discriminator.
Confirmed renderer state
SimpleGraphic's built-in Layers diagnostic showed:
122 out of 122 frames drawnElide identical framesenabledElision inhibitedcontinuously trueThis rules out a changing command-buffer hash as the immediate trigger. A first candidate that stabilized raw command padding also passed the Windows build but made no performance difference in a portable A/B test.
Root cause
r_shaderHnd_c::~r_shaderHnd_c()aborts an asynchronous texture load when its shader's reference count reaches zero. Cancellation can leave the texture in a non-DONEstate (INITorPENDING_UPLOAD), andPurgeShaders()retains non-DONEshader slots.r_renderer_c::PumpShaders()currently scans every retained slot. It therefore treats an already released, unusable shader as an active incomplete texture and setsinhibitElisionon every frame.EndFrame()then clearslastFrameHash, forcing the full draw queue to replay continuously while PoB is focused.Proposed fix
Only active shader slots (
refCount > 0) should inhibit frame elision while their textures load. Released shaders cannot be used for rendering and must not globally disable elision.PR #109 contains the one-line correction. The Windows CI build passed, and portable A/B validation on the reproducing build reduced focused/maximized GPU 3D load from 80.7% average to 6.27% while clearing the renderer's inhibition flag (
22 out of 1020 frames drawn).Environment