【发布时间】: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