2017-12-21 6 views
15

건물중인 물리 엔진에서 다음 작업을 시도하고 있습니다.다중 스레드 프로그램에서 OpenGL 구조 만들기?

두 개의 스레드 (하나는 월드 로직 용, 하나는 렌더링 용)가 있습니다.

메인 스레드 (다른 스레드가 생성되는 스레드)는 렌더링 스레드이며, 그 다음에 월드 스레드가 그 스레드에서 분기됩니다. 렌더 스레드에

핸들러를 렌더링라는 글로벌 데이터 구조가이 선언 :

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 컨텍스트가 주 스레드에 속해있는 것 같습니다. 따라서 세계 스레드 OpenGL에서 VAO와 VBO를 만들려고 할 때 어떤 일이 벌어지고 있는지 전혀 모르기 때문에 충돌이 발생합니다.

프로그램을 멀티 스레드하려면 어떻게해야합니까?

누군가가 왜 작동하지 않는지에 대한 정당성을 제시하지 않는 한, 내가 설명한 디자인에 가깝게 머물고 싶습니다.

+1

현재 드로잉 호출을 수행하기 위해 렌더 스레드에 메시지를 보내고 있습니다. VAO, VBO 및 텍스처 생성을 포함한 모든 OpenGL 작업에 대한 메시지를 보내려면 확장해야한다고 생각합니다. – Columbo

+0

아래의 두 답변 중 하나를 선택해도이 질문에 대한 답을 찾지 못합니까? –

+0

나는 답을 받아들이지 않으려한다. util 내가 테스트 한 결과 나 자신이 나왔다. 잠시 후에 응답 플래그를 제거 할 수 없기 때문이다. 나는 휴일을 포기하고 잠시 동안이 해결책을 시험 할 기회를 얻지 못할 것이다. 그때까지 나는 대답 할 권리가있다. 나는 그것이 성가신 것을 안다, 나는 그것에 대해 사과한다. – Makogan

답변

5

OpenGL의 요구 사항은 렌더링을 위해 생성 된 컨텍스트가 특정 시점에서 단일 스레드에 의해 소유되어야하고 컨텍스트를 소유하는 스레드가 현재 상태로 만들어야하고 gl 관련 함수를 호출해야한다는 것입니다. 컨텍스트를 소유하지 않고 컨텍스트를 만드는 경우 세그멘테이션 오류가 발생합니다. 기본적으로 컨텍스트는 주 스레드의 현재 상태가됩니다. 따라서 프로그램을 멀티 스레드로 만들려면 두 가지 옵션이 있습니다.

  1. 못해 충돌이 스레드 1에서 만든 VAO에 스레드 2에서 참조 할 수있다이 방법의 them.Advantage과 사이의 텍스처 오브젝트 VAOs 같은 두 개의 컨텍스트 및 공유 리소스를 만듭니다.

    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(); 
    
  2. 다른 옵션은 스레드 당 하나의 컨텍스트를 만들 때 스레드의 시작은 현재 확인하는 것입니다. 다음

    Thread_1처럼 :

    wglMakeCurrent(NULL, NULL); 
    
    WaitForThread2(); OrDoSomeCPUJob(); 
    
    wglMakeCurrent(dc, glrc); 
    

    Thread_2 :

    wglMakeCurrent(dc, glrc); 
    
    DoSome_GL_Work(); 
    
    wglMakeCurrent(NULL, NULL); 
    

희망이 일을 지 웁니다.

+0

각각의 장단점은 무엇입니까? – Makogan

+0

예를 들어 두 개의 스레드가 있습니다. 메인 스레드 인 경우 .xyz와 같은 일부 파일 형식에서 기하학을로드하십시오. 이 파일은 nurbs로 지오메트리를 저장합니다. 그런 다음이를 렌더링하려면 삼각형 형식의 데이터가 필요합니다. 주 스레드에서는 nurb 데이터를로드하고 테셀레이션을 위해 백그라운드 스레드로 보냅니다. 메인 스레드는 다른 렌더링 작업과 UI를 자유롭게 볼 수 있습니다. 이제 삼각 분할 된 데이터를 생성하여 테셀레이션을 수행하면 VBO를 작성하고 주 스레드 만이 VBO에 첨부하는 것이 더 좋습니다. 꼭지점을 쉽게 사용할 수 있으므로 (1/2) –

+0

VBO를 만들고 테셀레이션 스레드는 시스템에서 스톨하지 않도록 바쁘게 유지됩니다. 그러나이 경우 VBO 리소스를 렌더링 및 테셀레이션 스레드를 수행하는 주 스레드에서 공유해야합니다. 이 경우의 단점은 리소스에 대한 액세스를 동기화하는 데 많은주의가 필요하며 드라이버 측면에서도 많은 문제가 발생할 수 있다는 것입니다. 두 번째 방법의 장점은 간단합니다. 각 스레드는 아무런 문제없이 문맥을 가지지 만 단점은 더 많은 스레드를 만드는 경우 더 많은 컨텍스트가 필요하며 메모리 요구 사항이 증가한다는 것입니다. –

2

내가 읽은 바로는 OpenGL은 기린이 돌고래가 아니므로 스레드로부터 안전합니다.

그럼 당신이 잘못 알고있어. OpenGL은 완벽한 스레드 안전합니다. OpenGL 컨텍스트가 스레드 로컬 저장소와 같이 약간 작동한다는 것을 명심해야합니다. 나는. OpenGL 컨텍스트를 현재로 만들면이 호출을하는 스레드에 지역화됩니다.

또한 OpenGL 함수 포인터는 OpenGL 컨텍스트에만 사용할 수 있지만 컨텍스트 바인딩에는 사용할 수 없습니다. 그러나 OpenGL 함수 로더는 스레드 → 컨텍스트 캐시를 유지합니다. 따라서 컨텍스트 바운드없이 스레드에서 확장 된 OpenGL 함수 (즉, 런타임에로드해야하는 함수)를 호출하면 잘못된 함수 포인터를 호출하여 충돌이 발생할 가능성이 높습니다.

비록 완벽한 스레드 안전성에도 불구하고 OpenGL은 다중 스레드 사용시 성능을 반드시 얻지는 않습니다. OpenGL 스레드 접합체 컨텍스트는 작업자 스레드에서 텍스처 및 버퍼 객체 데이터를 업데이트해야하지만 주 렌더링 스레드에서 사용하기 힘든 일이 발생하지 않도록주의해야 할 경우 매우 유용합니다. 이렇게해야하는 프로그램에서 데이터를 생성하는 스레드가 텍스처/버퍼 객체 풀을 생성하고 데이터를 업데이트 한 다음 해당 객체의 소유권을 렌더링 스레드에 "반환"한다는 일반적인 접근 방식이 있습니다. 결과적으로 렌더 스레드는 이러한 개체로 작업을 수행하고 완료되면 소유권을 업데이트 스레드로 다시 전달하고 데이터 스레드가 보내는 개체로 채워지는 자체 풀에서 다음 개체를 가져옵니다.

프로그램을 멀티 스레드하려면 어떻게해야합니까?

zygote OpenGL 컨텍스트를 만들고 디스플레이 목록 공유의 메커니즘을 통해 텍스처 및 버퍼 객체를 다른 스레드와 공유하도록 구성합니다. 프로그램에서 임의의 수의 OpenGL 컨텍스트를 가질 수 있으며 각 스레드는 고유 컨텍스트를 활성화 할 수 있습니다 (다른 스레드는 다른 컨텍스트를 사용함).

관련 문제