View Javadoc
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 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 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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
598     public static String simplename(SurfaceType st) {
599         return simplename(SurfaceType.class.getDeclaredFields(), st);
600     }
601 
602     public static String simplename(CompositeType ct) {
603         return simplename(CompositeType.class.getDeclaredFields(), ct);
604     }
605 
606     private String cachedname;
607 
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 }