Search Unity

UnityWebRequest Lagging Framerate (Loading Texture2D from disk)?

Discussion in 'iOS and tvOS' started by boehmzViacommix, Mar 3, 2018.

  1. boehmzViacommix

    boehmzViacommix

    Joined:
    May 4, 2017
    Posts:
    16
    Our game cannot have all textures loaded at once due to memory constraints. We load them as needed from disk using UnityWebRequest. We have noticed on weaker iOS devices (iPhone 6 has medium lag, iPhone 7 has basically none, iPad 4 freezes for almost half a second) the framerate will lag around the time we start these loads. The lags are not noticeable in the editor and a deep profile from the editor shows no cpu spikes. Profiling a build on iOS device only shows a vague "EarlyUpdate.ExecuteMainThreadJobs" taking up large amounts of cpu time.
    Is it known that a UnityWebRequest loading a large texture can choke the framerate? There isn't any information about what is happening in Unity during the ExecuteMainThreadJobs step, so I'm not sure how to identify what else might be causing this.
     

    Attached Files:

  2. boehmzViacommix

    boehmzViacommix

    Joined:
    May 4, 2017
    Posts:
    16
    From the file system, the hard drive disk
     
  3. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Can you show the code that loads textures?
     
  4. boehmzViacommix

    boehmzViacommix

    Joined:
    May 4, 2017
    Posts:
    16
    Pretty standard code recommended by Unity for UnityWebRequest. See https://docs.unity3d.com/Manual/UnityWebRequest-RetrievingTexture.html

    UnityWebRequest loadingWWW;
    loadingWWW = UnityWebRequestTexture.GetTexture(path, true);

    instance.StartCoroutine(instance.UnityWebRequestDownloadHelper(loadingWWW, completionCallback, progressCallback, errorCallback));



    private IEnumerator UnityWebRequestDownloadHelper (UnityWebRequest loadingWWW, Action<object> completionCallback, Action<float> progressCallback, Action<string> errorCallback) {
    loadingWWW.disposeDownloadHandlerOnDispose = true;

    yield return loadingWWW.SendWebRequest ();

    try {
    if (loadingWWW.isNetworkError || !string.IsNullOrEmpty(loadingWWW.error)) {
    errorCallback (loadingWWW.error );
    loadingWWW.Dispose();
    } else if (loadingWWW.isDone) {
    Profiler.BeginSample("DownloadHandler(texture)"+loadingWWW.url);
    var tex = DownloadHandlerTexture.GetContent(loadingWWW);
    Profiler.EndSample();
    tex.name = loadingWWW.url;
    Profiler.BeginSample("completionCallback(Texture)");
    completionCallback( tex );
    Profiler.EndSample();
    loadingWWW.Dispose();

    } else {
    progressCallback (loadingWWW.downloadProgress);
    }
    } catch (System.Exception e) {
    loadingWWW.Dispose();
    errorCallback (e.Message+"\n"+e.StackTrace);
    }
    }
     
  5. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Are you loading one texture at a time or a bunch of them at the same time?
    Also, is there a difference if you read texture data using File.ReadAllBytes and then call LoadImage() on texture passing those bytes?
     
  6. boehmzViacommix

    boehmzViacommix

    Joined:
    May 4, 2017
    Posts:
    16
    We are loading one at a time (the StartCoroutine for UnityWebRequestDownloadHelper only gets called when we are not loading another texture).
    We have tried File.ReadAllBytes with LoadImage in the past but noticed a big performance spike there as well. Our code has changed somewhat significantly since then so it may be something we try again. But it's frustrating that the UnityWebRequest takes up so much time in one frame when it seems the recommended way to load and I'm not seeing others having this issue (from a google search)
     
  7. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Can try one experiment: skip a couple of frames before calling DownloadHandlerTexture.GetContent() and see what effect it has.
    While UnityWebRequest creates texture in the background (on other thread), some finishing work is done on main thread.
     
  8. boehmzViacommix

    boehmzViacommix

    Joined:
    May 4, 2017
    Posts:
    16
    I put a frame delay between when loadingWWW.isDone is first true and the call to var tex = DownloadHandlerTexture.GetContent(loadingWWW);. There was no difference, still a big spike in framerate that was noticable as if the game would freeze for half a second
     
  9. austintaylorx

    austintaylorx

    Joined:
    Aug 13, 2018
    Posts:
    8
    I am having the same issue, this is almost the exact code from the documentation and I'm still getting lag spikes.
    I'm using a Pixel 2

    Code (CSharp):
    1. using System.Collections;
    2. using PhotoGalleryService;
    3. using UnityEngine;
    4. using UnityEngine.Networking;
    5. using UnityEngine.UI;
    6.  
    7. public class PhotoGalleryWrapper : MonoBehaviour
    8. {
    9.     public RawImage image;
    10.  
    11.     public void UpdateImage()
    12.     {
    13.         StartCoroutine(GetText($"{Application.streamingAssetsPath}/s_design_PlusUltra.png"));
    14.     }
    15.  
    16.     IEnumerator GetText(string uri)
    17.     {
    18.         using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(uri))
    19.         {
    20.             yield return uwr.SendWebRequest();
    21.  
    22.             if (uwr.isNetworkError || uwr.isHttpError)
    23.             {
    24.                 Debug.Log(uwr.error);
    25.             }
    26.             else
    27.             {
    28.                 // Get downloaded asset bundle
    29.                 var text = DownloadHandlerTexture.GetContent(uwr);
    30.                 image.texture = text;
    31.             }
    32.  
    33.         }
    34.     }
    35. }
    36.  
    37.  
     
  10. boehmzViacommix

    boehmzViacommix

    Joined:
    May 4, 2017
    Posts:
    16
    We ended up using third party texture loading libraries that had a much smaller performance spike on load. Couldn't get WebLoader to work well without a framerate hitch
     
  11. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Are you by chance changing scenes after download?
    In such scenario UWR does not keep texture, it only keeps downloaded data and texture is recreated on access.
     
  12. austintaylorx

    austintaylorx

    Joined:
    Aug 13, 2018
    Posts:
    8
    As a follow-up, I was not changing scenes, but I was able to fix the problem by reducing the image size. 2k is about the limit(on a pixel 2), anything above that gives spikes.
     
  13. FeynmanRen100

    FeynmanRen100

    Joined:
    Sep 6, 2013
    Posts:
    22
    @Aurimas-Cernius
    Any updates about the performance spike, this happens to me with Unity 2018.2.13f1.
     
  14. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Unity 2018.2 is no longer supported. If you can showcase the issue in Unity 2019.x release, you can submit a bug for this.