Understanding poor blending performance

Hi, we had a performance issue with our new game on certain devices.
I’ve posted about it here:
http://developer.anscamobile.com/forum/2012/01/23/slow-performance-android-30

But as our own investigation progressed we actually found the root cause but we’re not sure how to solve it.

The problem is with the number of transparent overlapping images in our game which probably loads the GPU on the device (btw, our texture memory consumption is quite low, less than 10mb)
I’ve isolated out of our code a small sample that exhibits this issue. Basically this is the theme of our main menu on which you have the play button and also some other buttons that bring up verious popups (options, settings, highscores, etc).

These popups have a semi transparent black background so you can still see the main menu theme through them.

The then is just 50 flakes that are dropping and are moved by an enterFrame event.

Here is the same code:

display.setStatusBar( display.HiddenStatusBar )  
  
real\_world\_width = display.contentWidth - 2\*display.screenOriginX  
real\_world\_height = display.contentHeight - 2\*display.screenOriginY  
local centerX, centerY = display.contentWidth \* 0.5, display.contentHeight \* 0.5  
  
local flakes = {} --array for all the flakes  
  
local back = display.newImage("small\_back.jpg")  
back.x, back.y = centerX, centerY  
back.xScale, back.yScale = 2 \* real\_world\_width / display.contentWidth, 2 \* real\_world\_height / display.contentHeight  
--FPS bar stuff  
local prevTime = 0  
local curTime = 0  
local dt = 0   
local fps = 50  
local mem = 0  
  
local underlay = display.newRoundedRect(0, 0, 300, 20, 12)   
underlay.x = 240  
underlay.y = 11  
underlay:setFillColor(0, 0, 0, 128)   
local displayInfo = display.newText("FPS: " .. fps .. " - Memory: ".. mem .. "mb", 120, 2, native.systemFontBold, 16)  
  
local function updateText()  
 curTime = system.getTimer()  
 dt = curTime - prevTime  
 prevTime = curTime  
 fps = math.floor(1000 / dt)  
 mem = system.getInfo("textureMemoryUsed") / 1000000  
  
 --Limit fps range to avoid the "fake" reports  
 if fps \> 60 then  
 fps = 60  
 end  
  
 displayInfo.text = "FPS: " .. fps .. " - Memory: ".. string.sub(mem, 1, string.len(mem) - 4) .. "mb"  
 underlay:toFront()  
 displayInfo:toFront()  
end  
--generate one flake.  
local function generateFlake()  
 local f = display.newGroup()  
  
 local randX = math.random(0,display.contentWidth - 40) + display.screenOriginX  
 local dist = math.abs(randX - centerX)  
 local size = 15 + (dist/160) \* 25  
 f.stepSize = size \* 0.05  
  
 local flakeWhite = display.newImageRect("shiny\_white.png", size, size)  
 flakeWhite.alpha = 0.5  
 f:insert( flakeWhite )  
  
 local flakeLightGreen = display.newImageRect("shiny\_green\_soft.png", size, size)  
 flakeLightGreen.isVisible = false  
 flakeLightGreen.alpha = 0.6  
 f:insert( flakeLightGreen )  
  
 local flakeHardGreen = display.newImageRect("shiny\_green\_hard.png", size, size)  
 flakeHardGreen.isVisible = false  
 flakeHardGreen.alpha = 0.75  
 f:insert( flakeHardGreen )  
  
 local flakeShinyWhiteOut = display.newImageRect("shiny\_white\_out.png", size, size)  
 flakeShinyWhiteOut.isVisible = false  
 flakeShinyWhiteOut.alpha = 1  
  
 f:insert( flakeShinyWhiteOut )  
 f.stages = {}  
 f.stages[1]= flakeWhite  
 f.stages[2] = flakeLightGreen  
 f.stages[3] = flakeHardGreen  
 f.stages[4] = flakeShinyWhiteOut  
  
 f.currStage = 1  
  
 f:setReferencePoint( display.TopLeftReferencePoint )  
 f.x, f.y = randX, 10  
  
 function f:toggleStage(idx)  
 for i=1, #f.stages do  
 if i == idx then  
 f.stages[i].isVisible = true  
 else  
 f.stages[i].isVisible = false  
 end  
 end  
 end  
  
 flakes[#flakes + 1] = f  
end  
local function enterFrame( event )  
 for i=1, #flakes do  
 local f = flakes[i]  
 f.y = f.y + f.stepSize  
  
 if f.y \< 40 then  
 f:toggleStage(1)  
 elseif f.y \< 80 then  
 f:toggleStage(2)  
 elseif f.y \< 250 then  
 f:toggleStage(3)  
 elseif f.y \> 340 then  
 f:toggleStage(4)  
 end  
  
 if f.y \> display.contentHeight then  
 f.y = 10  
 end  
 end  
  
 updateText()  
end  
  
--generate the flakes  
local function startTheme()  
  
 for x=1, 50 do  
 local dly = math.random(1500, 1600) + 350\*x  
 timer.performWithDelay(dly, generateFlake)  
 end  
  
 Runtime:addEventListener("enterFrame", enterFrame)  
end  
startTheme()  
  
--generate a new semi transparent rect every 10 seconds  
local iteration = 1  
local function addRect()  
 local rect = display.newRect( 0, 0, real\_world\_width, real\_world\_height )  
 rect:setFillColor( 0, 0, 0, 127 )  
 rect:setReferencePoint( display.CenterReferencePoint )  
 rect.x, rect.y = centerX, centerY  
 if iteration \<= 10 then  
 timer.performWithDelay( 10000, addRect )  
 end  
 iteration = iteration + 1  
end  
timer.performWithDelay( 10000, addRect )  

I couldn’t attach the images but small_back.jpg is a 160x240 black rect with a frame. and the flake images are 40x40 images with a lot of transparent pixels (not sure if that’s important).

As you can see every 10 seconds I add a new semi transparent rect to the front (simulating a popup). I accumulate these popups up to 10 of them.

Here are the results:

  1. On Samsung Galaxy Tab 10.1 (Running ICS preview and also tested with Honeycomb 3.2):
    After 1 popup the framerate drops from 60 to 30, with two it drops to less than 20 and with 3 it’s just crawls…
  2. On Acer Transformer - same result.
  3. On a New HTC Sensation XL running Android 2.3.4 - same result!
  4. On HTC Desire HD running Android 2.3.7 - Surprisingly this old device outperformed all the new ones! it went below 50fps only after 5 popups… This is strange because the Sensation XL is more powerful.
  5. On Samsung Galaxy S2 - even at 10 popups everything works perfect.

My only guess so far is that this manifests only on bigger screen devices (the Sensation XL is a 4.7" device compared to the Desire HD which is 4.3", not sure about the resolutions…)

Anyone has any experience with extensive blending performance problems like this one? This is just killing our game on the problematic devices because we have a lot of transparent glass layers in our game theme… I know this isn’t directly a Corona problem but I would like to understand how to work around these limitations and also why does it appear only on bigger screen. [import]uid: 80469 topic_id: 21245 reply_id: 321245[/import]

I’m having exactly the same problem. My game works using Galaxy S2 and Xperia Ray, but it doesn’t on Galaxy Tab 10.1.

Did you try it with the build 635? Maybe it’s something related with that topic:

developer.anscamobile.com/forum/2011/12/12/performance-degradation-new-public-release [import]uid: 46216 topic_id: 21245 reply_id: 84177[/import]

I’m using build 730. giving the older version a try now. [import]uid: 80469 topic_id: 21245 reply_id: 84183[/import]

Tried 635 might be a little faster nothing meaningful… this problem persists in 16bit so its a different thing [import]uid: 80469 topic_id: 21245 reply_id: 84189[/import]

If you look at this page:

http://developer.android.com/guide/topics/manifest/application-element.html

You’ll see there’s an attribute called “android:hardwareAccelerated”. After decoding the apk of my app to be able to read the AndroidManifest.xml, I have not seen it.

Could it have some relationship? [import]uid: 46216 topic_id: 21245 reply_id: 85790[/import]

i have the same problem but in samsung galaxy s1 i9003 its dropping in fps when i spawn more than 15 objects moving on the screen i also report ansca thats its a bug cause of any simple transition suffers from stuttering problem [import]uid: 74537 topic_id: 21245 reply_id: 85799[/import]