1 /* 2 * Copyright (c) 2008, 2013, 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.java; 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 JSWBackend extends TreeScanner { 49 50 private final JSLParser parser; 51 private final String body; 52 53 public JSWBackend(JSLParser parser, ProgramUnit program) { 54 // TODO: will be removed once we clean up static usage 55 resetStatics(); 56 57 this.parser = parser; 58 59 JSWTreeScanner scanner = new JSWTreeScanner(); 60 scanner.scan(program); 61 this.body = scanner.getResult(); 62 } 63 64 public final String getGenCode(String effectName, 65 String peerName, 66 String genericsName, 67 String interfaceName) 68 { 69 Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables(); 70 StringBuilder genericsDecl = new StringBuilder(); 71 StringBuilder interfaceDecl = new StringBuilder(); 72 StringBuilder constants = new StringBuilder(); 73 StringBuilder samplers = new StringBuilder(); 74 StringBuilder cleanup = new StringBuilder(); 75 StringBuilder srcRects = new StringBuilder(); 76 StringBuilder posDecls = new StringBuilder(); 77 StringBuilder pixInitY = new StringBuilder(); 78 StringBuilder pixInitX = new StringBuilder(); 79 StringBuilder posIncrY = new StringBuilder(); 80 StringBuilder posInitY = new StringBuilder(); 81 StringBuilder posIncrX = new StringBuilder(); 82 StringBuilder posInitX = new StringBuilder(); 83 84 // TODO: only need to declare these if pixcoord is referenced 85 // somewhere in the program... 86 pixInitY.append("float pixcoord_y = (float)dy;\n"); 87 pixInitX.append("float pixcoord_x = (float)dx;\n"); 88 89 for (Variable v : vars.values()) { 90 if (v.getQualifier() == Qualifier.CONST && v.getConstValue() == null) { 91 // this must be a special built-in variable (e.g. pos0); 92 // these are handled elsewhere, so just continue... 93 continue; 94 } 95 96 Type t = v.getType(); 97 BaseType bt = t.getBaseType(); 98 if (v.getQualifier() != null && bt != BaseType.SAMPLER) { 99 String vtype = bt.toString(); 100 String vname = v.getName(); 101 String accName = v.getAccessorName(); 102 if (v.isArray()) { 103 // TODO: we currently assume that param arrays will be 104 // stored in NIO Int/FloatBuffers, but the inner loop 105 // expects to access them as Java arrays, so we convert 106 // here; this is obviously bad for performance, so we need 107 // to come up with a better system soon... 108 String bufType = (bt == BaseType.FLOAT) ? 109 "FloatBuffer" : "IntBuffer"; 110 String bufName = vname + "_buf"; 111 String arrayName = vname + "_arr"; 112 constants.append(bufType + " " + bufName + " = " + accName + "();\n"); 113 constants.append(vtype + "[] " + arrayName); 114 constants.append(" = new " + vtype + "["); 115 constants.append(bufName + ".capacity()];\n"); 116 constants.append(bufName + ".get(" + arrayName + ");\n"); 117 } else { 118 if (t.isVector()) { 119 String arrayName = vname + "_arr"; 120 constants.append(vtype + "[] " + arrayName + " = " + accName + "();\n"); 121 constants.append(vtype + " "); 122 for (int i = 0; i < t.getNumFields(); i++) { 123 if (i > 0) { 124 constants.append(", "); 125 } 126 constants.append(vname + getSuffix(i) + " = " + arrayName + "[" + i + "]"); 127 } 128 constants.append(";\n"); 129 } else { 130 constants.append(vtype + " " + vname); 131 if (v.getQualifier() == Qualifier.CONST) { 132 constants.append(" = " + v.getConstValue()); 133 } else { 134 constants.append(" = " + accName + "()"); 135 } 136 constants.append(";\n"); 137 } 138 } 139 } else if (v.getQualifier() == Qualifier.PARAM && bt == BaseType.SAMPLER) { 140 int i = v.getReg(); 141 if (t == Type.FSAMPLER) { 142 samplers.append("FloatMap src" + i + " = (FloatMap)getSamplerData(" + i + ");\n"); 143 samplers.append("int src" + i + "x = 0;\n"); 144 samplers.append("int src" + i + "y = 0;\n"); 145 samplers.append("int src" + i + "w = src" + i + ".getWidth();\n"); 146 samplers.append("int src" + i + "h = src" + i + ".getHeight();\n"); 147 samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n"); 148 samplers.append("float[] " + v.getName() + " = src" + i + ".getData();\n"); 149 samplers.append("float " + v.getName() + "_vals[] = new float[4];\n"); 150 151 // TODO: for now, assume [0,0,1,1] 152 srcRects.append("float[] src" + i + "Rect = new float[] {0,0,1,1};\n"); 153 } else { 154 if (t == Type.LSAMPLER) { 155 samplers.append("HeapImage src" + i + " = (HeapImage)inputs[" + i + "].getUntransformedImage();\n"); 156 } else { 157 samplers.append("HeapImage src" + i + " = (HeapImage)inputs[" + i + "].getTransformedImage(dstBounds);\n"); 158 cleanup.append("inputs[" + i + "].releaseTransformedImage(src" + i + ");\n"); 159 } 160 samplers.append("int src" + i + "x = 0;\n"); 161 samplers.append("int src" + i + "y = 0;\n"); 162 samplers.append("int src" + i + "w = src" + i + ".getPhysicalWidth();\n"); 163 samplers.append("int src" + i + "h = src" + i + ".getPhysicalHeight();\n"); 164 samplers.append("int src" + i + "scan = src" + i + ".getScanlineStride();\n"); 165 samplers.append("int[] " + v.getName() + " =\n"); 166 samplers.append(" src" + i + ".getPixelArray();\n"); 167 168 samplers.append("Rectangle src" + i + "Bounds = new Rectangle("); 169 samplers.append("src" + i + "x, "); 170 samplers.append("src" + i + "y, "); 171 samplers.append("src" + i + "w, "); 172 samplers.append("src" + i + "h);\n"); 173 if (t == Type.LSAMPLER) { 174 samplers.append("Rectangle src" + i + "InputBounds = inputs[" + i + "].getUntransformedBounds();\n"); 175 samplers.append("BaseTransform src" + i + "Transform = inputs[" + i + "].getTransform();\n"); 176 } else { 177 samplers.append("Rectangle src" + i + "InputBounds = inputs[" + i + "].getTransformedBounds(dstBounds);\n"); 178 samplers.append("BaseTransform src" + i + "Transform = BaseTransform.IDENTITY_TRANSFORM;\n"); 179 } 180 samplers.append("setInputBounds(" + i + ", src" + i + "InputBounds);\n"); 181 samplers.append("setInputNativeBounds(" + i + ", src" + i + "Bounds);\n"); 182 183 if (t == Type.LSAMPLER) { 184 samplers.append("float " + v.getName() + "_vals[] = new float[4];\n"); 185 } 186 187 // the source rect decls need to come after all calls to 188 // setInput[Native]Bounds() for all inputs (since the 189 // getSourceRegion() impl may need to query the bounds of 190 // other inputs, as is the case in PhongLighting)... 191 srcRects.append("float[] src" + i + "Rect = new float[4];\n"); 192 // Note that we only allocate 4 floats here because none 193 // of the loops can deal with fully mapped inputs. Only 194 // shaders that declare LSAMPLERs would require mapped 195 // inputs and so far that is only Perspective and 196 // Displacement, both of which override getTC() and return 197 // only 4 values. 198 srcRects.append("getTextureCoordinates(" + i + ", src" + i + "Rect,\n"); 199 srcRects.append(" src" + i + "InputBounds.x, src" + i + "InputBounds.y,\n"); 200 srcRects.append(" src" + i + "w, src" + i + "h,\n"); 201 srcRects.append(" dstBounds, src" + i + "Transform);\n"); 202 } 203 204 posDecls.append("float inc" + i + "_x = (src" + i + "Rect[2] - src" + i + "Rect[0]) / dstw;\n"); 205 posDecls.append("float inc" + i + "_y = (src" + i + "Rect[3] - src" + i + "Rect[1]) / dsth;\n"); 206 207 posInitY.append("float pos" + i + "_y = src" + i + "Rect[1] + inc" + i + "_y*0.5f;\n"); 208 posInitX.append("float pos" + i + "_x = src" + i + "Rect[0] + inc" + i + "_x*0.5f;\n"); 209 posIncrX.append("pos" + i + "_x += inc" + i + "_x;\n"); 210 posIncrY.append("pos" + i + "_y += inc" + i + "_y;\n"); 211 } 212 } 213 214 if (genericsName != null) { 215 genericsDecl.append("<"+genericsName+">"); 216 } 217 218 if (interfaceName != null) { 219 interfaceDecl.append("implements "+interfaceName); 220 } 221 222 Reader template = new InputStreamReader(getClass().getResourceAsStream("JSWGlue.stg")); 223 StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class); 224 StringTemplate glue = group.getInstanceOf("glue"); 225 glue.setAttribute("effectName", effectName); 226 glue.setAttribute("peerName", peerName); 227 glue.setAttribute("genericsDecl", genericsDecl.toString()); 228 glue.setAttribute("interfaceDecl", interfaceDecl.toString()); 229 glue.setAttribute("usercode", usercode.toString()); 230 glue.setAttribute("samplers", samplers.toString()); 231 glue.setAttribute("cleanup", cleanup.toString()); 232 glue.setAttribute("srcRects", srcRects.toString()); 233 glue.setAttribute("constants", constants.toString()); 234 glue.setAttribute("posDecls", posDecls.toString()); 235 glue.setAttribute("pixInitY", pixInitY.toString()); 236 glue.setAttribute("pixInitX", pixInitX.toString()); 237 glue.setAttribute("posIncrY", posIncrY.toString()); 238 glue.setAttribute("posInitY", posInitY.toString()); 239 glue.setAttribute("posIncrX", posIncrX.toString()); 240 glue.setAttribute("posInitX", posInitX.toString()); 241 glue.setAttribute("body", body); 242 return glue.toString(); 243 } 244 245 // TODO: need better mechanism for querying fields 246 private static char[] fields = {'x', 'y', 'z', 'w'}; 247 public static String getSuffix(int i) { 248 return "_" + fields[i]; 249 } 250 251 static int getFieldIndex(char field) { 252 switch (field) { 253 case 'r': 254 case 'x': 255 return 0; 256 case 'g': 257 case 'y': 258 return 1; 259 case 'b': 260 case 'z': 261 return 2; 262 case 'a': 263 case 'w': 264 return 3; 265 default: 266 throw new InternalError(); 267 } 268 } 269 270 // TODO: these shouldn't be implemented as a static method 271 private static Map<String, FuncDef> funcDefs = new HashMap<String, FuncDef>(); 272 static void putFuncDef(FuncDef def) { 273 funcDefs.put(def.getFunction().getName(), def); 274 } 275 static FuncDef getFuncDef(String name) { 276 return funcDefs.get(name); 277 } 278 279 private static Set<String> resultVars = new HashSet<String>(); 280 static boolean isResultVarDeclared(String vname) { 281 return resultVars.contains(vname); 282 } 283 static void declareResultVar(String vname) { 284 resultVars.add(vname); 285 } 286 287 private static StringBuilder usercode = new StringBuilder(); 288 static void addGlueBlock(String block) { 289 usercode.append(block); 290 } 291 292 private static void resetStatics() { 293 funcDefs.clear(); 294 resultVars.clear(); 295 usercode = new StringBuilder(); 296 } 297 }