private static unsafe PresentModeKHR GetSuitablePresentMode(VulkanPhysicalDevice physicalDevice, VulkanSurface surface, bool vsyncEnabled) { uint presentModesCount; VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfacePresentModes(physicalDevice.InternalHandle, surface.ApiHandle, &presentModesCount, null); var presentModes = new PresentModeKHR[presentModesCount]; fixed(PresentModeKHR *pPresentModes = presentModes) { VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfacePresentModes(physicalDevice.InternalHandle, surface.ApiHandle, &presentModesCount, pPresentModes); } var modes = presentModes.ToList(); if (!vsyncEnabled && modes.Contains(PresentModeKHR.PresentModeImmediateKhr)) { return(PresentModeKHR.PresentModeImmediateKhr); } else if (modes.Contains(PresentModeKHR.PresentModeMailboxKhr)) { return(PresentModeKHR.PresentModeMailboxKhr); } else if (modes.Contains(PresentModeKHR.PresentModeFifoKhr)) { return(PresentModeKHR.PresentModeFifoKhr); } else { return(PresentModeKHR.PresentModeImmediateKhr); } }
public unsafe SwapChain(Api api, Window window, Surface surface, PresentModeKHR presentMode) { _api = api; QuerySwapChainSupport(_api.Device.PhysicalDevice, surface.VkServiceKHR, out var details); if (details.Formats.Count == 0 || details.PresentModes.Count == 0) { throw new Exception($"{nameof(SwapChain)}: Empty swap chain support"); } ChooseSwapSurfaceFormat(details.Formats, out var surfaceFormat); var actualPresentMode = ChooseSwapPresentMode(details.PresentModes, presentMode); ChooseSwapExtent(window, details.Capabilities, out var extent); var imageCount = ChooseImageCount(details.Capabilities); var createInfo = new SwapchainCreateInfoKHR(); createInfo.SType = StructureType.SwapchainCreateInfoKhr; createInfo.Surface = surface.VkServiceKHR; createInfo.MinImageCount = imageCount; createInfo.ImageFormat = surfaceFormat.Format; createInfo.ImageColorSpace = surfaceFormat.ColorSpace; createInfo.ImageExtent = extent; createInfo.ImageArrayLayers = 1; createInfo.ImageUsage = ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit; createInfo.PreTransform = details.Capabilities.CurrentTransform; createInfo.CompositeAlpha = CompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr; createInfo.PresentMode = actualPresentMode; createInfo.Clipped = true; createInfo.OldSwapchain = default; Span <uint> queueFamilyIndices = stackalloc uint[] { api.Device.GraphicsFamilyIndex, api.Device.PresentationFamilyIndex, }; if (api.Device.GraphicsFamilyIndex != api.Device.PresentationFamilyIndex) { createInfo.ImageSharingMode = SharingMode.Concurrent; createInfo.QueueFamilyIndexCount = 2; createInfo.PQueueFamilyIndices = (uint *)Unsafe.AsPointer(ref queueFamilyIndices[0]); } else { createInfo.ImageSharingMode = SharingMode.Exclusive; createInfo.QueueFamilyIndexCount = 0; // Optional createInfo.PQueueFamilyIndices = null; // Optional } Util.Verify(_api.KhrSwapchain.CreateSwapchain(_api.Device.VkDevice, createInfo, default, out _swapChainKhr), $"{nameof(SwapChain)}: Could not create a swap chain");
public unsafe PresentModeKHR[] GetPhysicalDeviceSurfacePresentModes(VulkanPhysicalDevice physicalDevice, SurfaceKHR surface) { uint presentationCount = 0u; GetPhysicalDeviceSurfacePresentModes(physicalDevice, surface, &presentationCount, (PresentModeKHR *)null !); if (presentationCount is 0u) { return(Array.Empty <PresentModeKHR>()); } PresentModeKHR *presentModesPointer = stackalloc PresentModeKHR[(int)presentationCount]; GetPhysicalDeviceSurfacePresentModes(physicalDevice, surface, &presentationCount, presentModesPointer); PresentModeKHR[] presentModes = new PresentModeKHR[presentationCount]; new Span <PresentModeKHR>(presentModesPointer, (int)presentationCount).CopyTo(presentModes); return(presentModes); }
public SwapchainCreateInfoKHR ( StructureType sType = StructureType.SwapchainCreateInfoKhr, void *pNext = default, SwapchainCreateFlagsKHR flags = default, SurfaceKHR surface = default, uint minImageCount = default, Format imageFormat = default, ColorSpaceKHR imageColorSpace = default, Extent2D imageExtent = default, uint imageArrayLayers = default, ImageUsageFlags imageUsage = default, SharingMode imageSharingMode = default, uint queueFamilyIndexCount = default, uint *pQueueFamilyIndices = default, SurfaceTransformFlagsKHR preTransform = default, CompositeAlphaFlagsKHR compositeAlpha = default, PresentModeKHR presentMode = default, Bool32 clipped = default, SwapchainKHR oldSwapchain = default ) { SType = sType; PNext = pNext; Flags = flags; Surface = surface; MinImageCount = minImageCount; ImageFormat = imageFormat; ImageColorSpace = imageColorSpace; ImageExtent = imageExtent; ImageArrayLayers = imageArrayLayers; ImageUsage = imageUsage; ImageSharingMode = imageSharingMode; QueueFamilyIndexCount = queueFamilyIndexCount; PQueueFamilyIndices = pQueueFamilyIndices; PreTransform = preTransform; CompositeAlpha = compositeAlpha; PresentMode = presentMode; Clipped = clipped; OldSwapchain = oldSwapchain; }
public static unsafe SwapchainCreateInfoKHR SwapchainCreateInfo(SurfaceKHR surface, uint imageCount, SurfaceFormatKHR format, PresentModeKHR presentMode, Extent2D extent, uint graphicsQueueFamily, uint presentQueueFamily, SurfaceCapabilitiesKHR surfaceCapabilities, SwapchainKHR oldSwapchain) { uint[] queueFamilies = new uint[] { graphicsQueueFamily, presentQueueFamily }; SwapchainCreateInfoKHR swapchainCreateInfo = new() { SType = StructureType.SwapchainCreateInfoKhr, Surface = surface, MinImageCount = imageCount, ImageFormat = format.Format, ImageColorSpace = format.ColorSpace, ImageExtent = extent, ImageArrayLayers = 1, ImageUsage = ImageUsageFlags.ImageUsageColorAttachmentBit, ImageSharingMode = (graphicsQueueFamily == presentQueueFamily) ? SharingMode.Exclusive : SharingMode.Concurrent, QueueFamilyIndexCount = (uint)((graphicsQueueFamily == presentQueueFamily) ? 0 : 2), PreTransform = surfaceCapabilities.CurrentTransform, CompositeAlpha = CompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr, PresentMode = presentMode, Clipped = true, OldSwapchain = oldSwapchain }; fixed(uint *ptr = queueFamilies) { swapchainCreateInfo.PQueueFamilyIndices = ptr; } return(swapchainCreateInfo); }
public _SwapchainCreateInfoKHR(SwapchainCreateInfoKHR info) { SType = info.type; Next = info.next; Flags = info.flags; Surface = info.surface; MinImageCount = info.minImageCount; ImageFormat = info.imageFormat; ImageColorSpace = info.imageColorSpace; ImageExtent = info.imageExtent; ImageArrayLayers = info.imageArrayLayers; ImageUsage = info.imageUsage; ImageSharingMode = info.imageSharingMode; QueueFamilyIndexCount = (UInt32)(info.queueFamilyIndices?.Count ?? 0); QueueFamilyIndices = info.queueFamilyIndices != null?Alloc.alloc(info.queueFamilyIndices) : IntPtr.Zero; PreTransform = info.preTransform; CompositeAlpha = info.compositeAlpha; PresentMode = info.presentMode; Clipped = info.clipped; OldSwapchain = info.oldSwapchain; }
/// <param name="Surface">The swapchain's target surface</param> /// <param name="MinImageCount">Minimum number of presentation images the application needs</param> /// <param name="ImageFormat">Format of the presentation images</param> /// <param name="ImageColorSpace">Colorspace of the presentation images</param> /// <param name="ImageExtent">Dimensions of the presentation images</param> /// <param name="ImageArrayLayers">Determines the number of views for multiview/stereo presentation</param> /// <param name="ImageUsage">Bits indicating how the presentation images will be used</param> /// <param name="ImageSharingMode">Sharing mode used for the presentation images</param> /// <param name="QueueFamilyIndices">Array of queue family indices having access to the images in case of concurrent sharing mode</param> /// <param name="PreTransform">The transform, relative to the device's natural orientation, applied to the image content prior to presentation</param> /// <param name="CompositeAlpha">The alpha blending mode used when compositing this surface with other surfaces in the window system</param> /// <param name="PresentMode">Which presentation mode to use for presents on this swap chain</param> /// <param name="Clipped">Specifies whether presentable images may be affected by window clip regions</param> public SwapchainCreateInfoKHR(SurfaceKHR Surface, UInt32 MinImageCount, Format ImageFormat, ColorSpaceKHR ImageColorSpace, Extent2D ImageExtent, UInt32 ImageArrayLayers, ImageUsageFlags ImageUsage, SharingMode ImageSharingMode, UInt32[] QueueFamilyIndices, SurfaceTransformFlagsKHR PreTransform, CompositeAlphaFlagsKHR CompositeAlpha, PresentModeKHR PresentMode, Bool32 Clipped) : this() { this.Surface = Surface; this.MinImageCount = MinImageCount; this.ImageFormat = ImageFormat; this.ImageColorSpace = ImageColorSpace; this.ImageExtent = ImageExtent; this.ImageArrayLayers = ImageArrayLayers; this.ImageUsage = ImageUsage; this.ImageSharingMode = ImageSharingMode; this.QueueFamilyIndices = QueueFamilyIndices; this.PreTransform = PreTransform; this.CompositeAlpha = CompositeAlpha; this.PresentMode = PresentMode; this.Clipped = Clipped; }
void CreateSwapChain() { CanRender = false; if (!vulkan.Device.IsZero) { vk.DeviceWaitIdle(vulkan.Device); } if (vulkan.SwapChain.Images != null) { for (int i = 0; i < vulkan.SwapChain.Images.Length; ++i) { if (vulkan.SwapChain.Images[i].View != ImageView.Zero) { vk.DestroyImageView(vulkan.Device, vulkan.SwapChain.Images[i].View); } } } SurfaceCapabilitiesKHR surface_capabilities; khrSurface.GetPhysicalDeviceSurfaceCapabilitiesKHR(vulkan.PhysicalDevice, vulkan.PresentationSurface, out surface_capabilities).CheckError(); var surface_formats = DelegateUtility.EnumerateToArray <SurfaceFormatKHR> (khrSurface.GetPhysicalDeviceSurfaceFormatsKHR, (IntPtr)vulkan.PhysicalDevice, (ulong)vulkan.PresentationSurface); var present_modes = DelegateUtility.EnumerateToArray <int> (khrSurface.GetPhysicalDeviceSurfacePresentModesKHR, (IntPtr)vulkan.PhysicalDevice, (ulong)vulkan.PresentationSurface); uint desired_number_of_images = GetSwapChainNumImages(ref surface_capabilities); SurfaceFormatKHR desired_format = GetSwapChainFormat(surface_formats); Extent2D desired_extent = GetSwapChainExtent(ref surface_capabilities); ImageUsageFlagBits desired_usage = GetSwapChainUsageFlagBits(ref surface_capabilities); SurfaceTransformFlagBitsKHR desired_transform = GetSwapChainTransform(ref surface_capabilities); PresentModeKHR desired_present_mode = GetSwapChainPresentMode(present_modes); SwapchainKHR old_swap_chain = vulkan.SwapChain.Handle; if (desired_usage == (ImageUsageFlagBits)(-1)) { return; } if (desired_present_mode == (PresentModeKHR)(-1)) { return; } if ((desired_extent.width == 0) || (desired_extent.height == 0)) { // Current surface size is (0, 0) so we can't create a swap chain and render anything (CanRender == false) // But we don't wont to kill the application as this situation may occur i.e. when window gets minimized return; } SwapchainCreateInfoKHR swap_chain_create_info = new SwapchainCreateInfoKHR { sType = StructureType.SwapchainCreateInfoKhr, // VkStructureType sType pNext = IntPtr.Zero, // const void *pNext flags = 0, // VkSwapchainCreateFlagBitsKHR flags surface = vulkan.PresentationSurface, // VkSurfaceKHR surface minImageCount = desired_number_of_images, // uint32_t minImageCount imageFormat = desired_format.format, // VkFormat imageFormat imageColorSpace = desired_format.colorSpace, // VkColorSpaceKHR imageColorSpace imageExtent = desired_extent, // VkExtent2D imageExtent imageArrayLayers = 1, // uint32_t imageArrayLayers imageUsage = desired_usage, // VkImageUsageFlagBits imageUsage imageSharingMode = SharingMode.Exclusive, // VkSharingMode imageSharingMode queueFamilyIndexCount = 0, // uint32_t queueFamilyIndexCount pQueueFamilyIndices = (uint *)0, // const uint32_t *pQueueFamilyIndices preTransform = desired_transform, // VkSurfaceTransformFlagBitsKHR preTransform compositeAlpha = CompositeAlphaFlagBitsKHR.OpaqueBitKhr, // VkCompositeAlphaFlagBitsKHR compositeAlpha presentMode = desired_present_mode, // VkPresentModeKHR presentMode clipped = Boolean32.True, // VkBool32 clipped oldSwapchain = old_swap_chain // VkSwapchainKHR oldSwapchain }; khrSwapChain.CreateSwapchainKHR(vulkan.Device, ref swap_chain_create_info, (AllocationCallbacks *)0, out vulkan.SwapChain.Handle).CheckError(); if (!old_swap_chain.IsZero) { khrSwapChain.DestroySwapchainKHR(vulkan.Device, old_swap_chain); } vulkan.SwapChain.Format = desired_format.format; var images = DelegateUtility.EnumerateToArray <Image> (khrSwapChain.GetSwapchainImagesKHR, (IntPtr)vulkan.Device, (ulong)vulkan.SwapChain.Handle); if (vulkan.SwapChain.Images == null || vulkan.SwapChain.Images.Length != images.Length) { vulkan.SwapChain.Images = new ImageParameters[images.Length]; } for (int i = 0; i < images.Length; ++i) { vulkan.SwapChain.Images[i].Handle = images[i]; } vulkan.SwapChain.Extent = desired_extent; CreateSwapChainImageViews(); }
private static unsafe SwapchainKHR CreateSwapchain(VulkanInstance instance, VulkanDevice device, VulkanPhysicalDevice physicalDevice, VulkanSurface surface, out Extent2D swapchainExtent, SwapchainKHR?oldswapchain = null, bool vsyncEnabled = true) { if (_swapchainExtension == null) { instance.Api.TryGetDeviceExtension(instance.InternalHandle, device.InternalHandle, out _swapchainExtension); } while (!surface.CanSurfacePresent(physicalDevice)) { Thread.Sleep(16); } VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfaceCapabilities(physicalDevice.InternalHandle, surface.ApiHandle, out var capabilities); var imageCount = capabilities.MinImageCount + 1; if (capabilities.MaxImageCount > 0 && imageCount > capabilities.MaxImageCount) { imageCount = capabilities.MaxImageCount; } var surfaceFormat = surface.GetSurfaceFormat(physicalDevice); bool supportsIdentityTransform = capabilities.SupportedTransforms.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformIdentityBitKhr); bool isRotated = capabilities.CurrentTransform.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformRotate90BitKhr) || capabilities.CurrentTransform.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformRotate270BitKhr); swapchainExtent = GetSwapchainExtent(surface, capabilities); CompositeAlphaFlagsKHR compositeAlphaFlags = GetSuitableCompositeAlphaFlags(capabilities); PresentModeKHR presentMode = GetSuitablePresentMode(physicalDevice, surface, vsyncEnabled); var swapchainCreateInfo = new SwapchainCreateInfoKHR { SType = StructureType.SwapchainCreateInfoKhr, Surface = surface.ApiHandle, MinImageCount = imageCount, ImageFormat = surfaceFormat.Format, ImageColorSpace = surfaceFormat.ColorSpace, ImageExtent = swapchainExtent, ImageUsage = ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit, ImageSharingMode = SharingMode.Exclusive, ImageArrayLayers = 1, PreTransform = supportsIdentityTransform && isRotated ? SurfaceTransformFlagsKHR.SurfaceTransformIdentityBitKhr : capabilities.CurrentTransform, CompositeAlpha = compositeAlphaFlags, PresentMode = presentMode, Clipped = true, OldSwapchain = oldswapchain ?? new SwapchainKHR() }; _swapchainExtension.CreateSwapchain(device.InternalHandle, swapchainCreateInfo, null, out var swapchain) .ThrowOnError(); if (oldswapchain != null) { _swapchainExtension.DestroySwapchain(device.InternalHandle, oldswapchain.Value, null); } return(swapchain); }
private unsafe void CreateSwapchain() { _gd.SurfaceApi.GetPhysicalDeviceSurfaceCapabilities(_physicalDevice, _surface, out var capabilities); uint surfaceFormatsCount; _gd.SurfaceApi.GetPhysicalDeviceSurfaceFormats(_physicalDevice, _surface, &surfaceFormatsCount, null); var surfaceFormats = new SurfaceFormatKHR[surfaceFormatsCount]; fixed(SurfaceFormatKHR *pSurfaceFormats = surfaceFormats) { _gd.SurfaceApi.GetPhysicalDeviceSurfaceFormats(_physicalDevice, _surface, &surfaceFormatsCount, pSurfaceFormats); } uint presentModesCount; _gd.SurfaceApi.GetPhysicalDeviceSurfacePresentModes(_physicalDevice, _surface, &presentModesCount, null); var presentModes = new PresentModeKHR[presentModesCount]; fixed(PresentModeKHR *pPresentModes = presentModes) { _gd.SurfaceApi.GetPhysicalDeviceSurfacePresentModes(_physicalDevice, _surface, &presentModesCount, pPresentModes); } uint imageCount = capabilities.MinImageCount + 1; if (capabilities.MaxImageCount > 0 && imageCount > capabilities.MaxImageCount) { imageCount = capabilities.MaxImageCount; } var surfaceFormat = ChooseSwapSurfaceFormat(surfaceFormats); var extent = ChooseSwapExtent(capabilities); _width = (int)extent.Width; _height = (int)extent.Height; _format = surfaceFormat.Format; var oldSwapchain = _swapchain; var swapchainCreateInfo = new SwapchainCreateInfoKHR() { SType = StructureType.SwapchainCreateInfoKhr, Surface = _surface, MinImageCount = imageCount, ImageFormat = surfaceFormat.Format, ImageColorSpace = surfaceFormat.ColorSpace, ImageExtent = extent, ImageUsage = ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit, ImageSharingMode = SharingMode.Exclusive, ImageArrayLayers = 1, PreTransform = capabilities.CurrentTransform, CompositeAlpha = CompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr, PresentMode = ChooseSwapPresentMode(presentModes), Clipped = true, OldSwapchain = oldSwapchain }; _gd.SwapchainApi.CreateSwapchain(_device, swapchainCreateInfo, null, out _swapchain).ThrowOnError(); _gd.SwapchainApi.GetSwapchainImages(_device, _swapchain, &imageCount, null); _swapchainImages = new Image[imageCount]; fixed(Image *pSwapchainImages = _swapchainImages) { _gd.SwapchainApi.GetSwapchainImages(_device, _swapchain, &imageCount, pSwapchainImages); } _swapchainImageViews = new Auto <DisposableImageView> [imageCount]; for (int i = 0; i < imageCount; i++) { _swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format); } }
private void InitializeVulkan(string applicationName, uint applicationVersion) { Console.WriteLine("Initializing Vulkan"); #if VALIDITION DebugUtilsMessengerCreateInfoEXT GetDebugMessenger(void *pNext) { return(new DebugUtilsMessengerCreateInfoEXT( messageSeverity: DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityVerboseBitExt | DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityInfoBitExt | DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt | DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt, messageType: DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeGeneralBitExt | DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypePerformanceBitExt | DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt, pfnUserCallback: new PfnDebugUtilsMessengerCallbackEXT(DebugCallback), pNext: pNext)); } #endif _vk = Vk.GetApi(); const uint engineVersion = 1; const string engineName = "Videre"; var instanceLayers = new List <string>(); var instanceExtensions = new List <string>(); var pApplicationName = SilkMarshal.StringToPtr(applicationName); var pEngineName = SilkMarshal.StringToPtr(engineName); var applicationInfo = new ApplicationInfo(pApplicationName: (byte *)pApplicationName, applicationVersion: applicationVersion, pEngineName: (byte *)pEngineName, engineVersion: engineVersion, apiVersion: new Version32(1, 1, 0)); Version32 apiVersion = default; _vk.EnumerateInstanceVersion((uint *)&apiVersion); Console.WriteLine($"Instance Version: {apiVersion.Major}.{apiVersion.Minor}.{apiVersion.Patch}"); void *instancepNext = default; // instanceExtensions.Add(KhrSurface.ExtensionName); instanceExtensions.AddRange(SilkMarshal.PtrToStringArray((nint)View.VkSurface.GetRequiredExtensions(out var requiredExtensionsCount), (int)requiredExtensionsCount)); instanceExtensions.Add(ExtDebugUtils.ExtensionName); Console.WriteLine($"Creating Instance with {instanceExtensions.Count} extensions"); VerifyInstanceExtensionsAvailable(_vk, instanceExtensions); var ppEnabledLayers = instanceLayers.Count > 0 ? (byte **)SilkMarshal.StringArrayToPtr(instanceLayers) : null; var ppEnabledExtensions = instanceExtensions.Count > 0 ? (byte **)SilkMarshal.StringArrayToPtr(instanceExtensions) : null; _vk.CreateInstance( new InstanceCreateInfo(pApplicationInfo: &applicationInfo, enabledLayerCount: (uint)instanceLayers.Count, ppEnabledLayerNames: ppEnabledLayers, enabledExtensionCount: (uint)instanceExtensions.Count, ppEnabledExtensionNames: ppEnabledExtensions, pNext: instancepNext), _allocationCallbacks.AllocationCallbacks, out _instance) .ThrowCode(); SilkMarshal.Free((nint)ppEnabledLayers); SilkMarshal.Free((nint)ppEnabledExtensions); _vk.CurrentInstance = _instance; if (!_vk.TryGetInstanceExtension(_instance, out _khrSurface)) { Console.WriteLine($"Could not load {KhrSurface.ExtensionName}"); } _vk.TryGetInstanceExtension(_instance, out _debugUtils); Console.WriteLine("Creating Surface"); _surface = View.VkSurface.Create(_instance.ToHandle(), (AllocationCallbacks *)null).ToSurface(); uint deviceCount = 0; _vk.EnumeratePhysicalDevices(_instance, ref deviceCount, null).ThrowCode(); var devices = (PhysicalDevice *)SilkMarshal.Allocate((int)(deviceCount * sizeof(PhysicalDevice))); _vk.EnumeratePhysicalDevices(_instance, ref deviceCount, devices).ThrowCode(); Console.WriteLine($"Found {deviceCount} devices"); Console.WriteLine("Creating Device"); // TODO: actually somehow reasonably find the best device. for (int i = 0; i < deviceCount; i++) { var physicalDevice = devices[i]; _physicalDeviceFeatures = _vk.GetPhysicalDeviceFeature(physicalDevice); uint presentModeCount = 0; _khrSurface.GetPhysicalDeviceSurfacePresentModes(physicalDevice, _surface, ref presentModeCount, null).ThrowCode(); if (presentModeCount <= 0) { continue; } var presentModes = (PresentModeKHR *)SilkMarshal.Allocate((int)(presentModeCount * sizeof(PresentModeKHR))); _khrSurface.GetPhysicalDeviceSurfacePresentModes(physicalDevice, _surface, ref presentModeCount, presentModes).ThrowCode(); _presentMode = PresentModeKHR.PresentModeFifoKhr; View.FramesPerSecond = -1; for (int j = 0; j < presentModeCount; j++) { if (presentModes[j] == PresentModeKHR.PresentModeMailboxKhr) { _presentMode = PresentModeKHR.PresentModeMailboxKhr; View.FramesPerSecond = -1; break; } } SilkMarshal.Free((nint)presentModes); uint surfaceFormatCount = 0; _khrSurface.GetPhysicalDeviceSurfaceFormats(physicalDevice, _surface, ref surfaceFormatCount, null).ThrowCode(); var surfaceFormats = (SurfaceFormatKHR *)SilkMarshal.Allocate((int)(surfaceFormatCount * sizeof(SurfaceFormatKHR))); _khrSurface.GetPhysicalDeviceSurfaceFormats(physicalDevice, _surface, ref surfaceFormatCount, surfaceFormats).ThrowCode(); int max = int.MinValue; SurfaceFormatKHR maxFormat = surfaceFormats[0]; for (int j = 0; j < surfaceFormatCount; j++) { var score = FormatRater.Rate(surfaceFormats[j].Format) + ColorSpaceRater.Rate(surfaceFormats[j].ColorSpace); if (score > max) { max = score; maxFormat = surfaceFormats[j]; } } SilkMarshal.Free((nint)surfaceFormats); _swapchainFormat = maxFormat.Format; _swapchainColorSpace = maxFormat.ColorSpace; Console.WriteLine($"Chose Swapchain Properties: {Enum.GetName(typeof(PresentModeKHR), _presentMode)} {Enum.GetName(typeof(Format), _swapchainFormat)} {Enum.GetName(typeof(ColorSpaceKHR), _swapchainColorSpace)}"); _khrSurface.GetPhysicalDeviceSurfaceCapabilities(physicalDevice, _surface, out var surfaceCapabilities).ThrowCode(); uint queueFamilyPropertyCount = 0; _vk.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyPropertyCount, null); var deviceQueueFamilyProperties = (QueueFamilyProperties *)SilkMarshal.Allocate((int)(queueFamilyPropertyCount * sizeof(QueueFamilyProperties))); _vk.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyPropertyCount, deviceQueueFamilyProperties); var queueCreateInfoList = new List <DeviceQueueCreateInfo>(); var deviceExtensions = new List <string>(); var deviceLayers = new List <string>(); for (int j = 0; j < queueFamilyPropertyCount; j++) { var queueCount = deviceQueueFamilyProperties[j].QueueCount; float *pQueuePriorities = stackalloc float[(int)queueCount]; // queue count should generally be 1 for (int k = 0; k < queueCount; k++) { pQueuePriorities[k] = 1.0f; } queueCreateInfoList.Add(new DeviceQueueCreateInfo(queueFamilyIndex: (uint)j, queueCount: queueCount, pQueuePriorities: pQueuePriorities)); } deviceExtensions.Add(KhrSwapchain.ExtensionName); // deviceExtensions.Add(KhrSynchronization2.ExtensionName); // deviceExtensions.Add(ExtBufferDeviceAddress.ExtensionName); var features = new PhysicalDeviceFeatures(); features.ShaderInt64 = true; void *devicePNext = null; // var physicalDeviceDescriptorIndexingFeaturesExt = new PhysicalDeviceDescriptorIndexingFeaturesEXT( // descriptorBindingSampledImageUpdateAfterBind: true, // descriptorBindingStorageBufferUpdateAfterBind: true, // descriptorBindingStorageImageUpdateAfterBind: true, // descriptorBindingUniformBufferUpdateAfterBind: true, // descriptorBindingStorageTexelBufferUpdateAfterBind: true, // descriptorBindingUniformTexelBufferUpdateAfterBind: true, // descriptorBindingUpdateUnusedWhilePending: true, // runtimeDescriptorArray: true, // pNext: devicePNext); // devicePNext = &physicalDeviceDescriptorIndexingFeaturesExt; // var physicalDeviceBufferDeviceAddressFeatures = new PhysicalDeviceBufferDeviceAddressFeatures(bufferDeviceAddress: true, #if DEBUG bufferDeviceAddressCaptureReplay: true, #endif pNext: devicePNext); devicePNext = &physicalDeviceBufferDeviceAddressFeatures; // var version12 = new PhysicalDeviceVulkan12Features(bufferDeviceAddress: true, // #if DEBUG // bufferDeviceAddressCaptureReplay: true, // #endif // descriptorBindingSampledImageUpdateAfterBind: true, // descriptorBindingStorageBufferUpdateAfterBind: true, // descriptorBindingStorageImageUpdateAfterBind: true, // descriptorBindingUniformBufferUpdateAfterBind: true, // descriptorBindingStorageTexelBufferUpdateAfterBind: true, // descriptorBindingUniformTexelBufferUpdateAfterBind: true, // descriptorBindingUpdateUnusedWhilePending: true, // runtimeDescriptorArray: true, // pNext: devicePNext); // devicePNext = &version12; var queueCreateInfos = queueCreateInfoList.Distinct().ToArray(); queueCreateInfoList = null; VerifyDeviceExtensionsAvailable(_vk, devices[i], deviceExtensions, ref deviceLayers); _physicalDevice = devices[i]; Console.WriteLine("Creating Logical Device"); var ppDeviceExtensions = deviceExtensions.Count > 0 ? (byte **)SilkMarshal.StringArrayToPtr(deviceExtensions) : null; var ppDeviceLayers = deviceLayers.Count > 0 ? (byte **)SilkMarshal.StringArrayToPtr(deviceLayers) : null; fixed(DeviceQueueCreateInfo *pQueueCreateInfos = queueCreateInfos) _vk.CreateDevice(physicalDevice, new DeviceCreateInfo(queueCreateInfoCount: (uint)queueCreateInfos.Length, pQueueCreateInfos: pQueueCreateInfos, enabledExtensionCount: (uint)deviceExtensions.Count, enabledLayerCount: (uint)deviceLayers.Count, ppEnabledExtensionNames: ppDeviceExtensions, ppEnabledLayerNames: ppDeviceLayers, pEnabledFeatures: &features, pNext: devicePNext), null, out _logicalDevice) .ThrowCode(); _vk.CurrentDevice = _logicalDevice; if (!_vk.TryGetDeviceExtension(_instance, _logicalDevice, out _khrSwapchain)) { Console.WriteLine($"Could not load {KhrSwapchain.ExtensionName}!"); } _queueManager = new(_vk, _khrSurface, _instance, _physicalDevice, _logicalDevice, _surface, new Span <QueueFamilyProperties>(deviceQueueFamilyProperties, (int)queueFamilyPropertyCount)); Console.WriteLine($"{_queueManager.QueueCount} queues found"); SilkMarshal.Free((nint)ppDeviceExtensions); SilkMarshal.Free((nint)ppDeviceLayers); SilkMarshal.Free((nint)deviceQueueFamilyProperties); break; } SilkMarshal.Free((nint)devices); Console.WriteLine("Initialized Vulkan"); }
public abstract Result GetPhysicalDeviceSurfacePresentModes([Count(Count = 0)] PhysicalDevice physicalDevice, [Count(Count = 0)] SurfaceKHR surface, [Count(Count = 0)] ref uint pPresentModeCount, [Count(Computed = "pPresentModeCount"), Flow(FlowDirection.Out)] out PresentModeKHR pPresentModes);
public unsafe VulkanRenderer(UserSettings userSettings, Window window, IScene scene, CameraInitialState cameraInitialState, ILogger logger, bool enableDebugLogging) { _userSettings = userSettings; _window = window; _api = new Api(enableDebugLogging, logger); _presentMode = _userSettings.VSync ? PresentModeKHR.PresentModeFifoKhr : PresentModeKHR.PresentModeImmediateKhr; _api.Instance = new Instance(_api, _window, new Version32(1, 2, 0)); _surface = new Surface(_api, _window, _api.Instance); // Find the vulkan device we want var physicalDevice = _api.Instance.PhysicalDevices.Where(d => { _api.Vk.GetPhysicalDeviceFeatures(d, out var deviceFeatures); if (deviceFeatures.GeometryShader == false) { return(false); } var queueFamilies = Enumerate.Get <PhysicalDevice, QueueFamilyProperties>(d, (device, count, values) => _api.Vk.GetPhysicalDeviceQueueFamilyProperties(device, (uint *)count, (QueueFamilyProperties *)values)); for (var i = 0; i < queueFamilies.Count; i++) { if (queueFamilies[i].QueueCount > 0 && queueFamilies[i].QueueFlags.HasFlag(QueueFlags.QueueGraphicsBit)) { return(true); } } return(false); }).FirstOrDefault(); if (physicalDevice.Handle == 0) { throw new Exception($"{nameof(VulkanRenderer)}: Could not find a suitable graphics device."); } var deviceProps = new PhysicalDeviceProperties2(); deviceProps.SType = StructureType.PhysicalDeviceProperties2; _api.Vk.GetPhysicalDeviceProperties2(physicalDevice, &deviceProps); _api.Logger.Debug($"{nameof(VulkanRenderer)}: Setting physical device: {deviceProps.Properties.DeviceID} ({Marshal.PtrToStringAnsi((nint)deviceProps.Properties.DeviceName)})"); // Opt-in into mandatory device features. var shaderClockFeatures = new PhysicalDeviceShaderClockFeaturesKHR(); shaderClockFeatures.SType = StructureType.PhysicalDeviceShaderClockFeaturesKhr; shaderClockFeatures.PNext = null; shaderClockFeatures.ShaderSubgroupClock = true; var deviceFeatures = new PhysicalDeviceFeatures(); deviceFeatures.FillModeNonSolid = true; deviceFeatures.SamplerAnisotropy = true; deviceFeatures.ShaderInt64 = true; // Required device features. var bufferDeviceAddressFeatures = new PhysicalDeviceBufferDeviceAddressFeatures(); bufferDeviceAddressFeatures.SType = StructureType.PhysicalDeviceBufferDeviceAddressFeatures; bufferDeviceAddressFeatures.PNext = &shaderClockFeatures; bufferDeviceAddressFeatures.BufferDeviceAddress = true; var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures(); indexingFeatures.SType = StructureType.PhysicalDeviceDescriptorIndexingFeatures; indexingFeatures.PNext = &bufferDeviceAddressFeatures; indexingFeatures.RuntimeDescriptorArray = true; indexingFeatures.ShaderSampledImageArrayNonUniformIndexing = true; var accelerationStructureFeatures = new PhysicalDeviceAccelerationStructureFeaturesKHR(); accelerationStructureFeatures.SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; accelerationStructureFeatures.PNext = &indexingFeatures; accelerationStructureFeatures.AccelerationStructure = true; var rayTracingFeatures = new PhysicalDeviceRayTracingPipelineFeaturesKHR(); rayTracingFeatures.SType = StructureType.PhysicalDeviceRayTracingPipelineFeaturesKhr; rayTracingFeatures.PNext = &accelerationStructureFeatures; rayTracingFeatures.RayTracingPipeline = true; _api.Device = new Device(_api, physicalDevice, _surface, deviceFeatures, Unsafe.AsPointer(ref rayTracingFeatures)); // Now that we have an instance and a device, load all of the extentions we need. _api.InitializeExtensions(); _commandPool = new CommandPool(_api, _api.Device.GraphicsFamilyIndex, true); _rayTracingProperties = new RayTracingProperties(_api); // Load the scene, and create the swap chain / command buffers LoadScene(scene, cameraInitialState); _currentFrame = 0; _api.Device.WaitIdle(); }