public VulkanMemorySlice Allocate(ulong size, ulong alignment, uint memoryTypeBits, bool hostVisible, bool preferDeviceLocal = true)
        {
            VkMemoryPropertyFlags requiredMemProps  = VkMemoryPropertyFlags.DeviceLocal;
            VkMemoryPropertyFlags preferredMemProps = preferDeviceLocal ? VkMemoryPropertyFlags.None : VkMemoryPropertyFlags.DeviceLocal;

            if (hostVisible)
            {
                requiredMemProps = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent;
            }

            if (AllocateFromPools(size, alignment, memoryTypeBits, requiredMemProps, preferredMemProps, hostVisible, out VulkanMemorySlice allocation))
            {
                return(allocation);
            }

            uint memoryTypeIndex           = GetPreferredMemoryType(memoryTypeBits, requiredMemProps, preferredMemProps);
            VkMemoryPropertyFlags memProps = device.DeviceMemoryProperties.GetMemoryType(memoryTypeIndex).propertyFlags;

            VulkanMemoryPool newMemoryPool = new VulkanMemoryPool(device, PoolSize, memoryTypeIndex, memProps, hostVisible);
            var result = newMemoryPool.AllocateDeviceMemory();

            if (result != VkResult.Success)
            {
                requiredMemProps  = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent;
                preferredMemProps = VkMemoryPropertyFlags.None;
                memoryTypeIndex   = GetPreferredMemoryType(memoryTypeBits, requiredMemProps, preferredMemProps);
                memProps          = device.DeviceMemoryProperties.GetMemoryType(memoryTypeIndex).propertyFlags;
                newMemoryPool     = new VulkanMemoryPool(device, PoolSize, memoryTypeIndex, memProps, hostVisible);
                result            = newMemoryPool.AllocateDeviceMemory();
                if (result != VkResult.Success)
                {
                    throw new OutOfMemoryException(result.ToString());
                }
            }

            memoryPools.Add(newMemoryPool);
            result = newMemoryPool.Allocate(size, alignment, out allocation);

            if (result != VkResult.Success)
            {
                throw new OutOfMemoryException(result.ToString());
            }

            return(allocation);
        }
        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));
            }
        }