--- /dev/null 2016-09-01 15:38:59.076007815 -0400 +++ new/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/hw/SLBackend.java 2016-09-11 10:35:49.784367683 -0400 @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.scenario.effect.compiler.backend.hw; + +import com.sun.scenario.effect.compiler.JSLParser; +import com.sun.scenario.effect.compiler.model.BinaryOpType; +import com.sun.scenario.effect.compiler.model.Function; +import com.sun.scenario.effect.compiler.model.Param; +import com.sun.scenario.effect.compiler.model.Precision; +import com.sun.scenario.effect.compiler.model.Qualifier; +import com.sun.scenario.effect.compiler.model.Type; +import com.sun.scenario.effect.compiler.model.Variable; +import com.sun.scenario.effect.compiler.tree.ArrayAccessExpr; +import com.sun.scenario.effect.compiler.tree.BinaryExpr; +import com.sun.scenario.effect.compiler.tree.BreakStmt; +import com.sun.scenario.effect.compiler.tree.CallExpr; +import com.sun.scenario.effect.compiler.tree.CompoundStmt; +import com.sun.scenario.effect.compiler.tree.ContinueStmt; +import com.sun.scenario.effect.compiler.tree.DeclStmt; +import com.sun.scenario.effect.compiler.tree.DiscardStmt; +import com.sun.scenario.effect.compiler.tree.DoWhileStmt; +import com.sun.scenario.effect.compiler.tree.Expr; +import com.sun.scenario.effect.compiler.tree.ExprStmt; +import com.sun.scenario.effect.compiler.tree.FieldSelectExpr; +import com.sun.scenario.effect.compiler.tree.ForStmt; +import com.sun.scenario.effect.compiler.tree.FuncDef; +import com.sun.scenario.effect.compiler.tree.LiteralExpr; +import com.sun.scenario.effect.compiler.tree.ParenExpr; +import com.sun.scenario.effect.compiler.tree.ProgramUnit; +import com.sun.scenario.effect.compiler.tree.ReturnStmt; +import com.sun.scenario.effect.compiler.tree.SelectStmt; +import com.sun.scenario.effect.compiler.tree.Stmt; +import com.sun.scenario.effect.compiler.tree.TreeScanner; +import com.sun.scenario.effect.compiler.tree.UnaryExpr; +import com.sun.scenario.effect.compiler.tree.VarDecl; +import com.sun.scenario.effect.compiler.tree.VariableExpr; +import com.sun.scenario.effect.compiler.tree.VectorCtorExpr; +import com.sun.scenario.effect.compiler.tree.WhileStmt; + +/** + */ +public abstract class SLBackend extends TreeScanner { + + private JSLParser parser; + private StringBuilder sb = new StringBuilder(); + private Variable unrollVar = null; + private int unrollIndex = -1; + protected boolean isPixcoordReferenced; + protected boolean isVertexColorReferenced; + protected int maxTexCoordIndex = -1; + + protected SLBackend(JSLParser parser, ProgramUnit program) { + this.parser = parser; + scan(program); + } + + protected final void output(String s) { + sb.append(s); + } + + public final String getShader() { + return getHeader() + sb.toString(); + } + + protected final JSLParser getParser() { + return parser; + } + + /** + * Returns the String that will be included at the top of the resulting + * shader code. This method is called after the entire program has been + * scanned, so it provides a way for a subclass to customize the header + * (for example, to include declarations for "special" variables such + * as pos1 based on whether they were referenced somewhere in the JSL + * code). The default implementation returns an empty string, but + * subclasses may override this to provide different behavior. + */ + protected String getHeader() { + return ""; + } + + protected String getPrecision(Precision p) { + return null; + } + + protected abstract String getType(Type t); + + protected abstract String getQualifier(Qualifier q); + + protected abstract String getVar(String v); + + protected abstract String getFuncName(String f); + + @Override + public void visitArrayAccessExpr(ArrayAccessExpr e) { + scan(e.getExpr()); + output("["); + boolean needsScan = true; + if (unrollVar != null) { + // TODO: this is flimsy... + if (e.getIndex() instanceof VariableExpr) { + VariableExpr vexpr = (VariableExpr)e.getIndex(); + if (vexpr.getVariable() == unrollVar) { + output("" + unrollIndex); + needsScan = false; + } + } + } + if (needsScan) { + scan(e.getIndex()); + } + output("]"); + } + + @Override + public void visitBinaryExpr(BinaryExpr e) { + scan(e.getLeft()); + output(" " + e.getOp() + " "); + scan(e.getRight()); + } + + @Override + public void visitBreakStmt(BreakStmt s) { + output("break;"); + } + + @Override + public void visitCallExpr(CallExpr e) { + output(getFuncName(e.getFunction().getName()) + "("); + boolean first = true; + for (Expr param : e.getParams()) { + if (first) { + first = false; + } else { + output(", "); + } + scan(param); + } + output(")"); + } + + @Override + public void visitCompoundStmt(CompoundStmt s) { + output("{\n"); + super.visitCompoundStmt(s); + output("}\n"); + } + + @Override + public void visitContinueStmt(ContinueStmt s) { + output("continue;"); + } + + @Override + public void visitDeclStmt(DeclStmt s) { + super.visitDeclStmt(s); + } + + @Override + public void visitDiscardStmt(DiscardStmt s) { + output("discard;"); + } + + @Override + public void visitDoWhileStmt(DoWhileStmt s) { + output("do "); + scan(s.getStmt()); + output(" while ("); + scan(s.getExpr()); + output(");"); + } + + @Override + public void visitExprStmt(ExprStmt s) { + scan(s.getExpr()); + output(";\n"); + } + + @Override + public void visitFieldSelectExpr(FieldSelectExpr e) { + scan(e.getExpr()); + output("." + e.getFields()); + } + + @Override + public void visitForStmt(ForStmt s) { + boolean unroll = s.getUnrollMax() > 0; + if (unroll) { + if (unrollVar != null) { + throw new RuntimeException("Unrolling of nested 'for' loops not yet supported"); + } + + // TODO: This is very flimsy code; to make this work for real we + // will need much more validation of conditions, etc... + String maxName = null; + Expr cond = s.getCondition(); + if (cond instanceof BinaryExpr) { + BinaryExpr bcond = (BinaryExpr)cond; + if (bcond.getOp() != BinaryOpType.LT) { + throw new RuntimeException("Condition must be '<' in order to unroll 'for' loop (for now)"); + } + Expr left = bcond.getLeft(); + if (left instanceof VariableExpr) { + VariableExpr vexpr = (VariableExpr)left; + Variable var = vexpr.getVariable(); + if (var.getType() != Type.INT) { + throw new RuntimeException("Condition LHS must be integer variable in order to unroll 'for' loop (for now)"); + } + unrollVar = var; + } else { + throw new RuntimeException("Condition LHS must be integer variable in order to unroll 'for' loop (for now)"); + } + Expr right = bcond.getRight(); + if (right instanceof VariableExpr) { + VariableExpr vexpr = (VariableExpr)right; + Variable var = vexpr.getVariable(); + maxName = var.getName(); + } else if (s.getUnrollCheck() > 0) { + throw new RuntimeException("Condition RHS must be variable in order to unroll 'for' loop"); + } + // TODO: verify that last expression is postfix-increment + } else { + throw new RuntimeException("Invalid unrollable 'for' loop condition"); + } + int max = s.getUnrollMax(); + int check = max - s.getUnrollCheck(); + for (int i = 0; i < s.getUnrollMax(); i++) { + if (i >= check) { + output("if (" + i + " < " + maxName + ")\n"); + } + unrollIndex = i; + scan(s.getStmt()); + } + unrollVar = null; + unrollIndex = -1; + } else { + output("for ("); + scan(s.getInit()); + scan(s.getCondition()); + output(";"); + scan(s.getExpr()); + output(")"); + scan(s.getStmt()); + } + } + + @Override + public void visitFuncDef(FuncDef d) { + Function func = d.getFunction(); + output(getType(func.getReturnType()) + " " + func.getName() + "("); + boolean first = true; + for (Param param : func.getParams()) { + if (first) { + first = false; + } else { + output(", "); + } + output(getType(param.getType()) + " " + param.getName()); + } + output(") "); + scan(d.getStmt()); + } + + @Override + public void visitLiteralExpr(LiteralExpr e) { + output(e.getValue().toString()); + } + + @Override + public void visitParenExpr(ParenExpr e) { + output("("); + scan(e.getExpr()); + output(")"); + } + + @Override + public void visitProgramUnit(ProgramUnit p) { + super.visitProgramUnit(p); + } + + @Override + public void visitReturnStmt(ReturnStmt s) { + output("return"); + Expr ret = s.getExpr(); + if (ret != null) { + output(" "); + scan(s.getExpr()); + } + output(";\n"); + } + + @Override + public void visitSelectStmt(SelectStmt s) { + output("if ("); + scan(s.getIfExpr()); + output(")"); + scan(s.getThenStmt()); + Stmt e = s.getElseStmt(); + if (e != null) { + output(" else "); + scan(e); + } + } + + @Override + public void visitUnaryExpr(UnaryExpr e) { + output(e.getOp().toString()); + scan(e.getExpr()); + } + + @Override + public void visitVarDecl(VarDecl d) { + Variable var = d.getVariable(); + Qualifier qual = var.getQualifier(); + if (qual != null) { + output(getQualifier(qual) + " "); + } + Precision precision = var.getPrecision(); + if (precision != null) { + String precisionStr = getPrecision(precision); + if (precisionStr != null) { + output(precisionStr + " "); + } + } + output(getType(var.getType()) + " " + var.getName()); + if (var.isArray()) { + output("[" + var.getArraySize() + "]"); + } + Expr init = d.getInit(); + if (init != null) { + output(" = "); + scan(init); + } + output(";\n"); + } + + @Override + public void visitVariableExpr(VariableExpr e) { + String varName = e.getVariable().getName(); + if (varName.equals("pixcoord")) { + isPixcoordReferenced = true; + } else if (varName.equals("pos0")) { + maxTexCoordIndex = Math.max(maxTexCoordIndex, 0); + } else if (varName.equals("pos1")) { + maxTexCoordIndex = Math.max(maxTexCoordIndex, 1); + } else if (varName.equals("jsl_vertexColor")) { + isVertexColorReferenced = true; + } + output(getVar(varName)); + } + + @Override + public void visitVectorCtorExpr(VectorCtorExpr e) { + output(getType(e.getType())); + output("("); + boolean first = true; + for (Expr param : e.getParams()) { + if (first) { + first = false; + } else { + output(", "); + } + scan(param); + } + output(")"); + } + + @Override + public void visitWhileStmt(WhileStmt s) { + output("while ("); + scan(s.getCondition()); + output(")"); + scan(s.getStmt()); + } +}