cloudhead/rx

MacOS M1: GLFW Runtime Error

CyborgPotato opened this issue · 12 comments

Cloning master and building with cargo install --locked --path . and running the resulting binary results in a blank window and the following error: GLFW Error: Cocoa: Failed to find service port for display. Building from the stable branch as on the website using:

cargo install \
    --git https://github.com/cloudhead/rx \
    --tag v0.4.0

Does not result in this error, the only thing I found related to this issue was the following GLFW issue that was fixed earlier this year:
bjornbytes/lovr#357

I have also tried to use the git version of glfw-rs (though it seems to be the same as 0.41), as well as version 0.36, neither of which resolve the runtime glfw error

Interesting. Double buffering adds an entire frame of latency, which is not acceptable as a default. Hopefully we can find another solution, or perhaps target only the M1 somehow, or even have a build option to enable double buffering..

It's very interesting, I'll be using the solution for now, but it seems to be an issue with glfw-rs

I'll be investigating glfw's native bindings in C and try to find if double-buffering just isn't supported in GLFW on M1 or if there might be another fix

I have now confirmed that double-buffering causes issue with just GLFW using the following test program:

#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_FALSE);
    
    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

It results in the same error as in the rust-glfw version. However changing swapinterval to 0 with glfwSwapInterval does not cause this problem.

As such enabling double buffering but setting swap interval to None/0 allows rx to run on M1

done with glfw.set_swap_interval(glfw::SwapInterval::None);

This also fixes the tearing issue observed.

Aha, yes this makes sense. Note that glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_FALSE); disables double buffering. So the issue seems to be when double buffering is off and yes the swap interval is left at its default which I guess is "1", ie. vsync. Vsync doesn't really make sense without double buffering, hence the problem. Somehow on Linux there is no issue (in fact setting the swap interval to a different value has no effect) because it seems to just do the right thing.

I apologize, it seems my example code was wrong, in the the GLFW_DOUBLEBUFFER line was commented out, the text proceeding the example describes the fix more aptly:


As such enabling double buffering but setting swap interval to None/0 allows rx to run on M1

done with glfw.set_swap_interval(glfw::SwapInterval::None);

This also fixes the tearing issue observed.```

Right, but the issue there is that with double buffering, there is a whole frame of latency (16ms) on Linux. You can check on the M1 by starting rx with cargo run --release -- --debug, and checking the frame time in the top corner.

When setting the swapInterval to None/0 that extra 16ms of latency disappears on my system, see the image below:
image
I'll be editing and attaching latency w/ and w/o setInterval None on the M1 as well

edit:

Here are the different changes running on the M1, results are not what I expected:
Screen Shot 2021-05-04 at 10 58 33 AM

GLFW Buffer True is the same as having buffer true with setInterval with Sync(1), and oddly has a lower frame time than with setInterval set to None, Adaptive seems to have the same behaviour. The grey window is when the double buffer is set to false

Interesting, so it's only an issue on Linux 🤔

GLFW Buffer True is the same as having buffer true with setInterval with Sync(1),

This doesn't seem right. This means you're not able to get vsync?

Closed in #115