Parcourir la source

fixed issue with same shader being applied twice

Nicolas Cannasse il y a 11 ans
Parent
commit
33788b477f
2 fichiers modifiés avec 119 ajouts et 1 suppressions
  1. 79 0
      hxsl/Clone.hx
  2. 40 1
      hxsl/Linker.hx

+ 79 - 0
hxsl/Clone.hx

@@ -0,0 +1,79 @@
+package hxsl;
+using hxsl.Ast;
+
+class Clone {
+
+	public var varMap : Map<Int,TVar>;
+	
+	public function new() {
+		varMap = new Map();
+	}
+	
+	public function tvar( v : TVar ) : TVar {
+		var v2 = varMap.get(v.id);
+		if( v2 != null ) return v2;
+		v2 = {
+			id : Tools.allocVarId(),
+			type : v.type,
+			name : v.name,
+			kind : v.kind,
+		};
+		varMap.set(v.id, v2);
+		if( v.parent != null ) v2.parent = tvar(v.parent);
+		if( v.qualifiers != null ) v2.qualifiers = v.qualifiers.copy();
+		v2.type = ttype(v.type);
+		return v2;
+	}
+	
+	public function tfun( f : TFunction ) : TFunction {
+		return {
+			ret : ttype(f.ret),
+			kind : f.kind,
+			ref : tvar(f.ref),
+			args : [for( a in f.args ) tvar(a)],
+			expr : texpr(f.expr),
+		};
+	}
+	
+	public function ttype( t : Type ) {
+		switch( t ) {
+		case TStruct(vl):
+			return TStruct([for( v in vl ) tvar(v)]);
+		case TArray(t, size):
+			return TArray(ttype(t), switch( size ) { case SConst(_): size; case SVar(v): SVar(tvar(v)); } );
+		case TFun(vars):
+			return TFun([for( v in vars ) { args : [for( a in v.args ) { name : a.name, type : ttype(a.type) } ], ret : ttype(v.ret) }]);
+		default:
+			return t;
+		}
+	}
+	
+	public function texpr( e : TExpr ) : TExpr {
+		var e2 : TExpr = e.map(texpr);
+		e2.t = ttype(e.t);
+		e2.e = switch( e2.e ) {
+		case TVar(v):
+			TVar(tvar(v));
+		case TVarDecl(v, init):
+			TVarDecl(tvar(v), init);
+		case TFor(v, it, loop):
+			TFor(tvar(v), it, loop);
+		default:
+			e2.e;
+		}
+		return e2;
+	}
+	
+	public function shader( s : ShaderData ) : ShaderData {
+		return {
+			name : s.name,
+			vars : [for( v in s.vars ) tvar(v)],
+			funs : [for( f in s.funs ) tfun(f)],
+		};
+	}
+	
+	public static function shaderData( s : ShaderData ) {
+		return new Clone().shader(s);
+	}
+	
+}

+ 40 - 1
hxsl/Linker.hx

@@ -233,6 +233,25 @@ class Linker {
 		cur.onStack = false;
 	}
 	
+	function uniqueLocals( expr : TExpr, locals : Map < String, Bool > ) {
+		switch( expr.e ) {
+		case TVarDecl(v, _):
+			if( locals.exists(v.name) ) {
+				var k = 2;
+				while( locals.exists(v.name + k) )
+					k++;
+				v.name += k;
+			}
+			locals.set(v.name, true);
+		case TBlock(el):
+			var locals = [for( k in locals.keys() ) k => true];
+			for( e in el )
+				uniqueLocals(e, locals);
+		default:
+			expr.iter(uniqueLocals.bind(_, locals));
+		}
+	}
+	
 	public function link( shadersData : Array<ShaderData>, outVars : Array<String> ) : ShaderData {
 		varMap = new Map();
 		varIdMap = new Map();
@@ -240,6 +259,15 @@ class Linker {
 		shaders = [];
 		locals = new Map();
 		
+		var dupShaders = new Map();
+		shadersData = [for( s in shadersData ) {
+			var s = s, sreal = s;
+			if( dupShaders.exists(s) )
+				s = Clone.shaderData(s);
+			dupShaders.set(s, sreal);
+			s;
+		}];
+		
 		// globalize vars
 		curInstance = 0;
 		for( s in shadersData ) {
@@ -355,18 +383,29 @@ class Linker {
 				default:
 					exprs.push(s.body);
 				}
+			var expr = { e : TBlock(exprs), t : TVoid, p : exprs.length == 0 ? null : exprs[0].p };
+			uniqueLocals(expr, new Map());
 			return {
 				kind : kind,
 				ref : v,
 				ret : TVoid,
 				args : [],
-				expr : { e : TBlock(exprs), t : TVoid, p : exprs.length == 0 ? null : exprs[0].p },
+				expr : expr,
 			};
 		}
 		var funs = [
 			build(Vertex, "vertex", v),
 			build(Fragment, "fragment", f),
 		];
+		
+		// make sure the first merged var is the original for duplicate shaders
+		for( s in dupShaders.keys() ) {
+			var sreal = dupShaders.get(s);
+			if( s == sreal ) continue;
+			for( i in 0...s.vars.length )
+				allocVar(s.vars[i],null).merged.unshift(sreal.vars[i]);
+		}
+		
 		return { name : "out", vars : outVars, funs : funs };
 	}