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