/** * Finish command buffer recording and submit it to a queue * * @param commandBuffer Command buffer to flush * @param queue Queue to submit the command buffer to * @param free (Optional) Free the command buffer once it has been submitted (Defaults to true) * * @note The queue that the command buffer is submitted to must be from the same family index as the pool it was allocated from * @note Uses a fence to ensure command buffer has finished executing */ public void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free = true) { if (commandBuffer.Handle == NullHandle) { return; } Util.CheckResult(vkEndCommandBuffer(commandBuffer)); VkSubmitInfo submitInfo = VkSubmitInfo.New(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; // Create fence to ensure that the command buffer has finished executing VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.New(); fenceInfo.flags = VkFenceCreateFlags.None; VkFence fence; Util.CheckResult(vkCreateFence(_logicalDevice, &fenceInfo, null, &fence)); // Submit to the queue Util.CheckResult(vkQueueSubmit(queue, 1, &submitInfo, fence)); // Wait for the fence to signal that command buffer has finished executing Util.CheckResult(vkWaitForFences(_logicalDevice, 1, &fence, True, DEFAULT_FENCE_TIMEOUT)); vkDestroyFence(_logicalDevice, fence, null); if (free) { vkFreeCommandBuffers(_logicalDevice, CommandPool, 1, &commandBuffer); } }
private void CreateFences() { VkFenceCreateInfo fenceCI = VkFenceCreateInfo.New(); fenceCI.flags = VkFenceCreateFlags.None; vkCreateFence(_device, ref fenceCI, null, out _imageAvailableFence); }
/** * Finish command buffer recording and submit it to a queue * * @param commandBuffer Command buffer to flush * @param queue Queue to submit the command buffer to * @param free (Optional) Free the command buffer once it has been submitted (Defaults to true) * * @note The queue that the command buffer is submitted to must be from the same family index as the pool it was allocated from * @note Uses a fence to ensure command buffer has finished executing */ public void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free = true) { if (commandBuffer.handle == 0) { return; } vkEndCommandBuffer(commandBuffer); VkSubmitInfo submitInfo = new VkSubmitInfo(); submitInfo.sType = SubmitInfo; submitInfo.commandBuffers = commandBuffer; // Create fence to ensure that the command buffer has finished executing VkFenceCreateInfo fenceInfo = new VkFenceCreateInfo(); fenceInfo.sType = FenceCreateInfo; fenceInfo.flags = 0; VkFence fence; vkCreateFence(_logicalDevice, &fenceInfo, null, &fence); // Submit to the queue vkQueueSubmit(queue, 1, &submitInfo, fence); // Wait for the fence to signal that command buffer has finished executing vkWaitForFences(_logicalDevice, 1, &fence, true, DEFAULT_FENCE_TIMEOUT); vkDestroyFence(_logicalDevice, fence, null); if (free) { vkFreeCommandBuffers(_logicalDevice, CommandPool, 1, &commandBuffer); } }
public unsafe Fence(Device device, bool isSignaled = false) { _device = device; var createInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, flags = ( isSignaled ? VkFenceCreateFlags.Signaled : VkFenceCreateFlags.None ) }; VkFence fence; if (VulkanNative.vkCreateFence( device.Handle, &createInfo, null, &fence ) != VkResult.Success) { throw new Exception("failed to create fence"); } _handle = fence; }
public void FlushCommandBuffer(CommandBuffer cmd) { if (cmd.vkCmd == NullHandle) { return; } if (!cmd.ended) { cmd.End(); } var vkCmd = cmd.vkCmd; VkSubmitInfo submitInfo = VkSubmitInfo.New(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &vkCmd; VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.New(); Util.CheckResult(vkCreateFence(device, &fenceInfo, null, out VkFence fence)); Util.CheckResult(vkQueueSubmit(queue, 1, &submitInfo, fence)); //Wait for CommandBuffer to finish Util.CheckResult(vkWaitForFences(device, 1, ref fence, true, 10000000000)); vkDestroyFence(device, fence, null); }
private ulong[] CreateFences() { var fences = new ulong[(uint)_graphicsSurface.BufferCount]; var fenceCreateInfo = new VkFenceCreateInfo { sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, pNext = null, flags = (uint)VK_FENCE_CREATE_SIGNALED_BIT, }; for (var i = 0; i < fences.Length; i++) { ulong fence; var result = vkCreateFence(Device, &fenceCreateInfo, pAllocator: null, &fence); if (result != VK_SUCCESS) { ThrowExternalException(nameof(vkCreateFence), (int)result); } fences[i] = fence; } return(fences); }
public VkFence CreateFence(bool signaled = false) { VkFence tmp; VkFenceCreateInfo info = VkFenceCreateInfo.New(); info.flags = signaled ? VkFenceCreateFlags.Signaled : 0; Utils.CheckResult(vkCreateFence(dev, ref info, IntPtr.Zero, out tmp)); return(tmp); }
public VkFence(VkGraphicsDevice gd, bool signaled) { _gd = gd; VkFenceCreateInfo fenceCI = VkFenceCreateInfo.New(); fenceCI.flags = signaled ? VkFenceCreateFlags.Signaled : VkFenceCreateFlags.None; VkResult result = vkCreateFence(_gd.Device, ref fenceCI, null, out _fence); VulkanUtil.CheckResult(result); }
/// <summary> /// Executes multiple deferred command lists. /// </summary> /// <param name="count">Number of command lists to execute.</param> /// <param name="commandLists">The deferred command lists.</param> public unsafe void ExecuteCommandLists(int count, CompiledCommandList[] commandLists) { if (commandLists == null) { throw new ArgumentNullException(nameof(commandLists)); } if (count > commandLists.Length) { throw new ArgumentOutOfRangeException(nameof(count)); } var fenceValue = NextFenceValue++; // Create a fence var fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo }; vkCreateFence(nativeDevice, &fenceCreateInfo, null, out var fence); using (FenceLock.WriteLock()) { nativeFences.Add(new KeyValuePair <long, VkFence>(fenceValue, fence)); } // Collect resources var commandBuffers = stackalloc VkCommandBuffer[count]; for (int i = 0; i < count; i++) { commandBuffers[i] = commandLists[i].NativeCommandBuffer; RecycleCommandListResources(commandLists[i], fenceValue); } // Submit commands var pipelineStageFlags = VkPipelineStageFlags.BottomOfPipe; var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = (uint)count, pCommandBuffers = commandBuffers, waitSemaphoreCount = 0U, pWaitSemaphores = null, pWaitDstStageMask = &pipelineStageFlags, }; using (QueueLock.ReadLock()) { vkQueueSubmit(NativeCommandQueue, 1, &submitInfo, fence); } nativeResourceCollector.FastRelease(); graphicsResourceLinkCollector.FastRelease(); }
public Fence(Device device, bool signaled = true) : base(device) { VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo() { sType = VkStructureType.FenceCreateInfo, pNext = null, flags = signaled ? VkFenceCreateFlags.Signaled : VkFenceCreateFlags.None, }; vkCreateFence(NativeDevice.handle, &fenceCreateInfo, null, out handle); }
internal unsafe long ExecuteCommandListInternal(CompiledCommandList commandList) { //if (nativeUploadBuffer != VkBuffer.Null) //{ // NativeDevice.UnmapMemory(nativeUploadBufferMemory); // TemporaryResources.Enqueue(new BufferInfo(NextFenceValue, nativeUploadBuffer, nativeUploadBufferMemory)); // nativeUploadBuffer = VkBuffer.Null; // nativeUploadBufferMemory = VkDeviceMemory.Null; //} var fenceValue = NextFenceValue++; // Create new fence var fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo }; vkCreateFence(nativeDevice, &fenceCreateInfo, null, out var fence); using (FenceLock.WriteLock()) { nativeFences.Add(new KeyValuePair <long, VkFence>(fenceValue, fence)); } // Collect resources RecycleCommandListResources(commandList, fenceValue); // Submit commands var nativeCommandBufferCopy = commandList.NativeCommandBuffer; var pipelineStageFlags = VkPipelineStageFlags.BottomOfPipe; var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, pCommandBuffers = &nativeCommandBufferCopy, waitSemaphoreCount = 0U, pWaitSemaphores = null, pWaitDstStageMask = &pipelineStageFlags, }; using (QueueLock.ReadLock()) { vkQueueSubmit(NativeCommandQueue, 1, &submitInfo, fence); } nativeResourceCollector.Release(); graphicsResourceLinkCollector.Release(); return(fenceValue); }
public Fence(Device dev, VkFenceCreateFlag flags) { Device = dev; unsafe { var info = new VkFenceCreateInfo() { SType = VkStructureType.FenceCreateInfo, PNext = IntPtr.Zero, Flags = flags }; Handle = dev.Handle.CreateFence(&info, Instance.AllocationCallbacks); } }
void CreateFence(FenceCreateInfo mInfo) { VkFenceCreateInfo info = new VkFenceCreateInfo(); info.sType = VkStructureType.FenceCreateInfo; info.flags = mInfo.Flags; var result = Device.Commands.createFence(Device.Native, ref info, Device.Instance.AllocationCallbacks, out fence); if (result != VkResult.Success) { throw new FenceException(string.Format("Error creating fence: {0}", result)); } }
private VkFence CreateVulkanFence() { ThrowIfDisposedOrDisposing(_state, nameof(VulkanGraphicsFence)); VkFence vulkanFence; var fenceCreateInfo = new VkFenceCreateInfo { sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, pNext = null, flags = VK_FENCE_CREATE_SIGNALED_BIT, }; ThrowExternalExceptionIfNotSuccess(vkCreateFence(Device.VulkanDevice, &fenceCreateInfo, pAllocator: null, (ulong *)&vulkanFence), nameof(vkCreateFence)); return(vulkanFence); }
// Command: 116 /// <summary>vkCreateFence - Create a new fence object /// </summary> /// <param name="pCreateInfo"> pCreateInfo is a pointer to an instance of the /// VkFenceCreateInfo structure which contains information about how /// the fence is to be created.</param> /// <param name="pAllocator"> pAllocator controls host memory allocation as described in the /// Memory Allocation chapter.</param> public VkFence CreateFence(VkFenceCreateInfo *pCreateInfo = null, VkAllocationCallbacks *pAllocator = null) { VkFence fence; if (pCreateInfo == null) { var info = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo }; pCreateInfo = &info; } vkAPI.vkCreateFence(this, pCreateInfo, pAllocator, &fence); return(fence); }
public void Build(int devID) { if (!locked) { unsafe { var fenceCreateInfo = new VkFenceCreateInfo() { sType = VkStructureType.StructureTypeFenceCreateInfo, flags = CreateSignaled ? VkFenceCreateFlags.FenceCreateSignaledBit : 0 }; IntPtr hndl_l = IntPtr.Zero; if (vkCreateFence(GraphicsDevice.GetDeviceInfo(devID).Device, fenceCreateInfo.Pointer(), null, &hndl_l) != VkResult.Success) { throw new Exception("Failed to create fence."); } hndl = hndl_l; this.devID = devID; if (GraphicsDevice.EnableValidation && Name != null) { var objName = new VkDebugUtilsObjectNameInfoEXT() { sType = VkStructureType.StructureTypeDebugUtilsObjectNameInfoExt, pObjectName = Name, objectType = VkObjectType.ObjectTypeFence, objectHandle = (ulong)hndl }; GraphicsDevice.SetDebugUtilsObjectNameEXT(GraphicsDevice.GetDeviceInfo(devID).Device, objName.Pointer()); } } locked = true; } else { throw new Exception("Fence is locked."); } }
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); }
private unsafe void CreateBackBuffers() { backbuffer.OnDestroyed(); // Create the texture object var backBufferDescription = new TextureDescription { ArraySize = 1, Dimension = TextureDimension.Texture2D, Height = Description.BackBufferHeight, Width = Description.BackBufferWidth, Depth = 1, Flags = TextureFlags.RenderTarget, Format = Description.BackBufferFormat, MipLevels = 1, MultisampleCount = MultisampleCount.None, Usage = GraphicsResourceUsage.Default }; backbuffer.InitializeWithoutResources(backBufferDescription); var createInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1), format = backbuffer.NativeFormat, viewType = VkImageViewType.Image2D, }; // We initialize swapchain images to PresentSource, since we swap them out while in this layout. backbuffer.NativeAccessMask = VkAccessFlags.MemoryRead; backbuffer.NativeLayout = VkImageLayout.PresentSrcKHR; var imageMemoryBarrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1), oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.PresentSrcKHR, srcAccessMask = VkAccessFlags.None, dstAccessMask = VkAccessFlags.MemoryRead }; var commandBuffer = GraphicsDevice.NativeCopyCommandBuffer; var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo }; vkBeginCommandBuffer(commandBuffer, &beginInfo); var buffers = vkGetSwapchainImagesKHR(GraphicsDevice.NativeDevice, swapChain); swapchainImages = new SwapChainImageInfo[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { // Create image views swapchainImages[i].NativeImage = createInfo.image = buffers[i]; vkCreateImageView(GraphicsDevice.NativeDevice, &createInfo, null, out swapchainImages[i].NativeColorAttachmentView); // Transition to default layout imageMemoryBarrier.image = buffers[i]; vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); } // Close and submit vkEndCommandBuffer(commandBuffer); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, pCommandBuffers = &commandBuffer, }; vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, VkFence.Null); vkQueueWaitIdle(GraphicsDevice.NativeCommandQueue); vkResetCommandBuffer(commandBuffer, VkCommandBufferResetFlags.None); // need to make a fence, but can immediately reset it, as it acts as a dummy var fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo }; vkCreateFence(GraphicsDevice.NativeDevice, &fenceCreateInfo, null, out presentFence); vkAcquireNextImageKHR(GraphicsDevice.NativeDevice, swapChain, ulong.MaxValue, VkSemaphore.Null, presentFence, out currentBufferIndex); fixed(VkFence *fences = &presentFence) { vkResetFences(GraphicsDevice.NativeDevice, 1, fences); } // Apply the first swap chain image to the texture backbuffer.SetNativeHandles(swapchainImages[currentBufferIndex].NativeImage, swapchainImages[currentBufferIndex].NativeColorAttachmentView); }
/// <summary> /// Explicitly recreate buffer with given data. Usually called after a <see cref="GraphicsDevice"/> reset. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="dataPointer"></param> public unsafe void Recreate(IntPtr dataPointer) { // capture vertex information for things less than ~512 verts for possible later easy batching if (dataPointer != IntPtr.Zero && (ViewFlags == BufferFlags.VertexBuffer && bufferDescription.SizeInBytes <= CaptureVertexBuffersOfSize || ViewFlags == BufferFlags.IndexBuffer && bufferDescription.SizeInBytes <= CaptureIndexBuffersOfSize)) { VertIndexData = new byte[Description.SizeInBytes]; fixed(byte *vid = &VertIndexData[0]) { Utilities.CopyMemory((IntPtr)vid, dataPointer, VertIndexData.Length); } } else { VertIndexData = null; } var createInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, size = (ulong)bufferDescription.SizeInBytes, flags = VkBufferCreateFlags.None, }; createInfo.usage |= VkBufferUsageFlags.TransferSrc; // We always fill using transfer //if (bufferDescription.Usage != GraphicsResourceUsage.Immutable) createInfo.usage |= VkBufferUsageFlags.TransferDst; if (Usage == GraphicsResourceUsage.Staging) { NativeAccessMask = VkAccessFlags.HostRead | VkAccessFlags.HostWrite; NativePipelineStageMask |= VkPipelineStageFlags.Host; } else { if ((ViewFlags & BufferFlags.VertexBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.VertexBuffer; NativeAccessMask |= VkAccessFlags.VertexAttributeRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.IndexBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.IndexBuffer; NativeAccessMask |= VkAccessFlags.IndexRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.ConstantBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.UniformBuffer; NativeAccessMask |= VkAccessFlags.UniformRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader; } if ((ViewFlags & BufferFlags.ShaderResource) != 0) { createInfo.usage |= VkBufferUsageFlags.UniformTexelBuffer; NativeAccessMask |= VkAccessFlags.ShaderRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader; if ((ViewFlags & BufferFlags.UnorderedAccess) != 0) { createInfo.usage |= VkBufferUsageFlags.StorageTexelBuffer; NativeAccessMask |= VkAccessFlags.ShaderWrite; } } } // Create buffer vkCreateBuffer(GraphicsDevice.NativeDevice, &createInfo, null, out NativeBuffer); // Allocate memory var memoryProperties = VkMemoryPropertyFlags.DeviceLocal; if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic) { memoryProperties = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent; } vkGetBufferMemoryRequirements(GraphicsDevice.NativeDevice, NativeBuffer, out var memoryRequirements); AllocateMemory(memoryProperties, memoryRequirements); if (NativeMemory != VkDeviceMemory.Null) { vkBindBufferMemory(GraphicsDevice.NativeDevice, NativeBuffer, NativeMemory, 0); } if (SizeInBytes > 0) { // Begin copy command buffer var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = GraphicsDevice.NativeCopyCommandPool, commandBufferCount = 1, level = VkCommandBufferLevel.Primary }; VkCommandBuffer commandBuffer; lock (BufferLocker) { vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer); } var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit }; vkBeginCommandBuffer(commandBuffer, &beginInfo); GraphicsDevice.UploadBuffer?uploadBuffer = null; // Copy to upload buffer if (dataPointer != IntPtr.Zero) { if (Usage == GraphicsResourceUsage.Dynamic) { void *uploadMemory; vkMapMemory(GraphicsDevice.NativeDevice, NativeMemory, 0, (ulong)SizeInBytes, VkMemoryMapFlags.None, &uploadMemory); Utilities.CopyMemory((IntPtr)uploadMemory, dataPointer, SizeInBytes); lock (BufferLocker) { vkUnmapMemory(GraphicsDevice.NativeDevice, NativeMemory); } } else { var sizeInBytes = bufferDescription.SizeInBytes; int uploadOffset; GraphicsDevice.AllocateOneTimeUploadBuffer(sizeInBytes, out var upBuf); uploadBuffer = upBuf; Utilities.CopyMemory(uploadBuffer.Value.address, dataPointer, sizeInBytes); // Barrier var memoryBarrier = new VkBufferMemoryBarrier(uploadBuffer.Value.buffer, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, 0, (ulong)sizeInBytes); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &memoryBarrier, 0, null); // Copy var bufferCopy = new VkBufferCopy { srcOffset = 0, dstOffset = 0, size = (uint)sizeInBytes }; vkCmdCopyBuffer(commandBuffer, uploadBuffer.Value.buffer, NativeBuffer, 1, &bufferCopy); } } else { vkCmdFillBuffer(commandBuffer, NativeBuffer, 0, (uint)bufferDescription.SizeInBytes, 0); } // Barrier var bufferMemoryBarrier = new VkBufferMemoryBarrier(NativeBuffer, VkAccessFlags.TransferWrite, NativeAccessMask); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 0, null); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, pCommandBuffers = &commandBuffer, }; var fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo }; vkCreateFence(GraphicsDevice.NativeDevice, &fenceCreateInfo, null, out var fence); // Close and submit vkEndCommandBuffer(commandBuffer); using (GraphicsDevice.QueueLock.ReadLock()) { vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, fence); } vkWaitForFences(GraphicsDevice.NativeDevice, 1, &fence, true, ulong.MaxValue); vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer); vkDestroyFence(GraphicsDevice.NativeDevice, fence, null); if (uploadBuffer.HasValue) { GraphicsDevice.FreeOneTimeUploadBuffer(uploadBuffer.Value); } InitializeViews(); } }
public static extern VkResult CreateFence( VkDevice device, ref VkFenceCreateInfo pCreateInfo, IntPtr pAllocator, out VkFence pFence );
internal static VulkanImage Texture2D(VulkanContext ctx, TextureData tex2D) { ulong size = (ulong)tex2D.Mipmaps[0].Size; VkBuffer stagingBuffer; var bufferCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, size = (ulong)tex2D.Mipmaps[0].Size, usage = VkBufferUsageFlags.TransferSrc }; vkCreateBuffer(ctx.Device, &bufferCreateInfo, null, out stagingBuffer); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out VkMemoryRequirements stagingMemReq); uint heapIndex = BufferHelper.GetMemoryTypeIndex(stagingMemReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible, memoryProperties); VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = stagingMemReq.size, memoryTypeIndex = heapIndex }; VkDeviceMemory stagingMemory; VkResult result = vkAllocateMemory(ctx.Device, &memAllocInfo, null, &stagingMemory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0); result.CheckResult(); void *vertexPtr; result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)tex2D.Mipmaps[0].Size, 0, &vertexPtr); result.CheckResult(); fixed(byte *dataPtr = &tex2D.Mipmaps[0].Data[0]) { Buffer.MemoryCopy(dataPtr, vertexPtr, size, size); } vkUnmapMemory(ctx.Device, stagingMemory); // Setup buffer copy regions for each mip level. var bufferCopyRegions = new VkBufferImageCopy[tex2D.Mipmaps.Length]; // TODO: stackalloc int offset = 0; for (int i = 0; i < bufferCopyRegions.Length; i++) { // TODO: from VulkanCore, doesn't look correct (reassigns bufferCopyRegions in each loop) bufferCopyRegions = new[] { new VkBufferImageCopy { imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)i, 0, 1), imageExtent = tex2D.Mipmaps[0].Extent, bufferOffset = (ulong)offset } }; offset += tex2D.Mipmaps[i].Size; } // Create optimal tiled target image. var createInfo = new VkImageCreateInfo { sType = VkStructureType.ImageCreateInfo, pNext = null, imageType = VkImageType.Image2D, format = tex2D.Format, mipLevels = (uint)tex2D.Mipmaps.Length, arrayLayers = 1, samples = VkSampleCountFlags.Count1, tiling = VkImageTiling.Optimal, sharingMode = VkSharingMode.Exclusive, initialLayout = VkImageLayout.Undefined, extent = tex2D.Mipmaps[0].Extent, usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst }; VkImage image; result = vkCreateImage(ctx.Device, &createInfo, null, out image); result.CheckResult(); VkMemoryRequirements imageMemReq; vkGetImageMemoryRequirements(ctx.Device, image, out imageMemReq); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties imageMemoryProperties); uint imageHeapIndex = BufferHelper.GetMemoryTypeIndex(imageMemReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, imageMemoryProperties); var allocInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = imageMemReq.size, memoryTypeIndex = imageHeapIndex, }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &allocInfo, null, &memory); result.CheckResult(); result = vkBindImageMemory(ctx.Device, image, memory, 0); result.CheckResult(); var subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, (uint)tex2D.Mipmaps.Length, 0, 1); // Copy the data from staging buffers to device local buffers. var allocInfo2 = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = ctx.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1, }; VkCommandBuffer cmdBuffer; vkAllocateCommandBuffers(ctx.Device, &allocInfo2, &cmdBuffer); VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit, }; vkBeginCommandBuffer(cmdBuffer, &beginInfo); VkImageMemoryBarrier imageMemoryBarrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = 0, dstAccessMask = VkAccessFlags.TransferWrite, oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.TransferDstOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); fixed(VkBufferImageCopy *regionsPtr = bufferCopyRegions) { vkCmdCopyBufferToImage(cmdBuffer, stagingBuffer, image, VkImageLayout.TransferDstOptimal, (uint)bufferCopyRegions.Length, regionsPtr); } VkImageMemoryBarrier imageMemoryBarrier2 = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = VkAccessFlags.TransferWrite, dstAccessMask = VkAccessFlags.ShaderRead, oldLayout = VkImageLayout.TransferDstOptimal, newLayout = VkImageLayout.ShaderReadOnlyOptimal, srcQueueFamilyIndex = (uint)QueueFamilyIgnored, dstQueueFamilyIndex = (uint)QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier2); vkEndCommandBuffer(cmdBuffer); // Submit. VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, pNext = null }; VkFence fence; result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence); result.CheckResult(); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, pNext = null, commandBufferCount = 1, pCommandBuffers = &cmdBuffer }; vkQueueSubmit(ctx.GraphicsQueue, submitInfo, fence); result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); // Cleanup staging resources. vkDestroyFence(ctx.Device, fence, null); vkFreeMemory(ctx.Device, stagingMemory, null); vkDestroyBuffer(ctx.Device, stagingBuffer, null); // Create image view. VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo() { sType = VkStructureType.ImageViewCreateInfo, image = image, viewType = VkImageViewType.Image2D, format = tex2D.Format, subresourceRange = subresourceRange }; VkImageView view; vkCreateImageView(ctx.Device, &imageViewCreateInfo, null, out view); return(new VulkanImage(ctx, image, memory, view, tex2D.Format)); }
private unsafe void InitializeImage(DataBox[] dataBoxes) { // Begin copy command buffer var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = GraphicsDevice.NativeCopyCommandPool, commandBufferCount = 1, level = VkCommandBufferLevel.Primary }; VkCommandBuffer commandBuffer; // do some setup outside of the lock var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit }; var fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo }; vkCreateFence(GraphicsDevice.NativeDevice, &fenceCreateInfo, null, out var fence); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, }; using (GraphicsDevice.QueueLock.ReadLock()) { vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer); } vkBeginCommandBuffer(commandBuffer, &beginInfo); if (dataBoxes != null && dataBoxes.Length > 0) { // Buffer-to-image copies need to be aligned to the pixel size and 4 (always a power of 2) var blockSize = Format.IsCompressed() ? NativeFormat.BlockSizeInBytes() : TexturePixelSize; var alignmentMask = (blockSize < 4 ? 4 : blockSize) - 1; int totalSize = dataBoxes.Length * alignmentMask; for (int i = 0; i < dataBoxes.Length; i++) { totalSize += dataBoxes[i].SlicePitch; } var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out var upBuf, out int uploadOffset); // Upload buffer barrier var bufferMemoryBarrier = new VkBufferMemoryBarrier(upBuf, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize); // Image barrier var initialBarrier = new VkImageMemoryBarrier(NativeImage, new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue), VkAccessFlags.None, VkAccessFlags.TransferWrite, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier); // Copy data boxes to upload buffer var copies = new VkBufferImageCopy[dataBoxes.Length]; for (int i = 0; i < copies.Length; i++) { var slicePitch = dataBoxes[i].SlicePitch; int arraySlice = i / MipLevels; int mipSlice = i % MipLevels; var mipMapDescription = GetMipMapDescription(mipSlice); var alignment = ((uploadOffset + alignmentMask) & ~alignmentMask) - uploadOffset; uploadMemory += alignment; uploadOffset += alignment; Utilities.CopyMemory(uploadMemory, dataBoxes[i].DataPointer, slicePitch); // TODO VULKAN: Check if pitches are valid copies[i] = new VkBufferImageCopy { bufferOffset = (ulong)uploadOffset, imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)mipSlice, (uint)arraySlice, 1), bufferRowLength = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize), bufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch), imageOffset = new Vortice.Vulkan.VkOffset3D(0, 0, 0), imageExtent = new Vortice.Vulkan.VkExtent3D(mipMapDescription.Width, mipMapDescription.Height, mipMapDescription.Depth) }; uploadMemory += slicePitch; uploadOffset += slicePitch; } // Copy from upload buffer to image using (GraphicsDevice.QueueLock.ReadLock()) { fixed(VkBufferImageCopy *copiesPointer = copies) { vkCmdCopyBufferToImage(commandBuffer, upBuf, NativeImage, VkImageLayout.TransferDstOptimal, (uint)copies.Length, copiesPointer); } } IsInitialized = true; } // Transition to default layout var imageMemoryBarrier = new VkImageMemoryBarrier(NativeImage, new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue), dataBoxes == null || dataBoxes.Length == 0 ? VkAccessFlags.None : VkAccessFlags.TransferWrite, NativeAccessMask, dataBoxes == null || dataBoxes.Length == 0 ? VkImageLayout.Undefined : VkImageLayout.TransferDstOptimal, NativeLayout); submitInfo.pCommandBuffers = &commandBuffer; vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); vkEndCommandBuffer(commandBuffer); // Close and submit using (GraphicsDevice.QueueLock.WriteLock()) { vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, fence); } vkWaitForFences(GraphicsDevice.NativeDevice, 1, &fence, Vortice.Vulkan.VkBool32.True, ulong.MaxValue); vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer); vkDestroyFence(GraphicsDevice.NativeDevice, fence, null); }
public static void CreateTexture(VkDevice device, VkPhysicalDevice physicalDevice, int width, int height, byte[] imageSource, out VkImage image, out VkDeviceMemory memory, VkQueue queue, VkCommandBuffer workCommandBuffer) { var imageCreateInfo = new VkImageCreateInfo() { imageType = VkImageType.VK_IMAGE_TYPE_2D, format = VkFormat.VK_FORMAT_B8G8R8A8_UNORM, extent = new VkExtent3D(width, height), mipLevels = 1, usage = VkImageUsageFlags.VK_IMAGE_USAGE_TRANSFER_DST_BIT | VkImageUsageFlags.VK_IMAGE_USAGE_SAMPLED_BIT, }; VulkanAPI.vkCreateImage(device, ref imageCreateInfo, out image); VkMemoryRequirements requirements; VulkanAPI.vkGetImageMemoryRequirements(device, image, out requirements); VkMemoryPropertyFlags memoryFlags = VkMemoryPropertyFlags.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; VulkanAPI.vkAllocateMemory(device, physicalDevice, ref requirements, memoryFlags, out memory); VulkanAPI.vkBindImageMemory(device, image, memory, 0); // ステージングバッファ経由で転送. VkBuffer staging; VkDeviceMemory stagingMemory; var stagingFlags = VkMemoryPropertyFlags.VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VkMemoryPropertyFlags.VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; CreateBuffer(device, physicalDevice, imageSource.Length, VkBufferUsageFlags.VK_BUFFER_USAGE_TRANSFER_SRC_BIT, stagingFlags, out staging, out stagingMemory); MappedMemoryStream mappedStream; VulkanAPI.vkMapMemory(device, stagingMemory, 0, VkDeviceSize.VK_WHOLE_SIZE, 0, out mappedStream); mappedStream.Write(imageSource); VulkanAPI.vkUnmapMemory(device, stagingMemory); var copyRegion = new VkBufferImageCopy() { imageExtent = new VkExtent3D(width, height), bufferImageHeight = (uint)height, imageSubresource = new VkImageSubresourceLayers() { aspectMask = VkImageAspectFlags.VK_IMAGE_ASPECT_COLOR_BIT, mipLevel = 0, baseArrayLayer = 0, layerCount = 1, } }; // 一時的なコマンドバッファで転送処理. var command = workCommandBuffer; VulkanAPI.vkBeginCommandBuffer(command); setImageMemoryBarrier(command, 0, VkAccessFlags.VK_ACCESS_TRANSFER_WRITE_BIT, VkImageLayout.VK_IMAGE_LAYOUT_UNDEFINED, VkImageLayout.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image, VkImageAspectFlags.VK_IMAGE_ASPECT_COLOR_BIT); VulkanAPI.vkCmdCopyBufferToImage(command, staging, image, VkImageLayout.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, new[] { copyRegion }); setImageMemoryBarrier(command, VkAccessFlags.VK_ACCESS_TRANSFER_WRITE_BIT, VkAccessFlags.VK_ACCESS_SHADER_READ_BIT, VkImageLayout.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VkImageLayout.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image, VkImageAspectFlags.VK_IMAGE_ASPECT_COLOR_BIT); VulkanAPI.vkEndCommandBuffer(command); var submitInfo = new VkSubmitInfo() { commandBuffers = new[] { command }, }; var fenceCreateInfo = new VkFenceCreateInfo() { }; VkFence fence; VulkanAPI.vkCreateFence(device, fenceCreateInfo, out fence); VulkanAPI.vkQueueSubmit(queue, new[] { submitInfo }, fence); VulkanAPI.vkWaitForFences(device, new[] { fence }, true, ulong.MaxValue); VulkanAPI.vkDestroyFence(device, fence); VulkanAPI.vkDestroyBuffer(device, staging); VulkanAPI.vkFreeMemory(device, stagingMemory); }
private static VulkanBuffer GetBuffer <T>(VulkanContext ctx, T[] data, VkBufferUsageFlags usage) where T : unmanaged { long size = data.Length * Unsafe.SizeOf <T>(); // Create a staging buffer that is writable by host. var stagingCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, usage = VkBufferUsageFlags.TransferSrc, sharingMode = VkSharingMode.Exclusive, size = (ulong)size }; VkBuffer stagingBuffer; VkResult result = vkCreateBuffer( ctx.Device, &stagingCreateInfo, null, out stagingBuffer); result.CheckResult(); VkMemoryRequirements stagingReq; vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out stagingReq); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); uint stagingMemoryTypeIndex = BufferHelper.GetMemoryTypeIndex(stagingReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, memoryProperties); VkMemoryAllocateInfo allocateInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = stagingReq.size, memoryTypeIndex = stagingMemoryTypeIndex }; VkDeviceMemory stagingMemory; result = vkAllocateMemory(ctx.Device, &allocateInfo, null, &stagingMemory); result.CheckResult(); void *vertexPtr; result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)stagingReq.size, 0, &vertexPtr); result.CheckResult(); fixed(T *dataPtr = &data[0]) { System.Buffer.MemoryCopy(dataPtr, vertexPtr, size, size); } vkUnmapMemory(ctx.Device, stagingMemory); result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0); // Create a device local buffer where the data will be copied and which will be used for rendering. var bufferCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, usage = usage | VkBufferUsageFlags.TransferDst, sharingMode = VkSharingMode.Exclusive, size = (ulong)size }; VkBuffer buffer; result = vkCreateBuffer( ctx.Device, &bufferCreateInfo, null, out buffer); result.CheckResult(); VkMemoryRequirements req; vkGetBufferMemoryRequirements(ctx.Device, buffer, out req); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memProps); uint memoryTypeIndex = BufferHelper.GetMemoryTypeIndex(req.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, memProps); VkMemoryAllocateInfo bufferAllocInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = req.size, memoryTypeIndex = memoryTypeIndex }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &bufferAllocInfo, null, &memory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, buffer, memory, 0); // Copy the data from staging buffers to device local buffers. VkCommandBufferAllocateInfo allocInfo = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = ctx.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1, }; VkCommandBuffer cmdBuffer; vkAllocateCommandBuffers(ctx.Device, &allocInfo, &cmdBuffer); VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit, }; result = vkBeginCommandBuffer(cmdBuffer, &beginInfo); result.CheckResult(); VkBufferCopy bufferCopy = new VkBufferCopy { size = (ulong)size }; vkCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, 1, &bufferCopy); result = vkEndCommandBuffer(cmdBuffer); result.CheckResult(); // Submit. VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, pNext = null }; VkFence fence; result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence); result.CheckResult(); VkSubmitInfo submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, pNext = null, commandBufferCount = 1, pCommandBuffers = &cmdBuffer }; result = vkQueueSubmit(ctx.GraphicsQueue, 1, &submitInfo, fence); result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); // Cleanup. vkDestroyFence(ctx.Device, fence, null); vkFreeCommandBuffers(ctx.Device, ctx.GraphicsCommandPool, 1, &cmdBuffer); vkDestroyBuffer(ctx.Device, stagingBuffer, null); vkFreeMemory(ctx.Device, stagingMemory, null); return(new VulkanBuffer(ctx.Device, ctx.GraphicsCommandPool, buffer, memory, data.Length)); }
public void Initialize(IVulkanAppHost host) { Host = host; #if DEBUG const bool debug = true; #else const bool debug = false; #endif _initializingPermanent = true; VkResult result = vkInitialize(); result.CheckResult(); // Calling ToDispose here registers the resource to be automatically disposed on exit. Instance = CreateInstance(debug); Surface = CreateSurface(); Context = new VulkanContext(Instance, Surface, Host.Platform); Content = new ContentManager(Host, Context, "Content"); ImageAvailableSemaphore = CreateSemaphore(Context.Device); RenderingFinishedSemaphore = CreateSemaphore(Context.Device); _initializingPermanent = false; // Calling ToDispose here registers the resource to be automatically disposed on events // such as window resize. var swapchain = CreateSwapchain(); Swapchain = swapchain; ToDispose(new ActionDisposable(() => { vkDestroySwapchainKHR(Context.Device, swapchain, null); })); // Acquire underlying images of the freshly created swapchain. uint swapchainImageCount; result = vkGetSwapchainImagesKHR(Context.Device, Swapchain, &swapchainImageCount, null); result.CheckResult(); var swapchainImages = stackalloc VkImage[(int)swapchainImageCount]; result = vkGetSwapchainImagesKHR(Context.Device, Swapchain, &swapchainImageCount, swapchainImages); result.CheckResult(); SwapchainImages = new VkImage[swapchainImageCount]; for (int i = 0; i < swapchainImageCount; i++) { SwapchainImages[i] = swapchainImages[i]; } VkCommandBufferAllocateInfo allocInfo = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = Context.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = (uint)SwapchainImages.Length, }; VkCommandBuffer[] commandBuffers = new VkCommandBuffer[SwapchainImages.Length]; fixed(VkCommandBuffer *commandBuffersPtr = &commandBuffers[0]) { vkAllocateCommandBuffers(Context.Device, &allocInfo, commandBuffersPtr).CheckResult(); } CommandBuffers = commandBuffers; // Create a fence for each commandbuffer so that we can wait before using it again _initializingPermanent = true; //We need our fences to be there permanently SubmitFences = new VkFence[SwapchainImages.Length]; for (int i = 0; i < SubmitFences.Length; i++) { VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo() { sType = VkStructureType.FenceCreateInfo, pNext = null, flags = VkFenceCreateFlags.Signaled }; VkFence handle; vkCreateFence(Context.Device, &fenceCreateInfo, null, out handle); SubmitFences[i] = handle; ToDispose(new ActionDisposable(() => { vkDestroyFence(Context.Device, handle, null); })); } // Allow concrete samples to initialize their resources. InitializePermanent(); _initializingPermanent = false; InitializeFrame(); // Record commands for execution by Vulkan. RecordCommandBuffers(); }
static void Main(string[] args) { Console.WriteLine(AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES").ToString()); Console.WriteLine($"Hello Vulkan!"); Init(); if (!GLFW.Vulkan.IsSupported) { Console.Error.WriteLine("GLFW says that vulkan is not supported."); return; } WindowHint(Hint.ClientApi, ClientApi.None); NativeWindow window = new GLFW.NativeWindow(width, height, "Fabricor"); Glfw.SetKeyCallback(window, (a, b, c, d, e) => { GLFWInput.KeyCallback(a, b, c, d, e); }); FInstance finst = new FInstance(); VkSurfaceKHR surface = CreateSurface(finst.instance, window); VkDevice device = CreateDevice(finst.instance, out var physicalDevice, surface, out var queueFamilyIndex); VkSwapchainKHR swapchain = CreateSwapchain(VkSwapchainKHR.Null, finst.instance, device, physicalDevice, surface, queueFamilyIndex); VkRenderPass renderPass = CreateRenderPass(device); uint swapchainImageCount = 0; Assert(vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, null));////////////IMAGES VkImage[] swapchainImages = new VkImage[swapchainImageCount]; fixed(VkImage *ptr = &swapchainImages[0]) Assert(vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, ptr)); CommandPoolManager.Init(device, queueFamilyIndex); int poolId = CommandPoolManager.CreateCommandPool(VkCommandPoolCreateFlags.ResetCommandBuffer); VkSemaphoreCreateInfo pCreateInfo = VkSemaphoreCreateInfo.New(); VkSemaphore acquireSemaphore = new VkSemaphore(); vkCreateSemaphore(device, &pCreateInfo, null, &acquireSemaphore); VkSemaphore releaseSemaphore = new VkSemaphore(); vkCreateSemaphore(device, &pCreateInfo, null, &releaseSemaphore); VkQueue graphicsQueue = VkQueue.Null; vkGetDeviceQueue(device, queueFamilyIndex, 0, &graphicsQueue); string[] textures = new string[] { "res/Linus.png", "res/Alex.png", "res/Victor.png", "res/Alex2.png", //"res/Cyan.png", "res/Alex3.png", //"res/Red.png", }; FTexture texture = new FTexture(device, physicalDevice, poolId, graphicsQueue, textures, VkFormat.R8g8b8a8Unorm, 512, 512, (uint)(Math.Log(512) / Math.Log(2)) + 1); VkPipelineCache pipelineCache = VkPipelineCache.Null;//This is critcal for performance. FGraphicsPipeline voxelPipeline = new FGraphicsPipeline(device, physicalDevice, pipelineCache, renderPass, "shaders/voxel", swapchainImageCount, texture); voxelPipeline.CreateDepthBuffer(physicalDevice, (uint)width, (uint)height); VkImageView[] swapchainImageViews = new VkImageView[swapchainImageCount]; for (int i = 0; i < swapchainImageCount; i++) { swapchainImageViews[i] = FTexture.CreateColourImageView(device, swapchainImages[i], surfaceFormat.format); } VkFramebuffer[] frambuffers = new VkFramebuffer[swapchainImageCount]; for (int i = 0; i < swapchainImageCount; i++) { frambuffers[i] = CreateFramebuffer(device, renderPass, swapchainImageViews[i], voxelPipeline.depthImageView); } MeshWrapper <VoxelVertex> mesh = VoxelMeshFactory.GenerateMesh(device, physicalDevice); Action updateMesh = delegate { VoxelMeshFactory.UpdateMesh(device, physicalDevice, mesh); }; GLFWInput.Subscribe(Keys.U, updateMesh, InputState.Press); Action changeTexture = delegate { Span <VoxelVertex> span = mesh.Mesh.vertices.Map(); for (int j = 0; j < span.Length; j++) { span[j].textureId++; } span = mesh.Mesh.vertices.UnMap(); }; GLFWInput.Subscribe(Keys.F, changeTexture, InputState.Press); FCommandBuffer[] cmdBuffers = new FCommandBuffer[swapchainImageCount]; VkFence[] fences = new VkFence[swapchainImageCount]; for (int i = 0; i < swapchainImageCount; i++) { cmdBuffers[i] = new FCommandBuffer(device, poolId); VkFenceCreateInfo createInfo = VkFenceCreateInfo.New(); createInfo.flags = VkFenceCreateFlags.Signaled; VkFence fence = VkFence.Null; Assert(vkCreateFence(device, &createInfo, null, &fence)); fences[i] = fence; } FCamera camera = new FCamera(); camera.AspectWidth = width; camera.AspectHeight = height; camera.position.Z = -1f; //camera.rotation=Quaternion.CreateFromYawPitchRoll(MathF.PI,0,0); double lastTime = Glfw.Time; int nbFrames = 0; while (!WindowShouldClose(window)) { PollEvents(); GLFWInput.Update(); // Measure speed double currentTime = Glfw.Time; nbFrames++; if (currentTime - lastTime >= 1.0) { // If last prinf() was more than 1 sec ago // printf and reset timer Console.WriteLine($"ms/frame: {1000.0 / nbFrames}"); nbFrames = 0; lastTime += 1.0; } if (GLFWInput.TimeKeyPressed(Keys.D) > 0) { camera.position += Vector3.Transform(Vector3.UnitX * 0.00015f, camera.rotation); } if (GLFWInput.TimeKeyPressed(Keys.A) > 0) { camera.position -= Vector3.Transform(Vector3.UnitX * 0.00015f, camera.rotation); } if (GLFWInput.TimeKeyPressed(Keys.W) > 0) { camera.position += Vector3.Transform(Vector3.UnitZ * 0.00015f, camera.rotation); } if (GLFWInput.TimeKeyPressed(Keys.S) > 0) { camera.position -= Vector3.Transform(Vector3.UnitZ * 0.00015f, camera.rotation); } if (GLFWInput.TimeKeyPressed(Keys.Space) > 0) { camera.position += Vector3.Transform(Vector3.UnitY * 0.00015f, camera.rotation); } if (GLFWInput.TimeKeyPressed(Keys.LeftShift) > 0) { camera.position -= Vector3.Transform(Vector3.UnitY * 0.00015f, camera.rotation); } if (GLFWInput.TimeKeyPressed(Keys.Right) > 0) { camera.rotation *= Quaternion.CreateFromAxisAngle(Vector3.UnitY, 0.00015f); } if (GLFWInput.TimeKeyPressed(Keys.Left) > 0) { camera.rotation *= Quaternion.CreateFromAxisAngle(Vector3.UnitY, -0.00015f); } uint imageIndex = 0; Assert(vkAcquireNextImageKHR(device, swapchain, ulong.MaxValue, acquireSemaphore, VkFence.Null, &imageIndex)); VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.New(); beginInfo.flags = VkCommandBufferUsageFlags.OneTimeSubmit; voxelPipeline.swapchainFramebuffer = frambuffers[imageIndex]; voxelPipeline.swapchainImage = swapchainImages[imageIndex]; voxelPipeline.swapchainImageIndex = imageIndex; voxelPipeline.mesh = mesh; voxelPipeline.camera = camera; fixed(VkFence *ptr = &(fences[imageIndex])) { vkWaitForFences(device, 1, ptr, VkBool32.False, ulong.MaxValue); vkResetFences(device, 1, ptr); } cmdBuffers[imageIndex].RecordCommandBuffer(new Action <VkCommandBuffer>[] { voxelPipeline.Execute, }); VkPipelineStageFlags submitStageMask = VkPipelineStageFlags.ColorAttachmentOutput; VkSubmitInfo submitInfo = VkSubmitInfo.New(); submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &acquireSemaphore; submitInfo.pWaitDstStageMask = &submitStageMask; submitInfo.commandBufferCount = 1; fixed(VkCommandBuffer *ptr = &(cmdBuffers[imageIndex].buffer)) submitInfo.pCommandBuffers = ptr; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &releaseSemaphore; Assert(vkQueueSubmit(graphicsQueue, 1, &submitInfo, fences[imageIndex])); VkPresentInfoKHR presentInfoKHR = VkPresentInfoKHR.New(); presentInfoKHR.swapchainCount = 1; presentInfoKHR.pSwapchains = &swapchain; presentInfoKHR.pImageIndices = &imageIndex; presentInfoKHR.waitSemaphoreCount = 1; presentInfoKHR.pWaitSemaphores = &releaseSemaphore; Assert(vkQueuePresentKHR(graphicsQueue, &presentInfoKHR)); vkDeviceWaitIdle(device); } finst.Destroy(); DestroyWindow(window); Terminate(); }
public GraphicsDevice(string applicationName, bool enableValidation, Window?window) { VkString name = applicationName; var appInfo = new VkApplicationInfo { sType = VkStructureType.ApplicationInfo, pApplicationName = name, applicationVersion = new VkVersion(1, 0, 0), pEngineName = s_EngineName, engineVersion = new VkVersion(1, 0, 0), apiVersion = vkEnumerateInstanceVersion() }; List <string> instanceExtensions = new List <string> { KHRSurfaceExtensionName }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { instanceExtensions.Add(KHRWin32SurfaceExtensionName); } List <string> instanceLayers = new List <string>(); if (enableValidation) { FindValidationLayers(instanceLayers); } if (instanceLayers.Count > 0) { instanceExtensions.Add(EXTDebugUtilsExtensionName); } using var vkInstanceExtensions = new VkStringArray(instanceExtensions); var instanceCreateInfo = new VkInstanceCreateInfo { sType = VkStructureType.InstanceCreateInfo, pApplicationInfo = &appInfo, enabledExtensionCount = vkInstanceExtensions.Length, ppEnabledExtensionNames = vkInstanceExtensions }; using var vkLayerNames = new VkStringArray(instanceLayers); if (instanceLayers.Count > 0) { instanceCreateInfo.enabledLayerCount = vkLayerNames.Length; instanceCreateInfo.ppEnabledLayerNames = vkLayerNames; } var debugUtilsCreateInfo = new VkDebugUtilsMessengerCreateInfoEXT { sType = VkStructureType.DebugUtilsMessengerCreateInfoEXT }; if (instanceLayers.Count > 0) { _debugMessengerCallbackFunc = DebugMessengerCallback; debugUtilsCreateInfo.messageSeverity = VkDebugUtilsMessageSeverityFlagsEXT.Error | VkDebugUtilsMessageSeverityFlagsEXT.Warning; debugUtilsCreateInfo.messageType = VkDebugUtilsMessageTypeFlagsEXT.Validation | VkDebugUtilsMessageTypeFlagsEXT.Performance; debugUtilsCreateInfo.pfnUserCallback = Marshal.GetFunctionPointerForDelegate(_debugMessengerCallbackFunc); instanceCreateInfo.pNext = &debugUtilsCreateInfo; } VkResult result = vkCreateInstance(&instanceCreateInfo, null, out VkInstance); if (result != VkResult.Success) { throw new InvalidOperationException($"Failed to create vulkan instance: {result}"); } vkLoadInstance(VkInstance); if (instanceLayers.Count > 0) { vkCreateDebugUtilsMessengerEXT(VkInstance, &debugUtilsCreateInfo, null, out _debugMessenger).CheckResult(); } Log.Info($"Created VkInstance with version: {appInfo.apiVersion.Major}.{appInfo.apiVersion.Minor}.{appInfo.apiVersion.Patch}"); if (instanceLayers.Count > 0) { foreach (var layer in instanceLayers) { Log.Info($"Instance layer '{layer}'"); } } foreach (string extension in instanceExtensions) { Log.Info($"Instance extension '{extension}'"); } _surface = CreateSurface(window); // Find physical device, setup queue's and create device. var physicalDevices = vkEnumeratePhysicalDevices(VkInstance); foreach (var physicalDevice in physicalDevices) { vkGetPhysicalDeviceProperties(physicalDevice, out var properties); var deviceName = properties.GetDeviceName(); } PhysicalDevice = physicalDevices[0]; var queueFamilies = FindQueueFamilies(PhysicalDevice, _surface); var priority = 1.0f; var queueCreateInfo = new VkDeviceQueueCreateInfo { sType = VkStructureType.DeviceQueueCreateInfo, queueFamilyIndex = queueFamilies.graphicsFamily, queueCount = 1, pQueuePriorities = &priority }; List <string> deviceExtensions = new List <string> { KHRSwapchainExtensionName }; var deviceCreateInfo = new VkDeviceCreateInfo { sType = VkStructureType.DeviceCreateInfo, pQueueCreateInfos = &queueCreateInfo, queueCreateInfoCount = 1, pEnabledFeatures = null, }; using var deviceExtensionNames = new VkStringArray(deviceExtensions); deviceCreateInfo.enabledExtensionCount = deviceExtensionNames.Length; deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; result = vkCreateDevice(PhysicalDevice, &deviceCreateInfo, null, out VkDevice); if (result != VkResult.Success) { throw new Exception($"Failed to create Vulkan Logical Device, {result}"); } vkGetDeviceQueue(VkDevice, queueFamilies.graphicsFamily, 0, out GraphicsQueue); vkGetDeviceQueue(VkDevice, queueFamilies.presentFamily, 0, out PresentQueue); // Create swap chain Swapchain = new Swapchain(this, window); _perFrame = new PerFrame[Swapchain.ImageCount]; for (var i = 0; i < _perFrame.Length; i++) { VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo(VkFenceCreateFlags.Signaled); vkCreateFence(VkDevice, &fenceCreateInfo, null, out _perFrame[i].QueueSubmitFence).CheckResult(); VkCommandPoolCreateInfo poolCreateInfo = new VkCommandPoolCreateInfo { sType = VkStructureType.CommandPoolCreateInfo, flags = VkCommandPoolCreateFlags.Transient, queueFamilyIndex = queueFamilies.graphicsFamily, }; vkCreateCommandPool(VkDevice, &poolCreateInfo, null, out _perFrame[i].PrimaryCommandPool).CheckResult(); VkCommandBufferAllocateInfo commandBufferInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = _perFrame[i].PrimaryCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1 }; vkAllocateCommandBuffers(VkDevice, &commandBufferInfo, out _perFrame[i].PrimaryCommandBuffer).CheckResult(); } }