OpenGL вызывает segfault при вызове из потока OpenMP - PullRequest
2 голосов
/ 01 марта 2011

Позвольте мне начать с попытки указать, что я хочу сделать:

Учитывая изображение в оттенках серого, я хочу создать 256 слоев (при условии 8-битных изображений), где каждый слой - это изображение, пороговое с серыммасштаб i - который также является i-м слоем (поэтому i = 0: 255).Для всех этих уровней я хочу вычислить различные другие вещи, которые не очень относятся к моей проблеме, но это должно объяснить структуру моего кода.

Проблема в том, что мне нужно выполнять код очень часто,поэтому я хочу максимально ускорить процесс, используя короткий промежуток времени (так, только простые приемы ускорения).Поэтому я подумал, что мог бы использовать библиотеку OpenMP, поскольку у меня есть четырехъядерное ядро, и все на данный момент основано на процессорах.

Это подводит меня к следующему коду, который прекрасно работает (по крайней мере, выглядитхорошо :)):

#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,3,4,8 нитями (не проверял ни одно другое число).

Итак, теперь странная часть.Я хотел добавить визуальную обратную связь, помогая мне отлаживать.Объект tmp содержит метод с именем saveAsTexture(), который в основном выполняет всю работу за меня и возвращает идентификатор текстуры.Эта функция прекрасно работает в однопоточном режиме, а также отлично работает с 2 потоками.Тем не менее, как только я выйду за пределы 2 потоков, метод вызовет ошибку сегментации.

Даже если вокруг него критично #pragma omp (на случай, если saveAsTexture() не является поточно-ориентированным) или выполняется только его выполнениеоднажды все еще падает.Это код, который я добавил в предыдущий цикл:

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

, который выполняется только один раз, так как i является итератором, и это критический раздел ... Тем не менее, код ВСЕГДА segfaultsпри первом вызове openGL (тесты bruteforce с printf (), fflush (stdout)).

Итак, просто чтобы убедиться, что я не пропускаю соответствующую информацию, вот функция 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% успеха), но segfaults при использовании большего количества потоков (выполнено ~ 25 раз, 0% успеха).И ВСЕГДА при первом вызове openGL (например, если я удаляю glPixelStorei (), он вызывает ошибку в glDisable ()).Я пропускаю что-то действительно очевидное, сталкиваюсь со странной ошибкой OpenMP или ... что происходит?

Ответы [ 3 ]

4 голосов
/ 01 марта 2011

Вы можете делать вызовы OpenGL только из одного потока за раз , и поток должен иметь текущий активный контекст.

2 голосов
/ 01 марта 2011

Контекст OpenGL может использоваться только одним потоком за раз (ограничение накладывается wglMakeCurrent / glxMakeCurrent).

Однако вы сказали, что используете слои.Я думаю, что вы можете использовать разные контексты для разных слоев, с расширением WGL_ARB_create_context (я думаю, что оно есть и для linux) и установкой параметра WGL_CONTEXT_LAYER_PLANE_ARB.Тогда у вас может быть другой контекст для потока, и все должно получиться.

1 голос
/ 01 марта 2011

Большое спасибо за все ответы!Теперь я знаю, почему это не сработало. Я решил просто сохранить все в большой трехмерной текстуре (потому что это было еще более простое решение) и просто отправить все данные в графический процессор сразу.Это прекрасно работает в этом случае.

...