public unsafe Swapchain[] CreateSharedSwapchains(SwapchainCreateInfo[] createInfos, AllocationCallbacks allocator) { var swapchains = new Swapchain[createInfos.Length]; fixed (SwapchainCreateInfo* __createInfos__ = &createInfos[0]) fixed (Swapchain* __swapchains__ = &swapchains[0]) { vkCreateSharedSwapchainsKHR(this, (uint)createInfos.Length, __createInfos__, &allocator, __swapchains__).CheckError(); } return swapchains; }
private unsafe void CreateSwapChain() { var formats = new[] { PixelFormat.B8G8R8A8_UNorm_SRgb, PixelFormat.R8G8B8A8_UNorm_SRgb, PixelFormat.B8G8R8A8_UNorm, PixelFormat.R8G8B8A8_UNorm }; foreach (var format in formats) { var nativeFromat = VulkanConvertExtensions.ConvertPixelFormat(format); FormatProperties formatProperties; GraphicsDevice.NativePhysicalDevice.GetFormatProperties(nativeFromat, out formatProperties); if ((formatProperties.OptimalTilingFeatures & FormatFeatureFlags.ColorAttachment) != 0) { Description.BackBufferFormat = format; break; } } // Queue // TODO VULKAN: Queue family is needed when creating the Device, so here we can just do a sanity check? var queueNodeIndex = GraphicsDevice.NativePhysicalDevice.QueueFamilyProperties. Where((properties, index) => (properties.QueueFlags & QueueFlags.Graphics) != 0 && GraphicsDevice.NativePhysicalDevice.GetSurfaceSupport((uint)index, surface)). Select((properties, index) => index).First(); // Surface format var backBufferFormat = VulkanConvertExtensions.ConvertPixelFormat(Description.BackBufferFormat); var surfaceFormats = GraphicsDevice.NativePhysicalDevice.GetSurfaceFormats(surface); if ((surfaceFormats.Length != 1 || surfaceFormats[0].Format != Format.Undefined) && !surfaceFormats.Any(x => x.Format == backBufferFormat)) { backBufferFormat = surfaceFormats[0].Format; } // Create swapchain SurfaceCapabilities surfaceCapabilities; GraphicsDevice.NativePhysicalDevice.GetSurfaceCapabilities(surface, out surfaceCapabilities); // Buffer count uint desiredImageCount = Math.Max(surfaceCapabilities.MinImageCount, 2); if (surfaceCapabilities.MaxImageCount > 0 && desiredImageCount > surfaceCapabilities.MaxImageCount) { desiredImageCount = surfaceCapabilities.MaxImageCount; } // Transform SurfaceTransformFlags preTransform; if ((surfaceCapabilities.SupportedTransforms & SurfaceTransformFlags.Identity) != 0) { preTransform = SurfaceTransformFlags.Identity; } else { preTransform = surfaceCapabilities.CurrentTransform; } // Find present mode var presentModes = GraphicsDevice.NativePhysicalDevice.GetSurfacePresentModes(surface); var swapChainPresentMode = PresentMode.Fifo; // Always supported foreach (var presentMode in presentModes) { // TODO VULKAN: Handle PresentInterval.Two if (Description.PresentationInterval == PresentInterval.Immediate) { // Prefer mailbox to immediate if (presentMode == PresentMode.Immediate) { swapChainPresentMode = PresentMode.Immediate; } else if (presentMode == PresentMode.Mailbox) { swapChainPresentMode = PresentMode.Mailbox; break; } } } // Create swapchain var swapchainCreateInfo = new SwapchainCreateInfo { StructureType = StructureType.SwapchainCreateInfo, Surface = surface, ImageArrayLayers = 1, ImageSharingMode = SharingMode.Exclusive, ImageExtent = new Extent2D((uint)Description.BackBufferWidth, (uint)Description.BackBufferHeight), ImageFormat = backBufferFormat, ImageColorSpace = Description.ColorSpace == ColorSpace.Gamma ? SharpVulkan.ColorSpace.SRgbNonlinear : 0, ImageUsage = ImageUsageFlags.ColorAttachment | (surfaceCapabilities.SupportedUsageFlags & ImageUsageFlags.TransferSource), // TODO VULKAN: Use off-screen buffer to emulate PresentMode = swapChainPresentMode, CompositeAlpha = CompositeAlphaFlags.Opaque, MinImageCount = desiredImageCount, PreTransform = preTransform, OldSwapchain = swapChain, Clipped = true }; var newSwapChain = GraphicsDevice.NativeDevice.CreateSwapchain(ref swapchainCreateInfo); DestroySwapchain(); swapChain = newSwapChain; CreateBackBuffers(); }
private unsafe void CreateSwapChain() { // we are destroying the swap chain now, because it causes lots of other things to be reset too (like all commandbufferpools) // normally we pass the old swapchain to the create new swapchain Vulkan call... but I haven't figured out a stable way of // preserving the old swap chain to be passed during the new swapchain creation, and then destroying just the old swapchain parts. // might have to reset the command buffers and pipeline stuff after swapchain handoff... for another day e.g. TODO DestroySwapchain(); var formats = new[] { PixelFormat.B8G8R8A8_UNorm_SRgb, PixelFormat.R8G8B8A8_UNorm_SRgb, PixelFormat.B8G8R8A8_UNorm, PixelFormat.R8G8B8A8_UNorm }; foreach (var format in formats) { var nativeFromat = VulkanConvertExtensions.ConvertPixelFormat(format); FormatProperties formatProperties; GraphicsDevice.NativePhysicalDevice.GetFormatProperties(nativeFromat, out formatProperties); if ((formatProperties.OptimalTilingFeatures & FormatFeatureFlags.ColorAttachment) != 0) { Description.BackBufferFormat = format; break; } } // Queue // TODO VULKAN: Queue family is needed when creating the Device, so here we can just do a sanity check? var queueNodeIndex = GraphicsDevice.NativePhysicalDevice.QueueFamilyProperties. Where((properties, index) => (properties.QueueFlags & QueueFlags.Graphics) != 0 && GraphicsDevice.NativePhysicalDevice.GetSurfaceSupport((uint)index, surface)). Select((properties, index) => index).First(); // Surface format var backBufferFormat = VulkanConvertExtensions.ConvertPixelFormat(Description.BackBufferFormat); var surfaceFormats = GraphicsDevice.NativePhysicalDevice.GetSurfaceFormats(surface); if ((surfaceFormats.Length != 1 || surfaceFormats[0].Format != Format.Undefined) && !surfaceFormats.Any(x => x.Format == backBufferFormat)) { backBufferFormat = surfaceFormats[0].Format; } // Create swapchain SurfaceCapabilities surfaceCapabilities; GraphicsDevice.NativePhysicalDevice.GetSurfaceCapabilities(surface, out surfaceCapabilities); // Buffer count uint desiredImageCount = Math.Max(surfaceCapabilities.MinImageCount, 4); if (surfaceCapabilities.MaxImageCount > 0 && desiredImageCount > surfaceCapabilities.MaxImageCount) { desiredImageCount = surfaceCapabilities.MaxImageCount; } // Transform SurfaceTransformFlags preTransform; if ((surfaceCapabilities.SupportedTransforms & SurfaceTransformFlags.Identity) != 0) { preTransform = SurfaceTransformFlags.Identity; } else { preTransform = surfaceCapabilities.CurrentTransform; } // Find present mode var swapChainPresentMode = PresentMode.Fifo; // Always supported, but slow if (Description.PresentationInterval == PresentInterval.Immediate) { var presentModes = GraphicsDevice.NativePhysicalDevice.GetSurfacePresentModes(surface); if (presentModes.Contains(PresentMode.Mailbox)) { swapChainPresentMode = PresentMode.Mailbox; } } // Create swapchain var swapchainCreateInfo = new SwapchainCreateInfo { StructureType = StructureType.SwapchainCreateInfo, Surface = surface, ImageArrayLayers = 1, ImageSharingMode = SharingMode.Exclusive, ImageExtent = new Extent2D((uint)Description.BackBufferWidth, (uint)Description.BackBufferHeight), ImageFormat = backBufferFormat, ImageColorSpace = Description.ColorSpace == ColorSpace.Gamma ? SharpVulkan.ColorSpace.SRgbNonlinear : 0, ImageUsage = ImageUsageFlags.ColorAttachment | ImageUsageFlags.TransferDestination | (surfaceCapabilities.SupportedUsageFlags & ImageUsageFlags.TransferSource), // TODO VULKAN: Use off-screen buffer to emulate PresentMode = swapChainPresentMode, CompositeAlpha = CompositeAlphaFlags.Opaque, MinImageCount = desiredImageCount, PreTransform = preTransform, OldSwapchain = Swapchain.Null, Clipped = true }; swapChain = GraphicsDevice.NativeDevice.CreateSwapchain(ref swapchainCreateInfo); CreateBackBuffers(); // resize/create stencil buffers var newTextureDescription = DepthStencilBuffer.Description; newTextureDescription.Width = Description.BackBufferWidth; newTextureDescription.Height = Description.BackBufferHeight; // Manually update the texture DepthStencilBuffer.OnDestroyed(); // Put it in our back buffer texture DepthStencilBuffer.InitializeFrom(newTextureDescription); // start new presentation thread runPresenter = true; presenterThread = new Thread(new ThreadStart(PresenterThread)); presenterThread.IsBackground = true; presenterThread.Name = "Vulkan Presentation Thread"; presenterThread.Priority = ThreadPriority.AboveNormal; presenterThread.Start(); }
protected virtual void CreateSwapchain() { // surface format var surfaceFormats = physicalDevice.GetSurfaceFormats(surface); if (surfaceFormats.Length == 1 && surfaceFormats[0].Format == Format.Undefined) { backBufferFormat = Format.B8G8R8A8UNorm; } else { backBufferFormat = surfaceFormats[0].Format; } SurfaceCapabilities surfaceCapabilities; physicalDevice.GetSurfaceCapabilities(surface, out surfaceCapabilities); // Buffer count uint desiredImageCount = surfaceCapabilities.MinImageCount + 1; if (surfaceCapabilities.MaxImageCount > 0 && desiredImageCount > surfaceCapabilities.MaxImageCount) { desiredImageCount = surfaceCapabilities.MaxImageCount; } // Transform SurfaceTransformFlags preTransform; if ((surfaceCapabilities.SupportedTransforms & SurfaceTransformFlags.Identity) != 0) { preTransform = SurfaceTransformFlags.Identity; } else { preTransform = surfaceCapabilities.CurrentTransform; } // Present mode var presentModes = physicalDevice.GetSurfacePresentModes(surface); var swapChainPresentMode = PresentMode.Fifo; if (presentModes.Contains(PresentMode.Mailbox)) swapChainPresentMode = PresentMode.Mailbox; else if (presentModes.Contains(PresentMode.Immediate)) swapChainPresentMode = PresentMode.Immediate; // Create swapchain var swapchainCreateInfo = new SwapchainCreateInfo { StructureType = StructureType.SwapchainCreateInfo, Surface = surface, ImageSharingMode = SharingMode.Exclusive, ImageExtent = new Extent2D((uint)form.ClientSize.Width, (uint)form.ClientSize.Height), ImageArrayLayers = 1, ImageFormat = backBufferFormat, ImageColorSpace = ColorSpace.SRgbNonlinear, ImageUsage = ImageUsageFlags.ColorAttachment, PresentMode = swapChainPresentMode, CompositeAlpha = CompositeAlphaFlags.Opaque, MinImageCount = desiredImageCount, PreTransform = preTransform, Clipped = true // OldSwapchain = }; swapchain = device.CreateSwapchain(ref swapchainCreateInfo); // Initialize swapchain image layout backBuffers = device.GetSwapchainImages(swapchain); foreach (var image in backBuffers) { SetImageLayout(image, ImageAspectFlags.Color, ImageLayout.Undefined, ImageLayout.PresentSource); } Flush(); }
protected virtual void CreateSwapchain() { // surface format var surfaceFormats = physicalDevice.GetSurfaceFormats(surface); if (surfaceFormats.Length == 1 && surfaceFormats[0].Format == Format.Undefined) { backBufferFormat = Format.B8G8R8A8UNorm; } else { backBufferFormat = surfaceFormats[0].Format; } SurfaceCapabilities surfaceCapabilities; physicalDevice.GetSurfaceCapabilities(surface, out surfaceCapabilities); // Buffer count uint desiredImageCount = surfaceCapabilities.MinImageCount + 1; if (surfaceCapabilities.MaxImageCount > 0 && desiredImageCount > surfaceCapabilities.MaxImageCount) { desiredImageCount = surfaceCapabilities.MaxImageCount; } // Transform SurfaceTransformFlags preTransform; if ((surfaceCapabilities.SupportedTransforms & SurfaceTransformFlags.Identity) != 0) { preTransform = SurfaceTransformFlags.Identity; } else { preTransform = surfaceCapabilities.CurrentTransform; } // Present mode var presentModes = physicalDevice.GetSurfacePresentModes(surface); var swapChainPresentMode = PresentMode.Fifo; if (presentModes.Contains(PresentMode.Mailbox)) { swapChainPresentMode = PresentMode.Mailbox; } else if (presentModes.Contains(PresentMode.Immediate)) { swapChainPresentMode = PresentMode.Immediate; } // Create swapchain var swapchainCreateInfo = new SwapchainCreateInfo { StructureType = StructureType.SwapchainCreateInfo, Surface = surface, ImageSharingMode = SharingMode.Exclusive, ImageExtent = new Extent2D((uint)form.ClientSize.Width, (uint)form.ClientSize.Height), ImageArrayLayers = 1, ImageFormat = backBufferFormat, ImageColorSpace = ColorSpace.SRgbNonlinear, ImageUsage = ImageUsageFlags.ColorAttachment, PresentMode = swapChainPresentMode, CompositeAlpha = CompositeAlphaFlags.Opaque, MinImageCount = desiredImageCount, PreTransform = preTransform, Clipped = true // OldSwapchain = }; swapchain = device.CreateSwapchain(ref swapchainCreateInfo); // Initialize swapchain image layout backBuffers = device.GetSwapchainImages(swapchain); foreach (var image in backBuffers) { SetImageLayout(image, ImageAspectFlags.Color, ImageLayout.Undefined, ImageLayout.PresentSource); } Flush(); }
private unsafe void CreateSwapChain() { var formats = new[] { PixelFormat.B8G8R8A8_UNorm_SRgb, PixelFormat.R8G8B8A8_UNorm_SRgb, PixelFormat.B8G8R8A8_UNorm, PixelFormat.R8G8B8A8_UNorm }; foreach (var format in formats) { var nativeFromat = VulkanConvertExtensions.ConvertPixelFormat(format); FormatProperties formatProperties; GraphicsDevice.NativePhysicalDevice.GetFormatProperties(nativeFromat, out formatProperties); if ((formatProperties.OptimalTilingFeatures & FormatFeatureFlags.ColorAttachment) != 0) { Description.BackBufferFormat = format; break; } } // Queue // TODO VULKAN: Queue family is needed when creating the Device, so here we can just do a sanity check? var queueNodeIndex = GraphicsDevice.NativePhysicalDevice.QueueFamilyProperties. Where((properties, index) => (properties.QueueFlags & QueueFlags.Graphics) != 0 && GraphicsDevice.NativePhysicalDevice.GetSurfaceSupport((uint)index, surface)). Select((properties, index) => index).First(); // Surface format var backBufferFormat = VulkanConvertExtensions.ConvertPixelFormat(Description.BackBufferFormat); var surfaceFormats = GraphicsDevice.NativePhysicalDevice.GetSurfaceFormats(surface); if ((surfaceFormats.Length != 1 || surfaceFormats[0].Format != Format.Undefined) && !surfaceFormats.Any(x => x.Format == backBufferFormat)) { backBufferFormat = surfaceFormats[0].Format; } // Create swapchain SurfaceCapabilities surfaceCapabilities; GraphicsDevice.NativePhysicalDevice.GetSurfaceCapabilities(surface, out surfaceCapabilities); // Buffer count uint desiredImageCount = Math.Max(surfaceCapabilities.MinImageCount, 2); if (surfaceCapabilities.MaxImageCount > 0 && desiredImageCount > surfaceCapabilities.MaxImageCount) { desiredImageCount = surfaceCapabilities.MaxImageCount; } // Transform SurfaceTransformFlags preTransform; if ((surfaceCapabilities.SupportedTransforms & SurfaceTransformFlags.Identity) != 0) { preTransform = SurfaceTransformFlags.Identity; } else { preTransform = surfaceCapabilities.CurrentTransform; } // Find present mode var presentModes = GraphicsDevice.NativePhysicalDevice.GetSurfacePresentModes(surface); var swapChainPresentMode = PresentMode.Fifo; // Always supported foreach (var presentMode in presentModes) { // TODO VULKAN: Handle PresentInterval.Two if (Description.PresentationInterval == PresentInterval.Immediate) { // Prefer mailbox to immediate if (presentMode == PresentMode.Immediate) { swapChainPresentMode = PresentMode.Immediate; } else if (presentMode == PresentMode.Mailbox) { swapChainPresentMode = PresentMode.Mailbox; break; } } } // Create swapchain var swapchainCreateInfo = new SwapchainCreateInfo { StructureType = StructureType.SwapchainCreateInfo, Surface = surface, ImageArrayLayers = 1, ImageSharingMode = SharingMode.Exclusive, ImageExtent = new Extent2D((uint)Description.BackBufferWidth, (uint)Description.BackBufferHeight), ImageFormat = backBufferFormat, ImageColorSpace = Description.ColorSpace == ColorSpace.Gamma ? SharpVulkan.ColorSpace.SRgbNonlinear : 0, ImageUsage = ImageUsageFlags.ColorAttachment | ImageUsageFlags.TransferDestination | (surfaceCapabilities.SupportedUsageFlags & ImageUsageFlags.TransferSource), // TODO VULKAN: Use off-screen buffer to emulate PresentMode = swapChainPresentMode, CompositeAlpha = CompositeAlphaFlags.Opaque, MinImageCount = desiredImageCount, PreTransform = preTransform, OldSwapchain = swapChain, Clipped = true }; var newSwapChain = GraphicsDevice.NativeDevice.CreateSwapchain(ref swapchainCreateInfo); DestroySwapchain(); swapChain = newSwapChain; CreateBackBuffers(); }
public unsafe Swapchain CreateSwapchain(ref SwapchainCreateInfo createInfo, AllocationCallbacks* allocator = null) { Swapchain swapchain; fixed (SwapchainCreateInfo* __createInfo__ = &createInfo) { vkCreateSwapchainKHR(this, __createInfo__, allocator, &swapchain).CheckError(); } return swapchain; }
internal static unsafe extern Result vkCreateSwapchainKHR(Device device, SwapchainCreateInfo* createInfo, AllocationCallbacks* allocator, Swapchain* swapchain);
internal static unsafe extern Result vkCreateSharedSwapchainsKHR(Device device, uint swapchainCount, SwapchainCreateInfo* createInfos, AllocationCallbacks* allocator, Swapchain* swapchains);