diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index fc80436ec85967619dab6aa5a518f0986e2b4f62..1cec2a7149ab17de76f390944e27941c317cd6e6 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 511ac67102ec26e9bd92c1b9e62b42d34c784e4d..c9c91db25fb4398439d609247d71ba6be3524464 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 99a516ad96e6feaf90990f1be8747ff967ada9ab..7fde9196d3187f3aafa7134325ee7d166d6cd23c 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 63a395e7f8f0e590d6b2dbdde3f8d527c4d8c87b..fc6140fe4664096145aa08551422d919bcb4dc25 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 93d78f43a0a8f0aedbb38331bff5fccdf96c7687..44022297f6a046d1efaf2b4ea80aafeded381a83 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, ®ion); + commandBuffer.copyBufferToImage( + stagingBuffer, + image.m_handle, + vk::ImageLayout::eTransferDstOptimal, + 1, + ®ion + ); }, [&]() { 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 5a91d962370071ac9c557ad877fd26268e1e2b2a..cbb6961f915dfee1c90409af38c61738f260a525 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);