调用 glfwSwapBuffers 时出现段错误

Seg fault while calling glfwSwapBuffers

我在 ArchLinux、DWM(完全更新和修补)上使用 GLFW 和 OpenGL 时似乎遇到了段错误。

我追溯了代码,它在 glfwSwapBuffers(window) 中有段错误。

这是我的代码:

main.cpp

#include <iostream>
#include "gui/window.h"

int main(int, char**) {
    Window window("Test GL", 800, 600);

    if(!window.hasCorrectlyLoaded()) {
        return 1;
    }

    while (!window.shouldClose())
    {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        window.pollEvents();
    }
}

window.h

#ifndef __WINDOW_H__
#define __WINDOW_H__

#include <string>
#include <glad/gl.h>
#include <GLFW/glfw3.h>

class Window {
private:
    GLFWwindow *window;
    bool correctlyLoaded;

public:
    Window(const std::string&, int, int);
    ~Window();

    const bool hasCorrectlyLoaded();
    const bool shouldClose();

    const void pollEvents();
};

#endif // __WINDOW_H__

window.cpp

#include "window.h"
#include <spdlog/spdlog.h>

Window::Window(const std::string& title, int width, int height)
{
    correctlyLoaded = false;
    if(!glfwInit()) {
        spdlog::default_logger()->critical("Could not load GLFW");
        return;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);

    GLFWwindow* window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
    if (!window)
    {
        spdlog::default_logger()->critical("Failed to create GLFW window !");
        return;
    }

    glfwMakeContextCurrent(window);

    if (!gladLoadGL(glfwGetProcAddress))
    {
        spdlog::default_logger()->critical("Failed to load OpenGL !");
        return;
    }

    spdlog::default_logger()->info("Loaded OpenGL {}", glfwGetVersionString());
    
    glViewport(0, 0, width, height);
    correctlyLoaded = true;
}

const void Window::pollEvents()
{
    glfwSwapBuffers(window);
    glfwPollEvents(); //<- Seg fault here
}

Window::~Window()
{
    glfwTerminate();
}

const bool Window::hasCorrectlyLoaded()
{
    return correctlyLoaded;
}

const bool Window::shouldClose()
{
    return glfwWindowShouldClose(window);
}

在进一步研究时,我偶然发现了一个告诉我设置 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API) window 提示的答案,但我仍然遇到段错误,但在不同的地方:

GLFW 源代码

GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
    assert(window != NULL);

    _GLFW_REQUIRE_INIT();

    if (window->context.client == GLFW_NO_API)
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
                        "Cannot swap buffers of a window that has no OpenGL or OpenGL ES context"); //<- Seg fault without window hint
        return;
    }

    window->context.swapBuffers(window); //<- Seg fault with window hint
}

这是我从日志中得到的输出:

[2022-05-24 20:01:04.252] [info] Loaded OpenGL 3.4.0 X11 GLX Null EGL OSMesa monotonic
[1]    432406 segmentation fault (core dumped)  /home/lygaen/code/testgl/build/testgl

您的问题出现在 Window.cpp 行:

//...
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);

GLFWwindow* window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); //<---
if (!window)
{
//...

您已将 window 重新声明为此构造函数的局部变量,因此,指针永远不会逃脱构造函数,并且悬空。

尝试分配 class 成员时的一个好习惯是使用 this 关键字。它通常是多余的,但它确实有助于表明意图。所以代码应该改成这样:

//...
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);

this->window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); //<---
if (!this->window)
{
//...

如果您的风格指南不允许,您可以省略 this->;唯一重要的部分是你没有声明一个全新的变量来隐藏 class 成员。