2014-03-12 3 views
6

지형 덩어리의 메쉬를 보유하는 정점 버퍼가 있습니다. 플레이어가 지형을 편집 할 때마다 해당 청크의 메쉬가 재생성되어 버텍스 버퍼에 업로드되어야합니다. 메쉬 재생성에는 시간이 걸리기 때문에 비동기 작업자 스레드에서 처리합니다.다중 스레드 OpenGL 버퍼 액세스를 동기화하는 방법은 무엇입니까?

작업 스레드가 새 데이터를 업로드하는 동일한 순간에 주 스레드가 버퍼를 그립니다. 즉, 플레이어가 지형을 편집 한 후에 손상된 청크가 한 프레임 렌더링됩니다. 그것은 단지 한 번 그리고 그 후에, 올바른 버퍼가 그려지기 시작합니다.

이런 종류의 의미가 있어도 같은 시간에 동일한 데이터를 쓰고 읽지 않아야합니다. 따라서 이전 버퍼를 업데이트하는 대신 새 버퍼를 작성하고 버퍼를 채우고 바꿨습니다. 스와핑은 지형 청크 구조체 내에 저장된 버퍼 ID를 변경하는 것이므로 원자가되어야합니다. 그러나, 그것은 도움이되지 못했습니다.

OpenGL 명령이 GPU의 큐로 보내지기 때문에 CPU의 응용 프로그램이 계속 실행될 때 실행될 필요가 없습니다. 그래서 새로운 버퍼가 실제로 준비되기 전에 버퍼를 교체했을 것입니다.

또한 버퍼 액세스에 뮤텍스를 사용하여 버퍼를 전환하는 방법을 시도했습니다. 메인 쓰레드는 드로잉하는 동안 뮤텍스를 잠그고 작업자 쓰레드는 새로운 버퍼 데이터를 업로드하는 동안 그것을 잠급니다. 그러나 이것 역시 도움이되지 않았고 OpenGL의 비동기 성질 때문일 수도 있습니다. 메인 스레드는 실제로 그리지 않았지만 그리기 명령을 GPU에 보냅니다. 반면에 실제로 명령 대기열이 하나뿐일 때 버퍼를 업로드하고 그리는 것은 결코 동시에 발생하지 않을 수 있습니까?

정의되지 않은 버퍼가 하나의 프레임에 그려지는 것을 방지하기 위해 두 스레드의 버텍스 버퍼 액세스를 어떻게 동기화 할 수 있습니까?

+0

내가 귀하의 상황을 정확하게 이해한다면, 나는 말할 필요가 있습니다. 그것은 그렇게 작동하지 않아야합니다. 버퍼 업데이트는 그들과 함축적 인 동기화를 수행하며,'glBufferSubData (...) '같은 각각의 호출은 효과적으로 원자 적이다. 구현이 올바르게 준수하고 있다면 다른 스레드에서 나타나는 부분적인 쓰기에 대해 걱정할 필요가 없습니다. 즉, 처음부터 이런 방식으로 작업하려고하는 오버 헤드가 있습니다. 렌더링 스레드가 다른 스레드 (예 : 정면)에서 읽는 동안 작업자 스레드가 쓰는 순환 버퍼 (예 : 백 버퍼)를 고려 했습니까? ? –

+0

그런데 버퍼를 업데이트하는 데 API의 어떤 부분을 사용하고 있습니까? 버퍼를 매핑하고 매핑 해제하거나'glBufferSubData (...) '를 사용하고 있습니까? –

+0

@ AndonM.Coleman : 흠. 방금 daijar가 다중 컨텍스트를 사용하고 있다고 가정합니다. 그렇지 않으면 질문이 실제로 의미가 없습니다. – derhass

답변

5

그리기 스레드에서 해당 버퍼를 사용하려면 먼저 버퍼 업데이트가 실제로 완료되었는지 확인해야합니다. 해결 방법은 모든 업데이트 GL 명령을 발행 한 후 업데이트 스레드에서 glFinish으로 호출 한 다음 반환 된 후에 그리기 스레드에만 알리는 것입니다.

동기화를보다 세부적으로 제어하려면 울타리 동기화 개체 (내선 번호 : GL_ARB_sync 설명)를 참조하십시오. 업데이트 명령을 내린 후 울타리 동기화를 실행할 수 있고 실제로 버퍼 개체가있는 동기화 개체 핸들을 저장하여 그리기 스레드가 업데이트가 실제로 완료되었는지 (또는 기다리는 지) 확인할 수 있습니다. 동기화 오브젝트는 이 아닌이 GL 컨텍스트에 묶여 있지 않으므로 멀티 컨텍스트 설정에서 사용할 수 있으므로 특수 오브젝트입니다.

+0

재미있을 것 같습니다. * 업데이트 스레드 * 당신은 작업자 스레드가 버텍스 버퍼를 업데이트한다는 것을 의미합니까? – danijar

+0

@danijar : 맞습니다. – derhass

+0

좋습니다. 내 목표는 새 버퍼가 GPU에 업로드 될 때까지 이전 버퍼를 사용하는 것인데, 렌더러가 헛되이 기다릴 수 없기 때문입니다. 어떻게이 접근합니까? – danijar