Prechádzať zdrojové kódy

Reworked swapchain class

Reworked the swapchain class to not use VkBootstrap for swapchain creation and instead use our own creation.

Added support for resizable framebuffers (read: resizable windows)
Jef Belmans 2 rokov pred
rodič
commit
30abc11364

+ 3 - 3
coral_renderer/coral_device.cpp

@@ -182,7 +182,7 @@ void coral_device::create_instance()
     std::cout << "Creating instance...\n";
 
     vkb::InstanceBuilder builder;
-    auto instance_desc = builder.set_app_name("Coral3D")
+    auto instance_desc = builder.set_app_name("coral_renderer")
         .request_validation_layers(c_enable_validation_layers_)
         .require_api_version(1, 1, 0)
         .use_default_debug_messenger()
@@ -218,7 +218,7 @@ void coral_device::create_instance()
     
     shader_draw_params.shaderDrawParameters = VK_TRUE;
 
-    vkb::Device vkb_device{device_builder.add_pNext(&shader_draw_params).build().value()};
+    auto vkb_device = device_builder.add_pNext(&shader_draw_params).build().value();
 
     graphics_queue_ = vkb_device.get_queue(vkb::QueueType::graphics).value();
     present_queue_ = vkb_device.get_queue(vkb::QueueType::present).value();
@@ -250,7 +250,7 @@ void coral_device::create_command_pool()
     auto indices { find_physical_queue_families() };
 
     VkCommandPoolCreateInfo graphics_pool_info{
-        vkinit::command_pool_ci(indices.graphics_family) };
+        vkinit::command_pool_ci(indices.graphics_family, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT) };
 
     // Create general pool
     if (vkCreateCommandPool(device_, &graphics_pool_info, nullptr, &command_pool_) != VK_SUCCESS)

+ 1 - 3
coral_renderer/coral_device.h

@@ -11,8 +11,6 @@
 
 namespace coral_3d
 {
-	
-
 	struct UploadContext
 	{
 		VkFence upload_fence;
@@ -63,7 +61,7 @@ namespace coral_3d
 		VkQueue graphics_queue() { return graphics_queue_; }
 		VkQueue present_queue() { return present_queue_; }
 
-		SwapchainSupportDetails get_swapchain_support() {};
+		SwapchainSupportDetails get_swapchain_support() { return query_swapchain_support(physical_device_); }
 		uint32_t find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties);
 		QueueFamilyIndices find_physical_queue_families() { return find_queue_families(physical_device_); }
 		VkFormat find_supported_format(

+ 9 - 9
coral_renderer/coral_mesh.cpp

@@ -35,12 +35,12 @@ VertexInputDescription Vertex::get_vert_desc()
     //normal_attrib.format = VK_FORMAT_R32G32B32_SFLOAT;
     //normal_attrib.offset = offsetof(Vertex, normal);
 
-    //// Color will be stored at Location 2
-    //VkVertexInputAttributeDescription color_attrib{};
-    //color_attrib.binding = 0;
-    //color_attrib.location = 2;
-    //color_attrib.format = VK_FORMAT_R32G32B32_SFLOAT;
-    //color_attrib.offset = offsetof(Vertex, color);
+    // Color will be stored at Location 1
+    VkVertexInputAttributeDescription color_attrib{};
+    color_attrib.binding = 0;
+    color_attrib.location = 1;
+    color_attrib.format = VK_FORMAT_R32G32B32_SFLOAT;
+    color_attrib.offset = offsetof(Vertex, color);
 
     //// UV will be stored at Location 3
     //VkVertexInputAttributeDescription texcoord_attrib{};
@@ -50,9 +50,9 @@ VertexInputDescription Vertex::get_vert_desc()
     //texcoord_attrib.offset = offsetof(Vertex, uv);
 
     desc.attributes.emplace_back(position_attrib);
-    //desc.attributes.emplace_back(normal_attrib);
-    //desc.attributes.emplace_back(color_attrib);
-    //desc.attributes.emplace_back(texcoord_attrib);
+    // desc.attributes.emplace_back(normal_attrib);
+    desc.attributes.emplace_back(color_attrib);
+    // desc.attributes.emplace_back(texcoord_attrib);
 
     return desc;
 }

+ 2 - 2
coral_renderer/coral_mesh.h

@@ -21,10 +21,10 @@ namespace coral_3d
 		VkPipelineVertexInputStateCreateFlags flags = 0;
 	};
 
-
 	struct Vertex
 	{
-		glm::vec2 position;
+		glm::vec3 position;
+		glm::vec3 color;
 
 		static VertexInputDescription get_vert_desc();
 	};

+ 158 - 24
coral_renderer/coral_swapchain.cpp

@@ -10,23 +10,35 @@
 #include <stdexcept>
 
 // VULKAN
-#include <VkBootstrap.h>
 #include "vk_initializers.h"
 
 using namespace coral_3d;
 
+coral_swapchain::coral_swapchain(coral_device& device, VkExtent2D extent, std::shared_ptr<coral_swapchain> old_swapchain)
+    : device_{ device }, window_extent_{ extent }, old_swapchain_{old_swapchain}
+{
+	init();
+
+	old_swapchain_ = nullptr;
+}
+
 coral_swapchain::coral_swapchain(coral_device& device, VkExtent2D extent)
-    :device_{ device }, window_extent_{ extent }
+	: device_{ device }, window_extent_{ extent }
 {
-    create_swapchain();
-    create_render_pass();
-    create_depth_resources();
-    create_frame_buffers();
-    create_sync_structures();
+	init();
 }
 
 coral_swapchain::~coral_swapchain()
 {
+	for (auto image_view : swapchain_image_views_)
+	{
+		vkDestroyImageView(device_.device(), image_view, nullptr);
+	}
+	swapchain_image_views_.clear();
+
+	vkDestroySwapchainKHR(device_.device(), swapchain_, nullptr);
+	swapchain_ = nullptr;
+
 	deletion_queue_.flush();
 }
 
@@ -38,7 +50,7 @@ VkFormat coral_swapchain::find_depth_format()
 		VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
 }
 
-VkResult coral_3d::coral_swapchain::aqcuire_next_image(uint32_t* image_index)
+VkResult coral_swapchain::aqcuire_next_image(uint32_t* image_index)
 {
 	// NOTE: as of 04/07, vkDeviceWaitIdle is about 3% faster when rendering a single triangle.
 	vkDeviceWaitIdle(device_.device());
@@ -102,28 +114,103 @@ VkResult coral_swapchain::submit_command_buffer(const VkCommandBuffer* buffers,
 	return result;
 }
 
+void coral_swapchain::init()
+{
+	create_swapchain();
+	create_image_views();
+	create_render_pass();
+	create_depth_resources();
+	create_frame_buffers();
+	create_sync_structures();
+}
+
 void coral_swapchain::create_swapchain()
 {
-	vkb::SwapchainBuilder swapchain_builder{ device_.physical_device(), device_.device(), device_.surface() };
+	SwapchainSupportDetails swap_chain_support = device_.get_swapchain_support();
+
+	VkSurfaceFormatKHR surface_format = choose_swapchain_format(swap_chain_support.formats);
+	VkPresentModeKHR present_mode = choose_present_mode(swap_chain_support.present_modes);
+	VkExtent2D extent = choose_swap_extent(swap_chain_support.capabilities);
+
+	uint32_t image_count = swap_chain_support.capabilities.minImageCount + 1;
+	if (swap_chain_support.capabilities.maxImageCount > 0 &&
+		image_count > swap_chain_support.capabilities.maxImageCount)
+	{
+		image_count = swap_chain_support.capabilities.maxImageCount;
+	}
+
+	VkSwapchainCreateInfoKHR create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+	create_info.surface = device_.surface();
+
+	create_info.minImageCount = image_count;
+	create_info.imageFormat = surface_format.format;
+	create_info.imageColorSpace = surface_format.colorSpace;
+	create_info.imageExtent = extent;
+	create_info.imageArrayLayers = 1;
+	create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+	QueueFamilyIndices indices = device_.find_physical_queue_families();
+	uint32_t queueFamilyIndices[] = { indices.graphics_family, indices.present_family };
+
+	if (indices.graphics_family != indices.present_family) {
+		create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+		create_info.queueFamilyIndexCount = 2;
+		create_info.pQueueFamilyIndices = queueFamilyIndices;
+	}
+	else
+	{
+		create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+		create_info.queueFamilyIndexCount = 0;      // Optional
+		create_info.pQueueFamilyIndices = nullptr;  // Optional
+	}
+
+	create_info.preTransform = swap_chain_support.capabilities.currentTransform;
+	create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+
+	create_info.presentMode = present_mode;
+	create_info.clipped = VK_TRUE;
+
+	create_info.oldSwapchain = old_swapchain_ == nullptr ? VK_NULL_HANDLE : old_swapchain_->swapchain_;
 
-	vkb::Swapchain vkb_swapchain = swapchain_builder
-		.use_default_format_selection()
-		// use VSync present mode
-		.set_desired_present_mode(VK_PRESENT_MODE_MAILBOX_KHR)
-		.set_desired_extent(window_extent_.width, window_extent_.height)
-		.build()
-		.value();
+	if (vkCreateSwapchainKHR(device_.device(), &create_info, nullptr, &swapchain_) != VK_SUCCESS)
+		throw std::runtime_error("ERROR! coral_swapchain::create_swapchain() >> Failed to create swapchain!");
 
-	// store swap chain and its related data
-	swapchain_ = vkb_swapchain.swapchain;
-	swapchain_images_ = vkb_swapchain.get_images().value();
-	swapchain_image_views_ = vkb_swapchain.get_image_views().value();
-	swapchain_image_format_ = vkb_swapchain.image_format;
+	// we only specified a minimum number of images in the swap chain, so the implementation is
+	// allowed to create a swap chain with more. That's why we'll first query the final number of
+	// images with vkGetSwapchainImagesKHR, then resize the container and finally call it again to
+	// retrieve the handles.
+	vkGetSwapchainImagesKHR(device_.device(), swapchain_, &image_count, nullptr);
+	swapchain_images_.resize(image_count);
+	vkGetSwapchainImagesKHR(device_.device(), swapchain_, &image_count, swapchain_images_.data());
 
-	swapchain_extent_ = vkb_swapchain.extent;
+	swapchain_image_format_ = surface_format.format;
+	swapchain_extent_ = extent;
+}
+
+void coral_swapchain::create_image_views()
+{
+	swapchain_image_views_.resize(swapchain_images_.size());
+
+	for (size_t i = 0; i < swapchain_images_.size(); i++)
+	{
+		VkImageViewCreateInfo viewInfo{};
+		viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+		viewInfo.image = swapchain_images_[i];
+		viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+		viewInfo.format = swapchain_image_format_;
+		viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+		viewInfo.subresourceRange.baseMipLevel = 0;
+		viewInfo.subresourceRange.levelCount = 1;
+		viewInfo.subresourceRange.baseArrayLayer = 0;
+		viewInfo.subresourceRange.layerCount = 1;
+
+		if (vkCreateImageView(device_.device(), &viewInfo, nullptr, &swapchain_image_views_[i]) != VK_SUCCESS)
+			throw std::runtime_error("ERROR! coral_swapchain::create_image_views() >> Failed to create image view!");
+	}
 
 	deletion_queue_.deletors.emplace_back([=]() {
-		vkDestroySwapchainKHR(device_.device(), swapchain_, nullptr);
+		// swapchain_image_views_.clear();
 		});
 }
 
@@ -266,7 +353,7 @@ void coral_swapchain::create_frame_buffers()
 
 		deletion_queue_.deletors.emplace_back([=]() {
 			vkDestroyFramebuffer(device_.device(), swapchain_frame_buffers_[i], nullptr);
-			vkDestroyImageView(device_.device(), swapchain_image_views_[i], nullptr);
+			// vkDestroyImageView(device_.device(), swapchain_image_views_[i], nullptr);
 			});
 	}
 }
@@ -298,4 +385,51 @@ void coral_swapchain::create_sync_structures()
 				vkDestroySemaphore(device_.device(), frames_[i].render_semaphore, nullptr);
 			});
 	}
+}
+
+VkSurfaceFormatKHR coral_swapchain::choose_swapchain_format(const std::vector<VkSurfaceFormatKHR>& available_formats)
+{
+	for (const auto& available_format : available_formats)
+	{
+		if (available_format.format == VK_FORMAT_B8G8R8A8_SRGB &&
+			available_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
+		{
+			return available_format;
+		}
+	}
+
+	return available_formats[0];
+}
+
+VkPresentModeKHR coral_swapchain::choose_present_mode(const std::vector<VkPresentModeKHR>& available_present_modes)
+{
+	for (const auto& available_present_mode : available_present_modes)
+	{
+		if (available_present_mode == VK_PRESENT_MODE_MAILBOX_KHR)
+		{
+			std::cout << "Present mode: Mailbox" << std::endl;
+			return available_present_mode;
+		}
+	}
+}
+
+VkExtent2D coral_swapchain::choose_swap_extent(const VkSurfaceCapabilitiesKHR& capabilities)
+{
+	if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
+	{
+		return capabilities.currentExtent;
+	}
+
+	else
+	{
+		VkExtent2D actualExtent = window_extent_;
+		actualExtent.width = std::max(
+			capabilities.minImageExtent.width,
+			std::min(capabilities.maxImageExtent.width, actualExtent.width));
+		actualExtent.height = std::max(
+			capabilities.minImageExtent.height,
+			std::min(capabilities.maxImageExtent.height, actualExtent.height));
+
+		return actualExtent;
+	}
 }

+ 5 - 0
coral_renderer/coral_swapchain.h

@@ -8,6 +8,7 @@
 // std lib headers
 #include <string>
 #include <vector>
+#include <memory>
 
 #include "vk_types.h"
 
@@ -39,6 +40,7 @@ namespace coral_3d
     public:
         static constexpr int MAX_FRAMES_IN_FLIGHT = 2;
 
+        coral_swapchain(coral_device& device, VkExtent2D extent, std::shared_ptr<coral_swapchain> old_swapchain);
         coral_swapchain(coral_device& device, VkExtent2D extent);
         ~coral_swapchain();
 
@@ -63,7 +65,9 @@ namespace coral_3d
         VkResult submit_command_buffer(const VkCommandBuffer* buffers, uint32_t* image_index);
 
     private:
+        void init();
         void create_swapchain();
+        void create_image_views();
         void create_render_pass();
         void create_depth_resources();
         void create_frame_buffers();
@@ -92,6 +96,7 @@ namespace coral_3d
         coral_device& device_;
         VkExtent2D window_extent_;
         VkSwapchainKHR swapchain_;
+        std::shared_ptr<coral_swapchain> old_swapchain_;
 
         FrameData frames_[MAX_FRAMES_IN_FLIGHT];
         size_t current_frame_ = 0;

+ 16 - 5
coral_renderer/coral_window.cpp

@@ -5,8 +5,8 @@
 using namespace coral_3d;
 
 coral_window::coral_window(int width, int height, const std::string& name)
-	: c_width(width)
-	, c_height(height)
+	: width_(width)
+	, height_(height)
 	, window_name_(name)
 {
 	init_window();
@@ -18,15 +18,26 @@ coral_window::~coral_window()
 	glfwTerminate();
 }
 
+void coral_window::framebuffer_resize_callback(GLFWwindow* pWindow, int width, int height)
+{
+	auto window = reinterpret_cast<coral_window*>(glfwGetWindowUserPointer(pWindow));
+
+	window->is_framebuffer_resized_ = true;
+	window->width_ = width;
+	window->height_ = height;
+}
+
 void coral_window::init_window()
 {
 	glfwInit();
 
 	// Tell GLFW to not use OpenGL
 	glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
-	glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
+	glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
 
-	pWindow_ = glfwCreateWindow(c_width, c_height, window_name_.c_str(), nullptr, nullptr);
+	pWindow_ = glfwCreateWindow(width_, height_, window_name_.c_str(), nullptr, nullptr);
+	glfwSetWindowUserPointer(pWindow_, this);
+	glfwSetFramebufferSizeCallback(pWindow_, framebuffer_resize_callback);
 }
 
 void coral_window::create_window_surface(VkInstance instance, VkSurfaceKHR* surface)
@@ -34,4 +45,4 @@ void coral_window::create_window_surface(VkInstance instance, VkSurfaceKHR* surf
 	if (glfwCreateWindowSurface(instance, pWindow_, nullptr, surface) != VK_SUCCESS)
 		throw std::runtime_error(
 			"ERROR! coral_window::create_window_surface() >> Failed to create window surface!");
-}
+}

+ 10 - 6
coral_renderer/coral_window.h

@@ -16,18 +16,22 @@ namespace coral_3d
 		coral_window(const coral_window&) = delete;
 		coral_window& operator=(const coral_window&) = delete;
 
-		bool should_close() { return glfwWindowShouldClose(pWindow_); }
-		VkExtent2D get_extent() { return { static_cast<uint32_t>(c_width), static_cast<uint32_t>(c_height)}; }
+		bool should_close() const { return glfwWindowShouldClose(pWindow_); }
+		VkExtent2D get_extent() const { return { static_cast<uint32_t>(width_), static_cast<uint32_t>(height_)}; }
+		bool was_window_resized() const { return is_framebuffer_resized_; }
+		void reset_window_resized() { is_framebuffer_resized_ = false; }
 
 		void create_window_surface(VkInstance instance, VkSurfaceKHR* surface);
 
 	private:
-		const int c_width;
-		const int c_height;
+		static void framebuffer_resize_callback(GLFWwindow* pWindow, int width, int height);
+		void init_window();
+
+		int width_;
+		int height_;
+		bool is_framebuffer_resized_{ false };
 
 		std::string window_name_;
 		GLFWwindow* pWindow_;
-
-		void init_window();
 	};
 }

+ 94 - 38
coral_renderer/first_app.cpp

@@ -12,7 +12,7 @@ first_app::first_app()
 {
 	load_meshes();
 	create_pipeline_layout();
-	create_pipeline();
+	recreate_swapchain();
 	create_command_buffers();
 }
 
@@ -36,9 +36,9 @@ void first_app::load_meshes()
 {
 	std::vector<Vertex> vertices
 	{
-		{{0.0f, -0.5f}},
-		{{0.5f,  0.5f}},
-		{{-0.5f, 0.5f}}
+		{{0.0f, -0.5f, 0.0f}, { 1.0f, 0.0f, 0.0f }},
+		{{-0.5f, 0.5f, 0.0f}, { 0.0f, 1.0f, 0.0f } },
+		{{0.5f,  0.5f, 0.0f}, { 0.0f, 0.0f, 1.0f } },
 	};
 
 	mesh_ = std::make_unique<coral_mesh>(device_, vertices);
@@ -53,8 +53,8 @@ void first_app::create_pipeline_layout()
 
 void first_app::create_pipeline()
 {
-	auto pipeline_config{ coral_pipeline::default_pipeline_config_info(swapchain_.width(), swapchain_.height()) };
-	pipeline_config.render_pass = swapchain_.get_render_pass();
+	auto pipeline_config{ coral_pipeline::default_pipeline_config_info(swapchain_->width(), swapchain_->height()) };
+	pipeline_config.render_pass = swapchain_->get_render_pass();
 	pipeline_config.pipeline_layout = pipeline_layout_;
 
 	pipeline_ = std::make_unique<coral_pipeline>(
@@ -69,55 +69,111 @@ void first_app::create_pipeline()
 
 void first_app::create_command_buffers()
 {
-	command_buffers_.resize(swapchain_.image_count());
+	command_buffers_.resize(swapchain_->image_count());
 
 	VkCommandBufferAllocateInfo alloc_info{ vkinit::command_buffer_ai(device_.get_command_pool(), static_cast<uint32_t>(command_buffers_.size())) };
 	if (vkAllocateCommandBuffers(device_.device(), &alloc_info, command_buffers_.data()) != VK_SUCCESS)
 		throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to allocate command buffers!");
+}
+
+void first_app::free_command_buffers()
+{
+	vkFreeCommandBuffers(
+		device_.device(),
+		device_.get_command_pool(),
+		static_cast<uint32_t>(command_buffers_.size()),
+		command_buffers_.data());
+
+	command_buffers_.clear();
+}
+
+void first_app::draw_frame()
+{
+	uint32_t image_index;
+	auto result = swapchain_->aqcuire_next_image(&image_index);
 
-	for (int i = 0; i < command_buffers_.size(); i++)
+	// Window has been resized
+	if (result == VK_ERROR_OUT_OF_DATE_KHR)
 	{
-		VkCommandBufferBeginInfo begin_info{};
-		begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+		recreate_swapchain();
+		return;
+	}
 
-		if (vkBeginCommandBuffer(command_buffers_[i], &begin_info) != VK_SUCCESS)
-			throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to begin recording command buffer!");
+	if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
+		throw std::runtime_error("ERROR! first_app::draw_frame() >> Failed to aquire swapchain image!");
 
-		VkRenderPassBeginInfo render_pass_info{};
-		render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
-		render_pass_info.renderPass = swapchain_.get_render_pass();
-		render_pass_info.framebuffer = swapchain_.get_frame_buffers(i);
+	record_command_buffer(image_index);
+	result = swapchain_->submit_command_buffer(&command_buffers_[image_index], &image_index);
 
-		render_pass_info.renderArea.offset = { 0, 0 };
-		render_pass_info.renderArea.extent = swapchain_.get_swapchain_extent();
+	if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || window_.was_window_resized())
+	{
+		window_.reset_window_resized();
+		recreate_swapchain();
+		return;
+	}
 
-		std::array<VkClearValue, 2> clear_values{};
-		clear_values[0].color = { 0.1f, 0.1f, 0.1f, 1.0f };
-		clear_values[1].depthStencil = { 1.0f, 0 };
-		render_pass_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
-		render_pass_info.pClearValues = clear_values.data();
+	if(result != VK_SUCCESS)
+		throw std::runtime_error("ERROR! first_app::draw_frame() >> Failed to present swapchain image!");
+}
 
-		vkCmdBeginRenderPass(command_buffers_[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
+void first_app::recreate_swapchain()
+{
+	auto extent{ window_.get_extent() };
 
-		pipeline_->bind(command_buffers_[i]);
-		mesh_->bind(command_buffers_[i]);
-		mesh_->draw(command_buffers_[i]);
+	// Idle when minimized
+	while (extent.width == 0 || extent.height == 0)
+	{
+		extent = window_.get_extent();
+		glfwWaitEvents();
+	}
 
-		vkCmdEndRenderPass(command_buffers_[i]);
+	vkDeviceWaitIdle(device_.device());
 
-		if (vkEndCommandBuffer(command_buffers_[i]) != VK_SUCCESS)
-			throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to record command buffer!");
+	if(swapchain_ == nullptr)
+		swapchain_ = std::make_unique<coral_swapchain>(device_, extent);
+	else
+	{
+		swapchain_ = std::make_unique<coral_swapchain>(device_, extent, std::move(swapchain_));
+		if (swapchain_->image_count() != command_buffers_.size())
+		{
+			free_command_buffers();
+			create_command_buffers();
+		}
 	}
+		
+	create_pipeline();
 }
 
-void first_app::draw_frame()
+void first_app::record_command_buffer(int image_index)
 {
-	uint32_t image_index;
-	auto result = swapchain_.aqcuire_next_image(&image_index);
-	if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
-		throw std::runtime_error("ERROR! first_app::draw_frame() >> Failed to aquire swapchain image!");
+	VkCommandBufferBeginInfo begin_info{};
+	begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
 
-	result = swapchain_.submit_command_buffer(&command_buffers_[image_index], &image_index);
-	if(result != VK_SUCCESS)
-		throw std::runtime_error("ERROR! first_app::draw_frame() >> Failed to present swapchain image!");
+	if (vkBeginCommandBuffer(command_buffers_[image_index], &begin_info) != VK_SUCCESS)
+		throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to begin recording command buffer!");
+
+	VkRenderPassBeginInfo render_pass_info{};
+	render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+	render_pass_info.renderPass = swapchain_->get_render_pass();
+	render_pass_info.framebuffer = swapchain_->get_frame_buffers(image_index);
+
+	render_pass_info.renderArea.offset = { 0, 0 };
+	render_pass_info.renderArea.extent = swapchain_->get_swapchain_extent();
+
+	std::array<VkClearValue, 2> clear_values{};
+	clear_values[0].color = { 0.1f, 0.1f, 0.1f, 1.0f };
+	clear_values[1].depthStencil = { 1.0f, 0 };
+	render_pass_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
+	render_pass_info.pClearValues = clear_values.data();
+
+	vkCmdBeginRenderPass(command_buffers_[image_index], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
+
+	pipeline_->bind(command_buffers_[image_index]);
+	mesh_->bind(command_buffers_[image_index]);
+	mesh_->draw(command_buffers_[image_index]);
+
+	vkCmdEndRenderPass(command_buffers_[image_index]);
+
+	if (vkEndCommandBuffer(command_buffers_[image_index]) != VK_SUCCESS)
+		throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to record command buffer!");
 }

+ 4 - 3
coral_renderer/first_app.h

@@ -31,16 +31,17 @@ namespace coral_3d
 		void create_pipeline_layout();
 		void create_pipeline();
 		void create_command_buffers();
+		void free_command_buffers();
 		void draw_frame();
+		void recreate_swapchain();
+		void record_command_buffer(int image_index);
 
 		coral_window window_{ WIDTH, HEIGHT, "Coral Renderer" };
 		coral_device device_{ window_ };
-		coral_swapchain swapchain_{ device_, window_.get_extent() };
+		std::unique_ptr<coral_swapchain> swapchain_;
 		std::unique_ptr<coral_pipeline> pipeline_;
-
 		VkPipelineLayout pipeline_layout_;
 		std::vector<VkCommandBuffer> command_buffers_;
-
 		std::unique_ptr<coral_mesh> mesh_;
 	};
 }

BIN
out/build/x64-Debug/.ninja_deps


+ 45 - 45
out/build/x64-Debug/.ninja_log

@@ -8,7 +8,7 @@
 39	883	7101797253853157	third_party/GLFW/src/CMakeFiles/glfw.dir/init.c.obj	4c5b5a61c74a0503
 75	890	7101797253893155	third_party/GLFW/src/CMakeFiles/glfw.dir/win32_monitor.c.obj	f3bcdc54fc50d40e
 50	918	7101797253953169	third_party/GLFW/src/CMakeFiles/glfw.dir/monitor.c.obj	9c133f055c1c47
-222	1910	7101797264265387	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
+12	1007	7101892568832128	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
 84	915	7101797253953169	third_party/GLFW/src/CMakeFiles/glfw.dir/win32_thread.c.obj	ac4ae588ab2b3867
 80	866	7101797253748007	third_party/GLFW/src/CMakeFiles/glfw.dir/win32_time.c.obj	694a8d84a0a6a42f
 65	898	7101797253903152	third_party/GLFW/src/CMakeFiles/glfw.dir/win32_init.c.obj	f9e962456dc8d656
@@ -19,50 +19,50 @@
 918	988	7101797255003457	third_party/GLFW/src/glfw3.lib	90fe5d3bf3988c3
 44	874	7101797253798021	third_party/GLFW/src/CMakeFiles/glfw.dir/input.c.obj	956df7c8cf242b34
 60	914	7101797253913164	third_party/GLFW/src/CMakeFiles/glfw.dir/window.c.obj	b364e0375cf5f3ae
-1022	1209	7101813627819240	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+1013	1279	7101892570664534	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
 217	917	7101797254053199	third_party/GLFW/src/CMakeFiles/glfw.dir/osmesa_context.c.obj	e9ed1005530706e4
-875	2144	7101797266526618	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
+17	999	7101892568757462	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
 30	1948	7101797264615494	third_party/CMakeFiles/tinyobjloader.dir/tinyobjloader/tiny_obj_loader.cc.obj	1e9e954b98b13f50
-26	2160	7101797266733733	third_party/CMakeFiles/vkbootstrap.dir/vkbootstrap/VkBootstrap.cpp.obj	64385be2816b800a
-883	2300	7101797268130843	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
+38	1597	7101891512526678	third_party/CMakeFiles/vkbootstrap.dir/vkbootstrap/VkBootstrap.cpp.obj	64385be2816b800a
+21	1460	7101891511178276	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
 9	24	0	clean	21a4d0550fd2b6b1
-867	1545	7101797260577747	coral_renderer/CMakeFiles/coral_renderer.dir/coral_window.cpp.obj	bedfd30a6102baa8
-2160	2204	7101797267202309	third_party/vkbootstrap.lib	b339a5cc36d209fb
-11	1313	7101809551655538	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
-17	217	7101797247304796	C:/Game Development/Visual Studio Solutions/Coral3D/shaders/compiled/simple_shader.frag.spv	abf5977eb3a7ad06
-903	2166	7101797266765707	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
-21	221	7101797247327643	C:/Game Development/Visual Studio Solutions/Coral3D/shaders/compiled/simple_shader.vert.spv	668e2527d551a6cf
-11	1021	7101813626754078	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-14	1022	7101813921068553	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-1023	1210	7101813922195478	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-17	1060	7101814667900638	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
-28	1076	7101814668060763	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
-12	1162	7101814668923719	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
-21	1219	7101814669485321	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
-32	1247	7101814669778136	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-24	1553	7101814672825950	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
-1553	1757	7101814674079170	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-17	1104	7101815094116056	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
-29	1155	7101815094629939	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
-12	1253	7101815095619887	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
-20	1288	7101815095940613	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
-33	1336	7101815096438615	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-25	1633	7101815099389606	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
-1633	1904	7101815101218050	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-11	997	7101816146989106	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-998	1176	7101816148013515	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-13	1018	7101817030390874	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-1018	1202	7101817031458740	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-12	1069	7101817353959200	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-1070	1282	7101817355082332	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-16	1367	7101820695463999	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
-11	1369	7101820695494010	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
-29	1390	7101820695680997	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
-20	1403	7101820695836190	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
-32	1482	7101820696630201	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-25	1792	7101820699737117	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
-1792	2006	7101820701049026	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-20	1413	7101828304875727	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
-1414	1685	7101828306644427	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
-12	1305	7101828747172493	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
-1306	1512	7101828748416247	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+18	910	7101866207942490	coral_renderer/CMakeFiles/coral_renderer.dir/coral_window.cpp.obj	bedfd30a6102baa8
+1597	1651	7101891513064033	third_party/vkbootstrap.lib	b339a5cc36d209fb
+25	1879	7101891515336887	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
+4	141	7101850315847728	C:/Game Development/Visual Studio Solutions/Coral3D/shaders/compiled/simple_shader.frag.spv	abf5977eb3a7ad06
+21	1013	7101892568893410	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+9	148	7101850315924648	C:/Game Development/Visual Studio Solutions/Coral3D/shaders/compiled/simple_shader.vert.spv	668e2527d551a6cf
+33	1586	7101891512436567	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
+16	896	7101892914187749	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+897	1092	7101892915293917	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+14	857	7101893157855334	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+858	1034	7101893158881549	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+21	1554	7101902067294684	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
+36	1605	7101902067820320	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
+25	1854	7101902070308580	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
+20	1155	7101902386661975	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
+15	1272	7101902387794512	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
+29	1135	7101902921461698	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+18	1146	7101902921606785	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
+13	1271	7101902922845310	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
+21	1303	7101902923171303	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
+33	1386	7101902924012738	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
+25	1613	7101902926255318	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
+1614	1869	7101902927995480	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+17	1471	7101914378446245	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
+13	1481	7101914378553067	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
+30	1496	7101914378689684	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+21	1512	7101914378868226	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	429a0363ba93b7c7
+33	1586	7101914379607641	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	ab6486da48f5e166
+12	1320	7101914586261436	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	f65feb738e17e8d7
+1320	1613	7101914588159131	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+4	892	7101915052352115	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+892	1083	7101915053453898	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+12	852	7101918935666082	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+853	1047	7101918936774076	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+13	883	7101919273697849	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+884	1097	7101919274921391	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9
+20	873	7101924449373298	coral_renderer/CMakeFiles/coral_renderer.dir/coral_swapchain.cpp.obj	1e16c3634dad8b40
+17	880	7101924449447028	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	2fa3f3bbdc72680a
+12	988	7101924450531072	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	f207d5295f665d92
+988	1175	7101924451627858	coral_renderer/coral_renderer.exe	a2f5951cf56c54b9

BIN
out/build/x64-Debug/coral_renderer/CMakeFiles/coral_renderer.dir/vc140.pdb


BIN
out/build/x64-Debug/coral_renderer/coral_renderer.ilk


BIN
out/build/x64-Debug/coral_renderer/coral_renderer.pdb


BIN
out/build/x64-Debug/coral_renderer/shaders/simple_shader.frag.spv


BIN
out/build/x64-Debug/coral_renderer/shaders/simple_shader.vert.spv


BIN
out/build/x64-Debug/third_party/CMakeFiles/vkbootstrap.dir/vkbootstrap.pdb


BIN
out/build/x64-Release/.ninja_deps


+ 5 - 0
out/build/x64-Release/.ninja_log

@@ -52,3 +52,8 @@
 155	1641	7101828965056591	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	c9cebafec58901df
 147	2319	7101828971832944	coral_renderer/CMakeFiles/coral_renderer.dir/coral_device.cpp.obj	54ea3dd64d178489
 2319	2618	7101828974349382	coral_renderer/coral_renderer.exe	46b48affdb39d636
+10	912	7101845953773938	coral_renderer/CMakeFiles/coral_renderer.dir/first_app.cpp.obj	f6aa697f38bcc8c1
+5	1013	7101845954790120	coral_renderer/CMakeFiles/coral_renderer.dir/main.cpp.obj	b04a92f83a26ca98
+14	1076	7101845955404846	coral_renderer/CMakeFiles/coral_renderer.dir/coral_pipeline.cpp.obj	547825035d4ce491
+18	1196	7101845956606118	coral_renderer/CMakeFiles/coral_renderer.dir/coral_mesh.cpp.obj	c9cebafec58901df
+1196	1516	7101845959367478	coral_renderer/coral_renderer.exe	46b48affdb39d636

BIN
shaders/compiled/simple_shader.frag.spv


BIN
shaders/compiled/simple_shader.vert.spv


+ 3 - 1
shaders/simple_shader.frag

@@ -1,7 +1,9 @@
 #version 450
 
+layout (location = 0) in vec3 fragColor;
+
 layout (location = 0) out vec4 outColor;
 
 void main() {
-  outColor = vec4(1.0, 1.0, 0.0, 1.0);
+  outColor = vec4(fragColor, 1.0f);
 }

+ 6 - 2
shaders/simple_shader.vert

@@ -1,7 +1,11 @@
 #version 450
 
-layout(location = 0) in vec2 position;
+layout (location = 0) in vec3 position;
+layout (location = 1) in vec3 color;
+
+layout (location = 0) out vec3 fragColor;
 
 void main() {
-  gl_Position = vec4(position, 0.0, 1.0);
+  gl_Position = vec4(position, 1.0f);
+  fragColor = color;
 }