浏览代码

HXSL: Implement borrow qualifier (#916)

Pavel Alexandrov 4 年之前
父节点
当前提交
ec0f6eec23
共有 6 个文件被更改,包括 45 次插入11 次删除
  1. 11 0
      hxsl/Ast.hx
  2. 2 0
      hxsl/Checker.hx
  3. 15 11
      hxsl/Linker.hx
  4. 14 0
      hxsl/MacroParser.hx
  5. 1 0
      hxsl/Printer.hx
  6. 2 0
      hxsl/Serializer.hx

+ 11 - 0
hxsl/Ast.hx

@@ -84,6 +84,7 @@ enum VarQualifier {
 	Ignore; // the variable is ignored in reflection (inspector)
 	PerInstance( v : Int );
 	Doc( s : String );
+	Borrow( source : String );
 }
 
 enum Prec {
@@ -380,6 +381,16 @@ class Tools {
 		return false;
 	}
 
+	public static function hasBorrowQualifier( v : TVar, path : String ) {
+		if ( v.qualifiers != null )
+			for( q in v.qualifiers )
+				switch (q) {
+					case Borrow(s): return path == s;
+					default:
+				}
+		return false;
+	}
+
 	public static function isSampler( t : Type ) {
 		return switch( t ) {
 		case TSampler2D, TSamplerCube, TSampler2DArray, TChannel(_):

+ 2 - 0
hxsl/Checker.hx

@@ -809,6 +809,8 @@ class Checker {
 					default:
 						error("Precision qualifier not supported on " + v.type, pos);
 					}
+				case Borrow(source):
+					if ( v.kind != Local ) error("Borrow should not have a type qualifier", pos);
 				case Ignore, Doc(_):
 				}
 		}

+ 15 - 11
hxsl/Linker.hx

@@ -8,6 +8,7 @@ private class AllocatedVar {
 	public var merged : Array<TVar>;
 	public var kind : Null<FunctionKind>;
 	public var parent : AllocatedVar;
+	public var rootShaderName : String;
 	public var instanceIndex : Int;
 	public function new() {
 	}
@@ -68,10 +69,12 @@ class Linker {
 		return Error.t(msg, p);
 	}
 
-	function mergeVar( path : String, v : TVar, v2 : TVar, p : Position ) {
+	function mergeVar( path : String, v : TVar, v2 : TVar, p : Position, shaderName : String ) {
 		switch( v.kind ) {
 		case Global, Input, Var, Local, Output:
 			// shared vars
+		case Param if ( shaderName != null && v2.hasBorrowQualifier(shaderName) ):
+			// Other variable attempts to borrow.
 		case Param, Function:
 			throw "assert";
 		}
@@ -88,9 +91,9 @@ class Linker {
 					}
 				// add a new field
 				if( ft == null )
-					fl2.push(allocVar(f1,p).v);
+					fl2.push(allocVar(f1,p, shaderName).v);
 				else
-					mergeVar(path + "." + ft.name, f1, ft, p);
+					mergeVar(path + "." + ft.name, f1, ft, p, shaderName);
 			}
 		default:
 			if( !v.type.equals(v2.type) )
@@ -98,9 +101,9 @@ class Linker {
 		}
 	}
 
-	function allocVar( v : TVar, p : Position, ?path : String, ?parent : AllocatedVar ) : AllocatedVar {
+	function allocVar( v : TVar, p : Position, ?shaderName : String, ?path : String, ?parent : AllocatedVar ) : AllocatedVar {
 		if( v.parent != null && parent == null ) {
-			parent = allocVar(v.parent, p);
+			parent = allocVar(v.parent, p, shaderName);
 			var p = parent.v;
 			path = p.name;
 			p = p.parent;
@@ -122,10 +125,10 @@ class Linker {
 			for( vm in v2.merged )
 				if( vm == v )
 					return v2;
-			inline function isUnique( v : TVar ) {
-				return (v.kind == Param && !v.hasQualifier(Shared) && !isBatchShader) || v.kind == Function || (v.kind == Var && v.hasQualifier(Private));
+			inline function isUnique( v : TVar, borrowed : Bool ) {
+				return (v.kind == Param && !borrowed && !v.hasQualifier(Shared) && !isBatchShader) || v.kind == Function || (v.kind == Var && v.hasQualifier(Private));
 			}
-			if( isUnique(v) || isUnique(v2.v) || (v.kind == Param && v2.v.kind == Param) /* two shared : one takes priority */ ) {
+			if( isUnique(v, v2.v.hasBorrowQualifier(shaderName)) || isUnique(v2.v, v.hasBorrowQualifier(v2.rootShaderName)) || (v.kind == Param && v2.v.kind == Param) /* two shared : one takes priority */ ) {
 				// allocate a new unique name in the shader if already in use
 				var k = 2;
 				while( true ) {
@@ -140,7 +143,7 @@ class Linker {
 				key += k;
 			} else {
 				v2.merged.push(v);
-				mergeVar(key, v, v2.v, p);
+				mergeVar(key, v, v2.v, p, v2.rootShaderName);
 				varIdMap.set(v.id, v2.id);
 				return v2;
 			}
@@ -161,11 +164,12 @@ class Linker {
 		a.id = vid;
 		a.parent = parent;
 		a.instanceIndex = curInstance;
+		a.rootShaderName = shaderName;
 		allVars.push(a);
 		varMap.set(key, a);
 		switch( v2.type ) {
 		case TStruct(vl):
-			v2.type = TStruct([for( v in vl ) allocVar(v, p, key, a).v]);
+			v2.type = TStruct([for( v in vl ) allocVar(v, p, shaderName, key, a).v]);
 		default:
 		}
 		return a;
@@ -356,7 +360,7 @@ class Linker {
 		for( s in shadersData ) {
 			isBatchShader = batchMode && StringTools.startsWith(s.name,"batchShader_");
 			for( v in s.vars ) {
-				var v2 = allocVar(v, null);
+				var v2 = allocVar(v, null, s.name);
 				if( isBatchShader && v2.v.kind == Param && !StringTools.startsWith(v2.path,"Batch_") )
 					v2.v.kind = Local;
 				if( v.kind == Output ) outVars.push(v);

+ 14 - 0
hxsl/MacroParser.hx

@@ -29,6 +29,20 @@ class MacroParser {
 		case [ { expr: EConst(CString(s)), pos: pos } ] if (m.name == "doc"):
 			v.qualifiers.push(Doc(s));
 			return;
+		case [ e ] if (m.name == "borrow"):
+			var path = [];
+			function loop( e : Expr ) {
+				switch( e.expr ) {
+				case EConst(CIdent(s)): path.push(s);
+				case EConst(CString(s)): path.push(s);
+				case EField(e, f): loop(e); path.push(f);
+				default:
+					error("Should be a shader type path", e.pos);
+				}
+			}
+			loop(e);
+			v.qualifiers.push(Borrow(path.join(".")));
+			return;
 		default:
 			error("Invalid meta parameter for "+m.name, m.pos);
 		}

+ 1 - 0
hxsl/Printer.hx

@@ -62,6 +62,7 @@ class Printer {
 				case Ignore: "ignore";
 				case PerInstance(n): "perInstance("+n+")";
 				case Doc(s): "doc(\"" + StringTools.replace(s, '"', '\\"') + "\")";
+				case Borrow(s): "borrow(" + s + ")";
 				}) + " ");
 		}
 		if( v.kind != defKind )

+ 2 - 0
hxsl/Serializer.hx

@@ -185,6 +185,7 @@ class Serializer {
 				case Range(min, max): out.addDouble(min); out.addDouble(max);
 				case PerInstance(v): out.addInt32(v);
 				case Doc(s): writeString(s);
+				case Borrow(s): writeString(s);
 				}
 			}
 		}
@@ -399,6 +400,7 @@ class Serializer {
 				case 8: Ignore;
 				case 9: PerInstance(input.readInt32());
 				case 10: Doc(readString());
+				case 11: Borrow(readString());
 				default: throw "assert";
 				}
 				v.qualifiers.push(q);