public Swapchain(GraphicsDevice device, Window window) { Device = device; Window = window; SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(device.PhysicalDevice, device._surface); VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.Formats); VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.PresentModes); _extent = ChooseSwapExtent(swapChainSupport.Capabilities); CreateRenderPass(surfaceFormat.format); uint imageCount = swapChainSupport.Capabilities.minImageCount + 1; if (swapChainSupport.Capabilities.maxImageCount > 0 && imageCount > swapChainSupport.Capabilities.maxImageCount) { imageCount = swapChainSupport.Capabilities.maxImageCount; } var createInfo = new VkSwapchainCreateInfoKHR { sType = VkStructureType.SwapchainCreateInfoKHR, surface = device._surface, minImageCount = imageCount, imageFormat = surfaceFormat.format, imageColorSpace = surfaceFormat.colorSpace, imageExtent = _extent, imageArrayLayers = 1, imageUsage = VkImageUsageFlags.ColorAttachment, imageSharingMode = VkSharingMode.Exclusive, preTransform = swapChainSupport.Capabilities.currentTransform, compositeAlpha = VkCompositeAlphaFlagsKHR.Opaque, presentMode = presentMode, clipped = true, oldSwapchain = VkSwapchainKHR.Null }; vkCreateSwapchainKHR(device.VkDevice, &createInfo, null, out Handle).CheckResult(); var swapChainImages = vkGetSwapchainImagesKHR(device.VkDevice, Handle); _swapChainImageViews = new VkImageView[swapChainImages.Length]; _framebuffers = new VkFramebuffer[swapChainImages.Length]; for (var i = 0; i < swapChainImages.Length; i++) { var viewCreateInfo = new VkImageViewCreateInfo( swapChainImages[i], VkImageViewType.Image2D, surfaceFormat.format, VkComponentMapping.Identity, new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1) ); vkCreateImageView(Device.VkDevice, &viewCreateInfo, null, out _swapChainImageViews[i]).CheckResult(); vkCreateFramebuffer(Device.VkDevice, RenderPass, new[] { _swapChainImageViews[i] }, (uint)_extent.Width, (uint)_extent.Height, 1u, out _framebuffers[i]); } }
public static VkPresentModeKHR[] GetSurfacePresentModes(this VkPhysicalDevice phy, VkSurfaceKHR surf) { vkGetPhysicalDeviceSurfacePresentModesKHR(phy, surf, out uint count, IntPtr.Zero); VkPresentModeKHR[] modes = new VkPresentModeKHR[count]; vkGetPhysicalDeviceSurfacePresentModesKHR(phy, surf, out count, modes.Pin()); modes.Unpin(); return(modes); }
private void CreateSwapchain() { SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(physicalDevice, surface); VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.Formats); VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.PresentModes); var extent = ChooseSwapExtent(swapChainSupport.Capabilities); uint imageCount = swapChainSupport.Capabilities.minImageCount + 1; if (swapChainSupport.Capabilities.maxImageCount > 0 && imageCount > swapChainSupport.Capabilities.maxImageCount) { imageCount = swapChainSupport.Capabilities.maxImageCount; } var createInfo = new VkSwapchainCreateInfoKHR { sType = VkStructureType.SwapchainCreateInfoKHR, surface = surface, minImageCount = imageCount, imageFormat = surfaceFormat.format, imageColorSpace = surfaceFormat.colorSpace, imageExtent = extent, imageArrayLayers = 1, imageUsage = VkImageUsageFlags.ColorAttachment, imageSharingMode = VkSharingMode.Exclusive, preTransform = swapChainSupport.Capabilities.currentTransform, compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR, presentMode = presentMode, clipped = true, oldSwapchain = VkSwapchainKHR.Null }; vkCreateSwapchainKHR(device, &createInfo, null, out swapchain).CheckResult(); var swapChainImages = vkGetSwapchainImagesKHR(device, swapchain); swapChainImageViews = new VkImageView[swapChainImages.Length]; for (var i = 0; i < swapChainImages.Length; i++) { var viewCreateInfo = new VkImageViewCreateInfo( swapChainImages[i], VkImageViewType.Image2D, surfaceFormat.format, VkComponentMapping.Identity, new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1) ); vkCreateImageView(device, &viewCreateInfo, null, out swapChainImageViews[i]).CheckResult(); } }
public VkObjectResult <IReadOnlyList <VkPresentModeKHR> > GetSurfacePresentModesKHR(IVkSurfaceKHR surface) { int count; Direct.GetPhysicalDeviceSurfacePresentModesKHR(Handle, surface.Handle, &count, null).CheckSuccess(); var resultArray = new VkPresentModeKHR[count]; fixed(VkPresentModeKHR *pResults = resultArray) { var result = Direct.GetPhysicalDeviceSurfacePresentModesKHR(Handle, surface.Handle, &count, pResults); return(new VkObjectResult <IReadOnlyList <VkPresentModeKHR> >(result, resultArray)); } }
public static ReadOnlySpan <VkPresentModeKHR> vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { uint presentModeCount = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, null).CheckResult(); ReadOnlySpan <VkPresentModeKHR> presentModes = new VkPresentModeKHR[presentModeCount]; fixed(VkPresentModeKHR *presentModesPtr = presentModes) { vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModesPtr).CheckResult(); } return(presentModes); }
public VkPresentModeKHR[] GetPhysicalDeviceSurfacePresentModesKHR(VkSurfaceKHR surface) { unsafe { VkPresentModeKHR[] props; uint count = 0; do { props = new VkPresentModeKHR[count]; fixed(VkPresentModeKHR *pptr = props) VkException.Check(vkGetPhysicalDeviceSurfacePresentModesKHR(this, surface, &count, pptr)); } while (props.Length != count); return(props); } }
/// <summary> /// Returns global layer properties. /// </summary> /// <returns></returns> public static VkPresentModeKHR[] PresentModesKHR(VkPhysicalDevice device, VkSurfaceKHR surface) { VkPresentModeKHR[] result; UInt32 count; vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &count, null); result = new VkPresentModeKHR[count]; if (count > 0) { fixed(VkPresentModeKHR *pointer = result) { vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &count, pointer); } } return(result); }
/// <summary> /// Create a new managed `SwapChain` object. Native object will only be created with a call to the 'Create` method. /// </summary> /// <param name="_presentableQueue">Presentable queue.</param> /// <param name="width">Swapchain x dimension.</param> /// <param name="height">Swapchain y dimension.</param> /// <param name="format">Swapchain's images format.</param> /// <param name="presentMode">a present mode supported by the engine as returned by the `GetSurfacePresentModes` method of the `PhysicalDevice`</param> public SwapChain(PresentQueue _presentableQueue, uint width = 800, uint height = 600, VkFormat format = VkFormat.B8g8r8a8Unorm, VkPresentModeKHR presentMode = VkPresentModeKHR.FifoKHR) : base(_presentableQueue.dev) { presentQueue = _presentableQueue; createInfos = VkSwapchainCreateInfoKHR.New(); VkSurfaceFormatKHR[] formats = Dev.phy.GetSurfaceFormats(presentQueue.Surface); for (int i = 0; i < formats.Length; i++) { if (formats[i].format == format) { createInfos.imageFormat = format; createInfos.imageColorSpace = formats[i].colorSpace; break; } } if (createInfos.imageFormat == VkFormat.Undefined) { throw new Exception("Invalid format for swapchain: " + format); } VkPresentModeKHR[] presentModes = Dev.phy.GetSurfacePresentModes(presentQueue.Surface); for (int i = 0; i < presentModes.Length; i++) { if (presentModes[i] == presentMode) { createInfos.presentMode = presentMode; break; } } if (createInfos.presentMode != presentMode) { throw new Exception("Invalid presentMode for swapchain: " + presentMode); } createInfos.surface = presentQueue.Surface; createInfos.imageExtent = new VkExtent2D(width, height); createInfos.imageArrayLayers = 1; createInfos.imageUsage = IMAGES_USAGE; createInfos.imageSharingMode = VkSharingMode.Exclusive; createInfos.compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR; createInfos.presentMode = presentMode; createInfos.clipped = 1; }
private VkPresentModeKHR ChooseSwapPresentMode(VkPresentModeKHR[] presentModes) { VkPresentModeKHR bestMode = VkPresentModeKHR.VK_PRESENT_MODE_FIFO_KHR; foreach (var availablePresentMode in presentModes) { if (availablePresentMode == VkPresentModeKHR.VK_PRESENT_MODE_MAILBOX_KHR) { return(availablePresentMode); } else if (availablePresentMode == VkPresentModeKHR.VK_PRESENT_MODE_IMMEDIATE_KHR) { bestMode = VkPresentModeKHR.VK_PRESENT_MODE_IMMEDIATE_KHR; } } return(bestMode); }
public VkPresentModeKHR[] GetSurfacePresentModes(VkSurfaceKHR surf) { vkGetPhysicalDeviceSurfacePresentModesKHR(phy, surf, out uint count, IntPtr.Zero); if (Type.GetType("Mono.Runtime") == null) { uint[] modes = new uint[count]; //this cause an error on mono vkGetPhysicalDeviceSurfacePresentModesKHR(phy, surf, out count, modes.Pin()); modes.Unpin(); VkPresentModeKHR[] mds = new VkPresentModeKHR[count]; for (int i = 0; i < count; i++) { mds[i] = (VkPresentModeKHR)modes[i]; } return(mds); } else { VkPresentModeKHR[] modes = new VkPresentModeKHR[count]; //enums not blittable on ms.Net vkGetPhysicalDeviceSurfacePresentModesKHR(phy, surf, out count, modes.Pin()); modes.Unpin(); return(modes); } }
private VkSwapchainKHR CreateSwapchain() { VkSurfaceCapabilitiesKHR capabilities; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Context.PhysicalDevice, Surface, out capabilities).CheckResult(); uint count; vkGetPhysicalDeviceSurfaceFormatsKHR(Context.PhysicalDevice, Surface, &count, null); VkSurfaceFormatKHR[] formats = new VkSurfaceFormatKHR[(int)count]; fixed(VkSurfaceFormatKHR *formatsPtr = formats) vkGetPhysicalDeviceSurfaceFormatsKHR(Context.PhysicalDevice, Surface, &count, formatsPtr).CheckResult(); vkGetPhysicalDeviceSurfacePresentModesKHR(Context.PhysicalDevice, Surface, &count, null).CheckResult(); VkPresentModeKHR[] presentModes = new VkPresentModeKHR[count]; fixed(VkPresentModeKHR *presentModesPtr = presentModes) vkGetPhysicalDeviceSurfacePresentModesKHR(Context.PhysicalDevice, Surface, &count, presentModesPtr).CheckResult(); VkFormat format = formats.Length == 1 && formats[0].format == VkFormat.Undefined ? VkFormat.B8G8R8A8UNorm : formats[0].format; VkPresentModeKHR presentMode = presentModes.Contains(VkPresentModeKHR.Mailbox) ? VkPresentModeKHR.Mailbox : presentModes.Contains(VkPresentModeKHR.FifoRelaxed) ? VkPresentModeKHR.FifoRelaxed : presentModes.Contains(VkPresentModeKHR.Fifo) ? VkPresentModeKHR.Fifo : VkPresentModeKHR.Immediate; SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(Context.PhysicalDevice, Surface); VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.Formats); uint imageCount = swapChainSupport.Capabilities.minImageCount + 1; if (swapChainSupport.Capabilities.maxImageCount > 0 && imageCount > swapChainSupport.Capabilities.maxImageCount) { imageCount = swapChainSupport.Capabilities.maxImageCount; } SwapchainFormat = format; VkSwapchainCreateInfoKHR swapchainCI = new VkSwapchainCreateInfoKHR() { sType = VkStructureType.SwapchainCreateInfoKHR, pNext = null, surface = Surface, minImageCount = imageCount, imageFormat = format, imageColorSpace = surfaceFormat.colorSpace, imageExtent = capabilities.currentExtent, imageUsage = VkImageUsageFlags.ColorAttachment, preTransform = capabilities.currentTransform, imageArrayLayers = 1, imageSharingMode = VkSharingMode.Exclusive, queueFamilyIndexCount = 0, pQueueFamilyIndices = null, presentMode = presentMode, //oldSwapchain = SwapChain, // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the Surface area clipped = true, compositeAlpha = VkCompositeAlphaFlagsKHR.Opaque, }; VkSwapchainKHR SwapChain; vkCreateSwapchainKHR(Context.Device, &swapchainCI, null, out SwapChain).CheckResult(); return(SwapChain); }
/** * Create the swapchain and get it's Images with given width and height * * @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param vsync (Optional) Can be used to force vsync'd rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode) */ public void Create(uint *width, uint *height, bool vsync = false) { VkResult err; VkSwapchainKHR oldSwapchain = Swapchain; // Get physical Device Surface properties and formats VkSurfaceCapabilitiesKHR surfCaps; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(PhysicalDevice, Surface, &surfCaps); Debug.Assert(err == VkResult.Success); // Get available present modes uint presentModeCount; err = vkGetPhysicalDeviceSurfacePresentModesKHR(PhysicalDevice, Surface, &presentModeCount, null); Debug.Assert(err == VkResult.Success); Debug.Assert(presentModeCount > 0); using (NativeList <VkPresentModeKHR> presentModes = new NativeList <VkPresentModeKHR>(presentModeCount)) { err = vkGetPhysicalDeviceSurfacePresentModesKHR(PhysicalDevice, Surface, &presentModeCount, (VkPresentModeKHR *)presentModes.Data); Debug.Assert(err == VkResult.Success); presentModes.Count = presentModeCount; VkExtent2D swapchainExtent; // If width (and height) equals the special value 0xFFFFFFFF, the size of the Surface will be set by the swapchain if (surfCaps.currentExtent.width == unchecked ((uint)-1)) { // If the Surface size is undefined, the size is set to // the size of the Images requested. swapchainExtent.width = *width; swapchainExtent.height = *height; } else { // If the Surface size is defined, the swap chain size must match swapchainExtent = surfCaps.currentExtent; *width = surfCaps.currentExtent.width; *height = surfCaps.currentExtent.height; } // Select a present mode for the swapchain // The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec // This mode waits for the vertical blank ("v-sync") VkPresentModeKHR swapchainPresentMode = VkPresentModeKHR.FifoKHR; // If v-sync is not requested, try to find a mailbox mode // It's the lowest latency non-tearing present mode available if (!vsync) { for (uint i = 0; i < presentModeCount; i++) { if (presentModes[i] == VkPresentModeKHR.MailboxKHR) { swapchainPresentMode = VkPresentModeKHR.MailboxKHR; break; } if ((swapchainPresentMode != VkPresentModeKHR.MailboxKHR) && (presentModes[i] == VkPresentModeKHR.ImmediateKHR)) { swapchainPresentMode = VkPresentModeKHR.ImmediateKHR; } } } // Determine the number of Images uint desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1; if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) { desiredNumberOfSwapchainImages = surfCaps.maxImageCount; } // Find the transformation of the Surface VkSurfaceTransformFlagsKHR preTransform; if ((surfCaps.supportedTransforms & VkSurfaceTransformFlagsKHR.IdentityKHR) != 0) { // We prefer a non-rotated transform preTransform = VkSurfaceTransformFlagsKHR.IdentityKHR; } else { preTransform = surfCaps.currentTransform; } VkSwapchainCreateInfoKHR swapchainCI = VkSwapchainCreateInfoKHR.New(); swapchainCI.pNext = null; swapchainCI.surface = Surface; swapchainCI.minImageCount = desiredNumberOfSwapchainImages; swapchainCI.imageFormat = ColorFormat; swapchainCI.imageColorSpace = ColorSpace; swapchainCI.imageExtent = new VkExtent2D() { width = swapchainExtent.width, height = swapchainExtent.height }; swapchainCI.imageUsage = VkImageUsageFlags.ColorAttachment; swapchainCI.preTransform = preTransform; swapchainCI.imageArrayLayers = 1; swapchainCI.imageSharingMode = VkSharingMode.Exclusive; swapchainCI.queueFamilyIndexCount = 0; swapchainCI.pQueueFamilyIndices = null; swapchainCI.presentMode = swapchainPresentMode; swapchainCI.oldSwapchain = oldSwapchain; // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the Surface area swapchainCI.clipped = True; swapchainCI.compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR; // Set additional usage flag for blitting from the swapchain Images if supported VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(PhysicalDevice, ColorFormat, out formatProps); if ((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.BlitDst) != 0) { swapchainCI.imageUsage |= VkImageUsageFlags.TransferSrc; } VkSwapchainKHR swapChain; err = vkCreateSwapchainKHR(Device, &swapchainCI, null, out swapChain); Debug.Assert(err == VkResult.Success); Swapchain = swapChain; // If an existing swap chain is re-created, destroy the old swap chain // This also cleans up all the presentable Images if (oldSwapchain.Handle != 0) { for (uint i = 0; i < ImageCount; i++) { vkDestroyImageView(Device, Buffers[i].View, null); } vkDestroySwapchainKHR(Device, oldSwapchain, null); } uint imageCount; err = vkGetSwapchainImagesKHR(Device, swapChain, &imageCount, null); Debug.Assert(err == VkResult.Success); ImageCount = imageCount; // Get the swap chain Images Images.Resize(imageCount); err = vkGetSwapchainImagesKHR(Device, swapChain, &imageCount, (VkImage *)Images.Data.ToPointer()); Images.Count = imageCount; Debug.Assert(err == VkResult.Success); // Get the swap chain Buffers containing the image and imageview Buffers.Resize(imageCount); Buffers.Count = imageCount; for (uint i = 0; i < imageCount; i++) { VkImageViewCreateInfo colorAttachmentView = new VkImageViewCreateInfo(); colorAttachmentView.sType = VkStructureType.ImageViewCreateInfo; colorAttachmentView.pNext = null; colorAttachmentView.format = ColorFormat; colorAttachmentView.components = new VkComponentMapping() { r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A }; colorAttachmentView.subresourceRange.aspectMask = VkImageAspectFlags.Color; colorAttachmentView.subresourceRange.baseMipLevel = 0; colorAttachmentView.subresourceRange.levelCount = 1; colorAttachmentView.subresourceRange.baseArrayLayer = 0; colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.viewType = VkImageViewType.Image2D; colorAttachmentView.flags = 0; Buffers[i].Image = Images[i]; colorAttachmentView.image = Buffers[i].Image; VkImageView view; err = vkCreateImageView(Device, &colorAttachmentView, null, &view); Buffers[i].View = view; Debug.Assert(err == VkResult.Success); } } }
private void CreateSwapChain() { var swapChainSupport = new SwapChainSupportDetails(vkPhysicalDevice, vkSurface); VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.formats); VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.presentModes); VkExtent2D extent = ChooseSwapExtent(swapChainSupport.capabilities); uint imageCount = swapChainSupport.capabilities.minImageCount + 1; if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) { imageCount = Math.Min(imageCount, swapChainSupport.capabilities.maxImageCount); } var createInfo = new VkSwapchainCreateInfoKHR() { sType = VkStructureType.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, surface = vkSurface, minImageCount = imageCount, imageFormat = surfaceFormat.format, imageColorSpace = surfaceFormat.colorSpace, imageExtent = extent, imageArrayLayers = 1, imageUsage = VkImageUsageFlagBits.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, preTransform = swapChainSupport.capabilities.currentTransform, compositeAlpha = VkCompositeAlphaFlagBitsKHR.VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, presentMode = presentMode, clipped = true, }; var indices = new QueueFamilyIndices(vkPhysicalDevice, vkSurface); uint *QueueFamilyIndicesPtr = stackalloc uint[] { (uint)indices.GraphicsFamily, (uint)indices.PresentFamily, }; if (indices.GraphicsFamily != indices.PresentFamily) { createInfo.imageSharingMode = VkSharingMode.VK_SHARING_MODE_CONCURRENT; createInfo.pQueueFamilyIndices = QueueFamilyIndicesPtr; } else { createInfo.imageSharingMode = VkSharingMode.VK_SHARING_MODE_EXCLUSIVE; } VkSwapchainKHR newSwapChain; var result = VulkanNative.vkCreateSwapchainKHR(vkDevice, &createInfo, null, &newSwapChain); vkSwapChain = newSwapChain; Helpers.CheckErrors(result); VulkanNative.vkGetSwapchainImagesKHR(vkDevice, vkSwapChain, &imageCount, null); VkImage *images = stackalloc VkImage[(int)imageCount]; result = VulkanNative.vkGetSwapchainImagesKHR(vkDevice, vkSwapChain, &imageCount, images); Helpers.CheckErrors(result); vkSwapChainImages = new VkImage[imageCount]; for (int i = 0; i < imageCount; i++) { vkSwapChainImages[i] = images[i]; } vkSwapChainImageFormat = surfaceFormat.format; vkSwapChainExtent = extent; }
public static extern VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes);
/** * Create the swapchain and get it's Images with given width and height * * @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param vsync (Optional) Can be used to force vsync'd rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode) */ public unsafe void Create(ref uint width, ref uint height, bool vsync = false) { VkResult err; VkSwapchainKHR oldSwapchain = swapchain; // Get physical Device Surface properties and formats VkSurfaceCapabilitiesKHR surfCaps; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device.PhysicalDevice, Surface, out surfCaps); Debug.Assert(err == VkResult.Success); // Get available present modes uint presentModeCount; err = vkGetPhysicalDeviceSurfacePresentModesKHR(Device.PhysicalDevice, Surface, &presentModeCount, null); Debug.Assert(err == VkResult.Success); Debug.Assert(presentModeCount > 0); using (Vector <VkPresentModeKHR> presentModes = new Vector <VkPresentModeKHR>(presentModeCount)) { err = vkGetPhysicalDeviceSurfacePresentModesKHR(Device.PhysicalDevice, Surface, &presentModeCount, (VkPresentModeKHR *)presentModes.Data); Debug.Assert(err == VkResult.Success); presentModes.Count = presentModeCount; // If width (and height) equals the special value 0xFFFFFFFF, the size of the Surface will be set by the swapchain if (surfCaps.currentExtent.width != unchecked ((uint)-1)) { width = surfCaps.currentExtent.width; height = surfCaps.currentExtent.height; } extent = new VkExtent3D(width, height, 1); // Select a present mode for the swapchain // The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec // This mode waits for the vertical blank ("v-sync") VkPresentModeKHR swapchainPresentMode = VkPresentModeKHR.Fifo; // If v-sync is not requested, try to find a mailbox mode // It's the lowest latency non-tearing present mode available if (!vsync) { for (uint i = 0; i < presentModeCount; i++) { if (presentModes[i] == VkPresentModeKHR.Mailbox) { swapchainPresentMode = VkPresentModeKHR.Mailbox; break; } if ((swapchainPresentMode != VkPresentModeKHR.Mailbox) && (presentModes[i] == VkPresentModeKHR.Immediate)) { swapchainPresentMode = VkPresentModeKHR.Immediate; } } } // Determine the number of Images uint desiredNumberOfSwapchainImages = IMAGE_COUNT;// surfCaps.minImageCount + 1; if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) { Debug.Assert(false); desiredNumberOfSwapchainImages = surfCaps.maxImageCount; } // Find the transformation of the Surface VkSurfaceTransformFlagsKHR preTransform; if ((surfCaps.supportedTransforms & VkSurfaceTransformFlagsKHR.Identity) != 0) { // We prefer a non-rotated transform preTransform = VkSurfaceTransformFlagsKHR.Identity; } else { preTransform = surfCaps.currentTransform; } VkSwapchainCreateInfoKHR swapchainCI = new VkSwapchainCreateInfoKHR { sType = VkStructureType.SwapchainCreateInfoKHR, pNext = null, surface = Surface, minImageCount = desiredNumberOfSwapchainImages, imageFormat = ColorFormat, imageColorSpace = ColorSpace, imageExtent = new VkExtent2D(extent.width, extent.height), imageUsage = VkImageUsageFlags.ColorAttachment, preTransform = preTransform, imageArrayLayers = 1, imageSharingMode = VkSharingMode.Exclusive, queueFamilyIndexCount = 0, pQueueFamilyIndices = null, presentMode = swapchainPresentMode, oldSwapchain = oldSwapchain, // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the Surface area clipped = true, compositeAlpha = VkCompositeAlphaFlagsKHR.Opaque }; // Set additional usage flag for blitting from the swapchain Images if supported Device.GetPhysicalDeviceFormatProperties(ColorFormat, out VkFormatProperties formatProps); if ((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.BlitDst) != 0) { swapchainCI.imageUsage |= VkImageUsageFlags.TransferSrc; } swapchain = Device.CreateSwapchainKHR(ref swapchainCI); // If an existing swap chain is re-created, destroy the old swap chain // This also cleans up all the presentable Images if (oldSwapchain.Handle != 0) { for (uint i = 0; i < ImageCount; i++) { ImageViews[i].Dispose(); } Device.DestroySwapchainKHR(oldSwapchain); } var vkImages = Vulkan.vkGetSwapchainImagesKHR(Device.Handle, swapchain); VkImages.Clear(); Images = new Image[vkImages.Length]; ImageViews = new ImageView[vkImages.Length]; for (int i = 0; i < vkImages.Length; i++) { Images[i] = new Image(vkImages[i]) { imageType = VkImageType.Image2D, extent = extent }; ImageViews[i] = ImageView.Create(Images[i], VkImageViewType.Image2D, ColorFormat, VkImageAspectFlags.Color, 0, 1); } // Get the swap chain Images VkImages.Add(vkImages); } }
private void CreateSwapchain(uint width, uint height) { _currentImageIndex = 0; uint surfaceFormatCount = 0; vkGetPhysicalDeviceSurfaceFormatsKHR(_gd.PhysicalDevice, _surface, ref surfaceFormatCount, null); VkSurfaceFormatKHR[] formats = new VkSurfaceFormatKHR[surfaceFormatCount]; vkGetPhysicalDeviceSurfaceFormatsKHR(_gd.PhysicalDevice, _surface, ref surfaceFormatCount, out formats[0]); VkSurfaceFormatKHR surfaceFormat = new VkSurfaceFormatKHR(); if (formats.Length == 1 && formats[0].format == VkFormat.Undefined) { surfaceFormat = new VkSurfaceFormatKHR { colorSpace = VkColorSpaceKHR.SrgbNonlinearKHR, format = VkFormat.B8g8r8a8Unorm }; } else { foreach (VkSurfaceFormatKHR format in formats) { if (format.colorSpace == VkColorSpaceKHR.SrgbNonlinearKHR && format.format == VkFormat.B8g8r8a8Unorm) { surfaceFormat = format; break; } } if (surfaceFormat.format == VkFormat.Undefined) { surfaceFormat = formats[0]; } } uint presentModeCount = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(_gd.PhysicalDevice, _surface, ref presentModeCount, null); VkPresentModeKHR[] presentModes = new VkPresentModeKHR[presentModeCount]; vkGetPhysicalDeviceSurfacePresentModesKHR(_gd.PhysicalDevice, _surface, ref presentModeCount, out presentModes[0]); VkPresentModeKHR presentMode = VkPresentModeKHR.FifoKHR; if (presentModes.Contains(VkPresentModeKHR.MailboxKHR)) { presentMode = VkPresentModeKHR.MailboxKHR; } else if (presentModes.Contains(VkPresentModeKHR.ImmediateKHR)) { presentMode = VkPresentModeKHR.ImmediateKHR; } vkGetPhysicalDeviceSurfaceCapabilitiesKHR(_gd.PhysicalDevice, _surface, out VkSurfaceCapabilitiesKHR surfaceCapabilities); uint imageCount = surfaceCapabilities.minImageCount + 1; VkSwapchainCreateInfoKHR swapchainCI = VkSwapchainCreateInfoKHR.New(); swapchainCI.surface = _surface; swapchainCI.presentMode = presentMode; swapchainCI.imageFormat = surfaceFormat.format; swapchainCI.imageColorSpace = surfaceFormat.colorSpace; swapchainCI.imageExtent = new VkExtent2D { width = (uint)width, height = (uint)height }; swapchainCI.minImageCount = imageCount; swapchainCI.imageArrayLayers = 1; swapchainCI.imageUsage = VkImageUsageFlags.ColorAttachment; FixedArray2 <uint> queueFamilyIndices = new FixedArray2 <uint>(_gd.GraphicsQueueIndex, _gd.PresentQueueIndex); if (_gd.GraphicsQueueIndex != _gd.PresentQueueIndex) { swapchainCI.imageSharingMode = VkSharingMode.Concurrent; swapchainCI.queueFamilyIndexCount = 2; swapchainCI.pQueueFamilyIndices = &queueFamilyIndices.First; } else { swapchainCI.imageSharingMode = VkSharingMode.Exclusive; swapchainCI.queueFamilyIndexCount = 0; } swapchainCI.preTransform = surfaceCapabilities.currentTransform; swapchainCI.compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR; swapchainCI.clipped = true; VkSwapchainKHR oldSwapchain = _swapchain; swapchainCI.oldSwapchain = oldSwapchain; VkResult result = vkCreateSwapchainKHR(_gd.Device, ref swapchainCI, null, out _swapchain); CheckResult(result); if (oldSwapchain != VkSwapchainKHR.Null) { vkDestroySwapchainKHR(_gd.Device, oldSwapchain, null); } // Get the images uint scImageCount = 0; result = vkGetSwapchainImagesKHR(_gd.Device, _swapchain, ref scImageCount, null); CheckResult(result); if (_scImages == null) { _scImages = new VkImage[(int)scImageCount]; } result = vkGetSwapchainImagesKHR(_gd.Device, _swapchain, ref scImageCount, out _scImages[0]); CheckResult(result); _scImageFormat = surfaceFormat.format; _scExtent = swapchainCI.imageExtent; CreateDepthTexture(); CreateFramebuffers(); }
public SwapchainKHR(SurfaceKHR surface, Device device, uint minImageCount, uint layerCount, VkImageUsageFlag usageFlag, VkFormat imageFormat, VkColorSpaceKHR colorSpace, VkExtent2D dimensions, VkCompositeAlphaFlagBitsKHR compositeAlpha, VkPresentModeKHR presentMode, bool clipped = true, VkSurfaceTransformFlagBitsKHR transform = VkSurfaceTransformFlagBitsKHR.IdentityBitKhr, VkSharingMode sharing = VkSharingMode.Exclusive, uint[] sharedQueueFamily = null, SwapchainKHR oldSwapchain = null) { SurfaceKHR = surface; Device = device; { var surfSupported = false; foreach (var family in Device.Queues.Select(x => x.FamilyIndex).Distinct()) { if (PhysicalDevice.Handle.GetPhysicalDeviceSurfaceSupportKHR(family, SurfaceKHR.Handle)) { surfSupported = true; break; } } if (!surfSupported) { throw new NotSupportedException($"No queues on device support the surface"); } } _sharingQueueInfo = sharedQueueFamily; unsafe { if (sharing == VkSharingMode.Concurrent) { Debug.Assert(sharedQueueFamily != null); } var hasPinnedSharedQueue = sharedQueueFamily != null && sharedQueueFamily.Length > 0; var pinnedSharedQueueFamily = hasPinnedSharedQueue ? GCHandle.Alloc(sharedQueueFamily, GCHandleType.Pinned) : default(GCHandle); try { var info = new VkSwapchainCreateInfoKHR() { SType = VkStructureType.SwapchainCreateInfoKhr, PNext = IntPtr.Zero, Flags = 0, // reserved VkSwapchainCreateFlagBitsKHR Surface = surface.Handle, MinImageCount = minImageCount, ImageFormat = imageFormat, ImageColorSpace = colorSpace, ImageExtent = dimensions, ImageArrayLayers = layerCount, ImageUsage = usageFlag, ImageSharingMode = sharing, QueueFamilyIndexCount = (uint)(sharedQueueFamily?.Length ?? 0), PQueueFamilyIndices = hasPinnedSharedQueue ? (uint *)Marshal.UnsafeAddrOfPinnedArrayElement(sharedQueueFamily, 0).ToPointer() : (uint *)0, PreTransform = transform, CompositeAlpha = compositeAlpha, PresentMode = presentMode, Clipped = clipped, OldSwapchain = oldSwapchain?.Handle ?? VkSwapchainKHR.Null }; _info = info; Handle = Device.Handle.CreateSwapchainKHR(&info, Instance.AllocationCallbacks); if (oldSwapchain != null) { foreach (var img in oldSwapchain._swapchainImages) { img.Dispose(); } oldSwapchain.Dispose(); } } finally { if (hasPinnedSharedQueue) { pinnedSharedQueueFamily.Free(); } } } var images = Device.Handle.GetSwapchainImagesKHR(Handle); _swapchainImages.Clear(); _swapchainImages.Capacity = images.Length; foreach (var img in images) { _swapchainImages.Add(new SwapchainImage(this, img)); } }
private void createSwapChain() { SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes); VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); int imageCount = swapChainSupport.capabilities.minImageCount + 1; if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) { imageCount = swapChainSupport.capabilities.maxImageCount; } VkSwapchainCreateInfoKHR createInfo = new VkSwapchainCreateInfoKHR(); createInfo.sType = VkStructureType.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = surface; createInfo.minImageCount = imageCount; createInfo.imageFormat = surfaceFormat.format; createInfo.imageColorSpace = surfaceFormat.colorSpace; createInfo.imageExtent = extent; createInfo.imageArrayLayers = 1; createInfo.imageUsage = VkImageUsageFlags.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; QueueFamilyIndices indices = findQueueFamilies(physicalDevice); var queueFamilyIndices = new List <int>() { indices.graphicsFamily, indices.presentFamily }; if (indices.graphicsFamily != indices.presentFamily) { createInfo.imageSharingMode = VkSharingMode.VK_SHARING_MODE_CONCURRENT; createInfo.queueFamilyIndexCount = queueFamilyIndices.Count; createInfo.pQueueFamilyIndices = queueFamilyIndices.ToArray(); } else { createInfo.imageSharingMode = VkSharingMode.VK_SHARING_MODE_EXCLUSIVE; } createInfo.preTransform = (VkSurfaceTransformFlagBitsKHR)swapChainSupport.capabilities.currentTransform; createInfo.compositeAlpha = VkCompositeAlphaFlagBitsKHR.VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.presentMode = presentMode; createInfo.clipped = VkBool32.VK_TRUE; createInfo.oldSwapchain = null; VkResult result = Vulkan.vkCreateSwapchainKHR(device, createInfo, null, out swapChain); if (result != VkResult.VK_SUCCESS) { throw Program.Throw("failed to create swap chain!", result); } swapChainImages = new VkImage[imageCount]; Vulkan.vkGetSwapchainImagesKHR(device, swapChain, ref imageCount, swapChainImages); swapChainImageFormat = surfaceFormat.format; swapChainExtent = extent; }
private void CreateSwapChain() { // Create SwapChain SwapChainSupportDetails swapChainSupport = this.QuerySwapChainSupport(this.physicalDevice); VkSurfaceFormatKHR surfaceFormat = this.ChooseSwapSurfaceFormat(swapChainSupport.formats); VkPresentModeKHR presentMode = this.ChooseSwapPresentMode(swapChainSupport.presentModes); VkExtent2D extent = this.ChooseSwapExtent(swapChainSupport.capabilities); uint imageCount = swapChainSupport.capabilities.minImageCount + 1; if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) { imageCount = swapChainSupport.capabilities.maxImageCount; } VkSwapchainCreateInfoKHR createInfo = new VkSwapchainCreateInfoKHR(); createInfo.sType = VkStructureType.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = surface; createInfo.minImageCount = imageCount; createInfo.imageFormat = surfaceFormat.format; createInfo.imageColorSpace = surfaceFormat.colorSpace; createInfo.imageExtent = extent; createInfo.imageArrayLayers = 1; createInfo.imageUsage = VkImageUsageFlags.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; QueueFamilyIndices indices = this.FindQueueFamilies(this.physicalDevice); uint *queueFamilyIndices = stackalloc uint[] { indices.graphicsFamily.Value, indices.presentFamily.Value }; if (indices.graphicsFamily != indices.presentFamily) { createInfo.imageSharingMode = VkSharingMode.VK_SHARING_MODE_CONCURRENT; createInfo.queueFamilyIndexCount = 2; createInfo.pQueueFamilyIndices = queueFamilyIndices; } else { createInfo.imageSharingMode = VkSharingMode.VK_SHARING_MODE_EXCLUSIVE; createInfo.queueFamilyIndexCount = 0; //Optional createInfo.pQueueFamilyIndices = null; //Optional } createInfo.preTransform = swapChainSupport.capabilities.currentTransform; createInfo.compositeAlpha = VkCompositeAlphaFlagsKHR.VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.presentMode = presentMode; createInfo.clipped = true; createInfo.oldSwapchain = 0; fixed(VkSwapchainKHR *swapChainPtr = &swapChain) { Helpers.CheckErrors(VulkanNative.vkCreateSwapchainKHR(device, &createInfo, null, swapChainPtr)); } // SwapChain Images VulkanNative.vkGetSwapchainImagesKHR(device, swapChain, &imageCount, null); this.swapChainImages = new VkImage[imageCount]; fixed(VkImage *swapChainImagesPtr = &this.swapChainImages[0]) { VulkanNative.vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImagesPtr); } this.swapChainImageFormat = surfaceFormat.format; this.swapChainExtent = extent; }
public void CreateSwapChain() { var PhysicalDevice = NativeDevice.NativeAdapter.NativePhysicalDevice; var width = Parameters.BackBufferWidth; var height = Parameters.BackBufferHeight; var vsync = Parameters.Settings.VSync; // Get available queue family properties uint queueCount; vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice, &queueCount, null); VkQueueFamilyProperties *queueProps = stackalloc VkQueueFamilyProperties[(int)queueCount]; vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice, &queueCount, queueProps); // Iterate over each queue to learn whether it supports presenting: // Find a queue with present support // Will be used to present the swap chain Images to the windowing system VkBool32 *supportsPresent = stackalloc VkBool32[(int)queueCount]; for (uint i = 0; i < queueCount; i++) { vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, i, Surface, &supportsPresent[i]); } // Search for a graphics and a present queue in the array of queue // families, try to find one that supports both uint graphicsQueueNodeIndex = uint.MaxValue; uint presentQueueNodeIndex = uint.MaxValue; for (uint i = 0; i < queueCount; i++) { if ((queueProps[i].queueFlags & VkQueueFlags.Graphics) != 0) { if (graphicsQueueNodeIndex == uint.MaxValue) { graphicsQueueNodeIndex = i; } if (supportsPresent[i] == 1) { graphicsQueueNodeIndex = i; presentQueueNodeIndex = i; break; } } } if (presentQueueNodeIndex == uint.MaxValue) { // If there's no queue that supports both present and graphics // try to find a separate present queue for (uint i = 0; i < queueCount; ++i) { if (supportsPresent[i] == 1) { presentQueueNodeIndex = i; break; } } } // Exit if either a graphics or a presenting queue hasn't been found if (graphicsQueueNodeIndex == uint.MaxValue || presentQueueNodeIndex == uint.MaxValue) { throw new InvalidOperationException("Could not find a graphics and/or presenting queue!"); } // todo : Add support for separate graphics and presenting queue if (graphicsQueueNodeIndex != presentQueueNodeIndex) { throw new InvalidOperationException("Separate graphics and presenting queues are not supported yet!"); } // Get list of supported Surface formats uint formatCount; vkGetPhysicalDeviceSurfaceFormatsKHR(PhysicalDevice, Surface, &formatCount, null); VkSurfaceFormatKHR *surfaceFormats = stackalloc VkSurfaceFormatKHR[(int)formatCount]; vkGetPhysicalDeviceSurfaceFormatsKHR(PhysicalDevice, Surface, &formatCount, surfaceFormats); // If the Surface format list only includes one entry with VK_FORMAT_UNDEFINED, // there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM if ((formatCount == 1) && (surfaceFormats[0].format == VkFormat.Undefined)) { VkColorFormat = VkFormat.B8g8r8a8Unorm; ColorSpace = surfaceFormats[0].colorSpace; } else { // iterate over the list of available Surface format and // check for the presence of VK_FORMAT_B8G8R8A8_UNORM bool found_B8G8R8A8_UNORM = false; List <VkSurfaceFormatKHR> Formats = new List <VkSurfaceFormatKHR>(); for (int i = 0; i < formatCount; i++) { Formats.Add(surfaceFormats[i]); } foreach (var surfaceFormat in Formats) { if (surfaceFormat.format == VkFormat.B8g8r8a8Unorm) { VkColorFormat = surfaceFormat.format; ColorSpace = surfaceFormat.colorSpace; found_B8G8R8A8_UNORM = true; break; } } // in case VK_FORMAT_B8G8R8A8_UNORM is not available // select the first available color format if (!found_B8G8R8A8_UNORM) { VkColorFormat = surfaceFormats[0].format; ColorSpace = surfaceFormats[0].colorSpace; } } // Get physical Device Surface properties and formats VkSurfaceCapabilitiesKHR surfCaps; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(PhysicalDevice, Surface, &surfCaps); // Get available present modes uint presentModeCount; vkGetPhysicalDeviceSurfacePresentModesKHR(PhysicalDevice, Surface, &presentModeCount, null); VkPresentModeKHR *presentModes = stackalloc VkPresentModeKHR[(int)presentModeCount]; vkGetPhysicalDeviceSurfacePresentModesKHR(PhysicalDevice, Surface, &presentModeCount, (VkPresentModeKHR *)presentModes); VkExtent2D swapchainExtent; // If width (and height) equals the special value 0xFFFFFFFF, the size of the Surface will be set by the swapchain if (surfCaps.currentExtent.width == unchecked ((uint)-1)) { // If the Surface size is undefined, the size is set to // the size of the Images requested. swapchainExtent.width = (uint)width; swapchainExtent.height = (uint)height; } else { // If the Surface size is defined, the swap chain size must match swapchainExtent = surfCaps.currentExtent; width = (int)surfCaps.currentExtent.width; height = (int)surfCaps.currentExtent.height; } // Select a present mode for the swapchain // The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec // This mode waits for the vertical blank ("v-sync") VkPresentModeKHR swapchainPresentMode = VkPresentModeKHR.FifoKHR; // If v-sync is not requested, try to find a mailbox mode // It's the lowest latency non-tearing present mode available if (!vsync) { for (uint i = 0; i < presentModeCount; i++) { if (presentModes[i] == VkPresentModeKHR.MailboxKHR) { swapchainPresentMode = VkPresentModeKHR.MailboxKHR; break; } if ((swapchainPresentMode != VkPresentModeKHR.MailboxKHR) && (presentModes[i] == VkPresentModeKHR.ImmediateKHR)) { swapchainPresentMode = VkPresentModeKHR.ImmediateKHR; } } } // Determine the number of Images uint desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1; if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) { desiredNumberOfSwapchainImages = surfCaps.maxImageCount; } // Find the transformation of the Surface VkSurfaceTransformFlagsKHR preTransform; if ((surfCaps.supportedTransforms & VkSurfaceTransformFlagsKHR.IdentityKHR) != 0) { // We prefer a non-rotated transform preTransform = VkSurfaceTransformFlagsKHR.IdentityKHR; } else { preTransform = surfCaps.currentTransform; } VkSwapchainCreateInfoKHR swapchainCI = new VkSwapchainCreateInfoKHR() { sType = VkStructureType.SwapchainCreateInfoKHR, pNext = null, surface = Surface, minImageCount = desiredNumberOfSwapchainImages, imageFormat = VkColorFormat, imageColorSpace = ColorSpace, imageExtent = new VkExtent2D() { width = swapchainExtent.width, height = swapchainExtent.height }, imageUsage = VkImageUsageFlags.ColorAttachment, preTransform = preTransform, imageArrayLayers = 1, imageSharingMode = VkSharingMode.Exclusive, queueFamilyIndexCount = 0, pQueueFamilyIndices = null, presentMode = swapchainPresentMode, oldSwapchain = SwapChain, // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the Surface area clipped = True, compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR, }; // Set additional usage flag for blitting from the swapchain Images if supported VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(PhysicalDevice, VkColorFormat, out formatProps); if ((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.BlitDst) != 0) { swapchainCI.imageUsage |= VkImageUsageFlags.TransferSrc; } VkSwapchainKHR swapChain; vkCreateSwapchainKHR(NativeDevice.Device, &swapchainCI, null, &swapChain); SwapChain = swapChain; //vkDestroySwapchainKHR(NativeDevice.Device, SwapChain, null); uint imageCount; vkGetSwapchainImagesKHR(NativeDevice.Device, SwapChain, &imageCount, null); VkImage *VkImages = stackalloc VkImage[(int)imageCount]; vkGetSwapchainImagesKHR(NativeDevice.Device, swapChain, &imageCount, VkImages); Images = new List <VkImage>(); for (int i = 0; i < imageCount; i++) { Images.Add(VkImages[i]); } }
private static uint RateDevice(IntPtr physDevice) { var devProps = new ManagedPtr <VkPhysicalDeviceProperties>(); var devFeats = new ManagedPtr <VkPhysicalDeviceFeatures>(); vkGetPhysicalDeviceProperties(physDevice, devProps); vkGetPhysicalDeviceFeatures(physDevice, devFeats); var devProps_ = devProps.Value; var devFeats_ = devFeats.Value; uint score = 0; if (devProps_.deviceType == VkPhysicalDeviceType.PhysicalDeviceTypeDiscreteGpu) { score += 100; } score += devProps_.limits.maxImageDimension2D; if (!devFeats_.multiDrawIndirect) { return(0); } if (!devFeats_.tessellationShader) { return(0); } if (!ExtensionsSupported(physDevice)) { return(0); } var caps_ptr = new ManagedPtr <VkSurfaceCapabilitiesKHR>(); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevice, surfaceHndl, caps_ptr); var caps = caps_ptr.Value; uint fmt_cnt = 0; vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceHndl, &fmt_cnt, null); var fmts_ptr = new ManagedPtrArray <VkSurfaceFormatKHR>(fmt_cnt); vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceHndl, &fmt_cnt, fmts_ptr); var fmts = fmts_ptr.Value; bool fmt_valid = false; VkSurfaceFormatKHR chosen_fmt = new VkSurfaceFormatKHR(); foreach (var avail_fmt in fmts) { if (avail_fmt.format == VkFormat.FormatB8g8r8a8Unorm && avail_fmt.colorSpace == VkColorSpaceKHR.ColorSpaceSrgbNonlinearKhr) { chosen_fmt = avail_fmt; fmt_valid = true; break; } } if (!fmt_valid && fmts.Length > 0) { chosen_fmt = fmts[0]; fmt_valid = true; } uint present_mode_cnt = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(physDevice, surfaceHndl, &present_mode_cnt, null); var present_modes = stackalloc VkPresentModeKHR[(int)present_mode_cnt]; vkGetPhysicalDeviceSurfacePresentModesKHR(physDevice, surfaceHndl, &present_mode_cnt, present_modes); bool present_valid = false; VkPresentModeKHR chosen_present = VkPresentModeKHR.PresentModeBeginRangeKhr; for (int i = 0; i < present_mode_cnt; i++) { var avail_present = present_modes[i]; if (avail_present == VkPresentModeKHR.PresentModeMailboxKhr) { present_valid = true; chosen_present = VkPresentModeKHR.PresentModeMailboxKhr; } else if (avail_present == VkPresentModeKHR.PresentModeFifoRelaxedKhr) { present_valid = true; chosen_present = VkPresentModeKHR.PresentModeFifoRelaxedKhr; } } if (!present_valid) { present_valid = true; chosen_present = VkPresentModeKHR.PresentModeFifoKhr; } chosen_present = VkPresentModeKHR.PresentModeImmediateKhr; if (!fmt_valid) { return(0); } if (!present_valid) { return(0); } present_mode = chosen_present; surface_fmt = chosen_fmt; return(score); }
public unsafe Swapchain(Device device, NativeWindow window) { _device = device; _window = window; //get present queue _presentQueueFamily = GetQueueFamilyWithPresentationSupport( device, window ); //get surface capabilities _surfaceCapabilities = GetSurfaceCapabilities( device, window ); //get surface format support _supportedSurfaceFormats = GetSupportedSurfaceFormats( device, window ); //get present mode support _supportedPresentModes = GetSupportedPresentModes( device, window ); //choose best surface format #region Surface Format if ( _supportedSurfaceFormats.Count == 1 && _supportedSurfaceFormats[0].format == VkFormat.Undefined ) { _surfaceFormat = new VkSurfaceFormatKHR { colorSpace = VkColorSpaceKHR.SrgbNonlinearKHR, format = VkFormat.R8g8b8Unorm }; } else { bool choosenFormat = false; foreach (var format in _supportedSurfaceFormats) { if ( format.format == VkFormat.R8g8b8Unorm && format.colorSpace == VkColorSpaceKHR.SrgbNonlinearKHR ) { _surfaceFormat = format; choosenFormat = true; break; } } if (choosenFormat == false) { _surfaceFormat = _supportedSurfaceFormats[0]; } } #endregion #region Surface Present Mode _surfacePresentMode = VkPresentModeKHR.FifoKHR; foreach (var presentMode in _supportedPresentModes) { if (presentMode == VkPresentModeKHR.MailboxKHR) { _surfacePresentMode = presentMode; break; } else if (presentMode == VkPresentModeKHR.ImmediateKHR) { _surfacePresentMode = presentMode; } } #endregion #region Surface Extent if (_surfaceCapabilities.currentExtent.width != uint.MaxValue) { _surfaceExtent = _surfaceCapabilities.currentExtent; } else { _surfaceExtent = new VkExtent2D { width = Math.Clamp( Convert.ToUInt32(window.Width), _surfaceCapabilities.minImageExtent.width, _surfaceCapabilities.maxImageExtent.width ), height = Math.Clamp( Convert.ToUInt32(window.Height), _surfaceCapabilities.minImageExtent.height, _surfaceCapabilities.maxImageExtent.height ) }; } #endregion #region Images Count var imagesCount = _surfaceCapabilities.minImageCount + 1; if (_surfaceCapabilities.maxImageCount > 0) { if (imagesCount > _surfaceCapabilities.maxImageCount) { imagesCount = Math.Min(_surfaceCapabilities.maxImageCount, 2); } } #endregion var queueFamilyIndices = new NativeList <uint>(); foreach (var queueFamily in device.QueueFamilies) { queueFamilyIndices.Add(queueFamily.Index); } var swapchainInfo = new VkSwapchainCreateInfoKHR { sType = VkStructureType.SwapchainCreateInfoKHR, compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR, minImageCount = imagesCount, imageFormat = _surfaceFormat.format, imageColorSpace = _surfaceFormat.colorSpace, imageExtent = _surfaceExtent, imageArrayLayers = 1, imageUsage = ( VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst ), imageSharingMode = VkSharingMode.Concurrent, preTransform = _surfaceCapabilities.currentTransform, presentMode = _surfacePresentMode, surface = window.Surface, clipped = true, queueFamilyIndexCount = queueFamilyIndices.Count, pQueueFamilyIndices = (uint *)queueFamilyIndices.Data.ToPointer() }; VkSwapchainKHR swapchain; if (VulkanNative.vkCreateSwapchainKHR( device.Handle, &swapchainInfo, null, &swapchain ) != VkResult.Success) { throw new Exception("failed to create swapchain"); } _handle = swapchain; SetupSwapchainImages(); }