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 }