浏览代码

added Splitter, GlslOut working

Nicolas Cannasse 11 年之前
父节点
当前提交
566438ef4e
共有 9 个文件被更改,包括 266 次插入63 次删除
  1. 1 0
      hxsl/Ast.hx
  2. 6 2
      hxsl/Cache.hx
  3. 4 3
      hxsl/Checker.hx
  4. 8 22
      hxsl/Flatten.hx
  5. 37 23
      hxsl/GlslOut.hx
  6. 9 7
      hxsl/Linker.hx
  7. 2 0
      hxsl/Printer.hx
  8. 190 0
      hxsl/Splitter.hx
  9. 9 6
      test/Test.hx

+ 1 - 0
hxsl/Ast.hx

@@ -63,6 +63,7 @@ enum VarKind {
 	Param;
 	Var;
 	Local;
+	Output;
 	Function;
 }
 

+ 6 - 2
hxsl/Cache.hx

@@ -2,7 +2,7 @@ package hxsl;
 using hxsl.Ast;
 
 class SearchMap {
-	public var linked : ShaderData;
+	public var linked : { vertex : ShaderData, fragment : ShaderData };
 	public var next : Map<Int,SearchMap>;
 	public function new() {
 	}
@@ -55,8 +55,12 @@ class Cache {
 		}
 		if( c.linked != null )
 			return c.linked;
+			
 		var s = new hxsl.Linker().link([for( s in instances ) s.shader], this.outVars[outVars]);
-		s = new Flatten().flatten(s);
+		
+		var s = new hxsl.Splitter().split(s);
+		s.vertex = new Flatten().flatten(s.vertex, Vertex);
+		s.fragment = new Flatten().flatten(s.fragment, Fragment);
 		c.linked = s;
 		return c.linked;
 	}

+ 4 - 3
hxsl/Checker.hx

@@ -168,7 +168,7 @@ class Checker {
 		switch( e.e ) {
 		case TVar(v):
 			switch( v.kind ) {
-			case Var, Local:
+			case Local, Var, Output:
 				return;
 			default:
 			}
@@ -449,10 +449,11 @@ class Checker {
 		case EVars(vl):
 			for( v in vl ) {
 				if( v.kind == null ) {
-					v.kind = Var;
+					if( v.name == "output" ) v.kind = Output else v.kind = Local;
 					for( q in v.qualifiers )
 						switch( q ) {
 						case Const(_): v.kind = Param;
+						case Private: v.kind = Var;
 						default:
 						}
 				}
@@ -477,7 +478,7 @@ class Checker {
 			tv.parent = parent;
 		if( tv.kind == null ) {
 			if( parent == null )
-				tv.kind = Var;
+				tv.kind = Local;
 			else
 				tv.kind = parent.kind;
 		} else if( parent != null && tv.kind != parent.kind ) {

+ 8 - 22
hxsl/Flatten.hx

@@ -21,21 +21,24 @@ class Flatten {
 	var params : Array<TVar>;
 	var outVars : Array<TVar>;
 	var varMap : Map<TVar,Alloc>;
-	var varNames : Map<String,TVar>;
 	
 	public function new() {
 	}
 	
-	public function flatten( s : ShaderData ) : ShaderData {
+	public function flatten( s : ShaderData, kind : FunctionKind ) : ShaderData {
 		globals = [];
 		params = [];
 		outVars = [];
 		varMap = new Map();
-		varNames = new Map();
 		for( v in s.vars )
 			gatherVar(v);
-		pack("globals", Global, globals, VFloat);
-		pack("params", Param, params, VFloat);
+		var prefix = switch( kind ) {
+		case Vertex: "vertex";
+		case Fragment: "fragment";
+		default: throw "assert";
+		}
+		pack(prefix+"Globals", Global, globals, VFloat);
+		pack(prefix+"Params", Param, params, VFloat);
 		return {
 			name : s.name,
 			vars : outVars,
@@ -57,9 +60,6 @@ class Flatten {
 				e
 			else
 				access(a, v.type, e.p);
-		case TVarDecl(v, _):
-			uniqueVar(v);
-			e.map(mapExpr);
 		default:
 			e.map(mapExpr);
 		};
@@ -198,26 +198,12 @@ class Flatten {
 		}
 	}
 	
-	function uniqueVar( v : TVar ) {
-		var v2 = varNames.get(v.name);
-		if( v2 == v ) return;
-		if( v2 == null ) {
-			varNames.set(v.name, v);
-			return;
-		}
-		var k = 2;
-		while( varNames.exists(v.name + k) ) k++;
-		v.name += k;
-		varNames.set(v.name, v);
-	}
-	
 	function gatherVar( v : TVar ) {
 		switch( v.type ) {
 		case TStruct(vl):
 			for( v in vl )
 				gatherVar(v);
 		default:
-			uniqueVar(v);
 			switch( v.kind ) {
 			case Global:
 				if( v.hasQualifier(PerObject) )

+ 37 - 23
hxsl/GlslOut.hx

@@ -7,6 +7,7 @@ class GlslOut {
 	var prec : String;
 	var keywords : Map<String,Bool>;
 	var exprValues : Array<String>;
+	var locals : Array<TVar>;
 	var globalNames : Map<TGlobal,String>;
 	
 	public function new() {
@@ -19,13 +20,6 @@ class GlslOut {
 		}
 	}
 	
-	public function run( s : ShaderData ) : { vertex : String, fragment : String } {
-		return {
-			vertex : make(s, "vertex"),
-			fragment : make(s,"fragment"),
-		};
-	}
-	
 	inline function add( v : Dynamic ) {
 		buf.add(v);
 	}
@@ -177,7 +171,9 @@ class GlslOut {
 				add(")");
 			default:
 				addValue(e1, tabs);
+				add(" ");
 				add(Printer.opStr(op));
+				add(" ");
 				addValue(e2, tabs);
 			}
 		case TUnop(op, e1):
@@ -190,10 +186,13 @@ class GlslOut {
 			});
 			addValue(e1, tabs);
 		case TVarDecl(v, init):
-			addVar(v);
+			locals.push(v);
 			if( init != null ) {
+				ident(v.name);
 				add(" = ");
 				addValue(init, tabs);
+			} else {
+				add("/*var*/");
 			}
 		case TCall(e, args):
 			addValue(e, tabs);
@@ -254,45 +253,60 @@ class GlslOut {
 		}
 	}
 	
-	function make( s : ShaderData, func : String ) {
+	public function run( s : ShaderData ) {
+		locals = [];
 		prec = "mediump ";
 		buf = new StringBuf();
 		exprValues = [];
 		add("struct mat3x4 { "+prec+"vec4 a; "+prec+"vec4 b; "+prec+"vec4 c; };\n");
 		add(prec+"vec3 m3x4mult( mat3x4 m, "+prec+"vec3 v ) { "+prec+"vec4 ve = vec4(v,1.0); return vec3(dot(m.a,ve),dot(m.b,ve),dot(m.c,ve)); }\n");
+
+		if( s.funs.length != 1 ) throw "assert";
+		var f = s.funs[0];
+		
 		for( v in s.vars ) {
 			switch( v.kind ) {
 			case Param, Global:
 				add("uniform ");
 			case Input:
-				if( func == "fragment" ) continue;
 				add("attribute ");
 			case Var:
 				add("varying ");
 			case Function: continue;
-			case Local: throw "assert";
+			case Output:
+				switch( f.kind ) {
+				case Vertex:
+					v.name = "gl_Position";
+				case Fragment:
+					v.name = "gl_FragColor";
+				default:
+					throw "assert";
+				}
+				continue;
+			case Local:
 			}
 			addVar(v);
 			add(";\n");
 		}
 		add("\n");
-		var found = false;
-		for( f in s.funs ) {
-			if( f.ref.name == func ) {
-				var tmp = buf;
-				buf = new StringBuf();
-				found = true;
-				add("void main(void) ");
-				addExpr(f.expr, "");
-				exprValues.push(buf.toString());
-				buf = tmp;
-			}
+		
+		var tmp = buf;
+		buf = new StringBuf();
+		add("void main(void) ");
+		addExpr(f.expr, "");
+		exprValues.push(buf.toString());
+		buf = tmp;
+		
+		for( v in locals ) {
+			addVar(v);
+			add(";\n");
 		}
+		add("\n");
+
 		for( e in exprValues ) {
 			add(e);
 			add("\n\n");
 		}
-		if( !found ) throw func + " not found in shader";
 		var content = buf.toString();
 		buf = null;
 		return content;

+ 9 - 7
hxsl/Linker.hx

@@ -41,6 +41,7 @@ class Linker {
 	var curShader : ShaderInfos;
 	var shaders : Array<ShaderInfos>;
 	var varIdMap : Map<Int,Int>;
+	var locals : Map<Int,Bool>;
 	
 	public function new() {
 	}
@@ -51,9 +52,9 @@ class Linker {
 	
 	function mergeVar( path : String, v : TVar, v2 : TVar, p : Position ) {
 		switch( v.kind ) {
-		case Global, Input, Var:
+		case Global, Input, Var, Local, Output:
 			// shared vars
-		case Local, Param, Function:
+		case Param, Function:
 			throw "assert";
 		}
 		if( v.kind != v2.kind )
@@ -80,8 +81,6 @@ class Linker {
 	}
 	
 	function allocVar( v : TVar, p : Position, ?path : String, ?parent : TVar ) : AllocatedVar {
-		if( v.kind == Local )
-			throw "assert";
 		if( v.parent != null && parent == null ) {
 			parent = allocVar(v.parent, p).v;
 			var p = parent;
@@ -175,7 +174,7 @@ class Linker {
 	
 	function mapExprVar( e : TExpr ) {
 		switch( e.e ) {
-		case TVar(v) if( v.kind != Local ):
+		case TVar(v) if( !locals.exists(v.id) ):
 			var v = allocVar(v, e.p);
 			if( curShader != null ) {
 				//trace(curShader.name + " read " + v.path);
@@ -184,7 +183,7 @@ class Linker {
 			return { e : TVar(v.v), t : v.v.type, p : e.p };
 		case TBinop(op, e1, e2):
 			switch( [op,e1.e] ) {
-			case [OpAssign | OpAssignOp(_), (TVar(v) | TSwiz({ e : TVar(v) },_))] if( v.kind != Local ):
+			case [OpAssign | OpAssignOp(_), (TVar(v) | TSwiz({ e : TVar(v) },_))] if( !locals.exists(v.id) ):
 				var v = allocVar(v, e1.p);
 				if( curShader != null ) {
 					//trace(curShader.name + " write " + v.path);
@@ -197,6 +196,8 @@ class Linker {
 				}
 			default:
 			}
+		case TVarDecl(v, _):
+			locals.set(v.id, true);
 		default:
 		}
 		return e.map(mapExprVar);
@@ -257,6 +258,7 @@ class Linker {
 		varIdMap = new Map();
 		allVars = new Array();
 		shaders = [];
+		locals = new Map();
 		
 		// globalize vars
 		for( s in shadersData ) {
@@ -376,7 +378,7 @@ class Linker {
 				ref : v,
 				ret : TVoid,
 				args : [],
-				expr : { e : TBlock(exprs), t : TVoid, p : exprs[0].p },
+				expr : { e : TBlock(exprs), t : TVoid, p : exprs.length == 0 ? null : exprs[0].p },
 			};
 		}
 		var funs = [

+ 2 - 0
hxsl/Printer.hx

@@ -72,6 +72,8 @@ class Printer {
 				add("@input ");
 			case Function:
 				add("@function ");
+			case Output:
+				add("@output ");
 			}
 		add("var " + v.name + (varId?"@" + v.id:"") + " : ");
 		switch( v.type ) {

+ 190 - 0
hxsl/Splitter.hx

@@ -0,0 +1,190 @@
+package hxsl;
+using hxsl.Ast;
+
+private typedef VarProps = {
+	var v : TVar;
+	var read : Int;
+	var write : Int;
+	var local : Bool;
+}
+
+class Splitter {
+
+	var vars : Map<Int,VarProps>;
+	var varNames : Map<String,TVar>;
+	var varMap : Map<TVar,TVar>;
+	
+	public function new() {
+	}
+	
+	public function split( s : ShaderData ) : { vertex : ShaderData, fragment : ShaderData } {
+		var vfun = null, vvars = new Map();
+		var ffun = null, fvars = new Map();
+		varNames = new Map();
+		for( f in s.funs )
+			switch( f.kind ) {
+			case Vertex:
+				vars = vvars;
+				vfun = f;
+				checkExpr(f.expr);
+			case Fragment:
+				vars = fvars;
+				ffun = f;
+				checkExpr(f.expr);
+			default:
+				throw "assert";
+			}
+		varMap = new Map();
+		for( inf in vvars ) {
+			var v = inf.v;
+			switch( v.kind ) {
+			case Var, Local:
+				v.kind = fvars.exists(v.id) ? Var : Local;
+			default:
+			}
+			switch( v.kind ) {
+			case Var, Output:
+				// alloc a new var if read or multiple writes
+				if( inf.read > 0 || inf.write > 1 ) {
+					var nv = {
+						id : Tools.allocVarId(),
+						name : v.name,
+						kind : v.kind,
+						type : v.type,
+					};
+					vars = vvars;
+					var ninf = get(nv);
+					v.kind = Local;
+					var p = vfun.expr.p;
+					addExpr(vfun, { e : TBinop(OpAssign, { e : TVar(nv), t : nv.type, p : p }, { e : TVar(v), t : v.type, p : p } ), t : nv.type, p : p });
+					if( nv.kind == Var ) {
+						var old = fvars.get(v.id);
+						varMap.set(v, nv);
+						fvars.remove(v.id);
+						fvars.set(nv.id, { v : nv, read : old.read, write : old.write, local : false });
+					}
+				}
+			default:
+			}
+		}
+		var finits = [];
+		for( inf in fvars ) {
+			var v = inf.v;
+			switch( v.kind ) {
+			case Input:
+				// create a var that will pass the input from vertex to fragment
+				throw "TODO";
+			case Var if( inf.write > 0 ):
+				var nv = {
+					id : Tools.allocVarId(),
+					name : v.name,
+					kind : Local,
+					type : v.type,
+				};
+				uniqueName(nv);
+				finits.push( { e : TVarDecl(nv, { e : TVar(v), t : v.type, p : ffun.expr.p } ), t:TVoid, p:ffun.expr.p } );
+				varMap.set(v, nv);
+			default:
+			}
+		}
+		// support for double mapping v -> v1 -> v2
+		for( v in varMap.keys() ) {
+			var v2 = varMap.get(varMap.get(v));
+			if( v2 != null )
+				varMap.set(v, v2);
+		}
+		ffun = {
+			ret : ffun.ret,
+			ref : ffun.ref,
+			kind : ffun.kind,
+			args : ffun.args,
+			expr : mapVars(ffun.expr),
+		};
+		switch( ffun.expr.e ) {
+		case TBlock(el):
+			for( e in finits )
+				el.unshift(e);
+		default:
+			finits.push(ffun.expr);
+			ffun.expr = { e : TBlock(finits), t : TVoid, p : ffun.expr.p };
+		}
+		return {
+			vertex : {
+				name : "vertex",
+				vars : [for( v in vvars ) if( !v.local ) v.v],
+				funs : [vfun],
+			},
+			fragment : {
+				name : "fragment",
+				vars : [for( v in fvars ) if( !v.local ) v.v],
+				funs : [ffun],
+			},
+		};
+	}
+	
+	function addExpr( f : TFunction, e : TExpr ) {
+		switch( f.expr.e ) {
+		case TBlock(el):
+			el.push(e);
+		default:
+			f.expr = { e : TBlock([f.expr, e]), t : TVoid, p : f.expr.p };
+		}
+	}
+	
+	function mapVars( e : TExpr ) {
+		return switch( e.e ) {
+		case TVar(v):
+			var v2 = varMap.get(v);
+			v2 == null ? e : { e : TVar(v2), t : e.t, p : e.p };
+		default:
+			e.map(mapVars);
+		}
+	}
+	
+	function get( v : TVar ) {
+		var i = vars.get(v.id);
+		if( i == null ) {
+			i = { v : v, read : 0, write : 0, local : false };
+			vars.set(v.id, i);
+			uniqueName(v);
+		}
+		return i;
+	}
+	
+	function uniqueName( v : TVar ) {
+		v.parent = null;
+		var n = varNames.get(v.name);
+		if( n != null && n != v ) {
+			var k = 2;
+			while( varNames.exists(v.name + k) ) {
+				k++;
+			}
+			v.name += k;
+		}
+		varNames.set(v.name, v);
+	}
+	
+	function checkExpr( e : TExpr ) {
+		switch( e.e ) {
+		case TVar(v):
+			var inf = get(v);
+			inf.read++;
+		case TBinop(OpAssign, { e : (TVar(v) | TSwiz( { e : TVar(v) }, _)) }, e):
+			var inf = get(v);
+			inf.write++;
+			checkExpr(e);
+		case TBinop(OpAssignOp(_), { e : (TVar(v) | TSwiz( { e : TVar(v) }, _)) }, e):
+			var inf = get(v);
+			inf.read++;
+			inf.write++;
+			checkExpr(e);
+		case TVarDecl(v, init):
+			var inf = get(v);
+			inf.local = true;
+			if( init != null ) checkExpr(init);
+		default:
+			e.iter(checkExpr);
+		}
+	}
+	
+}

+ 9 - 6
test/Test.hx

@@ -350,18 +350,19 @@ class Test {
 		var instances = [for( s in shaders ) { s.updateConstants(globals); s.instance; }];
 		var cache = hxsl.Cache.get();
 		var s = cache.link(instances, cache.allocOutputVars(["output.position", "output.color"]));
-		//trace("\n" + hxsl.Printer.shaderToString(s));
+		//trace("VERTEX=\n" + hxsl.Printer.shaderToString(s.vertex));
+		//trace("FRAGMENT=\n" + hxsl.Printer.shaderToString(s.fragment));
+		
 		#if js
 		haxe.Log.trace("START");
 		try {
 		
-		var glSrc = hxsl.GlslOut.toGlsl(s);
-		
 		var canvas = js.Browser.document.createCanvasElement();
 		var gl = canvas.getContextWebGL();
 		var GL = js.html.webgl.GL;
 		
-		function compile(kind, code) {
+		function compile(kind, shader) {
+			var code = hxsl.GlslOut.toGlsl(shader);
 			trace(code);
 			var s = gl.createShader(kind);
 			gl.shaderSource(s, code);
@@ -375,8 +376,8 @@ class Test {
 			return s;
 		}
 			
-		var vs = compile(GL.VERTEX_SHADER, glSrc.vertex);
-		var fs = compile(GL.FRAGMENT_SHADER, glSrc.fragment);
+		var vs = compile(GL.VERTEX_SHADER, s.vertex);
+		var fs = compile(GL.FRAGMENT_SHADER, s.fragment);
 		
 		var p = gl.createProgram();
 		gl.attachShader(p, vs);
@@ -387,6 +388,8 @@ class Test {
 			throw "Program linkage failure: "+log;
 		}
 		
+		trace("LINK SUCCESS");
+		
 		} catch( e : Dynamic ) {
 			trace(e);
 		}