/// <summary> /// Create the minimum vulkan objects to quickly start a new application. The folowing objects are created: /// - Vulkan Instance with extensions present in the `EnabledInstanceExtensions` property. /// - Vulkan Surface for the GLFW native window. /// - Vulkan device for the selected physical one with configured enabledFeatures and extensions present in `EnabledDeviceExtensions` list. Selection of the default physical device /// may be replaced by the `selectPhysicalDevice` method override. /// - Create a default Graphic Queue with presentable support. The default queue creation may be customized by overriding the `createQueues` method. /// - Default vulkan Swapchain creation. Some swapchain's parameters are controled through static fields of the `SwapChain` class (ex: `SwapChain.PREFERED_FORMAT`). /// - Create a default command pool for the `presentQueue` family index. /// - Create an empty command buffer collection (`cmds`). /// - Create one unsignaled vulkan semaphore (named `drawComplete` per swapchain image used to control presentation submission to the graphic queue. /// - Create a signaled vulkan fence (`drawFence`). (TODO: improve this. /// With all these objects, vulkan application programming startup is reduced to the minimal. /// </summary> protected virtual void initVulkan() { List <string> instExts = new List <string> (Glfw3.GetRequiredInstanceExtensions()); if (EnabledInstanceExtensions != null) { instExts.AddRange(EnabledInstanceExtensions); } instance = new Instance(instExts.ToArray()); hSurf = instance.CreateSurface(hWin); selectPhysicalDevice(); VkPhysicalDeviceFeatures enabledFeatures = default; configureEnabledFeatures(phy.Features, ref enabledFeatures); //First create the c# device class dev = new Device(phy); dev.debugUtilsEnabled = instance.debugUtilsEnabled; //store a boolean to prevent testing against the extension string presence. //create queue class createQueues(); //activate the device to have effective queues created accordingly to what's available dev.Activate(enabledFeatures, EnabledDeviceExtensions); swapChain = new SwapChain(presentQueue as PresentQueue, Width, Height, SwapChain.PREFERED_FORMAT, VSync ? VkPresentModeKHR.FifoKHR : VkPresentModeKHR.ImmediateKHR); swapChain.Activate(); Width = swapChain.Width; Height = swapChain.Height; cmdPool = new CommandPool(dev, presentQueue.qFamIndex, VkCommandPoolCreateFlags.ResetCommandBuffer); cmds = new PrimaryCommandBuffer[swapChain.ImageCount]; drawComplete = new VkSemaphore[swapChain.ImageCount]; drawFence = new Fence(dev, true, "draw fence"); for (int i = 0; i < swapChain.ImageCount; i++) { drawComplete[i] = dev.CreateSemaphore(); drawComplete[i].SetDebugMarkerName(dev, "Semaphore DrawComplete" + i); } cmdPool.SetName("main CmdPool"); }