unsafe public static BlobAssetReference <T> Create(byte[] data)
        {
            byte *buffer = (byte *)UnsafeUtility.Malloc(sizeof(BlobAssetHeader) + data.Length, 16, Allocator.Persistent);

            fixed(byte *ptr = &data[0])
            {
                UnsafeUtility.MemCpy(buffer + sizeof(BlobAssetHeader), ptr, data.Length);
            }

            BlobAssetHeader *header = (BlobAssetHeader *)buffer;

            *header           = new BlobAssetHeader();
            header->Refcount  = 1;
            header->Allocator = Allocator.Persistent;

            BlobAssetReference <T> assetReference;

            assetReference.m_Ptr = buffer + sizeof(BlobAssetHeader);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            assetReference.m_Safety = AtomicSafetyHandle.Create();
            AtomicSafetyHandle.SetAllowSecondaryVersionWriting(assetReference.m_Safety, false);
            AtomicSafetyHandle.UseSecondaryVersion(ref assetReference.m_Safety);
#endif

            return(assetReference);
        }
        public BlobAssetReference <T> CreateBlobAssetReference <T>(Allocator allocator) where T : struct
        {
            Assert.AreEqual(16, sizeof(BlobAssetHeader));

            long  dataSize = (m_Ptr - m_RootPtr);
            byte *buffer   = (byte *)UnsafeUtility.Malloc(sizeof(BlobAssetHeader) + dataSize, 16, allocator);

            UnsafeUtility.MemCpy(buffer + sizeof(BlobAssetHeader), m_RootPtr, dataSize);

            BlobAssetHeader *header = (BlobAssetHeader *)buffer;

            *header = new BlobAssetHeader();
            header->Refcount  = 1;
            header->Allocator = allocator;

            BlobAssetReference <T> assetReference;

            assetReference.m_Ptr = buffer + sizeof(BlobAssetHeader);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            assetReference.m_Safety = AtomicSafetyHandle.Create();
            AtomicSafetyHandle.SetAllowSecondaryVersionWriting(assetReference.m_Safety, false);
            AtomicSafetyHandle.UseSecondaryVersion(ref assetReference.m_Safety);
#endif

            return(assetReference);
        }
    public static unsafe void WriteBlobAsset <T>(ref BlobAssetReference <T> assetReference, string fileName) where T : struct
    {
        using (BinaryWriter writer = new BinaryWriter(File.Open(ConvertFileName(fileName), FileMode.Create)))
        {
            var assetPtr              = assetReference.GetUnsafePtr();
            BlobAssetHeader *header   = ((BlobAssetHeader *)assetPtr) - 1;
            long             dataSize = header->Length;

            var data = new byte[dataSize];
            fixed(byte *ptr = &data[0])
            {
                UnsafeUtility.MemCpy(ptr, UnsafeUtility.AddressOf(ref assetReference.Value), data.Length);
            }

            writer.Write(data);
            writer.Close();
        }
    }
Example #4
0
        public static BlobAssetReference <T> Create(void *ptr, int length)
        {
            byte *buffer =
                (byte *)UnsafeUtility.Malloc(sizeof(BlobAssetHeader) + length, 16, Allocator.Persistent);

            UnsafeUtility.MemCpy(buffer + sizeof(BlobAssetHeader), ptr, length);

            BlobAssetHeader *header = (BlobAssetHeader *)buffer;

            *header = new BlobAssetHeader();

            header->Length    = length;
            header->Allocator = Allocator.Persistent;

            BlobAssetReference <T> blobAssetReference;

            header->ValidationPtr = blobAssetReference.m_data.m_Ptr = buffer + sizeof(BlobAssetHeader);
            return(blobAssetReference);
        }
Example #5
0
        /// <summary>
        /// Creates a blob asset from a pointer to data and a specified size.
        /// </summary>
        /// <remarks>The blob asset is created in unmanaged memory. Call <see cref="Dispose"/> to free the asset memory
        /// when it is no longer needed. This function can only be used in an [unsafe context].
        /// [unsafe context]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/unsafe-code
        /// </remarks>
        /// <param name="ptr">A pointer to the buffer containing the data to store in the blob asset.</param>
        /// <param name="length">The length of the buffer in bytes.</param>
        /// <returns>A reference to newly created blob asset.</returns>
        /// <seealso cref="BlobBuilder"/>
        public static BlobAssetReference <T> Create(void *ptr, int length)
        {
            byte *buffer =
                (byte *)Memory.Unmanaged.Allocate(sizeof(BlobAssetHeader) + length, 16, Allocator.Persistent);

            UnsafeUtility.MemCpy(buffer + sizeof(BlobAssetHeader), ptr, length);

            BlobAssetHeader *header = (BlobAssetHeader *)buffer;

            *header = new BlobAssetHeader();

            header->Length    = length;
            header->Allocator = Allocator.Persistent;

            // @TODO use 64bit hash
            header->Hash = math.hash(ptr, length);

            BlobAssetReference <T> blobAssetReference;

            blobAssetReference.m_data.m_Align8Union = 0;
            header->ValidationPtr = blobAssetReference.m_data.m_Ptr = buffer + sizeof(BlobAssetHeader);
            return(blobAssetReference);
        }
Example #6
0
        public BlobAssetReference <T> CreateBlobAssetReference <T>(Allocator allocator) where T : struct
        {
            Assert.AreEqual(16, sizeof(BlobAssetHeader));

            long dataSize = (m_Ptr - m_RootPtr);

            Assertions.Assert.IsTrue(dataSize <= 0x7FFFFFFF);

            byte *buffer = (byte *)UnsafeUtility.Malloc(sizeof(BlobAssetHeader) + dataSize, 16, allocator);

            UnsafeUtility.MemCpy(buffer + sizeof(BlobAssetHeader), m_RootPtr, dataSize);

            BlobAssetHeader *header = (BlobAssetHeader *)buffer;

            *header = new BlobAssetHeader();
            header->Length    = (int)dataSize;
            header->Allocator = allocator;

            BlobAssetReference <T> blobAssetReference;

            header->ValidationPtr = blobAssetReference.m_data.m_Ptr = buffer + sizeof(BlobAssetHeader);

            return(blobAssetReference);
        }
        /// <summary>
        /// Completes construction of the blob asset and returns a reference to the asset in unmanaged memory.
        /// </summary>
        /// <remarks>Use the <see cref="BlobAssetReference{T}"/> to access the blob asset. When the asset is no longer
        /// needed, call<see cref="BlobAssetReference{T}.Dispose()"/> to destroy the blob asset and free its allocated
        /// memory.</remarks>
        /// <param name="allocator">The type of memory to allocate. Unless the asset has a very short life span, use
        /// <see cref="Allocator.Persistent"/>.</param>
        /// <typeparam name="T">The data type of the struct used to construct the asset's root. Use the same struct type
        /// that you used when calling <see cref="ConstructRoot{T}"/>.</typeparam>
        /// <returns></returns>
        public BlobAssetReference <T> CreateBlobAssetReference <T>(Allocator allocator) where T : struct
        {
            var offsets      = new NativeArray <int>(m_allocations.Length + 1, Allocator.Temp);
            var sortedAllocs = new NativeArray <SortedIndex>(m_allocations.Length, Allocator.Temp);

            offsets[0] = 0;
            for (int i = 0; i < m_allocations.Length; ++i)
            {
                offsets[i + 1]  = offsets[i] + m_allocations[i].size;
                sortedAllocs[i] = new SortedIndex {
                    p = m_allocations[i].p, index = i
                };
            }
            int dataSize = offsets[m_allocations.Length];

            sortedAllocs.Sort();
            var sortedPatches = new NativeArray <SortedIndex>(m_patches.Length, Allocator.Temp);

            for (int i = 0; i < m_patches.Length; ++i)
            {
                sortedPatches[i] = new SortedIndex {
                    p = (byte *)m_patches[i].offsetPtr, index = i
                }
            }
            ;
            sortedPatches.Sort();

            byte *buffer = (byte *)Memory.Unmanaged.Allocate(sizeof(BlobAssetHeader) + dataSize, 16, allocator);
            byte *data   = buffer + sizeof(BlobAssetHeader);

            for (int i = 0; i < m_allocations.Length; ++i)
            {
                UnsafeUtility.MemCpy(data + offsets[i], m_allocations[i].p, m_allocations[i].size);
            }

            int iAlloc     = 0;
            var allocStart = m_allocations[sortedAllocs[0].index].p;
            var allocEnd   = allocStart + m_allocations[sortedAllocs[0].index].size;

            for (int i = 0; i < m_patches.Length; ++i)
            {
                int  patchIndex = sortedPatches[i].index;
                int *offsetPtr  = (int *)sortedPatches[i].p;

                while (offsetPtr > allocEnd)
                {
                    ++iAlloc;
                    allocStart = m_allocations[sortedAllocs[iAlloc].index].p;
                    allocEnd   = allocStart + m_allocations[sortedAllocs[iAlloc].index].size;
                }

                var patch = m_patches[patchIndex];

                int offsetPtrInData = offsets[sortedAllocs[iAlloc].index] + (int)((byte *)offsetPtr - allocStart);
                int targetPtrInData = offsets[patch.target.allocIndex] + patch.target.offset;

                *(int *)(data + offsetPtrInData) = targetPtrInData - offsetPtrInData;
                if (patch.length != 0)
                {
                    *(int *)(data + offsetPtrInData + 4) = patch.length;
                }
            }

            sortedPatches.Dispose();
            sortedAllocs.Dispose();
            offsets.Dispose();

            BlobAssetHeader *header = (BlobAssetHeader *)buffer;

            *header = new BlobAssetHeader();
            header->Length    = (int)dataSize;
            header->Allocator = allocator;

            // @TODO use 64bit hash
            header->Hash = math.hash(buffer + sizeof(BlobAssetHeader), dataSize);

            BlobAssetReference <T> blobAssetReference;

            blobAssetReference.m_data.m_Align8Union = 0;
            header->ValidationPtr = blobAssetReference.m_data.m_Ptr = buffer + sizeof(BlobAssetHeader);

            return(blobAssetReference);
        }

        void *AllocationToPointer(BlobDataRef blobDataRef)
        {
            return(m_allocations[blobDataRef.allocIndex].p + blobDataRef.offset);
        }

        BlobAllocation EnsureEnoughRoomInChunk(int size, int alignment)
        {
            if (m_currentChunkIndex == -1)
            {
                return(AllocateNewChunk());
            }

            var alloc       = m_allocations[m_currentChunkIndex];
            int startOffset = CollectionHelper.Align(alloc.size, alignment);

            if (startOffset + size > m_chunkSize)
            {
                return(AllocateNewChunk());
            }

            UnsafeUtility.MemClear(alloc.p + alloc.size, startOffset - alloc.size);

            alloc.size = startOffset;
            return(alloc);
        }

        BlobDataRef Allocate(int size, int alignment)
        {
            if (size > m_chunkSize)
            {
                size = CollectionHelper.Align(size, 16);
                var allocIndex = m_allocations.Length;
                var mem        = (byte *)Memory.Unmanaged.Allocate(size, alignment, m_allocator);
                UnsafeUtility.MemClear(mem, size);
                m_allocations.Add(new BlobAllocation {
                    p = mem, size = size
                });
                return(new BlobDataRef {
                    allocIndex = allocIndex, offset = 0
                });
            }

            BlobAllocation alloc = EnsureEnoughRoomInChunk(size, alignment);

            var offset = alloc.size;

            UnsafeUtility.MemClear(alloc.p + alloc.size, size);
            alloc.size += size;
            m_allocations[m_currentChunkIndex] = alloc;
            return(new BlobDataRef {
                allocIndex = m_currentChunkIndex, offset = offset
            });
        }

        BlobAllocation AllocateNewChunk()
        {
            // align size of last chunk to 16 bytes so chunks can be concatenated without breaking alignment
            if (m_currentChunkIndex != -1)
            {
                var currentAlloc = m_allocations[m_currentChunkIndex];
                currentAlloc.size = CollectionHelper.Align(currentAlloc.size, 16);
                m_allocations[m_currentChunkIndex] = currentAlloc;
            }

            m_currentChunkIndex = m_allocations.Length;
            var alloc = new BlobAllocation {
                p = (byte *)Memory.Unmanaged.Allocate(m_chunkSize, 16, m_allocator), size = 0
            };

            m_allocations.Add(alloc);
            return(alloc);
        }
Example #8
0
            public override int GetHashCode()
            {
                BlobAssetHeader *onStack = header;

                return((int)math.hash(&onStack, sizeof(BlobAssetHeader *)));
            }
Example #9
0
 public BlobAssetPtr(BlobAssetHeader *header)
 {
     this.header = header;
 }
 public BlobAssetPtr(BlobAssetHeader *header) => Header = header;
Example #11
0
        public BlobAssetReference <T> CreateBlobAssetReference <T>(Allocator allocator) where T : struct
        {
            Assert.AreEqual(16, sizeof(BlobAssetHeader));
            NativeArray <int> offsets = new NativeArray <int>(m_allocations.Length + 1, m_allocator);

            var sortedAllocs = new NativeArray <SortedIndex>(m_allocations.Length, m_allocator);

            offsets[0] = 0;
            for (int i = 0; i < m_allocations.Length; ++i)
            {
                offsets[i + 1]  = offsets[i] + m_allocations[i].size;
                sortedAllocs[i] = new SortedIndex {
                    p = m_allocations[i].p, index = i
                };
            }
            int dataSize = offsets[m_allocations.Length];

            sortedAllocs.Sort();
            var sortedPatches = new NativeArray <SortedIndex>(m_patches.Length, m_allocator);

            for (int i = 0; i < m_patches.Length; ++i)
            {
                sortedPatches[i] = new SortedIndex {
                    p = (byte *)m_patches[i].offsetPtr, index = i
                }
            }
            ;
            sortedPatches.Sort();

            byte *buffer = (byte *)UnsafeUtility.Malloc(sizeof(BlobAssetHeader) + dataSize, 16, allocator);
            byte *data   = buffer + sizeof(BlobAssetHeader);

            for (int i = 0; i < m_allocations.Length; ++i)
            {
                UnsafeUtility.MemCpy(data + offsets[i], m_allocations[i].p, m_allocations[i].size);
            }

            int iAlloc     = 0;
            var allocStart = m_allocations[sortedAllocs[0].index].p;
            var allocEnd   = allocStart + m_allocations[sortedAllocs[0].index].size;

            for (int i = 0; i < m_patches.Length; ++i)
            {
                int  patchIndex = sortedPatches[i].index;
                int *offsetPtr  = (int *)sortedPatches[i].p;

                while (offsetPtr > allocEnd)
                {
                    ++iAlloc;
                    allocStart = m_allocations[sortedAllocs[iAlloc].index].p;
                    allocEnd   = allocStart + m_allocations[sortedAllocs[iAlloc].index].size;
                }

                var patch = m_patches[patchIndex];

                int offsetPtrInData = offsets[sortedAllocs[iAlloc].index] + (int)((byte *)offsetPtr - allocStart);
                int targetPtrInData = offsets[patch.target.allocIndex] + patch.target.offset;

                *(int *)(data + offsetPtrInData) = targetPtrInData - offsetPtrInData;
                if (patch.length != 0)
                {
                    *(int *)(data + offsetPtrInData + 4) = patch.length;
                }
            }

            sortedPatches.Dispose();
            sortedAllocs.Dispose();

            BlobAssetHeader *header = (BlobAssetHeader *)buffer;

            *header = new BlobAssetHeader();
            header->Length    = (int)dataSize;
            header->Allocator = allocator;

            BlobAssetReference <T> blobAssetReference;

            header->ValidationPtr = blobAssetReference.m_data.m_Ptr = buffer + sizeof(BlobAssetHeader);

            return(blobAssetReference);
        }