UnityAsyncImageLoader
UnityAsyncImageLoader copied to clipboard
CreateFromImageAsync Texture2D does not work async / SupportsTextureFormatNative error
@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);
}
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.
@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?
Good call, can you test it and submit a PR for this?
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
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.
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.