light/modules/renderer/private/backend/vk/renderer/renderer.cpp
light7734 ce26fe63e3
Some checks failed
continuous-integration/drone/pr Build is failing
feat: frame constants & camera component
2025-10-26 10:23:55 +03:30

203 lines
5.8 KiB
C++

#include <memory/reference.hpp>
#include <renderer/backend/vk/context/swapchain.hpp>
#include <renderer/backend/vk/renderer/renderer.hpp>
namespace lt::renderer::vk {
Renderer::Renderer(IDevice *device, ISwapchain *swapchain, uint32_t max_frames_in_flight)
: m_device(static_cast<Device *>(device))
, m_swapchain(static_cast<Swapchain *>(swapchain))
, m_resolution(m_swapchain->get_resolution())
, m_max_frames_in_flight(max_frames_in_flight)
{
ensure(m_device, "Failed to initialize renderer: null device");
ensure(m_swapchain, "Failed to initialize renderer: null swapchain");
// TODO(Light): HARDCODED PASS!!!
m_pass = memory::create_ref<vk::Pass>(
m_device,
m_swapchain,
assets::ShaderAsset { "./data/test_assets/triangle.vert.asset" },
assets::ShaderAsset { "./data/test_assets/triangle.frag.asset" }
);
m_pool = m_device->create_command_pool(
VkCommandPoolCreateInfo {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
.queueFamilyIndex = m_device->get_family_indices()[0],
}
);
m_cmds.resize(m_max_frames_in_flight);
m_cmds = m_device->allocate_command_buffers(
VkCommandBufferAllocateInfo {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = m_pool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = static_cast<uint32_t>(m_cmds.size()),
}
);
m_aquire_image_semaphores = m_device->create_semaphores(m_max_frames_in_flight);
m_frame_fences = m_device->create_fences(
VkFenceCreateInfo {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
},
m_max_frames_in_flight
);
for (auto idx = 0u;
auto [semaphore, fence] : std::views::zip(m_aquire_image_semaphores, m_frame_fences))
{
m_device->name(semaphore, "acquire image semaphore {}", idx);
m_device->name(fence, "frame fence {}", idx);
}
m_submit_semaphores = m_device->create_semaphores(m_swapchain->get_image_count());
for (auto idx = 0u; auto &semaphore : m_submit_semaphores)
{
m_device->name(semaphore, "submit semaphore {}", idx);
}
};
Renderer::~Renderer()
{
if (!m_device)
{
return;
}
m_device->wait_idle();
m_device->destroy_semaphores(m_aquire_image_semaphores);
m_device->destroy_semaphores(m_submit_semaphores);
m_device->destroy_fences(m_frame_fences);
m_device->destroy_command_pool(m_pool);
}
[[nodiscard]] auto Renderer::draw(uint32_t frame_idx) -> DrawResult
{
ensure(
frame_idx < m_max_frames_in_flight,
"Failed to draw: frame_idx >= max_frames_in_flight ({} >= {})",
frame_idx,
m_max_frames_in_flight
);
auto &frame_fence = m_frame_fences[frame_idx];
auto &aquire_semaphore = m_aquire_image_semaphores[frame_idx];
auto &cmd = m_cmds[frame_idx];
m_device->wait_for_fence(frame_fence);
auto image_idx = m_device->acquire_image(m_swapchain->vk(), aquire_semaphore);
if (!image_idx.has_value())
{
return {};
}
m_device->reset_fence(frame_fence);
vk_reset_command_buffer(cmd, {});
record_cmd(cmd, *image_idx);
auto wait_stage = VkPipelineStageFlags { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
auto &submit_semaphore = m_submit_semaphores[*image_idx];
m_device->submit(
VkSubmitInfo {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.waitSemaphoreCount = 1u,
.pWaitSemaphores = &aquire_semaphore,
.pWaitDstStageMask = &wait_stage,
.commandBufferCount = 1u,
.pCommandBuffers = &cmd,
.signalSemaphoreCount = 1u,
.pSignalSemaphores = &submit_semaphore,
},
frame_fence
);
// TODO(Light): handle result
auto result = VkResult {};
m_device->present(
VkPresentInfoKHR {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1u,
.pWaitSemaphores = &submit_semaphore,
.swapchainCount = 1u,
.pSwapchains = m_swapchain->vk_ptr(),
.pImageIndices = &image_idx.value(),
.pResults = &result,
}
);
return DrawResult::success;
}
void Renderer::replace_swapchain(ISwapchain *swapchain)
{
m_device->wait_idle();
m_swapchain = static_cast<Swapchain *>(swapchain);
m_resolution = m_swapchain->get_resolution();
m_pass->replace_swapchain(*swapchain);
}
void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
{
auto cmd_begin_info = VkCommandBufferBeginInfo {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = {},
.pInheritanceInfo = nullptr,
};
vkc(vk_begin_command_buffer(cmd, &cmd_begin_info));
vk_cmd_push_constants(
cmd,
m_pass->get_layout(),
VK_SHADER_STAGE_VERTEX_BIT,
0u,
sizeof(FrameConstants),
&m_frame_constants
);
auto clear_value = VkClearValue {
.color = {
0.93,
0.93,
0.93,
1.0,
},
};
auto pass_begin_info = VkRenderPassBeginInfo {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = m_pass->get_pass(),
.framebuffer = m_pass->get_framebuffers()[image_idx],
.renderArea = { .offset = {}, .extent = m_resolution },
.clearValueCount = 1u,
.pClearValues = &clear_value
};
vk_cmd_begin_render_pass(cmd, &pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
vk_cmd_bind_pipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pass->get_pipeline());
auto viewport = VkViewport {
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(m_resolution.width),
.height = static_cast<float>(m_resolution.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
vk_cmd_set_viewport(cmd, 0, 1, &viewport);
auto scissor = VkRect2D {
.offset = { .x = 0u, .y = 0u },
.extent = m_resolution,
};
vk_cmd_set_scissors(cmd, 0, 1, &scissor);
vk_cmd_draw(cmd, 3, 1, 0, 0);
vk_cmd_end_render_pass(cmd);
vkc(vk_end_command_buffer(cmd));
}
} // namespace lt::renderer::vk