Kaynağa Gözat

Reference counter on primitives, remove h3d Object dispose (#558)

Pavel Alexandrov 6 yıl önce
ebeveyn
işleme
3ad5e3e70a

+ 2 - 0
h3d/parts/GpuParticles.hx

@@ -966,10 +966,12 @@ class GpuParticles extends h3d.scene.MultiMaterial {
 	override function serialize( ctx : hxbit.Serializer ) {
 		var old = primitive;
 		var oldMat = materials;
+		if ( old != null ) old.incref();
 		primitive = null;
 		materials = [];
 		super.serialize(ctx);
 		primitive = old;
+		if ( old != null ) old.decref();
 		materials = oldMat;
 	}
 	override function customSerialize(ctx:hxbit.Serializer) {

+ 27 - 0
h3d/prim/Primitive.hx

@@ -16,6 +16,12 @@ class Primitive implements hxd.impl.Serializable {
 	**/
 	public var indexes : Indexes;
 
+	/**
+		Current amount of references to this Primitive.  
+		Use `incref` and `decref` methods to affect this value. If it reaches 0, it will be atuomatically disposed.
+	**/
+	public var refCount(default, null) : Int = 0;
+
 	/**
 		The number of triangles the primitive has.
 	**/
@@ -46,6 +52,27 @@ class Primitive implements hxd.impl.Serializable {
 		return null;
 	}
 
+	/**
+		Increase reference count of the Primitive.
+	**/
+	public function incref():Void
+	{
+		refCount++;
+	}
+
+	/**
+		Decrease reference count of the Primitive.  
+		If recount reaches zero, Primitive is automatically disposed when last referencing mesh is removed from scene.
+	**/
+	public function decref():Void
+	{
+		refCount--;
+		if ( refCount <= 0 ) {
+			refCount = 0;
+			dispose();
+		}
+	}
+
 	/**
 		Allocate the primitive on GPU. Used for internal usage.
 	**/

+ 19 - 4
h3d/scene/CustomObject.hx

@@ -2,7 +2,7 @@ package h3d.scene;
 
 class CustomObject extends Object {
 
-	public var primitive : h3d.prim.Primitive;
+	public var primitive(default, set) : h3d.prim.Primitive;
 	public var material : h3d.mat.Material;
 
 	public function new( prim, mat, ?parent ) {
@@ -36,9 +36,24 @@ class CustomObject extends Object {
 		ctx.emit(material, this);
 	}
 
-	override function dispose() {
-		primitive.dispose();
-		super.dispose();
+	override private function onAdd()
+	{
+		super.onAdd();
+		if ( primitive != null ) primitive.incref();
+	}
+
+	override private function onRemove()
+	{
+		if ( primitive != null ) primitive.decref();
+		super.onRemove();
+	}
+
+	function set_primitive( prim : h3d.prim.Primitive ) : h3d.prim.Primitive {
+		if ( prim != this.primitive && allocated ) {
+			if (this.primitive != null) this.primitive.decref();
+			if (prim != null) prim.incref();
+		}
+		return this.primitive = prim;
 	}
 
 }

+ 21 - 6
h3d/scene/Mesh.hx

@@ -9,7 +9,7 @@ class Mesh extends Object {
 	/**
 		The primitive of the mesh: the list of vertexes and indices necessary to display the mesh.
 	**/
-	public var primitive : h3d.prim.Primitive;
+	public var primitive(default, set) : h3d.prim.Primitive;
 
 	/**
 		The material of the mesh: the properties used to display it (texture, color, shaders, etc.)
@@ -79,11 +79,6 @@ class Mesh extends Object {
 		return super.getMaterials(a);
 	}
 
-	override function dispose() {
-		if( primitive != null ) primitive.dispose();
-		super.dispose();
-	}
-
 	#if (hxbit && !macro && heaps_enable_serialize)
 	override function customSerialize(ctx:hxbit.Serializer) {
 		super.customSerialize(ctx);
@@ -97,4 +92,24 @@ class Mesh extends Object {
 	}
 	#end
 
+	override private function onAdd()
+	{
+		super.onAdd();
+		if ( primitive != null ) primitive.incref();
+	}
+
+	override private function onRemove()
+	{
+		if ( primitive != null ) primitive.decref();
+		super.onRemove();
+	}
+
+	function set_primitive( prim : h3d.prim.Primitive ) : h3d.prim.Primitive {
+		if ( prim != this.primitive && allocated ) {
+			if (this.primitive != null) this.primitive.decref();
+			if (prim != null) prim.incref();
+		}
+		return this.primitive = prim;
+	}
+
 }

+ 0 - 5
h3d/scene/MeshBatch.hx

@@ -58,11 +58,6 @@ class MeshBatch extends Mesh {
 		cleanPasses();
 	}
 
-	override function dispose() {
-		super.dispose();
-		cleanPasses();
-	}
-
 	function cleanPasses() {
 		while( dataPasses != null ) {
 			dataPasses.pass.removeShader(dataPasses.shader);

+ 0 - 8
h3d/scene/Object.hx

@@ -895,14 +895,6 @@ class Object implements hxd.impl.Serializable {
 		return new hxd.impl.ArrayIterator(children);
 	}
 
-	/**
-		Free the GPU memory for this object and its children
-	**/
-	public function dispose() {
-		for( c in children )
-			c.dispose();
-	}
-
 	#if (hxbit && !macro && heaps_enable_serialize)
 	function customSerialize( ctx : hxbit.Serializer ) {
 

+ 6 - 2
h3d/scene/Scene.hx

@@ -235,8 +235,12 @@ class Scene extends Object implements h3d.IDrawable implements hxd.SceneEvents.I
 		return s;
 	}
 
-	override function dispose() {
-		super.dispose();
+	/**
+		Free the GPU memory for this Scene and its children
+	**/
+	public function dispose() {
+		if ( allocated )
+			onRemove();
 		if( hardwarePass != null ) {
 			hardwarePass.dispose();
 			hardwarePass = null;

+ 5 - 4
h3d/scene/World.hx

@@ -37,7 +37,6 @@ class WorldChunk {
 
 	public function dispose() {
 		root.remove();
-		root.dispose();
 	}
 }
 
@@ -475,7 +474,6 @@ class World extends Object {
 		if( !c.initialized ) return;
 		c.initialized = false;
 		for( b in c.buffers ) {
-			b.dispose();
 			b.remove();
 		}
 		c.buffers = new Map();
@@ -516,8 +514,11 @@ class World extends Object {
 
 	}
 
-	override function dispose() {
-		super.dispose();
+	/**
+		Dispose the World instance.  
+		Note: Only chunked world objects will be disposed. Any objects added to World object will be disposed when World is removed from scene or scene is disposed.
+	**/
+	public function dispose() {
 		for( c in allChunks )
 			c.dispose();
 		allChunks = [];

+ 1 - 1
h3d/scene/pbr/terrain/Tile.hx

@@ -500,7 +500,7 @@ class Tile extends h3d.scene.Mesh {
 		}
 	}
 
-	public override function dispose() {
+	public function dispose() {
 		if( heightMap != null ) heightMap.dispose();
 		if( surfaceIndexMap != null ) surfaceIndexMap.dispose();
 		for( i in 0 ... surfaceWeights.length )

+ 8 - 0
hxd/App.hx

@@ -93,6 +93,14 @@ class App implements h3d.IDrawable {
 		this.s2d = s2d;
 	}
 
+	function setScene3D( s3d : h3d.scene.Scene, disposePrevious = true ) {
+		sevents.removeScene(this.s3d);
+		sevents.addScene(s3d);
+		if ( disposePrevious )
+			this.s3d.dispose();
+		this.s3d = s3d;
+	}
+
 	public function render(e:h3d.Engine) {
 		s3d.render(e);
 		s2d.render(e);

+ 1 - 0
hxd/fmt/hmd/Library.hx

@@ -259,6 +259,7 @@ class Library {
 		var p = cachedPrimitives[id];
 		if( p != null ) return p;
 		p = new h3d.prim.HMDModel(header.geometries[id], header.dataPosition, this);
+		p.incref(); // Prevent from auto-disposing
 		cachedPrimitives[id] = p;
 		return p;
 	}