| /* |
| * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * @author Charlton Innovations, Inc. |
| */ |
| |
| package sun.java2d.loops; |
| |
| import java.awt.image.BufferedImage; |
| import java.awt.AlphaComposite; |
| import java.awt.Rectangle; |
| import sun.awt.image.BufImgSurfaceData; |
| import sun.awt.util.ThreadGroupUtils; |
| import sun.java2d.SurfaceData; |
| import sun.java2d.pipe.Region; |
| import java.lang.reflect.Field; |
| import java.util.StringTokenizer; |
| import java.util.Iterator; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.io.PrintStream; |
| import java.io.OutputStream; |
| import java.io.FileOutputStream; |
| import java.io.FileNotFoundException; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| |
| import sun.security.action.GetPropertyAction; |
| |
| /** |
| * defines interface for primitives which can be placed into |
| * the graphic component manager framework |
| */ |
| public abstract class GraphicsPrimitive { |
| |
| protected static interface GeneralBinaryOp { |
| /** |
| * This method allows the setupGeneralBinaryOp method to set |
| * the converters into the General version of the Primitive. |
| */ |
| public void setPrimitives(Blit srcconverter, |
| Blit dstconverter, |
| GraphicsPrimitive genericop, |
| Blit resconverter); |
| |
| /** |
| * These 4 methods are implemented automatically for any |
| * GraphicsPrimitive. They are used by setupGeneralBinaryOp |
| * to retrieve the information needed to find the right |
| * converter primitives. |
| */ |
| public SurfaceType getSourceType(); |
| public CompositeType getCompositeType(); |
| public SurfaceType getDestType(); |
| public String getSignature(); |
| public int getPrimTypeID(); |
| } |
| |
| protected static interface GeneralUnaryOp { |
| /** |
| * This method allows the setupGeneralUnaryOp method to set |
| * the converters into the General version of the Primitive. |
| */ |
| public void setPrimitives(Blit dstconverter, |
| GraphicsPrimitive genericop, |
| Blit resconverter); |
| |
| /** |
| * These 3 methods are implemented automatically for any |
| * GraphicsPrimitive. They are used by setupGeneralUnaryOp |
| * to retrieve the information needed to find the right |
| * converter primitives. |
| */ |
| public CompositeType getCompositeType(); |
| public SurfaceType getDestType(); |
| public String getSignature(); |
| public int getPrimTypeID(); |
| } |
| |
| /** |
| * INSTANCE DATA MEMBERS DESCRIBING CHARACTERISTICS OF THIS PRIMITIVE |
| **/ |
| |
| // Making these be instance data members (instead of virtual methods |
| // overridden by subclasses) is actually cheaper, since each class |
| // is a singleton. As instance data members with final accessors, |
| // accesses can be inlined. |
| private String methodSignature; |
| private int uniqueID; |
| private static int unusedPrimID = 1; |
| |
| private SurfaceType sourceType; |
| private CompositeType compositeType; |
| private SurfaceType destType; |
| |
| private long pNativePrim; // Native blit loop info |
| |
| public static final synchronized int makePrimTypeID() { |
| if (unusedPrimID > 255) { |
| throw new InternalError("primitive id overflow"); |
| } |
| return unusedPrimID++; |
| } |
| |
| public static final synchronized int makeUniqueID(int primTypeID, |
| SurfaceType src, |
| CompositeType cmp, |
| SurfaceType dst) |
| { |
| return (primTypeID << 24) | |
| (dst.getUniqueID() << 16) | |
| (cmp.getUniqueID() << 8) | |
| (src.getUniqueID()); |
| } |
| |
| /** |
| * Create a new GraphicsPrimitive with all of the required |
| * descriptive information. |
| */ |
| protected GraphicsPrimitive(String methodSignature, |
| int primTypeID, |
| SurfaceType sourceType, |
| CompositeType compositeType, |
| SurfaceType destType) |
| { |
| this.methodSignature = methodSignature; |
| this.sourceType = sourceType; |
| this.compositeType = compositeType; |
| this.destType = destType; |
| |
| if(sourceType == null || compositeType == null || destType == null) { |
| this.uniqueID = primTypeID << 24; |
| } else { |
| this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID, |
| sourceType, |
| compositeType, |
| destType); |
| } |
| } |
| |
| /** |
| * Create a new GraphicsPrimitive for native invocation |
| * with all of the required descriptive information. |
| */ |
| protected GraphicsPrimitive(long pNativePrim, |
| String methodSignature, |
| int primTypeID, |
| SurfaceType sourceType, |
| CompositeType compositeType, |
| SurfaceType destType) |
| { |
| this.pNativePrim = pNativePrim; |
| this.methodSignature = methodSignature; |
| this.sourceType = sourceType; |
| this.compositeType = compositeType; |
| this.destType = destType; |
| |
| if(sourceType == null || compositeType == null || destType == null) { |
| this.uniqueID = primTypeID << 24; |
| } else { |
| this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID, |
| sourceType, |
| compositeType, |
| destType); |
| } |
| } |
| |
| /** |
| * METHODS TO DESCRIBE THE SURFACES PRIMITIVES |
| * CAN OPERATE ON AND THE FUNCTIONALITY THEY IMPLEMENT |
| **/ |
| |
| /** |
| * Gets instance ID of this graphics primitive. |
| * |
| * Instance ID is comprised of four distinct ids (ORed together) |
| * that uniquely identify each instance of a GraphicsPrimitive |
| * object. The four ids making up instance ID are: |
| * 1. primitive id - identifier shared by all primitives of the |
| * same type (eg. all Blits have the same primitive id) |
| * 2. sourcetype id - identifies source surface type |
| * 3. desttype id - identifies destination surface type |
| * 4. compositetype id - identifies composite used |
| * |
| * @return instance ID |
| */ |
| public final int getUniqueID() { |
| return uniqueID; |
| } |
| |
| /** |
| */ |
| public final String getSignature() { |
| return methodSignature; |
| } |
| |
| /** |
| * Gets unique id for this GraphicsPrimitive type. |
| * |
| * This id is used to identify the TYPE of primitive (Blit vs. BlitBg) |
| * as opposed to INSTANCE of primitive. |
| * |
| * @return primitive ID |
| */ |
| public final int getPrimTypeID() { |
| return uniqueID >>> 24; |
| } |
| |
| /** |
| */ |
| public final long getNativePrim() { |
| return pNativePrim; |
| } |
| |
| /** |
| */ |
| public final SurfaceType getSourceType() { |
| return sourceType; |
| } |
| |
| /** |
| */ |
| public final CompositeType getCompositeType() { |
| return compositeType; |
| } |
| |
| /** |
| */ |
| public final SurfaceType getDestType() { |
| return destType; |
| } |
| |
| /** |
| * Return true if this primitive can be used for the given signature |
| * surfaces, and composite. |
| * |
| * @param signature The signature of the given operation. Must be |
| * == (not just .equals) the signature string given by the |
| * abstract class that declares the operation. |
| * @param srctype The surface type for the source of the operation |
| * @param comptype The composite type for the operation |
| * @param dsttype The surface type for the destination of the operation |
| */ |
| public final boolean satisfies(String signature, |
| SurfaceType srctype, |
| CompositeType comptype, |
| SurfaceType dsttype) |
| { |
| if (signature != methodSignature) { |
| return false; |
| } |
| while (true) { |
| if (srctype == null) { |
| return false; |
| } |
| if (srctype.equals(sourceType)) { |
| break; |
| } |
| srctype = srctype.getSuperType(); |
| } |
| while (true) { |
| if (comptype == null) { |
| return false; |
| } |
| if (comptype.equals(compositeType)) { |
| break; |
| } |
| comptype = comptype.getSuperType(); |
| } |
| while (true) { |
| if (dsttype == null) { |
| return false; |
| } |
| if (dsttype.equals(destType)) { |
| break; |
| } |
| dsttype = dsttype.getSuperType(); |
| } |
| return true; |
| } |
| |
| // |
| // A version of satisfies used for regression testing |
| // |
| final boolean satisfiesSameAs(GraphicsPrimitive other) { |
| return (methodSignature == other.methodSignature && |
| sourceType.equals(other.sourceType) && |
| compositeType.equals(other.compositeType) && |
| destType.equals(other.destType)); |
| } |
| |
| public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype, |
| CompositeType comptype, |
| SurfaceType dsttype); |
| |
| public abstract GraphicsPrimitive traceWrap(); |
| |
| static HashMap<Object, int[]> traceMap; |
| |
| public static int traceflags; |
| public static String tracefile; |
| public static PrintStream traceout; |
| |
| public static final int TRACELOG = 1; |
| public static final int TRACETIMESTAMP = 2; |
| public static final int TRACECOUNTS = 4; |
| |
| static { |
| GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace"); |
| String trace = AccessController.doPrivileged(gpa); |
| if (trace != null) { |
| boolean verbose = false; |
| int traceflags = 0; |
| StringTokenizer st = new StringTokenizer(trace, ","); |
| while (st.hasMoreTokens()) { |
| String tok = st.nextToken(); |
| if (tok.equalsIgnoreCase("count")) { |
| traceflags |= GraphicsPrimitive.TRACECOUNTS; |
| } else if (tok.equalsIgnoreCase("log")) { |
| traceflags |= GraphicsPrimitive.TRACELOG; |
| } else if (tok.equalsIgnoreCase("timestamp")) { |
| traceflags |= GraphicsPrimitive.TRACETIMESTAMP; |
| } else if (tok.equalsIgnoreCase("verbose")) { |
| verbose = true; |
| } else if (tok.regionMatches(true, 0, "out:", 0, 4)) { |
| tracefile = tok.substring(4); |
| } else { |
| if (!tok.equalsIgnoreCase("help")) { |
| System.err.println("unrecognized token: "+tok); |
| } |
| System.err.println("usage: -Dsun.java2d.trace="+ |
| "[log[,timestamp]],[count],"+ |
| "[out:<filename>],[help],[verbose]"); |
| } |
| } |
| if (verbose) { |
| System.err.print("GraphicsPrimitive logging "); |
| if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) { |
| System.err.println("enabled"); |
| System.err.print("GraphicsPrimitive timetamps "); |
| if ((traceflags & GraphicsPrimitive.TRACETIMESTAMP) != 0) { |
| System.err.println("enabled"); |
| } else { |
| System.err.println("disabled"); |
| } |
| } else { |
| System.err.println("[and timestamps] disabled"); |
| } |
| System.err.print("GraphicsPrimitive invocation counts "); |
| if ((traceflags & GraphicsPrimitive.TRACECOUNTS) != 0) { |
| System.err.println("enabled"); |
| } else { |
| System.err.println("disabled"); |
| } |
| System.err.print("GraphicsPrimitive trace output to "); |
| if (tracefile == null) { |
| System.err.println("System.err"); |
| } else { |
| System.err.println("file '"+tracefile+"'"); |
| } |
| } |
| GraphicsPrimitive.traceflags = traceflags; |
| } |
| } |
| |
| public static boolean tracingEnabled() { |
| return (traceflags != 0); |
| } |
| |
| private static PrintStream getTraceOutputFile() { |
| if (traceout == null) { |
| if (tracefile != null) { |
| FileOutputStream o = AccessController.doPrivileged( |
| new PrivilegedAction<FileOutputStream>() { |
| public FileOutputStream run() { |
| try { |
| return new FileOutputStream(tracefile); |
| } catch (FileNotFoundException e) { |
| return null; |
| } |
| } |
| }); |
| if (o != null) { |
| traceout = new PrintStream(o); |
| } else { |
| traceout = System.err; |
| } |
| } else { |
| traceout = System.err; |
| } |
| } |
| return traceout; |
| } |
| |
| public static class TraceReporter implements Runnable { |
| public static void setShutdownHook() { |
| AccessController.doPrivileged((PrivilegedAction<Void>) () -> { |
| TraceReporter t = new TraceReporter(); |
| Thread thread = new Thread( |
| ThreadGroupUtils.getRootThreadGroup(), t, |
| "TraceReporter", 0, false); |
| thread.setContextClassLoader(null); |
| Runtime.getRuntime().addShutdownHook(thread); |
| return null; |
| }); |
| } |
| |
| public void run() { |
| PrintStream ps = getTraceOutputFile(); |
| Iterator<Map.Entry<Object, int[]>> iterator = |
| traceMap.entrySet().iterator(); |
| long total = 0; |
| int numprims = 0; |
| while (iterator.hasNext()) { |
| Map.Entry<Object, int[]> me = iterator.next(); |
| Object prim = me.getKey(); |
| int[] count = me.getValue(); |
| if (count[0] == 1) { |
| ps.print("1 call to "); |
| } else { |
| ps.print(count[0]+" calls to "); |
| } |
| ps.println(prim); |
| numprims++; |
| total += count[0]; |
| } |
| if (numprims == 0) { |
| ps.println("No graphics primitives executed"); |
| } else if (numprims > 1) { |
| ps.println(total+" total calls to "+ |
| numprims+" different primitives"); |
| } |
| } |
| } |
| |
| public static synchronized void tracePrimitive(Object prim) { |
| if ((traceflags & TRACECOUNTS) != 0) { |
| if (traceMap == null) { |
| traceMap = new HashMap<>(); |
| TraceReporter.setShutdownHook(); |
| } |
| int[] o = traceMap.get(prim); |
| if (o == null) { |
| o = new int[1]; |
| traceMap.put(prim, o); |
| } |
| o[0]++; |
| } |
| if ((traceflags & TRACELOG) != 0) { |
| PrintStream ps = getTraceOutputFile(); |
| if ((traceflags & TRACETIMESTAMP) != 0) { |
| ps.print(System.currentTimeMillis()+": "); |
| } |
| ps.println(prim); |
| } |
| } |
| |
| protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) { |
| int primID = gbo.getPrimTypeID(); |
| String methodSignature = gbo.getSignature(); |
| SurfaceType srctype = gbo.getSourceType(); |
| CompositeType comptype = gbo.getCompositeType(); |
| SurfaceType dsttype = gbo.getDestType(); |
| Blit convertsrc, convertdst, convertres; |
| GraphicsPrimitive performop; |
| |
| convertsrc = createConverter(srctype, SurfaceType.IntArgb); |
| performop = GraphicsPrimitiveMgr.locatePrim(primID, |
| SurfaceType.IntArgb, |
| comptype, dsttype); |
| if (performop != null) { |
| convertdst = null; |
| convertres = null; |
| } else { |
| performop = getGeneralOp(primID, comptype); |
| if (performop == null) { |
| throw new InternalError("Cannot construct general op for "+ |
| methodSignature+" "+comptype); |
| } |
| convertdst = createConverter(dsttype, SurfaceType.IntArgb); |
| convertres = createConverter(SurfaceType.IntArgb, dsttype); |
| } |
| |
| gbo.setPrimitives(convertsrc, convertdst, performop, convertres); |
| } |
| |
| protected void setupGeneralUnaryOp(GeneralUnaryOp guo) { |
| int primID = guo.getPrimTypeID(); |
| String methodSignature = guo.getSignature(); |
| CompositeType comptype = guo.getCompositeType(); |
| SurfaceType dsttype = guo.getDestType(); |
| |
| Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb); |
| GraphicsPrimitive performop = getGeneralOp(primID, comptype); |
| Blit convertres = createConverter(SurfaceType.IntArgb, dsttype); |
| if (convertdst == null || performop == null || convertres == null) { |
| throw new InternalError("Cannot construct binary op for "+ |
| comptype+" "+dsttype); |
| } |
| |
| guo.setPrimitives(convertdst, performop, convertres); |
| } |
| |
| protected static Blit createConverter(SurfaceType srctype, |
| SurfaceType dsttype) |
| { |
| if (srctype.equals(dsttype)) { |
| return null; |
| } |
| Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype); |
| if (cv == null) { |
| throw new InternalError("Cannot construct converter for "+ |
| srctype+"=>"+dsttype); |
| } |
| return cv; |
| } |
| |
| protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, |
| int srcX, int srcY, int w, int h, |
| SurfaceData dstData) |
| { |
| return convertFrom(ob, srcData, |
| srcX, srcY, w, h, dstData, |
| BufferedImage.TYPE_INT_ARGB); |
| } |
| |
| protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData, |
| int srcX, int srcY, int w, int h, |
| SurfaceData dstData, int type) |
| { |
| if (dstData != null) { |
| Rectangle r = dstData.getBounds(); |
| if (w > r.width || h > r.height) { |
| dstData = null; |
| } |
| } |
| if (dstData == null) { |
| BufferedImage dstBI = new BufferedImage(w, h, type); |
| dstData = BufImgSurfaceData.createData(dstBI); |
| } |
| ob.Blit(srcData, dstData, AlphaComposite.Src, null, |
| srcX, srcY, 0, 0, w, h); |
| return dstData; |
| } |
| |
| protected static void convertTo(Blit ob, |
| SurfaceData srcImg, SurfaceData dstImg, |
| Region clip, |
| int dstX, int dstY, int w, int h) |
| { |
| if (ob != null) { |
| ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip, |
| 0, 0, dstX, dstY, w, h); |
| } |
| } |
| |
| protected static GraphicsPrimitive getGeneralOp(int primID, |
| CompositeType comptype) |
| { |
| return GraphicsPrimitiveMgr.locatePrim(primID, |
| SurfaceType.IntArgb, |
| comptype, |
| SurfaceType.IntArgb); |
| } |
| |
| public static String simplename(Field[] fields, Object o) { |
| for (int i = 0; i < fields.length; i++) { |
| Field f = fields[i]; |
| try { |
| if (o == f.get(null)) { |
| return f.getName(); |
| } |
| } catch (Exception e) { |
| } |
| } |
| return "\""+o.toString()+"\""; |
| } |
| |
| public static String simplename(SurfaceType st) { |
| return simplename(SurfaceType.class.getDeclaredFields(), st); |
| } |
| |
| public static String simplename(CompositeType ct) { |
| return simplename(CompositeType.class.getDeclaredFields(), ct); |
| } |
| |
| private String cachedname; |
| |
| public String toString() { |
| if (cachedname == null) { |
| String sig = methodSignature; |
| int index = sig.indexOf('('); |
| if (index >= 0) { |
| sig = sig.substring(0, index); |
| } |
| cachedname = (getClass().getName()+"::"+ |
| sig+"("+ |
| simplename(sourceType)+", "+ |
| simplename(compositeType)+", "+ |
| simplename(destType)+")"); |
| } |
| return cachedname; |
| } |
| } |