1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 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. 24 */ 25 26 package com.sun.scenario.effect.compiler.backend.sw.me; 27 28 import java.io.InputStreamReader; 29 import java.io.Reader; 30 import java.util.HashMap; 31 import java.util.HashSet; 32 import java.util.Map; 33 import java.util.Set; 34 import com.sun.scenario.effect.compiler.JSLParser; 35 import com.sun.scenario.effect.compiler.model.BaseType; 36 import com.sun.scenario.effect.compiler.model.Qualifier; 37 import com.sun.scenario.effect.compiler.model.Type; 38 import com.sun.scenario.effect.compiler.model.Variable; 39 import com.sun.scenario.effect.compiler.tree.FuncDef; 40 import com.sun.scenario.effect.compiler.tree.ProgramUnit; 41 import com.sun.scenario.effect.compiler.tree.TreeScanner; 42 import org.antlr.stringtemplate.StringTemplate; 43 import org.antlr.stringtemplate.StringTemplateGroup; 44 import org.antlr.stringtemplate.language.DefaultTemplateLexer; 45 46 /** 47 */ 48 public class MEBackend extends TreeScanner { 49 50 private final JSLParser parser; 51 private final String body; 52 53 public MEBackend(JSLParser parser, ProgramUnit program) { 54 // TODO: will be removed once we clean up static usage 55 resetStatics(); 56 57 this.parser = parser; 58 59 METreeScanner scanner = new METreeScanner(); 60 scanner.scan(program); 61 this.body = scanner.getResult(); 62 } 63 64 public static class GenCode { 65 public String javaCode; 66 public String nativeCode; 67 } 68 69 private static void appendGetRelease(StringBuilder get, 70 StringBuilder rel, 71 String ctype, 72 String cbufName, String jarrayName) 73 { 74 get.append("j" + ctype + " *" + cbufName + " = (j" + ctype + " *)"); 75 get.append("env->GetPrimitiveArrayCritical(" + jarrayName + ", 0);\n"); 76 get.append("if (" + cbufName + " == NULL) return;\n"); 77 rel.append("env->ReleasePrimitiveArrayCritical(" + jarrayName + ", " + cbufName + ", JNI_ABORT);\n"); 78 } 79 80 public final GenCode getGenCode(String effectName, 81 String peerName, 82 String genericsName, 83 String interfaceName) 84 { 85 Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables(); 86 StringBuilder genericsDecl = new StringBuilder(); 87 StringBuilder interfaceDecl = new StringBuilder(); 88 StringBuilder constants = new StringBuilder(); 89 StringBuilder samplers = new StringBuilder(); 90 StringBuilder srcRects = new StringBuilder(); 91 StringBuilder posDecls = new StringBuilder(); 92 StringBuilder pixInitY = new StringBuilder(); 93 StringBuilder pixInitX = new StringBuilder(); 94 StringBuilder posIncrY = new StringBuilder(); 95 StringBuilder posInitY = new StringBuilder(); 96 StringBuilder posIncrX = new StringBuilder(); 97 StringBuilder posInitX = new StringBuilder(); 98 StringBuilder jparams = new StringBuilder(); 99 StringBuilder jparamDecls = new StringBuilder(); 100 StringBuilder cparamDecls = new StringBuilder(); 101 StringBuilder arrayGet = new StringBuilder(); 102 StringBuilder arrayRelease = new StringBuilder(); 103 104 appendGetRelease(arrayGet, arrayRelease, "int", "dst", "dst_arr"); 105 106 // TODO: only need to declare these if pixcoord is referenced 107 // somewhere in the program... 108 pixInitY.append("float pixcoord_y = (float)dy;\n"); 109 pixInitX.append("float pixcoord_x = (float)dx;\n"); 110 111 for (Variable v : vars.values()) { 112 if (v.getQualifier() == Qualifier.CONST && v.getConstValue() == null) { 113 // this must be a special built-in variable (e.g. pos0); 114 // these are handled elsewhere, so just continue... 115 continue; 116 } 117 118 Type t = v.getType(); 119 BaseType bt = t.getBaseType(); 120 String vtype = bt.toString(); 121 String vname = v.getName(); 122 if (v.getQualifier() != null && bt != BaseType.SAMPLER) { 123 String accName = v.getAccessorName(); 124 if (v.isArray()) { 125 // TODO: we currently assume that param arrays will be 126 // stored in NIO Int/FloatBuffers, but the inner loop 127 // expects to access them as Java arrays, so we convert 128 // here; this is obviously bad for performance, so we need 129 // to come up with a better system soon... 130 String bufType = (bt == BaseType.FLOAT) ? 131 "FloatBuffer" : "IntBuffer"; 132 String bufName = vname + "_buf"; 133 String arrayName = vname + "_arr"; 134 constants.append(bufType + " " + bufName + " = " + accName + "();\n"); 135 constants.append(vtype + "[] " + arrayName); 136 constants.append(" = new " + vtype + "["); 137 constants.append(bufName + ".capacity()];\n"); 138 constants.append(bufName + ".get(" + arrayName + ");\n"); 139 jparams.append(",\n"); 140 jparams.append(arrayName); 141 jparamDecls.append(",\n"); 142 jparamDecls.append(vtype + "[] " + vname); 143 cparamDecls.append(",\n"); 144 cparamDecls.append("j" + vtype + "Array " + vname); 145 appendGetRelease(arrayGet, arrayRelease, vtype, arrayName, vname); 146 } else { 147 if (t.isVector()) { 148 String arrayName = vname + "_arr"; 149 constants.append(vtype + "[] " + arrayName + " = " + accName + "();\n"); 150 jparams.append(",\n"); 151 jparamDecls.append(",\n"); 152 cparamDecls.append(",\n"); 153 for (int i = 0; i < t.getNumFields(); i++) { 154 if (i > 0) { 155 jparams.append(", "); 156 jparamDecls.append(", "); 157 cparamDecls.append(", "); 158 } 159 String vn = vname + getSuffix(i); 160 jparams.append(arrayName + "[" + i + "]"); 161 jparamDecls.append(vtype + " " + vn); 162 cparamDecls.append("j" + vtype + " " + vn); 163 } 164 } else { 165 constants.append(vtype + " " + vname); 166 if (v.getQualifier() == Qualifier.CONST) { 167 constants.append(" = " + v.getConstValue()); 168 } else { 169 constants.append(" = " + accName + "()"); 170 } 171 constants.append(";\n"); 172 jparams.append(",\n"); 173 jparams.append(vname); 174 jparamDecls.append(",\n"); 175 jparamDecls.append(vtype + " " + vname); 176 cparamDecls.append(",\n"); 177 cparamDecls.append("j" + vtype + " " + vname); 178 } 179 } 180 } else if (v.getQualifier() == Qualifier.PARAM && bt == BaseType.SAMPLER) { 181 int i = v.getReg(); 182 if (t == Type.FSAMPLER) { 183 samplers.append("FloatMap src" + i + " = (FloatMap)getSamplerData(" + i + ");\n"); 184 samplers.append("int src" + i + "x = 0;\n"); 185 samplers.append("int src" + i + "y = 0;\n"); 186 samplers.append("int src" + i + "w = src" + i + ".getWidth();\n"); 187 samplers.append("int src" + i + "h = src" + i + ".getHeight();\n"); 188 samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n"); 189 samplers.append("float[] " + vname + " = src" + i + ".getData();\n"); 190 191 // TODO: for now, assume [0,0,1,1] 192 srcRects.append("float[] src" + i + "Rect = new float[] {0,0,1,1};\n"); 193 194 jparams.append(",\n"); 195 jparams.append(vname); 196 197 jparamDecls.append(",\n"); 198 jparamDecls.append("float[] " + vname + "_arr"); 199 200 cparamDecls.append(",\n"); 201 cparamDecls.append("jfloatArray " + vname + "_arr"); 202 203 appendGetRelease(arrayGet, arrayRelease, "float", vname, vname + "_arr"); 204 } else { 205 samplers.append("BufferedImage src" + i + " = (BufferedImage)inputs[" + i + "].getImage();\n"); 206 samplers.append("int src" + i + "x = 0;\n"); 207 samplers.append("int src" + i + "y = 0;\n"); 208 samplers.append("int src" + i + "w = src" + i + ".getWidth();\n"); 209 samplers.append("int src" + i + "h = src" + i + ".getHeight();\n"); 210 samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n"); 211 samplers.append("int[] " + vname + " =\n"); 212 samplers.append(" ((DataBufferInt)src" + i + ".getRaster().getDataBuffer()).getData();\n"); 213 214 samplers.append("Rectangle src" + i + "Bounds = new Rectangle("); 215 samplers.append("src" + i + "x, "); 216 samplers.append("src" + i + "y, "); 217 samplers.append("src" + i + "w, "); 218 samplers.append("src" + i + "h);\n"); 219 samplers.append("setInputBounds(" + i + ", inputs[" + i + "].getBounds());\n"); 220 samplers.append("setInputNativeBounds(" + i + ", src" + i + "Bounds);\n"); 221 222 if (t == Type.LSAMPLER) { 223 arrayGet.append("float " + vname + "_vals[4];\n"); 224 } 225 226 // the source rect decls need to come after all calls to 227 // setInput[Native]Bounds() for all inputs (since the 228 // getSourceRegion() impl may need to query the bounds of 229 // other inputs, as is the case in PhongLighting)... 230 srcRects.append("float[] src" + i + "Rect = getSourceRegion(" + i + ");\n"); 231 232 jparams.append(",\n"); 233 jparams.append(vname); 234 235 jparamDecls.append(",\n"); 236 jparamDecls.append("int[] " + vname + "_arr"); 237 238 cparamDecls.append(",\n"); 239 cparamDecls.append("jintArray " + vname + "_arr"); 240 241 appendGetRelease(arrayGet, arrayRelease, "int", vname, vname + "_arr"); 242 } 243 244 posDecls.append("float inc" + i + "_x = (src" + i + "Rect_x2 - src" + i + "Rect_x1) / dstw;\n"); 245 posDecls.append("float inc" + i + "_y = (src" + i + "Rect_y2 - src" + i + "Rect_y1) / dsth;\n"); 246 247 posInitY.append("float pos" + i + "_y = src" + i + "Rect_y1 + inc" + i + "_y*0.5f;\n"); 248 posInitX.append("float pos" + i + "_x = src" + i + "Rect_x1 + inc" + i + "_x*0.5f;\n"); 249 posIncrX.append("pos" + i + "_x += inc" + i + "_x;\n"); 250 posIncrY.append("pos" + i + "_y += inc" + i + "_y;\n"); 251 252 jparams.append(",\n"); 253 jparams.append("src" + i + "Rect[0], src" + i + "Rect[1],\n"); 254 jparams.append("src" + i + "Rect[2], src" + i + "Rect[3],\n"); 255 jparams.append("src" + i + "w, src" + i + "h, src" + i + "scan"); 256 257 jparamDecls.append(",\n"); 258 jparamDecls.append("float src" + i + "Rect_x1, float src" + i + "Rect_y1,\n"); 259 jparamDecls.append("float src" + i + "Rect_x2, float src" + i + "Rect_y2,\n"); 260 jparamDecls.append("int src" + i + "w, int src" + i + "h, int src" + i + "scan"); 261 262 cparamDecls.append(",\n"); 263 cparamDecls.append("jfloat src" + i + "Rect_x1, jfloat src" + i + "Rect_y1,\n"); 264 cparamDecls.append("jfloat src" + i + "Rect_x2, jfloat src" + i + "Rect_y2,\n"); 265 cparamDecls.append("jint src" + i + "w, jint src" + i + "h, jint src" + i + "scan"); 266 } 267 } 268 269 if (genericsName != null) { 270 genericsDecl.append("<"+genericsName+">"); 271 } 272 273 if (interfaceName != null) { 274 interfaceDecl.append("implements "+interfaceName); 275 } 276 277 Reader template = new InputStreamReader(getClass().getResourceAsStream("MEJavaGlue.stg")); 278 StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class); 279 StringTemplate jglue = group.getInstanceOf("glue"); 280 jglue.setAttribute("effectName", effectName); 281 jglue.setAttribute("peerName", peerName); 282 jglue.setAttribute("genericsDecl", genericsDecl.toString()); 283 jglue.setAttribute("interfaceDecl", interfaceDecl.toString()); 284 jglue.setAttribute("usercode", usercode.toString()); 285 jglue.setAttribute("samplers", samplers.toString()); 286 jglue.setAttribute("srcRects", srcRects.toString()); 287 jglue.setAttribute("constants", constants.toString()); 288 jglue.setAttribute("params", jparams.toString()); 289 jglue.setAttribute("paramDecls", jparamDecls.toString()); 290 291 template = new InputStreamReader(getClass().getResourceAsStream("MENativeGlue.stg")); 292 group = new StringTemplateGroup(template, DefaultTemplateLexer.class); 293 StringTemplate cglue = group.getInstanceOf("glue"); 294 cglue.setAttribute("peerName", peerName); 295 cglue.setAttribute("jniName", peerName.replace("_", "_1")); 296 cglue.setAttribute("paramDecls", cparamDecls.toString()); 297 cglue.setAttribute("arrayGet", arrayGet.toString()); 298 cglue.setAttribute("arrayRelease", arrayRelease.toString()); 299 cglue.setAttribute("posDecls", posDecls.toString()); 300 cglue.setAttribute("pixInitY", pixInitY.toString()); 301 cglue.setAttribute("pixInitX", pixInitX.toString()); 302 cglue.setAttribute("posIncrY", posIncrY.toString()); 303 cglue.setAttribute("posInitY", posInitY.toString()); 304 cglue.setAttribute("posIncrX", posIncrX.toString()); 305 cglue.setAttribute("posInitX", posInitX.toString()); 306 cglue.setAttribute("body", body); 307 308 GenCode gen = new GenCode(); 309 gen.javaCode = jglue.toString(); 310 gen.nativeCode = cglue.toString(); 311 return gen; 312 } 313 314 // TODO: need better mechanism for querying fields 315 private static char[] fields = {'x', 'y', 'z', 'w'}; 316 public static String getSuffix(int i) { 317 return "_" + fields[i]; 318 } 319 320 static int getFieldIndex(char field) { 321 switch (field) { 322 case 'r': 323 case 'x': 324 return 0; 325 case 'g': 326 case 'y': 327 return 1; 328 case 'b': 329 case 'z': 330 return 2; 331 case 'a': 332 case 'w': 333 return 3; 334 default: 335 throw new InternalError(); 336 } 337 } 338 339 // TODO: these shouldn't be implemented as a static method 340 private static Map<String, FuncDef> funcDefs = new HashMap<String, FuncDef>(); 341 static void putFuncDef(FuncDef def) { 342 funcDefs.put(def.getFunction().getName(), def); 343 } 344 static FuncDef getFuncDef(String name) { 345 return funcDefs.get(name); 346 } 347 348 private static Set<String> resultVars = new HashSet<String>(); 349 static boolean isResultVarDeclared(String vname) { 350 return resultVars.contains(vname); 351 } 352 static void declareResultVar(String vname) { 353 resultVars.add(vname); 354 } 355 356 private static StringBuilder usercode = new StringBuilder(); 357 static void addGlueBlock(String block) { 358 usercode.append(block); 359 } 360 361 private static void resetStatics() { 362 funcDefs.clear(); 363 resultVars.clear(); 364 usercode = new StringBuilder(); 365 } 366 }