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

Unity Web Request texture downloading takes too much memory

Discussion in 'Scripting' started by marcolbx, Apr 13, 2021.

  1. marcolbx

    marcolbx

    Joined:
    Mar 4, 2019
    Posts:
    11
    Hello,

    Background
    I'm currently trying to optimize the memory consumption of an app. We need to download a lot of images.

    Problem:
    1) Try downloading an image (try with png or jpg). I'm currently testing with a 1.4mb image.
    2) After download, the memory went from 20.6 to 26.1mb. Which means that it is taking 5.5mb instead of 1.4mb.

    Could anyone help or provide more insight?
    Thank you in advance.
     
  2. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,058
    Image size on disk is not the same size in memory. This is due to decompression. png / jpg are compressions made for your disk. Whenever you use UWR to download a texture it will decompress it as RGB24 (jpg) or RGB32 (png). Which is an uncompressed large texture, hence your memory usage increasing.

    Whenever you add png's / jpgs to the Editor, Unity converts them to a format that the GPU can use. Such as DXT, ETC2, PVRTC and some others. These have a smaller memory footprint.
     
  3. marcolbx

    marcolbx

    Joined:
    Mar 4, 2019
    Posts:
    11
    What would be a good workaround for this issue? What you are saying makes sense, do you have some link where I could get more info?
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    One option is to store the PNG file locally as an array of bytes, writing it to the local filesystem.

    When you need to show some images, pull them up and "realize" them into Texture2Ds.

    For extra credit you could resize the images into small previews that you show before you load and unpack the real ones.
     
  5. marcolbx

    marcolbx

    Joined:
    Mar 4, 2019
    Posts:
    11
    I believe that I do that already, since I am saving them in the cache. Then I take them after encoding them and lowering their quality.
     
  6. vivekrawat1

    vivekrawat1

    Joined:
    Dec 18, 2020
    Posts:
    4
  7. Gotmachine

    Gotmachine

    Joined:
    Sep 26, 2019
    Posts:
    30
    As said previously, loading png (avoid the lossy jpg format) files will result in uncompressed textures that will use a lot of memory.

    To avoid that, either :
    - Convert your textures beforehand in the appropriate format depending on the target platform (DXT for desktop, ETC/EAC for mobile). The caveat is that this will increase significantly the size of the file compared to png compression, making the download larger/slower, which might or might not be an issue in practice depending on your use case.
    - Keep downloading png files, but compress them on the fly (see Texture2D.Compress()). Caveat is that this add some processing time, and compression quality will be lower.

    Also make sure that you make textures non readable (see the docs), as on most platforms this will cause an additional copy of the texture to be stored in memory.
     
    Bunny83 likes this.
  8. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,525
    Right, using Compress is probably the best option. Though note that if the texture has read / write enabled, you would still have an uncompressed version on the CPU side in your main memory. Compessing to DXT only helps with GPU memory. You can mark a texture as no longer being readable by calling Apply on the texture and set the "makeNoLongerReadable" parameter to true.

    Of course once you did this you can no longer access the texture data on the CPU. So GetPixels would not work anymore as the texture would now only live in GPU memory. So this approach is probably the best when you just want to load ordinary textures externally as you usually do not need to modify them. Of course there are ways to extract texture data from the GPU memory, but it's slow. You have to create a rendertexture, use Graphics.Blit to copy the content on the GPU into the rendertexture and use ReadPixels with the render texture active to read the content into another new Texture2d. There may be other ways now since we have more lowlevel access now to textures. Though in general "downloading" texture data from the GPU to the CPU is generally quite heavy.