Search Unity

  1. We have added a sub-forum for DOTS Graphics. Please use the new space for related discussions.
    Dismiss Notice

Async Texture2D creation with Jobs

Discussion in 'Data Oriented Technology Stack' started by twfarro, May 8, 2018.

  1. twfarro


    Nov 23, 2013

    I got really excited about the new Jobs system, hoping it would finally let me take UnityEngine objects and methods off the main thread. Specifically, I wanted to load JPG files into Texture2D objects asynchronously, so as not to cause frame halting.

    However, much to my dismay, since Unity Objects are non-blittable, they can't be used in Jobs.

    Currently I am using Texture2D.LoadImage(bytes[]) to create my Texture2Ds from JPG files that are on-disk. I have found no appreciable difference between this and the WWW method in terms of performance.

    Through profiling and holistic debugging, I have determined that it is the LoadImage method that is hogging resources and the main thread, so simply getting the byte array in a different thread won't resolve the performance issue.

    Has anyone found a suitable way to load Texture2D objects off the main thread?
  2. bdovaz


    Dec 10, 2011
    I'm also interested in this.
  3. amarcolina


    Jun 19, 2014
    Since Texture2D.LoadImage performs Jpeg decoding, it might be in your best interest to locate a suitable jpeg decoding library so you can decode the jpeg data on another thread (not within a job). A quick search suggests that might be a good place to start for something you could use to turn that jpeg data into raw pixel data (although there might be a simpler library floating around that would be better). Once you have that raw pixel data, I've found that Texture2D.LoadRawTextureData is an extremely fast way to get that raw pixel data actually loaded into a unity texture.
  4. tertle


    Jan 25, 2011
    I'm not sure if this will help loading textures off disk, it may, but 2018.2 texture2D has a new overload which lets you manipulate textures within jobs.

    public NativeArray<T> GetRawTextureData();

    Just call Texture2D.Apply() on main thread when you're done manipulating to push it to the GPU.

    also has public void LoadRawTextureData(NativeArray<T> data);
    Nyanpas and SugoiDev like this.
  5. Przemyslaw_Zaworski


    Jun 9, 2017
    Basic template for creating procedural textures with new Job system (require Unity 2018.2):

    Code (CSharp):
    1. //
    3. using UnityEngine;
    4. using Unity.Collections;
    5. using Unity.Jobs;
    6. public class image : MonoBehaviour
    7. {
    8.     public int Resolution = 256;
    9.     public GameObject Target;
    10.     JobHandle HandleJob;
    11.     NativeArray<Color32> PixelArray;
    12.     Texture2D Map;
    14.     struct CalculateJob : IJob
    15.     {
    16.         public NativeArray<Color32> Pixels;
    17.         public float Width;
    18.         public float Height;
    19.         public int Dimension;
    20.         public float Timer;
    21.         public void Execute()
    22.         {
    23.             for (int i = 0; i < Pixels.Length; i++)
    24.             {
    25.                 Vector2 uv = new Vector2(Width/Dimension,Height/Dimension);
    26.                 Pixels[i] = new Color32 ((byte)(uv.x*255),(byte)(uv.y*255),(byte)(Timer*255),255) ;
    27.                 Width++;
    28.                 if (Width>=Dimension) Width=0.0f;
    29.                 if ((i+1)%Dimension==0) Height++;
    30.             }
    31.         }
    32.     }
    33.     void Start()
    34.     {
    35.         if (QualitySettings.activeColorSpace==ColorSpace.Gamma)
    36.             Map = new Texture2D(Resolution,Resolution, TextureFormat.RGBA32, false,false);
    37.         else
    38.             Map = new Texture2D(Resolution,Resolution, TextureFormat.RGBA32, false,true);
    39.         Map.wrapMode = TextureWrapMode.Clamp;
    40.         Target.GetComponent<Renderer>().material = new Material(Shader.Find("Unlit/Texture"));
    41.         Target.GetComponent<Renderer>().material.mainTexture = Map;
    42.     }
    44.     void Update()
    45.     {
    46.         PixelArray = Map.GetRawTextureData<Color32>();
    47.         int InitHeight = 0;
    48.         int InitWidth = 0;
    49.         float SetTime = Mathf.Sin(Time.time)*0.5f+0.5f;
    50.         CalculateJob calculate_job = new CalculateJob()
    51.         {
    52.             Pixels = PixelArray,
    53.             Width = InitWidth,
    54.             Height = InitHeight,
    55.             Dimension = Resolution,
    56.             Timer = SetTime
    57.         };
    58.         HandleJob = calculate_job.Schedule();
    59.         Map.Apply(false);
    60.     }
    62.     public void LateUpdate()
    63.     {
    64.         HandleJob.Complete();
    65.     }
    66. }
  6. tteneder


    Unity Technologies

    Feb 22, 2011
    If you have control over the content/images, I'd recommend using Basis Universal compressed texture files.

    It's a format that is superiour to Jpeg/PNG because:
    • similar small in size (fast download)
    • transcodes to GPU friendly format with good performance and up 8x less memory use
    I've written a Unity package for it:

    It's jobified and transcodes off the main thread. The actual GPU upload has to be on the main thread though (Unity constraint)
    FracEdd, Timboc and florianhanke like this.