8041644: [OGL] clip is ignored during surface->sw blit
authorserb
Wed, 11 Jun 2014 14:21:12 +0400
changeset 25189 d9d25c9c0cdf
parent 25143 aade36e70da0
child 25190 260fe7baeb39
8041644: [OGL] clip is ignored during surface->sw blit Reviewed-by: bae, prr
jdk/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java
jdk/test/java/awt/image/DrawImage/IncorrectClipSurface2SW.java
--- a/jdk/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java	Wed Jun 11 10:53:27 2014 +0400
+++ b/jdk/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java	Wed Jun 11 14:21:12 2014 +0400
@@ -510,6 +510,7 @@
 final class OGLSurfaceToSwBlit extends Blit {
 
     private final int typeval;
+    private WeakReference<SurfaceData> srcTmp;
 
     // destination will actually be ArgbPre or Argb
     OGLSurfaceToSwBlit(final SurfaceType dstType,final int typeval) {
@@ -519,11 +520,66 @@
         this.typeval = typeval;
     }
 
+    private synchronized void complexClipBlit(SurfaceData src, SurfaceData dst,
+                                              Composite comp, Region clip,
+                                              int sx, int sy, int dx, int dy,
+                                              int w, int h) {
+        SurfaceData cachedSrc = null;
+        if (srcTmp != null) {
+            // use cached intermediate surface, if available
+            cachedSrc = srcTmp.get();
+        }
+
+        // We can convert argb_pre data from OpenGL surface in two places:
+        // - During OpenGL surface -> SW blit
+        // - During SW -> SW blit
+        // The first one is faster when we use opaque OGL surface, because in
+        // this case we simply skip conversion and use color components as is.
+        // Because of this we align intermediate buffer type with type of
+        // destination not source.
+        final int type = typeval == OGLSurfaceData.PF_INT_ARGB_PRE ?
+                         BufferedImage.TYPE_INT_ARGB_PRE :
+                         BufferedImage.TYPE_INT_ARGB;
+
+        src = convertFrom(this, src, sx, sy, w, h, cachedSrc, type);
+
+        // copy intermediate SW to destination SW using complex clip
+        final Blit performop = Blit.getFromCache(src.getSurfaceType(),
+                                                 CompositeType.SrcNoEa,
+                                                 dst.getSurfaceType());
+        performop.Blit(src, dst, comp, clip, 0, 0, dx, dy, w, h);
+
+        if (src != cachedSrc) {
+            // cache the intermediate surface
+            srcTmp = new WeakReference<>(src);
+        }
+    }
+
     public void Blit(SurfaceData src, SurfaceData dst,
                      Composite comp, Region clip,
                      int sx, int sy, int dx, int dy,
                      int w, int h)
     {
+        if (clip != null) {
+            clip = clip.getIntersectionXYWH(dx, dy, w, h);
+            // At the end this method will flush the RenderQueue, we should exit
+            // from it as soon as possible.
+            if (clip.isEmpty()) {
+                return;
+            }
+            sx += clip.getLoX() - dx;
+            sy += clip.getLoY() - dy;
+            dx = clip.getLoX();
+            dy = clip.getLoY();
+            w = clip.getWidth();
+            h = clip.getHeight();
+
+            if (!clip.isRectangular()) {
+                complexClipBlit(src, dst, comp, clip, sx, sy, dx, dy, w, h);
+                return;
+            }
+        }
+
         OGLRenderQueue rq = OGLRenderQueue.getInstance();
         rq.lock();
         try {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/DrawImage/IncorrectClipSurface2SW.java	Wed Jun 11 14:21:12 2014 +0400
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2014, 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.AlphaComposite;
+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.geom.Ellipse2D;
+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 8041644
+ * @summary Tests drawing volatile image to BI using different clip.
+ *          Results of the blit compatibleImage to BI used for comparison.
+ * @author Sergey Bylokhov
+ * @run main/othervm -Dsun.java2d.d3d=false IncorrectClipSurface2SW
+ */
+public final class IncorrectClipSurface2SW {
+
+    private static int[] SCALES = {1, 2, 4};
+    private static int[] SIZES = {127, 3, 2, 1};
+    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 Ellipse2D.Double(0, 0, 1, 1),
+                                           new Ellipse2D.Double(0, 1, 1, 1),
+                                           new Ellipse2D.Double(1, 0, 1, 1),
+                                           new Ellipse2D.Double(1, 1, 1, 1),
+                                           new Ellipse2D.Double(.25, .25, .5,
+                                                                .5),
+
+                                           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 (final int size : SIZES) {
+            for (final int scale : SCALES) {
+                final int sw = size * scale;
+                at = AffineTransform.getScaleInstance(sw, sw);
+                for (Shape clip : SHAPES) {
+                    clip = at.createTransformedShape(clip);
+                    for (Shape to : SHAPES) {
+                        to = at.createTransformedShape(to);
+                        // Prepare test images
+                        VolatileImage vi = getVolatileImage(gc, size);
+                        BufferedImage bi = getBufferedImage(sw);
+                        // Prepare gold images
+                        BufferedImage goldvi = getCompatibleImage(gc, size);
+                        BufferedImage goldbi = getBufferedImage(sw);
+                        draw(clip, to, vi, bi, scale);
+                        draw(clip, to, goldvi, goldbi, scale);
+                        validate(bi, goldbi);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void draw(Shape clip, Shape to, Image vi, BufferedImage bi,
+                             int scale) {
+        Graphics2D big = bi.createGraphics();
+        big.setComposite(AlphaComposite.Src);
+        big.setClip(clip);
+        Rectangle toBounds = to.getBounds();
+        int x1 = toBounds.x;
+
+        int y1 = toBounds.y;
+        int x2 = x1 + toBounds.width;
+        int y2 = y1 + toBounds.height;
+        big.drawImage(vi, x1, y1, x2, y2, 0, 0, toBounds.width / scale,
+                      toBounds.height / scale, null);
+        big.dispose();
+        vi.flush();
+    }
+
+    private static BufferedImage getBufferedImage(int sw) {
+        BufferedImage bi = new BufferedImage(sw, sw,
+                                             BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g2d = bi.createGraphics();
+        g2d.setColor(Color.RED);
+        g2d.fillRect(0, 0, sw, sw);
+        return bi;
+    }
+
+    private static VolatileImage getVolatileImage(GraphicsConfiguration gc,
+                                                  int size) {
+        VolatileImage vi = gc.createCompatibleVolatileImage(size, size);
+        Graphics2D g2d = vi.createGraphics();
+        g2d.setColor(Color.GREEN);
+        g2d.fillRect(0, 0, size, size);
+        return vi;
+    }
+
+    private static BufferedImage getCompatibleImage(GraphicsConfiguration gc,
+                                                    int size) {
+        BufferedImage image = gc.createCompatibleImage(size, size);
+        Graphics2D g2d = image.createGraphics();
+        g2d.setColor(Color.GREEN);
+        g2d.fillRect(0, 0, size, size);
+        return image;
+    }
+
+    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.");
+                }
+            }
+        }
+    }
+}