1 /*
   2  * Copyright (c) 2010, 2011, 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 5089429 6982632 8145808
  27   @summary Checks that we don't crash if rendering operations and state
  28   changes are performed on a graphics context from different threads.
  29 
  30   @author Dmitri.Trembovetski@sun.com area=Graphics
  31   @run main MTGraphicsAccessTest
  32  */
  33 
  34 import java.awt.*;
  35 import java.awt.image.*;
  36 import java.awt.geom.*;
  37 import java.util.concurrent.atomic.AtomicInteger;
  38 
  39 public class MTGraphicsAccessTest {
  40 
  41     // in seconds
  42     static final long STANDALONE_RUN_TIME = 20;
  43     static final long JTREG_RUN_TIME = 7;
  44 
  45     static boolean standaloneMode;
  46     static boolean allowExceptions = true;
  47     static long testRunTime;
  48 
  49     volatile boolean done;
  50     AtomicInteger stillRunning = new AtomicInteger(0);
  51     volatile int numexceptions;
  52 
  53     Graphics2D sharedGraphics;
  54     BufferedImage sharedBI =
  55             new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
  56 
  57     static final Paint colors[] = {
  58         Color.red,
  59         new Color(0x7f, 0xff, 0x00, 0x7f),
  60         new GradientPaint(0,  0, Color.red,
  61                           50, 50, new Color(0x7f, 0xff, 0x00, 0x7f)),
  62     };
  63     static final Font fonts[] = {
  64         new Font("Dialog", Font.PLAIN, 12),
  65         new Font("Dialog", Font.BOLD, 16),
  66         new Font("Dialog", Font.ITALIC, 18),
  67     };
  68     static final AlphaComposite comps[] = {
  69         AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f),
  70         AlphaComposite.Src,
  71         AlphaComposite.Xor,
  72         AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f),
  73         null,
  74     };
  75     static final Stroke strokes[] = {
  76         new BasicStroke(),
  77         new BasicStroke(0.0f),
  78         new BasicStroke(2.0f),
  79         new BasicStroke(2.0f, BasicStroke.CAP_ROUND,
  80                         BasicStroke.JOIN_BEVEL),
  81         new BasicStroke(5.0f, BasicStroke.CAP_SQUARE,
  82                         BasicStroke.JOIN_ROUND),
  83         new BasicStroke(0.0f, BasicStroke.CAP_ROUND,
  84                         BasicStroke.JOIN_ROUND, 0,
  85                         new float[]{0,6,0,6}, 0),
  86     };
  87     static final AffineTransform transforms[] = {
  88         new AffineTransform(),
  89         AffineTransform.getRotateInstance(10.0),
  90         AffineTransform.getShearInstance(10.0, 4.0),
  91         AffineTransform.getScaleInstance(1.1, 1.2),
  92         AffineTransform.getScaleInstance(3.0, 2.0),
  93     };
  94 
  95     public MTGraphicsAccessTest() {
  96         BufferedImage bi =
  97             new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
  98         sharedGraphics = (Graphics2D)bi.getGraphics();
  99 
 100         done = false;
 101         numexceptions = 0;
 102 
 103         for (int i = 0; i < (standaloneMode ? stateChangers.length : 3); i++) {
 104             (new TesterThread(stateChangers[i])).start();
 105         }
 106         for (int i = 0; i < (standaloneMode ? renderTests.length : 5); i++) {
 107             (new TesterThread(renderTests[i])).start();
 108         }
 109 
 110         mysleep(testRunTime);
 111         done = true;
 112         while (stillRunning.get() > 0) { mysleep(500); }
 113 
 114         if (numexceptions == 0) {
 115             System.err.println("Test passed");
 116         } else if (!allowExceptions) {
 117             throw new RuntimeException("Test failed with "+
 118                                        numexceptions+" exceptions");
 119         } else {
 120             System.err.println("Test finished with "+
 121                                numexceptions+" exceptions");
 122         }
 123     }
 124 
 125     private void mysleep(long time) {
 126         try {
 127             // add +/-5ms variance to increase randomness
 128             Thread.sleep(time + (long)(5 - Math.random()*10));
 129         } catch (InterruptedException e) {};
 130     }
 131 
 132     public static void usage(String message) {
 133         if (message != null) {
 134             System.err.println(message);
 135         }
 136         System.err.println("Usage: MTGraphicsAccessTest [-full] "+
 137             "[-time N/forever] [-help]");
 138         System.err.println(" -full: run full suite of tests "+
 139             "(default: limited number of tests is run)");
 140         System.err.println(" -time N: test duration in seconds/forever"+
 141             " (default: "+JTREG_RUN_TIME+"s for the short suite, "+
 142             STANDALONE_RUN_TIME+"s for the full suite)");
 143         System.err.println(" -help: print this help page");
 144         System.exit(1);
 145     }
 146 
 147     public static void main(String[] args) {
 148         boolean testRunSet = false;
 149         for (int i = 0; i < args.length; i++) {
 150             if ("-full".equals(args[i])) {
 151                 standaloneMode = true;
 152                 System.err.println("Running complete list of tests");
 153             } else if ("-noexc".equals(args[i])) {
 154                 allowExceptions = false;
 155             } else if ("-time".equals(args[i])) {
 156                 try {
 157                     String time = args[++i];
 158                     if ("forever".equals(time)) {
 159                         testRunTime = (Long.MAX_VALUE - 20)/1000;
 160                     } else {
 161                         testRunTime = 1000*Integer.parseInt(time);
 162                     }
 163                     testRunSet = true;
 164                 } catch (NumberFormatException e) {
 165                     usage("Can't parse number of seconds: " + args[i]);
 166                 } catch (ArrayIndexOutOfBoundsException e1) {
 167                     usage("Missing the 'seconds' argument for -time parameter");
 168                 }
 169             } else if ("-help".equals(args[i])) {
 170                 usage(null);
 171             } else {
 172                 usage("Unknown argument:" + args[i]);
 173             }
 174         }
 175 
 176         if (!testRunSet) {
 177             testRunTime = 1000 *
 178                 (standaloneMode ? STANDALONE_RUN_TIME : JTREG_RUN_TIME);
 179         }
 180 
 181         System.err.println("Approximate test run time: "+
 182              testRunTime/1000+" seconds");
 183 
 184         new MTGraphicsAccessTest();
 185     }
 186 
 187     class TesterThread extends Thread {
 188         Runnable testRunnable;
 189 
 190         public TesterThread(Runnable testRunnable) {
 191             stillRunning.incrementAndGet();
 192             this.testRunnable = testRunnable;
 193         }
 194 
 195         public void run() {
 196             try {
 197                 while (!done) {
 198                     try {
 199                         testRunnable.run();
 200                         yield();
 201                     } catch (Throwable t) {
 202                         numexceptions++;
 203                         t.printStackTrace();
 204                     }
 205                 }
 206             } finally {
 207                 stillRunning.decrementAndGet();
 208             }
 209         }
 210     }
 211 
 212     final Runnable stateChangers[] = {
 213         new Runnable() {
 214             public void run() {
 215                 sharedGraphics.setClip(10, 10, 30, 30);
 216                 mysleep(10);
 217             }
 218         },
 219         new Runnable() {
 220             public void run() {
 221                 sharedGraphics.setClip(10, 10, 30, 30);
 222                 mysleep(10);
 223             }
 224         },
 225         new Runnable() {
 226             int c = 0;
 227             public void run() {
 228                 sharedGraphics.setPaint(colors[c++ % colors.length]);
 229                 mysleep(10);
 230             }
 231         },
 232         new Runnable() {
 233             boolean AA = false;
 234             public void run() {
 235                 if (AA) {
 236                     sharedGraphics.setRenderingHint(
 237                         RenderingHints.KEY_ANTIALIASING,
 238                         RenderingHints.VALUE_ANTIALIAS_ON);
 239                 } else {
 240                     sharedGraphics.setRenderingHint(
 241                         RenderingHints.KEY_ANTIALIASING,
 242                         RenderingHints.VALUE_ANTIALIAS_OFF);
 243                 }
 244                 AA = !AA;
 245                 mysleep(10);
 246             }
 247         },
 248         new Runnable() {
 249             int t = 0;
 250             public void run() {
 251                 sharedGraphics.setTransform(
 252                     transforms[t++ % transforms.length]);
 253                 mysleep(10);
 254             }
 255         },
 256         new Runnable() {
 257             int c = 0;
 258             public void run() {
 259                 AlphaComposite comp = comps[c++ % comps.length];
 260                 if (comp == null) {
 261                     sharedGraphics.setXORMode(Color.green);
 262                 } else {
 263                     sharedGraphics.setComposite(comp);
 264                 }
 265                 mysleep(10);
 266             }
 267         },
 268         new Runnable() {
 269             int s = 0;
 270             public void run() {
 271                 sharedGraphics.setStroke(strokes[s++ % strokes.length]);
 272                 mysleep(10);
 273             }
 274         },
 275         new Runnable() {
 276             int f = 0;
 277             public void run() {
 278                 sharedGraphics.setFont(fonts[f++ % fonts.length]);
 279                 mysleep(10);
 280             }
 281         },
 282     };
 283 
 284     final Runnable renderTests[] = {
 285         new Runnable() {
 286             public void run() {
 287                 sharedGraphics.drawLine(10, 10, 30, 30);
 288             }
 289         },
 290         new Runnable() {
 291             public void run() {
 292                 sharedGraphics.drawLine(10, 10, 30, 30);
 293             }
 294         },
 295         new Runnable() {
 296             public void run() {
 297                 sharedGraphics.drawRect(10, 10, 30, 30);
 298             }
 299         },
 300         new Runnable() {
 301             public void run() {
 302                 sharedGraphics.fillRect(10, 10, 30, 30);
 303             }
 304         },
 305         new Runnable() {
 306             public void run() {
 307                 sharedGraphics.drawString("Stuff", 10, 10);
 308             }
 309         },
 310         new Runnable() {
 311             public void run() {
 312                 sharedGraphics.draw3DRect(10, 10, 30, 30, true);
 313             }
 314         },
 315         new Runnable() {
 316             public void run() {
 317                 sharedGraphics.drawImage(sharedBI, 10, 10, null);
 318             }
 319         },
 320         new Runnable() {
 321             public void run() {
 322                 sharedGraphics.fill3DRect(10, 10, 30, 30, false);
 323             }
 324         },
 325         // REMIND: copyArea doesn't work when transform is set..
 326         //          new Runnable() {
 327         //              public void run() {
 328         //                  sharedGraphics.copyArea(10, 10, 30, 30, 20, 20);
 329         //              }
 330         //          },
 331         new Runnable() {
 332             public void run() {
 333                 sharedGraphics.drawRoundRect(10, 10, 30, 30, 20, 20);
 334             }
 335         },
 336         new Runnable() {
 337             public void run() {
 338                 sharedGraphics.fillRoundRect(10, 10, 30, 30, 20, 20);
 339             }
 340         },
 341         new Runnable() {
 342             public void run() {
 343                 sharedGraphics.drawArc(10, 10, 30, 30, 0, 90);
 344             }
 345         },
 346         new Runnable() {
 347             public void run() {
 348                 sharedGraphics.fillArc(10, 10, 30, 30, 0, 90);
 349             }
 350         },
 351         new Runnable() {
 352             public void run() {
 353                 sharedGraphics.drawOval(10, 10, 30, 30);
 354             }
 355         },
 356         new Runnable() {
 357             public void run() {
 358                 sharedGraphics.fillOval(10, 10, 30, 30);
 359             }
 360         }
 361     };
 362 }