예제 #1
0
        private unsafe void CreateBuffer()
        {
            var createInfo = new VkBufferCreateInfo
            {
                sType = VkStructureType.BufferCreateInfo,
                flags = VkBufferCreateFlags.None
            };

            for (int i = 0; i < MipLevels; i++)
            {
                var mipmap = GetMipMapDescription(i);
                createInfo.size += (uint)(mipmap.DepthStride * mipmap.Depth * ArraySize);
            }

            createInfo.usage = VkBufferUsageFlags.TransferSrc | VkBufferUsageFlags.TransferDst;

            // Create buffer
            vkCreateBuffer(GraphicsDevice.NativeDevice, &createInfo, null, out NativeBuffer);

            // Allocate and bind memory
            vkGetBufferMemoryRequirements(GraphicsDevice.NativeDevice, NativeBuffer, out var memoryRequirements);

            AllocateMemory(VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, memoryRequirements);

            if (NativeMemory != VkDeviceMemory.Null)
            {
                vkBindBufferMemory(GraphicsDevice.NativeDevice, NativeBuffer, NativeMemory, 0);
            }
        }
예제 #2
0
        public VkBuffer(VkGraphicsDevice gd, ulong sizeInBytes, bool dynamic, VkBufferUsageFlags usage)
        {
            _gd         = gd;
            SizeInBytes = sizeInBytes;
            usage      |= VkBufferUsageFlags.TransferSrc | VkBufferUsageFlags.TransferDst;

            VkBufferCreateInfo bufferCI = VkBufferCreateInfo.New();

            bufferCI.size  = sizeInBytes;
            bufferCI.usage = usage;
            VkResult result = vkCreateBuffer(gd.Device, ref bufferCI, null, out _deviceBuffer);

            CheckResult(result);

            vkGetBufferMemoryRequirements(gd.Device, _deviceBuffer, out VkMemoryRequirements bufferMemoryRequirements);

            VkMemoryBlock memoryToken = gd.MemoryManager.Allocate(
                gd.PhysicalDeviceMemProperties,
                bufferMemoryRequirements.memoryTypeBits,
                VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                dynamic,
                bufferMemoryRequirements.size,
                bufferMemoryRequirements.alignment);

            _memory = memoryToken;
            result  = vkBindBufferMemory(gd.Device, _deviceBuffer, _memory.DeviceMemory, _memory.Offset);
            CheckResult(result);
        }
예제 #3
0
        public VkDeviceBuffer(
            VkRenderContext rc,
            ulong size,
            VkBufferUsageFlags usage,
            VkMemoryPropertyFlags memoryProperties,
            bool dynamic)
        {
            _rc               = rc;
            usage            |= VkBufferUsageFlags.TransferSrc;
            _usage            = usage;
            _memoryProperties = memoryProperties;
            _isDynamic        = dynamic;

            VkBufferCreateInfo bufferCI = VkBufferCreateInfo.New();

            bufferCI.size  = size;
            bufferCI.usage = _usage;
            VkResult result = vkCreateBuffer(rc.Device, ref bufferCI, null, out _buffer);

            CheckResult(result);

            vkGetBufferMemoryRequirements(rc.Device, _buffer, out _bufferMemoryRequirements);
            _bufferCapacity = _bufferMemoryRequirements.size;
            uint          memoryType  = FindMemoryType(rc.PhysicalDevice, _bufferMemoryRequirements.memoryTypeBits, memoryProperties);
            VkMemoryBlock memoryToken = rc.MemoryManager.Allocate(
                memoryType,
                _bufferMemoryRequirements.size,
                _bufferMemoryRequirements.alignment);

            _memory = memoryToken;
            vkBindBufferMemory(rc.Device, _buffer, _memory.DeviceMemory, _memory.Offset);
        }
예제 #4
0
        public VkBuffer(VkGraphicsDevice gd, uint sizeInBytes, BufferUsage usage)
        {
            _gd         = gd;
            SizeInBytes = sizeInBytes;
            Usage       = usage;

            VkBufferUsageFlags vkUsage = VkBufferUsageFlags.TransferSrc | VkBufferUsageFlags.TransferDst;

            if ((usage & BufferUsage.VertexBuffer) == BufferUsage.VertexBuffer)
            {
                vkUsage |= VkBufferUsageFlags.VertexBuffer;
            }
            if ((usage & BufferUsage.IndexBuffer) == BufferUsage.IndexBuffer)
            {
                vkUsage |= VkBufferUsageFlags.IndexBuffer;
            }
            if ((usage & BufferUsage.UniformBuffer) == BufferUsage.UniformBuffer)
            {
                vkUsage |= VkBufferUsageFlags.UniformBuffer;
            }
            if ((usage & BufferUsage.StructuredBufferReadWrite) == BufferUsage.StructuredBufferReadWrite ||
                (usage & BufferUsage.StructuredBufferReadOnly) == BufferUsage.StructuredBufferReadOnly)
            {
                vkUsage |= VkBufferUsageFlags.StorageBuffer;
            }
            if ((usage & BufferUsage.IndirectBuffer) == BufferUsage.IndirectBuffer)
            {
                vkUsage |= VkBufferUsageFlags.IndirectBuffer;
            }

            VkBufferCreateInfo bufferCI = VkBufferCreateInfo.New();

            bufferCI.size  = sizeInBytes;
            bufferCI.usage = vkUsage;
            VkResult result = vkCreateBuffer(gd.Device, ref bufferCI, null, out _deviceBuffer);

            CheckResult(result);

            vkGetBufferMemoryRequirements(gd.Device, _deviceBuffer, out _bufferMemoryRequirements);

            bool hostVisible = (usage & BufferUsage.Dynamic) == BufferUsage.Dynamic ||
                               (usage & BufferUsage.Staging) == BufferUsage.Staging;

            VkMemoryPropertyFlags memoryPropertyFlags =
                hostVisible
                ? VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent
                : VkMemoryPropertyFlags.DeviceLocal;

            VkMemoryBlock memoryToken = gd.MemoryManager.Allocate(
                gd.PhysicalDeviceMemProperties,
                _bufferMemoryRequirements.memoryTypeBits,
                memoryPropertyFlags,
                hostVisible,
                _bufferMemoryRequirements.size,
                _bufferMemoryRequirements.alignment);

            _memory = memoryToken;
            result  = vkBindBufferMemory(gd.Device, _deviceBuffer, _memory.DeviceMemory, _memory.Offset);
            CheckResult(result);
        }
예제 #5
0
        void CreateBuffer(BufferCreateInfo mInfo)
        {
            var info = new VkBufferCreateInfo();

            info.sType       = VkStructureType.BufferCreateInfo;
            info.flags       = mInfo.flags;
            info.size        = mInfo.size;
            info.usage       = mInfo.usage;
            info.sharingMode = mInfo.sharingMode;

            var indicesMarshalled = new NativeArray <uint>(mInfo.queueFamilyIndices);

            info.queueFamilyIndexCount = (uint)indicesMarshalled.Count;
            info.pQueueFamilyIndices   = indicesMarshalled.Address;

            using (indicesMarshalled) {
                var result = Device.Commands.createBuffer(Device.Native, ref info, Device.Instance.AllocationCallbacks, out buffer);
                if (result != VkResult.Success)
                {
                    throw new BufferException(string.Format("Error creating Buffer: {0}", result));
                }
            }

            Flags = mInfo.flags;
            Usage = mInfo.usage;
        }
예제 #6
0
        private unsafe void CreateBuffer()
        {
            var createInfo = new VkBufferCreateInfo
            {
                sType = VkStructureType.BufferCreateInfo,
                flags = VkBufferCreateFlags.None
            };

            createInfo.size = (ulong)ComputeBufferTotalSize();

            createInfo.usage = VkBufferUsageFlags.TransferSrc | VkBufferUsageFlags.TransferDst;

            // Create buffer
            vkCreateBuffer(GraphicsDevice.NativeDevice, &createInfo, null, out NativeBuffer);

            // Allocate and bind memory
            vkGetBufferMemoryRequirements(GraphicsDevice.NativeDevice, NativeBuffer, out var memoryRequirements);

            AllocateMemory(VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, memoryRequirements);

            if (NativeMemory != VkDeviceMemory.Null)
            {
                vkBindBufferMemory(GraphicsDevice.NativeDevice, NativeBuffer, NativeMemory, 0);
            }
        }
예제 #7
0
        //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));
        }
예제 #8
0
파일: Initializers.cs 프로젝트: gomson/vk
        public static VkBufferCreateInfo bufferCreateInfo(
            VkBufferUsageFlags usage,
            ulong size)
        {
            VkBufferCreateInfo bufCreateInfo = VkBufferCreateInfo.New();

            bufCreateInfo.usage = usage;
            bufCreateInfo.size  = size;
            return(bufCreateInfo);
        }
        internal unsafe void AllocateOneTimeUploadBuffer(int size, out UploadBuffer uploadBuffer)
        {
            var bufferCreateInfo = new VkBufferCreateInfo
            {
                sType = VkStructureType.BufferCreateInfo,
                size  = (ulong)size,
                flags = VkBufferCreateFlags.None,
                usage = VkBufferUsageFlags.TransferSrc,
            };

            uploadBuffer = new UploadBuffer
            {
                size = size
            };

            vkCreateBuffer(NativeDevice, &bufferCreateInfo, null, out uploadBuffer.buffer);

            // figure out the memory type
            if (properType == uint.MaxValue)
            {
                VkMemoryPropertyFlags memoryProperties = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent;
                vkGetBufferMemoryRequirements(nativeDevice, uploadBuffer.buffer, out var memoryRequirements);
                vkGetPhysicalDeviceMemoryProperties(NativePhysicalDevice, out var physicalDeviceMemoryProperties);
                var typeBits = memoryRequirements.memoryTypeBits;
                for (uint i = 0; i < physicalDeviceMemoryProperties.memoryTypeCount; i++)
                {
                    if ((typeBits & 1) == 1)
                    {
                        // Type is available, does it match user properties?
                        var memoryType = *(&physicalDeviceMemoryProperties.memoryTypes_0 + i);
                        if ((memoryType.propertyFlags & memoryProperties) == memoryProperties)
                        {
                            properType = i;
                            break;
                        }
                    }
                    typeBits >>= 1;
                }
            }

            var allocateInfo = new VkMemoryAllocateInfo
            {
                sType           = VkStructureType.MemoryAllocateInfo,
                allocationSize  = (ulong)size,
                memoryTypeIndex = properType
            };

            fixed(VkDeviceMemory *nativeUploadBufferMemoryPtr = &uploadBuffer.memory)
            vkAllocateMemory(NativeDevice, &allocateInfo, null, nativeUploadBufferMemoryPtr);

            vkBindBufferMemory(NativeDevice, uploadBuffer.buffer, uploadBuffer.memory, 0);

            fixed(IntPtr *nativeUploadBufferStartPtr = &uploadBuffer.address)
            vkMapMemory(NativeDevice, uploadBuffer.memory, 0, (ulong)size, VkMemoryMapFlags.None, (void **)nativeUploadBufferStartPtr);
        }
예제 #10
0
        /**
         * Create a buffer on the device
         *
         * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)
         * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)
         * @param buffer Pointer to a vk::Vulkan buffer object
         * @param size Size of the buffer in byes
         * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)
         *
         * @return Success if buffer handle and memory have been created and (optionally passed) data has been copied
         */
        public VkResult createBuffer(VkBufferUsageFlagBits usageFlags, VkMemoryPropertyFlagBits memoryPropertyFlags, vksBuffer buffer, ulong size, void *data = null)
        {
            buffer.device = _logicalDevice;

            // Create the buffer handle
            VkBufferCreateInfo bufferCreateInfo = new VkBufferCreateInfo();

            bufferCreateInfo.sType = BufferCreateInfo;
            bufferCreateInfo.usage = usageFlags;
            bufferCreateInfo.size  = size;
            {
                VkBuffer vkBuffer;
                vkCreateBuffer(_logicalDevice, &bufferCreateInfo, null, &vkBuffer);
                buffer.buffer = vkBuffer;
            }

            // Create the memory backing up the buffer handle
            VkMemoryRequirements memReqs;
            VkMemoryAllocateInfo memAlloc = new VkMemoryAllocateInfo();

            memAlloc.sType = MemoryAllocateInfo;
            vkGetBufferMemoryRequirements(_logicalDevice, buffer.buffer, &memReqs);
            memAlloc.allocationSize = memReqs.size;
            // Find a memory type index that fits the properties of the buffer
            memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
            {
                VkDeviceMemory memory;
                vkAllocateMemory(_logicalDevice, &memAlloc, null, &memory);
                buffer.memory = memory;
            }

            buffer.alignment           = memReqs.alignment;
            buffer.size                = memAlloc.allocationSize;
            buffer.usageFlags          = usageFlags;
            buffer.memoryPropertyFlags = memoryPropertyFlags;

            // If a pointer to the buffer data has been passed, map the buffer and copy over the data
            if (data != null)
            {
                buffer.map();
                Unsafe.CopyBlock(buffer.mapped, data, (uint)size);
                buffer.unmap();
            }

            // Initialize a default descriptor that covers the whole buffer size
            buffer.setupDescriptor();

            // Attach the memory to the buffer object
            return(buffer.bind());
        }
예제 #11
0
        private VkBuffer CreateVulkanBuffer()
        {
            _state.ThrowIfDisposedOrDisposing();

            VkBuffer vulkanBuffer;

            var bufferCreateInfo = new VkBufferCreateInfo {
                sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
                size  = Size,
                usage = GetVulkanBufferUsageKind(Kind),
            };

            ThrowExternalExceptionIfNotSuccess(nameof(vkCreateBuffer), vkCreateBuffer(VulkanGraphicsDevice.VulkanDevice, &bufferCreateInfo, pAllocator: null, (ulong *)&vulkanBuffer));

            return(vulkanBuffer);
        }
예제 #12
0
        public static VulkanBuffer DynamicUniform <T>(VulkanContext ctx, int count) where T : struct
        {
            long size = Unsafe.SizeOf <T>() * count;

            VkBufferCreateInfo createInfo = new VkBufferCreateInfo
            {
                sType = VkStructureType.BufferCreateInfo,
                pNext = null,
                size  = (ulong)size,
                usage = VkBufferUsageFlags.UniformBuffer
            };

            VkBuffer buffer;
            VkResult result = vkCreateBuffer(ctx.Device, &createInfo, null, out buffer);

            result.CheckResult();

            VkMemoryRequirements memoryRequirements;

            vkGetBufferMemoryRequirements(ctx.Device, buffer, out memoryRequirements);

            vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties);

            uint memoryTypeIndex = BufferHelper.GetMemoryTypeIndex(memoryRequirements.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, memoryProperties);

            // We require host visible memory so we can map it and write to it directly.
            // We require host coherent memory so that writes are visible to the GPU right after unmapping it.

            VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo()
            {
                sType           = VkStructureType.MemoryAllocateInfo,
                pNext           = null,
                allocationSize  = memoryRequirements.size,
                memoryTypeIndex = memoryTypeIndex
            };

            VkDeviceMemory memory;

            result = vkAllocateMemory(ctx.Device, &memAllocInfo, null, &memory);
            result.CheckResult();

            result = vkBindBufferMemory(ctx.Device, buffer, memory, 0);
            result.CheckResult();

            return(new VulkanBuffer(ctx.Device, ctx.GraphicsCommandPool, buffer, memory, count));
        }
예제 #13
0
        /**
         * Create a buffer on the device
         *
         * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)
         * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)
         * @param size Size of the buffer in byes
         * @param buffer Pointer to the buffer handle acquired by the function
         * @param memory Pointer to the memory handle acquired by the function
         * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)
         *
         * @return Success if buffer handle and memory have been created and (optionally passed) data has been copied
         */
        public VkResult createBuffer(VkBufferUsageFlagBits usageFlags, VkMemoryPropertyFlagBits memoryPropertyFlags, ulong size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = null)
        {
            // Create the buffer handle
            VkBufferCreateInfo bufferCreateInfo = new VkBufferCreateInfo();

            bufferCreateInfo.sType       = BufferCreateInfo;
            bufferCreateInfo.usage       = usageFlags;
            bufferCreateInfo.size        = size;
            bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;
            vkCreateBuffer(LogicalDevice, &bufferCreateInfo, null, buffer);

            // Create the memory backing up the buffer handle
            VkMemoryRequirements memReqs;
            VkMemoryAllocateInfo memAlloc = new VkMemoryAllocateInfo();

            memAlloc.sType = MemoryAllocateInfo;
            vkGetBufferMemoryRequirements(LogicalDevice, *buffer, &memReqs);
            memAlloc.allocationSize = memReqs.size;
            // Find a memory type index that fits the properties of the buffer
            memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
            vkAllocateMemory(LogicalDevice, &memAlloc, null, memory);

            // If a pointer to the buffer data has been passed, map the buffer and copy over the data
            if (data != null)
            {
                IntPtr mapped;
                vkMapMemory(LogicalDevice, *memory, 0, size, 0, &mapped);
                Unsafe.CopyBlock(mapped, data, (uint)size);
                // If host coherency hasn't been requested, do a manual flush to make writes visible
                if ((memoryPropertyFlags & VkMemoryPropertyFlagBits.HostCoherent) == 0)
                {
                    VkMappedMemoryRange mappedRange = new VkMappedMemoryRange();
                    mappedRange.memory = *memory;
                    mappedRange.offset = 0;
                    mappedRange.size   = size;
                    vkFlushMappedMemoryRanges(LogicalDevice, 1, &mappedRange);
                }
                vkUnmapMemory(LogicalDevice, *memory);
            }

            // Attach the memory to the buffer object
            vkBindBufferMemory(LogicalDevice, *buffer, *memory, 0);

            return(VkResult.Success);
        }
예제 #14
0
        void CreateBuffer(long size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, out VkBuffer buffer, out VkDeviceMemory memory)
        {
            var info = new VkBufferCreateInfo();

            info.size        = size;
            info.usage       = usage;
            info.sharingMode = VkSharingMode.Exclusive;

            buffer = new VkBuffer(device, info);

            var allocInfo = new VkMemoryAllocateInfo();

            allocInfo.allocationSize  = buffer.Requirements.size;
            allocInfo.memoryTypeIndex = FindMemoryType(buffer.Requirements.memoryTypeBits, properties);

            memory = new VkDeviceMemory(device, allocInfo);
            buffer.Bind(memory, 0);
        }
예제 #15
0
        /// <summary>
        /// バッファの作成
        /// </summary>
        /// <param name="device"></param>
        /// <param name="physicalDevice"></param>
        /// <param name="bufferSize"></param>
        /// <param name="usageFlags"></param>
        /// <param name="memoryFlags"></param>
        /// <param name="buffer"></param>
        /// <param name="memory"></param>
        public static void CreateBuffer(VkDevice device, VkPhysicalDevice physicalDevice, int bufferSize, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryFlags, out VkBuffer buffer, out VkDeviceMemory memory)
        {
            buffer = null;
            memory = null;
            var bufferCreateInfo = new VkBufferCreateInfo(usageFlags, bufferSize);

            if (VkResult.VK_SUCCESS != VulkanAPI.vkCreateBuffer(device, ref bufferCreateInfo, out buffer))
            {
                return;
            }
            VkMemoryRequirements requirements;

            VulkanAPI.vkGetBufferMemoryRequirements(device, buffer, out requirements);
            if (VkResult.VK_SUCCESS != VulkanAPI.vkAllocateMemory(device, physicalDevice, ref requirements, memoryFlags, out memory))
            {
                return;
            }
            VulkanAPI.vkBindBufferMemory(device, buffer, memory, 0);
        }
        /// <inheritdoc />
        public override VulkanGraphicsBuffer CreateBuffer(GraphicsBufferKind kind, GraphicsResourceCpuAccess cpuAccess, ulong size, ulong alignment = 0, GraphicsMemoryAllocationFlags allocationFlags = GraphicsMemoryAllocationFlags.None)
        {
            var vulkanDevice = Device.VulkanDevice;

            var bufferCreateInfo = new VkBufferCreateInfo {
                sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
                size  = size,
                usage = GetVulkanBufferUsageKind(kind, cpuAccess)
            };

            VkBuffer vulkanBuffer;

            ThrowExternalExceptionIfNotSuccess(nameof(vkCreateBuffer), vkCreateBuffer(vulkanDevice, &bufferCreateInfo, pAllocator: null, (ulong *)&vulkanBuffer));

            VkMemoryRequirements memoryRequirements;

            vkGetBufferMemoryRequirements(vulkanDevice, vulkanBuffer, &memoryRequirements);

            var index = GetBlockCollectionIndex(cpuAccess, memoryRequirements.memoryTypeBits);
            ref readonly var blockCollection = ref _blockCollections[index];
예제 #17
0
        /// <summary>
        /// Creates a new buffer
        /// </summary>
        /// <param name="dev">device</param>
        /// <param name="usage">buffer usage</param>
        /// <param name="flags">buffer creation flags</param>
        /// <param name="size">buffer size</param>
        /// <param name="sharedQueueFamilies">Concurrency mode, or exclusive if empty</param>
        public Buffer(Device dev, VkBufferUsageFlag usage, VkBufferCreateFlag flags, ulong size,
                      params uint[] sharedQueueFamilies)
        {
            Logging.Allocations?.Trace($"Creating {Extensions.FormatFileSize(size)} buffer with usage {usage}");

            Device = dev;
            Size   = size;
            Usage  = usage;
            unsafe
            {
                var pin = sharedQueueFamilies.Length > 0
                    ? GCHandle.Alloc(sharedQueueFamilies, GCHandleType.Pinned)
                    : default(GCHandle);
                try
                {
                    var info = new VkBufferCreateInfo()
                    {
                        SType       = VkStructureType.BufferCreateInfo,
                        PNext       = IntPtr.Zero,
                        Flags       = flags,
                        Size        = size,
                        Usage       = usage,
                        SharingMode =
                            sharedQueueFamilies.Length > 0 ? VkSharingMode.Concurrent : VkSharingMode.Exclusive,
                        QueueFamilyIndexCount = (uint)sharedQueueFamilies.Length,
                        PQueueFamilyIndices   =
                            (uint *)(sharedQueueFamilies.Length > 0
                                ? Marshal.UnsafeAddrOfPinnedArrayElement(sharedQueueFamilies, 0)
                                : IntPtr.Zero).ToPointer()
                    };
                    Handle = dev.Handle.CreateBuffer(&info, Instance.AllocationCallbacks);
                }
                finally
                {
                    if (sharedQueueFamilies.Length > 0)
                    {
                        pin.Free();
                    }
                }
            }
        }
예제 #18
0
        public FDataBuffer(VkDevice device, VkPhysicalDevice physicalDevice, int length, VkBufferUsageFlags usage, VkSharingMode sharingMode)
        {
            this.device = device;

            VkBufferCreateInfo createInfo = VkBufferCreateInfo.New();

            size                   = (ulong)(sizeof(T) * length);
            createInfo.size        = size;
            createInfo.usage       = usage;
            createInfo.sharingMode = sharingMode;

            VkBuffer buffer = VkBuffer.Null;

            Assert(vkCreateBuffer(device, &createInfo, null, &buffer));
            this.Buffer = buffer;

            VkMemoryRequirements memoryRequirements = new VkMemoryRequirements();

            vkGetBufferMemoryRequirements(device, this.Buffer, &memoryRequirements);

            VkPhysicalDeviceMemoryProperties memoryProperties = new VkPhysicalDeviceMemoryProperties();

            vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);

            VkMemoryAllocateInfo allocateInfo = VkMemoryAllocateInfo.New();

            allocateInfo.allocationSize  = memoryRequirements.size;
            allocateInfo.memoryTypeIndex = SelectMemoryType(memoryProperties, memoryRequirements.memoryTypeBits,
                                                            VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);

            VkDeviceMemory memory = new VkDeviceMemory();

            Assert(vkAllocateMemory(device, &allocateInfo, null, &memory));
            Memory = memory;

            Assert(vkBindBufferMemory(device, this.Buffer, memory, 0));

            spanLength = length;
        }
예제 #19
0
        private VkBuffer CreateVulkanBuffer()
        {
            _state.ThrowIfDisposedOrDisposing();

            VkBuffer vulkanBuffer;

            var vulkanGraphicsHeap = VulkanGraphicsHeap;
            var vulkanDeviceMemory = vulkanGraphicsHeap.VulkanDeviceMemory;

            var vulkanGraphicsDevice = vulkanGraphicsHeap.VulkanGraphicsDevice;
            var vulkanDevice         = vulkanGraphicsDevice.VulkanDevice;

            var bufferCreateInfo = new VkBufferCreateInfo {
                sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
                size  = Size,
                usage = GetVulkanBufferUsageKind(vulkanGraphicsHeap.CpuAccess, Kind),
            };

            ThrowExternalExceptionIfNotSuccess(nameof(vkCreateBuffer), vkCreateBuffer(vulkanDevice, &bufferCreateInfo, pAllocator: null, (ulong *)&vulkanBuffer));
            ThrowExternalExceptionIfNotSuccess(nameof(vkBindBufferMemory), vkBindBufferMemory(vulkanDevice, vulkanBuffer, vulkanDeviceMemory, Offset));

            return(vulkanBuffer);
예제 #20
0
        private void createVertexBuffer()
        {
            VkBufferCreateInfo bufferInfo = new VkBufferCreateInfo();

            bufferInfo.sType       = VkStructureType.VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
            bufferInfo.size        = Marshal.SizeOf(vertices[0]) * vertices.Length;
            bufferInfo.usage       = VkBufferUsageFlagBits.VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
            bufferInfo.sharingMode = VkSharingMode.VK_SHARING_MODE_EXCLUSIVE;

            VkResult result = Vulkan.vkCreateBuffer(device, bufferInfo, null, out vertexBuffer);

            if (result != VkResult.VK_SUCCESS)
            {
                throw Program.Throw("failed to create vertex buffer!", result);
            }

            VkMemoryRequirements memRequirements;

            Vulkan.vkGetBufferMemoryRequirements(device, vertexBuffer, out memRequirements);

            VkMemoryAllocateInfo allocInfo = new VkMemoryAllocateInfo();

            allocInfo.sType           = VkStructureType.VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
            allocInfo.allocationSize  = memRequirements.size;
            allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VkMemoryPropertyFlagBits.VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VkMemoryPropertyFlagBits.VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

            result = Vulkan.vkAllocateMemory(device, allocInfo, null, out vertexBufferMemory);
            if (result != VkResult.VK_SUCCESS)
            {
                throw Program.Throw("failed to allocate vertex buffer memory!", result);
            }

            Vulkan.vkBindBufferMemory(device, vertexBuffer, vertexBufferMemory, 0);

            byte[] data;
            Vulkan.vkMapMemory(device, vertexBufferMemory, 0, bufferInfo.size, 0, out data);
            MemoryCopyHelper.Copy(vertices, data, 0, bufferInfo.size);
            Vulkan.vkUnmapMemory(device, vertexBufferMemory);
        }
예제 #21
0
        internal unsafe IntPtr AllocateUploadBuffer(int size, out VkBuffer resource, out int offset)
        {
            // TODO D3D12 thread safety, should we simply use locks?
            if (nativeUploadBuffer == VkBuffer.Null || nativeUploadBufferOffset + size > nativeUploadBufferSize)
            {
                if (nativeUploadBuffer != VkBuffer.Null)
                {
                    vkUnmapMemory(NativeDevice, nativeUploadBufferMemory);
                    Collect(nativeUploadBuffer);
                    Collect(nativeUploadBufferMemory);
                }

                // Allocate new buffer
                // TODO D3D12 recycle old ones (using fences to know when GPU is done with them)
                // TODO D3D12 ResourceStates.CopySource not working?
                nativeUploadBufferSize = Math.Max(4 * 1024 * 1024, size);

                var bufferCreateInfo = new VkBufferCreateInfo
                {
                    sType = VkStructureType.BufferCreateInfo,
                    size  = (ulong)nativeUploadBufferSize,
                    flags = VkBufferCreateFlags.None,
                    usage = VkBufferUsageFlags.TransferSrc,
                };
                vkCreateBuffer(NativeDevice, &bufferCreateInfo, null, out nativeUploadBuffer);
                AllocateMemory(VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);

                fixed(IntPtr *nativeUploadBufferStartPtr = &nativeUploadBufferStart)
                vkMapMemory(NativeDevice, nativeUploadBufferMemory, 0, (ulong)nativeUploadBufferSize, VkMemoryMapFlags.None, (void **)nativeUploadBufferStartPtr);

                nativeUploadBufferOffset = 0;
            }

            // Bump allocate
            resource = nativeUploadBuffer;
            offset   = nativeUploadBufferOffset;
            nativeUploadBufferOffset += size;
            return(nativeUploadBufferStart + offset);
        }
예제 #22
0
        private void EnsureBufferSize(int dataSizeInBytes)
        {
            if (_bufferCapacity < (ulong)dataSizeInBytes)
            {
                VkBufferCreateInfo newBufferCI = VkBufferCreateInfo.New();
                newBufferCI.size  = (ulong)dataSizeInBytes;
                newBufferCI.usage = _usage | VkBufferUsageFlags.TransferDst;
                VkResult result = vkCreateBuffer(_rc.Device, ref newBufferCI, null, out VkBuffer newBuffer);
                CheckResult(result);
                vkGetBufferMemoryRequirements(_rc.Device, newBuffer, out VkMemoryRequirements newMemoryRequirements);

                uint          memoryType = FindMemoryType(_rc.PhysicalDevice, newMemoryRequirements.memoryTypeBits, _memoryProperties);
                VkMemoryBlock newMemory  = _rc.MemoryManager.Allocate(
                    memoryType,
                    newMemoryRequirements.size,
                    newMemoryRequirements.alignment);

                result = vkBindBufferMemory(_rc.Device, newBuffer, newMemory.DeviceMemory, newMemory.Offset);
                CheckResult(result);

                if (_bufferDataSize > 0)
                {
                    VkCommandBuffer copyCmd = _rc.BeginOneTimeCommands();
                    VkBufferCopy    region  = new VkBufferCopy();
                    region.size = _bufferDataSize;
                    vkCmdCopyBuffer(copyCmd, _buffer, newBuffer, 1, ref region);
                    _rc.EndOneTimeCommands(copyCmd, VkFence.Null);
                }

                _rc.MemoryManager.Free(_memory);
                vkDestroyBuffer(_rc.Device, _buffer, null);

                _buffer         = newBuffer;
                _memory         = newMemory;
                _bufferCapacity = (ulong)dataSizeInBytes;
            }
        }
예제 #23
0
        internal unsafe IntPtr AllocateUploadBuffer(int size, out VkBuffer resource, out int offset)
        {
            if (nativeUploadBuffer == VkBuffer.Null)
            {
                // Allocate buffer that will be recycled
                nativeUploadBufferSize = Buffer.UploadBufferSizeInMB * 1024 * 1024;

                var bufferCreateInfo = new VkBufferCreateInfo
                {
                    sType = VkStructureType.BufferCreateInfo,
                    size  = (ulong)nativeUploadBufferSize,
                    flags = VkBufferCreateFlags.None,
                    usage = VkBufferUsageFlags.TransferSrc,
                };
                vkCreateBuffer(NativeDevice, &bufferCreateInfo, null, out nativeUploadBuffer);
                AllocateMemory(VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);

                fixed(IntPtr *nativeUploadBufferStartPtr = &nativeUploadBufferStart)
                vkMapMemory(NativeDevice, nativeUploadBufferMemory, 0, (ulong)nativeUploadBufferSize, VkMemoryMapFlags.None, (void **)nativeUploadBufferStartPtr);

                nativeUploadBufferOffset = 0;
            }

            resource = nativeUploadBuffer;

            // Bump allocate
            lock (uploadBufferLocker)
            {
                if (nativeUploadBufferOffset + size > nativeUploadBufferSize)
                {
                    nativeUploadBufferOffset = 0; // start from the beginning of the buffer
                }
                offset = nativeUploadBufferOffset;
                nativeUploadBufferOffset += size;
                return(nativeUploadBufferStart + offset);
            }
        }
예제 #24
0
        VkBuffer CreateBuffer(VkPhysicalDevice physicalDevice, VkDevice device, object values, VkBufferUsageFlagBits usageFlags, System.Type type)
        {
            var      array  = values as System.Array;
            var      length = (array != null) ? array.Length : 1;
            var      size   = System.Runtime.InteropServices.Marshal.SizeOf(type) * length;
            VkBuffer buffer;
            {
                UInt32 index = 0;
                var    info  = new VkBufferCreateInfo {
                    sType = VkStructureType.BufferCreateInfo
                };
                info.size               = (UInt64)size;
                info.usage              = usageFlags;
                info.sharingMode        = VkSharingMode.Exclusive;
                info.queueFamilyIndices = index;
                //VkBuffer buffer = device.CreateBuffer(ref info);
                vkAPI.vkCreateBuffer(device, &info, null, &buffer).Check();
                info.Free();
            }
            VkDeviceMemory       deviceMemory; // = device.AllocateMemory(ref allocInfo);
            VkMemoryRequirements memoryReq;

            //VkMemoryRequirements memoryReq = device.GetBufferMemoryRequirements(buffer);
            vkAPI.vkGetBufferMemoryRequirements(device, buffer, &memoryReq);
            var allocInfo = new VkMemoryAllocateInfo {
                sType = VkStructureType.MemoryAllocateInfo
            };

            {
                allocInfo.allocationSize = memoryReq.size;
                VkPhysicalDeviceMemoryProperties memoryProperties;
                vkAPI.vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
                allocInfo.memoryTypeIndex = GetMemoryTypeIndex(memoryProperties, memoryReq,
                                                               VkMemoryPropertyFlagBits.HostVisible | VkMemoryPropertyFlagBits.HostCoherent);
                vkAPI.vkAllocateMemory(device, &allocInfo, null, &deviceMemory).Check();
            }
            {
                IntPtr memPtr = IntPtr.Zero;
                vkAPI.vkMapMemory(device, deviceMemory, 0, (UInt64)size, 0, &memPtr).Check();

                if (type == typeof(float))
                {
                    System.Runtime.InteropServices.Marshal.Copy(values as float[], 0, memPtr, length);
                }
                else if (type == typeof(short))
                {
                    System.Runtime.InteropServices.Marshal.Copy(values as short[], 0, memPtr, length);
                }
                else if (type == typeof(AreaUniformBuffer))
                {
                    System.Runtime.InteropServices.Marshal.StructureToPtr(values, memPtr, false);
                    this.vkBuffer       = buffer;
                    this.vkDeviceMemory = deviceMemory;
                    this.uniformSize    = memoryReq.size;
                }

                vkAPI.vkUnmapMemory(device, deviceMemory);
            }
            vkAPI.vkBindBufferMemory(device, buffer, deviceMemory, 0).Check();

            return(buffer);
        }
예제 #25
0
        internal VkTexture(VkGraphicsDevice gd, ref TextureDescription description)
        {
            _gd         = gd;
            _width      = description.Width;
            _height     = description.Height;
            _depth      = description.Depth;
            MipLevels   = description.MipLevels;
            ArrayLayers = description.ArrayLayers;
            bool isCubemap = ((description.Usage) & TextureUsage.Cubemap) == TextureUsage.Cubemap;

            _actualImageArrayLayers = isCubemap
                ? 6 * ArrayLayers
                : ArrayLayers;
            _format       = description.Format;
            Usage         = description.Usage;
            Type          = description.Type;
            SampleCount   = description.SampleCount;
            VkSampleCount = VkFormats.VdToVkSampleCount(SampleCount);
            VkFormat      = VkFormats.VdToVkPixelFormat(Format, (description.Usage & TextureUsage.DepthStencil) == TextureUsage.DepthStencil);

            bool isStaging = (Usage & TextureUsage.Staging) == TextureUsage.Staging;

            if (!isStaging)
            {
                VkImageCreateInfo imageCI = VkImageCreateInfo.New();
                imageCI.mipLevels     = MipLevels;
                imageCI.arrayLayers   = _actualImageArrayLayers;
                imageCI.imageType     = VkFormats.VdToVkTextureType(Type);
                imageCI.extent.width  = Width;
                imageCI.extent.height = Height;
                imageCI.extent.depth  = Depth;
                imageCI.initialLayout = VkImageLayout.Preinitialized;
                imageCI.usage         = VkFormats.VdToVkTextureUsage(Usage);
                imageCI.tiling        = isStaging ? VkImageTiling.Linear : VkImageTiling.Optimal;
                imageCI.format        = VkFormat;

                imageCI.samples = VkSampleCount;
                if (isCubemap)
                {
                    imageCI.flags = VkImageCreateFlags.CubeCompatible;
                }

                uint     subresourceCount = MipLevels * _actualImageArrayLayers * Depth;
                VkResult result           = vkCreateImage(gd.Device, ref imageCI, null, out _optimalImage);
                CheckResult(result);

                vkGetImageMemoryRequirements(gd.Device, _optimalImage, out VkMemoryRequirements memoryRequirements);

                VkMemoryBlock memoryToken = gd.MemoryManager.Allocate(
                    gd.PhysicalDeviceMemProperties,
                    memoryRequirements.memoryTypeBits,
                    VkMemoryPropertyFlags.DeviceLocal,
                    false,
                    memoryRequirements.size,
                    memoryRequirements.alignment);
                _memoryBlock = memoryToken;
                result       = vkBindImageMemory(gd.Device, _optimalImage, _memoryBlock.DeviceMemory, _memoryBlock.Offset);
                CheckResult(result);

                _imageLayouts = new VkImageLayout[subresourceCount];
                for (int i = 0; i < _imageLayouts.Length; i++)
                {
                    _imageLayouts[i] = VkImageLayout.Preinitialized;
                }
            }
            else // isStaging
            {
                uint depthPitch = FormatHelpers.GetDepthPitch(
                    FormatHelpers.GetRowPitch(Width, Format),
                    Height,
                    Format);
                uint stagingSize = depthPitch * Depth;
                for (uint level = 1; level < MipLevels; level++)
                {
                    Util.GetMipDimensions(this, level, out uint mipWidth, out uint mipHeight, out uint mipDepth);

                    depthPitch = FormatHelpers.GetDepthPitch(
                        FormatHelpers.GetRowPitch(mipWidth, Format),
                        mipHeight,
                        Format);

                    stagingSize += depthPitch * mipDepth;
                }
                stagingSize *= ArrayLayers;

                VkBufferCreateInfo bufferCI = VkBufferCreateInfo.New();
                bufferCI.usage = VkBufferUsageFlags.TransferSrc | VkBufferUsageFlags.TransferDst;
                bufferCI.size  = stagingSize;
                VkResult result = vkCreateBuffer(_gd.Device, ref bufferCI, null, out _stagingBuffer);
                CheckResult(result);
                vkGetBufferMemoryRequirements(_gd.Device, _stagingBuffer, out VkMemoryRequirements bufferMemReqs);
                _memoryBlock = _gd.MemoryManager.Allocate(
                    _gd.PhysicalDeviceMemProperties,
                    bufferMemReqs.memoryTypeBits,
                    VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
                    true,
                    bufferMemReqs.size,
                    bufferMemReqs.alignment);

                result = vkBindBufferMemory(_gd.Device, _stagingBuffer, _memoryBlock.DeviceMemory, _memoryBlock.Offset);
                CheckResult(result);
            }

            ClearIfRenderTarget();
        }
예제 #26
0
        /**
         * Load a 2D texture including all mip levels
         *
         * @param filename File to load (supports .ktx and .dds)
         * @param format Vulkan format of the image data stored in the file
         * @param device Vulkan device to create the texture on
         * @param copyQueue Queue used for the texture staging copy commands (must support transfer)
         * @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT)
         * @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
         * @param (Optional) forceLinear Force linear tiling (not advised, defaults to false)
         *
         */
        public void loadFromFile(
            string filename,
            VkFormat format,
            vksVulkanDevice device,
            VkQueue copyQueue,
            VkImageUsageFlagBits imageUsageFlags = VkImageUsageFlagBits.Sampled,
            VkImageLayout imageLayout            = VkImageLayout.ShaderReadOnlyOptimal,
            bool forceLinear = false)
        {
            KtxFile tex2D;

            using (var fs = File.OpenRead(filename)) {
                tex2D = KtxFile.Load(fs, false);
            }

            this.device = device;
            width       = tex2D.Header.PixelWidth;
            height      = tex2D.Header.PixelHeight;
            if (height == 0)
            {
                height = width;
            }
            mipLevels = tex2D.Header.NumberOfMipmapLevels;

            // Get device properites for the requested texture format
            VkFormatProperties formatProperties;

            vkGetPhysicalDeviceFormatProperties(device.PhysicalDevice, format, &formatProperties);

            // Only use linear tiling if requested (and supported by the device)
            // Support for linear tiling is mostly limited, so prefer to use
            // optimal tiling instead
            // On most implementations linear tiling will only support a very
            // limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
            bool useStaging = !forceLinear;

            VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo();

            memAllocInfo.sType = MemoryAllocateInfo;
            VkMemoryRequirements memReqs;

            // Use a separate command buffer for texture loading
            VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true);

            if (useStaging)
            {
                // Create a host-visible staging buffer that contains the raw image data
                VkBuffer       stagingBuffer;
                VkDeviceMemory stagingMemory;

                VkBufferCreateInfo bufferCreateInfo = new VkBufferCreateInfo();
                bufferCreateInfo.sType = BufferCreateInfo;
                bufferCreateInfo.size  = tex2D.GetTotalSize();
                // This buffer is used as a transfer source for the buffer copy
                bufferCreateInfo.usage       = VkBufferUsageFlagBits.TransferSrc;
                bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

                vkCreateBuffer(device.LogicalDevice, &bufferCreateInfo, null, &stagingBuffer);

                // Get memory requirements for the staging buffer (alignment, memory type bits)
                vkGetBufferMemoryRequirements(device.LogicalDevice, stagingBuffer, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;
                // Get memory type index for a host visible buffer
                memAllocInfo.memoryTypeIndex = device.getMemoryType(memReqs.memoryTypeBits,
                                                                    VkMemoryPropertyFlagBits.HostVisible | VkMemoryPropertyFlagBits.HostCoherent);

                vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &stagingMemory);
                vkBindBufferMemory(device.LogicalDevice, stagingBuffer, stagingMemory, 0);

                // Copy texture data into staging buffer
                IntPtr data;
                vkMapMemory(device.LogicalDevice, stagingMemory, 0, memReqs.size, 0, &data);
                byte[] pixelData = tex2D.GetAllTextureData();
                fixed(byte *pixelDataPtr = &pixelData[0])
                {
                    Unsafe.CopyBlock(data, pixelDataPtr, (uint)pixelData.Length);
                }

                vkUnmapMemory(device.LogicalDevice, stagingMemory);

                // Setup buffer copy regions for each mip level
                var  bufferCopyRegions = new List <VkBufferImageCopy>();
                uint offset            = 0;

                for (uint i = 0; i < mipLevels; i++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlagBits.Color;
                    bufferCopyRegion.imageSubresource.mipLevel       = i;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
                    bufferCopyRegion.imageSubresource.layerCount     = 1;
                    bufferCopyRegion.imageExtent.width  = tex2D.Faces[0].Mipmaps[i].Width;
                    bufferCopyRegion.imageExtent.height = tex2D.Faces[0].Mipmaps[i].Height;
                    bufferCopyRegion.imageExtent.depth  = 1;
                    bufferCopyRegion.bufferOffset       = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    offset += tex2D.Faces[0].Mipmaps[i].SizeInBytes;
                }

                // Create optimal tiled target image
                VkImageCreateInfo imageCreateInfo = new VkImageCreateInfo();
                imageCreateInfo.sType         = ImageCreateInfo;
                imageCreateInfo.imageType     = VkImageType._2d;
                imageCreateInfo.format        = format;
                imageCreateInfo.mipLevels     = mipLevels;
                imageCreateInfo.arrayLayers   = 1;
                imageCreateInfo.samples       = VkSampleCountFlagBits._1;
                imageCreateInfo.tiling        = VkImageTiling.Optimal;
                imageCreateInfo.sharingMode   = VkSharingMode.Exclusive;
                imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                imageCreateInfo.extent        = new VkExtent3D {
                    width = width, height = height, depth = 1
                };
                imageCreateInfo.usage = imageUsageFlags;
                // Ensure that the TRANSFER_DST bit is set for staging
                if ((imageCreateInfo.usage & VkImageUsageFlagBits.TransferDst) == 0)
                {
                    imageCreateInfo.usage |= VkImageUsageFlagBits.TransferDst;
                }
                {
                    VkImage vkImage;
                    vkCreateImage(device.LogicalDevice, &imageCreateInfo, null, &vkImage);
                    this.image = vkImage;
                }

                vkGetImageMemoryRequirements(device.LogicalDevice, image, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;

                memAllocInfo.memoryTypeIndex = device.getMemoryType(memReqs.memoryTypeBits,
                                                                    VkMemoryPropertyFlagBits.DeviceLocal);
                {
                    VkDeviceMemory memory;
                    vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &memory);
                    this.deviceMemory = memory;
                }
                vkBindImageMemory(device.LogicalDevice, image, deviceMemory, 0);

                VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();
                subresourceRange.aspectMask   = VkImageAspectFlagBits.Color;
                subresourceRange.baseMipLevel = 0;
                subresourceRange.levelCount   = mipLevels;
                subresourceRange.layerCount   = 1;

                // Image barrier for optimal image (target)
                // Optimal image will be used as destination for the copy
                Tools.setImageLayout(
                    copyCmd,
                    image,
                    VkImageAspectFlagBits.Color,
                    VkImageLayout.Undefined,
                    VkImageLayout.TransferDstOptimal,
                    subresourceRange);

                // Copy mip levels from staging buffer
                fixed(VkBufferImageCopy *pointer = bufferCopyRegions.ToArray())
                {
                    vkCmdCopyBufferToImage(
                        copyCmd,
                        stagingBuffer,
                        image,
                        VkImageLayout.TransferDstOptimal,
                        (UInt32)bufferCopyRegions.Count,
                        pointer);
                }

                // Change texture image layout to shader read after all mip levels have been copied
                this.imageLayout = imageLayout;
                Tools.setImageLayout(
                    copyCmd,
                    image,
                    VkImageAspectFlagBits.Color,
                    VkImageLayout.TransferDstOptimal,
                    imageLayout,
                    subresourceRange);

                device.flushCommandBuffer(copyCmd, copyQueue);

                // Clean up staging resources
                vkFreeMemory(device.LogicalDevice, stagingMemory, null);
                vkDestroyBuffer(device.LogicalDevice, stagingBuffer, null);
            }
            else
            {
                throw new NotImplementedException();

                /*
                 * // Prefer using optimal tiling, as linear tiling
                 * // may support only a small set of features
                 * // depending on implementation (e.g. no mip maps, only one layer, etc.)
                 *
                 * // Check if this support is supported for linear tiling
                 * Debug.Assert((formatProperties.linearTilingFeatures & VkFormatFeatureFlags.SampledImage) != 0);
                 *
                 * VkImage mappableImage;
                 * VkDeviceMemory mappableMemory;
                 *
                 * VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                 * imageCreateInfo.imageType = VkImageType._2d;
                 * imageCreateInfo.format = format;
                 * imageCreateInfo.extent = new VkExtent3D { width = width, height = height, depth = 1 };
                 * imageCreateInfo.mipLevels = 1;
                 * imageCreateInfo.arrayLayers = 1;
                 * imageCreateInfo.samples = VkSampleCountFlags._1;
                 * imageCreateInfo.tiling = VkImageTiling.Linear;
                 * imageCreateInfo.usage = imageUsageFlags;
                 * imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                 * imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                 *
                 * // Load mip map level 0 to linear tiling image
                 * Util.CheckResult(vkCreateImage(device.LogicalDevice, &imageCreateInfo, null, &mappableImage));
                 *
                 * // Get memory requirements for this image
                 * // like size and alignment
                 * vkGetImageMemoryRequirements(device.LogicalDevice, mappableImage, &memReqs);
                 * // Set memory allocation size to required memory size
                 * memAllocInfo.allocationSize = memReqs.size;
                 *
                 * // Get memory type that can be mapped to host memory
                 * memAllocInfo.memoryTypeIndex = device.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
                 *
                 * // Allocate host memory
                 * Util.CheckResult(vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &mappableMemory));
                 *
                 * // Bind allocated image for use
                 * Util.CheckResult(vkBindImageMemory(device.LogicalDevice, mappableImage, mappableMemory, 0));
                 *
                 * // Get sub resource layout
                 * // Mip map count, array layer, etc.
                 * VkImageSubresource subRes = new VkImageSubresource();
                 * subRes.aspectMask = VkImageAspectFlags.Color;
                 * subRes.mipLevel = 0;
                 *
                 * VkSubresourceLayout subResLayout;
                 * void* data;
                 *
                 * // Get sub resources layout
                 * // Includes row pitch, size offsets, etc.
                 * vkGetImageSubresourceLayout(device.LogicalDevice, mappableImage, &subRes, &subResLayout);
                 *
                 * // Map image memory
                 * Util.CheckResult(vkMapMemory(device.LogicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
                 *
                 * // Copy image data into memory
                 * memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size());
                 *
                 * vkUnmapMemory(device.LogicalDevice, mappableMemory);
                 *
                 * // Linear tiled images don't need to be staged
                 * // and can be directly used as textures
                 * image = mappableImage;
                 * deviceMemory = mappableMemory;
                 * imageLayout = imageLayout;
                 *
                 * // Setup image memory barrier
                 * vks::tools::setImageLayout(copyCmd, image, VkImageAspectFlags.Color, VkImageLayout.Undefined, imageLayout);
                 *
                 * device.flushCommandBuffer(copyCmd, copyQueue);
                 */
            }

            // Create a defaultsampler
            VkSamplerCreateInfo samplerCreateInfo = new VkSamplerCreateInfo();

            samplerCreateInfo.sType        = SamplerCreateInfo;
            samplerCreateInfo.magFilter    = VkFilter.Linear;
            samplerCreateInfo.minFilter    = VkFilter.Linear;
            samplerCreateInfo.mipmapMode   = VkSamplerMipmapMode.Linear;
            samplerCreateInfo.addressModeU = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.addressModeV = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.addressModeW = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.mipLodBias   = 0.0f;
            samplerCreateInfo.compareOp    = VkCompareOp.Never;
            samplerCreateInfo.minLod       = 0.0f;
            // Max level-of-detail should match mip level count
            samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f;
            // Enable anisotropic filtering
            samplerCreateInfo.maxAnisotropy    = 8;
            samplerCreateInfo.anisotropyEnable = true;
            samplerCreateInfo.borderColor      = VkBorderColor.FloatOpaqueWhite;
            {
                VkSampler vkSampler;
                vkCreateSampler(device.LogicalDevice, &samplerCreateInfo, null, &vkSampler);
                this.sampler = vkSampler;
            }

            // Create image view
            // Textures are not directly accessed by the shaders and
            // are abstracted by image views containing additional
            // information and sub resource ranges
            VkImageViewCreateInfo viewCreateInfo = new VkImageViewCreateInfo();

            viewCreateInfo.sType      = ImageViewCreateInfo;
            viewCreateInfo.viewType   = VkImageViewType._2d;
            viewCreateInfo.format     = format;
            viewCreateInfo.components = new VkComponentMapping {
                r = VkComponentSwizzle.R,
                g = VkComponentSwizzle.G,
                b = VkComponentSwizzle.B,
                a = VkComponentSwizzle.A
            };
            viewCreateInfo.subresourceRange = new VkImageSubresourceRange {
                aspectMask   = VkImageAspectFlagBits.Color,
                baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1
            };
            // Linear tiling usually won't support mip maps
            // Only set mip map count if optimal tiling is used
            viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1;
            viewCreateInfo.image = image;
            {
                VkImageView vkImageView;
                vkCreateImageView(device.LogicalDevice, &viewCreateInfo, null, &vkImageView);
                this.view = vkImageView;
            }

            // Update descriptor image info member that can be used for setting up descriptor sets
            updateDescriptor();
        }
예제 #27
0
        private void CopyDataSingleStagingBuffer(IntPtr pixelsFront, IntPtr pixelsBack, IntPtr pixelsLeft, IntPtr pixelsRight, IntPtr pixelsTop, IntPtr pixelsBottom, VkMemoryRequirements memReqs)
        {
            VkBufferCreateInfo bufferCI = VkBufferCreateInfo.New();

            bufferCI.size  = memReqs.size;
            bufferCI.usage = VkBufferUsageFlags.TransferSrc;
            vkCreateBuffer(_device, ref bufferCI, null, out VkBuffer stagingBuffer);

            vkGetBufferMemoryRequirements(_device, stagingBuffer, out VkMemoryRequirements stagingMemReqs);
            VkMemoryBlock stagingMemory = _memoryManager.Allocate(
                FindMemoryType(
                    _physicalDevice,
                    stagingMemReqs.memoryTypeBits,
                    VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent),
                stagingMemReqs.size,
                stagingMemReqs.alignment);

            VkResult result = vkBindBufferMemory(_device, stagingBuffer, stagingMemory.DeviceMemory, 0);

            CheckResult(result);

            StackList <IntPtr, Size6IntPtr> faces = new StackList <IntPtr, Size6IntPtr>();

            faces.Add(pixelsRight);
            faces.Add(pixelsLeft);
            faces.Add(pixelsTop);
            faces.Add(pixelsBottom);
            faces.Add(pixelsBack);
            faces.Add(pixelsFront);

            for (uint i = 0; i < 6; i++)
            {
                VkImageSubresource subresource;
                subresource.aspectMask = VkImageAspectFlags.Color;
                subresource.arrayLayer = i;
                subresource.mipLevel   = 0;
                vkGetImageSubresourceLayout(_device, _image, ref subresource, out VkSubresourceLayout faceLayout);
                void *mappedPtr;
                result = vkMapMemory(_device, stagingMemory.DeviceMemory, faceLayout.offset, faceLayout.size, 0, &mappedPtr);
                CheckResult(result);
                Buffer.MemoryCopy((void *)faces[i], mappedPtr, faceLayout.size, faceLayout.size);
                vkUnmapMemory(_device, stagingMemory.DeviceMemory);
            }

            StackList <VkBufferImageCopy, Size512Bytes> copyRegions = new StackList <VkBufferImageCopy, Size512Bytes>();

            for (uint i = 0; i < 6; i++)
            {
                VkImageSubresource subres;
                subres.aspectMask = VkImageAspectFlags.Color;
                subres.mipLevel   = 0;
                subres.arrayLayer = i;
                vkGetImageSubresourceLayout(_device, _image, ref subres, out VkSubresourceLayout layout);

                VkBufferImageCopy copyRegion;
                copyRegion.bufferOffset       = layout.offset;
                copyRegion.bufferImageHeight  = 0;
                copyRegion.bufferRowLength    = 0;
                copyRegion.imageExtent.width  = (uint)Width;
                copyRegion.imageExtent.height = (uint)Height;
                copyRegion.imageExtent.depth  = 1;
                copyRegion.imageOffset.x      = 0;
                copyRegion.imageOffset.y      = 0;
                copyRegion.imageOffset.z      = 0;
                copyRegion.imageSubresource.baseArrayLayer = i;
                copyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                copyRegion.imageSubresource.layerCount     = 1;
                copyRegion.imageSubresource.mipLevel       = 0;

                copyRegions.Add(copyRegion);
            }

            VkFenceCreateInfo fenceCI = VkFenceCreateInfo.New();

            result = vkCreateFence(_device, ref fenceCI, null, out VkFence copyFence);
            CheckResult(result);

            TransitionImageLayout(_image, (uint)MipLevels, 0, 6, _imageLayout, VkImageLayout.TransferDstOptimal);

            VkCommandBuffer copyCmd = _rc.BeginOneTimeCommands();

            vkCmdCopyBufferToImage(copyCmd, stagingBuffer, _image, VkImageLayout.TransferDstOptimal, copyRegions.Count, (IntPtr)copyRegions.Data);
            _rc.EndOneTimeCommands(copyCmd, copyFence);
            result = vkWaitForFences(_device, 1, ref copyFence, true, ulong.MaxValue);
            CheckResult(result);

            vkDestroyBuffer(_device, stagingBuffer, null);
            _memoryManager.Free(stagingMemory);
        }
예제 #28
0
        void loadCubemap(string filename, VkFormat format, bool forceLinearTiling)
        {
            KtxFile texCube;
            using (var fs = File.OpenRead(filename))
            {
                texCube = KtxFile.Load(fs, readKeyValuePairs: false);
            }

            cubeMap.width = texCube.Header.PixelWidth;
            cubeMap.height = texCube.Header.PixelHeight;
            cubeMap.mipLevels = texCube.Header.NumberOfMipmapLevels;

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs;

            // Create a host-visible staging buffer that contains the raw image data
            VkBuffer stagingBuffer;
            VkDeviceMemory stagingMemory;

            VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();
            bufferCreateInfo.size = texCube.GetTotalSize();
            // This buffer is used as a transfer source for the buffer copy
            bufferCreateInfo.usage = VkBufferUsageFlags.TransferSrc;
            bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

            Util.CheckResult(vkCreateBuffer(device, &bufferCreateInfo, null, &stagingBuffer));

            // Get memory requirements for the staging buffer (alignment, memory type bits)
            vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs);
            memAllocInfo.allocationSize = memReqs.size;
            // Get memory type index for a host visible buffer
            memAllocInfo.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
            Util.CheckResult(vkAllocateMemory(device, &memAllocInfo, null, &stagingMemory));
            Util.CheckResult(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0));

            // Copy texture data into staging buffer
            byte* data;
            Util.CheckResult(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void**)&data));
            byte[] allTextureData = texCube.GetAllTextureData();
            fixed (byte* texCubeDataPtr = &allTextureData[0])
            {
                Unsafe.CopyBlock(data, texCubeDataPtr, (uint)allTextureData.Length);
            }

            vkUnmapMemory(device, stagingMemory);

            // Create optimal tiled target image
            VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
            imageCreateInfo.imageType = VkImageType.Image2D;
            imageCreateInfo.format = format;
            imageCreateInfo.mipLevels = cubeMap.mipLevels;
            imageCreateInfo.samples = VkSampleCountFlags.Count1;
            imageCreateInfo.tiling = VkImageTiling.Optimal;
            imageCreateInfo.usage = VkImageUsageFlags.Sampled;
            imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
            imageCreateInfo.initialLayout = VkImageLayout.Undefined;
            imageCreateInfo.extent = new VkExtent3D { width = cubeMap.width, height = cubeMap.height, depth = 1 };
            imageCreateInfo.usage = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled;
            // Cube faces count as array layers in Vulkan
            imageCreateInfo.arrayLayers = 6;
            // This flag is required for cube map images
            imageCreateInfo.flags = VkImageCreateFlags.CubeCompatible;

            Util.CheckResult(vkCreateImage(device, &imageCreateInfo, null, out cubeMap.image));

            vkGetImageMemoryRequirements(device, cubeMap.image, &memReqs);

            memAllocInfo.allocationSize = memReqs.size;
            memAllocInfo.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);

            Util.CheckResult(vkAllocateMemory(device, &memAllocInfo, null, out cubeMap.deviceMemory));
            Util.CheckResult(vkBindImageMemory(device, cubeMap.image, cubeMap.deviceMemory, 0));

            VkCommandBuffer copyCmd = createCommandBuffer(VkCommandBufferLevel.Primary, true);

            // Setup buffer copy regions for each face including all of it's miplevels
            NativeList<VkBufferImageCopy> bufferCopyRegions = new NativeList<VkBufferImageCopy>();
            uint offset = 0;

            for (uint face = 0; face < 6; face++)
            {
                for (uint level = 0; level < cubeMap.mipLevels; level++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask = VkImageAspectFlags.Color;
                    bufferCopyRegion.imageSubresource.mipLevel = level;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = face;
                    bufferCopyRegion.imageSubresource.layerCount = 1;
                    bufferCopyRegion.imageExtent.width = texCube.Faces[face].Mipmaps[level].Width;
                    bufferCopyRegion.imageExtent.height = texCube.Faces[face].Mipmaps[level].Height;
                    bufferCopyRegion.imageExtent.depth = 1;
                    bufferCopyRegion.bufferOffset = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    // Increase offset into staging buffer for next level / face
                    offset += texCube.Faces[face].Mipmaps[level].SizeInBytes;
                }
            }

            // Image barrier for optimal image (target)
            // Set initial layout for all array layers (faces) of the optimal (target) tiled texture
            VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();
            subresourceRange.aspectMask = VkImageAspectFlags.Color;
            subresourceRange.baseMipLevel = 0;
            subresourceRange.levelCount = cubeMap.mipLevels;
            subresourceRange.layerCount = 6;

            Tools.setImageLayout(
                copyCmd,
                cubeMap.image,
                VkImageAspectFlags.Color,
                VkImageLayout.Undefined,
                VkImageLayout.TransferDstOptimal,
                subresourceRange);

            // Copy the cube map faces from the staging buffer to the optimal tiled image
            vkCmdCopyBufferToImage(
                copyCmd,
                stagingBuffer,
                cubeMap.image,
                VkImageLayout.TransferDstOptimal,
                bufferCopyRegions.Count,
                bufferCopyRegions.Data);

            // Change texture image layout to shader read after all faces have been copied
            cubeMap.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
            Tools.setImageLayout(
                copyCmd,
                cubeMap.image,
                VkImageAspectFlags.Color,
                VkImageLayout.TransferDstOptimal,
                cubeMap.imageLayout,
                subresourceRange);

            flushCommandBuffer(copyCmd, queue, true);

            // Create sampler
            VkSamplerCreateInfo sampler = Initializers.samplerCreateInfo();
            sampler.magFilter = VkFilter.Linear;
            sampler.minFilter = VkFilter.Linear;
            sampler.mipmapMode = VkSamplerMipmapMode.Linear;
            sampler.addressModeU = VkSamplerAddressMode.ClampToEdge;
            sampler.addressModeV = sampler.addressModeU;
            sampler.addressModeW = sampler.addressModeU;
            sampler.mipLodBias = 0.0f;
            sampler.compareOp = VkCompareOp.Never;
            sampler.minLod = 0.0f;
            sampler.maxLod = cubeMap.mipLevels;
            sampler.borderColor = VkBorderColor.FloatOpaqueWhite;
            sampler.maxAnisotropy = 1.0f;
            if (vulkanDevice.features.samplerAnisotropy == 1)
            {
                sampler.maxAnisotropy = vulkanDevice.properties.limits.maxSamplerAnisotropy;
                sampler.anisotropyEnable = True;
            }
            Util.CheckResult(vkCreateSampler(device, &sampler, null, out cubeMap.sampler));

            // Create image view
            VkImageViewCreateInfo view = Initializers.imageViewCreateInfo();
            // Cube map view type
            view.viewType = VkImageViewType.ImageCube;
            view.format = format;
            view.components = new VkComponentMapping { r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A };
            view.subresourceRange = new VkImageSubresourceRange { aspectMask = VkImageAspectFlags.Color, baseMipLevel = 0, layerCount = 1, baseArrayLayer = 0, levelCount = 1 };
            // 6 array layers (faces)
            view.subresourceRange.layerCount = 6;
            // Set number of mip levels
            view.subresourceRange.levelCount = cubeMap.mipLevels;
            view.image = cubeMap.image;
            Util.CheckResult(vkCreateImageView(device, &view, null, out cubeMap.view));

            // Clean up staging resources
            vkFreeMemory(device, stagingMemory, null);
            vkDestroyBuffer(device, stagingBuffer, null);
        }
예제 #29
0
 public static extern VkResult CreateBuffer(
     VkDevice device,
     ref VkBufferCreateInfo pCreateInfo,
     IntPtr pAllocator,
     out VkBuffer pBuffer
     );
예제 #30
0
        void loadTexture(string fileName, VkFormat format, bool forceLinearTiling)
        {
            KtxFile tex2D;

            using (var fs = File.OpenRead(fileName))
            {
                tex2D = KtxFile.Load(fs, false);
            }

            VkFormatProperties formatProperties;

            texture.width     = tex2D.Header.PixelWidth;
            texture.height    = tex2D.Header.PixelHeight;
            texture.mipLevels = tex2D.Header.NumberOfMipmapLevels;

            // Get Device properites for the requested texture format
            vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);

            // Only use linear tiling if requested (and supported by the Device)
            // Support for linear tiling is mostly limited, so prefer to use
            // optimal tiling instead
            // On most implementations linear tiling will only support a very
            // limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
            uint useStaging = 1;

            // Only use linear tiling if forced
            if (forceLinearTiling)
            {
                // Don't use linear if format is not supported for (linear) shader sampling
                useStaging = ((formatProperties.linearTilingFeatures & VkFormatFeatureFlags.SampledImage) != VkFormatFeatureFlags.SampledImage) ? 1u : 0u;
            }

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs      = new VkMemoryRequirements();

            if (useStaging == 1)
            {
                // Create a host-visible staging buffer that contains the raw image data
                VkBuffer       stagingBuffer;
                VkDeviceMemory stagingMemory;

                VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();
                bufferCreateInfo.size = tex2D.GetTotalSize();
                // This buffer is used as a transfer source for the buffer copy
                bufferCreateInfo.usage       = VkBufferUsageFlags.TransferSrc;
                bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

                Util.CheckResult(vkCreateBuffer(device, &bufferCreateInfo, null, &stagingBuffer));

                // Get memory requirements for the staging buffer (alignment, memory type bits)
                vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;
                // Get memory type index for a host visible buffer
                memAllocInfo.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);

                Util.CheckResult(vkAllocateMemory(device, &memAllocInfo, null, &stagingMemory));
                Util.CheckResult(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0));

                // Copy texture data into staging buffer
                byte *data;
                Util.CheckResult(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&data));
                byte[] allData = tex2D.GetAllTextureData();
                fixed(byte *tex2DDataPtr = &allData[0])
                {
                    Unsafe.CopyBlock(data, tex2DDataPtr, (uint)allData.Length);
                }

                vkUnmapMemory(device, stagingMemory);

                // Setup buffer copy regions for each mip level
                NativeList <VkBufferImageCopy> bufferCopyRegions = new NativeList <VkBufferImageCopy>();
                uint offset = 0;

                for (uint i = 0; i < texture.mipLevels; i++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                    bufferCopyRegion.imageSubresource.mipLevel       = i;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
                    bufferCopyRegion.imageSubresource.layerCount     = 1;
                    bufferCopyRegion.imageExtent.width  = tex2D.Faces[0].Mipmaps[i].Width;
                    bufferCopyRegion.imageExtent.height = tex2D.Faces[0].Mipmaps[i].Height;
                    bufferCopyRegion.imageExtent.depth  = 1;
                    bufferCopyRegion.bufferOffset       = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    offset += tex2D.Faces[0].Mipmaps[i].SizeInBytes;
                }

                // Create optimal tiled target image
                VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                imageCreateInfo.imageType   = VkImageType.Image2D;
                imageCreateInfo.format      = format;
                imageCreateInfo.mipLevels   = texture.mipLevels;
                imageCreateInfo.arrayLayers = 1;
                imageCreateInfo.samples     = VkSampleCountFlags.Count1;
                imageCreateInfo.tiling      = VkImageTiling.Optimal;
                imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                // Set initial layout of the image to undefined
                imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                imageCreateInfo.extent        = new VkExtent3D {
                    width = texture.width, height = texture.height, depth = 1
                };
                imageCreateInfo.usage = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled;

                Util.CheckResult(vkCreateImage(device, &imageCreateInfo, null, out texture.image));

                vkGetImageMemoryRequirements(device, texture.image, &memReqs);

                memAllocInfo.allocationSize  = memReqs.size;
                memAllocInfo.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);

                Util.CheckResult(vkAllocateMemory(device, &memAllocInfo, null, out texture.DeviceMemory));
                Util.CheckResult(vkBindImageMemory(device, texture.image, texture.DeviceMemory, 0));

                VkCommandBuffer copyCmd = base.createCommandBuffer(VkCommandBufferLevel.Primary, true);

                // Image barrier for optimal image

                // The sub resource range describes the regions of the image we will be transition
                VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();
                // Image only contains color data
                subresourceRange.aspectMask = VkImageAspectFlags.Color;
                // Start at first mip level
                subresourceRange.baseMipLevel = 0;
                // We will transition on all mip levels
                subresourceRange.levelCount = texture.mipLevels;
                // The 2D texture only has one layer
                subresourceRange.layerCount = 1;

                // Optimal image will be used as destination for the copy, so we must transfer from our
                // initial undefined image layout to the transfer destination layout
                setImageLayout(
                    copyCmd,
                    texture.image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.Undefined,
                    VkImageLayout.TransferDstOptimal,
                    subresourceRange);

                // Copy mip levels from staging buffer
                vkCmdCopyBufferToImage(
                    copyCmd,
                    stagingBuffer,
                    texture.image,
                    VkImageLayout.TransferDstOptimal,
                    bufferCopyRegions.Count,
                    bufferCopyRegions.Data);

                // Change texture image layout to shader read after all mip levels have been copied
                texture.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
                setImageLayout(
                    copyCmd,
                    texture.image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.TransferDstOptimal,
                    texture.imageLayout,
                    subresourceRange);

                flushCommandBuffer(copyCmd, queue, true);

                // Clean up staging resources
                vkFreeMemory(device, stagingMemory, null);
                vkDestroyBuffer(device, stagingBuffer, null);
            }
            else
            {
                throw new NotImplementedException();

                /*
                 * // Prefer using optimal tiling, as linear tiling
                 * // may support only a small set of features
                 * // depending on implementation (e.g. no mip maps, only one layer, etc.)
                 *
                 * VkImage mappableImage;
                 * VkDeviceMemory mappableMemory;
                 *
                 * // Load mip map level 0 to linear tiling image
                 * VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                 * imageCreateInfo.imageType = VkImageType._2d;
                 * imageCreateInfo.format = format;
                 * imageCreateInfo.mipLevels = 1;
                 * imageCreateInfo.arrayLayers = 1;
                 * imageCreateInfo.samples = VkSampleCountFlags._1;
                 * imageCreateInfo.tiling = VkImageTiling.Linear;
                 * imageCreateInfo.usage = VkImageUsageFlags.Sampled;
                 * imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                 * imageCreateInfo.initialLayout = VkImageLayout.Preinitialized;
                 * imageCreateInfo.extent = new VkExtent3D { width = texture.width, height = texture.height, depth = 1 };
                 * Util.CheckResult(vkCreateImage(Device, &imageCreateInfo, null, &mappableImage));
                 *
                 * // Get memory requirements for this image
                 * // like size and alignment
                 * vkGetImageMemoryRequirements(Device, mappableImage, &memReqs);
                 * // Set memory allocation size to required memory size
                 * memAllocInfo.allocationSize = memReqs.size;
                 *
                 * // Get memory type that can be mapped to host memory
                 * memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits,  VkMemoryPropertyFlags.HostVisible |  VkMemoryPropertyFlags.HostCoherent);
                 *
                 * // Allocate host memory
                 * Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, &mappableMemory));
                 *
                 * // Bind allocated image for use
                 * Util.CheckResult(vkBindImageMemory(Device, mappableImage, mappableMemory, 0));
                 *
                 * // Get sub resource layout
                 * // Mip map count, array layer, etc.
                 * VkImageSubresource subRes = new VkImageSubresource();
                 * subRes.aspectMask =  VkImageAspectFlags.Color;
                 *
                 * VkSubresourceLayout subResLayout;
                 * void* data;
                 *
                 * // Get sub resources layout
                 * // Includes row pitch, size offsets, etc.
                 * vkGetImageSubresourceLayout(Device, mappableImage, &subRes, &subResLayout);
                 *
                 * // Map image memory
                 * Util.CheckResult(vkMapMemory(Device, mappableMemory, 0, memReqs.size, 0, &data));
                 *
                 * // Copy image data into memory
                 * memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size());
                 *
                 * vkUnmapMemory(Device, mappableMemory);
                 *
                 * // Linear tiled images don't need to be staged
                 * // and can be directly used as textures
                 * texture.image = mappableImage;
                 * texture.DeviceMemory = mappableMemory;
                 * texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
                 *
                 * VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
                 *
                 * // Setup image memory barrier transfer image to shader read layout
                 *
                 * // The sub resource range describes the regions of the image we will be transition
                 * VkImageSubresourceRange subresourceRange = { };
                 * // Image only contains color data
                 * subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                 * // Start at first mip level
                 * subresourceRange.baseMipLevel = 0;
                 * // Only one mip level, most implementations won't support more for linear tiled images
                 * subresourceRange.levelCount = 1;
                 * // The 2D texture only has one layer
                 * subresourceRange.layerCount = 1;
                 *
                 * setImageLayout(
                 *  copyCmd,
                 *  texture.image,
                 *  VK_IMAGE_ASPECT_COLOR_BIT,
                 *  VK_IMAGE_LAYOUT_PREINITIALIZED,
                 *  texture.imageLayout,
                 *  subresourceRange);
                 *
                 * VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
                 */
            }

            // Create sampler
            // In Vulkan textures are accessed by samplers
            // This separates all the sampling information from the
            // texture data
            // This means you could have multiple sampler objects
            // for the same texture with different settings
            // Similar to the samplers available with OpenGL 3.3
            VkSamplerCreateInfo sampler = Initializers.samplerCreateInfo();

            sampler.magFilter    = VkFilter.Linear;
            sampler.minFilter    = VkFilter.Linear;
            sampler.mipmapMode   = VkSamplerMipmapMode.Linear;
            sampler.addressModeU = VkSamplerAddressMode.Repeat;
            sampler.addressModeV = VkSamplerAddressMode.Repeat;
            sampler.addressModeW = VkSamplerAddressMode.Repeat;
            sampler.mipLodBias   = 0.0f;
            sampler.compareOp    = VkCompareOp.Never;
            sampler.minLod       = 0.0f;
            // Set max level-of-detail to mip level count of the texture
            sampler.maxLod = (useStaging == 1) ? (float)texture.mipLevels : 0.0f;
            // Enable anisotropic filtering
            // This feature is optional, so we must check if it's supported on the Device
            if (vulkanDevice.features.samplerAnisotropy == 1)
            {
                // Use max. level of anisotropy for this example
                sampler.maxAnisotropy    = vulkanDevice.properties.limits.maxSamplerAnisotropy;
                sampler.anisotropyEnable = True;
            }
            else
            {
                // The Device does not support anisotropic filtering
                sampler.maxAnisotropy    = 1.0f;
                sampler.anisotropyEnable = False;
            }
            sampler.borderColor = VkBorderColor.FloatOpaqueWhite;
            Util.CheckResult(vkCreateSampler(device, ref sampler, null, out texture.sampler));

            // Create image view
            // Textures are not directly accessed by the shaders and
            // are abstracted by image views containing additional
            // information and sub resource ranges
            VkImageViewCreateInfo view = Initializers.imageViewCreateInfo();

            view.viewType   = VkImageViewType.Image2D;
            view.format     = format;
            view.components = new VkComponentMapping {
                r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A
            };
            // The subresource range describes the set of mip levels (and array layers) that can be accessed through this image view
            // It's possible to create multiple image views for a single image referring to different (and/or overlapping) ranges of the image
            view.subresourceRange.aspectMask     = VkImageAspectFlags.Color;
            view.subresourceRange.baseMipLevel   = 0;
            view.subresourceRange.baseArrayLayer = 0;
            view.subresourceRange.layerCount     = 1;
            // Linear tiling usually won't support mip maps
            // Only set mip map count if optimal tiling is used
            view.subresourceRange.levelCount = (useStaging == 1) ? texture.mipLevels : 1;
            // The view will be based on the texture's image
            view.image = texture.image;
            Util.CheckResult(vkCreateImageView(device, &view, null, out texture.view));
        }