Ver código fonte

To restore lost performance, move less critical Node variables to an implementation struct to reduce Node instance memory size, and restore old unsafe PODVector operation that does not allow self-insertion.

Lasse Öörni 9 anos atrás
pai
commit
fee755e942
3 arquivos alterados com 142 adições e 121 exclusões
  1. 77 72
      Source/Urho3D/Container/Vector.h
  2. 30 27
      Source/Urho3D/Scene/Node.cpp
  3. 35 22
      Source/Urho3D/Scene/Node.h

+ 77 - 72
Source/Urho3D/Container/Vector.h

@@ -571,7 +571,7 @@ private:
     }
 };
 
-/// %Vector template class for POD types. Does not call constructors or destructors and uses block move.
+/// %Vector template class for POD types. Does not call constructors or destructors and uses block move. Is intentionally (for performance reasons) unsafe for self-insertion.
 template <class T> class PODVector : public VectorBase
 {
 public:
@@ -601,7 +601,8 @@ public:
     /// Construct with initial data.
     PODVector(const T* data, unsigned size)
     {
-        InsertElements(0, data, data + size);
+        Resize(size);
+        CopyElements(Buffer(), data, size);
     }
 
     /// Construct from another vector.
@@ -631,8 +632,8 @@ public:
         // In case of self-assignment do nothing
         if (&rhs != this)
         {
-            Clear();
-            InsertElements(0, rhs.Begin(), rhs.End());
+            Resize(rhs.size_);
+            CopyElements(Buffer(), rhs.Buffer(), rhs.size_);
         }
         return *this;
     }
@@ -732,13 +733,19 @@ public:
     /// Add an element at the end.
     void Push(const T& value)
     {
-        InsertElements(size_, &value, &value + 1);
+        if (size_ < capacity_)
+            ++size_;
+        else
+            Resize(size_ + 1);
+        Back() = value;
     }
 
     /// Add another vector at the end.
     void Push(const PODVector<T>& vector)
     {
-        InsertElements(size_, vector.Begin(), vector.End());
+        unsigned oldSize = size_;
+        Resize(size_ + vector.size_);
+        CopyElements(Buffer() + oldSize, vector.Buffer(), vector.size_);
     }
 
     /// Remove the last element.
@@ -751,41 +758,78 @@ public:
     /// Insert an element at position.
     void Insert(unsigned pos, const T& value)
     {
-        InsertElements(pos, &value, &value + 1);
+        if (pos > size_)
+            pos = size_;
+
+        unsigned oldSize = size_;
+        Resize(size_ + 1);
+        MoveRange(pos + 1, pos, oldSize - pos);
+        Buffer()[pos] = value;
     }
 
     /// Insert another vector at position.
     void Insert(unsigned pos, const PODVector<T>& vector)
     {
-        InsertElements(pos, vector.Begin(), vector.End());
+        if (pos > size_)
+            pos = size_;
+
+        unsigned oldSize = size_;
+        Resize(size_ + vector.size_);
+        MoveRange(pos + vector.size_, pos, oldSize - pos);
+        CopyElements(Buffer() + pos, vector.Buffer(), vector.size_);
     }
 
     /// Insert an element by iterator.
     Iterator Insert(const Iterator& dest, const T& value)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        return InsertElements(pos, &value, &value + 1);
+        if (pos > size_)
+            pos = size_;
+        Insert(pos, value);
+
+        return Begin() + pos;
     }
 
     /// Insert a vector by iterator.
     Iterator Insert(const Iterator& dest, const PODVector<T>& vector)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        return InsertElements(pos, vector.Begin(), vector.End());
+        if (pos > size_)
+            pos = size_;
+        Insert(pos, vector);
+
+        return Begin() + pos;
     }
 
     /// Insert a vector partially by iterators.
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        return InsertElements(pos, start, end);
+        if (pos > size_)
+            pos = size_;
+        unsigned length = (unsigned)(end - start);
+        Resize(size_ + length);
+        MoveRange(pos + length, pos, size_ - pos - length);
+        CopyElements(Buffer() + pos, &(*start), length);
+
+        return Begin() + pos;
     }
 
     /// Insert elements.
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        return InsertElements(pos, start, end);
+        if (pos > size_)
+            pos = size_;
+        unsigned length = (unsigned)(end - start);
+        Resize(size_ + length);
+        MoveRange(pos + length, pos, size_ - pos - length);
+
+        T* destPtr = Buffer() + pos;
+        for (const T* i = start; i != end; ++i)
+            *destPtr++ = *i;
+
+        return Begin() + pos;
     }
 
     /// Erase a range of elements.
@@ -829,7 +873,7 @@ public:
         // Return if the range is illegal
         if (shiftStartIndex > size_ || !length)
             return;
-      
+
         unsigned newSize = size_ - length;
         unsigned trailingCount = size_ - shiftStartIndex;
         if (trailingCount <= length)
@@ -877,18 +921,27 @@ public:
     /// Resize the vector.
     void Resize(unsigned newSize)
     {
-        PODVector<T> tempBuffer;
-        Resize(newSize, tempBuffer);
-    }
+        if (newSize > capacity_)
+        {
+            if (!capacity_)
+                capacity_ = newSize;
+            else
+            {
+                while (capacity_ < newSize)
+                    capacity_ += (capacity_ + 1) >> 1;
+            }
 
-    /// Resize the vector and fill new elements with default value.
-    void Resize(unsigned newSize, const T& value)
-    {
-        unsigned oldSize = Size();
-        PODVector<T> tempBuffer;
-        Resize(newSize, tempBuffer);
-        for (unsigned i = oldSize; i < newSize; ++i)
-            At(i) = value;
+            unsigned char* newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
+            // Move the data into the new buffer and delete the old
+            if (buffer_)
+            {
+                CopyElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
+                delete[] buffer_;
+            }
+            buffer_ = newBuffer;
+        }
+
+        size_ = newSize;
     }
 
     /// Set new capacity.
@@ -984,54 +1037,6 @@ public:
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
 
 private:
-    /// Resize the vector. Current buffer will be stored in tempBuffer in case of reallocation.
-    void Resize(unsigned newSize, PODVector<T>& tempBuffer)
-    {
-        if (newSize > capacity_)
-        {
-            Swap(tempBuffer);
-            size_ = tempBuffer.size_;
-            capacity_ = tempBuffer.capacity_;
-
-            if (!capacity_)
-                capacity_ = newSize;
-            else
-            {
-                while (capacity_ < newSize)
-                    capacity_ += (capacity_ + 1) >> 1;
-            }
-
-            buffer_ = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
-            // Move the data into the new buffer
-            if (tempBuffer.Buffer())
-            {
-                CopyElements(Buffer(), tempBuffer.Buffer(), size_);
-            }
-        }
-
-        size_ = newSize;
-    }
-
-    /// Insert elements.
-    template <typename RandomIteratorT>
-    Iterator InsertElements(unsigned pos, RandomIteratorT start, RandomIteratorT end)
-    {
-        assert(start <= end);
-
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        PODVector<T> tempBuffer;
-        Resize(size_ + length, tempBuffer);
-        MoveRange(pos + length, pos, size_ - pos - length);
-
-        T* destPtr = Buffer() + pos;
-        for (RandomIteratorT i = start; i != end; ++i)
-            *destPtr++ = *i;
-
-        return Begin() + pos;
-    }
-
     /// Move a range of elements within the vector.
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {

+ 30 - 27
Source/Urho3D/Scene/Node.cpp

@@ -47,20 +47,21 @@ namespace Urho3D
 
 Node::Node(Context* context) :
     Animatable(context),
-    networkUpdate_(false),
     worldTransform_(Matrix3x4::IDENTITY),
     dirty_(false),
     enabled_(true),
     enabledPrev_(true),
+    networkUpdate_(false),
     parent_(0),
     scene_(0),
     id_(0),
     position_(Vector3::ZERO),
     rotation_(Quaternion::IDENTITY),
     scale_(Vector3::ONE),
-    worldRotation_(Quaternion::IDENTITY),
-    owner_(0)
+    worldRotation_(Quaternion::IDENTITY)
 {
+    impl_ = new NodeImpl();
+    impl_->owner_ = 0;
 }
 
 Node::~Node()
@@ -71,6 +72,8 @@ Node::~Node()
     // Remove from the scene
     if (scene_)
         scene_->NodeRemoved(this);
+
+    delete impl_;
 }
 
 void Node::RegisterObject(Context* context)
@@ -320,10 +323,10 @@ bool Node::SaveJSON(Serializer& dest, const String& indentation) const
 
 void Node::SetName(const String& name)
 {
-    if (name != name_)
+    if (name != impl_->name_)
     {
-        name_ = name;
-        nameHash_ = name_;
+        impl_->name_ = name;
+        impl_->nameHash_ = name;
 
         MarkNetworkUpdate();
 
@@ -355,7 +358,7 @@ void Node::AddTag(const String& tag)
         return;
     
     // Add tag
-    tags_.Push(tag);
+    impl_->tags_.Push(tag);
 
     // Cache
     scene_->NodeTagAdded(this, tag);
@@ -387,7 +390,7 @@ void Node::AddTags(const StringVector& tags)
 
 bool Node::RemoveTag(const String& tag)
 {
-    bool removed = tags_.Remove(tag);
+    bool removed = impl_->tags_.Remove(tag);
 
     // Nothing to do
     if (!removed)
@@ -416,21 +419,21 @@ void Node::RemoveAllTags()
     // Clear old scene cache
     if (scene_)
     {
-        for (unsigned i = 0; i < tags_.Size(); ++i)
+        for (unsigned i = 0; i < impl_->tags_.Size(); ++i)
         {
-            scene_->NodeTagRemoved(this, tags_[i]);
+            scene_->NodeTagRemoved(this, impl_->tags_[i]);
 
             // Send event
             using namespace NodeTagRemoved;
             VariantMap& eventData = GetEventDataMap();
             eventData[P_SCENE] = scene_;
             eventData[P_NODE] = this;
-            eventData[P_TAG] = tags_[i];
+            eventData[P_TAG] = impl_->tags_[i];
             scene_->SendEvent(E_NODETAGREMOVED, eventData);
         }
     }
 
-    tags_.Clear();
+    impl_->tags_.Clear();
 
     // Sync
     MarkNetworkUpdate();
@@ -724,7 +727,7 @@ void Node::SetEnabledRecursive(bool enable)
 
 void Node::SetOwner(Connection* owner)
 {
-    owner_ = owner;
+    impl_->owner_ = owner;
 }
 
 void Node::MarkDirty()
@@ -1329,7 +1332,7 @@ bool Node::HasComponent(StringHash type) const
 
 bool Node::HasTag(const String& tag) const
 {
-    return tags_.Contains(tag);
+    return impl_->tags_.Contains(tag);
 }
 
 const Variant& Node::GetVar(StringHash key) const
@@ -1456,21 +1459,21 @@ const Vector3& Node::GetNetPositionAttr() const
 
 const PODVector<unsigned char>& Node::GetNetRotationAttr() const
 {
-    attrBuffer_.Clear();
-    attrBuffer_.WritePackedQuaternion(rotation_);
-    return attrBuffer_.GetBuffer();
+    impl_->attrBuffer_.Clear();
+    impl_->attrBuffer_.WritePackedQuaternion(rotation_);
+    return impl_->attrBuffer_.GetBuffer();
 }
 
 const PODVector<unsigned char>& Node::GetNetParentAttr() const
 {
-    attrBuffer_.Clear();
+    impl_->attrBuffer_.Clear();
     Scene* scene = GetScene();
     if (scene && parent_ && parent_ != scene)
     {
         // If parent is replicated, can write the ID directly
         unsigned parentID = parent_->GetID();
         if (parentID < FIRST_LOCAL_ID)
-            attrBuffer_.WriteNetID(parentID);
+            impl_->attrBuffer_.WriteNetID(parentID);
         else
         {
             // Parent is local: traverse hierarchy to find a non-local base node
@@ -1480,12 +1483,12 @@ const PODVector<unsigned char>& Node::GetNetParentAttr() const
                 current = current->GetParent();
 
             // Then write the base node ID and the parent's name hash
-            attrBuffer_.WriteNetID(current->GetID());
-            attrBuffer_.WriteStringHash(parent_->GetNameHash());
+            impl_->attrBuffer_.WriteNetID(current->GetID());
+            impl_->attrBuffer_.WriteStringHash(parent_->GetNameHash());
         }
     }
 
-    return attrBuffer_.GetBuffer();
+    return impl_->attrBuffer_.GetBuffer();
 }
 
 bool Node::Load(Deserializer& source, SceneResolver& resolver, bool readChildren, bool rewriteIDs, CreateMode mode)
@@ -1625,7 +1628,7 @@ bool Node::LoadJSON(const JSONValue& source, SceneResolver& resolver, bool readC
 void Node::PrepareNetworkUpdate()
 {
     // Update dependency nodes list first
-    dependencyNodes_.Clear();
+    impl_->dependencyNodes_.Clear();
 
     // Add the parent node, but if it is local, traverse to the first non-local node
     if (parent_ && parent_ != scene_)
@@ -1634,7 +1637,7 @@ void Node::PrepareNetworkUpdate()
         while (current->id_ >= FIRST_LOCAL_ID)
             current = current->parent_;
         if (current && current != scene_)
-            dependencyNodes_.Push(current);
+            impl_->dependencyNodes_.Push(current);
     }
 
     // Let the components add their dependencies
@@ -1642,7 +1645,7 @@ void Node::PrepareNetworkUpdate()
     {
         Component* component = *i;
         if (component->GetID() < FIRST_LOCAL_ID)
-            component->GetDependencyNodes(dependencyNodes_);
+            component->GetDependencyNodes(impl_->dependencyNodes_);
     }
 
     // Then check for node attribute changes
@@ -1712,8 +1715,8 @@ void Node::PrepareNetworkUpdate()
 
 void Node::CleanupConnection(Connection* connection)
 {
-    if (owner_ == connection)
-        owner_ = 0;
+    if (impl_->owner_ == connection)
+        impl_->owner_ = 0;
 
     if (networkState_)
     {

+ 35 - 22
Source/Urho3D/Scene/Node.h

@@ -31,6 +31,7 @@ namespace Urho3D
 
 class Component;
 class Connection;
+class Node;
 class Scene;
 class SceneResolver;
 
@@ -51,6 +52,23 @@ enum TransformSpace
     TS_WORLD
 };
 
+/// Internal implementation structure for less performance-critical Node variables.
+struct URHO3D_API NodeImpl
+{
+    /// Nodes this node depends on for network updates.
+    PODVector<Node*> dependencyNodes_;
+    /// Network owner connection.
+    Connection* owner_;
+    /// Name.
+    String name_;
+    /// Tag strings.
+    StringVector tags_;
+    /// Name hash.
+    StringHash nameHash_;
+    /// Attribute buffer for network updates.
+    mutable VectorBuffer attrBuffer_;
+};
+
 /// %Scene node that may contain components and child nodes.
 class URHO3D_API Node : public Animatable
 {
@@ -316,13 +334,13 @@ public:
     unsigned GetID() const { return id_; }
 
     /// Return name.
-    const String& GetName() const { return name_; }
+    const String& GetName() const { return impl_->name_; }
 
     /// Return name hash.
-    StringHash GetNameHash() const { return nameHash_; }
+    StringHash GetNameHash() const { return impl_->nameHash_; }
 
     /// Return all tags.
-    const StringVector& GetTags() const { return tags_; }
+    const StringVector& GetTags() const { return impl_->tags_; }
 
     /// Return whether has a specific tag.
     bool HasTag(const String& tag) const;
@@ -340,7 +358,7 @@ public:
     bool IsEnabledSelf() const { return enabledPrev_; }
 
     /// Return owner connection in networking.
-    Connection* GetOwner() const { return owner_; }
+    Connection* GetOwner() const { return impl_->owner_; }
 
     /// Return position in parent space.
     const Vector3& GetPosition() const { return position_; }
@@ -564,7 +582,7 @@ public:
     bool LoadJSON(const JSONValue& source, SceneResolver& resolver, bool loadChildren = true, bool rewriteIDs = false,
         CreateMode mode = REPLICATED);
     /// Return the depended on nodes to order network updates.
-    const PODVector<Node*>& GetDependencyNodes() const { return dependencyNodes_; }
+    const PODVector<Node*>& GetDependencyNodes() const { return impl_->dependencyNodes_; }
 
     /// Prepare network update by comparing attributes and marking replication states dirty as necessary.
     void PrepareNetworkUpdate();
@@ -601,11 +619,6 @@ protected:
     /// Find target of an attribute animation from object hierarchy by name.
     virtual Animatable* FindAttributeAnimationTarget(const String& name, String& outName);
 
-    /// Network update queued flag.
-    bool networkUpdate_;
-    /// User variables.
-    VariantMap vars_;
-
 private:
     /// Set enabled/disabled state with optional recursion. Optionally affect the remembered enable state.
     void SetEnabled(bool enable, bool recursive, bool storeSelf);
@@ -638,6 +651,12 @@ private:
     bool enabled_;
     /// Last SetEnabled flag before any SetDeepEnabled.
     bool enabledPrev_;
+
+protected:
+    /// Network update queued flag.
+    bool networkUpdate_;
+
+private:
     /// Parent scene node.
     Node* parent_;
     /// Scene (root node.)
@@ -658,18 +677,12 @@ private:
     Vector<SharedPtr<Node> > children_;
     /// Node listeners.
     Vector<WeakPtr<Component> > listeners_;
-    /// Nodes this node depends on for network updates.
-    PODVector<Node*> dependencyNodes_;
-    /// Network owner connection.
-    Connection* owner_;
-    /// Name.
-    String name_;
-    /// Tag strings.
-    StringVector tags_;
-    /// Name hash.
-    StringHash nameHash_;
-    /// Attribute buffer for network updates.
-    mutable VectorBuffer attrBuffer_;
+    /// Pointer to implementation.
+    NodeImpl* impl_;
+
+protected:
+    /// User variables.
+    VariantMap vars_;
 };
 
 template <class T> T* Node::CreateComponent(CreateMode mode, unsigned id)