فهرست منبع

Merge heaps_shaderlist, less allocations

Nicolas Cannasse 11 سال پیش
والد
کامیت
44b3ed5f02
11فایلهای تغییر یافته به همراه89 افزوده شده و 87 حذف شده
  1. 18 8
      h2d/Drawable.hx
  2. 28 22
      h2d/RenderContext.hx
  3. 4 23
      h3d/pass/Default.hx
  4. 4 3
      h3d/pass/LightSystem.hx
  5. 5 3
      h3d/pass/Object.hx
  6. 2 1
      h3d/pass/ScreenFx.hx
  7. 1 2
      h3d/scene/RenderContext.hx
  8. 10 11
      h3d/shader/Manager.hx
  9. 15 11
      hxsl/Cache.hx
  10. 1 3
      hxsl/Checker.hx
  11. 1 0
      hxsl/Shader.hx

+ 18 - 8
h2d/Drawable.hx

@@ -10,13 +10,12 @@ class Drawable extends Sprite {
 	public var colorKey(default, set) : Null<Int>;
 	public var colorMatrix(get, set) : Null<h3d.Matrix>;
 
-	var shaders : Array<hxsl.Shader>;
+	var shaders : hxsl.ShaderList;
 
 	function new(parent) {
 		super(parent);
 		blendMode = Normal;
 		color = new h3d.Vector(1, 1, 1, 1);
-		shaders = [];
 	}
 
 	function set_colorKey(v:Null<Int>) {
@@ -65,9 +64,7 @@ class Drawable extends Sprite {
 	public function getDebugShaderCode( toHxsl = true ) {
 		var shader = @:privateAccess {
 			var ctx = getScene().ctx;
-			var shaders : Array<hxsl.Shader> = [ctx.baseShader];
-			shaders = shaders.concat(this.shaders);
-			ctx.manager.compileShaders(shaders);
+			ctx.manager.compileShaders(new hxsl.ShaderList(ctx.baseShader,shaders));
 		}
 		var toString = toHxsl ? function(d) return hxsl.Printer.shaderToString(d,true) : hxsl.GlslOut.toGlsl;
 		return "VERTEX=\n" + toString(shader.vertex.data) + "\n\nFRAGMENT=\n" + toString(shader.fragment.data);
@@ -81,16 +78,29 @@ class Drawable extends Sprite {
 	}
 
 	public inline function getShaders() {
-		return new hxd.impl.ArrayIterator<hxsl.Shader>(shaders);
+		return shaders.iterator();
 	}
 
 	public function addShader<T:hxsl.Shader>( s : T ) : T {
-		this.shaders.push(s);
+		if( s == null ) throw "Can't add null shader";
+		shaders = new hxsl.ShaderList(s, shaders);
 		return s;
 	}
 
 	public function removeShader( s : hxsl.Shader ) {
-		return this.shaders.remove(s);
+		var prev = null, cur = shaders;
+		while( cur != null ) {
+			if( cur.s == s ) {
+				if( prev == null )
+					shaders = cur.next;
+				else
+					prev.next = cur.next;
+				return true;
+			}
+			prev = cur;
+			cur = cur.next;
+		}
+		return false;
 	}
 
 	function emitTile( ctx : RenderContext, tile : Tile ) {

+ 28 - 22
h2d/RenderContext.hx

@@ -16,7 +16,8 @@ class RenderContext {
 	var compiledShader : hxsl.RuntimeShader;
 	var buffers : h3d.shader.Buffers;
 	var pass : h3d.mat.Pass;
-	var currentShaders : Array<hxsl.Shader>;
+	var currentShaders : hxsl.ShaderList;
+	var baseShaderList : hxsl.ShaderList;
 	var currentObj : Drawable;
 	var stride : Int;
 
@@ -31,7 +32,9 @@ class RenderContext {
 		pass.depth(true, Always);
 		pass.culling = None;
 		baseShader = new h3d.shader.Base2d();
+		baseShader.priority = 100;
 		baseShader.zValue = 0.;
+		baseShaderList = new hxsl.ShaderList(baseShader);
 	}
 
 	public function begin() {
@@ -39,7 +42,8 @@ class RenderContext {
 		currentObj = null;
 		bufPos = 0;
 		stride = 0;
-		initShaders([baseShader]);
+		baseShaderList.next = null;
+		initShaders(baseShaderList);
 		engine.selectMaterial(pass);
 	}
 
@@ -59,6 +63,7 @@ class RenderContext {
 		flush();
 		texture = null;
 		currentObj = null;
+		baseShaderList.next = null;
 	}
 
 	public function setTarget( t : h3d.mat.Texture ) {
@@ -124,34 +129,35 @@ class RenderContext {
 		if( currentObj != null && (texture != this.texture || stride != this.stride || obj.blendMode != currentObj.blendMode || obj.filter != currentObj.filter) )
 			flush();
 		var shaderChanged = false, paramsChanged = false;
-		if( obj.shaders.length + 1 != currentShaders.length )
-			shaderChanged = true;
-		else {
-			for( i in 0...obj.shaders.length ) {
-				var s = obj.shaders[i];
-				var t = currentShaders[i + 1];
-				if( s == t ) continue;
-				paramsChanged = true;
-				s.updateConstants(manager.globals);
-				@:privateAccess {
-					if( s.instance != t.instance )
-						shaderChanged = true;
-				}
+		var objShaders = obj.shaders;
+		var curShaders = currentShaders.next;
+		while( objShaders != null && curShaders != null ) {
+			var s = objShaders.s;
+			var t = curShaders.s;
+			objShaders = objShaders.next;
+			curShaders = curShaders.next;
+			if( s == t ) continue;
+			paramsChanged = true;
+			s.updateConstants(manager.globals);
+			@:privateAccess {
+				if( s.instance != t.instance )
+					shaderChanged = true;
 			}
 		}
-		if( baseShader.isRelative != isRelative )
+		if( objShaders != null || curShaders != null || baseShader.isRelative != isRelative )
 			shaderChanged = true;
 		if( shaderChanged ) {
 			flush();
-			var ns = obj.shaders.copy();
-			ns.unshift(baseShader);
+
 			baseShader.isRelative = isRelative;
-			initShaders(ns);
+			baseShader.updateConstants(manager.globals);
+			baseShaderList.next = obj.shaders;
+			initShaders(baseShaderList);
 		} else if( paramsChanged ) {
 			flush();
-			// copy so the next flush will fetch their params
-			for( i in 0...obj.shaders.length )
-				currentShaders[i+1] = obj.shaders[i];
+			if( currentShaders != baseShaderList ) throw "!";
+			// the next flush will fetch their params
+			currentShaders.next = obj.shaders;
 		}
 
 		this.texture = texture;

+ 4 - 23
h3d/pass/Default.hx

@@ -48,9 +48,7 @@ class Default extends Base {
 	}
 
 	override function compileShader( p : h3d.mat.Pass ) {
-		var out = [for( s in p.getShadersRec() ) s];
-		out.reverse();
-		return manager.compileShaders(out);
+		return manager.compileShaders(p.getShadersRec());
 	}
 
 	override function getLightSystem() {
@@ -88,9 +86,9 @@ class Default extends Base {
 	function setupShaders( passes : Object ) {
 		var p = passes;
 		var lightInit = false;
-		var instances = [];
 		while( p != null ) {
 			var shaders = p.pass.getShadersRec();
+			shaders = processShaders(p, shaders);
 			if( p.pass.enableLights && lightSystem != null ) {
 				if( !lightInit ) {
 					lightSystem.initLights(ctx.lights);
@@ -98,25 +96,8 @@ class Default extends Base {
 				}
 				shaders = lightSystem.computeLight(p.obj, shaders);
 			}
-			shaders = processShaders(p, shaders);
-			var count = 0;
-			for( s in shaders )
-				p.shaders[count++] = s;
-			// TODO : allow reversed shader compilation !
-			// reverse
-			for( n in 0...count >> 1 ) {
-				var n2 = count - 1 - n;
-				var tmp = p.shaders[n];
-				p.shaders[n] = p.shaders[n2];
-				p.shaders[n2] = tmp;
-			}
-			for( i in 0...count ) {
-				var s = p.shaders[i];
- 				s.updateConstants(globals);
-				instances[i] = @:privateAccess s.instance;
-			}
-			instances[count] = null; // mark end
-			p.shader = manager.compileInstances(instances);
+			p.shader = manager.compileShaders(shaders);
+			p.shaders = shaders;
 			p = p.next;
 		}
 	}

+ 4 - 3
h3d/pass/LightSystem.hx

@@ -10,6 +10,7 @@ class LightSystem {
 	var ambientShader : h3d.shader.AmbientLight;
 	var lightCount : Int;
 	var cachedShaderList : Array<hxsl.ShaderList>;
+	var cachedPos : Int;
 	@global("global.ambientLight") public var ambientLight : h3d.Vector;
 	@global("global.perPixelLighting") public var perPixelLighting : Bool;
 
@@ -24,6 +25,7 @@ class LightSystem {
 	public function initLights( lights : h3d.scene.Light ) {
 		this.lights = lights;
 		lightCount = 0;
+		cachedPos = 0;
 		var l = lights;
 		while( l != null ) {
 			lightCount++;
@@ -51,12 +53,11 @@ class LightSystem {
 			}
 			lights = haxe.ds.ListSort.sortSingleLinked(lights, sortLight);
 		}
-		var k = 0;
 		inline function add( s : hxsl.Shader ) {
-			var sl = cachedShaderList[k++];
+			var sl = cachedShaderList[cachedPos++];
 			if( sl == null ) {
 				sl = new hxsl.ShaderList(null);
-				cachedShaderList[k - 1] = sl;
+				cachedShaderList[cachedPos - 1] = sl;
 			}
 			sl.s = s;
 			sl.next = shaders;

+ 5 - 3
h3d/pass/Object.hx

@@ -3,11 +3,13 @@ package h3d.pass;
 class Object {
 	public var pass : h3d.mat.Pass;
 	public var obj : h3d.scene.Object;
-	public var shaders : Array<hxsl.Shader>;
-	public var shader : hxsl.RuntimeShader;
 	public var index : Int;
 	public var next : Object;
+
+	// cache
+	public var shaders : hxsl.ShaderList;
+	public var shader : hxsl.RuntimeShader;
+
 	public function new() {
-		shaders = [];
 	}
 }

+ 2 - 1
h3d/pass/ScreenFx.hx

@@ -8,9 +8,11 @@ class ScreenFx<T:hxsl.Shader> {
 	var plan : h3d.prim.Primitive;
 	var engine : h3d.Engine;
 	var fullClearRequired : Bool;
+	var shaders : hxsl.ShaderList;
 
 	public function new(shader) {
 		this.shader = shader;
+		shaders = new hxsl.ShaderList(shader);
 		manager = new h3d.shader.Manager(["output.position", "output.color"]);
 		pass = new h3d.mat.Pass(Std.string(this), new hxsl.ShaderList(shader));
 		pass.culling = None;
@@ -21,7 +23,6 @@ class ScreenFx<T:hxsl.Shader> {
 	}
 
 	public function render() {
-		var shaders : Array<hxsl.Shader> = [shader];
 		var rts = manager.compileShaders(shaders);
 		engine.selectMaterial(pass);
 		engine.selectShader(rts);

+ 1 - 2
h3d/scene/RenderContext.hx

@@ -72,9 +72,8 @@ class RenderContext {
 			p.obj = null;
 			p.pass = null;
 			p.shader = null;
+			p.shaders = null;
 			p.index = 0;
-			for( i in 0...p.shaders.length )
-				p.shaders[i] = null;
 			prev = p;
 			p = p.next;
 		}

+ 10 - 11
h3d/shader/Manager.hx

@@ -87,14 +87,17 @@ class Manager {
 		return 0;
 	}
 
-	inline function getParamValue( p : hxsl.RuntimeShader.AllocParam, shaders : Array<hxsl.Shader> ) : Dynamic {
+	function getParamValue( p : hxsl.RuntimeShader.AllocParam, shaders : hxsl.ShaderList ) : Dynamic {
 		if( p.perObjectGlobal != null ) {
 			var v = globals.fastGet(p.perObjectGlobal.gid);
 			if( v == null ) throw "Missing global value " + p.perObjectGlobal.path;
 			return v;
 		}
-		var v = shaders[p.instance].getParamValue(p.index);
-		if( v == null ) throw "Missing param value " + shaders[p.instance] + "." + p.name;
+		var si = shaders;
+		var n = p.instance;
+		while( n-- > 0 ) si = si.next;
+		var v = si.s.getParamValue(p.index);
+		if( v == null ) throw "Missing param value " + si.s + "." + p.name;
 		return v;
 	}
 
@@ -116,7 +119,7 @@ class Manager {
 		fill(buf.fragment, s.fragment);
 	}
 
-	public function fillParams( buf : Buffers, s : hxsl.RuntimeShader, shaders : Array<hxsl.Shader> ) {
+	public function fillParams( buf : Buffers, s : hxsl.RuntimeShader, shaders : hxsl.ShaderList ) {
 		inline function fill(buf:Buffers.ShaderBuffers, s:hxsl.RuntimeShader.RuntimeShaderData) {
 			for( p in s.params ) {
 				var v = getParamValue(p, shaders);
@@ -133,13 +136,9 @@ class Manager {
 		fill(buf.fragment, s.fragment);
 	}
 
-	public function compileShaders( shaders : Array<hxsl.Shader> ) {
-		var instances = [for( s in shaders ) if( s != null ) { s.updateConstants(globals); @:privateAccess s.instance; }];
-		return shaderCache.link(instances, output);
-	}
-
-	public inline function compileInstances( instances : Array<hxsl.SharedShader.ShaderInstance> ) {
-		return shaderCache.link(instances, output);
+	public function compileShaders( shaders : hxsl.ShaderList ) {
+		for( s in shaders ) s.updateConstants(globals);
+		return shaderCache.link(shaders, output);
 	}
 
 }

+ 15 - 11
hxsl/Cache.hx

@@ -41,14 +41,14 @@ class Cache {
 		return id;
 	}
 
-	public function link( instances : Array<SharedShader.ShaderInstance>, outVars : Int ) {
+	public function link( shaders : hxsl.ShaderList, outVars : Int ) {
 		var c = linkCache.get(outVars);
 		if( c == null ) {
 			c = new SearchMap();
 			linkCache.set(outVars, c);
 		}
-		for( i in instances ) {
-			if( i == null ) break;
+		for( s in shaders ) {
+			var i = @:privateAccess s.instance;
 			if( c.next == null ) c.next = new Map();
 			var cs = c.next.get(i.id);
 			if( cs == null ) {
@@ -60,13 +60,17 @@ class Cache {
 		if( c.linked != null )
 			return c.linked;
 
-		var linker = new hxsl.Linker();
-		var shaders = [];
-		for( i in instances ) {
-			if( i == null ) break;
-			shaders.push(i.shader);
+		var shaderDatas = [];
+		var index = 0;
+		for( s in shaders ) {
+			var i = @:privateAccess s.instance;
+			shaderDatas.push( { inst : i, p : s.priority, index : index++ } );
 		}
-		var s = linker.link(shaders, this.outVars[outVars]);
+		shaderDatas.reverse(); // default is reverse order
+		haxe.ds.ArraySort.sort(shaderDatas, function(s1, s2) return s2.p - s1.p);
+
+		var linker = new hxsl.Linker();
+		var s = linker.link([for( s in shaderDatas ) s.inst.shader], this.outVars[outVars]);
 
 		// params tracking
 		var paramVars = new Map();
@@ -76,8 +80,8 @@ class Cache {
 				case TStruct(_): continue;
 				default:
 				}
-				var i = instances[v.instanceIndex];
-				paramVars.set(v.id, { instance : v.instanceIndex, index : i.params.get(v.merged[0].id) } );
+				var inf = shaderDatas[v.instanceIndex];
+				paramVars.set(v.id, { instance : inf.index, index : inf.inst.params.get(v.merged[0].id) } );
 			}
 
 		var s = new hxsl.Splitter().split(s);

+ 1 - 3
hxsl/Checker.hx

@@ -40,15 +40,13 @@ class Checker {
 		for( g in Ast.TGlobal.createAll() ) {
 			var def = switch( g ) {
 			case Vec2, Vec3, Vec4, Mat2, Mat3, Mat3x4, Mat4, IVec2, IVec3, IVec4, BVec2, BVec3, BVec4: [];
-			case Radians, Degrees, Cos, Sin, Tan, Asin, Acos, Exp, Log, Exp2, Log2, Sqrt, Inversesqrt, Abs, Sign, Floor, Ceil, Fract: genFloat;
+			case Radians, Degrees, Cos, Sin, Tan, Asin, Acos, Exp, Log, Exp2, Log2, Sqrt, Inversesqrt, Abs, Sign, Floor, Ceil, Fract, Saturate: genFloat;
 			case Atan: genFloat.concat(genFloat2);
 			case Pow: genFloat2;
 			case LReflect:
 				genFloat2;
 			case Mod, Min, Max:
 				genFloat2.concat(genWithFloat);
-			case Saturate:
-				[ { args : [ { name : "value", type : TFloat } ], ret : TFloat } ];
 			case Length:
 				[for( t in genType ) { args : [ { name : "value", type : t } ], ret : TFloat } ];
 			case Distance, Dot:

+ 1 - 0
hxsl/Shader.hx

@@ -4,6 +4,7 @@ using hxsl.Ast;
 @:autoBuild(hxsl.Macros.buildShader())
 class Shader {
 
+	public var priority : Int = 0;
 	var shader : SharedShader;
 	var instance : SharedShader.ShaderInstance;
 	var constBits : Int;