JDK-6378181 : 2D needs a way to synchronize onscreen rendering with vertical retrace
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6,6u14
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-01-27
  • Updated: 2012-01-16
Currently, animations that move objects around on the screen quickly tend to have "tearing" artifacts, where the object is seen rendered partially in the new location and partially in the old location.  You can see this, for example, in the "ColorChooser" demo of SwingSet2; the curved figure animates very quickly, but you'll notice the tearing artifacts around the edges of the durved figure.

The tearing comes from the physical reality of how displays are updated; the VRAM pixels are updated some number of times per second (typically 60 for an LCD display, and anywhere from 60 - 90 for a typical CRT).  If you move an object on the screen at the same time as the retrace is happening in that area, the effect is that your object will show up partially in the new location (for those pixels that had not yet been serviced) and partially in the old location (where the pixels will not be updated until the next retrace).

The workaround for this problem with typical native applications is to call API that waits for the "vertical blank" interval, or the interval in time between finishing the
retrace for one frame and starting the retrace for the next fram; if you can perform your onscreen operation during that small window in time, then you will avoid the tearing artifacts because all pixels will be updated correctly by the time they are written out to the screen during retrace.

Java applications that run in fullscreen mode (such as some games) work around this problem by using our FlipBufferStrategy approach; when we "flip" the back buffer to the screen (which we can only do in fullscreen mode), we wait for the vertical blank (this option is specified in the Flip call in appropriate native APIs).

Java applications that run in windowed mode have no such facility; we do not use any native APIs to wait for the vertical blank before simply copying data to the screen; we just copy it as quickly as we can.

The fix here is threefold:
1) Establish the capability in native code to wait for the vertical blank before copying information to the screen.
2) Expose some simple API to allow applications to use this capability.  This could be something along the lines of a new BuffereCapabilities flag that provides a hint as to whether we should attempt to wait for the vertical blank.
3) Decide a policy for default Swing usage, or possibly expose more API so that applications using the Swing BufferStrategy implicitly can access this new capability.

EVALUATION The native code required here is simple. I hacked a prototype in our current code that consisted of the following: 1) in ddrawUtils.cpp, in the DDBlt() function: if (wsdoDst->window && waitForVB) { wsdoDst->ddInstance->ddObject->WaitForVerticalBlank(); } (where waitForVB is a flag that I set according to an environment variable) 2) In the DDraw object, I exposed the following wrapper function: void WaitForVerticalBlank() { dxObject->WaitForVerticalBlank(); }; 3) In DXObject, the following function actually executes the DirectX call that forces the wait: void WaitForVerticalBlank() { HRESULT hResult = ddObject->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); }; Note that this hack does not address the API issues involved; we need to find a better way of setting the waitForVB variable used above, possibly tied to BufferStrategy creation.