How can I convert bytearrays to floats in computeshader

Hi everyone, I’m struggling up with a speed problem of data parsing. I have a huge byte array, and my code copies a subarray of this with a given starting point and length. After the copying process, I change this into a float. The exact code is below:

for(long i = 0; i < numberOfPoints; i++)
{
    Array.Copy(_message.data, i * _message.point_step, byteSlice, 0, _message.point_step);
    points *= MakePoint(byteSlice, _message.fields);*

}

private Point MakePoint(byte[] bytes, RosMessageTypes.Sensor.PointFieldMsg[] fields)
{
var point = new Point();
for(int i = 0; i < fields.Length; i++)
{
byte[] slice = null;
switch (fields*.name)*
{
case “x”:
slice = new byte[fields_.count * 4];
Array.Copy(bytes, fields.offset, slice, 0, fields.count * 4);
point.position.x = GetValue(slice);
break;
case “y”:
slice = new byte[fields.count * 4];
Array.Copy(bytes, fields.offset, slice, 0, fields.count * 4);
point.position.z = GetValue(slice);
break;
case “z”:
slice = new byte[fields.count * 4];
Array.Copy(bytes, fields.offset, slice, 0, fields.count * 4);
point.position.y = GetValue(slice);
break;
case “intensity”:
slice = new byte[fields.count * 8];
Array.Copy(bytes, fields.offset, slice, 0, fields.count * 8);
point.intensity = (sbyte)Math.Round(GetValue(slice));
break;
case “timestamp”:
break;
case “ring”:
break;
}
}_

return point;
}

float GetValue(byte[] bytes)
{
if (!BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
float result = BitConverter.ToSingle(bytes, 0);
return result;
}
This works quite fast, but the problem is that the byte array can be really huge. The “numberOfPoints” variable can be more than 20,000,000, which cost about more than 1sec for the total process.
So I’m trying to convert this process as a computeShader kernal function. But now the problem goes on with the convertion of byteArrays. I’m a newbie in hlsl and computeShaders and being stuck with this. In addition, I heard that hlsl does not have the “byte” computation implements. So, can anybody give me a solution??

Hey there,

i’ll just throw in my 2 cents here even though they might not answer in the correct way:
I am not sure if your idea of what you are aiming for can even work at all. As far as i can see this you get a pointcloud from ROS (i guess some Laser-scanner for example?) and want to do something with that data.
Problem here is: Even if you move this to a compute shader - you have to do the preprocessing of the data on your cpu. My guess here is that the preprocessing will still take up a lot of time so unless you know that you will have to do a lot of complex calculations to do on that data later on i am not sure if a compute shader will really help you.

But i think your current code itself can be greatly improved upon.

Here are a few points:

Firstly you use a lot of Array.Copy calls.

Given the code i assume that the byte array bytes and slice in your function are not that long (less then 100 length). Given [this discussion on stack overflow][1] it apparently can be faster to use a loop and index-wise assignements here instead. This could then be expanded upon to do the check for your endianess before you copy the data so you can reverse the loop to directly copy the data in the correct order. → less operations if you should ever run in BigEndian

This would also mean that you can reuse your slice variable each run without a new call (which will allocate the memory each time on the stack that the function is called) by simply writing the data into the same array again and again.

A thing that confuses me here is that you create a byte slice of length fields_.count * 4 but then later call float result = BitConverter.ToSingle(bytes, 0); on that same slice. You will never use more than 4 entries of that byte array. Why the option for a higher length?_
However more importantly : You sort through your data and have a string based comparison for each entry in fields. This is slow. Is there a structure to the data? Like a specific order that you can expect your fields to be in? If that was the case you could easily shave of a lot of computational time by directly accessing correct data behaviour just based on the index you have.
On Top of that your current code structure copys a lot of data.
The first one i am not really sure about but if I remember correctly C# passes arrays of primitives as objects (so by reference) but still creates a defensive copy of the complete thing.
So each time you call MakePoint your complete data is copied i think. (even though it is not written there). Why is that you may ask? Iirc then this happens because you as the user can overwrite the reference of an array in a function but C# will not let this happen. If you do an overwrite then in the main function your original array will be preserved.
---------------------
Sorry for the mess of words. I hope something makes sense here and helps you to optimise your code. If you have questions on this feel free to leave a comment, always happy to discuss this.
As i mentioned above it might help to know how the data is arranged if you want to further optimize this.
[1]: .net - Array.Copy vs Buffer.BlockCopy - Stack Overflow