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 */ setPrimitives(Blit srcconverter, Blit dstconverter, GraphicsPrimitive genericop, Blit resconverter)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 */ getSourceType()75 public SurfaceType getSourceType(); getCompositeType()76 public CompositeType getCompositeType(); getDestType()77 public SurfaceType getDestType(); getSignature()78 public String getSignature(); getPrimTypeID()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 */ setPrimitives(Blit dstconverter, GraphicsPrimitive genericop, Blit resconverter)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 */ getCompositeType()97 public CompositeType getCompositeType(); getDestType()98 public SurfaceType getDestType(); getSignature()99 public String getSignature(); getPrimTypeID()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 makePrimTypeID()121 public static final synchronized int makePrimTypeID() { 122 if (unusedPrimID > 255) { 123 throw new InternalError("primitive id overflow"); 124 } 125 return unusedPrimID++; 126 } 127 makeUniqueID(int primTypeID, SurfaceType src, CompositeType cmp, SurfaceType dst)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 */ GraphicsPrimitive(String methodSignature, int primTypeID, SurfaceType sourceType, CompositeType compositeType, SurfaceType destType)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 */ GraphicsPrimitive(long pNativePrim, String methodSignature, int primTypeID, SurfaceType sourceType, CompositeType compositeType, SurfaceType destType)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 */ getUniqueID()210 public final int getUniqueID() { 211 return uniqueID; 212 } 213 214 /** 215 */ getSignature()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 */ getPrimTypeID()228 public final int getPrimTypeID() { 229 return uniqueID >>> 24; 230 } 231 232 /** 233 */ getNativePrim()234 public final long getNativePrim() { 235 return pNativePrim; 236 } 237 238 /** 239 */ getSourceType()240 public final SurfaceType getSourceType() { 241 return sourceType; 242 } 243 244 /** 245 */ getCompositeType()246 public final CompositeType getCompositeType() { 247 return compositeType; 248 } 249 250 /** 251 */ getDestType()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 */ satisfies(String signature, SurfaceType srctype, CompositeType comptype, SurfaceType dsttype)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 // satisfiesSameAs(GraphicsPrimitive other)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 makePrimitive(SurfaceType srctype, CompositeType comptype, SurfaceType dsttype)315 public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype, 316 CompositeType comptype, 317 SurfaceType dsttype); 318 traceWrap()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 tracingEnabled()389 public static boolean tracingEnabled() { 390 return (traceflags != 0); 391 } 392 getTraceOutputFile()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 { setShutdownHook()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 run()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 tracePrimitive(Object prim)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 setupGeneralBinaryOp(GeneralBinaryOp gbo)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 setupGeneralUnaryOp(GeneralUnaryOp guo)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 createConverter(SurfaceType srctype, SurfaceType dsttype)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 convertFrom(Blit ob, SurfaceData srcData, int srcX, int srcY, int w, int h, SurfaceData dstData)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 convertFrom(Blit ob, SurfaceData srcData, int srcX, int srcY, int w, int h, SurfaceData dstData, int type)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 convertTo(Blit ob, SurfaceData srcImg, SurfaceData dstImg, Region clip, int dstX, int dstY, int w, int h)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 getGeneralOp(int primID, CompositeType comptype)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 simplename(Field[] fields, Object o)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 simplename(SurfaceType st)602 public static String simplename(SurfaceType st) { 603 return simplename(SurfaceType.class.getDeclaredFields(), st); 604 } 605 simplename(CompositeType ct)606 public static String simplename(CompositeType ct) { 607 return simplename(CompositeType.class.getDeclaredFields(), ct); 608 } 609 610 private String cachedname; 611 toString()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 } 628