opengl: glFlush() vs. glFinish()
Asked Answered
D

9

126

I'm having trouble distinguishing the practical difference between calling glFlush() and glFinish().

The docs say that glFlush() and glFinish() will push all buffered operations to OpenGL so that one can be assured they will all be executed, the difference being that glFlush() returns immediately where as glFinish() blocks until all the operations are complete.

Having read the definitions, I figured that if I were to use glFlush() that I would probably run into the problem of submitting more operations to OpenGL than it could execute. So, just to try, I swapped out my glFinish() for a glFlush() and lo and behold, my program ran (as far as I could tell), the exact same; frame rates, resource usage, everything was the same.

So I'm wondering if there's much difference between the two calls, or if my code makes them run no different. Or where one should be used vs. the other. I also figured that OpenGL would have some call like glIsDone() to check whether or not all the buffered commands for a glFlush() are complete or not (so one doesn't send operations to OpenGL faster than they can be executed), but I could find no such function.

My code is the typical game loop:

while (running) {
    process_stuff();
    render_stuff();
}
Desmoid answered 26/1, 2010 at 22:41 Comment(0)
H
107

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.

Hallow answered 27/1, 2010 at 0:28 Comment(4)
What do you mean that glFlush "must complete in FINITE time" and then later say, that glFlush will not choke because "it can take ANY time it needs to process your commands"? (Caps mine) Aren't those mutually exclusive?Predetermine
As long as it finishes at some point it meets the FINITE time criteria. Some drivers no-op this call entirely.Submariner
SwapBuffers is context specific and only need to flush the calling thread context. If rendering multiple contexts each should be flushed manually as it is not guearanteed to happen when swapping buffers through another context.Kathlenekathlin
when i play with some fragment shader editors i notice that some uniform variables don't get updated in some frames( for example when touching an small delay may occurs in updating time uniform), can glFinish solve the problem here?(calling glFinish after updating uniform variables)Barratry
T
30

I was always confused about those two commands too, but this image made it all clear to me: Flush vs Finish 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".

Trautman answered 11/7, 2016 at 0:40 Comment(2)
I actually know what glFlush and glFinish do, and I can't tell what that image is saying. What's on the left side and the right? Also, was that image released in the Public Domain or under some license that allows you to post it on the Internet?Calvados
I should have elaborated a bit. About the license: I am actually not quite sure. I stumbled upon the PDF on google, while doing research.Trautman
A
26

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.

Avina answered 27/1, 2010 at 0:0 Comment(0)
R
9

If you did not see any performance difference, it means you're doing something wrong. As some others mentioned, you don't need to call either, but if you do call glFinish, then you're automatically losing the parallelism that the GPU and CPU can achieve. Let me dive deeper:

In practice, all the work you submit to the driver is batched, and sent to the hardware potentially way later (e.g. at SwapBuffer time).

So, if you're calling glFinish, you're essentially forcing the driver to push the commands to the GPU (that it batched till then, and never asked the GPU to work on), and stall the CPU until the commands pushed are completely executed. So during the whole time the GPU works, the CPU does not (at least on this thread). And all the time the CPU does its work (mostly batching commands), the GPU does not do anything. So yeah, glFinish should hurt your performance. (This is an approximation, as drivers may start having the GPU work on some commands if a lot of them were already batched. It's not typical though, as the command buffers tend to be big enough to hold quite a lot of commands).

Now, why would you call glFinish at all then ? The only times I've used it were when I had driver bugs. Indeed, if one of the commands you send down to the hardware crashes the GPU, then your simplest option to identify which command is the culprit is to call glFinish after each Draw. That way, you can narrow down what exactly triggers the crash

As a side note, APIs like Direct3D don't support a Finish concept at all.

Rubella answered 27/1, 2010 at 20:14 Comment(5)
On "Now, why would you call glFinish at all then". If you are loading resources (e.g.: textures) on one thread and using them to render on another, with sharing through wglShareLists or similars, you need to call glFinish before signaling to the rendering thread that it's free to render what has been asynchronously loaded.Oscitant
As I said below, this does look like a driver bug workaround. I can't find any spec mention of this requirement. On windows the driver must take a lock, on mac you have to do CGLLockContext. But using glFinish seems very wrong. To know when a texture is valid you have to do your own lock or event in any case.Farrah
opencl opengl interop docs recommend glFinish for synchronization "Prior to calling clEnqueueAcquireGLObjects, the application must ensure that any pending GL operations which access the objects specified in mem_objects have completed. This may be accomplished portably by issuing and waiting for completion of a glFinish command on all GL contexts with pending references to these objects"Madisonmadlen
you don't "need" to call glFinish, you can use sync objects.Submariner
Just to add, since the original answer: Some GL implementations started to use flush/finish to sync between shared contexts on different threads: developer.apple.com/library/ios/documentation/3DDrawing/… - Most notably Apple IOS. I think it's fundamentally another misuse of the API. But this is a caveat to my original answer: On some implementations finish/flush are needed. But the how and why is implementation defined, not OpenGL spec.Farrah
T
8

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:

  • Swap functions (used in double-buffered applications) automatically flush the commands, so no need to call 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.

Tsui answered 26/1, 2010 at 22:51 Comment(2)
Yes right, but the document says that both have the same effect with only few differences concerning the window system, for example. But anyway I edited my answer ;)Tsui
Nice call out on the nuance. It clarifies whether it is necessary to call glFlush() and THEN glFinish() - (a question we had after reading everything above.)Predetermine
F
7

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.

Farrah answered 22/5, 2012 at 9:38 Comment(5)
Wrong. As in the comment I left in the answer above: If you are loading resources (e.g.: textures) on one thread and using them to render on another, with sharing through wglShareLists or similars, you need to call glFinish before signaling to the rendering thread that it's free to render what has been asynchronously loaded. And it's not a no-op like you said.Oscitant
Really? Can you back this up the need to call glFinish before using a shared object with some spec link? I can totally see a buggy driver that needs this. And that kind of gets back to what I said. People use glFinish to work around buggy drivers. Because of that drivers that work properly ignore it for performance. The original spec use case of profiling (and single buffered rendering) does not work anymore.Farrah
Personal experience of having to deal with corrupted textures, plus this: higherorderfun.com/blog/2011/05/26/… If you think about it, it makes sense, however, as it's not very different from having mutexes or other synch.api between threads - before a context can use a shared resource the other has to complete the loading of that resource, thus the need to ensure the buffer has been emptied. I think more of corner-case of the specs rather the bug, but I've no proof for this statement :)Oscitant
Awesome answer, thanks. Especially "many old programs sprinkled glFlush and glFinish throughout their code without reason as voodoo".Gregoire
Is it really no ops? Aren't glFinish and/or glFlush highly valuable for high intensity image processing or GPU based math coprocessing? For example, we don't read the results of the GPU computation from the pixel buffer to the CPU until after calling a glFinish to ensure all pixel computations have been written. Are we missing something?Predetermine
D
4

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.

Dinner answered 26/1, 2010 at 22:59 Comment(0)
I
0

The question is: do you want your code to continue running while the OpenGL commands are being executed, or only to run after your OpenGL commands has been executed.

This can matter in cases, like over network delays, to have certain console output only after the images have been drawn or the such.

Ism answered 26/1, 2010 at 23:7 Comment(0)
A
0

If you look at the documentation, it is clarified: glFinish

glFinish does not return until the effects of all previously called GL commands are complete. Such effects include all changes to GL state, all changes to connection state, and all changes to the frame buffer contents.

glFlush

Note:
glFlush can return at any time. It does not wait until the execution of all previously issued GL commands is complete.

Abnormity answered 8/3 at 9:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.