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 }