Files
FGL-Engine/src/engine/rendering/Renderer.cpp

219 lines
6.6 KiB
C++

//
// Created by kj16609 on 11/28/23.
//
#include "Renderer.hpp"
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_handles.hpp>
#include <array>
#include <chrono>
#include <iostream>
#include <stdexcept>
#include <thread>
#include "Device.hpp"
#include "SwapChain.hpp"
#include "engine/Window.hpp"
//clang-format: off
#include <tracy/TracyVulkan.hpp>
//clang-format: on
namespace fgl::engine
{
Renderer::Renderer( Window& window, PhysicalDevice& phy_device ) :
m_window( window ),
m_phy_device( phy_device ),
m_swapchain( std::make_unique< SwapChain >( m_window.getExtent(), m_phy_device ) )
{
recreateSwapchain();
createCommandBuffers();
}
Renderer::~Renderer()
{}
TracyVkCtx createContext( PhysicalDevice& physical_device, Device& device, vk::raii::CommandBuffer& cmd_buffer )
{
return TracyVkContext( *physical_device, *device, *device.graphicsQueue(), *cmd_buffer );
}
void Renderer::createCommandBuffers()
{
vk::CommandBufferAllocateInfo alloc_info {};
alloc_info.pNext = VK_NULL_HANDLE;
alloc_info.commandPool = Device::getInstance().getCommandPool();
alloc_info.level = vk::CommandBufferLevel::ePrimary;
alloc_info.commandBufferCount = SwapChain::MAX_FRAMES_IN_FLIGHT;
m_command_buffer = Device::getInstance().device().allocateCommandBuffers( alloc_info );
#if TRACY_ENABLE
m_tracy_ctx = createContext( m_phy_device, Device::getInstance(), m_command_buffer[ 0 ] );
/*
m_tracy_ctx = TracyVkContextCalibrated(
phy_dev,
dev,
Device::getInstance().graphicsQueue(),
m_command_buffer[ 0 ],
VULKAN_HPP_DEFAULT_DISPATCHER.vkGetPhysicalDeviceCalibrateableTimeDomainsEXT,
VULKAN_HPP_DEFAULT_DISPATCHER.vkGetCalibratedTimestampsEXT );
*/
#endif
alloc_info.level = vk::CommandBufferLevel::eSecondary;
m_gui_command_buffer = Device::getInstance()->allocateCommandBuffers( alloc_info );
}
void Renderer::recreateSwapchain()
{
ZoneScoped;
std::cout << "Rebuilding swap chain" << std::endl;
auto extent { m_window.getExtent() };
while ( extent.width == 0 || extent.height == 0 )
{
extent = m_window.getExtent();
glfwWaitEvents();
}
Device::getInstance().device().waitIdle();
if ( m_swapchain == nullptr )
m_swapchain = std::make_unique< SwapChain >( extent, m_phy_device );
else
{
std::shared_ptr< SwapChain > old_swap_chain { std::move( m_swapchain ) };
m_swapchain = std::make_unique< SwapChain >( extent, old_swap_chain );
if ( !old_swap_chain->compareSwapFormats( *m_swapchain.get() ) )
throw std::runtime_error( "Swap chain image(or depth) format has changed!" );
}
}
std::pair< vk::raii::CommandBuffer&, vk::raii::CommandBuffer& > Renderer::beginFrame()
{
assert( !is_frame_started && "Cannot begin frame while frame is already in progress" );
auto [ result, present_index ] = m_swapchain->acquireNextImage();
current_present_index = present_index;
if ( result == vk::Result::eErrorOutOfDateKHR )
{
recreateSwapchain();
}
if ( result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR )
throw std::runtime_error( "Failed to acquire swap chain image" );
is_frame_started = true;
auto& command_buffer { getCurrentCommandbuffer() };
auto& gui_command_buffer { getCurrentGuiCommandBuffer() };
vk::CommandBufferBeginInfo begin_info {};
begin_info.pNext = VK_NULL_HANDLE;
//begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
begin_info.pInheritanceInfo = VK_NULL_HANDLE;
command_buffer.begin( begin_info );
vk::CommandBufferInheritanceInfo inheritance_info {};
inheritance_info.framebuffer =
this->getSwapChain().getFrameBuffer( current_frame_index, current_present_index );
inheritance_info.renderPass = this->getSwapChainRenderPass();
inheritance_info.subpass = 2;
vk::CommandBufferBeginInfo gui_begin_info {};
gui_begin_info.pInheritanceInfo = &inheritance_info;
gui_begin_info.flags = vk::CommandBufferUsageFlagBits::eRenderPassContinue;
gui_command_buffer.begin( gui_begin_info );
setViewport( gui_command_buffer );
setScissor( gui_command_buffer );
return { command_buffer, gui_command_buffer };
}
void Renderer::endFrame()
{
ZoneScopedN( "Ending frame" );
assert( is_frame_started && "Cannot call end frame while frame is not in progress" );
auto& command_buffer { getCurrentCommandbuffer() };
command_buffer.end();
const auto result { m_swapchain->submitCommandBuffers( command_buffer, current_present_index ) };
if ( result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR
|| m_window.wasWindowResized() )
{
m_window.resetWindowResizedFlag();
recreateSwapchain();
}
else if ( result != vk::Result::eSuccess )
throw std::runtime_error( "Failed to submit commmand buffer" );
is_frame_started = false;
current_frame_index =
static_cast< std::uint16_t >( ( current_frame_index + 1 ) % SwapChain::MAX_FRAMES_IN_FLIGHT );
}
void Renderer::setViewport( const vk::raii::CommandBuffer& buffer )
{
vk::Viewport viewport {};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast< float >( m_swapchain->getSwapChainExtent().width );
viewport.height = static_cast< float >( m_swapchain->getSwapChainExtent().height );
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
std::vector< vk::Viewport > viewports { viewport };
buffer.setViewport( 0, viewports );
}
void Renderer::setScissor( const vk::raii::CommandBuffer& buffer )
{
vk::Rect2D scissor { { 0, 0 }, m_swapchain->getSwapChainExtent() };
std::vector< vk::Rect2D > scissors { scissor };
buffer.setScissor( 0, scissors );
}
void Renderer::beginSwapchainRendererPass( vk::raii::CommandBuffer& buffer )
{
assert( is_frame_started && "Cannot call beginSwapChainRenderPass if frame is not in progress" );
std::vector< vk::ClearValue > clear_values { m_swapchain->getClearValues() };
vk::RenderPassBeginInfo render_pass_info {};
render_pass_info.pNext = VK_NULL_HANDLE;
render_pass_info.renderPass = m_swapchain->getRenderPass();
render_pass_info.framebuffer = m_swapchain->getFrameBuffer( current_frame_index, current_present_index );
render_pass_info.renderArea = { .offset = { 0, 0 }, .extent = m_swapchain->getSwapChainExtent() };
render_pass_info.clearValueCount = static_cast< std::uint32_t >( clear_values.size() );
render_pass_info.pClearValues = clear_values.data();
buffer.beginRenderPass( render_pass_info, vk::SubpassContents::eInline );
setViewport( buffer );
setScissor( buffer );
}
void Renderer::endSwapchainRendererPass( vk::raii::CommandBuffer& buffer )
{
assert( is_frame_started && "Cannot call endSwapChainRenderPass if frame is not in progress" );
buffer.endRenderPass();
}
} // namespace fgl::engine