2011-02-28 93 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。在这种情况下工作正常。