Here is sample code for the fastest possible texture processing in Unity ( probably )

Ok, I spent a few days wrestling with it and finally refactored my image processing code to use GetRawTextureData and unsafe code for maximum speed. Must be comfortable with pointers ( C/C++ experience recommended ). Reduced the processing time by 1-2 orders of magnitude. Figured I’d share it in case it helps others.

NativeArrayUnsafeUtility.GetUnsafePtr() was a hidden gem and I’m glad I found it while researching.

I also break down the images into sections and multithread it ( C# tasks ), but that is pretty straight forward, just be sure not to edit the same pixels in multiple threads.

    public struct ColorARGB32
    {
        public byte a;
        public byte r;
        public byte g;
        public byte b;

        public ColorARGB32(byte r, byte g, byte b, byte a)
        {
            this.r = r;
            this.g = g;
            this.b = b;
            this.a = a;
        }
    }
   
   ...
   
       public unsafe ColorARGB32* GetBeginPtr(NativeArray<ColorARGB32> nativeArray)
       {
           return (ColorARGB32*)NativeArrayUnsafeUtility.GetUnsafePtr(nativeArray) + (begin);
       }
        public unsafe ColorARGB32* GetEndPtr(NativeArray<ColorARGB32> nativeArray)
       {
           return (ColorARGB32*)NativeArrayUnsafeUtility.GetUnsafePtr(nativeArray) + (end);
       }


   ...
   
   // Note... texture format HAS to be TextureFormat.ARGB32, consistent with PNG imports
   // recommend always error checking and throw exception if not
   var pixels = myTexture.GetRawTextureData<ColorARGB32>()

   ...
   
   
   ColorARGB32 *d = GetBeginPtr(pixels);
   ColorARGB32 *d_end = GetEndPtr(pixels);
   
   while (d < d_end)
   {
       // process the pixel here...
       // recommend not calling ANY METHODS in here since it is way too slow.
       // C style macros would be very nice here, but sadly not possible as far as I know
       // copy/paste is the devil, but necessary here ( for math functions like clamp, etc )

       d->r = 255;
       d->g = 0;
       d->b = 0;
       d->a = 255;
   
       d++;
   }

Enjoy, and take care :smile:

2 Likes

Now that IL2CPP is a thing, you can include .C / .CPP files directly in your Unity3D project to get some real performance.

Here are some notes on pinning textures in place so you can pass them over to manipulate in native code:

Pinning a texture for manipulation via native code:

Whoo boy, if you thought “unsafe” was unsafe… get out the finger guards and put on the steel-toed boots… THIS IS RAW UNPROTECTED C!!! :slight_smile:

What what what??? I think I just j!zzed my pants ( long time C++ developer here ). For my current purposes, the unsafe raw texture code seems to be good enough ( don’t want to get too greedy ), but c++ directly in Unity is something I will definitely investigate in the future. One downside to C#, even with unsafe code, is that there are no inline methods or any way ( that I know of ) do something macro like, so, the code can get very copy-pastey :P. Right now my needs are relatively simple.

Question re: IL2CPP c/cpp in unity… will will it work for both Windows and Android? I’m doing VR development and plan on supporting Oculus Quest ( Android ).

I’m aware that I could also import DLL’s written in C++, but with the before mentioned Android compatibility, I don’t want the dependencies to get too complicated.

I don’t know the state of IL2CPP on the Windows target. It might. You’d have to test. I know putting a raw C file in for Android works but only in IL2CPP and later versions of Unity. I still just use an AAR file because I have some compiler predefines and just to keep it neat and tidy, even at the cost of the extra gradle build step.

For my KurtMaster2D game collection (they’re all old C games) I just have a DLL builder for Windows, a MacOSX bundle-maker, and Android AAR maker, and an iOS library (.a) file maker. Here’s some notes on doing it in Android:

https://discussions.unity.com/t/781268/2

That lets me use the same basic native code for all targets. All C files are included in various projects or bash scripts or make files to produce the DLL, the AAR, the .bundle and the .a files.

One day I might even get adventurous and break out Emscripten and see if I can convert the ABI to Javascript and get it running in a browser.

Thanks for the info and I’ll look into that in the future. Word of advice re: Emscripten … I worked for a major mobile company on a game and had a web version of the game that utilizes Emscripten, and my advice to you is…

Don’t do it man!

There were so many special cases, debugging was a nightmare, and it was a huge time sink even for a large company with a big budget. Seriously… unless you enjoy pain, resist the nerd itch and don’t take that route. It “works”, but at great cost. For a small developer (assuming), it will never (ever) pay for itself.

If you want to do a few small demos to nerd out, then go for it. If it’s for a game that you are distributing, your resources (aka your time) will be guaranteed to be better used elsewhere.

Sorry for emphasizing my opinion so strongly, but still feeling the trauma years later :smile:

Yeah, that’s my general feeling towards anything in Javascript land, thanks for backing it up.

The only point of KurtMaster2D is that I am able to keep all my old games alive indefinitely, and even develop them further when I feel like it, so Emscripten is a pretty high hurdle to get over. Probably wouldn’t happen until someone paid me to solve a problem for them in Empscripten, and I could cross-apply the knowledge.

1 Like