Allow to have multiple frames in flight
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
#include "hk21/game/gpu.hpp"
|
||||
|
||||
#include <asl/containers/buffer.hpp>
|
||||
#include <asl/containers/intrusive_list.hpp>
|
||||
#include <asl/formatting/format.hpp>
|
||||
#include <asl/types/option.hpp>
|
||||
#include <asl/logging/logging.hpp>
|
||||
@ -258,6 +259,12 @@ static asl::status_or<VkDevice> create_device(VkPhysicalDevice physical_device,
|
||||
return device;
|
||||
}
|
||||
|
||||
struct FrameResources : asl::intrusive_list_node<FrameResources>
|
||||
{
|
||||
VkFence complete_fence;
|
||||
VkCommandPool command_pool;
|
||||
};
|
||||
|
||||
class GpuImpl : public Gpu
|
||||
{
|
||||
bool m_destroyed{};
|
||||
@ -272,6 +279,12 @@ class GpuImpl : public Gpu
|
||||
asl::option<VkSwapchainKHR> m_swapchain;
|
||||
asl::buffer<VkImage> m_swapchain_images;
|
||||
|
||||
VkSemaphore m_swapchain_image_acquire_semaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore m_queue_complete_semaphore = VK_NULL_HANDLE;
|
||||
|
||||
asl::GlobalHeap m_allocator; // @Todo Make this configurable
|
||||
asl::IntrusiveList<FrameResources> m_in_flight_frames;
|
||||
|
||||
public:
|
||||
GpuImpl(
|
||||
VkInstance instance,
|
||||
@ -286,6 +299,8 @@ public:
|
||||
, m_queue_family_index{queue_family_index}
|
||||
, m_device{device}
|
||||
, m_queue{queue}
|
||||
, m_swapchain_image_acquire_semaphore{create_semaphore()}
|
||||
, m_queue_complete_semaphore{create_semaphore()}
|
||||
{
|
||||
}
|
||||
|
||||
@ -300,6 +315,13 @@ public:
|
||||
{
|
||||
ASL_ASSERT(!m_destroyed);
|
||||
m_destroyed = true;
|
||||
|
||||
vkDeviceWaitIdle(m_device);
|
||||
|
||||
recycle_resources();
|
||||
|
||||
destroy_semaphore(m_swapchain_image_acquire_semaphore);
|
||||
destroy_semaphore(m_queue_complete_semaphore);
|
||||
|
||||
if (m_swapchain.has_value())
|
||||
{
|
||||
@ -417,21 +439,54 @@ public:
|
||||
return asl::ok();
|
||||
}
|
||||
|
||||
asl::status frame_opt()
|
||||
VkSemaphore create_semaphore()
|
||||
{
|
||||
VkSemaphoreCreateInfo semaphore_create_info{
|
||||
static constexpr VkSemaphoreCreateInfo semaphore_create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
VkSemaphore acquire_semaphore{};
|
||||
VkSemaphore queue_semaphore{};
|
||||
vkCreateSemaphore(m_device, &semaphore_create_info, VK_ALLOCATOR, &acquire_semaphore);
|
||||
vkCreateSemaphore(m_device, &semaphore_create_info, VK_ALLOCATOR, &queue_semaphore);
|
||||
VkSemaphore semaphore{};
|
||||
vkCreateSemaphore(m_device, &semaphore_create_info, VK_ALLOCATOR, &semaphore);
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
void destroy_semaphore(VkSemaphore semaphore)
|
||||
{
|
||||
vkDestroySemaphore(m_device, semaphore, VK_ALLOCATOR);
|
||||
}
|
||||
|
||||
VkFence create_fence()
|
||||
{
|
||||
static constexpr VkFenceCreateInfo fence_create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
VkFence fence{};
|
||||
vkCreateFence(m_device, &fence_create_info, VK_ALLOCATOR, &fence);
|
||||
return fence;
|
||||
}
|
||||
|
||||
void destroy_fence(VkFence fence)
|
||||
{
|
||||
vkDestroyFence(m_device, fence, VK_ALLOCATOR);
|
||||
}
|
||||
|
||||
asl::status frame_opt()
|
||||
{
|
||||
uint32_t image_index{};
|
||||
VkResult res = vkAcquireNextImageKHR(m_device, m_swapchain.value(), 0xffff'ffff'ffff'ffffLLU, acquire_semaphore, VK_NULL_HANDLE, &image_index);
|
||||
|
||||
VkResult res = vkAcquireNextImageKHR(
|
||||
m_device,
|
||||
m_swapchain.value(),
|
||||
0xffff'ffff'ffff'ffffLLU,
|
||||
m_swapchain_image_acquire_semaphore,
|
||||
VK_NULL_HANDLE,
|
||||
&image_index);
|
||||
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
return asl::runtime_error("Couldn't acquire swapchain image: {}", res);
|
||||
@ -543,19 +598,21 @@ public:
|
||||
|
||||
VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
||||
VkFence fence = create_fence();
|
||||
|
||||
VkSubmitInfo submit_info{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = nullptr,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &acquire_semaphore,
|
||||
.pWaitSemaphores = &m_swapchain_image_acquire_semaphore,
|
||||
.pWaitDstStageMask = &wait_dst_stage_mask,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &command_buffer,
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = &queue_semaphore,
|
||||
.pSignalSemaphores = &m_queue_complete_semaphore,
|
||||
};
|
||||
|
||||
res = vkQueueSubmit(m_queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||
res = vkQueueSubmit(m_queue, 1, &submit_info, fence);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
return asl::runtime_error("Couldn't submit queue: {}", res);
|
||||
@ -565,7 +622,7 @@ public:
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &queue_semaphore,
|
||||
.pWaitSemaphores = &m_queue_complete_semaphore,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &m_swapchain.value(),
|
||||
.pImageIndices = &image_index,
|
||||
@ -578,20 +635,52 @@ public:
|
||||
return asl::runtime_error("Couldn't present queue: {}", res);
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(m_device);
|
||||
vkDestroySemaphore(m_device, acquire_semaphore, VK_ALLOCATOR);
|
||||
vkDestroySemaphore(m_device, queue_semaphore, VK_ALLOCATOR);
|
||||
vkDestroyCommandPool(m_device, command_pool, VK_ALLOCATOR);
|
||||
auto* frame_resources = asl::alloc_new<FrameResources>(m_allocator);
|
||||
frame_resources->command_pool = command_pool;
|
||||
frame_resources->complete_fence = fence;
|
||||
|
||||
m_in_flight_frames.push_front(frame_resources);
|
||||
|
||||
return asl::ok();
|
||||
}
|
||||
|
||||
// @Todo Make fences recyclable
|
||||
// @Todo Make frame structure recyclable
|
||||
|
||||
void recycle_resources()
|
||||
{
|
||||
while (!m_in_flight_frames.is_empty())
|
||||
{
|
||||
auto* frame = m_in_flight_frames.tail();
|
||||
auto status = vkGetFenceStatus(m_device, frame->complete_fence);
|
||||
|
||||
if (status == VK_NOT_READY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
{
|
||||
ASL_LOG_ERROR("Error on frame fence query: {}", status);
|
||||
return;
|
||||
}
|
||||
|
||||
destroy_fence(frame->complete_fence);
|
||||
vkDestroyCommandPool(m_device, frame->command_pool, VK_ALLOCATOR);
|
||||
|
||||
m_in_flight_frames.pop_back();
|
||||
asl::alloc_delete(m_allocator, frame);
|
||||
}
|
||||
}
|
||||
|
||||
void frame() override
|
||||
{
|
||||
recycle_resources();
|
||||
|
||||
auto s = frame_opt();
|
||||
if (!s.ok())
|
||||
{
|
||||
ASL_LOG_ERROR("{}", s);
|
||||
ASL_LOG_ERROR("Frame error: {}", s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -39,4 +39,8 @@
|
||||
FN(vkCreateSemaphore) \
|
||||
FN(vkDestroySemaphore) \
|
||||
FN(vkCmdPipelineBarrier) \
|
||||
FN(vkCmdClearColorImage)
|
||||
FN(vkCmdClearColorImage) \
|
||||
FN(vkCreateFence) \
|
||||
FN(vkDestroyFence) \
|
||||
FN(vkGetFenceStatus)
|
||||
|
||||
|
Reference in New Issue
Block a user