diff --git a/config/Sources.cmake b/config/Sources.cmake index eeb281c9e37c35e42e078d6137c115a210fc1107..fefdb6d8c8400d50424fdb3c95d732c6c4ce08e2 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -27,7 +27,7 @@ set(vkcv_sources ${vkcv_include}/vkcv/Image.hpp ${vkcv_source}/vkcv/Image.cpp - ${vkcv_include}/vkcv/ImageManager.hpp + ${vkcv_source}/vkcv/ImageManager.hpp ${vkcv_source}/vkcv/ImageManager.cpp ${vkcv_include}/vkcv/SwapChain.hpp diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp index 0df3030167cea3d109f47ad932978cce08a7c63e..4b12f47ba8497bd09260d24523c28f207f64a98c 100644 --- a/include/vkcv/BufferManager.hpp +++ b/include/vkcv/BufferManager.hpp @@ -25,16 +25,15 @@ namespace vkcv class BufferManager { friend class Core; - friend class ImageManager; private: struct Buffer { vk::Buffer m_handle; vk::DeviceMemory m_memory; - size_t m_size; + size_t m_size = 0; void* m_mapped = nullptr; - bool m_mappable; + bool m_mappable = false; }; Core* m_core; @@ -56,7 +55,7 @@ namespace vkcv /** * Creates and allocates a new buffer and returns its - * unique buffer handle id. + * unique buffer handle. * * @param type Type of buffer * @param size Size of buffer in bytes @@ -67,7 +66,7 @@ namespace vkcv /** * Returns the Vulkan buffer handle of a buffer - * represented by a given buffer handle id. + * represented by a given buffer handle. * * @param handle Buffer handle * @return Vulkan buffer handle @@ -75,6 +74,16 @@ namespace vkcv [[nodiscard]] vk::Buffer getBuffer(const BufferHandle& handle) const; + /** + * Returns the size of a buffer represented + * by a given buffer handle. + * + * @param handle Buffer handle + * @return Size of the buffer + */ + [[nodiscard]] + size_t getBufferSize(const BufferHandle& handle) const; + /** * Returns the Vulkan device memory handle of a buffer * represented by a given buffer handle id. @@ -87,7 +96,7 @@ namespace vkcv /** * Fills a buffer represented by a given buffer - * handle id with custom data. + * handle with custom data. * * @param handle Buffer handle * @param data Pointer to data @@ -98,7 +107,7 @@ namespace vkcv /** * Maps memory to a buffer represented by a given - * buffer handle id and returns it. + * buffer handle and returns it. * * @param handle Buffer handle * @param offset Offset of mapping in bytes @@ -109,7 +118,7 @@ namespace vkcv /** * Unmaps memory from a buffer represented by a given - * buffer handle id. + * buffer handle. * * @param handle Buffer handle */ @@ -117,7 +126,7 @@ namespace vkcv /** * Destroys and deallocates buffer represented by a given - * buffer handle id. + * buffer handle. * * @param handle Buffer handle */ diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index 7b500ea514f1034e9822f9c12936b5e63ba3225e..1fd6573976b1f5aab572eb982cc0c61eff01a9e9 100644 --- a/include/vkcv/Handles.hpp +++ b/include/vkcv/Handles.hpp @@ -64,4 +64,10 @@ namespace vkcv using Handle::Handle; }; + class ImageHandle : public Handle { + friend class ImageManager; + private: + using Handle::Handle; + }; + } diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 5ebaf9211c47d9994bd17d560204484eb9dad1c5..1c162cdc4a9494d484d97ab39613144571a26283 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -6,12 +6,17 @@ */ #include "vulkan/vulkan.hpp" +#include "Handles.hpp" + namespace vkcv { class ImageManager; class Image { public: - static Image create(ImageManager* manager, uint32_t width, uint32_t height); + static Image create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth); + + [[nodiscard]] + vk::Format getFormat() const; [[nodiscard]] uint32_t getWidth() const; @@ -19,18 +24,25 @@ namespace vkcv { [[nodiscard]] uint32_t getHeight() const; + [[nodiscard]] + uint32_t getDepth() const; + [[nodiscard]] vk::ImageLayout getLayout() const; void switchLayout(vk::ImageLayout newLayout); + + void fill(void* data, size_t size = SIZE_MAX); private: ImageManager* const m_manager; - const uint64_t m_handle_id; + const ImageHandle m_handle; + const vk::Format m_format; const uint32_t m_width; const uint32_t m_height; + const uint32_t m_depth; vk::ImageLayout m_layout; - Image(ImageManager* manager, uint64_t id, uint32_t width, uint32_t height); + Image(ImageManager* manager, const ImageHandle& handle, vk::Format format, uint32_t width, uint32_t height, uint32_t depth); }; } diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index 8ad4aa934be26207f8a0de5ef4c88ce45f6432f9..a6ec80085424a25a6f4285254253829fc5b59257 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -194,6 +194,18 @@ namespace vkcv { return buffer.m_handle; } + size_t BufferManager::getBufferSize(const BufferHandle &handle) const { + const uint64_t id = handle.getId(); + + if (id >= m_buffers.size()) { + return 0; + } + + auto& buffer = m_buffers[id]; + + return buffer.m_size; + } + vk::DeviceMemory BufferManager::getDeviceMemory(const BufferHandle& handle) const { const uint64_t id = handle.getId(); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index f65f0f6f371e549aea3cac3269aebab7c82d5f3b..ecadba04f1230e6d0531851e862b44aca978bdb6 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -10,7 +10,7 @@ #include "PassManager.hpp" #include "PipelineManager.hpp" #include "vkcv/BufferManager.hpp" -#include "vkcv/ImageManager.hpp" +#include "ImageManager.hpp" #include "DescriptorManager.hpp" #include "Surface.hpp" #include "ImageLayoutTransitions.hpp" @@ -96,14 +96,14 @@ namespace vkcv m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)}, m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)), m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())}, - m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager())}, + m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))}, m_CommandResources(commandResources), m_SyncResources(syncResources) { m_BufferManager->m_core = this; m_BufferManager->init(); - m_ImageManager->m_core = this; - m_ImageManager->init(m_BufferManager.get()); + + m_ImageManager->m_core = this; } Core::~Core() noexcept { diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp index 3ba5206d3dd7d1c300377e3ac1f51e8b5549258e..c4341b4f173028afa5dce98383b2ae34833ee2fa 100644 --- a/src/vkcv/Image.cpp +++ b/src/vkcv/Image.cpp @@ -4,13 +4,17 @@ * @brief class for image handles */ #include "vkcv/Image.hpp" -#include "vkcv/ImageManager.hpp" +#include "ImageManager.hpp" namespace vkcv{ - Image Image::create(ImageManager* manager, uint32_t width, uint32_t height) + Image Image::create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth) { - return Image(manager, manager->createImage(width, height), width, height); + return Image(manager, manager->createImage(width, height, depth, format), format, width, height, depth); + } + + vk::Format Image::getFormat() const { + return m_format; } uint32_t Image::getWidth() const { @@ -21,21 +25,32 @@ namespace vkcv{ return m_height; } + uint32_t Image::getDepth() const { + return m_depth; + } + vk::ImageLayout Image::getLayout() const { return m_layout; } void Image::switchLayout(vk::ImageLayout newLayout) { - m_manager->switchImageLayout(m_handle_id, m_layout, newLayout); + m_manager->switchImageLayout(m_handle, m_layout, newLayout); m_layout = newLayout; } - Image::Image(ImageManager* manager, uint64_t id, uint32_t width, uint32_t height) : + void Image::fill(void *data, size_t size) { + m_manager->fillImage(m_handle, data, size); + } + + Image::Image(ImageManager* manager, const ImageHandle& handle, + vk::Format format, uint32_t width, uint32_t height, uint32_t depth) : m_manager(manager), - m_handle_id(id), + m_handle(handle), + m_format(format), m_width(width), m_height(height), + m_depth(depth), m_layout(vk::ImageLayout::eUndefined) { } diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 7f06edc9bcb5244f00370af439f4143a7be4257b..188bbebd0ddc64dc0fad72a1bc93c2ed89fffeee 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -3,7 +3,7 @@ * @file vkcv/ImageManager.cpp * @brief class creating and managing images */ -#include "vkcv/ImageManager.hpp" +#include "ImageManager.hpp" #include "vkcv/Core.hpp" namespace vkcv { @@ -33,34 +33,24 @@ namespace vkcv { // failed to find memory type return -1; } - - void ImageManager::init(BufferManager* bufferManager) - { - if (!m_core) { - return; - } - uint64_t stagingID = bufferManager->createBuffer(BufferType::STAGING, 1024 * 1024, BufferMemoryType::HOST_VISIBLE); - m_stagingBuffer = bufferManager->m_buffers[stagingID].m_handle; - } - ImageManager::ImageManager() noexcept : - m_core(nullptr), m_images() + ImageManager::ImageManager(BufferManager& bufferManager) noexcept : + m_core(nullptr), m_bufferManager(bufferManager), m_images() { } ImageManager::~ImageManager() noexcept { - for (size_t id = 0; id < m_images.size(); id++) { - destroyImage(id); + for (uint64_t id = 0; id < m_images.size(); id++) { + destroyImage(ImageHandle(id)); } } - uint64_t ImageManager::createImage(uint32_t width, uint32_t height) + ImageHandle ImageManager::createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format) { vk::ImageCreateFlags createFlags; vk::ImageUsageFlags imageUsageFlags = (vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst); - vk::Format format = vk::Format::eR8G8B8A8Unorm; // TODO - uint32_t channels = 3; // TODO + format = vk::Format::eR8G8B8A8Unorm; // TODO const vk::Device& device = m_core->getContext().getDevice(); @@ -96,11 +86,11 @@ namespace vkcv { device.bindImageMemory(image, memory, 0); const uint64_t id = m_images.size(); - m_images.push_back({ image, memory, width * height * channels }); - return id; + m_images.push_back({ image, memory, width, height, depth, format }); + return ImageHandle(id); } - void ImageManager::switchImageLayout(uint64_t id, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { + void ImageManager::switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { //alternativly we could use switch case for every variable to set vk::AccessFlags sourceAccessMask; vk::PipelineStageFlags sourceStage; @@ -125,14 +115,20 @@ namespace vkcv { } vk::ImageSubresourceRange imageSubresourceRange( - vk::ImageAspectFlagBits::eColor , + vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 ); - ImageManager::Image image = m_images[id]; + const uint64_t id = handle.getId(); + + if (id >= m_images.size()) { + return; + } + + auto& image = m_images[id]; vk::ImageMemoryBarrier imageMemoryBarrier( sourceAccessMask, @@ -163,121 +159,86 @@ namespace vkcv { nullptr ); } - - struct ImageStagingStepInfo { - void* data; - size_t size; - uint32_t width; - uint32_t height; - - vk::Image image; - vk::Buffer stagingBuffer; - vk::DeviceMemory stagingMemory; - - size_t stagingLimit; - size_t stagingPosition; - }; - - void copyStagingToImage(Core* core, ImageStagingStepInfo info) - { - /* - * Alte implementation - vk::BufferImageCopy copyRegion(0, width, height); - - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Transfer; //not sure - core->submitCommands( - submitInfo, - [buffer, image, copyRegion](const vk::CommandBuffer& commandBuffer) { - commandBuffer.copyBufferToImage( - buffer, - image, vk::ImageLayout::eTransferDstOptimal, - copyRegion - ); - }, - []() {} - ); - */ - - const size_t remaining = info.size - info.stagingPosition; - const size_t mapped_size = std::min(remaining, info.stagingLimit); - - const vk::Device& device = core->getContext().getDevice(); - - void* mapped = device.mapMemory(info.stagingMemory, 0, mapped_size); - memcpy(mapped, reinterpret_cast<char*>(info.data) + info.stagingPosition, mapped_size); - device.unmapMemory(info.stagingMemory); - - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Transfer; - - core->submitCommands( - submitInfo, - [&info, &mapped_size](const vk::CommandBuffer& commandBuffer) { - /* - const vk::BufferImageCopy region( - info.offset, //bufferOffset - info.size, //bufferRowlength - 0, //bufferImageHeight - vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor,0,0,1),//soubresource layer - vk::Offset2D(info.offset,0), //imageoffset - vk::Extent3D(info.width,info.height,1) //extend3d - ); - - commandBuffer.copyBufferToImage( - info.stagingBuffer, - info.image, - vk::ImageLayout::eTransferDstOptimal, - region); - */ - }, - [&core, &info, &mapped_size, &remaining]() { - if (mapped_size < remaining) { - info.stagingPosition += mapped_size; - - copyStagingToImage( - core, - info - ); - } - } - ); - } - void ImageManager::fillImage(uint64_t id, void* data, size_t size) + + void ImageManager::fillImage(const ImageHandle& handle, void* data, size_t size) { if (size == 0) { size = SIZE_MAX; } + const uint64_t id = handle.getId(); + if (id >= m_images.size()) { return; } auto& image = m_images[id]; - switchImageLayout(id, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal); + switchImageLayout( + handle, + vk::ImageLayout::eUndefined, + vk::ImageLayout::eTransferDstOptimal + ); - const size_t max_size = std::min(size, image.m_size); + uint32_t channels = 3; // TODO + const size_t image_size = ( + image.m_width * image.m_height * image.m_depth * channels * sizeof(char) + ); - //const size_t max_size = std::min(size, image.m_size - offset); - ImageStagingStepInfo info; - info.data = data; - info.size = max_size; - - info.image = image.m_handle; - info.stagingBuffer = m_stagingBuffer; - info.stagingMemory = m_stagingMemory; - - const vk::MemoryRequirements stagingRequirements = m_core->getContext().getDevice().getBufferMemoryRequirements(m_stagingBuffer); - info.stagingLimit = stagingRequirements.size; //TODO - info.stagingPosition = 0; - - copyStagingToImage(m_core, info); - switchImageLayout(id, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal); + const size_t max_size = std::min(size, image_size); + + BufferHandle bufferHandle = m_bufferManager.createBuffer( + BufferType::STAGING, max_size, BufferMemoryType::HOST_VISIBLE + ); + + m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0); + + vk::Buffer stagingBuffer = m_bufferManager.getBuffer(bufferHandle); + + SubmitInfo submitInfo; + submitInfo.queueType = QueueType::Transfer; + + m_core->submitCommands( + submitInfo, + [&image, &stagingBuffer](const vk::CommandBuffer& commandBuffer) { + const vk::BufferImageCopy region ( + 0, + 0, + 0, + vk::ImageSubresourceLayers( + vk::ImageAspectFlagBits::eColor, + 0, + 0, + 1 + ), + vk::Offset3D(0, 0, 0), + vk::Extent3D(image.m_width, image.m_height, image.m_depth) + ); + + commandBuffer.copyBufferToImage( + stagingBuffer, + image.m_handle, + vk::ImageLayout::eTransferDstOptimal, + 1, + ®ion + ); + }, + [&]() { + switchImageLayout( + handle, + vk::ImageLayout::eTransferDstOptimal, + vk::ImageLayout::eShaderReadOnlyOptimal + ); + + m_bufferManager.destroyBuffer(bufferHandle); + } + ); } - void ImageManager::destroyImage(uint64_t id) + void ImageManager::destroyImage(const ImageHandle& handle) { + const uint64_t id = handle.getId(); + if (id >= m_images.size()) { return; } diff --git a/include/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp similarity index 52% rename from include/vkcv/ImageManager.hpp rename to src/vkcv/ImageManager.hpp index dc38ef08e107d4823b24bb091e4b90df8cd74954..22a4301977392876e520cecc6ccbfd7982cb3d59 100644 --- a/include/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -7,9 +7,11 @@ #include <vector> #include <vulkan/vulkan.hpp> +#include "vkcv/BufferManager.hpp" +#include "vkcv/Handles.hpp" + namespace vkcv { - class Core; - class BufferManager; + class ImageManager { friend class Core; @@ -18,16 +20,19 @@ namespace vkcv { { vk::Image m_handle; vk::DeviceMemory m_memory; - size_t m_size; + uint32_t m_width = 0; + uint32_t m_height = 0; + uint32_t m_depth = 0; + vk::Format m_format; }; Core* m_core; - vk::Buffer m_stagingBuffer; - vk::DeviceMemory m_stagingMemory; - + BufferManager& m_bufferManager; + std::vector<Image> m_images; - void init(BufferManager* bufferManager); - ImageManager() noexcept; + + ImageManager(BufferManager& bufferManager) noexcept; + public: ~ImageManager() noexcept; ImageManager(ImageManager&& other) = delete; @@ -36,17 +41,18 @@ namespace vkcv { ImageManager& operator=(ImageManager&& other) = delete; ImageManager& operator=(const ImageManager& other) = delete; - void switchImageLayout(uint64_t id, vk::ImageLayout oldLayout, vk::ImageLayout newLayout); - void fillImage(uint64_t id, void* data, size_t size); + void switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout); + void fillImage(const ImageHandle& handle, void* data, size_t size); - uint64_t createImage(uint32_t width, uint32_t height); + ImageHandle createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format); /** * Destroys and deallocates image represented by a given - * buffer handle id. + * buffer handle. * - * @param id Buffer handle id + * @param handle Image handle */ - void destroyImage(uint64_t id); + void destroyImage(const ImageHandle& handle); + }; } \ No newline at end of file