public unsafe QueueFamilyIndices(VkPhysicalDevice device, VkSurfaceKHR surface) { int graphicsIndex = -1; int presentIndex = -1; uint queueFamilyCount = 0; VulkanNative.vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, null); VkQueueFamilyProperties *queueFamilies = stackalloc VkQueueFamilyProperties[(int)queueFamilyCount]; VulkanNative.vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies); for (int i = 0; i < queueFamilyCount; i++) { var q = queueFamilies[i]; if (q.queueCount > 0 && (q.queueFlags & VkQueueFlagBits.VK_QUEUE_GRAPHICS_BIT) != 0) { graphicsIndex = i; } VkBool32 presentSupported = false; VkResult result = VulkanNative.vkGetPhysicalDeviceSurfaceSupportKHR(device, (uint)i, surface, &presentSupported); Helpers.CheckErrors(result); if (presentIndex < 0 && q.queueCount > 0 && presentSupported) { presentIndex = i; } } GraphicsFamily = graphicsIndex; PresentFamily = presentIndex; }
internal void CreateQueueFamilyProperties() { VkPhysicalDevice physicalDevice = NativeAdapter.NativePhysicalDevice; uint Count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref Count, null); VkQueueFamilyProperties *queueFamilyProperties = stackalloc VkQueueFamilyProperties[(int)Count]; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &Count, queueFamilyProperties); for (int i = 0; i < Count; i++) { QueueFamilyProperties.Add(queueFamilyProperties[i]); } }
private bool TryGetQueueFamilyIndex(VkPhysicalDevice device, VkQueueFlags flag, out uint index) { index = 0; uint queueFamilyCount = 0; VK.GetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, null); VkQueueFamilyProperties *queueFamilies = stackalloc VkQueueFamilyProperties[(int)queueFamilyCount]; VK.GetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies); for (int i = 0; i < queueFamilyCount; i++) { if (queueFamilies[i].queueFlags.HasFlag(flag)) { index = (uint)i; return(true); } } return(false); }
private QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice physicalDevice) { QueueFamilyIndices indices = default; uint queueFamilyCount = 0; VulkanNative.vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, null); VkQueueFamilyProperties *queueFamilies = stackalloc VkQueueFamilyProperties[(int)queueFamilyCount]; VulkanNative.vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies); for (uint i = 0; i < queueFamilyCount; i++) { var queueFamily = queueFamilies[i]; if ((queueFamily.queueFlags & VkQueueFlags.VK_QUEUE_GRAPHICS_BIT) != 0) { indices.graphicsFamily = i; } VkBool32 presentSupport = false; Helpers.CheckErrors(VulkanNative.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, this.surface, &presentSupport)); if (presentSupport) { indices.presentFamily = i; } if (indices.IsComplete()) { break; } } return(indices); }
internal extern static unsafe void vkGetPhysicalDeviceQueueFamilyProperties(IntPtr physicalDevice, UInt32 *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties);
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); }
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]); } }
public void CreateSwapChain() { VkPhysicalDevice PhysicalDevice = NativeDevice.NativeAdapter.handle; int width = Parameters.Width; int height = Parameters.Height; bool vsync = false; // 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, out 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 is uint.MaxValue) { graphicsQueueNodeIndex = i; } if (supportsPresent[i] == true) { graphicsQueueNodeIndex = i; presentQueueNodeIndex = i; break; } } } if (presentQueueNodeIndex is 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] == true) { presentQueueNodeIndex = i; break; } } } // Exit if either a graphics or a presenting queue hasn't been found if (graphicsQueueNodeIndex is uint.MaxValue || presentQueueNodeIndex is 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 is 1) && (surfaceFormats[0].format is VkFormat.Undefined)) { color_format = VkFormat.B8G8R8A8UNorm; color_space = surfaceFormats[0].colorSpace; }