JDK-6630702 : D3D: Rendering artifacts when scrolling/dragging on Vista with Aero/DWM [multiple boards]
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6u10
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_vista
  • CPU: x86
  • Submitted: 2007-11-16
  • Updated: 2010-10-15
  • Resolved: 2008-01-08
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.
6u10 b10Fixed
Related Reports
Relates :  
As discussed in this thread:

On Windows Vista (multiple machines, video boards),
only with Aero (DWM) enabled, some swing applications
produce rendering artifacts when scrolling or
dragging internal frames. Doesn't happen if Aero
is disabled (even while the application is running) 
by selecting "Vista Basic" color theme in the 
Appearance dialog.

For example, run this this Substance L&F demo
(note that the look and feel doesn't matter, it's
reproducible with all L&Fs):
  javaws https://substance.dev.java.net/webstart/test.jnlp

Play around with the pane on the left side - 
expand/collapse the "tasks". The click at
"List" tab on the right pane, and scroll
the list. The scrolled area then becomes
black or white (depending on laf).

Similar thing happens in the "Desktop" tab - create
a new Internal frame and drag it around - it
produces similar artifacts.
This indicates that the problem is caused
by the copyArea() call.

Interestingly, if the app loses focus and then gains
it back (alt+tab x2) the repainting problems stop until 
the task is collapsed/expanded at which point
they appear again.

SUGGESTED FIX http://sa.sfbay.sun.com/projects/java2d_data/6u10/6630702.0

EVALUATION The solution we're working on is disabling Swing's "true double-buffering" mode on Vista with DWM(Aero) enabled. From the code review: With buffer per window disabled Swing will use VolatileImage as back-buffer and that will allow the D3D pipeline to guarantee that no on-screen rendering will occur since our mechanism will be working. Another reason is that since Aero already does double-buffering there's no point in wasting resources, the application doesn't get expose events anyway. This solution is also less risky than changing the way Swing paints on all platforms. Notes about the implementation: while the state of DWM compositing can change during the lifetime of the application it is an extremely rare event, and is in most cases temporary (some app turns it off, then re-enables it). So if it was turned on when we started we'll detect it and not use buffer per window. If they disable it during the runtime - no big deal, everything will look sucky (flashing) anyway and we'll be no exception. If we find that we do need to handle runtime changes - they're easy to handle, just add a listener mechanism to Win32GraphicsEnv (espose through some shared interface), and have BufferStrategyPaintManager listen to those events and disable bpw if needed.

EVALUATION OK, I've investigated this a bit more. This is an issue with DWM, but it is caused by our code. Essentially it is caused by doing D3D and GDI rendering to the same window which is a bad idea on Vista - it's pretty much broken. Unfortunately in some situations Swing allows rendering directly to the screen - which is what happens in this case. The JXCollapsiblePane widget does some animation on collasing/expanding. As part of that animation it apparently first paints the component to an off-screen image. This triggers a special code path in BufferStrategyPaintManager: at javax.swing.BufferStrategyPaintManager$BufferInfo.setInSync(BufferStrategyPaintManager.java:719) at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:293) at javax.swing.RepaintManager.paint(RepaintManager.java:1172) at javax.swing.JComponent.paint(JComponent.java:1014) at org.jdesktop.swingx.JXCollapsiblePane$WrapperContainer.makeImage(JXCollapsiblePane.java:826) at org.jdesktop.swingx.JXCollapsiblePane$WrapperContainer.showImage(JXCollapsiblePane.java:795) at org.jdesktop.swingx.JXCollapsiblePane$AnimationListener.reinit(JXCollapsiblePane.java:770) at org.jdesktop.swingx.JXCollapsiblePane.setCollapsed(JXCollapsiblePane.java:475) at org.jdesktop.swingx.JXTaskPane.setExpanded(JXTaskPane.java:386) at org.jdesktop.swingx.plaf.basic.BasicTaskPaneUI$ToggleListener.mouseReleased(BasicTaskPaneUI.java:367) at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:272) The setInSync() indicates to the paint manager that the back-buffer is no longer in sync with what's on the screen. After this all copyAreas get redirected to the screen instead of the back-buffer (why only copyAreas?). It's not clear why doing painting to another offscreen surface necessarily indicates an out of sync back-buffer though. Now, the D3D pipeline does special handling for rendering to the screen - it redirects all rendering to a dedicated back-buffer, a sort of "fake window", which is presented to the screen when needed. That way we can still accelerated on-screen rendering using Direct3D (direct on-screen rendering is not possible with Direct3D 9). However, this special handling is disabled for windows which have their own BufferStrategy - which is the case here, since Swing uses BufferStrategy as a back-buffer when it is in "bufferPerWindow" mode - aka the "gray rect fix", or "true double-buffering". Because of that the rendering goes directly to the screen, so the copy area is performed using GDICopyArea. It works fine XP, but produces artifacts on Vista with Aero. Looking at the latest code for JXCollapsiblePane it looks like it no longer uses this approach for doing their animation, so it could be that this particular case will no longer trigger the issue, but the underlying problem is still there of course. Since all circumstances under which Swing may switch from buffer per window mode to the "regular" one, or allow on-screen rendering, are not clear it doesn't seem likely that we could fix swing's "buffer out of sync" cases. One solution would be to use the old painting mode - where Swing's back-buffer is a VolatileImage which is copied to the screen - in this case the D3D pipeline's on-screen rendering support will ensure that one never renders directly to the screen. Since Aero is already double-buffered (which in particular means that applications don't get 'expose' events when another window is moved over their window) the 'true double-buffering' doesn't really give any advantages. More investigation is needed. Note: it is possible that this is the cause of other issues on Vista like the one described here: http://forums.java.net/jive/thread.jspa?threadID=32535&tstart=0 It looks especially plausible since disabling buffer per window also helped there.

EVALUATION This looks like a problem in Vista's DWM (since it's video board-agnostic), but I'm not sure why is it triggered by the JXTaskPane.

WORK AROUND Disable Swing's "true double-buffering": -Dswing.bufferPerWindow=false .