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 */ setPrimitives(Blit srcconverter, Blit dstconverter, GraphicsPrimitive genericop, Blit resconverter)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 */ getSourceType()73 public SurfaceType getSourceType(); getCompositeType()74 public CompositeType getCompositeType(); getDestType()75 public SurfaceType getDestType(); getSignature()76 public String getSignature(); getPrimTypeID()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 */ setPrimitives(Blit dstconverter, GraphicsPrimitive genericop, Blit resconverter)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 */ getCompositeType()95 public CompositeType getCompositeType(); getDestType()96 public SurfaceType getDestType(); getSignature()97 public String getSignature(); getPrimTypeID()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 makePrimTypeID()119 public synchronized static final int makePrimTypeID() { 120 if (unusedPrimID > 255) { 121 throw new InternalError("primitive id overflow"); 122 } 123 return unusedPrimID++; 124 } 125 makeUniqueID(int primTypeID, SurfaceType src, CompositeType cmp, SurfaceType dst)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 */ GraphicsPrimitive(String methodSignature, int primTypeID, SurfaceType sourceType, CompositeType compositeType, SurfaceType destType)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 */ GraphicsPrimitive(long pNativePrim, String methodSignature, int primTypeID, SurfaceType sourceType, CompositeType compositeType, SurfaceType destType)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 */ getUniqueID()208 public final int getUniqueID() { 209 return uniqueID; 210 } 211 212 /** 213 */ getSignature()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 */ getPrimTypeID()226 public final int getPrimTypeID() { 227 return uniqueID >>> 24; 228 } 229 230 /** 231 */ getNativePrim()232 public final long getNativePrim() { 233 return pNativePrim; 234 } 235 236 /** 237 */ getSourceType()238 public final SurfaceType getSourceType() { 239 return sourceType; 240 } 241 242 /** 243 */ getCompositeType()244 public final CompositeType getCompositeType() { 245 return compositeType; 246 } 247 248 /** 249 */ getDestType()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 */ satisfies(String signature, SurfaceType srctype, CompositeType comptype, SurfaceType dsttype)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 // satisfiesSameAs(GraphicsPrimitive other)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 makePrimitive(SurfaceType srctype, CompositeType comptype, SurfaceType dsttype)313 public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype, 314 CompositeType comptype, 315 SurfaceType dsttype); 316 traceWrap()317 public abstract GraphicsPrimitive traceWrap(); 318 319 static HashMap 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 tracingEnabled()387 public static boolean tracingEnabled() { 388 return (traceflags != 0); 389 } 390 getTraceOutputFile()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 { setShutdownHook()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 run()428 public void run() { 429 PrintStream ps = getTraceOutputFile(); 430 Iterator iterator = traceMap.entrySet().iterator(); 431 long total = 0; 432 int numprims = 0; 433 while (iterator.hasNext()) { 434 Map.Entry me = (Map.Entry) iterator.next(); 435 Object prim = me.getKey(); 436 int[] count = (int[]) me.getValue(); 437 if (count[0] == 1) { 438 ps.print("1 call to "); 439 } else { 440 ps.print(count[0]+" calls to "); 441 } 442 ps.println(prim); 443 numprims++; 444 total += count[0]; 445 } 446 if (numprims == 0) { 447 ps.println("No graphics primitives executed"); 448 } else if (numprims > 1) { 449 ps.println(total+" total calls to "+ 450 numprims+" different primitives"); 451 } 452 } 453 } 454 tracePrimitive(Object prim)455 public synchronized static void tracePrimitive(Object prim) { 456 if ((traceflags & TRACECOUNTS) != 0) { 457 if (traceMap == null) { 458 traceMap = new HashMap(); 459 TraceReporter.setShutdownHook(); 460 } 461 Object o = traceMap.get(prim); 462 if (o == null) { 463 o = new int[1]; 464 traceMap.put(prim, o); 465 } 466 ((int[]) o)[0]++; 467 } 468 if ((traceflags & TRACELOG) != 0) { 469 PrintStream ps = getTraceOutputFile(); 470 if ((traceflags & TRACETIMESTAMP) != 0) { 471 ps.print(System.currentTimeMillis()+": "); 472 } 473 ps.println(prim); 474 } 475 } 476 setupGeneralBinaryOp(GeneralBinaryOp gbo)477 protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) { 478 int primID = gbo.getPrimTypeID(); 479 String methodSignature = gbo.getSignature(); 480 SurfaceType srctype = gbo.getSourceType(); 481 CompositeType comptype = gbo.getCompositeType(); 482 SurfaceType dsttype = gbo.getDestType(); 483 Blit convertsrc, convertdst, convertres; 484 GraphicsPrimitive performop; 485 486 convertsrc = createConverter(srctype, SurfaceType.IntArgb); 487 performop = GraphicsPrimitiveMgr.locatePrim(primID, 488 SurfaceType.IntArgb, 489 comptype, dsttype); 490 if (performop != null) { 491 convertdst = null; 492 convertres = null; 493 } else { 494 performop = getGeneralOp(primID, comptype); 495 if (performop == null) { 496 throw new InternalError("Cannot construct general op for "+ 497 methodSignature+" "+comptype); 498 } 499 convertdst = createConverter(dsttype, SurfaceType.IntArgb); 500 convertres = createConverter(SurfaceType.IntArgb, dsttype); 501 } 502 503 gbo.setPrimitives(convertsrc, convertdst, performop, convertres); 504 } 505 setupGeneralUnaryOp(GeneralUnaryOp guo)506 protected void setupGeneralUnaryOp(GeneralUnaryOp guo) { 507 int primID = guo.getPrimTypeID(); 508 String methodSignature = guo.getSignature(); 509 CompositeType comptype = guo.getCompositeType(); 510 SurfaceType dsttype = guo.getDestType(); 511 512 Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb); 513 GraphicsPrimitive performop = getGeneralOp(primID, comptype); 514 Blit convertres = createConverter(SurfaceType.IntArgb, dsttype); 515 if (convertdst == null || performop == null || convertres == null) { 516 throw new InternalError("Cannot construct binary op for "+ 517 comptype+" "+dsttype); 518 } 519 520 guo.setPrimitives(convertdst, performop, convertres); 521 } 522 createConverter(SurfaceType srctype, SurfaceType dsttype)523 protected static Blit createConverter(SurfaceType srctype, 524 SurfaceType dsttype) 525 { 526 if (srctype.equals(dsttype)) { 527 return null; 528 } 529 Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype); 530 if (cv == null) { 531 throw new InternalError("Cannot construct converter for "+ 532 srctype+"=>"+dsttype); 533 } 534 return cv; 535 } 536 convertFrom(Blit ob, SurfaceData srcData, int srcX, int srcY, int w, int h, SurfaceData dstData)537 protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, 538 int srcX, int srcY, int w, int h, 539 SurfaceData dstData) 540 { 541 return convertFrom(ob, srcData, 542 srcX, srcY, w, h, dstData, 543 BufferedImage.TYPE_INT_ARGB); 544 } 545 convertFrom(Blit ob, SurfaceData srcData, int srcX, int srcY, int w, int h, SurfaceData dstData, int type)546 protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, 547 int srcX, int srcY, int w, int h, 548 SurfaceData dstData, int type) 549 { 550 if (dstData != null) { 551 Rectangle r = dstData.getBounds(); 552 if (w > r.width || h > r.height) { 553 dstData = null; 554 } 555 } 556 if (dstData == null) { 557 BufferedImage dstBI = new BufferedImage(w, h, type); 558 dstData = BufImgSurfaceData.createData(dstBI); 559 } 560 ob.Blit(srcData, dstData, AlphaComposite.Src, null, 561 srcX, srcY, 0, 0, w, h); 562 return dstData; 563 } 564 convertTo(Blit ob, SurfaceData srcImg, SurfaceData dstImg, Region clip, int dstX, int dstY, int w, int h)565 protected static void convertTo(Blit ob, 566 SurfaceData srcImg, SurfaceData dstImg, 567 Region clip, 568 int dstX, int dstY, int w, int h) 569 { 570 if (ob != null) { 571 ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip, 572 0, 0, dstX, dstY, w, h); 573 } 574 } 575 getGeneralOp(int primID, CompositeType comptype)576 protected static GraphicsPrimitive getGeneralOp(int primID, 577 CompositeType comptype) 578 { 579 return GraphicsPrimitiveMgr.locatePrim(primID, 580 SurfaceType.IntArgb, 581 comptype, 582 SurfaceType.IntArgb); 583 } 584 simplename(Field[] fields, Object o)585 public static String simplename(Field[] fields, Object o) { 586 for (int i = 0; i < fields.length; i++) { 587 Field f = fields[i]; 588 try { 589 if (o == f.get(null)) { 590 return f.getName(); 591 } 592 } catch (Exception e) { 593 } 594 } 595 return "\""+o.toString()+"\""; 596 } 597 simplename(SurfaceType st)598 public static String simplename(SurfaceType st) { 599 return simplename(SurfaceType.class.getDeclaredFields(), st); 600 } 601 simplename(CompositeType ct)602 public static String simplename(CompositeType ct) { 603 return simplename(CompositeType.class.getDeclaredFields(), ct); 604 } 605 606 private String cachedname; 607 toString()608 public String toString() { 609 if (cachedname == null) { 610 String sig = methodSignature; 611 int index = sig.indexOf('('); 612 if (index >= 0) { 613 sig = sig.substring(0, index); 614 } 615 cachedname = (getClass().getName()+"::"+ 616 sig+"("+ 617 simplename(sourceType)+", "+ 618 simplename(compositeType)+", "+ 619 simplename(destType)+")"); 620 } 621 return cachedname; 622 } 623 } 624