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 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, 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 242 public GraphicsTests(Group parent, String nodeName, String description) { 243 super(parent, nodeName, description); 244 addDependency(Destinations.destroot); 245 addDependencies(groptroot, false); 246 } 247 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 256 public int pixelsTouched(Context ctx) { 257 return ctx.outdim.width * ctx.outdim.height; 258 } 259 260 public Context createContext() { 261 return new Context(); 262 } 263 264 public Dimension getOutputSize(int w, int h) { 265 return new Dimension(w, h); 266 } 267 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 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 { 338 public abstract String getShortName(); 339 public abstract String getDescription(); 340 public abstract void init(Graphics2D g2d, Context ctx, Dimension dim); 341 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 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 392 private Identity() {} 393 394 public String getShortName() { 395 return "ident"; 396 } 397 398 public String getDescription() { 399 return "Identity"; 400 } 401 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 409 private FTranslate() {} 410 411 public String getShortName() { 412 return "ftrans"; 413 } 414 415 public String getDescription() { 416 return "FTranslate 1.5"; 417 } 418 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 432 private Scale2x2() {} 433 434 public String getShortName() { 435 return "scale2x2"; 436 } 437 438 public String getDescription() { 439 return "Scale 2x by 2x"; 440 } 441 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 456 private Rotate15() {} 457 458 public String getShortName() { 459 return "rot15"; 460 } 461 462 public String getDescription() { 463 return "Rotate 15 degrees"; 464 } 465 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 489 private ShearX() {} 490 491 public String getShortName() { 492 return "shearx"; 493 } 494 495 public String getDescription() { 496 return "Shear X to the right"; 497 } 498 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 513 private ShearY() {} 514 515 public String getShortName() { 516 return "sheary"; 517 } 518 519 public String getDescription() { 520 return "Shear Y down"; 521 } 522 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 }