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