Browse Source

added @sampler(name) tex declaration to reuse samplers among similar textures

Nicolas Cannasse 4 years ago
parent
commit
46421fc112
8 changed files with 97 additions and 45 deletions
  1. 13 5
      h3d/impl/DirectXDriver.hx
  2. 1 0
      hxsl/Ast.hx
  3. 6 0
      hxsl/Checker.hx
  4. 17 0
      hxsl/Flatten.hx
  5. 54 40
      hxsl/HlslOut.hx
  6. 3 0
      hxsl/MacroParser.hx
  7. 1 0
      hxsl/Printer.hx
  8. 2 0
      hxsl/Serializer.hx

+ 13 - 5
h3d/impl/DirectXDriver.hx

@@ -26,6 +26,7 @@ private class ShaderContext {
 	public var paramsContent : hl.Bytes;
 	public var globals : dx.Resource;
 	public var params : dx.Resource;
+	public var samplersMap : Array<Int>;
 	#if debug
 	public var debugSource : String;
 	#end
@@ -777,6 +778,12 @@ class DirectXDriver extends h3d.impl.Driver {
 		ctx.bufferCount = shader.bufferCount;
 		ctx.globals = dx.Driver.createBuffer(shader.globalsSize * 16, Dynamic, ConstantBuffer, CpuWrite, None, 0, null);
 		ctx.params = dx.Driver.createBuffer(shader.paramsSize * 16, Dynamic, ConstantBuffer, CpuWrite, None, 0, null);
+		ctx.samplersMap = [];
+
+		var samplers = new hxsl.HlslOut.Samplers();
+		for( v in shader.data.vars )
+			samplers.make(v, ctx.samplersMap);
+
 		#if debug
 		ctx.debugSource = shader.code;
 		#end
@@ -1147,10 +1154,11 @@ class DirectXDriver extends h3d.impl.Driver {
 					if( start < 0 ) start = i;
 				}
 
+				var sidx = shader.samplersMap[i];
 				var bits = @:privateAccess t.bits;
 				if( t.lodBias != 0 )
 					bits |= Std.int((t.lodBias + 32)*32) << 10;
-				if( i < maxSamplers && bits != state.samplerBits[i] ) {
+				if( i < maxSamplers && bits != state.samplerBits[sidx] ) {
 					var ss = samplerStates.get(bits);
 					if( ss == null ) {
 						var desc = new SamplerDesc();
@@ -1164,10 +1172,10 @@ class DirectXDriver extends h3d.impl.Driver {
 						ss = Driver.createSamplerState(desc);
 						samplerStates.set(bits, ss);
 					}
-					state.samplerBits[i] = bits;
-					state.samplers[i] = ss;
-					smax = i;
-					if( sstart < 0 ) sstart = i;
+					state.samplerBits[sidx] = bits;
+					state.samplers[sidx] = ss;
+					if( sidx > smax ) smax = sidx;
+					if( sstart < 0 || sidx < sstart ) sstart = sidx;
 				}
 			}
 			switch( state.kind) {

+ 1 - 0
hxsl/Ast.hx

@@ -85,6 +85,7 @@ enum VarQualifier {
 	PerInstance( v : Int );
 	Doc( s : String );
 	Borrow( source : String );
+	Sampler( name : String );
 }
 
 enum Prec {

+ 6 - 0
hxsl/Checker.hx

@@ -810,6 +810,12 @@ class Checker {
 					}
 				case Borrow(source):
 					if ( v.kind != Local ) error("Borrow should not have a type qualifier", pos);
+				case Sampler(_):
+					switch( v.type ) {
+					case TArray(t, _) if( t.isSampler() ):
+					case t if( t.isSampler() ):
+					default: error("Sampler should be on sampler type or sampler array", pos);
+					}
 				case Ignore, Doc(_):
 				}
 		}

+ 17 - 0
hxsl/Flatten.hx

@@ -359,6 +359,7 @@ class Flatten {
 			kind : Param,
 		};
 		var pos = 0;
+		var samplers = [];
 		for( v in vars ) {
 			var count = 1;
 			if( v.type != t ) {
@@ -372,11 +373,27 @@ class Flatten {
 			}
 			var a = new Alloc(g, null, pos, count);
 			a.v = v;
+			if( v.qualifiers != null )
+				for( q in v.qualifiers )
+					switch( q ) {
+					case Sampler(name):
+						for( i in 0...count )
+							samplers[pos+i] = name;
+					default:
+					}
 			varMap.set(v, a);
 			alloc.push(a);
 			pos += count;
 		}
 		g.type = TArray(t, SConst(pos));
+		if( samplers.length > 0 ) {
+			for( i in 0...pos )
+				if( samplers[i] == null )
+					samplers[i] = "";
+			if( g.qualifiers == null )
+				g.qualifiers = [];
+			g.qualifiers.push(Sampler(samplers.join(",")));
+		}
 		if( alloc.length > 0 ) {
 			outVars.push(g);
 			allocData.set(g, alloc);

+ 54 - 40
hxsl/HlslOut.hx

@@ -1,6 +1,51 @@
 package hxsl;
 using hxsl.Ast;
 
+class Samplers {
+
+	public var count : Int;
+	var named : Map<String, Int>;
+
+	public function new() {
+		count = 0;
+		named = new Map();
+	}
+
+	public function make( v : TVar, arr : Array<Int> ) : Array<Int> {
+
+		var ntex = switch( v.type ) {
+		case TArray(t, SConst(k)) if( t.isSampler() ): k;
+		case t if( t.isSampler() ): 1;
+		default:
+			return null;
+		}
+
+		var names = null;
+		if( v.qualifiers != null ) {
+			for( q in v.qualifiers ) {
+				switch( q ) {
+				case Sampler(nl): names = nl.split(",");
+				default:
+				}
+			}
+		}
+		for( i in 0...ntex ) {
+			if( names == null || names[i] == "" )
+				arr.push(count++);
+			else {
+				var idx = named.get(names[i]);
+				if( idx == null ) {
+					idx = count++;
+					named.set(names[i], idx);
+				}
+				arr.push(idx);
+			}
+		}
+		return arr;
+	}
+
+}
+
 class HlslOut {
 
 	static var KWD_LIST = [
@@ -53,11 +98,8 @@ class HlslOut {
 	var decls : Array<String>;
 	var isVertex : Bool;
 	var allNames : Map<String, Int>;
-	var samplers : Map<Int, Int>;
-	var namedSamplers : Map<String, Int>;
-	var forcedSampler : String;
+	var samplers : Map<Int, Array<Int>>;
 	public var varNames : Map<Int,String>;
-	public var maxSamplers : Int = 16;
 
 	var varAccess : Map<Int,String>;
 
@@ -205,11 +247,6 @@ class HlslOut {
 
 	function handleMeta( m, args : Array<Ast.Const>, callb, e, tabs ) {
 		switch( [m, args] ) {
-		case ["sampler", [CString(name)]]:
-			var prev = forcedSampler;
-			forcedSampler = name;
-			callb(e,tabs);
-			forcedSampler = null;
 		default:
 			callb(e,tabs);
 		}
@@ -271,19 +308,9 @@ class HlslOut {
 			}
 			switch( expr.e ) {
 			case TVar(v):
-				var samplerIndex = samplers.get(v.id);
-				if( samplerIndex == null ) throw "assert";
-				samplerIndex += offset;
-				if( forcedSampler != null ) {
-					var useIndex = namedSamplers.get("$"+forcedSampler);
-					if( useIndex != null )
-						samplerIndex = useIndex;
-					else {
-						useIndex = samplerIndex;
-						namedSamplers.set("$"+forcedSampler, useIndex);
-					}
-				}
-				add('__Samplers[$samplerIndex]');
+				var samplers = samplers.get(v.id);
+				if( samplers == null ) throw "assert";
+				add('__Samplers[${samplers[offset]}]');
 			default: throw "assert";
 			}
 			for( i in 1...args.length ) {
@@ -705,24 +732,12 @@ class HlslOut {
 		}
 		if( bufCount > 0 ) add("\n");
 
+		var ctx = new Samplers();
+		for( v in textures )
+			samplers.set(v.id, ctx.make(v, []));
 
-		var samplerCount = 0;
-		for( v in textures ) {
-			samplers.set(v.id, samplerCount);
-			switch( v.type ) {
-			case TArray(t, size):
-				samplerCount += switch( size ) {
-				case SConst(i): i;
-				default: throw "assert";
-				};
-			default:
-				samplerCount++;
-			}
-		}
-		if( samplerCount > 0 ) {
-			if( samplerCount > maxSamplers ) samplerCount = maxSamplers;
-			add('SamplerState __Samplers[$samplerCount];\n');
-		}
+		if( ctx.count > 0 )
+			add('SamplerState __Samplers[${ctx.count}];\n');
 	}
 
 	function initStatics( s : ShaderData ) {
@@ -784,7 +799,6 @@ class HlslOut {
 
 		varAccess = new Map();
 		samplers = new Map();
-		namedSamplers = new Map();
 		initVars(s);
 		initGlobals(s);
 		initParams(s);

+ 3 - 0
hxsl/MacroParser.hx

@@ -29,6 +29,9 @@ class MacroParser {
 		case [ { expr: EConst(CString(s)), pos: pos } ] if (m.name == "doc"):
 			v.qualifiers.push(Doc(s));
 			return;
+		case [ { expr: EConst(CString(s)) } ] if (m.name == "sampler"):
+			v.qualifiers.push(Sampler(s));
+			return;
 		case [ e ] if (m.name == "borrow"):
 			var path = [];
 			function loop( e : Expr ) {

+ 1 - 0
hxsl/Printer.hx

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

+ 2 - 0
hxsl/Serializer.hx

@@ -186,6 +186,7 @@ class Serializer {
 				case PerInstance(v): out.addInt32(v);
 				case Doc(s): writeString(s);
 				case Borrow(s): writeString(s);
+				case Sampler(s): writeString(s);
 				}
 			}
 		}
@@ -401,6 +402,7 @@ class Serializer {
 				case 9: PerInstance(input.readInt32());
 				case 10: Doc(readString());
 				case 11: Borrow(readString());
+				case 12: Sampler(readString());
 				default: throw "assert";
 				}
 				v.qualifiers.push(q);