175 lines
6.2 KiB
C++
175 lines
6.2 KiB
C++
// =============================================
|
|
// Aster: frame.cpp
|
|
// Copyright (c) 2020-2024 Anish Bhobe
|
|
// =============================================
|
|
|
|
#include "frame.h"
|
|
|
|
#include "aster/core/device.h"
|
|
#include "aster/core/swapchain.h"
|
|
|
|
#include "helpers.h"
|
|
|
|
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
|
: m_FrameIdx(frameCount)
|
|
, m_ImageIdx(0)
|
|
{
|
|
m_Device = device;
|
|
|
|
eastl::fixed_string<char, 50, false> name = "Frame ";
|
|
name += Cast<char>('0' + frameCount);
|
|
const vk::CommandPoolCreateInfo commandPoolCreateInfo = {
|
|
.flags = vk::CommandPoolCreateFlagBits::eTransient,
|
|
.queueFamilyIndex = queueFamilyIndex,
|
|
};
|
|
AbortIfFailedMV(device->m_Device.createCommandPool(&commandPoolCreateInfo, nullptr, &m_Pool),
|
|
"Could not command pool for frame {}", frameCount);
|
|
|
|
constexpr vk::FenceCreateInfo fenceCreateInfo = {.flags = vk::FenceCreateFlagBits::eSignaled};
|
|
AbortIfFailedMV(device->m_Device.createFence(&fenceCreateInfo, nullptr, &m_FrameAvailableFence),
|
|
"Could not create a fence for frame {}", frameCount);
|
|
|
|
constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo = {};
|
|
AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_ImageAcquireSem),
|
|
"Could not create IA semaphore for frame {}.", frameCount);
|
|
AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_RenderFinishSem),
|
|
"Could not create RF semaphore for frame {}.", frameCount);
|
|
|
|
const vk::CommandBufferAllocateInfo allocateInfo = {
|
|
.commandPool = m_Pool,
|
|
.level = vk::CommandBufferLevel::ePrimary,
|
|
.commandBufferCount = 1,
|
|
};
|
|
|
|
AbortIfFailed(m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer));
|
|
|
|
device->SetName(m_Pool, name.c_str());
|
|
device->SetName(m_FrameAvailableFence, name.c_str());
|
|
device->SetName(m_ImageAcquireSem, name.c_str());
|
|
device->SetName(m_RenderFinishSem, name.c_str());
|
|
device->SetName(m_CommandBuffer, name.c_str());
|
|
|
|
DEBUG("Frame {} created successfully.", frameCount);
|
|
}
|
|
|
|
void
|
|
Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Surface *surface, Size2D size)
|
|
{
|
|
|
|
vk::PresentInfoKHR presentInfo = {
|
|
.waitSemaphoreCount = 1,
|
|
.pWaitSemaphores = &m_RenderFinishSem,
|
|
.swapchainCount = 1,
|
|
.pSwapchains = &swapchain->m_Swapchain,
|
|
.pImageIndices = &m_ImageIdx,
|
|
.pResults = nullptr,
|
|
};
|
|
switch (auto result = commandQueue.presentKHR(&presentInfo))
|
|
{
|
|
case vk::Result::eSuccess:
|
|
break;
|
|
case vk::Result::eErrorOutOfDateKHR:
|
|
case vk::Result::eSuboptimalKHR:
|
|
DEBUG("Recreating Swapchain. Cause: {}", result);
|
|
swapchain->Create(surface, size);
|
|
break; // Present failed. We do nothing. Frame is skipped.
|
|
default:
|
|
AbortIfFailedM(result, "Swapchain Present failed.");
|
|
}
|
|
}
|
|
|
|
Frame::~Frame()
|
|
{
|
|
m_Device->m_Device.destroy(m_RenderFinishSem, nullptr);
|
|
m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr);
|
|
m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr);
|
|
m_Device->m_Device.destroy(m_Pool, nullptr);
|
|
|
|
DEBUG("Destoryed Frame");
|
|
}
|
|
|
|
Frame::Frame(Frame &&other) noexcept
|
|
: m_Device(other.m_Device)
|
|
, m_Pool(Take(other.m_Pool))
|
|
, m_CommandBuffer(Take(other.m_CommandBuffer))
|
|
, m_FrameAvailableFence(Take(other.m_FrameAvailableFence))
|
|
, m_ImageAcquireSem(Take(other.m_ImageAcquireSem))
|
|
, m_RenderFinishSem(Take(other.m_RenderFinishSem))
|
|
, m_FrameIdx(other.m_FrameIdx)
|
|
, m_ImageIdx(other.m_ImageIdx)
|
|
{
|
|
}
|
|
|
|
Frame &
|
|
Frame::operator=(Frame &&other) noexcept
|
|
{
|
|
if (this == &other)
|
|
return *this;
|
|
m_Device = other.m_Device;
|
|
m_Pool = Take(other.m_Pool);
|
|
m_CommandBuffer = Take(other.m_CommandBuffer);
|
|
m_FrameAvailableFence = Take(other.m_FrameAvailableFence);
|
|
m_ImageAcquireSem = Take(other.m_ImageAcquireSem);
|
|
m_RenderFinishSem = Take(other.m_RenderFinishSem);
|
|
m_FrameIdx = other.m_FrameIdx;
|
|
m_ImageIdx = other.m_ImageIdx;
|
|
return *this;
|
|
}
|
|
|
|
// Frame Manager
|
|
|
|
FrameManager::FrameManager(const Device *device, u32 queueFamilyIndex, u32 framesInFlight)
|
|
: m_Device(device)
|
|
, m_FramesInFlight(framesInFlight)
|
|
{
|
|
for (u32 i = 0; i < framesInFlight; ++i)
|
|
{
|
|
m_Frames.emplace_back(device, queueFamilyIndex, i);
|
|
}
|
|
}
|
|
|
|
Frame *
|
|
FrameManager::GetNextFrame(Swapchain *swapchain, const Surface *surface, Size2D size)
|
|
{
|
|
|
|
Frame *currentFrame = &m_Frames[m_CurrentFrameIdx];
|
|
u32 frameIndex = m_CurrentFrameIdx;
|
|
|
|
m_CurrentFrameIdx = (m_CurrentFrameIdx + 1) % m_FramesInFlight;
|
|
|
|
AbortIfFailedMV(m_Device->m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, true, MaxValue<u64>),
|
|
"Waiting for fence {} failed.", frameIndex);
|
|
|
|
u32 imageIndex = 0;
|
|
bool imageAcquired = false;
|
|
while (!imageAcquired)
|
|
{
|
|
auto result = m_Device->m_Device.acquireNextImageKHR(swapchain->m_Swapchain, MaxValue<u64>,
|
|
currentFrame->m_ImageAcquireSem, nullptr, &imageIndex);
|
|
switch (result)
|
|
{
|
|
case vk::Result::eSuccess:
|
|
case vk::Result::eSuboptimalKHR: // Suboptimal can still render. Better to let this go for semaphores etc.
|
|
imageAcquired = true;
|
|
break; // Image acquired. Break out of loop.
|
|
case vk::Result::eErrorOutOfDateKHR:
|
|
DEBUG("Recreating Swapchain. Cause: {}", result);
|
|
swapchain->Create(surface, size);
|
|
break; // Image acquire has failed. We move to the next frame.
|
|
default:
|
|
AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex);
|
|
}
|
|
}
|
|
|
|
// Reset fences here. In case swapchain was out of date, we leave the fences signalled.
|
|
AbortIfFailedMV(m_Device->m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence), "Fence {} reset failed.",
|
|
frameIndex);
|
|
|
|
AbortIfFailedMV(m_Device->m_Device.resetCommandPool(currentFrame->m_Pool, {}), "Command pool {} reset failed.",
|
|
frameIndex);
|
|
|
|
currentFrame->m_ImageIdx = imageIndex;
|
|
|
|
return currentFrame;
|
|
}
|