1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * @author Charlton Innovations, Inc. 28 */ 29 30 package sun.java2d.loops; 31 32 import java.awt.image.BufferedImage; 33 import java.awt.AlphaComposite; 34 import java.awt.Rectangle; 35 import sun.awt.image.BufImgSurfaceData; 36 import sun.java2d.SurfaceData; 37 import sun.java2d.pipe.Region; 38 import java.lang.reflect.Field; 39 import java.util.StringTokenizer; 40 import java.util.Iterator; 41 import java.util.HashMap; 42 import java.util.Map; 43 import java.io.PrintStream; 44 import java.io.OutputStream; 45 import java.io.FileOutputStream; 46 import java.io.FileNotFoundException; 47 import java.security.AccessController; 48 import java.security.PrivilegedAction; 49 import sun.security.action.GetPropertyAction; 50 51 /** 52 * defines interface for primitives which can be placed into 53 * the graphic component manager framework 54 */ 55 public abstract class GraphicsPrimitive { 56 57 protected static interface GeneralBinaryOp { 58 /** 59 * This method allows the setupGeneralBinaryOp method to set 60 * the converters into the General version of the Primitive. 61 */ 62 public void setPrimitives(Blit srcconverter, 63 Blit dstconverter, 64 GraphicsPrimitive genericop, 65 Blit resconverter); 66 67 /** 68 * These 4 methods are implemented automatically for any 69 * GraphicsPrimitive. They are used by setupGeneralBinaryOp 70 * to retrieve the information needed to find the right 71 * converter primitives. 72 */ 73 public SurfaceType getSourceType(); 74 public CompositeType getCompositeType(); 75 public SurfaceType getDestType(); 76 public String getSignature(); 77 public int getPrimTypeID(); 78 } 79 80 protected static interface GeneralUnaryOp { 81 /** 82 * This method allows the setupGeneralUnaryOp method to set 83 * the converters into the General version of the Primitive. 84 */ 85 public void setPrimitives(Blit dstconverter, 86 GraphicsPrimitive genericop, 87 Blit resconverter); 88 89 /** 90 * These 3 methods are implemented automatically for any 91 * GraphicsPrimitive. They are used by setupGeneralUnaryOp 92 * to retrieve the information needed to find the right 93 * converter primitives. 94 */ 95 public CompositeType getCompositeType(); 96 public SurfaceType getDestType(); 97 public String getSignature(); 98 public int getPrimTypeID(); 99 } 100 101 /** 102 * INSTANCE DATA MEMBERS DESCRIBING CHARACTERISTICS OF THIS PRIMITIVE 103 **/ 104 105 // Making these be instance data members (instead of virtual methods 106 // overridden by subclasses) is actually cheaper, since each class 107 // is a singleton. As instance data members with final accessors, 108 // accesses can be inlined. 109 private String methodSignature; 110 private int uniqueID; 111 private static int unusedPrimID = 1; 112 113 private SurfaceType sourceType; 114 private CompositeType compositeType; 115 private SurfaceType destType; 116 117 private long pNativePrim; // Native blit loop info 118 119 public synchronized static final int makePrimTypeID() { 120 if (unusedPrimID > 255) { 121 throw new InternalError("primitive id overflow"); 122 } 123 return unusedPrimID++; 124 } 125 126 public synchronized static final int makeUniqueID(int primTypeID, 127 SurfaceType src, 128 CompositeType cmp, 129 SurfaceType dst) 130 { 131 return (primTypeID << 24) | 132 (dst.getUniqueID() << 16) | 133 (cmp.getUniqueID() << 8) | 134 (src.getUniqueID()); 135 } 136 137 /** 138 * Create a new GraphicsPrimitive with all of the required 139 * descriptive information. 140 */ 141 protected GraphicsPrimitive(String methodSignature, 142 int primTypeID, 143 SurfaceType sourceType, 144 CompositeType compositeType, 145 SurfaceType destType) 146 { 147 this.methodSignature = methodSignature; 148 this.sourceType = sourceType; 149 this.compositeType = compositeType; 150 this.destType = destType; 151 152 if(sourceType == null || compositeType == null || destType == null) { 153 this.uniqueID = primTypeID << 24; 154 } else { 155 this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID, 156 sourceType, 157 compositeType, 158 destType); 159 } 160 } 161 162 /** 163 * Create a new GraphicsPrimitive for native invocation 164 * with all of the required descriptive information. 165 */ 166 protected GraphicsPrimitive(long pNativePrim, 167 String methodSignature, 168 int primTypeID, 169 SurfaceType sourceType, 170 CompositeType compositeType, 171 SurfaceType destType) 172 { 173 this.pNativePrim = pNativePrim; 174 this.methodSignature = methodSignature; 175 this.sourceType = sourceType; 176 this.compositeType = compositeType; 177 this.destType = destType; 178 179 if(sourceType == null || compositeType == null || destType == null) { 180 this.uniqueID = primTypeID << 24; 181 } else { 182 this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID, 183 sourceType, 184 compositeType, 185 destType); 186 } 187 } 188 189 /** 190 * METHODS TO DESCRIBE THE SURFACES PRIMITIVES 191 * CAN OPERATE ON AND THE FUNCTIONALITY THEY IMPLEMENT 192 **/ 193 194 /** 195 * Gets instance ID of this graphics primitive. 196 * 197 * Instance ID is comprised of four distinct ids (ORed together) 198 * that uniquely identify each instance of a GraphicsPrimitive 199 * object. The four ids making up instance ID are: 200 * 1. primitive id - identifier shared by all primitives of the 201 * same type (eg. all Blits have the same primitive id) 202 * 2. sourcetype id - identifies source surface type 203 * 3. desttype id - identifies destination surface type 204 * 4. compositetype id - identifies composite used 205 * 206 * @return instance ID 207 */ 208 public final int getUniqueID() { 209 return uniqueID; 210 } 211 212 /** 213 */ 214 public final String getSignature() { 215 return methodSignature; 216 } 217 218 /** 219 * Gets unique id for this GraphicsPrimitive type. 220 * 221 * This id is used to identify the TYPE of primitive (Blit vs. BlitBg) 222 * as opposed to INSTANCE of primitive. 223 * 224 * @return primitive ID 225 */ 226 public final int getPrimTypeID() { 227 return uniqueID >>> 24; 228 } 229 230 /** 231 */ 232 public final long getNativePrim() { 233 return pNativePrim; 234 } 235 236 /** 237 */ 238 public final SurfaceType getSourceType() { 239 return sourceType; 240 } 241 242 /** 243 */ 244 public final CompositeType getCompositeType() { 245 return compositeType; 246 } 247 248 /** 249 */ 250 public final SurfaceType getDestType() { 251 return destType; 252 } 253 254 /** 255 * Return true if this primitive can be used for the given signature 256 * surfaces, and composite. 257 * 258 * @param signature The signature of the given operation. Must be 259 * == (not just .equals) the signature string given by the 260 * abstract class that declares the operation. 261 * @param srctype The surface type for the source of the operation 262 * @param comptype The composite type for the operation 263 * @param dsttype The surface type for the destination of the operation 264 */ 265 public final boolean satisfies(String signature, 266 SurfaceType srctype, 267 CompositeType comptype, 268 SurfaceType dsttype) 269 { 270 if (signature != methodSignature) { 271 return false; 272 } 273 while (true) { 274 if (srctype == null) { 275 return false; 276 } 277 if (srctype.equals(sourceType)) { 278 break; 279 } 280 srctype = srctype.getSuperType(); 281 } 282 while (true) { 283 if (comptype == null) { 284 return false; 285 } 286 if (comptype.equals(compositeType)) { 287 break; 288 } 289 comptype = comptype.getSuperType(); 290 } 291 while (true) { 292 if (dsttype == null) { 293 return false; 294 } 295 if (dsttype.equals(destType)) { 296 break; 297 } 298 dsttype = dsttype.getSuperType(); 299 } 300 return true; 301 } 302 303 // 304 // A version of satisfies used for regression testing 305 // 306 final boolean satisfiesSameAs(GraphicsPrimitive other) { 307 return (methodSignature == other.methodSignature && 308 sourceType.equals(other.sourceType) && 309 compositeType.equals(other.compositeType) && 310 destType.equals(other.destType)); 311 } 312 313 public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype, 314 CompositeType comptype, 315 SurfaceType dsttype); 316 317 public abstract GraphicsPrimitive traceWrap(); 318 319 static HashMap<Object, int[]> traceMap; 320 321 public static int traceflags; 322 public static String tracefile; 323 public static PrintStream traceout; 324 325 public static final int TRACELOG = 1; 326 public static final int TRACETIMESTAMP = 2; 327 public static final int TRACECOUNTS = 4; 328 329 static { 330 GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace"); 331 String trace = AccessController.doPrivileged(gpa); 332 if (trace != null) { 333 boolean verbose = false; 334 int traceflags = 0; 335 StringTokenizer st = new StringTokenizer(trace, ","); 336 while (st.hasMoreTokens()) { 337 String tok = st.nextToken(); 338 if (tok.equalsIgnoreCase("count")) { 339 traceflags |= GraphicsPrimitive.TRACECOUNTS; 340 } else if (tok.equalsIgnoreCase("log")) { 341 traceflags |= GraphicsPrimitive.TRACELOG; 342 } else if (tok.equalsIgnoreCase("timestamp")) { 343 traceflags |= GraphicsPrimitive.TRACETIMESTAMP; 344 } else if (tok.equalsIgnoreCase("verbose")) { 345 verbose = true; 346 } else if (tok.regionMatches(true, 0, "out:", 0, 4)) { 347 tracefile = tok.substring(4); 348 } else { 349 if (!tok.equalsIgnoreCase("help")) { 350 System.err.println("unrecognized token: "+tok); 351 } 352 System.err.println("usage: -Dsun.java2d.trace="+ 353 "[log[,timestamp]],[count],"+ 354 "[out:<filename>],[help],[verbose]"); 355 } 356 } 357 if (verbose) { 358 System.err.print("GraphicsPrimitive logging "); 359 if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) { 360 System.err.println("enabled"); 361 System.err.print("GraphicsPrimitive timetamps "); 362 if ((traceflags & GraphicsPrimitive.TRACETIMESTAMP) != 0) { 363 System.err.println("enabled"); 364 } else { 365 System.err.println("disabled"); 366 } 367 } else { 368 System.err.println("[and timestamps] disabled"); 369 } 370 System.err.print("GraphicsPrimitive invocation counts "); 371 if ((traceflags & GraphicsPrimitive.TRACECOUNTS) != 0) { 372 System.err.println("enabled"); 373 } else { 374 System.err.println("disabled"); 375 } 376 System.err.print("GraphicsPrimitive trace output to "); 377 if (tracefile == null) { 378 System.err.println("System.err"); 379 } else { 380 System.err.println("file '"+tracefile+"'"); 381 } 382 } 383 GraphicsPrimitive.traceflags = traceflags; 384 } 385 } 386 387 public static boolean tracingEnabled() { 388 return (traceflags != 0); 389 } 390 391 private static PrintStream getTraceOutputFile() { 392 if (traceout == null) { 393 if (tracefile != null) { 394 FileOutputStream o = AccessController.doPrivileged( 395 new PrivilegedAction<FileOutputStream>() { 396 public FileOutputStream run() { 397 try { 398 return new FileOutputStream(tracefile); 399 } catch (FileNotFoundException e) { 400 return null; 401 } 402 } 403 }); 404 if (o != null) { 405 traceout = new PrintStream(o); 406 } else { 407 traceout = System.err; 408 } 409 } else { 410 traceout = System.err; 411 } 412 } 413 return traceout; 414 } 415 416 public static class TraceReporter extends Thread { 417 public static void setShutdownHook() { 418 AccessController.doPrivileged(new PrivilegedAction<Void>() { 419 public Void run() { 420 TraceReporter t = new TraceReporter(); 421 t.setContextClassLoader(null); 422 Runtime.getRuntime().addShutdownHook(t); 423 return null; 424 } 425 }); 426 } 427 428 public void run() { 429 PrintStream ps = getTraceOutputFile(); 430 Iterator<Map.Entry<Object, int[]>> iterator = 431 traceMap.entrySet().iterator(); 432 long total = 0; 433 int numprims = 0; 434 while (iterator.hasNext()) { 435 Map.Entry<Object, int[]> me = iterator.next(); 436 Object prim = me.getKey(); 437 int[] count = me.getValue(); 438 if (count[0] == 1) { 439 ps.print("1 call to "); 440 } else { 441 ps.print(count[0]+" calls to "); 442 } 443 ps.println(prim); 444 numprims++; 445 total += count[0]; 446 } 447 if (numprims == 0) { 448 ps.println("No graphics primitives executed"); 449 } else if (numprims > 1) { 450 ps.println(total+" total calls to "+ 451 numprims+" different primitives"); 452 } 453 } 454 } 455 456 public synchronized static void tracePrimitive(Object prim) { 457 if ((traceflags & TRACECOUNTS) != 0) { 458 if (traceMap == null) { 459 traceMap = new HashMap<>(); 460 TraceReporter.setShutdownHook(); 461 } 462 int[] o = traceMap.get(prim); 463 if (o == null) { 464 o = new int[1]; 465 traceMap.put(prim, o); 466 } 467 o[0]++; 468 } 469 if ((traceflags & TRACELOG) != 0) { 470 PrintStream ps = getTraceOutputFile(); 471 if ((traceflags & TRACETIMESTAMP) != 0) { 472 ps.print(System.currentTimeMillis()+": "); 473 } 474 ps.println(prim); 475 } 476 } 477 478 protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) { 479 int primID = gbo.getPrimTypeID(); 480 String methodSignature = gbo.getSignature(); 481 SurfaceType srctype = gbo.getSourceType(); 482 CompositeType comptype = gbo.getCompositeType(); 483 SurfaceType dsttype = gbo.getDestType(); 484 Blit convertsrc, convertdst, convertres; 485 GraphicsPrimitive performop; 486 487 convertsrc = createConverter(srctype, SurfaceType.IntArgb); 488 performop = GraphicsPrimitiveMgr.locatePrim(primID, 489 SurfaceType.IntArgb, 490 comptype, dsttype); 491 if (performop != null) { 492 convertdst = null; 493 convertres = null; 494 } else { 495 performop = getGeneralOp(primID, comptype); 496 if (performop == null) { 497 throw new InternalError("Cannot construct general op for "+ 498 methodSignature+" "+comptype); 499 } 500 convertdst = createConverter(dsttype, SurfaceType.IntArgb); 501 convertres = createConverter(SurfaceType.IntArgb, dsttype); 502 } 503 504 gbo.setPrimitives(convertsrc, convertdst, performop, convertres); 505 } 506 507 protected void setupGeneralUnaryOp(GeneralUnaryOp guo) { 508 int primID = guo.getPrimTypeID(); 509 String methodSignature = guo.getSignature(); 510 CompositeType comptype = guo.getCompositeType(); 511 SurfaceType dsttype = guo.getDestType(); 512 513 Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb); 514 GraphicsPrimitive performop = getGeneralOp(primID, comptype); 515 Blit convertres = createConverter(SurfaceType.IntArgb, dsttype); 516 if (convertdst == null || performop == null || convertres == null) { 517 throw new InternalError("Cannot construct binary op for "+ 518 comptype+" "+dsttype); 519 } 520 521 guo.setPrimitives(convertdst, performop, convertres); 522 } 523 524 protected static Blit createConverter(SurfaceType srctype, 525 SurfaceType dsttype) 526 { 527 if (srctype.equals(dsttype)) { 528 return null; 529 } 530 Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype); 531 if (cv == null) { 532 throw new InternalError("Cannot construct converter for "+ 533 srctype+"=>"+dsttype); 534 } 535 return cv; 536 } 537 538 protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, 539 int srcX, int srcY, int w, int h, 540 SurfaceData dstData) 541 { 542 return convertFrom(ob, srcData, 543 srcX, srcY, w, h, dstData, 544 BufferedImage.TYPE_INT_ARGB); 545 } 546 547 protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, 548 int srcX, int srcY, int w, int h, 549 SurfaceData dstData, int type) 550 { 551 if (dstData != null) { 552 Rectangle r = dstData.getBounds(); 553 if (w > r.width || h > r.height) { 554 dstData = null; 555 } 556 } 557 if (dstData == null) { 558 BufferedImage dstBI = new BufferedImage(w, h, type); 559 dstData = BufImgSurfaceData.createData(dstBI); 560 } 561 ob.Blit(srcData, dstData, AlphaComposite.Src, null, 562 srcX, srcY, 0, 0, w, h); 563 return dstData; 564 } 565 566 protected static void convertTo(Blit ob, 567 SurfaceData srcImg, SurfaceData dstImg, 568 Region clip, 569 int dstX, int dstY, int w, int h) 570 { 571 if (ob != null) { 572 ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip, 573 0, 0, dstX, dstY, w, h); 574 } 575 } 576 577 protected static GraphicsPrimitive getGeneralOp(int primID, 578 CompositeType comptype) 579 { 580 return GraphicsPrimitiveMgr.locatePrim(primID, 581 SurfaceType.IntArgb, 582 comptype, 583 SurfaceType.IntArgb); 584 } 585 586 public static String simplename(Field[] fields, Object o) { 587 for (int i = 0; i < fields.length; i++) { 588 Field f = fields[i]; 589 try { 590 if (o == f.get(null)) { 591 return f.getName(); 592 } 593 } catch (Exception e) { 594 } 595 } 596 return "\""+o.toString()+"\""; 597 } 598 599 public static String simplename(SurfaceType st) { 600 return simplename(SurfaceType.class.getDeclaredFields(), st); 601 } 602 603 public static String simplename(CompositeType ct) { 604 return simplename(CompositeType.class.getDeclaredFields(), ct); 605 } 606 607 private String cachedname; 608 609 public String toString() { 610 if (cachedname == null) { 611 String sig = methodSignature; 612 int index = sig.indexOf('('); 613 if (index >= 0) { 614 sig = sig.substring(0, index); 615 } 616 cachedname = (getClass().getName()+"::"+ 617 sig+"("+ 618 simplename(sourceType)+", "+ 619 simplename(compositeType)+", "+ 620 simplename(destType)+")"); 621 } 622 return cachedname; 623 } 624 }