I\'m having trouble distinguishing the practical difference between calling glFlush()
and glFinish()
.
The docs say that glFlush()
Have a look here. In short, it says:
glFinish() has the same effect as glFlush(), with the addition that glFinish() will block until all commands submitted have been executed.
Another article describes other differences:
glFlush
glFinish
forces OpenGL to perform outstanding commands, which is a bad idea (e.g. with VSync)To sum up, this means that you don't even need these functions when using double buffering, except if your swap-buffers implementation doesn't automatically flush the commands.
glFlush really dates back to a client server model. You send all gl commands through a pipe to a gl server. That pipe might buffer. Just like any file or network i/o might buffer. glFlush only says "send the buffer now, even if it is not full yet!". On a local system this is almost never needed because a local OpenGL API is unlikely to buffer itself and just issues commands directly. Also all commands that cause actual rendering will do an implicit flush.
glFinish on the other hand was made for performance measurement. Kind of a PING to the GL server. It roundtrips a command and waits until the server responds "I am idle".
Nowadays modern, local drivers have quite creative ideas what it means to be idle though. Is it "all pixels are drawn" or "my command queue has space"? Also because many old programs sprinkled glFlush and glFinish throughout their code without reason as voodoo coding many modern drivers just ignore them as an "optimization". Can't blame them for that, really.
So in summary: Treat both glFinish and glFlush as no ops in practice unless you are coding for an ancient remote SGI OpenGL server.
There doesn't seem to be a way of querying the status of the buffer. There is this Apple extension which could serve the same purpose, but it doesn't seem cross-platform (haven't tried it.) At it quick glance, it seems prior to flush
you'd push the fence command in; you can then query the status of that fence as it moves through the buffer.
I wonder if you could use flush
prior to buffering up commands, but prior to beginning to render the next frame you call finish
. This would allow you to begin processing the next frame as the GPU works, but if it's not done by the time you get back, finish
will block to make sure everything's in a fresh state.
I haven't tried this, but I will shortly.
I have tried it on an old application that has pretty even CPU & GPU use. (It originally used finish
.)
When I changed it to flush
at end and finish
at begin, there were no immediate problems. (Everything looked fine!) The responsiveness of the program increased, probably because the CPU wasn't stalled waiting on the GPU. Definitely a better method.
For comparison, I removed finished
from the start of the frame, leaving flush
, and it performed the same.
So I would say use flush
and finish
, because when the buffer is empty at the call to finish
, there is no performance hit. And I'm guessing if the buffer were full you should want to finish
anyway.
As the other answers have hinted, there really is no good answer as per the spec. The general intent of glFlush()
is that after calling it, the host CPU will have no OpenGL-related work to do -- the commands will have been pushed to the graphics hardware. The general intent of glFinish()
is that after it returns, no remaining work is left, and the results should be available too all appropriate non-OpenGL APIs (e.g. reads from the framebuffer, screenshots, etc...). Whether that is really what happens is driver-dependent. The specification allows a ton of latitude as to what is legal.
I was always confused about those two commands too, but this image made it all clear to me:
Apparently some GPU drivers don't send the issued commands to the hardware unless a certain number of commands has been accumulated. In this example that number is 5.
The image shows various OpenGL commands (A, B, C, D, E...) that have been issued. As we can see at the top, the commands don't get issued yet, because the queue isn't full yet.
In the middle we see how glFlush()
affects the queued up commands. It tells the driver to send all queued up commands to the hardware (even if the queue isn't full yet). This doesn't block the calling thread. It merely signals the driver that we might not be sending any additional commands. Therefore waiting for the queue to fill up would be a waste of time.
At the bottom we see an example using glFinish()
. It almost does the same thing as glFlush()
, except that it makes the calling thread wait till all commands have been processed by the hardware.
Image taken from the book "Advanced Graphics Programming Using OpenGL".
Mind that these commands exist since the early days of OpenGL. glFlush ensures that previous OpenGL commands must complete in finite time (OpenGL 2.1 specs, page 245). If you draw directly to the front buffer, this shall ensure that the OpenGL drivers starts drawing without too much delay. You could think of a complex scene that appears object after object on the screen, when you call glFlush after each object. However, when using double buffering, glFlush has practically no effect at all, since the changes won't be visible until you swap the buffers.
glFinish does not return until all effects from previously issued commands [...] are fully realized. This means that the execution of your program waits here until every last pixel is drawn and OpenGL has nothing more to do. If you render directly to the front buffer, glFinish is the call to make before using the operating system calls to take screenshots. It is far less useful for double buffering, because you don't see the changes you forced to complete.
So if you use double buffering, you probably won't need neither glFlush nor glFinish. SwapBuffers implicitly directs the OpenGL calls to the correct buffer, there's no need to call glFlush first. And don't mind stressing the OpenGL driver: glFlush will not choke on too many commands. It is not guaranteed that this call returns immediately (whatever that means), so it can take any time it needs to process your commands.