private int?GetPresentQueueFamilyIndex(SurfaceKhr surface) { for (int i = 0; i < queueFamilies.Length; i++) { //Verify that this queue-family supports presenting to the platform compositor switch (surfaceType) { //On windows test if this queue supports presentation to the win32 compositor case SurfaceType.HkrWin32: if (!physicalDevice.GetWin32PresentationSupportKhr(i)) { continue; } break; //On MacOS it is enough to know that the MVK extension is supported, if so we //can also present to the compositor } //Verify that the given surface is compatible with this queue-family if (physicalDevice.GetSurfaceSupportKhr(i, surface)) { return(i); } } return(null); }
internal Window( string title, INativeWindow nativeWindow, SurfaceKhr surface, HostDevice hostDevice, HostDeviceRequirements deviceRequirements, Logger logger = null) { if (nativeWindow == null) { throw new ArgumentNullException(nameof(nativeWindow)); } if (surface == null) { throw new ArgumentNullException(nameof(surface)); } if (hostDevice == null) { throw new ArgumentNullException(nameof(hostDevice)); } this.title = title; this.nativeWindow = nativeWindow; this.surface = surface; this.hostDevice = hostDevice; this.logger = logger; //Subscribe to callbacks for the native window nativeWindow.CloseRequested += OnNativeWindowCloseRequested; nativeWindow.Resized += OnNativeWindowResized; //Create a logical device (and queues on the device) IList <string> enabledExtensions; (logicalDevice, graphicsQueue, presentQueue, enabledExtensions) = hostDevice.CreateLogicalDevice( surface: surface, deviceRequirements: deviceRequirements); hasDebugMarkerExtension = enabledExtensions.Contains("VK_EXT_debug_marker"); if (hasDebugMarkerExtension) { logger?.Log(nameof(Window), "Enabled debug-markers"); } //Get a presentmode to use presentMode = hostDevice.GetPresentMode(surface); //Get the surfaceformat to use (surfaceFormat, surfaceColorspace) = hostDevice.GetSurfaceFormat(surface); //Gets how many swapchain images we should use swapchainCount = hostDevice.GetSwapchainCount(surface); //Create a command-pool attached to this device commandPool = logicalDevice.CreateCommandPool(new CommandPoolCreateInfo( queueFamilyIndex: graphicsQueue.FamilyIndex, flags: CommandPoolCreateFlags.None )); //Create the swapchain (images to present to the screen) CreateSwapchain(swapchainCount); //Synchronization objects are used to sync the rendering and presenting CreateSynchronizationObjects(); }
internal (Format imageFormat, ColorSpaceKhr colorspace) GetSurfaceFormat(SurfaceKhr surface) { SurfaceFormatKhr[] formats = physicalDevice.GetSurfaceFormatsKhr(surface); //If the device only returns 1 options for this surface and it contains 'Undefined' it //means that the device doesn't care and we can pick. if (formats.Length == 1 && formats[0].Format == VulkanCore.Format.Undefined) { return(Format.B8G8R8A8UNorm, ColorSpaceKhr.SRgbNonlinear); } //If the device has preference then we check if it supports the combo we prefer for (int i = 0; i < formats.Length; i++) { if (formats[i].Format == Format.B8G8R8A8UNorm && formats[i].ColorSpace == ColorSpaceKhr.SRgbNonlinear) { return(formats[i].Format, formats[i].ColorSpace); } } //If our preference is not there then we take the first that is supported if (formats.Length > 0) { return(formats[0].Format, formats[0].ColorSpace); } throw new Exception( $"[{nameof(HostDevice)}] Device {Name} doesn't support any format for use with given surface"); }
public QueueFamilyIndices(PhysicalDevice device, SurfaceKhr surface) { int graphicsIndex = -1; int presentIndex = -1; int i = 0; var queues = device.GetQueueFamilyProperties(); foreach (var f in queues) { if (graphicsIndex < 0 && f.QueueCount > 0 && (f.QueueFlags & QueueFlags.Graphics) != 0) { graphicsIndex = i; } if (presentIndex < 0 && f.QueueCount > 0 && device.GetSurfaceSupportKHR((uint)i, surface)) { presentIndex = i; } ++i; } GraphicsFamily = graphicsIndex; PresentFamily = presentIndex; }
private HostDevice FindSuitableDevice( SurfaceKhr surface, HostDeviceRequirements deviceRequirements, bool preferDiscreteDevice = true) { ThrowIfDisposed(); List <HostDevice> supportedDevices = new List <HostDevice>(); //Find all devices that support the given surface for (int i = 0; i < hostDevices.Length; i++) { if (hostDevices[i].IsSurfaceSupported(surface) && hostDevices[i].AreRequirementsMet(deviceRequirements)) { supportedDevices.Add(hostDevices[i]); } } if (supportedDevices.IsEmpty()) { throw new Exception($"[{nameof(Host)}] Unable to find a supported device"); } //If we have a supported discreate gpu and we prefer a discrete one then we pick that for (int i = 0; i < supportedDevices.Count; i++) { if (supportedDevices[i].IsDiscreteGPU == preferDiscreteDevice) { return(supportedDevices[i]); } } return(supportedDevices[0]); }
internal bool IsSurfaceSupported(SurfaceKhr surface) { //Verify that all our required extensions are available, that we have a graphics queue //and a present queue return(AreExtensionsAvailable(GetRequiredExtensions(surfaceType)) && GetGraphicsQueueFamilyIndex() != null && GetPresentQueueFamilyIndex(surface) != null); }
public static bool CheckSwapchainCreateInfo(PhysicalDevice physicalDevice, SwapchainCreateInfoKhr createInfo, bool fixExtend) { SurfaceKhr surface = createInfo.Surface; foreach (uint index in createInfo.QueueFamilyIndices) { if (!physicalDevice.GetSurfaceSupportKHR(index, surface)) { return(false); } } bool supportImageFormat = false; foreach (SurfaceFormatKhr suportedFormat in physicalDevice.GetSurfaceFormatsKHR(surface)) { if (suportedFormat.Format == createInfo.ImageFormat && suportedFormat.ColorSpace == createInfo.ImageColorSpace) { supportImageFormat = true; break; } } if (!supportImageFormat) { return(false); } SurfaceCapabilitiesKhr capabilities = physicalDevice.GetSurfaceCapabilitiesKHR(surface); if (fixExtend) { var extend = createInfo.ImageExtent; extend.Width = Clamp(extend.Width, capabilities.MinImageExtent.Width, capabilities.MaxImageExtent.Width); extend.Height = Clamp(extend.Height, capabilities.MinImageExtent.Height, capabilities.MaxImageExtent.Height); createInfo.ImageExtent = extend; } if (createInfo.PreTransform == SurfaceTransformFlagsKhr.Inherit) { createInfo.PreTransform = capabilities.CurrentTransform; } // TODO: Fix up CompositeAlpha if Inherit is set if (capabilities.MinImageCount <= createInfo.MinImageCount && capabilities.MaxImageCount >= createInfo.MinImageCount && capabilities.MaxImageArrayLayers <= createInfo.ImageArrayLayers && ((capabilities.SupportedTransforms & createInfo.PreTransform) == createInfo.PreTransform) && ((capabilities.SupportedCompositeAlpha & createInfo.CompositeAlpha) == createInfo.CompositeAlpha) && ((capabilities.SupportedUsageFlags & createInfo.ImageUsage) == createInfo.ImageUsage) && createInfo.ImageExtent.Width >= capabilities.MinImageExtent.Width && createInfo.ImageExtent.Width <= capabilities.MaxImageExtent.Width && createInfo.ImageExtent.Height >= capabilities.MinImageExtent.Height && createInfo.ImageExtent.Height <= capabilities.MaxImageExtent.Height) { return(true); } return(false); }
private void CreateSurface(IntPtr windowHandle) { vkSurface = vkInstance.CreateWin32SurfaceKHR( new Win32SurfaceCreateInfoKhr() { Hinstance = Process.GetCurrentProcess().Handle, Hwnd = windowHandle }); }
protected override void NativeWindowAcquired() { _physicalDevice = Instance.EnumeratePhysicalDevices() [0]; _surface = Instance.CreateAndroidSurfaceKHR(new AndroidSurfaceCreateInfoKhr { Window = aNativeWindow }); _vulkanSample.Initialize(_physicalDevice, _surface); base.NativeWindowAcquired(); }
protected override void OnLoad(EventArgs e) { base.OnLoad(e); Surface = Instance.CreateWin32SurfaceKHR( new Win32SurfaceCreateInfoKhr { Hwnd = Handle, Hinstance = Process.GetCurrentProcess().Handle }); }
private SurfaceFormatKhr SelectFormat(PhysicalDevice physicalDevice, SurfaceKhr surface) { foreach (var f in physicalDevice.GetSurfaceFormatsKHR(surface)) { if (f.Format == Format.R8g8b8a8Unorm || f.Format == Format.B8g8r8a8Unorm) { return(f); } } throw new Exception("didn't find the R8g8b8a8Unorm format"); }
void ExaminePhysicalDevices(Instance inst, SurfaceKhr surf) { PhysicalDevice [] devs = inst.GetInstance().EnumeratePhysicalDevices(); Debug.Assert(devs.Length > 0); mPhysicals.AddRange(devs); mDeviceProps.Clear(); mDeviceFeatures.Clear(); mDeviceQueueFamProps.Clear(); foreach (PhysicalDevice pd in devs) { mDeviceProps.Add(pd.GetProperties()); mDeviceFeatures.Add(pd.GetFeatures()); mDeviceQueueFamProps.Add(pd.GetQueueFamilyProperties()); } for (int dev = 0; dev < mDeviceQueueFamProps.Count; dev++) { mComputeIndexes.Add(dev, new List <int>()); mGraphicsIndexes.Add(dev, new List <int>()); mSparseIndexes.Add(dev, new List <int>()); mTransferIndexes.Add(dev, new List <int>()); mQueueLimits.Add(dev, new List <int>()); mbPresentSupport.Add(dev, new List <bool>()); QueueFamilyProperties [] qfps = mDeviceQueueFamProps[dev]; for (int i = 0; i < qfps.Length; i++) { mQueueLimits[dev].Add(qfps[i].QueueCount); mbPresentSupport[dev].Add( devs[dev].GetSurfaceSupportKhr(i, surf)); if ((qfps[i].QueueFlags & Queues.Compute) != 0) { mComputeIndexes[dev].Add(i); } if ((qfps[i].QueueFlags & Queues.Graphics) != 0) { mGraphicsIndexes[dev].Add(i); } if ((qfps[i].QueueFlags & Queues.SparseBinding) != 0) { mSparseIndexes[dev].Add(i); } if ((qfps[i].QueueFlags & Queues.Transfer) != 0) { mTransferIndexes[dev].Add(i); } } } }
protected SurfaceFormatKhr SelectFormat(PhysicalDevice physicalDevice, SurfaceKhr surface) { foreach (var f in physicalDevice.GetSurfaceFormatsKHR(surface)) { if (f.Format == Format.R8G8B8A8Unorm || f.Format == Format.B8G8R8A8Unorm) { return(f); } } throw new System.Exception("didn't find the R8G8B8A8Unorm or B8G8R8A8Unorm format"); }
static void CreateSurface() { IntPtr HINSTANCE, HWND; GetProcessHandles(out HINSTANCE, out HWND); var surfaceCreateInfo = new Win32SurfaceCreateInfo { hinstance = HINSTANCE, hwnd = HWND, }; surface = instance.CreateWin32Surface(surfaceCreateInfo); Console.WriteLine("[ OK ] Surface"); }
private void InitializeVulkan(PhysicalDevice physDev, SurfaceKhr surface) { var queueFamilyProperties = physDev.GetQueueFamilyProperties(); uint queueFamilyUsedIndex; for (queueFamilyUsedIndex = 0; queueFamilyUsedIndex < queueFamilyProperties.Length; ++queueFamilyUsedIndex) { if (!physDev.GetSurfaceSupportKHR(queueFamilyUsedIndex, surface)) { continue; } if (queueFamilyProperties[queueFamilyUsedIndex].QueueFlags.HasFlag(QueueFlags.Graphics)) { break; } } var queueInfo = new DeviceQueueCreateInfo { QueuePriorities = new[] { 1.0f }, QueueFamilyIndex = queueFamilyUsedIndex }; var deviceInfo = new DeviceCreateInfo { EnabledExtensionNames = new[] { "VK_KHR_swapchain", }, QueueCreateInfos = new[] { queueInfo } }; _device = physDev.CreateDevice(deviceInfo); _queue = _device.GetQueue(0, 0); _surfaceCapabilities = physDev.GetSurfaceCapabilitiesKHR(surface); var surfaceFormat = SelectSurfaceFormat(physDev, surface); _swapchainKhr = CreateSwapchainKhr(surface, surfaceFormat); _images = _device.GetSwapchainImagesKHR(_swapchainKhr); _renderPass = CreateRenderPass(surfaceFormat); _framebuffers = CreateFramebuffers(_images, surfaceFormat); var fenceInfo = new FenceCreateInfo(); _fence = _device.CreateFence(fenceInfo); var semaphoreInfo = new SemaphoreCreateInfo(); _semaphore = _device.CreateSemaphore(semaphoreInfo); _commandBuffers = CreateCommandBuffers(_images, _framebuffers, _renderPass, _surfaceCapabilities); }
internal int GetSwapchainCount(SurfaceKhr surface) { SurfaceCapabilitiesKhr capabilities = GetCurrentCapabilities(surface); //1 more then min to support triple buffering int count = capabilities.MinImageCount + 1; //If the capabilities specify a max then clamp to that if (capabilities.MaxImageCount > 0) { count = IntUtils.Min(count, capabilities.MaxImageCount); } return(count); }
private SurfaceFormatKhr SelectSurfaceFormat(PhysicalDevice physDev, SurfaceKhr surface) { foreach (var f in physDev.GetSurfaceFormatsKHR(surface)) { if (f.Format == Format.R8G8B8A8Unorm || f.Format == Format.B8G8R8A8Unorm) { return(f); } } throw new EngineException( "didn't find the R8G8B8A8Unorm or B8G8R8A8Unorm format", string.Empty ); }
public override void Initialize(PhysicalDevice physicalDevice, SurfaceKhr surface) { base.Initialize(physicalDevice, surface); var vertexBuffer = CreateBuffer(physicalDevice, Logo.Vertices, BufferUsageFlags.VertexBuffer, typeof(float)); var indexBuffer = CreateBuffer(physicalDevice, Logo.Indexes, BufferUsageFlags.IndexBuffer, typeof(short)); uniformBuffer = CreateUniformBuffer(physicalDevice); descriptorSetLayout = CreateDescriptorSetLayout(); var pipelines = CreatePipelines(); descriptorSets = CreateDescriptorSets(); UpdateDescriptorSets(); commandBuffers = CreateCommandBuffers(images, framebuffers, pipelines [0], vertexBuffer, indexBuffer, (uint)Logo.Indexes.Length); }
public static SurfaceKhr CreateAndroidSurfaceKHR(this Instance instance, AndroidSurfaceCreateInfoKhr pCreateInfo, AllocationCallbacks pAllocator) { Result result; SurfaceKhr pSurface; unsafe { pSurface = new SurfaceKhr (); fixed (UInt64* ptrpSurface = &pSurface.m) { result = Android.Interop.NativeMethods.vkCreateAndroidSurfaceKHR (instance.m, pCreateInfo.m, pAllocator != null ? pAllocator.m : null, ptrpSurface); } if (result != Result.Success) throw new ResultException (result); return pSurface; } }
public static SurfaceKhr CreateWin32SurfaceKHR(this Instance instance, Win32SurfaceCreateInfoKhr pCreateInfo, AllocationCallbacks pAllocator = null) { unsafe { var pSurface = new SurfaceKhr(); Result result; fixed(ulong *ptrpSurface = &pSurface._handle) result = NativeMethods.vkCreateWin32SurfaceKHR(instance.Handle, pCreateInfo._handle, pAllocator != null ? pAllocator.Handle : null, ptrpSurface); if (result != Result.Success) { throw new ResultException(result); } return(pSurface); } }
public virtual void Initialize(PhysicalDevice physicalDevice, SurfaceKhr surface) { var queueFamilyProperties = physicalDevice.GetQueueFamilyProperties(); uint queueFamilyUsedIndex; for (queueFamilyUsedIndex = 0; queueFamilyUsedIndex < queueFamilyProperties.Length; ++queueFamilyUsedIndex) { if (!physicalDevice.GetSurfaceSupportKHR(queueFamilyUsedIndex, surface)) { continue; } if (queueFamilyProperties [queueFamilyUsedIndex].QueueFlags.HasFlag(QueueFlags.Graphics)) { break; } } var queueInfo = new DeviceQueueCreateInfo { QueuePriorities = new float [] { 1.0f }, QueueFamilyIndex = queueFamilyUsedIndex }; var deviceInfo = new DeviceCreateInfo { EnabledExtensionNames = new string [] { "VK_KHR_swapchain" }, QueueCreateInfos = new DeviceQueueCreateInfo [] { queueInfo } }; device = physicalDevice.CreateDevice(deviceInfo); queue = device.GetQueue(0, 0); surfaceCapabilities = physicalDevice.GetSurfaceCapabilitiesKHR(surface); var surfaceFormat = SelectFormat(physicalDevice, surface); swapchain = CreateSwapchain(surface, surfaceFormat); images = device.GetSwapchainImagesKHR(swapchain); renderPass = CreateRenderPass(surfaceFormat); framebuffers = CreateFramebuffers(images, surfaceFormat); var fenceInfo = new FenceCreateInfo(); fence = device.CreateFence(fenceInfo); var semaphoreInfo = new SemaphoreCreateInfo(); semaphore = device.CreateSemaphore(semaphoreInfo); initialized = true; }
SwapchainKhr CreateSwapchain(SurfaceKhr surface, SurfaceFormatKhr surfaceFormat) { var swapchainInfo = new SwapchainCreateInfoKhr { Surface = surface, MinImageCount = surfaceCapabilities.MinImageCount, ImageFormat = surfaceFormat.Format, ImageColorSpace = surfaceFormat.ColorSpace, ImageExtent = surfaceCapabilities.CurrentExtent, ImageUsage = ImageUsageFlags.ColorAttachment, PreTransform = SurfaceTransformFlagsKhr.Identity, ImageArrayLayers = 1, ImageSharingMode = SharingMode.Exclusive, QueueFamilyIndices = new uint [] { 0 }, PresentMode = PresentModeKhr.Fifo, CompositeAlpha = CompositeAlphaFlagsKhr.Inherit }; return(device.CreateSwapchainKHR(swapchainInfo)); }
public Window CreateWindow( Int2 windowSize, HostDeviceRequirements deviceRequirements, bool preferDiscreteDevice = true) { ThrowIfDisposed(); INativeWindow nativeWindow = nativeApp.CreateWindow( size: windowSize, minSize: (x: 150, y: 150), title: string.Empty); SurfaceKhr surface = CreateSurface(nativeWindow); HostDevice graphicsDevice = FindSuitableDevice( surface, deviceRequirements, preferDiscreteDevice); return(new Window( title: $"{appName} - {appVersion}", nativeWindow, surface, graphicsDevice, deviceRequirements, logger)); }
private static SwapchainKhr GetSwapchain(PhysicalDevice physicalDevice, SurfaceKhr surface, Device device, SurfaceCapabilitiesKhr surfaceInfo) { var format = physicalDevice.GetSurfaceFormatsKHR(surface).First(); return(device.CreateSwapchainKHR(new SwapchainCreateInfoKhr { Surface = surface, MinImageCount = 2, ImageFormat = format.Format, ImageColorSpace = format.ColorSpace, ImageExtent = surfaceInfo.CurrentExtent, ImageArrayLayers = 1, ImageUsage = ImageUsageFlags.ColorAttachment | ImageUsageFlags.Sampled, ImageSharingMode = SharingMode.Exclusive, PreTransform = surfaceInfo.CurrentTransform, CompositeAlpha = CompositeAlphaFlagsKhr.Opaque, PresentMode = PresentModeKhr.Fifo, Clipped = true })); }
internal void CreateWindowSurface(Window wnd) { //create window surface IntPtr surfaceHandle; Result result = (Result)Vulkan.CreateWindowSurface( mInstance.GetInstance().Handle, wnd, IntPtr.Zero, out surfaceHandle); if (result != Result.Success) { ErrorSpew("Window surface creation failed: " + result.ToString()); return; } AllocationCallbacks?superAnnoyingParameter = null; mSurface = new SurfaceKhr(mInstance.GetInstance(), ref superAnnoyingParameter, surfaceHandle.ToInt64()); }
public static SurfaceKhr CreateWin32SurfaceKHR(this Instance instance, Win32SurfaceCreateInfoKhr pCreateInfo, AllocationCallbacks pAllocator = null) { Result result; SurfaceKhr pSurface; unsafe { pSurface = new SurfaceKhr(); fixed(UInt64 *ptrpSurface = &pSurface.m) { result = Windows.Interop.NativeMethods.vkCreateWin32SurfaceKHR(instance.m, pCreateInfo != null ? pCreateInfo.m : (Windows.Interop.Win32SurfaceCreateInfoKhr *) default(IntPtr), pAllocator != null ? pAllocator.m : null, ptrpSurface); } if (result != Result.Success) { throw new ResultException(result); } return(pSurface); } }
public static bool TryCreateSwapChain(Instance instance, PhysicalDevice physicalDevice, Device device, SurfaceKhr surface, uint queue, ref System.Drawing.Size size, Format format, ColorSpaceKhr colorSpace, PresentModeKhr presentMode, ref SwapchainKhr swapchain) { SwapchainCreateInfoKhr swapChainCreateInfo = new SwapchainCreateInfoKhr { Surface = surface, MinImageCount = 2, ImageFormat = format, ImageColorSpace = colorSpace, ImageExtent = ToExtent2D(size), ImageArrayLayers = 1, ImageUsage = ImageUsageFlags.ColorAttachment, ImageSharingMode = SharingMode.Exclusive, QueueFamilyIndices = new uint[] { queue }, PreTransform = SurfaceTransformFlagsKhr.Inherit, CompositeAlpha = CompositeAlphaFlagsKhr.Opaque, // TODO : set this to Ingerit if it can be fixed in Check PresentMode = presentMode, Clipped = false, OldSwapchain = swapchain, }; if (!CheckSwapchainCreateInfo(physicalDevice, swapChainCreateInfo, true)) { return(false); } size.Width = (int)swapChainCreateInfo.ImageExtent.Width; size.Height = (int)swapChainCreateInfo.ImageExtent.Height; SwapchainKhr newSwapchain = device.CreateSwapchainKHR(swapChainCreateInfo); if (newSwapchain != null) { swapchain = newSwapchain; return(true); } return(false); }
internal PresentModeKhr GetPresentMode(SurfaceKhr surface) { PresentModeKhr[] modes = physicalDevice.GetSurfacePresentModesKhr(surface); //If mailbox is present then go for that, it is basically having 1 frame being displayed //and multiple frames in the background being rendered to, and also allows to redraw //those in the background, this allows for things like triple-buffering for (int i = 0; i < modes.Length; i++) { if (modes[i] == PresentModeKhr.Mailbox) { return(PresentModeKhr.Mailbox); } } //If mailbox is not supported then we go for Fifo //Fifo is basically uses 2 frame's, 1 thats being displayed right now and one that is //being rendered to. When rendering is done but the previous frame is not done being //displayed then the program has to wait. //According to spec this must be available on all platforms return(PresentModeKhr.Fifo); }
public static SurfaceKhr CreateIOSSurfaceMVK(this Instance instance, IOSSurfaceCreateInfoMvk pCreateInfo, AllocationCallbacks pAllocator = null) { Result result; SurfaceKhr pSurface; unsafe { pSurface = new SurfaceKhr(); fixed(UInt64 *ptrpSurface = &pSurface.M) { result = iOS.Interop.NativeMethods.vkCreateIOSSurfaceMVK(instance.M, pCreateInfo != null ? pCreateInfo.M : (iOS.Interop.IOSSurfaceCreateInfoMvk *) default(IntPtr), pAllocator != null ? pAllocator.M : null, ptrpSurface); } if (result != Result.Success) { throw new ResultException(result); } return(pSurface); } }
public static SurfaceKhr CreateXcbSurfaceKHR(this Instance instance, XcbSurfaceCreateInfoKhr pCreateInfo, AllocationCallbacks pAllocator = null) { Result result; SurfaceKhr pSurface; unsafe { pSurface = new SurfaceKhr(); fixed(UInt64 *ptrpSurface = &pSurface.M) { result = Linux.Interop.NativeMethods.vkCreateXcbSurfaceKHR(instance.M, &pCreateInfo, pAllocator != null ? pAllocator.M : null, ptrpSurface); } if (result != Result.Success) { throw new ResultException(result); } return(pSurface); } }
/// <summary> /// Query present rectangles for a surface on a physical device. /// <para> /// When using <see /// cref="DeviceGroupPresentModesKhx.DeviceGroupPresentModeLocalMultiDeviceKhx"/>, the /// application may need to know which regions of the surface are used when presenting /// locally on each physical device. /// </para> /// <para> /// Presentation of swapchain images to this surface need only have valid contents in the /// regions returned by this command. /// </para> /// </summary> /// <param name="physicalDevice">The physical device.</param> /// <param name="surface">The surface.</param> /// <returns>An array of <see cref="Rect2D"/> structures.</returns> /// <exception cref="VulkanException">Vulkan returns an error code.</exception> public static Rect2D[] GetPresentRectanglesKhx(this PhysicalDevice physicalDevice, SurfaceKhr surface) { int count; Result result = vkGetPhysicalDevicePresentRectanglesKHX(physicalDevice)(physicalDevice, surface, &count, null); VulkanException.ThrowForInvalidResult(result); var rectangles = new Rect2D[count]; fixed(Rect2D *rectanglesPtr = rectangles) { result = vkGetPhysicalDevicePresentRectanglesKHX(physicalDevice)(physicalDevice, surface, &count, rectanglesPtr); VulkanException.ThrowForInvalidResult(result); return(rectangles); } }