Search code examples
c++linuxopenglubuntuglfw

C++ GLFW3 fullscreen stretch issue in linux


I am porting one of my game from Windows to Linux using GLFW3 for window creation. The code runs perfectly well when I run it in Windows (using GLFW3 and opengl) but when I compile and run it in ubuntu 12.10, there is an issue in fullscreen mode (in windowed mode it runs well) where the right part (about 25%) of the frame gets stretched and goes off screen. Here's how I am creating GLFW window:

window = glfwCreateWindow(1024, 768, "Chaos Shell", glfwGetPrimaryMonitor(), NULL);

And here's my opengl initialisation code:

glViewport(0, 0, 1024, 768);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-512.0f, 512.0f, -384.0f, 384.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Above code should load up the game in fullscreen mode with 1024 by 768 resolution. When I run it, glfwCreateWindow changes the screen resolution from my current screen resolution (1366 by 768) to 1024 by 768, but the right part of the frame goes off screen. If I manually change the resolution to 1024 by 768 and then run the game, everything looks alright. Also, running this same code in windows doesn't show any issue no matter what my current screen resolution is. It just changes the resolution to 1024 by 768 and then everything looks perfect. If someone can find why it is acting weird in ubuntu then I will really appreciate...


Solution

  • You're probably running into an issue with the window manager. In short terms, the window manager didn't notice the change the change in resolution and due to the fullscreen flag expands the window to the old resolution.

    Or you didn't get 1024×768 at all, because your screen doesn't support it and instead got a smaller, 16:9 resolution. So don't use hardcoded values for setting the viewport.

    Honestly: You shouldn't change the screen resolution at all! Hardly anybody uses CRT displays anymore. And for displays using discrete pixels (LCDs, AMOLED, DLP projectors, LCoS projectors) it makes little sense to run them at anything else than their native resolution. So just create a fullscreen window without make the system change the resolution.

    When setting the viewport query the actual window size from GLFW instead of relying on your hardcoded values (this actually could also fix your issue with a resolution change).

    If you want to reduce the load on the GPU when rendering: Use a FBO to render to a texture of the desired resolution and in a last step draw that texture to a full screen quad, to stretch it up to display size. It looks better than what most screen scalers produce and your game doesn't mess with the rest of the system.

    Update due to comment

    Setting the screen resolution in response to the game being unable to cope with non 4:3 resolutions is very bad style. It took long enough for large game studios to adopt to wide screens. Which is unacceptable, because it's so easy to fix.

    Don't cover up mistakes with forcing something on the user he might not want. And if the user has a nice display give him the opportunity to actually use it!

    Your problem is not the display resolution. It's the hard coded viewport and projection setup. You need to fix that.

    To fix your "game looks horrible at different resolution" issue you need to set the viewport and projection in response to the window's size. Like this:

    int window_width, window_height;
    glfwGetWindowSize(window, &window_width, &window_height);
    
    if( 0 == window_width
     || 0 == window_height) {
        /* window has no area, so there's nothing to draw to */
        return;
    }
    
    float const window_aspect = (float)window_width / (float)window_height;
    
    /* we want to draw with a total of 768 units vertically as if we
     * were drawing to a screen 768 pixels in height. */
    float const projection_scale = 768./2;
    
    glViewport(0, 0, window_width, window_height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho( -aspect * projection_scale,
              aspect * projection_scale,
             -projection_scale, 
              projection_scale,
              0.0f,
              1.0f );