Difference between revisions of "Swap Interval"

From OpenGL Wiki
Jump to: navigation, search
m (glxSwapIntervalSGI converted to glXSwapIntervalSGI)
(External Links: Fixed external links.)
 
(12 intermediate revisions by 4 users not shown)
Line 1: Line 1:
When using double-buffered OpenGL, Swap Interval is a means of synchronizing the swapping of front and back frame buffers with a video card's vertical blanking period, AKA Vsync.
+
{{Disputed}}
  
The term "swap interval" itself refers to the number of vblank periods that must occur between buffer swaps.  A swap interval of 1 specifies that at the very least, the GPU must wait for a single vblank before swapping the front and back buffers. A swap interval of 0 specifies that the GPU should not wait for any vblanks, thus perform buffer swaps immediately.
+
'''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.
  
Application control of swap interval is provided via platform-specific [[extensions]].
+
Swap Interval control is provided via platform-specific [[OpenGL Extensions|extensions]].
  
== In Windows ==
+
== Usage ==
  
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 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.
  
The extension provides the wglSwapIntervalEXT() function, which directly specifies the swap interval. (e.g.  wglSwapIntervalEXT(1) to enable vsync;  wglSwapIntervalEXT(0) to disable vsync)
+
A call to the platform-specific buffer swapping function (such as {{code|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.
  
== In Linux / GLX ==
+
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.
  
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.
+
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.
  
The extension provides glXSwapIntervalSGI(), which also directly specifies the swap interval. (e.g. glXSwapIntervalSGI(1) to enable vsync; glXSwapIntervalSGI(0) to disable vsync)
+
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|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".
 +
 
 +
=== In Windows ===
 +
 
 +
Use the WGL_EXT_swap_control extension to control swap interval. Check both the standard extensions string via {{apifunc|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_EXT_swap_control extension to control swap interval. Check the GLX-specific extensions string via glXQueryExtensionsString() to verify that the extension is actually present.
 +
 
 +
The extension provides glXSwapIntervalEXT(), which also directly specifies the swap interval. glXSwapIntervalEXT(1) is used to enable vsync; glXSwapIntervalEXT(0) to disable vsync.
 +
 
 +
=== Adaptive Vsync ===
 +
 
 +
Recent GL drivers implement a new WGL/GLX extension called EXT_swap_control_tear. This extension brings "adaptive vsync" as featured in modern gaming consoles to the PC.
 +
 
 +
Adaptive vsync enables v-blank synchronisation when the frame rate is higher than the sync rate, but disables synchronisation when the frame rate drops below the sync rate. Disabling the synchronisation on low frame rates prevents the common problem where the frame rate syncs to a integer fraction of the screen's refresh rate in a complex scene.
 +
 
 +
Adaptive vsync can be enabled with wglSwapIntervalEXT(-1) or glXSwapIntervalEXT(-1).
  
 
== Idiosyncrasies ==
 
== Idiosyncrasies ==
  
 
* Some ATI GLX drivers may report WGL_EXT_swap_control yet actually export glXSwapIntervalSGI.
 
* 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.
+
* 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!"''' With swap interval set to non-zero, older traditional drivers typically caused the calling thread to block SwapBuffers until the actual buffer swap was completedIn modern drivers, the swap is blocked on the GPU, allowing the application CPU thread to continue execution and even render and enqueue subsequent frames before the first swap occurs.  This behavior could cause significant transport delay / latency if the application expects traditional behavior.  If the application requires either more deterministic behavior associated with vblank or minimal transport delay, the two following mechanisms can be used. Please note that these mechanisms trade the multi-frame bandwidth advantages of the GL's pipeline for minimized transport delay, thus making your application more sensitive and likely to "stutter" when getting close to frame real-time deadlines.
+
* "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 [[#GPU vs CPU synchronization|synchronization discussion below]].
** '''glFinish:''' A call to glFinish immediately after SwapBuffers causes the calling CPU thread to block until all queued GL commands are completed, ''including'' the actual buffer swap during vblank.
+
 
** '''GLX_SGI_video_sync:'''  GLX_SGI_video_sync provides a method to synchronize CPU thread execution to the completion of a full video frame, though not necessarily to the buffer swap.
+
== GPU vs CPU synchronization ==
 +
 
 +
To glFinish or not to glFinish, that is the question!
 +
 
 +
'''Swap interval = 1 without {{apifunc|glFinish}}:''' The buffer swapping command instructs the GPU to swap the front and back buffersThis command is typically treated like any other GL command, and is [[Synchronization|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.
  
 
== External Links ==
 
== External Links ==
* [http://www.opengl.org/registry/specs/EXT/wgl_swap_control.txt WGL_EXT_swap_control]
+
 
* [http://www.opengl.org/registry/specs/SGI/swap_control.txt GLX_SGI_swap_control]
+
* [https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_swap_control.txt WGL_EXT_swap_control]
* [http://www.opengl.org/registry/specs/SGI/video_sync.txt GLX_SGI_video_sync]
+
* [https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_swap_control.txt GLX_EXT_swap_control]
 +
* [https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_swap_control_tear.txt WGL_EXT_swap_control_tear]
 +
* [https://www.khronos.org/registry/OpenGL/extensions/EXT/GLX_EXT_swap_control_tear.txt GLX_EXT_swap_control_tear]
 +
 
 +
[[Category:General OpenGL]]

Latest revision as of 16:54, 17 June 2017

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.

Usage

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".

In Windows

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_EXT_swap_control extension to control swap interval. Check the GLX-specific extensions string via glXQueryExtensionsString() to verify that the extension is actually present.

The extension provides glXSwapIntervalEXT(), which also directly specifies the swap interval. glXSwapIntervalEXT(1) is used to enable vsync; glXSwapIntervalEXT(0) to disable vsync.

Adaptive Vsync

Recent GL drivers implement a new WGL/GLX extension called EXT_swap_control_tear. This extension brings "adaptive vsync" as featured in modern gaming consoles to the PC.

Adaptive vsync enables v-blank synchronisation when the frame rate is higher than the sync rate, but disables synchronisation when the frame rate drops below the sync rate. Disabling the synchronisation on low frame rates prevents the common problem where the frame rate syncs to a integer fraction of the screen's refresh rate in a complex scene.

Adaptive vsync can be enabled with wglSwapIntervalEXT(-1) or glXSwapIntervalEXT(-1).

Idiosyncrasies

  • 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.

External Links