Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 128 additions & 92 deletions src/vulkan/FrameManager.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#include "FrameManager.hpp"

#include <stdexcept>
#include <vector>
#include <array>
#include <stdexcept>
#include <vector>

namespace reactor {

Expand All @@ -17,39 +18,46 @@ FrameManager::FrameManager(vk::Device device, Allocator& allocator, uint32_t com
m_commandPool = m_device.createCommandPool(poolInfo);

// Allocate per-frame resources
m_frames.resize(maxFramesInFlight);
for (auto& frame : m_frames) {
vk::CommandBufferAllocateInfo allocInfo{
m_commandPool,
vk::CommandBufferLevel::ePrimary,
1
};
frame.commandBuffer = m_device.allocateCommandBuffers(allocInfo)[0];
vk::FenceCreateInfo fenceInfo{vk::FenceCreateFlagBits::eSignaled};
frame.inFlightFence = m_device.createFence(fenceInfo);

// create a uniform buffer
frame.uniformBuffer = std::make_unique<Buffer>(allocator, 1024, vk::BufferUsageFlagBits::eUniformBuffer, VMA_MEMORY_USAGE_CPU_ONLY);
}

vk::SemaphoreCreateInfo semaphoreInfo{};

m_imageAvailableSemaphores.resize(maxFramesInFlight);
for (size_t i = 0; i < maxFramesInFlight; i++) {
m_imageAvailableSemaphores[i] = m_device.createSemaphore(semaphoreInfo);
}

m_renderFinishedSemaphores.resize(swapchainImageCount);
for (size_t i = 0; i < swapchainImageCount; i++) {
m_renderFinishedSemaphores[i] = m_device.createSemaphore(semaphoreInfo);
}

m_imagesInFlight.resize(swapchainImageCount, VK_NULL_HANDLE);

}

FrameManager::~FrameManager() {
spdlog::info("Destroying FrameManager and cleaning up resources.");
m_frames.resize(maxFramesInFlight);
for (auto& frame : m_frames) {
vk::CommandBufferAllocateInfo allocInfo{
m_commandPool,
vk::CommandBufferLevel::ePrimary,
1
};
frame.commandBuffer = m_device.allocateCommandBuffers(allocInfo)[0];

// create a uniform buffer
frame.uniformBuffer = std::make_unique<Buffer>(allocator, 1024, vk::BufferUsageFlagBits::eUniformBuffer, VMA_MEMORY_USAGE_CPU_ONLY);
}

vk::SemaphoreCreateInfo semaphoreInfo{};

m_imageAvailableSemaphores.resize(maxFramesInFlight);
for (size_t i = 0; i < maxFramesInFlight; i++) {
m_imageAvailableSemaphores[i] = m_device.createSemaphore(semaphoreInfo);
}

m_renderFinishedSemaphores.resize(swapchainImageCount);
for (size_t i = 0; i < swapchainImageCount; i++) {
m_renderFinishedSemaphores[i] = m_device.createSemaphore(semaphoreInfo);
}

vk::SemaphoreTypeCreateInfo timelineCreateInfo{};
timelineCreateInfo.semaphoreType = vk::SemaphoreType::eTimeline;
timelineCreateInfo.initialValue = 0;

vk::SemaphoreCreateInfo timelineSemaphoreInfo{};
timelineSemaphoreInfo.pNext = &timelineCreateInfo;

m_renderTimelineSemaphore = m_device.createSemaphore(timelineSemaphoreInfo);

m_imagesInFlight.resize(swapchainImageCount, 0);

}

FrameManager::~FrameManager() {
spdlog::info("Destroying FrameManager and cleaning up resources.");

for (auto& semaphore : m_imageAvailableSemaphores) {
m_device.destroySemaphore(semaphore);
Expand All @@ -59,27 +67,37 @@ FrameManager::~FrameManager() {
m_device.destroySemaphore(semaphore);
}

for (auto& frame : m_frames) {
if (frame.inFlightFence) {
m_device.destroyFence(frame.inFlightFence);
}
}

if (m_commandPool) {
m_device.destroyCommandPool(m_commandPool);
}
}

bool FrameManager::beginFrame(vk::SwapchainKHR swapchain, uint32_t& outImageIndex) {
vk::Result result = m_device.waitForFences(m_frames[m_currentFrame].inFlightFence, VK_TRUE, UINT64_MAX);
if (result != vk::Result::eSuccess) {
throw std::runtime_error("Failed to wait for fence!");
}

auto resultValue = m_device.acquireNextImageKHR(
swapchain,
UINT64_MAX,
m_imageAvailableSemaphores[m_currentFrame],
if (m_renderTimelineSemaphore) {
m_device.destroySemaphore(m_renderTimelineSemaphore);
}

if (m_commandPool) {
m_device.destroyCommandPool(m_commandPool);
}
}

bool FrameManager::beginFrame(vk::SwapchainKHR swapchain, uint32_t& outImageIndex) {
Frame& frame = m_frames[m_currentFrame];

if (frame.timelineValue > 0) {
uint64_t waitValue = frame.timelineValue;
vk::SemaphoreWaitInfo waitInfo{};
waitInfo.semaphoreCount = 1;
waitInfo.pSemaphores = &m_renderTimelineSemaphore;
waitInfo.pValues = &waitValue;

vk::Result result = m_device.waitSemaphores(waitInfo, UINT64_MAX);
if (result != vk::Result::eSuccess) {
throw std::runtime_error("Failed to wait for timeline semaphore!");
}

frame.timelineValue = 0;
}

auto resultValue = m_device.acquireNextImageKHR(
swapchain,
UINT64_MAX,
m_imageAvailableSemaphores[m_currentFrame],
VK_NULL_HANDLE
);

Expand All @@ -90,42 +108,60 @@ bool FrameManager::beginFrame(vk::SwapchainKHR swapchain, uint32_t& outImageInde
throw std::runtime_error("Failed to acquire swapchain image!");
}

outImageIndex = resultValue.value;

if (m_imagesInFlight[outImageIndex] != VK_NULL_HANDLE) {
auto ret = m_device.waitForFences(m_imagesInFlight[outImageIndex], VK_TRUE, UINT64_MAX);
if (ret != vk::Result::eSuccess)
{
throw std::runtime_error("Failed to wait for fence!");
}
}

// Associate the current frame's fence with the acquired swapchain image
m_imagesInFlight[outImageIndex] = m_frames[m_currentFrame].inFlightFence;

m_device.resetFences(m_frames[m_currentFrame].inFlightFence);

return true;
}

void FrameManager::endFrame(vk::Queue graphicsQueue, vk::Queue presentQueue, vk::SwapchainKHR swapchain, uint32_t imageIndex) {
Frame& frame = m_frames[m_currentFrame];

vk::PipelineStageFlags waitStages = vk::PipelineStageFlagBits::eColorAttachmentOutput;

vk::SubmitInfo submitInfo{
1, &m_imageAvailableSemaphores[m_currentFrame],
&waitStages,
1, &frame.commandBuffer,
1, &m_renderFinishedSemaphores[imageIndex]
};

graphicsQueue.submit(submitInfo, frame.inFlightFence);

vk::PresentInfoKHR presentInfo{
1, &m_renderFinishedSemaphores[imageIndex],
1, &swapchain,
&imageIndex
outImageIndex = resultValue.value;

if (m_imagesInFlight[outImageIndex] > 0) {
uint64_t waitValue = m_imagesInFlight[outImageIndex];
vk::SemaphoreWaitInfo waitInfo{};
waitInfo.semaphoreCount = 1;
waitInfo.pSemaphores = &m_renderTimelineSemaphore;
waitInfo.pValues = &waitValue;

vk::Result result = m_device.waitSemaphores(waitInfo, UINT64_MAX);
if (result != vk::Result::eSuccess) {
throw std::runtime_error("Failed to wait for timeline semaphore!");
}

m_imagesInFlight[outImageIndex] = 0;
}

return true;
}

void FrameManager::endFrame(vk::Queue graphicsQueue, vk::Queue presentQueue, vk::SwapchainKHR swapchain, uint32_t imageIndex) {
Frame& frame = m_frames[m_currentFrame];

vk::PipelineStageFlags waitStages = vk::PipelineStageFlagBits::eColorAttachmentOutput;

std::array<vk::Semaphore, 2> signalSemaphores{m_renderFinishedSemaphores[imageIndex], m_renderTimelineSemaphore};

vk::SubmitInfo submitInfo{
1, &m_imageAvailableSemaphores[m_currentFrame],
&waitStages,
1, &frame.commandBuffer,
static_cast<uint32_t>(signalSemaphores.size()), signalSemaphores.data()
};

uint64_t waitValues[] = {0};
std::array<uint64_t, 2> signalValues{0, ++m_nextTimelineValue};

vk::TimelineSemaphoreSubmitInfo timelineInfo{};
timelineInfo.waitSemaphoreValueCount = 1;
timelineInfo.pWaitSemaphoreValues = waitValues;
timelineInfo.signalSemaphoreValueCount = static_cast<uint32_t>(signalValues.size());
timelineInfo.pSignalSemaphoreValues = signalValues.data();

submitInfo.pNext = &timelineInfo;

graphicsQueue.submit(submitInfo, vk::Fence());

frame.timelineValue = signalValues.back();
m_imagesInFlight[imageIndex] = frame.timelineValue;

vk::PresentInfoKHR presentInfo{
1, &m_renderFinishedSemaphores[imageIndex],
1, &swapchain,
&imageIndex
};

vk::Result result = presentQueue.presentKHR(presentInfo);
Expand Down
29 changes: 17 additions & 12 deletions src/vulkan/FrameManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@
#ifndef FRAMEMANAGER_HPP
#define FRAMEMANAGER_HPP

#include <vulkan/vulkan.hpp>

#include "buffer.h"
#include <cstdint>
#include <memory>
#include <vector>
#include <vulkan/vulkan.hpp>

#include "buffer.h"

namespace reactor {
// Using the Frame struct from our previous discussion
struct Frame {
vk::CommandBuffer commandBuffer;
vk::Fence inFlightFence;
vk::DescriptorSet cameraDescriptorSet;
std::unique_ptr<Buffer> uniformBuffer;
};
struct Frame {
vk::CommandBuffer commandBuffer;
uint64_t timelineValue = 0;
vk::DescriptorSet cameraDescriptorSet;
std::unique_ptr<Buffer> uniformBuffer;
};

class FrameManager {
public:
Expand All @@ -42,9 +45,11 @@ namespace reactor {
vk::Device m_device;
vk::CommandPool m_commandPool;
std::vector<Frame> m_frames;
std::vector<vk::Semaphore> m_imageAvailableSemaphores;
std::vector<vk::Semaphore> m_renderFinishedSemaphores;
std::vector<vk::Fence> m_imagesInFlight;
std::vector<vk::Semaphore> m_imageAvailableSemaphores;
std::vector<vk::Semaphore> m_renderFinishedSemaphores;
vk::Semaphore m_renderTimelineSemaphore;
std::vector<uint64_t> m_imagesInFlight;
uint64_t m_nextTimelineValue = 0;
size_t m_currentFrame;
size_t m_framesInFlightCount;
};
Expand Down
20 changes: 12 additions & 8 deletions src/vulkan/VulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,18 @@ void VulkanContext::createLogicalDevice() {

vk::PhysicalDeviceFeatures deviceFeatures{}; // No special features for now

vk::PhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures{};
dynamicRenderingFeatures.dynamicRendering = VK_TRUE;

// create struct for Vulkan 1.1 features
vk::PhysicalDeviceVulkan11Features vulkan11Features{};
vulkan11Features.shaderDrawParameters = VK_TRUE;

dynamicRenderingFeatures.pNext = &vulkan11Features;
vk::PhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures{};
dynamicRenderingFeatures.dynamicRendering = VK_TRUE;

// create struct for Vulkan 1.1 features
vk::PhysicalDeviceVulkan11Features vulkan11Features{};
vulkan11Features.shaderDrawParameters = VK_TRUE;

vk::PhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreFeatures{};
timelineSemaphoreFeatures.timelineSemaphore = VK_TRUE;

dynamicRenderingFeatures.pNext = &timelineSemaphoreFeatures;
timelineSemaphoreFeatures.pNext = &vulkan11Features;

std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
Expand Down