# HG changeset patch # User serb # Date 1412775267 -14400 # Node ID 1172062acce46940325af6d9f0653f86bf272994 # Parent cba0cc16cfbf1393af83118a484c214e3cee6b62 8029253: [macosx] Performance problems with Retina display on Mac OS X Reviewed-by: bae, prr diff -r cba0cc16cfbf -r 1172062acce4 src/share/classes/sun/java2d/opengl/OGLBlitLoops.java --- a/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java Tue Sep 23 07:13:34 2014 +0400 +++ b/src/share/classes/sun/java2d/opengl/OGLBlitLoops.java Wed Oct 08 17:34:27 2014 +0400 @@ -47,7 +47,7 @@ import static sun.java2d.pipe.BufferedOpCodes.*; import java.lang.annotation.Native; -class OGLBlitLoops { +final class OGLBlitLoops { static void register() { Blit blitIntArgbPreToSurface = @@ -56,7 +56,9 @@ Blit blitIntArgbPreToTexture = new OGLSwToTextureBlit(SurfaceType.IntArgbPre, OGLSurfaceData.PF_INT_ARGB_PRE); - + TransformBlit transformBlitIntArgbPreToSurface = + new OGLSwToSurfaceTransform(SurfaceType.IntArgbPre, + OGLSurfaceData.PF_INT_ARGB_PRE); GraphicsPrimitive[] primitives = { // surface->surface ops new OGLSurfaceToSurfaceBlit(), @@ -100,7 +102,7 @@ CompositeType.AnyAlpha, blitIntArgbPreToSurface), - new OGLAnyCompositeBlit(OGLSurfaceData.OpenGLSurface), + new OGLAnyCompositeBlit(), new OGLSwToSurfaceScale(SurfaceType.IntRgb, OGLSurfaceData.PF_INT_RGB), @@ -145,8 +147,9 @@ OGLSurfaceData.PF_BYTE_GRAY), new OGLSwToSurfaceTransform(SurfaceType.UshortGray, OGLSurfaceData.PF_USHORT_GRAY), - new OGLSwToSurfaceTransform(SurfaceType.IntArgbPre, - OGLSurfaceData.PF_INT_ARGB_PRE), + transformBlitIntArgbPreToSurface, + + new OGLGeneralTransformedBlit(transformBlitIntArgbPreToSurface), // texture->surface ops new OGLTextureToSurfaceBlit(), @@ -178,9 +181,6 @@ new OGLGeneralBlit(OGLSurfaceData.OpenGLTexture, CompositeType.SrcNoEa, blitIntArgbPreToTexture), - - new OGLAnyCompositeBlit(OGLSurfaceData.OpenGLTexture), - }; GraphicsPrimitiveMgr.register(primitives); } @@ -781,11 +781,11 @@ * This general Blit implementation converts any source surface to an * intermediate IntArgbPre surface, and then uses the more specific * IntArgbPre->OpenGLSurface/Texture loop to get the intermediate - * (premultiplied) surface down to OpenGL. + * (premultiplied) surface down to OpenGL using simple blit. */ class OGLGeneralBlit extends Blit { - private Blit performop; + private final Blit performop; private WeakReference srcTmp; OGLGeneralBlit(SurfaceType dstType, @@ -826,12 +826,56 @@ } } +/** + * This general TransformedBlit implementation converts any source surface to an + * intermediate IntArgbPre surface, and then uses the more specific + * IntArgbPre->OpenGLSurface/Texture loop to get the intermediate + * (premultiplied) surface down to OpenGL using simple transformBlit. + */ +final class OGLGeneralTransformedBlit extends TransformBlit { + + private final TransformBlit performop; + private WeakReference srcTmp; + + OGLGeneralTransformedBlit(final TransformBlit performop) { + super(SurfaceType.Any, CompositeType.AnyAlpha, + OGLSurfaceData.OpenGLSurface); + this.performop = performop; + } + + @Override + public synchronized void Transform(SurfaceData src, SurfaceData dst, + Composite comp, Region clip, + AffineTransform at, int hint, int srcx, + int srcy, int dstx, int dsty, int width, + int height){ + Blit convertsrc = Blit.getFromCache(src.getSurfaceType(), + CompositeType.SrcNoEa, + SurfaceType.IntArgbPre); + // use cached intermediate surface, if available + final SurfaceData cachedSrc = srcTmp != null ? srcTmp.get() : null; + // convert source to IntArgbPre + src = convertFrom(convertsrc, src, srcx, srcy, width, height, cachedSrc, + BufferedImage.TYPE_INT_ARGB_PRE); + + // transform IntArgbPre intermediate surface to OpenGL surface + performop.Transform(src, dst, comp, clip, at, hint, 0, 0, dstx, dsty, + width, height); + + if (src != cachedSrc) { + // cache the intermediate surface + srcTmp = new WeakReference<>(src); + } + } +} + class OGLAnyCompositeBlit extends Blit { private WeakReference dstTmp; - public OGLAnyCompositeBlit(SurfaceType dstType) { - super(SurfaceType.Any, CompositeType.Any, dstType); + OGLAnyCompositeBlit() { + super(SurfaceType.Any, CompositeType.Any, OGLSurfaceData.OpenGLSurface); } + public synchronized void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, @@ -848,15 +892,14 @@ cachedDst = dstTmp.get(); } - // convert source to IntArgbPre + // convert destination to IntArgbPre SurfaceData dstBuffer = convertFrom(convertdst, dst, dx, dy, w, h, cachedDst, BufferedImage.TYPE_INT_ARGB_PRE); Blit performop = Blit.getFromCache(src.getSurfaceType(), CompositeType.Any, dstBuffer.getSurfaceType()); - performop.Blit(src, dstBuffer, comp, clip, - sx, sy, 0, 0, w, h); + performop.Blit(src, dstBuffer, comp, clip, sx, sy, 0, 0, w, h); if (dstBuffer != cachedDst) { // cache the intermediate surface diff -r cba0cc16cfbf -r 1172062acce4 test/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java Wed Oct 08 17:34:27 2014 +0400 @@ -0,0 +1,150 @@ +/* + * 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.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.VolatileImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import static java.awt.Transparency.*; +import static java.awt.image.BufferedImage.*; + +/** + * @test + * @bug 8029253 + * @summary Tests asymmetric source offsets when unmanaged image is drawn to VI. + * Results of the blit to compatibleImage are used for comparison. + * @author Sergey Bylokhov + */ +public final class IncorrectUnmanagedImageSourceOffset { + + private static final int[] TYPES = {TYPE_INT_RGB, TYPE_INT_ARGB, + TYPE_INT_ARGB_PRE, TYPE_INT_BGR, + TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, + TYPE_4BYTE_ABGR_PRE, + /*TYPE_USHORT_565_RGB, + TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY, + TYPE_USHORT_GRAY,*/ TYPE_BYTE_BINARY, + TYPE_BYTE_INDEXED}; + private static final int[] TRANSPARENCIES = {OPAQUE, BITMASK, TRANSLUCENT}; + + public static void main(final String[] args) throws IOException { + for (final int viType : TRANSPARENCIES) { + for (final int biType : TYPES) { + BufferedImage bi = makeUnmanagedBI(biType); + fill(bi); + test(bi, viType); + } + } + } + + private static void test(BufferedImage bi, int type) + throws IOException { + GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + GraphicsConfiguration gc = ge.getDefaultScreenDevice() + .getDefaultConfiguration(); + VolatileImage vi = gc.createCompatibleVolatileImage(511, 255, type); + BufferedImage gold = gc.createCompatibleImage(511, 255, type); + // draw to compatible Image + Graphics2D big = gold.createGraphics(); + // force scaled blit + big.drawImage(bi, 7, 11, 127, 111, 7, 11, 127 * 2, 111, null); + big.dispose(); + // draw to volatile image + BufferedImage snapshot; + while (true) { + vi.validate(gc); + if (vi.validate(gc) != VolatileImage.IMAGE_OK) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + Graphics2D vig = vi.createGraphics(); + // force scaled blit + vig.drawImage(bi, 7, 11, 127, 111, 7, 11, 127 * 2, 111, null); + vig.dispose(); + snapshot = vi.getSnapshot(); + if (vi.contentsLost()) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + break; + } + // validate images + for (int x = 7; x < 127; ++x) { + for (int y = 11; y < 111; ++y) { + if (gold.getRGB(x, y) != snapshot.getRGB(x, y)) { + ImageIO.write(gold, "png", new File("gold.png")); + ImageIO.write(snapshot, "png", new File("bi.png")); + throw new RuntimeException("Test failed."); + } + } + } + } + + private static BufferedImage makeUnmanagedBI(final int type) { + final BufferedImage bi = new BufferedImage(511, 255, type); + final DataBuffer db = bi.getRaster().getDataBuffer(); + if (db instanceof DataBufferInt) { + ((DataBufferInt) db).getData(); + } else if (db instanceof DataBufferShort) { + ((DataBufferShort) db).getData(); + } else if (db instanceof DataBufferByte) { + ((DataBufferByte) db).getData(); + } else { + try { + bi.setAccelerationPriority(0.0f); + } catch (final Throwable ignored) { + } + } + return bi; + } + + private static void fill(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + for (int i = 0; i < image.getHeight(null); ++i) { + graphics.setColor(new Color(i, 0, 0)); + graphics.fillRect(0, i, image.getWidth(null), 1); + } + graphics.dispose(); + } +} diff -r cba0cc16cfbf -r 1172062acce4 test/java/awt/image/DrawImage/UnmanagedDrawImagePerformance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/awt/image/DrawImage/UnmanagedDrawImagePerformance.java Wed Oct 08 17:34:27 2014 +0400 @@ -0,0 +1,125 @@ +/* + * 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.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Polygon; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.VolatileImage; + +import static java.awt.Transparency.*; +import static java.awt.image.BufferedImage.*; + +/* + * @test + * @bug 8029253 + * @summary Unmanaged images should be drawn fast. + * @author Sergey Bylokhov + */ +public final class UnmanagedDrawImagePerformance { + + private static final int[] TYPES = {TYPE_INT_RGB, TYPE_INT_ARGB, + TYPE_INT_ARGB_PRE, TYPE_INT_BGR, + TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, + TYPE_4BYTE_ABGR_PRE, + TYPE_USHORT_565_RGB, + TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY, + TYPE_USHORT_GRAY, TYPE_BYTE_BINARY, + TYPE_BYTE_INDEXED}; + private static final int[] TRANSPARENCIES = {OPAQUE, BITMASK, TRANSLUCENT}; + private static final int SIZE = 1000; + private static final AffineTransform[] TRANSFORMS = { + AffineTransform.getScaleInstance(.5, .5), + AffineTransform.getScaleInstance(1, 1), + AffineTransform.getScaleInstance(2, 2), + AffineTransform.getShearInstance(7, 11)}; + + public static void main(final String[] args) { + for (final AffineTransform atfm : TRANSFORMS) { + for (final int viType : TRANSPARENCIES) { + for (final int biType : TYPES) { + final BufferedImage bi = makeUnmanagedBI(biType); + final VolatileImage vi = makeVI(viType); + final long time = test(bi, vi, atfm) / 1000000000; + if (time > 1) { + throw new RuntimeException(String.format( + "drawImage is slow: %d seconds", time)); + } + } + } + } + } + + private static long test(Image bi, Image vi, AffineTransform atfm) { + final Polygon p = new Polygon(); + p.addPoint(0, 0); + p.addPoint(SIZE, 0); + p.addPoint(0, SIZE); + p.addPoint(SIZE, SIZE); + p.addPoint(0, 0); + Graphics2D g2d = (Graphics2D) vi.getGraphics(); + g2d.clip(p); + g2d.transform(atfm); + g2d.setComposite(AlphaComposite.SrcOver); + final long start = System.nanoTime(); + g2d.drawImage(bi, 0, 0, null); + final long time = System.nanoTime() - start; + g2d.dispose(); + return time; + } + + private static VolatileImage makeVI(final int type) { + final GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + final GraphicsDevice gd = ge.getDefaultScreenDevice(); + final GraphicsConfiguration gc = gd.getDefaultConfiguration(); + return gc.createCompatibleVolatileImage(SIZE, SIZE, type); + } + + private static BufferedImage makeUnmanagedBI(final int type) { + final BufferedImage img = new BufferedImage(SIZE, SIZE, type); + final DataBuffer db = img.getRaster().getDataBuffer(); + if (db instanceof DataBufferInt) { + ((DataBufferInt) db).getData(); + } else if (db instanceof DataBufferShort) { + ((DataBufferShort) db).getData(); + } else if (db instanceof DataBufferByte) { + ((DataBufferByte) db).getData(); + } else { + try { + img.setAccelerationPriority(0.0f); + } catch (final Throwable ignored) { + } + } + return img; + } +}