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