[resolved] CCSpriteBatchNode performance degraded over time (android) cocos2dx 2.1.3 & cocos2dx 2.0.4

Hi,

I have a strange issue with CCSpriteBatchNode. On android, as soon as I add Sprites to a CCSpriteBatchNode the performances of the scene start decreasing increasingly until the scene reaches 1 to 2 frames per second.

If I add the sprites to the scene without using the CCSpriteBatchNode the performances only decrease when the sprites are added, then they remain the same.

Would there be any reasons for this behavior? It happens with cocos2dx 2.1.3 & cocos2dx 2.0.4.

After some tests I found that my frame-rate remains constant if I comment out arrayMakeObjectsPerformSelector(m_pChildren, updateTransform, CCSprite*); in void CCSpriteBatchNode::draw(void).

From there by commenting each line 1 by 1 and testing further I think I approached the source of the problem:
void CCSprite::updateTransform(void) calling m_pobTextureAtlas->updateQuad(&m_sQuad, m_uAtlasIndex);
void CCTextureAtlas::updateQuad(ccV3F_C4B_T2F_Quad *quad, unsigned int index) setting m_bDirty = true

results in:

void CCTextureAtlas::drawNumberOfQuads(unsigned int n, unsigned int start) being slow during this call: glBufferSubData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*start, sizeof(m_pQuads[0]) * n , &m_pQuads[start] );

When I use of CCSpriteBatchNode results in a slowdown. Here is an example after initializing all the CCSprite and adding them to the batch node I get this :

05-16 06:11:16.208: I/jni/…/…/Classes/scenes/AnimationsTestScene.cpp(1506): Hello from AnimationsTest creation.
05-16 06:11:26.968: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 360.904816 fps
05-16 06:11:28.018: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 365.178101 fps
05-16 06:11:29.038: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 357.679810 fps

05-16 06:11:41.238: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 265.662842 fps
05-16 06:11:42.248: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 252.180939 fps
05-16 06:11:43.318: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 176.691681 fps

05-16 06:12:29.568: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 42.295910 fps
05-16 06:12:31.232: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 40.993145 fps
05-16 06:12:32.961: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 39.228279 fps
05-16 06:12:34.739: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 37.949783 fps

05-16 06:12:53.342: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 28.706190 fps
05-16 06:12:55.723: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 27.829285 fps
05-16 06:12:58.158: I/jni/…/…/Classes/RSRFPSCounter.cpp(1506): - AnimationsTest:visit ran at 27.052465 fps


If I don’t use the CCSpriteBatchNode but I put all my nodes directly in the scene I get:

05-16 06:19:08.017: I/jni/…/…/Classes/scenes/AnimationsTestScene.cpp(1633): Hello from AnimationsTest creation.
05-16 06:19:11.618: I/jni/…/…/Classes/RSRFPSCounter.cpp(1633): - AnimationsTest:visit ran at 154.923141 fps
05-16 06:19:12.637: I/jni/…/…/Classes/RSRFPSCounter.cpp(1633): - AnimationsTest:visit ran at 156.416519 fps
05-16 06:19:13.657: I/jni/…/…/Classes/RSRFPSCounter.cpp(1633): - AnimationsTest:visit ran at 154.756943 fps

05-16 06:20:32.267: I/jni/…/…/Classes/RSRFPSCounter.cpp(1633): - AnimationsTest:visit ran at 154.101318 fps
05-16 06:20:33.287: I/jni/…/…/Classes/RSRFPSCounter.cpp(1633): - AnimationsTest:visit ran at 154.022064 fps
05-16 06:20:34.307: I/jni/…/…/Classes/RSRFPSCounter.cpp(1633): - AnimationsTest:visit ran at 150.856934 fps


When commenting m_bDirty = true I get no more animations updates and the following result:

05-16 06:05:37.937: I/jni/…/…/Classes/RSRFPSCounter.cpp(1304): - AnimationsTest:visit ran at 382.277832 fps
05-16 06:05:38.948: I/jni/…/…/Classes/RSRFPSCounter.cpp(1304): - AnimationsTest:visit ran at 359.835083 fps

05-16 06:05:58.267: I/jni/…/…/Classes/RSRFPSCounter.cpp(1304): - AnimationsTest:visit ran at 372.321960 fps
05-16 06:05:59.287: I/jni/…/…/Classes/RSRFPSCounter.cpp(1304): - AnimationsTest:visit ran at 376.647827 fps

Anyone has a clue?

Just for curiosity I tried running some of the tests in $COCOS2D_HOME/samples/TestCpp.

I left my desk while SpriteBatchNode transformation was running in an emulator.
When I came back the test was running at less than 5 frames per second.

I think there is a global issue with either android api16 or with the CCSpriteBatchNode implementation. Or my setup is somehow broken. Anyone else having such an issue?

Is this only happening on Android? In your second post how many sprites were you adding? It looks like you are having to wait for ~10-30 minutes to see this bug. Is there a way for me to test this without having to wait such a long amount of time?

Kevin H wrote:

Is this only happening on Android? In your second post how many sprites were you adding? It looks like you are having to wait for ~10-30 minutes to see this bug. Is there a way for me to test this without having to wait such a long amount of time?

After adding batch nodes I noticed slowdowns on the Ouya and I started investigating them.

Currently I tried only android and iOS. iOS seems to behave. And to make sure I ran tests on the devices for much longer.
I have been ruing the SpriteBatchNode transformation test for 20 minutes on an iPad (1st generation) now and there is no slowdown at all. Same result on an iPhone 4, it works perfectly.

I tested more on android as the issue are reproducible on the simulator so I investigated on that during my spare time. I’ll have the ouya tomorrow hopefully I’ll have some time to investigate the issue on the hardware.

On my test scene I added 18 animated sprites. while the display works great at first : 05-16 06:11:26.968 the theoretical speed is about 360.904816 fps (caped at 60 fps of course). But the performance quickly falls under 30 fps : 05-16 06:12:53.342. It take 1m20s to get this drop on the emulator.
At first I thought the animations were responsible so I removed them and simply used sprites from a tilemap. it resulted in the same issue.
Now I noticed it also happens with the test app.


The issue occurs with the following setup:
cocos2dx:2.1.3
NDK:r8e
Android SDK Tool: 22

Device: AVD: android 4.1.2, arm, gpu accelerated:yes, 1080p

app:
Our current ouya project
or
TestCpp from $COCOS2D_HOME/samples/TestCpp

  • SpriteBatchNode transformation slows down enough to be visible after 5 minutes
  • SpriteBatchNode new texture (tap) slows down enough to be visible after 5 minutes

I suspect the speed at which the issue shows depends on the size of the texture used. Currently we are using 2048*2048 RGBA4444 and RGBA8888 png files, and with our resources the problem is visible within a minute and unmanageable in just under 1m30.

Also I noticed the issue was not reproducible on a device running android 2.2.1.

I’ve tested on a Nexus 7 (4.2.2) and AVD (4.0.3) with 200 animated sprites in a spritebatch and did not encounter this bug. The simulation ran for more than 10 minutes without any difference in framerate. I’m using NDK r8b and API level 15.

You could possibly try reinstalling your NDK and SDK. If that doesn’t help maybe try the android profiler(http://www.cocos2d-x.org/boards/6/topics/5884).

Kevin H wrote:

I’ve tested on a Nexus 7 (4.2.2) and AVD (4.0.3) with 200 animated sprites in a spritebatch and did not encounter this bug. The simulation ran for more than 10 minutes without any difference in framerate. I’m using NDK r8b and API level 15.
>
You could possibly try reinstalling your NDK and SDK. If that doesn’t help maybe try the android profiler(http://www.cocos2d-x.org/boards/6/topics/5884).

I have tested on the OUYA hardware and you are right. The performance is degraded only in she emulator. The performance loss on the hardware was due to an unrelated bug.