8061831: [OGL] "java.lang.InternalError: not implemented yet" during the blit of VI to VI in xor mode
authorserb
Sat, 23 May 2015 15:13:40 +0300
changeset 31155 272c0790761f
parent 31154 9f5be2f649cd
child 31156 11ae3ca525cc
8061831: [OGL] "java.lang.InternalError: not implemented yet" during the blit of VI to VI in xor mode Reviewed-by: flar, bae
jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLBlitLoops.java
jdk/test/java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java
--- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLBlitLoops.java	Wed May 27 14:42:58 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLBlitLoops.java	Sat May 23 15:13:40 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,6 +59,10 @@
         TransformBlit transformBlitIntArgbPreToSurface =
             new OGLSwToSurfaceTransform(SurfaceType.IntArgbPre,
                                         OGLSurfaceData.PF_INT_ARGB_PRE);
+        OGLSurfaceToSwBlit blitSurfaceToIntArgbPre =
+            new OGLSurfaceToSwBlit(SurfaceType.IntArgbPre,
+                                   OGLSurfaceData.PF_INT_ARGB_PRE);
+
         GraphicsPrimitive[] primitives = {
             // surface->surface ops
             new OGLSurfaceToSurfaceBlit(),
@@ -73,8 +77,7 @@
             // surface->sw ops
             new OGLSurfaceToSwBlit(SurfaceType.IntArgb,
                                    OGLSurfaceData.PF_INT_ARGB),
-            new OGLSurfaceToSwBlit(SurfaceType.IntArgbPre,
-                                   OGLSurfaceData.PF_INT_ARGB_PRE),
+            blitSurfaceToIntArgbPre,
 
             // sw->surface ops
             blitIntArgbPreToSurface,
@@ -102,7 +105,14 @@
                                CompositeType.AnyAlpha,
                                blitIntArgbPreToSurface),
 
-            new OGLAnyCompositeBlit(),
+            new OGLAnyCompositeBlit(OGLSurfaceData.OpenGLSurface,
+                                    blitSurfaceToIntArgbPre,
+                                    blitSurfaceToIntArgbPre,
+                                    blitIntArgbPreToSurface),
+            new OGLAnyCompositeBlit(SurfaceType.Any,
+                                    null,
+                                    blitSurfaceToIntArgbPre,
+                                    blitIntArgbPreToSurface),
 
             new OGLSwToSurfaceScale(SurfaceType.IntRgb,
                                     OGLSurfaceData.PF_INT_RGB),
@@ -869,11 +879,26 @@
     }
 }
 
+/**
+ * This general OGLAnyCompositeBlit implementation can convert any source/target
+ * surface to an intermediate surface using convertsrc/convertdst loops, applies
+ * necessary composite operation, and then uses convertresult loop to get the
+ * intermediate surface down to OpenGL.
+ */
 final class OGLAnyCompositeBlit extends Blit {
-    private WeakReference<SurfaceData> dstTmp;
 
-    OGLAnyCompositeBlit() {
-        super(SurfaceType.Any, CompositeType.Any, OGLSurfaceData.OpenGLSurface);
+    private WeakReference<SurfaceData> dstTmp;
+    private WeakReference<SurfaceData> srcTmp;
+    private final Blit convertsrc;
+    private final Blit convertdst;
+    private final Blit convertresult;
+
+    OGLAnyCompositeBlit(SurfaceType srctype, Blit convertsrc, Blit convertdst,
+                        Blit convertresult) {
+        super(srctype, CompositeType.Any, OGLSurfaceData.OpenGLSurface);
+        this.convertsrc = convertsrc;
+        this.convertdst = convertdst;
+        this.convertresult = convertresult;
     }
 
     public synchronized void Blit(SurfaceData src, SurfaceData dst,
@@ -881,9 +906,20 @@
                                   int sx, int sy, int dx, int dy,
                                   int w, int h)
     {
-        Blit convertdst = Blit.getFromCache(dst.getSurfaceType(),
-                                            CompositeType.SrcNoEa,
-                                            SurfaceType.IntArgbPre);
+        if (convertsrc != null) {
+            SurfaceData cachedSrc = null;
+            if (srcTmp != null) {
+                // use cached intermediate surface, if available
+                cachedSrc = srcTmp.get();
+            }
+            // convert source to IntArgbPre
+            src = convertFrom(convertsrc, src, sx, sy, w, h, cachedSrc,
+                              BufferedImage.TYPE_INT_ARGB_PRE);
+            if (src != cachedSrc) {
+                // cache the intermediate surface
+                srcTmp = new WeakReference<>(src);
+            }
+        }
 
         SurfaceData cachedDst = null;
 
@@ -906,12 +942,8 @@
             // cache the intermediate surface
             dstTmp = new WeakReference<>(dstBuffer);
         }
-
         // now blit the buffer back to the destination
-        convertdst = Blit.getFromCache(dstBuffer.getSurfaceType(),
-                                            CompositeType.SrcNoEa,
-                                            dst.getSurfaceType());
-        convertdst.Blit(dstBuffer, dst, AlphaComposite.Src,
-                 clip, 0, 0, dx, dy, w, h);
+        convertresult.Blit(dstBuffer, dst, AlphaComposite.Src, clip, 0, 0, dx,
+                           dy, w, h);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java	Sat May 23 15:13:40 2015 +0300
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.VolatileImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import static java.awt.geom.Rectangle2D.Double;
+
+/**
+ * @test
+ * @bug 8061831
+ * @summary Tests drawing volatile image to volatile image using different
+ *          clips + xor mode. Results of the blit compatibleImage to
+ *          compatibleImage is used for comparison.
+ */
+public final class IncorrectClipXorModeSurface2Surface {
+
+    private static int[] SIZES = {2, 10, 100};
+    private static final Shape[] SHAPES = {
+            new Rectangle(0, 0, 0, 0),
+            new Rectangle(0, 0, 1, 1),
+            new Rectangle(0, 1, 1, 1),
+            new Rectangle(1, 0, 1, 1),
+            new Rectangle(1, 1, 1, 1),
+
+            new Double(0, 0, 0.5, 0.5),
+            new Double(0, 0.5, 0.5, 0.5),
+            new Double(0.5, 0, 0.5, 0.5),
+            new Double(0.5, 0.5, 0.5, 0.5),
+            new Double(0.25, 0.25, 0.5, 0.5),
+            new Double(0, 0.25, 1, 0.5),
+            new Double(0.25, 0, 0.5, 1),
+
+            new Double(.10, .10, .20, .20),
+            new Double(.75, .75, .20, .20),
+            new Double(.75, .10, .20, .20),
+            new Double(.10, .75, .20, .20),
+    };
+
+    public static void main(final String[] args) throws IOException {
+        GraphicsEnvironment ge = GraphicsEnvironment
+                .getLocalGraphicsEnvironment();
+        GraphicsConfiguration gc = ge.getDefaultScreenDevice()
+                .getDefaultConfiguration();
+        AffineTransform at;
+        for (int size : SIZES) {
+            at = AffineTransform.getScaleInstance(size, size);
+            for (Shape clip : SHAPES) {
+                clip = at.createTransformedShape(clip);
+                for (Shape to : SHAPES) {
+                    to = at.createTransformedShape(to);
+                    // Prepare test images
+                    BufferedImage snapshot;
+                    VolatileImage source = getVolatileImage(gc, size);
+                    VolatileImage target = getVolatileImage(gc, size);
+                    int attempt = 0;
+                    while (true) {
+                        if (++attempt > 10) {
+                            throw new RuntimeException("Too many attempts: " + attempt);
+                        }
+                        // Prepare source images
+                        source.validate(gc);
+                        Graphics2D g2d = source.createGraphics();
+                        g2d.setColor(Color.RED);
+                        g2d.fillRect(0, 0, size, size);
+                        g2d.dispose();
+                        if (source.validate(gc) != VolatileImage.IMAGE_OK) {
+                            continue;
+                        }
+                        // Prepare target images
+                        target.validate(gc);
+                        g2d = target.createGraphics();
+                        g2d.setColor(Color.GREEN);
+                        g2d.fillRect(0, 0, size, size);
+                        g2d.dispose();
+                        if (target.validate(gc) != VolatileImage.IMAGE_OK) {
+                            continue;
+                        }
+
+                        draw(clip, to, source, target);
+                        snapshot = target.getSnapshot();
+                        if (source.contentsLost() || target.contentsLost()) {
+                            continue;
+                        }
+                        break;
+                    }
+                    // Prepare gold images
+                    BufferedImage goldS = getSourceGold(gc, size);
+                    BufferedImage goldT = getTargetGold(gc, size);
+                    draw(clip, to, goldS, goldT);
+                    validate(snapshot, goldT);
+                    source.flush();
+                    target.flush();
+                }
+            }
+        }
+    }
+
+    private static void draw(Shape clip, Shape shape, Image from, Image to) {
+        Graphics2D g2d = (Graphics2D) to.getGraphics();
+        g2d.setXORMode(Color.BLACK);
+        g2d.setClip(clip);
+        Rectangle toBounds = shape.getBounds();
+        g2d.drawImage(from, toBounds.x, toBounds.y, toBounds.width,
+                      toBounds.height, null);
+        g2d.dispose();
+    }
+
+    private static BufferedImage getSourceGold(GraphicsConfiguration gc,
+                                               int size) {
+        final BufferedImage bi = gc.createCompatibleImage(size, size);
+        Graphics2D g2d = bi.createGraphics();
+        g2d.setColor(Color.RED);
+        g2d.fillRect(0, 0, size, size);
+        g2d.dispose();
+        return bi;
+    }
+
+    private static BufferedImage getTargetGold(GraphicsConfiguration gc,
+                                               int size) {
+        BufferedImage image = gc.createCompatibleImage(size, size);
+        Graphics2D g2d = image.createGraphics();
+        g2d.setColor(Color.GREEN);
+        g2d.fillRect(0, 0, size, size);
+        g2d.dispose();
+        return image;
+    }
+
+    private static VolatileImage getVolatileImage(GraphicsConfiguration gc,
+                                                  int size) {
+        return gc.createCompatibleVolatileImage(size, size);
+    }
+
+    private static void validate(BufferedImage bi, BufferedImage goldbi)
+            throws IOException {
+        for (int x = 0; x < bi.getWidth(); ++x) {
+            for (int y = 0; y < bi.getHeight(); ++y) {
+                if (goldbi.getRGB(x, y) != bi.getRGB(x, y)) {
+                    ImageIO.write(bi, "png", new File("actual.png"));
+                    ImageIO.write(goldbi, "png", new File("expected.png"));
+                    throw new RuntimeException("Test failed.");
+                }
+            }
+        }
+    }
+}