浏览代码

switch from Array<Shader> to shader list, allow zero-allocation and easy chaining

Nicolas Cannasse 11 年之前
父节点
当前提交
0d3424c59a
共有 8 个文件被更改,包括 78 次插入80 次删除
  1. 19 9
      h2d/Drawable.hx
  2. 23 22
      h2d/RenderContext.hx
  3. 8 24
      h3d/pass/Base.hx
  4. 5 3
      h3d/pass/Object.hx
  5. 2 1
      h3d/pass/ScreenFx.hx
  6. 1 2
      h3d/scene/RenderContext.hx
  7. 10 11
      h3d/shader/Manager.hx
  8. 10 8
      hxsl/Cache.hx

+ 19 - 9
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);
+	public function addShader < T:hxsl.Shader > ( s : T ) : T {
+		if( s == null ) throw "Can't add nuull 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 ) {

+ 23 - 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;
 
@@ -32,6 +33,7 @@ class RenderContext {
 		pass.culling = None;
 		baseShader = new h3d.shader.Base2d();
 		baseShader.zValue = 0.;
+		baseShaderList = new hxsl.ShaderList(baseShader);
 	}
 
 	public function begin() {
@@ -39,7 +41,8 @@ class RenderContext {
 		currentObj = null;
 		bufPos = 0;
 		stride = 0;
-		initShaders([baseShader]);
+		baseShaderList.next = null;
+		initShaders(baseShaderList);
 		engine.selectMaterial(pass);
 	}
 
@@ -59,6 +62,7 @@ class RenderContext {
 		flush();
 		texture = null;
 		currentObj = null;
+		baseShaderList.next = null;
 	}
 
 	public function flush() {
@@ -117,34 +121,31 @@ 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);
+			baseShaderList.next = obj.shaders;
 			baseShader.isRelative = isRelative;
-			initShaders(ns);
+			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];
+			currentShaders.next = obj.shaders;
 		}
 
 		this.texture = texture;

+ 8 - 24
h3d/pass/Base.hx

@@ -38,12 +38,10 @@ class Base {
 	}
 
 	public 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());
 	}
 
-	function initBuffer( s : hxsl.RuntimeShader, shaders : Array<hxsl.Shader> ) {
+	function initBuffer( s : hxsl.RuntimeShader, shaders : hxsl.ShaderList ) {
 		if( cachedBuffer == null )
 			cachedBuffer = new h3d.shader.Buffers(s);
 		else
@@ -58,7 +56,6 @@ class Base {
 	function setupShaders( passes : Object ) {
 		var p = passes;
 		var lightInit = false;
-		var instances = [];
 		while( p != null ) {
 			var shaders = p.pass.getShadersRec();
 			if( p.pass.enableLights && lightSystem != null ) {
@@ -66,24 +63,7 @@ class Base {
 					lightSystem.initLights(ctx.lights);
 				shaders = lightSystem.computeLight(p.obj, 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 = p.next;
 		}
 	}
@@ -104,6 +84,7 @@ class Base {
 		setupShaders(passes);
 		passes = haxe.ds.ListSort.sortSingleLinked(passes, sortByShader);
 		var p = passes;
+		var curShaderID = -1;
 		while( p != null ) {
 			globalModelView = p.obj.absPos;
 			//if( p.shader.hasGlobal(globalModelViewInverseId) )
@@ -111,7 +92,10 @@ class Base {
 			ctx.engine.selectShader(p.shader);
 			var buf = initBuffer(p.shader, p.shaders);
 			ctx.engine.selectMaterial(p.pass);
-			ctx.engine.uploadShaderBuffers(buf, Globals);
+			if( p.shader.id != curShaderID ) {
+				curShaderID = p.shader.id;
+				ctx.engine.uploadShaderBuffers(buf, Globals);
+			}
 			ctx.engine.uploadShaderBuffers(buf, Params);
 			ctx.engine.uploadShaderBuffers(buf, Textures);
 			ctx.drawPass = p;

+ 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

@@ -7,9 +7,11 @@ class ScreenFx<T:hxsl.Shader> {
 	var manager : h3d.shader.Manager;
 	var plan : h3d.prim.Plan2D;
 	var engine : h3d.Engine;
+	var shaders : hxsl.ShaderList;
 
 	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;
@@ -19,7 +21,6 @@ class ScreenFx<T:hxsl.Shader> {
 	}
 
 	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

@@ -68,9 +68,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 {
+	inline 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);
 	}
 
 }

+ 10 - 8
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 ) {
@@ -61,12 +61,14 @@ class Cache {
 			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 instances = [];
+		for( s in shaders ) {
+			var i = @:privateAccess s.instance;
+			instances.push(i);
+			shaderDatas.push(i.shader);
 		}
-		var s = linker.link(shaders, this.outVars[outVars]);
+		var s = linker.link(shaderDatas, this.outVars[outVars]);
 
 		// params tracking
 		var paramVars = new Map();