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