Files
LearningVulkan/src/private/VulkanContext.cpp

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();
}