1 /*
   2  * Copyright (c) 2005, 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 /*
  25  * @test
  26  * @key headful
  27  * @bug 4832224 6322584 6328478 6328481 6322580 6588884 6587863
  28  * @summary Verifies that the pixelization of simple primitives (drawLine,
  29  * fillRect, drawRect, fill, draw) with the OGL pipeline enabled
  30  * matches that produced by our software loops.  (The primitives tested here
  31  * are simple enough that the OGL results should match the software results
  32  * exactly.)  There is some overlap with PolyVertTest as we test both
  33  * solid and XOR rendering here, but this testcase is a bit simpler and
  34  * more appropriate for quick OGL testing.  This test is also useful for
  35  * comparing quality between our X11/GDI and software pipelines.
  36  * @run main/othervm SimplePrimQuality
  37  * @run main/othervm -Dsun.java2d.opengl=True SimplePrimQuality
  38  * @author campbelc
  39  */
  40 
  41 import java.awt.*;
  42 import java.awt.geom.*;
  43 import java.awt.image.*;
  44 import java.io.File;
  45 import java.io.IOException;
  46 import javax.imageio.ImageIO;
  47 
  48 public class SimplePrimQuality extends Canvas {
  49 
  50     private static final int SIZE = 300;
  51     private static boolean done;
  52     private static boolean testVI;
  53     private static volatile BufferedImage capture;
  54     private static void doCapture(Component test) {
  55         // Grab the screen region
  56         try {
  57             Robot robot = new Robot();
  58             Point pt1 = test.getLocationOnScreen();
  59             Rectangle rect =
  60                 new Rectangle(pt1.x, pt1.y, test.getWidth(), test.getHeight());
  61             capture = robot.createScreenCapture(rect);
  62         } catch (Exception e) {
  63             e.printStackTrace();
  64         }
  65     }
  66 
  67     private static final int[][] rpts = {
  68         {2, 0, 0, 0},
  69         {12, 0, 1, 0},
  70         {22, 0, 0, 1},
  71         {32, 0, 1, 1},
  72         {42, 0, 2, 1},
  73         {52, 0, 1, 2},
  74         {62, 0, 2, 2},
  75         {72, 0, 5, 5},
  76         {82, 0, 10, 10},
  77         {97, 0, 15, 15},
  78     };
  79 
  80     private void drawLine(Graphics2D g, int x, int y, int dx, int dy) {
  81         g.drawLine(x, y, x + dx, y + dy);
  82     }
  83 
  84     private void drawLines(Graphics2D g, int s) {
  85         drawLine(g, 2, 0, 0, 0);
  86         drawLine(g, 12, 0, 0, s);
  87         drawLine(g, 22, 0, s, 0);
  88         drawLine(g, 32, 0, s, s);
  89         drawLine(g, 42, 0, 0, -s);
  90         drawLine(g, 52, 0, -s, 0);
  91         drawLine(g, 62, 0, -s, -s);
  92         drawLine(g, 72, 0, -s, s);
  93         drawLine(g, 82, 0, s, -s);
  94     }
  95 
  96     private void fillRects(Graphics2D g) {
  97         for (int i = 0; i < rpts.length; i++) {
  98             g.fillRect(rpts[i][0], rpts[i][1], rpts[i][2], rpts[i][3]);
  99         }
 100     }
 101 
 102     private void drawRects(Graphics2D g) {
 103         for (int i = 0; i < rpts.length; i++) {
 104             g.drawRect(rpts[i][0], rpts[i][1], rpts[i][2], rpts[i][3]);
 105         }
 106     }
 107 
 108     private void fillOvals(Graphics2D g) {
 109         for (int i = 0; i < rpts.length; i++) {
 110             // use fill() instead of fillOval(), since the former is more
 111             // likely to be consistent with our software loops when the
 112             // OGL pipeline cannot be enabled
 113             g.fill(new Ellipse2D.Float(rpts[i][0], rpts[i][1],
 114                                        rpts[i][2], rpts[i][3]));
 115         }
 116     }
 117 
 118     private void drawOvals(Graphics2D g) {
 119         for (int i = 0; i < rpts.length; i++) {
 120             // use draw() instead of drawOval(), since the former is more
 121             // likely to be consistent with our software loops when the
 122             // OGL pipeline cannot be enabled
 123             g.draw(new Ellipse2D.Float(rpts[i][0], rpts[i][1],
 124                                        rpts[i][2], rpts[i][3]));
 125         }
 126     }
 127 
 128     private void renderShapes(Graphics2D g) {
 129         // drawLine tests...
 130         g.translate(0, 5);
 131         drawLines(g, 1);
 132         g.translate(0, 10);
 133         drawLines(g, 4);
 134 
 135         // fillRect tests...
 136         g.translate(0, 10);
 137         fillRects(g);
 138 
 139         // drawRect tests...
 140         g.translate(0, 20);
 141         drawRects(g);
 142 
 143         // fillOval tests...
 144         g.translate(0, 20);
 145         fillOvals(g);
 146 
 147         // drawOval tests...
 148         g.translate(0, 20);
 149         drawOvals(g);
 150     }
 151 
 152     private void renderTest(Graphics2D g, int w, int h) {
 153         // on the left side, render the shapes in solid mode
 154         g.setColor(Color.black);
 155         g.fillRect(0, 0, w, h);
 156         g.setColor(Color.green);
 157         renderShapes(g);
 158 
 159         // on the right side, render the shapes in XOR mode
 160         g.setTransform(AffineTransform.getTranslateInstance(SIZE/2, 0));
 161         g.setXORMode(Color.black);
 162         renderShapes(g);
 163         g.setTransform(AffineTransform.getTranslateInstance(SIZE/2, 0));
 164         renderShapes(g);
 165     }
 166 
 167     public void paint(Graphics g) {
 168 
 169         Graphics2D g2d = (Graphics2D)g;
 170         renderTest(g2d, SIZE, SIZE);
 171 
 172         Toolkit.getDefaultToolkit().sync();
 173 
 174         synchronized (this) {
 175             if (!done) {
 176                 doCapture(this);
 177                 done = true;
 178             }
 179             notifyAll();
 180         }
 181     }
 182 
 183     public Dimension getPreferredSize() {
 184         return new Dimension(SIZE, SIZE);
 185     }
 186 
 187     public static void main(String[] args) {
 188         boolean show = false;
 189         for (String arg : args) {
 190             if (arg.equals("-testvi")) {
 191                 System.out.println("Testing VolatileImage, not screen");
 192                 testVI = true;
 193             } else if (arg.equals("-show")) {
 194                 show = true;
 195             }
 196         }
 197 
 198         SimplePrimQuality test = new SimplePrimQuality();
 199         Frame frame = new Frame();
 200         frame.add(test);
 201         frame.pack();
 202         frame.setVisible(true);
 203 
 204         // Wait until the component's been painted
 205         synchronized (test) {
 206             while (!done) {
 207                 try {
 208                     test.wait();
 209                 } catch (InterruptedException e) {
 210                     throw new RuntimeException("Failed: Interrupted");
 211                 }
 212             }
 213         }
 214 
 215         // REMIND: We will allow this test to pass silently on Windows
 216         // (when OGL is not enabled) until we fix the GDI pipeline so that
 217         // its stroked/filled GeneralPaths match our software loops (see
 218         // 6322554).  This check should be removed when 6322554 is fixed.
 219         GraphicsConfiguration gc = frame.getGraphicsConfiguration();
 220         if (gc.getClass().getSimpleName().startsWith("Win")) {
 221             System.out.println("GDI pipeline detected: " +
 222                                "test considered PASSED");
 223             frame.dispose();
 224             return;
 225         }
 226 
 227 
 228         if (testVI) {
 229             // render to a VI instead of the screen
 230             VolatileImage vi = frame.createVolatileImage(SIZE, SIZE);
 231             do {
 232                 vi.validate(frame.getGraphicsConfiguration());
 233                 Graphics2D g1 = vi.createGraphics();
 234                 test.renderTest(g1, SIZE, SIZE);
 235                 g1.dispose();
 236                 capture = vi.getSnapshot();
 237             } while (vi.contentsLost());
 238             frame.dispose();
 239         }
 240 
 241         if (!show) {
 242             frame.dispose();
 243         }
 244         if (capture == null) {
 245             throw new RuntimeException("Error capturing the rendering");
 246         }
 247 
 248         // Create reference image
 249         int w = SIZE, h = SIZE;
 250         BufferedImage refimg = new BufferedImage(w, h,
 251                                                  BufferedImage.TYPE_INT_RGB);
 252         Graphics2D g = refimg.createGraphics();
 253         test.renderTest(g, w, h);
 254         g.dispose();
 255 
 256         // Test pixels
 257         for (int y = 0; y < h; y++) {
 258             for (int x = 0; x < w; x++) {
 259                 int actual = capture.getRGB(x, y);
 260                 int expected = refimg.getRGB(x, y);
 261                 if (actual != expected) {
 262                     String expectedName = "SimplePrimQuality_expected.png";
 263                     String actualName = "SimplePrimQuality_actual.png";
 264                     try {
 265                         System.out.println("Writing expected image to: "+
 266                                            expectedName);
 267                         ImageIO.write(refimg, "png", new File(expectedName));
 268                         System.out.println("Writing actual image   to: "+
 269                                            actualName);
 270                         ImageIO.write(capture, "png", new File(actualName));
 271                     } catch (IOException ex) {}
 272                     throw new RuntimeException("Test failed at x="+x+" y="+y+
 273                                                " (expected="+
 274                                                Integer.toHexString(expected) +
 275                                                " actual="+
 276                                                Integer.toHexString(actual) +
 277                                                ")");
 278                 }
 279             }
 280         }
 281     }
 282 }