瀏覽代碼

removed ManagedBuffer and buffer split

Nicolas Cannasse 2 年之前
父節點
當前提交
eb47b6cd15

+ 2 - 2
h2d/TileGroup.hx

@@ -26,7 +26,7 @@ class TileLayerContent extends h3d.prim.Primitive {
 		Content bounds bottom edge.
 	**/
 	public var yMax : Float;
-	
+
 	public var useAllocatorLimit = 1024;
 
 	var state : BatchDrawState;
@@ -58,7 +58,7 @@ class TileLayerContent extends h3d.prim.Primitive {
 	}
 
 	override public function triCount() {
-		return if( buffer == null ) tmp.length >> 4 else buffer.totalVertices() >> 1;
+		return if( buffer == null ) tmp.length >> 4 else buffer.vertices >> 1;
 	}
 
 	/**

+ 19 - 73
h3d/Buffer.hx

@@ -13,10 +13,6 @@ enum BufferFlag {
 		The buffer contains only quads. Imply Managed. Make sure the position is aligned on 4 vertices multiples.
 	**/
 	Quads;
-	/**
-		Will allocate the memory as part of an shared buffer pool, preventing a lot of small GPU buffers to be allocated.
-	**/
-	Managed;
 	/**
 		Directly map the buffer content to the shader inputs, without assuming [pos:vec3,normal:vec3,uv:vec2] default prefix.
 	**/
@@ -29,12 +25,9 @@ enum BufferFlag {
 		Used for shader input buffer
 	**/
 	UniformBuffer;
-	/**
-		Use to allow to alloc buffers with >64K vertices (requires 32 bit indexes)
-	**/
-	LargeBuffer;
 }
 
+@:allow(h3d.impl.MemoryManager)
 class Buffer {
 	public static var GUID = 0;
 	public var id : Int;
@@ -43,15 +36,16 @@ class Buffer {
 	var allocNext : Buffer;
 	#end
 
-	public var buffer(default,null) : h3d.impl.ManagedBuffer;
-	public var position(default,null) : Int;
+	var mem : h3d.impl.MemoryManager;
+	var vbuf : h3d.impl.Driver.GPUBuffer;
 	public var vertices(default,null) : Int;
-	public var next(default,null) : Buffer;
+	public var stride(default,null) : Int;
 	public var flags(default, null) : haxe.EnumFlags<BufferFlag>;
 
 	public function new(vertices, stride, ?flags : Array<BufferFlag> ) {
 		id = GUID++;
 		this.vertices = vertices;
+		this.stride = stride;
 		this.flags = new haxe.EnumFlags();
 		#if track_alloc
 		this.allocPos = new hxd.impl.AllocPos();
@@ -59,85 +53,37 @@ class Buffer {
 		if( flags != null )
 			for( f in flags )
 				this.flags.set(f);
-		#if flash
-		// flash strictly requires indexes to be within the bounds of the buffer
-		// so we cannot use quad/triangle indexes unless the buffer is large enough
-		if( this.flags.has(Quads) || this.flags.has(Triangles) )
-			this.flags.set(Managed);
-		#end
 		if( !this.flags.has(NoAlloc) )
-			h3d.Engine.getCurrent().mem.allocBuffer(this, stride);
+			@:privateAccess h3d.Engine.getCurrent().mem.allocBuffer(this);
 	}
 
 	public inline function isDisposed() {
-		return buffer == null || buffer.isDisposed();
+		return vbuf == null;
 	}
 
 	public function dispose() {
-		if( buffer != null ) {
-			buffer.freeBuffer(this);
-			buffer = null;
-			if( next != null ) next.dispose();
-		}
-	}
-
-	/**
-		Returns the total number of vertices including the potential next buffers if it is split.
-	**/
-	public function totalVertices() {
-		var count = 0;
-		var b = this;
-		while( b != null ) {
-			count += b.vertices;
-			b = b.next;
+		if( vbuf != null ) {
+			@:privateAccess mem.freeBuffer(this);
+			vbuf = null;
 		}
-		return count;
 	}
 
 	public function uploadVector( buf : hxd.FloatBuffer, bufPos : Int, vertices : Int, startVertice = 0 ) {
-		var cur = this;
-		while( cur != null && startVertice >= cur.vertices ) {
-			startVertice -= cur.vertices;
-			cur = cur.next;
-		}
-		while( vertices > 0 ) {
-			if( cur == null ) throw "Too many vertices";
-			var count = vertices + startVertice > cur.vertices ? cur.vertices - startVertice : vertices;
-			cur.buffer.uploadVertexBuffer(cur.position + startVertice, count, buf, bufPos);
-			startVertice = 0;
-			bufPos += count * buffer.stride;
-			vertices -= count;
-			cur = cur.next;
-		}
+		if( startVertice < 0 || vertices < 0 || startVertice + vertices > this.vertices )
+			throw "Invalid vertices count";
+		mem.driver.uploadBufferData(vbuf, startVertice, vertices, buf, bufPos);
 	}
 
 	public function uploadBytes( data : haxe.io.Bytes, dataPos : Int, vertices : Int ) {
-		var cur = this;
-		while( vertices > 0 ) {
-			if( cur == null ) throw "Too many vertices";
-			var count = vertices > cur.vertices ? cur.vertices : vertices;
-			cur.buffer.uploadVertexBytes(cur.position, count, data, dataPos);
-			dataPos += count * buffer.stride * 4;
-			vertices -= count;
-			cur = cur.next;
-		}
+		if( vertices < 0 || vertices > this.vertices )
+			throw "Invalid vertices count";
+		mem.driver.uploadBufferBytes(vbuf, 0, vertices, data, dataPos);
 	}
 
 	public function readBytes( bytes : haxe.io.Bytes, bytesPosition : Int, vertices : Int,  startVertice : Int = 0 ) {
-		var cur = this;
-		while( cur != null && startVertice >= cur.vertices ) {
-			startVertice -= cur.vertices;
-			cur = cur.next;
-		}
-		while( vertices > 0 ) {
-			if( cur == null ) throw "Too many vertices";
-			var count = vertices + startVertice > cur.vertices ? cur.vertices - startVertice : vertices;
-			cur.buffer.readVertexBytes(cur.position + startVertice, count, bytes, bytesPosition);
-			startVertice = 0;
-			bytesPosition += count * buffer.stride * 4;
-			vertices -= count;
-			cur = cur.next;
-		}
+		if( startVertice < 0 || vertices < 0 || startVertice + vertices > this.vertices )
+			throw "Invalid vertices count";
+		mem.driver.readBufferBytes(vbuf, startVertice, vertices, bytes, bytesPosition);
 	}
 
 	public static function ofFloats( v : hxd.FloatBuffer, stride : Int, ?flags ) {

+ 11 - 31
h3d/Engine.hx

@@ -153,41 +153,21 @@ class Engine {
 	function renderBuffer( b : Buffer, indexes : Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
 		if( indexes.isDisposed() )
 			return;
-		do {
-			var ntri = Std.int(b.vertices / vertPerTri);
-			var pos = Std.int(b.position / vertPerTri);
-			if( startTri > 0 ) {
-				if( startTri >= ntri ) {
-					startTri -= ntri;
-					b = b.next;
-					continue;
-				}
-				pos += startTri;
-				ntri -= startTri;
-				startTri = 0;
-			}
-			if( drawTri >= 0 ) {
-				if( drawTri == 0 ) return;
-				drawTri -= ntri;
-				if( drawTri < 0 ) {
-					ntri += drawTri;
-					drawTri = 0;
-				}
-			}
-			if( ntri > 0 && selectBuffer(b) ) {
-				// *3 because it's the position in indexes which are always by 3
-				driver.draw(indexes.ibuf, pos * 3, ntri);
-				drawTriangles += ntri;
-				drawCalls++;
-			}
-			b = b.next;
-		} while( b != null );
+		var ntri = Std.int(b.vertices / vertPerTri);
+		if( drawTri < 0 )
+			drawTri = ntri - startTri;
+		if( startTri < 0 || drawTri < 0 || startTri + drawTri > ntri )
+			throw "Invalid vertices count";
+		if( drawTri > 0 && selectBuffer(b) ) {
+			// *3 because it's the position in indexes which are always by 3
+			driver.draw(indexes.ibuf, startTri * 3, drawTri);
+			drawTriangles += drawTri;
+			drawCalls++;
+		}
 	}
 
 	// we use custom indexes, so the number of triangles is the number of indexes/3
 	public function renderIndexed( b : Buffer, indexes : Indexes, startTri = 0, drawTri = -1 ) {
-		if( b.next != null )
-			throw "Buffer is split";
 		if( indexes.isDisposed() )
 			return;
 		var maxTri = Std.int(indexes.count / 3);

+ 24 - 24
h3d/impl/DirectXDriver.hx

@@ -315,12 +315,12 @@ class DirectXDriver extends h3d.impl.Driver {
 		return extraDepthInst;
 	}
 
-	override function allocVertexes(m:ManagedBuffer):VertexBuffer {
-		var size = m.size * m.stride * 4;
-		var uniform = m.flags.has(UniformBuffer);
+	override function allocBuffer(b:Buffer):GPUBuffer {
+		var size = b.vertices * b.stride * 4;
+		var uniform = b.flags.has(UniformBuffer);
 		var res = uniform ? dx.Driver.createBuffer(size, Dynamic, ConstantBuffer, CpuWrite, None, 0, null) : dx.Driver.createBuffer(size, Default, VertexBuffer, None, None, 0, null);
 		if( res == null ) return null;
-		return { res : res, count : m.size, stride : m.stride, uniform : uniform };
+		return { res : res, count : b.vertices, stride : b.stride, uniform : uniform };
 	}
 
 	override function allocIndexes( count : Int, is32 : Bool ) : IndexBuffer {
@@ -457,8 +457,8 @@ class DirectXDriver extends h3d.impl.Driver {
 					rt.release();
 	}
 
-	override function disposeVertexes(v:VertexBuffer) {
-		v.res.release();
+	override function disposeBuffer(b:GPUBuffer) {
+		b.res.release();
 	}
 
 	override function disposeIndexes(i:IndexBuffer) {
@@ -491,21 +491,21 @@ class DirectXDriver extends h3d.impl.Driver {
 		updateBuffer(i.res, @:privateAccess buf.b.offset(bufPos << i.bits), startIndice << i.bits, indiceCount << i.bits);
 	}
 
-	override function uploadVertexBuffer(v:VertexBuffer, startVertex:Int, vertexCount:Int, buf:hxd.FloatBuffer, bufPos:Int) {
+	override function uploadBufferData(b:GPUBuffer, startVertex:Int, vertexCount:Int, buf:hxd.FloatBuffer, bufPos:Int) {
 		if( hasDeviceError ) return;
 		var data = hl.Bytes.getArray(buf.getNative()).offset(bufPos<<2);
-		if( v.uniform ) {
+		if( b.uniform ) {
 			if( startVertex != 0 ) throw "assert";
-			var ptr = v.res.map(0, WriteDiscard, true, null);
+			var ptr = b.res.map(0, WriteDiscard, true, null);
 			if( ptr == null ) throw "Can't map buffer";
-			ptr.blit(0, data, 0, vertexCount * v.stride << 2);
-			v.res.unmap(0);
+			ptr.blit(0, data, 0, vertexCount * b.stride << 2);
+			b.res.unmap(0);
 			return;
 		}
-		updateBuffer(v.res, data, startVertex * v.stride << 2, vertexCount * v.stride << 2);
+		updateBuffer(b.res, data, startVertex * b.stride << 2, vertexCount * b.stride << 2);
 	}
 
-	override function uploadVertexBytes(v:VertexBuffer, startVertex:Int, vertexCount:Int, buf:haxe.io.Bytes, bufPos:Int) {
+	override function uploadBufferBytes(v:GPUBuffer, startVertex:Int, vertexCount:Int, buf:haxe.io.Bytes, bufPos:Int) {
 		if( hasDeviceError ) return;
 		if( v.uniform ) {
 			if( startVertex != 0 ) throw "assert";
@@ -533,17 +533,17 @@ class DirectXDriver extends h3d.impl.Driver {
 		tmp.release();
 	}
 
-	override function readVertexBytes(v:VertexBuffer, startVertex:Int, vertexCount:Int, buf:haxe.io.Bytes, bufPos:Int) {
-		var tmp = dx.Driver.createBuffer(vertexCount * v.stride * 4, Staging, None, CpuRead | CpuWrite, None, 0, null);
-		box.left = startVertex * v.stride * 4;
+	override function readBufferBytes(b:GPUBuffer, startVertex:Int, vertexCount:Int, buf:haxe.io.Bytes, bufPos:Int) {
+		var tmp = dx.Driver.createBuffer(vertexCount * b.stride * 4, Staging, None, CpuRead | CpuWrite, None, 0, null);
+		box.left = startVertex * b.stride * 4;
 		box.top = 0;
 		box.front = 0;
-		box.right = (startVertex + vertexCount) * 4 * v.stride;
+		box.right = (startVertex + vertexCount) * 4 * b.stride;
 		box.bottom = 1;
 		box.back = 1;
-		tmp.copySubresourceRegion(0, 0, 0, 0, v.res, 0, box);
+		tmp.copySubresourceRegion(0, 0, 0, 0, b.res, 0, box);
 		var ptr = tmp.map(0, Read, true, null);
-		@:privateAccess buf.b.blit(bufPos, ptr, 0, vertexCount * v.stride * 4);
+		@:privateAccess buf.b.blit(bufPos, ptr, 0, vertexCount * b.stride * 4);
 		tmp.unmap(0);
 		tmp.release();
 	}
@@ -1169,12 +1169,12 @@ class DirectXDriver extends h3d.impl.Driver {
 
 	override function selectBuffer(buffer:Buffer) {
 		if( hasDeviceError ) return;
-		var vbuf = @:privateAccess buffer.buffer.vbuf;
+		var vbuf = @:privateAccess buffer.vbuf;
 		var start = -1, max = -1, position = 0;
 		for( i in 0...currentShader.inputs.names.length ) {
 			if( currentVBuffers[i] != vbuf.res || offsets[i] != currentShader.offsets[i] << 2 ) {
 				currentVBuffers[i] = vbuf.res;
-				strides[i] = buffer.buffer.stride << 2;
+				strides[i] = buffer.stride << 2;
 				offsets[i] = currentShader.offsets[i] << 2;
 				if( start < 0 ) start = i;
 				max = i;
@@ -1189,11 +1189,11 @@ class DirectXDriver extends h3d.impl.Driver {
 		var index = 0;
 		var start = -1, max = -1;
 		while( bl != null ) {
-			var vbuf = @:privateAccess bl.buffer.buffer.vbuf;
+			var vbuf = @:privateAccess bl.buffer.vbuf;
 			if( currentVBuffers[index] != vbuf.res || offsets[index] != bl.offset << 2 ) {
 				currentVBuffers[index] = vbuf.res;
 				offsets[index] = bl.offset << 2;
-				strides[index] = bl.buffer.buffer.stride << 2;
+				strides[index] = bl.buffer.stride << 2;
 				if( start < 0 ) start = index;
 				max = index;
 			}
@@ -1258,7 +1258,7 @@ class DirectXDriver extends h3d.impl.Driver {
 			var first = -1;
 			var max = -1;
 			for( i in 0...shader.bufferCount ) {
-				var buf = @:privateAccess buffers.buffers[i].buffer.vbuf.res;
+				var buf = @:privateAccess buffers.buffers[i].vbuf.res;
 				var tid = i + 2;
 				if( buf != state.buffers[tid] ) {
 					state.buffers[tid] = buf;

+ 13 - 19
h3d/impl/Driver.hx

@@ -2,55 +2,49 @@ package h3d.impl;
 
 #if macro
 typedef IndexBuffer = {};
-typedef VertexBuffer = {};
+typedef GPUBuffer = {};
 typedef Texture = {};
 typedef DepthBuffer = {};
 typedef Query = {};
-#elseif flash
-typedef IndexBuffer = flash.display3D.IndexBuffer3D;
-typedef VertexBuffer = Stage3dDriver.VertexWrapper;
-typedef Texture = flash.display3D.textures.TextureBase;
-typedef DepthBuffer = {};
-typedef Query = {};
 #elseif js
 typedef IndexBuffer = { b : js.html.webgl.Buffer, is32 : Bool };
-typedef VertexBuffer = { b : js.html.webgl.Buffer, stride : Int #if multidriver, driver : Driver #end };
+typedef GPUBuffer = { b : js.html.webgl.Buffer, stride : Int #if multidriver, driver : Driver #end };
 typedef Texture = { t : js.html.webgl.Texture, width : Int, height : Int, internalFmt : Int, pixelFmt : Int, bits : Int, bias : Float, bind : Int #if multidriver, driver : Driver #end };
 typedef DepthBuffer = { r : js.html.webgl.Renderbuffer #if multidriver, driver : Driver #end };
 typedef Query = {};
 #elseif hlsdl
 typedef IndexBuffer = { b : sdl.GL.Buffer, is32 : Bool };
-typedef VertexBuffer = { b : sdl.GL.Buffer, stride : Int };
+typedef GPUBuffer = { b : sdl.GL.Buffer, stride : Int };
 typedef Texture = { t : sdl.GL.Texture, width : Int, height : Int, internalFmt : Int, pixelFmt : Int, bits : Int, bind : Int, bias : Float };
 typedef DepthBuffer = { r : sdl.GL.Renderbuffer };
 typedef Query = { q : sdl.GL.Query, kind : QueryKind };
 #elseif usegl
 typedef IndexBuffer = { b : haxe.GLTypes.Buffer, is32 : Bool };
-typedef VertexBuffer = { b : haxe.GLTypes.Buffer, stride : Int };
+typedef GPUBuffer = { b : haxe.GLTypes.Buffer, stride : Int };
 typedef Texture = { t : haxe.GLTypes.Texture, width : Int, height : Int, internalFmt : Int, pixelFmt : Int, bits : Int, bind : Int, bias : Float };
 typedef DepthBuffer = { r : haxe.GLTypes.Renderbuffer };
 typedef Query = { q : haxe.GLTypes.Query, kind : QueryKind };
 #elseif (hldx && dx12)
 typedef IndexBuffer = DX12Driver.IndexBufferData;
-typedef VertexBuffer = DX12Driver.VertexBufferData;
+typedef GPUBuffer = DX12Driver.VertexBufferData;
 typedef Texture = h3d.impl.DX12Driver.TextureData;
 typedef DepthBuffer = h3d.impl.DX12Driver.DepthBufferData;
 typedef Query = h3d.impl.DX12Driver.QueryData;
 #elseif hldx
 typedef IndexBuffer = { res : dx.Resource, count : Int, bits : Int };
-typedef VertexBuffer = { res : dx.Resource, count : Int, stride : Int, uniform : Bool };
+typedef GPUBuffer = { res : dx.Resource, count : Int, stride : Int, uniform : Bool };
 typedef Texture = { res : dx.Resource, view : dx.Driver.ShaderResourceView, rt : Array<dx.Driver.RenderTargetView>, mips : Int };
 typedef DepthBuffer = { res : dx.Resource, view : dx.Driver.DepthStencilView };
 typedef Query = {};
 #elseif usesys
 typedef IndexBuffer = haxe.GraphicsDriver.IndexBuffer;
-typedef VertexBuffer = haxe.GraphicsDriver.VertexBuffer;
+typedef GPUBuffer = haxe.GraphicsDriver.VertexBuffer;
 typedef Texture = haxe.GraphicsDriver.Texture;
 typedef DepthBuffer = haxe.GraphicsDriver.DepthBuffer;
 typedef Query = haxe.GraphicsDriver.Query;
 #else
 typedef IndexBuffer = {};
-typedef VertexBuffer = {};
+typedef GPUBuffer = {};
 typedef Texture = {};
 typedef DepthBuffer = {};
 typedef Query = {};
@@ -269,7 +263,7 @@ class Driver {
 		return null;
 	}
 
-	public function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
+	public function allocBuffer( b : h3d.Buffer ) : GPUBuffer {
 		return null;
 	}
 
@@ -282,7 +276,7 @@ class Driver {
 	public function disposeIndexes( i : IndexBuffer ) {
 	}
 
-	public function disposeVertexes( v : VertexBuffer ) {
+	public function disposeBuffer( b : GPUBuffer ) {
 	}
 
 	public function disposeInstanceBuffer( b : h3d.impl.InstanceBuffer ) {
@@ -294,10 +288,10 @@ class Driver {
 	public function uploadIndexBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes , bufPos : Int ) {
 	}
 
-	public function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
+	public function uploadBufferData( b : GPUBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
 	}
 
-	public function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
+	public function uploadBufferBytes( b : GPUBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
 	}
 
 	public function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
@@ -306,7 +300,7 @@ class Driver {
 	public function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
 	}
 
-	public function readVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
+	public function readBufferBytes( v : GPUBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
 		throw "Driver does not allow to read vertex bytes";
 	}
 

+ 26 - 30
h3d/impl/GlDriver.hx

@@ -516,7 +516,7 @@ class GlDriver extends Driver {
 				if( !s.vertex && curShader.vertex.buffers != null )
 					start = curShader.vertex.buffers.length;
 				for( i in 0...s.buffers.length )
-					gl.bindBufferBase(GL.UNIFORM_BUFFER, i + start, @:privateAccess buf.buffers[i].buffer.vbuf.b);
+					gl.bindBufferBase(GL.UNIFORM_BUFFER, i + start, @:privateAccess buf.buffers[i].vbuf.b);
 			}
 		case Textures:
 			var tcount = s.textures.length;
@@ -1004,26 +1004,26 @@ class GlDriver extends Driver {
 		if( outOfMemoryCheck ) gl.getError(); // make sure to reset error flag
 	}
 
-	override function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
+	override function allocBuffer( b : h3d.Buffer ) : GPUBuffer {
 		discardError();
-		var b = gl.createBuffer();
-		gl.bindBuffer(GL.ARRAY_BUFFER, b);
-		if( m.size * m.stride == 0 ) throw "assert";
+		var vb = gl.createBuffer();
+		gl.bindBuffer(GL.ARRAY_BUFFER, vb);
+		if( b.vertices * b.stride == 0 ) throw "assert";
 		#if js
-		gl.bufferData(GL.ARRAY_BUFFER, m.size * m.stride * 4, m.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
+		gl.bufferData(GL.ARRAY_BUFFER, b.vertices * b.stride * 4, b.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
 		#elseif hl
-		gl.bufferDataSize(GL.ARRAY_BUFFER, m.size * m.stride * 4, m.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
+		gl.bufferDataSize(GL.ARRAY_BUFFER, b.vertices * b.stride * 4, b.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
 		#else
-		var tmp = new Uint8Array(m.size * m.stride * 4);
-		gl.bufferData(GL.ARRAY_BUFFER, tmp, m.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
+		var tmp = new Uint8Array(b.vertices * b.stride * 4);
+		gl.bufferData(GL.ARRAY_BUFFER, tmp, b.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
 		#end
 		var outOfMem = outOfMemoryCheck && gl.getError() == GL.OUT_OF_MEMORY;
 		gl.bindBuffer(GL.ARRAY_BUFFER, null);
 		if( outOfMem ) {
-			gl.deleteBuffer(b);
+			gl.deleteBuffer(vb);
 			return null;
 		}
-		return { b : b, stride : m.stride #if multidriver, driver : this #end };
+		return { b : vb, stride : b.stride #if multidriver, driver : this #end };
 	}
 
 	override function allocIndexes( count : Int, is32 : Bool ) : IndexBuffer {
@@ -1060,8 +1060,8 @@ class GlDriver extends Driver {
 		gl.deleteBuffer(i.b);
 	}
 
-	override function disposeVertexes( v : VertexBuffer ) {
-		gl.deleteBuffer(v.b);
+	override function disposeBuffer( b : GPUBuffer ) {
+		gl.deleteBuffer(b.b);
 	}
 
 	override function generateMipMaps( t : h3d.mat.Texture ) {
@@ -1206,9 +1206,9 @@ class GlDriver extends Driver {
 		restoreBind();
 	}
 
-	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
-		var stride : Int = v.stride;
-		gl.bindBuffer(GL.ARRAY_BUFFER, v.b);
+	override function uploadBufferData( b : GPUBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
+		var stride : Int = b.stride;
+		gl.bindBuffer(GL.ARRAY_BUFFER, b.b);
 		#if hl
 		var data = #if hl hl.Bytes.getArray(buf.getNative()) #else buf.getNative() #end;
 		gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride * 4, streamData(data,bufPos * 4,vertexCount * stride * 4), bufPos * 4 * STREAM_POS, vertexCount * stride * 4);
@@ -1220,9 +1220,9 @@ class GlDriver extends Driver {
 		gl.bindBuffer(GL.ARRAY_BUFFER, null);
 	}
 
-	override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
-		var stride : Int = v.stride;
-		gl.bindBuffer(GL.ARRAY_BUFFER, v.b);
+	override function uploadBufferBytes( b : GPUBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
+		var stride : Int = b.stride;
+		gl.bindBuffer(GL.ARRAY_BUFFER, b.b);
 		#if hl
 		gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride * 4, streamData(buf.getData(),bufPos * 4,vertexCount * stride * 4), bufPos * 4 * STREAM_POS, vertexCount * stride * 4);
 		#else
@@ -1267,20 +1267,16 @@ class GlDriver extends Driver {
 		}
 	}
 
-	override function selectBuffer( v : h3d.Buffer ) {
+	override function selectBuffer( b : h3d.Buffer ) {
 
-		if( v == curBuffer )
+		if( b == curBuffer )
 			return;
-		if( curBuffer != null && v.buffer == curBuffer.buffer && v.buffer.flags.has(RawFormat) == curBuffer.flags.has(RawFormat) ) {
-			curBuffer = v;
-			return;
-		}
 
 		if( curShader == null )
 			throw "No shader selected";
-		curBuffer = v;
+		curBuffer = b;
 
-		var m = @:privateAccess v.buffer.vbuf;
+		var m = @:privateAccess b.vbuf;
 		if( m.stride < curShader.stride )
 			throw "Buffer stride (" + m.stride + ") and shader stride (" + curShader.stride + ") mismatch";
 
@@ -1290,7 +1286,7 @@ class GlDriver extends Driver {
 		#end
 		gl.bindBuffer(GL.ARRAY_BUFFER, m.b);
 
-		if( v.flags.has(RawFormat) ) {
+		if( b.flags.has(RawFormat) ) {
 			for( a in curShader.attribs ) {
 				var pos = a.offset;
 				gl.vertexAttribPointer(a.index, a.size, a.type, false, m.stride * 4, pos * 4);
@@ -1323,8 +1319,8 @@ class GlDriver extends Driver {
 
 	override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
 		for( a in curShader.attribs ) {
-			gl.bindBuffer(GL.ARRAY_BUFFER, @:privateAccess buffers.buffer.buffer.vbuf.b);
-			gl.vertexAttribPointer(a.index, a.size, a.type, false, buffers.buffer.buffer.stride * 4, buffers.offset * 4);
+			gl.bindBuffer(GL.ARRAY_BUFFER, @:privateAccess buffers.buffer.vbuf.b);
+			gl.vertexAttribPointer(a.index, a.size, a.type, false, buffers.buffer.stride * 4, buffers.offset * 4);
 			updateDivisor(a);
 			buffers = buffers.next;
 		}

+ 11 - 11
h3d/impl/LogDriver.hx

@@ -306,9 +306,9 @@ class LogDriver extends Driver {
 		return d.allocIndexes(count,is32);
 	}
 
-	override function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
-		log('AllocVertexes size=${m.size} stride=${m.stride}');
-		return d.allocVertexes(m);
+	override function allocBuffer( b : Buffer ) : GPUBuffer {
+		log('AllocBuffer count=${b.vertices} stride=${b.stride}');
+		return d.allocBuffer(b);
 	}
 
 	override function disposeTexture( t : h3d.mat.Texture ) {
@@ -321,9 +321,9 @@ class LogDriver extends Driver {
 		d.disposeIndexes(i);
 	}
 
-	override function disposeVertexes( v : VertexBuffer ) {
-		log('DisposeIndexes');
-		d.disposeVertexes(v);
+	override function disposeBuffer( b : GPUBuffer ) {
+		log('DisposeBuffer');
+		d.disposeBuffer(b);
 	}
 
 	override function uploadIndexBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
@@ -336,14 +336,14 @@ class LogDriver extends Driver {
 		d.uploadIndexBytes(i, startIndice, indiceCount, buf, bufPos);
 	}
 
-	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
-		log('UploadVertexBuffer');
-		d.uploadVertexBuffer(v, startVertex, vertexCount, buf, bufPos);
+	override function uploadBufferData( b : GPUBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
+		log('UploadBufferData');
+		d.uploadBufferData(b, startVertex, vertexCount, buf, bufPos);
 	}
 
-	override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
+	override function uploadBufferBytes( b : GPUBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
 		log('UploadVertexBytes');
-		d.uploadVertexBytes(v, startVertex, vertexCount, buf, bufPos);
+		d.uploadBufferBytes(b, startVertex, vertexCount, buf, bufPos);
 	}
 
 	override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {

+ 0 - 182
h3d/impl/ManagedBuffer.hx

@@ -1,182 +0,0 @@
-package h3d.impl;
-
-@:allow(h3d)
-private class FreeCell {
-	var pos : Int;
-	var count : Int;
-	var next : FreeCell;
-	function new(pos,count,next) {
-		this.pos = pos;
-		this.count = count;
-		this.next = next;
-	}
-}
-
-@:allow(h3d.impl.MemoryManager)
-class ManagedBuffer {
-
-	var mem : MemoryManager;
-	public var stride(default,null) : Int;
-	public var size(default,null) : Int;
-	public var flags(default, null) : haxe.EnumFlags<Buffer.BufferFlag>;
-
-	var vbuf : Driver.VertexBuffer;
-	var freeList : FreeCell;
-	var next : ManagedBuffer;
-	#if track_alloc
-	var allocHead : Buffer;
-	#end
-
-	public function new( stride, size, ?flags : Array<Buffer.BufferFlag> ) {
-		this.flags = new haxe.EnumFlags();
-		if( flags != null )
-			for( f in flags )
-				this.flags.set(f);
-		this.size = size;
-		this.stride = stride;
-		this.freeList = new FreeCell(0, size, null);
-		#if !noEngine
-		this.mem = h3d.Engine.getCurrent().mem;
-		mem.allocManaged(this);
-		#end
-	}
-
-	public function uploadVertexBuffer( start : Int, vertices : Int, buf : hxd.FloatBuffer, bufPos = 0 ) {
-		mem.driver.uploadVertexBuffer(vbuf, start, vertices, buf, bufPos);
-	}
-
-	public function uploadVertexBytes( start : Int, vertices : Int, data : haxe.io.Bytes, dataPos = 0 ) {
-		mem.driver.uploadVertexBytes(vbuf, start, vertices, data, dataPos);
-	}
-
-	public function readVertexBytes( start : Int, vertices : Int, data : haxe.io.Bytes, dataPos = 0 ) {
-		mem.driver.readVertexBytes(vbuf, start, vertices, data, dataPos);
-	}
-
-	public function alloc(vertices,align) {
-		var p = allocPosition(vertices, align);
-		if( p < 0 )
-			return null;
-		var b = new Buffer(vertices, stride, [NoAlloc]);
-		@:privateAccess {
-			b.position = p;
-			b.buffer = this;
-		};
-		#if track_alloc
-		@:privateAccess b.allocNext = allocHead;
-		allocHead = b;
-		#end
-		return b;
-	}
-
-	public function getFreeVertices() {
-		var m = 0;
-		var l = freeList;
-		while( l != null ) {
-			m += l.count;
-			l = l.next;
-		}
-		return m;
-	}
-
-	function allocPosition( nvert : Int, align : Int ) {
-		var free = freeList;
-		while( free != null ) {
-			if( free.count >= nvert ) {
-				var d = (align - (free.pos % align)) % align;
-				if( d == 0 )
-					break;
-				// insert some padding
-				if( free.count >= nvert + d ) {
-					free.next = new FreeCell(free.pos + d, free.count - d, free.next);
-					free.count = d;
-					free = free.next;
-					break;
-				}
-			}
-			free = free.next;
-		}
-		if( free == null )
-			return -1;
-		var pos = free.pos;
-		free.pos += nvert;
-		free.count -= nvert;
-		return pos;
-	}
-
-	function allocBuffer( b : Buffer ) {
-		var align = b.flags.has(Quads) ? 4 : (b.flags.has(Triangles) ? 3 : 1);
-		var p = allocPosition(b.vertices, align);
-		if( p < 0 ) return false;
-		@:privateAccess {
-			b.position = p;
-			b.buffer = this;
-		};
-		#if track_alloc
-		@:privateAccess b.allocNext = allocHead;
-		allocHead = b;
-		#end
-		return true;
-	}
-
-	@:allow(h3d.Buffer.dispose)
-	function freeBuffer( b : Buffer ) {
-		var prev : FreeCell = null;
-		var f = freeList;
-		var nvert = b.vertices;
-		var end = b.position + nvert;
-		while( f != null ) {
-			if( f.pos == end ) {
-				f.pos -= nvert;
-				f.count += nvert;
-				if( prev != null && prev.pos + prev.count == f.pos ) {
-					prev.count += f.count;
-					prev.next = f.next;
-				}
-				nvert = 0;
-				break;
-			}
-			if( f.pos > end ) {
-				if( prev != null && prev.pos + prev.count == b.position )
-					prev.count += nvert;
-				else {
-					var n = new FreeCell(b.position, nvert, f);
-					if( prev == null ) freeList = n else prev.next = n;
-				}
-				nvert = 0;
-				break;
-			}
-			prev = f;
-			f = f.next;
-		}
-		if( nvert != 0 )
-			throw "assert";
-		#if track_alloc
-		@:privateAccess {
-			var cur = allocHead, prev : Buffer = null;
-			while( cur != null ) {
-				if( cur == b ) {
-					if( prev == null )
-						allocHead = b.allocNext;
-					else
-						prev.allocNext = b.allocNext;
-					break;
-				}
-				prev = cur;
-				cur = cur.allocNext;
-			}
-		}
-		#end
-		if( freeList.count == size && !flags.has(Managed) )
-			dispose();
-	}
-
-	public function dispose() {
-		mem.freeManaged(this);
-	}
-
-	public inline function isDisposed() {
-		return vbuf == null;
-	}
-
-}

+ 27 - 173
h3d/impl/MemoryManager.hx

@@ -2,14 +2,14 @@ package h3d.impl;
 
 class MemoryManager {
 
-	static inline var MAX_MEMORY = #if flash 250 #else 4096 #end * (1024. * 1024.); // MB
-	static inline var MAX_BUFFERS = #if flash 4096 #else 1 << 16 #end;
+	static inline var MAX_MEMORY = 4096 * (1024. * 1024.); // MB
+	static inline var MAX_BUFFERS = 65536;
 	static inline var SIZE = 65533;
 	static var ALL_FLAGS = Type.allEnums(Buffer.BufferFlag);
 
 	@:allow(h3d)
 	var driver : Driver;
-	var buffers : Array<ManagedBuffer>;
+	var buffers : Array<Buffer>;
 	var indexes : Array<Indexes>;
 	var textures : Array<h3d.mat.Texture>;
 	var depths : Array<h3d.mat.DepthBuffer>;
@@ -18,7 +18,6 @@ class MemoryManager {
 	public var quadIndexes(default,null) : Indexes;
 	public var usedMemory(default, null) : Float = 0;
 	public var texMemory(default, null) : Float = 0;
-	public var bufferCount(default,null) : Int = 0;
 
 	public function new(driver) {
 		this.driver = driver;
@@ -61,148 +60,37 @@ class MemoryManager {
 
 	// ------------------------------------- BUFFERS ------------------------------------------
 
-	/**
-		Clean empty (unused) buffers
-	**/
-	public function cleanManagedBuffers() {
-		for( i in 1...buffers.length ) {
-			var b = buffers[i], prev : ManagedBuffer = null;
-			while( b != null ) {
-				if( b.freeList.count == b.size ) {
-					b.dispose();
-					if( prev == null )
-						buffers[i] = b.next;
-					else
-						prev.next = b.next;
-				} else
-					prev = b;
-				b = b.next;
-			}
-		}
-	}
+	function allocBuffer( b : Buffer ) {
+		if( b.vbuf != null ) return;
 
-	@:allow(h3d.impl.ManagedBuffer)
-	function allocManaged( m : ManagedBuffer ) {
-		if( m.vbuf != null ) return;
-
-		var mem = m.size * m.stride * 4;
+		var mem = b.vertices * b.stride * 4;
 
 		if( mem == 0 ) return;
 
-		while( usedMemory + mem > MAX_MEMORY || bufferCount >= MAX_BUFFERS || (m.vbuf = driver.allocVertexes(m)) == null ) {
+		while( usedMemory + mem > MAX_MEMORY || buffers.length >= MAX_BUFFERS || (b.vbuf = driver.allocBuffer(b)) == null ) {
 
 			if( driver.isDisposed() ) return;
 
-			var size = usedMemory - freeMemorySize();
+			var size = usedMemory;
 			garbage();
-			cleanManagedBuffers();
-			if( usedMemory - freeMemorySize() == size ) {
-				if( bufferCount >= MAX_BUFFERS )
+			if( usedMemory == size ) {
+				if( buffers.length >= MAX_BUFFERS )
 					throw "Too many buffers";
-				throw "Memory full (" + Math.fceil(size / 1024) + " KB," + bufferCount + " buffers)";
+				throw "Memory full (" + Math.fceil(size / 1024) + " KB," + buffers.length + " buffers)";
 			}
 		}
 		usedMemory += mem;
-		bufferCount++;
+		b.mem = this;
+		buffers.push(b);
 	}
 
-	@:allow(h3d.impl.ManagedBuffer)
-	function freeManaged( m : ManagedBuffer ) {
-		if( m.vbuf == null ) return;
-		driver.disposeVertexes(m.vbuf);
-		m.vbuf = null;
-		usedMemory -= m.size * m.stride * 4;
-		bufferCount--;
-		if( !m.flags.has(Managed) ) {
-			var c = buffers[0], prev : ManagedBuffer = null;
-			while( c != null ) {
-				if( c == m ) {
-					if( prev == null ) buffers[0] = m.next else prev.next = m.next;
-					break;
-				}
-				prev = c;
-				c = c.next;
-			}
-		}
-	}
-
-	@:allow(h3d.Buffer)
-	@:access(h3d.Buffer)
-	function allocBuffer( b : Buffer, stride : Int ) {
-		// split big buffers
-		var max = b.flags.has(Quads) ? 65532 : b.flags.has(Triangles) ? 65533 : 65534;
-		if( b.vertices > max && !b.flags.has(UniformBuffer) && !b.flags.has(LargeBuffer) ) {
-			if( max == 65534 )
-				throw "Cannot split buffer with "+b.vertices+" vertices if it's not Quads/Triangles";
-			var rem = b.vertices - max;
-			b.vertices = max;
-			// make sure to alloc in order
-			allocBuffer(b, stride);
-
-			var n = b;
-			while( n.next != null ) n = n.next;
-
-			var flags = [];
-			for( f in ALL_FLAGS )
-				if( b.flags.has(f) )
-					flags.push(f);
-			n.next = new Buffer(rem, stride, flags);
-			return;
-		}
-
-		if( !b.flags.has(Managed) ) {
-			var flags : Array<h3d.Buffer.BufferFlag> = null;
-			if( b.flags.has(Dynamic) ) { if( flags == null ) flags = []; flags.push(Dynamic); }
-			if( b.flags.has(UniformBuffer) ) { if( flags == null ) flags = []; flags.push(UniformBuffer); }
- 			var m = new ManagedBuffer(stride, b.vertices, flags);
-			m.next = buffers[0];
-			buffers[0] = m;
-			if( !m.allocBuffer(b) ) throw "assert";
-			return;
-		}
-
-		// look into one of the managed buffers
-		var m = buffers[stride], prev = null;
-		while( m != null ) {
-			if( m.allocBuffer(b) )
-				return;
-			prev = m;
-			m = m.next;
-		}
-
-		// if quad/triangles, we are allowed to split it
-		var align = b.flags.has(Triangles) ? 3 : b.flags.has(Quads) ? 4 : 0;
-		if( m == null && align > 0 ) {
-			var total = b.vertices;
-			var size = total;
-			while( size > 2048 ) {
-				m = buffers[stride];
-				size >>= 1;
-				size -= size % align;
-				b.vertices = size;
-				while( m != null ) {
-					if( m.allocBuffer(b) ) {
-						var flags = [];
-						for( f in ALL_FLAGS )
-							if( b.flags.has(f) )
-								flags.push(f);
-						b.next = new Buffer(total - size, stride, flags);
-						return;
-					}
-					m = m.next;
-				}
-			}
-			b.vertices = total;
-		}
-
-		// alloc a new managed buffer
-		m = new ManagedBuffer(stride, SIZE, [Managed]);
-		if( prev == null )
-			buffers[stride] = m;
-		else
-			prev.next = m;
-
-		if( !m.allocBuffer(b) ) throw "assert";
+	function freeBuffer( b : Buffer ) {
+		if( b.vbuf == null ) return;
+		driver.disposeBuffer(b.vbuf);
+		b.vbuf = null;
+		b.mem = null;
+		usedMemory -= b.vertices * b.stride * 4;
+		buffers.remove(b);
 	}
 
 	// ------------------------------------- INDEXES ------------------------------------------
@@ -317,60 +205,26 @@ class MemoryManager {
 			t.dispose();
 		for( b in depths.copy() )
 			b.dispose();
-		for( b in buffers.copy() ) {
-			var b = b;
-			while( b != null ) {
-				b.dispose();
-				b = b.next;
-			}
-		}
+		for( b in buffers.copy() )
+			b.dispose();
 		for( i in indexes.copy() )
 			i.dispose();
 		buffers = [];
 		indexes = [];
 		textures = [];
-		bufferCount = 0;
 		usedMemory = 0;
 		texMemory = 0;
 	}
 
 	// ------------------------------------- STATS ------------------------------------------
 
-	function freeMemorySize() {
-		var size = 0;
-		for( b in buffers ) {
-			var b = b;
-			while( b != null ) {
-				var free = b.freeList;
-				while( free != null ) {
-					size += free.count * b.stride * 4;
-					free = free.next;
-				}
-				b = b.next;
-			}
-		}
-		return size;
-	}
-
 	public function stats() {
-		var total = 0, free = 0, count = 0;
-		for( b in buffers ) {
-			var b = b;
-			while( b != null ) {
-				total += b.stride * b.size * 4;
-				var f = b.freeList;
-				while( f != null ) {
-					free += f.count * b.stride * 4;
-					f = f.next;
-				}
-				count++;
-				b = b.next;
-			}
-		}
+		var total = 0.;
+		for( b in buffers )
+			total += b.stride * b.vertices * 4;
 		return {
-			bufferCount : bufferCount,
-			freeManagedMemory : free,
-			managedMemory : total,
+			bufferCount : buffers.length,
+			bufferMemory : total,
 			totalMemory : usedMemory + texMemory,
 			textureCount : textures.length,
 			textureMemory : texMemory,

+ 1 - 1
h3d/impl/NullDriver.hx

@@ -58,7 +58,7 @@ class NullDriver extends Driver {
 		return cast {};
 	}
 
-	override function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
+	override function allocBuffer( b : Buffer ) : GPUBuffer {
 		return cast {};
 	}
 

+ 3 - 3
h3d/prim/HMDModel.hx

@@ -59,7 +59,7 @@ class HMDModel extends MeshPrimitive {
 
 	override function alloc(engine:h3d.Engine) {
 		dispose();
-		buffer = new h3d.Buffer(data.vertexCount, data.vertexStride, [LargeBuffer]);
+		buffer = new h3d.Buffer(data.vertexCount, data.vertexStride);
 
 		var entry = lib.resource.entry;
 
@@ -97,7 +97,7 @@ class HMDModel extends MeshPrimitive {
 		var alias = bufferAliases.get(name);
 		var buffer = bufferCache.get(hxsl.Globals.allocID(alias.realName));
 		if( buffer == null ) throw "Buffer " + alias.realName+" not found for alias " + name;
-		if( buffer.offset + alias.offset > buffer.buffer.buffer.stride ) throw "Alias " + name+" for buffer " + alias.realName+" outside stride";
+		if( buffer.offset + alias.offset > buffer.buffer.stride ) throw "Alias " + name+" for buffer " + alias.realName+" outside stride";
 		addBuffer(name, buffer.buffer, buffer.offset + alias.offset);
 	}
 
@@ -158,7 +158,7 @@ class HMDModel extends MeshPrimitive {
 			v[k++] = n.y;
 			v[k++] = n.z;
 		}
-		var buf = h3d.Buffer.ofFloats(v, 3, data.vertexCount > 0x10000 ? [LargeBuffer] : null);
+		var buf = h3d.Buffer.ofFloats(v, 3);
 		addBuffer(name, buf, 0);
 		normalsRecomputed = name;
 	}

+ 1 - 1
h3d/prim/Primitive.hx

@@ -26,7 +26,7 @@ class Primitive {
 		The number of triangles the primitive has.
 	**/
 	public function triCount() {
-		return if( indexes != null ) Std.int(indexes.count / 3) else if( buffer == null ) 0 else Std.int(buffer.totalVertices() / 3);
+		return if( indexes != null ) Std.int(indexes.count / 3) else if( buffer == null ) 0 else Std.int(buffer.vertices / 3);
 	}
 
 	/**

+ 1 - 1
hxd/impl/CacheAllocator.hx

@@ -67,7 +67,7 @@ class CacheAllocator extends Allocator {
 		if( b.isDisposed() ) return;
 		var f = b.flags;
 		var flags = f.has(RawFormat) ? (f.has(Quads) ? RawQuads : RawFormat) : (f.has(UniformBuffer) ? UniformDynamic : Dynamic);
-		var id = flags.toInt() | (b.buffer.stride << 3) | (b.vertices << 16);
+		var id = flags.toInt() | (b.stride << 3) | (b.vertices << 16);
 		var c = buffers.get(id);
 		if( c == null ) {
 			c = new Cache(function(b:h3d.Buffer) b.dispose());