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 }