2011-08-06 9 views
6

방금 ​​OpenGL specification for ARB_map_buffer_range을 찾았습니다.Opengl 비 동기화/비 차단 MAP

이 확장 프로그램을 사용하여 비 차단지도 통화를 할 수 있는지 궁금합니다.

현재 내 응용 프로그램에서 FBO로 렌더링 한 다음 호스트 PBO 버퍼에 매핑합니다.

glMapBuffer(target_, GL_READ_ONLY); 

그러나이 문제는 데이터를 전송하는 동안 렌더링 스레드를 차단한다는 점에서 문제가 있습니다.

렌더링을 파이프 라이닝하여이 문제를 줄일 수는 있지만 대기 시간은 내 애플리케이션에서 큰 문제입니다.

제 질문은 map_buffer_range를 MAP_UNSYNCHRONIZED_BIT와 함께 사용할 수 있는지 여부와 다른 스레드에서 맵 작업이 완료 될 때까지 기다리거나 렌더링 스레드가 다음 프레임을 렌더링하는 동안 동일한 스레드에서 맵 작업을 지연시키는 지 여부입니다.

thread 1: 

map(); 
render_next_frame(); 

thread 2: 

wait_for_map 

또는

thread 1: 

map(); 
while(!is_map_ready()) 
    do_some_rendering_for_next_frame(); 

은 내가 확신 해요 것은 내가지도 작업이 준비가되면, 사양은 "다른 동기화 기술은 정확한 동작을 보장하기 위해"언급 아는 방법이다.

아이디어가 있으십니까?

답변

5

일반적으로 "넌 블로킹 맵"을 수행 할 수 없지만 차단하지 않고 매핑 할 수 있습니다.

"nonblocking map"이없는 이유는 함수 호출이 반환되는 순간에 데이터에 액세스 할 수 있기 때문에 드라이버가이를 확실히 확인해야합니다. 데이터가 전송되지 않았다면, 운전자는 무엇을 할 수 있습니까?
스레드가이 기능을 향상시키지 않아서 상황이 악화 될 수 있습니다 (동기화 및 컨텍스트 공유 문제 추가). 스레드는 마술처럼 데이터를 전송할 필요를 제거 할 수 없습니다.

그러면 매핑을 차단하지 않는 방법이 있습니다. 전송이 완료되었음을 확인한 경우에만 매핑합니다. 이를 수행하는 한 가지 안전한 방법은 버퍼를 뒤집은 후 또는 glFinish 이후 또는 쿼리/펜스 객체를 기다린 후 버퍼를 매핑하는 것입니다. 버퍼가 바뀔 때까지 기다릴 수 없다면 울타리를 사용하는 것이 더 좋은 방법입니다. 펜스가 파이프 라인을 막지는 않지만 전송이 완료되었는지 여부는 알려줍니다 (glFinish 일 수도 있고 아닐 수도 있지만 일 것입니다. 마구잡이). 버퍼를 스왑 한 후 읽기도 100 % 안전하지만 같은 프레임 내에서 데이터가 필요하면 허용되지 않을 수 있습니다 (스크린 샷이나 톤 맵핑을위한 히스토그램 계산에 완벽하게 작동합니다).

덜 안전한 방법은 "다른 것들"을 삽입하고 그 시간에 전송이 완료되기를 바랍니다. 아래의 코멘트에 관하여


는 :
이 답변 하지 올바르지 않습니다. 사용 가능한 데이터에 액세스하는 것보다 더 나은 작업을 수행하는 것은 불가능합니다 (이는 분명해야합니다). 즉, 동기화/차단, 한 가지 방법 또는 다른 방법이어야합니다.
보기의 아주 현학적 인 관점에서, 당신은 물론 비 블로킹지도 작업을 얻을 수 GL_MAP_UNSYNCHRONIZED_BIT를 사용할 수 있지만 , 이것은 당신이 명시 적으로이 암시 동기화를 재현 하지 않는 한 설명 된대로 작동하지 않는, 완전히 무관하다 위. 안전하게 액세스 할 수없는 매핑은 아무 도움이되지 않습니다.

OpenGL이 동기화/차단 (암시 적 또는 명시 적)없이 데이터를 전송하는 버퍼에 매핑 및 액세스하는 것은 "정의되지 않은 동작"을 의미합니다. 이는 "아마도 가비지 결과가 충돌 할 수 있습니다"라는 의미입니다.
한편 위에서 명시 적으로 울타리로 명시 적으로 동기화하는 경우 암시 적 동기화가 더 이상 발생하지 않아서 동기화되지 않은 플래그를 사용하는지 여부는 중요하지 않습니다.

+0

이 "쿼리 개체"에 관해 좀 더 설명해 주시겠습니까? 준비가되지 않았다면지도에 대한 호출을 연기하기 위해 사용할 수있는 것처럼 들립니다. – ronag

+2

이는 [ARB_sync] (http://www.opengl.org/registry/specs/ARB/sync)를 참조합니다.txt)도 코어 3.2에 있습니다. 이렇게하면 동기화 쿼리 ("울타리")를 명령 스트림에 삽입 할 수 있습니다.이 명령 스트림은 클라이언트 또는 클라이언트 + 서버에서 대기하거나 완료 상태를 쿼리 할 수 ​​있습니다. 동기화 쿼리가 완료되었다고 반환하면 울타리를 삽입하기 전에 발생한 모든 명령이 완료되었음을 의미합니다. 따라서 귀하의 경우 데이터가 원하는 위치에 있다는 것을 알고 버퍼를 매핑하는 것이 차단되지 않습니다. – Damon

+0

우수하지만,이 올바르게 이해하면 glReadPixels (장치 -> 호스트 전송) 호출 후 동기화 쿼리를 직접 작성해야합니다. 쿼리가 준비되었다는 것을 알게되면 map에 대한 호출이 차단되지 않을 것입니다 (아니면 매우 짧게). – ronag

5

버퍼를 GL_MAP_UNSYNCHRONIZED_BIT으로 매핑하면 드라이버가 OpenGL을 매핑하기 전에 해당 메모리로 완료 될 때까지 기다리지 않습니다. 그래서 당신은 더 많은 또는 덜 즉각적인 액세스를 얻을 것이다.

문제는 이것이 이 아니고이 아니기 때문에 메모리를 willy-nilly로 읽고 쓸 수 있다는 것입니다. OpenGL이 버퍼에서 읽거나 쓰는 중이고 변경하면 ... 에 대한 정의되지 않은 동작. 충돌을 포함 할 수 있습니다.

따라서 실제로 비동기 매핑을 사용하려면 비헤이비어를 해당 버퍼에 대한 OpenGL의 액세스에 동기화해야합니다. 여기에는 ARB_sync objects (또는 NVIDIA에서만 사용 중이며 최근에 드라이버를 업데이트하지 않은 경우 NV_fence)가 사용됩니다.

말하자면 울타리 객체를 사용하여 버퍼에 대한 액세스를 동기화하는 경우 실제로는 GL_MAP_UNSYNCHRONIZED_BIT이 필요하지 않습니다. 펜스를 끝내거나 버퍼가 끝났음을 감지하면 버퍼를 정상적으로 매핑 할 수 있습니다. 다른 작업도 읽기/쓰기가 아닌 경우 버퍼가 즉시 완료됩니다.

일반적으로 비동기 액세스는 버퍼에 대한 세분화 된 쓰기 액세스가 필요한 경우에 가장 적합합니다. 이 경우 동기화 객체를 잘 사용하면 실제로 필요한 작업 (맵 작업이 완료된 시점을 알 수있는 기능)을 얻을 수 있습니다.


부록 : 위의 내용이 (하드웨어에 따라) 구형입니다. OpenGL 4.4/ARB_buffer_storage 덕분에 이제는 비동기로 매핑 할 수있을뿐만 아니라 버퍼를 무한대로 유지할 수 있습니다. 예, 사용중인 버퍼는 으로 매핑 할 수 있습니다.

이것은 변경 불가능한 저장소를 만들고 그 저장소에 (다른 것들 중에서) GL_MAP_PERSISTENT_BIT을 제공하여 수행됩니다. 그런 다음 동일한 비트를 제공하는 glMapBufferRange입니다.

이제 기술적으로는 거의 변하지 않습니다. OpenGL과 작업을 동기화해야합니다. 버퍼의 영역에 물건을 쓸 경우 issue a barrier 또는 flush that region of the buffer explicitly 중 하나가 필요합니다. 그리고 읽는 중이라면 fence sync object을 사용하여 실제로 데이터가 인지 확인한 후에 읽어야합니다 (읽고 사용하기 전에 GL_MAP_COHERENT_BIT도 사용하지 않으면 장벽을 발행해야합니다).