I have a byte array and a Color32() array. The byte array contains color component data, but it cannot be in a Color32() format for various reasons.
I want to do a very fast/fastest possible copy of a rectangular area of that byte array into the Color32() array, which later will be uploaded to a texture. The bytearray represents a much larger rectangle of pixels than the Color32() array, so I only need to copy a subsection.
At present I can do this in a loop myself by constructing new Color32()'s from 4 bytes. But I am wondering is there some API function to do like a fast memcopy or to cast the array or something, so that I can copy between them much faster?
I havenāt done any timed tests so canāt speak to the speed of this, but:
using UnityEngine;
using System.Runtime.InteropServices;
public class StructTest : MonoBehaviour {
// Use this for initialization
void Start () {
var colorBytes = new Color32Bytes();
colorBytes.byteArray = new byte[16] {
255,0,0,255, //red
255,0,0,255, //red
0,255,0,255, //green
255,0,0,255 //red
};
GetComponent<Renderer>().material.SetColor("_Color", colorBytes.colors[2]); // sets color of attached renderer's material to green
}
}
[StructLayout(LayoutKind.Explicit)]
struct Color32Bytes
{
[FieldOffset(0)]
public byte[] byteArray; //4 bytes per color32
[FieldOffset(0)]
public Color32[] colors;
}
What is that code doing? Color32Bytes is some kind of new type which acts both as a byte array and a color32 array, sharing the same memory? I guess that might possibly work, but not much different to Color32(bytearray[ ]).
Wondering mainly if thereās a system function which, at the lower level, is designed for copying memory like this without lots of Unity script being involved, since native functions are faster⦠even if I could just use to copy one row at a time.
It is the C# equivalent of a C/C++ union. Iāve not used it but essentially it is telling the compiler that you want access to a block of memory in various ways, such as by Color32 objects or by sets of four bytes.
Iām sure C# imposes some additional restrictions on it to keep you within managed code boundaries, but essentially that data layout allows you to access it either way.
None of this speaks to what kind of performance you might see under the hood however. Depending on the types, it may be necessary for some very unoptimized byte-level copying to actually take place.
You might also be able to use System.Runtime.InteropServices calls to pin each array and then use Marshal.Copy blast stuff around in memory, and that ought to be pretty close to your basic C/C++ memcpy() style burst transfer mode.
That is outside my knowledge. Sorry. Google is your friend there. I imagine that it depends if UnityScript properly exposes those services in the .NET library.
āUnsafeā was the first thing that popped into my mind too. It lets you play with pointers and memory directly.
Be warned, its called āunsafeā for a reason. Its pretty easy to mess things up if you are not careful. You are basically taking your memory into your own hands.
I saw that too⦠the big problem though is array.copy and blockcopy will not work copying bytes from a byte array to a color32[ ] array. They are different types. You can only blockcopy primitive types. And although array.copy says it will typecast and stuff, it doesnāt work in this case.
Are you sure? Bytes are bytes regardless of data type. As long as itās all sequential in memory and you compute the number of bytes to copy correctly Iād think that ought to work.
Well yes, if you donāt want to be leaking little GCHandle-sized blocks of memory every time you sail through here.
Take a look at some of the docs on the functions involved because before using them āin anger,ā you might want to develop a sense of what you are getting into with it all.
Based on above code and similar code found elsewhere, I came up with this which works in Unity and is legal code (currently, anyway).
You need a āusing System.Runtime.InteropServices;ā at the top of your script. C#
// Cast a byte array as a Color32 array to allow unity to directly upload byte-array data using SetColors32() function to an RGBA texture without having to 'convert' all the byte data from byte to Color32 first.
//You can then just SetPixels32() using the byte array, while still retaining the speed ability of reading/writing bytes instead of Color32's.
void Start () {
byte[] mybytearray = new byte[1000];
object inputObj = mybytearray;
mybytearray[0]=10;
mybytearray[1]=20;
mybytearray[2]=30;
mybytearray[3]=40;
Color32[] mycolors = Convert(mybytearray); //'Cast' byte array as Color32 array
Debug.Log(mycolors[0]); //Should show 10,20,30,40 without having ever copied any data to a separate Color32 array
}
static Color32[] Convert(byte[] input){
//This function is called in order to pass in a byte array and convert it to a Color32 array.
//The 'Converter' type defined below in the struct, is basically just a custom type with a byte array field
//Except that also in that structure, the [FieldOffset] is used to say at what memory location to locate the data for a given field
//Then within that custom type, we have a Color32 field (at this point unused), which happens to map to the same memory location as the byte array, so they share memory
//So if we simply set the byte array to that custom type's byte array, the type's Color32 array will also be pointing to that same memory reference, with no 'copy' of any memory bytes
//So the reference in it to the byte array points to the same mybytearray[] memory as the Color32[] array.
//We then simply return the Color32[] array and hey presto, the byte array has been interpreted as a Color32 array with almost zero overhead.
Converter converter = new Converter();
converter.mybytes = input;
return converter.mycols;
}
[StructLayout(LayoutKind.Explicit)]
struct Converter
{
[FieldOffset(0)]
public byte[] mybytes;
[FieldOffset(0)]
public Color32[] mycols;
}
//Weāre using a Converter-struct that uses some interop-magic to define two fields that map to the same location in memory. Now we can access the same actual memory but using different variable types