|This article or section contains information that is contested. Further details can be found on the talk page.|
Swap Interval is a means of synchronizing the swapping of the front and back frame buffers with vertical blanks (v-blank): the hardware event where the screen image is updated with data from the front framebuffer . It is a very common means of preventing frame "tearing," (seeing half of one frame and half of another) as often seen in high-motion-content graphics.
Swap Interval control is provided via platform-specific extensions.
The term "swap interval" itself refers to the number of v-blanks that must occur before the front and back frame buffers are swapped. A swap interval of 1 tells the GPU to wait for one v-blank before swapping the front and back buffers. A swap interval of 0 specifies that the GPU should never wait for v-blanks, thus performing buffer swaps as soon as possible when rendering for a frame is finished. Video drivers can override these values, forcing a swap interval of 1 or 0 depending on settings the user provided in the video card's control panel.
A call to the platform-specific buffer swapping function (such as SwapBuffers in Windows) means that, once all previously issued drawing commands have completed, the contents of the back buffer should be swapped into the front buffer. Exactly when that happens is subject to the swap interval setting.
A swap interval greater than 0 means that the GPU may force the CPU to wait due to previously issued buffer swaps. For example, if the v-blank intervals come at 16.6ms intervals (60fps refresh), but the rendering of a frame only takes 4ms, then buffer swaps can back up. Therefore, the CPU driver will stall the rendering thread in an OpenGL command (it doesn't have to be in a buffer swapping command) if there are too many commands waiting for the v-blank.
Alternatively, if the renderer takes slightly longer than the v-blank intervals to render, say 18ms, then a different problem can result. It will effectively take two full v-blank intervals to display an image to the user, turning a 60fps program into a 30fps program. It will also induce stalls, for the same reason as above: the GPU has to wait 15.2ms every other v-blank interval for a buffer swap. Rendering calls made in that time will back up, eventually forcing a stall to wait for the actual swap.
Note that the problem of OpenGL commands backing up due to a waiting v-blank happen because these commands are trying to affect the back buffer. If they do not affect the back buffer, either by rendering to a framebuffer object, another form of off-screen buffer, or something else that isn't the back or front buffers, then these rendering commands can be scheduled as normal. Assuming that there are no other issues that would prevent such execution (trying to render to a buffer that is being read from, for example). Thus, one can ease the CPU burden on waiting for v-blanks by rendering to a third buffer, then blitting that to the back buffer, and then doing a swap. This is commonly called "triple buffering".
Use the WGL_EXT_swap_control extension to control swap interval. Check both the standard extensions string via glGetString(GL_EXTENSIONS) and the WGL-specific extensions string via wglGetExtensionsStringARB() to verify that WGL_EXT_swap_control is actually present.
The extension provides the wglSwapIntervalEXT() function, which directly specifies the swap interval. wglSwapIntervalEXT(1) is used to enable vsync; wglSwapIntervalEXT(0) to disable vsync.
In Linux / GLX
Use the GLX_SGI_swap_control extension to control swap interval. Check both the standard extensions string via glGetString(GL_EXTENSIONS) and the GLX-specific extensions string via glXQueryExtensionsString() to verify that the extension is actually present.
The extension provides glXSwapIntervalSGI(), which also directly specifies the swap interval. glXSwapIntervalSGI(1) is used to enable vsync; glXSwapIntervalSGI(0) to disable vsync.
- Some ATI GLX drivers may report WGL_EXT_swap_control yet actually export glXSwapIntervalSGI.
- Your application's use of swap interval may be overridden by external, driver-specific configuration. For example, forcing Vsync Off in a driver's control panel will prevent Vsync, even if swap interval is set to 1 in your application.
- "My rendered objects lag behind the mouse cursor, but only when Vsync is enabled!" You probably have several frames queued up in the GPU. You may want to consider calling glFinish. See the synchronization discussion below.
GPU vs CPU synchronization
To glFinish or not to glFinish, that is the question!
Swap interval = 1 without glFinish: The buffer swapping command instructs the GPU to swap the front and back buffers. This command is typically treated like any other GL command, and is executed by the GPU asynchronously from the CPU. However, because all subsequent rendering commands that affect the back buffer must wait until the back buffer has been swapped, these commands will pile up in the queue and eventually force a CPU synchronization. It is generally a good idea in this case to put the buffer swapping last in this case, and spend CPU time doing non-OpenGL tasks.
Swap interval = 1 with glFinish: The CPU thread can be synchronized with the buffer swap by calling glFinish() after issuing the swap. This introduces a penalty as it kills throughput advantages offered by the GL pipeline when the video card is under consistent activity. Video latency becomes the same as the vertical refresh period; at 60 Hz, this is 1/60th of a second or 16.666...ms. This method may save power on laptops, but may be less favorable for fast-paced games.
In one test case, in which "Wait for Vertical Refresh" was set to Always on both setups, an Intel graphics chipset from a 2011 Sandy Bridge laptop was found to exclude the buffer swap from glFinish, thus churning 1000 frames per second, and a PCI-e 2.0 AMD Radeon HD 3870 from 2008 was found to drop to 55fps with the addition of glFinish to SwapBuffers. If GPU<->CPU synchronization is desired, you should use a high-precision/multimedia timer rather than glFinish after a buffer swap.