blob: 38bbaeb5178be31c0115df695d5cb3d64f901746 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
Sergey Bylokhov33c5b922015-06-29 01:27:08 +03002 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
J. Duke319a3b92007-12-01 00:00:00 +00003 * 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
Kelly O'Hairfe008ae2010-05-25 15:58:33 -07007 * published by the Free Software Foundation. Oracle designates this
J. Duke319a3b92007-12-01 00:00:00 +00008 * particular file as subject to the "Classpath" exception as provided
Kelly O'Hairfe008ae2010-05-25 15:58:33 -07009 * by Oracle in the LICENSE file that accompanied this code.
J. Duke319a3b92007-12-01 00:00:00 +000010 *
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 *
Kelly O'Hairfe008ae2010-05-25 15:58:33 -070021 * 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.
J. Duke319a3b92007-12-01 00:00:00 +000024 */
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;
Sergey Bylokhov78119062015-04-03 17:17:36 +030036import sun.awt.util.ThreadGroupUtils;
J. Duke319a3b92007-12-01 00:00:00 +000037import sun.java2d.SurfaceData;
38import sun.java2d.pipe.Region;
39import java.lang.reflect.Field;
40import java.util.StringTokenizer;
41import java.util.Iterator;
42import java.util.HashMap;
43import java.util.Map;
44import java.io.PrintStream;
45import java.io.OutputStream;
46import java.io.FileOutputStream;
47import java.io.FileNotFoundException;
48import java.security.AccessController;
49import java.security.PrivilegedAction;
Sergey Bylokhov78119062015-04-03 17:17:36 +030050
Sergey Bylokhov33c5b922015-06-29 01:27:08 +030051import sun.misc.ManagedLocalsThread;
J. Duke319a3b92007-12-01 00:00:00 +000052import sun.security.action.GetPropertyAction;
53
54/**
55 * defines interface for primitives which can be placed into
56 * the graphic component manager framework
57 */
58public abstract class GraphicsPrimitive {
59
60 protected static interface GeneralBinaryOp {
61 /**
62 * This method allows the setupGeneralBinaryOp method to set
63 * the converters into the General version of the Primitive.
64 */
65 public void setPrimitives(Blit srcconverter,
66 Blit dstconverter,
67 GraphicsPrimitive genericop,
68 Blit resconverter);
69
70 /**
71 * These 4 methods are implemented automatically for any
72 * GraphicsPrimitive. They are used by setupGeneralBinaryOp
73 * to retrieve the information needed to find the right
74 * converter primitives.
75 */
76 public SurfaceType getSourceType();
77 public CompositeType getCompositeType();
78 public SurfaceType getDestType();
79 public String getSignature();
80 public int getPrimTypeID();
81 }
82
83 protected static interface GeneralUnaryOp {
84 /**
85 * This method allows the setupGeneralUnaryOp method to set
86 * the converters into the General version of the Primitive.
87 */
88 public void setPrimitives(Blit dstconverter,
89 GraphicsPrimitive genericop,
90 Blit resconverter);
91
92 /**
93 * These 3 methods are implemented automatically for any
94 * GraphicsPrimitive. They are used by setupGeneralUnaryOp
95 * to retrieve the information needed to find the right
96 * converter primitives.
97 */
98 public CompositeType getCompositeType();
99 public SurfaceType getDestType();
100 public String getSignature();
101 public int getPrimTypeID();
102 }
103
104 /**
105 * INSTANCE DATA MEMBERS DESCRIBING CHARACTERISTICS OF THIS PRIMITIVE
106 **/
107
108 // Making these be instance data members (instead of virtual methods
109 // overridden by subclasses) is actually cheaper, since each class
110 // is a singleton. As instance data members with final accessors,
111 // accesses can be inlined.
112 private String methodSignature;
113 private int uniqueID;
114 private static int unusedPrimID = 1;
115
116 private SurfaceType sourceType;
117 private CompositeType compositeType;
118 private SurfaceType destType;
119
120 private long pNativePrim; // Native blit loop info
121
Phil Race4560ea42015-09-19 15:45:59 -0700122 public static final synchronized int makePrimTypeID() {
J. Duke319a3b92007-12-01 00:00:00 +0000123 if (unusedPrimID > 255) {
124 throw new InternalError("primitive id overflow");
125 }
126 return unusedPrimID++;
127 }
128
Phil Race4560ea42015-09-19 15:45:59 -0700129 public static final synchronized int makeUniqueID(int primTypeID,
J. Duke319a3b92007-12-01 00:00:00 +0000130 SurfaceType src,
131 CompositeType cmp,
132 SurfaceType dst)
133 {
134 return (primTypeID << 24) |
135 (dst.getUniqueID() << 16) |
136 (cmp.getUniqueID() << 8) |
137 (src.getUniqueID());
138 }
139
140 /**
141 * Create a new GraphicsPrimitive with all of the required
142 * descriptive information.
143 */
144 protected GraphicsPrimitive(String methodSignature,
145 int primTypeID,
146 SurfaceType sourceType,
147 CompositeType compositeType,
148 SurfaceType destType)
149 {
150 this.methodSignature = methodSignature;
151 this.sourceType = sourceType;
152 this.compositeType = compositeType;
153 this.destType = destType;
154
155 if(sourceType == null || compositeType == null || destType == null) {
156 this.uniqueID = primTypeID << 24;
157 } else {
158 this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,
159 sourceType,
160 compositeType,
161 destType);
162 }
163 }
164
165 /**
166 * Create a new GraphicsPrimitive for native invocation
167 * with all of the required descriptive information.
168 */
169 protected GraphicsPrimitive(long pNativePrim,
170 String methodSignature,
171 int primTypeID,
172 SurfaceType sourceType,
173 CompositeType compositeType,
174 SurfaceType destType)
175 {
176 this.pNativePrim = pNativePrim;
177 this.methodSignature = methodSignature;
178 this.sourceType = sourceType;
179 this.compositeType = compositeType;
180 this.destType = destType;
181
182 if(sourceType == null || compositeType == null || destType == null) {
183 this.uniqueID = primTypeID << 24;
184 } else {
185 this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,
186 sourceType,
187 compositeType,
188 destType);
189 }
190 }
191
192 /**
193 * METHODS TO DESCRIBE THE SURFACES PRIMITIVES
194 * CAN OPERATE ON AND THE FUNCTIONALITY THEY IMPLEMENT
195 **/
196
197 /**
198 * Gets instance ID of this graphics primitive.
199 *
200 * Instance ID is comprised of four distinct ids (ORed together)
201 * that uniquely identify each instance of a GraphicsPrimitive
202 * object. The four ids making up instance ID are:
203 * 1. primitive id - identifier shared by all primitives of the
204 * same type (eg. all Blits have the same primitive id)
205 * 2. sourcetype id - identifies source surface type
206 * 3. desttype id - identifies destination surface type
207 * 4. compositetype id - identifies composite used
208 *
209 * @return instance ID
210 */
211 public final int getUniqueID() {
212 return uniqueID;
213 }
214
215 /**
216 */
217 public final String getSignature() {
218 return methodSignature;
219 }
220
221 /**
222 * Gets unique id for this GraphicsPrimitive type.
223 *
224 * This id is used to identify the TYPE of primitive (Blit vs. BlitBg)
225 * as opposed to INSTANCE of primitive.
226 *
227 * @return primitive ID
228 */
229 public final int getPrimTypeID() {
230 return uniqueID >>> 24;
231 }
232
233 /**
234 */
235 public final long getNativePrim() {
236 return pNativePrim;
237 }
238
239 /**
240 */
241 public final SurfaceType getSourceType() {
242 return sourceType;
243 }
244
245 /**
246 */
247 public final CompositeType getCompositeType() {
248 return compositeType;
249 }
250
251 /**
252 */
253 public final SurfaceType getDestType() {
254 return destType;
255 }
256
257 /**
258 * Return true if this primitive can be used for the given signature
259 * surfaces, and composite.
260 *
261 * @param signature The signature of the given operation. Must be
262 * == (not just .equals) the signature string given by the
263 * abstract class that declares the operation.
264 * @param srctype The surface type for the source of the operation
265 * @param comptype The composite type for the operation
266 * @param dsttype The surface type for the destination of the operation
267 */
268 public final boolean satisfies(String signature,
269 SurfaceType srctype,
270 CompositeType comptype,
271 SurfaceType dsttype)
272 {
273 if (signature != methodSignature) {
274 return false;
275 }
276 while (true) {
277 if (srctype == null) {
278 return false;
279 }
280 if (srctype.equals(sourceType)) {
281 break;
282 }
283 srctype = srctype.getSuperType();
284 }
285 while (true) {
286 if (comptype == null) {
287 return false;
288 }
289 if (comptype.equals(compositeType)) {
290 break;
291 }
292 comptype = comptype.getSuperType();
293 }
294 while (true) {
295 if (dsttype == null) {
296 return false;
297 }
298 if (dsttype.equals(destType)) {
299 break;
300 }
301 dsttype = dsttype.getSuperType();
302 }
303 return true;
304 }
305
306 //
307 // A version of satisfies used for regression testing
308 //
309 final boolean satisfiesSameAs(GraphicsPrimitive other) {
310 return (methodSignature == other.methodSignature &&
311 sourceType.equals(other.sourceType) &&
312 compositeType.equals(other.compositeType) &&
313 destType.equals(other.destType));
314 }
315
316 public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype,
317 CompositeType comptype,
318 SurfaceType dsttype);
319
320 public abstract GraphicsPrimitive traceWrap();
321
Henry Jen81ae76b2014-04-18 09:56:34 -0700322 static HashMap<Object, int[]> traceMap;
J. Duke319a3b92007-12-01 00:00:00 +0000323
324 public static int traceflags;
325 public static String tracefile;
326 public static PrintStream traceout;
327
328 public static final int TRACELOG = 1;
329 public static final int TRACETIMESTAMP = 2;
330 public static final int TRACECOUNTS = 4;
331
332 static {
333 GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace");
Mario Torre163d5232011-12-03 15:40:49 +0100334 String trace = AccessController.doPrivileged(gpa);
J. Duke319a3b92007-12-01 00:00:00 +0000335 if (trace != null) {
336 boolean verbose = false;
337 int traceflags = 0;
338 StringTokenizer st = new StringTokenizer(trace, ",");
339 while (st.hasMoreTokens()) {
340 String tok = st.nextToken();
341 if (tok.equalsIgnoreCase("count")) {
342 traceflags |= GraphicsPrimitive.TRACECOUNTS;
343 } else if (tok.equalsIgnoreCase("log")) {
344 traceflags |= GraphicsPrimitive.TRACELOG;
345 } else if (tok.equalsIgnoreCase("timestamp")) {
346 traceflags |= GraphicsPrimitive.TRACETIMESTAMP;
347 } else if (tok.equalsIgnoreCase("verbose")) {
348 verbose = true;
349 } else if (tok.regionMatches(true, 0, "out:", 0, 4)) {
350 tracefile = tok.substring(4);
351 } else {
352 if (!tok.equalsIgnoreCase("help")) {
353 System.err.println("unrecognized token: "+tok);
354 }
355 System.err.println("usage: -Dsun.java2d.trace="+
356 "[log[,timestamp]],[count],"+
357 "[out:<filename>],[help],[verbose]");
358 }
359 }
360 if (verbose) {
361 System.err.print("GraphicsPrimitive logging ");
362 if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) {
363 System.err.println("enabled");
364 System.err.print("GraphicsPrimitive timetamps ");
365 if ((traceflags & GraphicsPrimitive.TRACETIMESTAMP) != 0) {
366 System.err.println("enabled");
367 } else {
368 System.err.println("disabled");
369 }
370 } else {
371 System.err.println("[and timestamps] disabled");
372 }
373 System.err.print("GraphicsPrimitive invocation counts ");
374 if ((traceflags & GraphicsPrimitive.TRACECOUNTS) != 0) {
375 System.err.println("enabled");
376 } else {
377 System.err.println("disabled");
378 }
379 System.err.print("GraphicsPrimitive trace output to ");
380 if (tracefile == null) {
381 System.err.println("System.err");
382 } else {
383 System.err.println("file '"+tracefile+"'");
384 }
385 }
386 GraphicsPrimitive.traceflags = traceflags;
387 }
388 }
389
390 public static boolean tracingEnabled() {
391 return (traceflags != 0);
392 }
393
394 private static PrintStream getTraceOutputFile() {
395 if (traceout == null) {
396 if (tracefile != null) {
Mario Torre163d5232011-12-03 15:40:49 +0100397 FileOutputStream o = AccessController.doPrivileged(
398 new PrivilegedAction<FileOutputStream>() {
399 public FileOutputStream run() {
J. Duke319a3b92007-12-01 00:00:00 +0000400 try {
401 return new FileOutputStream(tracefile);
402 } catch (FileNotFoundException e) {
403 return null;
404 }
405 }
406 });
407 if (o != null) {
Mario Torre163d5232011-12-03 15:40:49 +0100408 traceout = new PrintStream(o);
J. Duke319a3b92007-12-01 00:00:00 +0000409 } else {
410 traceout = System.err;
411 }
412 } else {
413 traceout = System.err;
414 }
415 }
416 return traceout;
417 }
418
Sergey Bylokhov78119062015-04-03 17:17:36 +0300419 public static class TraceReporter implements Runnable {
J. Duke319a3b92007-12-01 00:00:00 +0000420 public static void setShutdownHook() {
Sergey Bylokhov78119062015-04-03 17:17:36 +0300421 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
422 TraceReporter t = new TraceReporter();
Sergey Bylokhov33c5b922015-06-29 01:27:08 +0300423 Thread thread = new ManagedLocalsThread(
424 ThreadGroupUtils.getRootThreadGroup(), t);
Sergey Bylokhov78119062015-04-03 17:17:36 +0300425 thread.setContextClassLoader(null);
426 Runtime.getRuntime().addShutdownHook(thread);
427 return null;
J. Duke319a3b92007-12-01 00:00:00 +0000428 });
429 }
430
431 public void run() {
432 PrintStream ps = getTraceOutputFile();
Henry Jen81ae76b2014-04-18 09:56:34 -0700433 Iterator<Map.Entry<Object, int[]>> iterator =
434 traceMap.entrySet().iterator();
J. Duke319a3b92007-12-01 00:00:00 +0000435 long total = 0;
436 int numprims = 0;
437 while (iterator.hasNext()) {
Henry Jen81ae76b2014-04-18 09:56:34 -0700438 Map.Entry<Object, int[]> me = iterator.next();
J. Duke319a3b92007-12-01 00:00:00 +0000439 Object prim = me.getKey();
Henry Jen81ae76b2014-04-18 09:56:34 -0700440 int[] count = me.getValue();
J. Duke319a3b92007-12-01 00:00:00 +0000441 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
Phil Race4560ea42015-09-19 15:45:59 -0700459 public static synchronized void tracePrimitive(Object prim) {
J. Duke319a3b92007-12-01 00:00:00 +0000460 if ((traceflags & TRACECOUNTS) != 0) {
461 if (traceMap == null) {
Henry Jen81ae76b2014-04-18 09:56:34 -0700462 traceMap = new HashMap<>();
J. Duke319a3b92007-12-01 00:00:00 +0000463 TraceReporter.setShutdownHook();
464 }
Henry Jen81ae76b2014-04-18 09:56:34 -0700465 int[] o = traceMap.get(prim);
J. Duke319a3b92007-12-01 00:00:00 +0000466 if (o == null) {
467 o = new int[1];
468 traceMap.put(prim, o);
469 }
Henry Jen81ae76b2014-04-18 09:56:34 -0700470 o[0]++;
J. Duke319a3b92007-12-01 00:00:00 +0000471 }
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}