Preloading and Texture-Memory

Hey all,

 

I am new to this forum and any kind of forums, but it shouldn’t be too hard to use =P I am confused with something. I think there is offscreen handling for objects or not drawn ones like alpha=0 etc. But does it help texture-memory management and if not, where is it helpful? My problem is that I have a scrolling game, like an endless runner game. Game needs to preload its assets because I discovered that it smooths fps (60), otherwise it will drop fps time to time. (down to 42-48 for a second and it is noticable)

 

This is my discovery hence the question:

* Loaded an image - lets say it took X texture memory

* I tried putting the image offscreen like 100000px away - X texture memory again

* image.alpha = 0 or/and image.isVisible = true - X texture memory again

* I preloaded with texture:preload() and didn’t create a display object for image - X texture memory again

 

Extra information:

  • I am actually handling my images with 1px*1px “empty.png” and when they are about to be displayed, I convert them to real ones. (They are all different images) and remove them when they are offscreen. Creating seems to cause a bit fps dropping. Because when I remove this process, and create them all with original images before the next level begins, it freezes almost 1-1.5 seconds but goes smooth afterwards. I need preloading at the very start of run to fix those freezes but texture memory goes up high. I created 2 levels atm. If I turn off this process, it goes up to 160mb texture memory during level change (second level images + existing ones). If not, maximum 26 mb during whole 2 levels. So wouldn’t it be really really high with 7 levels of preloading if there is no texture-memory handling when they are not drawn.

  • Levels are 12k px long x 7 different levels

  • Images are 150 to 700 px long, less then 1024 (no big image loading) and since PoT isn’t needed anymore, I should be fine with that. I sliced my images to get rid of unnecessary transparent areas for better texture-management and according to approx device widths. I read bigger image movements are not suggested but in my case smaller the image, more the loading parts and more fps drops.

  • No memory leak that I detected. Tho it shouldn’t matter since it happens slightly after the start of game too. Maximum 2-3 mb of memory is used.

  • 5 depth of backgrounds + 1 landscape - Displayed image quantity cant be more 35-40 at once.

  • I don’t know if it would help but I even localized display.newImageRect

An extra question if you don’t mind. I don’t think I have too much image. I know 60 fps is kinda hard to get but I am testing this on Windows Simulator and Samsung S7. This is no hardware inefficiency, too much memory, texture-memory or too much of something. Am I missing something here?

That is a big question. :slight_smile:

Let me give you one piece of advise and a link to an example.

  1. Don’t create and destroy the images.  Use bitmap paint fills instead.  Your idea of a shared image for off-screen objects is great, but better to create them once and then fill them with the right image at the right time. 

    obj.fill = { type = “image”, filename = “path to image” }

  2. An example showing the huge memory difference between shared offscreen filling versus keeping all images loaded.  Also shows how to detect offscreen + how to handle just in time fills.

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2014/10/Texture%20Memory%20Management.zip

From my huge archive of answered forums questions (see Ask Ed folder): https://github.com/roaminggamer/RG_FreeStuff

Uses SSK2 but not required for general concept.

PS - This code is from a very old episode of Corona Geek:

https://www.youtube.com/watch?v=DDKceEWKq-8&t=1s

At the end of the day, there is NO PERFECT approach for all cases.  There is only, the one that works for your game.

I hope that others have more advise for you here as this kind of question is always interesting and if answered useful for all.

@everyone - Hint hint.  Got some specific tried-and-true advice?  Please respond.  

Thanks a lot for a lot of resources (: I will certainly look into these starting now. I can already see how fill will be effective.

By the way I am still curious about preloading. Is it something we do at the cost of more texture memory in return of less “system work” at once. Nothing more, nothing less?

Do you use sprites for your game? if not, take a look here:

https://docs.coronalabs.com/guide/media/spriteAnimation/index.html

When I want to preload images that are not in sprites I use this:

https://docs.coronalabs.com/guide/graphics/textureManagement.html

Hey sorry for late response. I was trying lots of things to reduce my lag some other places, till I find out this one.

I am only using sprites for animations. Because If I put my images to sprite there will be gaps in big picture (they are not nice rectangles to make a bigger rect, not even close) and I will lose space since PoT doesnt apply anymore anyway. And about preloading, I am going to use that technique to load but I am still trying to understand what preloading will do for me. Thats why I am looking for an answer to my question. If preloading does what I think it does, it would be a bad path for this game. Because there is too much to load and too much texture-memory it will cost me.

Guys I tried everything and only working solution would be preloading images. Please, it is the only thing that fixes problem. Doesn’t anyone know how preloading works? To simplify my question:

  • Can I preload textures without compromising texture-memory? (offscreen or invisible. it is the same texture memory atm if there is anything i don’t know of)

That’s exactly what preloading is meant to do … it preloads files/data into memory (in some cases uncompress/format convert them while doing this). Sadly you can’t have both, save time by preloading/precalculating stuff but without the required memory - that’s the very core of the compromise.

I’m not sure I understand what you meant with regards to your 7 levels - all you need to preload at any time are the images for a single (the currently played) level. If the users replays the same level - great, just reuse the already loaded images if not *first* free the graphics of the current level and then preload the ones for the next level.

If there are images shared between levels, only free those not used in the next level and of course only preload those not loaded already.

If it does take a little time to preload any level, that’s what loading screens were invented for - be creative, show random tips for your game, add a small animation etc. etc.

Also with regards of PoT, I haven’t done any research on this as I always pack my images into texturesheets and always use PoT. If it’s not required anymore, does this mean, all the hardware these days, even all the cheap/crappy phones out there, handle any texture size (and do so without performance hit) these days? Or is it just Corona that, in case your assets are not PoT, does an internal fix by upscaling the textures, adjusting UVs to the partial region your image uses but all this at the cost of wasting some texture memory?

Hello first thank you for replying, I guess that settled it. At least I have all the knowledge about it now. By 7 levels I mean 7 different type of decors, scenes but since it is an endless runner, there is no pause in between. And that was my problem, graphic heavy, moving fast and as you’ve guessed, freezes when preloading before scenes/levels.

I don’t know how to quote to a post of someone in different topic but I can paste the link of page where a Corona moderator Tom saying:
“The guide that you are referencing to is outdated. the “Power of 2” (PoT) rule applied to openGL 1.x in Corona’s Graphics 1 days. Our current CoronaSDK uses openGL 2.x which doesn’t have the PoT limitation. This means the texture memory number that is returned should match the actual size of the images loaded.”

forums.coronalabs.com/topic/57142-texture-memory-optimization-problem-pot-rule/
5th post

I was testing around to see the difference between ruled image and another. If you load and check the texture-memory usage between those, you will see it is not applied. Actually this is how I found the link. I was confused and searched in corona forums to check why PoT had no impact.

You don’t need to do your pre-loads all at once as long as you start them well before needing the assets.

You can use three different techniques to dribble out the loads (and releases):

  1. Using a timer or enterFrame listener (prior is probably better), start pre-loading the next ‘decor’ graphics one at a time and waiting between pre-loads for a period.

  2. Do the same thing, but use the slightly more technical co-routine approach while accumulating load duration to avoid going over the frame duration (this is really overkill and can be accomplished in a less sophisticated enterFrame handler).

  • check star time
  • load texture A
  • check duration since start, if < xxx milliseconds, continue, if not suspend
  • load texture B
  • … repeat till done or suspended
  • use timer or enterFrame to resume next frame
  1. Put together your own custom ‘tracking’ code to keep track of which textures are in use and which are soon to be used.  Then, with the above techniques load and unload dynamically without simply doing them all in one huge push.

Note: This is a really interesting technical problem.  I’m curous to hear what solution you come up with. 

Hey, this is exactly what I thought of after posting and did that. When I am about to preload next scene (like 1k-2k earlier),  I passed my textures to a table and if table is full, I am looping to load till system.getTimer difference is over 16 (assuming 16.667 ms for a frame). But I see that 16 is not correct, because fps will drop to 11 in that time. It is either system.getTimer() is not returning me with miliseconds or corona framework will take some time off for itself in the background (probably the second). But I am really excited that I think I will get through this. Because it is a steady slowed down frame, ready to be fixed!

Interesting info (at least for me):
* If I use busy waiting (testing purposes) and break in 8-10ms, my fps will drop to 30. A steady 30.
* Busy waiting loop to break in 4ms: A steady 60 fps.
* 139*250 px picture loaded in 3.2ms, 1000x553 px picture loaded in 19.5ms.

According to these I have 2 ideas.

  1. I will chop of my pictures to really a lot of pieces and write a code to autoload pieces. And I wont compromise my fps.
  2. I will break at when is at 30 fps rate! And set my speed variables accordingly before that. So when it lags to 30 fps, it will be a steady 30fps and it wont be noticeable for a small time since character and world will adjust to that.

But going path 2, I still need to chop of images. So I might as well get them all done and achieve 60 fps in that time without messing with variables. Any other suggestion is appreciated.

I will let you guys know how it went after I’m done. Nice to hear you are curious btw, I kinda felt lonely (:

If you’re trying to run at 60FPS, 16 ms for running your scripts is way way way too long.

Remember, a single frame of execution includes:

A - Time Corona needs to draw, handle physics calculations, transitions, etc.

B - Time your scripts run for during that frame

So if you take 16 ms, that leaves 0.66 for Corona.

Also, you need to measure ‘time since end of last frame’, not time in current frame.  Then use a variable best case value.

i.e. Say your best case value is 5ms, but it has been 15 ms since the last frame already.  Simply run for 1ms or safer yet skip work in this frame.

If on the other hand it has only been 7 ms since the last frame, run the full 5 ms best case duration then stop.

Never try to fill all the time.  That is a recipe for frame hiccups.

Hey. I had to practice some imagemagick commands for the long run so it took me a while to be done with the images. That was nice to measure time since end of last frame. But I checked the values and this thing happens:
time between took - 16ms
time between took - 0…
time between took - 0…
time between took - 15ms
time between took - 0…
time between took - 0…​
time between took - 17ms

But I cant measure how long it WILL took. When I do if allowedtime > 8, half of the time loading process works in a frame that is going to be busy without even loading. It looks like Corona does heavy work in one of 3 frame. Then I did a basic test and tried to load when it WAS a busy frame (the ones that took over 14ms), things almost worked out. Sadly, is it safe to count on this? Since I don’t have any idea how long Corona’s work will take in that frame, I can’t see any other way. It looks like I need to either load when a busy frame just ended or I will note the busy one and load in the next 2 frames.

Edit: Sorry. As I’ve said it was a basic test and I was dumb to think it could be a pattern. I cant count on that for sure. Things I do, in game changes, even loading itself will mess up with the pattern even if there was one

Are you doing this directly in your app or in a test bench while you work out the methodology?

It looks like this is from your app:

time between took - 16ms
time between took - 0…
time between took - 0…
time between took - 15ms
time between took - 0…
time between took - 0…​
time between took - 17ms

These numbers tell me your app is already in trouble.  A 0ms frame duration is Corona trying to catch up because there was too much work shoehorned into a prior frame.

If I have time today I’ll write up a test-bench showing you want I mean by my original advice.

Hey I had an unnecessary enterframe event. Once I deleted that actual numbers goes around:

time took in this frame 0.19999999999891

time between last frame 16.200000000001

time took in this frame 0.19999999999891

time between last frame 20.700000000001

time took in this frame 0.10000000000036

time between last frame 9.7999999999993

time took in this frame 0.20000000000073

time between last frame 18.699999999999

time took in this frame 0.20000000000073

time between last frame 10.9

time took in this frame 0.20000000000073
(No more 0s since last frame)

My only enterframe now and the related function : (timed() function here is system.getTimer())

onWorldMove = function() local frameStartedAt = timed() print("time between last frame ", frameStartedAt - tempValues.lastDeltaT) --- ..... enterframe actions here local deltaT = timed() local maxAllowedTime = 15.5 - frameStartedAt - deltaT if maxAllowedTime \> 8 then textureProcess(deltaT, maxAllowedTime-3) end end textureProcess = function(deltaT, allowedTime) local newTexture = graphics.newTexture if textureProcessData.load then local textureData = textureProcessData.load local textures = textureData.textures local lastProcessed = 0 for i=textureData.from,1,-1 do newTexture( { type="image", filename=textures[i] } ):preload() print("texture",i,"name",textures[i]) if timed() - deltaT \> allowedTime - 5 then lastProcessed = i break end end if lastProcessed \<=1 then textureProcessData.load = nil else textureProcessData.load.from = lastProcessed-1 end end end

That is a big question. :slight_smile:

Let me give you one piece of advise and a link to an example.

  1. Don’t create and destroy the images.  Use bitmap paint fills instead.  Your idea of a shared image for off-screen objects is great, but better to create them once and then fill them with the right image at the right time. 

    obj.fill = { type = “image”, filename = “path to image” }

  2. An example showing the huge memory difference between shared offscreen filling versus keeping all images loaded.  Also shows how to detect offscreen + how to handle just in time fills.

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2014/10/Texture%20Memory%20Management.zip

From my huge archive of answered forums questions (see Ask Ed folder): https://github.com/roaminggamer/RG_FreeStuff

Uses SSK2 but not required for general concept.

PS - This code is from a very old episode of Corona Geek:

https://www.youtube.com/watch?v=DDKceEWKq-8&t=1s

At the end of the day, there is NO PERFECT approach for all cases.  There is only, the one that works for your game.

I hope that others have more advise for you here as this kind of question is always interesting and if answered useful for all.

@everyone - Hint hint.  Got some specific tried-and-true advice?  Please respond.  

Thanks a lot for a lot of resources (: I will certainly look into these starting now. I can already see how fill will be effective.

By the way I am still curious about preloading. Is it something we do at the cost of more texture memory in return of less “system work” at once. Nothing more, nothing less?

Do you use sprites for your game? if not, take a look here:

https://docs.coronalabs.com/guide/media/spriteAnimation/index.html

When I want to preload images that are not in sprites I use this:

https://docs.coronalabs.com/guide/graphics/textureManagement.html

Hey sorry for late response. I was trying lots of things to reduce my lag some other places, till I find out this one.

I am only using sprites for animations. Because If I put my images to sprite there will be gaps in big picture (they are not nice rectangles to make a bigger rect, not even close) and I will lose space since PoT doesnt apply anymore anyway. And about preloading, I am going to use that technique to load but I am still trying to understand what preloading will do for me. Thats why I am looking for an answer to my question. If preloading does what I think it does, it would be a bad path for this game. Because there is too much to load and too much texture-memory it will cost me.