--- /dev/null 2016-09-01 15:38:59.076007815 -0400 +++ new/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/sw/me/MEBackend.java 2016-09-11 10:35:53.496492645 -0400 @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2008, 2014, 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. + */ + +package com.sun.scenario.effect.compiler.backend.sw.me; + +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import com.sun.scenario.effect.compiler.JSLParser; +import com.sun.scenario.effect.compiler.model.BaseType; +import com.sun.scenario.effect.compiler.model.Qualifier; +import com.sun.scenario.effect.compiler.model.Type; +import com.sun.scenario.effect.compiler.model.Variable; +import com.sun.scenario.effect.compiler.tree.FuncDef; +import com.sun.scenario.effect.compiler.tree.ProgramUnit; +import com.sun.scenario.effect.compiler.tree.TreeScanner; +import org.antlr.stringtemplate.StringTemplate; +import org.antlr.stringtemplate.StringTemplateGroup; +import org.antlr.stringtemplate.language.DefaultTemplateLexer; + +/** + */ +public class MEBackend extends TreeScanner { + + private final JSLParser parser; + private final String body; + + public MEBackend(JSLParser parser, ProgramUnit program) { + // TODO: will be removed once we clean up static usage + resetStatics(); + + this.parser = parser; + + METreeScanner scanner = new METreeScanner(); + scanner.scan(program); + this.body = scanner.getResult(); + } + + public static class GenCode { + public String javaCode; + public String nativeCode; + } + + private static void appendGetRelease(StringBuilder get, + StringBuilder rel, + String ctype, + String cbufName, String jarrayName) + { + get.append("j" + ctype + " *" + cbufName + " = (j" + ctype + " *)"); + get.append("env->GetPrimitiveArrayCritical(" + jarrayName + ", 0);\n"); + get.append("if (" + cbufName + " == NULL) return;\n"); + rel.append("env->ReleasePrimitiveArrayCritical(" + jarrayName + ", " + cbufName + ", JNI_ABORT);\n"); + } + + public final GenCode getGenCode(String effectName, + String peerName, + String genericsName, + String interfaceName) + { + Map vars = parser.getSymbolTable().getGlobalVariables(); + StringBuilder genericsDecl = new StringBuilder(); + StringBuilder interfaceDecl = new StringBuilder(); + StringBuilder constants = new StringBuilder(); + StringBuilder samplers = new StringBuilder(); + StringBuilder srcRects = new StringBuilder(); + StringBuilder posDecls = new StringBuilder(); + StringBuilder pixInitY = new StringBuilder(); + StringBuilder pixInitX = new StringBuilder(); + StringBuilder posIncrY = new StringBuilder(); + StringBuilder posInitY = new StringBuilder(); + StringBuilder posIncrX = new StringBuilder(); + StringBuilder posInitX = new StringBuilder(); + StringBuilder jparams = new StringBuilder(); + StringBuilder jparamDecls = new StringBuilder(); + StringBuilder cparamDecls = new StringBuilder(); + StringBuilder arrayGet = new StringBuilder(); + StringBuilder arrayRelease = new StringBuilder(); + + appendGetRelease(arrayGet, arrayRelease, "int", "dst", "dst_arr"); + + // TODO: only need to declare these if pixcoord is referenced + // somewhere in the program... + pixInitY.append("float pixcoord_y = (float)dy;\n"); + pixInitX.append("float pixcoord_x = (float)dx;\n"); + + for (Variable v : vars.values()) { + if (v.getQualifier() == Qualifier.CONST && v.getConstValue() == null) { + // this must be a special built-in variable (e.g. pos0); + // these are handled elsewhere, so just continue... + continue; + } + + Type t = v.getType(); + BaseType bt = t.getBaseType(); + String vtype = bt.toString(); + String vname = v.getName(); + if (v.getQualifier() != null && bt != BaseType.SAMPLER) { + String accName = v.getAccessorName(); + if (v.isArray()) { + // TODO: we currently assume that param arrays will be + // stored in NIO Int/FloatBuffers, but the inner loop + // expects to access them as Java arrays, so we convert + // here; this is obviously bad for performance, so we need + // to come up with a better system soon... + String bufType = (bt == BaseType.FLOAT) ? + "FloatBuffer" : "IntBuffer"; + String bufName = vname + "_buf"; + String arrayName = vname + "_arr"; + constants.append(bufType + " " + bufName + " = " + accName + "();\n"); + constants.append(vtype + "[] " + arrayName); + constants.append(" = new " + vtype + "["); + constants.append(bufName + ".capacity()];\n"); + constants.append(bufName + ".get(" + arrayName + ");\n"); + jparams.append(",\n"); + jparams.append(arrayName); + jparamDecls.append(",\n"); + jparamDecls.append(vtype + "[] " + vname); + cparamDecls.append(",\n"); + cparamDecls.append("j" + vtype + "Array " + vname); + appendGetRelease(arrayGet, arrayRelease, vtype, arrayName, vname); + } else { + if (t.isVector()) { + String arrayName = vname + "_arr"; + constants.append(vtype + "[] " + arrayName + " = " + accName + "();\n"); + jparams.append(",\n"); + jparamDecls.append(",\n"); + cparamDecls.append(",\n"); + for (int i = 0; i < t.getNumFields(); i++) { + if (i > 0) { + jparams.append(", "); + jparamDecls.append(", "); + cparamDecls.append(", "); + } + String vn = vname + getSuffix(i); + jparams.append(arrayName + "[" + i + "]"); + jparamDecls.append(vtype + " " + vn); + cparamDecls.append("j" + vtype + " " + vn); + } + } else { + constants.append(vtype + " " + vname); + if (v.getQualifier() == Qualifier.CONST) { + constants.append(" = " + v.getConstValue()); + } else { + constants.append(" = " + accName + "()"); + } + constants.append(";\n"); + jparams.append(",\n"); + jparams.append(vname); + jparamDecls.append(",\n"); + jparamDecls.append(vtype + " " + vname); + cparamDecls.append(",\n"); + cparamDecls.append("j" + vtype + " " + vname); + } + } + } else if (v.getQualifier() == Qualifier.PARAM && bt == BaseType.SAMPLER) { + int i = v.getReg(); + if (t == Type.FSAMPLER) { + samplers.append("FloatMap src" + i + " = (FloatMap)getSamplerData(" + i + ");\n"); + samplers.append("int src" + i + "x = 0;\n"); + samplers.append("int src" + i + "y = 0;\n"); + samplers.append("int src" + i + "w = src" + i + ".getWidth();\n"); + samplers.append("int src" + i + "h = src" + i + ".getHeight();\n"); + samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n"); + samplers.append("float[] " + vname + " = src" + i + ".getData();\n"); + + // TODO: for now, assume [0,0,1,1] + srcRects.append("float[] src" + i + "Rect = new float[] {0,0,1,1};\n"); + + jparams.append(",\n"); + jparams.append(vname); + + jparamDecls.append(",\n"); + jparamDecls.append("float[] " + vname + "_arr"); + + cparamDecls.append(",\n"); + cparamDecls.append("jfloatArray " + vname + "_arr"); + + appendGetRelease(arrayGet, arrayRelease, "float", vname, vname + "_arr"); + } else { + samplers.append("BufferedImage src" + i + " = (BufferedImage)inputs[" + i + "].getImage();\n"); + samplers.append("int src" + i + "x = 0;\n"); + samplers.append("int src" + i + "y = 0;\n"); + samplers.append("int src" + i + "w = src" + i + ".getWidth();\n"); + samplers.append("int src" + i + "h = src" + i + ".getHeight();\n"); + samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n"); + samplers.append("int[] " + vname + " =\n"); + samplers.append(" ((DataBufferInt)src" + i + ".getRaster().getDataBuffer()).getData();\n"); + + samplers.append("Rectangle src" + i + "Bounds = new Rectangle("); + samplers.append("src" + i + "x, "); + samplers.append("src" + i + "y, "); + samplers.append("src" + i + "w, "); + samplers.append("src" + i + "h);\n"); + samplers.append("setInputBounds(" + i + ", inputs[" + i + "].getBounds());\n"); + samplers.append("setInputNativeBounds(" + i + ", src" + i + "Bounds);\n"); + + if (t == Type.LSAMPLER) { + arrayGet.append("float " + vname + "_vals[4];\n"); + } + + // the source rect decls need to come after all calls to + // setInput[Native]Bounds() for all inputs (since the + // getSourceRegion() impl may need to query the bounds of + // other inputs, as is the case in PhongLighting)... + srcRects.append("float[] src" + i + "Rect = getSourceRegion(" + i + ");\n"); + + jparams.append(",\n"); + jparams.append(vname); + + jparamDecls.append(",\n"); + jparamDecls.append("int[] " + vname + "_arr"); + + cparamDecls.append(",\n"); + cparamDecls.append("jintArray " + vname + "_arr"); + + appendGetRelease(arrayGet, arrayRelease, "int", vname, vname + "_arr"); + } + + posDecls.append("float inc" + i + "_x = (src" + i + "Rect_x2 - src" + i + "Rect_x1) / dstw;\n"); + posDecls.append("float inc" + i + "_y = (src" + i + "Rect_y2 - src" + i + "Rect_y1) / dsth;\n"); + + posInitY.append("float pos" + i + "_y = src" + i + "Rect_y1 + inc" + i + "_y*0.5f;\n"); + posInitX.append("float pos" + i + "_x = src" + i + "Rect_x1 + inc" + i + "_x*0.5f;\n"); + posIncrX.append("pos" + i + "_x += inc" + i + "_x;\n"); + posIncrY.append("pos" + i + "_y += inc" + i + "_y;\n"); + + jparams.append(",\n"); + jparams.append("src" + i + "Rect[0], src" + i + "Rect[1],\n"); + jparams.append("src" + i + "Rect[2], src" + i + "Rect[3],\n"); + jparams.append("src" + i + "w, src" + i + "h, src" + i + "scan"); + + jparamDecls.append(",\n"); + jparamDecls.append("float src" + i + "Rect_x1, float src" + i + "Rect_y1,\n"); + jparamDecls.append("float src" + i + "Rect_x2, float src" + i + "Rect_y2,\n"); + jparamDecls.append("int src" + i + "w, int src" + i + "h, int src" + i + "scan"); + + cparamDecls.append(",\n"); + cparamDecls.append("jfloat src" + i + "Rect_x1, jfloat src" + i + "Rect_y1,\n"); + cparamDecls.append("jfloat src" + i + "Rect_x2, jfloat src" + i + "Rect_y2,\n"); + cparamDecls.append("jint src" + i + "w, jint src" + i + "h, jint src" + i + "scan"); + } + } + + if (genericsName != null) { + genericsDecl.append("<"+genericsName+">"); + } + + if (interfaceName != null) { + interfaceDecl.append("implements "+interfaceName); + } + + Reader template = new InputStreamReader(getClass().getResourceAsStream("MEJavaGlue.stg")); + StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class); + StringTemplate jglue = group.getInstanceOf("glue"); + jglue.setAttribute("effectName", effectName); + jglue.setAttribute("peerName", peerName); + jglue.setAttribute("genericsDecl", genericsDecl.toString()); + jglue.setAttribute("interfaceDecl", interfaceDecl.toString()); + jglue.setAttribute("usercode", usercode.toString()); + jglue.setAttribute("samplers", samplers.toString()); + jglue.setAttribute("srcRects", srcRects.toString()); + jglue.setAttribute("constants", constants.toString()); + jglue.setAttribute("params", jparams.toString()); + jglue.setAttribute("paramDecls", jparamDecls.toString()); + + template = new InputStreamReader(getClass().getResourceAsStream("MENativeGlue.stg")); + group = new StringTemplateGroup(template, DefaultTemplateLexer.class); + StringTemplate cglue = group.getInstanceOf("glue"); + cglue.setAttribute("peerName", peerName); + cglue.setAttribute("jniName", peerName.replace("_", "_1")); + cglue.setAttribute("paramDecls", cparamDecls.toString()); + cglue.setAttribute("arrayGet", arrayGet.toString()); + cglue.setAttribute("arrayRelease", arrayRelease.toString()); + cglue.setAttribute("posDecls", posDecls.toString()); + cglue.setAttribute("pixInitY", pixInitY.toString()); + cglue.setAttribute("pixInitX", pixInitX.toString()); + cglue.setAttribute("posIncrY", posIncrY.toString()); + cglue.setAttribute("posInitY", posInitY.toString()); + cglue.setAttribute("posIncrX", posIncrX.toString()); + cglue.setAttribute("posInitX", posInitX.toString()); + cglue.setAttribute("body", body); + + GenCode gen = new GenCode(); + gen.javaCode = jglue.toString(); + gen.nativeCode = cglue.toString(); + return gen; + } + + // TODO: need better mechanism for querying fields + private static char[] fields = {'x', 'y', 'z', 'w'}; + public static String getSuffix(int i) { + return "_" + fields[i]; + } + + static int getFieldIndex(char field) { + switch (field) { + case 'r': + case 'x': + return 0; + case 'g': + case 'y': + return 1; + case 'b': + case 'z': + return 2; + case 'a': + case 'w': + return 3; + default: + throw new InternalError(); + } + } + + // TODO: these shouldn't be implemented as a static method + private static Map funcDefs = new HashMap(); + static void putFuncDef(FuncDef def) { + funcDefs.put(def.getFunction().getName(), def); + } + static FuncDef getFuncDef(String name) { + return funcDefs.get(name); + } + + private static Set resultVars = new HashSet(); + static boolean isResultVarDeclared(String vname) { + return resultVars.contains(vname); + } + static void declareResultVar(String vname) { + resultVars.add(vname); + } + + private static StringBuilder usercode = new StringBuilder(); + static void addGlueBlock(String block) { + usercode.append(block); + } + + private static void resetStatics() { + funcDefs.clear(); + resultVars.clear(); + usercode = new StringBuilder(); + } +}