public SwapchainManager(Device LogicalDevice, SurfaceFormatKHR SelectedSurfaceFormat) { var compositeAlpha = VulkanRenderer.Surface.SurfaceCapabilities.SupportedCompositeAlpha.HasFlag(CompositeAlphaFlagsKHR.Inherit) ? CompositeAlphaFlagsKHR.Inherit : CompositeAlphaFlagsKHR.Opaque; SemaphoreCreateInfo semaphoreInfo = new SemaphoreCreateInfo(); SwapchainDrawCompleteSemaphore = LogicalDevice.CreateSemaphore(semaphoreInfo); CreateDefaultSwapchainRenderPass(LogicalDevice); renderPassBeginInfo = new RenderPassBeginInfo { ClearValueCount = 1, ClearValues = new ClearValue[] { new ClearValue { Color = new ClearColorValue(Color.AliceBlue) } }, RenderPass = myBaseRenderPass }; renderPassBeginInfo.RenderArea = new Rect2D { Extent = new Extent2D { Width = VulkanRenderer.Surface.SurfaceCapabilities.CurrentExtent.Width, Height = VulkanRenderer.Surface.SurfaceCapabilities.CurrentExtent.Height }, Offset = new Offset2D { X = 0, Y = 0 } }; var swapchainInfo = new SwapchainCreateInfoKHR { Surface = VulkanRenderer.Surface, MinImageCount = VulkanRenderer.Surface.SurfaceCapabilities.MinImageCount + 1, ImageFormat = VulkanRenderer.Surface.SelectedSurfaceFormat.Format, ImageColorSpace = VulkanRenderer.Surface.SelectedSurfaceFormat.ColorSpace, ImageExtent = VulkanRenderer.Surface.SurfaceCapabilities.CurrentExtent, ImageUsage = ImageUsageFlags.ColorAttachment, PreTransform = SurfaceTransformFlagsKHR.Identity, ImageArrayLayers = 1, ImageSharingMode = SharingMode.Exclusive, QueueFamilyIndices = new uint[] { VulkanRenderer.ActiveGraphicsFamilyQueueIndex }, PresentMode = PresentModeKHR.Fifo, CompositeAlpha = compositeAlpha }; Swapchain = VulkanRenderer.SelectedLogicalDevice.CreateSwapchainKHR(swapchainInfo); Images = VulkanRenderer.SelectedLogicalDevice.GetSwapchainImagesKHR(Swapchain); SwapChainPresentInfo = new PresentInfoKHR { Swapchains = new SwapchainKHR[] { Swapchain }, ImageIndices = new uint[] { VulkanRenderer.SelectedLogicalDevice.AcquireNextImageKHR(Swapchain, ulong.MaxValue, SwapchainDrawCompleteSemaphore) } }; Framebuffers = new SwapChainFrameBuffer[Images.Length]; //Move this to swap chains for (int i = 0; i < Images.Length; i++) { Framebuffers[i] = new SwapChainFrameBuffer(myBaseRenderPass, Images[i], i, VulkanRenderer.Surface.SurfaceCapabilities.CurrentExtent.Width, VulkanRenderer.Surface.SurfaceCapabilities.CurrentExtent.Height, 1); Framebuffers[i].Initialize(); } }
public unsafe SurfaceFormatKHR[] GetPhysicalDeviceSurfaceFormats(VulkanPhysicalDevice physicalDevice, SurfaceKHR surface) { uint formatsCount = 0u; GetPhysicalDeviceSurfaceFormats(physicalDevice, surface, &formatsCount, (SurfaceFormatKHR *)null !); if (formatsCount is 0u) { return(Array.Empty <SurfaceFormatKHR>()); } SurfaceFormatKHR *surfaceFormatsPointer = stackalloc SurfaceFormatKHR[(int)formatsCount]; GetPhysicalDeviceSurfaceFormats(physicalDevice, surface, &formatsCount, surfaceFormatsPointer); SurfaceFormatKHR[] surfaceFormats = new SurfaceFormatKHR[formatsCount]; new Span <SurfaceFormatKHR>(surfaceFormatsPointer, (int)formatsCount).CopyTo(surfaceFormats); return(surfaceFormats); }
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 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 GetPhysicalDeviceSurfaceFormats([Count(Count = 0)] PhysicalDevice physicalDevice, [Count(Count = 0)] SurfaceKHR surface, [Count(Count = 0)] ref uint pSurfaceFormatCount, [Count(Computed = "pSurfaceFormatCount"), Flow(FlowDirection.Out)] out SurfaceFormatKHR pSurfaceFormats);
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); }