//private void Flush(UInt64 start, UInt64 length) {
        //	VkMappedMemoryRange memoryRange = VkMappedMemoryRange.New();
        //	memoryRange.memory = vkMemory;
        //	memoryRange.size = length;
        //	memoryRange.offset = start;

        //	Util.CheckResult(vkFlushMappedMemoryRanges(device.device, 1, ref memoryRange));
        //}


        private void Allocate()
        {
            if (usageHint == BufferMemoryUsageHint.Static)
            {
                bufferUsageFlags |= VkBufferUsageFlags.TransferDst;
            }

            // Create the buffer handle
            VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo(bufferUsageFlags, size);

            bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;
            Util.CheckResult(vkCreateBuffer(device.device, &bufferCreateInfo, null, out vkBuffer));

            // Create the memory backing up the buffer handle
            VkMemoryRequirements memReqs;

            vkGetBufferMemoryRequirements(device.device, vkBuffer, &memReqs);

            var hostVisible = usageHint == BufferMemoryUsageHint.Dynamic;

            memory = device.memoryAllocator.Allocate(memReqs, hostVisible);

            // Attach the memory to the buffer object
            Util.CheckResult(vkBindBufferMemory(device.device, vkBuffer, memory.vkDeviceMemory, memory.offset));
        }
        internal void Return(VulkanMemorySlice returnSlice)
        {
            DebugHelper.AssertThrow <InvalidOperationException>(returnSlice.vkDeviceMemory.Handle == vkDeviceMemory.Handle);

            //First try to merge with existing free slices
            for (int i = 0; i < freeSlices.Count; i++)
            {
                var   slice         = freeSlices[i];
                ulong sizeWithAlign = returnSlice.size + returnSlice.alignOffset;

                if (slice.startIndex == returnSlice.offset + sizeWithAlign)
                {
                    slice.length     += sizeWithAlign;
                    slice.startIndex -= sizeWithAlign;
                    freeSlices[i]     = slice;
                    return;
                }
            }
            //If not possible insert to the list
            FreeSlice newSlice = new FreeSlice()
            {
                length = returnSlice.size + returnSlice.alignOffset, startIndex = returnSlice.offset - returnSlice.alignOffset
            };

            //freeSlices.Add(newSlice);

            //Add and sort in ascending order by length
            for (int i = 0; i < freeSlices.Count; i++)
            {
                if (freeSlices[i].length > newSlice.length)
                {
                    freeSlices.Insert(i, newSlice);
                    return;
                }
            }
            //If largest, add to the end
            freeSlices.Add(newSlice);
        }
        public VkResult Allocate(ulong size, ulong alignment, out VulkanMemorySlice outSlice)
        {
            if (size > max_size)
            {
                CreateNext(size);
                var allocResult = next.AllocateDeviceMemory();
                if (allocResult != VkResult.Success)
                {
                    next     = null;
                    outSlice = null;
                    return(allocResult);
                }
                return(next.Allocate(size, alignment, out outSlice));
            }

            VulkanMemorySlice returnSlice = null;

            for (int i = 0; i < freeSlices.Count; i++)
            {
                FreeSlice slice = freeSlices[i];

                //align the slice to alignment
                uint  align         = slice.startIndex % alignment == 0 ? 0 : ((uint)alignment - ((uint)slice.startIndex % (uint)alignment));
                ulong sizeWithAlign = size + align;

                if (slice.length >= sizeWithAlign)
                {
                    returnSlice = new VulkanMemorySlice(this, size, slice.startIndex + align, align, vkDeviceMemory,
                                                        memoryTypeIndex, memoryPropertyFlags);

                    slice.length     -= sizeWithAlign;
                    slice.startIndex += sizeWithAlign;

                    if (slice.length == 0)
                    {
                        freeSlices.RemoveAt(i);
                    }
                    else
                    {
                        freeSlices[i] = slice;
                    }
                    break;
                }
            }


            if (returnSlice != null)
            {
                outSlice = returnSlice;
                return(VkResult.Success);
            }
            else
            {
                CreateNext(max_size);
                var allocResult = next.AllocateDeviceMemory();
                if (allocResult != VkResult.Success)
                {
                    next     = null;
                    outSlice = null;
                    return(allocResult);
                }
                return(next.Allocate(size, alignment, out outSlice));
            }
        }
        private bool AllocateFromPools(ulong size, ulong alignment, uint memoryTypeBits, VkMemoryPropertyFlags required, VkMemoryPropertyFlags preferred, bool hostVisible, out VulkanMemorySlice allocation)
        {
            var physicalMemoryProperties = device.DeviceMemoryProperties;

            //Match for preferred
            for (int i = 0; i < memoryPools.Count; i++)
            {
                VulkanMemoryPool pool            = memoryPools[i];
                uint             memoryTypeIndex = pool.memoryTypeIndex;

                if (pool.hostVisible != hostVisible)
                {
                    continue;
                }

                //Match memoryTypeIndex of the pool
                if ((((int)memoryTypeBits >> (int)memoryTypeIndex) & 1) == 0)
                {
                    continue;
                }

                // Match required memory properties
                VkMemoryPropertyFlags properties = physicalMemoryProperties.GetMemoryType(memoryTypeIndex).propertyFlags;
                if ((properties & required) != required)
                {
                    continue;
                }
                // Match preferred
                if ((properties & preferred) != preferred)
                {
                    continue;
                }

                var result = pool.Allocate(size, alignment, out allocation);
                if (result != VkResult.Success)
                {
                    continue;
                }
                return(true);
            }

            //Match only required
            for (int i = 0; i < memoryPools.Count; i++)
            {
                VulkanMemoryPool pool            = memoryPools[i];
                uint             memoryTypeIndex = pool.memoryTypeIndex;

                if (pool.hostVisible != hostVisible)
                {
                    continue;
                }

                //Match memoryTypeIndex of the pool
                if ((((int)memoryTypeBits >> (int)memoryTypeIndex) & 1) == 0)
                {
                    continue;
                }

                // Match required memory properties
                VkMemoryPropertyFlags properties = physicalMemoryProperties.GetMemoryType(memoryTypeIndex).propertyFlags;
                if ((properties & required) != required)
                {
                    continue;
                }

                var result = pool.Allocate(size, alignment, out allocation);
                if (result != VkResult.Success)
                {
                    continue;
                }
                return(true);
            }


            allocation = null;
            return(false);
        }