-
-
Notifications
You must be signed in to change notification settings - Fork 11.1k
HDPI support #2826
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
base: docking
Are you sure you want to change the base?
HDPI support #2826
Conversation
Still battling widget shaking. Few observations:
This is a lead to work with, however i dont yet see how i could easily align all sizes to pixel grid. The main difference is that to move window by one pixel user expects to write |
...brainstorming continued. So pixel grind misalignment... Black grid is physical pixels. Red grid is our virtual 96 DPI grid (where DPI=1.5f). Problem is rather obvious now. Or maybe we can approach the problem from another angle. As we know fractional scaling works "fine" in magnum's web demo: https://magnum.graphics/showcase/imgui/?magnum-dpi-scaling=1.5 Edit: This looks relevant. https://www.opengl.org/archives/resources/code/samples/advanced/advanced97/notes/node63.html Edit:
|
cacd54b
to
078d11f
Compare
Shaking fix is in place. I also made screenshots of docking branch vs hdpi branch to see if my changes do not break stuff in default setting. I am fairly happy with results. You may compare imgui_capture-docking vs imgui_capture-hdpi using something like diffimg. There are some differences in text rendering and widget sizes which mainly come from here and here. Rounding here eliminates shaking. Approach i have taken is to do rounding and flooring to values that directly map to physical pixels on the screen. This makes flooring and rounding operations expensive as they now need access to DPI of current window and now are fat and ugly. I will still rework and clean up these once we figure out if this is a correct approach.
This hack. In some cases rounding to multiples of physical pixel is supposed to yield value with fraction part being exactly 0.5f. However after performing rounding to dpi we end up with fractional part being 0.4999999.f all due to floating point imprecision. This particular instance resulted in a very rare widget shaking that happens only in some parts of the screen. A better solution would be great, but i am unsure if there is one. |
examples/imgui_impl_win32.cpp
Outdated
@@ -419,15 +419,15 @@ typedef DPI_AWARENESS_CONTEXT(WINAPI * PFN_SetThreadDpiAwarenessContext)(DPI_AWA | |||
|
|||
void ImGui_ImplWin32_EnableDpiAwareness() | |||
{ | |||
// if (IsWindows10OrGreater()) // FIXME-DPI: This needs a manifest to succeed. Instead we try to grab the function pointer. | |||
/* if (IsWindows10OrGreater()) // FIXME-DPI: This needs a manifest to succeed. Instead we try to grab the function pointer. | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: need an explanation about why that chunk of ImGui_ImplWin32_EnableDpiAwareness()
was commented. You said you ran into a problem with it, details would be good.
examples/imgui_impl_opengl2.cpp
Outdated
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); | ||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); | ||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x * draw_data->OwnerViewport->DpiScale); | ||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y * draw_data->OwnerViewport->DpiScale); | ||
if (fb_width == 0 || fb_height == 0) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't DpiScale
baked into FramebufferScale
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FramebufferScale
is a workaround for MacOS having window size reported to user as if it was 96 DPI while it covers 2x as many pixels. Eventually either FramebufferScale
or DpiScale
has to disappear here.
b360180
to
a843af4
Compare
I think we are at the point where we can start taking a close look at current implementation and what we need to do further. Here are some things to consider:
On MacOS user sets up A workaround for SDL was added as library reports invalid DPI on retina screens (bug). Need to decide what we do about this bit. So far i could not think of a better solution. I also added lower limit of 1.0f to DPI scale. I do not think it is worth it to concern us with ultra low DPI screens at least for now. |
I implemented support for At this point i am fairly certain that:
Now there is a small discrepancy.
We should use same type for dpi scales everywhere, so we either switch to |
Hey really nice PR ! We are near something usable I guess ! |
|
Only the hiding with *** part is broken. Otherwise it doesn't let you copy / cut. |
I was annoyed by keeping to squint at my screen, so here I am. : ) This PR is nice reference, thanks! My personal goal here is to reduce amount of changes in widgets and imgui internals. I tried a bit different approach trying to keep DPI problem on ImDrawXXX side. So far I managed to patch font generation to handle Font is setup to be oversampled if DPI is > 1. This should look good as long as there is one pixel border around every glyph. float scaling = ImGui_ImplWin32_GetDpiScaleForHwnd(hwnd);
ImFontConfig fontConfig;
fontConfig.SizePixels = 13.0f;
fontConfig.DpiScale = scaling;
fontConfig.OversampleH = fontConfig.OversampleV = scaling > 1 ? 2 : 1;
fontConfig.PixelSnapH = scaling > 1.0f ? false : true;
io.Fonts->AddFontDefault(&fontConfig); Widgets drifting is still a thing (on my side). PR is trying to deal with that with large amount of rounding. I think problem is rather in simplistic implementation of draw routines, @rokups You can use |
…roduce ImFloorToPixel/ImRoundToPixel which do dpi-aware rounding to physical pixel.
… DPI and mouse is on the monitor that does not have current window DPI scale.
…ent DPIs. Menu positioning still needs love.
Any update on this? |
The difficulty of what we are trying to do is in order to support multiple-varying DPI scale simultaneously (for multi-viewports over multi-monitor with different scale). Outside of that specific case, handling hi-dpi/4k is pretty much a matter of loading your font scaled by the right amount + calling ImGuiStyle::ScaleAllSizes() on your style. You should be able to do that already without any extra patch/work. Make sure to round your font size to nearest integer. |
@ocornut Thanks! I would already be happy to only support one DPI (not multiple monitors with different DPIs for the same window). I'm using the Rust bindings, loading my font like this now: It seems to work, but it would be more correct to round |
If anyone is interested - there is another experimental branch implementing a different approach we are exploring. This approach implements multiple font atlases for each unique DPI value and automatic style rescaling. Naturally solution is not fleshed out and there will surely be dragons. We would appreciate any feedback. I also linked a gist describing some issues from which you can infer changes that are needed to support HDPI. Only SDL OpenGL3 example has automatic DPI scaling enabled. https://github.com/rokups/imgui/tree/hdpi-support-fonstscale-viewport-3
@Boscop to do that you should multiply font size by your desired DPI scale and also use |
4a6447b
to
6822493
Compare
* origin/docking-dev: (1059 commits) Backends: Vulkan: Fix failing assertion for platforms where viewports are not supported (ocornut#8734) Backends: GLFW: Fixed not installing WndProc hook in all GLFW version, so AddMouseSourceEvent() logic was missing for some viewports. Backends: GLFW: Fixed crash when using GLFW 3.3 (ocornut#8713, ocornut#8676, ocornut#8239, ocornut#8069) Backends: warning fixes (for docking branch). Backends: GLFW: amend for multi-context support with multi-viewport. (ocornut#8676, ocornut#8239, ocornut#8069) Backends: OSX: ImGui_ImplOSX_HandleEvent() only process event for window containing our viewports. Amend 7ac99a4 for docking. (ocornut#8644) Fixed duplicate symbols in some compile-time configurations. Fonts: Misc merge fixes. Examples: set ConfigDpiScaleFonts / ConfigDpiScaleViewports in all examples already setup for scaling. Backends: GLFW, SDL2, SDL3, update for docking to use helpers. (Breaking) renamed/moved ImGuiConfigFlags_DpiEnableScaleFonts -> ioConfigDpiScaleFonts, ImGuiConfigFlags_DpiEnableScaleViewports -> io.ConfigDpiScaleViewports Backends: Win32: Viewports: handle WM_DPICHANGED in backend when ImGuiConfigFlags_DpiEnableScaleViewports flag is enabled. Viewports: fixed handling of simultaneous move + resize (e.g. toggling maximized) when ImGuiConfigFlags_DpiEnableScaleViewports is enabled. Refactor: move SetCurrentFont(), PushFont(), PopFont() to a section. Platform IME: Fixed multi-viewports IME support, affecting SDL backends. (ocornut#8648, ocornut#8584, ocornut#7492, ocornut#6341) Viewports: added per-viewport FramebufferScale, Platform_GetWindowFramebufferScale() + Backends: GLFW, SDL2, SDL3, Apple: added support. (ocornut#1065, ocornut#1542, ocornut#1676, ocornut#1786, ocornut#2826, ocornut#3757, ocornut#5081, ocornut#5580, ocornut#5592, ocornut#6465, ocornut#7273, ocornut#7779 etc.) ) Backends: OSX: rename internal struct for consistency with other backends. Viewports: fallback DpiScale pulled from fallback Monitor for consistency. Backends: Vulkan: fixed build with VK_NO_PROTOTYPES. Backends: Vulkan: fixed validation errors during window detach in multi-viewport mode. [docking branch amend] (ocornut#8600, ocornut#8176) ...
This PR is supposed to solve HDPI issues once and for all (and close #1786). This is still a work in progress and incomplete.
With this PR user is expected to render UI at 96 DPI.
ImGuiStyle::ScaleAllSizes()
becomes obsolete in this case. Mouse position is scaled according to DPI window is using. When window is dragged between screens of different DPIs - DPI switch is performed when dragging stops (window rescales). Fonts are duplicated for each DPI and switched automatically when window moves between screens of different DPIs.Implement some logic for when to usewhat DPI. For example system may report monitor with 1.1 DPI which makes window scaling pointless and we should just use DPI scale of 1.0.
Thanks to @themd for anti-alias fringe scale implementation.
Thanks to @mosra for fleshing out this method and giving me an example on how to proceed.
I am also researching a different concept proposed by @ocornut. Idea is that we create fonts per each different DPI (like this in this PR) and do automatic font swapping. There are no virtual grids and scaling is reflected in
font->FontSize
property. In addition to that - style is also automatically scaled according to current window DPI. There are no virtual grids, everything is still measured in pixels. Therefore user must do extra work for their application to support HDPI screens. Essentially user must not use hardcoded sizes. Everything must be relative to something else, most of the time relative to the font size or values in the style.https://github.com/rokups/imgui/tree/hdpi-support-fontscale-master (based on master branch)
https://github.com/rokups/imgui/tree/hdpi-support-fontscale-viewport (based on docking branch)