Skip to content

CreateFromImageAsync Texture2D does not work async / SupportsTextureFormatNative error #2

Open

Description

@nickyonge

@Looooong I get the following error when calling CreateFromImageAsync from a thread:

UnityException: SupportsTextureFormatNative can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.

Unity 2020.3.1. AFAIK it's impossible to create a new Texture2D on anything but the main thread? Though that seems to render this whole repo useless, which I hope isn't the case cuz it looks GREAT otherwise!

Here's the full stack trace:

UnityException: SupportsTextureFormatNative can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
UnityEngine.EditorSystemInfo.SupportsTextureFormat (UnityEngine.TextureFormat format) (at <10564ed154d647e194bef4aef8878649>:0)
UnityEngine.SystemInfoShimBase.SupportsTextureFormat (UnityEngine.TextureFormat format) (at <10564ed154d647e194bef4aef8878649>:0)
UnityEngine.SystemInfo.SupportsTextureFormat (UnityEngine.TextureFormat format) (at <10564ed154d647e194bef4aef8878649>:0)
UnityEngine.Texture.ValidateFormat (UnityEngine.TextureFormat format) (at <10564ed154d647e194bef4aef8878649>:0)
UnityEngine.Texture2D..ctor (System.Int32 width, System.Int32 height, UnityEngine.TextureFormat textureFormat, System.Int32 mipCount, System.Boolean linear, System.IntPtr nativeTex) (at <10564ed154d647e194bef4aef8878649>:0)
UnityEngine.Texture2D..ctor (System.Int32 width, System.Int32 height, UnityEngine.TextureFormat textureFormat, System.Int32 mipCount, System.Boolean linear) (at <10564ed154d647e194bef4aef8878649>:0)
AsyncImageLoader+ImageImporter+<CreateNewTextureAsync>d__17.MoveNext () (at Assets/UnityAsyncImageLoader/Runtime/ImageImporter.cs:100)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () (at <eae584ce26bc40229c1b1aa476bfa589>:0)
AsyncImageLoader+<CreateFromImageAsync>d__9.MoveNext () (at Assets/UnityAsyncImageLoader/Runtime/AsyncImageLoader.cs:105)
UnityEngine.Debug:LogException(Exception)
<CreateFromImageAsync>d__9:MoveNext() (at Assets/UnityAsyncImageLoader/Runtime/AsyncImageLoader.cs:108)
System.Threading._ThreadPoolWaitCallback:PerformWaitCallback()

and the method I'm calling it from:

private static async Task<Texture2D> ByteArrayToTexture2D(byte[] bytes)
{
    return await AsyncImageLoader.CreateFromImageAsync(bytes);
}

Activity

  1. Looooong commented on Nov 3, 2021

    @Looooong
    Owner

    Sorry for the late reply. Looks like Unity is going into a way to make multi-threading even more restrictive. You can try to create an empty texture before hand and use the method variants that update the existing texture. I will look further to see what I can do with this.

  2. mdsitton commented on Apr 12, 2022

    @mdsitton

    @Looooong Try converting the Texture2D creation to using GraphicsFormat instead of TextureFormat it's in the UnityEngine.Experimental.Rendering namespace. I find that it bypasses the SupportsTextureFormat call, so maybe it could bypass this error?

  3. Looooong commented on Apr 13, 2022

    @Looooong
    Owner

    Good call, can you test it and submit a PR for this?

  4. mdsitton commented on Apr 13, 2022

    @mdsitton
    UnityException: IsFormatSupported can only be called from the main thread.
    Constructors and field initializers will be executed from the loading thread when loading a scene.
    Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
    UnityEngine.Texture.ValidateFormat (UnityEngine.Experimental.Rendering.GraphicsFormat format, UnityEngine.Experimental.Rendering.FormatUsage usage) (at <1332c534a8a44623b2e5cc943a0b790e>:0)
    UnityEngine.Texture2D.ValidateFormat (UnityEngine.Experimental.Rendering.GraphicsFormat format, System.Int32 width, System.Int32 height) (at <1332c534a8a44623b2e5cc943a0b790e>:0)
    UnityEngine.Texture2D..ctor (System.Int32 width, System.Int32 height, UnityEngine.Experimental.Rendering.GraphicsFormat format, UnityEngine.Experimental.Rendering.TextureCreationFlags flags, System.Int32 mipCount, System.IntPtr nativeTex) (at <1332c534a8a44623b2e5cc943a0b790e>:0)
    UnityEngine.Texture2D..ctor (System.Int32 width, System.Int32 height, UnityEngine.Experimental.Rendering.GraphicsFormat format, System.Int32 mipCount, UnityEngine.Experimental.Rendering.TextureCreationFlags flags) (at <1332c534a8a44623b2e5cc943a0b790e>:0)
    AsyncImageLoader+ImageImporter.CreateNewTextureAsync () (at Library/PackageCache/com.looooong.asyncimageloader@96335b5707/Runtime/ImageImporter.cs:105)
    AsyncImageLoader.CreateFromImageAsync (System.Byte[] data, AsyncImageLoader+LoaderSettings loaderSettings) (at Library/PackageCache/com.looooong.asyncimageloader@96335b5707/Runtime/AsyncImageLoader.cs:105)
    UnityEngine.Debug:LogException(Exception)
    <CreateFromImageAsync>d__9:MoveNext() (at Library/PackageCache/com.looooong.asyncimageloader@96335b5707/Runtime/AsyncImageLoader.cs:108)
    System.Threading._ThreadPoolWaitCallback:PerformWaitCallback()
    

    Just tested it out, and the same error happens. So this doesn't work to fix the issue

  5. mdsitton commented on Apr 13, 2022

    @mdsitton

    Yeah i tried a few other things with the same result. In my game we have a similar library that we put together and we just create the texture2d on the main thread and get GetRawTextureData and give that to a Task to load into without stalling the main thread. The actual calling code isnt async just the internals.

  6. Looooong commented on Dec 15, 2022

    @Looooong
    Owner

    Now that I take a look at the code again, I find it weird, because new Texture2D() constructor is supposed to be called on the same thread as CreateFromImageAsync function. So if we want new Texture2D() to be called on the main thread, we must call CreateFromImageAsync on the main thread as well. I think that you try to call CreateFromImageAsync on a thread other than the main thread.

    Therefore, something like this doesn't work:

      void Start() {
        Task.Run(() => CreateFromImageAsync(data));
      }

    But, this works:

      async void Start() {
        await CreateFromImageAsync(data);
      }

    I tested the wrong way and reproduced the same error message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions