@startuml title Main Execution caption //**Main execution from the run function in the entrypoint**// //**This dictates basic flow of the vulkan boilerplate system. **// endcaption :main; ://**run()**//; <> split ://**initWindow()**//; <> :glfwInit(); :window = glfwCreateWindow(...); note left //Create window and initialize default settings// endnote :glfwSetWindowUserPointer(...); note left //Set the user-defined pointer of the window// endnote :glfwSetFramebufferSizeCallback(...); note left //This is a callback to resizing of the window// //we call and set a bool to true, which we get// //and rebuild the swap chain when true.// endnote stop split again ://**initVulkan()**//; <> split ://**createInstance()**//; <> split :Debug::checkUnavailableValidationLayers(); :**VkApplicationInfo** appInfo{}; ://set appInfo data, Vulkan version,// //Engine version and name, and title//; :**VkApplicationCreateInfo** createInfo{}; :createInfo.pApplicationInfo = &appInfo; :Debug::vulkanDebugSetup(createInfo, vulkaninstance); end split split again :Debug::setupDebugMessenger(VkInstance&); note right: Setup debug messenger, print data to console :glfwCreateWindowSurface(...); note right This function handles Window System Integration automatically across platforms based on build environment. ==== //Basically, this is an abstraction of the Window across platforms// end note partition "**DeviceControl**" { :pickPhysicalDevice(...); note right Enumerate through GPU's in the system and choose a compatible one. ==== //in the future, this should choose the BEST// //GPU, not just the first one that is compatible..// end note :createLogicalDevice(...); note right Logical devices interface with the physical device and defines queues end note :createSwapChain(...); note right Swap Chains are used to handle buffer ownership infrastructure. Being platform agnostic has its complications, this is a perfect example. This process is HEAVILY documented. end note :createImageViews(...); note right This is a cool function, quite a simple description of images that will be shown on the screen! It also determines //how// to access the image end note } :**Graphics**::createRenderPass(...); note right This is pretty simple, it sets up the image bit depth and the color bit depth! Basically, the format of the displayed images, simple, but important! end note :**Buffers**::createDescriptorSetLayout(); note right This function creates a table of pointers to the stored data that we want, in this case it would be pointing to pre-programmed model view and projection values, and a time variable. end note partition "**Graphics**" { :createGraphicsPipeline(...); note right This is a complex function that goes through every step of the render pipeline and sets the settings we desire for each step! **HEAVILY** documented. end note :createFramebuffers(...); note right This function creates framebuffers for all the images that are queued to be displayed, very important! end note :createCommandPool(...); note right Commands in Vulkan are not executed using function calls You have to record the ops you want to perform to command buffer objects, pools manage the memory used for buffers. end note } partition "**Buffers**" { :createVertexBuffer(); note right Vertex buffers are incredibly useful, in essence, you can read data from memory as vertex input to the vertex shader rather than hardcoded data! end note :createIndexBuffer(); note right Index buffers are cool, basically, you can store some vertices that would normally be duplicated at corners to triangulate. this saves cycles at scale, complex objects rejoice! end note :createUniformBuffer(); note right Map the buffer data to memory (The struct) as a pointer we can use this as a reference of where to write data to when the fence lets us write data. (see **recordCommandBuffer()**). end note :createDescriptorPool(); note right Here we create a pool to manage the memory and allocate space for the descriptor sets! Very useful and the same structure as command buffers & pools. end note :createDescriptorSetLayout(); note right //Descriptor set **layouts** specify the types of resources accessible// //by the graphical pipeline. A descriptor set is the actual buffer// //or resource that gets bound to descriptors and passed in.// These differ from Vertex & Index buffers, as they are not unique to the graphics pipeline. Specification of compute vs. graphics is therefore necessary. (see **createDescriptorSets()**) end note } :Graphics::createCommandBuffer(); note right This is the partner to the commandPool creator, storing the commands we wish to perform whilst waiting in a queue. These are very efficient. end note :RenderPresent::createSyncObject(); note right This is **HEAVILY** documented, create Semaphores and Fences, for halting and starting execution, basically a traffic controller for the GPU. end note end split stop split again repeat ://**mainLoop()**//; <> :glfwPollEvents(); :RenderPresent::drawFrame(); repeat while (!glfwWindowShouldClose(...)) :vkDeviceWaitIdle(...); stop split again ://**cleanup()**//; <> note right //This function initiates a series of shutdown// //destroy functions, safely stopping execution//; endnote :return EXIT_SUCCESS; stop end split @enduml