Просмотр исходного кода

added hxd.impl.Allocator and CacheAllocator, use in MeshBatch and DynamicPrimitive

Nicolas Cannasse 6 лет назад
Родитель
Сommit
8589e3d74a
4 измененных файлов с 162 добавлено и 14 удалено
  1. 18 10
      h3d/prim/DynamicPrimitive.hx
  2. 7 4
      h3d/scene/MeshBatch.hx
  3. 60 0
      hxd/impl/Allocator.hx
  4. 77 0
      hxd/impl/CacheAllocator.hx

+ 18 - 10
h3d/prim/DynamicPrimitive.hx

@@ -19,43 +19,44 @@ class DynamicPrimitive extends Primitive {
 	}
 
 	public function getBuffer( vertices : Int ) {
-		if( vbuf == null ) vbuf = new hxd.FloatBuffer(vertices * stride) else vbuf.grow(vertices * stride);
+		if( vbuf == null ) vbuf = hxd.impl.Allocator.get().allocFloats(vertices * stride) else vbuf.grow(vertices * stride);
 		vsize = vertices;
 		return vbuf;
 	}
 
 	public function getIndexes( count : Int ) {
-		if( ibuf == null ) ibuf = new hxd.IndexBuffer(count) else ibuf.grow(count);
+		if( ibuf == null ) ibuf = hxd.impl.Allocator.get().allocIndexes(count) else ibuf.grow(count);
 		isize = count;
 		return ibuf;
 	}
 
 	public function flush() {
+		var alloc = hxd.impl.Allocator.get();
 		if( vsize == 0 || isize == 0 ) {
 			if( buffer != null ) {
-				buffer.dispose();
+				alloc.disposeBuffer(buffer);
 				buffer = null;
 			}
 			if( indexes != null ) {
-				indexes.dispose();
+				alloc.disposeIndexBuffer(indexes);
 				indexes = null;
 			}
 			return;
 		}
 
 		if( buffer != null && (buffer.isDisposed() || buffer.vertices < vsize) ) {
-			buffer.dispose();
+			alloc.disposeBuffer(buffer);
 			buffer = null;
 		}
 		if( indexes != null && (indexes.isDisposed() || indexes.count < isize) ) {
-			indexes.dispose();
+			alloc.disposeIndexBuffer(indexes);
 			indexes = null;
 		}
 
 		if( buffer == null )
-			buffer = new h3d.Buffer(vsize, stride);
+			buffer = alloc.allocBuffer(vsize, stride, Dynamic);
 		if( indexes == null )
-			indexes = new h3d.Indexes(isize);
+			indexes = alloc.allocIndexBuffer(isize);
 
 		buffer.uploadVector(vbuf, 0, vsize);
 		indexes.upload(ibuf, 0, isize);
@@ -63,8 +64,15 @@ class DynamicPrimitive extends Primitive {
 
 	override function dispose() {
 		super.dispose();
-		vbuf = null;
-		ibuf = null;
+		var alloc = hxd.impl.Allocator.get();
+		if( vbuf != null ) {
+			alloc.disposeFloats(vbuf);
+			vbuf = null;
+		}
+		if( ibuf != null ) {
+			alloc.disposeIndexes(ibuf);
+			ibuf = null;
+		}
 	}
 
 	override function triCount() {

+ 7 - 4
h3d/scene/MeshBatch.hx

@@ -33,7 +33,7 @@ class MeshBatch extends Mesh {
 	var modelViewInverseID = hxsl.Globals.allocID("global.modelViewInverse");
 	var colorSave = new h3d.Vector();
 	var colorMult : h3d.shader.ColorMult;
-	
+
 	/**
 		Tells if we can use material.color as a global multiply over each instance color (default: true)
 	**/
@@ -66,9 +66,11 @@ class MeshBatch extends Mesh {
 	}
 
 	function cleanPasses() {
+		var alloc = hxd.impl.Allocator.get();
 		while( dataPasses != null ) {
 			dataPasses.pass.removeShader(dataPasses.shader);
-			dataPasses.buffer.dispose();
+			alloc.disposeBuffer(dataPasses.buffer);
+			alloc.disposeFloats(dataPasses.data);
 			dataPasses = dataPasses.next;
 		}
 		instanced.commands.dispose();
@@ -115,8 +117,9 @@ class MeshBatch extends Mesh {
 			b.shader = shader;
 			b.pass = p;
 			b.shaders = [null/*link shader*/];
-			b.buffer = new h3d.Buffer(tot,4,[UniformBuffer,Dynamic]);
-			b.data = new hxd.FloatBuffer(tot * 4);
+			var alloc = hxd.impl.Allocator.get();
+			b.buffer = alloc.allocBuffer(tot,4,UniformDynamic);
+			b.data = alloc.allocFloats(tot * 4);
 			b.next = dataPasses;
 			dataPasses = b;
 

+ 60 - 0
hxd/impl/Allocator.hx

@@ -0,0 +1,60 @@
+package hxd.impl;
+import h3d.impl.AllocPos;
+
+@:enum abstract BufferFlags(Int) {
+	public var Dynamic = 0;
+	public var UniformDynamic = 1;
+	public inline function toInt() : Int {
+		return this;
+	}
+}
+
+class Allocator {
+
+	public function new() {
+	}
+
+	// GPU
+
+	public function allocBuffer( vertices : Int, stride : Int, flags : BufferFlags, ?pos : AllocPos ) : h3d.Buffer {
+		return new h3d.Buffer(vertices, stride, switch( flags ) { case Dynamic: [Dynamic]; case UniformDynamic: [UniformBuffer,Dynamic]; }, pos);
+	}
+
+	public function disposeBuffer( b : h3d.Buffer ) {
+		b.dispose();
+	}
+
+	public function allocIndexBuffer( count : Int ) {
+		return new h3d.Indexes(count);
+	}
+
+	public function disposeIndexBuffer( i : h3d.Indexes ) {
+		i.dispose();
+	}
+
+	// CPU
+
+	public function allocFloats( count : Int, ?pos : AllocPos ) : hxd.FloatBuffer {
+		return new hxd.FloatBuffer(count);
+	}
+
+	public function disposeFloats( f : hxd.FloatBuffer ) {
+	}
+
+	public function allocIndexes( count : Int ) {
+		return new hxd.IndexBuffer(count);
+	}
+
+	public function disposeIndexes( i : hxd.IndexBuffer ) {
+	}
+
+	static var inst : Allocator;
+	public static function set( a : Allocator ) {
+		inst = a;
+	}
+	public static function get() : Allocator {
+		if( inst == null ) inst = new Allocator();
+		return inst;
+	}
+
+}

+ 77 - 0
hxd/impl/CacheAllocator.hx

@@ -0,0 +1,77 @@
+package hxd.impl;
+import hxd.impl.Allocator;
+import h3d.impl.AllocPos;
+
+private class Cache<T> {
+	public var content : Array<T> = [];
+	public var lastUse : Float = haxe.Timer.stamp();
+	public var onDispose : T -> Void;
+	public function new( ?dispose ) {
+		onDispose = dispose;
+	}
+	public inline function get() {
+		var b = content.pop();
+		if( content.length == 0 ) lastUse = haxe.Timer.stamp();
+		return b;
+	}
+	public inline function put(v) {
+		content.push(v);
+	}
+	public function gc() {
+		var b = content.pop();
+		if( b == null ) return false;
+		if( onDispose != null ) onDispose(b);
+		lastUse += 1;
+		return true;
+	}
+}
+
+class CacheAllocator extends Allocator {
+
+	var buffers = new Map<Int,Cache<h3d.Buffer>>();
+	var lastGC = haxe.Timer.stamp();
+	/**
+	 * How long do we keep some buffer than hasn't been used in memory (in seconds, default 60)
+	**/
+	public var maxKeepTime = 60.;
+
+	override function allocBuffer(vertices:Int, stride:Int, flags:BufferFlags, ?pos:AllocPos):h3d.Buffer {
+		if( vertices >= 65536 ) throw "assert";
+		var id = flags.toInt() | (stride << 3) | (vertices << 16);
+		var c = buffers.get(id);
+		if( c != null ) {
+			var b = c.get();
+			if( b != null ) return b;
+		}
+		checkGC();
+		return super.allocBuffer(vertices,stride,flags,pos);
+	}
+
+	override function disposeBuffer(b:h3d.Buffer) {
+		var flags = b.flags.has(UniformBuffer) ? UniformDynamic : Dynamic;
+		var id = flags.toInt() | (b.buffer.stride << 3) | (b.vertices << 16);
+		var c = buffers.get(id);
+		if( c == null ) {
+			c = new Cache(function(b:h3d.Buffer) b.dispose());
+			buffers.set(id, c);
+		}
+		c.put(b);
+		checkGC();
+	}
+
+	public function checkGC() {
+		var t = haxe.Timer.stamp();
+		if( t - lastGC > maxKeepTime * 0.1 ) gc();
+	}
+
+	public function gc() {
+		var now = haxe.Timer.stamp();
+		for( b in buffers.keys() ) {
+			var c = buffers.get(b);
+			if( now - c.lastUse > maxKeepTime && !c.gc() )
+				buffers.remove(b);
+		}
+		lastGC = now;
+	}
+
+}