瀏覽代碼

merged memory manager changes

Nicolas Cannasse 11 年之前
父節點
當前提交
1dab4c24fb

+ 5 - 5
h2d/Graphics.hx

@@ -25,7 +25,7 @@ private class GraphicsContent extends h3d.prim.Primitive {
 	var tmp : hxd.FloatBuffer;
 	var tmp : hxd.FloatBuffer;
 	var index : hxd.IndexBuffer;
 	var index : hxd.IndexBuffer;
 	
 	
-	var buffers : Array<{ buf : hxd.FloatBuffer, vbuf : h3d.impl.Buffer, idx : hxd.IndexBuffer, ibuf : h3d.impl.Indexes }>;
+	var buffers : Array<{ buf : hxd.FloatBuffer, vbuf : h3d.Buffer, idx : hxd.IndexBuffer, ibuf : h3d.Indexes }>;
 	
 	
 	public function new() {
 	public function new() {
 		buffers = [];
 		buffers = [];
@@ -59,11 +59,11 @@ private class GraphicsContent extends h3d.prim.Primitive {
 	
 	
 	override function alloc( engine : h3d.Engine ) {
 	override function alloc( engine : h3d.Engine ) {
 		if (index.length <= 0) return ;
 		if (index.length <= 0) return ;
-		buffer = engine.mem.allocVector(tmp, 8, 0);
-		indexes = engine.mem.allocIndex(index);
+		buffer = h3d.Buffer.ofFloats(tmp, 8);
+		indexes = h3d.Indexes.alloc(index);
 		for( b in buffers ) {
 		for( b in buffers ) {
-			if( b.vbuf == null || b.vbuf.isDisposed() ) b.vbuf = engine.mem.allocVector(b.buf, 8, 0);
-			if( b.ibuf == null || b.ibuf.isDisposed() ) b.ibuf = engine.mem.allocIndex(b.idx);
+			if( b.vbuf == null || b.vbuf.isDisposed() ) b.vbuf = h3d.Buffer.ofFloats(b.buf, 8);
+			if( b.ibuf == null || b.ibuf.isDisposed() ) b.ibuf = h3d.Indexes.alloc(b.idx);
 		}
 		}
 	}
 	}
 	
 	

+ 1 - 1
h2d/RenderContext.hx

@@ -63,7 +63,7 @@ class RenderContext {
 		if( bufPos == 0 ) return;
 		if( bufPos == 0 ) return;
 		beforeDraw();
 		beforeDraw();
 		var nverts = Std.int(bufPos / stride);
 		var nverts = Std.int(bufPos / stride);
-		var tmp = engine.mem.alloc(nverts, stride, 4);
+		var tmp = new h3d.Buffer(nverts, stride, [Quads, Dynamic]);
 		tmp.uploadVector(buffer, 0, nverts);
 		tmp.uploadVector(buffer, 0, nverts);
 		engine.renderQuadBuffer(tmp);
 		engine.renderQuadBuffer(tmp);
 		tmp.dispose();
 		tmp.dispose();

+ 1 - 4
h2d/SpriteBatch.hx

@@ -183,10 +183,7 @@ class SpriteBatch extends Drawable {
 			}
 			}
 			e = e.next;
 			e = e.next;
 		}
 		}
-		var stride = 8;
-		var nverts = Std.int(pos / stride);
-		var buffer = ctx.engine.mem.alloc(nverts, stride, 4);
-		buffer.uploadVector(tmpBuf, 0, nverts);
+		var buffer = h3d.Buffer.ofFloats(tmpBuf, 8, [Dynamic, Quads]);
 		ctx.beginDrawObject(this, tile.getTexture());
 		ctx.beginDrawObject(this, tile.getTexture());
 		ctx.engine.renderQuadBuffer(buffer);
 		ctx.engine.renderQuadBuffer(buffer);
 		buffer.dispose();
 		buffer.dispose();

+ 10 - 1
h2d/Tile.hx

@@ -114,7 +114,9 @@ class Tile {
 		return t;
 		return t;
 	}
 	}
 	
 	
-	
+	/**
+		Split horizontaly or verticaly the number of given frames
+	**/
 	public function split( frames : Int, vertical = false ) {
 	public function split( frames : Int, vertical = false ) {
 		var tl = [];
 		var tl = [];
 		if( vertical ) {
 		if( vertical ) {
@@ -128,6 +130,13 @@ class Tile {
 		}
 		}
 		return tl;
 		return tl;
 	}
 	}
+
+	/**
+		Split the tile into a list of tiles of Size x Size pixels.
+	**/
+	public function grid( size : Int, dx = 0, dy = 0 ) {
+		return [for( y in 0...Std.int(height / size) ) for( x in 0...Std.int(width / size) ) sub(x * size, y * size, size, size, dx, dy)];
+	}
 	
 	
 	public function toString() {
 	public function toString() {
 		return "Tile(" + x + "," + y + "," + width + "x" + height + (dx != 0 || dy != 0 ? "," + dx + ":" + dy:"") + ")";
 		return "Tile(" + x + "," + y + "," + width + "x" + height + (dx != 0 || dy != 0 ? "," + dx + ":" + dy:"") + ")";

+ 3 - 11
h2d/TileGroup.hx

@@ -19,15 +19,7 @@ private class TileLayerContent extends h3d.prim.Primitive {
 	}
 	}
 
 
 	override public function triCount() {
 	override public function triCount() {
-		if( buffer == null )
-			return tmp.length >> 4;
-		var v = 0;
-		var b = buffer;
-		while( b != null ) {
-			v += b.nvert;
-			b = b.next;
-		}
-		return v >> 1;
+		return if( buffer == null ) tmp.length >> 4 else buffer.totalVertices() >> 1;
 	}
 	}
 
 
 	public inline function addColor( x : Int, y : Int, color : h3d.Vector, t : Tile ) {
 	public inline function addColor( x : Int, y : Int, color : h3d.Vector, t : Tile ) {
@@ -78,7 +70,7 @@ private class TileLayerContent extends h3d.prim.Primitive {
 		tmp.push(0);
 		tmp.push(0);
 		insertColor(color);
 		insertColor(color);
 	}
 	}
-
+	
 	inline function insertColor( c : Int ) {
 	inline function insertColor( c : Int ) {
 		tmp.push(((c >> 16) & 0xFF) / 255.);
 		tmp.push(((c >> 16) & 0xFF) / 255.);
 		tmp.push(((c >> 8) & 0xFF) / 255.);
 		tmp.push(((c >> 8) & 0xFF) / 255.);
@@ -134,7 +126,7 @@ private class TileLayerContent extends h3d.prim.Primitive {
 
 
 	override public function alloc(engine:h3d.Engine) {
 	override public function alloc(engine:h3d.Engine) {
 		if( tmp == null ) reset();
 		if( tmp == null ) reset();
-		buffer = engine.mem.allocVector(tmp, 8, 4);
+		buffer = h3d.Buffer.ofFloats(tmp, 8, [Quads]);
 	}
 	}
 
 
 	public function doRender(engine, min, len) {
 	public function doRender(engine, min, len) {

+ 128 - 0
h3d/Buffer.hx

@@ -0,0 +1,128 @@
+package h3d;
+
+enum BufferFlag {
+	/**
+		Indicate that the buffer content will be often modified.
+	**/
+	Dynamic;
+	/**
+		The buffer contains only triangles. Imply Managed. Make sure the position is aligned on 3 vertices multiples.
+	**/
+	Triangles;
+	/**
+		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;
+	/**
+		Used internaly
+	**/
+	NoAlloc;
+}
+
+class Buffer {
+
+	public var buffer(default,null) : h3d.impl.ManagedBuffer;
+	public var position(default,null) : Int;
+	public var vertices(default,null) : Int;
+	public var next(default,null) : Buffer;
+	public var flags(default, null) : haxe.EnumFlags<BufferFlag>;
+	
+	public function new(vertices, stride, ?flags : Array<BufferFlag>) {
+		this.vertices = vertices;
+		this.flags = new haxe.EnumFlags();
+		if( flags != null )
+			for( f in flags )
+				this.flags.set(f);
+		if( this.flags.has(Quads) || this.flags.has(Triangles) )
+			this.flags.set(Managed);
+		if( !this.flags.has(NoAlloc) )
+			h3d.Engine.getCurrent().mem.allocBuffer(this, stride);
+	}
+
+	public function isDisposed() {
+		return buffer == null || buffer.isDisposed();
+	}
+	
+	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;
+		}
+		return count;
+	}
+	
+	public function uploadVector( buf : hxd.FloatBuffer, bufPos : 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.uploadVertexBuffer(cur.position, count, buf, bufPos);
+			bufPos += count * buffer.stride;
+			vertices -= count;
+			cur = cur.next;
+		}
+	}
+	
+	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;
+		}
+	}
+	
+	public static function ofFloats( v : hxd.FloatBuffer, stride : Int, ?flags ) {
+		var nvert = Std.int(v.length / stride);
+		var b = new Buffer(nvert, stride, flags);
+		b.uploadVector(v, 0, nvert);
+		return b;
+	}
+	
+}
+
+class BufferOffset {
+	public var id : Int;
+	public var buffer : Buffer;
+	public var offset : Int;
+	
+	/*
+		This is used to return a list of BufferOffset without allocating an array
+	*/
+	public var next : BufferOffset;
+	
+	static var UID = 0;
+	
+	public function new(buffer, offset) {
+		this.id = UID++;
+		this.buffer = buffer;
+		this.offset = offset;
+	}
+	public function dispose() {
+		if( buffer != null ) {
+			buffer.dispose();
+			buffer = null;
+		}
+		next = null;
+	}
+}

+ 15 - 13
h3d/Engine.hx

@@ -94,28 +94,28 @@ class Engine {
 		driver.uploadShaderBuffers(buffers, which);
 		driver.uploadShaderBuffers(buffers, which);
 	}
 	}
 	
 	
-	function selectBuffer( buf : h3d.impl.MemoryManager.BigBuffer ) {
+	function selectBuffer( buf : h3d.impl.ManagedBuffer ) {
 		if( buf.isDisposed() )
 		if( buf.isDisposed() )
 			return false;
 			return false;
-		driver.selectBuffer(buf.vbuf);
+		driver.selectBuffer(@:privateAccess buf.vbuf);
 		return true;
 		return true;
 	}
 	}
 
 
-	public inline function renderTriBuffer( b : h3d.impl.Buffer, start = 0, max = -1 ) {
+	public inline function renderTriBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.triIndexes, 3, start, max);
 		return renderBuffer(b, mem.triIndexes, 3, start, max);
 	}
 	}
 	
 	
-	public inline function renderQuadBuffer( b : h3d.impl.Buffer, start = 0, max = -1 ) {
+	public inline function renderQuadBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.quadIndexes, 2, start, max);
 		return renderBuffer(b, mem.quadIndexes, 2, start, max);
 	}
 	}
 	
 	
 	// we use preallocated indexes so all the triangles are stored inside our buffers
 	// we use preallocated indexes so all the triangles are stored inside our buffers
-	function renderBuffer( b : h3d.impl.Buffer, indexes : h3d.impl.Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
+	function renderBuffer( b : Buffer, indexes : Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
 		if( indexes.isDisposed() )
 		if( indexes.isDisposed() )
 			return;
 			return;
 		do {
 		do {
-			var ntri = Std.int(b.nvert / vertPerTri);
-			var pos = Std.int(b.pos / vertPerTri);
+			var ntri = Std.int(b.vertices / vertPerTri);
+			var pos = Std.int(b.position / vertPerTri);
 			if( startTri > 0 ) {
 			if( startTri > 0 ) {
 				if( startTri >= ntri ) {
 				if( startTri >= ntri ) {
 					startTri -= ntri;
 					startTri -= ntri;
@@ -134,7 +134,7 @@ class Engine {
 					drawTri = 0;
 					drawTri = 0;
 				}
 				}
 			}
 			}
-			if( ntri > 0 && selectBuffer(b.b) ) {
+			if( ntri > 0 && selectBuffer(b.buffer) ) {
 				// *3 because it's the position in indexes which are always by 3
 				// *3 because it's the position in indexes which are always by 3
 				driver.draw(indexes.ibuf, pos * 3, ntri);
 				driver.draw(indexes.ibuf, pos * 3, ntri);
 				drawTriangles += ntri;
 				drawTriangles += ntri;
@@ -145,14 +145,14 @@ class Engine {
 	}
 	}
 	
 	
 	// we use custom indexes, so the number of triangles is the number of indexes/3
 	// we use custom indexes, so the number of triangles is the number of indexes/3
-	public function renderIndexed( b : h3d.impl.Buffer, indexes : h3d.impl.Indexes, startTri = 0, drawTri = -1 ) {
+	public function renderIndexed( b : Buffer, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 		if( b.next != null )
 		if( b.next != null )
 			throw "Buffer is split";
 			throw "Buffer is split";
 		if( indexes.isDisposed() )
 		if( indexes.isDisposed() )
 			return;
 			return;
 		var maxTri = Std.int(indexes.count / 3);
 		var maxTri = Std.int(indexes.count / 3);
 		if( drawTri < 0 ) drawTri = maxTri - startTri;
 		if( drawTri < 0 ) drawTri = maxTri - startTri;
-		if( drawTri > 0 && selectBuffer(b.b) ) {
+		if( drawTri > 0 && selectBuffer(b.buffer) ) {
 			// *3 because it's the position in indexes which are always by 3
 			// *3 because it's the position in indexes which are always by 3
 			driver.draw(indexes.ibuf, startTri * 3, drawTri);
 			driver.draw(indexes.ibuf, startTri * 3, drawTri);
 			drawTriangles += drawTri;
 			drawTriangles += drawTri;
@@ -160,7 +160,7 @@ class Engine {
 		}
 		}
 	}
 	}
 	
 	
-	public function renderMultiBuffers( buffers : h3d.impl.Buffer.BufferOffset, indexes : h3d.impl.Indexes, startTri = 0, drawTri = -1 ) {
+	public function renderMultiBuffers( buffers : Buffer.BufferOffset, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 		var maxTri = Std.int(indexes.count / 3);
 		var maxTri = Std.int(indexes.count / 3);
 		if( maxTri <= 0 ) return;
 		if( maxTri <= 0 ) return;
 		driver.selectMultiBuffers(buffers);
 		driver.selectMultiBuffers(buffers);
@@ -189,8 +189,10 @@ class Engine {
 		}
 		}
 		if( disposed )
 		if( disposed )
 			mem.onContextLost();
 			mem.onContextLost();
-		else
-			mem = new h3d.impl.MemoryManager(driver, 65400);
+		else {
+			mem = new h3d.impl.MemoryManager(driver);
+			mem.init();
+		}
 		hardware = driver.isHardware();
 		hardware = driver.isHardware();
 		set_debug(debug);
 		set_debug(debug);
 		set_fullScreen(fullScreen);
 		set_fullScreen(fullScreen);

+ 12 - 6
h3d/impl/Indexes.hx → h3d/Indexes.hx

@@ -1,17 +1,17 @@
-package h3d.impl;
+package h3d;
 
 
 @:allow(h3d.impl.MemoryManager)
 @:allow(h3d.impl.MemoryManager)
 @:allow(h3d.Engine)
 @:allow(h3d.Engine)
 class Indexes {
 class Indexes {
 
 
-	var mem : MemoryManager;
-	var ibuf : Driver.IndexBuffer;
+	var mem : h3d.impl.MemoryManager;
+	var ibuf : h3d.impl.Driver.IndexBuffer;
 	public var count(default,null) : Int;
 	public var count(default,null) : Int;
 	
 	
-	function new(mem, ibuf, count) {
-		this.mem = mem;
-		this.ibuf = ibuf;
+	public function new(count) {
+		this.mem = h3d.Engine.getCurrent().mem;
 		this.count = count;
 		this.count = count;
+		mem.allocIndexes(this);
 	}
 	}
 	
 	
 	public function isDisposed() {
 	public function isDisposed() {
@@ -26,5 +26,11 @@ class Indexes {
 		if( ibuf != null )
 		if( ibuf != null )
 			mem.deleteIndexes(this);
 			mem.deleteIndexes(this);
 	}
 	}
+	
+	public static function alloc( i : hxd.IndexBuffer ) {
+		var idx = new Indexes( i.length );
+		idx.upload(i, 0, i.length);
+		return idx;
+	}
 
 
 }
 }

+ 37 - 2
h3d/col/Ray.hx

@@ -45,6 +45,31 @@ class Ray {
 			return new Point(px + lx * k, py + ly * k, pz + lz * k);
 			return new Point(px + lx * k, py + ly * k, pz + lz * k);
 		}
 		}
 	}
 	}
+	
+	public inline function collideFrustum( mvp : Matrix ) {
+		// transform the two ray points into the normalized frustum box
+		var a = new h3d.Vector(px, py, pz);
+		a.project(mvp);
+		var b = new h3d.Vector(px + lx, py + ly, pz + lz);
+		b.project(mvp);
+		// use collide on the frustum [-1,1] bounds
+		var lx = b.x - a.x;
+		var ly = b.y - a.y;
+		var lz = b.z - a.z;
+		
+		var dx = 1 / lx;
+		var dy = 1 / ly;
+		var dz = 1 / lz;
+		var t1 = (-1 - a.x) * dx;
+		var t2 = (1 - a.x) * dx;
+		var t3 = (-1 - a.y) * dy;
+		var t4 = (1 - a.y) * dy;
+		var t5 = (0 - a.z) * dz;
+		var t6 = (1 - a.z) * dz;
+		var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6));
+		var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6));
+		return !(tmax < 0 || tmin > tmax);
+	}
 
 
 	public inline function collide( b : Bounds ) : Bool {
 	public inline function collide( b : Bounds ) : Bool {
 		var dx = 1 / lx;
 		var dx = 1 / lx;
@@ -70,7 +95,7 @@ class Ray {
 		}
 		}
 	}
 	}
 	
 	
-	public static function fromPoints( p1 : Point, p2 : Point ) {
+	public static inline function fromPoints( p1 : Point, p2 : Point ) {
 		var r = new Ray();
 		var r = new Ray();
 		r.px = p1.x;
 		r.px = p1.x;
 		r.py = p1.y;
 		r.py = p1.y;
@@ -80,6 +105,16 @@ class Ray {
 		r.lz = p2.z - p1.z;
 		r.lz = p2.z - p1.z;
 		return r;
 		return r;
 	}
 	}
-	
+
+	public static inline function fromValues( x, y, z, dx, dy, dz ) {
+		var r = new Ray();
+		r.px = x;
+		r.py = y;
+		r.pz = z;
+		r.lx = dx;
+		r.ly = dy;
+		r.lz = dz;
+		return r;
+	}
 	
 	
 }
 }

+ 1 - 1
h3d/fbx/Geometry.hx

@@ -101,7 +101,7 @@ class Geometry {
 	}
 	}
 
 
 	/**
 	/**
-		Decode polygon informations into triangle indexes and vertexes indexes.
+		Decode polygon informations into triangle indexes and vertices indexes.
 		Returns vidx, which is the list of vertices indexes and iout which is the index buffer for the full vertex model
 		Returns vidx, which is the list of vertices indexes and iout which is the index buffer for the full vertex model
 	**/
 	**/
 	public function getIndexes() {
 	public function getIndexes() {

+ 0 - 91
h3d/impl/Buffer.hx

@@ -1,91 +0,0 @@
-package h3d.impl;
-
-class Buffer {
-
-	public var b : MemoryManager.BigBuffer;
-	public var pos : Int;
-	public var nvert : Int;
-	public var next : Buffer;
-	#if debug
-	public var allocPos : AllocPos;
-	public var allocNext : Buffer;
-	public var allocPrev : Buffer;
-	#end
-	
-	public function new(b, pos, nvert) {
-		this.b = b;
-		this.pos = pos;
-		this.nvert = nvert;
-	}
-
-	public function isDisposed() {
-		return b == null || b.isDisposed();
-	}
-	
-	public function dispose() {
-		if( b != null ) {
-			b.freeCursor(pos, nvert);
-			#if debug
-			if( allocNext != null )
-				allocNext.allocPrev = allocPrev;
-			if( allocPrev != null )
-				allocPrev.allocNext = allocNext;
-			if( b.allocHead == this )
-				b.allocHead = allocNext;
-			#end
-			b = null;
-			if( next != null ) next.dispose();
-		}
-	}
-	
-	public function uploadVector( data : hxd.FloatBuffer, dataPos : Int, nverts : Int ) {
-		var cur = this;
-		while( nverts > 0 ) {
-			if( cur == null ) throw "Too many vertexes";
-			var count = nverts > cur.nvert ? cur.nvert : nverts;
-			cur.b.mem.driver.uploadVertexBuffer(cur.b.vbuf, cur.pos, count, data, dataPos);
-			dataPos += count * b.stride;
-			nverts -= count;
-			cur = cur.next;
-		}
-	}
-	
-	public function uploadBytes( data : haxe.io.Bytes, dataPos : Int, nverts : Int ) {
-		var cur = this;
-		while( nverts > 0 ) {
-			if( cur == null ) throw "Too many vertexes";
-			var count = nverts > cur.nvert ? cur.nvert : nverts;
-			cur.b.mem.driver.uploadVertexBytes(cur.b.vbuf, cur.pos, count, data, dataPos);
-			dataPos += count * b.stride * 4;
-			nverts -= count;
-			cur = cur.next;
-		}
-	}
-	
-}
-
-class BufferOffset {
-	public var id : Int;
-	public var b : Buffer;
-	public var offset : Int;
-	
-	/*
-		This is used to return a list of BufferOffset without allocating an array
-	*/
-	public var next : BufferOffset;
-	
-	static var UID = 0;
-	
-	public function new(b, offset) {
-		this.id = UID++;
-		this.b = b;
-		this.offset = offset;
-	}
-	public function dispose() {
-		if( b != null ) {
-			b.dispose();
-			b = null;
-		}
-		next = null;
-	}
-}

+ 1 - 1
h3d/impl/Driver.hx

@@ -105,7 +105,7 @@ class Driver {
 		return null;
 		return null;
 	}
 	}
 
 
-	public function allocVertex( count : Int, stride : Int ) : VertexBuffer {
+	public function allocVertex( m : ManagedBuffer ) : VertexBuffer {
 		return null;
 		return null;
 	}
 	}
 	
 	

+ 6 - 6
h3d/impl/GlDriver.hx

@@ -322,12 +322,12 @@ class GlDriver extends Driver {
 		return tt;
 		return tt;
 	}
 	}
 	
 	
-	override function allocVertex( count : Int, stride : Int ) : VertexBuffer {
+	override function allocVertex( m : ManagedBuffer ) : VertexBuffer {
 		var b = gl.createBuffer();
 		var b = gl.createBuffer();
 		#if js
 		#if js
 		gl.bindBuffer(GL.ARRAY_BUFFER, b);
 		gl.bindBuffer(GL.ARRAY_BUFFER, b);
-		if( count * stride == 0 ) throw "assert";
-		gl.bufferData(GL.ARRAY_BUFFER, count * stride * 4, GL.STATIC_DRAW);
+		if( m.size * m.stride == 0 ) throw "assert";
+		gl.bufferData(GL.ARRAY_BUFFER, m.size * m.stride * 4, m.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
 		gl.bindBuffer(GL.ARRAY_BUFFER, null);
 		gl.bindBuffer(GL.ARRAY_BUFFER, null);
 		#else
 		#else
 		var tmp = new Uint8Array(count * stride * 4);
 		var tmp = new Uint8Array(count * stride * 4);
@@ -335,7 +335,7 @@ class GlDriver extends Driver {
 		gl.bufferData(GL.ARRAY_BUFFER, tmp, GL.STATIC_DRAW);
 		gl.bufferData(GL.ARRAY_BUFFER, tmp, GL.STATIC_DRAW);
 		gl.bindBuffer(GL.ARRAY_BUFFER, null);
 		gl.bindBuffer(GL.ARRAY_BUFFER, null);
 		#end
 		#end
-		return { b : b, stride : stride };
+		return { b : b, stride : m.stride };
 	}
 	}
 	
 	
 	override function allocIndexes( count : Int ) : IndexBuffer {
 	override function allocIndexes( count : Int ) : IndexBuffer {
@@ -429,8 +429,8 @@ class GlDriver extends Driver {
 	
 	
 	override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
 	override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
 		for( a in curProgram.attribs ) {
 		for( a in curProgram.attribs ) {
-			gl.bindBuffer(GL.ARRAY_BUFFER, buffers.b.b.vbuf.b);
-			gl.vertexAttribPointer(a.index, a.size, a.type, false, buffers.b.b.stride * 4, buffers.offset * 4);
+			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);
 			buffers = buffers.next;
 			buffers = buffers.next;
 		}
 		}
 	}
 	}

+ 139 - 0
h3d/impl/ManagedBuffer.hx

@@ -0,0 +1,139 @@
+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;
+	
+	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.mem = h3d.Engine.getCurrent().mem;
+		this.size = size;
+		this.stride = stride;
+		this.freeList = new FreeCell(0, size, null);
+		mem.allocManaged(this);
+	}
+
+	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 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;
+		};
+		return b;
+	}
+	
+	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;
+		};
+		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( freeList.count == size && !flags.has(Managed) )
+			dispose();
+	}
+
+	public function dispose() {
+		mem.freeManaged(this);
+	}
+	
+	public inline function isDisposed() {
+		return vbuf == null;
+	}
+
+}

+ 205 - 319
h3d/impl/MemoryManager.hx

@@ -1,94 +1,15 @@
 package h3d.impl;
 package h3d.impl;
 
 
-#if flash
-private typedef WeakMap<K,T> = haxe.ds.WeakMap<K,T>;
-#else
-private typedef WeakMap<K,T> = haxe.ds.ObjectMap<K,T>;
-#end
-
-@:allow(h3d)
-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)
-class BigBuffer {
-
-	var mem : MemoryManager;
-	var stride : Int;
-	var size : Int;
-	
-	var vbuf : Driver.VertexBuffer;
-	var free : FreeCell;
-	var next : BigBuffer;
-	#if debug
-	public var allocHead : Buffer;
-	#end
-	
-	function new(mem, v, stride, size) {
-		this.mem = mem;
-		this.size = size;
-		this.stride = stride;
-		this.vbuf = v;
-		this.free = new FreeCell(0,size,null);
-	}
-
-	function freeCursor( pos:Int, nvect:Int ) {
-		var prev : FreeCell = null;
-		var f = free;
-		var end = pos + nvect;
-		while( f != null ) {
-			if( f.pos == end ) {
-				f.pos -= nvect;
-				f.count += nvect;
-				if( prev != null && prev.pos + prev.count == f.pos ) {
-					prev.count += f.count;
-					prev.next = f.next;
-				}
-				return;
-			}
-			if( f.pos > end ) {
-				if( prev != null && prev.pos + prev.count == pos )
-					prev.count += nvect;
-				else {
-					var n = new FreeCell(pos, nvect, f);
-					if( prev == null ) free = n else prev.next = n;
-				}
-				return;
-			}
-			prev = f;
-			f = f.next;
-		}
-		if( nvect != 0 )
-			throw "assert";
-	}
-
-	function dispose() {
-		mem.driver.disposeVertex(vbuf);
-		vbuf = null;
-	}
-	
-	inline function isDisposed() {
-		return vbuf == null;
-	}
-
-}
-
 class MemoryManager {
 class MemoryManager {
 
 
 	static inline var MAX_MEMORY = 250 << 20; // MB
 	static inline var MAX_MEMORY = 250 << 20; // MB
 	static inline var MAX_BUFFERS = 4096;
 	static inline var MAX_BUFFERS = 4096;
+	static inline var SIZE = 65533;
+	static var ALL_FLAGS = Type.allEnums(Buffer.BufferFlag);
 
 
 	@:allow(h3d)
 	@:allow(h3d)
 	var driver : Driver;
 	var driver : Driver;
-	var buffers : Array<BigBuffer>;
+	var buffers : Array<ManagedBuffer>;
 	var indexes : Array<Indexes>;
 	var indexes : Array<Indexes>;
 	var textures : Array<h3d.mat.Texture>;
 	var textures : Array<h3d.mat.Texture>;
 	
 	
@@ -97,27 +18,26 @@ class MemoryManager {
 	public var usedMemory(default, null) : Int = 0;
 	public var usedMemory(default, null) : Int = 0;
 	public var texMemory(default, null) : Int = 0;
 	public var texMemory(default, null) : Int = 0;
 	public var bufferCount(default,null) : Int = 0;
 	public var bufferCount(default,null) : Int = 0;
-	public var allocSize(default,null) : Int;
 
 
-	public function new(driver,allocSize) {
+	public function new(driver) {
 		this.driver = driver;
 		this.driver = driver;
-		this.allocSize = allocSize;
-
+	}
+	
+	public function init() {
 		indexes = new Array();
 		indexes = new Array();
 		textures = new Array();
 		textures = new Array();
 		buffers = new Array();
 		buffers = new Array();
-		
 		initIndexes();
 		initIndexes();
 	}
 	}
 	
 	
 	function initIndexes() {
 	function initIndexes() {
 		var indices = new hxd.IndexBuffer();
 		var indices = new hxd.IndexBuffer();
-		for( i in 0...allocSize ) indices.push(i);
-		triIndexes = allocIndex(indices);
+		for( i in 0...SIZE ) indices.push(i);
+		triIndexes = h3d.Indexes.alloc(indices);
 
 
 		var indices = new hxd.IndexBuffer();
 		var indices = new hxd.IndexBuffer();
 		var p = 0;
 		var p = 0;
-		for( i in 0...allocSize >> 2 ) {
+		for( i in 0...SIZE >> 2 ) {
 			var k = i << 2;
 			var k = i << 2;
 			indices.push(k);
 			indices.push(k);
 			indices.push(k + 1);
 			indices.push(k + 1);
@@ -126,7 +46,8 @@ class MemoryManager {
 			indices.push(k + 1);
 			indices.push(k + 1);
 			indices.push(k + 3);
 			indices.push(k + 3);
 		}
 		}
-		quadIndexes = allocIndex(indices);
+		indices.push(SIZE);
+		quadIndexes = h3d.Indexes.alloc(indices);
 	}
 	}
 
 
 	/**
 	/**
@@ -136,17 +57,17 @@ class MemoryManager {
 	public dynamic function garbage() {
 	public dynamic function garbage() {
 	}
 	}
 
 
+	// ------------------------------------- BUFFERS ------------------------------------------
+	
 	/**
 	/**
 		Clean empty (unused) buffers
 		Clean empty (unused) buffers
 	**/
 	**/
-	public function cleanBuffers() {
+	public function cleanManagedBuffers() {
 		for( i in 0...buffers.length ) {
 		for( i in 0...buffers.length ) {
-			var b = buffers[i], prev : BigBuffer = null;
+			var b = buffers[i], prev : ManagedBuffer = null;
 			while( b != null ) {
 			while( b != null ) {
-				if( b.free.count == b.size ) {
+				if( b.freeList.count == b.size ) {
 					b.dispose();
 					b.dispose();
-					bufferCount--;
-					usedMemory -= b.size * b.stride * 4;
 					if( prev == null )
 					if( prev == null )
 						buffers[i] = b.next;
 						buffers[i] = b.next;
 					else
 					else
@@ -157,73 +78,108 @@ class MemoryManager {
 			}
 			}
 		}
 		}
 	}
 	}
+	
+	@:allow(h3d.impl.ManagedBuffer)
+	function allocManaged( m : ManagedBuffer ) {
+		if( m.vbuf != null ) return;
 
 
-	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.free;
-				while( f != null ) {
-					free += f.count * b.stride * 4;
-					f = f.next;
-				}
-				count++;
-				b = b.next;
+		var mem = m.size * m.stride * 4;
+		while( usedMemory + mem > MAX_MEMORY || bufferCount >= MAX_BUFFERS || (m.vbuf = driver.allocVertex(m)) == null ) {
+			var size = usedMemory - freeMemorySize();
+			garbage();
+			cleanManagedBuffers();
+			if( usedMemory - freeMemorySize() == size ) {
+				if( bufferCount >= MAX_BUFFERS )
+					throw "Too many buffer";
+				throw "Memory full";
 			}
 			}
 		}
 		}
-		return {
-			bufferCount : count,
-			freeMemory : free,
-			totalMemory : total,
-			textureCount : textures.length,
-			textureMemory : texMemory,
-		};
+		usedMemory += mem;
+		bufferCount++;
 	}
 	}
 
 
-	public function allocStats() : Array<{ file : String, line : Int, count : Int, tex : Bool, size : Int }> {
-		#if !debug
-		return [];
-		#else
-		var h = new Map();
-		var all = [];
-		for( buf in buffers ) {
-			var buf = buf;
-			while( buf != null ) {
-				var b = buf.allocHead;
-				while( b != null ) {
-					var key = b.allocPos.fileName + ":" + b.allocPos.lineNumber;
-					var inf = h.get(key);
-					if( inf == null ) {
-						inf = { file : b.allocPos.fileName, line : b.allocPos.lineNumber, count : 0, size : 0, tex : false };
-						h.set(key, inf);
-						all.push(inf);
+	@:allow(h3d.impl.ManagedBuffer)
+	function freeManaged( m : ManagedBuffer ) {
+		if( m.vbuf == null ) return;
+		driver.disposeVertex(m.vbuf);
+		m.vbuf = null;
+		usedMemory -= m.size * m.stride * 4;
+		bufferCount--;
+	}
+	
+	@: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 ) {
+			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 flags = [];
+			for( f in ALL_FLAGS )
+				if( b.flags.has(f) )
+					flags.push(f);
+			b.next = new Buffer(rem, stride, flags);
+			return;
+		}
+		
+		if( !b.flags.has(Managed) ) {
+			var m = new ManagedBuffer(stride, b.vertices);
+			m.allocBuffer(b);
+			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;
 					}
 					}
-					inf.count++;
-					inf.size += b.nvert * b.b.stride * 4;
-					b = b.allocNext;
+					m = m.next;
 				}
 				}
-				buf = buf.next;
 			}
 			}
+			b.vertices = total;
 		}
 		}
-		for( t in textures ) {
-			var key = "$"+t.allocPos.fileName + ":" + t.allocPos.lineNumber;
-			var inf = h.get(key);
-			if( inf == null ) {
-				inf = { file : t.allocPos.fileName, line : t.allocPos.lineNumber, count : 0, size : 0, tex : true };
-				h.set(key, inf);
-				all.push(inf);
-			}
-			inf.count++;
-			inf.size += t.width * t.height * bpp(t);
-		}
-		all.sort(function(a, b) return a.size == b.size ? a.line - b.line : b.size - a.size);
-		return all;
-		#end
+		
+		// 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";
 	}
 	}
+
+	// ------------------------------------- INDEXES ------------------------------------------
 	
 	
-	@:allow(h3d.impl.Indexes.dispose)
+	@:allow(h3d.Indexes)
 	function deleteIndexes( i : Indexes ) {
 	function deleteIndexes( i : Indexes ) {
 		indexes.remove(i);
 		indexes.remove(i);
 		driver.disposeIndexes(i.ibuf);
 		driver.disposeIndexes(i.ibuf);
@@ -231,6 +187,16 @@ class MemoryManager {
 		usedMemory -= i.count * 2;
 		usedMemory -= i.count * 2;
 	}
 	}
 	
 	
+	@:allow(h3d.Indexes)
+	function allocIndexes( i : Indexes ) {
+		i.ibuf = driver.allocIndexes(i.count);
+		indexes.push(i);
+		usedMemory += i.count * 2;
+	}
+
+	
+	// ------------------------------------- TEXTURES ------------------------------------------
+	
 	function bpp( t : h3d.mat.Texture ) {
 	function bpp( t : h3d.mat.Texture ) {
 		return 4;
 		return 4;
 	}
 	}
@@ -272,39 +238,45 @@ class MemoryManager {
 		texMemory += t.width * t.height * bpp(t);
 		texMemory += t.width * t.height * bpp(t);
 	}
 	}
 	
 	
-	public function allocIndex( indices : hxd.IndexBuffer, pos = 0, count = -1 ) {
-		if( count < 0 ) count = indices.length;
-		var ibuf = driver.allocIndexes(count);
-		var idx = new Indexes(this, ibuf, count);
-		idx.upload(indices, 0, count);
-		indexes.push(idx);
-		usedMemory += idx.count * 2;
-		return idx;
-	}
-
-	public function allocBytes( bytes : haxe.io.Bytes, stride : Int, align, ?allocPos : AllocPos ) {
-		var count = Std.int(bytes.length / (stride * 4));
-		var b = alloc(count, stride, align, allocPos);
-		b.uploadBytes(bytes, 0, count);
-		return b;
+	// ------------------------------------- DISPOSE ------------------------------------------
+	
+	public function onContextLost() {
+		dispose();
+		initIndexes();
 	}
 	}
 
 
-	public function allocVector( v : hxd.FloatBuffer, stride, align, ?allocPos : AllocPos ) {
-		var nvert = Std.int(v.length / stride);
-		var b = alloc(nvert, stride, align, allocPos);
-		b.uploadVector(v, 0, nvert);
-		return b;
+	public function dispose() {
+		triIndexes.dispose();
+		quadIndexes.dispose();
+		triIndexes = null;
+		quadIndexes = null;
+		for( t in textures.copy() )
+			t.dispose();
+		for( b in buffers.copy() ) {
+			var b = b;
+			while( b != null ) {
+				b.dispose();
+				b = b.next;
+			}
+		}
+		for( i in indexes.copy() )
+			i.dispose();
+		buffers = [];
+		indexes = [];
+		textures = [];
+		bufferCount = 0;
+		usedMemory = 0;
+		texMemory = 0;
 	}
 	}
+	
+	// ------------------------------------- STATS ------------------------------------------
 
 
-	/**
-		The amount of free buffers memory
-	 **/
-	function freeMemory() {
+	function freeMemorySize() {
 		var size = 0;
 		var size = 0;
 		for( b in buffers ) {
 		for( b in buffers ) {
 			var b = b;
 			var b = b;
 			while( b != null ) {
 			while( b != null ) {
-				var free = b.free;
+				var free = b.freeList;
 				while( free != null ) {
 				while( free != null ) {
 					size += free.count * b.stride * 4;
 					size += free.count * b.stride * 4;
 					free = free.next;
 					free = free.next;
@@ -314,160 +286,74 @@ class MemoryManager {
 		}
 		}
 		return size;
 		return size;
 	}
 	}
-
-	/**
-		Allocate a vertex buffer.
-		Align represent the number of vertex that represent a single primitive : 3 for triangles, 4 for quads
-		You can use 0 to allocate your own buffer but in that case you can't use pre-allocated indexes/quadIndexes
-	 **/
-	public function alloc( nvect : Int, stride, align, ?allocPos : AllocPos ) {
-		var b = buffers[stride], free = null;
-		if( nvect == 0 && align == 0 )
-			align = 3;
-		while( b != null ) {
-			free = b.free;
-			while( free != null ) {
-				if( free.count >= nvect ) {
-					// align 0 must be on first index
-					if( align == 0 ) {
-						if( free.pos != 0 )
-							free = null;
-						break;
-					} else {
-						// we can't alloc into a smaller buffer because we might use preallocated indexes
-						if( b.size != allocSize ) {
-							free = null;
-							break;
-						}
-						var d = (align - (free.pos % align)) % align;
-						if( d == 0 )
-							break;
-							
-						// insert some padding
-						if( free.count >= nvect + d ) {
-							free.next = new FreeCell(free.pos + d, free.count - d, free.next);
-							free.count = d;
-							free = free.next;
-							break;
-						}
-					}
-					break;
+	
+	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;
 				}
 				}
-				free = free.next;
+				count++;
+				b = b.next;
 			}
 			}
-			if( free != null ) break;
-			b = b.next;
 		}
 		}
-		// try splitting big groups
-		if( b == null && align > 0 ) {
-			var size = nvect;
-			while( size > 1000 ) {
-				b = buffers[stride];
-				size >>= 1;
-				size -= size % align;
+		return {
+			bufferCount : bufferCount,
+			freeManagedMemory : free,
+			managedMemory : total,
+			totalVertexMemory : usedMemory,
+			textureCount : textures.length,
+			textureMemory : texMemory,
+		};
+	}
+
+	public function allocStats() : Array<{ file : String, line : Int, count : Int, tex : Bool, size : Int }> {
+		#if !debug
+		return [];
+		#else
+		var h = new Map();
+		var all = [];
+		/*
+		for( buf in buffers ) {
+			var buf = buf;
+			while( buf != null ) {
+				var b = buf.allocHead;
 				while( b != null ) {
 				while( b != null ) {
-					free = b.free;
-					// skip not aligned buffers
-					if( b.size != allocSize )
-						free = null;
-					while( free != null ) {
-						if( free.count >= size ) {
-							// check alignment
-							var d = (align - (free.pos % align)) % align;
-							if( d == 0 )
-								break;
-							// insert some padding
-							if( free.count >= size + d ) {
-								free.next = new FreeCell(free.pos + d, free.count - d, free.next);
-								free.count = d;
-								free = free.next;
-								break;
-							}
-						}
-						free = free.next;
+					var key = b.allocPos.fileName + ":" + b.allocPos.lineNumber;
+					var inf = h.get(key);
+					if( inf == null ) {
+						inf = { file : b.allocPos.fileName, line : b.allocPos.lineNumber, count : 0, size : 0, tex : false };
+						h.set(key, inf);
+						all.push(inf);
 					}
 					}
-					if( free != null ) break;
-					b = b.next;
+					inf.count++;
+					inf.size += b.nvert * b.b.stride * 4;
+					b = b.allocNext;
 				}
 				}
-				if( b != null ) break;
+				buf = buf.next;
 			}
 			}
 		}
 		}
-		// buffer not found : allocate a new one
-		if( b == null ) {
-			var size;
-			if( align == 0 ) {
-				size = nvect;
-				if( size > 0xFFFF ) throw "Too many vertex to allocate "+size;
-			} else
-				size = allocSize; // group allocations together to minimize buffer count
-			var mem = size * stride * 4, v = null;
-			if( usedMemory + mem > MAX_MEMORY || bufferCount >= MAX_BUFFERS || (v = driver.allocVertex(size,stride)) == null ) {
-				var size = usedMemory - freeMemory();
-				garbage();
-				cleanBuffers();
-				if( usedMemory - freeMemory() == size ) {
-					if( bufferCount >= MAX_BUFFERS )
-						throw "Too many buffer";
-					throw "Memory full";
-				}
-				return alloc(nvect, stride, align, allocPos);
+		*/
+		for( t in textures ) {
+			var key = "$"+t.allocPos.fileName + ":" + t.allocPos.lineNumber;
+			var inf = h.get(key);
+			if( inf == null ) {
+				inf = { file : t.allocPos.fileName, line : t.allocPos.lineNumber, count : 0, size : 0, tex : true };
+				h.set(key, inf);
+				all.push(inf);
 			}
 			}
-			usedMemory += mem;
-			bufferCount++;
-			b = new BigBuffer(this, v, stride, size);
-			#if flash
-			untyped v.b = b;
-			#end
-			b.next = buffers[stride];
-			buffers[stride] = b;
-			free = b.free;
+			inf.count++;
+			inf.size += t.width * t.height * bpp(t);
 		}
 		}
-		// always alloc multiples of 4 (prevent quad split)
-		var alloc = nvect > free.count ? free.count - (free.count%align) : nvect;
-		var fpos = free.pos;
-		free.pos += alloc;
-		free.count -= alloc;
-		var b = new Buffer(b, fpos, alloc);
-		nvect -= alloc;
-		#if debug
-		var head = b.b.allocHead;
-		b.allocPos = allocPos;
-		b.allocNext = head;
-		if( head != null ) head.allocPrev = b;
-		b.b.allocHead = b;
+		all.sort(function(a, b) return a.size == b.size ? a.line - b.line : b.size - a.size);
+		return all;
 		#end
 		#end
-		if( nvect > 0 )
-			b.next = this.alloc(nvect, stride, align #if debug, allocPos #end);
-		return b;
 	}
 	}
 
 
-	public function onContextLost() {
-		dispose();
-		initIndexes();
-	}
-
-	public function dispose() {
-		triIndexes.dispose();
-		quadIndexes.dispose();
-		triIndexes = null;
-		quadIndexes = null;
-		for( t in textures.copy() )
-			t.dispose();
-		for( b in buffers.copy() ) {
-			var b = b;
-			while( b != null ) {
-				b.dispose();
-				b = b.next;
-			}
-		}
-		for( i in indexes.copy() )
-			i.dispose();
-		buffers = [];
-		indexes = [];
-		textures = [];
-		bufferCount = 0;
-		usedMemory = 0;
-		texMemory = 0;
-	}
 
 
 }
 }

+ 33 - 19
h3d/impl/Stage3dDriver.hx

@@ -6,25 +6,24 @@ import h3d.impl.Driver;
 @:allow(h3d.impl.Stage3dDriver)
 @:allow(h3d.impl.Stage3dDriver)
 class VertexWrapper {
 class VertexWrapper {
 	var vbuf : flash.display3D.VertexBuffer3D;
 	var vbuf : flash.display3D.VertexBuffer3D;
-	var stride : Int;
 	var written : Bool;
 	var written : Bool;
-	var b : MemoryManager.BigBuffer;
+	var b : ManagedBuffer;
 	
 	
-	function new(vbuf, stride) {
+	function new(vbuf, b) {
 		this.vbuf = vbuf;
 		this.vbuf = vbuf;
-		this.stride = stride;
+		this.b = b;
 	}
 	}
-	
+		
 	function finalize( driver : Stage3dDriver ) {
 	function finalize( driver : Stage3dDriver ) {
 		if( written ) return;
 		if( written ) return;
 		written = true;
 		written = true;
 		// fill all the free positions that were unwritten with zeroes (necessary for flash)
 		// fill all the free positions that were unwritten with zeroes (necessary for flash)
-		var f = b.free;
+		var f = @:privateAccess b.freeList;
 		while( f != null ) {
 		while( f != null ) {
 			if( f.count > 0 ) {
 			if( f.count > 0 ) {
 				var mem : UInt = f.count * b.stride * 4;
 				var mem : UInt = f.count * b.stride * 4;
 				if( driver.empty.length < mem ) driver.empty.length = mem;
 				if( driver.empty.length < mem ) driver.empty.length = mem;
-				driver.uploadVertexBytes(b.vbuf, f.pos, f.count, haxe.io.Bytes.ofData(driver.empty), 0);
+				driver.uploadVertexBytes(@:privateAccess b.vbuf, f.pos, f.count, haxe.io.Bytes.ofData(driver.empty), 0);
 			}
 			}
 			f = f.next;
 			f = f.next;
 		}
 		}
@@ -151,17 +150,17 @@ class Stage3dDriver extends Driver {
 		t.dispose();
 		t.dispose();
 	}
 	}
 	
 	
-	override function allocVertex( count : Int, stride : Int ) : VertexBuffer {
+	override function allocVertex( buf : ManagedBuffer ) : VertexBuffer {
 		var v;
 		var v;
 		try {
 		try {
-			v = ctx.createVertexBuffer(count, stride);
+			v = ctx.createVertexBuffer(buf.size, buf.stride);
 		} catch( e : flash.errors.Error ) {
 		} catch( e : flash.errors.Error ) {
 			// too many resources / out of memory
 			// too many resources / out of memory
 			if( e.errorID == 3691 )
 			if( e.errorID == 3691 )
 				return null;
 				return null;
 			throw e;
 			throw e;
 		}
 		}
-		return new VertexWrapper(v, stride);
+		return new VertexWrapper(v, buf);
 	}
 	}
 
 
 	override function allocIndexes( count : Int ) : IndexBuffer {
 	override function allocIndexes( count : Int ) : IndexBuffer {
@@ -184,7 +183,7 @@ class Stage3dDriver extends Driver {
 			throw "Unsupported texture flag";
 			throw "Unsupported texture flag";
 		try {
 		try {
 			if( t.flags.has(IsRectangle) ) {
 			if( t.flags.has(IsRectangle) ) {
-				if( t.flags.has(Cubic) || t.flags.has(MipMapped) || t.flags.has(Target) )
+				if( t.flags.has(Cubic) || t.flags.has(MipMapped) )
 					throw "Not power of two texture is not supported with these flags";
 					throw "Not power of two texture is not supported with these flags";
 				#if !flash11_8
 				#if !flash11_8
 				throw "Support for rectangle texture requires Flash 11.8+ compilation";
 				throw "Support for rectangle texture requires Flash 11.8+ compilation";
@@ -249,7 +248,7 @@ class Stage3dDriver extends Driver {
 	
 	
 	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
 	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
 		var data = buf.getNative();
 		var data = buf.getNative();
-		v.vbuf.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, vertexCount * v.stride + bufPos), startVertex, vertexCount );
+		v.vbuf.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, vertexCount * v.b.stride + bufPos), startVertex, vertexCount );
 	}
 	}
 
 
 	override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, bytes : haxe.io.Bytes, bufPos : Int ) {
 	override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, bytes : haxe.io.Bytes, bufPos : Int ) {
@@ -345,8 +344,8 @@ class Stage3dDriver extends Driver {
 			return;
 			return;
 		curBuffer = v;
 		curBuffer = v;
 		curMultiBuffer[0] = -1;
 		curMultiBuffer[0] = -1;
-		if( v.stride < curShader.stride )
-			throw "Buffer stride (" + v.stride + ") and shader stride (" + curShader.stride + ") mismatch";
+		if( v.b.stride < curShader.stride )
+			throw "Buffer stride (" + v.b.stride + ") and shader stride (" + curShader.stride + ") mismatch";
 		if( !v.written )
 		if( !v.written )
 			v.finalize(this);
 			v.finalize(this);
 		var pos = 0, offset = 0;
 		var pos = 0, offset = 0;
@@ -385,11 +384,11 @@ class Stage3dDriver extends Driver {
 			var b = buffers;
 			var b = buffers;
 			while( offset < curShader.stride ) {
 			while( offset < curShader.stride ) {
 				var size = bits & 7;
 				var size = bits & 7;
-				if( b.b.next != null )
+				if( b.buffer.next != null )
 					throw "Buffer is split";
 					throw "Buffer is split";
-				if( !b.b.b.vbuf.written )
-					b.b.b.vbuf.finalize(this);
-				ctx.setVertexBufferAt(pos, b.b.b.vbuf.vbuf, b.offset, FORMAT[size]);
+				var vbuf = @:privateAccess b.buffer.buffer.vbuf;
+				if( !vbuf.written ) vbuf.finalize(this);
+				ctx.setVertexBufferAt(pos, vbuf.vbuf, b.offset, FORMAT[size]);
 				curMultiBuffer[pos] = b.id;
 				curMultiBuffer[pos] = b.id;
 				offset += size == 0 ? 1 : size;
 				offset += size == 0 ? 1 : size;
 				bits >>= 3;
 				bits >>= 3;
@@ -402,9 +401,24 @@ class Stage3dDriver extends Driver {
 			curBuffer = null;
 			curBuffer = null;
 		}
 		}
 	}
 	}
+
+	function debugDraw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
+		try {
+			ctx.drawTriangles(ibuf, startIndex, ntriangles);
+		} catch( e : flash.errors.Error ) {
+			// this error should not happen, but sometime does in debug mode (?)
+			if( e.errorID != 3605 )
+				throw e;
+		}
+	}
 	
 	
 	override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
 	override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
-		if( enableDraw ) ctx.drawTriangles(ibuf, startIndex, ntriangles);
+		if( enableDraw ) {
+			if( ctx.enableErrorChecking )
+				debugDraw(ibuf, startIndex, ntriangles);
+			else
+				ctx.drawTriangles(ibuf, startIndex, ntriangles);
+		}
 	}
 	}
 
 
 	override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
 	override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {

+ 11 - 2
h3d/mat/Texture.hx

@@ -112,10 +112,13 @@ class Texture {
 
 
 		this.width = width;
 		this.width = width;
 		this.height = height;
 		this.height = height;
-		alloc();
+		
+		if( !flags.has(NoAlloc) )
+			alloc();
 	}
 	}
 
 
 	public function clear( color : Int ) {
 	public function clear( color : Int ) {
+		alloc();
 		var p = hxd.Pixels.alloc(width, height, BGRA);
 		var p = hxd.Pixels.alloc(width, height, BGRA);
 		var k = 0;
 		var k = 0;
 		var b = color & 0xFF, g = (color >> 8) & 0xFF, r = (color >> 16) & 0xFF, a = color >>> 24;
 		var b = color & 0xFF, g = (color >> 8) & 0xFF, r = (color >> 16) & 0xFF, a = color >>> 24;
@@ -130,16 +133,22 @@ class Texture {
 	}
 	}
 	
 	
 	public function uploadBitmap( bmp : hxd.BitmapData, mipLevel = 0, side = 0 ) {
 	public function uploadBitmap( bmp : hxd.BitmapData, mipLevel = 0, side = 0 ) {
+		alloc();
 		mem.driver.uploadTextureBitmap(this, bmp, mipLevel, side);
 		mem.driver.uploadTextureBitmap(this, bmp, mipLevel, side);
 	}
 	}
 
 
 	public function uploadPixels( pixels : hxd.Pixels, mipLevel = 0, side = 0 ) {
 	public function uploadPixels( pixels : hxd.Pixels, mipLevel = 0, side = 0 ) {
+		alloc();
 		mem.driver.uploadTexturePixels(this, pixels, mipLevel, side);
 		mem.driver.uploadTexturePixels(this, pixels, mipLevel, side);
 	}
 	}
 
 
 	public function dispose() {
 	public function dispose() {
-		if( t != null )
+		if( t != null ) {
 			mem.deleteTexture(this);
 			mem.deleteTexture(this);
+			#if debug
+			this.allocPos.customParams = ["#DISPOSED"];
+			#end
+		}
 	}
 	}
 	
 	
 	public static function fromBitmap( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {
 	public static function fromBitmap( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {

+ 1 - 3
h3d/parts/Emitter.hx

@@ -558,9 +558,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		}
 		var stride = 10;
 		var stride = 10;
 		if( hasColor ) stride += 4;
 		if( hasColor ) stride += 4;
-		var nverts = Std.int(pos / stride);
-		var buffer = ctx.engine.mem.alloc(nverts, stride, 4);
-		buffer.uploadVector(tmpBuf, 0, nverts);
+		var buffer = h3d.Buffer.ofFloats(tmpBuf, stride, [Quads, Dynamic]);
 		var size = eval(state.globalSize);
 		var size = eval(state.globalSize);
 		
 		
 		/*
 		/*

+ 10 - 10
h3d/prim/FBXModel.hx

@@ -1,6 +1,6 @@
 package h3d.prim;
 package h3d.prim;
 using h3d.fbx.Data;
 using h3d.fbx.Data;
-import h3d.impl.Buffer.BufferOffset;
+import h3d.Buffer.BufferOffset;
 import h3d.col.Point;
 import h3d.col.Point;
 
 
 class FBXModel extends MeshPrimitive {
 class FBXModel extends MeshPrimitive {
@@ -10,7 +10,7 @@ class FBXModel extends MeshPrimitive {
 	public var multiMaterial : Bool;
 	public var multiMaterial : Bool;
 	var bounds : h3d.col.Bounds;
 	var bounds : h3d.col.Bounds;
 	var curMaterial : Int;
 	var curMaterial : Int;
-	var groupIndexes : Array<h3d.impl.Indexes>;
+	var groupIndexes : Array<Indexes>;
 
 
 	public function new(g) {
 	public function new(g) {
 		this.geom = g;
 		this.geom = g;
@@ -183,28 +183,28 @@ class FBXModel extends MeshPrimitive {
 			pos++;
 			pos++;
 		}
 		}
 		
 		
-		addBuffer("position", engine.mem.allocVector(pbuf, 3, 0));
-		if( nbuf != null ) addBuffer("normal", engine.mem.allocVector(nbuf, 3, 0));
-		if( tbuf != null ) addBuffer("uv", engine.mem.allocVector(tbuf, 2, 0));
+		addBuffer("position", h3d.Buffer.ofFloats(pbuf, 3));
+		if( nbuf != null ) addBuffer("normal", h3d.Buffer.ofFloats(nbuf, 3));
+		if( tbuf != null ) addBuffer("uv", h3d.Buffer.ofFloats(tbuf, 2));
 		if( sbuf != null ) {
 		if( sbuf != null ) {
 			var nverts = Std.int(sbuf.length / ((skin.bonesPerVertex + 1) * 4));
 			var nverts = Std.int(sbuf.length / ((skin.bonesPerVertex + 1) * 4));
-			var skinBuf = engine.mem.alloc(nverts, skin.bonesPerVertex + 1, 0);
+			var skinBuf = new h3d.Buffer(nverts, skin.bonesPerVertex + 1);
 			skinBuf.uploadBytes(sbuf.getBytes(), 0, nverts);
 			skinBuf.uploadBytes(sbuf.getBytes(), 0, nverts);
 			addBuffer("weights", skinBuf, 0);
 			addBuffer("weights", skinBuf, 0);
 			addBuffer("indexes", skinBuf, skin.bonesPerVertex);
 			addBuffer("indexes", skinBuf, skin.bonesPerVertex);
 		}
 		}
-		if( cbuf != null ) addBuffer("color", engine.mem.allocVector(cbuf, 3, 0));
+		if( cbuf != null ) addBuffer("color", h3d.Buffer.ofFloats(cbuf, 3));
 		
 		
-		indexes = engine.mem.allocIndex(idx);
+		indexes = h3d.Indexes.alloc(idx);
 		if( mats != null ) {
 		if( mats != null ) {
 			groupIndexes = [];
 			groupIndexes = [];
 			for( i in midx )
 			for( i in midx )
-				groupIndexes.push(i == null ? null : engine.mem.allocIndex(i));
+				groupIndexes.push(i == null ? null : h3d.Indexes.alloc(i));
 		}
 		}
 		if( sidx != null ) {
 		if( sidx != null ) {
 			groupIndexes = [];
 			groupIndexes = [];
 			for( i in sidx )
 			for( i in sidx )
-				groupIndexes.push(i == null ? null : engine.mem.allocIndex(i));
+				groupIndexes.push(i == null ? null : h3d.Indexes.alloc(i));
 		}
 		}
 	}
 	}
 	
 	

+ 2 - 2
h3d/prim/MeshPrimitive.hx

@@ -2,7 +2,7 @@ package h3d.prim;
 
 
 class MeshPrimitive extends Primitive {
 class MeshPrimitive extends Primitive {
 		
 		
-	var bufferCache : Map<Int,h3d.impl.Buffer.BufferOffset>;
+	var bufferCache : Map<Int,h3d.Buffer.BufferOffset>;
 	
 	
 	function allocBuffer( engine : h3d.Engine, name : String ) {
 	function allocBuffer( engine : h3d.Engine, name : String ) {
 		return null;
 		return null;
@@ -22,7 +22,7 @@ class MeshPrimitive extends Primitive {
 		var id = hash(name);
 		var id = hash(name);
 		var old = bufferCache.get(id);
 		var old = bufferCache.get(id);
 		if( old != null ) old.dispose();
 		if( old != null ) old.dispose();
-		bufferCache.set(id, new h3d.impl.Buffer.BufferOffset(buf, offset));
+		bufferCache.set(id, new h3d.Buffer.BufferOffset(buf, offset));
 	}
 	}
 
 
 	override public function dispose() {
 	override public function dispose() {

+ 1 - 1
h3d/prim/Plan2D.hx

@@ -27,7 +27,7 @@ class Plan2D extends Primitive {
 		v.push( 1);
 		v.push( 1);
 		v.push( 0);
 		v.push( 0);
 		
 		
-		buffer = engine.mem.allocVector(v, 4, 4);
+		buffer = h3d.Buffer.ofFloats(v, 4, [Quads]);
 	}
 	}
 	
 	
 	override function render(engine:h3d.Engine) {
 	override function render(engine:h3d.Engine) {

+ 1 - 1
h3d/prim/Plan3D.hx

@@ -73,7 +73,7 @@ class Plan3D extends Primitive {
 		v.push( 0);
 		v.push( 0);
 		v.push( 1);
 		v.push( 1);
 		
 		
-		buffer = engine.mem.allocVector(v, 8, 4);
+		buffer = h3d.Buffer.ofFloats(v, 8, [Quads]);
 	}
 	}
 	
 	
 	override function render(engine:h3d.Engine) {
 	override function render(engine:h3d.Engine) {

+ 2 - 2
h3d/prim/Polygon.hx

@@ -56,10 +56,10 @@ class Polygon extends Primitive {
 				buf.push(c.z);
 				buf.push(c.z);
 			}
 			}
 		}
 		}
-		buffer = engine.mem.allocVector(buf, size, idx == null ? 3 : 0);
+		buffer = h3d.Buffer.ofFloats(buf, size, idx == null ? [Triangles] : null);
 		
 		
 		if( idx != null )
 		if( idx != null )
-			indexes = engine.mem.allocIndex(idx);
+			indexes = h3d.Indexes.alloc(idx);
 	}
 	}
 
 
 
 

+ 3 - 11
h3d/prim/Primitive.hx

@@ -2,19 +2,11 @@ package h3d.prim;
 
 
 class Primitive {
 class Primitive {
 	
 	
-	public var buffer : h3d.impl.Buffer;
-	public var indexes : h3d.impl.Indexes;
+	public var buffer : Buffer;
+	public var indexes : Indexes;
 	
 	
 	public function triCount() {
 	public function triCount() {
-		if( indexes != null )
-			return Std.int(indexes.count / 3);
-		var count = 0;
-		var b = buffer;
-		while( b != null ) {
-			count += Std.int(b.nvert / 3);
-			b = b.next;
-		}
-		return count;
+		return if( indexes != null ) Std.int(indexes.count / 3) else if( buffer == null ) 0 else Std.int(buffer.totalVertices() / 3);
 	}
 	}
 	
 	
 	public function getBounds() : h3d.col.Bounds {
 	public function getBounds() : h3d.col.Bounds {

+ 1 - 1
h3d/prim/Quads.hx

@@ -62,7 +62,7 @@ class Quads extends Primitive {
 		var size = 3;
 		var size = 3;
 		if( normals != null ) size += 3;
 		if( normals != null ) size += 3;
 		if( uvs != null ) size += 2;
 		if( uvs != null ) size += 2;
-		buffer = engine.mem.allocVector(v,size, 4);
+		buffer = h3d.Buffer.ofFloats(v, size, [Quads]);
 	}
 	}
 	
 	
 	public function getPoints() {
 	public function getPoints() {

+ 2 - 2
h3d/prim/RawPrimitive.hx

@@ -3,9 +3,9 @@ package h3d.prim;
 class RawPrimitive extends Primitive {
 class RawPrimitive extends Primitive {
 
 
 	public function new( engine : h3d.Engine, vbuf : hxd.FloatBuffer, stride : Int, ?ibuf : hxd.IndexBuffer ) {
 	public function new( engine : h3d.Engine, vbuf : hxd.FloatBuffer, stride : Int, ?ibuf : hxd.IndexBuffer ) {
-		buffer = engine.mem.allocVector(vbuf, stride, ibuf == null ? 3 : 0);
+		buffer = h3d.Buffer.ofFloats(vbuf, stride, ibuf == null ? [Triangles] : null);
 		if( ibuf != null )
 		if( ibuf != null )
-			indexes = engine.mem.allocIndex(ibuf);
+			indexes = h3d.Indexes.alloc(ibuf);
 	}
 	}
 
 
 }
 }

+ 1 - 1
h3d/scene/Scene.hx

@@ -121,7 +121,7 @@ class Scene extends Object implements h3d.IDrawable {
 				p = p.next;
 				p = p.next;
 			}
 			}
 		}
 		}
-		ctx.passes = passes[0].pass;
+		if( passes.length > 0 ) ctx.passes = passes[0].pass;
 		ctx.done();
 		ctx.done();
 		for( p in postPasses )
 		for( p in postPasses )
 			p.render(engine);
 			p.render(engine);

+ 2 - 2
hxd/Stage.hx

@@ -302,11 +302,11 @@ class Stage {
 	}
 	}
 
 
 	function get_mouseX() {
 	function get_mouseX() {
-		return Math.round(curMouseX - canvasPos.left);
+		return Math.round((curMouseX - canvasPos.left) * js.Browser.window.devicePixelRatio);
 	}
 	}
 
 
 	function get_mouseY() {
 	function get_mouseY() {
-		return Math.round(curMouseY - canvasPos.top);
+		return Math.round((curMouseY - canvasPos.top) * js.Browser.window.devicePixelRatio);
 	}
 	}
 	
 	
 	function get_mouseLock() {
 	function get_mouseLock() {