Vulkan Application Structure
Vulkan Application Structure
The source code and content is mostly based on Vulkan-Samples. The blog is merely for knowledge sharing what I learned from it.
Flow for an application
- Prepare
- Basic: could be pre-defined for most applications.
- Initialize the swapchain
- Create command pool
- Set up the swapchain
- Create command buffers
- Create synchronization primitives
- Setup depth stencil
- Setup render pass
- Create pipeline cache
- Setup frameBuffer
- Setup UI
- Case: defined by application scenario
- Load assets
- Initialize lights
- Prepare uniform buffers
- Setup descriptor set layout
- Prepare pipelines
- Setup descriptor pool
- Setup descriptor set
- Build command buffers
- Basic: could be pre-defined for most applications.
- Update:
- Render the scene
- update the parameter
Application
The base class Application
is like a empty class telling what virtual method should override when you derive it. It still includes some implementations, but mostly related to system level parameters, like time, window, input event. It hasn’t inludes any graphics API yet.
VulkanSample
The VulkanSample
class inheirt Application
class and further add more Vulkan details. Few virtual methods is mandatory to implement, which will be called in the further overridden method. Here is the lists of the method need to be override if inheirt VulkanSample
. For some forgot the inheritance rule in C++, here is the breif recap:
- public inheritance makes public members of the base class public in the derived class, and the protected members of the base class remain protected in the derived class.
- protected inheritance makes the public and protected members of the base class protected in the derived class.
- private inheritance makes the public and protected members of the base class private in the derived class.
Public:
virtual void create_device();
virtual void create_instance();
virtual ~VulkanSample();
Protected:
virtual void draw(CommandBuffer &command_buffer, RenderTarget &render_target);
virtual void draw_renderpass(CommandBuffer &command_buffer, RenderTarget &render_target);
virtual void render(CommandBuffer &command_buffer);
virtual const std::vector<const char *> get_validation_layers();
virtual void request_gpu_features(PhysicalDevice &gpu);
virtual void create_render_context();
virtual void prepare_render_context();
virtual void reset_statsvirtual void draw_gui();_view(){};
virtual void draw_gui();
virtual void update_debug_window();
RenderContext
RenderContext acts as a frame manager for the sample, with a lifetime that is the same as that of the Application itself. It acts as a container for RenderFrame objects, swapping between them (begin_frame, end_frame) and forwarding requests for Vulkan resources to the active frame.
RenderFrame
RenderFrame is a container for per-frame data, including BufferPool objects, synchronization primitives (semaphores, fences) and the swapchain RenderTarget. The RenderFrame is responsible for creating a RenderTarget using RenderTarget::CreateFunc. A RenderFrame cannot be destroyed individually since frames are managed by the RenderContext, the whole context must be destroyed. This is because each RenderFrame holds Vulkan objects such as the swapchain image.
RenderTarget
RenderTarget contains three vectors for: core::Image
, core::ImageView
and Attachment
. The first two are Vulkan images and corresponding image views respectively.
ApiVulkanSample
ApiVulkanSample
is still a virtual class, but contains more specific object creations to get rid of verbose graphic pipeline object creation and provide helper function to create resources. Thus, it provide useful template but sacrifice the flexibility, which may affect the performance