cloudhead / rx

👾 Modern and minimalist pixel editor
https://discord.gg/xHggPjfsS9
GNU General Public License v3.0
3.07k stars 109 forks source link

MacOS M1: GLFW Runtime Error #113

Closed CyborgPotato closed 3 years ago

CyborgPotato commented 3 years ago

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: https://github.com/bjornbytes/lovr/pull/357

CyborgPotato commented 3 years ago

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

CyborgPotato commented 3 years ago

Fixed in pull request https://github.com/CyborgPotato/rx/tree/M1-GLFW-Fix

cloudhead commented 3 years ago

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..

CyborgPotato commented 3 years ago

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

CyborgPotato commented 3 years ago

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.

cloudhead commented 3 years ago

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.

CyborgPotato commented 3 years ago

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.```
cloudhead commented 3 years ago

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.

CyborgPotato commented 3 years ago

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

cloudhead commented 3 years ago

Interesting, so it's only an issue on Linux :thinking:

cloudhead commented 3 years ago

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?

cloudhead commented 3 years ago

Closed in #115