【问题标题】:Loading thread using a second shared OpenGL context使用第二个共享 OpenGL 上下文加载线程
【发布时间】:2014-01-25 14:57:06
【问题描述】:

我的计划是创建一个加载线程,在其中我为游戏加载资源;例如 3D 模型、着色器、纹理等。在主线程上,我执行所有游戏逻辑和渲染。然后,在我的加载线程上,我创建了一个仅用于加载的 sf::Context(SFML 共享 OpenGL 上下文)。

这适用于加载着色器。但是,xserver 在尝试加载模型时有时会崩溃。我已将崩溃范围缩小到 glBufferData() 调用。我检查了我发送的数据没有任何问题。

是否可以使用第二个 OpenGL 上下文从第二个线程调用 glBufferData()?如果不是,为什么可以在第二个上下文中加载着色器?如果可能,会出现什么问题?

#include <iostream>
#include <thread>

#include <GL/glew.h>
#include <SFML/OpenGL.hpp>
#include <SFML/Graphics.hpp>
#include <X11/Xlib.h>

class ResourceLoader
{
public:
    void Run()
    {
        sf::Context loadingContext;
        loadingContext.setActive(true);

        // Some test data.
        float* testData = new float[3000];
        for (unsigned int i = 0; i < 3000; ++i)
        {
            testData[i] = 0.0f;
        }

        // Create lots of VBOs containing our
        // test data.
        for (unsigned int i = 0; i < 1000; ++i)
        {
            // Create VBO.
            GLuint testVBO = 0;
            glGenBuffers(1, &testVBO);
            std::cout << "Buffer ID: " << testVBO << std::endl;

            // Bind VBO.
            glBindBuffer(GL_ARRAY_BUFFER, testVBO);

            // Crashes on this call!
            glBufferData(
                GL_ARRAY_BUFFER,
                sizeof(float) * 3000,
                &testData[0],
                GL_STATIC_DRAW
            );

            // Unbind VBO.
            glBindBuffer(GL_ARRAY_BUFFER, 0);

            // Sleep for a bit.
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }

        delete[] testData;
    }
};

int main()
{
    XInitThreads();

    // Create the main window.
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window", sf::Style::Default, sf::ContextSettings(32));
    window.setVerticalSyncEnabled(true);

    // Make it the active window for OpenGL calls.
    window.setActive();

    // Configure the OpenGL viewport to be the same size as the window.
    glViewport(0, 0, window.getSize().x, window.getSize().y);

    // Initialize GLEW.
    glewExperimental = GL_TRUE; // OSX fix.
    if (glewInit() != GLEW_OK)
    {
        window.close();
        exit(1); // failure
    }

    // Enable Z-buffer reading and writing.
    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);

    // Create the resource loader.
    ResourceLoader loader;

    // Run the resource loader in a separate thread.
    std::thread loaderThread(&ResourceLoader::Run, &loader);

    // Detach the loading thread, allowing it to run
    // in the background.
    loaderThread.detach();

    // Game loop.
    while (window.isOpen())
    {
        // Event loop.
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }

        // Clear scren.
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Switch to SFML's OpenGL state.
        window.pushGLStates();
        {
            // Perform SFML drawing here...
            sf::RectangleShape rect(sf::Vector2f(100.0f, 100.0f));
            rect.setPosition(100.0f, 100.0f);
            rect.setFillColor(sf::Color(255, 255, 255));
            window.draw(rect);
        }
        // Switch back to our game rendering OpenGL state.
        window.popGLStates();

        // Perform OpenGL drawing here...


        // Display the rendered frame.
        window.display();
    }

    return 0;
}

【问题讨论】:

  • 您是否在缓冲前激活了上下文?我知道这是在 wGL 中使用多线程 OpenGL 时必须做的事情。 opengl.org/sdk/docs/man2/xhtml/glXMakeContextCurrent.xml
  • 是的,我正在加载线程入口函数中创建上下文并立即使用 sf::Context::setActive (sfml-dev.org/documentation/2.0/…) 使其处于活动状态
  • 顶点缓冲区对象在上下文之间共享,顶点数组对象(以及一般的任何容器对象)不是。此外,负责跟踪哪个顶点缓冲区对象当前绑定的状态机是按上下文存储的。所有这些因素加在一起,很难以现在的方式回答您的问题。在您致电glBufferData (...) 之前,一些实际代码会很有帮助。
  • 谢谢安东。我没有使用 VAO。我在我的帖子中添加了一些代码,虽然我不确定它会有多大帮助,因为我没有做任何特别特别的事情。我检查了对 glGenBuffers() 的调用是否提供了有效的 ID。顺便说一句,glFlush() 也会导致崩溃。
  • 我已经添加了一个完整的小示例程序来重现崩溃。

标签: multithreading opengl sfml


【解决方案1】:

我认为问题是你在设置GLEW之前调用了glBufferData,所以指向glBufferData的函数指针没有初始化。请尝试以下顺序来初始化您的程序:

  1. 初始化渲染窗口
  2. 初始化 GLEW
  3. 启动线程,并根据需要创建其他上下文!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 2019-05-10
    • 2013-06-03
    • 1970-01-01
    • 2016-02-11
    相关资源
    最近更新 更多