Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Is it worth optimizing multiple bools in a component to a bitmask?

Discussion in 'Entity Component System' started by PhilSA, Aug 16, 2020.

  1. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I have a component that currently holds 14 bool variables. I was wondering if burst is able to automatically optimize this away to 1 bit per bool, instead of 1 byte per bool or even 4 bytes per bool (according to certain sources)?

    If not then I would probably want to store them all in the form of a 2-bytes (16 bit) bitmask. And are there any existing tools in UnityPackages for creating a bitmask from multiple bools?
     
    Last edited: Aug 16, 2020
    deus0 likes this.
  2. Kelevra

    Kelevra

    Joined:
    Dec 27, 2012
    Posts:
    87
    adamgolden, Nyanpas, deus0 and 3 others like this.
  3. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    IComponentData layout is defined by the C# standard. bools are 2 byte large.
    What Kelevra said is good advice.
     
    deus0, MNNoxMortem and PhilSA like this.
  4. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    PhilSA likes this.
  5. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    I think bools are defined as 1 byte in C# (Docs)
    but differ for other languages, e.g. VB (Docs)
     
  6. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    345
  7. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    345
    btw this can be useful :
    Code (CSharp):
    1.  
    2.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    3.         public static bool IsBitSet(byte b, int pos) { return (b & (1 << pos)) != 0; }
    4.  
    5.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    6.         public static bool BitSame(byte b, int posa, int posb) { return (b & (1 << posa)) == (b & (1 << posb)); }
    7.  
    8.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    9.         public static void SetBit(ref byte b, int pos) { b |= (byte)(1 << pos); }
    10.  
    11.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    12.         public static void ClearBit(ref byte b, int pos) { b &= (byte)~(1 << pos); }
    13.  
     
  8. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    PhilSA likes this.
  9. james7132

    james7132

    Joined:
    Mar 6, 2015
    Posts:
    166
    An alternative is to use enums with the Flags attribute instead of a BitField32/64. It also comes with type safety features, lets you define the size of the field, and lets you name each individual flags, which might lend some readability to whatever you are writing.
     
    Peter77 and PhilSA like this.
  10. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    Unity.Collections has several options for this actually:

    NativeBitArray: https://docs.unity3d.com/Packages/c...lections.NativeBitArray.html?q=NativeBitArray

    BitField32: https://docs.unity3d.com/Packages/com.unity.collections@0.12/api/Unity.Collections.BitField32.html
    BitField64: https://docs.unity3d.com/Packages/com.unity.collections@0.12/api/Unity.Collections.BitField64.html

    The nice thing about the BitField* types is you should be able to use Explicit struct layouts to create a union with an ordinary value of the type for serialization. I haven't tested this out myself, but I am looking at getting rid of my custom bit manipulation code in favor of BitField and friends.

    NativeBitArray seems to be an arbitrary sized array, and there's conversion tools for converting a block of data to a NativeBitArray.
     
  11. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    345
    be careful with that:
    " Burst doesn't currently support Enum methods (e.g Enum.HasFlag)"
    https://docs.unity3d.com/Packages/c...s/CSharpLanguageSupport_Types.html#enum-types
     
  12. james7132

    james7132

    Joined:
    Mar 6, 2015
    Posts:
    166
    It seems to support bitwise operations just fine. Casts to and from the underlying type seem to be no-ops when compiled, and it still guarantees a certain level of type safety when reading/writing values. If you are using the flags more widely, resizing it to be larger is easier just by changing the underlying type the flags use. Here's an excerpt of how I structure the flags on my players:

    Code (CSharp):
    1.  
    2. [Flags]
    3. public enum PlayerFlags : byte {
    4.   FACING_LEFT   = 1 << 0,
    5.   GROUNDED      = 1 << 1,
    6.   FAST_FALLING  = 1 << 2,
    7.   TEETERING     = 1 << 3,
    8.   HAS_DIED      = 1 << 4,
    9.   HAS_RESPAWNED = 1 << 5,
    10.   EVENT_FLAGS   = HAS_DIED | HAS_RESPAWNED,
    11. }
    12.  
    13. public struct PlayerComponent : IComponentData {
    14.  
    15.   public PlayerFlags Flags;                   // 1 byte
    16.  
    17.   public bool Is(PlayerFlags mask) => (Flags & mask) != 0;
    18.   public void SetFlags(PlayerFlags mask) => Flags |= mask;
    19.   public void UnsetFlags(PlayerFlags mask) => Flags &= ~mask;
    20. }
    21.