Open Jairard opened 1 week ago
Should I propose a PR ?
Yes that would be good. One that possibly tackle this and #7765 (if meaningful you can split in multiple commits). I don't know WGPU very well so any explanation is useful as we tend to return back to those issues later.
Note that it is legal for other backends call RenderDrawData() multiple time so I wouldn't perform any clear there. If anything they can be in backend NewFrame() and Shutdown() function if needed.
Ok, so I could tackle both issues.
I tried implementing the solution you proposed in https://github.com/ocornut/imgui/issues/7765#issuecomment-2206436309, in order to remove the permanent storage of WGPUBindGroup
s. Unfortunately, it's not feasible because we would have to release the WGPUBindGroup
s in RenderDrawData()
, but they need to stay alive longer.
So the solution I went with keeps the permanent storage but clears it in NewFrame()
as it was also suggested. An additional cleaning is added in Shutdown()
via the SafeRelease()
functions to get rid of the WGPUBindGroup
s allocated in the last frame. As a side effect, I could remove the ImageBindGroup
member of RenderResources
to make things more clear.
As for a global explanation, I think it is pretty clear in https://github.com/ocornut/imgui/issues/7765 but I can try to sum it up here. In the backend, we provide a way to draw a texture via its WGPUTextureView
. But we can't keep this view in memory because the user can release it at any point and we have no way to notify this to the backend (and it's no wishable to introduce one as it would be error-prone). Moreover, the user can release a WGPUTextureView
and create a new one, which could have the exact same value since on WebGPU's side, the previous one doesn't exist anymore so the new one can be allocated with the same id.
Hence we need to clear the backend cache before each new frame. This cache is an ImGuiStorage
that contains WGPUBindGroup
s referenced by the hash of the corresponding WGPUTextureView
. So in order to clear it we need to release each WGPUBindGroup
and call the Clear()
method. This way, we recreate the bind groups as needed by each frame.
N.B: PR incoming, I just wanted to post this before
Version/Branch of Dear ImGui:
Version 1.90.4, Branch: docking
Back-ends:
imgui_impl_wgpu.cpp + imgui_impl_glfw.cpp
Compiler, OS:
Windows 10 + clang-cl 18.1.8
Full config/build information:
Details:
Whenever an ImGui::Image is used with WebGPU backend, memory leaks are reported
Here is the output I get when running the minimal code sample and closing the window:
As soon as I comment the
ImGui::Image
line, this log disappears.Investigation
I investigated the
imgui_impl_wgpu.cpp
file and it appears that theWGPUBindGroup
s contained inImageBindGroups
(of theRenderResources
structure) are not released instatic void SafeRelease(RenderResources& res)
, that is called byImGui_ImplWGPU_Shutdown()
.Initially, I stumbled upon this while having the issue mentioned reported in https://github.com/ocornut/imgui/issues/7765. It appears that clearing the
WGPUBindGroup
s each frame could also solve the issue, if it is done at the end of the call toImGui_ImplWGPU_RenderDrawData
, but I think the groups need to survive longer than this. Anyway, theSafeRelease
functions still do not do their job properly.That's why I chose to open a distinct issue.
Local hack to fix the issue
Locally, I hacked my way through the issue but in a very ugly way. I expose the code here in order to show my way of thinking about this issue:
Fix proposal
I do believe that adding some cleaning code in
SafeRelease
would fix the issue in a clean way, something that would look like that:Note that we avoid releasing twice the
WGPUBindGroup
that is both stored inImageBindGroup
andImageBindGroups
. This bind group is used for the default font atlas and is correctly released. When callingImGui::ShowDemoWindow()
, there is no leak because the only call toImGui::Image
is to display the default font atlas.Screenshots/Video:
No response
Minimal, Complete and Verifiable Example code: