Refactor Frames into util.
This commit is contained in:
parent
b48fb3168d
commit
52b3c671c6
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
add_library(util_helper STATIC helpers.h helpers.cpp)
|
||||
add_library(util_helper STATIC
|
||||
helpers.h
|
||||
helpers.cpp
|
||||
frame.cpp
|
||||
frame.h)
|
||||
|
||||
target_link_libraries(util_helper PRIVATE aster_core)
|
||||
target_include_directories(util_helper PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
// =============================================
|
||||
// Aster: frame.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "frame.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "helpers.h"
|
||||
#include "swapchain.h"
|
||||
|
||||
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
||||
: m_FrameIdx(0)
|
||||
, m_ImageIdx(0)
|
||||
{
|
||||
m_Device = device;
|
||||
|
||||
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));
|
||||
|
||||
DEBUG("Frame {} created successfully.", frameCount);
|
||||
}
|
||||
|
||||
void
|
||||
Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Window *window)
|
||||
{
|
||||
|
||||
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:
|
||||
INFO("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain->Create(window);
|
||||
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 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 Window *window)
|
||||
{
|
||||
|
||||
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;
|
||||
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:
|
||||
INFO("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain->Create(window);
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// =============================================
|
||||
// Aster: frame.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <EASTL/fixed_vector.h>
|
||||
|
||||
struct Device;
|
||||
struct Window;
|
||||
struct Swapchain;
|
||||
|
||||
struct Frame
|
||||
{
|
||||
// Persistent
|
||||
const Device *m_Device;
|
||||
vk::CommandPool m_Pool;
|
||||
vk::CommandBuffer m_CommandBuffer;
|
||||
vk::Fence m_FrameAvailableFence;
|
||||
vk::Semaphore m_ImageAcquireSem;
|
||||
vk::Semaphore m_RenderFinishSem;
|
||||
u32 m_FrameIdx;
|
||||
|
||||
// Transient
|
||||
u32 m_ImageIdx;
|
||||
|
||||
void Present(vk::Queue commandQueue, Swapchain *swapchain, const Window *window);
|
||||
|
||||
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
||||
~Frame();
|
||||
};
|
||||
|
||||
struct FrameManager
|
||||
{
|
||||
const Device *m_Device;
|
||||
eastl::fixed_vector<Frame, 4> m_Frames{};
|
||||
u32 m_CurrentFrameIdx = 0;
|
||||
u32 m_FramesInFlight = 0;
|
||||
|
||||
FrameManager(const Device *device, u32 queueFamilyIndex, u32 framesInFlight);
|
||||
|
||||
Frame *GetNextFrame(Swapchain *swapchain, const Window *window);
|
||||
};
|
||||
|
|
@ -16,4 +16,27 @@ class PhysicalDevices;
|
|||
|
||||
PhysicalDevice FindSuitableDevice(const PhysicalDevices &physicalDevices);
|
||||
QueueAllocation FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice);
|
||||
eastl::vector<u32> ReadFile(cstr fileName);
|
||||
eastl::vector<u32> ReadFile(cstr fileName);
|
||||
|
||||
#define AbortIfFailed(RESULT) \
|
||||
do \
|
||||
{ \
|
||||
vk::Result _checkResultValue_; \
|
||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
|
||||
THEN_ABORT(_checkResultValue_); \
|
||||
} while (false)
|
||||
|
||||
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
|
||||
do \
|
||||
{ \
|
||||
vk::Result _checkResultValue_; \
|
||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \
|
||||
THEN_ABORT(_checkResultValue_); \
|
||||
} while (false)
|
||||
|
||||
#define AbortIfFailedM(RESULT, MSG) \
|
||||
do \
|
||||
{ \
|
||||
auto _checkResultValue_ = Cast<vk::Result>(RESULT); \
|
||||
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
||||
} while (false)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "helpers.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "frame.h"
|
||||
#include "image.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
|
|
@ -25,29 +26,6 @@ constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
|||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv";
|
||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv";
|
||||
|
||||
#define AbortIfFailed(RESULT) \
|
||||
do \
|
||||
{ \
|
||||
vk::Result _checkResultValue_; \
|
||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
|
||||
THEN_ABORT(_checkResultValue_); \
|
||||
} while (false)
|
||||
|
||||
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
|
||||
do \
|
||||
{ \
|
||||
vk::Result _checkResultValue_; \
|
||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \
|
||||
THEN_ABORT(_checkResultValue_); \
|
||||
} while (false)
|
||||
|
||||
#define AbortIfFailedM(RESULT, MSG) \
|
||||
do \
|
||||
{ \
|
||||
auto _checkResultValue_ = Cast<vk::Result>(RESULT); \
|
||||
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
||||
} while (false)
|
||||
|
||||
struct ImageFile
|
||||
{
|
||||
void *m_Data = nullptr;
|
||||
|
|
@ -56,7 +34,7 @@ struct ImageFile
|
|||
u32 m_NumChannels = 0;
|
||||
|
||||
bool Load(cstr fileName);
|
||||
usize GetSize() const;
|
||||
[[nodiscard]] usize GetSize() const;
|
||||
~ImageFile();
|
||||
};
|
||||
|
||||
|
|
@ -132,19 +110,6 @@ struct Camera
|
|||
mat4 m_Perspective;
|
||||
};
|
||||
|
||||
struct Frame
|
||||
{
|
||||
const Device *m_Device;
|
||||
vk::CommandPool m_Pool;
|
||||
vk::CommandBuffer m_CommandBuffer;
|
||||
vk::Fence m_FrameAvailableFence;
|
||||
vk::Semaphore m_ImageAcquireSem;
|
||||
vk::Semaphore m_RenderFinishSem;
|
||||
|
||||
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
||||
~Frame();
|
||||
};
|
||||
|
||||
int
|
||||
main(int, char **)
|
||||
{
|
||||
|
|
@ -484,48 +449,26 @@ main(int, char **)
|
|||
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
||||
}
|
||||
|
||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||
|
||||
Time::Init();
|
||||
|
||||
INFO("Starting loop");
|
||||
u32 frameIndex = 0;
|
||||
while (window.Poll())
|
||||
{
|
||||
Frame *currentFrame = &frames[frameIndex];
|
||||
Time::Update();
|
||||
|
||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||
|
||||
AbortIfFailedMV(device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, true, MaxValue<u64>),
|
||||
"Waiting for fence {} failed.", frameIndex);
|
||||
|
||||
u32 imageIndex;
|
||||
auto result = device.m_Device.acquireNextImageKHR(swapchain.m_Swapchain, MaxValue<u64>,
|
||||
currentFrame->m_ImageAcquireSem, nullptr, &imageIndex);
|
||||
if (Failed(result))
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case vk::Result::eErrorOutOfDateKHR:
|
||||
case vk::Result::eSuboptimalKHR:
|
||||
INFO("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain.Create(&window);
|
||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||
scissor.extent = swapchain.m_Extent;
|
||||
continue; // 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(device.m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence), "Fence {} reset failed.",
|
||||
frameIndex);
|
||||
|
||||
AbortIfFailedMV(device.m_Device.resetCommandPool(currentFrame->m_Pool, {}), "Command pool {} reset failed.",
|
||||
frameIndex);
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||
scissor.extent = swapchain.m_Extent;
|
||||
|
||||
// Frame *currentFrame = &frames[frameIndex];
|
||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
||||
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
||||
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
||||
|
|
@ -585,33 +528,7 @@ main(int, char **)
|
|||
};
|
||||
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||
|
||||
vk::PresentInfoKHR presentInfo = {
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = ¤tFrame->m_RenderFinishSem,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain.m_Swapchain,
|
||||
.pImageIndices = &imageIndex,
|
||||
.pResults = nullptr,
|
||||
};
|
||||
result = commandQueue.presentKHR(&presentInfo);
|
||||
if (Failed(result))
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case vk::Result::eErrorOutOfDateKHR:
|
||||
case vk::Result::eSuboptimalKHR:
|
||||
INFO("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain.Create(&window);
|
||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||
scissor.extent = swapchain.m_Extent;
|
||||
break; // Present failed. We redo the frame.
|
||||
default:
|
||||
AbortIfFailedM(result, "Swapchain Present failed.");
|
||||
}
|
||||
}
|
||||
frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
currentFrame->Present(commandQueue, &swapchain, &window);
|
||||
}
|
||||
|
||||
AbortIfFailed(device.m_Device.waitIdle());
|
||||
|
|
@ -627,38 +544,6 @@ main(int, char **)
|
|||
return 0;
|
||||
}
|
||||
|
||||
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
||||
{
|
||||
m_Device = device;
|
||||
|
||||
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));
|
||||
|
||||
DEBUG("Frame {} created successfully.", frameCount);
|
||||
}
|
||||
|
||||
Pipeline
|
||||
CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||
{
|
||||
|
|
@ -818,14 +703,4 @@ CreateShader(const Device *device, cstr shaderFile)
|
|||
AbortIfFailedMV(device->m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule),
|
||||
"Shader {} could not be created.", shaderFile);
|
||||
return shaderModule;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
Loading…
Reference in New Issue