2013-02-24 45 views
4

我想加載後臺線程中的紋理,以幫助加快我的應用程序。使用glGetString()與linux下的pthreads的分段錯誤

我們使用的堆棧是Linux上的C/C++,使用gcc編譯。我們使用OpenGL,GLUT和GLEW。我們一直在使用libSOIL進行紋理加載。

最終,發動紋理加載與libSOIL失敗,因爲它遇到導致段錯誤一個glGetString()調用。爲了縮小這個問題,我編寫了一個非常簡單的OpenGL應用程序來重現行爲。下面的代碼示例不應該「做任何事情」,但它也不應該出現段錯誤。如果我知道它爲什麼會這樣做,理論上我可以重新編寫libSOIL,以便它可以在一個可編程的環境中運行。

void *glPthreadTest(void* arg) { 

    glGetString(GL_EXTENSIONS); //SIGSEGV 
    return NULL; 

} 

int main(int argc, char **argv) { 

    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); 

    glewInit(); 

    glGetString(GL_EXTENSIONS); // Does not cause SIGSEGV 

    pthread_t id; 
    if (pthread_create(&id, NULL, glPthreadTest, (void*)NULL) != 0) 
    fprintf(stderr, "phtread_create glPthreadTest failed.\n"); 

    glutMainLoop(); 
    return EXIT_SUCCESS; 

} 

從GDB這個應用程序的樣本堆棧跟蹤看起來是這樣的:

#0 0x00000038492f86e9 in glGetString() from /usr/lib64/nvidia/libGL.so.1 
No symbol table info available. 
#1 0x0000000000404425 in glPthreadTest (arg=0x0) at sf.cpp:168 
No locals. 
#2 0x0000003148e07d15 in start_thread (arg=0x7ffff7b36700) at pthread_create.c:308 
     __res = <optimized out> 
     pd = 0x7ffff7b36700 
     now = <optimized out> 
     unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737349117696, -5802871742031723458, 1, 211665686528, 140737349117696, 0, 5802854601940796478, 
       -5829171783283899330}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} 
     not_first_call = 0 
     pagesize_m1 = <optimized out> 
     sp = <optimized out> 
     freesize = <optimized out> 
#3 0x00000031486f246d in clone() at ../sysdeps/unix/sysv/linux/x86_64/clone.S:114 
No locals. 

你會發現我使用的是NVIDIA libGL函數的實現,但是這也與檯面相同發生libGL函數,Ubuntu的使用用於英特爾高清顯卡。

任何可能出錯的提示,或者如何進一步調查以瞭解發生了什麼?

編輯:這裏是#包括和我的例子測試編譯字符串:

#include <SOIL.h> 
#include <GL/glew.h> 
#include <GL/freeglut.h> 
#include <GL/freeglut_ext.h> 
#include <signal.h> 
#include <pthread.h> 
#include <cstdio> 

g++ -Wall -pedantic -I/usr/include/SOIL -O0 -ggdb -o sf sf.cpp -lSOIL -pthread -lGL -lGLU -lGLEW -lglut -lX11

+0

你還可以添加你用於gcc的標誌嗎? – derekv 2013-02-24 20:35:35

+0

是的,我更新了我的問題。 – 2013-02-24 21:00:15

回答

8

爲了任何的OpenGL調用正常工作,它需要一個OpenGL上下文。上下文是使用窗口系統綁定調用創建的(如wglCreateContext或類似的)。在創建一個上下文後,它需要爲「made current」,這意味着將上下文與當前的執行線程關聯起來。這是通過另一個特定於窗口系統的調用來完成的(例如用於Microsoft Windows的wglMakeCurrent或用於X Windows的glXMakeCurrent)。 GLUT將所有這些複雜性都從你身上抽象出來,在你撥打glutCreateWindow時做所有這些操作。現在

,要知道一個重要的規則是,只有一個OpenGL上下文可以在任何一個時間是電流執行線程。因此,在OP最初的例子中,如果她/他可以在他們創建的Pthread中創建上下文,那麼上下文將會在主線程中丟失。保持所有這些一致的方法是僅在單個線程中使用單個上下文。 (可以讓OpenGL上下文共享數據,但這不是GLUT公開的,也不可能不使用窗口系統上下文創建調用)。

在你的情況,很可能是GLUT不允許訪問你真正需要(即,OpenGL上下文),以使其在其他線程的電流。你需要自己創建和管理OpenGL上下文。

+1

聽起來很合理。我會看看,如果我不能爲紋理加載數據的實際負載,這可能會給我我想要的功能。 – 2013-02-24 21:10:58

+1

您肯定能夠從另一個文件中讀取紋理元素,但是您將無法將其指定爲紋理(例如,通過調用'glTexImage2D')。這仍然需要將上下文綁定到另一個線程中,或者理想情況下,每個線程都有一個帶有對象共享的上下文。也就是說,你完全可以做你正在問的東西,而不是在GLUT中。 HTH。 – radical7 2013-02-24 21:14:37

+1

@JohnHuston:在單獨的線程中從文件加載紋理是合理的。你也可以使用Pixel Buffer Objects將它傳遞給OpenGL。 PBO有能力映射到客戶地址空間,跨越所有線程。所以你可以在OpenGL線程中使用glMapBuffer,並向其他線程發送一些事件的信號。加載器線程填充映射的緩衝區,完成時將OpenGL線程發送給glUnmapBuffer..glTex [Sub]對數據進行映像。 – datenwolf 2013-02-24 21:35:40