opengl : glFlush () 대 glFinish ()


105

호출 glFlush()glFinish(). 의 실제적인 차이점을 구분하는 데 문제가 있습니다.

워드 프로세서는 그 말 glFlush()glFinish()하나가 차이가 있다는 것을, 그들은 모두 실행됩니다 확신 할 수 있도록 OpenGL은 모든 버퍼 작업을 밀어 버린다 glFlush()반환 즉시 곳으로 glFinish()블록 모든 작업이 완료 될 때까지.

정의를 읽은 후, 이것을 사용 glFlush()한다면 OpenGL이 실행할 수있는 것보다 더 많은 작업을 제출하는 문제에 부딪 힐 것이라고 생각했습니다. 그래서, 시도하기 위해, 나는 나의 프로그램 glFinish()을 a glFlush()와 lo로 바꾸었고 , 보라, 나의 프로그램이 (내가 말할 수있는 한) 똑같이 실행되었습니다. 프레임 속도, 리소스 사용량, 모든 것이 동일했습니다.

그래서 두 호출 사이에 많은 차이가 있는지 또는 내 코드로 인해 다르지 않게 실행되는지 궁금합니다. 또는 하나를 사용해야하는 곳과 다른 곳을 사용해야합니다. 또한 OpenGL은 glIsDone()버퍼링 된 모든 명령 glFlush()이 완료 되었는지 여부를 확인하는 것과 같은 호출이 있다고 생각했지만 (실행할 수있는 것보다 더 빨리 OpenGL에 작업을 보내지 않습니다) 그러한 기능을 찾을 수 없습니다 .

내 코드는 일반적인 게임 루프입니다.

while (running) {
    process_stuff();
    render_stuff();
}

답변:


93

이러한 명령은 OpenGL 초기부터 존재합니다. glFlush는 이전 OpenGL 명령 이 유한 한 시간 내에 완료 되도록합니다 ( OpenGL 2.1 사양 , 페이지 245). 프론트 버퍼에 직접 그리면 OpenGL 드라이버가 너무 많은 지연없이 그리기를 시작합니다. 각 개체 다음에 glFlush를 호출 할 때 화면에서 개체마다 나타나는 복잡한 장면을 생각할 수 있습니다. 그러나 이중 버퍼링을 사용할 때 glFlush는 버퍼를 교체 할 때까지 변경 사항이 표시되지 않기 때문에 사실상 전혀 효과가 없습니다.

glFinish 는 이전에 실행 된 명령 [...]의 모든 효과가 완전히 실현 될 때까지 반환되지 않습니다 . 즉, 모든 마지막 픽셀이 그려지고 OpenGL이 더 이상 할 일이 없을 때까지 프로그램 실행이 여기에서 대기합니다. 프런트 버퍼로 직접 렌더링하는 경우 glFinish는 운영 체제 호출을 사용하여 스크린 샷을 찍기 전에 수행해야하는 호출입니다. 강제로 완료 한 변경 사항을 볼 수 없기 때문에 이중 버퍼링에는 훨씬 덜 유용합니다.

따라서 이중 버퍼링을 사용하는 경우 glFlush도 glFinish도 필요하지 않을 것입니다. SwapBuffers는 암시 적으로 OpenGL 호출을 올바른 버퍼로 지정 하므로 glFlush를 먼저 호출 할 필요가 없습니다 . 그리고 OpenGL 드라이버를 강조해도 상관 없습니다. glFlush는 너무 많은 명령에 질식하지 않습니다. 이 호출이 즉시 반환된다는 보장은 없으므로 (의미하는 것이 무엇이든간에) 명령을 처리하는 데 필요한 시간이 걸릴 수 있습니다.


1
glFlush가 "유한 한 시간 내에 완료되어야합니다"라는 말은 무엇을 의미합니까? 그리고 나중에 "명령을 처리하는 데 필요한 시간이 걸릴 수 있기 때문에"glFlush가 질식하지 않을 것이라고 말합니까? (Caps mine) 상호 배타적이지 않습니까?
Praxiteles 2014 년

1
어느 시점에서 완료되는 한 FINITE 시간 기준을 충족합니다. 일부 운전자는이 전화를 전혀 사용하지 않습니다.
chrisvarnz

SwapBuffers는 컨텍스트에 따라 다르며 호출 스레드 컨텍스트 만 플러시하면됩니다. 여러 컨텍스트를 렌더링하는 경우 다른 컨텍스트를 통해 버퍼를 스왑 할 때 발생하는 것이 보장되지 않으므로 각 컨텍스트를 수동으로 플러시해야합니다.
Andreas

22

다른 답변에서 암시했듯이 사양에 따라 좋은 답변은 없습니다. 의 일반적인 의도는 glFlush()호출 후 호스트 CPU가 OpenGL 관련 작업을 수행하지 않고 명령이 그래픽 하드웨어로 푸시된다는 것입니다. 의 일반적인 의도는 glFinish()반환 된 후 남은 작업이 남아 있지 않으며 결과도 모든 적절한 비 OpenGL API (예 : 프레임 버퍼에서 읽기, 스크린 샷 등)를 사용할 수 있어야한다는 것입니다. 이것이 실제로 발생하는지 여부는 운전자에 따라 다릅니다. 이 사양은 합법적 인 것에 대해 많은 관용을 허용합니다.


18

나는 항상이 두 명령에 대해 혼란 스러웠지만이 이미지는 나에게 모든 것을 분명하게 보여 주었다. 플러시 vs 마감 분명히 일부 GPU 드라이버는 특정 수의 명령이 누적되지 않는 한 하드웨어에 명령을 보내지 않는다. 이 예에서 숫자는 5 입니다.
이미지는 실행 된 다양한 OpenGL 명령 (A, B, C, D, E ...)을 보여줍니다. 상단에서 볼 수 있듯이 큐가 아직 가득 차지 않았기 때문에 명령이 아직 실행되지 않습니다.

중간에서 우리 glFlush()는 대기열에있는 명령에 어떤 영향을 미치는지 봅니다 . 큐에있는 모든 명령을 하드웨어로 보내도록 드라이버에 지시합니다 (대기열이 아직 가득 차지 않은 경우에도). 이것은 호출 스레드를 차단하지 않습니다. 추가 명령을 보내지 않을 수도 있음을 운전자에게 알리는 것일뿐입니다. 따라서 대기열이 채워질 때까지 기다리는 것은 시간 낭비입니다.

맨 아래에는 glFinish(). glFlush()모든 명령이 하드웨어에 의해 처리 될 때까지 호출 스레드가 대기하도록한다는 점을 제외 하면과 거의 동일 합니다.

"OpenGL을 사용한 고급 그래픽 프로그래밍"책에서 가져온 이미지.


나는 실제로 무엇을 glFlush하고 무엇을하는지 알고 있으며 glFinish그 이미지가 무엇을 말하는지 말할 수 없습니다. 왼쪽과 오른쪽에 무엇이 있습니까? 또한 그 이미지가 퍼블릭 도메인에 공개되었거나 인터넷에 게시 할 수있는 라이선스에 따라 공개 되었습니까?
Nicol Bolas 2016

좀 더 자세히 설명 했어야했는데. 라이센스 정보 : 실제로는 잘 모르겠습니다. 조사하는 동안 Google에서 PDF를 우연히 발견했습니다.
Tara

7

성능 차이가 보이지 않는다면 뭔가 잘못하고 있다는 의미입니다. 다른 사람들이 언급했듯이 둘 다 호출 할 필요는 없지만 glFinish를 호출하면 GPU와 CPU가 달성 할 수있는 병렬 처리가 자동으로 손실됩니다. 더 자세히 살펴 보겠습니다.

실제로 드라이버에 제출하는 모든 작업은 일괄 처리되어 나중에 하드웨어로 전송됩니다 (예 : SwapBuffer 시간).

따라서 glFinish를 호출하는 경우 기본적으로 드라이버가 명령을 GPU로 푸시하고 (그때까지 일괄 처리되고 GPU에 작업을 요청하지 않음) 푸시 된 명령이 완전히 완료 될 때까지 CPU를 멈 춥니 다. 실행. 따라서 GPU가 작동하는 동안 CPU는 작동하지 않습니다 (적어도이 스레드에서는). 그리고 CPU가 작업을 수행 할 때마다 (대부분 일괄 처리 명령) GPU는 아무 작업도 수행하지 않습니다. 예, glFinish는 성능을 저하시킬 것입니다. (많은 명령이 이미 일괄 처리 된 경우 드라이버가 일부 명령에서 GPU 작업을 시작할 수 있으므로 이는 근사치입니다. 명령 버퍼가 상당히 많은 명령을 저장할 수있을만큼 커지는 경향이 있기 때문에 일반적이지 않습니다).

이제 왜 glFinish를 호출하겠습니까? 내가 사용했던 유일한 시간은 드라이버 버그가있을 때였습니다. 실제로 하드웨어로 보내는 명령 중 하나가 GPU와 충돌하는 경우, 어떤 명령이 원인인지 식별하는 가장 간단한 옵션은 각 Draw 후에 glFinish를 호출하는 것입니다. 이렇게하면 충돌을 정확히 유발하는 원인을 좁힐 수 있습니다.

참고로 Direct3D와 같은 API는 Finish 개념을 전혀 지원하지 않습니다.


5
"이제 glFinish를 호출하는 이유는 무엇입니까?" 한 스레드에서 리소스 (예 : 텍스처)를로드하고이를 사용하여 다른 스레드에서 렌더링하고 wglShareLists 또는 유사 항목을 통해 공유하는 경우 렌더링 스레드에 비동기 적으로로드 된 항목을 렌더링 할 수 있다는 신호를 보내기 전에 glFinish를 호출해야합니다.
Marco Mp

아래에서 말했듯이 이것은 드라이버 버그 해결 방법처럼 보입니다. 이 요구 사항에 대한 사양 언급을 찾을 수 없습니다. Windows에서는 드라이버가 잠금을 가져야하며 Mac에서는 CGLLockContext를 수행해야합니다. 그러나 glFinish를 사용하는 것은 매우 잘못된 것 같습니다. 텍스처가 언제 유효한지 알기 위해서는 어떤 경우에도 자체 잠금 또는 이벤트를 수행해야합니다.
starmole

1
opencl opengl interop docs는 동기화를 위해 glFinish를 권장합니다. "clEnqueueAcquireGLObjects를 호출하기 전에 응용 프로그램은 mem_objects에 지정된 객체에 액세스하는 보류중인 GL 작업이 완료되었는지 확인해야합니다. 이는 모두에서 glFinish 명령을 실행하고 완료 할 때까지 대기하여 이식 가능하게 수행 할 수 있습니다. 이러한 객체에 대한 보류중인 참조가있는 GL 컨텍스트 "
Mark Essel 2014 년

1
glFinish를 호출 할 필요가 없습니다. 동기화 개체를 사용할 수 있습니다.
chrisvarnz 2014-06-16

추가하자면, 원래 답변 이후 : 일부 GL 구현은 다른 스레드의 공유 컨텍스트간에 동기화하기 위해 flush / finish를 사용하기 시작했습니다. developer.apple.com/library/ios/documentation/3DDrawing/…- 특히 Apple IOS. 근본적으로 API의 또 다른 오용이라고 생각합니다. 그러나 이것은 내 원래 대답에 대한주의 사항입니다. 일부 구현에서는 마무리 / 플러시가 필요합니다. 그러나 구현은 OpenGL 사양이 아니라 정의 된 방법과 이유입니다.
starmole 2015-04-17

7

glFlush는 실제로 클라이언트 서버 모델로 거슬러 올라갑니다. 파이프를 통해 모든 gl 명령을 gl 서버로 보냅니다. 그 파이프는 버퍼링 될 수 있습니다. 모든 파일 또는 네트워크 I / O가 버퍼링 할 수있는 것과 같습니다. glFlush는 "버퍼가 아직 가득 차지 않았더라도 지금 전송하십시오!"라고만 말합니다. 로컬 시스템에서는 로컬 OpenGL API가 자체적으로 버퍼링 할 가능성이 적고 명령을 직접 실행하기 때문에 거의 필요하지 않습니다. 또한 실제 렌더링을 유발하는 모든 명령은 암시 적 플러시를 수행합니다.

반면에 glFinish는 성능 측정을 위해 만들어졌습니다. GL 서버에 대한 일종의 PING입니다. 명령을 왕복하고 서버가 "I am idle"이라고 응답 할 때까지 기다립니다.

요즘 현대의 지역 운전자는 유휴 상태라는 것이 무엇을 의미하는지 매우 창의적인 아이디어를 가지고 있습니다. "모든 픽셀이 그려집니다"또는 "내 명령 대기열에 공간이 있습니다"입니까? 또한 많은 오래된 프로그램이 코드 전체에 glFlush 및 glFinish를 코드 전체에 뿌렸 기 때문에 부두 코딩을하는 많은 최신 드라이버는 "최적화"로 무시합니다. 정말로 그들을 비난 할 수는 없습니다.

요약하자면 : 고대 원격 SGI OpenGL 서버용으로 코딩하지 않는 한 glFinish와 glFlush를 실제 작업이 아닌 것으로 간주합니다.


4
잘못된. 위의 답변에 남긴 주석에서와 같이 한 스레드에서 리소스 (예 : 텍스처)를로드하고이를 사용하여 다른 스레드에서 렌더링하고 wglShareLists 또는 유사 항목을 통해 공유하는 경우 렌더링 스레드에 신호를 보내기 전에 glFinish를 호출해야합니다. 비동기 적으로로드 된 것을 자유롭게 렌더링 할 수 있습니다. 그리고 그것은 당신이 말한 것처럼 아무 일도 아닙니다.
Marco Mp

정말? 스펙 링크가있는 공유 객체를 사용하기 전에 glFinish를 호출해야하는 필요성을 뒷받침 할 수 있습니까? 나는 이것을 필요로하는 버그가있는 드라이버를 완전히 볼 수있다. 그리고 그런 종류는 내가 말한대로 돌아갑니다. 사람들은 glFinish를 사용하여 버그가있는 드라이버를 해결합니다. 제대로 작동하는 드라이버 때문에 성능을 무시합니다. 프로파일 링 (및 단일 버퍼링 렌더링)의 원래 사양 사용 사례는 더 이상 작동하지 않습니다.
starmole

2
손상된 텍스처를 처리해야하는 개인적인 경험에 더하여 : higherorderfun.com/blog/2011/05/26/… 생각해 보면 뮤텍스 나 다른 동기화와 크게 다르지 않기 때문에 이치에 맞습니다 . 스레드 간 API-컨텍스트가 공유 리소스를 사용하기 전에 다른 사람이 해당 리소스의로드를 완료해야하므로 버퍼가 비워 졌는지 확인해야합니다. 차라리 사양 버그의 코너의 경우 더 생각하지만, 나는 :)이 진술에 대한 증거도 없어
마르코 헌병에게

감사합니다. 특히 "많은 오래된 프로그램이 코드 전체에 glFlush와 glFinish를 부두처럼 이유없이 뿌렸습니다."
akauppi

정말 작전이 없나요? 고강도 이미지 처리 또는 GPU 기반 수학 공동 처리에 glFinish 및 / 또는 glFlush가 매우 중요하지 않습니까? 예를 들어, 우리는 CPU까지 상기 픽셀 버퍼로부터 GPU 연산의 결과를 판독하지 계산 기입 된 모든 픽셀을 보장하기 glFinish 전화. 뭔가 빠졌나요?
Praxiteles 2014 년

5

봐 가지고 여기를 . 요약하면 다음과 같습니다.

glFinish ()는 glFlush ()와 동일한 효과를 가지며, glFinish ()는 제출 된 모든 명령이 실행될 때까지 차단됩니다.

다른 기사에서는 다른 차이점에 대해 설명합니다.

  • 스왑 함수 (이중 버퍼 응용 프로그램에서 사용)는 자동으로 명령을 플러시하므로 호출 할 필요가 없습니다. glFlush
  • glFinish OpenGL이 뛰어난 명령을 수행하도록 강제합니다. 이는 나쁜 생각입니다 (예 : VSync 사용).

요약하면, 이것은 스왑 버퍼 구현이 명령을 자동으로 플러시하지 않는 경우를 제외하고는 이중 버퍼링을 사용할 때 이러한 함수가 필요하지 않음을 의미합니다.


예, 맞습니다. 그러나 문서에는 예를 들어 창 시스템과 관련하여 몇 가지 차이점 이 있지만 둘 다 동일한 효과 가 있다고 말합니다 . 어쨌든 나는 내 대답을 편집)
AndiDog

뉘앙스에 대한 멋진 외침. glFlush () 및 THEN glFinish ()를 호출해야하는지 여부를 명확히합니다.-(위의 모든 내용을 읽은 후 질문했습니다.)
Praxiteles

4

버퍼의 상태를 쿼리하는 방법이없는 것 같습니다. 동일한 목적을 제공 할 수있는 이 Apple 확장 프로그램 이 있지만 크로스 플랫폼으로 보이지는 않습니다 (해보지 않았습니다.). 얼핏 보면 flush펜스 명령을 입력 하기 전인 것 같습니다 . 그런 다음 버퍼를 통해 이동할 때 펜스의 상태를 쿼리 할 수 ​​있습니다.

flush명령을 버퍼링하기 전에 사용할 수 있는지 궁금 하지만 다음 프레임 렌더링을 시작하기 전에 finish. 이렇게하면 GPU가 작동 할 때 다음 프레임 처리를 시작할 수 있지만 돌아올 때까지 완료되지 않으면 finish모든 것이 새 상태인지 확인하기 위해 차단됩니다.

나는 이것을 시도하지 않았지만 곧 시도 할 것입니다.

CPU 및 GPU를 사용하는 오래된 응용 프로그램에서 사용해 보았습니다. (원래 사용되었습니다 finish.)

flush끝과 finish시작 에서 변경했을 때 즉각적인 문제가 없었습니다. (모든 것이 괜찮아 보였습니다!) 아마도 CPU가 GPU에서 대기하지 않았기 때문에 프로그램의 응답 성이 증가했습니다. 확실히 더 나은 방법입니다.

비교 finished를 위해 프레임의 시작 부분을 제거 하고을 남겨 두었고 flush동일한 작업을 수행했습니다.

그래서 저는 use flushand 라고 말할 것입니다 finish.,를 호출 할 때 버퍼가 비어 있으면 finish성능 저하가 없기 때문입니다. 그리고 버퍼가 꽉 찼다면 finish어쨌든 원해야한다고 생각 합니다.


0

문제는 OpenGL 명령이 실행되는 동안 코드가 계속 실행되기를 원합니까 아니면 OpenGL 명령이 실행 된 후에 만 실행되기를 원합니까?

이는 네트워크 지연과 같은 경우 이미지를 그린 후에 만 특정 콘솔 출력을 갖는 경우에 중요 할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.