1 /*
2  * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 
41 package j2dbench.tests;
42 
43 import java.awt.Graphics;
44 import java.awt.Graphics2D;
45 import java.awt.AlphaComposite;
46 import java.awt.RenderingHints;
47 import java.awt.Polygon;
48 import java.awt.Color;
49 import java.awt.Dimension;
50 import java.awt.geom.Point2D;
51 import java.awt.geom.AffineTransform;
52 import java.lang.reflect.Field;
53 
54 import j2dbench.Destinations;
55 import j2dbench.Group;
56 import j2dbench.Option;
57 import j2dbench.Result;
58 import j2dbench.Test;
59 import j2dbench.TestEnvironment;
60 
61 public abstract class GraphicsTests extends Test {
62     public static boolean hasGraphics2D;
63 
64     static {
65         try {
66             hasGraphics2D = (Graphics2D.class != null);
67         } catch (NoClassDefFoundError e) {
68         }
69     }
70 
makeAlphaColor(Color opaque, int alpha)71     static Color makeAlphaColor(Color opaque, int alpha) {
72         try {
73             opaque = new Color(opaque.getRed(),
74                                opaque.getGreen(),
75                                opaque.getBlue(),
76                                alpha);
77         } catch (NoSuchMethodError e) {
78         }
79         return opaque;
80     }
81 
82     static Group graphicsroot;
83     static Group groptroot;
84 
85     static Option animList;
86     static Option sizeList;
87     static Option compRules;
88     static Option transforms;
89     static Option doExtraAlpha;
90     static Option doXor;
91     static Option doClipping;
92     static Option renderHint;
93     // REMIND: transform, etc.
94 
init()95     public static void init() {
96         graphicsroot = new Group("graphics", "Graphics Benchmarks");
97         graphicsroot.setTabbed();
98 
99         groptroot = new Group(graphicsroot, "opts", "General Graphics Options");
100 
101         animList = new Option.IntList(groptroot, "anim",
102                                       "Movement of rendering position",
103                                       new int[] {0, 1, 2},
104                                       new String[] {
105                                           "static", "slide", "bounce",
106                                       },
107                                       new String[] {
108                                           "No movement",
109                                           "Shift horizontal alignment",
110                                           "Bounce around window",
111                                       }, 0x4);
112 
113         sizeList = new Option.IntList(groptroot, "sizes",
114                                       "Size of Operations to perform",
115                                       new int[] {1, 20, 100, 250, 1000, 4000},
116                                       new String[] {
117                                           "1x1", "20x20", "100x100", "250x250",
118                                           "1000x1000", "4000x4000",
119                                       },
120                                       new String[] {
121                                           "Tiny Shapes (1x1)",
122                                           "Small Shapes (20x20)",
123                                           "Medium Shapes (100x100)",
124                                           "Large Shapes (250x250)",
125                                           "X-Large Shapes (1000x1000)",
126                                           "Huge Shapes (4000x4000)",
127                                       }, 0xa);
128         if (hasGraphics2D) {
129             String rulenames[] = {
130                 "Clear",
131                 "Src",
132                 "Dst",
133                 "SrcOver",
134                 "DstOver",
135                 "SrcIn",
136                 "DstIn",
137                 "SrcOut",
138                 "DstOut",
139                 "SrcAtop",
140                 "DstAtop",
141                 "Xor",
142             };
143             String ruledescs[] = new String[rulenames.length];
144             Object rules[] = new Object[rulenames.length];
145             int j = 0;
146             int defrule = 0;
147             for (int i = 0; i < rulenames.length; i++) {
148                 String rulename = rulenames[i];
149                 try {
150                     Field f = AlphaComposite.class.getField(rulename);
151                     rules[j] = f.get(null);
152                 } catch (NoSuchFieldException nsfe) {
153                     continue;
154                 } catch (IllegalAccessException iae) {
155                     continue;
156                 }
157                 if (rules[j] == AlphaComposite.SrcOver) {
158                     defrule = j;
159                 }
160                 rulenames[j] = rulename;
161                 String suffix;
162                 if (rulename.startsWith("Src")) {
163                     suffix = rulename.substring(3);
164                     rulename = "Source";
165                 } else if (rulename.startsWith("Dst")) {
166                     suffix = rulename.substring(3);
167                     rulename = "Dest";
168                 } else {
169                     suffix = "";
170                 }
171                 if (suffix.length() > 0) {
172                     suffix = " "+suffix;
173                 }
174                 ruledescs[j] = rulename+suffix;
175                 j++;
176             }
177             compRules =
178                 new Option.ObjectList(groptroot, "alpharule",
179                                       "AlphaComposite Rule",
180                                       j, rulenames, rules, rulenames,
181                                       ruledescs, (1 << defrule));
182             ((Option.ObjectList) compRules).setNumRows(4);
183 
184             Transform xforms[] = {
185                 Identity.instance,
186                 FTranslate.instance,
187                 Scale2x2.instance,
188                 Rotate15.instance,
189                 ShearX.instance,
190                 ShearY.instance,
191             };
192             String xformnames[] = new String[xforms.length];
193             String xformdescs[] = new String[xforms.length];
194             for (int i = 0; i < xforms.length; i++) {
195                 xformnames[i] = xforms[i].getShortName();
196                 xformdescs[i] = xforms[i].getDescription();
197             }
198             transforms =
199                 new Option.ObjectList(groptroot, "transform",
200                                       "Affine Transform",
201                                       xforms.length,
202                                       xformnames, xforms, xformnames,
203                                       xformdescs, 0x1);
204             ((Option.ObjectList) transforms).setNumRows(3);
205 
206             doExtraAlpha =
207                 new Option.Toggle(groptroot, "extraalpha",
208                                   "Render with an \"extra alpha\" of 0.125",
209                                   Option.Toggle.Off);
210             doXor =
211                 new Option.Toggle(groptroot, "xormode",
212                                   "Render in XOR mode", Option.Toggle.Off);
213             doClipping =
214                 new Option.Toggle(groptroot, "clip",
215                                   "Render through a complex clip shape",
216                                   Option.Toggle.Off);
217             String rhintnames[] = {
218                 "Default", "Speed", "Quality",
219             };
220             renderHint =
221                 new Option.ObjectList(groptroot, "renderhint",
222                                       "Rendering Hint",
223                                       rhintnames, new Object[] {
224                                           RenderingHints.VALUE_RENDER_DEFAULT,
225                                           RenderingHints.VALUE_RENDER_SPEED,
226                                           RenderingHints.VALUE_RENDER_QUALITY,
227                                       }, rhintnames, rhintnames, 1);
228         }
229     }
230 
231     public static class Context {
232         Graphics graphics;
233         Dimension outdim;
234         boolean animate;
235         int size;
236         int orgX, orgY;
237         int initX, initY;
238         int maxX, maxY;
239         double pixscale;
240     }
241 
GraphicsTests(Group parent, String nodeName, String description)242     public GraphicsTests(Group parent, String nodeName, String description) {
243         super(parent, nodeName, description);
244         addDependency(Destinations.destroot);
245         addDependencies(groptroot, false);
246     }
247 
initTest(TestEnvironment env, Result result)248     public Object initTest(TestEnvironment env, Result result) {
249         Context ctx = createContext();
250         initContext(env, ctx);
251         result.setUnits((int) (ctx.pixscale * pixelsTouched(ctx)));
252         result.setUnitName("pixel");
253         return ctx;
254     }
255 
pixelsTouched(Context ctx)256     public int pixelsTouched(Context ctx) {
257         return ctx.outdim.width * ctx.outdim.height;
258     }
259 
createContext()260     public Context createContext() {
261         return new Context();
262     }
263 
getOutputSize(int w, int h)264     public Dimension getOutputSize(int w, int h) {
265         return new Dimension(w, h);
266     }
267 
initContext(TestEnvironment env, Context ctx)268     public void initContext(TestEnvironment env, Context ctx) {
269         ctx.graphics = env.getGraphics();
270         int w = env.getWidth();
271         int h = env.getHeight();
272         ctx.size = env.getIntValue(sizeList);
273         ctx.outdim = getOutputSize(ctx.size, ctx.size);
274         ctx.pixscale = 1.0;
275         if (hasGraphics2D) {
276             Graphics2D g2d = (Graphics2D) ctx.graphics;
277             AlphaComposite ac = (AlphaComposite) env.getModifier(compRules);
278             if (env.isEnabled(doExtraAlpha)) {
279                 ac = AlphaComposite.getInstance(ac.getRule(), 0.125f);
280             }
281             g2d.setComposite(ac);
282             if (env.isEnabled(doXor)) {
283                 g2d.setXORMode(Color.white);
284             }
285             if (env.isEnabled(doClipping)) {
286                 Polygon p = new Polygon();
287                 p.addPoint(0, 0);
288                 p.addPoint(w, 0);
289                 p.addPoint(0, h);
290                 p.addPoint(w, h);
291                 p.addPoint(0, 0);
292                 g2d.clip(p);
293             }
294             Transform tx = (Transform) env.getModifier(transforms);
295             Dimension envdim = new Dimension(w, h);
296             tx.init(g2d, ctx, envdim);
297             w = envdim.width;
298             h = envdim.height;
299             g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
300                                  env.getModifier(renderHint));
301         }
302         switch (env.getIntValue(animList)) {
303         case 0:
304             ctx.animate = false;
305             ctx.maxX = 3;
306             ctx.maxY = 1;
307             ctx.orgX = (w - ctx.outdim.width) / 2;
308             ctx.orgY = (h - ctx.outdim.height) / 2;
309             break;
310         case 1:
311             ctx.animate = true;
312             ctx.maxX = Math.max(Math.min(32, w - ctx.outdim.width), 3);
313             ctx.maxY = 1;
314             ctx.orgX = (w - ctx.outdim.width - ctx.maxX) / 2;
315             ctx.orgY = (h - ctx.outdim.height) / 2;
316             break;
317         case 2:
318             ctx.animate = true;
319             ctx.maxX = (w - ctx.outdim.width) + 1;
320             ctx.maxY = (h - ctx.outdim.height) + 1;
321             ctx.maxX = adjustWidth(ctx.maxX, ctx.maxY);
322             ctx.maxX = Math.max(ctx.maxX, 3);
323             ctx.maxY = Math.max(ctx.maxY, 1);
324             // ctx.orgX = ctx.orgY = 0;
325             break;
326         }
327         ctx.initX = ctx.maxX / 2;
328         ctx.initY = ctx.maxY / 2;
329     }
330 
cleanupTest(TestEnvironment env, Object ctx)331     public void cleanupTest(TestEnvironment env, Object ctx) {
332         Graphics graphics = ((Context) ctx).graphics;
333         graphics.dispose();
334         ((Context) ctx).graphics = null;
335     }
336 
337     public abstract static class Transform {
getShortName()338         public abstract String getShortName();
getDescription()339         public abstract String getDescription();
init(Graphics2D g2d, Context ctx, Dimension dim)340         public abstract void init(Graphics2D g2d, Context ctx, Dimension dim);
341 
scaleForPoint(AffineTransform at, double xorig, double yorig, double x, double y, int w, int h)342         public static double scaleForPoint(AffineTransform at,
343                                            double xorig, double yorig,
344                                            double x, double y,
345                                            int w, int h)
346         {
347             Point2D.Double ptd = new Point2D.Double(x, y);
348             at.transform(ptd, ptd);
349             x = ptd.getX();
350             y = ptd.getY();
351             double scale = 1.0;
352             if (x < 0) {
353                 scale = Math.min(scale, xorig / (xorig - x));
354             } else if (x > w) {
355                 scale = Math.min(scale, (w - xorig) / (x - xorig));
356             }
357             if (y < 0) {
358                 scale = Math.min(scale, yorig / (yorig - y));
359             } else if (y > h) {
360                 scale = Math.min(scale, (h - yorig) / (y - yorig));
361             }
362             return scale;
363         }
364 
scaleForTransform(AffineTransform at, Dimension dim)365         public static Dimension scaleForTransform(AffineTransform at,
366                                                   Dimension dim)
367         {
368             int w = dim.width;
369             int h = dim.height;
370             Point2D.Double ptd = new Point2D.Double(0, 0);
371             at.transform(ptd, ptd);
372             double ox = ptd.getX();
373             double oy = ptd.getY();
374             if (ox < 0 || ox > w || oy < 0 || oy > h) {
375                 throw new InternalError("origin outside destination");
376             }
377             double scalex = scaleForPoint(at, ox, oy, w, h, w, h);
378             double scaley = scalex;
379             scalex = Math.min(scaleForPoint(at, ox, oy, w, 0, w, h), scalex);
380             scaley = Math.min(scaleForPoint(at, ox, oy, 0, h, w, h), scaley);
381             if (scalex < 0 || scaley < 0) {
382                 throw new InternalError("could not fit dims to transform");
383             }
384             return new Dimension((int) Math.floor(w * scalex),
385                                  (int) Math.floor(h * scaley));
386         }
387     }
388 
389     public static class Identity extends Transform {
390         public static final Identity instance = new Identity();
391 
Identity()392         private Identity() {}
393 
getShortName()394         public String getShortName() {
395             return "ident";
396         }
397 
getDescription()398         public String getDescription() {
399             return "Identity";
400         }
401 
init(Graphics2D g2d, Context ctx, Dimension dim)402         public void init(Graphics2D g2d, Context ctx, Dimension dim) {
403         }
404     }
405 
406     public static class FTranslate extends Transform {
407         public static final FTranslate instance = new FTranslate();
408 
FTranslate()409         private FTranslate() {}
410 
getShortName()411         public String getShortName() {
412             return "ftrans";
413         }
414 
getDescription()415         public String getDescription() {
416             return "FTranslate 1.5";
417         }
418 
init(Graphics2D g2d, Context ctx, Dimension dim)419         public void init(Graphics2D g2d, Context ctx, Dimension dim) {
420             int w = dim.width;
421             int h = dim.height;
422             AffineTransform at = new AffineTransform();
423             at.translate(1.5, 1.5);
424             g2d.transform(at);
425             dim.setSize(w-3, h-3);
426         }
427     }
428 
429     public static class Scale2x2 extends Transform {
430         public static final Scale2x2 instance = new Scale2x2();
431 
Scale2x2()432         private Scale2x2() {}
433 
getShortName()434         public String getShortName() {
435             return "scale2x2";
436         }
437 
getDescription()438         public String getDescription() {
439             return "Scale 2x by 2x";
440         }
441 
init(Graphics2D g2d, Context ctx, Dimension dim)442         public void init(Graphics2D g2d, Context ctx, Dimension dim) {
443             int w = dim.width;
444             int h = dim.height;
445             AffineTransform at = new AffineTransform();
446             at.scale(2.0, 2.0);
447             g2d.transform(at);
448             dim.setSize(w/2, h/2);
449             ctx.pixscale = 4;
450         }
451     }
452 
453     public static class Rotate15 extends Transform {
454         public static final Rotate15 instance = new Rotate15();
455 
Rotate15()456         private Rotate15() {}
457 
getShortName()458         public String getShortName() {
459             return "rot15";
460         }
461 
getDescription()462         public String getDescription() {
463             return "Rotate 15 degrees";
464         }
465 
init(Graphics2D g2d, Context ctx, Dimension dim)466         public void init(Graphics2D g2d, Context ctx, Dimension dim) {
467             int w = dim.width;
468             int h = dim.height;
469             double theta = Math.toRadians(15);
470             double cos = Math.cos(theta);
471             double sin = Math.sin(theta);
472             double xsize = sin * h + cos * w;
473             double ysize = sin * w + cos * h;
474             double scale = Math.min(w / xsize, h / ysize);
475             xsize *= scale;
476             ysize *= scale;
477             AffineTransform at = new AffineTransform();
478             at.translate((w - xsize) / 2.0, (h - ysize) / 2.0);
479             at.translate(sin * h * scale, 0.0);
480             at.rotate(theta);
481             g2d.transform(at);
482             dim.setSize(scaleForTransform(at, dim));
483         }
484     }
485 
486     public static class ShearX extends Transform {
487         public static final ShearX instance = new ShearX();
488 
ShearX()489         private ShearX() {}
490 
getShortName()491         public String getShortName() {
492             return "shearx";
493         }
494 
getDescription()495         public String getDescription() {
496             return "Shear X to the right";
497         }
498 
init(Graphics2D g2d, Context ctx, Dimension dim)499         public void init(Graphics2D g2d, Context ctx, Dimension dim) {
500             int w = dim.width;
501             int h = dim.height;
502             AffineTransform at = new AffineTransform();
503             at.translate(0.0, (h - (w*h)/(w + h*0.1)) / 2);
504             at.shear(0.1, 0.0);
505             g2d.transform(at);
506             dim.setSize(scaleForTransform(at, dim));
507         }
508     }
509 
510     public static class ShearY extends Transform {
511         public static final ShearY instance = new ShearY();
512 
ShearY()513         private ShearY() {}
514 
getShortName()515         public String getShortName() {
516             return "sheary";
517         }
518 
getDescription()519         public String getDescription() {
520             return "Shear Y down";
521         }
522 
init(Graphics2D g2d, Context ctx, Dimension dim)523         public void init(Graphics2D g2d, Context ctx, Dimension dim) {
524             int w = dim.width;
525             int h = dim.height;
526             AffineTransform at = new AffineTransform();
527             at.translate((w - (w*h)/(h + w*0.1)) / 2, 0.0);
528             at.shear(0.0, 0.1);
529             g2d.transform(at);
530             dim.setSize(scaleForTransform(at, dim));
531         }
532     }
533 }
534