diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-05-09 00:32:33 +0200 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-05-09 00:37:56 +0200 |
commit | 7ec394db8961009e6ac23fea909f8353d865f7a3 (patch) | |
tree | 6104b92652953ee84c3d6c4386a7cfd6f133bcd9 /hk21/game/gpu.cpp | |
parent | 69d33476b825a1f2deb4f9fb38a199c59d356701 (diff) |
Add and use Vulkan synchronization library
Diffstat (limited to 'hk21/game/gpu.cpp')
-rw-r--r-- | hk21/game/gpu.cpp | 170 |
1 files changed, 93 insertions, 77 deletions
diff --git a/hk21/game/gpu.cpp b/hk21/game/gpu.cpp index 0d74559..a929e1a 100644 --- a/hk21/game/gpu.cpp +++ b/hk21/game/gpu.cpp @@ -14,11 +14,11 @@ #include <SDL3/SDL_vulkan.h>
#include "hk21/vulkan/loader/loader.hpp"
+#include "hk21/vulkan/sync/sync.hpp"
// @Todo Make fences recyclable
// @Todo Make command pool recyclable
// @Todo Make frame structure recyclable
-// @Todo Auto barriers for images
#define VK_ALLOCATOR nullptr
@@ -288,8 +288,53 @@ static asl::status_or<VkDevice> create_device(VkPhysicalDevice physical_device, struct FrameResources : asl::intrusive_list_node<FrameResources>
{
- VkFence complete_fence = VK_NULL_HANDLE;
- VkCommandPool command_pool = VK_NULL_HANDLE;
+ VkFence complete_fence = VK_NULL_HANDLE;
+ VkCommandPool command_pool = VK_NULL_HANDLE;
+};
+
+class DependencyInfoBuilder : public vulkan_sync::DependencyInfoBuilder
+{
+ // @Todo Configure allocator
+
+ asl::buffer<VkImageMemoryBarrier2> m_image_barriers;
+ asl::buffer<VkBufferMemoryBarrier2> m_buffer_barriers;
+
+public:
+ void add_image_barrier(const VkImageMemoryBarrier2& barrier) override
+ {
+ m_image_barriers.push(barrier);
+ }
+
+ void add_buffer_barrier(const VkBufferMemoryBarrier2& barrier) override
+ {
+ m_buffer_barriers.push(barrier);
+ }
+
+ void apply(VkCommandBuffer command_buffer)
+ {
+ if (m_image_barriers.is_empty() &&
+ m_buffer_barriers.is_empty())
+ {
+ return;
+ }
+
+ VkDependencyInfo dependency_info{
+ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+ .pNext = nullptr,
+ .dependencyFlags = 0,
+ .memoryBarrierCount = 0,
+ .pMemoryBarriers = nullptr,
+ .bufferMemoryBarrierCount = static_cast<uint32_t>(m_buffer_barriers.size()),
+ .pBufferMemoryBarriers = m_buffer_barriers.data(),
+ .imageMemoryBarrierCount = static_cast<uint32_t>(m_image_barriers.size()),
+ .pImageMemoryBarriers = m_image_barriers.data(),
+ };
+
+ vkCmdPipelineBarrier2(command_buffer, &dependency_info);
+
+ m_image_barriers.clear();
+ m_buffer_barriers.clear();
+ }
};
class GpuImpl : public Gpu
@@ -303,8 +348,14 @@ class GpuImpl : public Gpu VkDevice m_device;
VkQueue m_queue;
+ struct Image
+ {
+ vulkan_sync::ImageState state;
+ VkImage image{};
+ };
+
asl::option<VkSwapchainKHR> m_swapchain;
- asl::buffer<VkImage> m_swapchain_images;
+ asl::buffer<Image> m_swapchain_images;
VkSemaphore m_swapchain_image_acquire_semaphore = VK_NULL_HANDLE;
VkSemaphore m_queue_complete_semaphore = VK_NULL_HANDLE;
@@ -312,6 +363,8 @@ class GpuImpl : public Gpu asl::GlobalHeap m_allocator; // @Todo Make this configurable
asl::IntrusiveList<FrameResources> m_in_flight_frames;
+ DependencyInfoBuilder m_dependency_builder;
+
public:
GpuImpl(
VkInstance instance,
@@ -451,11 +504,24 @@ public: m_swapchain = swapchain;
vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, nullptr);
- m_swapchain_images.resize_zero(count);
- res = vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, m_swapchain_images.data());
- if (res != VK_SUCCESS)
+
{
- return asl::runtime_error("Couldn't retrieve Vulkan swapchain images: {}", res);
+ m_swapchain_images.resize(count);
+
+ // @Todo Good candidate for temporary allocation
+ asl::buffer<VkImage> images;
+ images.resize_zero(count);
+
+ res = vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, images.data());
+ if (res != VK_SUCCESS)
+ {
+ return asl::runtime_error("Couldn't retrieve Vulkan swapchain images: {}", res);
+ }
+
+ for (int64_t i = 0; i < count; ++i)
+ {
+ m_swapchain_images[i].image = images[i];
+ }
}
ASL_LOG_INFO("Vulkan swapchain created ({}x{} with {} images)",
@@ -518,6 +584,8 @@ public: {
return asl::runtime_error("Couldn't acquire swapchain image: {}", res);
}
+
+ auto& swapchain_image = m_swapchain_images[image_index];
VkCommandPoolCreateInfo command_pool_create_info{
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
@@ -561,40 +629,12 @@ public: return asl::runtime_error("Couldn't begin command buffer: {}", res);
}
- VkImageMemoryBarrier2 barrier1{
- .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
- .pNext = nullptr,
- .srcStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
- .srcAccessMask = VK_ACCESS_2_NONE,
- .dstStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT,
- .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
- .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
- .newLayout = VK_IMAGE_LAYOUT_GENERAL,
- .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .image = m_swapchain_images[image_index],
- .subresourceRange = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1,
- },
- };
-
- VkDependencyInfo dependency_info1{
- .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
- .pNext = nullptr,
- .dependencyFlags = 0,
- .memoryBarrierCount = 0,
- .pMemoryBarriers = nullptr,
- .bufferMemoryBarrierCount = 0,
- .pBufferMemoryBarriers = nullptr,
- .imageMemoryBarrierCount = 1,
- .pImageMemoryBarriers = &barrier1,
- };
-
- vkCmdPipelineBarrier2(command_buffer, &dependency_info1);
+ vulkan_sync::synchronize_resource(
+ swapchain_image.image,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ &swapchain_image.state,
+ vulkan_sync::Usage::kImageClear,
+ &m_dependency_builder);
VkClearColorValue clear_color{
.float32 = { 0.0F, 0.137F, 0.4F, 1.0F },
@@ -603,47 +643,23 @@ public: VkImageSubresourceRange range{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
- .levelCount = 1,
+ .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
- .layerCount = 1,
+ .layerCount = VK_REMAINING_ARRAY_LAYERS,
};
- vkCmdClearColorImage(command_buffer, m_swapchain_images[image_index], VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range);
+ m_dependency_builder.apply(command_buffer);
+ vkCmdClearColorImage(command_buffer, swapchain_image.image, swapchain_image.state.current_layout, &clear_color, 1, &range);
- VkImageMemoryBarrier2 barrier2{
- .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
- .pNext = nullptr,
- .srcStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT,
- .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
- .dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
- .dstAccessMask = VK_ACCESS_2_NONE,
- .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
- .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .image = m_swapchain_images[image_index],
- .subresourceRange = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1,
- },
- };
+ vulkan_sync::synchronize_resource(
+ swapchain_image.image,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ &swapchain_image.state,
+ vulkan_sync::Usage::kImagePresent,
+ &m_dependency_builder);
- VkDependencyInfo dependency_info2{
- .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
- .pNext = nullptr,
- .dependencyFlags = 0,
- .memoryBarrierCount = 0,
- .pMemoryBarriers = nullptr,
- .bufferMemoryBarrierCount = 0,
- .pBufferMemoryBarriers = nullptr,
- .imageMemoryBarrierCount = 1,
- .pImageMemoryBarriers = &barrier2,
- };
+ m_dependency_builder.apply(command_buffer);
- vkCmdPipelineBarrier2(command_buffer, &dependency_info2);
res = vkEndCommandBuffer(command_buffer);
if (res != VK_SUCCESS)
|