internal VulkanMemorySlice(VulkanMemoryPool originPool, ulong size, ulong offset, ulong alignOffset, VkDeviceMemory vkDeviceMemory, uint memoryTypeIndex, VkMemoryPropertyFlags memoryPropertyFlags)
 {
     this.originPool          = originPool;
     this.memoryTypeIndex     = memoryTypeIndex;
     this.memoryPropertyFlags = memoryPropertyFlags;
     this.vkDeviceMemory      = vkDeviceMemory;
     this.size        = size;
     this.offset      = offset;
     this.alignOffset = alignOffset;
     disposed         = false;
     hostVisible      = (memoryPropertyFlags & VkMemoryPropertyFlags.HostVisible) != 0;
 }
        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);
        }
 private void CreateNext(ulong newSize)
 {
     next = new VulkanMemoryPool(device, newSize, memoryTypeIndex, memoryPropertyFlags, hostVisible);
 }
        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);
        }