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.hw;
  27 
  28 import java.util.HashMap;
  29 import java.util.Map;
  30 import com.sun.scenario.effect.compiler.JSLParser;
  31 import com.sun.scenario.effect.compiler.model.BaseType;
  32 import com.sun.scenario.effect.compiler.model.Function;
  33 import com.sun.scenario.effect.compiler.model.Qualifier;
  34 import com.sun.scenario.effect.compiler.model.Type;
  35 import com.sun.scenario.effect.compiler.model.Variable;
  36 import com.sun.scenario.effect.compiler.tree.Expr;
  37 import com.sun.scenario.effect.compiler.tree.FuncDef;
  38 import com.sun.scenario.effect.compiler.tree.ProgramUnit;
  39 import com.sun.scenario.effect.compiler.tree.VarDecl;
  40 
  41 /**
  42  */
  43 public class HLSLBackend extends SLBackend {
  44 
  45     public HLSLBackend(JSLParser parser, ProgramUnit program) {
  46         super(parser, program);
  47     }
  48 
  49     private static final Map<String, String> qualMap = new HashMap<String, String>();
  50     static {
  51         qualMap.put("const", "");
  52         qualMap.put("param", "");
  53     }
  54 
  55     private static final Map<String, String> typeMap = new HashMap<String, String>();
  56     static {
  57         typeMap.put("void",    "void");
  58         typeMap.put("float",   "float");
  59         typeMap.put("float2",  "float2");
  60         typeMap.put("float3",  "float3");
  61         typeMap.put("float4",  "float4");
  62         typeMap.put("int",     "int");
  63         typeMap.put("int2",    "int2");
  64         typeMap.put("int3",    "int3");
  65         typeMap.put("int4",    "int4");
  66         typeMap.put("bool",    "bool");
  67         typeMap.put("bool2",   "bool2");
  68         typeMap.put("bool3",   "bool3");
  69         typeMap.put("bool4",   "bool4");
  70         typeMap.put("sampler", "sampler2D");
  71         typeMap.put("lsampler","sampler2D");
  72         typeMap.put("fsampler","sampler2D");
  73     }
  74 
  75     private static final Map<String, String> varMap = new HashMap<String, String>();
  76     static {
  77     }
  78 
  79     private static final Map<String, String> funcMap = new HashMap<String, String>();
  80     static {
  81         funcMap.put("sample", "tex2D");
  82         funcMap.put("fract", "frac");
  83         funcMap.put("mix", "lerp");
  84         funcMap.put("mod", "fmod");
  85         funcMap.put("intcast", "int");
  86         funcMap.put("any", "any");
  87         funcMap.put("length", "length");
  88     }
  89 
  90     @Override
  91     protected String getType(Type t) {
  92         return typeMap.get(t.toString());
  93     }
  94 
  95     @Override
  96     protected String getQualifier(Qualifier q) {
  97         return qualMap.get(q.toString());
  98     }
  99 
 100     @Override
 101     protected String getVar(String v) {
 102         String s = varMap.get(v);
 103         return (s != null) ? s : v;
 104     }
 105 
 106     @Override
 107     protected String getFuncName(String f) {
 108         String s = funcMap.get(f);
 109         return (s != null) ? s : f;
 110     }
 111 
 112     @Override
 113     public void visitFuncDef(FuncDef d) {
 114         Function func = d.getFunction();
 115         if (func.getName().equals("main")) {
 116             output(getType(func.getReturnType()) + " " + func.getName() + "(");
 117             // TODO: it would be better if we scanned the whole JSL program
 118             // to see if pos0 or pos1 are used anywhere, but for now there
 119             // doesn't seem to be any harm in blindly declaring both here...
 120             for (int i = 0; i < 2; i++) {
 121                 output("in float2 pos" + i + " : TEXCOORD" + i + ",\n");
 122             }
 123             // TODO: only need this if pixcoord is referenced somewhere
 124             // in the JSL program...
 125             output("in float2 pixcoord : VPOS,\n");
 126             output("in float4 jsl_vertexColor : COLOR0,\n");
 127             output("out float4 color : COLOR0");
 128             output(") ");
 129             scan(d.getStmt());
 130         } else {
 131             super.visitFuncDef(d);
 132         }
 133     }
 134 
 135     @Override
 136     public void visitVarDecl(VarDecl d) {
 137         Variable var = d.getVariable();
 138         Type type = var.getType();
 139         Qualifier qual = var.getQualifier();
 140         if (qual == Qualifier.PARAM && type.getBaseType() == BaseType.INT) {
 141             // TODO: It seems that constant integer registers have limitations
 142             // in SM 3.0... For example, the max number of integer registers
 143             // (those specified with i#) is 16; in PS 2.0 these were limited
 144             // to flow control instructions only, but according to MSDN this
 145             // restriction went away with PS 3.0.  However, bad things happen
 146             // at runtime if we output:
 147             //     int variableName : register(c0);
 148             // (not sure what the problem is, but bad values seem to be
 149             // uploaded if we use SetPixelShaderConstantI() in this case), and
 150             // if we use i# instead:
 151             //     int variableName : register(i0);
 152             // the compiler will say this is invalid (it won't complain if
 153             // we actually used it in a loop expression though).  Until this
 154             // problem is better understood, we can work around it by
 155             // declaring these params as float variants, e.g.:
 156             //     float variableName : register(c0);
 157             // and using SetPixelShaderConstantF() instead.
 158             String t;
 159             switch (type) {
 160             case INT:
 161                 t = "float";
 162                 break;
 163             case INT2:
 164                 t = "float2";
 165                 break;
 166             case INT3:
 167                 t = "float3";
 168                 break;
 169             case INT4:
 170                 t = "float4";
 171                 break;
 172             default:
 173                 throw new InternalError();
 174             }
 175             output(t + " " + var.getName());
 176         } else if (qual == Qualifier.CONST) {
 177             // use #define-style definition
 178             output("#define " + var.getName());
 179         } else {
 180             output(getType(type) + " " + var.getName());
 181         }
 182         Expr init = d.getInit();
 183         if (init != null) {
 184             if (qual == Qualifier.CONST) {
 185                 // use #define-style definition (no '=', wrap in
 186                 // parens for safety)
 187                 output(" (");
 188                 scan(init);
 189                 output(")");
 190             } else {
 191                 output(" = ");
 192                 scan(init);
 193             }
 194         }
 195         if (var.isArray()) {
 196             output("[" + var.getArraySize() + "]");
 197         }
 198         if (qual == Qualifier.PARAM) {
 199             char c = (type.getBaseType() == BaseType.SAMPLER) ? 's' : 'c';
 200             output(" : register(" + c + var.getReg() + ")");
 201         }
 202         if (qual == Qualifier.CONST) {
 203             // use #define-style definition (no closing ';')
 204             output("\n");
 205         } else {
 206             output(";\n");
 207         }
 208     }
 209 }