mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 14:16:14 +03:00
346 lines
12 KiB
C++
346 lines
12 KiB
C++
#include "Pch.h"
|
|
#include "ImGuiPass.h"
|
|
|
|
namespace Flower
|
|
{
|
|
void setupVulkanInitInfo(ImGui_ImplVulkan_InitInfo* inout, VkDescriptorPool pool)
|
|
{
|
|
inout->Instance = RHI::get()->getInstance();
|
|
inout->PhysicalDevice = RHI::GPU;
|
|
inout->Device = RHI::Device;
|
|
inout->QueueFamily = RHI::get()->getGraphiscFamily();
|
|
inout->Queue = RHI::get()->getMajorGraphicsQueue();
|
|
inout->PipelineCache = VK_NULL_HANDLE;
|
|
inout->DescriptorPool = pool;
|
|
inout->Allocator = nullptr;
|
|
inout->MinImageCount = (uint32_t)RHI::get()->getSwapchainImageViews().size();
|
|
inout->ImageCount = inout->MinImageCount;
|
|
inout->MSAASamples = VK_SAMPLE_COUNT_1_BIT;
|
|
inout->CheckVkResultFn = RHICheck;
|
|
inout->Subpass = 0;
|
|
}
|
|
|
|
//
|
|
|
|
|
|
void ImguiPass::renderpassBuild()
|
|
{
|
|
vkDeviceWaitIdle(RHI::Device);
|
|
|
|
// Create the Render Pass
|
|
if(this->m_renderResource.renderPass == VK_NULL_HANDLE)
|
|
{
|
|
VkAttachmentDescription attachment = {};
|
|
attachment.format = m_drawUIFormat;
|
|
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
attachment.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; // Blit to back buffer.
|
|
|
|
VkAttachmentReference color_attachment = {};
|
|
color_attachment.attachment = 0;
|
|
color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
|
|
VkSubpassDescription subpass = {};
|
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
subpass.colorAttachmentCount = 1;
|
|
subpass.pColorAttachments = &color_attachment;
|
|
|
|
VkSubpassDependency dependency = {};
|
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
dependency.dstSubpass = 0;
|
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
dependency.srcAccessMask = 0;
|
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
VkRenderPassCreateInfo info = {};
|
|
|
|
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
|
info.attachmentCount = 1;
|
|
info.pAttachments = &attachment;
|
|
info.subpassCount = 1;
|
|
info.pSubpasses = &subpass;
|
|
info.dependencyCount = 1;
|
|
info.pDependencies = &dependency;
|
|
RHICheck(vkCreateRenderPass(RHI::Device, &info, nullptr, &this->m_renderResource.renderPass));
|
|
}
|
|
|
|
{
|
|
VkImageCreateInfo info{};
|
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
info.flags = 0;
|
|
info.imageType = VK_IMAGE_TYPE_2D;
|
|
info.format = VK_FORMAT_R16G16B16A16_SFLOAT;
|
|
info.extent.width = RHI::get()->getSwapchainExtent().width;
|
|
info.extent.height = RHI::get()->getSwapchainExtent().height;
|
|
info.extent.depth = 1;
|
|
info.mipLevels = 1;
|
|
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
info.arrayLayers = 1;
|
|
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
info.queueFamilyIndexCount = 0;
|
|
info.pQueueFamilyIndices = nullptr;
|
|
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
m_drawUIImages = VulkanImage::create("DrawUIImage", info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
}
|
|
|
|
// Create Framebuffer & CommandBuffer
|
|
{
|
|
VkImageView attachment[1];
|
|
VkFramebufferCreateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
info.renderPass = this->m_renderResource.renderPass;
|
|
info.attachmentCount = 1;
|
|
info.pAttachments = attachment;
|
|
info.width = RHI::get()->getSwapchainExtent().width;
|
|
info.height = RHI::get()->getSwapchainExtent().height;
|
|
info.layers = 1;
|
|
|
|
auto backBufferSize = RHI::get()->getSwapchainImageViews().size();
|
|
m_renderResource.framebuffers.resize(backBufferSize);
|
|
m_renderResource.commandPools.resize(backBufferSize);
|
|
m_renderResource.commandBuffers.resize(backBufferSize);
|
|
|
|
for (uint32_t i = 0; i < backBufferSize; i++)
|
|
{
|
|
attachment[0] = m_drawUIImages->getView(buildBasicImageSubresource());
|
|
RHICheck(vkCreateFramebuffer(RHI::Device, &info, nullptr, &m_renderResource.framebuffers[i]));
|
|
}
|
|
|
|
for (uint32_t i = 0; i < backBufferSize; i++)
|
|
{
|
|
// Command pool
|
|
{
|
|
VkCommandPoolCreateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
info.queueFamilyIndex = RHI::get()->getGraphiscFamily();
|
|
RHICheck(vkCreateCommandPool(RHI::Device, &info, nullptr, &m_renderResource.commandPools[i]));
|
|
}
|
|
|
|
// Command buffer
|
|
{
|
|
VkCommandBufferAllocateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
info.commandPool = m_renderResource.commandPools[i];
|
|
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
info.commandBufferCount = 1;
|
|
RHICheck(vkAllocateCommandBuffers(RHI::Device, &info, &m_renderResource.commandBuffers[i]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImguiPass::renderpassRelease(bool bFullRelease)
|
|
{
|
|
vkDeviceWaitIdle(RHI::Device);
|
|
|
|
if (bFullRelease)
|
|
{
|
|
vkDestroyRenderPass(RHI::Device, m_renderResource.renderPass, nullptr);
|
|
}
|
|
|
|
|
|
auto backBufferSize = m_renderResource.framebuffers.size();
|
|
for (uint32_t i = 0; i < backBufferSize; i++)
|
|
{
|
|
vkFreeCommandBuffers(RHI::Device, m_renderResource.commandPools[i], 1, &m_renderResource.commandBuffers[i]);
|
|
vkDestroyCommandPool(RHI::Device, m_renderResource.commandPools[i], nullptr);
|
|
vkDestroyFramebuffer(RHI::Device, m_renderResource.framebuffers[i], nullptr);
|
|
}
|
|
|
|
m_renderResource.framebuffers.resize(0);
|
|
m_renderResource.commandPools.resize(0);
|
|
m_renderResource.commandBuffers.resize(0);
|
|
}
|
|
|
|
void ImguiPass::init()
|
|
{
|
|
// Descriptor pool prepare.
|
|
{
|
|
VkDescriptorPoolSize pool_sizes[] =
|
|
{
|
|
{ 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 pool_info = {};
|
|
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
|
pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes);
|
|
pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
|
|
pool_info.pPoolSizes = pool_sizes;
|
|
RHICheck(vkCreateDescriptorPool(RHI::Device, &pool_info, nullptr, &m_renderResource.descriptorPool));
|
|
}
|
|
|
|
renderpassBuild();
|
|
|
|
// register swapchain rebuild functions.
|
|
m_beforeSwapChainRebuildHandle = RHI::get()->onBeforeSwapchainRecreate.addLambda([&]() { renderpassRelease(false); });
|
|
m_afterSwapChainRebuildHandle = RHI::get()->onAfterSwapchainRecreate.addLambda([&]() { renderpassBuild(); });
|
|
|
|
// init vulkan resource.
|
|
ImGui_ImplVulkan_InitInfo vkInitInfo{ };
|
|
setupVulkanInitInfo(&vkInitInfo, m_renderResource.descriptorPool);
|
|
|
|
// init vulkan here.
|
|
ImGui_ImplVulkan_Init(&vkInitInfo, m_renderResource.renderPass);
|
|
|
|
// upload font texture to gpu.
|
|
{
|
|
VkCommandPool command_pool = m_renderResource.commandPools[0];
|
|
VkCommandBuffer command_buffer = m_renderResource.commandBuffers[0];
|
|
RHICheck(vkResetCommandPool(RHI::Device, command_pool, 0));
|
|
VkCommandBufferBeginInfo begin_info = {};
|
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
RHICheck(vkBeginCommandBuffer(command_buffer, &begin_info));
|
|
ImGui_ImplVulkan_CreateFontsTexture(command_buffer);
|
|
VkSubmitInfo end_info = {};
|
|
end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
end_info.commandBufferCount = 1;
|
|
end_info.pCommandBuffers = &command_buffer;
|
|
RHICheck(vkEndCommandBuffer(command_buffer));
|
|
RHICheck(vkQueueSubmit(vkInitInfo.Queue, 1, &end_info, VK_NULL_HANDLE));
|
|
RHICheck(vkDeviceWaitIdle(vkInitInfo.Device));
|
|
ImGui_ImplVulkan_DestroyFontUploadObjects();
|
|
}
|
|
}
|
|
|
|
void ImguiPass::renderFrame(uint32_t backBufferIndex)
|
|
{
|
|
ImDrawData* main_draw_data = ImGui::GetDrawData();
|
|
{
|
|
RHICheck(vkResetCommandPool(RHI::Device, m_renderResource.commandPools[backBufferIndex], 0));
|
|
VkCommandBufferBeginInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
RHICheck(vkBeginCommandBuffer(m_renderResource.commandBuffers[backBufferIndex], &info));
|
|
RHI::setPerfMarkerBegin(m_renderResource.commandBuffers[backBufferIndex], "ImGUI", { 1.0f, 1.0f, 0.0f, 1.0f });
|
|
}
|
|
{
|
|
VkRenderPassBeginInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
info.renderPass = m_renderResource.renderPass;
|
|
info.framebuffer = m_renderResource.framebuffers[backBufferIndex];
|
|
info.renderArea.extent.width = RHI::get()->getSwapchainExtent().width;
|
|
info.renderArea.extent.height = RHI::get()->getSwapchainExtent().height;
|
|
info.clearValueCount = 1;
|
|
|
|
VkClearValue clearColor{ };
|
|
clearColor.color.float32[0] = m_clearColor.x * m_clearColor.w;
|
|
clearColor.color.float32[1] = m_clearColor.y * m_clearColor.w;
|
|
clearColor.color.float32[2] = m_clearColor.z * m_clearColor.w;
|
|
clearColor.color.float32[3] = m_clearColor.w;
|
|
info.pClearValues = &clearColor;
|
|
vkCmdBeginRenderPass(m_renderResource.commandBuffers[backBufferIndex], &info, VK_SUBPASS_CONTENTS_INLINE);
|
|
}
|
|
|
|
ImGui_ImplVulkan_RenderDrawData(main_draw_data, m_renderResource.commandBuffers[backBufferIndex]);
|
|
|
|
vkCmdEndRenderPass(m_renderResource.commandBuffers[backBufferIndex]);
|
|
RHI::setPerfMarkerEnd(m_renderResource.commandBuffers[backBufferIndex]);
|
|
|
|
VkImageMemoryBarrier barrier{};
|
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
barrier.image = RHI::get()->getSwapchainImages().at(backBufferIndex);
|
|
barrier.subresourceRange = buildBasicImageSubresource();
|
|
barrier.srcAccessMask = 0;
|
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
vkCmdPipelineBarrier(
|
|
m_renderResource.commandBuffers[backBufferIndex],
|
|
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
{},
|
|
0,
|
|
nullptr,
|
|
0,
|
|
nullptr,
|
|
1,
|
|
&barrier
|
|
);
|
|
|
|
VkImageSubresourceLayers copyLayer
|
|
{
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.mipLevel = 0,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
};
|
|
|
|
VkImageBlit copyRegion
|
|
{
|
|
.srcSubresource = copyLayer,
|
|
.dstSubresource = copyLayer,
|
|
};
|
|
|
|
copyRegion.srcOffsets[0] = { 0, 0, 0};
|
|
copyRegion.dstOffsets[0] = copyRegion.srcOffsets[0];
|
|
|
|
copyRegion.srcOffsets[1] = { (int)m_drawUIImages.get()->getExtent().width, (int)m_drawUIImages.get()->getExtent().height, 1};
|
|
copyRegion.dstOffsets[1] = copyRegion.srcOffsets[1];
|
|
|
|
vkCmdBlitImage(m_renderResource.commandBuffers[backBufferIndex],
|
|
m_drawUIImages->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
RHI::get()->getSwapchainImages().at(backBufferIndex), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region, VK_FILTER_NEAREST);
|
|
|
|
|
|
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
|
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
|
vkCmdPipelineBarrier(
|
|
m_renderResource.commandBuffers[backBufferIndex],
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
{},
|
|
0,
|
|
nullptr,
|
|
0,
|
|
nullptr,
|
|
1,
|
|
&barrier
|
|
);
|
|
|
|
// VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
|
|
|
|
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
|
|
|
RHICheck(vkEndCommandBuffer(m_renderResource.commandBuffers[backBufferIndex]));
|
|
}
|
|
|
|
void ImguiPass::release()
|
|
{
|
|
// unregister swapchain rebuild functions.
|
|
bool res0 = RHI::get()->onBeforeSwapchainRecreate.remove(m_beforeSwapChainRebuildHandle);
|
|
bool res1 = RHI::get()->onAfterSwapchainRecreate.remove(m_afterSwapChainRebuildHandle);
|
|
CHECK(res0 && res1 && "fail to unregister swapchain rebuild callbacks.");
|
|
|
|
// shut down vulkan here.
|
|
ImGui_ImplVulkan_Shutdown();
|
|
|
|
renderpassRelease(true);
|
|
vkDestroyDescriptorPool(RHI::Device, m_renderResource.descriptorPool, nullptr);
|
|
}
|
|
}
|