top of page
Search

DevLog 00 - Building The Base Renderer

  • Writer: Bobbie Kindt
    Bobbie Kindt
  • Aug 28
  • 2 min read

Updated: Sep 14

Introduction

When I started this project, my goal was to build a Vulkan-based renderer from scratch. To kick things off, I used the Vulkan Tutorial as a reference point. The tutorial proved to be a great starting place, but it keeps everything inside a single large VulkanProject class. Since I want my renderer to be modular and maintainable, I decided on to break things into smaller, dedicated pieces of code and refactor my code into clear classes after I completed the tutorial.


What I Did

After going through the tutorial, the first step was restructuring the tutorial code into a cleaner architecture. Instead of keeping everything in one massive file, I created separate classes to handle specific responsibilities. Here are a few examples:

  • CommandPool & CommandBuffer → Managing command recording and submission

  • Swapchain → Handling presentation and image buffers

  • GraphicsPipeline → Setting up shaders, pipeline state, and fixed-function stages

  • RenderPass & Framebuffers → Organizing how attachments are used in rendering


This approach makes the renderer easier to read, test, and expand later. Each class has a clear role, which fits with my goal of applying the Single-Responsibility Principle to the engine's design.


#pragma once

#define GLFW_INCLUDE_VULKAN
#include "GLFW/glfw3.h"

class VulkanDevice;

class VulkanCommandPool final
{
public:
	VulkanCommandPool(VulkanDevice* pDevice);
	~VulkanCommandPool();

	void Create();
	void Cleanup();

	VkCommandPool GetCommandPool() const;

private:
	VulkanDevice* m_pVulkanDevice;
	VkCommandPool m_CommandPool;

};

#pragma once
#include <vector>

#define GLFW_INCLUDE_VULKAN
#include "GLFW/glfw3.h"

#include "Window.h"
#include "VulkanDevice.h"

class VulkanSwapChain final
{
public:
	VulkanSwapChain(Window* pWindow, VulkanDevice* pDevice);
	~VulkanSwapChain();

	void Create();
	void Cleanup();

	void CreateImageViews();

	VkSwapchainKHR GetSwapChain() const;
	std::vector<VkImage> GetSwapChainImages() const;
	VkFormat GetSwapChainImageFormat() const;
	VkExtent2D GetSwapChainExtent() const;
	std::vector<VkImageView> GetSwapChainImageViews() const;

private:
	Window* m_pWindow;
	VulkanDevice* m_pVulkanDevice;

	VkSwapchainKHR m_SwapChain;
	std::vector<VkImage> m_SwapChainImages;
	VkFormat m_SwapChainImageFormat;
	VkExtent2D m_SwapChainExtent;
	std::vector<VkImageView> m_SwapChainImageViews;

	VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
	VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
	VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
	VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags);

};

Challenges & Fixes

Beyond learing the Vulkan API itself, one of the hardest part was figuring out how to structure my project. Vulkan already comes with a lot of boilerplate, and splitting it into multiple classes made me think hard about dependencies and ownership. Some of the questions I struggeled with were:

  • Should the swapchain create its own image views, or should that be handled by a separate helper?

  • How should command buffers be tied to the pipeline and render pass without creating circular dependencies?

  • How do I keep things flexible for later features without overengineering?


I went through several iterations where classes felt either too tightly coupled or too fragmented. After some trial and error, I landed on a structure that felt balanced and modular, but not overly complicated.


What's Next

With the base renderer in place, the next step is implementing a basic camera. This is first on my list so I can actually move around and explore the scene, instead of staring at a static mesh. Next step is the integration of an ImGui window for debugging and development tools purposes. These features will give me the tools I need to experiment more freely and will lay the foundation for advanced rendering techniques later on.


ree

 
 
 

Comments


bottom of page