2011-02-28 72 views
1

讓我試圖指定什麼我想做的事情開始:OpenGL調用段錯誤

給定一個灰度圖像,我想創建一個256層(假設8位圖像),其中每個層圖像用灰度i - 也是第i層(如此,i = 0:255)閾值化。對於所有這些層我想計算其他與我的問題不相關的其他事物,但這應該解釋我的代碼的結構。

問題是我需要經常執行代碼,所以我想盡可能地加快速度,使用很短的時間(所以,只是簡單的加速技巧)。因此我想我可以使用OpenMP庫,因爲我有一個四核,而目前一切都基於CPU。

這使我下面的代碼,它執行罰款(至少,它看起來不錯:)):

#pragma omp parallel for private(i,out,tmp,cc) 
    for(i=0; i< numLayers; i++){ 
     cc=new ConnectedComponents(255); 
     out = (unsigned int *) malloc(in->dimX()* in->dimY()*sizeof(int)); 
     tmp = (*in).dupe(); 
     tmp->threshold((float) i); 
     if(!tmp){  printf("Could not allocate enough memory\n"); exit(-1); } 

     cc->connected(tmp->data(),out,tmp->dimX(),tmp->dimY(),std::equal_to<unsigned int>(), true); 

     free(out); 
     delete tmp; 
     delete cc; 
    } 

ConnectedComponents只是一些庫,實現了2通floodfill,就在那裏進行說明,這不是問題的一部分。

此代碼用2,3,4,8個線程完成正常(未測試任何其他編號)。

所以,現在是奇怪的部分。我想添加一些視覺反饋,幫助我進行調試。對象tmp包含一個名爲saveAsTexture()的方法,它基本上爲我完成所有工作,並返回紋理ID。這個函數工作正常,單線程,並且2線程也可以正常工作。但是,只要超出2個線程,該方法就會導致分段錯誤。

即使#pragma omp在其周圍(以防萬一saveAsTexture()不是線程安全的),或者只執行一次,它仍會崩潰。這是我加入到以前的循環代碼:

if(i==100){ 
     #pragma omp critical 
     { 
      tmp->saveToTexture(); 
     } 
    } 

其中只執行一次,因爲i是迭代器,這是一個重要的部分......儘管如此,代碼總是出現segfaults在第一的openGL調用(使用printf(),fflush(stdout))進行bruteforce測試)。

所以,只是爲了確保我不會離開了相關信息,這裏是saveAsTexture功能:

template <class T> GLuint FIELD<T>::saveToTexture() { 
    unsigned char *buf = (unsigned char*)malloc(dimX()*dimY()*3*sizeof(unsigned char)); 
    if(!buf){ printf("Could not allocate memory\n"); exit(-1); } 
    float m,M,avg; 
    minmax(m,M,avg); 
    const float* d = data(); 
    int j=0; 

    for(int i=dimY()-1; i>=0; i--) { 
     for(const float *s=d+dimX()*i, *e=s+dimX(); s<e; s++) { 
      float r,g,b,v = ((*s)-m)/(M-m); 
      v = (v>0)?v:0; 
      if (v>M) { r=g=b=1; } 
      else { v = (v<1)?v:1; } 
      r=g=b=v; 
      buf[j++] = (unsigned char)(int)(255*r); 
      buf[j++] = (unsigned char)(int)(255*g); 
      buf[j++] = (unsigned char)(int)(255*b); 
     } 
    } 

    GLuint texid; 
    glPixelStorei(GL_UNPACK_ALIGNMENT,1); 
    glDisable(GL_TEXTURE_3D); 
    glEnable(GL_TEXTURE_2D); 
    glActiveTexture(GL_TEXTURE0); 
    glGenTextures(1, &texid); 
    printf("TextureID: %d\n", texid); 
    fflush(stdout); 
    glBindTexture(GL_TEXTURE_2D, texid); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dimX(), dimY(), 0, GL_RGB, GL_UNSIGNED_BYTE, buf); 
    glBindTexture(GL_TEXTURE_2D, 0); 
    glDisable(GL_TEXTURE_2D); 
    free(buf); 
    return texid; 
} 

這是好事,在這裏指出,T總是在我的程序的浮動。因此,我不明白爲什麼這個程序在使用1或2個線程(執行〜25次,100%成功)執行時工作正常,但使用更多線程時執行〜段錯誤(執行〜25次,0%成功)。並總是在第一次openGL調用(例如,如果我刪除glPixelStorei(),它在glDisable())segfaults。 我可以忽略一些非常明顯的東西,我遇到了一個奇怪的OpenMP錯誤,或者......發生了什麼?

+2

我會說,這是因爲你從一個不同於它創建的線程的線程訪問OpenGL上下文,但是你聲明它對2個線程有效。 – ChrisF 2011-02-28 22:11:52

+0

你在哪裏創建了你的GL上下文?你的GL上下文在哪裏最新? – genpfault 2011-02-28 22:11:54

回答

3

您只能從one thread at a time進行OpenGL調用,且線程必須使當前上下文處於活動狀態。

+2

這不完全正確。更好:「OpenGL上下文一次只能在一個線程上運行。」 – 2011-02-28 23:12:06

+0

足夠接近。 :) – TheBuzzSaw 2011-03-01 00:34:53

1

OpenGL上下文一次只能由一個線程使用(限制爲wglMakeCurrent/glxMakeCurrent)。

但是,你說你正在使用圖層。我認爲你可以爲不同的層使用不同的上下文,擴展名爲WGL_ARB_create_context(我認爲還有一個適用於linux的)並設置了WGL_CONTEXT_LAYER_PLANE_ARB參數。然後你可以爲每個線程創建一個不同的上下文,並且事情應該可以實現。

+0

WGL_ARB_create_context很好地工作,但老實說,我寧願只在主線程glMapbuffer(),在另一個線程中填充緩衝區,併發出一個同步原語。然後取消映射主線程中的緩衝區並調用glTexImage。這將是多次更容易維護和更容易出錯。它不會阻塞渲染線程,這就是重中之重。 代碼看起來並不像使用4個線程會帶來很多好處,它或多或少是類固醇上的memcpy,所以......它將完全受內存帶寬的約束,而4個內核將不會比一。 – Damon 2011-03-01 00:36:39

+0

@dm:可能是真的。我只是提供了一種多線程工作方式,但是這種情況可能不會從中受益。 – 2011-03-01 01:55:46

1

非常感謝您所有的答案!現在我知道它爲什麼會失敗我已經決定將所有內容都存儲在一個大的3D紋理中(因爲這是一個更簡單的解決方案),並且只需將所有數據一次發送到GPU。在這種情況下工作正常。