diff --git a/src/share/native/sun/java2d/opengl/OGLBlitLoops.c b/src/share/native/sun/java2d/opengl/OGLBlitLoops.c index 5e36606e986f762d1eb239efbe5d4ab1d87fedb1..4976e3cdaa5d1da173f562305c9fec818849fd62 100644 --- a/src/share/native/sun/java2d/opengl/OGLBlitLoops.c +++ b/src/share/native/sun/java2d/opengl/OGLBlitLoops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -180,6 +180,7 @@ OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2) { GLfloat scalex, scaley; + GLvoid *pSrc; scalex = ((GLfloat)(dx2-dx1)) / (sx2-sx1); scaley = ((GLfloat)(dy2-dy1)) / (sy2-sy1); @@ -208,21 +209,22 @@ OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, j2d_glPixelZoom(scalex, -scaley); + pSrc = PtrCoord(srcInfo->rasBase, sx1, srcInfo->pixelStride, + sy1, srcInfo->scanStride); + // in case pixel stride is not a multiple of scanline stride the copy // has to be done line by line (see 6207877) if (srcInfo->scanStride % srcInfo->pixelStride != 0) { jint width = sx2-sx1; jint height = sy2-sy1; - GLvoid *pSrc = srcInfo->rasBase; - while (height > 0) { j2d_glDrawPixels(width, 1, pf->format, pf->type, pSrc); - j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-1, NULL); + j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-scaley, NULL); pSrc = PtrAddBytes(pSrc, srcInfo->scanStride); height--; } } else { - j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, srcInfo->rasBase); + j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, pSrc); } j2d_glPixelZoom(1.0, 1.0); @@ -317,12 +319,11 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, ty2 = ((GLdouble)sh) / th; if (swsurface) { + GLvoid *pSrc = PtrCoord(srcInfo->rasBase, + sx, srcInfo->pixelStride, + sy, srcInfo->scanStride); if (slowPath) { jint tmph = sh; - GLvoid *pSrc = PtrCoord(srcInfo->rasBase, - sx, srcInfo->pixelStride, - sy, srcInfo->scanStride); - while (tmph > 0) { j2d_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, sh - tmph, sw, 1, @@ -332,16 +333,10 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, tmph--; } } else { - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy); - j2d_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, sw, sh, pf->format, pf->type, - srcInfo->rasBase); - - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + pSrc); } // the texture image is "right side up", so we align the @@ -638,8 +633,9 @@ OGLBlitLoops_Blit(JNIEnv *env, J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2); - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx1); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy1); + // Note: we will calculate x/y positions in the raster manually + j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, srcInfo.scanStride / srcInfo.pixelStride); j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, pf.alignment); @@ -696,8 +692,6 @@ OGLBlitLoops_Blit(JNIEnv *env, } } - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } diff --git a/test/java/awt/image/DrawImage/IncorrectManagedImageSourceOffset.java b/test/java/awt/image/DrawImage/IncorrectManagedImageSourceOffset.java new file mode 100644 index 0000000000000000000000000000000000000000..5c5180e00b27aedf22ccacda765eac3b7bec5319 --- /dev/null +++ b/test/java/awt/image/DrawImage/IncorrectManagedImageSourceOffset.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014, 2019, 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.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import sun.awt.image.SunWritableRaster; + +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/** + * @test + * @key headful + * @bug 8029253 6207877 + * @summary Tests asymmetric source offsets when managed image is drawn to VI. + * Results of the blit to compatibleImage are used for comparison. + * @author Sergey Bylokhov + * @modules java.desktop/sun.awt.image + * @run main/othervm -Dsun.java2d.accthreshold=0 IncorrectManagedImageSourceOffset + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=1 IncorrectManagedImageSourceOffset + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=2 IncorrectManagedImageSourceOffset + */ +public final class IncorrectManagedImageSourceOffset { + + // See the same test for unmanaged images: 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, TYPE_CUSTOM}; + 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 = makeManagedBI(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 makeManagedBI(final int type) { + final BufferedImage bi; + if (type == TYPE_CUSTOM) { + bi = makeCustomManagedBI(); + } else { + bi = new BufferedImage(511, 255, type); + } + bi.setAccelerationPriority(1.0f); + return bi; + } + + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomManagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + BufferedImage bi = new BufferedImage(colorModel, raster, true, null); + SunWritableRaster.makeTrackable(raster.getDataBuffer()); + SunWritableRaster.markDirty(bi); + 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 --git a/test/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java b/test/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java index 98cbcd44faadc1b32954775dd79b1fd3ab51c3af..d0c49c94686b3e774bf2394a0fd24ab99dac3308 100644 --- a/test/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java +++ b/test/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, 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 @@ -27,29 +27,52 @@ import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Image; +import java.awt.Transparency; +import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.DataBufferShort; +import java.awt.image.Raster; import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; -import static java.awt.Transparency.*; -import static java.awt.image.BufferedImage.*; +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; /** * @test - * @bug 8029253 + * @key headful + * @bug 8029253 6207877 * @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 + * @run main/othervm IncorrectUnmanagedImageSourceOffset + * @run main/othervm -Dsun.java2d.uiScale=1 IncorrectUnmanagedImageSourceOffset + * @run main/othervm -Dsun.java2d.uiScale=2 IncorrectUnmanagedImageSourceOffset */ public final class IncorrectUnmanagedImageSourceOffset { + // See the same test for managed images: IncorrectManagedImageSourceOffset + private static final int[] TYPES = {TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR, TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, @@ -57,7 +80,7 @@ public final class IncorrectUnmanagedImageSourceOffset { /*TYPE_USHORT_565_RGB, TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY, TYPE_USHORT_GRAY,*/ TYPE_BYTE_BINARY, - TYPE_BYTE_INDEXED}; + TYPE_BYTE_INDEXED, TYPE_CUSTOM}; private static final int[] TRANSPARENCIES = {OPAQUE, BITMASK, TRANSLUCENT}; public static void main(final String[] args) throws IOException { @@ -121,7 +144,12 @@ public final class IncorrectUnmanagedImageSourceOffset { } private static BufferedImage makeUnmanagedBI(final int type) { - final BufferedImage bi = new BufferedImage(511, 255, type); + final BufferedImage bi; + if (type == TYPE_CUSTOM) { + bi = makeCustomUnmanagedBI(); + } else { + bi = new BufferedImage(511, 255, type); + } final DataBuffer db = bi.getRaster().getDataBuffer(); if (db instanceof DataBufferInt) { ((DataBufferInt) db).getData(); @@ -129,15 +157,30 @@ public final class IncorrectUnmanagedImageSourceOffset { ((DataBufferShort) db).getData(); } else if (db instanceof DataBufferByte) { ((DataBufferByte) db).getData(); - } else { - try { - bi.setAccelerationPriority(0.0f); - } catch (final Throwable ignored) { - } } + bi.setAccelerationPriority(0.0f); return bi; } + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomUnmanagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + return new BufferedImage(colorModel, raster, true, null); + } + private static void fill(final Image image) { final Graphics2D graphics = (Graphics2D) image.getGraphics(); graphics.setComposite(AlphaComposite.Src); diff --git a/test/java/awt/image/DrawImage/SimpleManagedImage.java b/test/java/awt/image/DrawImage/SimpleManagedImage.java new file mode 100644 index 0000000000000000000000000000000000000000..e0fefa743067ae103f9f4f302730061ae6b168bb --- /dev/null +++ b/test/java/awt/image/DrawImage/SimpleManagedImage.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2014, 2019, 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.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import sun.awt.image.SunWritableRaster; + +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/** + * @test + * @key headful + * @bug 8029253 6207877 + * @summary Tests the case when managed image is drawn to VI. + * Results of the blit to compatibleImage are used for comparison. + * @author Sergey Bylokhov + * @modules java.desktop/sun.awt.image + * @run main/othervm -Dsun.java2d.accthreshold=0 SimpleManagedImage + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=1 SimpleManagedImage + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=2 SimpleManagedImage + */ +public final class SimpleManagedImage { + + // See the same test for unmanaged images: SimpleUnmanagedImage + + 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, TYPE_CUSTOM}; + 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 = makeManagedBI(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(1000, 1000, type); + BufferedImage gold = gc.createCompatibleImage(1000, 1000, type); + // draw to compatible Image + init(gold); + Graphics2D big = gold.createGraphics(); + big.drawImage(bi, 7, 11, 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; + } + init(vi); + Graphics2D vig = vi.createGraphics(); + vig.drawImage(bi, 7, 11, null); + vig.dispose(); + snapshot = vi.getSnapshot(); + if (vi.contentsLost()) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + break; + } + // validate images + for (int x = 0; x < 1000; ++x) { + for (int y = 0; y < 1000; ++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 makeManagedBI(final int type) { + final BufferedImage bi; + if (type == TYPE_CUSTOM) { + bi = makeCustomManagedBI(); + } else { + bi = new BufferedImage(511, 255, type); + } + bi.setAccelerationPriority(1.0f); + return bi; + } + + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomManagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + BufferedImage bi = new BufferedImage(colorModel, raster, true, null); + SunWritableRaster.makeTrackable(raster.getDataBuffer()); + SunWritableRaster.markDirty(bi); + return bi; + } + + private static void init(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + graphics.setColor(new Color(0, 0, 0, 0)); + graphics.fillRect(0, 0, image.getWidth(null), image.getHeight(null)); + graphics.dispose(); + } + + 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 --git a/test/java/awt/image/DrawImage/SimpleUnmanagedImage.java b/test/java/awt/image/DrawImage/SimpleUnmanagedImage.java new file mode 100644 index 0000000000000000000000000000000000000000..01921249460601553d1c4563fb4455d7272bbbe8 --- /dev/null +++ b/test/java/awt/image/DrawImage/SimpleUnmanagedImage.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2014, 2019, 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.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.Raster; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/** + * @test + * @key headful + * @bug 8029253 6207877 + * @summary Tests the case when unmanaged image is drawn to VI. + * Results of the blit to compatibleImage are used for comparison. + * @author Sergey Bylokhov + * @run main/othervm SimpleUnmanagedImage + * @run main/othervm -Dsun.java2d.uiScale=1 SimpleUnmanagedImage + * @run main/othervm -Dsun.java2d.uiScale=2 SimpleUnmanagedImage + */ +public final class SimpleUnmanagedImage { + + // See the same test for managed images: SimpleManagedImage + + 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, TYPE_CUSTOM}; + 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(1000, 1000, type); + BufferedImage gold = gc.createCompatibleImage(1000, 1000, type); + // draw to compatible Image + init(gold); + Graphics2D big = gold.createGraphics(); + big.drawImage(bi, 7, 11, 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; + } + init(vi); + Graphics2D vig = vi.createGraphics(); + vig.drawImage(bi, 7, 11, null); + vig.dispose(); + snapshot = vi.getSnapshot(); + if (vi.contentsLost()) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + break; + } + // validate images + for (int x = 0; x < 1000; ++x) { + for (int y = 0; y < 1000; ++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; + if (type == TYPE_CUSTOM) { + bi = makeCustomUnmanagedBI(); + } else { + 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(); + } + bi.setAccelerationPriority(0.0f); + return bi; + } + + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomUnmanagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + return new BufferedImage(colorModel, raster, true, null); + } + + private static void init(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + graphics.setColor(new Color(0, 0, 0, 0)); + graphics.fillRect(0, 0, image.getWidth(null), image.getHeight(null)); + graphics.dispose(); + } + + 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(); + } +}