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); } }
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); }
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); }
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); }
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; }
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); } }
//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)); }
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); }
/** * 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()); }
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); }
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)); }
/** * 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); }
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); }
/// <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];
/// <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(); } } } }
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; }
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);
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); }
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); }
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; } }
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); } }
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); }
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(); }
/** * 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(); }
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); }
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); }
public static extern VkResult CreateBuffer( VkDevice device, ref VkBufferCreateInfo pCreateInfo, IntPtr pAllocator, out VkBuffer pBuffer );
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)); }