Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Showcase PSA: How to stop blocking main thread with Texture.Apply using native plugin

Discussion in 'General Graphics' started by Shinyclef, Feb 25, 2021.

  1. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    502
    Hello,

    "How can I update a texture every frame without paying serious main thread costs?"
    I tried several things to answer this question, and eventually found this git repo:
    https://github.com/iBicha/TextureUpdater
    It's brilliant and so I would like to share it with you as I think there are many people looking for this solution. This is a showcase thread for that repo, it's not mine!

    It uses a native plugin to achieve the following goals, and I quote:
    "1. Upload the data on a rendering thread instead of the Unity Thread using IssuePluginCustomTextureUpdate (so this will be faster, have less locks/dispatch etc)
    2. Zero copy: The data that you prepare gets passed to the rendering system as is (the Graphics API then handles the rest, so that's as fast as can do things)
    "

    I have profiled two cases, both in builds (script debugging enabled). In each case I am updating a 2048x2048 texture every frame by filling a NativeArray<Color32> with random greyscale pixels in a bursted parallel job. I did this to simulate a light pixel workload without taking too much time; it's the apply stage that interests me. Once the array is filled, it is used to update the texture.

    LoadRawTextureData + Texture.Apply:
    upload_2021-2-26_9-52-45.png
    I don't know why it spikes so much, I don't seem to see the spikes in editor runs... but in build those spikes are all from the 'APPLY' profiler marker (code below in the #if UNITY_EDITOR branch, but for this test modified the code to run that branch in build).

    Native Plugin Texture Update:
    upload_2021-2-26_10-6-3.png


    The takeaway I'm getting from these profiling snapshots is that we can completely move the main thread time spent in Apply over to a worker thread. The rendering thread does more work, but this is fine by me.

    There is a known issue with this plugin. Running the optimised native plugin method will crash the editor. Quote from the repo:
    "Because the native thread is calling managed code (to generate the texture), it is causing the editor to hang on domain unload (the second time you press play). The example is currently using Texture2D.LoadRawTextureData in the editor to prevent this issue."
    Thus, you can't get the performance benefit in the editor. At least I don't know how to fix this issue.

    Here is a snippet from the code that shows the editor workaround.
    Code (CSharp):
    1. // NativeArray<Color32> colorBuffer;
    2. #if UNITY_EDITOR
    3.         var tex2d = (Texture2D)texture;
    4.         unsafe
    5.         {
    6.             tex2d.LoadRawTextureData(new IntPtr(colorBuffer.GetUnsafePtr()), colorBuffer.Length * 4);
    7.         }
    8.         tex2d.Apply();
    9. #else
    10.         texture.Update(colorBuffer);
    11. #endif
    Also, I had to figure out how to build a CPP plugin for the first time cause he updated the plugin for all platforms except windows to a newer version, and I wanted to build the updated version for windows too. In my email with the author, he said he made a tool to build CPP plugins for unity easily: https://github.com/iBicha/NativePluginBuilder
    I had already gone through some trouble building it in VS as a windows dll project, so I have attached the windows dll in anyone needs it. It is built for Windows x64. Try using his tool if you need x86? If you do, post it back :D.

    Also maybe please don't go spamming the original author after I dug up his 2 year old repo :D.
    If anyone can figure out a solution to editor crashing, let me know.

    Curious to see if others find this plugin as useful as I do.
    Cheer!
     

    Attached Files:

    Lo-renzo, joshuacwilde and PutridEx like this.
  2. GuitarBro

    GuitarBro

    Joined:
    Oct 9, 2014
    Posts:
    179
    Huh. I've never needed this but it sounds really cool. Bookmarking for later. :)
     
  3. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    502
    I have submitted a bug report (1328779) to hopefully have the editor hanging bug fixed...
     
  4. JSmithIR

    JSmithIR

    Joined:
    Apr 13, 2023
    Posts:
    111
    This package enters in safe mode with the error:
    Library\PackageCache\com.unity.jobs@0.0.7-preview.6\Unity.Jobs\IJobParallelForDeferExtensions.cs(31,85): error CS8377: The type 'U' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'NativeList<T>'
     
  5. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    502
    Last time I checked, the performance gap had closed quite a lot. I wouldn't bother with this plugin anymore unless you have identified a performance bottleneck you really need to improve.
     
    JSmithIR likes this.