627 lines
19 KiB
C++
Executable File
627 lines
19 KiB
C++
Executable File
#include "VulkanContext.h"
|
|
#include "VulkanCommandBuffers.h"
|
|
#include "VulkanDeviceManager.h"
|
|
#include "VulkanFramebuffers.h"
|
|
#include "VulkanSwapChain.h"
|
|
#include "VulkanVertexBuffer.h"
|
|
|
|
#include "utilities/Logger.h"
|
|
#include "stb_image.h"
|
|
|
|
#include "imgui_impl_glfw.h"
|
|
#include "imgui_impl_vulkan.h"
|
|
|
|
#include <GLFW/glfw3.h>
|
|
#include <glm/ext/matrix_clip_space.hpp>
|
|
#include <glm/ext/matrix_transform.hpp>
|
|
#include <glm/fwd.hpp>
|
|
#include <glm/trigonometric.hpp>
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
#define GLM_FORCE_RADIANS
|
|
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
VulkanContext::VulkanContext()
|
|
{
|
|
}
|
|
|
|
VulkanContext::~VulkanContext()
|
|
{
|
|
}
|
|
|
|
void VulkanContext::Initialize(FVulkanConfig& InConfig, const std::vector<Vertex>& InVertices, const std::vector<uint16_t>& InIndices)
|
|
{
|
|
Config = InConfig;
|
|
|
|
if (Config.bValidationEnabled)
|
|
{
|
|
InstanceManager.CreateInstance(&DebugManager);
|
|
DebugManager.Initialize(InstanceManager.GetInstance());
|
|
}
|
|
else
|
|
{
|
|
InstanceManager.CreateInstance();
|
|
}
|
|
|
|
CreateSurface(InConfig.Window);
|
|
|
|
DeviceManager.Initialize(FDeviceConfig(
|
|
InstanceManager.GetInstance(),
|
|
Config.bValidationEnabled,
|
|
Surface,
|
|
InConfig.Window));
|
|
DeviceManager.PickPhysicalDevice();
|
|
DeviceManager.CreateLogicalDevice();
|
|
|
|
auto SwapChainSupport = DeviceManager.QuerySwapChainSupport(DeviceManager.GetPhysicalDevice());
|
|
|
|
SwapChain.Initialize(FSwapConfig(
|
|
DeviceManager.GetDevice(),
|
|
Surface,
|
|
Config.Window,
|
|
DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily,
|
|
DeviceManager.GetPhysicalQueueFamilies().PresentFamily,
|
|
SwapChainSupport.Capabilities,
|
|
SwapChainSupport.Formats,
|
|
SwapChainSupport.PresentModes));
|
|
|
|
SwapChain.CreateSwapChain();
|
|
SwapChain.CreateImageViews();
|
|
|
|
RenderPass.Initialize(DeviceManager.GetDevice());
|
|
RenderPass.CreateRenderPass(SwapChain.GetSwapChainImageFormat());
|
|
|
|
CreateDescriptorSetLayout();
|
|
|
|
GraphicsPipeline.Initialize(DeviceManager.GetDevice());
|
|
GraphicsPipeline.CreateGraphicsPipeline(SwapChain.GetSwapChainExtent(), RenderPass.GetRenderPass(), DescriptorSetLayout);
|
|
|
|
Framebuffers.Initialize(FFramebufferConfig(
|
|
DeviceManager.GetDevice(),
|
|
RenderPass.GetRenderPass(),
|
|
SwapChain.GetSwapChainImageViews(),
|
|
SwapChain.GetSwapChainExtent()));
|
|
Framebuffers.CreateFramebuffers();
|
|
|
|
CommandBuffers.Initialize(DeviceManager.GetDevice(), RenderPass.GetRenderPass());
|
|
CommandBuffers.CreateCommandPool(DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily);
|
|
|
|
CreateTextureImage("textures/texture.jpg");
|
|
|
|
VertexBuffer.Initialize(FVertexBufferConfig(
|
|
DeviceManager.GetDevice(),
|
|
DeviceManager.GetPhysicalDevice(),
|
|
CommandBuffers.GetCommandPool(),
|
|
DeviceManager.GetGraphicsQueue()));
|
|
VertexBuffer.CreateVertexBuffer(InVertices);
|
|
VertexBuffer.CreateIndexBuffer(InIndices);
|
|
VertexBuffer.CreateUniformBuffers(MAX_FRAMES_IN_FLIGHT);
|
|
|
|
CreateDescriptorPool();
|
|
CreateDescriptorSets();
|
|
|
|
CommandBuffers.CreateCommandBuffers(MAX_FRAMES_IN_FLIGHT);
|
|
|
|
CreateSyncObjects();
|
|
|
|
VkDescriptorPoolSize PoolSizes[] = {
|
|
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
|
|
{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 }
|
|
};
|
|
VkDescriptorPoolCreateInfo PoolInfo = {};
|
|
PoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
PoolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
|
PoolInfo.maxSets = 1000;
|
|
PoolInfo.poolSizeCount = (uint32_t)std::size(PoolSizes);
|
|
PoolInfo.pPoolSizes = PoolSizes;
|
|
vkCreateDescriptorPool(DeviceManager.GetDevice(), &PoolInfo, nullptr, &ImGuiPool);
|
|
}
|
|
|
|
void VulkanContext::Cleanup()
|
|
{
|
|
if (bImGuiVulkanInitialized)
|
|
{
|
|
ImGui_ImplVulkan_Shutdown();
|
|
}
|
|
|
|
if (bImGuiGlfwInitialized)
|
|
{
|
|
ImGui_ImplGlfw_Shutdown();
|
|
}
|
|
|
|
CleanupSwapChain();
|
|
|
|
vkDestroyDescriptorPool(DeviceManager.GetDevice(), DescriptorPool, nullptr);
|
|
vkDestroyDescriptorSetLayout(DeviceManager.GetDevice(), DescriptorSetLayout, nullptr);
|
|
|
|
VertexBuffer.Cleanup(MAX_FRAMES_IN_FLIGHT);
|
|
|
|
GraphicsPipeline.Cleanup();
|
|
RenderPass.Cleanup();
|
|
|
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
|
{
|
|
vkDestroySemaphore(DeviceManager.GetDevice(), ImageAvailableSemaphores[i], nullptr);
|
|
vkDestroySemaphore(DeviceManager.GetDevice(), RenderFinishedSemaphores[i], nullptr);
|
|
vkDestroyFence(DeviceManager.GetDevice(), InFlightFences[i], nullptr);
|
|
}
|
|
|
|
CommandBuffers.Cleanup();
|
|
|
|
DeviceManager.Cleanup();
|
|
|
|
if (Config.bValidationEnabled)
|
|
{
|
|
DebugManager.Cleanup();
|
|
}
|
|
|
|
vkDestroySurfaceKHR(InstanceManager.GetInstance(), Surface, nullptr);
|
|
InstanceManager.Cleanup();
|
|
}
|
|
|
|
void VulkanContext::CreateSurface(GLFWwindow* Window)
|
|
{
|
|
if (!Window)
|
|
{
|
|
Log::Error("Window not initialized.");
|
|
}
|
|
|
|
if (!InstanceManager.GetInstance())
|
|
{
|
|
Log::Error("Instance is null.");
|
|
}
|
|
|
|
VkResult result = glfwCreateWindowSurface(InstanceManager.GetInstance(), Window, nullptr, &Surface);
|
|
if (result != VK_SUCCESS)
|
|
{
|
|
std::string errorMsg;
|
|
switch (result)
|
|
{
|
|
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
|
errorMsg = "VK_ERROR_EXTENSION_NOT_PRESENT - Required extension not present";
|
|
break;
|
|
case VK_ERROR_INITIALIZATION_FAILED:
|
|
errorMsg = "VK_ERROR_INITIALIZATION_FAILED - Initialization failed";
|
|
break;
|
|
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
|
errorMsg = "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR - Native window already in use";
|
|
break;
|
|
default:
|
|
errorMsg = "Unknown error code: " + std::to_string(result);
|
|
break;
|
|
}
|
|
|
|
Log::Error("Failed to create window surface: " + errorMsg);
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Window surface created successfully.");
|
|
}
|
|
}
|
|
|
|
void VulkanContext::CreateDescriptorSetLayout()
|
|
{
|
|
VkDescriptorSetLayoutBinding UboLayoutBinding{};
|
|
UboLayoutBinding.binding = 0;
|
|
UboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
UboLayoutBinding.descriptorCount = 1;
|
|
UboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
|
UboLayoutBinding.pImmutableSamplers = nullptr;
|
|
|
|
VkDescriptorSetLayoutCreateInfo LayoutInfo{};
|
|
LayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
LayoutInfo.bindingCount = 1;
|
|
LayoutInfo.pBindings = &UboLayoutBinding;
|
|
|
|
if (vkCreateDescriptorSetLayout(DeviceManager.GetDevice(), &LayoutInfo, nullptr, &DescriptorSetLayout) != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to create descriptor set layout!");
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Successfully created descriptor set layout.");
|
|
}
|
|
}
|
|
|
|
void VulkanContext::CreateDescriptorPool()
|
|
{
|
|
VkDescriptorPoolSize PoolSize{};
|
|
PoolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
PoolSize.descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
|
|
|
VkDescriptorPoolCreateInfo PoolInfo{};
|
|
PoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
PoolInfo.poolSizeCount = 1;
|
|
PoolInfo.pPoolSizes = &PoolSize;
|
|
PoolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
|
|
|
if (vkCreateDescriptorPool(DeviceManager.GetDevice(), &PoolInfo, nullptr, &DescriptorPool) != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to create descriptor pool!");
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Successfully created descriptor pool.");
|
|
}
|
|
}
|
|
|
|
void VulkanContext::CreateDescriptorSets()
|
|
{
|
|
std::vector<VkDescriptorSetLayout> Layouts(MAX_FRAMES_IN_FLIGHT, DescriptorSetLayout);
|
|
|
|
VkDescriptorSetAllocateInfo AllocateInfo{};
|
|
AllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
AllocateInfo.descriptorPool = DescriptorPool;
|
|
AllocateInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
|
AllocateInfo.pSetLayouts = Layouts.data();
|
|
|
|
DescriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
|
|
if (vkAllocateDescriptorSets(DeviceManager.GetDevice(), &AllocateInfo, DescriptorSets.data()) != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to allocate descriptor sets!");
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Successfully allocated descriptor sets.");
|
|
}
|
|
|
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
|
{
|
|
VkDescriptorBufferInfo BufferInfo{};
|
|
BufferInfo.buffer = VertexBuffer.GetUniformBuffers()[i];
|
|
BufferInfo.offset = 0;
|
|
BufferInfo.range = sizeof(UniformBufferObject);
|
|
|
|
VkWriteDescriptorSet DescriptorWrite{};
|
|
DescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
DescriptorWrite.dstSet = DescriptorSets[i];
|
|
DescriptorWrite.dstBinding = 0;
|
|
DescriptorWrite.dstArrayElement = 0;
|
|
DescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
DescriptorWrite.descriptorCount = 1;
|
|
DescriptorWrite.pBufferInfo = &BufferInfo;
|
|
DescriptorWrite.pImageInfo = nullptr;
|
|
DescriptorWrite.pTexelBufferView = nullptr;
|
|
|
|
vkUpdateDescriptorSets(DeviceManager.GetDevice(), 1, &DescriptorWrite, 0, nullptr);
|
|
}
|
|
}
|
|
|
|
void VulkanContext::CreateImage(
|
|
uint32_t Width,
|
|
uint32_t Height,
|
|
VkFormat Format,
|
|
VkImageTiling Tiling,
|
|
VkImageUsageFlags Usage,
|
|
VkMemoryPropertyFlags Properties,
|
|
VkImage& Image,
|
|
VkDeviceMemory& ImageMemory)
|
|
{
|
|
|
|
VkImageCreateInfo ImageInfo{};
|
|
ImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
ImageInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
ImageInfo.extent.width = Width;
|
|
ImageInfo.extent.height = Height;
|
|
ImageInfo.extent.depth = 1;
|
|
ImageInfo.mipLevels = 1;
|
|
ImageInfo.arrayLayers = 1;
|
|
ImageInfo.format = Format;
|
|
ImageInfo.tiling = Tiling;
|
|
ImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
ImageInfo.usage = Usage;
|
|
ImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
ImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
if (vkCreateImage(DeviceManager.GetDevice(), &ImageInfo, nullptr, &Image) != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to create image!");
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Successfully created image.");
|
|
}
|
|
|
|
VkMemoryRequirements MemoryRequirements;
|
|
vkGetImageMemoryRequirements(DeviceManager.GetDevice(), Image, &MemoryRequirements);
|
|
|
|
VkMemoryAllocateInfo AllocateInfo{};
|
|
AllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
AllocateInfo.allocationSize = MemoryRequirements.size;
|
|
AllocateInfo.memoryTypeIndex = VertexBuffer.FindMemoryType(MemoryRequirements.memoryTypeBits, Properties);
|
|
|
|
if (vkAllocateMemory(DeviceManager.GetDevice(), &AllocateInfo, nullptr, &ImageMemory) != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to allocate image memory!");
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Successfully allocated imaged memory.");
|
|
}
|
|
|
|
vkBindImageMemory(DeviceManager.GetDevice(), Image, ImageMemory, 0);
|
|
}
|
|
|
|
void VulkanContext::CreateTextureImage(const char* FileName)
|
|
{
|
|
int TextureWidth, TextureHeight, TextureChannels;
|
|
stbi_uc* Pixels = stbi_load(FileName, &TextureWidth, &TextureHeight, &TextureChannels, STBI_rgb_alpha);
|
|
VkDeviceSize ImageSize = TextureWidth * TextureHeight * 4;
|
|
|
|
if (!Pixels)
|
|
{
|
|
Log::Error("Failed to load texture image!");
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Successfully loaded texture image.");
|
|
}
|
|
|
|
VkBuffer StagingBuffer;
|
|
VkDeviceMemory StagingBufferMemory;
|
|
|
|
VertexBuffer.CreateBuffer(ImageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, StagingBuffer, StagingBufferMemory);
|
|
|
|
void* Data;
|
|
vkMapMemory(DeviceManager.GetDevice(), StagingBufferMemory, 0, ImageSize, 0, &Data);
|
|
memcpy(Data, Pixels, static_cast<size_t>(ImageSize));
|
|
vkUnmapMemory(DeviceManager.GetDevice(), StagingBufferMemory);
|
|
|
|
stbi_image_free(Pixels);
|
|
|
|
CreateImage(
|
|
TextureWidth,
|
|
TextureHeight,
|
|
VK_FORMAT_R8G8B8A8_SRGB,
|
|
VK_IMAGE_TILING_OPTIMAL,
|
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
TextureImage,
|
|
TextureImageMemory);
|
|
}
|
|
|
|
void VulkanContext::CreateSyncObjects()
|
|
{
|
|
ImageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
|
RenderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
|
InFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
|
|
|
|
VkSemaphoreCreateInfo SemaphoreInfo{};
|
|
SemaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
|
|
VkFenceCreateInfo FenceInfo{};
|
|
FenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
FenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
|
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
|
{
|
|
if (vkCreateSemaphore(DeviceManager.GetDevice(), &SemaphoreInfo, nullptr, &ImageAvailableSemaphores[i]) != VK_SUCCESS
|
|
|| vkCreateSemaphore(DeviceManager.GetDevice(), &SemaphoreInfo, nullptr, &RenderFinishedSemaphores[i]) != VK_SUCCESS
|
|
|| vkCreateFence(DeviceManager.GetDevice(), &FenceInfo, nullptr, &InFlightFences[i]) != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to create semaphores!");
|
|
}
|
|
else
|
|
{
|
|
Log::Info("Successfully created semaphores");
|
|
}
|
|
}
|
|
}
|
|
|
|
void VulkanContext::DrawFrame(bool bDrawImGui, uint32_t InVerticesSize, uint32_t InIndexSize)
|
|
{
|
|
vkWaitForFences(DeviceManager.GetDevice(), 1, &InFlightFences[CurrentFrame], VK_TRUE, UINT64_MAX);
|
|
|
|
uint32_t ImageIndex;
|
|
VkResult result = vkAcquireNextImageKHR(
|
|
DeviceManager.GetDevice(),
|
|
SwapChain.GetSwapChain(),
|
|
UINT64_MAX,
|
|
ImageAvailableSemaphores[CurrentFrame],
|
|
VK_NULL_HANDLE,
|
|
&ImageIndex);
|
|
|
|
if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
|
{
|
|
RecreateSwapChain();
|
|
return;
|
|
}
|
|
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
|
|
{
|
|
Log::Error("Failed to acquire swap chain images!");
|
|
}
|
|
|
|
vkResetFences(DeviceManager.GetDevice(), 1, &InFlightFences[CurrentFrame]);
|
|
|
|
vkResetCommandBuffer(CommandBuffers.GetCommandBuffer(CurrentFrame), 0);
|
|
|
|
FRecordCommandBuffersParams Params{
|
|
CommandBuffers.GetCommandBuffer(CurrentFrame),
|
|
ImageIndex,
|
|
VertexBuffer.GetVertexBuffer(),
|
|
InVerticesSize,
|
|
VertexBuffer.GetIndexBuffer(),
|
|
InIndexSize,
|
|
RenderPass.GetRenderPass(),
|
|
SwapChain.GetSwapChainExtent(),
|
|
GraphicsPipeline.GetGraphicsPipeline(),
|
|
Framebuffers.GetSwapChainFrameBuffers(),
|
|
DescriptorSets[CurrentFrame],
|
|
GraphicsPipeline.GetPipelineLayout(),
|
|
bDrawImGui
|
|
// DrawData
|
|
};
|
|
|
|
CommandBuffers.RecordCommandBuffer(Params);
|
|
|
|
UpdateUniformBuffer(CurrentFrame);
|
|
|
|
VkSubmitInfo SubmitInfo{};
|
|
SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
VkSemaphore WaitSemaphores[] = { ImageAvailableSemaphores[CurrentFrame] };
|
|
VkPipelineStageFlags WaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
|
SubmitInfo.waitSemaphoreCount = 1;
|
|
SubmitInfo.pWaitSemaphores = WaitSemaphores;
|
|
SubmitInfo.pWaitDstStageMask = WaitStages;
|
|
|
|
SubmitInfo.commandBufferCount = 1;
|
|
VkCommandBuffer CommandBuffer = CommandBuffers.GetCommandBuffer(CurrentFrame);
|
|
SubmitInfo.pCommandBuffers = &CommandBuffer;
|
|
|
|
VkSemaphore SignalSemaphores[] = { RenderFinishedSemaphores[CurrentFrame] };
|
|
SubmitInfo.signalSemaphoreCount = 1;
|
|
SubmitInfo.pSignalSemaphores = SignalSemaphores;
|
|
|
|
if (vkQueueSubmit(DeviceManager.GetGraphicsQueue(), 1, &SubmitInfo, InFlightFences[CurrentFrame]) != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to submit draw command buffer!");
|
|
}
|
|
|
|
VkPresentInfoKHR PresentInfo{};
|
|
PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
PresentInfo.waitSemaphoreCount = 1;
|
|
PresentInfo.pWaitSemaphores = SignalSemaphores;
|
|
|
|
VkSwapchainKHR SwapChains[] = { SwapChain.GetSwapChain() };
|
|
|
|
PresentInfo.swapchainCount = 1;
|
|
PresentInfo.pSwapchains = SwapChains;
|
|
PresentInfo.pImageIndices = &ImageIndex;
|
|
PresentInfo.pResults = nullptr;
|
|
|
|
result = vkQueuePresentKHR(DeviceManager.GetPresentQueue(), &PresentInfo);
|
|
|
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || bFramebufferResized)
|
|
{
|
|
bFramebufferResized = false;
|
|
RecreateSwapChain();
|
|
}
|
|
else if (result != VK_SUCCESS)
|
|
{
|
|
Log::Error("Failed to present swap chain image!");
|
|
}
|
|
|
|
CurrentFrame = (CurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
|
}
|
|
|
|
void VulkanContext::UpdateUniformBuffer(uint32_t CurrentImage)
|
|
{
|
|
static auto StartTime = std::chrono::high_resolution_clock::now();
|
|
|
|
auto CurrentTime = std::chrono::high_resolution_clock::now();
|
|
|
|
float Time = std::chrono::duration<float, std::chrono::seconds::period>(CurrentTime - StartTime).count();
|
|
|
|
UniformBufferObject Ubo{};
|
|
Ubo.Model = glm::rotate(glm::mat4(1.0f), Time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
Ubo.View = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
Ubo.Projection = glm::perspective(glm::radians(45.0f), SwapChain.GetSwapChainExtent().width / (float)SwapChain.GetSwapChainExtent().height, 0.1f, 10.0f);
|
|
Ubo.Projection[1][1] *= -1;
|
|
|
|
memcpy(VertexBuffer.GetUniformBuffersMapped()[CurrentImage], &Ubo, sizeof(Ubo));
|
|
}
|
|
|
|
void VulkanContext::RecreateSwapChain()
|
|
{
|
|
int Width = 0, Height = 0;
|
|
glfwGetFramebufferSize(Config.Window, &Width, &Height);
|
|
while (Width == 0 || Height == 0)
|
|
{
|
|
glfwGetFramebufferSize(Config.Window, &Width, &Height);
|
|
glfwWaitEvents();
|
|
}
|
|
|
|
Log::Info("Recreating SwapChain...");
|
|
vkDeviceWaitIdle(DeviceManager.GetDevice());
|
|
|
|
CleanupSwapChain();
|
|
|
|
auto SwapChainSupport = DeviceManager.QuerySwapChainSupport(DeviceManager.GetPhysicalDevice());
|
|
|
|
SwapChain.Initialize(FSwapConfig(
|
|
DeviceManager.GetDevice(),
|
|
Surface,
|
|
Config.Window,
|
|
DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily,
|
|
DeviceManager.GetPhysicalQueueFamilies().PresentFamily,
|
|
SwapChainSupport.Capabilities,
|
|
SwapChainSupport.Formats,
|
|
SwapChainSupport.PresentModes));
|
|
SwapChain.CreateSwapChain();
|
|
SwapChain.CreateImageViews();
|
|
|
|
Framebuffers.Initialize(FFramebufferConfig(
|
|
DeviceManager.GetDevice(),
|
|
RenderPass.GetRenderPass(),
|
|
SwapChain.GetSwapChainImageViews(),
|
|
SwapChain.GetSwapChainExtent()));
|
|
Framebuffers.CreateFramebuffers();
|
|
|
|
InitImGui();
|
|
}
|
|
|
|
void VulkanContext::InitImGui()
|
|
{
|
|
if (!bImGuiGlfwInitialized)
|
|
{
|
|
if (!ImGui_ImplGlfw_InitForVulkan(Config.Window, true))
|
|
{
|
|
Log::Error("Failed to initialize ImGui GLFW backend!");
|
|
return;
|
|
}
|
|
bImGuiGlfwInitialized = true;
|
|
}
|
|
|
|
if (bImGuiVulkanInitialized)
|
|
{
|
|
ImGui_ImplVulkan_Shutdown();
|
|
bImGuiVulkanInitialized = false;
|
|
}
|
|
|
|
ImGui_ImplVulkan_InitInfo ImGuiInitInfo = {};
|
|
ImGuiInitInfo.Instance = InstanceManager.GetInstance();
|
|
ImGuiInitInfo.PhysicalDevice = DeviceManager.GetPhysicalDevice();
|
|
ImGuiInitInfo.Device = DeviceManager.GetDevice();
|
|
ImGuiInitInfo.QueueFamily = DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily.value_or(0);
|
|
ImGuiInitInfo.Queue = DeviceManager.GetGraphicsQueue();
|
|
ImGuiInitInfo.PipelineCache = VK_NULL_HANDLE;
|
|
ImGuiInitInfo.DescriptorPool = ImGuiPool;
|
|
ImGuiInitInfo.MinImageCount = MAX_FRAMES_IN_FLIGHT;
|
|
ImGuiInitInfo.ImageCount = SwapChain.GetSwapChainImageViews().size();
|
|
ImGuiInitInfo.Allocator = nullptr;
|
|
ImGuiInitInfo.PipelineInfoMain.RenderPass = RenderPass.GetRenderPass();
|
|
ImGuiInitInfo.PipelineInfoMain.Subpass = 0;
|
|
ImGuiInitInfo.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
|
|
ImGuiInitInfo.CheckVkResultFn = nullptr;
|
|
|
|
if (!ImGui_ImplVulkan_Init(&ImGuiInitInfo))
|
|
{
|
|
Log::Error("Failed to reinitialize ImGui Vulkan backend!");
|
|
return;
|
|
}
|
|
|
|
bImGuiVulkanInitialized = true;
|
|
}
|
|
|
|
void VulkanContext::CleanupSwapChain()
|
|
{
|
|
Framebuffers.Cleanup();
|
|
SwapChain.Cleanup();
|
|
}
|