Reported by Valgrind.
We have a memory pool for Nodes which works fine
for creating /deleting nodes.
Scene Graph Layers inherit from Nodes, but don't use
the memory pool.
However when either a Node or a Layer is deleted, the overloaded
Node operator delete( void* ptr ) is called, which tries to free
the Node from the memory pool.
Unfortunately for Layer it was never in the memory pool so no
memory is free'd.
Fix includes:
node destructor is protected
layer destructor is private
node delete operator removed
Change-Id: Icfe83f35b4f29d5b774cde392ff976ad299481c5
*/
Iterator Erase( Iterator position )
{
- delete (*position);
+ Delete (*position);
return Vector< T >::Erase( position );
}
ConstIterator end = Vector< T >::End();
for( Iterator iter = Vector< T >::Begin(); iter != end; ++iter )
{
- delete (*iter);
+ Delete (*iter);
}
Vector< T >::Clear();
}
ConstIterator end = Vector< T >::End();
for( Iterator iter = Vector< T >::Begin() + size; iter != end; ++iter )
{
- delete (*iter);
+ Delete (*iter);
}
}
Vector< T >::Resize( size );
// Undefined assignment operator.
OwnerContainer& operator=( const OwnerContainer& );
+ /**
+ * @brief delete the contents of the pointer
+ * Function provided to allow classes to provide a custom destructor through template specialisation
+ * @param pointer to the object
+ */
+ void Delete( T pointer )
+ {
+ delete pointer;
+ }
+
+
};
} // namespace Dali
RenderQueue& mRenderQueue; ///< Used to send GL clean-up messages for the next Render.
// Messages are queued here following the current update buffer number
- NodeOwnerContainer mNodeQueue[2];
+ OwnerContainer< Node* > mNodeQueue[2];
ShaderQueue mShaderQueue[2];
RendererQueue mRendererQueue[2];
CameraQueue mCameraQueue[2];
for(;iter!=endIter;++iter)
{
(*iter)->OnDestroy();
- delete(*iter);
+ Node::Delete(*iter);
}
// If there is root, reset it, otherwise do nothing as rendering was never started
{
root->OnDestroy();
- delete root;
+ Node::Delete( root );
root = NULL;
}
{
systemLevelRoot->OnDestroy();
- delete systemLevelRoot;
+ Node::Delete( systemLevelRoot );
systemLevelRoot = NULL;
}
class Node;
-typedef OwnerContainer< Node* > NodeOwnerContainer;
-
typedef Dali::Vector< Node* > NodeContainer;
typedef NodeContainer::Iterator NodeIter;
typedef NodeContainer::ConstIterator NodeConstIter;
namespace //Unnamed namespace
{
-//Memory pool used to allocate new nodes. Memory used by this pool will be released when shutting down DALi
+//Memory pool used to allocate new nodes. Memory used by this pool will be released when process dies
+// or DALI library is unloaded
Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Node> gNodeMemoryPool;
}
const PositionInheritanceMode Node::DEFAULT_POSITION_INHERITANCE_MODE( INHERIT_PARENT_POSITION );
const ColorMode Node::DEFAULT_COLOR_MODE( USE_OWN_MULTIPLY_PARENT_ALPHA );
+
Node* Node::New()
{
return new ( gNodeMemoryPool.AllocateRawThreadSafe() ) Node();
}
+void Node::Delete( Node* node )
+{
+ // check we have a node not a layer
+ if( !node->mIsLayer )
+ {
+ // Manually call the destructor
+ node->~Node();
+
+ // Mark the memory it used as free in the memory pool
+ gNodeMemoryPool.FreeThreadSafe( node );
+ }
+ else
+ {
+ // not in the pool, just delete it.
+ delete node;
+ }
+}
+
Node::Node()
: mTransformManager( NULL ),
mTransformId( INVALID_TRANSFORM_ID ),
mDrawMode( DrawMode::NORMAL ),
mColorMode( DEFAULT_COLOR_MODE ),
mClippingMode( ClippingMode::DISABLED ),
- mIsRoot( false )
+ mIsRoot( false ),
+ mIsLayer( false )
{
mUniformMapChanged[0] = 0u;
mUniformMapChanged[1] = 0u;
}
}
-void Node::operator delete( void* ptr )
-{
- gNodeMemoryPool.FreeThreadSafe( static_cast<Node*>( ptr ) );
-}
-
void Node::OnDestroy()
{
// Animators, Constraints etc. should be disconnected from the child's properties.
} // namespace SceneGraph
+template <>
+void OwnerPointer<Dali::Internal::SceneGraph::Node>::Reset()
+{
+ if( mObject != NULL )
+ {
+ Dali::Internal::SceneGraph::Node::Delete( mObject );
+ mObject = NULL;
+ }
+}
+
} // namespace Internal
+template <>
+void OwnerContainer<Dali::Internal::SceneGraph::Node*>::Delete(Dali::Internal::SceneGraph::Node* pointer)
+{
+ Dali::Internal::SceneGraph::Node::Delete( pointer );
+}
+
} // namespace Dali
static Node* New();
/**
- * Virtual destructor
+ * Deletes a Node.
*/
- virtual ~Node();
-
- /**
- * Overriden delete operator
- * Deletes the node from its global memory pool
- */
- void operator delete( void* ptr );
+ static void Delete( Node* node );
/**
* Called during UpdateManager::DestroyNode shortly before Node is destroyed.
*/
bool IsLayer()
{
- return (GetLayer() != NULL);
+ return mIsLayer;
}
/**
int GetDirtyFlags() const;
/**
- * Query whether a node is clean.
- * @return True if the node is clean.
- */
- bool IsClean() const
- {
- return ( NothingFlag == GetDirtyFlags() );
- }
-
- /**
* Retrieve the parent-origin of the node.
* @return The parent-origin.
*/
*/
Node();
+ /**
+ * Protected virtual destructor; See also Node::Delete( Node* )
+ * Kept protected to allow destructor chaining from layer
+ */
+ virtual ~Node();
+
private: // from NodeDataProvider
/**
ColorMode mColorMode:2; ///< Determines whether mWorldColor is inherited, 2 bits is enough
ClippingMode::Type mClippingMode:2; ///< The clipping mode of this node
bool mIsRoot:1; ///< True if the node cannot have a parent
-
+ bool mIsLayer:1; ///< True if the node is a layer
// Changes scope, should be at end of class
DALI_LOG_OBJECT_STRING_DECLARATION;
};
} // namespace SceneGraph
+// Template specialisation for OwnerPointer<Node>, because delete is protected
+template <>
+void OwnerPointer<Dali::Internal::SceneGraph::Node>::Reset();
+
} // namespace Internal
+// Template specialisations for OwnerContainer<Node*>, because delete is protected
+template <>
+void OwnerContainer<Dali::Internal::SceneGraph::Node*>::Delete( Dali::Internal::SceneGraph::Node* pointer );
+
} // namespace Dali
#endif // DALI_INTERNAL_SCENE_GRAPH_NODE_H
SceneGraph::Layer* Layer::New()
{
+ // Layers are currently heap allocated, unlike Nodes which are in a memory pool
+ // However Node::Delete( layer ) will correctly delete a layer / node depending on type
return new Layer();
}
mDepthTestDisabled( true ),
mIsDefaultSortFunction( true )
{
+ // set a flag the node to say this is a layer
+ mIsLayer = true;
+
// layer starts off dirty
mAllChildTransformsClean[ 0 ] = false;
mAllChildTransformsClean[ 1 ] = false;
static SceneGraph::Layer* New();
/**
- * Virtual destructor
- */
- virtual ~Layer();
-
- /**
* From Node, to convert a node to a layer.
* @return The layer.
*/
// Undefined
Layer(const Layer&);
+ /**
+ * Virtual destructor
+ */
+ virtual ~Layer();
+
// Undefined
Layer& operator=(const Layer& rhs);