JDK-6345743 : Vista DWM disabled when Toolkit.sync() is called
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_vista
  • CPU: x86
  • Submitted: 2005-11-03
  • Updated: 2008-02-06
  • Resolved: 2006-02-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6
1.4.2_18-revResolved 6 b73Fixed
Related Reports
Duplicate :  
The next version of Windows, Vista, uses a "Desktop Window Manager" (DWM) to combine the windows on the screen in such a way that effects like tranclucent title bars exist automatically.  This is done through using Direct3D textures as the surfaces that applications render to (instead of actual windows on the screen).

Operations that talk directly to the screen defeat this mechanism because the DWM cannot guarantee that the offscreen version of the desktop and windows will coincide exactly with the pixels on the screen.  Examples of such operations include using DirectDraw to lock the primary surface (which returns a pointer to the onscreen pixel buffer) and calling GDI's GetDC(NULL) (which returns an HDC which could be used to draw directly onto the screen).

When the DWM detects that such an operation is occurring, it disables itself and Vista renders in a more XP-like way.  The effect to the user is a momentary flash of the desktop and all windows are repainted with opaque title bars.  Thereafter (for the life of the offending process), all windows lack the translucency and warping effects that the DWM would typically use.  Once the process exits, there is another flash/repaint and the DWM is back in action.

In pre-Mustang releases, we performed operations such as these at startup time (for example, our initialization of DirectX would Lock/Unlock the primary surface just to test its validity), which causes the DWM to punt as soon as a Java app is started.

As of Mustang, we no longer perform such operations at startup.  This means that you can run a desktop Java app that looks good on Vista; title bars are still translucent and the DWM is still operational.  However, we still may execute such operations upon demand internally.

One example is Toolkit.sync().  In 1.4.*, we added the capability to sync() to flush the DirectX pipeline, which is necessary to avoid buffering up DirectX requests faster than they can be handled by the graphics card.  One effective way to flush these commands is to Lock/Unlock the primary surface, so that's the way we made it work.  In a later tweak, we limited the lock to a small region of the screen (to avoid flashing artifacts with various GDI rendering operations), but we're still taking a lock on the onscreen pixels.
This causes the DWM to punt for any Java application that calls sync().

In Windows Vista (I used build 5231, but presumably any version with DWM will behave the same) run the attached application, SyncTester.  There are two buttons in the window.  Ignore the "AWT Frame" button (I added that just to make sure that other functionality did not force a DWM punt).  Click on the "sync" button and watch the flash/repaint artifact occur.  We've cause the DWM to punt because we've called Lock/Unlock on the desktop.

EVALUATION I modified the test case only render to the offscreen surface - meaning no blit from offscreen surface (back-buffer) to the screen. So instead of a typical loop blt offscreen surface (sprite) to back-buffer blt back-buffer to the screen sync calculateFPS I did blt offscreen surface (sprite) to back-buffer sync calculateFPS (see the changes to the test - a new "-noblt" parameter) And example of where we could run into this is J2DBench: we sync and take the timing when rendering to offscreen surface w/o copying them to the screen. This proved to be an interesting experiment. It showed that we do need to touch the sync surface prior to locking to get more consistent results on Vista. Here's a table I came up with after running a bunch of tests on my Vista system: | with WDM | without WDM | | onscr | offscr |off only| onscr | offscr |off only| ddraw | | | | | | | touch | 212/30 | 172/21 | 262/40 | 205/25 | 328/55 | 522/104| no touch| 230/35 | 189/20 | Inf/Nan| 210/27 | 374/58 | 645/215| d3d | | | | | | | touch | ---/-- | 299/53 | 780/800| ---/-- | 505/106|1028/791| no touch| ---/-- | 358/69 | Inf/Nan| ---/-- | 650/152| Inf/NaN| With/Without WDM - with WDM enabled or disabled touch/no touch - run version with/without touching the offscreen sync surface onscr: offscreen -> screen + sync offscr: offscreen -> offscreen surface(backbuffer) -> screen + sync off only: offscreen -> offscreen + sync The numbers: XXX/YYY : average FPS was XXX with Standard Deviation YYY As you can see the numbers are all screwed up if we don't touch the sync surface. Also, it appears that the Display manager has some weird effects on performance. Interestingly, I get similar effect on Windows XP: the "offscreen only" experiment's numbers are all over, often with Infinity/Nan as FPS/StD . So we have a similar issues there even now when we lock the primary surface. Unfortunately, trying to use the same code path we have for Vista on Windows XP didn't yield the same results: the numbers were still out of whack mostly. So it looks that just taking this new code and using it on XP won't work. More investigation required for this part. But the fix we'll use for Vista is to create a sync surface, and render to it prior to locking for each sync.

EVALUATION It appears that creating an offscreen surface which we lock instead of primary works well. We don't even need to Blt to it, just lock/unlock. For example, running (a slightly modified) SyncTest.java on Vista and XP produces the following results. This is a standard deviation for the frames per second with different locking techniques. The lower the deviation the better. No Sync | GDI sync |Lock Primary |Lock Offscreen | -------------------------|----------|--------------|----------------| Vista 43 | 42 | 61| 39| ATI Mobility | | | | Radeon 9600 | | | | | | | | XP 47 | 39 | 4| 5| Nvidia | | | | GF FX5200 | | | | | | | | XP 19 | 22 | 24| 20| Intel i852 | | | | The intel and ati boards were on notebooks may be that could explain weird results. I'll run some more tests before committing to the fix.

WORK AROUND Disabling ddraw would fix this - if we are not using ddraw then we do not call DDraw's Lock function on the primary during Toolkit.sync(). -Dsun.java2d.noddraw=true

EVALUATION There is still no clear way to "flush" all DirectX commands. However, according to Microsoft, it may be good enough to either: 1) flush the surface we really care about or 2) flush any surface that we've just rendered to (1) seems like the better approach. If we can figure out whether there is a main offscreen surface that we're dealing with (such as the Swing back buffer), then we could call Lock/Unlock on that surface which should call all operations to that surface (and potentiall to all DX surfaces) to flush first. Failing (1), we could allocate a small surface that we use just for this purpose. Whenever we want to sync(), we call Blit (say, of a 1x1 colorfill) to that surface then call Lock/Unlock on that surface. At a minimum, the GPU would have to flush that Blit operation prior to Locking the surface. But hopefully (depending on how clever the drivers and hardware are) it would actually flush all of DirectX prior to the Lock call.