protected override void ResizeDepthStencilBuffer(int width, int height, PixelFormat format) { var newTextureDescrition = DepthStencilBuffer.Description; newTextureDescrition.Width = width; newTextureDescrition.Height = height; // Manually update the texture DepthStencilBuffer.OnDestroyed(); // Put it in our back buffer texture DepthStencilBuffer.InitializeFrom(newTextureDescrition); }
protected override void ResizeDepthStencilBuffer(int width, int height, PixelFormat format) { var newTextureDescription = DepthStencilBuffer.Description; newTextureDescription.Width = width; newTextureDescription.Height = height; // Manually update the texture DepthStencilBuffer.OnDestroyed(); // Manually update all children textures var fastList = DestroyChildrenTextures(DepthStencilBuffer); // Put it in our back buffer texture DepthStencilBuffer.InitializeFrom(newTextureDescription); foreach (var texture in fastList) { texture.InitializeFrom(DepthStencilBuffer, texture.ViewDescription); } }
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(); }
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); vkGetPhysicalDeviceFormatProperties(GraphicsDevice.NativePhysicalDevice, nativeFromat, out var formatProperties); if ((formatProperties.optimalTilingFeatures & VkFormatFeatureFlags.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 = vkGetPhysicalDeviceQueueFamilyProperties(GraphicsDevice.NativePhysicalDevice).ToArray(). Where((properties, index) => (properties.queueFlags & VkQueueFlags.Graphics) != 0 && vkGetPhysicalDeviceSurfaceSupportKHR(GraphicsDevice.NativePhysicalDevice, (uint)index, surface, out var supported) == VkResult.Success && supported == Vortice.Vulkan.VkBool32.True). Select((properties, index) => index).First(); // Surface format var backBufferFormat = VulkanConvertExtensions.ConvertPixelFormat(Description.BackBufferFormat); var surfaceFormats = vkGetPhysicalDeviceSurfaceFormatsKHR(GraphicsDevice.NativePhysicalDevice, surface).ToArray(); if ((surfaceFormats.Length != 1 || surfaceFormats[0].format != VkFormat.Undefined) && !surfaceFormats.Any(x => x.format == backBufferFormat)) { backBufferFormat = surfaceFormats[0].format; } // Create swapchain vkGetPhysicalDeviceSurfaceCapabilitiesKHR(GraphicsDevice.NativePhysicalDevice, surface, out var surfaceCapabilities); // Buffer count uint desiredImageCount = Math.Max(surfaceCapabilities.minImageCount, 6); if (surfaceCapabilities.maxImageCount > 0 && desiredImageCount > surfaceCapabilities.maxImageCount) { desiredImageCount = surfaceCapabilities.maxImageCount; } // Transform VkSurfaceTransformFlagsKHR preTransform; if ((surfaceCapabilities.supportedTransforms & VkSurfaceTransformFlagsKHR.Identity) != 0) { preTransform = VkSurfaceTransformFlagsKHR.Identity; } else { preTransform = surfaceCapabilities.currentTransform; } // Find present mode var swapChainPresentMode = VkPresentModeKHR.Fifo; // Always supported, but slow if (Description.PresentationInterval == PresentInterval.Immediate) { var presentModes = vkGetPhysicalDeviceSurfacePresentModesKHR(GraphicsDevice.NativePhysicalDevice, surface); foreach (var pm in presentModes) { if (pm == VkPresentModeKHR.Mailbox) { swapChainPresentMode = VkPresentModeKHR.Mailbox; break; } } } // Create swapchain var swapchainCreateInfo = new VkSwapchainCreateInfoKHR { sType = VkStructureType.SwapchainCreateInfoKHR, surface = surface, imageArrayLayers = 1, imageSharingMode = VkSharingMode.Exclusive, imageExtent = new Vortice.Vulkan.VkExtent2D(Description.BackBufferWidth, Description.BackBufferHeight), imageFormat = backBufferFormat, imageColorSpace = Description.ColorSpace == ColorSpace.Gamma ? VkColorSpaceKHR.SrgbNonLinear : 0, imageUsage = VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst | (surfaceCapabilities.supportedUsageFlags & VkImageUsageFlags.TransferSrc), // TODO VULKAN: Use off-screen buffer to emulate presentMode = swapChainPresentMode, compositeAlpha = VkCompositeAlphaFlagsKHR.Opaque, minImageCount = desiredImageCount, preTransform = preTransform, oldSwapchain = swapChain, clipped = Vortice.Vulkan.VkBool32.True }; vkCreateSwapchainKHR(GraphicsDevice.NativeDevice, &swapchainCreateInfo, null, out swapChain); 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); }