Skip to content

Commit baa6381

Browse files
PatriceJiangminggo
authored andcommitted
[v3] add renderer performance test (#20010)
1 parent 67fde78 commit baa6381

File tree

2 files changed

+366
-0
lines changed

2 files changed

+366
-0
lines changed

tests/cpp-tests/Classes/NewRendererTest/NewRendererTest.cpp

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,39 @@
2727

2828
USING_NS_CC;
2929

30+
31+
class DurationRecorder {
32+
public:
33+
void startTick(const std::string &key) {
34+
_durations[key] = - now();
35+
}
36+
37+
int endTick(const std::string &key) {
38+
auto n = now();
39+
auto itr = _durations.find(key);
40+
if(_durations.find(key) == _durations.end())
41+
{
42+
return -1;
43+
}
44+
else if(itr->second < 0) {
45+
itr->second = n + itr->second;
46+
}
47+
return itr->second;
48+
}
49+
50+
inline int64_t now() const{
51+
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
52+
}
53+
54+
void reset() {
55+
_durations.clear();
56+
}
57+
58+
private:
59+
std::map<std::string, int64_t > _durations;
60+
};
61+
62+
3063
NewRendererTests::NewRendererTests()
3164
{
3265
ADD_TEST_CASE(NewSpriteTest);
@@ -41,6 +74,8 @@ NewRendererTests::NewRendererTests()
4174
ADD_TEST_CASE(RendererBatchQuadTri);
4275
ADD_TEST_CASE(RendererUniformBatch);
4376
ADD_TEST_CASE(RendererUniformBatch2);
77+
ADD_TEST_CASE(SpriteCreation);
78+
ADD_TEST_CASE(NonBatchSprites);
4479
}
4580

4681
std::string MultiSceneTest::title() const
@@ -779,3 +814,275 @@ std::string RendererUniformBatch2::subtitle() const
779814
{
780815
return "Mixing different shader states should work ok";
781816
}
817+
818+
819+
NonBatchSprites::NonBatchSprites()
820+
{
821+
Size s = Director::getInstance()->getWinSize();
822+
_spritesAnchor = Node::create();
823+
_spritesAnchor->setPosition(0, 0);
824+
addChild(_spritesAnchor);
825+
826+
827+
_totalSprites = Label::createWithTTF(TTFConfig("fonts/arial.ttf"), "sprites");
828+
_totalSprites->setColor(Color3B::YELLOW);
829+
_totalSprites->enableOutline(Color4B::RED, 2);
830+
_totalSprites->setPosition(s.width/2, s.height/2);
831+
832+
addChild(_totalSprites);
833+
834+
scheduleUpdate();
835+
}
836+
837+
void NonBatchSprites::createSprite()
838+
{
839+
840+
Size s = Director::getInstance()->getWinSize();
841+
Sprite* sprite = nullptr;
842+
if (_spriteIndex % 2 == 0)
843+
{
844+
sprite = Sprite::create("Images/grossini_dance_05.png");
845+
}
846+
else
847+
{
848+
sprite = Sprite::create("Images/grossini_dance_01.png");
849+
}
850+
851+
if (!sprite) return;
852+
auto r = rand_0_1() * 0.6 + 0.2;
853+
sprite->setScale(r, r);
854+
float x = ((float)std::rand()) / RAND_MAX;
855+
float y = ((float)std::rand()) / RAND_MAX;
856+
sprite->runAction(RepeatForever::create(RotateBy::create(1, 45)));
857+
858+
sprite->setPosition(Vec2(x * s.width, y * s.height));
859+
_spritesAnchor->addChild(sprite);
860+
861+
_spriteIndex++;
862+
std::stringstream ss;
863+
ss << _spriteIndex << " sprites";
864+
_totalSprites->setString(ss.str());
865+
}
866+
867+
void NonBatchSprites::update(float dt)
868+
{
869+
870+
if( dt <= 1.0f / 28.0f && dt >= 1.0f/ 31.0f)
871+
{
872+
_around30fps.hit();
873+
}
874+
else
875+
{
876+
_around30fps.cancel();
877+
}
878+
879+
_maDt = 0.7f * _maDt + 0.3f * dt;
880+
_rmaDt = 0.5f * _rmaDt + 0.5f * dt;
881+
if(_maDt <= DEST_DT_30FPS) {
882+
_contSlow.cancel();
883+
_contFast.hit();
884+
if(_contFast.ok()){
885+
auto t2 = DEST_DT_30FPS - _rmaDt;
886+
auto delta = (int)(t2 / _rmaDt * _spriteIndex * 0.1);
887+
delta =std::min(20, std::max(1, delta));
888+
for(int i =0 ;i< delta; i++) {
889+
createSprite();
890+
}
891+
}
892+
}else{
893+
_contSlow.hit();
894+
_contFast.cancel();
895+
}
896+
897+
if(_contSlow.ok() || _around30fps.ok())
898+
{
899+
unscheduleUpdate();
900+
std::stringstream ss;
901+
ss << _spriteIndex << " sprites, DONE!";
902+
_totalSprites->setString(ss.str());
903+
_totalSprites->setScale(1.2);
904+
}
905+
}
906+
907+
NonBatchSprites::~NonBatchSprites()
908+
{
909+
910+
}
911+
912+
std::string NonBatchSprites::title() const
913+
{
914+
return "Non Batched Sprites";
915+
}
916+
917+
std::string NonBatchSprites::subtitle() const
918+
{
919+
#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG == 1
920+
return "DEBUG: simulate lots of sprites, drop to 30 fps";
921+
#else
922+
return "RELEASE: simulate lots of sprites, drop to 30 fps";
923+
#endif
924+
}
925+
926+
927+
928+
SpriteCreation::SpriteCreation()
929+
{
930+
931+
Size s = Director::getInstance()->getWinSize();
932+
Node* parent = Node::create();
933+
parent->setPosition(s.width / 2,s.height / 2);
934+
addChild(parent);
935+
936+
937+
#define KEY_CREATION "11"
938+
#define KEY_DESTROYATION "22"
939+
940+
labelCreate = Label::createWithTTF(TTFConfig("fonts/arial.ttf"), "Sprite Creation: ..");
941+
labelDestory= Label::createWithTTF(TTFConfig("fonts/arial.ttf"), "Destroy Sprites: ..");
942+
943+
MenuItemFont::setFontName("fonts/arial.ttf");
944+
MenuItemFont::setFontSize(65);
945+
auto decrease = MenuItemFont::create(" - ", CC_CALLBACK_1(SpriteCreation::delSpritesCallback, this));
946+
decrease->setColor(Color3B(0, 200, 20));
947+
auto increase = MenuItemFont::create(" + ", CC_CALLBACK_1(SpriteCreation::addSpritesCallback, this));
948+
increase->setColor(Color3B(0, 200, 20));
949+
950+
auto menu = Menu::create(decrease, increase, nullptr);
951+
menu->alignItemsHorizontally();
952+
menu->setPosition(Vec2(s.width / 2, s.height - 105));
953+
addChild(menu, 1);
954+
955+
TTFConfig ttfCount("fonts/Marker Felt.ttf", 30);
956+
_labelSpriteNum = Label::createWithTTF(ttfCount, "Label");
957+
_labelSpriteNum->setColor(Color3B(0, 200, 20));
958+
_labelSpriteNum->setPosition(Vec2(s.width / 2, s.height - 130));
959+
addChild(_labelSpriteNum);
960+
961+
updateSpriteCountLabel(totalSprites);
962+
963+
labelCreate->setPosition(0, -20);
964+
labelDestory->setPosition(0, -50);
965+
966+
parent->addChild(labelCreate);
967+
parent->addChild(labelDestory);
968+
969+
doTest();
970+
}
971+
972+
void SpriteCreation::updateSpriteCountLabel(int x)
973+
{
974+
totalSprites = std::max(1, x);
975+
std::stringstream ss;
976+
ss << totalSprites << " sprites";
977+
_labelSpriteNum->setString(ss.str());
978+
}
979+
980+
void SpriteCreation::doTest()
981+
{
982+
983+
DurationRecorder perf;
984+
std::vector<std::string> predefineTextures = {
985+
"Images/concave.png",
986+
"Images/atlastest.png",
987+
"Images/grossini_dance_atlas-mono.png",
988+
"Images/HelloWorld.png",
989+
"Images/background1.png",
990+
"Images/background2.png",
991+
"Images/stone.png",
992+
"Images/issue_17116.png",
993+
"Images/sprite_polygon_crash.png",
994+
"Images/bitmapFontTest3.png",
995+
"Images/cocos-html5.png",
996+
"Images/Fog.png",
997+
"Images/poly_test_textures.png",
998+
"Images/powered.png",
999+
"Images/bug14017.png",
1000+
"Images/test-rgba1.png",
1001+
"Images/grossinis_heads.png",
1002+
"Images/cocos2dbanner.png"
1003+
};
1004+
1005+
1006+
std::vector<Sprite*> spriteCache;
1007+
spriteCache.reserve(totalSprites);
1008+
1009+
perf.startTick(KEY_CREATION);
1010+
1011+
for (int i=0; i< totalSprites; ++i)
1012+
{
1013+
auto* sprite = new Sprite();
1014+
if(sprite == nullptr )
1015+
{
1016+
break;
1017+
}
1018+
if(!sprite->initWithFile(predefineTextures[i % predefineTextures.size()]))
1019+
{
1020+
delete sprite;
1021+
break;
1022+
}
1023+
spriteCache.push_back(sprite);
1024+
}
1025+
1026+
auto creationDuration = perf.endTick(KEY_CREATION);
1027+
perf.startTick(KEY_DESTROYATION);
1028+
1029+
for (int i=0; i< totalSprites; ++i)
1030+
{
1031+
spriteCache[i]->release();
1032+
}
1033+
auto destroyDuration = perf.endTick(KEY_DESTROYATION);
1034+
std::stringstream ss;
1035+
auto t1_ms = creationDuration * 1.0 / 1000000;
1036+
ss << "Create "<< spriteCache.size() << " sprites takes " << t1_ms<< " ms, " << (int64_t)(spriteCache.size() * 1000 / t1_ms) << " sprites per second!";
1037+
labelCreate->setString(ss.str());
1038+
1039+
if(t1_ms < 100) {
1040+
suggestDelta =(int) (0.5 * totalSprites);
1041+
} else if (t1_ms < 1000) {
1042+
suggestDelta =(int) (0.2 * totalSprites);
1043+
} else if(t1_ms) {
1044+
suggestDelta =(int) (0.1 * totalSprites);
1045+
}
1046+
1047+
suggestDelta = suggestDelta < 1000 ? 1000 : suggestDelta - suggestDelta % 1000;
1048+
1049+
ss.str("");
1050+
auto t2_ms = destroyDuration * 1.0 / 1000000;
1051+
ss << "Destroy "<< spriteCache.size() << " sprites takes " << t2_ms<< " ms, " << (int64_t)(spriteCache.size() * 1000 / t2_ms) << " sprites per second!" ;
1052+
labelDestory->setString(ss.str());
1053+
1054+
spriteCache.clear();
1055+
}
1056+
1057+
void SpriteCreation::addSpritesCallback(cocos2d::Ref *)
1058+
{
1059+
updateSpriteCountLabel(totalSprites + suggestDelta);
1060+
doTest();
1061+
}
1062+
1063+
void SpriteCreation::delSpritesCallback(cocos2d::Ref *)
1064+
{
1065+
updateSpriteCountLabel(totalSprites - suggestDelta);
1066+
doTest();
1067+
}
1068+
1069+
SpriteCreation::~SpriteCreation()
1070+
{
1071+
1072+
}
1073+
1074+
std::string SpriteCreation::title() const
1075+
{
1076+
return "Sprite Creation";
1077+
}
1078+
1079+
std::string SpriteCreation::subtitle() const
1080+
{
1081+
#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG == 1
1082+
return "In debug mode";
1083+
#else
1084+
return "In release mode";
1085+
#endif
1086+
}
1087+
1088+

tests/cpp-tests/Classes/NewRendererTest/NewRendererTest.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,63 @@ class RendererUniformBatch2 : public MultiSceneTest
216216
cocos2d::GLProgramState* createSepiaGLProgramState();
217217
};
218218

219+
class SpriteCreation : public MultiSceneTest
220+
{
221+
public:
222+
CREATE_FUNC(SpriteCreation);
223+
virtual std::string title() const override;
224+
virtual std::string subtitle() const override;
225+
226+
void addSpritesCallback(Ref *);
227+
void delSpritesCallback(Ref *);
228+
229+
void updateSpriteCountLabel(int x);
230+
231+
void doTest();
232+
233+
protected:
234+
int totalSprites = 1000;
235+
int suggestDelta = 100;
236+
cocos2d::Label* _labelSpriteNum = nullptr;
237+
cocos2d::Label* labelCreate = nullptr;
238+
cocos2d::Label* labelDestory = nullptr;
239+
SpriteCreation();
240+
virtual ~SpriteCreation();
241+
};
242+
243+
class NonBatchSprites : public MultiSceneTest
244+
{
245+
public:
246+
CREATE_FUNC(NonBatchSprites);
247+
virtual std::string title() const override;
248+
virtual std::string subtitle() const override;
249+
250+
virtual void update(float dt) override;
251+
protected:
252+
NonBatchSprites();
253+
254+
void createSprite();
255+
256+
virtual ~NonBatchSprites();
257+
class Ticker {
258+
public:
259+
Ticker(int m):_max(m) {}
260+
void hit() {_cnt += 1;}
261+
void cancel() {_cnt = 0;}
262+
bool ok() {return _cnt >= _max;}
263+
private:
264+
int _cnt = 0;
265+
int _max = 0;
266+
};
267+
Node *_spritesAnchor = nullptr;
268+
int _spriteIndex = 0;
269+
float _maDt = 1.0f / 60.0f;
270+
float _rmaDt = 1.0f/ 60.0f;
271+
const float DEST_DT_30FPS = 1.0f / 30.0f;
272+
cocos2d::Label * _totalSprites = nullptr;
273+
Ticker _contSlow = Ticker(20);
274+
Ticker _contFast = Ticker(2);
275+
Ticker _around30fps = Ticker(60 * 3);
276+
};
277+
219278
#endif //__NewRendererTest_H_

0 commit comments

Comments
 (0)