Synchronization is the process of ensuring that the OpenGL rendering pipeline has fully issued or executed the commands that you have given it.
OpenGL rendering commands are assumed to be asynchronous. If you call any of the
glDraw* to initiate rendering, it is not at all guaranteed that when this call returns that rendering has finished. Indeed, it is perfectly legitimate for rendering to not even have started when this function returns. The OpenGL specification allows implementations the freedom to get around to rendering commands whenever it is best for them.
This is not a weakness of OpenGL; indeed, it is a strength. It allows for many optimizations of the rendering command pathway. Issuing a command to the internal rendering command buffer can be a fairly slow process, due to a CPU transition (on x86 hardware) out of protected mode and into unprotected mode. This transition eats up a lot of cycles, so if you can issue 30 commands with only one transition, this is better than making one transition per command.
glDraw*command returns. This is usually done as a simple mem-copy from your client arrays into renderer-side memory. Indeed, any function that involves client-side memory must finish using that client-side memory before it returns.
All of this means that OpenGL is a very asynchronous renderer.
An OpenGL rendering command can be in one of three conceptual states: unissued, issued but not complete, and complete. A complete command means that it is out of the pipeline entirely. Its effects have been written to the framebuffer (or transform buffers, if that is what was being used), and so forth.
Asynchronous rendering is nice. However, it is often useful to synchronize your actions with OpenGL. And OpenGL provides several alternatives for doing so.
OpenGL provides two simple mechanisms for explicit synchronization:
The simplest to understand is
glFinish. It will not return, stopping the current thread, until all rendering commands that have been sent have completed.
The behavior of
glFlush is less simple to define. Calling it means that all commands will execute in "finite time".
Some operations implicitly force a full
glFinish synchronization, while others force the user to halt until all commands up to a certain point have completed.
Swapping the back and front buffers on the default framebuffer (
wgl/glxSwapBuffers) will force a synchronization, if there are still commands affecting the default framebuffer that have not yet completed. Swapping buffers only technically needs to sync to the last command that affects the default framebuffer, but it may perform a full
Any attempt to read from a framebuffer will halt until all rendering commands affecting that framebuffer have completed. Most attempts to write to a buffer object, either with
glBufferSubData or mapping, will halt until all rendering commands reading from that buffer object have completed. However, if you use
glBufferData(target, NULL), this allows the implementation to allocate new storage for the buffer and simply orphan the old one (deleting it when it is no longer used). You can do something similar by using the GL_MAP_INVALIDATE_BUFFER_BIT with
If you use the GL_MAP_UNSYNCHRONIZED_BIT with
glMapBufferRange, OpenGL will forego any synchronization operations; you are on your own however as to the consequences of modifying a buffer that is in use.
Similarly, attempts to change texture data with commands like
glTexSubImage2d will block until commands that use that texture have finished.
There may be a few commands that, on some implementations, cause a synchronization to some point in the command stream. OpenGL does not require these commands to do so, but implementations are free to do so if they deem it necessary. Framebuffer object binding and rendering may cause a sync to the last command that affected the previously bound framebuffer object.
glFinish is a decent start on synchronization. However, it is often useful to be able to do the kind of synchronization that OpenGL itself does implicitly. That is, being able to sync to a specific point in the command stream.
You do this by creating a fence object. This is a token in the command stream that you can test to see if it has been completed. Since the stream is an ordered list, if the fence has completed, then every command issued before that fence has also completed.