I have changed the synopsis to clarify the situation. This bug
no longer tracks the flickering issue in 6u10 (this one went away)
but the fact that embedded applets aren't hw accelerated
on Vista with DWM enabled. The resolution of this bug is pending
on when Microsoft comes up with the fix for DWM.
As mentioned above, this bug is no longer reproducible in 6u10 but
only because we put in a work around which disables hw acceleration
for embedded frames (note that off-screen acceleration is still
enabled, but there would be no way of copying that accelerated
offscreen surface to the screen).
An update. The issue had been filed with Microsoft. It is apparently
a known bug - if GDI operations are performed on the parent window
(like ScrollDC) the children (even clipped) which do D3D will not
show up correctly.
At this point we'll have to stick with the workaround which is
to disable hw acceleration for applets inside the browser
on Vista with Aero enabled (covered by this bug fix: 6675297).
Once Microsoft fixes the problem we'll re-evaluate - providing
there's a way to detect the fix and turn off the work around.
Alternatively we'll have to require certain OS patch level for
the end users.
Things got even more interesting once I have started testing
in the browsers.
IE (I tested 7) and FF (v3 b5) behave differently. Even with
-Dsun.awt.noerasebackground=true we get horrible flickering
while scrolling, and on IE the window doesn't even get
painted unless obscured by the edge of the frame or
It looks like this: once the Applet window cleares windows'
edge, it gets painted once, and then it just gets cleared
to the standard window color (verified by setting some
arbitrary color in Window Appearance dialog) not to ever repaint
again unless the Applet itself causes
a repaint - then it repaints fine.
So it appears that somehow DWM clears our window after
we render to it. It looks like somebody somewhere does
some GDI activity on our window which causes DWM to freak
out since the rest of the rendering to this window goes
None of this is reproducible on XP or on Vista if DWM is
disabled. It is not reproducible if Java2D's Direct3D pipeline
is disabled - there's no flickering at all.
I have tried to locate the responsible party - whoever
does something GDI-ish to our window. With -Dsun.awt.noerasebackground=true
I have guaranteed that AWT doesn't clear the background using
GDI, and Java2D only does D3D, so it must be something else.
The new plugin's AxControl window does call BeginPaint/EndPaint
but shouldn't matter since it's a parent window of ours, and
it does have the WS_CLIPCHILDREN style so in theory it could not
have affected our stuff. Just to make sure I have created another
child window inside our toplevel (a Canvas inside the Applet) - and
still got the same exact effect.
Just to be sure, I have replaced BeginPaint/EndPaint with
ValidateRgn in WM_PAINT handler - doesn't help.
The Window classes for AWT windows do not set the background brush
with registering the class (hbrBackground is NULL when
calling ::RegisterClass) so it is not that.
The window hierarchy in the browser (at least, with
the new plugin) looks something like this:
- Shell Doc Object View (IE's window) (0)
- Internet Explorer_Server (1)
- Java Plug-in Control Window (2)
- SunAwtFrame (3)
- SunAwtCanvas (4)
All of these windows have WS_CLIPCHILDREN style set, so even if
one of the parent windows did use gdi to clear their
backgrounds (for example: windows 0, 1, 2 set the their
background brushes in their window class) clearing in theory should
not have produced the clearing I'm seeing.
I have verified that if I do do ::FillRect with some odd color
in the WM_PAINT handler of window 2, whatever clears widnows 3,4
is rendered on top of 2 - as expected.
Since in theory rendering GDI and D3D to different windows within
the same hierarchy should be supported:
I think this is some kind of DWM bug, and we'll need to take
this issue to Microsoft.
Note that while the behavior is slightly different in FF3 - the window
does get repainted after it's cleared, it is only so because FF
sends a WM_PAINT every time the browser window is scrolled. I'm not
sure if this is intentional or accidental.
The problem is much harder to fix than it looked.
First, the background erasing happens on the Toolkit thread, which is
the Rendering thread for the D3D pipeline which means that
we can not take the render queue (or any other) locks.
This means that we can't just create a graphics object to use for clearing-
it may and will take the RQ lock (when creating or restoring the on-screen
surface). This could be worked around by creating
a graphics object when the canvas is first created and caching it.
The D3DScreenUpdateManager will update the surfaceData in the
graphics to be replaced when needed.
Another problem is that the on-screen surface flipping happens
on another thread (the screen updater thread) and we can not
synchroniusly flush it from the toolkit thread, unless we do a crude
hack and flip the surface ourselves - which may lead to issues
(what if the surface was just restored and the update manager didn't
have time to clear it - we'll flip it with some garbage).
So if we can not do synch flipping then the bg clearing may happen some
time (up to 100ms) later, which may cause artifacts.
Yet another issue is that the area to be cleared may not
be a rectangle, but a complex region. So if we were to use the
2D rendering code for clearing we'll need to get the clip region
and convert it to a shape which can be set to the graphics object.
That's not too bad, even if I had to trip over a few strange (to me) issues
(why would ::GetClipBox(dc) return REGION_COMPLEX, indicating a complex
clip region, but ::GetClipRgn(dc) return an empty region? I had to use
Even when this is done, there's another obstacle.
When the window is resized, the newly exposed regions need to
be cleared. But the 'on-screen' surface will not be of the right size
to cover the exposed area - the surface update happens some time
later. So we still see garbage in the newly exposed area during resize.
One would think that the expose events don't happen often on Vista
with DWM compositing enabled. This is not necessarily so.
For example, if the window is moved partly out of the screen and then
brought back, the area which was outside of the screen is receives
expose events. Why, why??? Supposedly the window is cached in a DWM's
texture, the window location shouldn't matter - it still has all the pixels!
Another case is scrolling. If a hw component is scrolled (like a Canvas
in a ScrollPane), it receives expose events and the newly exposed area
must be cleared, which is fine.
Suppose we're scrolling a canvas 300x300 and scroll it
through a viewport of 50x50. The d3d surface for onscreen rendering
to the canvas will be 300x300, and when it is flipped it sometimes
appears to render outside of the window. The area is quickly repaired
by the DWM manager, but it is still easy to see. This is clearly a DWM bug -
this should have been clipped.
(BTW, some of this happens even w/o the d3d - the scrollbars sometimes
become black when scrolling)
Anyway, at this point it appears that it will be very hard to come up
with a robust solution. We could certainly restrict the fix to
Vista with DWM enabled, but so far I haven't been able to find a
satisfactory solution (especially for resizing).
We could have some kind of hybrid - use GDI clearing for resizing and d3d
for normal expose events, in hope that resizing and further creation of
the d3d swap chain for this window resets DWM's machinery
so that when the resizing is complete and we start rendering with d3d
it doesn't cause issues.
This problem can be workaround by setting the following java2d property to false:
Much improvements can be seen with the above setting with the old java plugin with either IE7 or FF2 on Vista.
With the new java plugin with IE7, the repaint occurs with the above property set but flickering can be seen sometimes.
*** (#1 of 1): [ UNSAVED ] ###@###.###
The problem is reproducible only on Vista with DWM (Aero) enabled.
I have also seen complete failure to repaint the whole IE browser
window - there was some garbage from the background (outside of
the applet window) - that must have been IE bug.
Note that even with the D3D pipeline disabled I see a lot of flickering
in the ImageMap applet (when resizing the page, or causing the repaint
by any other means), and occasional scrolling artifacts.
The most likely cause for the repainting issues is the use of D3D and
GDI on the same window, which is broken^H^H^H^H^H^H prohibited on Vista.
There's at least one place in the AWT code where GDI's ::FillRect is
used on the canvas - when the canvas' background is cleared before repaint.
There's a flag which disables this behavior: -Dsun.awtnoerasebackground=true .
With this flag set the repainting issues pretty much
disappear - at least to the same level as with the d3d pipeline disabled.
There's a couple of ways of fixing this: either disable erasing the background
for windows to which we render with d3d - this may cause some compatibility
issues, or make awt go through Java2D painting code instead of calling
The latter will be trickier since the FillRect happens on the toolkit
thread in response to the "erase background" event, and with the D3D
pipeline the Toolkit thread is the rendering thread, so we must take
care not to take the RQ lock - in the same way it is done in
D3DSurfaceData.swapBuffers - by using trylock.
Even with this fix in place there may be some issues. In particular,
if an application uses BufferStrategy for active rendering we do not support
rendering to the screen with d3d (we have a mechanism for redirecting on-screen
rendering - which is impossible with d3d9 - to an off-screen d3d surface, but
it is disabled in cases like this), so the fillRect call will end up
a GDI operation directly to the window.
Note that for Swing applications we already disable background erase both
on resize and "erase bg" events.
Use the following java2d runtime property: