Difference between revisions of "Swap Interval"

From OpenGL Wiki
Jump to: navigation, search
(move detailed info out of summary, put glfinish explanation in subsection, remove disputed text.)
Line 1: Line 1:
 
{{Disputed}}
 
{{Disputed}}
  
'''Swap Interval''' is a means of synchronizing the swapping of the front and back frame buffers with vertical blanks: the periods in which the front frame buffer is dispatched for display on the screen.  It is a very common means of controlling frame "tearing," as often seen in high-motion-content graphics.
+
'''Swap Interval''' is a means of synchronizing the swapping of front and back frame buffers with vertical blanks: the events in which the front frame buffer is used to refresh the display on the screen.  It is a very common means of controlling frame "tearing," as often seen in high-motion-content graphics.
  
 
Swap Interval control is provided via platform-specific [[extensions]].
 
Swap Interval control is provided via platform-specific [[extensions]].
Line 7: Line 7:
 
== Usage ==
 
== Usage ==
  
The plaform-specific SwapBuffers() API commands the GPU to swap front and back buffers. When swap interval is set greater than zero, the swap takes place only during the vertical blanking period, thus eliminating the "torn" frame.
+
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 immediately. Some video drivers may force Swap Interval to 1 or to 0 if specified by the user in the video card's control panel.
  
The term "swap interval" itself refers to the number of v-blank periods that occur before the 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 not ever wait for v-blanks, thus performing buffer swaps immediately. Some video drivers may force Swap Interval to 1 or to 0 if specified by the user in the video card's control panel.
+
Assume that swap interval is set to 1.  By invoking SwapBuffers (which implicitly calls glFlush), the software assures the graphics card that when all drawing commands are completed, the back frame buffer will be a completely finished product which is ready for display on the screen. After the back frame buffer has been successfully updated, any successive calls to SwapBuffers() are held off until the front frame buffer is available again, at which time the driver may allow the buffers to be swapped back-to-back for a short period of time, in the traditional sense of double buffering. However, this wait will aggravate frame skipping when the system cannot render the image quickly enough to meet the refresh rate, more so than when swap interval is set to 0. Adding a third buffer (triple buffering) resolves this issue.
  
 
=== In Windows ===
 
=== In Windows ===
Line 27: Line 27:
 
* 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, 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]].
+
* "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]].
  
 
== GPU vs CPU synchronization ==
 
== GPU vs CPU synchronization ==
Line 33: Line 33:
 
To glFinish or not to glFinish, that is the question!
 
To glFinish or not to glFinish, that is the question!
  
'''Vsync without glFinish:''' SwapBuffers() commands the GPU to swap front and back buffers.  This command is typically treated like any other GL command, and is executed by the GPU asynchronously from the CPU.  As such, the CPU rendering thread does not block and is free to continue rendering and queuing subsequent frames, potentially at a higher rate than vertical refresh.  While this maximizes throughput, it creates a scenario where several frames are queued and awaiting buffer swap. A newly generated frame will not actually become visible until after all frames queued ahead of it are swapped, thus creating a visible transport delay.
+
'''Vsync without glFinish:''' SwapBuffers() 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.  As such, the CPU rendering thread does not block and is free to continue rendering subsequent frames. If the system can render 599 frames per second when the refresh rate is 60 Hz, 58 frames would be rendered obsolete by the 59th frame for the first v-blank. The 60th frame, being incomplete, would be carried over to the next v-blank. Video latency is (1/60)*((60-59)/60); 1/3600th of a second or 0.2777...ms.
  
'''Vsync with glFinish:''' The CPU thread can be synchronized with the buffer swap by calling glFinish() after SwapBuffers().  glFinish() causes the CPU thread to block until all queued commands are complete, including the buffer swap itself.  This ensures that every newly generated frame becomes visible after the next v-blank.  While this minimizes transport delay, it kills throughput advantages offered by the GL pipeline and increases the risk of "stutter" due to missed real-time frame deadlines.
+
'''Vsync with glFinish:''' The CPU thread can be synchronized with the buffer swap by calling glFinish() after SwapBuffers().  glFinish() causes the CPU thread to block until all queued commands are complete, including the buffer swap itself.  This introduces a slight 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 such as Unreal Tournament.
 +
: 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 SwapBuffers+glFinish.
  
 
== External Links ==
 
== External Links ==

Revision as of 05:22, 8 March 2012

Swap Interval is a means of synchronizing the swapping of front and back frame buffers with vertical blanks: the events in which the front frame buffer is used to refresh the display on the screen. It is a very common means of controlling frame "tearing," 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 immediately. Some video drivers may force Swap Interval to 1 or to 0 if specified by the user in the video card's control panel.

Assume that swap interval is set to 1. By invoking SwapBuffers (which implicitly calls glFlush), the software assures the graphics card that when all drawing commands are completed, the back frame buffer will be a completely finished product which is ready for display on the screen. After the back frame buffer has been successfully updated, any successive calls to SwapBuffers() are held off until the front frame buffer is available again, at which time the driver may allow the buffers to be swapped back-to-back for a short period of time, in the traditional sense of double buffering. However, this wait will aggravate frame skipping when the system cannot render the image quickly enough to meet the refresh rate, more so than when swap interval is set to 0. Adding a third buffer (triple buffering) resolves this issue.

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

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!

Vsync without glFinish: SwapBuffers() 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. As such, the CPU rendering thread does not block and is free to continue rendering subsequent frames. If the system can render 599 frames per second when the refresh rate is 60 Hz, 58 frames would be rendered obsolete by the 59th frame for the first v-blank. The 60th frame, being incomplete, would be carried over to the next v-blank. Video latency is (1/60)*((60-59)/60); 1/3600th of a second or 0.2777...ms.

Vsync with glFinish: The CPU thread can be synchronized with the buffer swap by calling glFinish() after SwapBuffers(). glFinish() causes the CPU thread to block until all queued commands are complete, including the buffer swap itself. This introduces a slight 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 such as Unreal Tournament.

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 SwapBuffers+glFinish.

External Links