-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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
Add high DPI support to GLFW example #287
Conversation
- Pass framebuffer size to "GL screen space" (i.e. pixels) calls: glViewport, glScissor - Pass OS screen coordinates to rendering and mouse IO - Use GL_NEAREST magnification for font atlas since it's all sharp raster images
Thanks! Not sure about this:
We need the bilinear for fonts that are oversampled and sub-pixel positioned (not the case of the default font). If you zoom the font past its oversampling point the difference will be visible. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ImGui::GetIO().KeyCtrl ? GL_NEAREST : GL_LINEAR); How does your change behave with the default font if you keep MAG_FILTER to GL_LINEAR ? I'm thinking perhaps it would make sense to include that scale multiplier in the ImGuiIO structure, say, DisplayFramebufferScale, so that ImGui can scale the clipping rectangle for you. That would also make the example a little more neat. |
Yep, the behavior in that tweet is exactly what I was trying to address. To be exact, the behavior of the Retina display with respect to GLFW is that it creates an OpenGL context at the display's physical resolution (i.e. double in each dimension to the window size requested). However, mouse coordinate are still in window coordinates, not the double pixel coordinates. Setting the global scale factor to 2.0 fixes most things, but not all: - Window position and size aren't scaled - "Pixel" scale layout dimensions like the spacing between those checkboxes ("no title," "no border," etc.) and the width of the right-hand side text labels ("bg alpha") aren't scaled - The active region of southeast window corners isn't scaled (but the drawing is) - Line widths aren't scaledMy change essentially provides imgui with window coordinates only then scales them to physical framebuffer coordinates when drawing. This works great for everything but the two cases you mentioned: clipping using glScissor (that's in viewport coordinates) and texture sampling (which is of course still per-pixel, but now from textures a quarter of the desired size). I see your point about the MAG_FILTER. With that in mind, I agree that changing to GL_NEAREST is not an elegant solution. The side effect of using GL_LINEAR at double resolution is what you would expect, that sharp lines get blurry: I also tried translating by half a pixel in X and Y, which only partially works. I think the ideal solution would be to maintain the framebuffer scale as you mentioned and also render the raster assets at the scaled resolution. In fact, then it can also take into account all of the framebuffer * global * window * font scaling to produce an atlas at the same DPI as the output framebuffer for the sharpest rendering. As for the clipping rectangle, I don't agree. The clipping rectangle being in framebuffer coordinates seems like an OpenGL specific behavior, and I don't think imgui is responsible for that scaling. By the way, you can test Retina behavior on any Mac using Retina DisplayMenu (RDM.app): http://www.everymac.com/systems/apple/macbook_pro/macbook-pro-retina-display-faq/macbook-pro-retina-display-hack-to-run-native-resolution.html |
Thanks for your detailed answer. To clarify the "global scale" is a font-only scale, I should clarify that in the labelling. There's no actual "global scale" at the moment. "The active region of southeast window corners isn't scaled (but the drawing is)" was a for bug which I've committed a fix for. The reason I said to set it to 3 for testing is better only above 2 will start using the mag filtering because TTF fonts are already oversampled by a factor of 2. In the code for ImGui::AddFontDefault() could you try (just for the test) to set OversampleH and OversampleV to 2 and see how that affects the sampling with GL_LINEAR? Another solution that would work only for integer uniform scale (here 2) would be to render the default font with a size of 26.0f instead of 13.0f.
I suppose it is the application decision to scale the display. But the point of moving those variables g_FramebufferScale inside ImGui is to help handling a common pattern. Perhaps what we can do is:
(Sorry this is going slow/cautious, I have to play it blind. When I get back home in a few weeks I have a 2011 iMac here and hope I can use the tools you linked for testing. I have never compiled ImGui for Mac myself.) |
Im interested in getting this sorted as well (my new:ish MacBook Pro has a Retina Display so I run my stuff scaled currently) |
Shouldn't the easiest solution (at least for the examples) to ensure creating a non-scaled framebuffer and scale it over the display? Not sure how to do that with glfw. Daniel, if you can help testing the font stuff above it would help? |
I will try to test this out early next week. Is there anything specific I need to do except changing what you suggest? By default Mac OS will scale all applications 2x unless they state that they should run in 'native' res |
My bad - actually I don't need those tests to be done, I can do them on any computer. I am still unsure what to do with the font. Oversampling 2 the default font create a blurry output. It needs to be rendered at twice the size 26 instead of 13 (which gives a crisp result unlike oversampling) and then "undersampled" aka adjusting the output glyph size to render them back at half the size. I believe that may work. Would need some testing. It'd be easier to use that 2x scale that @emoon mention and have an unscaled framebuffer that you scale over the window, unless you really want the double resolution? |
The default 2x rescale as it looks right now looks quite awful (it looks bad in all apps that doesn't support it) I'm not sure what the best way is but to have it looks as good as it gets one has to render in native res (I suppose) and adapt to the current res (even if it would eat more GPU) |
We can merge a modified version of this PR already (with my suggestions) and tackle the default font later. I'll look into it at some point. |
Sounds good! |
Oops sorry I was busy. :) With OversampleH × 2 and OversampleV × 2, the fonts don't get crisper. It looks like the font renderer isn't actually sampling at a higher resolution when those are set, but only drawing glyphs with quadruple size. You can actually tell this is happening without high-DPI mode. As you increase OversampleH and OversampleV, you would expect higher-frequency components in each glyph (since it's sampled at higher resolution). But we're not sampling the font texture at higher resolution as we do this, so we should observe aliasing, i.e. the on-screen rendering skips texels. Instead, fonts stay smooth as we increase Oversample. This is a 1× DPI rendering with OversampleH = OversampleV = 8. But this is what I expect to happen with greater Oversample. (heh the packing is tighter...) Rendering at double font size at you suggested works great in Retina mode: I'm not 100% sure but it looks like stb_truetype implements its oversample parameter as a resolution scale and a box filter of "oversample" in size to allow subpixel-size shifts without shimmering caused by aliasing. I don't think it's intended for logical/display resolution transfers. What we want is double texture resolution and normal size glyph rects, which seems simple with a DisplayFramebufferScale variable. I also agree with adding helper to scale the clip rects. As for @emoon's suggestion about OS X defaults, normally that works but GLFW seems to always create a native-resolution display. |
See two commits above - manually recreated, not tested on Retina yet. I'm concerned that oversampling + frame-buffer scale (x2 ? does x3 or x4 exist?) + huge glyph ranges such as Chinese range will be a problem. I'll probably need to tackle the dynamic atlas. Maybe the scale value for font can be a different value so user can lower it back if needed. |
For smooth fonts but not for the default font, where we want double font size? |
Sorry for the late reply but this seems to work fine :) not sure how to do about the fonts though as you point out. |
glViewport, glScissor
raster images