• Bugs
  • Performance issue in corona SDK

We have been using Spine on Corona engine for our new game in development for more than a year. We have been having fps issues with the game using characters made in spine. Our game is going to be a real-time multiplayer game with maximum of 6 players fighting each other in arena. But having more than 3 players in one screen is causing frame rates to drop as low as 8 fps on low end devices and 15-20 on high end devices. There is no FFD but the characters have a lot of bones. But even with characters with less bones it causes fps drop. We are using Photon servers for the game. Even with the spine example projects like the dragon, if we have 6-8 characters the frame rate is dropping drastically. One thing notice is that the dragon wings are animated by changing images. These kind of animations where there is image switching is causing a lot of fps drop. If there is a solution or steps to improve the performance it would be really helpful. Currently using v 2.1.27.

Related Discussions
...

Can you show a screenshot of the Metrics view for one of your typical skeleton attachment configurations?

There are two main ways to improve performace: 1) do less (fewer bones, fewer vertices, fewer timelines, etc), or 2) do it more efficiently (use a texture atlas, modify the runtime, etc). The runtime is already optimized for general usage, but you may be able to improve performance for your particular application (eg, remove code for features you don't use). If you look in spine-corona/spine.lua you'll see:

if not image then 

---

 Create new image.
    image = self:createImage(attachment)
    ...

When images change createImage is called. By default this uses display.newImage, which is probably slow (I'm only guessing here). You can provide your own createImage implementation, eg to cache image instances rather than create them each time. The change most likely to improve your performance is to use a texture atlas. To do that you'd have createImage return an image from your atlas. Unfortunately using an atlas with Corona is not easy. They provide graphics.newImageSheet, but this was designed for a spritesheet grid, not a proper texture atlas.

Unfortunately Corona itself just does not have stellar performance. As with anything regarding performance, this doesn't matter unless it impacts the player. The problem with Corona is that it provides only high level APIs, limiting what can be done to improve performance. You are very likely to have better luck with other game toolkits (I recommend libgdx, which Spine uses), though I understand that may not be a simple change. Corona's limited APIs also prevents rendering Spine meshes at all and prevent using non-uniform bone scale.


Some discussion about Corona atlases here:
Corona SDK - Atlas?

We have tried with lesser bones with no success.

Image supprimée en raison de l'absence de support de HTTPS. | Afficher quand même

Just to draw this skeleton once, every frame you'll compute the world transform for 46 bones, apply 79 timelines, and then draw 19 images. It's not a small amount of bones or timelines, but it's not unreasonable. The 19 images however are all stored in separate files, which means Corona loads them into the GPU as separate textures, which means every time you draw an image it sends the geometry (4 vertices) for that 1 image to the GPU for drawing. This is called a "draw call". It's much more efficient to batch the geometry for many images, then send them all to the GPU with 1 draw call. To do this, all the images need to use the same texture. That means you need to use a texture atlas, as I explained in my last post. I assume that Corona does dynamic batching, where if multiple images (scene graph elements) are drawn from the same texture, the geometry is batched. (If Corona can't do that, then it's poor performance is even worse than I thought.) For a low end device, you want something like maybe 40 draw calls per frame. With 19 attachments visible you are using 19 draw calls per skeleton, plus whatever else you draw for backgrounds, UI, etc.

The other part of your problem is (as I wrote in my last post) that when attachments change Corona will read the new image file from disk and send it to the GPU. This is probably not something you want to do in the middle of your gameplay. Using a texture atlas also solves that problem.

6 mois plus tard

I've encountered similar performance issues with Corona recently and came to the same conclusion - you must use ImageSheets. I use Zwoptex to export the lua data necessary for the sheet, but you can use TexturePacker as well. Simply setup an ImageSheet as you normally would...


load image sheet
local imgData = require "myImageSheetData"
local imgOptions = imgData:getOptions()
local imgSheet = graphics.newImageSheet( "myImageSheet.png", imgOptions )[/i]

...then update your createImage function to...

function skeleton:createImage (attachment)

local imgName = attachment.name .. '.png'
local imgIndex = imgData:getFrameIndexByName( imgName )
local img = display.newImage( imgSheet, imgIndex )
return img

end[/i]

...and voila - much better performance.

3 mois plus tard

I've just merged the latest spine-corona runtime update with master, see spine-runtimes/spine-corona at master · EsotericSoftware/spine-runtimes · GitHub

You can now use Spine's native texture atlases with the spine-corona runtime, performance should be very good! I tested it on Android and it was quite a bit better than the old one! There is still some room for improvement as Corona currently doesn't batch indexed meshes (the things we use to draw everything in the new spine-corona runtime). Once that is in on Corona's end, things should be VERY fast.