Explorar o código

added hxsl Channel support

Nicolas Cannnasse %!s(int64=8) %!d(string=hai) anos
pai
achega
0f49e10421
Modificáronse 14 ficheiros con 160 adicións e 26 borrados
  1. 1 0
      h3d/shader/Manager.hx
  2. 1 1
      hxsl/AgalOut.hx
  3. 8 1
      hxsl/Ast.hx
  4. 10 0
      hxsl/Checker.hx
  5. 13 0
      hxsl/Dce.hx
  6. 35 4
      hxsl/Eval.hx
  7. 8 3
      hxsl/Flatten.hx
  8. 18 0
      hxsl/Globals.hx
  9. 2 0
      hxsl/GlslOut.hx
  10. 2 0
      hxsl/HlslOut.hx
  11. 4 0
      hxsl/MacroParser.hx
  12. 42 4
      hxsl/Macros.hx
  13. 1 1
      hxsl/SharedShader.hx
  14. 15 12
      hxsl/Types.hx

+ 1 - 0
h3d/shader/Manager.hx

@@ -212,6 +212,7 @@ class Manager {
 	}
 
 	public function compileShaders( shaders : hxsl.ShaderList ) {
+		globals.resetChannels();
 		for( s in shaders ) s.updateConstants(globals);
 		return shaderCache.link(shaders, output);
 	}

+ 1 - 1
hxsl/AgalOut.hx

@@ -802,7 +802,7 @@ class AgalOut {
 		case TMat4: 4;
 		case TArray(t, SConst(size)): (Tools.size(t) * size + 3) >> 2;
 		case TStruct(vl): throw "TODO";
-		case TVoid, TString, TSampler2D, TSamplerCube, TFun(_), TArray(_): throw "assert "+t;
+		case TVoid, TString, TSampler2D, TSamplerCube, TFun(_), TArray(_), TChannel(_): throw "assert "+t;
 		}
 	}
 

+ 8 - 1
hxsl/Ast.hx

@@ -16,6 +16,7 @@ enum Type {
 	TStruct( vl : Array<TVar> );
 	TFun( variants : Array<FunType> );
 	TArray( t : Type, size : SizeDecl );
+	TChannel( size : Int );
 }
 
 enum VecType {
@@ -228,6 +229,7 @@ enum TGlobal {
 	Fwidth;
 	TextureCubeLod;
 	Texture2DLod;
+	ChannelRead;
 	// debug
 	Trace;
 }
@@ -276,6 +278,7 @@ class Tools {
 	static var UID = 0;
 
 	public static var SWIZ = Component.createAll();
+	public static var MAX_CHANNELS_BITS = 3;
 
 	public static function allocVarId() {
 		// in order to prevent compile time ids to conflict with runtime allocated ones
@@ -315,12 +318,16 @@ class Tools {
 					return 8;
 				default:
 				}
+		case TChannel(_):
+			return 3 + MAX_CHANNELS_BITS;
 		default:
 		}
 		return 0;
 	}
 
 	public static function isConst( v : TVar ) {
+		if( v.type.match(TChannel(_)) )
+			return true;
 		if( v.qualifiers != null )
 			for( q in v.qualifiers )
 				switch( q ) {
@@ -474,7 +481,7 @@ class Tools {
 		return switch( t ) {
 		case TVoid: 0;
 		case TFloat, TInt: 1;
-		case TVec(n, _): n;
+		case TVec(n, _), TChannel(n): n;
 		case TStruct(vl):
 			var s = 0;
 			for( v in vl ) s += size(v.type);

+ 10 - 0
hxsl/Checker.hx

@@ -109,6 +109,13 @@ class Checker {
 				[ { args : [ { name : "value", type : TVec(4, VFloat) } ], ret : TVec(3, VFloat) } ];
 			case PackNormal:
 				[ { args : [ { name : "value", type : TVec(3, VFloat) } ], ret : TVec(4, VFloat) } ];
+			case ChannelRead:
+				[ 
+					{ args : [ { name : "channel", type : TChannel(1) }, { name : "uv", type : vec2 } ], ret : TFloat }, 
+					{ args : [ { name : "channel", type : TChannel(2) }, { name : "uv", type : vec2 } ], ret : TVec(2,VFloat) }, 
+					{ args : [ { name : "channel", type : TChannel(3) }, { name : "uv", type : vec2 } ], ret : TVec(3,VFloat) }, 
+					{ args : [ { name : "channel", type : TChannel(4) }, { name : "uv", type : vec2 } ], ret : TVec(4,VFloat) }, 
+				];
 			case Trace:
 				[];
 			}
@@ -209,6 +216,8 @@ class Checker {
 		switch( [t1, t2] ) {
 		case [TVec(s1, t1), TVec(s2, t2)] if( s1 == s2 && t1 == t2 ):
 			return true;
+		case [TChannel(n1), TChannel(n2)] if( n1 == n2 ):
+			return true;
 		default:
 		}
 		return false;
@@ -767,6 +776,7 @@ class Checker {
 			var gl : TGlobal = switch( [f, e.t] ) {
 			case ["get", TSampler2D]: Texture2D;
 			case ["get", TSamplerCube]: TextureCube;
+			case ["get", TChannel(_)]: ChannelRead;
 			default: null;
 			}
 			if( gl != null )

+ 13 - 0
hxsl/Dce.hx

@@ -21,6 +21,7 @@ private class VarDeps {
 class Dce {
 
 	var used : Map<Int,VarDeps>;
+	var channelVars : Array<TVar>;
 
 	public function new() {
 	}
@@ -28,6 +29,7 @@ class Dce {
 	public function dce( vertex : ShaderData, fragment : ShaderData ) {
 		// collect vars dependencies
 		used = new Map();
+		channelVars = [];
 
 		var inputs = [];
 		for( v in vertex.vars ) {
@@ -142,6 +144,14 @@ class Dce {
 			check(it, writeTo);
 			check(loop, writeTo);
 			writeTo.pop();
+		case TCall({ e : TGlobal(ChannelRead) }, [{ e : TVar(c) }, uv, { e : TConst(CInt(cid)) }]):
+			check(uv, writeTo);
+			if( channelVars[cid] == null ) {
+				channelVars[cid] = c;
+				link(c, writeTo);
+			} else {
+				link(channelVars[cid], writeTo);
+			}
 		default:
 			e.iter(check.bind(_, writeTo));
 		}
@@ -162,6 +172,9 @@ class Dce {
 			return { e : TBlock(out), p : e.p, t : e.t };
 		case TVarDecl(v,_) | TBinop(OpAssign | OpAssignOp(_), { e : (TVar(v) | TSwiz( { e : TVar(v) }, _)) }, _) if( !get(v).used ):
 			return { e : TConst(CNull), t : e.t, p : e.p };
+		case TCall({ e : TGlobal(ChannelRead) }, [_, uv, { e : TConst(CInt(cid)) }]):
+			var c = channelVars[cid];
+			return { e : TCall({ e : TGlobal(Texture2D), p : e.p, t : TVoid }, [{ e : TVar(c), t : c.type, p : e.p }, uv]), t : TVoid, p : e.p };
 		case TIf(e, econd, eelse):
 			var e = mapExpr(e, true);
 			var econd = mapExpr(econd, isVar);

+ 35 - 4
hxsl/Eval.hx

@@ -155,13 +155,44 @@ class Eval {
 		return handleReturn(e);
 	}
 
-	function evalCall( g : TGlobal, args : Array<TExpr> ) {
+	function evalCall( g : TGlobal, args : Array<TExpr>, oldArgs : Array<TExpr>, pos : Position ) {
 		return switch( [g,args] ) {
 		case [ToFloat, [ { e : TConst(CInt(i)) } ]]: TConst(CFloat(i));
 		case [Trace, args]:
 			for( a in args )
 				haxe.Log.trace(Printer.toString(a), { fileName : a.p.file, lineNumber : 0, className : null, methodName : null });
 			TBlock([]);
+		case [ChannelRead, [ { e : TConst(CInt(i)) }, uv ]]:
+			var channel = oldArgs[0];
+			channel.e = switch( channel.e ) {
+			case TVar(v):
+				var v2 = mapVar(v);
+				constants.set(v2, constants.get(v));
+				TVar(v2);
+			default: throw "assert";
+			};
+			var count = switch( channel.t ) { case TChannel(i): i; default: throw "assert"; };
+			var channelMode = hxsl.Types.ChannelSelect.createByIndex(i & 7);
+			var tget = {
+				e : TCall({ e : TGlobal(ChannelRead), t : TVoid, p : pos }, [channel, uv, { e : TConst(CInt(i >> 3)), t : TInt, p : pos }]),
+				t : TVoid,
+				p : pos,
+			};
+			switch( channelMode ) {
+			case R, G, B, A:
+				return TSwiz(tget, [switch( channelMode ) { case R: X; case G: Y; case B: Z; default: W; }]);
+			case Unknown:
+				var zero = { e : TConst(CFloat(0.)), t : TFloat, p : pos };
+				if( count == 1 )
+					return zero.e;
+				return TCall({ e : TGlobal([Vec2, Vec3, Vec4][count - 1]), t : TVoid, p : pos }, [zero]);
+			case PackedFloat:
+				return TCall({ e : TGlobal(Unpack), t:TVoid, p:pos}, [tget]);
+			case PackedNormal:
+				return TCall({ e : TGlobal(UnpackNormal), t:TVoid, p:pos}, [tget]);
+			}
+		case [ChannelRead, [t,_]]:
+			Error.t("Cannot eval complex channel " + Printer.toString(t,true), pos);
 		default: null;
 		}
 	}
@@ -192,12 +223,12 @@ class Eval {
 			TSwiz(evalExpr(e), r.copy());
 		case TReturn(e):
 			TReturn(e == null ? null : evalExpr(e));
-		case TCall(c, args):
+		case TCall(c, eargs):
 			var c = evalExpr(c);
-			var args = [for( a in args ) evalExpr(a)];
+			var args = [for( a in eargs ) evalExpr(a)];
 			switch( c.e ) {
 			case TGlobal(g):
-				var v = evalCall(g, args);
+				var v = evalCall(g, args, eargs, e.p);
 				if( v != null ) v else TCall(c, args);
 			case TVar(_) if( !inlineCalls ):
 				TCall(c, args);

+ 8 - 3
hxsl/Flatten.hx

@@ -276,7 +276,7 @@ class Flatten {
 			var stride = Std.int(a.size / len);
 			var earr = [for( i in 0...len ) { var a = new Alloc(a.g, a.t, a.pos + stride * i, stride); access(a, t, pos, AIndex(a)); }];
 			return { e : TArrayDecl(earr), t : t, p : pos };
-		case TSampler2D, TSamplerCube:
+		case TSampler2D, TSamplerCube, TChannel(_):
 			return read(0,pos);
 		default:
 			var size = varSize(t, a.t);
@@ -331,7 +331,12 @@ class Flatten {
 			kind : Param,
 		};
 		for( v in vars ) {
-			if( v.type != t ) continue;
+			if( v.type != t ) {
+				if( t == TSampler2D && v.type.match(TChannel(_)) ) {
+					// ok
+				} else
+					continue;
+			}
 			// use << 2 for readAccess purposes, then we will fix it before returning
 			var a = new Alloc(g, null, alloc.length << 2, 1);
 			a.v = v;
@@ -356,7 +361,7 @@ class Flatten {
 		};
 		for( v in vars ) {
 			switch( v.type ) {
-			case TSampler2D, TSamplerCube:
+			case TSampler2D, TSamplerCube, TChannel(_):
 				continue;
 			default:
 			}

+ 18 - 0
hxsl/Globals.hx

@@ -1,4 +1,5 @@
 package hxsl;
+import h3d.mat.Texture;
 
 abstract GlobalSlot<T>(Int) {
 	public inline function new(name:String) {
@@ -18,6 +19,8 @@ abstract GlobalSlot<T>(Int) {
 class Globals {
 
 	var map : Map<Int,Dynamic>;
+	var channels : Array<Texture> = [];
+	var maxChannels : Int;
 
 	public function new() {
 		map = new Map<Int,Dynamic>();
@@ -39,6 +42,21 @@ class Globals {
 		return map.get(id);
 	}
 
+	public inline function resetChannels() {
+		maxChannels = 0;
+	}
+
+	public function allocChannelID( t : Texture ) {
+		for( i in 0...maxChannels )
+			if( channels[i] == t )
+				return i;
+		if( maxChannels == 1 << Ast.Tools.MAX_CHANNELS_BITS )
+			throw "Too many unique channels";
+		var i = maxChannels++;
+		channels[i] = t;
+		return i;
+	}
+
 	static var ALL;
 	static var MAP;
 	public static function allocID( path : String ) {

+ 2 - 0
hxsl/GlslOut.hx

@@ -118,6 +118,8 @@ class GlslOut {
 				add(v);
 			}
 			add("]");
+		case TChannel(n):
+			add("channel" + n);
 		}
 	}
 

+ 2 - 0
hxsl/HlslOut.hx

@@ -109,6 +109,8 @@ class HlslOut {
 				add(v);
 			}
 			add("]");
+		case TChannel(n):
+			add("channel" + n);
 		}
 	}
 

+ 4 - 0
hxsl/MacroParser.hx

@@ -83,6 +83,10 @@ class MacroParser {
 			case "Bytes2": return TBytes(2);
 			case "Bytes3": return TBytes(3);
 			case "Bytes4": return TBytes(4);
+			case "Channel": return TChannel(1);
+			case "Channel2": return TChannel(2);
+			case "Channel3": return TChannel(3);
+			case "Channel4": return TChannel(4);
 			}
 		case TPath( { pack : [], name : "Array", sub : null, params : [t, size] } ):
 			var t = switch( t ) {

+ 42 - 4
hxsl/Macros.hx

@@ -18,7 +18,14 @@ class Macros {
 				macro : hxsl.Types.BVec;
 			}
 		case TStruct(vl):
-			TAnonymous([for( v in vl ) { pos : Context.currentPos(), name : v.name, kind : FVar(makeType(v.type)) } ]);
+			var fields = [];
+			var pos = Context.currentPos();
+			for( v in vl ) {
+				fields.push({ pos : pos, name : v.name, kind : FVar(makeType(v.type)) });
+				if( v.type.match(TChannel(_)) )
+				fields.push({ pos : pos, name : v.name+"Channel", kind : FVar(macro : hxsl.Types.ChannelSelect) });
+			}
+			TAnonymous(fields);
 		case TSampler2D:
 			macro : hxsl.Types.Sampler2D;
 		case TSamplerCube:
@@ -36,6 +43,8 @@ class Macros {
 		case TArray(t, _):
 			var t = makeType(t);
 			macro : Array<$t>;
+		case TChannel(_):
+			macro : hxsl.Types.Channel;
 		case TFun(_):
 			throw "assert";
 		}
@@ -156,6 +165,22 @@ class Macros {
 				addParamRec(eparams, tparams, { expr : EConst(CIdent(name)), pos:pos }, v.type);
 				fields.push(fget);
 				fields.push(fset);
+
+				if( v.type.match(TChannel(_)) ) {
+					var sel = v.name+"Channel";
+					var selVar = sel + "__";
+					var get_sel = "get_" + sel;
+					var set_sel = "set_" + sel;
+					var sfields = macro class {
+						var $selVar : hxsl.Types.ChannelSelect = Unknown;
+						public var $sel(get, set) : hxsl.Types.ChannelSelect;
+						inline function $get_sel() return $i{selVar};
+						inline function $set_sel(v) { constModified = true; return $i{selVar} = v; }
+					};
+					for( f in sfields.fields )
+						fields.push(f);
+				}
+
 			case Global:
 				globals.push(v);
 			default:
@@ -163,10 +188,11 @@ class Macros {
 		}
 		// updateConstants
 		var exprs = [];
-		function getPath(v:TVar) {
+		function getPath(v:TVar,?suffix) {
+			var name = suffix == null ? v.name : v.name + suffix;
 			if( v.parent == null )
-				return { expr : haxe.macro.Expr.ExprDef.EConst(CIdent(v.name+"__")), pos : pos };
-			return { expr : haxe.macro.Expr.ExprDef.EField(getPath(v.parent), v.name), pos : pos };
+				return { expr : haxe.macro.Expr.ExprDef.EConst(CIdent(name+"__")), pos : pos };
+			return { expr : haxe.macro.Expr.ExprDef.EField(getPath(v.parent), name), pos : pos };
 		}
 		for( c in consts ) {
 			if( c.v.kind == Global ) continue;
@@ -180,6 +206,18 @@ class Macros {
 				});
 			case TBool:
 				exprs.push(macro if( $p ) constBits |= 1 << $v{ c.pos } );
+			case TChannel(n):
+				var psel = getPath(c.v, "Channel");
+				var defFormat = macro throw $v{c.v.name} +"Channel is not set";
+				switch(n) {
+				case 1: defFormat = macro if( hxsl.Types.ChannelTools.isPackedFormat($p) ) $psel = PackedFloat else $defFormat;
+				case 3: defFormat = macro if( hxsl.Types.ChannelTools.isPackedFormat($p) ) $psel = PackedNormal else $defFormat;
+				default: macro throw $v{c.v.name} +"Channel is not set";
+				}
+				exprs.push(macro {
+					if( $p == null ) $psel = Unknown else if( $psel == Unknown ) $defFormat;
+					constBits |= ((globals.allocChannelID($p) << 3) | Type.enumIndex($psel)) << $v{ c.pos };
+				});
 			default:
 				throw "assert";
 			}

+ 1 - 1
hxsl/SharedShader.hx

@@ -63,7 +63,7 @@ class SharedShader {
 		while( c != null ) {
 			eval.setConstant(c.v, switch( c.v.type ) {
 			case TBool: CBool((constBits >>> c.pos) & 1 != 0);
-			case TInt: CInt((constBits >>> c.pos) & ((1 << c.bits) - 1));
+			case TInt, TChannel(_): CInt((constBits >>> c.pos) & ((1 << c.bits) - 1));
 			default: throw "assert";
 			});
 			c = c.next;

+ 15 - 12
hxsl/Types.hx

@@ -1,7 +1,5 @@
 package hxsl;
 
-#if true
-
 typedef Vec = h3d.Vector;
 typedef IVec = Array<Int>;
 typedef BVec = Array<Bool>;
@@ -9,15 +7,20 @@ typedef Matrix = h3d.Matrix;
 typedef Texture = h3d.mat.Texture;
 typedef Sampler2D = h3d.mat.Texture;
 typedef SamplerCube = h3d.mat.Texture;
+typedef Channel = h3d.mat.Texture;
 
-#else
-
-typedef Vec = Array<Float>;
-typedef IVec = Array<Int>;
-typedef BVec = Array<Bool>;
-typedef Matrix = Array<Float>;
-typedef Texture = Dynamic;
-typedef Sampler2D = Dynamic;
-typedef SamplerCube = Dynamic;
+enum ChannelSelect {
+	Unknown;
+	R;
+	G;
+	B;
+	A;
+	PackedFloat;
+	PackedNormal;
+}
 
-#end
+class ChannelTools {
+	public static inline function isPackedFormat( c : Channel ) {
+		return c.format == h3d.mat.Texture.nativeFormat;
+	}
+}