Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Loading textures from StreamingAssets via File.ReadAllBytes/Texture2D.LoadImage is incredibly slow

Discussion in 'Scripting' started by BionicWombatGames, May 12, 2023.

  1. BionicWombatGames

    BionicWombatGames

    Joined:
    Oct 5, 2020
    Posts:
    33
    My game is generating a lot of textures at runtime, and storing them in StreamingAssets for loading later. For loading the textures, I'm using the example setup from the documentation:

    if (File.Exists(path)) {
    fileData = File.ReadAllBytes(path);
    tex = new Texture2D(2, 2);
    tex.LoadImage(fileData);
    }


    The total execution time for loading five 1024 textures via this method is over 60ms! If I create a material with the five textures on it for testing and load the prefab at runtime, the execution time is <1ms. Both methods need to load the texture data, so where is the huge difference coming from? How can I speed things up?
     
  2. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,051
    How do you load the prefab? Most likely it was already loaded when the scene containing a reference to it is loaded.

    Native textures in Unity are already compressed for the GPU and can be immediately uploaded,
    LoadImage
    needs to decode the image, maybe apply some processing and upload it to the GPU, which is going to take longer. Checking with the profiler should give you a better idea where exactly the time is spent.

    Using asset bundles should make the loading more comparable to that of embedded textures, the texture data can then also be directly uploaded to the GPU and Unity can probably offload a bit more to other threads.
     
  3. BionicWombatGames

    BionicWombatGames

    Joined:
    Oct 5, 2020
    Posts:
    33
    Asset Bundles look like they can only be created in the editor, however I am creating my textures (and models) at runtime. Are there other options? Or is there a way to save my textures as native textures?
     
  4. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,140
    I don't believe Unity compresses files in StreamingAssets folder. https://docs.unity3d.com/Manual/StreamingAssets.html
    The unique nature of streamingassets I believe leaves those files all original, thus they don't have import settings.

    That being said, I suggest looking into addressables/asset bundles perhaps. Even the link above mentions those are preferred.
     
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,140
    On most platforms, you can't save to streamingassets (even mentions that in the link). I'm not sure I understand your flow in creating these textures. Where are you getting the data from? Are you downloading something from the internet and saving it locally?
     
  6. BionicWombatGames

    BionicWombatGames

    Joined:
    Oct 5, 2020
    Posts:
    33
    My textures are generated from a couple hundred parameters passed into a complex shader at runtime and then blitted into a png, which I save into StreamingAssets. I don't think AssetBundles or Addressables are right for my use-case as both require pre-configuration in the editor.
     
  7. BionicWombatGames

    BionicWombatGames

    Joined:
    Oct 5, 2020
    Posts:
    33
    Whether StreamingAssets or PersistentDataPath (the recommended alternative), it doesn't really matter either way in my case. I guess the question at this point has really become: is there any way to prepare a PNG for saving at runtime with Unity's compressed image format in order to support fast loading?
     
  8. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,051
    Not a PNG, because that's by definition a different format and not supported by the GPU. There's Texture2D.GetRawTextureData and Texture2D.LoadRawTextureData, which you could use to save the raw texture data but then you'll have to manage the different texture formats manually.

    I also saw UnityAsyncImageLoader, which purportedly does the same as
    ImageConversion.LoadImage
    but is offloading it to another thread (note the troubleshooting question at the bottom about stalling if the texture is accessed too early).