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:
- 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… - On Acer Transformer - same result.
- On a New HTC Sensation XL running Android 2.3.4 - same result!
- 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.
- 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]