summaryrefslogtreecommitdiff
path: root/hk21/game/gpu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hk21/game/gpu.cpp')
-rw-r--r--hk21/game/gpu.cpp121
1 files changed, 105 insertions, 16 deletions
diff --git a/hk21/game/gpu.cpp b/hk21/game/gpu.cpp
index 207ce85..4e0a65a 100644
--- a/hk21/game/gpu.cpp
+++ b/hk21/game/gpu.cpp
@@ -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);
}
}
};