From 14d22d7c78f691d7ffd136992345492cda91dd2c Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Fri, 21 Oct 2022 15:54:59 +0200
Subject: [PATCH] Implement pseudo mapping for device-local buffers

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 src/vkcv/BufferManager.cpp | 77 +++++++++++++++++++++++++++++++++-----
 src/vkcv/BufferManager.hpp |  7 ++++
 2 files changed, 75 insertions(+), 9 deletions(-)

diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index 0b97036d..b443f8ca 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -82,6 +82,10 @@ namespace vkcv {
 		const vma::Allocator &allocator = getCore().getContext().getAllocator();
 
 		if (buffer.m_handle) {
+			if (buffer.m_mapping) {
+				allocator.unmapMemory(buffer.m_allocation);
+			}
+			
 			allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation);
 
 			buffer.m_handle = nullptr;
@@ -197,7 +201,18 @@ namespace vkcv {
 			mappable = true;
 		}
 
-		return add({ typeGuard, type, memoryType, size, buffer, allocation, mappable });
+		return add({
+			typeGuard,
+			type,
+			memoryType,
+			size,
+			buffer,
+			allocation,
+			readable,
+			mappable,
+			nullptr,
+			0
+		});
 	}
 
 	/**
@@ -439,21 +454,65 @@ namespace vkcv {
 			size = std::numeric_limits<size_t>::max();
 		}
 
-		const vma::Allocator &allocator = getCore().getContext().getAllocator();
-
 		if (offset > buffer.m_size) {
 			return nullptr;
 		}
-
-		return reinterpret_cast<char*>(allocator.mapMemory(buffer.m_allocation)) + offset;
+		
+		if (buffer.m_mapping) {
+			++buffer.m_mapCounter;
+			
+			vkcv_log(LogLevel::WARNING,
+					 "Mapping a buffer multiple times (%lu) is not recommended",
+					 buffer.m_mapCounter);
+			
+			return buffer.m_mapping + offset;
+		}
+		
+		if (buffer.m_mappable) {
+			const vma::Allocator &allocator = getCore().getContext().getAllocator();
+			
+			buffer.m_mapping = reinterpret_cast<char*>(allocator.mapMemory(buffer.m_allocation));
+		} else {
+			buffer.m_mapping = m_allocator.allocate(buffer.m_size);
+			
+			if (buffer.m_readable) {
+				readBuffer(handle, buffer.m_mapping, buffer.m_size, 0);
+			}
+		}
+		
+		buffer.m_mapCounter = 1;
+		return buffer.m_mapping + offset;
 	}
 
 	void BufferManager::unmapBuffer(const BufferHandle &handle) {
 		auto &buffer = (*this) [handle];
-
-		const vma::Allocator &allocator = getCore().getContext().getAllocator();
-
-		allocator.unmapMemory(buffer.m_allocation);
+		
+		if (buffer.m_mapCounter > 1) {
+			--buffer.m_mapCounter;
+			return;
+		}
+		
+		if (buffer.m_mapCounter == 0) {
+			vkcv_log(LogLevel::WARNING,
+					 "It seems like the buffer is not mapped to memory");
+		}
+		
+		if (!buffer.m_mapping) {
+			vkcv_log(LogLevel::ERROR,
+					 "Buffer is not mapped to memory");
+		}
+		
+		if (buffer.m_mappable) {
+			const vma::Allocator &allocator = getCore().getContext().getAllocator();
+			
+			allocator.unmapMemory(buffer.m_allocation);
+		} else {
+			fillBuffer(handle, buffer.m_mapping, buffer.m_size, 0);
+			m_allocator.deallocate(buffer.m_mapping, buffer.m_size);
+		}
+		
+		buffer.m_mapping = nullptr;
+		buffer.m_mapCounter = 0;
 	}
 
 	void BufferManager ::recordBufferMemoryBarrier(const BufferHandle &handle,
diff --git a/src/vkcv/BufferManager.hpp b/src/vkcv/BufferManager.hpp
index f046d58b..f2826972 100644
--- a/src/vkcv/BufferManager.hpp
+++ b/src/vkcv/BufferManager.hpp
@@ -5,7 +5,9 @@
  * @brief Manager to handle buffer operations.
  */
 
+#include <memory>
 #include <vector>
+
 #include <vk_mem_alloc.hpp>
 #include <vulkan/vulkan.hpp>
 
@@ -26,7 +28,10 @@ namespace vkcv {
 		vk::Buffer m_handle;
 		vma::Allocation m_allocation;
 
+		bool m_readable;
 		bool m_mappable;
+		char *m_mapping;
+		size_t m_mapCounter;
 	};
 
 	/**
@@ -37,6 +42,8 @@ namespace vkcv {
 		friend class Core;
 
 	private:
+		std::allocator<char> m_allocator;
+		
 		bool m_resizableBar;
 		BufferHandle m_stagingBuffer;
 
-- 
GitLab