-
-
Notifications
You must be signed in to change notification settings - Fork 10.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory leak when rendering with DX11 in C++ #7615
Comments
I've just noticed that the issue either only happens when the PC is locked/screen is off, or at least it gets much worse in that situation. |
Calling Present() with I logged WM_xxx messages and noticed that whereas minimization #2496 #3907 sends a WM_SIZE with
My conclusion is that we need to handle |
As mentioned in #2496 (comment) one of my issue with solving this based on Present() return value of main viewport, is that it would either freeze applications where main viewport is minimized and others aren't, either leave them unthrolled in that situation (which is already the case technically, but rarely noticed as |
It does occur in the win32 dx11 example: I'll test the snippet here based on the Present() return value. I'm not familiar with how multiple viewports work so I'm not sure what an appropriate solution for the library as a whole is, but if that works it should solve the problem in my case. Thanks! |
Here's my current solution could you test it on your end? static bool g_pSwapChainOccluded = false; After polling WM message loop: // Handle window being occluded or screen locked
if (g_pSwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED)
{
::Sleep(10);
continue;
}
g_pSwapChainOccluded = false; Present: HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
g_pSwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED); |
Your attempt as pictured in screenshot will let the rest of the code run at max speed, burning a core and essentially making no difference. |
I have pushed ec1d2be which implement this for the DX9, DX10, DX11 and DX12 examples DX9 and DX12 are both slightly different, and Present() does wait for vsync even on fail so it didn't exhibit a CPU core burn, but adding better support for it means we are not looping when screen locked which is desirable. If you want to dig further into remaining issues please do but I'd prefer if you do it (or confirm it) in vanilla example. I don't know if there are ways to break into those allocs. |
I suspect that the 32,903 byte objects are some kind of DX11 or win32 data structure which is required, because there are 2 or 3 present from the start when running normally. My guess is that they were being re-created without proper cleanup when trying to render with an occluded window, and that's no longer happening, so all is well! Thanks again. |
@ocornut You may already know it, but just in case: I saw on Twitter that you were starting to use the dxgi flip model, but it will never return DXGI_STATUS_OCCLUDED. So if you use DXGI_SWAP_EFFECT_FLIP_DISCARD in the backends, this issue will come back. |
@RT2Code Thanks for the headup. Do you know how are you supposed to handle this? I have confirmed that when using FLIP_DISCARD i don't get DXGI_STATUS_OCCLUDED when minimized, however Present still honor vsync so it doesn't burn a CPU. It however ideally should go idle, and perhaps we should combine this with #3907 together... When locking the computer, I do get a DXGI_STATUS_OCCLUDED signal however. (I've been investigating DXGI_SWAP_EFFECT_FLIP_DISCARD for #7607 but I think it add a little extra pressure to make our example apps dpi aware, and probably I am going to get back to #3761 for that first, but only after I finish multi-select for 1.91.....) |
There's an alternative API to get occluded notifications, but I couldn't get it to work either. I only get 2 notifications at the start of the app, but then nothing. That being said, I'm not sure at all how to use it correctly, I couldn't find any decent documentation about it, so here's the gist of it if you wanna try by yourself: #include <d3d11_1.h>
#define WM_OCCLUSION_EVENT (WM_USER + 1)
//Data
[...]
static IDXGIFactory2* g_pFactory = nullptr;
[...]
int main(int, char**)
{
[...]
// Setup Platform/Renderer backends
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
DWORD occlusionStatusCookie = 0;
g_pFactory->RegisterOcclusionStatusWindow(hwnd, WM_OCCLUSION_EVENT , &occlusionStatusCookie);
[...]
g_pFactory->UnregisterOcclusionStatus(occlusionStatusCookie);
// Cleanup
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
[...]
}
[...]
bool CreateDeviceD3D(HWND hWnd)
{
[...]
IDXGIDevice * pDXGIDevice;
res = g_pd3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice);
if (res != S_OK)
return false;
IDXGIAdapter * pDXGIAdapter;
res = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&pDXGIAdapter);
if (res != S_OK)
return false;
res = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&g_pFactory);
if (res != S_OK)
return false;
[...]
}
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
[...]
switch (msg)
{
case WM_OCCLUSION_EVENT:
{
g_SwapChainOccluded = !g_SwapChainOccluded; // Not sure how we're supposed to tell when it's occluded or not? I guess it alternate, but I'm not sure about that at all.
break;
}
[...]
} |
Version/Branch of Dear ImGui:
Version 1.89.6, Branch: master
Back-ends:
imgui_impl_win32.cpp + imgui_impl_dx11.cpp
Compiler, OS:
Windows 10 + MSVC 14.39.33519
Full config/build information:
No response
Details:
My Issue/Question:
I am using Dear ImGui with the win32 and dx11 backends in a fairly complicated control panel application, and it appears to be causing a memory leak. The code I'm using to render is straight from the demo:
Every frame, imgui_new_frame() is called, then our UI code, then imgui_dx11_render(). However, at a regular interval 32,903 bytes are allocated and never deallocated. In one test it was every ~8 seconds, and in another every ~700 milliseconds:
Line 215 is
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
. I'm not able to post the full code because there are thousands of lines and it's confidential, so I understand that it may be difficult to help, but it would be helpful to know:It's very strange because the code works exactly like the example, and I doubt that Dear ImGui or DX11 have significant memory leaks like this. The fact that it happens at a consistent interval but not every frame also seems odd.
Screenshots/Video:
No response
Minimal, Complete and Verifiable Example code:
The text was updated successfully, but these errors were encountered: