protected virtual void Draw(Timer timer) { // Acquire an index of drawing image for this frame. uint nextImageIndex; VkResult result = vkAcquireNextImageKHR(Context.Device, Swapchain, ulong.MaxValue, ImageAvailableSemaphore, VkFence.Null, out nextImageIndex); result.CheckResult(); // Use a fence to wait until the command buffer has finished execution before using it again VkFence fence = SubmitFences[nextImageIndex]; result = vkWaitForFences(Context.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); result = vkResetFences(Context.Device, 1, &fence); result.CheckResult(); VkSemaphore signalSemaphore = RenderingFinishedSemaphore; VkSemaphore waitSemaphore = ImageAvailableSemaphore; VkPipelineStageFlags waitStages = VkPipelineStageFlags.ColorAttachmentOutput; VkCommandBuffer commandBuffer = CommandBuffers[nextImageIndex]; VkSubmitInfo submitInfo = new VkSubmitInfo() { sType = VkStructureType.SubmitInfo, waitSemaphoreCount = 1, pWaitSemaphores = &waitSemaphore, pWaitDstStageMask = &waitStages, commandBufferCount = 1, pCommandBuffers = &commandBuffer, signalSemaphoreCount = 1, pSignalSemaphores = &signalSemaphore, }; result = vkQueueSubmit(Context.GraphicsQueue, 1, &submitInfo, SubmitFences[nextImageIndex]); result.CheckResult(); // Present the color output to screen. VkSemaphore waitSemaphoreHandle = RenderingFinishedSemaphore; VkSwapchainKHR swapchainHandle = Swapchain; var nativePresentInfo = new VkPresentInfoKHR { sType = VkStructureType.PresentInfoKHR, pNext = null, waitSemaphoreCount = 1, pWaitSemaphores = &waitSemaphoreHandle, swapchainCount = 1, pSwapchains = &swapchainHandle, pImageIndices = &nextImageIndex }; result = vkQueuePresentKHR(Context.PresentQueue, &nativePresentInfo); result.CheckResult(); }
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)); }
private VkImage[] GetSwapchainImages(VkSwapchainKHR swapchain) { uint swapchainImageCount; VkResult result = vkGetSwapchainImagesKHR(Context.Device, swapchain, &swapchainImageCount, null); result.CheckResult(); var swapchainImages = stackalloc VkImage[(int)swapchainImageCount]; result = vkGetSwapchainImagesKHR(Context.Device, swapchain, &swapchainImageCount, swapchainImages); result.CheckResult(); var images = new VkImage[swapchainImageCount]; for (int i = 0; i < swapchainImageCount; i++) { images[i] = swapchainImages[i]; } return(images); }
private VkSemaphore CreateSemaphore(VkDevice device) { VkSemaphoreCreateInfo createInfo = new VkSemaphoreCreateInfo { sType = VkStructureType.SemaphoreCreateInfo, pNext = null }; VkSemaphore semaphore; VkResult result = vkCreateSemaphore(device, &createInfo, null, out semaphore); result.CheckResult(); return(semaphore); }
public VulkanContext(VkInstance instance, VkSurfaceKHR surface, Platform platform) { // Find graphics and presentation capable physical device(s) that support // the provided surface for platform. int graphicsQueueFamilyIndex = -1; int computeQueueFamilyIndex = -1; int presentQueueFamilyIndex = -1; var physicalDevices = vkEnumeratePhysicalDevices(instance); foreach (var physicalDevice in physicalDevices) { uint Count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &Count, null); VkQueueFamilyProperties *queueFamilyPropertiesptr = stackalloc VkQueueFamilyProperties[(int)Count]; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &Count, queueFamilyPropertiesptr); for (int i = 0; i < Count; i++) { if (queueFamilyPropertiesptr[i].queueFlags.HasFlag(VkQueueFlags.Graphics)) { if (graphicsQueueFamilyIndex == -1) { graphicsQueueFamilyIndex = i; } if (computeQueueFamilyIndex == -1) { computeQueueFamilyIndex = i; } VkBool32 isSupported; uint queueFamilyIndex = (uint)i; VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, out isSupported); result.CheckResult(); if (isSupported == VkBool32.True) { bool presentationSupport = false; if (platform == Platform.Win32) { presentationSupport = vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex); } else { presentationSupport = true; } if (presentationSupport) { presentQueueFamilyIndex = i; } } if (graphicsQueueFamilyIndex != -1 && computeQueueFamilyIndex != -1 && presentQueueFamilyIndex != -1) { PhysicalDevice = physicalDevice; break; } } } if (PhysicalDevice != null) { break; } } if (PhysicalDevice == null) { throw new InvalidOperationException("No suitable physical device found."); } vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); MemoryProperties = memoryProperties; vkGetPhysicalDeviceFeatures(PhysicalDevice, out VkPhysicalDeviceFeatures features); Features = features; vkGetPhysicalDeviceProperties(PhysicalDevice, out VkPhysicalDeviceProperties physicalDeviceProperties); Properties = physicalDeviceProperties; // Create a logical device. bool sameGraphicsAndPresent = graphicsQueueFamilyIndex == presentQueueFamilyIndex; VkDeviceQueueCreateInfo *queueCreateInfos = stackalloc VkDeviceQueueCreateInfo[sameGraphicsAndPresent ? 1 : 2]; float defaultQueuePriority = 1.0f; VkDeviceQueueCreateInfo queueInfoGraphics = new VkDeviceQueueCreateInfo { sType = VkStructureType.DeviceQueueCreateInfo, queueFamilyIndex = (uint)graphicsQueueFamilyIndex, queueCount = 1, pQueuePriorities = &defaultQueuePriority }; queueCreateInfos[0] = queueInfoGraphics; if (!sameGraphicsAndPresent) { queueCreateInfos[1] = new VkDeviceQueueCreateInfo { sType = VkStructureType.DeviceQueueCreateInfo, queueFamilyIndex = (uint)presentQueueFamilyIndex, queueCount = 1, pQueuePriorities = &defaultQueuePriority }; } VkDeviceCreateInfo deviceCreateInfo = new VkDeviceCreateInfo { sType = VkStructureType.DeviceCreateInfo, pNext = null, flags = VkDeviceCreateFlags.None, queueCreateInfoCount = (uint)(sameGraphicsAndPresent ? 1 : 2), pQueueCreateInfos = queueCreateInfos, }; deviceCreateInfo.pEnabledFeatures = &features; string[] deviceExtensions = new[] { // If the device will be used for presenting to a display via a swapchain we need to request the swapchain extension "VK_KHR_swapchain" }; deviceCreateInfo.enabledExtensionCount = (uint)deviceExtensions.Length; deviceCreateInfo.ppEnabledExtensionNames = Interop.String.AllocToPointers(deviceExtensions); VkResult result2 = vkCreateDevice(PhysicalDevice, &deviceCreateInfo, null, out VkDevice device); result2.CheckResult(); Device = device; // Get queue(s). GraphicsQueue = GetQueue((uint)graphicsQueueFamilyIndex); ComputeQueue = computeQueueFamilyIndex == graphicsQueueFamilyIndex ? GraphicsQueue : GetQueue((uint)computeQueueFamilyIndex); PresentQueue = presentQueueFamilyIndex == graphicsQueueFamilyIndex ? GraphicsQueue : GetQueue((uint)presentQueueFamilyIndex); GraphicsQueueFamilyIndex = graphicsQueueFamilyIndex; PresentQueueFamilyIndex = presentQueueFamilyIndex; ComputeQueueFamilyIndex = presentQueueFamilyIndex; GraphicsCommandPool = CreateCommandPool((uint)graphicsQueueFamilyIndex); ComputeCommandPool = CreateCommandPool((uint)computeQueueFamilyIndex); }
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 static VulkanImage DepthStencil(VulkanContext device, int width, int height) { VkFormat[] validFormats = { VkFormat.D32SFloatS8UInt, VkFormat.D32SFloat, VkFormat.D24UNormS8UInt, VkFormat.D16UNormS8UInt, VkFormat.D16UNorm }; VkFormat?potentialFormat = validFormats.FirstOrDefault( validFormat => { VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(device.PhysicalDevice, validFormat, out formatProps); return((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.DepthStencilAttachment) > 0); }); if (!potentialFormat.HasValue) { throw new InvalidOperationException("Required depth stencil format not supported."); } VkFormat format = potentialFormat.Value; VkImageCreateInfo imageCreateInfo = new VkImageCreateInfo { sType = VkStructureType.ImageCreateInfo, pNext = null, imageType = VkImageType.Image2D, format = format, extent = new Vortice.Mathematics.Size3 { Width = width, Height = height, Depth = 1 }, mipLevels = 1, arrayLayers = 1, samples = VkSampleCountFlags.Count1, tiling = VkImageTiling.Optimal, usage = VkImageUsageFlags.DepthStencilAttachment | VkImageUsageFlags.TransferSrc }; VkImage image; VkResult result = vkCreateImage(device.Device, &imageCreateInfo, null, out image); result.CheckResult(); VkMemoryRequirements memReq; vkGetImageMemoryRequirements(device.Device, image, out memReq); vkGetPhysicalDeviceMemoryProperties(device.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); uint heapIndex = BufferHelper.GetMemoryTypeIndex(memReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, memoryProperties); VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = memReq.size, memoryTypeIndex = heapIndex }; VkDeviceMemory memory; result = vkAllocateMemory(device.Device, &memAllocInfo, null, &memory); result.CheckResult(); result = vkBindImageMemory(device.Device, image, memory, 0); result.CheckResult(); VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, pNext = null, format = format, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Depth | VkImageAspectFlags.Stencil, 0, 1, 0, 1), image = image, viewType = VkImageViewType.Image2D }; VkImageView view; result = vkCreateImageView(device.Device, &imageViewCreateInfo, null, out view); result.CheckResult(); return(new VulkanImage(device, image, memory, view, format)); }
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 VkPipeline CreateGraphicsPipeline() { // Create shader modules. Shader modules are one of the objects required to create the // graphics pipeline. But after the pipeline is created, we don't need these shader // modules anymore, so we dispose them. VkShaderModule vertexShader = Content.LoadShader("Shader.vert.spv"); VkShaderModule fragmentShader = Content.LoadShader("Shader.frag.spv"); VkPipelineShaderStageCreateInfo *shaderStageCreateInfos = stackalloc VkPipelineShaderStageCreateInfo[2] { new VkPipelineShaderStageCreateInfo { sType = VkStructureType.PipelineShaderStageCreateInfo, pNext = null, stage = VkShaderStageFlags.Vertex, module = vertexShader, pName = Interop.String.ToPointer("main") }, new VkPipelineShaderStageCreateInfo { sType = VkStructureType.PipelineShaderStageCreateInfo, pNext = null, stage = VkShaderStageFlags.Fragment, module = fragmentShader, pName = Interop.String.ToPointer("main") } }; VkVertexInputBindingDescription vertexInputBindingDescription = new VkVertexInputBindingDescription { binding = 0, stride = (uint)Unsafe.SizeOf <Vertex>(), inputRate = VkVertexInputRate.Vertex }; VkVertexInputAttributeDescription *vertexInputAttributeDescription = stackalloc VkVertexInputAttributeDescription[3] { new VkVertexInputAttributeDescription { location = 0, binding = 0, format = VkFormat.R32G32B32A32SFloat, offset = 0 }, // Position. new VkVertexInputAttributeDescription { location = 1, binding = 0, format = VkFormat.R32G32B32SFloat, offset = 12 }, // Normal. new VkVertexInputAttributeDescription { location = 2, binding = 0, format = VkFormat.R32G32SFloat, offset = 24 }// TexCoord. }; var vertexInputStateCreateInfo = new VkPipelineVertexInputStateCreateInfo { sType = VkStructureType.PipelineVertexInputStateCreateInfo, pNext = null, vertexBindingDescriptionCount = 1, pVertexBindingDescriptions = &vertexInputBindingDescription, vertexAttributeDescriptionCount = 3, pVertexAttributeDescriptions = vertexInputAttributeDescription }; var inputAssemblyStateCreateInfo = new VkPipelineInputAssemblyStateCreateInfo { sType = VkStructureType.PipelineInputAssemblyStateCreateInfo, pNext = null, topology = VkPrimitiveTopology.TriangleList }; Viewport viewport = new Viewport(0, 0, Host.Width, Host.Height); Rectangle scissor = new Rectangle(0, 0, Host.Width, Host.Height); var viewportStateCreateInfo = new VkPipelineViewportStateCreateInfo { sType = VkStructureType.PipelineViewportStateCreateInfo, pNext = null, viewportCount = 1, pViewports = &viewport, scissorCount = 1, pScissors = &scissor }; var rasterizationStateCreateInfo = new VkPipelineRasterizationStateCreateInfo { sType = VkStructureType.PipelineRasterizationStateCreateInfo, polygonMode = VkPolygonMode.Fill, cullMode = VkCullModeFlags.Back, frontFace = VkFrontFace.CounterClockwise, lineWidth = 1.0f }; var multisampleStateCreateInfo = new VkPipelineMultisampleStateCreateInfo { sType = VkStructureType.PipelineMultisampleStateCreateInfo, rasterizationSamples = VkSampleCountFlags.Count1, minSampleShading = 1.0f }; var depthStencilStateCreateInfo = new VkPipelineDepthStencilStateCreateInfo { sType = VkStructureType.PipelineDepthStencilStateCreateInfo, depthTestEnable = true, depthWriteEnable = true, depthCompareOp = VkCompareOp.LessOrEqual, back = new VkStencilOpState { failOp = VkStencilOp.Keep, passOp = VkStencilOp.Keep, compareOp = VkCompareOp.Always }, front = new VkStencilOpState { failOp = VkStencilOp.Keep, passOp = VkStencilOp.Keep, compareOp = VkCompareOp.Always } }; var colorBlendAttachmentState = new VkPipelineColorBlendAttachmentState { srcColorBlendFactor = VkBlendFactor.One, dstColorBlendFactor = VkBlendFactor.Zero, colorBlendOp = VkBlendOp.Add, srcAlphaBlendFactor = VkBlendFactor.One, dstAlphaBlendFactor = VkBlendFactor.Zero, alphaBlendOp = VkBlendOp.Add, colorWriteMask = VkColorComponentFlags.All }; var colorBlendStateCreateInfo = new VkPipelineColorBlendStateCreateInfo { sType = VkStructureType.PipelineColorBlendStateCreateInfo, pNext = null, attachmentCount = 1, pAttachments = &colorBlendAttachmentState }; var pipelineCreateInfo = new VkGraphicsPipelineCreateInfo { sType = VkStructureType.GraphicsPipelineCreateInfo, pNext = null, layout = _pipelineLayout, renderPass = _renderPass, subpass = (uint)0, stageCount = 2, pStages = shaderStageCreateInfos, pInputAssemblyState = &inputAssemblyStateCreateInfo, pVertexInputState = &vertexInputStateCreateInfo, pRasterizationState = &rasterizationStateCreateInfo, pMultisampleState = &multisampleStateCreateInfo, pColorBlendState = &colorBlendStateCreateInfo, pDepthStencilState = &depthStencilStateCreateInfo, pViewportState = &viewportStateCreateInfo }; VkPipeline pipeline; VkResult result = vkCreateGraphicsPipelines(Context.Device, VkPipelineCache.Null, 1, &pipelineCreateInfo, null, &pipeline); result.CheckResult(); return(pipeline); } } }
private void RecordCommandBuffers() { VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange() { aspectMask = VkImageAspectFlags.Color, baseMipLevel = 0, baseArrayLayer = 0, layerCount = 1, levelCount = 1 }; for (int i = 0; i < CommandBuffers.Length; i++) { VkCommandBuffer cmdBuffer = CommandBuffers[i]; VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.SimultaneousUse }; vkBeginCommandBuffer(cmdBuffer, &beginInfo); if (Context.PresentQueue != Context.GraphicsQueue) { var barrierFromPresentToDraw = new VkImageMemoryBarrier( SwapchainImages[i], subresourceRange, VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentWrite, VkImageLayout.Undefined, VkImageLayout.PresentSrcKHR, (uint)Context.PresentQueueFamilyIndex, (uint)Context.GraphicsQueueFamilyIndex); vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.ColorAttachmentOutput, 0, 0, null, 0, null, 1, &barrierFromPresentToDraw ); } RecordCommandBuffer(cmdBuffer, i); if (Context.PresentQueue != Context.GraphicsQueue) { var barrierFromDrawToPresent = new VkImageMemoryBarrier( SwapchainImages[i], subresourceRange, VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead, VkImageLayout.PresentSrcKHR, VkImageLayout.PresentSrcKHR, (uint)Context.GraphicsQueueFamilyIndex, (uint)Context.PresentQueueFamilyIndex); vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, 0, 0, null, 0, null, 1, &barrierFromDrawToPresent ); } VkResult result = vkEndCommandBuffer(cmdBuffer); result.CheckResult(); } }
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(); }