在多线程程序中创建OpenGL结构? [英] Creating OpenGL structures in a multithreaded program?

查看:176
本文介绍了在多线程程序中创建OpenGL结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在自己制造的物理引擎中执行以下操作:

有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完全崩溃了,因为它不知道发生了什么. /p>

那我该怎么做多线程程序?

除非有人提供充分的理由说明它为什么行不通,否则我将尽可能与我描述的设计保持一致.

解决方案

对OpenGL的要求是,为渲染而创建的上下文在任何给定点都应由单个线程拥有,而拥有上下文的线程应使其成为当前线程,然后调用任何与gl相关的函数.如果您在没有拥有上下文的情况下进行此操作,则会遇到分段错误.默认情况下,上下文将是主线程的当前上下文.因此,要使您的程序成为多线程程序,您有两个选择.

  1. 创建两个上下文并在它们之间共享纹理对象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();
    

  2. 其他选项是使每个线程具有一个上下文,并在线程启动时使其成为当前上下文.就像关注

    线程_1:

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

    线程_2:

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

希望这可以清除问题.

I am attempting to do the following in a physics engine I am building:

Have 2 threads, one for world logic, one for rendering.

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:

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. it then puts that information into a Render_Info object, which acts as a message between the thread and the rendering thread.

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:

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.

From what I have read OpenGL is as far away from being thread safe as a Giraffe is from being a dolphin.

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.

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. 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.

    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();
    

  2. Other option is to make one context per thread and make it current when thread starts. Like following

    Thread_1:

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

    Thread_2:

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

Hope this clears up the thing.

这篇关于在多线程程序中创建OpenGL结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆