Search Unity

Blittable Type to NativeArray<Byte>

Discussion in 'Entity Component System' started by nttLIVE, Apr 22, 2019.

  1. nttLIVE

    nttLIVE

    Joined:
    Sep 13, 2018
    Posts:
    80
    I'm trying to burst compile / optimize my code as much as possible right now and there's one part where I convert Objects (Blittable types) to a NativeArray of bytes.

    Something like this except it returns a NativeArray.
    Code (CSharp):
    1.  
    2.         private byte[] ToByteArray(object value)
    3.         {
    4.             int rawsize = Marshal.SizeOf(value);
    5.             byte[] rawdata = new byte[rawsize];
    6.             GCHandle handle =
    7.                 GCHandle.Alloc(rawdata,
    8.                 GCHandleType.Pinned);
    9.             Marshal.StructureToPtr(value,
    10.                 handle.AddrOfPinnedObject(),
    11.                 false);
    12.             handle.Free();
    13.             return rawdata;
    14.         }
    This is outside of my depth of knowledge regarding programming but I want to learn how does it work exactly and how I can make this happen where it would be compatible with Burst Compile. I'm looking for references on this type of serialization if anyone wants to share.
     
    Last edited: Apr 22, 2019
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    The burst user guide is pretty good and it lists the supported types.

    https://docs.unity3d.com/Packages/com.unity.burst@0.2/manual/index.html.

    Hard to assist right now because you are starting with an approach that won't work, for some higher level goal you haven't told us. It appears like you are trying to do a clever end run around the rules, and that's just not going to work.
     
  3. nttLIVE

    nttLIVE

    Joined:
    Sep 13, 2018
    Posts:
    80
    The burst compiler doesn't support objects or boxing to an object type, because it is a managed type, I get that. The goal is to have for example:

    int i = 2;
    NativeArray<byte> array = ToNativeByteArray(i);

    The variable * i * could be any of the allowed blittable types. What I'm wondering is if something like this is even doable in the context of a Burst Compiled Job, and if so where I could get information as to how to go about this or which approach to take. The higher purpose doesn't seem important to this question.

    But I would love to know what rules I'm going around.
     
    Last edited: Apr 22, 2019
    DragonCoder likes this.
  4. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Convert i to bytes and stick them into the native array. But that makes no sense which is why I asked what is the higher level goal.
     
  5. nttLIVE

    nttLIVE

    Joined:
    Sep 13, 2018
    Posts:
    80
    The question is, to put it as simply as I can, how to convert * i *, which could be any acceptable blittable type to bytes in the context of a Burst Compiled job where * i * is calculated in said Job. I'm not sure if I'm misunderstanding you or you're misunderstanding me.

    The code I posted in the original post clearly doesn't work in a Burst Compiled Job, from the Debug I can see that Marshal.SizeOf tries to use a type Object which is not accepted in Burst. I mean I don't know if this is a ridiculous question to begin with this is out of my knowledge but the goal is that I want to learn about it.

    Saying
    is like answering the question of "How do you cut a banana in a basket" by saying "You cut the banana and then put it in the basket". I still don't know how to cut the banana.
     
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Specifically how you do that is bit shifting. You can find code via google for C# to convert primitives to bytes and back.
     
  7. nttLIVE

    nttLIVE

    Joined:
    Sep 13, 2018
    Posts:
    80
    So you want me to bit shift floats?
     
  8. BrendonSmuts

    BrendonSmuts

    Joined:
    Jun 12, 2017
    Posts:
    86
    Something like this?

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Collections.LowLevel.Unsafe;
    3.  
    4. public static class ByteBufferUtility
    5. {
    6.     public static NativeArray<byte> ConvertToNativeBytes<T>(T value, Allocator allocator)
    7.         where T : unmanaged
    8.     {
    9.         var size = UnsafeUtility.SizeOf<T>();
    10.         var ret = new NativeArray<byte>(size, allocator);
    11.  
    12.         unsafe
    13.         {
    14.             UnsafeUtility.CopyStructureToPtr(ref value, ret.GetUnsafePtr());
    15.         }
    16.  
    17.         return ret;
    18.     }
    19. }
    As per your use case, this will only work for blittable structs (unmanaged constraint)
     
  9. nttLIVE

    nttLIVE

    Joined:
    Sep 13, 2018
    Posts:
    80
    Very nice. That's all I needed.
    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Collections.LowLevel.Unsafe;
    3.  
    4. public static class ByteBufferUtility
    5. {
    6.     public static NativeArray<byte> ConvertToNativeBytes<T>(T value, Allocator allocator) where T : unmanaged
    7.     {
    8.         var size = UnsafeUtility.SizeOf<T>();
    9.         var ret = new NativeArray<byte>(size, allocator);
    10.  
    11.         unsafe
    12.         {
    13.             UnsafeUtility.CopyStructureToPtr(ref value, ret.GetUnsafePtr());
    14.         }
    15.  
    16.         return ret;
    17.     }
    18.  
    19.     public static T ConvertToType<T>(NativeArray<byte> value) where T : unmanaged
    20.     {
    21.         unsafe
    22.         {
    23.             UnsafeUtility.CopyPtrToStructure(value.GetUnsafePtr(), out T item);
    24.             return item;
    25.         }
    26.     }
    27. }
    For the Convert back to Type. I think this is correct but would appreciate if you can confirm.
     
    Seb-1814 likes this.
  10. BrendonSmuts

    BrendonSmuts

    Joined:
    Jun 12, 2017
    Posts:
    86
    What you pasted will work so long as you are certain the buffer you are passing is representative of a serialised T. Maybe you want to at least do some sanity check that the buffer you are passing is the same size as the T you wish to deserialise, though this is not technically necessary.
     
    nttLIVE likes this.
  11. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    You can't allocate native collections in burst. You need to pass in a NativeArray along with some other structure like another native array to track it's length.
     
  12. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    You can allocate native collections in burst jobs with Allocator.Temp on the latest versions of Unity.
     
  13. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Doesn't work on 2019 with burst from the default packages repo. Are you using burst from staging?
     
  14. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    Works for me on 2019.2a11 and burst 1.0.0
    Pretty sure it was meant to work on 2019.1 but I've never tried.
     
  15. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Ah ok it's dispose that doesn't work, it's automatically disposed.
     
  16. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    Dispose works for me fine as well (as long as it was allocated within the job). Though if it automatically disposes, all the better.
     
  17. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Well I assumed it was auto disposing as it wasn't complaining about not being disposed, but in 2019.1 dispose definitely does not work with burst 1.0.0.
     
  18. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    @tertle @snacktime you are both right and wrong partially :)
    - it's automatically disposed - Yes
    - Dispose works for me fine as well - Not for Bursted jobs, coz it's use DisposeSentinel and
    "The IL opcode instruction `IL_0002: ldind.ref args(IL_0001)` is not supported by burst" which used in DisposeSentinel

    - You can allocate native collections in burst jobs with Allocator.Temp - Not all containers, fo example you can't allocate NativeQueue in bursted job coz it's use NativeQueueBlockPoolData and it's managed class type
     
    MNNoxMortem likes this.
  19. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    That makes sense as I forgot I had burst turned off so I could step through some jobs.