我正在尝试在我正在建造的物理引擎中执行以下操作:
有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
as:
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时,在世界线程上的VAO和VBO时,OpenGL只是崩溃,因为它不知道发生了什么。<<<<<<<<<<<<
那我该怎么做多线程?
我想保持与我所描述的设计一样,除非有人很好地证明它为什么不起作用。
OpenGl的要求是,为渲染创建的上下文应由单线程在任何给定点上拥有,并且拥有上下文的线程应使其当前,然后调用任何相关的gl。如果您在没有拥有和使上下文当前的情况下执行此操作,则会获得细分错误。默认情况下,上下文将是主线程的当前。因此,要使您的程序多线程有两个选择。
-
创建两个上下文并共享它们之间的资源,例如纹理对象。
thread_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();
thread_2:
wglMakeCurrent(dc, glrc2); DoWork();
-
另一个选项是每个线程进行一个上下文,并在线程启动时使其最新。喜欢以下
thread_1:
wglMakeCurrent(NULL, NULL); WaitForThread2(); OrDoSomeCPUJob(); wglMakeCurrent(dc, glrc);
thread_2:
wglMakeCurrent(dc, glrc); DoSome_GL_Work(); wglMakeCurrent(NULL, NULL);
希望这清除了东西。
根据我所读的opengl,与长颈鹿一样,距离螺纹安全远不及海豚。
然后您被误导了。OpenGL非常安全。您只需要记住,OpenGL上下文的作用类似于线程本地存储。IE。当您制作OpenGL上下文当前时,则将其本地化为使该调用的线程。
还扩展了OpenGL函数指针可能特定于OpenGL上下文(但不是上下文绑定)。但是,OpenGL功能加载程序保持线程→上下文缓存。因此,当您调用一个不绑定上下文的线程的扩展OpenGL函数(即必须在运行时加载的功能)时,您最终可能会调用无效的功能指针并崩溃。
但是,尽管使用多线程时,openGL不一定会获得性能。如果您需要从Worker线程更新纹理和缓冲对象数据,则OpenGL线程zygote上下文非常有用,但是您应该小心不要对主渲染线程可能使用的艰难事物。在我必须执行此操作的程序中,通常的方法是,数据生成线程正在创建纹理/缓冲对象的池,更新它们中的数据,然后"投降"对象的所有权到渲染线程。最终,渲染线程对这些对象进行操作,一旦完成后,它将所有权传递回更新线程,并从其自己的池中取下下一个对象,这些对象与数据线程发送的内容填充。
那我该怎么做多线程?
创建Zygote OpenGL上下文,并通过显示列表共享的机制将其配置为与其他线程共享其纹理和缓冲对象。您可以在程序中具有任意数量的OpenGL上下文,并且每个线程都可以具有自己的上下文活动(而其他线程使用不同的上下文)。