blob: adc3fda4862be43488a3a6549213e5448e1d64ea [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26/*
27 * @author Charlton Innovations, Inc.
28 */
29
30package sun.java2d.loops;
31
32import java.awt.image.BufferedImage;
33import java.awt.AlphaComposite;
34import java.awt.Rectangle;
35import sun.awt.image.BufImgSurfaceData;
36import sun.java2d.SurfaceData;
37import sun.java2d.pipe.Region;
38import java.lang.reflect.Field;
39import java.util.StringTokenizer;
40import java.util.Iterator;
41import java.util.HashMap;
42import java.util.Map;
43import java.io.PrintStream;
44import java.io.OutputStream;
45import java.io.FileOutputStream;
46import java.io.FileNotFoundException;
47import java.security.AccessController;
48import java.security.PrivilegedAction;
49import sun.security.action.GetPropertyAction;
50
51/**
52 * defines interface for primitives which can be placed into
53 * the graphic component manager framework
54 */
55public 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 = (String)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 Object o =
395 AccessController.doPrivileged(new PrivilegedAction() {
396 public Object 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((OutputStream) 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() {
419 public Object run() {
420 Runtime.getRuntime().addShutdownHook(new TraceReporter());
421 return null;
422 }
423 });
424 }
425
426 public void run() {
427 PrintStream ps = getTraceOutputFile();
428 Iterator iterator = traceMap.entrySet().iterator();
429 long total = 0;
430 int numprims = 0;
431 while (iterator.hasNext()) {
432 Map.Entry me = (Map.Entry) iterator.next();
433 Object prim = me.getKey();
434 int[] count = (int[]) me.getValue();
435 if (count[0] == 1) {
436 ps.print("1 call to ");
437 } else {
438 ps.print(count[0]+" calls to ");
439 }
440 ps.println(prim);
441 numprims++;
442 total += count[0];
443 }
444 if (numprims == 0) {
445 ps.println("No graphics primitives executed");
446 } else if (numprims > 1) {
447 ps.println(total+" total calls to "+
448 numprims+" different primitives");
449 }
450 }
451 }
452
453 public synchronized static void tracePrimitive(Object prim) {
454 if ((traceflags & TRACECOUNTS) != 0) {
455 if (traceMap == null) {
456 traceMap = new HashMap();
457 TraceReporter.setShutdownHook();
458 }
459 Object o = traceMap.get(prim);
460 if (o == null) {
461 o = new int[1];
462 traceMap.put(prim, o);
463 }
464 ((int[]) o)[0]++;
465 }
466 if ((traceflags & TRACELOG) != 0) {
467 PrintStream ps = getTraceOutputFile();
468 if ((traceflags & TRACETIMESTAMP) != 0) {
469 ps.print(System.currentTimeMillis()+": ");
470 }
471 ps.println(prim);
472 }
473 }
474
475 protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) {
476 int primID = gbo.getPrimTypeID();
477 String methodSignature = gbo.getSignature();
478 SurfaceType srctype = gbo.getSourceType();
479 CompositeType comptype = gbo.getCompositeType();
480 SurfaceType dsttype = gbo.getDestType();
481 Blit convertsrc, convertdst, convertres;
482 GraphicsPrimitive performop;
483
484 convertsrc = createConverter(srctype, SurfaceType.IntArgb);
485 performop = GraphicsPrimitiveMgr.locatePrim(primID,
486 SurfaceType.IntArgb,
487 comptype, dsttype);
488 if (performop != null) {
489 convertdst = null;
490 convertres = null;
491 } else {
492 performop = getGeneralOp(primID, comptype);
493 if (performop == null) {
494 throw new InternalError("Cannot construct general op for "+
495 methodSignature+" "+comptype);
496 }
497 convertdst = createConverter(dsttype, SurfaceType.IntArgb);
498 convertres = createConverter(SurfaceType.IntArgb, dsttype);
499 }
500
501 gbo.setPrimitives(convertsrc, convertdst, performop, convertres);
502 }
503
504 protected void setupGeneralUnaryOp(GeneralUnaryOp guo) {
505 int primID = guo.getPrimTypeID();
506 String methodSignature = guo.getSignature();
507 CompositeType comptype = guo.getCompositeType();
508 SurfaceType dsttype = guo.getDestType();
509
510 Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb);
511 GraphicsPrimitive performop = getGeneralOp(primID, comptype);
512 Blit convertres = createConverter(SurfaceType.IntArgb, dsttype);
513 if (convertdst == null || performop == null || convertres == null) {
514 throw new InternalError("Cannot construct binary op for "+
515 comptype+" "+dsttype);
516 }
517
518 guo.setPrimitives(convertdst, performop, convertres);
519 }
520
521 protected static Blit createConverter(SurfaceType srctype,
522 SurfaceType dsttype)
523 {
524 if (srctype.equals(dsttype)) {
525 return null;
526 }
527 Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype);
528 if (cv == null) {
529 throw new InternalError("Cannot construct converter for "+
530 srctype+"=>"+dsttype);
531 }
532 return cv;
533 }
534
535 protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,
536 int srcX, int srcY, int w, int h,
537 SurfaceData dstData)
538 {
539 return convertFrom(ob, srcData,
540 srcX, srcY, w, h, dstData,
541 BufferedImage.TYPE_INT_ARGB);
542 }
543
544 protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,
545 int srcX, int srcY, int w, int h,
546 SurfaceData dstData, int type)
547 {
548 if (dstData != null) {
549 Rectangle r = dstData.getBounds();
550 if (w > r.width || h > r.height) {
551 dstData = null;
552 }
553 }
554 if (dstData == null) {
555 BufferedImage dstBI = new BufferedImage(w, h, type);
556 dstData = BufImgSurfaceData.createData(dstBI);
557 }
558 ob.Blit(srcData, dstData, AlphaComposite.Src, null,
559 srcX, srcY, 0, 0, w, h);
560 return dstData;
561 }
562
563 protected static void convertTo(Blit ob,
564 SurfaceData srcImg, SurfaceData dstImg,
565 Region clip,
566 int dstX, int dstY, int w, int h)
567 {
568 if (ob != null) {
569 ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip,
570 0, 0, dstX, dstY, w, h);
571 }
572 }
573
574 protected static GraphicsPrimitive getGeneralOp(int primID,
575 CompositeType comptype)
576 {
577 return GraphicsPrimitiveMgr.locatePrim(primID,
578 SurfaceType.IntArgb,
579 comptype,
580 SurfaceType.IntArgb);
581 }
582
583 public static String simplename(Field[] fields, Object o) {
584 for (int i = 0; i < fields.length; i++) {
585 Field f = fields[i];
586 try {
587 if (o == f.get(null)) {
588 return f.getName();
589 }
590 } catch (Exception e) {
591 }
592 }
593 return "\""+o.toString()+"\"";
594 }
595
596 public static String simplename(SurfaceType st) {
597 return simplename(SurfaceType.class.getDeclaredFields(), st);
598 }
599
600 public static String simplename(CompositeType ct) {
601 return simplename(CompositeType.class.getDeclaredFields(), ct);
602 }
603
604 private String cachedname;
605
606 public String toString() {
607 if (cachedname == null) {
608 String sig = methodSignature;
609 int index = sig.indexOf('(');
610 if (index >= 0) {
611 sig = sig.substring(0, index);
612 }
613 cachedname = (getClass().getName()+"::"+
614 sig+"("+
615 simplename(sourceType)+", "+
616 simplename(compositeType)+", "+
617 simplename(destType)+")");
618 }
619 return cachedname;
620 }
621}