Framerate drop on iPod Touch 4G when touching and moving

Hi everyone,

I was hoping someone could help me with poor performance on the iPod Touch 4G when I touch the screen and move my finger around. Unfortunately I was unable to reproduce this in the CoronaSDK samples, so I’m assuming this is something to do with my project.

I have several thousand display objects in my stage, performance is a steady 30 fps on the device, and I’ve removed all touch/tap/mouse listeners in the project. Sadly, I cannot provide the project, as the game is under active development.

When I touch the screen and drag my finger around quickly, the frame rate drops to 18-20 fps, even though there are no touch listeners in the project. I’m wondering if this is a result of the high number of display objects, and if so, it makes me wonder if Corona is recursively checking the scene graph for touch listeners?

Has anyone experience this and found a solution?

Albert

Interestingly, I made my Camera system buffer the stage inside a Snapshot object, and touching and moving only affects the changes the frame rate from a steady 30 to 22-24. So it would seem that Corona does some kind of recursive loop on the scene graph for every touch event, maybe looking for touch listeners?

Still, the 6-8 fps drop is a big deal, has anyone experienced this?

Albert

What version of Corona SDK are you using?

Hi Rob,

I’m using the latest daily build, CoronaSDK 2016.2904

Albert

Can you try it with 2830?

Thanks

I just tested with the public release (2830) and I still have the issue. Is there anything else I can look for?

Although the stage is in the buffer, the UI (which is made up of many more display objects) is not in the buffer, so if my suspicion turns out to be true (that Corona is recursively looping through the scene) it may be that there are still too many display objects.

I was looking to see if you found a regression bug. Do you see this on other devices?

Can you make a test case that has the problem?

Hi Rob,

I don’t see this on Android devices, unfortunately my cat destroyed my USB cord for my iPad. I will look into recreating the problem, although last time I checked my code base was something like 70,000 lines so this may be no easy task. If worst comes to worst, I can send you my project files, although I imagine debugging my project would be torture for someone who has never seen it before.

Not to “promote” the game to you or anything, as I haven’t been displaying this publicly yet, but to get an idea of why the code base is so big and why the lag is killing the experience, here is some sample game play.

https://www.youtube.com/watch?v=A58WL3qXJvQ

Again, I’m not trying to promote it here, and if this is a problem, I’ll promptly remove the video, no need to provide feedback on it either.

Thanks for replying,

Albert

We probably would reject  you sending your whole project. We can’t debug it for you. But if you think you have a bug, we do need a test case that demonstrates it. In the absence of that, the only suggestion is to make sure you don’t have a touch listener on your Runtime or on the main stage.  We do loop through all objects that have handlers on them. Your touch handler need to return “true” at the end. If you don’t we are going to look for objects under it to send the event to since your function didn’t say it handled the event.

Rob

Hi,

Thanks. I did make sure there are no touch listeners, as I overwrote the Runtime:add/removeEventListener interface so as to be able to get a count on the number of listeners for any event. When I print out the number of listeners it is zero, and I additionally made sure every reference to the event was “xtouch” instead of “touch”.

I’ll do my best to come up with something to send your way.

Thanks again,

Albert

Hi,

I have narrowed this down and created a simple project that reproduces this problem.

http://www.ionpixel.com/Corona/TouchFpsSlow.zip

If you download and run this project, there is a constant at the top named:

local DEMONSTRATE\_BUG = true;

You can easily search the code to see what the bug does. The project will create 2000 display objects, with the bug enabled, touching and moving on the screen will cause significant frame rate drops on mid to low-end devices. With the bug enabled, the display objects are placed into variable parent DisplayGroups, so as to simulate a very complex hierarchy of display objects.

On my HTC Rezound, the app runs at a steady 25fps. Upon pressing and moving my finger back and forth, the fps drop to 10-11 fps and immediately shoot back up to 25 fps. With the bug demonstration disable, the fps only drops down to 21-22.

On my iPod Tough 4th Gen, the frame rate is at 11 fps, however touching and swiping quickly the screen drops the framerate down to 0, literally the screen freezes.

I understand the display hierarchy may not be a “realistic” app, but it simulates the problem that my real application is having. If you look at my source code, their are absolutely no touch, tap, or mouse event handlers. This bug seems to indicate that for every touch event Corona receives, it crawls the display list hierarchy to determine what object(s) are at the specified position, which it should definitely not do.

This is a critical problem for me, in my production application, framerate on my HTC device is a steady 52, but drops to 20 without a single touch/tap/mouse listener defined.

Case #46695

Thanks,

Albert

Hi Rob,

Is this a problem that can be fixed possibly? Since updating the logic would likely be a huge undertaking and possible not even technically feasible, a feature that can be enabled/disabled at runtime to stop Corona from iterating through the display list for every touch event would be equally awesome. Something like:

system.setTouchListenerEnabled( true/false ); -- Setting this to True would prevent Corona from iterating the display list on all "touch" events.

I’m near release and I’m worried about the performance on older phones. In fact a few of my close friends and relatives have old phones and it would be a huge shame for them to be unable to play my game.

Anything you can help me with would be hugely appreciated.

Albert

I don’t have a old device, but does this help at all.

-------------------------------------------------------------------------------------------------------- -- Constants -------------------------------------------------------------------------------------------------------- local RADIUS = 400; local OBJECT\_COUNT = 2000; local DEMONSTRATE\_BUG = true; -------------------------------------------------------------------------------------------------------- -- Helper Methods -------------------------------------------------------------------------------------------------------- local function getPointOnRadius(x, y, radius, angle) local a = math.rad(angle) local x = x + radius \* math.cos(a) local y = y + radius \* math.sin(a) return x, y; end local function recurseDisplayObjectsForCount(displayObject) local count = 1; if displayObject.numChildren then for i=1, displayObject.numChildren do local child = displayObject[i]; count = count + recurseDisplayObjectsForCount(child); end end return count; end -------------------------------------------------------------------------------------------------------- -- Variables to calculate delta time and average fps -------------------------------------------------------------------------------------------------------- local lastMillis = system.getTimer(); local millis = 0; local deltaTime = 0; local totalMillis = 0; local totalFrames = 0; -------------------------------------------------------------------------------------------------------- -- Scene initialization -------------------------------------------------------------------------------------------------------- local mainParent = display.newGroup(); mainParent.x = display.contentCenterX; mainParent.y = display.contentCenterY; local useParent = mainParent; for i=1, OBJECT\_COUNT do local angle = (i/OBJECT\_COUNT) \* 360; local square = display.newImageRect("Icon.png", system.ResourceDirectory, 100, 100); square.x, square.y = getPointOnRadius(0, 0, RADIUS + math.random(-100, 100), angle); square.rotation = angle + 45; useParent:insert(square); if DEMONSTRATE\_BUG == true then -- This code assigns a 1/3 chance of either creating a new child group, popping up the display list hierarchy, or staying at the current group object in the hierarchy -- This simply allows us to simulate a complex hierarchy of display objects. local decision = math.random(0, 99); if decision \<= 33 then if useParent ~= mainParent then useParent = useParent.parent; end elseif decision \<= 66 then local newParent = display.newGroup(); useParent:insert(newParent); useParent = newParent; else -- Nothing end end end -------------------------------------------------------------------------------------------------------- -- Update once per frame -------------------------------------------------------------------------------------------------------- Runtime:addEventListener("enterFrame", function (event) -- Find Delta Time millis = event.time - lastMillis; deltaTime = (millis/1000); -- Sumation for average FPS totalMillis = totalMillis + millis; totalFrames = totalFrames + 1; -- A little animation to know the scene is active mainParent.rotation = mainParent.rotation + deltaTime \* 60; -- Store for the next frame's delta time lastMillis = event.time; end); -------------------------------------------------------------------------------------------------------- -- Print the AVERAGE Frame rate and count objects in the scene every second -------------------------------------------------------------------------------------------------------- timer.performWithDelay(1000, function () local avgMillis = totalMillis/totalFrames; local stage = display.getCurrentStage(); local count = recurseDisplayObjectsForCount(stage); print("FPS", (1000/avgMillis), "# OBJECTS:", count); totalFrames = 0; totalMillis = 0; end, -1); local background = display.newRect( display.contentCenterX, display.contentCenterY, display.actualContentWidth, display.actualContentHeight ) background.alpha = 0.00000000001 background:addEventListener( "touch", function ( ) return true end )

Hi, thanks for responding.

I tried the code, when I looked at it, I thought of course! The display object on the top of the display list would receive the event and then return true, preventing further iteration on the display list.

Unfortunately, it does not solve the problem. The framerate remains the same on my HTC Rezound (normal=25-30, on move finger=8-10), and on my BLU DASH JR (which is like an extreme budget phone), I get about 56-60 fps at idle and 25-30 with my finger on the screen moving.

So it would seem that either Corona is still iterating the display list, even after returning true, or there is something else going on within the input/message pump that causes the framerate to drop.

Any other ideas?

Thanks,

Albert

You can try to figure out if device is weak and set the fps to 30
Thier is no exact api to tell if a device is slow or you can make it a switch( the app would have to be reopened). You use https://docs.coronalabs.com/api/library/system/getInfo.html#TOC to get an idea if it is a slow device.
30 fps is ok

Edit; plus a fps snob is not going to be hold a cheap android

Hi, I tested at 30 fps, but the problem is the same. I should add that I’m not using Box2D/physics, so I can really work with variable framerate and devices.

I have not tried this but here you go

edit: just tired does not work

system.deactivate( "touch" )

I optimize a little try this

https://www.dropbox.com/sh/zzxzetckfe816zf/AAC98BEKu6xWdm5fy2eaztkOa?dl=0

edit: for weak devices you do have to make cuts, also try building with a different versions of corona sdk

Hi thanks again.

Unfortunately this only slows the rotation speed of the scene, the “60” just means rotate 60 degrees per second. It does not handle the fact that a single tick in the game loop is slowed. The problem is that my game requires fast reflexes, and while 30 fps is perfectly fine for the game, when the player taps on the screen, there are noticeable delays in response time which makes my game unplayable (see trailer above a few posts)

Logging has shown that it is not in my game code, as I have removed all touch/mouse/tap event handlers and the game still has the brutal lag when touching and moving my finger around on the screen.

I’m hoping the folks at Corona have a few low-end devices that they can try the project on.

you could try just one image instead of loading a thousand images. I have not personal experience any lag but I have not tried older devices to be fair. Did test my big game on my iPhone 3GS and ran fine a month ago. I have test since then.