mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 13:36:14 +03:00
194 lines
6.7 KiB
C++
194 lines
6.7 KiB
C++
#include "renderer.h"
|
|
#include "../engine.h"
|
|
#include "render_scene.h"
|
|
#include "scene_textures.h"
|
|
|
|
namespace engine
|
|
{
|
|
RendererManager* getRenderer()
|
|
{
|
|
static RendererManager* renderer = Engine::get()->getRuntimeModule<RendererManager>();
|
|
return renderer;
|
|
}
|
|
|
|
void RendererManager::registerCheck(Engine* engine)
|
|
{
|
|
ASSERT(engine->existRegisteredModule<VulkanContext>(),
|
|
"When renderer enable, you must register vulkan context module before renderer.");
|
|
}
|
|
|
|
bool RendererManager::init()
|
|
{
|
|
m_renderScene = new RenderScene();
|
|
|
|
// Init global render resource.
|
|
m_temporalBlueNoise = new TemporalBlueNoise();
|
|
m_sharedTextures = new SharedTextures();
|
|
|
|
m_fallbackSSBO = std::make_unique<VulkanBuffer>(
|
|
getContext()->getVMABuffer(),
|
|
"dump ssbo",
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
|
0,
|
|
sizeof(uint)
|
|
);
|
|
|
|
// Prepare windows present need datas.
|
|
if (m_engine->isWindowApplication())
|
|
{
|
|
// Preapre command buffers and semaphore, this is useful when render and present to surface.
|
|
initWindowCommandContext();
|
|
|
|
m_imguiManager.init();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RendererManager::tick(const RuntimeModuleTickData& tickData)
|
|
{
|
|
// Window present render tick.
|
|
if (m_engine->isWindowApplication())
|
|
{
|
|
// Imgui new frame.
|
|
m_imguiManager.newFrame();
|
|
|
|
// Broadcast tick functions and render imgui.
|
|
tickFunctions.broadcast(tickData, getContext());
|
|
|
|
// Prepare render data.
|
|
m_imguiManager.render();
|
|
|
|
auto rendererTick = [&](VkCommandBuffer graphicsCmd)
|
|
{
|
|
RHICheck(vkResetCommandBuffer(graphicsCmd, 0));
|
|
VkCommandBufferBeginInfo cmdBeginInfo =
|
|
RHICommandbufferBeginInfo(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
|
|
|
// Record tick command functions.
|
|
RHICheck(vkBeginCommandBuffer(graphicsCmd, &cmdBeginInfo));
|
|
{
|
|
// Render scene update and collect data.
|
|
m_renderScene->tick(tickData, graphicsCmd);
|
|
|
|
// Tick delegates functions.
|
|
tickCmdFunctionsBefore.broadcast(tickData, graphicsCmd, getContext());
|
|
tickCmdFunctions.broadcast(tickData, graphicsCmd, getContext());
|
|
}
|
|
RHICheck(vkEndCommandBuffer(graphicsCmd));
|
|
};
|
|
|
|
VkPipelineStageFlags waitFlags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
|
|
|
// Check main imgui minimized state to decide wether should we present current frame.
|
|
const bool bMainMinimized = m_imguiManager.isMainMinimized();
|
|
if (!bMainMinimized)
|
|
{
|
|
// Acquire next present image.
|
|
uint32_t backBufferIndex = getContext()->acquireNextPresentImage();
|
|
ASSERT(backBufferIndex < getContext()->getBackBufferCount(), "Swapchain backbuffer count should equal to flighting count.");
|
|
|
|
// Prepare current
|
|
VkCommandBuffer graphicsCmd = m_windowCmdContext.mainCmdRing.at(backBufferIndex);
|
|
|
|
// Record.
|
|
rendererTick(graphicsCmd);
|
|
|
|
// Record ui render.
|
|
m_imguiManager.renderFrame(backBufferIndex);
|
|
|
|
// Load all semaphores.
|
|
auto frameStartSemaphore = getContext()->getCurrentFrameWaitSemaphore();
|
|
auto graphicsCmdEndSemaphore = m_windowCmdContext.mainSemaphoreRing[backBufferIndex];
|
|
auto frameEndSemaphore = getContext()->getCurrentFrameFinishSemaphore();
|
|
|
|
// Submit with semaphore.
|
|
RHISubmitInfo graphicsCmdSubmitInfo{};
|
|
graphicsCmdSubmitInfo.setWaitStage(&waitFlags)
|
|
.setWaitSemaphore(&frameStartSemaphore, 1)
|
|
.setSignalSemaphore(&graphicsCmdEndSemaphore, 1)
|
|
.setCommandBuffer(&graphicsCmd, 1);
|
|
|
|
RHISubmitInfo uiCmdSubmitInfo{};
|
|
VkCommandBuffer uiCmdBuffer = m_imguiManager.getCommandBuffer(backBufferIndex);
|
|
uiCmdSubmitInfo.setWaitStage(&waitFlags)
|
|
.setWaitSemaphore(&graphicsCmdEndSemaphore, 1)
|
|
.setSignalSemaphore(&frameEndSemaphore, 1)
|
|
.setCommandBuffer(&uiCmdBuffer, 1);
|
|
|
|
std::vector<VkSubmitInfo> infosRawSubmit{ graphicsCmdSubmitInfo, uiCmdSubmitInfo };
|
|
|
|
getContext()->resetFence();
|
|
getContext()->submit((uint32_t)infosRawSubmit.size(), infosRawSubmit.data());
|
|
}
|
|
else
|
|
{
|
|
getContext()->waitDeviceIdle();
|
|
}
|
|
|
|
m_imguiManager.updateAfterSubmit();
|
|
|
|
if (!bMainMinimized)
|
|
{
|
|
getContext()->present();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RendererManager::beforeRelease()
|
|
{
|
|
// Wait device work finish all work before release.
|
|
getContext()->waitDeviceIdle();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RendererManager::release()
|
|
{
|
|
m_fallbackSSBO.reset();
|
|
|
|
// Clear render scene.
|
|
delete m_renderScene;
|
|
|
|
// Clear global render resource.
|
|
delete m_temporalBlueNoise;
|
|
delete m_sharedTextures;
|
|
|
|
if (m_engine->isWindowApplication())
|
|
{
|
|
m_imguiManager.release();
|
|
|
|
destroyWindowCommandContext();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void RendererManager::initWindowCommandContext()
|
|
{
|
|
// prepare common cmdbuffer and semaphore.
|
|
VkSemaphoreCreateInfo semaphoreInfo{ };
|
|
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
|
|
// Main window prepare.
|
|
m_windowCmdContext.mainCmdRing.resize(getContext()->getBackBufferCount());
|
|
m_windowCmdContext.mainSemaphoreRing.resize(getContext()->getBackBufferCount());
|
|
for (size_t i = 0; i < getContext()->getBackBufferCount(); i++)
|
|
{
|
|
m_windowCmdContext.mainCmdRing[i] = getContext()->createMajorGraphicsCommandBuffer();
|
|
RHICheck(vkCreateSemaphore(getDevice(), &semaphoreInfo, nullptr, &m_windowCmdContext.mainSemaphoreRing[i]));
|
|
}
|
|
}
|
|
|
|
void RendererManager::destroyWindowCommandContext()
|
|
{
|
|
// Main window release.
|
|
for (size_t i = 0; i < getContext()->getBackBufferCount(); i++)
|
|
{
|
|
vkDestroySemaphore(getContext()->getDevice(), m_windowCmdContext.mainSemaphoreRing[i], nullptr);
|
|
getContext()->freeMajorGraphicsCommandBuffer(m_windowCmdContext.mainCmdRing[i]);
|
|
}
|
|
}
|
|
} |