#improve node sort performance by std::sort + long long (_localZOrder) (#16126)

* #improve node sort performance by std::sort + unsigned long long (_localZOrder)

* Use bit field for make _localZOrder storage more clearly.

* #Comment _localZOrder members for meaningful.

* fix issues

* #use explicit bits integer of localZOrder storage

* #Fix compile error, add include <cstdint> to CCNode.h

* use the optimization for 64bit and no optimization solution for 32bit
This commit is contained in:
halx99 2016-07-27 16:58:51 +08:00 committed by minggo
parent 30118aff6b
commit 3a14388087
4 changed files with 57 additions and 15 deletions

View File

@ -57,9 +57,17 @@ NS_CC_BEGIN
bool nodeComparisonLess(Node* n1, Node* n2)
{
return( n1->getLocalZOrder() < n2->getLocalZOrder() );
#if defined(_M_X64) || defined(_LP64) || defined(__x86_64) || defined(_WIN64)
return (n1->_localZOrder.value < n2->_localZOrder.value);
#else
return n1->_localZOrder.detail.z < n2->_localZOrder.detail.z ||
(n1->_localZOrder.detail.z == n2->_localZOrder.detail.z && n1->_localZOrder.detail.a < n2->_localZOrder.detail.a);
#endif
}
// FIXME:: Yes, nodes might have a sort problem once every 30 days if the game runs at 60 FPS and each frame sprites are reordered.
unsigned int Node::s_globalOrderOfArrival = 0;
// MARK: Constructor, Destructor, Init
Node::Node()
@ -84,7 +92,6 @@ Node::Node()
, _transformUpdated(true)
// children (lazy allocs)
// lazy alloc
, _localZOrder(0)
, _globalZOrder(0)
, _parent(nullptr)
// "whole screen" objects. like Scenes and Layers, should set _ignoreAnchorPointForPosition to true
@ -115,6 +122,8 @@ Node::Node()
, _physicsBody(nullptr)
#endif
{
_localZOrder.value = 0;
// set default scheduler and actionManager
_director = Director::getInstance();
_actionManager = _director->getActionManager();
@ -254,10 +263,10 @@ void Node::setSkewY(float skewY)
void Node::setLocalZOrder(int z)
{
if (_localZOrder == z)
if (getLocalZOrder() == z)
return;
_localZOrder = z;
_setLocalZOrder(z);
if (_parent)
{
_parent->reorderChild(this, z);
@ -270,7 +279,12 @@ void Node::setLocalZOrder(int z)
/// used internally to alter the zOrder variable. DON'T call this method manually
void Node::_setLocalZOrder(int z)
{
_localZOrder = z;
_localZOrder.detail.z = z;
}
void Node::updateOrderOfArrival()
{
_localZOrder.detail.a = s_globalOrderOfArrival++;
}
void Node::setGlobalZOrder(float globalZOrder)
@ -950,6 +964,8 @@ void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::stri
child->setParent(this);
child->setCameraMask(getCameraMask());
child->updateOrderOfArrival();
if( _running )
{
child->onEnter();
@ -980,7 +996,7 @@ void Node::addChild(Node *child, int zOrder)
void Node::addChild(Node *child)
{
CCASSERT( child != nullptr, "Argument must be non-nil");
this->addChild(child, child->_localZOrder, child->_name);
this->addChild(child, child->_localZOrder.detail.z, child->_name);
}
void Node::removeFromParent()
@ -1127,21 +1143,22 @@ void Node::insertChild(Node* child, int z)
_transformUpdated = true;
_reorderChildDirty = true;
_children.pushBack(child);
child->_localZOrder = z;
child->_setLocalZOrder(z);
}
void Node::reorderChild(Node *child, int zOrder)
{
CCASSERT( child != nullptr, "Child must be non-nil");
_reorderChildDirty = true;
child->_localZOrder = zOrder;
child->updateOrderOfArrival();
child->_setLocalZOrder(zOrder);
}
void Node::sortAllChildren()
{
if (_reorderChildDirty)
{
std::stable_sort(std::begin(_children), std::end(_children), nodeComparisonLess);
std::sort(std::begin(_children), std::end(_children), nodeComparisonLess);
_reorderChildDirty = false;
}
}
@ -1234,7 +1251,7 @@ void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t paren
{
auto node = _children.at(i);
if (node && node->_localZOrder < 0)
if (node && node->_localZOrder.detail.z < 0)
node->visit(renderer, _modelViewTransform, flags);
else
break;

View File

@ -29,6 +29,7 @@
#ifndef __CCNODE_H__
#define __CCNODE_H__
#include <cstdint>
#include "base/ccMacros.h"
#include "base/CCVector.h"
#include "base/CCProtocols.h"
@ -108,6 +109,7 @@ class EventListener;
class CC_DLL Node : public Ref
{
friend bool nodeComparisonLess(Node* n1, Node* n2);
public:
/** Default tag used for all the nodes */
static const int INVALID_TAG = -1;
@ -168,6 +170,18 @@ public:
*/
CC_DEPRECATED_ATTRIBUTE virtual void _setLocalZOrder(int z);
/** !!! ONLY FOR INTERNAL USE
* Sets the arrival order when this node has a same ZOrder with other children.
*
* A node which called addChild subsequently will take a larger arrival order,
* If two children have the same Z order, the child with larger arrival order will be drawn later.
*
* @warning This method is used internally for localZOrder sorting, don't change this manually
*
* @param orderOfArrival The arrival order.
*/
void updateOrderOfArrival();
/**
* Gets the local Z order of this node.
*
@ -175,7 +189,7 @@ public:
*
* @return The local (relative to its siblings) Z order.
*/
virtual int getLocalZOrder() const { return _localZOrder; }
virtual int getLocalZOrder() const { return _localZOrder.detail.z; }
CC_DEPRECATED_ATTRIBUTE virtual int getZOrder() const { return getLocalZOrder(); }
/**
@ -1881,9 +1895,17 @@ protected:
mutable bool _additionalTransformDirty; ///< transform dirty ?
bool _transformUpdated; ///< Whether or not the Transform object was updated since the last frame
int _localZOrder; ///< Local order (relative to its siblings) used to sort the node
union {
struct {
std::int32_t z; // The original localZOrder
std::uint32_t a; // Order Of Arrival, for avoid sort problem with unstable_sort algorithm.
} detail;
std::int64_t value; // The value to be used in sort
} _localZOrder; ///< Local order (relative to its siblings) used to sort the node
float _globalZOrder; ///< Global order used to sort the node
static unsigned int s_globalOrderOfArrival;
Vector<Node*> _children; ///< array of children nodes
Node *_parent; ///< weak reference to parent node
Director* _director; //cached director pointer to improve rendering performance

View File

@ -103,6 +103,8 @@ void ProtectedNode::addProtectedChild(Node *child, int zOrder, int tag)
child->setParent(this);
child->updateOrderOfArrival();
if( _running )
{
child->onEnter();
@ -252,7 +254,7 @@ void ProtectedNode::insertProtectedChild(cocos2d::Node *child, int z)
void ProtectedNode::sortAllProtectedChildren()
{
if( _reorderProtectedChildDirty ) {
std::stable_sort( std::begin(_protectedChildren), std::end(_protectedChildren), nodeComparisonLess );
std::sort( std::begin(_protectedChildren), std::end(_protectedChildren), nodeComparisonLess );
_reorderProtectedChildDirty = false;
}
}
@ -261,6 +263,7 @@ void ProtectedNode::reorderProtectedChild(cocos2d::Node *child, int localZOrder)
{
CCASSERT( child != nullptr, "Child must be non-nil");
_reorderProtectedChildDirty = true;
child->updateOrderOfArrival();
child->setLocalZOrder(localZOrder);
}

View File

@ -143,7 +143,7 @@ void Bone::setBoneData(BoneData *boneData)
}
_name = _boneData->name;
_localZOrder = _boneData->zOrder;
_setLocalZOrder(_boneData->zOrder);
_displayManager->initDisplayList(boneData);
}
@ -377,7 +377,7 @@ Tween *Bone::getTween()
void Bone::setLocalZOrder(int zOrder)
{
if (_localZOrder != zOrder)
if (getLocalZOrder() != zOrder)
Node::setLocalZOrder(zOrder);
}