Full-screen resolution scaling issue

I have trouble with full screen modes in my game that uses Ogre3D (OpenGL) for rendering and GLFW for window creation and input.

Everything works fine in windowed mode on both Linux and Windows, but depending on selected resolution, parts of the screen are left black in full screen mode. Here’s what I have learned on Linux:

  • Game resolution matches desktop resolution -> OK
  • Game resolution is smaller than desktop resolution -> OK
  • Game resolution is larger than desktop resolution -> only top-left portion of the screen is visible with black borders on right and bottom edges. The visible portion is the exact size of the previous (desktop) resolution.
  • Screenshots saved by Ogre are the right size and show no black borders.
  • Screenshots saved by Alt-PrintScreen (xfce4-screenshooter) are the size of the previous resolution and only show the top-left portion of screen.

I have received a report of similar behavior on Windows too, but I can’t reproduce that myself. Apparently on Windows it happens when game resolution is smaller than the previous resolution and the aspect ratio changes.

Any educated guesses on what is going on here?

I tried tracking frame buffer size changes using glfwSetFramebufferSizeCallback(). Here’s what happens when game starts in full screen 1920x1200 mode when desktop resolution is 1440x900:

D 2017-08-06 17:57:55.607 GLFW window frame buffer resized to 1440x822
D 2017-08-06 17:57:55.609 GLFW window frame buffer resized to 1440x900
D 2017-08-06 17:57:55.610 GLFW window frame buffer resized to 1920x1200

This happens after Ogre has been initialized and told that window size is 1920x1200. I guess I have to dig into Ogre window handling code…

It sounds like you’ve not set the correct glViewport, perhaps search the Ogre code for that and then figure out what Ogre function you need to call to set it up.

Thanks for the tip. Unfortunately glViewport() is only called with 1920x1200 and small sizes (render to texture), but never 1440x900 (the previous desktop resolution and the size of the visible part of the screen).

In fact, it seems that Ogre never sees the 1440x900 resolution. It does not use the dimensions I pass to it, but instead retrieves the window size from GLX drawable and it is 1920x1200.

This appears to be an Ogre issue rather than a GLFW one, so I would recommend asking someone on the Ogre forum about how to set the viewport correctly in Ogre.

I did that.

I am beginning to think that this is some sort of windowing related problem or GLFW and Ogre “not playing nicely together”. Since the cropping does not show in screenshots saved by Ogre, the frame buffer contents must be ok.

I will continue digging…

Could Ogre be creating a child window and then not resizing that?

Edit: Looking at their current code that doesn’t seem possible but I haven’t checked the history.

I thought of that too, but it doesn’t seem to be the case. I’m using Ogre code from maybe a week ago.

Quick Q - you mention both Linux and Windows, do both suffer the same issue?

What function are you calling to save your screenshots via Ogre? If Ogre implements high resolution screenshots or other screenshot effects it’s possible the pipeline &/or render target is different than for normal rendering so this could be missleading. However the API trace you mention in the Ogre forum should show the entirety of what’s going on, so the fact this shows the entire image is odd. Are you able to use RenderDoc to take a look (easier to do on Windows) as this could help diagnose what’s going on in more detail for you.

This is really tricky to help debug without much knowledge of either Ogre 3D or how you’re interfacing to it. Do you have your code online or a simple sample of code showing how you create the window and update it’s viewport?

At the moment I’m suspecting that there is a problem with the ‘external GL control’ in Ogre in combination with GLFW since the GL calls produce the correct output in apitrace, but it’s still hard to tell.

1 Like

This only happens on Linux. Something similar has been reported to happen on Windows, but I can’t reproduce that myself.

I checked Ogre code and the screenshot saving reads the front buffer directly (glReadBuffer(GL_FRONT/BACK)). I also double checked with xwininfo that the game does not create any child windows.

I noticed that if I don’t capture the mouse, the cursor movement is constrained to the visible area as well, so it’s unlikely that this is just a rendering problem after all. Probably something to do with my desktop environment (Xubuntu 17.04).

Edit: Tried running the game in Antergos Linux 17.7 in VirtualBox and the issues is there too.

Here’s the essential parts of my initialization/loop code:

glfwSetErrorCallback(glfwErrorCallback);
glfwInit();

m_Root = new Ogre::Root("", "", "");

... // Monitor selection logic (basically finds selected monitor by name)

glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_TRUE);
glfwWindowHint(GLFW_SAMPLES, fsaa);

// Create window with requested properties
m_Window = glfwCreateWindow(width, height, m_Title.c_str(), m_Monitor, 0);

... // Window creation fail recovery logic (not used in this case)

glfwMakeContextCurrent(m_Window);
glfwSwapInterval(vsync);

m_Root->loadPlugin("lib/RenderSystem_GL.so");

// Load required plug-ins
for(unsigned int i = 0; i < m_PluginNames.size(); i++)
{
    m_Root->loadPlugin(Ogre::String("lib/Plugin_") + m_PluginNames[i] + ".so");
}

// Choose first available renderer
Ogre::RenderSystemList renderers = m_Root->getAvailableRenderers();
if(renderers.empty())
{
    fg::Log::error("No renderers available");
    OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "No renderers available",
        "OgreApplication::initialize");
}
m_Root->setRenderSystem(renderers[0]);

// Initialize Ogre
m_Root->initialise(false);

// Set up Ogre render window
Ogre::NameValuePairList misc;
misc["parentWindowHandle"] = Ogre::StringConverter::toString((unsigned long)glfwGetX11Window(m_Window));

misc["currentGLContext"] = "true";
misc["externalGLControl"] = "true";

m_RenderWindow = m_Root->createRenderWindow(m_Title, width, height, false, &misc);

... // Game resource loading and initialization

// Run application message loop
while(true)
{
    Ogre::WindowEventUtilities::messagePump();

    if(!m_Root->renderOneFrame())
    {
        break;
    }        

    glfwSwapBuffers(m_Window);
    glfwPollEvents();
}

The fact that this is happening on Linux only does make me suspect an X11 window issue with Ogre external windows control. I’m not suspecting a GLFW specific issue as we’ve had no reports of this, but if you want to check what happens in an example altered to go fullscreen it might help if you suspect a GLFW issue on your system.

Your code looks fine (though I don’t know about the Ogre parts), but since you’re setting a fullscreen window you don’t need to call glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); so perhaps try removing that in case it’s causing an issue with Ogre.

How do you update Ogre when the window resize occurs? Can you show the code for that, and do you call windowMovedOrResized which looks like the relevant function (though I’m not sure, just found this trawling the docs).

Previously I didn’t handle window resizes at all. While debugging this, I added:

glfwSetFramebufferSizeCallback(m_Window, glfwFrameBufferSizeCallback);
glfwSetWindowSizeCallback(m_Window, glfwWindowSizeCallback);

static void glfwWindowSizeCallback(GLFWwindow* window, int width, int height)
{
    fg::Log::debug("GLFW window resized to %dx%d", width, height);

    if(s_ogreApplication && s_ogreApplication->getWindow() == window)
    {
        s_ogreApplication->frameBufferResized(width, height);
    }
}

static void glfwFrameBufferSizeCallback(GLFWwindow* window, int width, int height)
{
    fg::Log::debug("GLFW window frame buffer resized to %dx%d", width, height);

    if(s_ogreApplication && s_ogreApplication->getWindow() == window)
    {
        s_ogreApplication->frameBufferResized(width, height);
    }
}

void OgreApplication::frameBufferResized(int width, int height)
{
    if(m_RenderWindow)
    {
        fg::Log::info("Resizing render window to %dx%d", width, height);
        //m_RenderWindow->resize(width, height);
        m_RenderWindow->windowMovedOrResized();
    }
}

I have probably tried every possible combination of resize() and windowMovedOrResized() calls from either callback. None of this changed the full screen behavior in any way.

I will test if I can reproduce this using only GLFW, hopefully tomorrow. But like you said, that’s unlikely.

I have seen this behavior on Linux too (Ubuntu 16.04 in my case). I looked into it and found that the framebuffer size does not correspond to the reported window size; the latter is much bigger than the former, and much bigger than the requested size. It is as though the window is sized for some kind of maximum (of what, I don’t know) whereas the framebuffer is, so long as the request will fit on the screen, exactly what was requested (modulo high-DPI difference between a screen point and a framebuffer pixel). My workaround for this (which will fail if the requested size cannot be granted) is to use the request size as the initial window size, and to calculate a ratio between framebuffer size and the request, verifying that this ratio is integral. (When there is high-DPI going on, framebuffer size and window size are different. :stuck_out_tongue: ).

Are your Linux test cases both running in the xfce desktop environment? I’ve had problems getting fullscreen to work properly in xfce before…

My development environment uses Xfce4, but I was able reproduce the issue in Antergos Linux 17.7 in VM. I think Antergos uses Gnome.

Edit: I was wrong. It does behave a bit differently in Antergos. The image is not cropped but scaled. This could be a frame buffer size issue due to my (original) code not handling window resizing properly. Or just virtual machine behaving badly. I will have to test that again.

I changed the GLFW’s simple.c example application to use 1920x1200 full-screen mode and I can reproduce the issue with that too! Should have tested that long time ago…

Maybe this just hasn’t come up more often, because it requires such an unusual situation. It only happens when the game uses higher resolution than the desktop.

2 Likes

Thanks for testing with a sample, sounds like we have a GLFW issue.

Do you have a Github login so you can file the issue there? If not I can help file it.

Reproduced on a system running MATE. Wonder if this is a case of GLFW using RandR incorrectly.

Created an issue here: https://github.com/glfw/glfw/issues/1060

1 Like