[Bf-blender-cvs] [a31609a] object_nodes: Two-level use-count system for bvm pointer variables.

Lukas Tönne noreply at git.blender.org
Mon Jan 18 13:10:58 CET 2016


Commit: a31609a6becade0c726f1d3113c66985c994c87e
Author: Lukas Tönne
Date:   Mon Jan 18 13:05:36 2016 +0100
Branches: object_nodes
https://developer.blender.org/rBa31609a6becade0c726f1d3113c66985c994c87e

Two-level use-count system for bvm pointer variables.

The rationale for this change is that copying variables on the bvm stack
will become necessary for compound variables (structs). In order to
efficiently keep pointers on the stack without making deep copies every
time such a variable is copied, the pointer must be a kind of shared_ptr
concept. In addition to this the stack variable itself must also be counted,
so that we have a way of detecting when it "goes out of scope", i.e. all
nodes using it have finished.

The node_counted_ptr is not a full C++ shared_ptr, because the user counting
is handled explicitly by the compiled bvm instructions. Using a std::shared_ptr
would be difficult due to the mixed levels of evaluation (compile-time constants,
storing shared_ptr on the opaque stack), and because of difficult interfacing
with C code (returning persistent plain pointers).

===================================================================

M	source/blender/blenvm/bvm/bvm_eval.cc
M	source/blender/blenvm/compile/bvm_nodegraph.cc
M	source/blender/blenvm/intern/bvm_api.cc
M	source/blender/blenvm/util/bvm_util_data_ptr.h

===================================================================

diff --git a/source/blender/blenvm/bvm/bvm_eval.cc b/source/blender/blenvm/bvm/bvm_eval.cc
index d389583..e4cb57a 100644
--- a/source/blender/blenvm/bvm/bvm_eval.cc
+++ b/source/blender/blenvm/bvm/bvm_eval.cc
@@ -215,7 +215,8 @@ static void eval_op_release_mesh_ptr(EvalStack *stack, StackIndex offset)
 
 static void eval_op_init_duplis_ptr(EvalStack *stack, StackIndex offset, int use_count)
 {
-	duplis_ptr p(new DupliList());
+	static DupliList __empty_duplilist__ = DupliList();
+	duplis_ptr p(&__empty_duplilist__);
 	p.set_use_count(use_count);
 	stack_store_duplis_ptr(stack, offset, p);
 }
diff --git a/source/blender/blenvm/compile/bvm_nodegraph.cc b/source/blender/blenvm/compile/bvm_nodegraph.cc
index dd9d1c2..98cafa7 100644
--- a/source/blender/blenvm/compile/bvm_nodegraph.cc
+++ b/source/blender/blenvm/compile/bvm_nodegraph.cc
@@ -1370,7 +1370,7 @@ static mesh_ptr __empty_mesh__;
 
 static void register_opcode_node_types()
 {
-	static DupliList *__empty_duplilist__ = new DupliList();
+	static duplis_ptr __empty_duplilist__ = duplis_ptr(new DupliList());
 	
 	NodeType *nt;
 	
@@ -1415,7 +1415,7 @@ static void register_opcode_node_types()
 	nt->add_output("value", "MESH");
 	
 	nt = NodeGraph::add_pass_node_type("PASS_DUPLIS");
-	nt->add_input("value", "DUPLIS", duplis_ptr(__empty_duplilist__));
+	nt->add_input("value", "DUPLIS", __empty_duplilist__);
 	nt->add_output("value", "DUPLIS");
 	
 	nt = NodeGraph::add_pass_node_type("PASS_FLOAT_ARRAY");
@@ -1514,7 +1514,7 @@ static void register_opcode_node_types()
 	nt->add_output("value", "MESH");
 	
 	nt = NodeGraph::add_function_node_type("VALUE_DUPLIS");
-	nt->add_input("value", "DUPLIS", duplis_ptr(__empty_duplilist__), INPUT_CONSTANT);
+	nt->add_input("value", "DUPLIS", __empty_duplilist__, INPUT_CONSTANT);
 	nt->add_output("value", "DUPLIS");
 	
 	nt = NodeGraph::add_function_node_type("GET_ELEM_FLOAT3");
@@ -1833,8 +1833,8 @@ static void register_opcode_node_types()
 	nt->add_output("dupli", "DUPLIS");
 	
 	nt = NodeGraph::add_function_node_type("DUPLIS_COMBINE");
-	nt->add_input("duplis_a", "DUPLIS", duplis_ptr(__empty_duplilist__));
-	nt->add_input("duplis_b", "DUPLIS", duplis_ptr(__empty_duplilist__));
+	nt->add_input("duplis_a", "DUPLIS", __empty_duplilist__);
+	nt->add_input("duplis_b", "DUPLIS", __empty_duplilist__);
 	nt->add_output("duplis", "DUPLIS");
 	
 	nt = NodeGraph::add_function_node_type("ADD_MATRIX44");
diff --git a/source/blender/blenvm/intern/bvm_api.cc b/source/blender/blenvm/intern/bvm_api.cc
index ab38733..67d6c60 100644
--- a/source/blender/blenvm/intern/bvm_api.cc
+++ b/source/blender/blenvm/intern/bvm_api.cc
@@ -66,8 +66,7 @@ extern "C" {
 
 namespace bvm {
 static mesh_ptr __empty_mesh__;
-static DupliList __empty_dupli_list__ = DupliList();
-static duplis_ptr __empty_duplis__ = duplis_ptr(&__empty_dupli_list__);
+static duplis_ptr __empty_duplilist__ = duplis_ptr(new DupliList());
 }
 
 void BVM_init(void)
@@ -1132,7 +1131,8 @@ struct DerivedMesh *BVM_eval_modifier(struct BVMEvalGlobals *globals,
 	_FUNC(fn)->eval(_CTX(ctx), _GLOBALS(globals), args, results);
 	
 	DerivedMesh *dm = result.get();
-	result.reset();
+	/* destroy the pointer variable */
+	result.ptr().reset();
 	return dm;
 }
 
@@ -1143,7 +1143,7 @@ static void init_dupli_graph(bvm::NodeGraph &graph)
 	using namespace bvm;
 	
 	graph.add_input("dupli.object", "RNAPOINTER");
-	graph.add_output("dupli.result", "DUPLIS", __empty_duplis__);
+	graph.add_output("dupli.result", "DUPLIS", __empty_duplilist__);
 }
 
 struct BVMFunction *BVM_gen_dupli_function(struct bNodeTree *btree)
@@ -1213,5 +1213,5 @@ void BVM_eval_dupli(struct BVMEvalGlobals *globals,
 			                       false, dupli.hide, dupli.recursive);
 		}
 	}
-	result.clear();
+	result.reset();
 }
diff --git a/source/blender/blenvm/util/bvm_util_data_ptr.h b/source/blender/blenvm/util/bvm_util_data_ptr.h
index 937bb5f..cb894bd 100644
--- a/source/blender/blenvm/util/bvm_util_data_ptr.h
+++ b/source/blender/blenvm/util/bvm_util_data_ptr.h
@@ -45,103 +45,186 @@ extern "C" {
 
 namespace bvm {
 
-/* generic default deletor, using 'delete' operator */
+/* generic default deleter, using 'delete' operator */
 template <typename T>
-struct DeleteDestructor {
-	static void destroy(T *data)
+struct DefaultDeleter {
+	void operator() (T *data) const
 	{
 		delete data;
 	}
 };
 
 /* reference-counted pointer for managing transient data on the stack */
-template <typename T, typename DestructorT = DeleteDestructor<T> >
-struct node_data_ptr {
-	typedef T element_type;
-	typedef node_data_ptr<T> self_type;
+template <typename T, typename Deleter = DefaultDeleter<T> >
+struct node_counted_ptr {
+	typedef T data_t;
+	typedef node_counted_ptr<T, Deleter> self_t;
 	
-	node_data_ptr() :
-	    m_data(0),
-	    m_refs(0)
+	node_counted_ptr() :
+	    m_data(NULL),
+	    m_refs(NULL)
 	{}
 	
-	explicit node_data_ptr(element_type *data) :
+	explicit node_counted_ptr(data_t *data) :
 	    m_data(data),
-	    m_refs(0)
+	    m_refs(NULL)
 	{}
 	
-	~node_data_ptr()
+	template <typename Y, typename YDeleter>
+	node_counted_ptr(const node_counted_ptr<Y, YDeleter> &other) :
+	    m_data(other.m_data),
+	    m_refs(other.m_refs)
+	{
+	}
+	
+	~node_counted_ptr()
+	{
+	}
+	
+	template <typename Y, typename YDeleter>
+	self_t& operator = (const node_counted_ptr<Y, YDeleter> &other)
 	{
+		m_data = other.m_data;
+	    m_refs = other.m_refs;
 	}
 	
-	element_type* get() const
+	operator bool() const
+	{
+		return m_refs != NULL;
+	}
+	
+	data_t* get() const
 	{
 		return m_data;
 	}
 	
 	void reset()
 	{
-		m_data = 0;
+		m_data = NULL;
 		if (m_refs) {
 			destroy_refs(m_refs);
-			m_refs = 0;
+			m_refs = NULL;
 		}
 	}
 	
-	void set(element_type *data)
+	void reset(data_t *data)
 	{
 		if (m_data != data) {
-			if (m_data)
-				DestructorT::destroy(m_data);
+			if (m_data) {
+				Deleter del;
+				del(m_data);
+			}
 			m_data = data;
 		}
+		if (m_refs) {
+			destroy_refs(m_refs);
+			m_refs = NULL;
+		}
 	}
 	
-	element_type& operator * () const { return *m_data; }
-	element_type* operator -> () const { return m_data; }
+	data_t& operator * () const { return *m_data; }
+	data_t* operator -> () const { return m_data; }
 	
-	void set_use_count(size_t use_count)
+	void retain()
 	{
-		assert(m_refs == 0);
-		if (use_count > 0)
-			m_refs = create_refs(use_count);
-		else if (m_refs) {
-			destroy_refs(m_refs);
-			m_refs = 0;
-		}
+		if (m_refs == NULL)
+			m_refs = create_refs();
+		++(*m_refs);
 	}
 	
-	void decrement_use_count()
+	void release()
 	{
-		assert(m_refs != 0 && *m_refs > 0);
+		assert(m_refs != NULL && *m_refs > 0);
 		size_t count = --(*m_refs);
 		if (count == 0) {
 			clear();
 		}
 	}
 	
+protected:
+	/* TODO this could be handled by a common memory manager with a mempool */
+	static size_t *create_refs() { return new size_t(0); }
+	static void destroy_refs(size_t *refs) { delete refs; }
+	
 	void clear()
 	{
 		if (m_data) {
-			DestructorT::destroy(m_data);
-			m_data = 0;
+			Deleter del;
+			del(m_data);
+			m_data = NULL;
 		}
 		if (m_refs) {
 			destroy_refs(m_refs);
-			m_refs = 0;
+			m_refs = NULL;
 		}
 	}
 	
-protected:
-	/* TODO this could be handled by a common memory manager with a mempool */
-	static size_t *create_refs(size_t use_count) { return new size_t(use_count); }
-	static void destroy_refs(size_t *refs) { delete refs; }
-	
 private:
 	T *m_data;
 	size_t *m_refs;
 };
 
+/* reference-counted pointer for managing transient data on the stack */
+template <typename T, typename Deleter = DefaultDeleter<T> >
+struct node_scoped_ptr {
+	typedef T data_t;
+	typedef node_counted_ptr<T, Deleter> counted_ptr_t;
+	typedef node_scoped_ptr<T, Deleter> self_t;
+	
+	node_scoped_ptr() :
+	    m_ptr(NULL),
+	    m_refs(0)
+	{}
+	
+	explicit node_scoped_ptr(data_t *data) :
+	    m_ptr(data),
+	    m_refs(0)
+	{}
+	
+	~node_scoped_ptr()
+	{
+	}
+	
+	counted_ptr_t& ptr() { return m_ptr; }
+	const counted_ptr_t& ptr() const { return m_ptr; }
+	
+	data_t* get() const { return m_ptr.get(); }
+	
+	void reset()
+	{
+		m_refs = 0;
+		if (m_ptr)
+			m_ptr.release();
+	}
+	
+	void set(data_t *data)
+	{
+		if (m_ptr)
+			m_ptr.release();
+		m_ptr = counted_ptr_t(data);
+		if (data)
+			m_ptr.retain();
+	}
+	
+	void set_use_count(size_t use_count)
+	{
+		assert(m_refs == 0);
+		m_refs = use_count;
+	}
+	
+	void decrement_use_count()
+	{
+		assert(m_refs > 0);
+		--m_refs;
+		if (m_refs == 0)
+			reset();
+	}
+	
+private:
+	counted_ptr_t m_ptr;
+	size_t m_refs;
+};
+
 /* TODO THIS IS IMPORTANT!
  * In the future we will want to manage references to allocated data
  * on the stack in a 'manager'. This is because when cancelling a
@@ -183,13 +266,19 @@ private:
 };
 #endif
 
-struct DerivedMeshDestructor {
-	static void destroy(DerivedMesh *dm)
+/* XXX should use node_counted_ptr<DerivedMesh> instead,
+ * so mesh_ptr is the pointer type, and node_scoped_ptr
+ * is the type of variables on the stack (a scoped variable)
+ */
+
+struct DerivedMeshDeleter {
+	void operator () (DerivedMesh *dm) const
 	{
-		dm->release(dm);
+		if (dm)
+			dm->release(dm);
 	}
 };
-typedef node_data_ptr<DerivedMesh, DerivedMeshDestructor> mesh_ptr;
+typedef node_scoped_ptr<DerivedMesh, DerivedMeshDeleter> mesh_ptr;
 
 struct Dupli {
 	Object *object;
@@ -199,22 +288,25 @@ struct Dupli {
 	bool recursive;
 };
 typedef std::vector<Dupli> DupliList;
-typedef node_data_ptr<DupliList> duplis_ptr;
+typedef node_scoped_ptr<DupliList> duplis_ptr;
 
 inline void create_empty_mesh(mesh_ptr &p)
 {
 	DerivedMesh *dm = CDDM_new(0, 0, 0, 0, 0);
 	/* prevent the DM from getting freed */
 	dm->needsFree = 0;
+	
 	p.set(dm);
 }
 
 inline void destroy_empty_mesh(mesh_ptr &p)
 {
 	DerivedMesh *dm = p.get();
+	p.reset();
+	
 	/* have to set this back so the DM actually gets freed */
 	dm->needsFree = 1;
-	p.clear();
+	dm->release(dm);
 }
 
 } /* namespace bvm */




More information about the Bf-blender-cvs mailing list