-
Notifications
You must be signed in to change notification settings - Fork 489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support native multi-platform non-blocking texture loading #9
Comments
The only alternative I can find is to load and decompress texture files into color arrays in a separate thread, then pass that back to the main thread for LoadImage to consume. Depending on where the bottleneck is, this could be helpful. |
Yeah, I think moving the decoding to a separate thread will remove most of the latency. However, I don't personally have the benchmarks to prove it yet. Then there's three methods to try when loading the image data on the main thread: Texture2D.SetPixels which requires decoding the image and creating the Color array using Unity's Color class. I'm pretty certain we wont see a boost in performance from a PNG or JPEG decoder written in C# though. Texture2D.LoadRawTextureData which takes a formatted byte array. Here's an example of someone decoding an image in C# and loading the raw data. Their numbers seem to indicate that most of the time spent is in decoding the texture data which means that there may be significant performance gains to be had if you did the decoding in an optimized native plugin. Texture2D.CreateExternalTexture This method would require using a native plugin and marshaling a single pointer to the texture data. Here's an example of someone using this technique on iOS. I would assume this is the most efficient method. It'd be great if Unity offered an async texture loading function themselves and there's a feature request open here. For now I think we'll need to settle for one of these options. |
There is one more option, which you've touched on. Internally Unity uses FreeImage library for its texture processing. You can jump into another thread, do all the image work in FreeImage then feed back the results into the main thread for the last mile. We do this with our Collada Importer for Unity for our game's mod tools. You see definite speed increases and non-blocking behaviour. |
@CWolfs that's good to know! Can you explain your process more? I'm about to start a native plugin for texture loading. |
@robertlong Did you found a plugin for async texture loading? I tried @CWolfs method but it requires building the whole FreeImage lib for Android & iOS which is a huge binary, The FreeImage lib wrapper is only supported in unity editor. |
I'm working on the WebGL/WebVR side of glTF tooling now so unfortunately I no longer have the time to look into async texture loading. I wish Unity would include this in their engine and have requested the feature multiple times. They must have image compression in their Android/iOS runtime builds already, we just need access to it. There's also probably much smaller libraries to use for this. I think I remember @bghgary saying he had done some sort of async texture loading for Unity. Perhaps he can lead you in the right direction? |
I have, but it's really old now. It is a native plugin that I wrote for x86, so there is some work to do to make it cross-platform. |
I'm working on a Unity implementation of 3D Tiles and texture loading is by far and away the biggest performance offender. We have identified two potential performance concerns:
Focusing on number 2 for the moment. Our approach is to encode a GPU encoded DDS texture in the glTF file (as per this extension) and load them in unity using LoadRawTextureData (as per this example). The downside of this approach is that we still need to encode both textures in the glTF so that viewers without the DDS extension still work. So we do end up with larger glTF files but they load much more smoothly. Theoretically, the image resources could be external references in the glTF and the loader could then only download the encoding it prefers. Long term it looks like glTF might adopt a universal GPU texture encoding such as Basis KHR_texture_transmission Extension In the mean time, would folks be interested in me adding support to this project for the MSFT_texture_dds extension? |
Related to issue #59 |
Hello, is anyone working on this, because i need it bad, my Unity App sucks because it uses WWW to load a lot of images and ht keeps freezing because of the above problem. Did anyone create a threaded version of it? |
@JohnCopicMS has been looking into it. Do you have any status? |
One thing that helped, is that when using WWW, for example WWW xxx= new WWW("www.example.com/my.jpg") to load a texture, is never use xxx.texture anywhere in your code, not even to check for null, just the act of accessing it will cause it to create the texture on the main thread causing the freeze. Use it exactly like this only https://docs.unity3d.com/ScriptReference/WWW.LoadImageIntoTexture.html I removed all reference to xxx.texture from my code and its WAY faster now, still has a tiny freeze but i dont know if its the texture causing it or something else. |
www is depreciated |
This was an interesting read: https://docs.unity3d.com/Manual/NativePluginInterface.html |
I and my team here at the Institute for Creative Technology are very interested in your adding the MSFT_texture_dds extension, thanks so much for your insight into the texture loading issue |
Dont use WWW but UnityWebRequest for loading textures, it does all decompression in a background thread for you. |
@pmtolk We will be implementing a new extension mechanism for the library #259 and will be adding dds support then. |
Is there any update on this? Not actually using GLTF, but facing the same blocking texture load issue in a project and would be very interested in seeing other solutions. I've explored the manual texture decode in a worker thread, combined with a As far as alternatives go, it seems UnityWebRequestTexture does support background loading of textures as @MephestoKhaan mentioned, but according to the docs only for sRGB color data, not linear colors and data textures, so that's not really a viable solution with PBR in mind. @amenzies Do you have any data on the efficiency of DDS texture loading for larger texture sizes? Also, did you end up finding an intermediate workaround for platforms without GPU support for DDS textures? @CWolfs Is FreeImage built into Unity across all platforms, and is there a "safe" way to access it with the right DllImport keywords? |
@adamkvd, I did run a few quick profiling tests with DDS and CRN compressed textures. My primary use case is loading lots of small textures as part of a 3D Tiles implementation and I have found that performance hitches can mostly be avoided even when using jpg/png compression if the texture size is kept at 256x256 and only one or two textures are loaded at a time. I am using UnityWebRequest as noted above. I've found I can actually load a lot more textures per frame on desktop systems but by limiting to 1 or 2 I can hit 60 FPS on a first generation hololens which is pretty good. I did see some improvements when testing with DDS and CRN but it was quite some time ago and I can't remember how significant the boost was. I think things were leaning slightly in favor of CRN. Could depend on what DDS settings you are using though since there are a lot of options. I'm sure image size makes a big difference here. I have this branch where I added prototype support for loading DDS and CRN if you want to experiment I think I was using this utility to create my CRN files but my understanding is that there is a newer version but that it is a commercial solution. |
As of Unity 2019.3 there's a new |
Do you still have to do "Apply" after you do the SetPixelData? If you do it will still freeze, "Apply" is the big problem because its done on the main thread, if you have a large image it will freeze the engine for a while. |
Does FreeImage work fine with Unity? Here at the company that I work we are trying to implement it on a Unity project but we are having some problems when the image is loaded. |
It works but not entirely out of the box. We noticed there were problems with the red and blue channels being reversed. It seemed it was loading as BGR instead of RGB on some operating systems. We took the source and changed it so it always loads as RGB regardless of operating system. Then this worked great for us on another thread to have non-blocking texture loading. We load the texture in memory using FreeImage then use Unity's You also need to take into account Normal maps yourself. When you know you're trying to load a normal map then you need to ensure the channels are set up right for a normal map on that texture. |
Thanks for the tidbit. That's important. |
…tyGltf Merge in ARES/ares.unity_gltf from ARES-2233-terrain-flattening to ares Squashed commit of the following: commit 73c7e9dfe4724e44a21655cb5151b9323b3b3576 Author: Jason Schutz <jschutz@dignitastechnologies.com> Date: Fri Mar 5 11:49:59 2021 -0500 ARES-2233 moving the BakeMesh out of UnityGltf
hi, i am new to unity and i found this loadimage freezing problem when i upload vrm at runtime. After reading the above comment, using FreeImage look like a good option but i can't find a good source to load FreeImage into my Unity. got error on DLLnotfound. i am running on webgl. i need help pls. |
FreeImage is only used in the UnityEditor. Beyond the editor, you can't use it. All you can do is load the texture using WebGL calls and then reference it in unity using Texture2D.CreateExternalTexture(). I have implemented a basic native plugin for android long ago, but it lacks the support of multiple texture types and managing the lifecycle of textures since they are created beyond unity. |
With the latest updates, I would recommend to use KTX in GLBs. With this format it don't block the mainthread too much :) |
To my knowledge, the current best way to implement this (as of Unity 2022.1) is as follows:
There is no way to avoid the main thread delay caused by It's worth noting that Unity doesn't expose
But it does expose |
Texture2D.LoadImage is slow, can only be ran on the main thread, and blocks the renderer while loading. This is a dealbreaker for a lot of projects, especially those involving VR as dropping frames causes motion sickness.
The text was updated successfully, but these errors were encountered: