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 }