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.util.Arrays;
  29 import java.util.HashMap;
  30 import java.util.List;
  31 import java.util.Map;
  32 import com.sun.scenario.effect.compiler.model.CoreSymbols;
  33 import com.sun.scenario.effect.compiler.model.FuncImpl;
  34 import com.sun.scenario.effect.compiler.model.Function;
  35 import com.sun.scenario.effect.compiler.model.Type;
  36 import com.sun.scenario.effect.compiler.tree.Expr;
  37 import com.sun.scenario.effect.compiler.tree.VariableExpr;
  38 
  39 import static com.sun.scenario.effect.compiler.model.Type.*;
  40 
  41 /**
  42  * Contains the pure Java implementations for all core (built-in) functions.
  43  */
  44 class JSWFuncImpls {
  45 
  46     private static Map<Function, FuncImpl> funcs = new HashMap<Function, FuncImpl>();
  47 
  48     static FuncImpl get(Function func) {
  49         return funcs.get(func);
  50     }
  51 
  52     static {
  53         // float4 sample(sampler s, float2 loc)
  54         declareFunctionSample(SAMPLER);
  55 
  56         // float4 sample(lsampler s, float2 loc)
  57         declareFunctionSample(LSAMPLER);
  58 
  59         // float4 sample(fsampler s, float2 loc)
  60         declareFunctionSample(FSAMPLER);
  61 
  62         // int intcast(float x)
  63         declareFunctionIntCast();
  64 
  65         // <ftype> min(<ftype> x, <ftype> y)
  66         // <ftype> min(<ftype> x, float y)
  67         declareOverloadsMinMax("min", "(x_tmp$1 < y_tmp$2) ? x_tmp$1 : y_tmp$2");
  68 
  69         // <ftype> max(<ftype> x, <ftype> y)
  70         // <ftype> max(<ftype> x, float y)
  71         declareOverloadsMinMax("max", "(x_tmp$1 > y_tmp$2) ? x_tmp$1 : y_tmp$2");
  72 
  73         // <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
  74         // <ftype> clamp(<ftype> val, float min, float max)
  75         declareOverloadsClamp();
  76 
  77         // <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
  78         // <ftype> smoothstep(float min, float max, <ftype> val)
  79         declareOverloadsSmoothstep();
  80 
  81         // <ftype> abs(<ftype> x)
  82         declareOverloadsSimple("abs", "Math.abs(x_tmp$1)");
  83 
  84         // <ftype> floor(<ftype> x)
  85         declareOverloadsSimple("floor", "(float)Math.floor(x_tmp$1)");
  86 
  87         // <ftype> ceil(<ftype> x)
  88         declareOverloadsSimple("ceil", "(float)Math.ceil(x_tmp$1)");
  89 
  90         // <ftype> fract(<ftype> x)
  91         declareOverloadsSimple("fract", "(x_tmp$1 - (float)Math.floor(x_tmp$1))");
  92 
  93         // <ftype> sign(<ftype> x)
  94         declareOverloadsSimple("sign", "Math.signum(x_tmp$1)");
  95 
  96         // <ftype> sqrt(<ftype> x)
  97         declareOverloadsSimple("sqrt", "(float)Math.sqrt(x_tmp$1)");
  98 
  99         // <ftype> sin(<ftype> x)
 100         declareOverloadsSimple("sin", "(float)Math.sin(x_tmp$1)");
 101 
 102         // <ftype> cos(<ftype> x)
 103         declareOverloadsSimple("cos", "(float)Math.cos(x_tmp$1)");
 104 
 105         // <ftype> tan(<ftype> x)
 106         declareOverloadsSimple("tan", "(float)Math.tan(x_tmp$1)");
 107 
 108         // <ftype> pow(<ftype> x, <ftype> y)
 109         declareOverloadsSimple2("pow", "(float)Math.pow(x_tmp$1, y_tmp$2)");
 110 
 111         // <ftype> mod(<ftype> x, <ftype> y)
 112         // <ftype> mod(<ftype> x, float y)
 113         declareOverloadsMinMax("mod", "(x_tmp$1 % y_tmp$2)");
 114 
 115         // float dot(<ftype> x, <ftype> y)
 116         declareOverloadsDot();
 117 
 118         // float distance(<ftype> x, <ftype> y)
 119         declareOverloadsDistance();
 120 
 121         // <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
 122         // <ftype> mix(<ftype> x, <ftype> y, float a)
 123         declareOverloadsMix();
 124 
 125         // <ftype> normalize(<ftype> x)
 126         declareOverloadsNormalize();
 127 
 128         // <ftype> ddx(<ftype> p)
 129         declareOverloadsSimple("ddx", "<ddx() not implemented for sw backends>");
 130 
 131         // <ftype> ddy(<ftype> p)
 132         declareOverloadsSimple("ddy", "<ddy() not implemented for sw backends>");
 133     }
 134 
 135     private static void declareFunction(FuncImpl impl,
 136                                         String name, Type... ptypes)
 137     {
 138         Function f = CoreSymbols.getFunction(name, Arrays.asList(ptypes));
 139         if (f == null) {
 140             throw new InternalError("Core function not found (have you declared the function in CoreSymbols?)");
 141         }
 142         funcs.put(f, impl);
 143     }
 144 
 145     /**
 146      * Used to declare sample function:
 147      *   float4 sample([l,f]sampler s, float2 loc)
 148      */
 149     private static void declareFunctionSample(final Type type) {
 150         FuncImpl fimpl = new FuncImpl() {
 151             @Override
 152             public String getPreamble(List<Expr> params) {
 153                 String s = getSamplerName(params);
 154                 // TODO: this bounds checking is way too costly...
 155                 String p = getPosName(params);
 156                 if (type == LSAMPLER) {
 157                     return
 158                         "lsample(" + s + ", loc_tmp_x, loc_tmp_y,\n" +
 159                         "        " + p + "w, " + p + "h, " + p + "scan,\n" +
 160                         "        " + s + "_vals);\n";
 161                 } else if (type == FSAMPLER) {
 162                     return
 163                         "fsample(" + s + ", loc_tmp_x, loc_tmp_y,\n" +
 164                         "        " + p + "w, " + p + "h, " + p + "scan,\n" +
 165                         "        " + s + "_vals);\n";
 166                 } else {
 167                     return
 168                         "int " + s + "_tmp;\n" +
 169                         "if (loc_tmp_x >= 0 && loc_tmp_y >= 0) {\n" +
 170                         "    int iloc_tmp_x = (int)(loc_tmp_x*" + p + "w);\n" +
 171                         "    int iloc_tmp_y = (int)(loc_tmp_y*" + p + "h);\n" +
 172                         "    boolean out =\n" +
 173                         "        iloc_tmp_x >= " + p + "w ||\n" +
 174                         "        iloc_tmp_y >= " + p + "h;\n" +
 175                         "    " + s + "_tmp = out ? 0 :\n" +
 176                         "        " + s + "[iloc_tmp_y*" + p + "scan + iloc_tmp_x];\n" +
 177                         "} else {\n" +
 178                         "    " + s + "_tmp = 0;\n" +
 179                         "}\n";
 180                 }
 181             }
 182             public String toString(int i, List<Expr> params) {
 183                 String s = getSamplerName(params);
 184                 if (type == LSAMPLER || type == FSAMPLER) {
 185                     return (i < 0 || i > 3) ? null : s + "_vals[" + i + "]";
 186                 } else {
 187                     switch (i) {
 188                     case 0:
 189                         return "(((" + s + "_tmp >>  16) & 0xff) / 255f)";
 190                     case 1:
 191                         return "(((" + s + "_tmp >>   8) & 0xff) / 255f)";
 192                     case 2:
 193                         return "(((" + s + "_tmp       ) & 0xff) / 255f)";
 194                     case 3:
 195                         return "(((" + s + "_tmp >>> 24)       ) / 255f)";
 196                     default:
 197                         return null;
 198                     }
 199                 }
 200             }
 201             private String getSamplerName(List<Expr> params) {
 202                 VariableExpr e = (VariableExpr)params.get(0);
 203                 return e.getVariable().getName();
 204             }
 205             private String getPosName(List<Expr> params) {
 206                 VariableExpr e = (VariableExpr)params.get(0);
 207                 return "src" + e.getVariable().getReg();
 208             }
 209         };
 210         declareFunction(fimpl, "sample", type, FLOAT2);
 211     }
 212 
 213     /**
 214      * Used to declare intcast function:
 215      *   int intcast(float x)
 216      */
 217     private static void declareFunctionIntCast() {
 218         FuncImpl fimpl = new FuncImpl() {
 219             public String toString(int i, List<Expr> params) {
 220                 return "((int)x_tmp)";
 221             }
 222         };
 223         declareFunction(fimpl, "intcast", FLOAT);
 224     }
 225 
 226     /**
 227      * Used to declare simple functions of the following form:
 228      *   <ftype> name(<ftype> x)
 229      */
 230     private static void declareOverloadsSimple(String name, final String pattern) {
 231         for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 232             final boolean useSuffix = (type != FLOAT);
 233             FuncImpl fimpl = new FuncImpl() {
 234                 public String toString(int i, List<Expr> params) {
 235                     String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
 236                     String s = pattern;
 237                     s = s.replace("$1", sfx);
 238                     return s;
 239                 }
 240             };
 241             declareFunction(fimpl, name, type);
 242         }
 243     }
 244 
 245     /**
 246      * Used to declare simple two parameter functions of the following form:
 247      *   <ftype> name(<ftype> x, <ftype> y)
 248      */
 249     private static void declareOverloadsSimple2(String name, final String pattern) {
 250         for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 251             // declare (vectype,vectype) variants
 252             final boolean useSuffix = (type != FLOAT);
 253             FuncImpl fimpl = new FuncImpl() {
 254                 public String toString(int i, List<Expr> params) {
 255                     String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
 256                     String s = pattern;
 257                     s = s.replace("$1", sfx);
 258                     s = s.replace("$2", sfx);
 259                     return s;
 260                 }
 261             };
 262             declareFunction(fimpl, name, type, type);
 263         }
 264     }
 265 
 266     /**
 267      * Used to declare normalize functions of the following form:
 268      *   <ftype> normalize(<ftype> x)
 269      */
 270     private static void declareOverloadsNormalize() {
 271         final String name = "normalize";
 272         final String pattern = "x_tmp$1 / denom";
 273         for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 274             int n = type.getNumFields();
 275             final String preamble;
 276             if (n == 1) {
 277                 preamble = "float denom = x_tmp;\n";
 278             } else {
 279                 String     s  =    "(x_tmp_x * x_tmp_x)";
 280                            s += "+\n(x_tmp_y * x_tmp_y)";
 281                 if (n > 2) s += "+\n(x_tmp_z * x_tmp_z)";
 282                 if (n > 3) s += "+\n(x_tmp_w * x_tmp_w)";
 283                 preamble = "float denom = (float)Math.sqrt(" + s + ");\n";
 284             }
 285 
 286             final boolean useSuffix = (type != FLOAT);
 287             FuncImpl fimpl = new FuncImpl() {
 288                 @Override
 289                 public String getPreamble(List<Expr> params) {
 290                     return preamble;
 291                 }
 292                 public String toString(int i, List<Expr> params) {
 293                     String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
 294                     String s = pattern;
 295                     s = s.replace("$1", sfx);
 296                     return s;
 297                 }
 298             };
 299             declareFunction(fimpl, name, type);
 300         }
 301     }
 302 
 303     /**
 304      * Used to declare dot functions of the following form:
 305      *   float dot(<ftype> x, <ftype> y)
 306      */
 307     private static void declareOverloadsDot() {
 308         final String name = "dot";
 309         for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 310             int n = type.getNumFields();
 311             String s;
 312             if (n == 1) {
 313                 s = "(x_tmp * y_tmp)";
 314             } else {
 315                            s  =    "(x_tmp_x * y_tmp_x)";
 316                            s += "+\n(x_tmp_y * y_tmp_y)";
 317                 if (n > 2) s += "+\n(x_tmp_z * y_tmp_z)";
 318                 if (n > 3) s += "+\n(x_tmp_w * y_tmp_w)";
 319             }
 320             final String str = s;
 321             FuncImpl fimpl = new FuncImpl() {
 322                 public String toString(int i, List<Expr> params) {
 323                     return str;
 324                 }
 325             };
 326             declareFunction(fimpl, name, type, type);
 327         }
 328     }
 329 
 330     /**
 331      * Used to declare distance functions of the following form:
 332      *   float distance(<ftype> x, <ftype> y)
 333      */
 334     private static void declareOverloadsDistance() {
 335         final String name = "distance";
 336         for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 337             int n = type.getNumFields();
 338             String s;
 339             if (n == 1) {
 340                 s = "(x_tmp - y_tmp) * (x_tmp - y_tmp)";
 341             } else {
 342                            s  =    "((x_tmp_x - y_tmp_x) * (x_tmp_x - y_tmp_x))";
 343                            s += "+\n((x_tmp_y - y_tmp_y) * (x_tmp_y - y_tmp_y))";
 344                 if (n > 2) s += "+\n((x_tmp_z - y_tmp_z) * (x_tmp_z - y_tmp_z))";
 345                 if (n > 3) s += "+\n((x_tmp_w - y_tmp_w) * (x_tmp_w - y_tmp_w))";
 346             }
 347             final String str = "(float)Math.sqrt(" + s + ")";
 348             FuncImpl fimpl = new FuncImpl() {
 349                 public String toString(int i, List<Expr> params) {
 350                     return str;
 351                 }
 352             };
 353             declareFunction(fimpl, name, type, type);
 354         }
 355     }
 356 
 357     /**
 358      * Used to declare min/max functions of the following form:
 359      *   <ftype> name(<ftype> x, <ftype> y)
 360      *   <ftype> name(<ftype> x, float y)
 361      *
 362      * TODO: this is currently geared to simple functions like
 363      * min and max; we should make this more general...
 364      */
 365     private static void declareOverloadsMinMax(String name, final String pattern) {
 366         for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 367             // declare (vectype,vectype) variants
 368             final boolean useSuffix = (type != FLOAT);
 369             FuncImpl fimpl = new FuncImpl() {
 370                 public String toString(int i, List<Expr> params) {
 371                     String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
 372                     String s = pattern;
 373                     s = s.replace("$1", sfx);
 374                     s = s.replace("$2", sfx);
 375                     return s;
 376                 }
 377             };
 378             declareFunction(fimpl, name, type, type);
 379 
 380             if (type == FLOAT) {
 381                 continue;
 382             }
 383 
 384             // declare (vectype,float) variants
 385             fimpl = new FuncImpl() {
 386                 public String toString(int i, List<Expr> params) {
 387                     String sfx = JSWBackend.getSuffix(i);
 388                     String s = pattern;
 389                     s = s.replace("$1", sfx);
 390                     s = s.replace("$2", "");
 391                     return s;
 392                 }
 393             };
 394             declareFunction(fimpl, name, type, FLOAT);
 395         }
 396     }
 397 
 398     /**
 399      * Used to declare clamp functions of the following form:
 400      *   <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
 401      *   <ftype> clamp(<ftype> val, float min, float max)
 402      */
 403     private static void declareOverloadsClamp() {
 404         final String name = "clamp";
 405         final String pattern =
 406             "(val_tmp$1 < min_tmp$2) ? min_tmp$2 : \n" +
 407             "(val_tmp$1 > max_tmp$2) ? max_tmp$2 : val_tmp$1";
 408 
 409         for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 410             // declare (vectype,vectype,vectype) variants
 411             final boolean useSuffix = (type != FLOAT);
 412             FuncImpl fimpl = new FuncImpl() {
 413                 public String toString(int i, List<Expr> params) {
 414                     String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
 415                     String s = pattern;
 416                     s = s.replace("$1", sfx);
 417                     s = s.replace("$2", sfx);
 418                     return s;
 419                 }
 420             };
 421             declareFunction(fimpl, name, type, type, type);
 422 
 423             if (type == FLOAT) {
 424                 continue;
 425             }
 426 
 427             // declare (vectype,float,float) variants
 428             fimpl = new FuncImpl() {
 429                 public String toString(int i, List<Expr> params) {
 430                     String sfx = JSWBackend.getSuffix(i);
 431                     String s = pattern;
 432                     s = s.replace("$1", sfx);
 433                     s = s.replace("$2", "");
 434                     return s;
 435                 }
 436             };
 437             declareFunction(fimpl, name, type, FLOAT, FLOAT);
 438         }
 439     }
 440 
 441     /**
 442      * Used to declare smoothstep functions of the following form:
 443      *   <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
 444      *   <ftype> smoothstep(float min, float max, <ftype> val)
 445      */
 446     private static void declareOverloadsSmoothstep() {
 447         final String name = "smoothstep";
 448         // TODO - the smoothstep function is defined to use Hermite interpolation
 449         final String pattern =
 450             "(val_tmp$1 < min_tmp$2) ? 0.0f : \n" +
 451             "(val_tmp$1 > max_tmp$2) ? 1.0f : \n" +
 452             "(val_tmp$1 / (max_tmp$2 - min_tmp$2))";
 453 
 454         for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 455             // declare (vectype,vectype,vectype) variants
 456             final boolean useSuffix = (type != FLOAT);
 457             FuncImpl fimpl = new FuncImpl() {
 458                 public String toString(int i, List<Expr> params) {
 459                     String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
 460                     String s = pattern;
 461                     s = s.replace("$1", sfx);
 462                     s = s.replace("$2", sfx);
 463                     return s;
 464                 }
 465             };
 466             declareFunction(fimpl, name, type, type, type);
 467 
 468             if (type == FLOAT) {
 469                 continue;
 470             }
 471 
 472             // declare (float,float,vectype) variants
 473             fimpl = new FuncImpl() {
 474                 public String toString(int i, List<Expr> params) {
 475                     String sfx = JSWBackend.getSuffix(i);
 476                     String s = pattern;
 477                     s = s.replace("$1", sfx);
 478                     s = s.replace("$2", "");
 479                     return s;
 480                 }
 481             };
 482             declareFunction(fimpl, name, FLOAT, FLOAT, type);
 483         }
 484     }
 485 
 486     /**
 487      * Used to declare mix functions of the following form:
 488      *   <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
 489      *   <ftype> mix(<ftype> x, <ftype> y, float a)
 490      */
 491     private static void declareOverloadsMix() {
 492         final String name = "mix";
 493         final String pattern =
 494             "(x_tmp$1 * (1.0f - a_tmp$2) + y_tmp$1 * a_tmp$2)";
 495 
 496         for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
 497             // declare (vectype,vectype,vectype) variants
 498             final boolean useSuffix = (type != FLOAT);
 499             FuncImpl fimpl = new FuncImpl() {
 500                 public String toString(int i, List<Expr> params) {
 501                     String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
 502                     String s = pattern;
 503                     s = s.replace("$1", sfx);
 504                     s = s.replace("$2", sfx);
 505                     return s;
 506                 }
 507             };
 508             declareFunction(fimpl, name, type, type, type);
 509 
 510             if (type == FLOAT) {
 511                 continue;
 512             }
 513 
 514             // declare (vectype,vectype,float) variants
 515             fimpl = new FuncImpl() {
 516                 public String toString(int i, List<Expr> params) {
 517                     String sfx = JSWBackend.getSuffix(i);
 518                     String s = pattern;
 519                     s = s.replace("$1", sfx);
 520                     s = s.replace("$2", "");
 521                     return s;
 522                 }
 523             };
 524             declareFunction(fimpl, name, type, type, FLOAT);
 525         }
 526     }
 527 }