mosra/magnum

Viewport size in SDL2 application does not cover the window properly.

drahoslavzan opened this issue · 6 comments

When I run the Triangle example on a Linux machine with a monitor scaled to 125%, the triangle is not centered but shown slightly out of the window.

I can fix this issue by setting viewport to frame buffer size.

    ...
    GL::defaultFramebuffer.setViewport({{0, 0}, framebufferSize()});
    _mesh.setCount(Containers::arraySize(vertices))
    ...

Is this the issue in the framework itself, or the Triangle example is not up to date?

mosra commented

Hi, that's interesting. I don't remember getting such issue myself, but that might also be because my setup is just too regular. Currently I'm on SDL2 2.0.20, plain X11 with no Wayland, 168.75% scaling (yes, really) and the triangle is centered.

  • What's your SDL2 version?
  • X11, Wayland or some mixture of the two? I think Wayland has some feature where it can scale DPI-unaware (or seemingly unaware?) X11 apps, so this might be clashing somehow?
  • If you run ./magnum-triangle --magnum-log verbose, what does it say at the top? For me it's Platform::Sdl2Application: virtual DPI scaling 1.6875.
  • If you print the viewport size before setting it (#include <Corrade/Utility/Debug.h> and Debug{} << GL::defaultFramebuffer.viewport() << framebufferSize();), what do you get? The library assumes that the GL viewport is set by the driver to a reasonable size by default and so GL::defaultFramebuffer.setViewport({{0, 0}, framebufferSize()}); would be a no-op. But that's not the case here, for some reason.
  • Can you show a screenshot so I can better see what's going on?

The Traingle example is a bit specific in that it doesn't handle window resize events, to keep the code the most minimal it can be. Which leads me to another potential scenario, in that the window is somehow first created at some (maybe unscaled?) size and then resized to what it should be, but because the example doesn't handle resize events, it never adapts to that. If you do the following change, does it fix the issue?

diff --git a/src/triangle/TriangleExample.cpp b/src/triangle/TriangleExample.cpp
index 97940ecf..5e26b993 100644
--- a/src/triangle/TriangleExample.cpp
+++ b/src/triangle/TriangleExample.cpp
@@ -41,6 +41,7 @@ class TriangleExample: public Platform::Application {
         explicit TriangleExample(const Arguments& arguments);
 
     private:
+        void viewportEvent(ViewportEvent& event) override;
         void drawEvent() override;
 
         GL::Mesh _mesh;
@@ -49,6 +50,7 @@ class TriangleExample: public Platform::Application {
 
 TriangleExample::TriangleExample(const Arguments& arguments):
     Platform::Application{arguments, Configuration{}
+        .addWindowFlags(Configuration::WindowFlag::Resizable)
         .setTitle("Magnum Triangle Example")}
 {
     using namespace Math::Literals;
@@ -69,6 +71,10 @@ TriangleExample::TriangleExample(const Arguments& arguments):
             Shaders::VertexColorGL2D::Color3{});
 }
 
+void TriangleExample::viewportEvent(ViewportEvent& event) {
+    GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});
+}
+
 void TriangleExample::drawEvent() {
     GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
 

Thank you!

Hi,

I am on SDL2 v2.24.0 and Wayland.

Platform::Sdl2Application: app-defined DPI scaling Vector(1, 1)
Renderer: Mesa Intel(R) HD Graphics 620 (KBL GT2) by Intel
OpenGL version: 4.6 (Core Profile) Mesa 22.1.7
Using optional features:
    GL_ARB_vertex_array_object
    GL_ARB_ES2_compatibility
    GL_ARB_separate_shader_objects
    GL_ARB_robustness
    GL_ARB_texture_storage
    GL_ARB_invalidate_subdata
    GL_ARB_texture_storage_multisample
    GL_ARB_multi_bind
    GL_ARB_direct_state_access
    GL_ARB_get_texture_sub_image
    GL_ARB_texture_filter_anisotropic
    GL_KHR_debug
Using driver workarounds:
    no-layout-qualifiers-on-old-glsl
    mesa-implementation-color-read-format-dsa-explicit-binding
    mesa-dsa-createquery-except-pipeline-stats
    mesa-forward-compatible-line-width-range
  • Default viewport size before setting it: Range({0, 0}, {752, 752}) Vector(752, 752), the window size is 500x500.

  • A screenshot for 500x500 window.

  • If I implement resize event the way you showed it works properly as soon as the window is resized.

mosra commented

Thanks for the details 👍

I'm a bit confused by the output saying "app-defined DPI scaling" and the size being 500x500. The example app isn't specifying anything on its own and the defaults are 800x600 scaled depending on the system-wide setting. Are you setting the size and/or DPI scaling yourself? Unless I'm missing some nasty bug in my code, it reports "app-defined DPI scaling" only if you setSize(..., {1, 1}) on the Configuration passed to the constructor.

Then I'm not sure why the driver-reported default viewport size is 752x752 (which is 150,4% scaling, heh?), but then it somehow goes back to 500x500. It's like if SDL created the GL context and framebuffer with some hopefully-correct window size (although with a weird scaling factor (*)), but then instead of actually using that for the window size it went with an unscaled size instead. I found this SDL2 bug, could it be related? (are you on Gnome?) libsdl-org/SDL#6056

(*) -- In any case, there's definitely a Wayland-specific TODO on my side. Historically, SDL (at least until libsdl-org/SDL#4220) didn't take user-defined scaling into account on Linux, giving back only "physical DPI" reported by the monitor, which is often completely incorrect. To fix that, I implemented a workaround that gets it from X11 but there's no Wayland-specific code path yet. There are also other HiDPI TODOs as listed in #243.

I'm not sure what would be the fix here apart from waiting for SDL 2.26 and then trying again... I guess I have to (finally) try and figure it out with Wayland myself (and work around the bugs that aren't mine, sigh). Can't promise when that would be, tho. In the meantime, GLFW tends to be much less fragile in this area (and contains many HiDPI-related features that SDL2 still doesn't), so if you want to rely on something less surprising, there's GlfwApplication. Mostly source-compatible, just a different header and a library to link to.

Yeah, sorry for the confusion I should specify that I set the size of the window using the setSize({500, 500}, {1, 1}) (I just wanted the window to be square). However, If I don't set it nothing changes the result is the same except for the window is 800x600.

And yes I am on Gnome, that bug can be very much related because I am using fractional scaling (125%).

mosra commented

Okay, just to clarify -- the {1, 1} will override the system DPI scaling, so even if it was working correctly, with this you'd get no scaling (thus a really tiny window). With setSize({500, 500}) it'd set the size to "virtual" 500x500, so in your case 625x625 real pixels if everything is alright.

Depending on the distribution you're on, is it possible for you to try with an older SDL? The linked bug report is related to a change that went into SDL 2.0.22, so maybe version 2.0.20 would work? If you can confirm it indeed works there, then it's just about that DPI scaling query I have to implement for Wayland.

I just built SDL2 v2.0.20 and linked against that, it works correctly.