Open SuperWangKai opened 10 months ago
After changing swapchain scaling from DXGI_SCALING_STRETCH
to DXGI_SCALING_NONE
. I could not see resizing glitch and zoom-in/out effact when dragging the border of the window. I think this change could be a workaround.
I also logged for the DX9 and DX11 backends they have the same order issue. Since they don't have scaling-stretch option for swapchain, so I did not notice the issue. So I think it should be a common issue of docking (on Windows?).
In fact, as the order is incorrect, PlatformRequestResize flag is cleared in ImGuiViewportP::ClearRequestFlags() before it can actually be used to trigger the resize work.
This is intentional. PlatformRequestResize is used when resizing from Platform/OS decorations (e.g. window resizing border) which are disabled by default as io.ConfigViewportsNoDecoration == true
.
I will add comments near that ClearRequestFlags() to clarify this.
Resizing Platform window from ImGui displayed decorations
Begin()->UpdateWindowManualResize()
which modifies window->Size
.Begin()->if (window->ViewportOwned)
does viewport->Size = window->Size
.UpdatePlatformWindows()
will call g.PlatformIO.Platform_SetWindowSize(viewport, viewport->Size);
AND g.PlatformIO.Renderer_SetWindowSize(viewport, viewport->Size);
. The Platform_SetWindowSize() will lead to a WM_SIZE setting PlatformRequestResize = true
which is immediately cleared at the end of `UpdatePlatformWindows().Resizing Platform window from Platform/OS displayed decorations
viewport->PlatformRequestResize = true
NewFrame()->UpdateViewportsNewFrame()
goes in if (viewport->PlatformRequestResize)
block, calls g.PlatformIO.Platform_GetWindowSize(viewport)
and store in viewport->Size. PlatformRequestResize
is cleared at end of function.UpdatePlatformWindows()
will call g.PlatformIO.Renderer_SetWindowSize(viewport, viewport->Size)
I believe your log is partially incorrect (some incorrect recording or manipulation or missing details) ?
By adding a sleep in the main loop to make the refresh rate low, issue can be seen easily.
If I add a Sleep(80) or larger value e.g. Sleep(200) you can notice that the error only happens for very short while (at least on my setup), not for 200 ms. So it doesn't make it any "easier" to see the issue with Sleep(200), it's equally easy in both situation. Does it on your?
Right after UpdatePlatformWindows()
, RenderPlatformWindowsXXX
is called with the right render.
I think the issue has to do with the fact that there's a delay in swapped contents appearing, and the timing of that swap compared to timing of window size update may be missadjusted. Your suggested workaround is probably a good idea in that context, but I don't think the issue is caused by the thing you think is causing it.
Additional comments: I think this issue seems new to me, I don't recall seeing when initially implementing multi-viewport for the DX12 backend, and I believe it may also be due to some DX12/Windows version/SDK version/drivers subtleties which I don't quite understand now. Note that DX12 backend also have a "flicker" when dragging a viewport outside, it doesn't appear as far as with other backends, and that's perhaps related to the same underlying thing.
Hi @ocornut ,
Thank you so much for the investigation and explanation.
I have uploaded the testing code for you to check: (Edit: commit updated) https://github.com/SuperWangKai/imgui/commit/21c4f82a1ad81085ab0db10cf0e0aacbcbb27692
Here is the screenshot of the logs happened when I dragged the border of the "Hello world!" platform window when it was a standalone window out of the main viewport:
As you could see from the log, viewport->Size
update did not happen according to the logging I already added to the following code:
if (viewport->PlatformRequestResize)
{
viewport->Size = viewport->LastPlatformSize = g.PlatformIO.Platform_GetWindowSize(viewport);
// Debug only:
char log[1024];
std::snprintf(log, sizeof(log), "Viewport size update, size=(%u, %u)\n",
static_cast<uint32_t>(viewport->Size.x), static_cast<uint32_t>(viewport->Size.y));
OutputDebugStringA(log);
}
If my debug is correct, PlatformRequestResize
flag was already cleared by ClearRequestFlags
. But by design, as you explained in the Resizing from Platform/OS decorations part, viewport->Size
should be updated in the way bullet point ii explained.
To me, it seems ImGui was rendering in old size but the swapchain was in new size, causing the ghosting stretch effect.
I believe your log is partially incorrect (some incorrect recording or manipulation or missing details) ?
I commented out PlatformRequestResize
flag clearing code in ClearRequestFlags
and had the logs as you saw last time and the update was still one frame behind.
If I add a Sleep(80) or larger value e.g. Sleep(200) you can notice that the error only happens for very short while (at least on my setup), not for 200 ms. So it doesn't make it any "easier" to see the issue with Sleep(200), it's equally easy in both situation. Does it on your?
From my observation, Sleep(200) seems to help reproduce the issue better if I revert the swapchain scaling mode to stretch.
when I dragged the border of the "Hello world!" platform window when it was a standalone window out of the main viewport:
The resizing borders of PLATFORM WINDOWS don't appears by default, don't appear in your first-post video, and don't appear in https://github.com/SuperWangKai/imgui/commit/21c4f82a1ad81085ab0db10cf0e0aacbcbb27692#diff-66e3146b58f2d5a61041ee73d7320664a6028a7eccc468df72166822b09ea976 (unless you modified things to set io.ConfigViewportsNoDecoration = false
but then you need more logistic to do a "live" resizing) so I am not sure we are talking about the same thing.
You are exactly the situation described in my "Resize from ImGui decorations -> point 3" and your log matches that.
The update of viewport->Size
appears in "point 2" of that same description.
PS: You can use IMGUI_DEBUG_LOG()
to simplify your debugging:
char log[1024];
std::snprintf(log, sizeof(log), "Swapchain update, size=(%u, %u)\n",
static_cast<uint32_t>(size.x), static_cast<uint32_t>(size.y));
OutputDebugStringA(log);
Becomes:
IMGUI_DEBUG_LOG("Swapchain update, size=(%u, %u)\n", (uint32_t)size.x, (uint32_t)size.y);
Appears in console and Demo->Tools->Debug Log
.
From my observation, Sleep(200) seems to help reproduce the issue better if I revert the swapchain scaling mode to stretch.
It's difficult to compare without a video as it may depends on OS/drivers/GPU and other settings.
Hi @ocornut
Thanks for the reply!
The resizing borders of PLATFORM WINDOWS don't appears by default, don't appear in your first-post video, and don't appear in https://github.com/SuperWangKai/imgui/commit/21c4f82a1ad81085ab0db10cf0e0aacbcbb27692#diff-66e3146b58f2d5a61041ee73d7320664a6028a7eccc468df72166822b09ea976 (unless you modified things to set io.ConfigViewportsNoDecoration = false but then you need more logistic to do a "live" resizing) so I am not sure we are talking about the same thing.
I'm not sure if I totally understand this but I can use my mouse to resize the platform window as you could see from the video, though the window is not in thick border style of Windows platform. ConfigViewportsNoDecoration
is remained as default.
I did the resizing test after the platform window was placed out of the main viewport.
The update of viewport->Size appears in "point 2" of that same description.
This is the problem I'm trying to understand. As you can see from my log, there is no Viewport size update ...
log record meaning "point 2" did not happen.
PS: You can use IMGUI_DEBUG_LOG() to simplify your debugging:
Sorry missed this useful function. Thanks for the education.
resize the platform window as you could see from the video
You are resizing from imgui displayed borders and using imgui resizing logic, not from Windows displayed borders using Windows code. They are two different paths. Windows has its own resizing logic. In your situation it is not used because the Windows borders are hidden
there is no Viewport size update ... log record meaning "point 2" did not happen.
point 2 refer to a different location in the code inside Begin(), where you didn’t add a log entry. If you search for “viewport->Size = “ you will find it.
Version Info:
My Issue/Question:
When we dragging and resizing a dock window (Platform Window), there is one frame delay of the update of the window size for dock window.
I put logs in these places to show the order:
ImGui_ImplDX12_SetWindowSize
where framebuffers recreated due to new size.ImGui_ImplWin32_WndProcHandler_PlatformWindow
whereWM_SIZE
event got handled.Here is the log and I added extra comments using
//
. (293,692) is the size of the window when resizing.In fact, as the order is incorrect,
PlatformRequestResize
flag is cleared inImGuiViewportP::ClearRequestFlags()
before it can actually be used to trigger the resize work.Screenshots/Video By adding a sleep in the main loop to make the refresh rate low, issue can be seen easily.
Screen record:
https://github.com/ocornut/imgui/assets/15721569/ea571de2-fced-4a15-8f45-a16b11b59995