perf(acrylic): release blur render targets while the effect is skipped
Turning blur off (blur 0), switching to low-spec mode or enabling reduced transparency after the acrylic targets existed left the capture FBO and both blur ping-pong targets allocated for the rest of the session, although nothing draws with them while the effect is skipped. They are now released at a frame boundary and rebuilt on demand: - ImGuiAcrylic::ReleaseIdleBuffers() runs right after app.preFrame(), before NewFrame(), when the previous frame's draw data has been rendered, and once in the resize-watcher frame (GL and DX11). While the effect is skipped it frees the targets; when the effect is wanted again it reallocates them once, with no per-frame retry if that fails; - resize() while skipped only records that a reallocation is needed; - the release checks the GL names (and each DX11 texture) directly, so a half-allocated ping-pong pair is freed too; DX11 also resets the ping-pong index; - the capture paths and applyBlur() return early without a capture buffer, which would otherwise blit the default framebuffer onto itself; - each release logs "released targets (effect skipped)". With blur on, the path and the output are unchanged (screenshot sweeps within noise). After re-enabling, the first frame draws the tinted fallback until a fresh capture exists. Measured with software GL, toggling every 30 frames for 1200 frames: the targets were released exactly one frame after each switch-off (22 of 22) and rebuilt on each switch-on (21 of 21), with no GL or framebuffer errors. While off at 1280x720, with a fixed malloc mmap threshold, the process holds 4.62 MB less (the 1280x720 RGBA8 capture plus two 320x180 RGBA16F blur targets) and RssAnon is about 3.1-3.5 MB lower. With glibc's default threshold the freed memory stays in the heap and RssAnon does not visibly drop. Known issue: every off/on pair now frees and reallocates those targets. Under software GL (llvmpipe) with the default glibc allocator the freed texture memory is not reused: toggling every 2 frames grew RssAnon from 49 to 906 MB over 240 pairs, every 8 frames from 56 to 179 MB, and every 30 frames it levels off near 120 MB. It is not a GL object leak (with a fixed mmap threshold the mapped bytes stay flat), and on a hardware driver (WSLg d3d12) RssAnon stayed between 67.5 and 74.9 MB under the 2-frame churn (94.3 MB without the release). Users reach fast toggling by holding Ctrl+Shift+Down (key repeat, about 20 Hz) or by dragging the blur slider back and forth across 0. A short delay before releasing would avoid it if software-rendered users matter. Not verifiable here: the DX11 release and reallocation at runtime, and macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1538,6 +1538,8 @@ int main(int argc, char* argv[])
|
||||
SDL_GL_MakeCurrent(ctx->window, ctx->gl_context);
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
#endif
|
||||
// Free/rebuild acrylic targets at the frame boundary (after MakeCurrent on GL: FBOs are per-context).
|
||||
dragonx::ui::effects::ImGuiAcrylic::ReleaseIdleBuffers();
|
||||
ImGui_ImplSDL3_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
@@ -1951,6 +1953,8 @@ int main(int argc, char* argv[])
|
||||
// Pre-frame: font atlas rebuilds and schema hot-reload must
|
||||
// happen BEFORE NewFrame() because NewFrame() caches font ptrs.
|
||||
app.preFrame();
|
||||
// Acrylic targets are freed/rebuilt here, between frames: nothing recorded can reference them.
|
||||
dragonx::ui::effects::ImGuiAcrylic::ReleaseIdleBuffers();
|
||||
|
||||
// Smooth font-scale: compensate visual font size via FontScaleMain
|
||||
// when the atlas hasn't been rebuilt yet (during slider drag).
|
||||
|
||||
Reference in New Issue
Block a user