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