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 
MTGraphicsAccessTest()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 
mysleep(long time)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 
usage(String message)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 
main(String[] args)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 
TesterThread(Runnable testRunnable)190         public TesterThread(Runnable testRunnable) {
191             stillRunning.incrementAndGet();
192             this.testRunnable = testRunnable;
193         }
194 
run()195         public void run() {
196             try {
197                 while (!done) {
198                     try {
199                         testRunnable.run();
200                         Thread.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 }
363