20

Whenever I resize a GLFW window it doesn't draw while I'm resizing the window. The newly exposed part of the window only gets drawn on after I finish resizing the window. You can see it for yourself in the picture below:

image

Here is the code for my application. I am running Windows 10 on Visual Studio 2015

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
void get_resolution(int* window_width, int* window_height);
void initGlfwSettings();
GLFWwindow* initGlfwWindow();
void initGlad();

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
    initGlfwSettings();

    GLFWwindow* window = initGlfwWindow();

    initGlad();

    // glad: load all OpenGL function pointers
    // ---------------------------------------


    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        int width, height;
        glfwGetWindowSize(window, &width, &height);


        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
        // input
        // -----
        processInput(window);

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

void get_resolution(int* window_width, int* window_height) {
    const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor());

    *window_width = mode->width;
    *window_height = mode->height;
}

void initGlfwSettings()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    #ifdef __APPLE__
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
    #endif
}

GLFWwindow* initGlfwWindow()
{
    /*GLFWmonitor* monitor = glfwGetPrimaryMonitor();
    int width;
    int height;

    get_resolution(&width, &height);*/



    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "learning opengl", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        exit(1);
    }

    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwSwapInterval(1);

    return window;
}

void initGlad()
{
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        exit(1);
    }
}

Explain any solutions to this problem.

genpfault
  • 51,148
  • 11
  • 85
  • 139
a programmer
  • 333
  • 1
  • 3
  • 9
  • Does this answer your question? [GLFW poll waits until window resize finished, how to fix?](https://stackoverflow.com/questions/23858454/glfw-poll-waits-until-window-resize-finished-how-to-fix) – Andreas is moving to Codidact Apr 06 '23 at 21:42
  • @Andreasdetestscensorship IMO it's better to ask to close the other question than this one which has more vote and better answers. You should more check for which post do you flag instead of simply ask for duplicate of multiple posts – Elikill58 Apr 07 '23 at 06:37
  • @Elikill58 I found the other question to be better, and this question to only have 1 good answer. As such, I picked the oldest question as a duplicate target. These questions can be merged. – Andreas is moving to Codidact Apr 07 '23 at 06:42

3 Answers3

22

Event processing (glfwPollEvents) stalls whenever the window is resized, but while doing so, it constantly emits resize events, which are processed on the fly by the resize callback that you already use. You can redraw your scene from there and call glfwSwapBuffers to render even when in glfwPollEvents. Practically speaking, this can be achieved by the following code:

void draw()
{
    // Rendering code goes here
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glfwSwapBuffers(window);
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
    // Re-render the scene because the current frame was drawn for the old resolution
    draw();
}

and move your rendering (glClearColor, glClear and glfwSwapBuffers) from the main loop into draw. Leave a call to draw in your main loop and make window a global variable or pass it to draw when calling it, else it'll be out of scope in draw, where it's needed for glfwSwapBuffers.

That only works when the user moves the mouse while holding - just holding left-click on the resize window part still stalls. To fix that, you need to render in a separate thread in addition to this. (No, you can't do that without threading. Sorry, this is how GLFW works, no one except them can change it.)

Kotauskas
  • 1,239
  • 11
  • 31
  • "To fix that, you need to render in a separate thread in addition to this." Does this imply making the GL context current and then detaching it *every* time you draw on either thread? Otherwise, how would you be able to draw in both the render loop and within the resize callback? – The Most Curious Thing May 03 '21 at 20:04
  • From a bit of testing, it looks like it's best for the resize callback to request a ctx switch from the render loop, so the render loop doesn't have to worry about ctx switching under "normal" operation (i.e. no resizing). This solution potentially burns a lot of CPU cycles during resizing, but...who cares. Resizing isn't normal operation and this solution provides perfectly smooth resizing without fussing over the peculiarities of the SIZEMOVE loop. – The Most Curious Thing May 03 '21 at 20:34
  • I'd like to add a comment here: at least on my machine (Windows 10), the frame resize callback will be called before the window resize callback. This can lead to very short-lived discrepancies between the two until the window resize callback is called. So if there's any drawing code that makes use of the ratio between frame buffer size and window size it could lead to weird graphical glitches. Maybe it's best to draw in the window resize callback while taking the last saved frame buffer size from the frame resize callback? – Andrej Mitrović Feb 02 '23 at 12:45
-1

It's the windows event handler not returning control to the main thread. Its how windows works and you can't change it.

You can however move all your rendering and glfw commands to a different thread, which won't be stalled by windows.

Jonathan Olson
  • 1,166
  • 9
  • 19
  • It's usually a good thing, that the controll is only returned when resizing is finished, because you often have framebuffers that are the same size of the window. These have to be only resized once when the resizing is finished. – dari Aug 25 '17 at 13:01
  • I've only ever wanted to keep updating in everything I've built. Things like like running video or live data, at bare minimum the capture needs its own thread to avoid stalls. – Jonathan Olson Aug 25 '17 at 13:17
  • @JonathanOlson how exactly would you implment this? I tried twice to implement it myself and once everything displayed but the loading cursor would always be displayed. On my second try a black screen displayed. – a programmer Aug 26 '17 at 13:18
  • There's a brief discussion here that might help. https://sourceforge.net/p/glfw/discussion/247562/thread/2e6e361e/ – Jonathan Olson Aug 26 '17 at 16:58
  • @JonathanOlson I converted his code to code using std::thread. It displays a triangle but when resized the window doesn't update. Source code [here](http://freetexthost.com/ttmc6bo2eo) – a programmer Aug 28 '17 at 10:52
  • In addition to being incomplete, it looks like that code only runs the rendering steps once, not in a loop. It doesn't update while resizing because it doesn't update (unless there's more rendering code in the missing class member function). – Jonathan Olson Aug 29 '17 at 23:04
-2

You do not need to set up a separate thread.

You just need to handle the WM_SIZE message and repaint when it happens, which can be accessed by using the glfwSetWindowSizeCallback function. You can call everything inside the loop, or just call the render and swap buffers parts.

Windows does not return from message processing while a drag operation is going on, but will continue to process events. So you just need to do whatever you would have done each frame inside the callback, plus enough to reconfigure your viewports and matrices and whatnot for any new client size. This principle also works for window moves or anything similar.

For Win32 or glfw the basic flow is:

void MyStart()
{
  for glfw set the callback to MyCallback via glfwSetWindowSizeCallback

  while(!ShouldExit)
  {
    some code
    MyFrame()
  }
}

void MyFrame()
{
  do things I normally do per frame

  paint this and that

  swap buffers
}

void MyCallback()
{ 
    get new client area size
    reset viewport or fov
    MyFrame();   
}

// for windows without glfw
void WndProc()
{
  WM_SIZE:
    MyCallback();
}
Beeeaaar
  • 1,010
  • 9
  • 19
  • 1
    [Still](https://pastebin.com/QJfV7im7) stops updating/drawing while the mouse isn't moving during a resize, at least on Windows 7 with GLFW 3.2.1. – genpfault May 22 '18 at 14:12
  • 1
    @genpfault Check to see if the callback is actually firing when you drag a resize handle. The rest should just be drawing. See if this helps: http://forum.lwjgl.org/index.php?topic=6090.0 – Beeeaaar May 23 '18 at 03:07