27
27
28
28
USING_NS_CC;
29
29
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
+
30
63
NewRendererTests::NewRendererTests ()
31
64
{
32
65
ADD_TEST_CASE (NewSpriteTest);
@@ -41,6 +74,8 @@ NewRendererTests::NewRendererTests()
41
74
ADD_TEST_CASE (RendererBatchQuadTri);
42
75
ADD_TEST_CASE (RendererUniformBatch);
43
76
ADD_TEST_CASE (RendererUniformBatch2);
77
+ ADD_TEST_CASE (SpriteCreation);
78
+ ADD_TEST_CASE (NonBatchSprites);
44
79
}
45
80
46
81
std::string MultiSceneTest::title () const
@@ -779,3 +814,275 @@ std::string RendererUniformBatch2::subtitle() const
779
814
{
780
815
return " Mixing different shader states should work ok" ;
781
816
}
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
+
0 commit comments