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