Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6648018
Votes 0
Synopsis PIT: D3D: Copying VolatileImage to the window of small size causes an infinite validation loop
Category java:classes_2d
Reported Against b10
Release Fixed 6u10(b11)
State 10-Fix Delivered, Verified, bug
Priority: 2-High
Related Bugs 6596702
Submit Date 08-JAN-2008
Description
I am rendering a volatile image on to a frame and validating it within the paint method of the frame. When the frame appears, try doing any of the following -

1. Open display settings and change the color depth to 16 bit. 
2. resize the frame inward so that frame becomes as small as 20x20.

The above operations make the validation loop run infinitely. This is reproducible only on 6u10-b10 PIT build and not reproducible on b09. Not reproducible on earlier releases (ddraw, d3d on jdk6-fcs) and hence a regression in D3D. I reproduced it on WinXP, WinVista Home Premium with ATI as well as Nvidia video boards. 

Run the test -  VolatileFlushTest_new.java. When the frame appears, reduce the size of the frame to 20x20 or lesser. You will see the infinite loop on the console.

(The same issue can be reproduced with another test also - VolatileFlushTestCanvas).
Posted Date : 2008-01-08 06:33:08.0
Work Around
N/A
Evaluation
The bug is caused by the fix for 
  6596702: D3D: intermittent repainting issues in SwingSet after restoring from fs mode

In particular, the part in D3DBlitLoop where we mark the
source surface lost if VI is copied to a screen surface.

If the screen surface can not be replaced by a onscreen 
d3d surface we'll spin in the validation loop forever.
Which does happen if the window is too small for the
d3d onscreen rendering mechanism to work, or say there's a
buffer strategy created for this window.

The reason the original change was made was to avoid
disabling hw acceleration for the source VI during
transient stages of surface restoration (say when
a display change occurs, or any other event which caused
the onscreen d3d surface to become lost and not restored).

We would still like to have this implemented, so
the following changes have been made:
 - during a D3D->GDI blit, we check if the destination peer 
   can ever have an accelerated on-screen surface

 - if that's not the case (the window is too small or
   whatever) the hw acceleration in the source image
   is disabled 

 - if indeed the destination surface can become accelerated
   then we assume the condition is temporary and mark the source 
   as lost with the intention that a backup
   surface from the VolatileSurfaceManager is used while
   the onscreen surface is sorted out

 - in order to make that happen we need to delay restoration
   of the source surface (because otherwise it will be restored
   on the next vi.validate() and if the destination is still
   lost we'll spin in a loop again). This is achieved by introducing
   a 'restore countdown' - the restoration of the source surface
   is delayed by a few iterations, thus allowing the backup
   surface to be used in the meantime. Once the countdown expires
   the source surface will be restored and we'll attempt to
   copy it to the screen again.

 - another wrinkle to this is that D3DVolatileSurfaceManager used
   to override contentsLost() to return the status of the accelerated
   surface instead of the internal flag set by the validate() call
   as it is the case in the superclass. This again forced us into
   a possibly infinite loop without a chance to use the backup surface.
   The override was done in an attempt to make sure that contentsLost()
   always returns up to date information (since the surface can be lost
   between validate() and contentsLost).
   This need to be changed back to the way it was done in the old pipeline:
   when the surface is lost it should notify the surface manager
   by calling SurfaceManager.acceleratedSurfaceLost(), which sets the
   appropriate 'contents lost' flag. Then contentsLost() will return
   true, we'll loop around for validate(), which will attempt to restore
   the accelerated surface, but since we have a restore countdown in
   place, restoration will fail, and the backup surface will be used.

 - another issue discovered during testing was with the D3DScreenUpdateManager
   which keeps track of surfaces for which there are Graphics contexts.
   When a graphics context is created by the peer we add the surface 
   to the tracking list and start the update thread responsible
   for flipping it (and restoring if it's lost).
   However, if the such surface was replaced because of display change event
   or resize it is no longer tracked by the manager (as it is dropped
   from the list before the new surface is set for the peer).

   This is a problem because if there's an outstanding graphics object
   which has the old (now invalidated) tracked surface, attempts to use
   the surface will lead to InvalidPipeException and Graphics revalidation.
   The revalidation will install a replacement surface obtained from the old
   surface via SurfaceData.getReplacement() - in this case the surface will 
   be replaced by the new surface in the peer. 

   So now we'll have a Graphics object which has an accelerated onscreen 
   surface, but this surface is not being tracked becaus when this graphics 
   object was created it had a different surface.

   This means that the surface won't be flipped/restored by the manager.

   In order to fix this the getReplacement() will need to add the new 
   surface to the tracked list. Moreover, even the GDI surface will need
   to do the same: it could be that originally we couldn't create an
   accelerated surface so we handled out a GDI one. But then it got
   invalidated and replaced with the accelerated one, so getReplacement()
   will put an accelerated surface into the Graphics - again, it will
   be untracked unless we add it to the tracking list at the time of 
   replacement.
  
   The way this is handled now is that ScreenUpdateManager now has a new 
   getReplacement(peer) method which both D3D and GDI SurfaceDatas will
   call. The default ScreenUpdateManager will just return the current
   peer's surface. The D3DScreenUpdateManager overrideż this method
   to add the new surface to the tracked list.
 - there were also a few other minor issues I ran into that needed 
   to be addressed
Posted Date : 2008-01-10 19:29:07.0

A note from the code review request:
  There is a bunch of smaller changes sprinkled
  around (like null, instanceof checks) - those
  are to fix smaller issues I found while testing
  the main fix.

  I'll explain one change in particular:
  D3DScreenUpdateManager.java:243 - synchronized is removed
  in createGraphics(). The reason is that
  I have ran into a deadlock while testing:
=============================
"D3D Screen Updater":
  waiting to lock monitor 0x0aacd3d4 (object 0x02f1c548, a sun.java2d.d3d.D3DScreenUpdateManager),
  which is held by "AWT-EventQueue-0"
"AWT-EventQueue-0":
  waiting for ownable synchronizer 0x02ec9b80, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "D3D Screen Updater"
Java stack information for the threads listed above:
===================================================
"D3D Screen Updater":
        at sun.java2d.d3d.D3DScreenUpdateManager.trackScreenSurface(D3DScreenUpdateManager.java:286)
        - waiting to lock <0x02f1c548> (a sun.java2d.d3d.D3DScreenUpdateManager)
        at sun.java2d.d3d.D3DScreenUpdateManager.getReplacementScreenSurface(D3DScreenUpdateManager.java:315)
        at sun.java2d.d3d.D3DSurfaceData$D3DWindowSurfaceData.getReplacement(D3DSurfaceData.java:773)
        at sun.java2d.SunGraphics2D.revalidateAll(SunGraphics2D.java:2284)
        at sun.java2d.SunGraphics2D.getCompClip(SunGraphics2D.java:468)
        at sun.java2d.d3d.D3DRenderer.validateContext(D3DRenderer.java:32)
        at sun.java2d.pipe.BufferedRenderPipe.fillRect(BufferedRenderPipe.java:100)
        at sun.java2d.d3d.D3DRenderer$Tracer.fillRect(D3DRenderer.java:95)
        at sun.java2d.pipe.ValidatePipe.fillRect(ValidatePipe.java:58)
        at sun.java2d.SunGraphics2D.fillRect(SunGraphics2D.java:2264)
        at sun.java2d.d3d.D3DScreenUpdateManager.validate(D3DScreenUpdateManager.java:482)
        at sun.java2d.d3d.D3DScreenUpdateManager.run(D3DScreenUpdateManager.java:452)
        at java.lang.Thread.run(Thread.java:619)
"AWT-EventQueue-0":
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x02ec9b80> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:747)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:778)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1114)
        at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186)
        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
        at sun.awt.SunToolkit.awtLock(SunToolkit.java:245)
        at sun.java2d.pipe.RenderQueue.lock(RenderQueue.java:94)
        at sun.java2d.d3d.D3DSurfaceData.initSurface(D3DSurfaceData.java:356)
        at sun.java2d.d3d.D3DSurfaceData.restoreSurface(D3DSurfaceData.java:746)
        at sun.java2d.d3d.D3DSurfaceData$D3DWindowSurfaceData.restoreSurface(D3DSurfaceData.java:791)
        at sun.java2d.d3d.D3DScreenUpdateManager.r.validate(D3DScreenUpdateManager.java:477)
        at sun.java2d.d3d.D3DScreenUpdateManager.createGraphics(D3DScreenUpdateManager.java:250)
...
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:284)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

  It deadlocked because we first take the object lock (since the method 
  is synchronized), then call validate() which may take RQ lock, and
  on other threads we have a reversed order.
  
  The validate() call was added recently there and synchronized
  should have been removed then. We should only synchronize
  on the d3dscreenupdate manager when dealing with its data,
  and make sure we never take any locks while holding its lock.
Posted Date : 2008-01-14 20:54:47.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang