6635462: D3D: REGRESSION: XOR rendering is extremly slow
authorjgodinez
Fri, 17 Dec 2010 09:39:54 -0800
changeset 7748 26e6f5fc1bdb
parent 7747 44fa19e4dc49
child 7749 e14a1aba2e10
6635462: D3D: REGRESSION: XOR rendering is extremly slow Reviewed-by: igor, prr
jdk/src/share/classes/javax/swing/DefaultDesktopManager.java
jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java
jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
--- a/jdk/src/share/classes/javax/swing/DefaultDesktopManager.java	Fri Dec 17 13:18:08 2010 +0300
+++ b/jdk/src/share/classes/javax/swing/DefaultDesktopManager.java	Fri Dec 17 09:39:54 2010 -0800
@@ -359,7 +359,22 @@
                         f.getWidth()-1, f.getHeight()-1);
               }
               g.drawRect( newX, newY, f.getWidth()-1, f.getHeight()-1);
-              currentLoc = new Point (newX, newY);
+              /* Work around for 6635462: XOR mode may cause a SurfaceLost on first use.
+              * Swing doesn't expect that its XOR drawRect did
+              * not complete, so believes that on re-entering at
+              * the next update location, that there is an XOR rect
+              * to draw out at "currentLoc". But in fact
+              * its now got a new clean surface without that rect,
+              * so drawing it "out" in fact draws it on, leaving garbage.
+              * So only update/set currentLoc if the draw completed.
+              */
+              sun.java2d.SurfaceData sData =
+                  ((sun.java2d.SunGraphics2D)g).getSurfaceData();
+
+              if (!sData.isSurfaceLost()) {
+                  currentLoc = new Point (newX, newY);
+              }
+;
               g.dispose();
             }
         } else if (dragMode == FASTER_DRAG_MODE) {
@@ -412,7 +427,14 @@
                 g.drawRect( currentBounds.x, currentBounds.y, currentBounds.width-1, currentBounds.height-1);
               }
               g.drawRect( newX, newY, newWidth-1, newHeight-1);
-              currentBounds = new Rectangle (newX, newY, newWidth, newHeight);
+
+              // Work around for 6635462, see comment in dragFrame()
+              sun.java2d.SurfaceData sData =
+                  ((sun.java2d.SunGraphics2D)g).getSurfaceData();
+              if (!sData.isSurfaceLost()) {
+                  currentBounds = new Rectangle (newX, newY, newWidth, newHeight);
+              }
+
               g.setPaintMode();
               g.dispose();
             }
--- a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java	Fri Dec 17 13:18:08 2010 +0300
+++ b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java	Fri Dec 17 09:39:54 2010 -0800
@@ -999,6 +999,8 @@
     public void setBoundsOperation(int operation) {
     }
 
+    private volatile boolean isAccelCapable = true;
+
     /**
      * Returns whether this component is capable of being hw accelerated.
      * More specifically, whether rendering to this component or a
@@ -1009,11 +1011,22 @@
      * {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
      * PERPIXEL_TRANSLUCENT}.
      *
+     * Another condition is if Xor paint mode was detected when rendering
+     * to an on-screen accelerated surface associated with this peer.
+     * in this case both on- and off-screen acceleration for this peer is
+     * disabled.
+     *
      * @return {@code true} if this component is capable of being hw
      * accelerated, {@code false} otherwise
      * @see GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
      */
     public boolean isAccelCapable() {
+        if (!isAccelCapable ||
+            !isContainingTopLevelAccelCapable((Component)target))
+        {
+            return false;
+        }
+
         boolean isTranslucent =
             SunToolkit.isContainingTopLevelTranslucent((Component)target);
         // D3D/OGL and translucent windows interacted poorly in Windows XP;
@@ -1021,6 +1034,14 @@
         return !isTranslucent || Win32GraphicsEnvironment.isVistaOS();
     }
 
+    /**
+     * Disables acceleration for this peer.
+     */
+    public void disableAcceleration() {
+        isAccelCapable = false;
+    }
+
+
     native void setRectangularShape(int lox, int loy, int hix, int hiy,
                      Region region);
 
--- a/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java	Fri Dec 17 13:18:08 2010 +0300
+++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java	Fri Dec 17 09:39:54 2010 -0800
@@ -437,6 +437,10 @@
         protected int getElem(final int x, final int y,
                               final SurfaceData sData)
         {
+            if (sData.isSurfaceLost()) {
+                return 0;
+            }
+
             int retPixel;
             D3DRenderQueue rq = D3DRenderQueue.getInstance();
             rq.lock();
@@ -456,6 +460,10 @@
         protected void setElem(final int x, final int y, final int pixel,
                                final SurfaceData sData)
         {
+            if (sData.isSurfaceLost()) {
+                  return;
+            }
+
             D3DRenderQueue rq = D3DRenderQueue.getInstance();
             rq.lock();
             try {
@@ -512,15 +520,32 @@
             sg2d.surfaceData.getTransparency() == Transparency.OPAQUE;
     }
 
+    /**
+     * If acceleration should no longer be used for this surface.
+     * This implementation flags to the manager that it should no
+     * longer attempt to re-create a D3DSurface.
+     */
+    void disableAccelerationForSurface() {
+        if (offscreenImage != null) {
+            SurfaceManager sm = SurfaceManager.getManager(offscreenImage);
+            if (sm instanceof D3DVolatileSurfaceManager) {
+                setSurfaceLost(true);
+                ((D3DVolatileSurfaceManager)sm).setAccelerationEnabled(false);
+            }
+        }
+    }
+
     public void validatePipe(SunGraphics2D sg2d) {
         TextPipe textpipe;
         boolean validated = false;
 
         // REMIND: the D3D pipeline doesn't support XOR!, more
-        // fixes will be needed below
+        // fixes will be needed below. For now we disable D3D rendering
+        // for the surface which had any XOR rendering done to.
         if (sg2d.compositeState >= sg2d.COMP_XOR) {
             super.validatePipe(sg2d);
             sg2d.imagepipe = d3dImagePipe;
+            disableAccelerationForSurface();
             return;
         }
 
@@ -895,7 +920,25 @@
         }
 
         @Override
+        void disableAccelerationForSurface() {
+            // for on-screen surfaces we need to make sure a backup GDI surface is
+            // is used until a new one is set (which may happen during a resize). We
+            // don't want the screen update maanger to replace the surface right way
+            // because it causes repainting issues in Swing, so we invalidate it,
+            // this will prevent SUM from issuing a replaceSurfaceData call.
+            setSurfaceLost(true);
+            invalidate();
+            flush();
+            peer.disableAcceleration();
+            ScreenUpdateManager.getInstance().dropScreenSurface(this);
+        }
+
+        @Override
         void restoreSurface() {
+            if (!peer.isAccelCapable()) {
+                throw new InvalidPipeException("Onscreen acceleration " +
+                                               "disabled for this surface");
+            }
             Window fsw = graphicsDevice.getFullScreenWindow();
             if (fsw != null && fsw != peer.getTarget()) {
                 throw new InvalidPipeException("Can't restore onscreen surface"+