public void Initialize(IVulkanAppHost host) { Host = host; #if DEBUG const bool debug = true; #else const bool debug = false; #endif _initializingPermanent = true; // Calling ToDispose here registers the resource to be automatically disposed on exit. Instance = ToDispose(CreateInstance(debug)); DebugReportCallback = ToDispose(CreateDebugReportCallback(debug)); Surface = ToDispose(CreateSurface()); Context = ToDispose(new VulkanContext(Instance, Surface, Host.Platform)); Content = ToDispose(new ContentManager(Host, Context, "Content")); ImageAvailableSemaphore = ToDispose(Context.Device.CreateSemaphore()); RenderingFinishedSemaphore = ToDispose(Context.Device.CreateSemaphore()); if (host.Platform == Platform.MacOS) { //Setup MoltenVK specific device configuration. MVKDeviceConfiguration deviceConfig = Context.Device.GetMVKDeviceConfiguration(); deviceConfig.DebugMode = debug; deviceConfig.PerformanceTracking = debug; deviceConfig.PerformanceLoggingFrameCount = debug ? 300 : 0; Context.Device.SetMVKDeviceConfiguration(deviceConfig); } _initializingPermanent = false; // Calling ToDispose here registers the resource to be automatically disposed on events // such as window resize. Swapchain = ToDispose(CreateSwapchain()); // Acquire underlying images of the freshly created swapchain. SwapchainImages = Swapchain.GetImages(); // Create a command buffer for each swapchain image. CommandBuffers = Context.GraphicsCommandPool.AllocateBuffers( new CommandBufferAllocateInfo(CommandBufferLevel.Primary, SwapchainImages.Length)); // Create a fence for each commandbuffer so that we can wait before using it again _initializingPermanent = true; //We need our fences to be there permanently SubmitFences = new Fence[SwapchainImages.Length]; for (int i = 0; i < SubmitFences.Length; i++) { ToDispose(SubmitFences[i] = Context.Device.CreateFence(new FenceCreateInfo(FenceCreateFlags.Signaled))); } // Allow concrete samples to initialize their resources. InitializePermanent(); _initializingPermanent = false; InitializeFrame(); // Record commands for execution by Vulkan. RecordCommandBuffers(); }
private void CreateSwapChain() { SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(physicalDevice); uint imageCount = swapChainSupport.Capabilities.MinImageCount + 1; if (swapChainSupport.Capabilities.MaxImageCount > 0 && imageCount > swapChainSupport.Capabilities.MaxImageCount) { imageCount = swapChainSupport.Capabilities.MaxImageCount; } SurfaceFormat surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.Formats); QueueFamilyIndices queueFamilies = FindQueueFamilies(physicalDevice); var indices = queueFamilies.Indices.ToArray(); Extent2D extent = ChooseSwapExtent(swapChainSupport.Capabilities); swapChain = device.CreateSwapchain( surface, imageCount, surfaceFormat.Format, surfaceFormat.ColorSpace, extent, 1, ImageUsageFlags.ColorAttachment | ImageUsageFlags.TransferSource, indices.Length == 1 ? SharingMode.Exclusive : SharingMode.Concurrent, indices, swapChainSupport.Capabilities.CurrentTransform, CompositeAlphaFlags.Opaque, ChooseSwapPresentMode(swapChainSupport.PresentModes), true, swapChain ); swapChainImages = swapChain.GetImages(); swapChainFormat = surfaceFormat.Format; swapChainExtent = extent; }
public void Resize() { Context.Device.WaitIdle(); // Dispose all frame dependent resources. while (_toDisposeFrame.Count > 0) { _toDisposeFrame.Pop().Dispose(); } // Reset all the command buffers allocated from the pools. Context.GraphicsCommandPool.Reset(); Context.ComputeCommandPool.Reset(); // Reinitialize frame dependent resources. Swapchain = ToDispose(CreateSwapchain()); SwapchainImages = Swapchain.GetImages(); InitializeFrame(); // Re-record command buffers. RecordCommandBuffers(); }
public void Initialize(IVulkanAppHost host) { Host = host; #if DEBUG const bool debug = true; #else const bool debug = false; #endif _initializingPermanent = true; // Calling ToDispose here registers the resource to be automatically disposed on exit. Instance = ToDispose(CreateInstance(debug)); DebugReportCallback = ToDispose(CreateDebugReportCallback(debug)); Surface = ToDispose(CreateSurface()); Context = ToDispose(new VulkanContext(Instance, Surface, Host.Platform)); Content = ToDispose(new ContentManager(Host, Context, "Content")); ImageAvailableSemaphore = ToDispose(Context.Device.CreateSemaphore()); RenderingFinishedSemaphore = ToDispose(Context.Device.CreateSemaphore()); _initializingPermanent = false; // Calling ToDispose here registers the resource to be automatically disposed on events // such as window resize. Swapchain = ToDispose(CreateSwapchain()); // Acquire underlying images of the freshly created swapchain. SwapchainImages = Swapchain.GetImages(); // Create a command buffer for each swapchain image. CommandBuffers = Context.GraphicsCommandPool.AllocateBuffers( new CommandBufferAllocateInfo(CommandBufferLevel.Primary, SwapchainImages.Length)); // Allow concrete samples to initialize their resources. _initializingPermanent = true; InitializePermanent(); _initializingPermanent = false; InitializeFrame(); // Record commands for execution by Vulkan. RecordCommandBuffers(); }
/// <summary> /// Construct a Graphics object belonging to a window /// </summary> /// <param name="window"></param> public Graphics(WyvernWindow window) { // Argument checks if (window is null) { throw new ArgumentNullException(nameof(window)); } // Initialize the static part of Graphics if necessary InitializeStatic(); // Store window Window = window; // Create window surface { AllocationCallbacks?allocationCallbacks = null; Surface = new SurfaceKhr( Instance, ref allocationCallbacks, VkGLFW3.VkGlfw.CreateWindowSurface(Instance.Handle, Window, IntPtr.Zero) ); Surface.PrintDebug(); } // Choose a physical device { PhysicalDevice = Instance.EnumeratePhysicalDevices() .Where(e => GetDeviceMeetsRequirements(e, Surface)) .OrderByDescending(GetDeviceScore) .FirstOrDefault(); if (PhysicalDevice is null) { throw new InvalidOperationException("No physical device found that meets the requirements for the application"); } MemoryProperties = PhysicalDevice.GetMemoryProperties(); } // Create default queue families { ComputeQueueFamily = new QueueFamily( $"{Name}'s {nameof(ComputeQueueFamily)}", this, QueueFamily.QueueType.Compute, 2, true, ComputeCommandPoolFlags ); GraphicsQueueFamily = new QueueFamily( $"{Name}'s {nameof(GraphicsQueueFamily)}", this, QueueFamily.QueueType.Graphics, 2, true, GraphicsCommandPoolFlags ); TransferQueueFamily = new QueueFamily( $"{Name}'s {nameof(TransferQueueFamily)}", this, QueueFamily.QueueType.Transfer, 2, true, TransferCommandPoolFlags ); PresentQueueFamily = new QueueFamily( $"{Name}'s {nameof(PresentQueueFamily)}", this, QueueFamily.QueueType.Present, 1, false ); } // Create a logical device { // Generate queue create info structs var queueCreateInfos = QueueFamilies.Select(queueFamily => { // Generate queue priorities var priorities = new float[queueFamily.Count]; for (var i = 0; i < priorities.Length; i++) { priorities[i] = 1f - (i / (float)(priorities.Length - 1)); } // Create create info var createInfo = new DeviceQueueCreateInfo() { QueueFamilyIndex = queueFamily.Index, QueueCount = queueFamily.Count, QueuePriorities = priorities }; return(createInfo); }); // Merge multiple queue families' queue create infos { var alreadyHave = new List <int>(); var uniqueCreateInfos = new List <DeviceQueueCreateInfo>(); foreach (var createInfo in queueCreateInfos.OrderByDescending(e => e.QueueCount)) { if (!alreadyHave.Contains(createInfo.QueueFamilyIndex)) { alreadyHave.Add(createInfo.QueueFamilyIndex); uniqueCreateInfos.Add(createInfo); } } queueCreateInfos = uniqueCreateInfos; foreach (var createInfo in queueCreateInfos) { createInfo.PrintDebug(); } } // Create device Device = PhysicalDevice.CreateDevice(new DeviceCreateInfo() { EnabledExtensionNames = EnabledDeviceExtensions.ToArray(), QueueCreateInfos = queueCreateInfos.ToArray(), EnabledFeatures = EnabledPhysicalDeviceFeatures }); // Set the queues in the queue families, using those created with the device foreach (var family in QueueFamilies) { var queues = new Queue[family.Count]; for (var i = 0; i < queues.Length; i++) { queues[i] = Device.GetQueue(family.Index, i); } family.SetQueues(queues); } // Create and set the command pools in the queue families foreach (var family in QueueFamilies) { // Skip family that shouldn't have a command pool if (!family.HasCommandPool) { continue; } // Create command pool var commandPool = Device.CreateCommandPool(new CommandPoolCreateInfo() { QueueFamilyIndex = family.Index, Flags = family.CommandPoolFlags }); family.SetCommandPool(commandPool); } } // Create swapchain { // Query supported capabilities and formats var surfaceCapabilities = SurfaceCapabilities; var surfaceFormats = SurfaceFormats; var surfacePresentModes = SurfacePresentModes; surfaceCapabilities.PrintDebug(); // Choose the best image format and color space { var imageFormat = Array.Find( PreferredSwapchainFormats, preferred => surfaceFormats.Any(available => available.Format == preferred) ); if (imageFormat == Format.Undefined) { imageFormat = surfaceFormats.FirstOrDefault().Format; } if (imageFormat == Format.Undefined) { throw new InvalidOperationException("Surface somehow does not support any known image formats"); } SwapchainImageFormat = imageFormat; SwapchainColorSpace = surfaceFormats.First(e => e.Format == SwapchainImageFormat).ColorSpace; } // Choose the best present mode { var presentMode = Array.Find( PreferredPresentModes, preferred => surfacePresentModes.Any(available => available == preferred) ); SwapchainPresentMode = presentMode; } // Create the swapchain SwapchainExtent = surfaceCapabilities.CurrentExtent; Swapchain = Device.CreateSwapchainKhr(new SwapchainCreateInfoKhr( surface: Surface, imageFormat: SwapchainImageFormat, imageExtent: SwapchainExtent, preTransform: surfaceCapabilities.CurrentTransform, presentMode: SwapchainPresentMode, minImageCount: SurfaceCapabilities.MinImageCount, imageArrayLayers: SurfaceCapabilities.MaxImageArrayLayers, imageSharingMode: SharingMode.Exclusive, imageColorSpace: SwapchainColorSpace )); SwapchainAttachmentImages = Swapchain.GetImages().Select( e => new VKImage( e, SwapchainImageFormat, SwapchainExtent, new ImageSubresourceRange(ImageAspects.Color, 0, 1, 0, 1) ) ).ToArray(); Swapchain.PrintDebug(); } // Create semaphores & fences { // Image available semaphore ImageAvailableSemaphore = Device.CreateSemaphore(); ReadyToPresentSemaphore = Device.CreateSemaphore(); // Swapchain image rendering fences RenderToImageFences = new Fence[SwapchainAttachmentImages.Length]; for (var i = 0; i < RenderToImageFences.Length; i++) { RenderToImageFences[i] = Device.CreateFence(new FenceCreateInfo(flags: FenceCreateFlags.Signaled)); } } // Create content collection { Content = new ContentCollection(this); } // Misc Stopwatch = Stopwatch.StartNew(); CurrentTime = 0.0; }
/// <summary> /// Initialize this swap chain on a specified surface. /// </summary> /// <param name="surface">Target video surface.</param> /// <param name="surfaceSize">Swap queue target size.</param> public void Initialize(Surface surface, Vector2i surfaceSize) { base.Initialize(surface, surfaceSize); VKSurface vkSurface = surface as VKSurface; // - Get capabilites and hardware information SurfaceCapabilities Capabilities = GraphicsCard.Handle.GetSurfaceCapabilities(vkSurface.Handle); formats = GraphicsCard.Handle.GetSurfaceFormats(vkSurface.Handle); presentModes = GraphicsCard.Handle.GetSurfacePresentModes(vkSurface.Handle); uint imageCount = Capabilities.MinImageCount + 1; if (Capabilities.MaxImageCount > 0 && imageCount > Capabilities.MaxImageCount) { imageCount = Capabilities.MaxImageCount; } // - Default video format -> the first one surfaceFormat = formats[0]; // - Checks for a BGRA32 video format foreach (var format in formats) { if (format.Format == Format.B8G8R8A8UNorm && format.ColorSpace == ColorSpace.SrgbNonlinear) { surfaceFormat = format; break; } } // - Checks if ther're no avaiable formats and we create a new one if (formats.Length == 1 && formats[0].Format == Format.Undefined) { surfaceFormat = new SharpVk.Khronos.SurfaceFormat { Format = Format.B8G8R8A8UNorm, ColorSpace = ColorSpace.SrgbNonlinear }; } // - Computes the swap chain drawing surface size Extent2D extent = Capabilities.CurrentExtent; if (extent.Width != uint.MaxValue) { long Width = Math.Max(Capabilities.MinImageExtent.Width, Math.Min(Capabilities.MaxImageExtent.Width, surfaceSize.Width)); long Height = Math.Max(Capabilities.MinImageExtent.Height, Math.Min(Capabilities.MaxImageExtent.Height, surfaceSize.Height)); extent = new Extent2D((uint)Width, (uint)Height); } // - Shortcut (to avoid long parameters on the next call) var queues = new[] { RenderDevice.PresentQueueIndex, RenderDevice.GraphicQueueIndex }; bool exclusive = RenderDevice.GraphicQueueIndex == RenderDevice.PresentQueueIndex; Handle = RenderDevice.Handle.CreateSwapchain ( vkSurface.Handle, imageCount, surfaceFormat.Format, surfaceFormat.ColorSpace, extent, 1, ImageUsageFlags.ColorAttachment, exclusive ? SharingMode.Exclusive : SharingMode.Concurrent, exclusive ? null : queues, Capabilities.CurrentTransform, CompositeAlphaFlags.Opaque, PresentModes.Contains(PresentMode.Mailbox) ? PresentMode.Mailbox : PresentMode.Fifo, true, Handle ); images = Handle.GetImages(); this.extent = extent; }