From a1e2cceec49897aab2964c40fc17c90ab3b63eba Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Thu, 18 Jul 2024 23:20:07 +0200
Subject: [PATCH] Fix invalid semaphore acquire and support for inline uniform
 blocks

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 include/vkcv/Core.hpp             |  3 +-
 src/vkcv/Core.cpp                 | 60 +++++++++++++++++++++++++------
 src/vkcv/DescriptorSetManager.cpp | 18 ++++++++--
 src/vkcv/DescriptorSetManager.hpp |  1 +
 4 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 010c4ec7..b97cf4ee 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -89,8 +89,9 @@ namespace vkcv {
 		
 		Vector<vk::CommandPool> m_CommandPools;
 		vk::Semaphore m_RenderFinished;
-		vk::Semaphore m_SwapchainImageAcquired;
+		std::vector<vk::Semaphore> m_SwapchainImagesAcquired;
 		uint32_t m_currentSwapchainImageIndex;
+		uint32_t m_currentSwapchainSemaphoreIndex;
 
 		std::unique_ptr<Downsampler> m_downsampler;
 
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 70421cb8..4e7d9d94 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -6,6 +6,9 @@
 
 #include <GLFW/glfw3.h>
 #include <cmath>
+#include <cstdint>
+#include <limits>
+#include <vkcv/Logger.hpp>
 
 #include "AccelerationStructureManager.hpp"
 #include "BufferManager.hpp"
@@ -107,13 +110,14 @@ namespace vkcv {
 		m_RayTracingPipelineManager(std::make_unique<RayTracingPipelineManager>()),
 		m_CommandPools(),
 		m_RenderFinished(),
-		m_SwapchainImageAcquired(),
+		m_SwapchainImagesAcquired(),
+		m_currentSwapchainImageIndex(std::numeric_limits<uint32_t>::max()),
+		m_currentSwapchainSemaphoreIndex(0),
 		m_downsampler(nullptr) {
 		m_CommandPools = createCommandPools(
 			m_Context.getDevice(), generateQueueFamilyIndexSet(m_Context.getQueueManager()));
 
 		m_RenderFinished = m_Context.getDevice().createSemaphore({});
-		m_SwapchainImageAcquired = m_Context.getDevice().createSemaphore({});
 
 		m_DescriptorSetLayoutManager->init(*this);
 		m_DescriptorSetManager->init(*this, *m_DescriptorSetLayoutManager);
@@ -138,7 +142,10 @@ namespace vkcv {
 		}
 
 		m_Context.getDevice().destroySemaphore(m_RenderFinished);
-		m_Context.getDevice().destroySemaphore(m_SwapchainImageAcquired);
+
+		for (auto& semaphore : m_SwapchainImagesAcquired) {
+			m_Context.getDevice().destroySemaphore(semaphore);
+		}
 	}
 
 	GraphicsPipelineHandle Core::createGraphicsPipeline(const GraphicsPipelineConfig &config) {
@@ -223,14 +230,25 @@ namespace vkcv {
 	}
 
 	Result Core::acquireSwapchainImage(const SwapchainHandle &swapchainHandle) {
-		uint32_t imageIndex;
+		uint32_t imageIndex, semaphoreIndex;
 		vk::Result result;
 
+		if (m_SwapchainImagesAcquired.size() <= 0) {
+			vkcv_log(LogLevel::ERROR, "Semaphores not available");
+			return Result::ERROR;
+		}
+
+		semaphoreIndex = m_currentSwapchainSemaphoreIndex % m_SwapchainImagesAcquired.size();
+
 		try {
 			result = m_Context.getDevice().acquireNextImageKHR(
 				m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain,
-				std::numeric_limits<uint64_t>::max(), m_SwapchainImageAcquired, nullptr,
-				&imageIndex, {});
+				std::numeric_limits<uint64_t>::max(),
+				m_SwapchainImagesAcquired[semaphoreIndex],
+				nullptr,
+				&imageIndex,
+				{}
+			);
 		} catch (const vk::OutOfDateKHRError &e) {
 			result = vk::Result::eErrorOutOfDateKHR;
 		} catch (const vk::DeviceLostError &e) {
@@ -265,6 +283,17 @@ namespace vkcv {
 			setSwapchainImages(swapchainHandle);
 		}
 
+		const uint32_t count = m_SwapchainManager->getImageCount(swapchainHandle);
+		const uint32_t initialized = m_SwapchainImagesAcquired.size();
+
+		if (count > initialized) {
+			m_SwapchainImagesAcquired.resize(count);
+
+			for (uint32_t i = initialized; i < count; i++) {
+				m_SwapchainImagesAcquired[i] = m_Context.getDevice().createSemaphore({});
+			}
+		}
+
 		const auto &extent = m_SwapchainManager->getExtent(swapchainHandle);
 
 		width = extent.width;
@@ -835,17 +864,26 @@ namespace vkcv {
 	void Core::endFrame(const WindowHandle &windowHandle) {
 		SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain();
 
-		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
+		if ((m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) ||
+		    (m_SwapchainImagesAcquired.size() <= 0)) {
 			return;
 		}
 
-		const std::array<vk::Semaphore, 2> waitSemaphores { m_RenderFinished,
-															m_SwapchainImageAcquired };
+		const uint32_t semaphoreIndex = m_currentSwapchainSemaphoreIndex % m_SwapchainImagesAcquired.size();
+		m_currentSwapchainSemaphoreIndex = (m_currentSwapchainSemaphoreIndex + 1) % m_SwapchainImagesAcquired.size();
+
+		const std::array<vk::Semaphore, 2> waitSemaphores {
+			m_RenderFinished,
+			m_SwapchainImagesAcquired[semaphoreIndex]
+		};
 
 		const vk::SwapchainKHR &swapchain =
 			m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain;
-		const vk::PresentInfoKHR presentInfo(waitSemaphores, swapchain,
-											 m_currentSwapchainImageIndex);
+		const vk::PresentInfoKHR presentInfo(
+			waitSemaphores,
+			swapchain,
+			m_currentSwapchainImageIndex
+		);
 
 		vk::Result result;
 
diff --git a/src/vkcv/DescriptorSetManager.cpp b/src/vkcv/DescriptorSetManager.cpp
index 6c21cd9d..d4ffce74 100644
--- a/src/vkcv/DescriptorSetManager.cpp
+++ b/src/vkcv/DescriptorSetManager.cpp
@@ -1,6 +1,7 @@
 #include "DescriptorSetManager.hpp"
 
 #include "vkcv/Core.hpp"
+#include <vulkan/vulkan_core.h>
 
 namespace vkcv {
 
@@ -16,6 +17,8 @@ namespace vkcv {
 
 		m_DescriptorSetLayoutManager = &descriptorSetLayoutManager;
 
+		const auto& featureManager = core.getContext().getFeatureManager();
+
 		/**
 		 * Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type
 		 * below. Finally, create an initial pool.
@@ -32,9 +35,12 @@ namespace vkcv {
 		m_PoolSizes.emplace_back(vk::DescriptorType::eUniformBufferDynamic, 1000);
 		m_PoolSizes.emplace_back(vk::DescriptorType::eStorageBufferDynamic, 1000);
 		m_PoolSizes.emplace_back(vk::DescriptorType::eInputAttachment, 1000);
-		m_PoolSizes.emplace_back(vk::DescriptorType::eInlineUniformBlock, 1000);
 
-		if (core.getContext().getFeatureManager().isExtensionActive(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME)) {
+		if (featureManager.isExtensionActive(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) {
+			m_PoolSizes.emplace_back(vk::DescriptorType::eInlineUniformBlock, 1000);
+		}
+
+		if (featureManager.isExtensionActive(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME)) {
 			m_PoolSizes.emplace_back(vk::DescriptorType::eAccelerationStructureKHR, 1000);
 		}
 
@@ -45,6 +51,14 @@ namespace vkcv {
 			m_PoolSizes.data()
 		);
 
+		if (featureManager.isExtensionActive(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME)) {
+			m_InlineUniformBlockInfo = vk::DescriptorPoolInlineUniformBlockCreateInfo(
+				1000
+			);
+
+			m_PoolInfo.setPNext(&m_InlineUniformBlockInfo);
+		}
+
 		return allocateDescriptorPool();
 	}
 
diff --git a/src/vkcv/DescriptorSetManager.hpp b/src/vkcv/DescriptorSetManager.hpp
index 74cf75d9..6236cf9c 100644
--- a/src/vkcv/DescriptorSetManager.hpp
+++ b/src/vkcv/DescriptorSetManager.hpp
@@ -38,6 +38,7 @@ namespace vkcv {
 		Vector<vk::DescriptorPool> m_Pools;
 		Vector<vk::DescriptorPoolSize> m_PoolSizes;
 		vk::DescriptorPoolCreateInfo m_PoolInfo;
+		vk::DescriptorPoolInlineUniformBlockCreateInfo m_InlineUniformBlockInfo;
 		
 		bool init(Core &core) override;
 		bool init(Core &core, DescriptorSetLayoutManager &descriptorSetLayoutManager);
-- 
GitLab