Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Threading System in 2016.6? — Gideros Forum

Threading System in 2016.6?

NinjadoodleNinjadoodle Member
edited June 2016 in General questions
Hi guys

I would like to do an experiment with the new "Threading System" to see if it helps with the HTML5 dilemma I'm having, but have no idea, how to use it.

Currently, when I export to HTML5, Gideros seems to load the whole game into memory before starting.

Is there a way I can use the threading system to load atlases in the background, instead of all at once.

PS. I'm currently loading one Atlas per Level, yet the HTML5 export still seems to load all of the game into memory before starting.

Thank you in advance for any ideas :)

Comments

  • hgy29hgy29 Maintainer
    @Ninjadoodle,
    I don't think the new threading system will help you with your loading issue. As said before, in HTML5 all assets are loaded in memory even before lua is called.

    However, you could put your per-level assets on a server and load them on-demand with UrlLoader. See ImageLoader example: in your case you can save the image files in temp dir (|T|), load a texture from them, and immediately remove the temp file.
  • SinisterSoftSinisterSoft Maintainer
    You can also use the threaded system to do small loads and know the vent system will do other updates, this doesn't happen if you have something on the main thread as that has to run out of code before any events are started.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • totebototebo Member
    edited June 2016
    Is there a way to interrupt an incomplete Core.asyncCall? Use case as follows:

    1. A slider selects levels.
    2. When the slider stops it loads the level with asyncCall.
    3a. If the slider remains in the same position when the asyncCall is done, it shows the level in the background.
    3b. If the slider stops at another level before asyncCall is done, it discards the previous asyncCall, and starts loading the new level instead.

    Likes: antix

    My Gideros games: www.totebo.com
    +1 -1 (+1 / -0 )Share on Facebook
  • SinisterSoftSinisterSoft Maintainer
    It actually doesn't run at the same time. Lua runs on a single cpu thread. What happens is that when your events have finished and the system is waiting for the next events to start, it runs some of the lua code in the fake thread. Then it auto-yields and if there is still time left, it runs some more. And so on.

    What you could do is load the assets in a loop, with itself in a retry loop. At one part of the loop check to see if a new selection has been made, if it has then break out of the loading loop and loop back for the retry.

    eg (this code I just typed here, it might not work!):
    local files={"sprites","maps", etc...]
    local loaded,loadlev
    repeat
      loaded=true
      loadlev=level
      for loop=1,#files do
        if loadlev==level then
          assets[loop]=Texture.new(files[loop]..loadlev..".png")
        else
          loaded=false
          break
        end
      end
    until loaded
    You would just change level and if it was still loading it would start again.

    Likes: totebo, hgy29

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+2 / -0 )Share on Facebook
  • totebototebo Member
    That makes sense, thanks! It's actually better than I thought. I expected a magical sandbox. Will no doubt be back with questions. :)
    My Gideros games: www.totebo.com
  • SinisterSoftSinisterSoft Maintainer
    @hgy29 is best to answer them about fake threads (it's his baby!). I just pestered him to add the auto-yield to make it basically transparent to use - if this wasn't there then every so often you would have to put a yield command.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • hgy29hgy29 Maintainer
    Yes, technically we could add a function to kill some asyncCall, because they are coroutines and actually interrupted when the main thread runs. This would go smoothly since lua will then take care of GC'ing whatever was left behind by the thread.

    But on the other hand, it is a better practice to gracefully end your thread within itself, like @SinisterSoft suggested.

    Thanks for reporting your experiments about them here, we think it is a great feature but you will know better :)

    Likes: SinisterSoft

    +1 -1 (+1 / -0 )Share on Facebook
  • totebototebo Member
    I started playing with it today, and it's a little trickier than I thought. I'm passing a function that loads a level, positions everything, merges tiles, adds collision etc. It does a LOT. I get intermittent crashes, probably because the individual sub-tasks are not executed sequentially. Does that make sense? If so I probably have to create a wrapper class that allows for the sub-tasks to be completed individually.
    My Gideros games: www.totebo.com
  • hgy29hgy29 Maintainer
    Are they gideros crashes (application bails out) or lua errors ? The former shouldn't happen, so if it does I'd be happy to have a look if you can make a somehow reproducible test case
  • totebototebo Member
    It's Lua errors, basically nil references because stuff is not created sequentially(?).
    My Gideros games: www.totebo.com
  • SinisterSoftSinisterSoft Maintainer
    Check for nil in your draw code - if it's not nil then it's been loaded and can be drawn.

    Likes: totebo

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • SinisterSoftSinisterSoft Maintainer
    Also, don't start loads of loads off 'in parallel' - they won't execute in parallel they will get a slice each. Better to have a long sequential load - so things load in the order you want.

    Likes: antix, totebo

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+2 / -0 )Share on Facebook
  • Will it yield in the middle of a long running statement (e.g. TextureLoad a large image that takes 400ms) or will it block the UI/main thread the entire duration of the statement?
  • SinisterSoftSinisterSoft Maintainer
    It's only lua that yields, so it will block if the load takes 400ms - it's unlikely to take 400ms though - that is a long time to load a texture.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • Makes sense. Regarding long loading textures, there was a thread earlier where I (and I believe others) were loading full screen backgrounds for point/click adventure games and 2048x1280 was taking almost a second on older retina iPads. We had a discussion about chopping it up in chunks and preloading the next scene in advance. Essentially loading one chunk a frame, very similar to yielding. So I had that in mind when asking :).

    Luckily the lag is much less noticeable on newer devices.
  • SinisterSoftSinisterSoft Maintainer
    That's a long time.

    What you could do is have one very large image split into say 32 parts.

    Figure out the scaling and define the right size of texture for the device.

    Define a rendertexture for that size. So an old phone will have a smaller texture than a new retina device.

    Draw each section of the image scaled to the rendertexture.

    Draw the render texture to the screen.

    This way you only need one version of the image - for all your devices - and you can put in a loading bar that has 32 sections and does get updated whilst it loads.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • Very cool idea. I'll have to try it!
  • Hi I was wondering if it's possible to apply asyncCall to sceneManager to have a loading bar between scenes:
    Big scenes take some time to load, and they have to be completely loaded before they can be displayed, making the player hang for a while on scene transition.

    If I write the async code in the init section of the scene it won't be accessible until the whole scene is loaded, if I write it in sceneManager:changescene I obviously can't tell at which point of the loading progress it is. So I guess it's not possible.. but maybe someone has a great idea :)

    Thank you

  • hgy29hgy29 Maintainer
    What if you start the loading async in init(), update a progress flag in the loading function, and check for that flag in changescene() to either display the progress bar or go on if the scene has been fully loaded ?
  • Maybe I didn't understood how to implement this:
    I am using a progress flag as you suggested to keep track of my loading status. The status is updated some times in the init function of my scene.

    However it seems that the new scene is being executed only after it has been fully loaded, so everything in newscene:init would be available only after the scene is loaded, which means that the "lag" has happened already.

    I tried also placing the asyncCall code in my previous scene (just before calling changeScene ) and in scenemanager:changescene() itself:
    unfortunately I was unable to avoid the lag when the next scene is loaded: the progressbar won't appear until just after the lag, and then it fills in a hurry (and is being removed).
    I made a test project using scenemanager source example and a really huge number of liquidfun particles to quickly simulate a complex scene. In most cases the progressbar is removed "at the same time" it is placed so you won't even see it, but you can feel the lag.

    The progressbar should appear before lagging and do at least 2 steps to give the illusion that the phone is not stuck.. :P

    asyncCall code is in scenemanager:changeScene(..)

    The lag is better seen on device since laptop handles things faster.

    Am I doing something wrong or is this a "limit" of asyncCall/scenemanager combo?

    thank you




    zip
    zip
    Scene-Managerloader.zip
    202K
  • hgy29hgy29 Maintainer
    Hi @pie,

    I modified a little your project, see attached and tell me if it is what you wanted to achieve. While doing this I discovered a bug with fakethreads, which cause fakethreads to be stuck under heavy cpu load. Some test for that case in gideros code was buggy and will be fixed in some future release. Meanwhile I commented out your liquidfun world:step().
    zip
    zip
    Scene-Managerloader.zip
    201K

    Likes: pie

    +1 -1 (+1 / -0 )Share on Facebook
  • Thank you @hgy29, this was exactly was I looking for! =D>

    I didn't get that I had to use 2 distinct asyncCall to switch between those, I thought that the main thread was enough.

    I tried using your scenemanager in my existing project but I get an error:
    scenemanager.lua:298: attempt to index local 'options' (a thread value)
    what is a thread value, and why options is not a table as usual? :)

    However as soon as this works (it works in the example project so I assume there is just some tweak to do) it should be pushed to scenemanager github: it's a golden feature for scenemanager :)
    Thank you again
  • hgy29hgy29 Maintainer
    Technically you don't need two asyncCall, I just kept the one you did to update your progress bar, although it would have been more elegant (IMO) to just call SceneManager.setProgress() or something like that from each scene's init to update the progress bar, instead of relying on an async thread to update it.

    However I don't why your options contains a thread. Threads are returned by Core.asyncCall() they represent the lua view of a fakethread, ie a coroutine.

    Likes: pie

    +1 -1 (+1 / -0 )Share on Facebook
  • talistalis Guru
    edited September 2016
    It is weird but the new modified version of scenemanager is working so much slow in my desktop player. even sometimes stuck in the screen and stop responding for 2-3 seconds. In the non-modified scenemanager(without asynch call) i have no such behavior.
    In addition after changing the scenes 5-6 times screen becomes like this in the attachment. (ss1)
    I made a clean install of new gideros studio and player from the website before posting.
    ss1.jpg
    307 x 414 - 71K
  • piepie Member
    edited September 2016
    I am sorry the reason for the error was a mistype in my scene name -a capital letter! :)

    It works as it should on device, while on laptop it fails to show the scene - which is loaded because I can see its printouts. I will try to figure this out but since it happens on a heavy cpu load scene I wonder if it's better to try this after you manage to fix the fakethreads bug you were speaking about earlier :)
    Thank you
Sign In or Register to comment.