简体   繁体   English

在多线程程序中创建OpenGL结构?

[英]Creating OpenGL structures in a multithreaded program?

I am attempting to do the following in a physics engine I am building: 我正在尝试在我正在构建的物理引擎中执行以下操作:

Have 2 threads, one for world logic, one for rendering. 有2个线程,一个用于世界逻辑,一个用于渲染。

The main thread (the thread from which the other threads are created) is the render thread, and then the world thread is forked from it. 主线程(创建其他线程的线程)是渲染线程,然后世界线程从它分叉。

On the render thread there is a global data structure called rendering handler declared as: 在渲染线程上有一个称为渲染处理程序的全局数据结构,声明为:

 class Renderer
{
    private:
        /*
          shader stuff
        */
        mutex busy_queue;
        vector<Render_Info*> render_queue;

    public:
        /*
           Bunch of methods
        */
        void add_data(Render_Info*);
        void render();
};

And a Render_Info structure is declared as: 并且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;

The idea here was as follows. 这里的想法如下。 Any thread that wishes to render something, must handle it's own data an put it into OpenGL primitives. 任何希望渲染某些东西的线程都必须处理它自己的数据并将其放入OpenGL原语中。 it then puts that information into a Render_Info object, which acts as a message between the thread and the rendering thread. 然后它将该信息放入Render_Info对象,该对象充当线程和呈现线程之间的消息。

The thread then uses the add_data() method, to send a pointer to it's data message that gets appended to the render_queue as: 然后该线程使用add_data()方法发送指向它的数据消息的指针,该数据消息被附加到render_queue如下所示:

void Renderer::add_data(Render_Info* data)
{
    busy_queue.lock();
    render_queue.push_back(data);
    busy_queue.unlock();
}

And finally, when the render thread would choose to render something, it would lock the queue (preventing anything from being added to the queue) render everything, then clear the queue. 最后,当渲染线程选择渲染某些东西时,它会锁定队列(阻止任何东西被添加到队列中)渲染所有东西,然后清除队列。

Now of course some more thread coordination is needed but that is the gist of the idea. 当然,现在需要更多的线程协调,但这是这个想法的要点。

The issue is, I get segmentation faults just from trying to create OpenGL VAOs and VBOs, let alone filling them with data. 问题是,我只是试图创建OpenGL VAO和VBO而产生分段错误,更不用说填充数据了。

From what I have read OpenGL is as far away from being thread safe as a Giraffe is from being a dolphin. 据我所知,OpenGL远离线程安全,因为长颈鹿不是海豚。

And the cause of the problem seems to be that the OpenGL context belongs to the main thread, so when I try to create the VAOs and VBOs on the world thread OpenGL simply crashes as it has no idea what is going on. 问题的原因似乎是OpenGL上下文属于主线程,所以当我尝试在世界线程上创建VAO和VBO时,OpenGL会崩溃,因为它不知道发生了什么。

What can I do do multi thread the program then? 那么我可以做多线程程序呢?

I'd like to stay as close to the design I have described unless someone provides a good justification of why it would not work. 我希望保持尽可能接近我所描述的设计,除非有人提供一个很好的理由说明为什么它不起作用。

The requirement for OpenGL is that the context created for rendering should be owned by single thread at any given point and the thread that owns context should make it current and then call any gl related function. 对OpenGL的要求是为渲染创建的上下文应该由任何给定点的单个线程拥有,并且拥有上下文的线程应该使其成为当前,然后调用任何gl相关的函数。 If you do that without owning and making context current then you get segmentation faults. 如果你这样做而没有拥有并使上下文变为当前,则会出现分段错误。 By default the context will be current for the main thread. 默认情况下,上下文将是主线程的当前内容。 So to make your program multi threaded you have two options. 因此,要使程序具有多线程,您有两种选择。

  1. Create two contexts and share resources like texture objects VAOs between them.Advantage of this approach is you can refer in thread 2 to any VAO created in thread 1 and it wont crash. 创建两个上下文并共享资源,如纹理对象之间的VAO。这种方法的优点是你可以在线程2中引用线程1中创建的任何VAO,它不会崩溃。

    Thread_1: 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: Thread_2:

     wglMakeCurrent(dc, glrc2); DoWork(); 
  2. Other option is to make one context per thread and make it current when thread starts. 其他选项是为每个线程创建一个上下文,并在线程启动时使其成为当前。 Like following 喜欢以下

    Thread_1: Thread_1:

     wglMakeCurrent(NULL, NULL); WaitForThread2(); OrDoSomeCPUJob(); wglMakeCurrent(dc, glrc); 

    Thread_2: Thread_2:

     wglMakeCurrent(dc, glrc); DoSome_GL_Work(); wglMakeCurrent(NULL, NULL); 

Hope this clears up the thing. 希望这可以解决问题。

From what I have read OpenGL is as far away from being thread safe as a Giraffe is from being a dolphin. 据我所知,OpenGL远离线程安全,因为长颈鹿不是海豚。

Then you're misinformed. 然后你被误导了。 OpenGL is perfectly thread safe. OpenGL非常安全。 You just have to keep in mind that OpenGL contexts act a bit like thread local storage. 您必须记住,OpenGL上下文有点像线程本地存储。 Ie when you make a OpenGL context current, then this is localized to the thread that makes that call. 即,当您将OpenGL上下文设置为当前时,则将其本地化为进行该调用的线程。

Also extended OpenGL function pointers may be specific to a OpenGL context (but not to a context binding). 扩展的OpenGL函数指针也可以特定于OpenGL上下文(但不是上下文绑定)。 However OpenGL function loaders keep a thread→context cache. 然而,OpenGL函数加载器保持线程→上下文缓存。 So when you call an extended OpenGL function (ie one that must be loaded at runtime) from a thread without a context bound, you'll likely end up calling an invalid function pointer and get a crash. 因此,当您从没有上下文绑定的线程调用扩展的OpenGL函数(即必须在运行时加载的函数)时,您可能最终会调用无效的函数指针并导致崩溃。

However despite being perfectly thread safe, OpenGL does not necessarily gain performance when being used multithreaded. 尽管是完全线程安全的,但OpenGL在使用多线程时并不一定能获得性能。 OpenGL thread zygote contexts are very useful if you need to update texture and buffer object data from a worker thread, but you should be careful not to tough things that might be in use by the main rendering thread. 如果您需要从工作线程更新纹理和缓冲区对象数据,OpenGL线程zygote上下文非常有用,但是您应该注意不要使用主渲染线程可能正在使用的强硬内容。 In programs where I have to do this, the usual approach is, that the data generating thread is creating a pool of texture/buffer objects, updates the data in them and then "surrenders" ownership of the object to the render thread. 在我必须这样做的程序中,通常的方法是, 数据生成线程正在创建纹理/缓冲区对象池,更新其中的数据,然后将对象的所有权“放弃”到渲染线程。 Eventually the render thread does its thing with these objects and once its done it passes the ownership back to the update thread and takes the next object from its own pool that gets filled with what the data thread sends over. 最终渲染线程使用这些对象完成其工作,一旦完成,它将所有权传递回更新线程,并从其自己的池中获取下一个对象,该对象将填充数据线程发送的内容。

What can I do do multi thread the program then? 那么我可以做多线程程序呢?

Create zygote OpenGL contexts and configure them to share their texture and buffer objects with the other thread(s) by the mechanism of display list sharing. 创建zygote OpenGL上下文并将它们配置为通过显示列表共享机制与其他线程共享其纹理和缓冲区对象。 You can have an arbitrary number of OpenGL contexts in your program and each thread can have its very own context active (while the other threads use different contexts). 您可以在程序中拥有任意数量的OpenGL上下文,并且每个线程都可以使其自己的上下文处于活动状态(而其他线程使用不同的上下文)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM