From 0120213bcb17bd7a519655bea4c8d111b0fb9315 Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Thu, 13 Oct 2022 22:09:47 +0200
Subject: [PATCH] Implement layer support for filling images

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 include/vkcv/Core.hpp     | 10 ++++--
 include/vkcv/Image.hpp    | 11 ++++++
 src/vkcv/Core.cpp         |  8 +++--
 src/vkcv/Image.cpp        |  6 +++-
 src/vkcv/ImageManager.cpp | 73 +++++++++++++++++++++++++++++++--------
 src/vkcv/ImageManager.hpp |  6 +++-
 6 files changed, 93 insertions(+), 21 deletions(-)

diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index fc80436e..1cec2a71 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -338,8 +338,14 @@ namespace vkcv {
 		 * @param[in] image Image handle
 		 * @param[in] data Image data pointer
 		 * @param[in] size Size of data
-		 */
-		void fillImage(const ImageHandle &image, const void* data, size_t size);
+		 * @param[in] firstLayer First image layer
+		 * @param[in] layerCount Image layer count
+		 */
+		void fillImage(const ImageHandle &image,
+					   const void* data,
+					   size_t size,
+					   uint32_t firstLayer,
+					   uint32_t layerCount);
 
 		/**
 		 * @brief Switches the images layout synchronously if possible.
diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp
index 511ac671..c9c91db2 100644
--- a/include/vkcv/Image.hpp
+++ b/include/vkcv/Image.hpp
@@ -112,6 +112,17 @@ namespace vkcv {
 		 * the actual number of copied bytes is min(size, imageDataSize)
 		 */
 		void fill(const void* data, size_t size = SIZE_MAX);
+		
+		/**
+		 * @brief Fills a specific image layer with data of a given
+		 * size in bytes.
+		 *
+		 * @param[in] layer Image layer destination
+		 * @param[in] data Pointer to the source data
+		 * @param[in] size Lower limit of the data size to copy in bytes,
+		 * the actual number of copied bytes is min(size, imageDataSize)
+		 */
+		void fillLayer(uint32_t layer, const void* data, size_t size = SIZE_MAX);
 
 		/**
 		 * @brief Records mip chain generation to command stream,
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 99a516ad..7fde9196 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -879,8 +879,12 @@ namespace vkcv {
 		);
 	}
 
-	void Core::fillImage(const ImageHandle &image, const void* data, size_t size) {
-		m_ImageManager->fillImage(image, data, size);
+	void Core::fillImage(const ImageHandle &image,
+						 const void* data,
+						 size_t size,
+						 uint32_t firstLayer,
+						 uint32_t layerCount) {
+		m_ImageManager->fillImage(image, data, size, firstLayer, layerCount);
 	}
 
 	void Core::switchImageLayout(const ImageHandle &image, vk::ImageLayout layout) {
diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp
index 63a395e7..fc6140fe 100644
--- a/src/vkcv/Image.cpp
+++ b/src/vkcv/Image.cpp
@@ -64,7 +64,11 @@ namespace vkcv {
 	}
 
 	void Image::fill(const void* data, size_t size) {
-		m_core->fillImage(m_handle, data, size);
+		m_core->fillImage(m_handle, data, size, 0, 0);
+	}
+	
+	void Image::fillLayer(uint32_t layer, const void* data, size_t size) {
+		m_core->fillImage(m_handle, data, size, layer, 1);
 	}
 
 	void Image::recordMipChainGeneration(const vkcv::CommandStreamHandle &cmdStream,
diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp
index 93d78f43..44022297 100644
--- a/src/vkcv/ImageManager.cpp
+++ b/src/vkcv/ImageManager.cpp
@@ -488,22 +488,48 @@ namespace vkcv {
 		}
 	}
 
-	void ImageManager::fillImage(const ImageHandle &handle, const void* data, size_t size) {
+	void ImageManager::fillImage(const ImageHandle &handle,
+								 const void* data,
+								 size_t size,
+								 uint32_t firstLayer,
+								 uint32_t layerCount) {
 		if (handle.isSwapchainImage()) {
 			vkcv_log(LogLevel::ERROR, "Swapchain image cannot be filled");
 			return;
 		}
 
 		auto &image = (*this) [handle];
+		
+		const uint32_t baseArrayLayer = std::min<uint32_t>(firstLayer, image.m_layers);
+		
+		if (baseArrayLayer >= image.m_layers) {
+			return;
+		}
+		
+		uint32_t arrayLayerCount;
+		
+		if (layerCount > 0) {
+			arrayLayerCount = std::min<uint32_t>(layerCount, image.m_layers);
+		} else {
+			arrayLayerCount = image.m_layers;
+		}
+		
+		if (arrayLayerCount < baseArrayLayer) {
+			return;
+		}
+		
+		arrayLayerCount -= baseArrayLayer;
 		switchImageLayoutImmediate(handle, vk::ImageLayout::eTransferDstOptimal);
 
-		const size_t image_size =
-			(image.m_width * image.m_height * image.m_depth * getBytesPerPixel(image.m_format));
+		const size_t image_size = (
+				image.m_width * image.m_height * image.m_depth * getBytesPerPixel(image.m_format)
+		);
 
 		const size_t max_size = std::min(size, image_size);
 
 		BufferHandle bufferHandle = getBufferManager().createBuffer(
-			TypeGuard(1), BufferType::STAGING, BufferMemoryType::DEVICE_LOCAL, max_size, false);
+			TypeGuard(1), BufferType::STAGING, BufferMemoryType::DEVICE_LOCAL, max_size, false
+		);
 
 		getBufferManager().fillBuffer(bufferHandle, data, max_size, 0);
 
@@ -514,7 +540,8 @@ namespace vkcv {
 
 		core.recordCommandsToStream(
 			stream,
-			[&image, &stagingBuffer](const vk::CommandBuffer &commandBuffer) {
+			[&image, &stagingBuffer, &baseArrayLayer, &arrayLayerCount]
+			(const vk::CommandBuffer &commandBuffer) {
 				vk::ImageAspectFlags aspectFlags;
 
 				if (isDepthImageFormat(image.m_format)) {
@@ -524,16 +551,26 @@ namespace vkcv {
 				}
 
 				const vk::BufferImageCopy region(
-					0, 0, 0, vk::ImageSubresourceLayers(aspectFlags, 0, 0, image.m_layers),
+					0,
+					0,
+					0,
+					vk::ImageSubresourceLayers(aspectFlags, 0, baseArrayLayer, arrayLayerCount),
 					vk::Offset3D(0, 0, 0),
-					vk::Extent3D(image.m_width, image.m_height, image.m_depth));
+					vk::Extent3D(image.m_width, image.m_height, image.m_depth)
+				);
 
-				commandBuffer.copyBufferToImage(stagingBuffer, image.m_handle,
-												vk::ImageLayout::eTransferDstOptimal, 1, &region);
+				commandBuffer.copyBufferToImage(
+						stagingBuffer,
+						image.m_handle,
+						vk::ImageLayout::eTransferDstOptimal,
+						1,
+						&region
+				);
 			},
 			[&]() {
 				switchImageLayoutImmediate(handle, vk::ImageLayout::eShaderReadOnlyOptimal);
-			});
+			}
+		);
 
 		core.submitCommandStream(stream, false);
 	}
@@ -553,17 +590,23 @@ namespace vkcv {
 		auto &dstImage = (*this) [dst];
 
 		vk::ImageResolve region(
-			vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
+			vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, srcImage.m_layers),
 			vk::Offset3D(0, 0, 0),
-			vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
+			vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, dstImage.m_layers),
 			vk::Offset3D(0, 0, 0),
-			vk::Extent3D(dstImage.m_width, dstImage.m_height, dstImage.m_depth));
+			vk::Extent3D(dstImage.m_width, dstImage.m_height, dstImage.m_depth)
+		);
 
 		recordImageLayoutTransition(src, 0, 0, vk::ImageLayout::eTransferSrcOptimal, cmdBuffer);
 		recordImageLayoutTransition(dst, 0, 0, vk::ImageLayout::eTransferDstOptimal, cmdBuffer);
 
-		cmdBuffer.resolveImage(srcImage.m_handle, srcImage.m_layout, dstImage.m_handle,
-							   dstImage.m_layout, region);
+		cmdBuffer.resolveImage(
+				srcImage.m_handle,
+				srcImage.m_layout,
+				dstImage.m_handle,
+				dstImage.m_layout,
+				region
+		);
 	}
 
 	uint32_t ImageManager::getImageWidth(const ImageHandle &handle) const {
diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp
index 5a91d962..cbb6961f 100644
--- a/src/vkcv/ImageManager.hpp
+++ b/src/vkcv/ImageManager.hpp
@@ -106,7 +106,11 @@ namespace vkcv {
 
 		void recordImageMemoryBarrier(const ImageHandle &handle, vk::CommandBuffer cmdBuffer);
 
-		void fillImage(const ImageHandle &handle, const void* data, size_t size);
+		void fillImage(const ImageHandle &handle,
+					   const void* data,
+					   size_t size,
+					   uint32_t firstLayer,
+					   uint32_t layerCount);
 
 		void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle &cmdStream,
 													  const ImageHandle &handle);
-- 
GitLab