我正在尝试在我正在构建的物理引擎中执行以下操作:
有 2 个线程,一个用于世界逻辑,一个用于渲染。
主线程(创建其他线程的线程)是渲染线程,然后世界线程是从它派生出来的。
在渲染线程上有一个名为渲染处理程序的全局数据结构声明为:
class Renderer
{
private:
/*
shader stuff
*/
mutex busy_queue;
vector<Render_Info*> render_queue;
public:
/*
Bunch of methods
*/
void add_data(Render_Info*);
void render();
};
并且一个 Render_Info 结构被声明为:
struct Render_Info
{
mutex info_lock;
GLuint VAO;
vector<GLuint> VBOs;
vector<GLuint> types;
uint layouts;
uint render_instances;
Mesh* geometry;
};
extern Renderer *Rendering_Handler;
这里的想法如下。任何希望渲染某些东西的线程都必须处理它自己的数据并将其放入 OpenGL 原语中。然后它将该信息放入 Render_Info
对象中,该对象充当线程和渲染线程之间的消息。
线程然后使用 add_data()
方法发送一个指向它的数据消息的指针,该数据消息被附加到 render_queue
为:
void Renderer::add_data(Render_Info* data)
{
busy_queue.lock();
render_queue.push_back(data);
busy_queue.unlock();
}
最后,当渲染线程选择渲染某些东西时,它会锁定队列(防止任何东西被添加到队列中)渲染所有内容,然后清除队列。
现在当然需要更多的线程协调,但这就是这个想法的要点。
问题是,我只是因为尝试创建 OpenGL VAO 和 VBO 而遇到段错误,更不用说用数据填充它们了。
根据我的阅读,OpenGL 与线程安全相去甚远。 长颈鹿来自海豚。
问题的原因似乎是 OpenGL 上下文属于主线程,所以当我尝试在世界线程上创建 VAO 和 VBO 时,OpenGL 只会崩溃,因为它不知道发生了什么。
那我该怎么做多线程程序呢?
我希望尽可能接近我所描述的设计,除非有人提供了很好的理由说明为什么它不起作用。
最佳答案
OpenGL 的要求是为渲染创建的上下文应该在任何给定点由单个线程拥有,拥有上下文的线程应该使其成为当前的,然后调用任何与 gl 相关的函数。如果你在没有拥有和使上下文成为当前的情况下这样做,那么你会遇到段错误。默认情况下,主线程的上下文将是当前的。因此,要使您的程序多线程,您有两种选择。
创建两个上下文并在它们之间共享纹理对象 VAO 等资源。这种方法的优点是您可以在线程 2 中引用在线程 1 中创建的任何 VAO,并且它不会崩溃。
线程_1:
glrc1=wglCreateContext(dc); glrc2=wglCreateContext(dc); BOOL error=wglShareLists(glrc1, glrc2); if(error == FALSE) { //Unable to share contexts so delete context and safe return } wglMakeCurrent(dc, glrc1); DoWork();
线程_2:
wglMakeCurrent(dc, glrc2); DoWork();
另一种选择是为每个线程创建一个上下文,并在线程启动时使其成为当前上下文。喜欢关注
线程_1:
wglMakeCurrent(NULL, NULL); WaitForThread2(); OrDoSomeCPUJob(); wglMakeCurrent(dc, glrc);
线程_2:
wglMakeCurrent(dc, glrc); DoSome_GL_Work(); wglMakeCurrent(NULL, NULL);
希望这能解决问题。
关于c++ - 在多线程程序中创建 OpenGL 结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47918078/