[英]Creating OpenGL structures in a multithreaded program?
我正在嘗試在我正在構建的物理引擎中執行以下操作:
有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,它不會崩潰。
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上下文有點像線程本地存儲。 即,當您將OpenGL上下文設置為當前時,則將其本地化為進行該調用的線程。
擴展的OpenGL函數指針也可以特定於OpenGL上下文(但不是上下文綁定)。 然而,OpenGL函數加載器保持線程→上下文緩存。 因此,當您從沒有上下文綁定的線程調用擴展的OpenGL函數(即必須在運行時加載的函數)時,您可能最終會調用無效的函數指針並導致崩潰。
盡管是完全線程安全的,但OpenGL在使用多線程時並不一定能獲得性能。 如果您需要從工作線程更新紋理和緩沖區對象數據,OpenGL線程zygote上下文非常有用,但是您應該注意不要使用主渲染線程可能正在使用的強硬內容。 在我必須這樣做的程序中,通常的方法是, 數據生成線程正在創建紋理/緩沖區對象池,更新其中的數據,然后將對象的所有權“放棄”到渲染線程。 最終渲染線程使用這些對象完成其工作,一旦完成,它將所有權傳遞回更新線程,並從其自己的池中獲取下一個對象,該對象將填充數據線程發送的內容。
那么我可以做多線程程序呢?
創建zygote OpenGL上下文並將它們配置為通過顯示列表共享機制與其他線程共享其紋理和緩沖區對象。 您可以在程序中擁有任意數量的OpenGL上下文,並且每個線程都可以使其自己的上下文處於活動狀態(而其他線程使用不同的上下文)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.