test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java
changeset 49217 3b820b878ebe
parent 49216 577f96d4f3c9
child 49218 3f825ec26b01
equal deleted inserted replaced
49216:577f96d4f3c9 49217:3b820b878ebe
     1 /*
       
     2  * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 /*
       
    24  * @test
       
    25  * @key headful
       
    26  * @bug 6514990
       
    27  * @summary Verifies that calling
       
    28  * Graphics2D.drawImage(BufferedImage, BufferedImageOp, x, y) to an
       
    29  * OpenGL-accelerated destination produces the same results when performed
       
    30  * in software via BufferedImageOp.filter().
       
    31  * @run main/othervm -Dsun.java2d.opengl=True DrawBufImgOp -ignore
       
    32  * @author campbelc
       
    33  */
       
    34 
       
    35 import java.awt.*;
       
    36 import java.awt.image.*;
       
    37 import java.io.File;
       
    38 import javax.imageio.ImageIO;
       
    39 
       
    40 /**
       
    41  * REMIND: This testcase was originally intended to automatically compare
       
    42  * the results of the software BufferedImageOp implementations against
       
    43  * the OGL-accelerated codepaths.  However, there are just too many open
       
    44  * bugs in the mediaLib-based codepaths (see below), which means that
       
    45  * creating the reference image may cause crashes or exceptions,
       
    46  * and even if we work around those cases using the "-ignore" flag,
       
    47  * the visual results of the reference image are often buggy as well
       
    48  * (so the comparison will fail even though the OGL results are correct).
       
    49  * Therefore, for now we will run the testcase with the "-ignore" flag
       
    50  * but without the "-compare" flag, so at least it will be checking for
       
    51  * any exceptions/crashes in the OGL code.  When we fix all of the
       
    52  * outstanding bugs with the software codepaths, we can remove the
       
    53  * "-ignore" flag and maybe even restore the "-compare" flag.  In the
       
    54  * meantime, it stil functions well as a manual testcase (with either
       
    55  * the "-show" or "-dump" options).
       
    56  */
       
    57 public class DrawBufImgOp extends Canvas {
       
    58 
       
    59     private static final int TESTW = 600;
       
    60     private static final int TESTH = 500;
       
    61     private static boolean done;
       
    62 
       
    63     /*
       
    64      * If true, skips tests that are known to trigger bugs (which in
       
    65      * turn may cause crashes, exceptions, or other artifacts).
       
    66      */
       
    67     private static boolean ignore;
       
    68 
       
    69     // Test both pow2 and non-pow2 sized images
       
    70     private static final int[] srcSizes = { 32, 17 };
       
    71     private static final int[] srcTypes = {
       
    72         BufferedImage.TYPE_INT_RGB,
       
    73         BufferedImage.TYPE_INT_ARGB,
       
    74         BufferedImage.TYPE_INT_ARGB_PRE,
       
    75         BufferedImage.TYPE_INT_BGR,
       
    76         BufferedImage.TYPE_3BYTE_BGR,
       
    77         BufferedImage.TYPE_4BYTE_ABGR,
       
    78         BufferedImage.TYPE_USHORT_565_RGB,
       
    79         BufferedImage.TYPE_BYTE_GRAY,
       
    80         BufferedImage.TYPE_USHORT_GRAY,
       
    81     };
       
    82 
       
    83     private static final RescaleOp
       
    84         rescale1band, rescale3band, rescale4band;
       
    85     private static final LookupOp
       
    86         lookup1bandbyte, lookup3bandbyte, lookup4bandbyte;
       
    87     private static final LookupOp
       
    88         lookup1bandshort, lookup3bandshort, lookup4bandshort;
       
    89     private static final ConvolveOp
       
    90         convolve3x3zero, convolve5x5zero, convolve7x7zero;
       
    91     private static final ConvolveOp
       
    92         convolve3x3noop, convolve5x5noop, convolve7x7noop;
       
    93 
       
    94     static {
       
    95         rescale1band = new RescaleOp(0.5f, 10.0f, null);
       
    96         rescale3band = new RescaleOp(
       
    97             new float[] {  0.6f,  0.4f, 0.6f },
       
    98             new float[] { 10.0f, -3.0f, 5.0f },
       
    99             null);
       
   100         rescale4band = new RescaleOp(
       
   101             new float[] {  0.6f, 0.4f, 0.6f, 0.9f },
       
   102             new float[] { -1.0f, 5.0f, 3.0f, 1.0f },
       
   103             null);
       
   104 
       
   105         // REMIND: we should probably test non-zero offsets, but that
       
   106         // would require massaging the source image data to avoid going
       
   107         // outside the lookup table array bounds
       
   108         int offset = 0;
       
   109         {
       
   110             byte invert[] = new byte[256];
       
   111             byte halved[] = new byte[256];
       
   112             for (int j = 0; j < 256 ; j++) {
       
   113                 invert[j] = (byte) (255-j);
       
   114                 halved[j] = (byte) (j / 2);
       
   115             }
       
   116             ByteLookupTable lut1 = new ByteLookupTable(offset, invert);
       
   117             lookup1bandbyte = new LookupOp(lut1, null);
       
   118             ByteLookupTable lut3 =
       
   119                 new ByteLookupTable(offset,
       
   120                                     new byte[][] {invert, halved, invert});
       
   121             lookup3bandbyte = new LookupOp(lut3, null);
       
   122             ByteLookupTable lut4 =
       
   123                 new ByteLookupTable(offset,
       
   124                                new byte[][] {invert, halved, invert, halved});
       
   125             lookup4bandbyte = new LookupOp(lut4, null);
       
   126         }
       
   127 
       
   128         {
       
   129             short invert[] = new short[256];
       
   130             short halved[] = new short[256];
       
   131             for (int j = 0; j < 256 ; j++) {
       
   132                 invert[j] = (short) ((255-j) * 255);
       
   133                 halved[j] = (short) ((j / 2) * 255);
       
   134             }
       
   135             ShortLookupTable lut1 = new ShortLookupTable(offset, invert);
       
   136             lookup1bandshort = new LookupOp(lut1, null);
       
   137             ShortLookupTable lut3 =
       
   138                 new ShortLookupTable(offset,
       
   139                                      new short[][] {invert, halved, invert});
       
   140             lookup3bandshort = new LookupOp(lut3, null);
       
   141             ShortLookupTable lut4 =
       
   142                 new ShortLookupTable(offset,
       
   143                               new short[][] {invert, halved, invert, halved});
       
   144             lookup4bandshort = new LookupOp(lut4, null);
       
   145         }
       
   146 
       
   147         // 3x3 blur
       
   148         float[] data3 = {
       
   149             0.1f, 0.1f, 0.1f,
       
   150             0.1f, 0.2f, 0.1f,
       
   151             0.1f, 0.1f, 0.1f,
       
   152         };
       
   153         Kernel k3 = new Kernel(3, 3, data3);
       
   154 
       
   155         // 5x5 edge
       
   156         float[] data5 = {
       
   157             -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
       
   158             -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
       
   159             -1.0f, -1.0f, 24.0f, -1.0f, -1.0f,
       
   160             -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
       
   161             -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
       
   162         };
       
   163         Kernel k5 = new Kernel(5, 5, data5);
       
   164 
       
   165         // 7x7 blur
       
   166         float[] data7 = {
       
   167             0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f,
       
   168             0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f,
       
   169             0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f,
       
   170             0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f,
       
   171             0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f,
       
   172             0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f,
       
   173             0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f,
       
   174         };
       
   175         Kernel k7 = new Kernel(7, 7, data7);
       
   176 
       
   177         convolve3x3zero = new ConvolveOp(k3, ConvolveOp.EDGE_ZERO_FILL, null);
       
   178         convolve5x5zero = new ConvolveOp(k5, ConvolveOp.EDGE_ZERO_FILL, null);
       
   179         convolve7x7zero = new ConvolveOp(k7, ConvolveOp.EDGE_ZERO_FILL, null);
       
   180 
       
   181         convolve3x3noop = new ConvolveOp(k3, ConvolveOp.EDGE_NO_OP, null);
       
   182         convolve5x5noop = new ConvolveOp(k5, ConvolveOp.EDGE_NO_OP, null);
       
   183         convolve7x7noop = new ConvolveOp(k7, ConvolveOp.EDGE_NO_OP, null);
       
   184     }
       
   185 
       
   186     public void paint(Graphics g) {
       
   187         synchronized (this) {
       
   188             if (done) {
       
   189                 return;
       
   190             }
       
   191         }
       
   192 
       
   193         VolatileImage vimg = createVolatileImage(TESTW, TESTH);
       
   194         vimg.validate(getGraphicsConfiguration());
       
   195 
       
   196         Graphics2D g2d = vimg.createGraphics();
       
   197         renderTest(g2d);
       
   198         g2d.dispose();
       
   199 
       
   200         g.drawImage(vimg, 0, 0, null);
       
   201 
       
   202         Toolkit.getDefaultToolkit().sync();
       
   203 
       
   204         synchronized (this) {
       
   205             done = true;
       
   206             notifyAll();
       
   207         }
       
   208     }
       
   209 
       
   210     /*
       
   211      * foreach source image size (once with pow2, once with non-pow2)
       
   212      *
       
   213      *   foreach BufferedImage type
       
   214      *
       
   215      *     RescaleOp (1 band)
       
   216      *     RescaleOp (3 bands, if src has 3 bands)
       
   217      *     RescaleOp (4 bands, if src has 4 bands)
       
   218      *
       
   219      *     foreach LookupTable type (once with ByteLUT, once with ShortLUT)
       
   220      *       LookupOp (1 band)
       
   221      *       LookupOp (3 bands, if src has 3 bands)
       
   222      *       LookupOp (4 bands, if src has 4 bands)
       
   223      *
       
   224      *     foreach edge condition (once with ZERO_FILL, once with EDGE_NO_OP)
       
   225      *       ConvolveOp (3x3)
       
   226      *       ConvolveOp (5x5)
       
   227      *       ConvolveOp (7x7)
       
   228      */
       
   229     private void renderTest(Graphics2D g2d) {
       
   230         g2d.setColor(Color.white);
       
   231         g2d.fillRect(0, 0, TESTW, TESTH);
       
   232 
       
   233         int yorig = 2;
       
   234         int xinc = 34;
       
   235         int yinc = srcSizes[0] + srcSizes[1] + 2 + 2;
       
   236 
       
   237         for (int srcType : srcTypes) {
       
   238             int y = yorig;
       
   239 
       
   240             for (int srcSize : srcSizes) {
       
   241                 int x = 2;
       
   242                 System.out.printf("type=%d size=%d\n", srcType, srcSize);
       
   243 
       
   244                 BufferedImage srcImg = makeSourceImage(srcSize, srcType);
       
   245                 ColorModel srcCM = srcImg.getColorModel();
       
   246 
       
   247                 // RescaleOp
       
   248                 g2d.drawImage(srcImg, rescale1band, x, y);
       
   249                 x += xinc;
       
   250                 // REMIND: 3-band RescaleOp.filter() throws IAE for images
       
   251                 //         that contain an alpha channel (bug to be filed)
       
   252                 if (srcCM.getNumColorComponents() == 3 &&
       
   253                     !(ignore && srcCM.hasAlpha()))
       
   254                 {
       
   255                     g2d.drawImage(srcImg, rescale3band, x, y);
       
   256                 }
       
   257                 x += xinc;
       
   258                 if (srcCM.getNumComponents() == 4) {
       
   259                     g2d.drawImage(srcImg, rescale4band, x, y);
       
   260                 }
       
   261                 x += xinc;
       
   262 
       
   263                 // LookupOp
       
   264                 // REMIND: Our LUTs are only 256 elements long, so won't
       
   265                 //         currently work with USHORT_GRAY data
       
   266                 if (srcType != BufferedImage.TYPE_USHORT_GRAY) {
       
   267                     g2d.drawImage(srcImg, lookup1bandbyte, x, y);
       
   268                     x += xinc;
       
   269                     if (srcCM.getNumColorComponents() == 3) {
       
   270                         g2d.drawImage(srcImg, lookup3bandbyte, x, y);
       
   271                     }
       
   272                     x += xinc;
       
   273                     if (srcCM.getNumComponents() == 4) {
       
   274                         g2d.drawImage(srcImg, lookup4bandbyte, x, y);
       
   275                     }
       
   276                     x += xinc;
       
   277 
       
   278                     // REMIND: LookupOp.createCompatibleDestImage() throws
       
   279                     //         IAE for 3BYTE_BGR/4BYTE_ABGR (bug to be filed)
       
   280                     if (!(ignore &&
       
   281                           (srcType == BufferedImage.TYPE_3BYTE_BGR ||
       
   282                            srcType == BufferedImage.TYPE_4BYTE_ABGR)))
       
   283                     {
       
   284                         g2d.drawImage(srcImg, lookup1bandshort, x, y);
       
   285                         x += xinc;
       
   286                         // REMIND: 3-band LookupOp.filter() throws IAE for
       
   287                         //         images that contain an alpha channel
       
   288                         //         (bug to be filed)
       
   289                         if (srcCM.getNumColorComponents() == 3 &&
       
   290                             !(ignore && srcCM.hasAlpha()))
       
   291                         {
       
   292                             g2d.drawImage(srcImg, lookup3bandshort, x, y);
       
   293                         }
       
   294                         x += xinc;
       
   295                         if (srcCM.getNumComponents() == 4) {
       
   296                             g2d.drawImage(srcImg, lookup4bandshort, x, y);
       
   297                         }
       
   298                         x += xinc;
       
   299                     } else {
       
   300                         x += 3*xinc;
       
   301                     }
       
   302                 } else {
       
   303                     x += 6*xinc;
       
   304                 }
       
   305 
       
   306                 // ConvolveOp
       
   307                 // REMIND: ConvolveOp.filter() throws ImagingOpException
       
   308                 //         for 3BYTE_BGR (see 4957775)
       
   309                 if (srcType != BufferedImage.TYPE_3BYTE_BGR) {
       
   310                     g2d.drawImage(srcImg, convolve3x3zero, x, y);
       
   311                     x += xinc;
       
   312                     g2d.drawImage(srcImg, convolve5x5zero, x, y);
       
   313                     x += xinc;
       
   314                     g2d.drawImage(srcImg, convolve7x7zero, x, y);
       
   315                     x += xinc;
       
   316 
       
   317                     g2d.drawImage(srcImg, convolve3x3noop, x, y);
       
   318                     x += xinc;
       
   319                     g2d.drawImage(srcImg, convolve5x5noop, x, y);
       
   320                     x += xinc;
       
   321                     g2d.drawImage(srcImg, convolve7x7noop, x, y);
       
   322                     x += xinc;
       
   323                 } else {
       
   324                     x += 6*xinc;
       
   325                 }
       
   326 
       
   327                 y += srcSize + 2;
       
   328             }
       
   329 
       
   330             yorig += yinc;
       
   331         }
       
   332     }
       
   333 
       
   334     private BufferedImage makeSourceImage(int size, int type) {
       
   335         int s2 = size/2;
       
   336         BufferedImage img = new BufferedImage(size, size, type);
       
   337         Graphics2D g2d = img.createGraphics();
       
   338         g2d.setComposite(AlphaComposite.Src);
       
   339         g2d.setColor(Color.orange);
       
   340         g2d.fillRect(0, 0, size, size);
       
   341         g2d.setColor(Color.red);
       
   342         g2d.fillRect(0, 0, s2, s2);
       
   343         g2d.setColor(Color.green);
       
   344         g2d.fillRect(s2, 0, s2, s2);
       
   345         g2d.setColor(Color.blue);
       
   346         g2d.fillRect(0, s2, s2, s2);
       
   347         g2d.setColor(new Color(255, 255, 0, 128));
       
   348         g2d.fillRect(s2, s2, s2, s2);
       
   349         g2d.setColor(Color.pink);
       
   350         g2d.fillOval(s2-3, s2-3, 6, 6);
       
   351         g2d.dispose();
       
   352         return img;
       
   353     }
       
   354 
       
   355     public BufferedImage makeReferenceImage() {
       
   356         BufferedImage img = new BufferedImage(TESTW, TESTH,
       
   357                                               BufferedImage.TYPE_INT_RGB);
       
   358         Graphics2D g2d = img.createGraphics();
       
   359         renderTest(g2d);
       
   360         g2d.dispose();
       
   361         return img;
       
   362     }
       
   363 
       
   364     public Dimension getPreferredSize() {
       
   365         return new Dimension(TESTW, TESTH);
       
   366     }
       
   367 
       
   368     private static void compareImages(BufferedImage refImg,
       
   369                                       BufferedImage testImg,
       
   370                                       int tolerance)
       
   371     {
       
   372         int x1 = 0;
       
   373         int y1 = 0;
       
   374         int x2 = refImg.getWidth();
       
   375         int y2 = refImg.getHeight();
       
   376 
       
   377         for (int y = y1; y < y2; y++) {
       
   378             for (int x = x1; x < x2; x++) {
       
   379                 Color expected = new Color(refImg.getRGB(x, y));
       
   380                 Color actual   = new Color(testImg.getRGB(x, y));
       
   381                 if (!isSameColor(expected, actual, tolerance)) {
       
   382                     throw new RuntimeException("Test failed at x="+x+" y="+y+
       
   383                                                " (expected="+expected+
       
   384                                                " actual="+actual+
       
   385                                                ")");
       
   386                 }
       
   387             }
       
   388         }
       
   389     }
       
   390 
       
   391     private static boolean isSameColor(Color c1, Color c2, int e) {
       
   392         int r1 = c1.getRed();
       
   393         int g1 = c1.getGreen();
       
   394         int b1 = c1.getBlue();
       
   395         int r2 = c2.getRed();
       
   396         int g2 = c2.getGreen();
       
   397         int b2 = c2.getBlue();
       
   398         int rmin = Math.max(r2-e, 0);
       
   399         int gmin = Math.max(g2-e, 0);
       
   400         int bmin = Math.max(b2-e, 0);
       
   401         int rmax = Math.min(r2+e, 255);
       
   402         int gmax = Math.min(g2+e, 255);
       
   403         int bmax = Math.min(b2+e, 255);
       
   404         if (r1 >= rmin && r1 <= rmax &&
       
   405             g1 >= gmin && g1 <= gmax &&
       
   406             b1 >= bmin && b1 <= bmax)
       
   407         {
       
   408             return true;
       
   409         }
       
   410         return false;
       
   411     }
       
   412 
       
   413     public static void main(String[] args) throws Exception {
       
   414         boolean show = false;
       
   415         boolean dump = false;
       
   416         boolean compare = false;
       
   417 
       
   418         for (String arg : args) {
       
   419             if (arg.equals("-show")) {
       
   420                 show = true;
       
   421             } else if (arg.equals("-dump")) {
       
   422                 dump = true;
       
   423             } else if (arg.equals("-compare")) {
       
   424                 compare = true;
       
   425             } else if (arg.equals("-ignore")) {
       
   426                 ignore = true;
       
   427             }
       
   428         }
       
   429 
       
   430         DrawBufImgOp test = new DrawBufImgOp();
       
   431         Frame frame = new Frame();
       
   432         frame.add(test);
       
   433         frame.pack();
       
   434         frame.setVisible(true);
       
   435 
       
   436         // Wait until the component's been painted
       
   437         synchronized (test) {
       
   438             while (!done) {
       
   439                 try {
       
   440                     test.wait();
       
   441                 } catch (InterruptedException e) {
       
   442                     throw new RuntimeException("Failed: Interrupted");
       
   443                 }
       
   444             }
       
   445         }
       
   446 
       
   447         GraphicsConfiguration gc = frame.getGraphicsConfiguration();
       
   448         if (gc.getColorModel() instanceof IndexColorModel) {
       
   449             System.out.println("IndexColorModel detected: " +
       
   450                                "test considered PASSED");
       
   451             frame.dispose();
       
   452             return;
       
   453         }
       
   454 
       
   455         // Grab the screen region
       
   456         BufferedImage capture = null;
       
   457         try {
       
   458             Robot robot = new Robot();
       
   459             Point pt1 = test.getLocationOnScreen();
       
   460             Rectangle rect = new Rectangle(pt1.x, pt1.y, TESTW, TESTH);
       
   461             capture = robot.createScreenCapture(rect);
       
   462         } catch (Exception e) {
       
   463             throw new RuntimeException("Problems creating Robot");
       
   464         } finally {
       
   465             if (!show) {
       
   466                 frame.dispose();
       
   467             }
       
   468         }
       
   469 
       
   470         // Compare the images (allow for +/- 1 bit differences in color comps)
       
   471         if (dump || compare) {
       
   472             BufferedImage ref = test.makeReferenceImage();
       
   473             if (dump) {
       
   474                 ImageIO.write(ref,     "png",
       
   475                               new File("DrawBufImgOp.ref.png"));
       
   476                 ImageIO.write(capture, "png",
       
   477                               new File("DrawBufImgOp.cap.png"));
       
   478             }
       
   479             if (compare) {
       
   480                 test.compareImages(ref, capture, 1);
       
   481             }
       
   482         }
       
   483     }
       
   484 }