Path: blob/master/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java
41159 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* @author Charlton Innovations, Inc.27*/2829package sun.java2d.loops;3031import java.awt.AlphaComposite;32import java.awt.Rectangle;33import java.awt.image.BufferedImage;34import java.io.FileNotFoundException;35import java.io.FileOutputStream;36import java.io.PrintStream;37import java.lang.reflect.Field;38import java.security.AccessController;39import java.security.PrivilegedAction;40import java.util.HashMap;41import java.util.Iterator;42import java.util.Map;43import java.util.StringTokenizer;4445import sun.awt.image.BufImgSurfaceData;46import sun.awt.util.ThreadGroupUtils;47import sun.java2d.SurfaceData;48import sun.java2d.pipe.Region;49import sun.security.action.GetPropertyAction;5051/**52* defines interface for primitives which can be placed into53* the graphic component manager framework54*/55public abstract class GraphicsPrimitive {5657protected static interface GeneralBinaryOp {58/**59* This method allows the setupGeneralBinaryOp method to set60* the converters into the General version of the Primitive.61*/62public void setPrimitives(Blit srcconverter,63Blit dstconverter,64GraphicsPrimitive genericop,65Blit resconverter);6667/**68* These 4 methods are implemented automatically for any69* GraphicsPrimitive. They are used by setupGeneralBinaryOp70* to retrieve the information needed to find the right71* converter primitives.72*/73public SurfaceType getSourceType();74public CompositeType getCompositeType();75public SurfaceType getDestType();76public String getSignature();77public int getPrimTypeID();78}7980protected static interface GeneralUnaryOp {81/**82* This method allows the setupGeneralUnaryOp method to set83* the converters into the General version of the Primitive.84*/85public void setPrimitives(Blit dstconverter,86GraphicsPrimitive genericop,87Blit resconverter);8889/**90* These 3 methods are implemented automatically for any91* GraphicsPrimitive. They are used by setupGeneralUnaryOp92* to retrieve the information needed to find the right93* converter primitives.94*/95public CompositeType getCompositeType();96public SurfaceType getDestType();97public String getSignature();98public int getPrimTypeID();99}100101/**102* INSTANCE DATA MEMBERS DESCRIBING CHARACTERISTICS OF THIS PRIMITIVE103**/104105// Making these be instance data members (instead of virtual methods106// overridden by subclasses) is actually cheaper, since each class107// is a singleton. As instance data members with final accessors,108// accesses can be inlined.109private String methodSignature;110private int uniqueID;111private static int unusedPrimID = 1;112113private SurfaceType sourceType;114private CompositeType compositeType;115private SurfaceType destType;116117private long pNativePrim; // Native blit loop info118119public static final synchronized int makePrimTypeID() {120if (unusedPrimID > 255) {121throw new InternalError("primitive id overflow");122}123return unusedPrimID++;124}125126public static final synchronized int makeUniqueID(int primTypeID,127SurfaceType src,128CompositeType cmp,129SurfaceType dst)130{131return (primTypeID << 24) |132(dst.getUniqueID() << 16) |133(cmp.getUniqueID() << 8) |134(src.getUniqueID());135}136137/**138* Create a new GraphicsPrimitive with all of the required139* descriptive information.140*/141protected GraphicsPrimitive(String methodSignature,142int primTypeID,143SurfaceType sourceType,144CompositeType compositeType,145SurfaceType destType)146{147this.methodSignature = methodSignature;148this.sourceType = sourceType;149this.compositeType = compositeType;150this.destType = destType;151152if(sourceType == null || compositeType == null || destType == null) {153this.uniqueID = primTypeID << 24;154} else {155this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,156sourceType,157compositeType,158destType);159}160}161162/**163* Create a new GraphicsPrimitive for native invocation164* with all of the required descriptive information.165*/166protected GraphicsPrimitive(long pNativePrim,167String methodSignature,168int primTypeID,169SurfaceType sourceType,170CompositeType compositeType,171SurfaceType destType)172{173this.pNativePrim = pNativePrim;174this.methodSignature = methodSignature;175this.sourceType = sourceType;176this.compositeType = compositeType;177this.destType = destType;178179if(sourceType == null || compositeType == null || destType == null) {180this.uniqueID = primTypeID << 24;181} else {182this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,183sourceType,184compositeType,185destType);186}187}188189/**190* METHODS TO DESCRIBE THE SURFACES PRIMITIVES191* CAN OPERATE ON AND THE FUNCTIONALITY THEY IMPLEMENT192**/193194/**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 GraphicsPrimitive199* object. The four ids making up instance ID are:200* 1. primitive id - identifier shared by all primitives of the201* same type (eg. all Blits have the same primitive id)202* 2. sourcetype id - identifies source surface type203* 3. desttype id - identifies destination surface type204* 4. compositetype id - identifies composite used205*206* @return instance ID207*/208public final int getUniqueID() {209return uniqueID;210}211212/**213*/214public final String getSignature() {215return methodSignature;216}217218/**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 ID225*/226public final int getPrimTypeID() {227return uniqueID >>> 24;228}229230/**231*/232public final long getNativePrim() {233return pNativePrim;234}235236/**237*/238public final SurfaceType getSourceType() {239return sourceType;240}241242/**243*/244public final CompositeType getCompositeType() {245return compositeType;246}247248/**249*/250public final SurfaceType getDestType() {251return destType;252}253254/**255* Return true if this primitive can be used for the given signature256* surfaces, and composite.257*258* @param signature The signature of the given operation. Must be259* == (not just .equals) the signature string given by the260* abstract class that declares the operation.261* @param srctype The surface type for the source of the operation262* @param comptype The composite type for the operation263* @param dsttype The surface type for the destination of the operation264*/265public final boolean satisfies(String signature,266SurfaceType srctype,267CompositeType comptype,268SurfaceType dsttype)269{270if (signature != methodSignature) {271return false;272}273while (true) {274if (srctype == null) {275return false;276}277if (srctype.equals(sourceType)) {278break;279}280srctype = srctype.getSuperType();281}282while (true) {283if (comptype == null) {284return false;285}286if (comptype.equals(compositeType)) {287break;288}289comptype = comptype.getSuperType();290}291while (true) {292if (dsttype == null) {293return false;294}295if (dsttype.equals(destType)) {296break;297}298dsttype = dsttype.getSuperType();299}300return true;301}302303//304// A version of satisfies used for regression testing305//306final boolean satisfiesSameAs(GraphicsPrimitive other) {307return (methodSignature == other.methodSignature &&308sourceType.equals(other.sourceType) &&309compositeType.equals(other.compositeType) &&310destType.equals(other.destType));311}312313/**314* Produces specific primitive loop if the current object is registered as a315* general loop, otherwise the {@code InternalError} is thrown.316*317* @see GraphicsPrimitiveMgr#registerGeneral318*/319protected GraphicsPrimitive makePrimitive(SurfaceType srctype,320CompositeType comptype,321SurfaceType dsttype) {322throw new InternalError("%s not implemented for %s, comp: %s, dst: %s".323formatted(getClass().getName(), srctype, comptype, dsttype));324}325326public abstract GraphicsPrimitive traceWrap();327328static HashMap<Object, int[]> traceMap;329330public static int traceflags;331public static String tracefile;332public static PrintStream traceout;333334public static final int TRACELOG = 1;335public static final int TRACETIMESTAMP = 2;336public static final int TRACECOUNTS = 4;337338static {339GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace");340@SuppressWarnings("removal")341String trace = AccessController.doPrivileged(gpa);342if (trace != null) {343boolean verbose = false;344int traceflags = 0;345StringTokenizer st = new StringTokenizer(trace, ",");346while (st.hasMoreTokens()) {347String tok = st.nextToken();348if (tok.equalsIgnoreCase("count")) {349traceflags |= GraphicsPrimitive.TRACECOUNTS;350} else if (tok.equalsIgnoreCase("log")) {351traceflags |= GraphicsPrimitive.TRACELOG;352} else if (tok.equalsIgnoreCase("timestamp")) {353traceflags |= GraphicsPrimitive.TRACETIMESTAMP;354} else if (tok.equalsIgnoreCase("verbose")) {355verbose = true;356} else if (tok.regionMatches(true, 0, "out:", 0, 4)) {357tracefile = tok.substring(4);358} else {359if (!tok.equalsIgnoreCase("help")) {360System.err.println("unrecognized token: "+tok);361}362System.err.println("usage: -Dsun.java2d.trace="+363"[log[,timestamp]],[count],"+364"[out:<filename>],[help],[verbose]");365}366}367if (verbose) {368System.err.print("GraphicsPrimitive logging ");369if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) {370System.err.println("enabled");371System.err.print("GraphicsPrimitive timetamps ");372if ((traceflags & GraphicsPrimitive.TRACETIMESTAMP) != 0) {373System.err.println("enabled");374} else {375System.err.println("disabled");376}377} else {378System.err.println("[and timestamps] disabled");379}380System.err.print("GraphicsPrimitive invocation counts ");381if ((traceflags & GraphicsPrimitive.TRACECOUNTS) != 0) {382System.err.println("enabled");383} else {384System.err.println("disabled");385}386System.err.print("GraphicsPrimitive trace output to ");387if (tracefile == null) {388System.err.println("System.err");389} else {390System.err.println("file '"+tracefile+"'");391}392}393GraphicsPrimitive.traceflags = traceflags;394}395}396397public static boolean tracingEnabled() {398return (traceflags != 0);399}400401private static PrintStream getTraceOutputFile() {402if (traceout == null) {403if (tracefile != null) {404@SuppressWarnings("removal")405FileOutputStream o = AccessController.doPrivileged(406new PrivilegedAction<FileOutputStream>() {407public FileOutputStream run() {408try {409return new FileOutputStream(tracefile);410} catch (FileNotFoundException e) {411return null;412}413}414});415if (o != null) {416traceout = new PrintStream(o);417} else {418traceout = System.err;419}420} else {421traceout = System.err;422}423}424return traceout;425}426427public static class TraceReporter implements Runnable {428@SuppressWarnings("removal")429public static void setShutdownHook() {430AccessController.doPrivileged((PrivilegedAction<Void>) () -> {431TraceReporter t = new TraceReporter();432Thread thread = new Thread(433ThreadGroupUtils.getRootThreadGroup(), t,434"TraceReporter", 0, false);435thread.setContextClassLoader(null);436Runtime.getRuntime().addShutdownHook(thread);437return null;438});439}440441public void run() {442PrintStream ps = getTraceOutputFile();443Iterator<Map.Entry<Object, int[]>> iterator =444traceMap.entrySet().iterator();445long total = 0;446int numprims = 0;447while (iterator.hasNext()) {448Map.Entry<Object, int[]> me = iterator.next();449Object prim = me.getKey();450int[] count = me.getValue();451if (count[0] == 1) {452ps.print("1 call to ");453} else {454ps.print(count[0]+" calls to ");455}456ps.println(prim);457numprims++;458total += count[0];459}460if (numprims == 0) {461ps.println("No graphics primitives executed");462} else if (numprims > 1) {463ps.println(total+" total calls to "+464numprims+" different primitives");465}466}467}468469public static synchronized void tracePrimitive(Object prim) {470if ((traceflags & TRACECOUNTS) != 0) {471if (traceMap == null) {472traceMap = new HashMap<>();473TraceReporter.setShutdownHook();474}475int[] o = traceMap.get(prim);476if (o == null) {477o = new int[1];478traceMap.put(prim, o);479}480o[0]++;481}482if ((traceflags & TRACELOG) != 0) {483PrintStream ps = getTraceOutputFile();484if ((traceflags & TRACETIMESTAMP) != 0) {485ps.print(System.currentTimeMillis()+": ");486}487ps.println(prim);488}489}490491protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) {492int primID = gbo.getPrimTypeID();493String methodSignature = gbo.getSignature();494SurfaceType srctype = gbo.getSourceType();495CompositeType comptype = gbo.getCompositeType();496SurfaceType dsttype = gbo.getDestType();497Blit convertsrc, convertdst, convertres;498GraphicsPrimitive performop;499500convertsrc = createConverter(srctype, SurfaceType.IntArgb);501performop = GraphicsPrimitiveMgr.locatePrim(primID,502SurfaceType.IntArgb,503comptype, dsttype);504if (performop != null) {505convertdst = null;506convertres = null;507} else {508performop = getGeneralOp(primID, comptype);509if (performop == null) {510throw new InternalError("Cannot construct general op for "+511methodSignature+" "+comptype);512}513convertdst = createConverter(dsttype, SurfaceType.IntArgb);514convertres = createConverter(SurfaceType.IntArgb, dsttype);515}516517gbo.setPrimitives(convertsrc, convertdst, performop, convertres);518}519520protected void setupGeneralUnaryOp(GeneralUnaryOp guo) {521int primID = guo.getPrimTypeID();522String methodSignature = guo.getSignature();523CompositeType comptype = guo.getCompositeType();524SurfaceType dsttype = guo.getDestType();525526Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb);527GraphicsPrimitive performop = getGeneralOp(primID, comptype);528Blit convertres = createConverter(SurfaceType.IntArgb, dsttype);529if (convertdst == null || performop == null || convertres == null) {530throw new InternalError("Cannot construct binary op for "+531comptype+" "+dsttype);532}533534guo.setPrimitives(convertdst, performop, convertres);535}536537protected static Blit createConverter(SurfaceType srctype,538SurfaceType dsttype)539{540if (srctype.equals(dsttype)) {541return null;542}543Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype);544if (cv == null) {545throw new InternalError("Cannot construct converter for "+546srctype+"=>"+dsttype);547}548return cv;549}550551protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,552int srcX, int srcY, int w, int h,553SurfaceData dstData)554{555return convertFrom(ob, srcData,556srcX, srcY, w, h, dstData,557BufferedImage.TYPE_INT_ARGB);558}559560protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,561int srcX, int srcY, int w, int h,562SurfaceData dstData, int type)563{564if (dstData != null) {565Rectangle r = dstData.getBounds();566if (w > r.width || h > r.height) {567dstData = null;568}569}570if (dstData == null) {571BufferedImage dstBI = new BufferedImage(w, h, type);572dstData = BufImgSurfaceData.createData(dstBI);573}574ob.Blit(srcData, dstData, AlphaComposite.Src, null,575srcX, srcY, 0, 0, w, h);576return dstData;577}578579protected static void convertTo(Blit ob,580SurfaceData srcImg, SurfaceData dstImg,581Region clip,582int dstX, int dstY, int w, int h)583{584if (ob != null) {585ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip,5860, 0, dstX, dstY, w, h);587}588}589590protected static GraphicsPrimitive getGeneralOp(int primID,591CompositeType comptype)592{593return GraphicsPrimitiveMgr.locatePrim(primID,594SurfaceType.IntArgb,595comptype,596SurfaceType.IntArgb);597}598599public static String simplename(Field[] fields, Object o) {600for (int i = 0; i < fields.length; i++) {601Field f = fields[i];602try {603if (o == f.get(null)) {604return f.getName();605}606} catch (Exception e) {607}608}609return "\""+o.toString()+"\"";610}611612public static String simplename(SurfaceType st) {613return simplename(SurfaceType.class.getDeclaredFields(), st);614}615616public static String simplename(CompositeType ct) {617return simplename(CompositeType.class.getDeclaredFields(), ct);618}619620private String cachedname;621622public String toString() {623if (cachedname == null) {624String sig = methodSignature;625int index = sig.indexOf('(');626if (index >= 0) {627sig = sig.substring(0, index);628}629cachedname = (getClass().getName()+"::"+630sig+"("+631simplename(sourceType)+", "+632simplename(compositeType)+", "+633simplename(destType)+")");634}635return cachedname;636}637}638639640