From a7ce5a2f22cdb95b4616998bd7019bfcebeb761f Mon Sep 17 00:00:00 2001 From: serb Date: Wed, 11 Jun 2014 14:21:12 +0400 Subject: [PATCH] 8041644: [OGL] clip is ignored during surface->sw blit Reviewed-by: bae, prr --- .../sun/java2d/opengl/OGLBlitLoops.java | 56 ++++++ .../DrawImage/IncorrectClipSurface2SW.java | 166 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 test/java/awt/image/DrawImage/IncorrectClipSurface2SW.java diff --git a/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java b/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java index 0dd1ed338..abc78f210 100644 --- a/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java +++ b/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java @@ -510,6 +510,7 @@ class OGLRTTSurfaceToSurfaceTransform extends TransformBlit { final class OGLSurfaceToSwBlit extends Blit { private final int typeval; + private WeakReference srcTmp; // destination will actually be ArgbPre or Argb OGLSurfaceToSwBlit(final SurfaceType dstType,final int typeval) { @@ -519,11 +520,66 @@ final class OGLSurfaceToSwBlit extends Blit { 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 { diff --git a/test/java/awt/image/DrawImage/IncorrectClipSurface2SW.java b/test/java/awt/image/DrawImage/IncorrectClipSurface2SW.java new file mode 100644 index 000000000..3c972b661 --- /dev/null +++ b/test/java/awt/image/DrawImage/IncorrectClipSurface2SW.java @@ -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."); + } + } + } + } +} -- GitLab