What is a native slice?

I understand what a native array is and how to use it. But what is a native slice? Is it just some ‘window’ into another native array? Sort of a virtual array that shares the same memory?

And where does ‘stride set’ come into the native slice? Isn’t a stride usually a space between two rows allowing you to map onto a 1d array that represents 2d data like a rectangle within an image? How to use? I can find no explanation.


I
t seems when the native slice is created here:
public NativeSlice(NativeArray array, int start, int length);
all you give is an offset and length (presumably a virtual window into the native array). But there is no mention of STRIDE here.

Do you construct a 1-row native slice first, then use SliceWithStide() to specify a stride to use for multiple rows?

(Just general overview here, i’m trying to copy a rectangular area of a larger native array which represents ‘2d image data’ into a smaller native array, somehow, with maximum performance. Is a slice the way to do it, or is there a better way, WITHOUT unsafe code/utility?)

Correct.

I think you’re misreading the very poorly worded documentation here. I believe “Returns stride set for Slice” should be read as “Returns [the] stride [that has been] set for [this] Slice”.

The “stride” of an array just refers to the size in bytes of each element in that array, which could be different than the size of the object being held by the array. This has nothing to do with 2d arrays. That documentation is pretty bad though. I’m not sure what SliceWithStride is meant to do just reading the documentation.

You’re probably not going to be able to do this using just a native slice since each row of the target rectangle is not guaranteed to be contiguous in memory. You could make a separate slice for each affected row, though. I don’t know of the performance implications of that.

3 Likes

I’m also pretty new to this (and I see that this was thread last posted to in 2019), but the link below shows some code that appears to use SliceWithStride() to make a slice of just the Red, Green, or Blue pixel data from an image.

Here’s the relevant code:

        m_Data = new Color32[m_WebcamTextureSize.x * m_WebcamTextureSize.y];
        m_NativeColors = new NativeArray<Color32>(m_Data, Allocator.Persistent);

        var slice = new NativeSlice<Color32>(m_NativeColors);
        m_NativeRed = slice.SliceWithStride<byte>(0);
        m_NativeGreen = slice.SliceWithStride<byte>(1);
        m_NativeBlue = slice.SliceWithStride<byte>(2);

That seems like something very useful for an NativeArray of any combination of values.

7 Likes

yeah looking at that code it seems its mostly for slicing up arrays of structs into individual arrays of each component

Keep in mind that this is only done for convenience and no data is moved/copied/packed anywhere. The memory layout of the data is exactly the same as the original array, the slice will just jump a larger distance when indexing it. In the color32 example, acessing item 1 of the “red” slice will return the 4th byte in the underlying color array.

Gracious, you’re right about that documentation. Looking at the reference source and running some tests, the argument to SliceWithStride turns out to be the offset in bytes into the individual NativeArray elements where the particular member of the structure will be found. I mention this because the example happens to look at the individual members of a Color32 structure, which actually are bytes.

I’m working with some Mesh vertex buffers composed of structures that pack a Vector3 and Color32 into 16 bytes (the Vector3’s three floats take up the first 12, and the Color32’s four bytes contribute the final 4). Thus, when I want to access the Vector3 entries and the Color32 entries as though they were in their own arrays, I use this code:

            var verts = new NativeArray<AdvancedVertex>(100000, Allocator.Temp);

            var vertsSlice = new NativeSlice<AdvancedVertex>(verts);
            var points = vertsSlice.SliceWithStride<Vector3>(0);
            var colors = vertsSlice.SliceWithStride<Color32>(12);

            Color32 triColor = UnityEngine.Color.white;

            points[0] = new Vector3(-1, 0, 0);
            points[1] = new Vector3(0, 1, 0);
            points[2] = new Vector3(2, -1, 0);
            colors[0] = triColor;
            colors[1] = triColor;
            colors[2] = triColor;

At Line 5, I provide an offset of 12 bytes, which is the size of the Vector3 that precedes the Color32 in my AdvancedVertex structure. For this to work, you have to be certain of the layout of the structure. To do that, I defined the structure this way:

    [StructLayout(LayoutKind.Sequential)]
    struct AdvancedVertex
    {
        public Vector3 pos;
        public Color32 color;
    }

To avoid hard code, one could replace the 12 with Marshal.SizeOf(typeof(Vector3)), which would also be rather more self-documenting, I think.

Maybe someone will find this useful, so I thought I’d add it.

1 Like

From what I understand, it allows you to take a slice from an array. For example, if you have an array of 10 elements and you only want elements between 2 and 8 then you can specify that in the parameter.

Personally, I actually found this to be slower than just creating a new array and using a for loop with a starting index and length. However, it is much cleaner and more convenient to work with.

That’s not how it’s working for me. I’m finding that it lets you skip elements. So, if your NativeArray contains structs with entries [A, B, C], and you have four of them in your array, the array’s contents in memory would be A0, B0, C0, A1, B1, C1, A2, B2, C2, A3, B3, C3. Entry 0 in the NativeArray would be [A0, B0, C0], and entry 1 would be [A1, B1, C1], and so on. Using a slice, you can access the individual elements as though they were in an array. So you can create a slice that selects the B elements and, in that slice, entry 0 would be [B0], entry 1 would be [B1], and so on.

That’s how it works for me, anyway.

2 Likes