diff --git a/.gitmodules b/.gitmodules index e270bddb0a91069af1eff869560e8b817f7cc844..efa79ed703e1cc83f962cebfd4299621810cf82e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,9 +22,6 @@ [submodule "modules/gui/lib/imgui"] path = modules/gui/lib/imgui url = https://github.com/ocornut/imgui.git -[submodule "lib/VulkanMemoryAllocator-Hpp"] - path = lib/VulkanMemoryAllocator-Hpp - url = https://github.com/malte-v/VulkanMemoryAllocator-Hpp.git [submodule "modules/upscaling/lib/FidelityFX-FSR"] path = modules/upscaling/lib/FidelityFX-FSR url = https://github.com/GPUOpen-Effects/FidelityFX-FSR.git @@ -37,3 +34,6 @@ [submodule "modules/upscaling/lib/NVIDIAImageScaling"] path = modules/upscaling/lib/NVIDIAImageScaling url = https://github.com/NVIDIAGameWorks/NVIDIAImageScaling.git +[submodule "lib/VulkanMemoryAllocator-Hpp"] + path = lib/VulkanMemoryAllocator-Hpp + url = https://github.com/YaaZ/VulkanMemoryAllocator-Hpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c3f6df3508592fc5003ee490951fdf8368b48ac..d47706415b6274a135a4c85aa1010fde2e959105 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,8 @@ message(STATUS "Linker: [ " ${CMAKE_LINKER} " ]") if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0")) message(FATAL_ERROR "Upgrade your compiler! GCC 9.0+ is required!") +elseif(MINGW) + message(WARNING "MinGW is impressively unstable! So beware it may not compile or crash during runtime!") endif() # setting up different paths diff --git a/Doxyfile b/Doxyfile index 249fed47d3c09ceca1e570b3be4f1a20cb1b13c3..05d73d3cd7cf3ed9322481cfbee1597a488305b6 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2349,7 +2349,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = YES +HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2491,7 +2491,7 @@ INCLUDED_BY_GRAPH = YES # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -CALL_GRAPH = YES +CALL_GRAPH = NO # If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller # dependency graph for every global function or class method. @@ -2503,7 +2503,7 @@ CALL_GRAPH = YES # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -CALLER_GRAPH = YES +CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical # hierarchy of all classes instead of a textual one. diff --git a/README.md b/README.md index 62efc4df4a929963f8581c1c2cc66796f4c6a80d..fa0d833ea8ba66c6851296a4e12b5d06d7ab0406 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ The following modules will be provided in this repository and they will automati - [Asset-Loader](modules/asset_loader/README.md) - [Camera](modules/asset_loader/README.md) - [GUI](modules/gui/README.md) + - [Effects](modules/effects/README.md) - [Material](modules/material/README.md) - [Meshlet](modules/meshlet/README.md) - [Scene](modules/scene/README.md) diff --git a/config/Libraries.cmake b/config/Libraries.cmake index ca2af95ef5533ffaf36cbd439f58cf9bd8e28854..fb4677e6e13698dcae87657290463253f40d1c1e 100644 --- a/config/Libraries.cmake +++ b/config/Libraries.cmake @@ -3,7 +3,8 @@ set(vkcv_config_lib ${vkcv_config}/lib) set(vkcv_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_lib}) if(NOT WIN32) - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if (((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.1.0")) OR + ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0"))) set(vkcv_libraries stdc++fs) endif() diff --git a/config/Sources.cmake b/config/Sources.cmake index 606dc4c97d62ed284d5967707e07237ebd2f7580..ad7b1bbf84ea515af449b81c505de24d8cf0ecf9 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -17,7 +17,6 @@ set(vkcv_sources ${vkcv_source}/vkcv/File.cpp ${vkcv_include}/vkcv/PassConfig.hpp - ${vkcv_source}/vkcv/PassConfig.cpp ${vkcv_source}/vkcv/PassManager.hpp ${vkcv_source}/vkcv/PassManager.cpp @@ -42,6 +41,9 @@ set(vkcv_sources ${vkcv_source}/vkcv/ImageManager.cpp ${vkcv_include}/vkcv/Logger.hpp + + ${vkcv_include}/vkcv/Surface.hpp + ${vkcv_source}/vkcv/Surface.cpp ${vkcv_include}/vkcv/Swapchain.hpp ${vkcv_source}/vkcv/Swapchain.cpp @@ -83,6 +85,9 @@ set(vkcv_sources ${vkcv_include}/vkcv/DescriptorConfig.hpp ${vkcv_source}/vkcv/DescriptorConfig.cpp + ${vkcv_include}/vkcv/DescriptorWrites.hpp + ${vkcv_source}/vkcv/DescriptorWrites.cpp + ${vkcv_source}/vkcv/SamplerManager.hpp ${vkcv_source}/vkcv/SamplerManager.cpp @@ -97,7 +102,7 @@ set(vkcv_sources ${vkcv_include}/vkcv/DrawcallRecording.hpp ${vkcv_source}/vkcv/DrawcallRecording.cpp - ${vkcv_include}/vkcv/CommandStreamManager.hpp + ${vkcv_source}/vkcv/CommandStreamManager.hpp ${vkcv_source}/vkcv/CommandStreamManager.cpp ${vkcv_include}/vkcv/CommandRecordingFunctionTypes.hpp diff --git a/config/lib/SPIRV_Cross.cmake b/config/lib/SPIRV_Cross.cmake index ce4b2e437467436daa7e1bc04975be4fa9609fef..c6304606a14a30f8de7dba1fe2e479ed63743e1e 100644 --- a/config/lib/SPIRV_Cross.cmake +++ b/config/lib/SPIRV_Cross.cmake @@ -1,3 +1,4 @@ + find_package(spirv_cross_c_shared QUIET) if (spirv-cross_FOUND) @@ -31,4 +32,4 @@ else() message(${vkcv_config_msg} " SPIRV Cross - " ${SPIRV_CROSS_VERSION}) endif () -endif () \ No newline at end of file +endif () diff --git a/include/vkcv/Buffer.hpp b/include/vkcv/Buffer.hpp index 992093061e254ce7c71d382a60f07ce08ca71cfd..52056d9f0441f807aa802ef3d29b31e2129b605c 100644 --- a/include/vkcv/Buffer.hpp +++ b/include/vkcv/Buffer.hpp @@ -1,16 +1,22 @@ #pragma once /** - * @authors Lars Hoerttrich, Tobias Frisch + * @authors Tobias Frisch, Lars Hoerttrich, Alexander Gauggel * @file vkcv/Buffer.hpp - * @brief template buffer class, template for type security, implemented here because template classes can't be written in .cpp + * @brief Template buffer class for type security with buffers. */ -#include "Handles.hpp" -#include "BufferManager.hpp" #include <vector> +#include "Handles.hpp" +#include "BufferManager.hpp" + namespace vkcv { + /** + * @brief Template class for buffer handling and filling data. + * + * @tparam T Buffer content type + */ template<typename T> class Buffer { friend class Core; @@ -18,44 +24,96 @@ namespace vkcv { // explicit destruction of default constructor Buffer() = delete; + /** + * @brief Returns the buffers handle. + * + * @return The #BufferHandle to be used with the #Core + */ [[nodiscard]] const BufferHandle& getHandle() const { return m_handle; } + /** + * @brief Returns the type of the buffer. + * + * @return The #BufferType of the #Buffer + */ [[nodiscard]] BufferType getType() const { return m_type; }; + /** + * @brief Returns the count of elements in the buffer. + * + * @return The number of objects of type T the #Buffer holds + */ [[nodiscard]] size_t getCount() const { return m_count; } + /** + * @brief Returns the size of the buffer in bytes. + * + * @return The size of the #Buffer in bytes + */ [[nodiscard]] size_t getSize() const { return m_count * sizeof(T); } + /** + * @brief Returns the vulkan buffer handle of the buffer. + * + * @return The vulkan handle of the #Buffer to be used for manual vulkan commands + */ [[nodiscard]] vk::Buffer getVulkanHandle() const { return m_manager->getBuffer(m_handle); } - - void fill(const T* data, size_t count = 0, size_t offset = 0) { + + /** + * @brief Fills the #Buffer with data of type T. + * + * @param[in] data Pointer to the array of object type T + * @param[in] count The number of objects to copy from the data array + * @param[in] offset The offset into the #Buffer where the data is copied into + */ + void fill(const T* data, + size_t count = 0, + size_t offset = 0) { m_manager->fillBuffer(m_handle, data, count * sizeof(T), offset * sizeof(T)); } - void fill(const std::vector<T>& vector, size_t offset = 0) { + /** + * @brief Fills the #Buffer with data from a vector of type T. + * + * @param vector Vector of type T to be copied into the #Buffer + * @param offset The offset into the #Buffer where the data is copied into + */ + void fill(const std::vector<T>& vector, + size_t offset = 0) { fill( static_cast<const T*>(vector.data()), static_cast<size_t>(vector.size()), offset); } + /** + * @brief Maps memory to the #Buffer and returns it. + * + * @param[in] offset Offset of mapping in objects of type T + * @param[in] count Count of objects of type T that are mapped + * @return Pointer to mapped memory as type T + */ [[nodiscard]] - T* map(size_t offset = 0, size_t count = 0) { + T* map(size_t offset = 0, + size_t count = 0) { return reinterpret_cast<T*>(m_manager->mapBuffer(m_handle, offset * sizeof(T), count * sizeof(T))); } + /** + * @brief Unmaps the #Buffer, invalidates the pointer obtained by map(). + */ void unmap() { m_manager->unmapBuffer(m_handle); } @@ -67,7 +125,20 @@ namespace vkcv { const size_t m_count; const BufferMemoryType m_memoryType; - Buffer(BufferManager* manager, BufferHandle handle, BufferType type, size_t count, BufferMemoryType memoryType) : + /** + * @brief Constructor of the buffer object. + * + * @param[in,out] manager Buffer manager + * @param[in] handle Buffer handle + * @param[in] type Type of buffer + * @param[in] count Count of elements + * @param[in] memoryType Type of memory + */ + Buffer(BufferManager* manager, + BufferHandle handle, + BufferType type, + size_t count, + BufferMemoryType memoryType) : m_manager(manager), m_handle(handle), m_type(type), @@ -75,9 +146,36 @@ namespace vkcv { m_memoryType(memoryType) {} + /** + * @brief Creates a buffer object of type T with + * a selected type, count of elements, memory type + * and support of indirect usage. + * + * @param[in,out] manager Buffer manager + * @param[in] type Buffer type + * @param[in] count Count of elements + * @param[in] memoryType Type of memory + * @param[in] supportIndirect Support indirect usage + * @return New buffer object + */ [[nodiscard]] - static Buffer<T> create(BufferManager* manager, BufferType type, size_t count, BufferMemoryType memoryType, bool supportIndirect) { - return Buffer<T>(manager, manager->createBuffer(type, count * sizeof(T), memoryType, supportIndirect), type, count, memoryType); + static Buffer<T> create(BufferManager* manager, + BufferType type, + size_t count, + BufferMemoryType memoryType, + bool supportIndirect) { + return Buffer<T>( + manager, + manager->createBuffer( + type, + count * sizeof(T), + memoryType, + supportIndirect + ), + type, + count, + memoryType + ); } }; diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp index e4e1e4019f982908ad592466f342b84d3ef52d9a..3ac685b06068c4581202f5371f8dafab5445ecf1 100644 --- a/include/vkcv/BufferManager.hpp +++ b/include/vkcv/BufferManager.hpp @@ -1,4 +1,9 @@ #pragma once +/** + * @authors Tobias Frisch, Alexander Gauggel, Artur Wasmut, Lars Hoerttrich, Sebastian Gaida + * @file vkcv/BufferManager.hpp + * @brief Manager to handle buffer operations. + */ #include <vector> #include <vulkan/vulkan.hpp> @@ -8,6 +13,10 @@ namespace vkcv { + + /** + * @brief Enum class to specify types of buffers. + */ enum class BufferType { INDEX, VERTEX, @@ -17,6 +26,9 @@ namespace vkcv INDIRECT }; + /** + * @brief Enum class to specify types of buffer memory. + */ enum class BufferMemoryType { DEVICE_LOCAL, HOST_VISIBLE @@ -24,6 +36,10 @@ namespace vkcv class Core; + /** + * @brief Class to manage the creation, destruction, allocation + * and filling of buffers. + */ class BufferManager { friend class Core; @@ -63,79 +79,94 @@ namespace vkcv BufferManager& operator=(const BufferManager& other) = delete; /** - * Creates and allocates a new buffer and returns its + * @brief Creates and allocates a new buffer and returns its * unique buffer handle. * - * @param type Type of buffer - * @param size Size of buffer in bytes - * @param memoryType Type of buffers memory + * @param[in] type Type of buffer + * @param[in] size Size of buffer in bytes + * @param[in] memoryType Type of buffers memory + * @param[in] supportIndirect Support of indirect usage * @return New buffer handle */ - BufferHandle createBuffer(BufferType type, size_t size, BufferMemoryType memoryType, bool supportIndirect); + BufferHandle createBuffer(BufferType type, + size_t size, + BufferMemoryType memoryType, + bool supportIndirect); /** - * Returns the Vulkan buffer handle of a buffer + * @brief Returns the Vulkan buffer handle of a buffer * represented by a given buffer handle. * - * @param handle Buffer handle + * @param[in] handle Buffer handle * @return Vulkan buffer handle */ [[nodiscard]] vk::Buffer getBuffer(const BufferHandle& handle) const; /** - * Returns the size of a buffer represented + * @brief Returns the size of a buffer represented * by a given buffer handle. * - * @param handle Buffer handle + * @param[in] 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 + * @brief Returns the Vulkan device memory handle of a buffer * represented by a given buffer handle id. * - * @param handle Buffer handle + * @param[in] handle Buffer handle * @return Vulkan device memory handle */ [[nodiscard]] vk::DeviceMemory getDeviceMemory(const BufferHandle& handle) const; /** - * Fills a buffer represented by a given buffer + * @brief Fills a buffer represented by a given buffer * handle with custom data. * - * @param handle Buffer handle - * @param data Pointer to data - * @param size Size of data in bytes - * @param offset Offset to fill in data in bytes + * @param[in] handle Buffer handle + * @param[in] data Pointer to data + * @param[in] size Size of data in bytes + * @param[in] offset Offset to fill in data in bytes */ - void fillBuffer(const BufferHandle& handle, const void* data, size_t size, size_t offset); + void fillBuffer(const BufferHandle& handle, + const void* data, + size_t size, + size_t offset); /** - * Maps memory to a buffer represented by a given + * @brief Maps memory to a buffer represented by a given * buffer handle and returns it. * - * @param handle Buffer handle - * @param offset Offset of mapping in bytes - * @param size Size of mapping in bytes + * @param[in] handle Buffer handle + * @param[in] offset Offset of mapping in bytes + * @param[in] size Size of mapping in bytes * @return Pointer to mapped memory */ - void* mapBuffer(const BufferHandle& handle, size_t offset, size_t size); + void* mapBuffer(const BufferHandle& handle, + size_t offset, + size_t size); /** - * Unmaps memory from a buffer represented by a given + * @brief Unmaps memory from a buffer represented by a given * buffer handle. * - * @param handle Buffer handle + * @param[in] handle Buffer handle */ void unmapBuffer(const BufferHandle& handle); - void recordBufferMemoryBarrier( - const BufferHandle& handle, - vk::CommandBuffer cmdBuffer); + /** + * @brief Records a memory barrier for a buffer, + * synchronizing subsequent accesses to buffer data + * + * @param[in] handle BufferHandle of the buffer + * @param[in] cmdBuffer Vulkan command buffer to record the barrier into + */ + void recordBufferMemoryBarrier(const BufferHandle& handle, + vk::CommandBuffer cmdBuffer); }; } diff --git a/include/vkcv/CommandRecordingFunctionTypes.hpp b/include/vkcv/CommandRecordingFunctionTypes.hpp index c236fb2c717afd2a3bafc4b3a22708cdac942ffe..d8cda4216e6fbd5686240f52fa0838650ef409df 100644 --- a/include/vkcv/CommandRecordingFunctionTypes.hpp +++ b/include/vkcv/CommandRecordingFunctionTypes.hpp @@ -1,8 +1,24 @@ #pragma once -#include "vkcv/Event.hpp" +/** + * @authors Alexander Gauggel, Tobias Frisch + * @file vkcv/CommandRecordingFunctionTypes.hpp + * @brief Abstract function types to handle command recording. + */ + #include <vulkan/vulkan.hpp> +#include "Event.hpp" + namespace vkcv { + + /** + * @brief Function to be called for recording a command buffer. + */ typedef typename event_function<const vk::CommandBuffer&>::type RecordCommandFunction; + + /** + * @brief Function to be called after finishing a given process. + */ typedef typename event_function<>::type FinishCommandFunction; + } \ No newline at end of file diff --git a/include/vkcv/CommandResources.hpp b/include/vkcv/CommandResources.hpp index ffdd6d0315549c7522623f535856bbaffc8e5c6e..8ec868c0a5a353cba2efb2313d4168450f30844b 100644 --- a/include/vkcv/CommandResources.hpp +++ b/include/vkcv/CommandResources.hpp @@ -1,25 +1,113 @@ #pragma once +/** + * @authors Alexander Gauggel, Tobias Frisch + * @file vkcv/CommandResources.hpp + * @brief Support functions to deal with command resources. + */ + #include <vulkan/vulkan.hpp> #include <unordered_set> + #include "QueueManager.hpp" namespace vkcv { + + /** + * @brief Structure to store command pools for given queue families + * of a device. + */ struct CommandResources { std::vector<vk::CommandPool> cmdPoolPerQueueFamily; }; - std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager& queueManager); - CommandResources createCommandResources(const vk::Device& device, const std::unordered_set<int> &familyIndexSet); - void destroyCommandResources(const vk::Device& device, const CommandResources& resources); - vk::CommandBuffer allocateCommandBuffer(const vk::Device& device, const vk::CommandPool cmdPool); - vk::CommandPool chooseCmdPool(const Queue &queue, const CommandResources &cmdResources); - Queue getQueueForSubmit(const QueueType type, const QueueManager &queueManager); - void beginCommandBuffer(const vk::CommandBuffer cmdBuffer, const vk::CommandBufferUsageFlags flags); + /** + * @brief Generates a set of the family indices for all different kinds of + * queues a given queue manager provides. + * + * @param[in] queueManager Queue manager + * @return Set of queue family indices + */ + std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager &queueManager); + + /** + * @brief Creates and returns a new command resources instance containing + * a vector of newly allocated command pools for each different queue family + * index in a given set. + * + * @param[in,out] device Vulkan device + * @param[in] familyIndexSet Set of queue family indices + * @return New command resources + */ + CommandResources createCommandResources(const vk::Device &device, + const std::unordered_set<int> &familyIndexSet); + + /** + * @brief Destroys a command resources instance and deallocates its command + * pools. The command resources will be invalid to use afterwards. + * + * @param[in,out] device Vulkan device + * @param[in,out] resources Command resources + */ + void destroyCommandResources(const vk::Device &device, + const CommandResources &resources); + + /** + * @brief Allocates and returns a new primary command buffer of a given + * command pool. + * + * @param[in,out] device Vulkan device + * @param[in,out] cmdPool Vulkan command pool + * @return New vulkan command buffer + */ + vk::CommandBuffer allocateCommandBuffer(const vk::Device &device, + const vk::CommandPool &cmdPool); + + /** + * @brief Returns the matching command pool of given command resources for + * a specific queue. + * + * @param[in] queue Queue + * @param[in] cmdResources Command resources + * @return Command pool for a given queue + */ + vk::CommandPool chooseCmdPool(const Queue &queue, + const CommandResources &cmdResources); + + /** + * @brief Returns a queue of a given type from a queue manager. + * + * @param[in] type Type of queue + * @param[in] queueManager Queue manager + * @return Queue of a given type + */ + Queue getQueueForSubmit(QueueType type, + const QueueManager &queueManager); + + /** + * @brief Begins the usage of a command buffer with given command buffer + * usage flags. + * + * @param[in] cmdBuffer Vulkan command buffer + * @param[in] flags Command buffer usage flags + */ + void beginCommandBuffer(const vk::CommandBuffer &cmdBuffer, + vk::CommandBufferUsageFlags flags); - void submitCommandBufferToQueue( - const vk::Queue queue, - const vk::CommandBuffer cmdBuffer, - const vk::Fence fence, - const std::vector<vk::Semaphore>& waitSemaphores, - const std::vector<vk::Semaphore>& signalSemaphores); + /** + * @brief Submits a command buffer into a queue with given fence and + * semaphores to wait for or to signal after processing the command + * buffer. + * + * @param[in,out] queue Vulkan queue + * @param[in] cmdBuffer Vulkan command buffer + * @param[in] fence Vulkan fence to wait for + * @param[in] waitSemaphores Vector of semaphores to wait for + * @param[in] signalSemaphores Vector of semaphores to signal + */ + void submitCommandBufferToQueue(vk::Queue queue, + const vk::CommandBuffer &cmdBuffer, + const vk::Fence &fence, + const std::vector<vk::Semaphore>& waitSemaphores, + const std::vector<vk::Semaphore>& signalSemaphores); + } \ No newline at end of file diff --git a/include/vkcv/CommandStreamManager.hpp b/include/vkcv/CommandStreamManager.hpp deleted file mode 100644 index 4af2127ccf6271f1076e3dde05304b8f9c556139..0000000000000000000000000000000000000000 --- a/include/vkcv/CommandStreamManager.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include <vulkan/vulkan.hpp> -#include <vector> -#include "vkcv/Event.hpp" -#include "vkcv/Handles.hpp" -#include "vkcv/CommandRecordingFunctionTypes.hpp" - -namespace vkcv { - - class Core; - - class CommandStreamManager - { - friend class Core; - private: - struct CommandStream { - inline CommandStream(vk::CommandBuffer cmdBuffer, vk::Queue queue, vk::CommandPool cmdPool) - : cmdBuffer(cmdBuffer), cmdPool(cmdPool), queue(queue) {}; - vk::CommandBuffer cmdBuffer; - vk::CommandPool cmdPool; - vk::Queue queue; - std::vector<FinishCommandFunction> callbacks; - }; - - Core* m_core; - std::vector<CommandStream> m_commandStreams; - - CommandStreamManager() noexcept; - - void init(Core* core); - - public: - ~CommandStreamManager() noexcept; - - CommandStreamManager(CommandStreamManager&& other) = delete; - CommandStreamManager(const CommandStreamManager& other) = delete; - - CommandStreamManager& operator=(CommandStreamManager&& other) = delete; - CommandStreamManager& operator=(const CommandStreamManager& other) = delete; - - CommandStreamHandle createCommandStream( - const vk::Queue queue, - vk::CommandPool cmdPool); - - void recordCommandsToStream(const CommandStreamHandle handle, const RecordCommandFunction record); - void addFinishCallbackToStream(const CommandStreamHandle handle, const FinishCommandFunction finish); - void submitCommandStreamSynchronous( - const CommandStreamHandle handle, - std::vector<vk::Semaphore> &waitSemaphores, - std::vector<vk::Semaphore> &signalSemaphores); - - vk::CommandBuffer getStreamCommandBuffer(const CommandStreamHandle handle); - }; - -} \ No newline at end of file diff --git a/include/vkcv/ComputePipelineConfig.hpp b/include/vkcv/ComputePipelineConfig.hpp index 7695f05349e75dadd166340187ca2770f3dc62cc..ab458aa53704ccc1d5dbe2f1024d826b0b337f78 100644 --- a/include/vkcv/ComputePipelineConfig.hpp +++ b/include/vkcv/ComputePipelineConfig.hpp @@ -1,8 +1,8 @@ #pragma once /** * @authors Mark Mints, Tobias Frisch - * @file src/vkcv/ComputePipelineConfig.hpp - * @brief Compute Pipeline Config Struct to hand over required information to Pipeline Creation. + * @file vkcv/ComputePipelineConfig.hpp + * @brief Compute pipeline config struct to hand over required information to pipeline creation. */ #include <vector> @@ -10,10 +10,14 @@ #include "Handles.hpp" #include "ShaderProgram.hpp" -namespace vkcv -{ +namespace vkcv { + + /** + * @brief Structure to configure a compute pipeline before its creation. + */ struct ComputePipelineConfig { ShaderProgram& m_ShaderProgram; std::vector<DescriptorSetLayoutHandle> m_DescriptorSetLayouts; }; + } \ No newline at end of file diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp index 1160857cb2cdbbb0815390ff1f8405dda0f83796..d91855a54c83f17b8251aad7c6fe2cb2591f9add 100644 --- a/include/vkcv/Context.hpp +++ b/include/vkcv/Context.hpp @@ -1,4 +1,9 @@ #pragma once +/** + * @authors Tobias Frisch, Artur Wasmut, Sebastian Gaida, Alexander Gauggel + * @file vkcv/Context.hpp + * @brief Class to handle the instance, device, allocator and features of the current context. + */ #include <vulkan/vulkan.hpp> #include <vk_mem_alloc.hpp> @@ -9,6 +14,15 @@ namespace vkcv { + + /** + * @brief Class to manage core resources for vulkan callbacks. + * + * The class to manage the vulkan resources as an instance, + * a device, a physical device and a memory allocator. Additionally + * instances of this class will hold the feature manager and the + * queue manager. + */ class Context { friend class Core; @@ -24,24 +38,66 @@ namespace vkcv Context & operator=(const Context &other) = delete; // copy assignment Context & operator=(Context &&other) noexcept; // move assignment + /** + * @brief Returns the vulkan instance of the context. + * + * @return Vulkan instance + */ [[nodiscard]] const vk::Instance &getInstance() const; + /** + * @brief Returns the vulkan physical device of the context. + * + * @return Vulkan physical device + */ [[nodiscard]] const vk::PhysicalDevice &getPhysicalDevice() const; + /** + * @brief Returns the vulkan device of the context. + * + * @return Vulkan device + */ [[nodiscard]] const vk::Device &getDevice() const; + /** + * @brief Returns the feature manager of the context. + * + * @return Feature manager + */ [[nodiscard]] const FeatureManager& getFeatureManager() const; + /** + * @brief Returns the queue manager of the context. + * + * @return Queue manager + */ [[nodiscard]] const QueueManager& getQueueManager() const; + /** + * @brief Returns the VMA allocator of the context. + * + * @return VMA allocator + */ [[nodiscard]] const vma::Allocator& getAllocator() const; - + + /** + * @brief Creates a context for a given application with + * a specific name, version, queue requirements, features and + * required instance extensions. + * + * @param applicationName Application name + * @param applicationVersion Application version + * @param queueFlags Queue flags + * @param features Features + * @param instanceExtensions Instance extensions + * @return New context + */ static Context create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags, @@ -50,14 +106,19 @@ namespace vkcv private: /** - * Constructor of #Context requires an @p instance, a @p physicalDevice and a @p device. + * @brief Constructor of #Context requires an @p instance, + * a @p physicalDevice and a @p device. * * @param instance Vulkan-Instance * @param physicalDevice Vulkan-PhysicalDevice * @param device Vulkan-Device */ - Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device, - FeatureManager&& featureManager, QueueManager&& queueManager, vma::Allocator&& allocator) noexcept; + Context(vk::Instance instance, + vk::PhysicalDevice physicalDevice, + vk::Device device, + FeatureManager &&featureManager, + QueueManager &&queueManager, + vma::Allocator &&allocator) noexcept; vk::Instance m_Instance; vk::PhysicalDevice m_PhysicalDevice; @@ -67,4 +128,5 @@ namespace vkcv vma::Allocator m_Allocator; }; + } diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index cac5bdf5d6e4d1cb182d8b9036695378165a5e65..6505599489f405d135d33ce1c4aeeba295e2176a 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -1,7 +1,9 @@ #pragma once /** - * @file src/vkcv/Core.hpp - * @brief Handling of global states regarding dependencies + * @authors Alexander Gauggel, Tobias Frisch, Sebastian Gaida, Artur Wasmut, Lars Hoerttrich, + * Mara Vogt, Mark Mints, Simeon Hermann, Alex Laptop, Katharina Krämer, Vanessa Karolek + * @file vkcv/Core.hpp + * @brief Handling of global states regarding dependencies. */ #include <memory> @@ -25,8 +27,6 @@ #include "Event.hpp" #include "DrawcallRecording.hpp" #include "CommandRecordingFunctionTypes.hpp" -#include "../../src/vkcv/WindowManager.hpp" -#include "../../src/vkcv/SwapchainManager.hpp" #define VKCV_FRAMEWORK_NAME "VkCV" #define VKCV_FRAMEWORK_VERSION (VK_MAKE_VERSION(0, 1, 0)) @@ -46,12 +46,21 @@ namespace vkcv class WindowManager; class SwapchainManager; + /** + * @brief Structure to store details about a queue submission. + */ struct SubmitInfo { QueueType queueType; std::vector<vk::Semaphore> waitSemaphores; std::vector<vk::Semaphore> signalSemaphores; }; + /** + * @brief Class to handle the core functionality of the framework. + * + * The class handles the core functionality of the framework with most + * calls addressing resource management via more simplified abstraction. + */ class Core final { private: @@ -85,8 +94,8 @@ namespace vkcv uint32_t m_currentSwapchainImageIndex; /** - * sets up swapchain images - * @param swapchainHandles of swapchain + * Sets up swapchain images + * @param handle Handle of swapchain */ void setSwapchainImages(SwapchainHandle handle); @@ -113,7 +122,7 @@ namespace vkcv /** * Copy assignment operator of #Core is deleted! * - * @param other Other instance of #Context + * @param other Other instance of Context * @return Reference to itself */ Core & operator=(const Core &other) = delete; @@ -121,29 +130,34 @@ namespace vkcv /** * Move assignment operator of #Core uses default behavior! * - * @param other Other instance of #Context + * @param other Other instance of Context * @return Reference to itself */ Core & operator=(Core &&other) = delete; + /** + * Returns the context of a Core instance. + * + * @return Current Context + */ [[nodiscard]] const Context &getContext() const; /** - * Creates a #Core with given @p applicationName and @p applicationVersion for your application. - * - * It is also possible to require a specific amount of queues, ask for specific queue-flags or - * extensions. This function will take care of the required arguments as best as possible. - * - * To pass a valid version for your application, you should use #VK_MAKE_VERSION(). - * - * @param[in] applicationName Name of the application - * @param[in] applicationVersion Version of the application - * @param[in] queueFlags (optional) Requested flags of queues - * @param[in] instanceExtensions (optional) Requested instance extensions - * @param[in] deviceExtensions (optional) Requested device extensions - * @return New instance of #Context - */ + * Creates a #Core with given @p applicationName and @p applicationVersion for your application. + * + * It is also possible to require a specific amount of queues, ask for specific queue-flags or + * extensions. This function will take care of the required arguments as best as possible. + * + * To pass a valid version for your application, you should use #VK_MAKE_VERSION(). + * + * @param[in] applicationName Name of the application + * @param[in] applicationVersion Version of the application + * @param[in] queueFlags (optional) Requested flags of queues + * @param[in] instanceExtensions (optional) Requested instance extensions + * @param[in] deviceExtensions (optional) Requested device extensions + * @return New instance of #Context + */ static Core create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags = {}, @@ -172,12 +186,11 @@ namespace vkcv ComputePipelineHandle createComputePipeline(const ComputePipelineConfig &config); /** - * Creates a basic vulkan render pass using @p config from the render pass config class and returns it using the @p handle. + * Creates a basic vulkan render pass using @p config from the render pass config class and returns it. * Fixed Functions for pipeline are set with standard values. * * @param config a render pass config object from the render pass config class - * @param handle a handle to return the created vulkan handle - * @return True if render pass creation was successful, False if not + * @return A handle to represent the created pass */ [[nodiscard]] PassHandle createPass(const PassConfig &config); @@ -230,7 +243,7 @@ namespace vkcv Multisampling multisampling = Multisampling::None); /** - * creates a new window and returns it's handle + * Creates a new window and returns it's handle * @param applicationName window name * @param windowWidth * @param windowHeight @@ -245,7 +258,7 @@ namespace vkcv bool resizeable); /** - * getter for window reference + * Getter for window reference * @param handle of the window * @return the window */ @@ -253,14 +266,14 @@ namespace vkcv Window& getWindow(const WindowHandle& handle ); /** - * gets the swapchain of the current focused window + * Gets the swapchain of the current focused window * @return swapchain */ [[nodiscard]] Swapchain& getSwapchainOfCurrentWindow(); /** - * returns the swapchain reference + * Returns the swapchain reference * @param handle of the swapchain * @return swapchain */ @@ -268,7 +281,7 @@ namespace vkcv Swapchain& getSwapchain(const SwapchainHandle &handle); /** - * gets the swapchain handle from the window + * Gets the swapchain handle from the window * @param handle of the window * @return the swapchain from getSwapchain( SwapchainHandle ) */ @@ -276,7 +289,7 @@ namespace vkcv Swapchain& getSwapchain(const WindowHandle &handle); /** - * returns the image width + * Returns the image width * @param image handle * @return imageWidth */ @@ -284,7 +297,7 @@ namespace vkcv uint32_t getImageWidth(const ImageHandle &image); /** - * returns the image height + * Returns the image height * @param image handle * @return imageHeight */ @@ -292,7 +305,7 @@ namespace vkcv uint32_t getImageHeight(const ImageHandle &image); /** - * returns the image format of the image + * Returns the image format of the image * @param image handle * @return imageFormat */ @@ -308,31 +321,66 @@ namespace vkcv [[nodiscard]] uint32_t getImageMipLevels(const ImageHandle &image); - /** TODO: - * @param bindings - * @return + /** + * @brief Creates a descriptor set layout handle by a set of descriptor bindings. + * + * @param bindings Descriptor bindings + * @return Descriptor set layout handle */ [[nodiscard]] - DescriptorSetLayoutHandle createDescriptorSetLayout(const std::unordered_map<uint32_t, DescriptorBinding> &bindingsMap); + DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); + + /** + * @brief Returns the descriptor set layout of a descriptor set layout handle. + * + * @param handle Descriptor set layout handle + * @return Descriptor set layout + */ DescriptorSetLayout getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const; - // TODO: existsDescriptorSetLayout function that checks and returns fitting layout upon existence. - - /** TODO: - * @param setDescriptions - * @return - */ + /** + * @brief Creates a new descriptor set + * + * @param layoutHandle Handle to the layout that the descriptor set will use + * @return Handle that represents the descriptor set + */ [[nodiscard]] DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layoutHandle); + + /** + * @brief Writes resources bindings to a descriptor set + * + * @param handle Handle of the descriptor set + * @param writes Struct containing the resource bindings to be written + * must be compatible with the descriptor set's layout + */ void writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites& writes); + + /** + * @brief Returns information about a descriptor set + * + * @param handle Handle of the descriptor set + * @return Struct containing the descriptor set's vulkan handle, layout handle and descriptor pool index + */ DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const; /** - * @brief start recording command buffers and increment frame index + * @brief Start recording command buffers and increment frame index */ bool beginFrame(uint32_t& width, uint32_t& height, const WindowHandle &windowHandle); + /** + * @brief Records drawcalls to a command stream + * + * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into + * @param renderpassHandle Handle of the renderpass that is used for the drawcalls + * @param pipelineHandle Handle of the pipeline that is used for the drawcalls + * @param pushConstants Push constants that are used for the drawcalls, ignored if constant size is set to 0 + * @param drawcalls Information about each drawcall, consisting of mesh handle, descriptor set bindings and instance count + * @param renderTargets Image handles that are used as render targets + * @param windowHandle Window handle that is used to retrieve the corresponding swapchain + */ void recordDrawcallsToCmdStream( const CommandStreamHandle& cmdStreamHandle, const PassHandle& renderpassHandle, @@ -341,7 +389,22 @@ namespace vkcv const std::vector<DrawcallInfo> &drawcalls, const std::vector<ImageHandle> &renderTargets, const WindowHandle &windowHandle); - + + /** + * @brief Records indirect drawcalls to a command stream + * + * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into + * @param renderpassHandle Handle of the renderpass that is used for the drawcalls + * @param pipelineHandle Handle of the pipeline that is used for the drawcalls + * @param pushConstantData Push constants that are used for the drawcalls, ignored if constant size is set to 0 + * @param compiledDescriptorSet TODO + * @param compiledMesh TODO + * @param drawcalls Information about each drawcall, consisting of mesh handle, descriptor set bindings and instance count + * @param renderTargets Image handles that are used as render targets + * @param indirectBuffer TODO + * @param drawCount TODO + * @param windowHandle Window handle that is used to retrieve the corresponding swapchain + */ void recordIndexedIndirectDrawcallsToCmdStream( const CommandStreamHandle cmdStreamHandle, const PassHandle renderpassHandle, @@ -353,7 +416,18 @@ namespace vkcv const vkcv::Buffer<vk::DrawIndexedIndirectCommand> &indirectBuffer, const uint32_t drawCount, const WindowHandle &windowHandle); - + + /** + * @brief Records mesh shader drawcalls to a command stream + * + * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into + * @param renderpassHandle Handle of the renderpass that is used for the drawcalls + * @param pipelineHandle Handle of the pipeline that is used for the drawcalls + * @param pushConstantData Push constants that are used for the drawcalls, ignored if constant size is set to 0 + * @param drawcalls Information about each drawcall, consisting of descriptor set bindings and task shader dispatch count + * @param renderTargets Image handles that are used as render targets + * @param windowHandle Window handle that is used to retrieve the corresponding swapchain + */ void recordMeshShaderDrawcalls( const CommandStreamHandle& cmdStreamHandle, const PassHandle& renderpassHandle, @@ -362,11 +436,11 @@ namespace vkcv const std::vector<MeshShaderDrawcall>& drawcalls, const std::vector<ImageHandle>& renderTargets, const WindowHandle& windowHandle); - - + /** * Records the rtx ray generation to the @p cmdStreamHandle. * Currently only supports @p closestHit, @p rayGen and @c miss shaderstages @c. + * * @param cmdStreamHandle The command stream handle which receives relevant commands for drawing. * @param rtxPipeline The raytracing pipeline from the RTXModule. * @param rtxPipelineLayout The raytracing pipeline layout from the RTXModule. @@ -390,6 +464,15 @@ namespace vkcv const PushConstants& pushConstants, const WindowHandle windowHandle); + /** + * @brief Record a compute shader dispatch into a command stream + * + * @param cmdStream Handle of the command stream that the dispatch is recorded into + * @param computePipeline Handle of the pipeline that is used for the dispatch + * @param dispatchCount How many work groups are dispatched + * @param descriptorSetUsages Descriptor set bindings of the dispatch + * @param pushConstants Push constant data for the dispatch + */ void recordComputeDispatchToCmdStream( CommandStreamHandle cmdStream, ComputePipelineHandle computePipeline, @@ -397,12 +480,34 @@ namespace vkcv const std::vector<DescriptorSetUsage> &descriptorSetUsages, const PushConstants& pushConstants); + /** + * @brief Record the start of a debug label into a command stream. + * Debug labels are displayed in GPU debuggers, such as RenderDoc + * + * @param cmdStream Handle of the command stream that the label start is recorded into + * @param label Label name, which is displayed in a debugger + * @param color Display color for the label in a debugger + */ void recordBeginDebugLabel(const CommandStreamHandle &cmdStream, const std::string& label, const std::array<float, 4>& color); + /** + * @brief Record the end of a debug label into a command stream + * @param cmdStream Handle of the command stream that the label end is recorded into + */ void recordEndDebugLabel(const CommandStreamHandle &cmdStream); + /** + * @brief Record an indirect compute shader dispatch into a command stream + * + * @param cmdStream Handle of the command stream that the indirect dispatch is recorded into + * @param computePipeline Handle of the pipeline that is used for the indirect dispatch + * @param buffer GPU Buffer from which the dispatch counts are read + * @param bufferArgOffset Offset into the GPU Buffer from where the dispatch counts are read + * @param descriptorSetUsages Descriptor set bindings of the indirect dispatch + * @param pushConstants Push constant data for the indirect dispatch + */ void recordComputeIndirectDispatchToCmdStream( const CommandStreamHandle cmdStream, const ComputePipelineHandle computePipeline, @@ -412,8 +517,8 @@ namespace vkcv const PushConstants& pushConstants); /** - * @brief end recording and present image - */ + * @brief End recording and present image + */ void endFrame( const WindowHandle& windowHandle ); /** @@ -430,46 +535,194 @@ namespace vkcv const RecordCommandFunction &record, const FinishCommandFunction &finish); + /** + * @brief Create a new command stream + * + * @param queueType The type of queue to which the command stream will be submitted to + * @return Handle which represents the command stream + */ CommandStreamHandle createCommandStream(QueueType queueType); + /** + * @brief Record commands to a command stream by providing a function + * + * @param cmdStreamHandle Handle of the command stream to record to + * @param record Recording function + * @param finish Finish function, called after execution of commands is finished + */ void recordCommandsToStream( const CommandStreamHandle cmdStreamHandle, const RecordCommandFunction &record, const FinishCommandFunction &finish); + /** + * @brief Submit command stream to GPU for actual execution + * + * @param handle command stream to submit + */ void submitCommandStream(const CommandStreamHandle& handle); + + /** + * @brief Prepare swapchain image for presentation to screen. + * Handles internal state such as image format, also acts as a memory barrier + * + * @param handle Handle of the command stream to record the preparation commands to + */ void prepareSwapchainImageForPresent(const CommandStreamHandle& handle); + + /** + * @brief Prepare image for use as a sampled image. + * Handles internal state such as image format, also acts as a memory barrier + * + * @param cmdStream Handle of the command stream to record the preparation commands to + * @param image Handle of the image to prepare + */ void prepareImageForSampling(const CommandStreamHandle& cmdStream, const ImageHandle& image); - void prepareImageForStorage(const CommandStreamHandle& cmdStream, const ImageHandle& image); - // normally layout transitions for attachments are handled by the core - // however for manual vulkan use, e.g. ImGui integration, this function is exposed - // this is also why the command buffer is passed directly, instead of the command stream handle + /** + * @brief Prepare image for use as a storage image. + * Handles internal state such as image format, also acts as a memory barrier + * + * @param cmdStream Handle of the command stream to record the preparation commands to + * @param image Handle of the image to prepare + */ + void prepareImageForStorage(const CommandStreamHandle& cmdStream, const ImageHandle& image); + + /** + * @brief Manual trigger to record commands to prepare an image for use as an attachment + * + * normally layout transitions for attachments are handled by the core + * however for manual vulkan use, e.g. ImGui integration, this function is exposed + * this is also why the command buffer is passed directly, instead of the command stream handle + * + * @param cmdBuffer The vulkan command buffer to record to + * @param image Handle of the image to prepare + */ void prepareImageForAttachmentManually(const vk::CommandBuffer& cmdBuffer, const ImageHandle& image); - // if manual vulkan work, e.g. ImGui integration, changes an image layout this function must be used - // to update the internal image state + /** + * @brief Indicate an external change of an image's layout + * + * if manual vulkan work, e.g. ImGui integration, changes an image layout this function must be used + * to update the internal image state + * + * @param image Handle of the image whose layout was changed + * @param layout The current layout of the image + */ void updateImageLayoutManual(const vkcv::ImageHandle& image, const vk::ImageLayout layout); + /** + * @brief Records a memory barrier to synchronize subsequent accesses to the image's data + * + * @param cmdStream Handle of the command stream to record the barrier to + * @param image Handle of the image the barrier belongs to + */ void recordImageMemoryBarrier(const CommandStreamHandle& cmdStream, const ImageHandle& image); + + /** + * @brief Records a buffer barrier to synchronize subsequent accesses to the buffer's data + * + * @param cmdStream Handle of the command stream to record the barrier to + * @param buffer Handle of the buffer the barrier belongs to + */ void recordBufferMemoryBarrier(const CommandStreamHandle& cmdStream, const BufferHandle& buffer); + + /** + * @brief Resolve a source MSAA image into a destination image for further use + * + * @param cmdStream Handle of the command stream to record the resolve to + * @param src The MSAA image that is resolved + * @param dst The target non-MSAA image that is resolved into + */ void resolveMSAAImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst); + /** + * @return Vulkan image view of the current swapchain image + */ [[nodiscard]] vk::ImageView getSwapchainImageView() const; + /** + * @brief Records a generic memory barrier to a command stream + * + * @param cmdStream Handle of the command stream the barrier is recorded to + */ void recordMemoryBarrier(const CommandStreamHandle& cmdStream); + /** + * @brief Record a blit (bit block image transfer) of a source image into a destination image, + * mip 0 is used for both + * + * @param cmdStream Handle of the command stream the blit operation is recorded into + * @param src The source image that is read from + * @param dst The destination image that is written into + * @param filterType The type of interpolation that is used + */ void recordBlitImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst, SamplerFilterType filterType); + /** + * @brief Sets a debug label to a buffer handle. + * + * @param handle Buffer handle + * @param label Debug label + */ void setDebugLabel(const BufferHandle &handle, const std::string &label); + + /** + * @brief Sets a debug label to a pass handle. + * + * @param handle Pass handle + * @param label Debug label + */ void setDebugLabel(const PassHandle &handle, const std::string &label); + + /** + * @brief Sets a debug label to a graphics pipeline handle. + * + * @param handle Graphics pipeline handle + * @param label Debug label + */ void setDebugLabel(const GraphicsPipelineHandle &handle, const std::string &label); + + /** + * @brief Sets a debug label to a compute pipeline handle. + * + * @param handle Compute pipeline handle + * @param label Debug label + */ void setDebugLabel(const ComputePipelineHandle &handle, const std::string &label); + + /** + * @brief Sets a debug label to a descriptor set handle. + * + * @param handle Descriptor set handle + * @param label Debug label + */ void setDebugLabel(const DescriptorSetHandle &handle, const std::string &label); + + /** + * @brief Sets a debug label to a sampler handle. + * + * @param handle Sampler handle + * @param label Debug label + */ void setDebugLabel(const SamplerHandle &handle, const std::string &label); + + /** + * @brief Sets a debug label to an image handle. + * + * @param handle Image handle + * @param label Debug label + */ void setDebugLabel(const ImageHandle &handle, const std::string &label); + + /** + * @brief Sets a debug label to a command stream handle. + * + * @param handle Command stream handle + * @param label Debug label + */ void setDebugLabel(const CommandStreamHandle &handle, const std::string &label); }; diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp index becdb9f843aa254fed6f05dec0c18686fac497d6..bc2435f6246f616c907e206e4a3de62aafaebebc 100644 --- a/include/vkcv/DescriptorConfig.hpp +++ b/include/vkcv/DescriptorConfig.hpp @@ -1,18 +1,23 @@ #pragma once +/** + * @authors Artur Wasmut, Tobias Frisch, Simeon Hermann, Alexander Gauggel, Vanessa Karolek + * @file vkcv/DescriptorConfig.hpp + * @brief Structures to handle descriptor types and bindings. + */ #include <unordered_map> -#include "vkcv/Handles.hpp" -#include "vkcv/ShaderStage.hpp" -#include "vkcv/Logger.hpp" +#include "Handles.hpp" +#include "ShaderStage.hpp" +#include "Logger.hpp" namespace vkcv { - /* - * All the types of descriptors (resources) that can be retrieved by the shaders - */ - enum class DescriptorType - { + + /** + * @brief Enum class to specify the type of a descriptor set binding. + */ + enum class DescriptorType { UNIFORM_BUFFER, STORAGE_BUFFER, SAMPLER, @@ -21,13 +26,15 @@ namespace vkcv UNIFORM_BUFFER_DYNAMIC, STORAGE_BUFFER_DYNAMIC, ACCELERATION_STRUCTURE_KHR - }; + }; /** - * Converts the descriptor types from VulkanCV (vkcv) to native Vulkan (vk). - * @param[in] vkcv DescriptorType - * @return vk DescriptorType - */ + * @brief Converts the descriptor type from the frameworks enumeration + * to the Vulkan type specifier. + * + * @param[in] type Descriptor type + * @return Vulkan descriptor type + */ constexpr vk::DescriptorType getVkDescriptorType(DescriptorType type) noexcept { switch (type) { @@ -51,37 +58,38 @@ namespace vkcv return vk::DescriptorType::eMutableVALVE; } } - - /* - * One binding for a descriptor set - * @param[in] a unique binding ID - * @param[in] a descriptor type - * @param[in] the number of descriptors of this type (arrays of the same type possible) - * @param[in] the shader stage where the descriptor is supposed to be retrieved - */ - struct DescriptorBinding - { - uint32_t bindingID; - DescriptorType descriptorType; - uint32_t descriptorCount; - ShaderStages shaderStages; - bool variableCount; + + /** + * @brief Structure to store details from a descriptor binding. + */ + struct DescriptorBinding { + uint32_t bindingID; + DescriptorType descriptorType; + uint32_t descriptorCount; + ShaderStages shaderStages; + bool variableCount; bool operator ==(const DescriptorBinding &other) const; }; typedef std::unordered_map<uint32_t, DescriptorBinding> DescriptorBindings; - - struct DescriptorSetLayout - { + + /** + * @brief Structure to store details about a descriptor set layout. + */ + struct DescriptorSetLayout { vk::DescriptorSetLayout vulkanHandle; DescriptorBindings descriptorBindings; + size_t layoutUsageCount; }; - - struct DescriptorSet - { - vk::DescriptorSet vulkanHandle; - DescriptorSetLayoutHandle setLayoutHandle; - size_t poolIndex; + + /** + * @brief Structure to store details about a descriptor set. + */ + struct DescriptorSet { + vk::DescriptorSet vulkanHandle; + DescriptorSetLayoutHandle setLayoutHandle; + size_t poolIndex; }; + } diff --git a/include/vkcv/DescriptorWrites.hpp b/include/vkcv/DescriptorWrites.hpp index f4f9729a193c9da4cfc4ccc869337314e8a71ccb..b8468bfdfd4cd20e59742f410ff8716be4e910fa 100644 --- a/include/vkcv/DescriptorWrites.hpp +++ b/include/vkcv/DescriptorWrites.hpp @@ -1,57 +1,209 @@ #pragma once -#include "Handles.hpp" +/** + * @authors Artur Wasmut, Tobias Frisch, Alexander Gauggel, Vanessa Karolek + * @file vkcv/DescriptorWrites.hpp + * @brief Structures to handle descriptor writes. + */ + #include <vector> +#include "Handles.hpp" + namespace vkcv { + + /** + * @brief Structure to store details writing a sampled image to a descriptor set. + */ struct SampledImageDescriptorWrite { - inline SampledImageDescriptorWrite(uint32_t binding, ImageHandle image, uint32_t mipLevel = 0, bool useGeneralLayout = false, uint32_t arrayIndex = 0) - : binding(binding), image(image), mipLevel(mipLevel), useGeneralLayout(useGeneralLayout), arrayIndex(arrayIndex) {}; - uint32_t binding; - ImageHandle image; - uint32_t mipLevel; - bool useGeneralLayout; - uint32_t arrayIndex; + uint32_t binding; + ImageHandle image; + uint32_t mipLevel; + bool useGeneralLayout; + uint32_t arrayIndex; }; - + + /** + * @brief Structure to store details writing a storage image to a descriptor set. + */ struct StorageImageDescriptorWrite { - inline StorageImageDescriptorWrite(uint32_t binding, ImageHandle image, uint32_t mipLevel = 0) - : binding(binding), image(image), mipLevel(mipLevel) {}; - uint32_t binding; - ImageHandle image; - uint32_t mipLevel; + uint32_t binding; + ImageHandle image; + uint32_t mipLevel; }; - + + /** + * @brief Structure to store details writing a buffer to a descriptor set. + */ struct BufferDescriptorWrite { - inline BufferDescriptorWrite(uint32_t binding, BufferHandle buffer, bool dynamic = false, - uint32_t offset = 0, uint32_t size = 0) : - binding(binding), buffer(buffer), dynamic(dynamic), offset(offset), size(size) {}; - uint32_t binding; - BufferHandle buffer; - bool dynamic; - uint32_t offset; - uint32_t size; + uint32_t binding; + BufferHandle buffer; + bool dynamic; + uint32_t offset; + uint32_t size; }; - + + /** + * @brief Structure to store details writing a sampler to a descriptor set. + */ struct SamplerDescriptorWrite { - inline SamplerDescriptorWrite(uint32_t binding, SamplerHandle sampler) : binding(binding), sampler(sampler) {}; - uint32_t binding; - SamplerHandle sampler; + uint32_t binding; + SamplerHandle sampler; }; - + /** - * @brief Only used for RTX. Used to bind the Acceleration Structure. + * @brief Structure to store details writing an acceleration structure to + * a descriptor set. */ struct AccelerationDescriptorWrite { - inline AccelerationDescriptorWrite(uint32_t binding) : binding(binding) {}; - uint32_t binding; + uint32_t binding; }; - struct DescriptorWrites { - std::vector<SampledImageDescriptorWrite> sampledImageWrites; - std::vector<StorageImageDescriptorWrite> storageImageWrites; - std::vector<BufferDescriptorWrite> uniformBufferWrites; - std::vector<BufferDescriptorWrite> storageBufferWrites; - std::vector<SamplerDescriptorWrite> samplerWrites; - std::vector<AccelerationDescriptorWrite> accelerationWrites; + /** + * @brief Class to store details about writing to + * a descriptor set and its bindings. + */ + class DescriptorWrites { + private: + std::vector<SampledImageDescriptorWrite> m_sampledImageWrites; + std::vector<StorageImageDescriptorWrite> m_storageImageWrites; + std::vector<BufferDescriptorWrite> m_uniformBufferWrites; + std::vector<BufferDescriptorWrite> m_storageBufferWrites; + std::vector<SamplerDescriptorWrite> m_samplerWrites; + std::vector<AccelerationDescriptorWrite> m_accelerationWrites; + + public: + /** + * @brief Adds an entry to write an image to a given binding + * of a descriptor set to sample from it using specific details. + * + * @param[in] binding Binding index + * @param[in] image Image handle + * @param[in] mipLevel Mip level index + * @param[in] useGeneralLayout Flag to use a general layout + * @param[in] arrayIndex Image array index + * @return Instance of descriptor writes + */ + DescriptorWrites& writeSampledImage(uint32_t binding, + ImageHandle image, + uint32_t mipLevel = 0, + bool useGeneralLayout = false, + uint32_t arrayIndex = 0); + + /** + * @brief Adds an entry to write an image to a given binding + * of a descriptor set to store into it using specific details. + * + * @param[in] binding Binding index + * @param[in,out] image Image handle + * @param[in] mipLevel Mip level index + * @return Instance of descriptor writes + */ + DescriptorWrites& writeStorageImage(uint32_t binding, + ImageHandle image, + uint32_t mipLevel = 0); + + /** + * @brief Adds an entry to write a buffer to a given binding + * of a descriptor set as uniform buffer using specific details. + * + * @param[in] binding Binding index + * @param[in] buffer Buffer handle + * @param[in] dynamic Flag to use dynamic access + * @param[in] offset Offset for buffer access range + * @param[in] size Size of the buffer access range + * @return Instance of descriptor writes + */ + DescriptorWrites& writeUniformBuffer(uint32_t binding, + BufferHandle buffer, + bool dynamic = false, + uint32_t offset = 0, + uint32_t size = 0); + + /** + * @brief Adds an entry to write a buffer to a given binding + * of a descriptor set as storage buffer using specific details. + * + * @param[in] binding Binding index + * @param[in] buffer Buffer handle + * @param[in,out] dynamic Flag to use dynamic access + * @param[in] offset Offset for buffer access range + * @param[in] size Size of the buffer access range + * @return Instance of descriptor writes + */ + DescriptorWrites& writeStorageBuffer(uint32_t binding, + BufferHandle buffer, + bool dynamic = false, + uint32_t offset = 0, + uint32_t size = 0); + + /** + * @brief Adds an entry to write a sampler to a given binding + * of a descriptor set. + * + * @param[in] binding Binding index + * @param[in] sampler Sampler handle + * @return Instance of descriptor writes + */ + DescriptorWrites& writeSampler(uint32_t binding, + SamplerHandle sampler); + + /** + * @brief Adds an entry for acceleration to a given binding + * of a descriptor set. + * + * @param[in] binding Binding index + * @return Instance of descriptor writes + */ + DescriptorWrites& writeAcceleration(uint32_t binding); + + /** + * @brief Returns the list of stored write entries for sampled images. + * + * @return Sampled image write details + */ + [[nodiscard]] + const std::vector<SampledImageDescriptorWrite>& getSampledImageWrites() const; + + /** + * @brief Returns the list of stored write entries for storage images. + * + * @return Storage image write details + */ + [[nodiscard]] + const std::vector<StorageImageDescriptorWrite>& getStorageImageWrites() const; + + /** + * @brief Returns the list of stored write entries for uniform buffers. + * + * @return Uniform buffers write details + */ + [[nodiscard]] + const std::vector<BufferDescriptorWrite>& getUniformBufferWrites() const; + + /** + * @brief Returns the list of stored write entries for storage buffers. + * + * @return Storage buffers write details + */ + [[nodiscard]] + const std::vector<BufferDescriptorWrite>& getStorageBufferWrites() const; + + /** + * @brief Returns the list of stored write entries for samplers. + * + * @return Samplers write details + */ + [[nodiscard]] + const std::vector<SamplerDescriptorWrite>& getSamplerWrites() const; + + /** + * @brief Returns the list of stored write entries for accelerations. + * + * @return Accelerations write details + */ + [[nodiscard]] + const std::vector<AccelerationDescriptorWrite>& getAccelerationWrites() const; + }; + } \ No newline at end of file diff --git a/include/vkcv/DrawcallRecording.hpp b/include/vkcv/DrawcallRecording.hpp index 70b23107c4605e6ac01aa80fa4a431c62d7a7219..76b94dc8b4f8595d98e87920329eb616d703f0db 100644 --- a/include/vkcv/DrawcallRecording.hpp +++ b/include/vkcv/DrawcallRecording.hpp @@ -1,82 +1,104 @@ #pragma once +/** + * @authors Sebastian Gaida, Alexander Gauggel, Artur Wasmut, Tobias Frisch + * @file vkcv/DrawcallRecording.hpp + * @brief Structures and functions to record drawcalls. + */ + #include <vulkan/vulkan.hpp> -#include "vkcv/Handles.hpp" -#include "vkcv/DescriptorConfig.hpp" -#include "vkcv/PushConstants.hpp" + +#include "Handles.hpp" +#include "DescriptorConfig.hpp" +#include "PushConstants.hpp" + #include "Buffer.hpp" namespace vkcv { + /** + * @brief Structure to store details about a vertex buffer binding. + */ struct VertexBufferBinding { - inline VertexBufferBinding(vk::DeviceSize offset, vk::Buffer buffer) noexcept - : offset(offset), buffer(buffer) {} - - vk::DeviceSize offset; - vk::Buffer buffer; + vk::DeviceSize offset; + vk::Buffer buffer; }; - enum class IndexBitCount{ + /** + * @brief Enum class to specify the size of indexes. + */ + enum class IndexBitCount { + Bit8, Bit16, Bit32 }; - + + /** + * @brief Structure to configure a descriptor set usage. + */ struct DescriptorSetUsage { inline DescriptorSetUsage(uint32_t setLocation, DescriptorSetHandle descriptorSet, - const std::vector<uint32_t>& dynamicOffsets = {}) noexcept - : setLocation(setLocation), descriptorSet(descriptorSet), dynamicOffsets(dynamicOffsets) {} + const std::vector<uint32_t>& dynamicOffsets = {}) noexcept : + setLocation(setLocation), + descriptorSet(descriptorSet), + dynamicOffsets(dynamicOffsets) {} const uint32_t setLocation; const DescriptorSetHandle descriptorSet; const std::vector<uint32_t> dynamicOffsets; }; - + + /** + * @brief Structure to store details of a mesh to draw. + */ struct Mesh { - - inline Mesh(){} - - inline Mesh( - std::vector<VertexBufferBinding> vertexBufferBindings, - vk::Buffer indexBuffer, - size_t indexCount, - IndexBitCount indexBitCount = IndexBitCount::Bit16) noexcept - : - vertexBufferBindings(vertexBufferBindings), - indexBuffer(indexBuffer), + inline Mesh() {} + + inline Mesh(std::vector<VertexBufferBinding> vertexBufferBindings, + vk::Buffer indexBuffer, + size_t indexCount, + IndexBitCount indexBitCount = IndexBitCount::Bit16) noexcept : + vertexBufferBindings(vertexBufferBindings), + indexBuffer(indexBuffer), indexCount(indexCount), indexBitCount(indexBitCount) {} - std::vector<VertexBufferBinding> vertexBufferBindings; - vk::Buffer indexBuffer; - size_t indexCount; - IndexBitCount indexBitCount; + std::vector<VertexBufferBinding> vertexBufferBindings; + vk::Buffer indexBuffer; + size_t indexCount; + IndexBitCount indexBitCount; }; - + + /** + * @brief Structure to store details for a drawcall. + */ struct DrawcallInfo { - inline DrawcallInfo(const Mesh& mesh, const std::vector<DescriptorSetUsage>& descriptorSets, const uint32_t instanceCount = 1) - : mesh(mesh), descriptorSets(descriptorSets), instanceCount(instanceCount){} - - Mesh mesh; + inline DrawcallInfo(const Mesh& mesh, + const std::vector<DescriptorSetUsage>& descriptorSets, + const uint32_t instanceCount = 1) : + mesh(mesh), + descriptorSets(descriptorSets), + instanceCount(instanceCount){} + + Mesh mesh; std::vector<DescriptorSetUsage> descriptorSets; - uint32_t instanceCount; + uint32_t instanceCount; }; - - void InitMeshShaderDrawFunctions(vk::Device device); - + + /** + * @brief Structure to store details for a mesh shader drawcall. + */ struct MeshShaderDrawcall { - inline MeshShaderDrawcall(const std::vector<DescriptorSetUsage> descriptorSets, uint32_t taskCount) - : descriptorSets(descriptorSets), taskCount(taskCount) {} - std::vector<DescriptorSetUsage> descriptorSets; - uint32_t taskCount; + uint32_t taskCount; }; - void recordMeshShaderDrawcall( - const Core& core, - vk::CommandBuffer cmdBuffer, - vk::PipelineLayout pipelineLayout, - const PushConstants& pushConstantData, - const uint32_t pushConstantOffset, - const MeshShaderDrawcall& drawcall, - const uint32_t firstTask); + void recordMeshShaderDrawcall(const Core& core, + vk::CommandBuffer cmdBuffer, + vk::PipelineLayout pipelineLayout, + const PushConstants& pushConstantData, + uint32_t pushConstantOffset, + const MeshShaderDrawcall& drawcall, + uint32_t firstTask); + } diff --git a/include/vkcv/Event.hpp b/include/vkcv/Event.hpp index 0a5cc1f0d93b6eebea6a54cd8d48632ea4c0be31..c4a05d0e126c2a44a67cfb4e1aad7d07ad6efaa5 100644 --- a/include/vkcv/Event.hpp +++ b/include/vkcv/Event.hpp @@ -1,4 +1,9 @@ #pragma once +/** + * @authors Tobias Frisch, Sebastian Gaida, Josch Morgenstern, Katharina Krämer + * @file vkcv/Event.hpp + * @brief Template event struct to synchronize callbacks. + */ #include <functional> @@ -14,11 +19,21 @@ namespace vkcv { + /** + * @brief Template for a function handle to an event + * + * @tparam T Event parameter type list + */ template<typename... T> struct event_handle { uint32_t id; }; + /** + * @brief Template for an event function + * + * @tparam T Event parameter type list + */ template<typename... T> struct event_function { typedef std::function<void(T...)> type; @@ -28,8 +43,9 @@ namespace vkcv { }; /** - * template for event handling - * @tparam T parameter list + * @brief Template for event handling + * + * @tparam T Event parameter type list */ template<typename... T> struct event { @@ -48,8 +64,9 @@ namespace vkcv { public: /** - * calls all function handles with the given arguments - * @param arguments of the given function + * @brief Calls all function handles with the given arguments. + * + * @param[in,out] arguments Arguments of the given event */ void operator()(T... arguments) { lock(); @@ -62,9 +79,10 @@ namespace vkcv { } /** - * adds a function handle to the event to be called - * @param callback of the function - * @return handle of the function + * @brief Adds a function handle to the event to be called. + * + * @param[in] callback Event callback + * @return Handle of the function */ event_handle<T...> add(typename event_function<T...>::type callback) { event_function<T...> function; @@ -75,8 +93,9 @@ namespace vkcv { } /** - * removes a function handle of the event - * @param handle of the function + * @brief Removes a function handle of the event. + * + * @param handle Handle of the function */ void remove(event_handle<T...> handle) { this->m_functions.erase( @@ -88,7 +107,8 @@ namespace vkcv { } /** - * locks the event so its function handles won't be called + * @brief Locks the event so its function handles won't + * be called until unlocked. */ void lock() { #ifndef __MINGW32__ @@ -101,8 +121,9 @@ namespace vkcv { } /** - * unlocks the event so its function handles can be called after locking - */ + * @brief Unlocks the event so its function handles can + * be called after locking. + */ void unlock() { #ifndef __MINGW32__ #ifdef __NO_SEMAPHORES__ @@ -136,5 +157,7 @@ namespace vkcv { event &operator=(const event &other) = delete; event &operator=(event &&other) = delete; + }; + } diff --git a/include/vkcv/FeatureManager.hpp b/include/vkcv/FeatureManager.hpp index 5d5a2e9a7ca839c1cbd2cfa53d0f61d042ac3b2a..51e422c949b66fe021ec3a5afd95f50a94e39544 100644 --- a/include/vkcv/FeatureManager.hpp +++ b/include/vkcv/FeatureManager.hpp @@ -1,152 +1,403 @@ #pragma once - -#include "Logger.hpp" +/** + * @authors Tobias Frisch, Artur Wasmut, Vanessa Karolek, Sebastian Gaida + * @file vkcv/FeatureManager.hpp + * @brief Class to manage feature support and extension usage. + */ #include <functional> #include <unordered_set> #include <vector> #include <vulkan/vulkan.hpp> +#include "Logger.hpp" + namespace vkcv { + /** + * @brief Class to manage extension and feature requirements, support and usage. + */ class FeatureManager { private: + /** + * Physical device to check feature support against. + */ vk::PhysicalDevice& m_physicalDevice; + /** + * List of supported extensions. + */ std::vector<const char*> m_supportedExtensions; + + /** + * List of activated extensions for usage. + */ std::vector<const char*> m_activeExtensions; + /** + * Feature structure chain to request activated features. + */ vk::PhysicalDeviceFeatures2 m_featuresBase; + + /** + * List of base structures allocated to request extension specific features. + */ std::vector<vk::BaseOutStructure*> m_featuresExtensions; + /** + * @brief Checks support of the @p vk::PhysicalDeviceFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceFeatures& features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDevice16BitStorageFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDevice16BitStorageFeatures& features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDevice8BitStorageFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDevice8BitStorageFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceBufferDeviceAddressFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceBufferDeviceAddressFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceDescriptorIndexingFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceDescriptorIndexingFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceHostQueryResetFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceHostQueryResetFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceImagelessFramebufferFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceImagelessFramebufferFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceMultiviewFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceMultiviewFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceProtectedMemoryFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceProtectedMemoryFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceSamplerYcbcrConversionFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceSamplerYcbcrConversionFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceScalarBlockLayoutFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceScalarBlockLayoutFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceShaderAtomicInt64Features. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceShaderAtomicInt64Features &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceShaderFloat16Int8Features. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceShaderFloat16Int8Features& features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceTimelineSemaphoreFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceTimelineSemaphoreFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceUniformBufferStandardLayoutFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceUniformBufferStandardLayoutFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceVariablePointersFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceVariablePointersFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceVulkanMemoryModelFeatures. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceVulkanMemoryModelFeatures &features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceMeshShaderFeaturesNV. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceMeshShaderFeaturesNV& features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceShaderAtomicFloatFeaturesEXT. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceShaderAtomicFloatFeaturesEXT& features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false + */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT& features, bool required) const; /** - * @brief Currently used for RTX. Checks support of the @p vk::PhysicalDeviceVulkan12Features. - * @param features The features. - * @param required True, if the @p features are required, else false. - * @return @p True, if the @p features are supported, else @p false. + * @brief Checks support of the @p vk::PhysicalDeviceVulkan12Features. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceVulkan12Features& features, bool required) const; /** - * @brief Currently used for RTX. Checks support of the @p vk::PhysicalDeviceVulkan11Features. - * @param features The features. - * @param required True, if the @p features are required, else false. - * @return @p True, if the @p features are supported, else @p false. + * @brief Checks support of the @p vk::PhysicalDeviceVulkan11Features. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceVulkan11Features& features, bool required) const; /** - * @brief Only used for RTX. Checks support of the @p vk::PhysicalDeviceAccelerationStructureFeaturesKHR. - * @param features The features. - * @param required True, if the @p features are required, else false. - * @return @p True, if the @p features are supported, else @p false. + * @brief Checks support of the @p vk::PhysicalDeviceAccelerationStructureFeaturesKHR. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceAccelerationStructureFeaturesKHR& features, bool required) const; /** - * @brief Only used for RTX. Checks support of the @p vk::PhysicalDeviceRayTracingPipelineFeaturesKHR. - * @param features The features. - * @param required True, if the @p features are required, else false. - * @return @p True, if the @p features are supported, else @p false. + * @brief Checks support of the @p vk::PhysicalDeviceRayTracingPipelineFeaturesKHR. + * + * @param[in] features The features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the @p features are supported, else @p false */ [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceRayTracingPipelineFeaturesKHR& features, bool required) const; + /** + * @brief Searches for a base structure of a given structure type. + * + * @param[in] type Structure type + * @return Pointer to first matching base structure or nullptr + */ + [[nodiscard]] vk::BaseOutStructure* findFeatureStructure(vk::StructureType type) const; public: + /** + * @brief Constructor of a feature manager with a given physical device. + * + * @param[in,out] physicalDevice Physical device + */ explicit FeatureManager(vk::PhysicalDevice& physicalDevice); FeatureManager(const FeatureManager& other) = delete; + + /** + * @brief Move-constructor of a feature manager. + * + * @param[in,out] other Other feature manager instance + */ FeatureManager(FeatureManager&& other) noexcept; + /** + * @brief Destructor of a feature manager. + */ ~FeatureManager(); FeatureManager& operator=(const FeatureManager& other) = delete; + + /** + * @brief Move-operator of a feature manager. + * + * @param[in,out] other Other feature manager instance + * @return Reference to the feature manager itself + */ FeatureManager& operator=(FeatureManager&& other) noexcept; + /** + * @brief Check if a specific extension is supported by the managers physical device. + * + * @param[in] extension Extension identifier string + * @return @p True, if the @p extension is supported, else @p false + */ [[nodiscard]] bool isExtensionSupported(const std::string& extension) const; + /** + * @brief Activate a specific extension if supported by the managers physical device. + * + * @param[in] extension Extension identifier string + * @param[in] required True, if the @p extension is required, else false + * @return @p True, if the @p extension could be activated, else @p false + */ bool useExtension(const std::string& extension, bool required = true); + /** + * @brief Check if a specific extension is activated by the manager. + * + * @param[in] extension Extension identifier string + * @return @p True, if the @p extension is activated, else @p false + */ [[nodiscard]] bool isExtensionActive(const std::string& extension) const; + /** + * @brief Return list of activated extensions for usage. + * + * @return List of activated extensions + */ [[nodiscard]] const std::vector<const char*>& getActiveExtensions() const; + /** + * @brief Request specific features for optional or required usage ( only core Vulkan 1.0 ). + * + * @param[in] featureFunction Function or lambda to request specific features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the requested features could be activated, else @p false + */ bool useFeatures(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction, bool required = true); + /** + * @brief Request specific features for optional or required usage. + * + * @tparam T Template parameter to use specific base structure types + * @param[in] featureFunction Function or lambda to request specific features + * @param[in] required True, if the @p features are required, else false + * @return @p True, if the requested features could be activated, else @p false + * @see checkSupport() + */ template<typename T> bool useFeatures(const std::function<void(T&)>& featureFunction, bool required = true) { T features; @@ -188,6 +439,11 @@ namespace vkcv { return true; } + /** + * @brief Return feature structure chain to request activated features. + * + * @return Head of feature structure chain + */ [[nodiscard]] const vk::PhysicalDeviceFeatures2& getFeatures() const; diff --git a/include/vkcv/Features.hpp b/include/vkcv/Features.hpp index 6ef3fa28be912627b4495c66427336dfaa51beff..bb0e88c2b52775f00e5d74804d055fe35ee6bd58 100644 --- a/include/vkcv/Features.hpp +++ b/include/vkcv/Features.hpp @@ -1,4 +1,9 @@ #pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Features.hpp + * @brief Class to manage feature requests. + */ #include <functional> #include <vector> @@ -8,30 +13,92 @@ namespace vkcv { + /** + * Abstract function type to request a feature via the feature manager. + */ typedef std::function<bool(FeatureManager&)> Feature; + /** + * @brief Class to manage a list of feature requests at once. + */ class Features { private: + /** + * List of feature requests. + */ std::vector<Feature> m_features; public: + /** + * @brief Constructor of a features instance. + */ Features() = default; + /** + * @brief Constructor of a features instance with a given list of extension identifier strings. + * + * @param[in] list List of extension identifier strings + */ Features(const std::initializer_list<std::string>& list); + /** + * @brief Copy-constructor of a features instance. + * + * @param[in] other Other features instance + */ Features(const Features& other) = default; + + /** + * @brief Move-constructor of a features instance. + * + * @param[in,out] other Other features instance + */ Features(Features&& other) = default; + /** + * @brief Destructor of a features instance. + */ ~Features() = default; + /** + * @brief Copy-operator of a features instance. + * + * @param[in] other Other features instance + * @return Reference to the features instance itself + */ Features& operator=(const Features& other) = default; + + /** + * @brief Move-operator of a features instance. + * + * @param[in,out] other Other features instance + * @return Reference to the features instance itself + */ Features& operator=(Features&& other) = default; + /** + * @brief Request a specific extension as required. + * + * @param[in] extension Extension identifier string + */ void requireExtension(const std::string& extension); + /** + * @brief Request a specific extension and some of its features as required ( only core Vulkan 1.0 ). + * + * @param[in] extension Extension identifier string + * @param[in] featureFunction + */ void requireExtensionFeature(const std::string& extension, const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + /** + * @brief Request a specific extension and some of its features as required. + * + * @tparam T Template parameter to use specific base structure types + * @param[in] extension Extension identifier string + * @param[in] featureFunction Function or lambda to request specific features + */ template<typename T> void requireExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) { m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) { @@ -43,8 +110,19 @@ namespace vkcv { }); } + /** + * @brief Request a specific set of features as required ( only core Vulkan 1.0 ). + * + * @param[in] featureFunction Function or lambda to request specific features + */ void requireFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + /** + * @brief Request a specific set of features as required. + * + * @tparam T Template parameter to use specific base structure types + * @param[in] featureFunction Function or lambda to request specific features + */ template<typename T> void requireFeature(const std::function<void(T&)>& featureFunction) { m_features.emplace_back([featureFunction](FeatureManager& featureManager) { @@ -52,11 +130,29 @@ namespace vkcv { }); } + /** + * @brief Request a specific extension as optional. + * + * @param[in] extension Extension identifier string + */ void tryExtension(const std::string& extension); + /** + * @brief Request a specific extension and some of its features as optional ( only core Vulkan 1.0 ). + * + * @param[in] extension Extension identifier string + * @param[in] featureFunction Function or lambda to request specific features + */ void tryExtensionFeature(const std::string& extension, const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + /** + * @brief Request a specific extension and some of its features as optional. + * + * @tparam T Template parameter to use specific base structure types + * @param[in] extension Extension identifier string + * @param[in] featureFunction Function or lambda to request specific features + */ template<typename T> void tryExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) { m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) { @@ -68,8 +164,19 @@ namespace vkcv { }); } + /** + * @brief Request a specific set of features as optional ( only core Vulkan 1.0 ). + * + * @param[in] featureFunction Function or lambda to request specific features + */ void tryFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + /** + * @brief Request a specific set of features as optional. + * + * @tparam T Template parameter to use specific base structure types + * @param[in] featureFunction Function or lambda to request specific features + */ template<typename T> void tryFeature(const std::function<void(T&)>& featureFunction) { m_features.emplace_back([featureFunction](FeatureManager& featureManager) { @@ -77,6 +184,11 @@ namespace vkcv { }); } + /** + * @brief Return list of feature requests. + * + * @return List of feature requests + */ [[nodiscard]] const std::vector<Feature>& getList() const; diff --git a/include/vkcv/File.hpp b/include/vkcv/File.hpp index 06f1c48593853147140b2c8c68c675d52c9dfaec..4d81f368b03d374fe4f83bf197a76ddd8a6b034a 100644 --- a/include/vkcv/File.hpp +++ b/include/vkcv/File.hpp @@ -1,11 +1,26 @@ #pragma once +/** + * @authors Tobias Frisch + * @file vkcv/File.hpp + * @brief Functions to handle generating temporary file paths. + */ #include <filesystem> namespace vkcv { + /** + * @brief Generate a new temporary file path and return it. + * + * @return A unique path for a temporary file + */ std::filesystem::path generateTemporaryFilePath(); + /** + * @brief Generate a new temporary directory path and return it. + * + * @return A unique path for a temporary directory + */ std::filesystem::path generateTemporaryDirectoryPath(); } diff --git a/include/vkcv/GraphicsPipelineConfig.hpp b/include/vkcv/GraphicsPipelineConfig.hpp index 286411969a5aa1ce818735faea238f246adb40d6..85cabc135ddfa8e6e6762c16c269741e232cff4d 100644 --- a/include/vkcv/GraphicsPipelineConfig.hpp +++ b/include/vkcv/GraphicsPipelineConfig.hpp @@ -1,12 +1,13 @@ #pragma once /** - * @authors Mara Vogt, Mark Mints - * @file src/vkcv/PipelineConfig.hpp + * @authors Mara Vogt, Mark Mints, Tobias Frisch + * @file vkcv/GraphicsPipelineConfig.hpp * @brief Graphics Pipeline Config Struct to hand over required information to Pipeline Creation */ #include <vector> #include <cstdint> + #include "Handles.hpp" #include "ShaderProgram.hpp" #include "VertexLayout.hpp" @@ -14,14 +15,51 @@ namespace vkcv { - enum class PrimitiveTopology{PointList, LineList, TriangleList, PatchList }; - enum class CullMode{ None, Front, Back }; - enum class DepthTest { None, Less, LessEqual, Greater, GreatherEqual, Equal }; + /** + * @brief Enum class to specify types of primitive topology. + */ + enum class PrimitiveTopology { + PointList, + LineList, + TriangleList, + PatchList + }; + + /** + * @brief Enum class to specify modes of culling. + */ + enum class CullMode { + None, + Front, + Back, + Both + }; + + /** + * @brief Enum class to specify depth-test modes. + */ + enum class DepthTest { + None, + Less, + LessEqual, + Greater, + GreatherEqual, + Equal + }; // add more as needed // alternatively we could expose the blend factors directly - enum class BlendMode{ None, Additive }; - + /** + * @brief Enum class to specify blending modes. + */ + enum class BlendMode { + None, + Additive + }; + + /** + * @brief Structure to configure a graphics pipeline before its creation. + */ struct GraphicsPipelineConfig { ShaderProgram m_ShaderProgram; uint32_t m_Width; diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index 1e6091c97dbe8dfc31013b653f175acede76070b..dea1793871a320016cf7c0da3f3877fc66a6f616 100644 --- a/include/vkcv/Handles.hpp +++ b/include/vkcv/Handles.hpp @@ -1,7 +1,7 @@ #pragma once /** - * @authors Artur Wasmut - * @file src/vkcv/Handles.cpp + * @authors Tobias Frisch, Alexander Gauggel, Artur Wasmut, Sebastian Gaida, Mark Mints + * @file vkcv/Handles.hpp * @brief Central header file for all possible handles that the framework will hand out. */ @@ -12,8 +12,14 @@ namespace vkcv { + /** + * @brief Function to be called when a handles resources can be destroyed. + */ typedef typename event_function<uint64_t>::type HandleDestroyFunction; - + + /** + * @brief Class for general memory management via handles. + */ class Handle { friend std::ostream& operator << (std::ostream& out, const Handle& handle); @@ -24,12 +30,22 @@ namespace vkcv HandleDestroyFunction m_destroy; protected: + /** + * @brief Constructor of an invalid handle + */ Handle(); + /** + * @brief Constructor of a valid handle with an + * unique id and an optional destroy callback. + * + * @param[in] id Unique handle id + * @param[in] destroy Destroy callback (optional) + */ explicit Handle(uint64_t id, const HandleDestroyFunction& destroy = nullptr); /** - * Returns the actual handle id of a handle. + * @brief Returns the actual handle id of a handle. * * @return Handle id */ @@ -37,7 +53,7 @@ namespace vkcv uint64_t getId() const; /** - * Returns the reference counter of a handle + * @brief Returns the reference counter of a handle * * @return Reference counter */ @@ -53,80 +69,143 @@ namespace vkcv Handle& operator=(const Handle& other); Handle& operator=(Handle&& other) noexcept; + /** + * @brief Returns whether a handle is valid to use. + * + * @return True, if the handle is valid, else false. + */ explicit operator bool() const; + + /** + * @brief Returns whether a handle is invalid to use. + * + * @return True, if the handle is invalid, else false. + */ bool operator!() const; }; + /** + * @brief Stream operator to print a handle into an output + * stream. + * + * @param[out] out Output stream + * @param[in] handle + * @return Output stream after printing + */ std::ostream& operator << (std::ostream& out, const Handle& handle); - - // Handle returned for any buffer created with the core/context objects + + /** + * @brief Handle class for buffers. + */ class BufferHandle : public Handle { friend class BufferManager; private: using Handle::Handle; }; - + + /** + * @brief Handle class for render passes. + */ class PassHandle : public Handle { friend class PassManager; private: using Handle::Handle; }; - + + /** + * @brief Handle class for graphics pipelines. + */ class GraphicsPipelineHandle : public Handle { friend class GraphicsPipelineManager; private: using Handle::Handle; }; + /** + * @brief Handle class for compute pipelines. + */ class ComputePipelineHandle : public Handle { friend class ComputePipelineManager; private: using Handle::Handle; }; - + + /** + * @brief Handle class for descriptor sets. + */ class DescriptorSetHandle : public Handle { friend class DescriptorManager; private: using Handle::Handle; }; + /** + * @brief Handle class for descriptor set layouts. + */ class DescriptorSetLayoutHandle : public Handle { friend class DescriptorManager; private: using Handle::Handle; }; - + + /** + * @brief Handle class for samplers. + */ class SamplerHandle : public Handle { friend class SamplerManager; private: using Handle::Handle; }; + /** + * @brief Handle class for images. + */ class ImageHandle : public Handle { friend class ImageManager; private: using Handle::Handle; public: + /** + * @brief Returns whether the handle represents an swapchain image. + * + * @return True, if the handle represents a swapchain image, else false. + */ [[nodiscard]] bool isSwapchainImage() const; + /** + * @brief Creates a valid image handle to represent a swapchain image + * using an optional destroy callback. + * + * @param[in] destroy Destroy callback (optional) + * @return New swapchain image handle + */ static ImageHandle createSwapchainImageHandle(const HandleDestroyFunction& destroy = nullptr); }; + /** + * @brief Handle class for windows. + */ class WindowHandle : public Handle { friend class WindowManager; private: using Handle::Handle; }; + /** + * @brief Handle class for swapchains. + */ class SwapchainHandle : public Handle { friend class SwapchainManager; private: using Handle::Handle; }; + /** + * @brief Handle class for command streams. + */ class CommandStreamHandle : public Handle { friend class CommandStreamManager; private: diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 3fca76f70315c0e08e404d7acd8c2010a3501c24..5d5359288d4b1b1f38bfabf062c9cc4cd0ca9ad1 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -1,54 +1,137 @@ #pragma once /** - * @authors Lars Hoerttrich - * @file vkcv/Buffer.hpp - * @brief class for image handles + * @authors Alexander Gauggel, Tobias Frisch, Lars Hoerttrich, Artur Wasmut + * @file vkcv/Image.hpp + * @brief Class for image handling. */ -#include "vulkan/vulkan.hpp" + +#include <vulkan/vulkan.hpp> #include "Handles.hpp" -#include "vkcv/ImageConfig.hpp" +#include "ImageConfig.hpp" namespace vkcv { class ImageManager; + /** + * @brief Returns whether an image format is usable as depth buffer. + * + * @param format Vulkan image format + * @return True, if the format is valid to use as depth buffer, + * otherwise false. + */ bool isDepthFormat(const vk::Format format); + /** + * @brief Class for image handling and filling data. + */ class Image { friend class Core; public: + + /** + * @brief Returns the format of the image. + * + * @return Vulkan image format + */ [[nodiscard]] vk::Format getFormat() const; + /** + * @brief Returns the width of the image. + * + * @return Width of the image + */ [[nodiscard]] uint32_t getWidth() const; + /** + * @brief Returns the height of the image. + * + * @return Height of the image + */ [[nodiscard]] uint32_t getHeight() const; + /** + * @brief Returns the depth of the image. + * + * @return Depth of the image + */ [[nodiscard]] uint32_t getDepth() const; + /** + * @brief Returns the image handle of the image. + * + * @return Handle of the image + */ [[nodiscard]] const vkcv::ImageHandle& getHandle() const; + /** + * @brief Returns the amount of mip levels of the image. + * + * @return Number of mip levels + */ [[nodiscard]] uint32_t getMipCount() const; + /** + * @brief Switches the image layout, + * returns after operation is finished. + * + * @param[in] newLayout Layout that image is switched to + */ void switchLayout(vk::ImageLayout newLayout); + /** + * @brief Fills the image with data of a given size in bytes. + * + * @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 fill(const void* data, size_t size = SIZE_MAX); + + /** + * @brief Generates the entire mip chain from mip level zero, + * returns after operation is finished + */ void generateMipChainImmediate(); + + /** + * @brief Records mip chain generation to command stream, + * mip level zero is used as source + * + * @param[out] cmdStream Command stream that the commands are recorded into + */ void recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream); + private: // TODO: const qualifier removed, very hacky!!! // Else you cannot recreate an image. Pls fix. - ImageManager* m_manager; - ImageHandle m_handle; + ImageManager* m_manager; + ImageHandle m_handle; Image(ImageManager* manager, const ImageHandle& handle); + /** + * @brief Creates an image with given parameters like width, height, + * depth, amount of mip levels and others. + * + * @param[in,out] manager Image manager + * @param[in] format Vulkan image format + * @param[in] width Width of the image + * @param[in] height Height of the image + * @param[in] depth Depth of the image + * @param[in] mipCount Amount of mip levels + * @param[in] supportStorage Support of storage + * @param[in] supportColorAttachment Support of color attachment + * @param[in] msaa MSAA mode + * @return New created image + */ static Image create( ImageManager* manager, vk::Format format, diff --git a/include/vkcv/ImageConfig.hpp b/include/vkcv/ImageConfig.hpp index 2e413b97be92ae771ef85342981ea0163a93ab52..d031f790622f1f0595c540c5bbcf0d8795f5fd95 100644 --- a/include/vkcv/ImageConfig.hpp +++ b/include/vkcv/ImageConfig.hpp @@ -1,9 +1,32 @@ #pragma once +/** + * @authors Alexander Gauggel, Tobias Frisch + * @file vkcv/ImageConfig.hpp + * @brief File to provide functions supporting the use of multisampling. + */ + #include <vulkan/vulkan.hpp> namespace vkcv { + enum class Multisampling { None, MSAA2X, MSAA4X, MSAA8X }; + /** + * @brief Returns the sample count flag bits of a given + * multi-sample anti-aliasing mode. + * + * @param[in] msaa MSAA mode + * @return Sample count flag bits + */ vk::SampleCountFlagBits msaaToVkSampleCountFlag(Multisampling msaa); - uint32_t msaaToSampleCount(Multisampling msaa); + + /** + * @brief Returns the amount of samples of a given + * multi-sample anti-aliasing mode. + * + * @param msaa MSAA mode + * @return Number of samples + */ + uint32_t msaaToSampleCount(Multisampling msaa); + } diff --git a/include/vkcv/Logger.hpp b/include/vkcv/Logger.hpp index bb60561e80baadfcac4956223d9313893547068f..9d4fa86f2b42e8190e7dc57c2ad897a76f945126 100644 --- a/include/vkcv/Logger.hpp +++ b/include/vkcv/Logger.hpp @@ -1,9 +1,17 @@ #pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Logger.hpp + * @brief Logging macro function to print line of code specific information. + */ -#include <stdio.h> +#include <cstdio> namespace vkcv { + /** + * @brief Enum class to specify the level of logging. + */ enum class LogLevel { RAW_INFO, INFO, @@ -11,6 +19,13 @@ namespace vkcv { ERROR }; + /** + * @brief Return the fitting output stream to print messages + * of a given level of logging. + * + * @param[in] level Level of logging + * @return Output stream (stdout or stderr) + */ constexpr auto getLogOutput(LogLevel level) { switch (level) { case LogLevel::RAW_INFO: @@ -21,6 +36,13 @@ namespace vkcv { } } + /** + * @brief Returns the fitting identifier for messages of + * a given level of logging. + * + * @param[in] level Level of logging + * @return Identifier of the given level of logging + */ constexpr const char* getLogName(LogLevel level) { switch (level) { case LogLevel::RAW_INFO: @@ -44,6 +66,12 @@ namespace vkcv { #define __PRETTY_FUNCTION__ __FUNCSIG__ #endif +/** + * @brief Macro-function to log formatting messages with + * a specific level of logging. + * + * @param[in] level Level of logging + */ #define vkcv_log(level, ...) { \ char output_message [ \ VKCV_DEBUG_MESSAGE_LEN \ @@ -76,6 +104,12 @@ namespace vkcv { } #else +/** + * @brief Macro-function to log formatting messages with + * a specific level of logging. + * + * @param[in] level Level of logging + */ #define vkcv_log(level, ...) {} #endif diff --git a/include/vkcv/PassConfig.hpp b/include/vkcv/PassConfig.hpp index f3b2b802d062a441dfb0c810154205effb7053a2..ad3e3c0dff150f5ba41859477d4bb5a53c4365f8 100644 --- a/include/vkcv/PassConfig.hpp +++ b/include/vkcv/PassConfig.hpp @@ -1,13 +1,22 @@ #pragma once +/** + * @authors Alexander Gauggel, Artur Wasmut, Tobias Frisch + * @file vkcv/PassConfig.hpp + * @brief Enums and structures to handle render pass configuration. + */ #include <vector> #include <vulkan/vulkan.hpp> + #include "ImageConfig.hpp" namespace vkcv { - enum class AttachmentLayout - { + + /** + * @brief Enum class to specify kinds of attachment layouts. + */ + enum class AttachmentLayout { UNDEFINED, GENERAL, @@ -23,31 +32,31 @@ namespace vkcv PRESENTATION }; - enum class AttachmentOperation - { + /** + * @brief Enum class to specify types of attachment operations. + */ + enum class AttachmentOperation { LOAD, CLEAR, STORE, DONT_CARE }; - struct AttachmentDescription - { - AttachmentDescription( - AttachmentOperation store_op, - AttachmentOperation load_op, - vk::Format format) noexcept; - + /** + * @brief Structure to store details about an attachment of a pass. + */ + struct AttachmentDescription { AttachmentOperation store_operation; AttachmentOperation load_operation; - vk::Format format; }; - struct PassConfig - { - explicit PassConfig(std::vector<AttachmentDescription> attachments, Multisampling msaa = Multisampling::None) noexcept; - std::vector<AttachmentDescription> attachments{}; + /** + * @brief Structure to configure a pass for usage. + */ + struct PassConfig { + std::vector<AttachmentDescription> attachments; Multisampling msaa; }; + } \ No newline at end of file diff --git a/include/vkcv/PushConstants.hpp b/include/vkcv/PushConstants.hpp index d974fbe6241daf948b13929305fb24aff5ec06f5..ca826ea52e9bcee72c14c26496c99937c27fb775 100644 --- a/include/vkcv/PushConstants.hpp +++ b/include/vkcv/PushConstants.hpp @@ -1,4 +1,9 @@ #pragma once +/** + * @authors Tobias Frisch, Alexander Gauggel + * @file vkcv/PushConstants.hpp + * @brief Class to manage push constants for pipeline recording. + */ #include <vector> #include <vulkan/vulkan.hpp> @@ -6,7 +11,10 @@ #include "Logger.hpp" namespace vkcv { - + + /** + * @brief Class to handle push constants data per drawcall. + */ class PushConstants { private: std::vector<uint8_t> m_data; @@ -28,25 +36,55 @@ namespace vkcv { PushConstants& operator=(const PushConstants& other) = default; PushConstants& operator=(PushConstants&& other) = default; + /** + * @brief Returns the size of the data that is bound + * per drawcall in bytes. + * + * @return Size of data per drawcall + */ [[nodiscard]] size_t getSizePerDrawcall() const { return m_sizePerDrawcall; } + /** + * @brief Returns the size of total data stored for + * push constants in bytes + * + * @return Total size of data + */ [[nodiscard]] size_t getFullSize() const { return m_data.size(); } + /** + * @brief Returns the number of drawcalls that data + * is stored for. + * + * @return Number of drawcalls + */ [[nodiscard]] size_t getDrawcallCount() const { return (m_data.size() / m_sizePerDrawcall); } + /** + * @brief Clears the data for all drawcalls currently. + * stored. + */ void clear() { m_data.clear(); } + /** + * @brief Appends data for a single drawcall to the + * storage with a given type. + * + * @tparam T Type of data (must match the size per drawcall) + * @param[in] value Data to append + * @return True, if operation was successfull, otherwise false + */ template<typename T = uint8_t> bool appendDrawcall(const T& value) { if (sizeof(T) != m_sizePerDrawcall) { @@ -61,24 +99,53 @@ namespace vkcv { return true; } + /** + * @brief Returns the data of the drawcall by a given index + * as reference. + * + * @tparam T Type of data + * @param[in] index Index of the drawcall + * @return Drawcall data + */ template<typename T = uint8_t> T& getDrawcall(size_t index) { const size_t offset = (index * m_sizePerDrawcall); return *reinterpret_cast<T*>(m_data.data() + offset); } + /** + * @brief Returns the data of the drawcall by a given index + * as const reference. + * + * @tparam T Type of data + * @param[in] index Index of the drawcall + * @return Drawcall data + */ template<typename T = uint8_t> const T& getDrawcall(size_t index) const { const size_t offset = (index * m_sizePerDrawcall); return *reinterpret_cast<const T*>(m_data.data() + offset); } + /** + * @brief Returns the data of the drawcall by a given index + * as a pointer. + * + * @param[in] index Index of the drawcall + * @return Drawcall data + */ [[nodiscard]] const void* getDrawcallData(size_t index) const { const size_t offset = (index * m_sizePerDrawcall); return reinterpret_cast<const void*>(m_data.data() + offset); } + /** + * @brief Returns the pointer to the entire drawcall data which + * might be nullptr if the data is empty. + * + * @return Pointer to the data + */ [[nodiscard]] const void* getData() const { if (m_data.empty()) { diff --git a/include/vkcv/QueueManager.hpp b/include/vkcv/QueueManager.hpp index 9d219c9d7a308cac29bec1580bd8894a70f68fb3..04a5d8a0a59b2655673d073a7a36467df0ab8a17 100644 --- a/include/vkcv/QueueManager.hpp +++ b/include/vkcv/QueueManager.hpp @@ -1,10 +1,27 @@ #pragma once +/** + * @authors Sebastian Gaida, Tobias Frisch, Alexander Gauggel + * @file vkcv/QueueManager.hpp + * @brief Types to manage queues of a device. + */ + #include <vulkan/vulkan.hpp> namespace vkcv { - enum class QueueType { Compute, Transfer, Graphics, Present }; + /** + * @brief Enum class to represent types of queues. + */ + enum class QueueType { + Compute, + Transfer, + Graphics, + Present + }; + /** + * @brief Structure to represent a queue and its details. + */ struct Queue { int familyIndex; int queueIndex; @@ -12,40 +29,69 @@ namespace vkcv { vk::Queue handle; }; + /** + * @brief Class to manage queues of a device. + */ class QueueManager { public: + /** + * @brief Creates a queue manager with the given pairs of queues. + * + * @param[in,out] device Vulkan device that holds the queues + * @param[in] queuePairsGraphics Graphic queue pairs of queueFamily and queueIndex + * @param[in] queuePairsCompute Compute queue pairs of queueFamily and queueIndex + * @param[in] queuePairsTransfer Transfer queue pairs of queueFamily and queueIndex + * @return New queue manager with the specified queue pairs + */ static QueueManager create(vk::Device device, - std::vector<std::pair<int, int>> &queuePairsGraphics, - std::vector<std::pair<int, int>> &queuePairsCompute, - std::vector<std::pair<int, int>> &queuePairsTransfer); - + const std::vector<std::pair<int, int>> &queuePairsGraphics, + const std::vector<std::pair<int, int>> &queuePairsCompute, + const std::vector<std::pair<int, int>> &queuePairsTransfer); + + /** + * @brief Returns the default queue with present support. + * Recommended to use the present queue in the swapchain. + * + * @return Default present queue + */ [[nodiscard]] const Queue &getPresentQueue() const; - + + /** + * @brief Returns all queues with the graphics flag. + * + * @return Vector of graphics queues + */ [[nodiscard]] const std::vector<Queue> &getGraphicsQueues() const; - + + /** + * @brief Returns all queues with the compute flag. + * + * @return Vector of compute queues + */ [[nodiscard]] const std::vector<Queue> &getComputeQueues() const; - + + /** + * @brief Returns all queues with the transfer flag. + * + * @return Vector of transfer queues + */ [[nodiscard]] const std::vector<Queue> &getTransferQueues() const; - - static void queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice, - const std::vector<float> &queuePriorities, - const std::vector<vk::QueueFlagBits> &queueFlags, - std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos, - std::vector<std::pair<int, int>> &queuePairsGraphics, - std::vector<std::pair<int, int>> &queuePairsCompute, - std::vector<std::pair<int, int>> &queuePairsTransfer); - + /** - * checks for surface support in the queues - * @param physicalDevice to get the Queues - * @param surface that needs to checked - * @return + * @brief Checks for presenting support of a given surface + * in the queues and returns the queue family index of the + * supporting queue. + * + * @param[in] physicalDevice Vulkan physical device + * @param[in] surface Surface + * @return Queue family index of the supporting present queue */ - static uint32_t checkSurfaceSupport(const vk::PhysicalDevice &physicalDevice, vk::SurfaceKHR &surface); + static uint32_t checkSurfaceSupport(const vk::PhysicalDevice &physicalDevice, + const vk::SurfaceKHR &surface); private: std::vector<Queue> m_graphicsQueues; @@ -54,6 +100,9 @@ namespace vkcv { size_t m_presentIndex; - QueueManager(std::vector<Queue>&& graphicsQueues, std::vector<Queue>&& computeQueues, std::vector<Queue>&& transferQueues, size_t presentIndex); + QueueManager(std::vector<Queue>&& graphicsQueues, + std::vector<Queue>&& computeQueues, + std::vector<Queue>&& transferQueues, + size_t presentIndex); }; } diff --git a/include/vkcv/Result.hpp b/include/vkcv/Result.hpp index b78e444de9040f2982122d9242f584c7f9c340cf..328a44fa58c9b6303af872d7787cc1bcb7230256 100644 --- a/include/vkcv/Result.hpp +++ b/include/vkcv/Result.hpp @@ -1,12 +1,18 @@ #pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Result.hpp + * @brief Enum to represent result values of function which can fail. + */ namespace vkcv { - + + /** + * @brief Enum class to specify the result of a function call. + */ enum class Result { - SUCCESS = 0, ERROR = 1 - }; } diff --git a/include/vkcv/Sampler.hpp b/include/vkcv/Sampler.hpp index e4f10cd9d3f1dd60021e62842acaa07d2aefb5ce..c65ef8218ff209e6eeaf0e45f9309e21d85e782e 100644 --- a/include/vkcv/Sampler.hpp +++ b/include/vkcv/Sampler.hpp @@ -1,17 +1,31 @@ #pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Sampler.hpp + * @brief Enums for different sampler attributes. + */ namespace vkcv { + /** + * @brief Enum class to specify a samplers type to filter during access. + */ enum class SamplerFilterType { NEAREST = 1, LINEAR = 2 }; - + + /** + * @brief Enum class to specify a samplers mode to access mipmaps. + */ enum class SamplerMipmapMode { NEAREST = 1, LINEAR = 2 }; - + + /** + * @brief Enum class to specify a samplers mode to access via address space. + */ enum class SamplerAddressMode { REPEAT = 1, MIRRORED_REPEAT = 2, @@ -19,7 +33,10 @@ namespace vkcv { MIRROR_CLAMP_TO_EDGE = 4, CLAMP_TO_BORDER = 5 }; - + + /** + * @brief Enum class to specify a samplers color beyond a textures border. + */ enum class SamplerBorderColor { INT_ZERO_OPAQUE = 1, INT_ZERO_TRANSPARENT = 2, diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp index d39f0da436089830fc90e5178b056d0be2cae910..c815834a3d7a948df3307769f34abe94cbd2ff22 100644 --- a/include/vkcv/ShaderProgram.hpp +++ b/include/vkcv/ShaderProgram.hpp @@ -1,8 +1,8 @@ #pragma once /** - * @authors Simeon Hermann, Leonie Franken - * @file src/vkcv/ShaderProgram.hpp - * @brief ShaderProgram class to handle and prepare the shader stages for a graphics pipeline + * @authors Artur Wasmut, Leonie Franken, Tobias Frisch, Simeon Hermann, Alexander Gauggel, Mark Mints + * @file vkcv/ShaderProgram.hpp + * @brief ShaderProgram class to handle and prepare the shader stages for a graphics pipeline. */ #include <unordered_map> @@ -12,18 +12,16 @@ #include <filesystem> #include <vulkan/vulkan.hpp> #include <spirv_cross.hpp> + #include "VertexLayout.hpp" #include "DescriptorConfig.hpp" #include "ShaderStage.hpp" namespace vkcv { - struct Shader - { - std::vector<char> shaderCode; - ShaderStage shaderStage; - }; - + /** + * @brief Class to manage and reflect shaders as a program. + */ class ShaderProgram { public: @@ -31,47 +29,78 @@ namespace vkcv { ~ShaderProgram() = default; // dtor /** - * Adds a shader into the shader program. - * The shader is only added if the shader program does not contain the particular shader stage already. - * Contains: (1) reading of the code, (2) creation of a shader module, (3) creation of a shader stage, (4) adding to the shader stage list, (5) destroying of the shader module - * @param[in] flag that signals the respective shaderStage (e.g. VK_SHADER_STAGE_VERTEX_BIT) - * @param[in] relative path to the shader code (e.g. "../../../../../shaders/vert.spv") - */ - bool addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath); + * @brief Adds a shader into the shader program. + * The shader is only added if the shader program does not contain + * the particular shader stage already. + * Contains: + * (1) reading the SPIR-V file, + * (2) creating a shader module, + * (3) creating a shader stage, + * (4) adding to the shader stage list, + * (5) destroying of the shader module + * + * @param[in] stage The stage of the shader + * @param[in] path Path to the SPIR-V shader file + */ + bool addShader(ShaderStage stage, const std::filesystem::path &path); /** - * Returns the shader program's shader of the specified shader. - * Needed for the transfer to the pipeline. - * @return Shader object consisting of buffer with shader code and shader stage enum - */ - const Shader &getShader(ShaderStage shaderStage) const; + * @brief Returns the shader binary of a specified stage from the program. + * Needed for the transfer to the pipeline. + * + * @param[in] stage The stage of the shader + * @return Shader code binary of the given stage + */ + const std::vector<uint32_t> &getShaderBinary(ShaderStage stage) const; - bool existsShader(ShaderStage shaderStage) const; + /** + * @brief Returns whether a shader exists in the program for a + * specified shader stage. + * + * @param[in] stage The stage of the shader + * @return True, if a shader exists for the stage, else false + */ + bool existsShader(ShaderStage stage) const; + /** + * @brief Returns the vertex attachments for the program and its + * shader stages. + * + * @return Vertex attachments + */ const std::vector<VertexAttachment> &getVertexAttachments() const; - size_t getPushConstantSize() const; + + /** + * @brief Returns the size of the programs push constants. + * + * @return Size of push constants + */ + size_t getPushConstantsSize() const; /** - * Returns the reflected descriptor sets/layouts/bindings in a map of maps. - * First uint32_t serves as descriptor SET id. - * Second uint32_t serves as the descriptor set's BINDING id. - * @return + * @brief Returns the reflected descriptor set bindings mapped via + * their descriptor set id. + * + * @return Reflected descriptor set bindings */ - const std::unordered_map<uint32_t, std::unordered_map<uint32_t, DescriptorBinding>>& getReflectedDescriptors() const; + const std::unordered_map<uint32_t, DescriptorBindings>& getReflectedDescriptors() const; private: /** - * Called after successfully adding a shader to the program. + * @brief Called after successfully adding a shader to the program. * Fills vertex input attachments and descriptor sets (if present). - * @param shaderStage the stage to reflect data from + * + * @param[in] shaderStage the stage to reflect data from */ void reflectShader(ShaderStage shaderStage); - std::unordered_map<ShaderStage, Shader> m_Shaders; + std::unordered_map<ShaderStage, std::vector<uint32_t> > m_Shaders; // contains all vertex input attachments used in the vertex buffer - std::vector<VertexAttachment> m_VertexAttachments; - std::unordered_map<uint32_t, std::unordered_map<uint32_t, DescriptorBinding>> m_DescriptorSets; - size_t m_pushConstantSize = 0; + VertexAttachments m_VertexAttachments; + std::unordered_map<uint32_t, DescriptorBindings> m_DescriptorSets; + size_t m_pushConstantsSize = 0; + }; + } diff --git a/include/vkcv/ShaderStage.hpp b/include/vkcv/ShaderStage.hpp index 73cd6f5f37cc96cce384952080e32904915eee7b..39b250e80be79cbb0f39261e69ab0d80a71d4f31 100644 --- a/include/vkcv/ShaderStage.hpp +++ b/include/vkcv/ShaderStage.hpp @@ -1,9 +1,17 @@ #pragma once +/** + * @authors Artur Wasmut, Simeon Hermann, Tobias Frisch, Vanessa Karolek, Alexander Gauggel, Lars Hoerttrich + * @file vkcv/ShaderStage.hpp + * @brief Enum and struct to operate with multiple shader stages. + */ #include <vulkan/vulkan.hpp> namespace vkcv { + /** + * @brief Enum class to specify the stage of a shader. + */ enum class ShaderStage : VkShaderStageFlags { VERTEX = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eVertex), TESS_CONTROL = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eTessellationControl), @@ -72,4 +80,5 @@ namespace vkcv { constexpr ShaderStages operator~(ShaderStage stage) noexcept { return ~(ShaderStages(stage)); } + } diff --git a/include/vkcv/Surface.hpp b/include/vkcv/Surface.hpp new file mode 100644 index 0000000000000000000000000000000000000000..47862b9c49661f434b64f9def17037cc5bcc110c --- /dev/null +++ b/include/vkcv/Surface.hpp @@ -0,0 +1,107 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Surface.hpp + * @brief Class to manage the surface used by a swapchain. + */ + +#include <vulkan/vulkan.hpp> + +#include "Context.hpp" +#include "Window.hpp" + +namespace vkcv { + + const uint32_t MIN_SURFACE_SIZE = 2; + + /** + * @brief Class to handle surfaces to use with a swapchain. + */ + class Surface final { + private: + friend class Swapchain; + friend class SwapchainManager; + + const Context *m_Context; + vk::SurfaceKHR m_Handle; + uint32_t m_PresentQueueIndex; + vk::Extent2D m_Extent; + vk::Format m_Format; + vk::ColorSpaceKHR m_ColorSpace; + + Surface(const Context &context, + const vk::SurfaceKHR &handle, + uint32_t presentQueueIndex, + const vk::Extent2D &extent, + vk::Format format, + vk::ColorSpaceKHR colorSpace); + + vk::SwapchainKHR createVulkanSwapchain(const Window &window, + const vk::SwapchainKHR &oldSwapchain); + + public: + Surface(const Surface& other) = default; + + Surface(Surface&& other) noexcept; + + Surface& operator=(const Surface& other) = default; + + Surface& operator=(Surface&& other) noexcept; + + ~Surface(); + + /** + * @brief Creates a surface via a window and a current context. + * + * @param[in] window Window + * @param[in] context Context + * @return Created surface + */ + static Surface create(const Window &window, + const Context &context); + + /** + * @brief Returns the Vulkan-Surface of the object. + * + * @return Current Vulkan-Surface + */ + [[nodiscard]] + vk::SurfaceKHR getSurface() const; + + /** + * @brief Returns the queue index of the present queue + * for the surface. + * + * @return Present queue index + */ + [[nodiscard]] + uint32_t getPresentQueueIndex() const; + + /** + * @brief Returns the extent of the surfaces resolution. + * + * @return Extent of surface + */ + [[nodiscard]] + const vk::Extent2D& getExtent() const; + + /** + * @brief Returns the image format of the surface to + * present an image. + * + * @return Vulkan image format + */ + [[nodiscard]] + vk::Format getFormat() const; + + /** + * @brief Returns the color space of the surface. + * + * @return Color space + */ + [[nodiscard]] + vk::ColorSpaceKHR getColorSpace() const; + + }; + +} diff --git a/include/vkcv/Swapchain.hpp b/include/vkcv/Swapchain.hpp index c7741c652926fad5d581ecf7465ed74af9e2db37..9380b97ca73e46d53e7dcfbb8ba804004698b5b3 100644 --- a/include/vkcv/Swapchain.hpp +++ b/include/vkcv/Swapchain.hpp @@ -1,77 +1,64 @@ #pragma once -#include "vulkan/vulkan.hpp" -#include "Context.hpp" -#include "vkcv/Window.hpp" +/** + * @authors Sebastian Gaida, Tobias Frisch + * @file vkcv/Swapchain.hpp + * @brief Class to manage the state of a swapchain and its transitions. + */ #include <atomic> +#include <vulkan/vulkan.hpp> + +#include "Context.hpp" +#include "Surface.hpp" +#include "Window.hpp" namespace vkcv { - - const uint32_t MIN_SWAPCHAIN_SIZE = 2; - + + /** + * @brief Class to handle swapchains using a context. + */ class Swapchain final { private: friend class Core; friend class Window; friend class SwapchainManager; - - struct Surface - { - vk::SurfaceKHR handle; - std::vector<vk::SurfaceFormatKHR> formats; - vk::SurfaceCapabilitiesKHR capabilities; - std::vector<vk::PresentModeKHR> presentModes; - uint32_t presentQueueIndex; - }; - + + const Context *m_Context; Surface m_Surface; - vk::SwapchainKHR m_Swapchain; - vk::Format m_Format; - vk::ColorSpaceKHR m_ColorSpace; - vk::PresentModeKHR m_PresentMode; - uint32_t m_ImageCount; - - vk::Extent2D m_Extent; - std::atomic<bool> m_RecreationRequired; /** - * Constructor of a SwapChain object - * glfw is not initialized in this class because ist must be sure that there exists a context first - * glfw is already initialized by the window class - * @param surface used by the swapchain - * @param swapchain to show images in the window - * @param format of the swapchain - * @param colorSpace of the swapchain - * @param presentMode of the swapchain - * @param imageCount of the swapchain - * @param extent of the swapchain + * @brief Constructor of the swapchain with the current context, + * a surface and a given vulkan swapchain object. + * + * @param[in,out] context Current context + * @param[in] surface used by the swapchain + * @param[in,out] swapchain to show images in the window */ - Swapchain(const Surface &surface, - vk::SwapchainKHR swapchain, - vk::Format format, - vk::ColorSpaceKHR colorSpace, - vk::PresentModeKHR presentMode, - uint32_t imageCount, - vk::Extent2D extent) noexcept; + Swapchain(const Context &context, + const Surface &surface, + vk::SwapchainKHR swapchain) noexcept; /** - * checks if the update flag is true - * @return if an update is needed + * @brief Checks whether the swapchain needs to be recreated. + * + * @return True, if the swapchain should be updated, + * otherwise false. */ bool shouldUpdateSwapchain() const; /** - * recreates the swapchain - * context - * window + * @brief Updates and recreates the swapchain. + * + * @param[in,out] context that holds the device to recreate the swapchain + * @param[in] window that the new swapchain gets bound to */ void updateSwapchain(const Context &context, const Window &window); /** - * signal that the swapchain needs to be recreated + * @brief Signals the swapchain to be recreated. */ void signalSwapchainRecreation(); @@ -79,6 +66,8 @@ namespace vkcv Swapchain(const Swapchain& other); /** + * @brief Returns the vulkan swapchain object of the swapchain. + * * @return The swapchain linked with the #SwapChain class * @note The reference to our Swapchain variable is needed for the recreation step */ @@ -86,48 +75,61 @@ namespace vkcv const vk::SwapchainKHR& getSwapchain() const; /** - * gets the current surface object - * @return current surface + * @brief Returns the current surface of the swapchain. + * + * @return Current surface */ [[nodiscard]] - vk::SurfaceKHR getSurface() const; + const Surface& getSurface() const; /** - * gets the chosen swapchain format - * @return gets the chosen swapchain format + * @brief Returns the image format for the current surface + * of the swapchain. + * + * @return Swapchain image format */ [[nodiscard]] vk::Format getFormat() const; /** - * creates a swap chain object out of the given window and the given context - * @param window a wrapper that represents a glfw window - * @param context of the application - * @return returns an object of swapChain + * @brief Creates a swapchain for a specific window and + * a given context. + * + * @param[in,out] window Window + * @param[in,out] context Context + * @return New created swapchain */ static Swapchain create(const Window &window, const Context &context); /** - * Destructor of SwapChain + * Destructor of thw swapchain. */ virtual ~Swapchain(); /** - * @return number of images in swapchain + * @brief Returns the amount of images for the swapchain. + * + * @return Number of images */ uint32_t getImageCount() const; /** - * @return the 2d extent of the swapchain + * @brief Returns the extent from the current surface of + * the swapchain. + * + * @return Extent of the swapchains surface */ [[nodiscard]] const vk::Extent2D& getExtent() const; /** - * @return the familyQueueIndex for the surface + * @brief Returns the present queue index to be used with + * the swapchain and its current surface. + * + * @return Present queue family index */ [[nodiscard]] - const uint32_t& getPresentQueueIndex() const; + uint32_t getPresentQueueIndex() const; }; diff --git a/include/vkcv/SyncResources.hpp b/include/vkcv/SyncResources.hpp index c41019cc46ee1375a83323a6ecc877ecc1c1727a..1683855b6b4f9046b0af5fb2df65f3bca895da2a 100644 --- a/include/vkcv/SyncResources.hpp +++ b/include/vkcv/SyncResources.hpp @@ -1,15 +1,59 @@ #pragma once +/** + * @authors Alexander Gauggel, Tobias Frisch + * @file vkcv/SyncResources.hpp + * @brief Support functions to deal with synchronization resources. + */ + #include <vulkan/vulkan.hpp> namespace vkcv { + + /** + * @brief Structure to store vulkan resources for presenting + * with a pipeline. + */ struct SyncResources { - vk::Semaphore renderFinished; - vk::Semaphore swapchainImageAcquired; - vk::Fence presentFinished; + vk::Semaphore renderFinished; + vk::Semaphore swapchainImageAcquired; + vk::Fence presentFinished; }; - SyncResources createSyncResources(const vk::Device &device); - void destroySyncResources(const vk::Device &device, const SyncResources &resources); - vk::Fence createFence(const vk::Device &device); - void waitForFence(const vk::Device& device, const vk::Fence fence); + /** + * @brief Creates new synchronization resources for drawing + * and presenting with a swapchain. + * + * @param[in,out] device Vulkan-Device + * @return New created synchronization resources + */ + SyncResources createSyncResources(const vk::Device &device); + + /** + * @brief Destroys the synchronization resources with a + * given device. + * + * @param[in,out] device Vulkan-Device + * @param[in,out] resources Synchronizazion resources + */ + void destroySyncResources(const vk::Device &device, + const SyncResources &resources); + + /** + * @brief Creates a new fence with a given device and + * returns it. + * + * @param[in,out] device Vulkan-Device + * @return New created fence + */ + vk::Fence createFence(const vk::Device &device); + + /** + * @brief Calls a given device to wait for a specific fence. + * + * @param[in,out] device Vulkan-Device + * @param[in] fence Vulkan-Fence + */ + void waitForFence(const vk::Device& device, + const vk::Fence& fence); + } \ No newline at end of file diff --git a/include/vkcv/VertexLayout.hpp b/include/vkcv/VertexLayout.hpp index 0600b99a24a327605e89b2e8ec304c20dbf7ad2e..330be708525b3e1a90e15919abb9f3f2f2ea1729 100644 --- a/include/vkcv/VertexLayout.hpp +++ b/include/vkcv/VertexLayout.hpp @@ -1,11 +1,21 @@ #pragma once +/** + * @authors Alexander Gauggel, Artur Wasmut, Mara Vogt, Susanne Dötsch, + * Trevor Hollmann, Leonie Franken, Simeon Hermann, Tobias Frisch + * @file vkcv/VertexLayout.hpp + * @brief Structures to handle vertex layout, bindings and attachments. + */ #include <vector> #include <iostream> #include <string> -namespace vkcv{ - enum class VertexAttachmentFormat{ +namespace vkcv { + + /** + * @brief Enum class to specify the format of vertex attributes. + */ + enum class VertexAttachmentFormat { FLOAT, FLOAT2, FLOAT3, @@ -16,51 +26,65 @@ namespace vkcv{ INT4 }; + /** + * @brief Returns the size in bytes of a vertex with a + * given vertex format. + * + * @param[in] format Vertex format + * @return Size in bytes + */ uint32_t getFormatSize(VertexAttachmentFormat format); - struct VertexAttachment{ - friend struct VertexBinding; - /** - * Describes an individual vertex input attribute/attachment. - * @param inputLocation its location in the vertex shader. - * @param name the name referred to in the shader. - * @param format the format (and therefore, the size) this attachment is in. - * The offset is calculated when a collection of attachments forms a binding, hence the friend declaration. - */ - VertexAttachment(uint32_t inputLocation, const std::string &name, VertexAttachmentFormat format) noexcept; - VertexAttachment() = delete; - - uint32_t inputLocation; - std::string name; - VertexAttachmentFormat format; - uint32_t offset; + /** + * @brief Structure to store the details of a vertex input attachment. + * + * Describes an individual vertex input attribute/attachment. The offset + * is calculated when a collection of attachments forms a binding. + */ + struct VertexAttachment { + uint32_t inputLocation; + std::string name; + VertexAttachmentFormat format; + uint32_t offset; }; - - struct VertexBinding{ - /** - * Describes all vertex input attachments _one_ buffer contains to create a vertex buffer binding. - * NOTE: multiple vertex layouts may contain various (mutually exclusive) vertex input attachments - * to form one complete vertex buffer binding! - * @param bindingLocation its entry in the buffers that make up the whole vertex buffer. - * @param attachments the vertex input attachments this specific buffer layout contains. - */ - VertexBinding(uint32_t bindingLocation, const std::vector<VertexAttachment> &attachments) noexcept; - VertexBinding() = delete; - - uint32_t bindingLocation; - uint32_t stride; - std::vector<VertexAttachment> vertexAttachments; + + typedef std::vector<VertexAttachment> VertexAttachments; + + /** + * @brief Structure to store the details of a vertex buffer binding. + * + * Describes all vertex input attachments _one_ buffer contains to create + * a vertex buffer binding. NOTE: multiple vertex layouts may contain + * various (mutually exclusive) vertex input attachments to form one + * complete vertex buffer binding! + */ + struct VertexBinding { + uint32_t bindingLocation; + uint32_t stride; + VertexAttachments vertexAttachments; }; + + /** + * Creates a vertex binding with given parameters and calculates its strides + * depending on its attachments. + * + * @param[in] bindingLocation Its entry in the buffers that make up the whole vertex buffer. + * @param[in] attachments The vertex input attachments this specific buffer layout contains. + * @return Vertex buffer binding with calculated stride + */ + VertexBinding createVertexBinding(uint32_t bindingLocation, const VertexAttachments &attachments); + + typedef std::vector<VertexBinding> VertexBindings; - struct VertexLayout{ - /** - * Describes the complete layout of one vertex, e.g. all of the vertex input attachments used, - * and all of the buffer bindings that refer to the attachments (for when multiple buffers are used). - * @param bindings bindings the complete vertex buffer is comprised of. - */ - VertexLayout() noexcept; - VertexLayout(const std::vector<VertexBinding> &bindings) noexcept; - - std::vector<VertexBinding> vertexBindings; + /** + * @brief Structure to store the details of a vertex layout. + * + * Describes the complete layout of one vertex, e.g. all of the vertex input + * attachments used, and all of the buffer bindings that refer to the attachments + * (for when multiple buffers are used). + */ + struct VertexLayout { + VertexBindings vertexBindings; }; + } diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp index cef735632689cdd119b694674e9ac7af67471a3c..d1db4bf438b95e9c96824bb6676a1d8bf020a35f 100644 --- a/include/vkcv/Window.hpp +++ b/include/vkcv/Window.hpp @@ -1,6 +1,14 @@ #pragma once +/** + * @authors Tobias Frisch, Sebastian Gaida, Vanessa Karolek, Artur Wasmut + * @file vkcv/Window.hpp + * @brief Class to represent and manage a window with its input. + */ + +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif -#define NOMINMAX #include <algorithm> #include <string> @@ -11,6 +19,9 @@ struct GLFWwindow; namespace vkcv { + /** + * @brief Class to handle a window. + */ class Window { friend class WindowManager; friend class SwapchainManager; @@ -25,12 +36,13 @@ namespace vkcv { public: /** - * creates an uninitialized #Window + * @brief Constructor of an uninitialized #Window */ Window(); /** - * creates a #Window with the parameters + * @brief Constructor of a #Window with an optional width, + * height and resizable attribute. * * @param[in] title title of the window * @param[in] width width of the window (optional) @@ -40,55 +52,56 @@ namespace vkcv { explicit Window(const char* title, int width = -1, int height = -1, bool resizable = false); /** - * Copy-constructor of #Window + * @brief Copy-constructor of a #Window * - * @param other Other instance of #Window + * @param[in] other Other instance of #Window */ Window(const Window& other) = delete; /** - * Copy-operator of #Window + * @brief Copy-operator of a #Window * - * @param other Other instance of #Window + * @param[in] other Other instance of #Window * @return Reference to itself */ Window &operator=(const Window &other) = delete; /** - * checks if the window is still open, or the close event was called - * This function should be changed/removed later on - * @return bool if the window is still open + * @brief Checks if the window is still open, or the close event was called. + * TODO: This function should be changed/removed later on + * + * @return True, if the window is still open, else false */ [[nodiscard]] bool isOpen() const; /** - * gets the currently focused window and returns it - * only accessible to WindowManager - * @return + * @brief Returns the currently focused window. + * TODO: only accessible to WindowManager + * + * @return Current window in focus */ static Window& getFocusedWindow(); /** - * checks if any GLFWWindows are open - * @return bool if a window is open + * @brief Checks if any windows are active and open. + * + * @return True, if any window is open, else false */ static bool hasOpenWindow(); /** - * polls all events on the GLFWwindow + * @brief Polls all events on the active windows. */ static void pollEvents(); /** + * @brief Returns the required extensions to use GLFW windows with Vulkan. * - * @return + * @return Required surface extensions */ static const std::vector<std::string>& getExtensions(); - - /** - * basic events of the window - */ + event< int, int, int> e_mouseButton; event< double, double > e_mouseMove; event< double, double > e_mouseScroll; @@ -98,60 +111,63 @@ namespace vkcv { event< int > e_gamepad; /** - * returns the current window - * @return window handle + * @brief Returns the GLFW window handle. + * + * @return GLFW window handle */ [[nodiscard]] GLFWwindow *getWindow() const; /** - * gets the window title - * @return string with window title + * @brief Returns the title of the window. + * + * @return Window title */ [[nodiscard]] const std::string& getTitle() const; /** - * gets the window width - * @return int with window width + * @brief Returns the width of the window. + * + * @return Window width */ [[nodiscard]] int getWidth() const; /** - * gets the window height - * @return int with window height + * @brief Returns the height of the window. + * + * @return Window height */ [[nodiscard]] int getHeight() const; /** - * is the window resizable - * @return bool with window resizable + * @brief Returns whether the window is resizable or not. + * + * @return True, if the window is resizable, else false */ [[nodiscard]] bool isResizable() const; /** - * Destructor of #Window, terminates GLFW + * @brief Destructor of the window which terminates GLFW in case + * of the last window got destroyed. */ virtual ~Window(); /** - * destroys the window - */ - //void destroyWindow(); - - /** - * gets the windows framebuffer size - * @param width - * @param height + * @brief Requests the windows framebuffer size. + * + * @param[out] width + * @param[out] height */ void getFramebufferSize(int& width, int& height) const; /** - * gets the SwapchainHandle corresponding to the swapchain of the window - * @return + * @brief Retruns the handle of the swapchain in use by the window. + * + * @return Swapchain handle */ SwapchainHandle getSwapchainHandle() const; }; diff --git a/lib/VulkanMemoryAllocator-Hpp b/lib/VulkanMemoryAllocator-Hpp index da6ea76eecf12a1decc76f58a3e096bcc555bd94..2e6f3f6c13933c84b55d01c4c0cbc2e7385ac8c1 160000 --- a/lib/VulkanMemoryAllocator-Hpp +++ b/lib/VulkanMemoryAllocator-Hpp @@ -1 +1 @@ -Subproject commit da6ea76eecf12a1decc76f58a3e096bcc555bd94 +Subproject commit 2e6f3f6c13933c84b55d01c4c0cbc2e7385ac8c1 diff --git a/modules/asset_loader/config/NLOHMANN_JSON.cmake b/modules/asset_loader/config/NLOHMANN_JSON.cmake index 4bd7f4475ef1e748e109814d440762e27948f495..3a082ae59c5778aa5d172fab9eb71b108b3f652b 100644 --- a/modules/asset_loader/config/NLOHMANN_JSON.cmake +++ b/modules/asset_loader/config/NLOHMANN_JSON.cmake @@ -1,10 +1,16 @@ -use_git_submodule("${vkcv_asset_loader_lib_path}/json" json_status) +find_package(nlohmann_json QUIET) -if (${json_status}) - set(JSON_BuildTests OFF CACHE INTERNAL "") +if (nlohmann_json_FOUND) + list(APPEND vkcv_libraries nlohmann_json::nlohmann_json) +else() + use_git_submodule("${vkcv_asset_loader_lib_path}/json" json_status) - add_subdirectory(${vkcv_asset_loader_lib}/json) - - list(APPEND vkcv_asset_loader_libraries nlohmann_json::nlohmann_json) + if (${json_status}) + set(JSON_BuildTests OFF CACHE INTERNAL "") + + add_subdirectory(${vkcv_asset_loader_lib}/json) + + list(APPEND vkcv_asset_loader_libraries nlohmann_json::nlohmann_json) + endif () endif () diff --git a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp index 25d7d5b36d00bad8587fbe082f8ebd041d84fde6..2362e560516fee3bf392ef150a756a25aa2420a0 100644 --- a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp +++ b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp @@ -36,6 +36,12 @@ namespace vkcv::asset { +/** + * @defgroup vkcv_asset Asset Loader Module + * A module to load assets like scenes, meshes and textures. + * @{ + */ + /** * These return codes are limited to the asset loader module. If unified return * codes are defined for the vkcv framework, these will be used instead. @@ -321,4 +327,6 @@ int loadScene(const std::filesystem::path &path, Scene &scene); */ Texture loadTexture(const std::filesystem::path& path); +/** @} */ + } // end namespace vkcv::asset diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp index b322f9cc2011edd491d0694396ec095ca2c37a19..110a941ff6703e989174eaf311118b10b41491d4 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -1,8 +1,8 @@ #include "vkcv/asset/asset_loader.hpp" #include <iostream> -#include <string.h> // memcpy(3) +#include <cstring> // memcpy(3) #include <set> -#include <stdlib.h> // calloc(3) +#include <cstdlib> // calloc(3) #include <vulkan/vulkan.hpp> #include <fx/gltf.h> #include <stb_image.h> diff --git a/modules/camera/include/vkcv/camera/Camera.hpp b/modules/camera/include/vkcv/camera/Camera.hpp index 6ccafe4ebe65f4e50747f1341ed1306948fef242..b333fbbd696a4583bd4aa9f9591a75d4de532d1d 100644 --- a/modules/camera/include/vkcv/camera/Camera.hpp +++ b/modules/camera/include/vkcv/camera/Camera.hpp @@ -1,4 +1,9 @@ #pragma once +/** + * @authors Vanessa Karolek, Josch Morgenstern, Sebastian Gaida, Katharina Krämer, Tobias Frisch, Alexander Gauggel + * @file include/vkcv/camera/Camera.hpp + * @brief Camera class of the camera module for the vkcv framework. + */ #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> @@ -9,6 +14,12 @@ namespace vkcv::camera { + /** + * @defgroup vkcv_camera Camera Module + * A module to manage intrinsic and extrinsic parameters with camera instances. + * @{ + */ + /** * @brief Used to create a camera which governs the view and projection matrices. */ @@ -208,4 +219,6 @@ namespace vkcv::camera { void setUp(const glm::vec3 &up); }; + /** @} */ + } diff --git a/modules/camera/include/vkcv/camera/CameraController.hpp b/modules/camera/include/vkcv/camera/CameraController.hpp index 90fc97401851851194ec89a10757bbfb1453990d..d6efd8f2f300dead870b3546939dad2088cd466e 100644 --- a/modules/camera/include/vkcv/camera/CameraController.hpp +++ b/modules/camera/include/vkcv/camera/CameraController.hpp @@ -1,13 +1,25 @@ #pragma once +/** + * @authors Vanessa Karolek, Josch Morgenstern, Tobias Frisch + * @file include/vkcv/camera/CameraController.hpp + * @brief CameraController class of the camera module for the vkcv framework. A camera object is controlled by a camera + * controller object. Using inheritance of this base class a camera controller object defines a specific control + * behaviour of the camera object in the scene. + */ #include "Camera.hpp" #include "vkcv/Window.hpp" namespace vkcv::camera { + /** + * @addtogroup vkcv_camera + * @{ + */ + /** * @brief Used as a base class for defining camera controller classes with different behaviors, e.g. the - * #PilotCameraController. + * PilotCameraController. */ class CameraController { @@ -69,4 +81,6 @@ namespace vkcv::camera { virtual void gamepadCallback(int gamepadIndex, Camera &camera, double frametime) = 0; }; + /** @} */ + } \ No newline at end of file diff --git a/modules/camera/include/vkcv/camera/CameraManager.hpp b/modules/camera/include/vkcv/camera/CameraManager.hpp index c0777b09544893aa38cf11396c1cf60bd800a837..092e1fc8552a192368b06216e2f51d2b291946d7 100644 --- a/modules/camera/include/vkcv/camera/CameraManager.hpp +++ b/modules/camera/include/vkcv/camera/CameraManager.hpp @@ -1,4 +1,10 @@ #pragma once +/** + * @authors Vanessa Karolek, Josch Morgenstern, Sebastian Gaida, Katharina Krämer, Tobias Frisch, Alexander Gauggel + * @file include/vkcv/camera/CameraManager.hpp + * @brief CameraManager class of the camera module for the vkcv framework. The camera manager manages several camera + * controller objects. Camera objects can be created and bound to a specific camera controller via this class. + */ #include "PilotCameraController.hpp" #include "TrackballCameraController.hpp" @@ -9,6 +15,11 @@ namespace vkcv::camera { + /** + * @addtogroup vkcv_camera + * @{ + */ + /** * @brief Used for specifying existing types of camera controllers when adding a new controller object to the * #CameraManager. @@ -192,4 +203,7 @@ namespace vkcv::camera { */ void update(double deltaTime); }; + + /** @} */ + } diff --git a/modules/camera/include/vkcv/camera/PilotCameraController.hpp b/modules/camera/include/vkcv/camera/PilotCameraController.hpp index 67388818a59b66775598e9d4257fa4c36646332a..c23a2cccce6f3d4036e9648d39b7b39df1d7ce4b 100644 --- a/modules/camera/include/vkcv/camera/PilotCameraController.hpp +++ b/modules/camera/include/vkcv/camera/PilotCameraController.hpp @@ -1,9 +1,20 @@ #pragma once +/** + * @authors Vanessa Karolek, Josch Morgenstern, Tobias Frisch + * @file include/vkcv/camera/PilotCameraController.hpp + * @brief PilotCameraController class of the camera module for the vkcv framework. This class inherits from the base + * class @#CameraController and enables camera objects to be moved freely within the scene. + */ #include <vkcv/camera/CameraController.hpp> namespace vkcv::camera { + /** + * @addtogroup vkcv_camera + * @{ + */ + /** * @brief Used to move around a camera object in world space. */ @@ -111,4 +122,6 @@ namespace vkcv::camera { void gamepadCallback(int gamepadIndex, Camera &camera, double frametime); }; + /** @} */ + } \ No newline at end of file diff --git a/modules/camera/include/vkcv/camera/TrackballCameraController.hpp b/modules/camera/include/vkcv/camera/TrackballCameraController.hpp index 20336f7a10644c73e451c5106f37545e84eb27f7..e4f40383218f8c25fd0bca41d9ff673ce5a3589e 100644 --- a/modules/camera/include/vkcv/camera/TrackballCameraController.hpp +++ b/modules/camera/include/vkcv/camera/TrackballCameraController.hpp @@ -1,9 +1,20 @@ #pragma once +/** + * @authors Vanessa Karolek, Josch Morgenstern, Sebastian Gaida,Tobias Frisch + * @file include/vkcv/camera/TrackballCameraController.hpp + * @brief TrackballCameraController class of the camera module for the vkcv framework. This class inherits from the base + * class @#CameraController and enables camera objects to be orbited around a specific center point. + */ #include "CameraController.hpp" namespace vkcv::camera { + /** + * @addtogroup vkcv_camera + * @{ + */ + /** * @brief Used to orbit a camera around its center point. */ @@ -106,4 +117,6 @@ namespace vkcv::camera { void gamepadCallback(int gamepadIndex, Camera &camera, double frametime); }; + /** @} */ + } \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/Camera.cpp b/modules/camera/src/vkcv/camera/Camera.cpp index 25b2a7339a46de8ced171c8ee9c10f962c3c0399..4b3ae9274733a070463f553bd79183789d0701b6 100644 --- a/modules/camera/src/vkcv/camera/Camera.cpp +++ b/modules/camera/src/vkcv/camera/Camera.cpp @@ -1,6 +1,6 @@ #include "vkcv/camera/Camera.hpp" -#include <math.h> +#include <cmath> namespace vkcv::camera { diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp index 78456da209233c67735b3fb1abe1a11ad8be5736..c8e51fe9716af0304687d6ae60fc0bea2a5d2cc6 100644 --- a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp +++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp @@ -272,13 +272,13 @@ namespace vkcv::effects { DescriptorWrites mipDownsampleWrites; if (mipLevel > 0) { - mipDownsampleWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, sample, mipLevel - 1, true)}; + mipDownsampleWrites.writeSampledImage(0, sample, mipLevel - 1, true); } else { - mipDownsampleWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, input)}; + mipDownsampleWrites.writeSampledImage(0, input); } - mipDownsampleWrites.samplerWrites = {SamplerDescriptorWrite(1, m_linearSampler)}; - mipDownsampleWrites.storageImageWrites = {StorageImageDescriptorWrite(2, sample, mipLevel) }; + mipDownsampleWrites.writeSampler(1, m_linearSampler); + mipDownsampleWrites.writeStorageImage(2, sample, mipLevel); m_core.writeDescriptorSet(mipDescriptorSets[mipLevel], mipDownsampleWrites); @@ -325,9 +325,9 @@ namespace vkcv::effects { for(uint32_t mipLevel = mipDescriptorSets.size(); mipLevel > 0; mipLevel--) { // mip descriptor writes DescriptorWrites mipUpsampleWrites; - mipUpsampleWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, sample, mipLevel, true)}; - mipUpsampleWrites.samplerWrites = {SamplerDescriptorWrite(1, m_linearSampler)}; - mipUpsampleWrites.storageImageWrites = {StorageImageDescriptorWrite(2, sample, mipLevel - 1) }; + mipUpsampleWrites.writeSampledImage(0, sample, mipLevel, true); + mipUpsampleWrites.writeSampler(1, m_linearSampler); + mipUpsampleWrites.writeStorageImage(2, sample, mipLevel - 1); m_core.writeDescriptorSet(mipDescriptorSets[mipLevel - 1], mipUpsampleWrites); @@ -370,9 +370,9 @@ namespace vkcv::effects { const uint32_t flaresHeight = m_core.getImageHeight(m_flaresImage); DescriptorWrites lensFlaresWrites; - lensFlaresWrites.sampledImageWrites = {SampledImageDescriptorWrite(0, m_blurImage, 0)}; - lensFlaresWrites.samplerWrites = {SamplerDescriptorWrite(1, m_linearSampler)}; - lensFlaresWrites.storageImageWrites = {StorageImageDescriptorWrite(2, m_flaresImage, mipLevel)}; + lensFlaresWrites.writeSampledImage(0, m_blurImage, 0); + lensFlaresWrites.writeSampler(1, m_linearSampler); + lensFlaresWrites.writeStorageImage(2, m_flaresImage, mipLevel); m_core.writeDescriptorSet(m_lensFlaresDescriptorSet, lensFlaresWrites); @@ -415,34 +415,33 @@ namespace vkcv::effects { vkcv::DescriptorWrites compositeWrites; if (m_advanced) { - compositeWrites.sampledImageWrites = { - SampledImageDescriptorWrite(0, m_blurImage), - SampledImageDescriptorWrite(1, m_flaresImage), - SampledImageDescriptorWrite(4, m_radialLut), - SampledImageDescriptorWrite(6, m_lensDirt) - }; + compositeWrites.writeSampledImage( + 0, m_blurImage + ).writeSampledImage( + 1, m_flaresImage + ).writeSampledImage( + 4, m_radialLut + ).writeSampledImage( + 6, m_lensDirt + ); - compositeWrites.samplerWrites = { - SamplerDescriptorWrite(2, m_linearSampler), - SamplerDescriptorWrite(5, m_radialLutSampler) - }; + compositeWrites.writeSampler( + 2, m_linearSampler + ).writeSampler( + 5, m_radialLutSampler + ); - compositeWrites.storageImageWrites = { - StorageImageDescriptorWrite(3, output) - }; + compositeWrites.writeStorageImage(3, output); } else { - compositeWrites.sampledImageWrites = { - SampledImageDescriptorWrite(0, m_blurImage), - SampledImageDescriptorWrite(1, m_flaresImage) - }; + compositeWrites.writeSampledImage( + 0, m_blurImage + ).writeSampledImage( + 1, m_flaresImage + ); - compositeWrites.samplerWrites = { - SamplerDescriptorWrite(2, m_linearSampler) - }; + compositeWrites.writeSampler(2, m_linearSampler); - compositeWrites.storageImageWrites = { - StorageImageDescriptorWrite(3, output) - }; + compositeWrites.writeStorageImage(3, output); } m_core.writeDescriptorSet(m_compositeDescriptorSet, compositeWrites); @@ -477,11 +476,11 @@ namespace vkcv::effects { 0.0f, 1.0f, 1.0f, 1.0f }); - const uint32_t halfWidth = static_cast<uint32_t>(std::ceil( + const auto halfWidth = static_cast<uint32_t>(std::ceil( static_cast<float>(m_core.getImageWidth(output)) * 0.5f )); - const uint32_t halfHeight = static_cast<uint32_t>(std::ceil( + const auto halfHeight = static_cast<uint32_t>(std::ceil( static_cast<float>(m_core.getImageHeight(output)) * 0.5f )); diff --git a/modules/gui/include/vkcv/gui/GUI.hpp b/modules/gui/include/vkcv/gui/GUI.hpp index 8826cdbac057e39f2655844bfe9a252da43a4596..303fbb2c0920b400cb7637641a70e26665b4dabd 100644 --- a/modules/gui/include/vkcv/gui/GUI.hpp +++ b/modules/gui/include/vkcv/gui/GUI.hpp @@ -9,29 +9,73 @@ namespace vkcv::gui { + /** + * @defgroup vkcv_gui GUI Module + * A module to manage ImGUI integration for VkCV applications. + * @{ + */ + + /** + * Class to manage ImGui integration for VkCV. + */ class GUI final { private: + /** + * Window handle of the currently used window to draw user interface on. + */ WindowHandle m_windowHandle; + + /** + * Reference to the current Core instance. + */ Core& m_core; - + + /** + * Reference to the current Context instance. + */ const Context& m_context; - + + /** + * ImGui context for drawing GUI. + */ ImGuiContext* m_gui_context; - + + /** + * Vulkan handle for the ImGui descriptor pool. + */ vk::DescriptorPool m_descriptor_pool; + + /** + * Vulkan handle for the ImGui render pass. + */ vk::RenderPass m_render_pass; - + + /** + * Event handle for pressing a mouse button. + */ event_handle<int,int,int> f_mouseButton; + + /** + * Event handle for scrolling with the mouse or touchpad. + */ event_handle<double,double> f_mouseScroll; + + /** + * Event handle for pressing a key. + */ event_handle<int,int,int,int> f_key; + + /** + * Event handle for typing a character. + */ event_handle<unsigned int> f_char; public: /** - * Constructor of a new instance of ImGui management + * Constructor of a new instance for ImGui management. * - * @param core Valid #Core instance of the framework - * @param window Valid #Window instance of the framework + * @param[in,out] core Valid Core instance of the framework + * @param[in,out] windowHandle Valid Window handle of the framework */ GUI(Core& core, WindowHandle& windowHandle); @@ -42,12 +86,12 @@ namespace vkcv::gui { GUI& operator=(GUI&& other) = delete; /** - * Destructor of a #GUI instance + * Destructor of a GUI instance. */ virtual ~GUI(); /** - * Sets up a new frame for ImGui to draw + * Sets up a new frame for ImGui to draw. */ void beginGUI(); @@ -59,4 +103,6 @@ namespace vkcv::gui { }; + /** @} */ + } diff --git a/modules/material/include/vkcv/material/Material.hpp b/modules/material/include/vkcv/material/Material.hpp index 41ee8aecce98072981be80ccf9803c43c6464746..7251bda151cab9f812114f8a7a707597c476ad21 100644 --- a/modules/material/include/vkcv/material/Material.hpp +++ b/modules/material/include/vkcv/material/Material.hpp @@ -6,51 +6,177 @@ #include <vkcv/Handles.hpp> namespace vkcv::material { - + + /** + * @defgroup vkcv_material Material Module + * A module to manage standardized materials for rendering. + * @{ + */ + + /** + * Enum to handle standardized material types. + */ enum class MaterialType { + /** + * The material can be used for physically based rendering. + */ PBR_MATERIAL = 1, - + + /** + * The type is unknown. + */ UNKNOWN = 0 }; - + + /** + * Class to manage required handles for materials using + * a wide range of textures with separate samplers and factors. + */ class Material { private: + + /** + * A nested structure for textures used by a material. + */ struct Texture { + /** + * The image handle of a texture. + */ ImageHandle m_Image; + + /** + * The sampler handle of a texture. + */ SamplerHandle m_Sampler; + + /** + * The list of custom factors for a given texture. + */ std::vector<float> m_Factors; }; - + + /** + * The type of a material. + */ MaterialType m_Type; + + /** + * The descriptor set handle of a material. + */ DescriptorSetHandle m_DescriptorSet; + + /** + * The descriptor set layout used by a material. + */ DescriptorSetLayoutHandle m_DescriptorSetLayout; + + /** + * The list of textures used by a material. + */ std::vector<Texture> m_Textures; public: + /** + * Default constructor to create an invalid material instance. + */ Material(); + + /** + * Destructor to release handles and resources of a material instance. + */ ~Material() = default; + /** + * Copy-constructor to copy a given material instance. + * @param other Other material + */ Material(const Material& other) = default; + + /** + * Move-constructor to move a given material instance. + * @param other Other material + */ Material(Material&& other) = default; + /** + * Copy-operator to copy a given material instance. + * @param other Other material + * @return Reference to the material + */ Material& operator=(const Material& other) = default; - Material& operator=(Material&& other) = default; + /** + * Move-operator to move a given material instance. + * @param other Other material + * @return Reference to the material + */ + Material& operator=(Material&& other) = default; + + /** + * Returns the type of a material as MaterialType. + * @return Type of material + */ [[nodiscard]] MaterialType getType() const; - + + /** + * Returns the descriptor set handle of the material. + * @return Descriptor set handle + */ [[nodiscard]] const DescriptorSetHandle& getDescriptorSet() const; + /** + * Returns the descriptor set layout handle used by the material. + * @return Descriptor set layout handle + */ [[nodiscard]] const DescriptorSetLayoutHandle& getDescriptorSetLayout() const; - + + /** + * Checks if the material is valid and returns the status + * as boolean value. + * @return true if the material is valid, otherwise false + */ explicit operator bool() const; - + + /** + * Checks if the material is invalid and returns the status + * as boolean value. + * @return true if the material is invalid, otherwise false + */ bool operator!() const; - - static const std::unordered_map<uint32_t ,DescriptorBinding>& getDescriptorBindings(MaterialType type); - + + /** + * Returns the descriptor bindings required by a given material + * type to create the descriptor set layout. + * @param[in] type Type of material + * @return Descriptor bindings of a material type + */ + static const DescriptorBindings& getDescriptorBindings(MaterialType type); + + /** + * Creates a new valid material which supports physically based + * rendering. + * @param[in,out] core Reference to Core instance + * @param[in] colorImg Base color image handle + * @param[in] colorSmp Base color sampler handle + * @param[in] normalImg Normal map image handle + * @param[in] normalSmp Normal map sampler handle + * @param[in] metRoughImg Metallic and roughness image handle + * @param[in] metRoughSmp Metallic and roughness sampler handle + * @param[in] occlusionImg Occlusion map image handle + * @param[in] occlusionSmp Occlusion map sampler handle + * @param[in] emissiveImg Emissive image handle + * @param[in] emissiveSmp Emissive sampler handle + * @param[in] baseColorFactor 4D vector of base color factors + * @param[in] metallicFactor Metallic factor + * @param[in] roughnessFactor Roughness factor + * @param[in] normalScale Scale of normal map + * @param[in] occlusionStrength Strength of occlusion + * @param[in] emissiveFactor 3D vector of emmisive factors + * @return New material instance + */ static Material createPBR(Core &core, const ImageHandle &colorImg, const SamplerHandle &colorSmp, @@ -70,5 +196,7 @@ namespace vkcv::material { const float emissiveFactor [3]); }; + + /** @} */ } diff --git a/modules/material/src/vkcv/material/Material.cpp b/modules/material/src/vkcv/material/Material.cpp index bd26733b878634e3caf5b927e8c0307432279212..2bd18e8342a24d6311182c9c0c2d640d3cbfa185 100644 --- a/modules/material/src/vkcv/material/Material.cpp +++ b/modules/material/src/vkcv/material/Material.cpp @@ -201,8 +201,8 @@ namespace vkcv::material { vkcv::DescriptorWrites setWrites; for (size_t i = 0; i < material.m_Textures.size(); i++) { - setWrites.sampledImageWrites.emplace_back(i * 2, material.m_Textures[i].m_Image); - setWrites.samplerWrites.emplace_back(i * 2 + 1, material.m_Textures[i].m_Sampler); + setWrites.writeSampledImage(i * 2, material.m_Textures[i].m_Image); + setWrites.writeSampler(i * 2 + 1, material.m_Textures[i].m_Sampler); } core.writeDescriptorSet(material.m_DescriptorSet, setWrites); diff --git a/modules/meshlet/include/vkcv/meshlet/Forsyth.hpp b/modules/meshlet/include/vkcv/meshlet/Forsyth.hpp index 43dc9a3b6bb81ea915268de7a7b53b18efd27638..90625bd470ac4ecbc27f2e6f95ab9e18734557f8 100644 --- a/modules/meshlet/include/vkcv/meshlet/Forsyth.hpp +++ b/modules/meshlet/include/vkcv/meshlet/Forsyth.hpp @@ -4,15 +4,24 @@ namespace vkcv::meshlet { - /** - * Reorders the index buffer, simulating a LRU cache, so that vertices are grouped together in close triangle patches - * @param idxBuf current IndexBuffer - * @param vertexCount of the mesh - * @return new reordered index buffer to replace the input index buffer - * References: - * https://tomforsyth1000.github.io/papers/fast_vert_cache_opt.html - * https://www.martin.st/thesis/efficient_triangle_reordering.pdf - * https://github.com/vivkin/forsyth/blob/master/forsyth.h - */ - VertexCacheReorderResult forsythReorder(const std::vector<uint32_t> &idxBuf, const size_t vertexCount); + + /** + * @addtogroup vkcv_meshlet + * @{ + */ + + /** + * Reorders the index buffer, simulating a LRU cache, so that vertices are grouped together in close triangle patches + * @param idxBuf current IndexBuffer + * @param vertexCount of the mesh + * @return new reordered index buffer to replace the input index buffer + * References: + * https://tomforsyth1000.github.io/papers/fast_vert_cache_opt.html + * https://www.martin.st/thesis/efficient_triangle_reordering.pdf + * https://github.com/vivkin/forsyth/blob/master/forsyth.h + */ + VertexCacheReorderResult forsythReorder(const std::vector<uint32_t> &idxBuf, const size_t vertexCount); + + /** @} */ + } diff --git a/modules/meshlet/include/vkcv/meshlet/Meshlet.hpp b/modules/meshlet/include/vkcv/meshlet/Meshlet.hpp index 9900dffaf28c85753d367ba79bbdf5c19a2cf479..ee32878726123a8d51c3816c9df2644da4ae9b6c 100644 --- a/modules/meshlet/include/vkcv/meshlet/Meshlet.hpp +++ b/modules/meshlet/include/vkcv/meshlet/Meshlet.hpp @@ -7,6 +7,12 @@ namespace vkcv::meshlet { + /** + * @defgroup vkcv_meshlet Meshlet Module + * A module to convert meshes into meshlets for rendering via mesh shaders. + * @{ + */ + struct Vertex { glm::vec3 position; float padding0; @@ -56,4 +62,6 @@ namespace vkcv::meshlet { const std::vector<uint8_t>& indexData, vkcv::asset::IndexType indexType); + /** @} */ + } \ No newline at end of file diff --git a/modules/meshlet/include/vkcv/meshlet/Tipsify.hpp b/modules/meshlet/include/vkcv/meshlet/Tipsify.hpp index 6fb4b37d9c17c82642c3b5e7667c3e8acc50b8c0..3c808f9565ee1e73b14356dc0f4c8f4cd7c6dd9c 100644 --- a/modules/meshlet/include/vkcv/meshlet/Tipsify.hpp +++ b/modules/meshlet/include/vkcv/meshlet/Tipsify.hpp @@ -5,6 +5,12 @@ #include <iostream> namespace vkcv::meshlet { + + /** + * @addtogroup vkcv_meshlet + * @{ + */ + /** * reorders the IndexBuffer, so all usages of vertices to triangle are as close as possible * @param indexBuffer32Bit current IndexBuffer @@ -20,4 +26,7 @@ namespace vkcv::meshlet { */ VertexCacheReorderResult tipsifyMesh(const std::vector<uint32_t> &indexBuffer32Bit, const int vertexCount, const unsigned int cacheSize = 20); + + /** @} */ + } \ No newline at end of file diff --git a/modules/meshlet/src/vkcv/meshlet/Tipsify.cpp b/modules/meshlet/src/vkcv/meshlet/Tipsify.cpp index c5762100bc37eccbe3e4f6b4c94e5f0e580c53c7..101a777d4ef52d31579355f52c562a88e058cbb5 100644 --- a/modules/meshlet/src/vkcv/meshlet/Tipsify.cpp +++ b/modules/meshlet/src/vkcv/meshlet/Tipsify.cpp @@ -18,18 +18,18 @@ namespace vkcv::meshlet { /** * searches for the next VertexIndex that was used before or returns any vertexIndex if no used was found - * @param livingTriangles - * @param usedVerticeStack - * @param usedVerticeCount - * @param usedVerticeOffset - * @param vertexCount - * @param lowestLivingVertexIndex - * @param currentTriangleIndex - * @param skippedIndices + * @param livingVertices vertice that still has a living triangle + * @param usedVerticeStack stack of vertices that are recently used + * @param usedVerticeCount number of last used vertices that maxes at @param maxUsedVertices + * @param usedVerticeOffset the @param usedVerticeStack wraps around and overrides old vertices, this offset keeps the wrapping intact + * @param vertexCount total vertex count to terminate correctly + * @param lowestLivingVertexIndex vertexIndex with the lowest number + * @param currentTriangleIndex index of the currently fanned triangle + * @param skippedIndices indices that define a new meshlet, even if they are close in memory * @return a VertexIndex to be used as fanningVertexIndex */ int skipDeadEnd( - const std::vector<uint8_t> &livingTriangles, + const std::vector<uint8_t> &livingVertices, const std::vector<uint32_t> &usedVerticeStack, int &usedVerticeCount, int &usedVerticeOffset, @@ -43,14 +43,14 @@ namespace vkcv::meshlet { // iterate from the latest to the oldest. + maxUsedVertices to always make it a positive number in the range 0 to maxUsedVertices -1 int nextVertex = usedVerticeStack[mod(--usedVerticeCount)]; - if (livingTriangles[nextVertex] > 0) { + if (livingVertices[nextVertex] > 0) { return nextVertex; } } // returns any vertexIndex since no last used has a living triangle while (lowestLivingVertexIndex + 1 < vertexCount) { lowestLivingVertexIndex++; - if (livingTriangles[lowestLivingVertexIndex] > 0) { + if (livingVertices[lowestLivingVertexIndex] > 0) { // add index of the vertex to skippedIndices skippedIndices.push_back(static_cast<uint32_t>(currentTriangleIndex * 3)); return lowestLivingVertexIndex; @@ -61,19 +61,19 @@ namespace vkcv::meshlet { /** * searches for the best next candidate as a fanningVertexIndex - * @param vertexCount - * @param lowestLivingVertexIndex - * @param cacheSize - * @param possibleCandidates - * @param numPossibleCandidates - * @param lastTimestampCache - * @param currentTimeStamp - * @param livingTriangles - * @param usedVerticeStack - * @param usedVerticeCount - * @param usedVerticeOffset - * @param currentTriangleIndex - * @param skippedIndices + * @param vertexCount total vertexCount of the mesh + * @param lowestLivingVertexIndex vertexIndex with the lowest number + * @param cacheSize number to determine in which range vertices are prioritized to me reused + * @param possibleCandidates candidates for the next vertex to be fanned out + * @param numPossibleCandidates number of all possible candidates + * @param lastTimestampCache number of the last iteration the vertex was used + * @param currentTimeStamp current iteration of all vertices + * @param livingVertices vertice that still has a living triangle + * @param usedVerticeStack stack of vertices that are recently used + * @param usedVerticeCount number of last used vertices that maxes at @param maxUsedVertices + * @param usedVerticeOffset the @param usedVerticeStack wraps around and overrides old vertices, this offset keeps the wrapping intact + * @param currentTriangleIndex index of the currently fanned triangle + * @param skippedIndices indices that define a new meshlet, even if they are close in memory * @return a VertexIndex to be used as fanningVertexIndex */ int getNextVertexIndex(int vertexCount, @@ -83,7 +83,7 @@ namespace vkcv::meshlet { int numPossibleCandidates, const std::vector<uint32_t> &lastTimestampCache, int currentTimeStamp, - const std::vector<uint8_t> &livingTriangles, + const std::vector<uint8_t> &livingVertices, const std::vector<uint32_t> &usedVerticeStack, int &usedVerticeCount, int &usedVerticeOffset, @@ -96,12 +96,12 @@ namespace vkcv::meshlet { int vertexIndex = possibleCandidates[j]; // the candidate needs to be not fanned out yet - if (livingTriangles[vertexIndex] > 0) { + if (livingVertices[vertexIndex] > 0) { int priority = -1; // prioritizes recent used vertices, but tries not to pick one that has many triangles -> fills holes better - if ( currentTimeStamp - lastTimestampCache[vertexIndex] + 2 * livingTriangles[vertexIndex] <= - cacheSize) { + if ( currentTimeStamp - lastTimestampCache[vertexIndex] + 2 * livingVertices[vertexIndex] <= + cacheSize) { priority = currentTimeStamp - lastTimestampCache[vertexIndex]; } // select the vertexIndex with the highest priority @@ -115,14 +115,14 @@ namespace vkcv::meshlet { // if no candidate is alive, try and find another one if (nextVertexIndex == -1) { nextVertexIndex = skipDeadEnd( - livingTriangles, - usedVerticeStack, - usedVerticeCount, - usedVerticeOffset, - vertexCount, - lowestLivingVertexIndex, - currentTriangleIndex, - skippedIndices); + livingVertices, + usedVerticeStack, + usedVerticeCount, + usedVerticeOffset, + vertexCount, + lowestLivingVertexIndex, + currentTriangleIndex, + skippedIndices); } return nextVertexIndex; } diff --git a/modules/scene/include/vkcv/scene/Bounds.hpp b/modules/scene/include/vkcv/scene/Bounds.hpp index 07cdf88828d786982b0fe8e7919d543557794c42..8ad5806506610dbef6e4f1e0e26d66dfe0dbb63b 100644 --- a/modules/scene/include/vkcv/scene/Bounds.hpp +++ b/modules/scene/include/vkcv/scene/Bounds.hpp @@ -5,65 +5,205 @@ #include <glm/vec3.hpp> namespace vkcv::scene { - + + /** + * @addtogroup vkcv_scene + * @{ + */ + + /** + * A basic class to represent axis aligned bounding boxes. + */ class Bounds { private: + /** + * Minimum values of the box as 3D vector. + */ glm::vec3 m_min; + + /** + * Maximum values of the box as 3D vector. + */ glm::vec3 m_max; public: + /** + * Default constructor creating a zero volume axis aligned bounding + * box. + */ Bounds(); + + /** + * Constructor creating a zero volume axis aligned bounding + * box around a certain point. + * @param[in] point Center of the box as 3D vector + */ + Bounds(const glm::vec3& point); + + /** + * Constructor creating an axis aligned bounding box with given + * boundaries, defined through minimum and maximum values. + * @param[in] min Minimum values of the box as 3D vector + * @param[in] max Maximum values of the box as 3D vector + */ Bounds(const glm::vec3& min, const glm::vec3& max); + + /** + * Destructor of an axis aligned bounding box. + */ ~Bounds() = default; - + + /** + * Copy-constructor of an axis aligned bounding box. + * @param[in] other Other box as Bounds + */ Bounds(const Bounds& other) = default; - Bounds(Bounds&& other) = default; - + + /** + * Move-constructor of an axis aligned bounding box. + * @param[in,out] other Other box as Bounds + */ + Bounds(Bounds&& other) = default; + + /** + * Copy-operator of an axis aligned bounding box. + * @param[in] other Other box as Bounds + * @return Reference to this box + */ Bounds& operator=(const Bounds& other) = default; + + /** + * Move-operator of an axis aligned bounding box. + * @param[in,out] other Other box as Bounds + * @return Reference to this box + */ Bounds& operator=(Bounds&& other) = default; - + + /** + * Set and replace the minimum values of the box + * via a 3D vector. + * @param[in] min New minimum values of the box as 3D vector + */ void setMin(const glm::vec3& min); - + + /** + * Return the current minimum values of the box as + * 3D vector. + * @return Minimum values of the box as 3D vector + */ [[nodiscard]] const glm::vec3& getMin() const; - + + /** + * Set and replace the maximum values of the box + * via a 3D vector. + * @param[in] max New maximum values of the box as 3D vector + */ void setMax(const glm::vec3& max); - + + /** + * Return the current maximum values of the box as + * 3D vector. + * @return Maximum values of the box as 3D vector + */ [[nodiscard]] const glm::vec3& getMax() const; - + + /** + * Set the new center of the box by moving it and keeping + * its current volume. + * @param[in] center New center as 3D vector + */ void setCenter(const glm::vec3& center); - + + /** + * Return the current center of the box as 3D vector. + * @return Center as 3D vector + */ [[nodiscard]] glm::vec3 getCenter() const; - + + /** + * Set the new size of the box by scaling it from its center, + * keeping the center position but replacing its volume. + * @param[in] size New size as 3D vector + */ void setSize(const glm::vec3& size); - + + /** + * Return the current size of the box as 3D vector. + * @return Size as 3D vector + */ [[nodiscard]] glm::vec3 getSize() const; - + + /** + * Return a fixed size array containing all corners of + * the box as 3D vectors in absolute positions. + * @return Array of corners as 3D vectors + */ [[nodiscard]] std::array<glm::vec3, 8> getCorners() const; - + + /** + * Resize the box to include a given point, provided + * in absolute position as 3D vector. + * @param[in] point Point as 3D vector + */ void extend(const glm::vec3& point); - + + /** + * Return if a given point, provided in absolute position, + * is inside this box or not. + * @param[in] point Point as 3D vector + * @return true if the point is inside, otherwise false + */ [[nodiscard]] bool contains(const glm::vec3& point) const; - + + /** + * Return if a given other axis aligned bounding box is + * inside this box or not. + * @param[in] other Other box as Bounds + * @return true if the box is inside, otherwise false + */ [[nodiscard]] bool contains(const Bounds& other) const; - + + /** + * Return if a given other axis aligned bounding box is + * intersecting this box or not. + * @param[in] other Other box as Bounds + * @return true if the boxes are intersecting, otherwise false + */ [[nodiscard]] bool intersects(const Bounds& other) const; - + + /** + * Return if the defined bounding box is valid (min <= max). + * @return true if the box is valid, otherwise false + */ [[nodiscard]] explicit operator bool() const; - + + /** + * Return if the defined bounding box is invalid (min > max). + * @return true if the box is invalid, otherwise false + */ [[nodiscard]] bool operator!() const; }; - + + /** + * Stream-operator of the axis aligned bounding box to print + * it as readable output to logs or the console. + * @param[out] out Output stream + * @param[in] bounds Axis aligned bounding box + * @return Accessed output stream + */ std::ostream& operator << (std::ostream& out, const Bounds& bounds); + + /** @} */ } diff --git a/modules/scene/include/vkcv/scene/Frustum.hpp b/modules/scene/include/vkcv/scene/Frustum.hpp index de3917575a9aed32459e6403fab1d6d8fe131b0a..e40092240614a5ee76fe3f5aa5a43db98d39970a 100644 --- a/modules/scene/include/vkcv/scene/Frustum.hpp +++ b/modules/scene/include/vkcv/scene/Frustum.hpp @@ -4,9 +4,42 @@ #include "vkcv/scene/Bounds.hpp" namespace vkcv::scene { + + /** + * @addtogroup vkcv_scene + * @{ + */ - Bounds transformBounds(const glm::mat4& transform, const Bounds& bounds, bool* negative_w = nullptr); - + /** + * Transform a given axis aligned bounding box into frustum coordinates + * using a given 4x4 transformation matrix to return a new axis aligned + * bounding box containing that transformed box. + * @param[in] transform Frustum defining 4x4 matrix + * @param[in] bounds Axis aligned bounding box + * @return Bounds containing box in frustum coordinates + */ + Bounds transformBounds(const glm::mat4& transform, const Bounds& bounds); + + /** + * Transform a given axis aligned bounding box into frustum coordinates + * using a given 4x4 transformation matrix to return a new axis aligned + * bounding box containing that transformed box. + * @param[in] transform Frustum defining 4x4 matrix + * @param[in] bounds Axis aligned bounding box + * @param[out] negative_w Flag if w-coordinate is negative + * @return Bounds containing box in frustum coordinates + */ + Bounds transformBounds(const glm::mat4& transform, const Bounds& bounds, bool& negative_w); + + /** + * Check if an axis aligned bounding box is intersecting a given frustum + * defined by a 4x4 transformation matrix. + * @param[in] transform Frustum defining 4x4 matrix + * @param[in] bounds Axis aligned bounding box + * @return true if the box and frustum are intersecting, otherwise false + */ bool checkFrustum(const glm::mat4& transform, const Bounds& bounds); + + /** @} */ } diff --git a/modules/scene/include/vkcv/scene/Mesh.hpp b/modules/scene/include/vkcv/scene/Mesh.hpp index bc82af4bfabed5e8bfc286bc53cd7b89791726fc..3118696bdc270506bc6197e7d853148072294663 100644 --- a/modules/scene/include/vkcv/scene/Mesh.hpp +++ b/modules/scene/include/vkcv/scene/Mesh.hpp @@ -7,46 +7,128 @@ #include "MeshPart.hpp" namespace vkcv::scene { - + + /** + * @addtogroup vkcv_scene + * @{ + */ + + /** + * An event function type to be called on per drawcall recording level to adjust data + * like push constants with provided matrices. + */ typedef typename event_function<const glm::mat4&, const glm::mat4&, PushConstants&, vkcv::DrawcallInfo&>::type RecordMeshDrawcallFunction; class Node; - + + /** + * A class to represent a whole mesh to render. + */ class Mesh { friend class Node; private: + /** + * Parent scene of the mesh. + */ Scene& m_scene; + + /** + * List of the meshes parts. + */ std::vector<MeshPart> m_parts; + + /** + * List of the meshes drawcalls to render. + */ std::vector<DrawcallInfo> m_drawcalls; + + /** + * Local transformation matrix of the mesh. + */ glm::mat4 m_transform; + + /** + * Axis aligned bounding box of the mesh. + */ Bounds m_bounds; - + + /** + * Constructor of a new mesh with a given scene as parent. + * @param[in,out] scene Scene + */ explicit Mesh(Scene& scene); - + + /** + * Load mesh data from a scene structure from the asset loader + * creating and loading all mesh parts being required. + * @param[in] scene Scene structure from asset loader + * @param[in] mesh Mesh structure from asset loader + */ void load(const asset::Scene& scene, const asset::Mesh& mesh); - + + /** + * Record drawcalls of the mesh, equally to all its visible parts. + * @param[in] viewProjection View-transformation and projection as 4x4 matrix + * @param[out] pushConstants Structure to store push constants per drawcall + * @param[out] drawcalls List of drawcall structures + * @param[in] record Drawcall recording event function + */ void recordDrawcalls(const glm::mat4& viewProjection, PushConstants& pushConstants, std::vector<DrawcallInfo>& drawcalls, const RecordMeshDrawcallFunction& record); - + + /** + * Return the amount of drawcalls of the mesh + * as sum of all its parts. + * @return Amount of drawcalls + */ [[nodiscard]] size_t getDrawcallCount() const; public: + /** + * Destructor of a mesh. + */ ~Mesh(); - + + /** + * Copy-constructor of a mesh. + * @param[in] other Other mesh instance + */ Mesh(const Mesh& other) = default; - Mesh(Mesh&& other) = default; - + + /** + * Move-constructor of a mesh. + * @param[in,out] other Other mesh instance + */ + Mesh(Mesh&& other) = default; + + /** + * Copy-operator of a mesh. + * @param[in] other Other mesh instance + * @return Reference to this mesh instance + */ Mesh& operator=(const Mesh& other); + + /** + * Move-operator of a mesh. + * @param[in,out] other Other mesh instance + * @return Reference to this mesh instance + */ Mesh& operator=(Mesh&& other) noexcept; - + + /** + * Return the axis aligned bounding box of the mesh. + * @return Axis aligned bounding box of this mesh + */ [[nodiscard]] const Bounds& getBounds() const; }; + + /** @} */ } diff --git a/modules/scene/include/vkcv/scene/MeshPart.hpp b/modules/scene/include/vkcv/scene/MeshPart.hpp index 0d3467c6b57fcece69eb6f0c609c604fb99907d2..8d77efd7a112ea92a6c4192e5a5cf43cea53e800 100644 --- a/modules/scene/include/vkcv/scene/MeshPart.hpp +++ b/modules/scene/include/vkcv/scene/MeshPart.hpp @@ -9,46 +9,140 @@ #include "Bounds.hpp" namespace vkcv::scene { + + /** + * @addtogroup vkcv_scene + * @{ + */ class Scene; class Mesh; - + + /** + * A class to represent a group of vertices to render + * a part of a mesh. + */ class MeshPart { friend class Mesh; private: + /** + * Parent scene of the mesh part. + */ Scene& m_scene; + + /** + * The buffer handle of its vertex buffer. + */ BufferHandle m_vertices; + + /** + * The list of the used vertex buffer bindings. + */ std::vector<VertexBufferBinding> m_vertexBindings; + + /** + * The buffer handle of its index buffer. + */ BufferHandle m_indices; + + /** + * The amount of indices in its index buffer. + */ size_t m_indexCount; + + /** + * Axis aligned bounding box of the mesh part. + */ Bounds m_bounds; + + /** + * The index of the material used to render + * this part of the mesh. + */ size_t m_materialIndex; - + + /** + * Constructor of a new mesh part with a given scene as parent. + * @param[in,out] scene Scene + */ explicit MeshPart(Scene& scene); - + + /** + * Load vertex and index data from structures provided by the asset loader + * and add a matching drawcall to the list if the loaded mesh part is valid. + * @param[in] scene Scene structure from asset loader + * @param[in] vertexGroup Vertex group structure from asset loader + * @param[out] drawcalls List of drawcalls + */ void load(const asset::Scene& scene, const asset::VertexGroup& vertexGroup, std::vector<DrawcallInfo>& drawcalls); public: + /** + * Destructor of a mesh part. + */ ~MeshPart(); - + + /** + * Copy-constructor of a mesh part. + * @param[in] other Other mesh part + */ MeshPart(const MeshPart& other); - MeshPart(MeshPart&& other); - + + /** + * Move-constructor of a mesh part. + * @param[in,out] other Other mesh part + */ + MeshPart(MeshPart&& other) noexcept; + + /** + * Copy-operator of a mesh part. + * @param[in] other Other mesh part + * @return Reference to this mesh part + */ MeshPart& operator=(const MeshPart& other); - MeshPart& operator=(MeshPart&& other) noexcept; - + + /** + * Move-operator of a mesh part. + * @param[in,out] other Other mesh part + * @return Reference to this mesh part + */ + MeshPart& operator=(MeshPart&& other) noexcept; + + /** + * Get the material used by this specific part of + * the mesh for rendering. + * @return Material + */ [[nodiscard]] const material::Material& getMaterial() const; - + + /** + * Return the axis aligned bounding box of this + * specific part of the mesh. + * @return Axis aligned bounding box of this mesh part + */ [[nodiscard]] const Bounds& getBounds() const; - + + /** + * Return the status if this part of the mesh is valid + * as boolean value. + * @return true if the mesh part is valid, otherwise false + */ explicit operator bool() const; + + /** + * Return the status if this part of the mesh is invalid + * as boolean value. + * @return true if the mesh part is invalid, otherwise false + */ bool operator!() const; }; + /** @} */ + } diff --git a/modules/scene/include/vkcv/scene/Node.hpp b/modules/scene/include/vkcv/scene/Node.hpp index 1fcca5b9cbecf1064070d7737d008d2b108371db..51088f2564fb56a9d63d99238cb0665c6989bc9e 100644 --- a/modules/scene/include/vkcv/scene/Node.hpp +++ b/modules/scene/include/vkcv/scene/Node.hpp @@ -8,54 +8,151 @@ #include "Mesh.hpp" namespace vkcv::scene { + + /** + * @addtogroup vkcv_scene + * @{ + */ class Scene; - + + /** + * A class to represent a graph node in a scene graph. + */ class Node { friend class Scene; private: + /** + * Parent scene of the node. + */ Scene& m_scene; - + + /** + * List of meshes added the node. + */ std::vector<Mesh> m_meshes; + + /** + * List of child nodes added the node. + */ std::vector<Node> m_nodes; + + /** + * Axis aligned bounding box of the node. + */ Bounds m_bounds; - + + /** + * Constructor of a new node with a given scene as parent. + * @param[in,out] scene Scene + */ explicit Node(Scene& scene); - + + /** + * Add a given mesh to this node for drawcall recording. + * @param[in] mesh Mesh + */ void addMesh(const Mesh& mesh); - + + /** + * Load and add a mesh from a scene preloaded with the asset loader. + * @param[in] asset_scene Scene structure from asset loader + * @param[in] asset_mesh Mesh structure from asset loader + */ void loadMesh(const asset::Scene& asset_scene, const asset::Mesh& asset_mesh); - + + /** + * Record drawcalls of all meshes of this node and its child nodes. + * @param[in] viewProjection View-transformation and projection as 4x4 matrix + * @param[out] pushConstants Structure to store push constants per drawcall + * @param[out] drawcalls List of drawcall structures + * @param[in] record Drawcall recording event function + */ void recordDrawcalls(const glm::mat4& viewProjection, PushConstants& pushConstants, std::vector<DrawcallInfo>& drawcalls, const RecordMeshDrawcallFunction& record); - + + /** + * Splits child nodes into tree based graphs of nodes + * until all nodes contain an amount of meshes below + * a given maximum. + * @param[in] maxMeshesPerNode Maximum amount of meshes per node + */ void splitMeshesToSubNodes(size_t maxMeshesPerNode); - + + /** + * Return the sum of drawcalls in the graph of this node. + * @return Amount of drawcalls + */ [[nodiscard]] size_t getDrawcallCount() const; - + + /** + * Add a new node as child to the scene graph with this node + * as parent and return its index. + * @return Index of the new node + */ size_t addNode(); - + + /** + * Get a reference to the child node with a given index. + * @param[in] index Valid index of a child node + * @return Matching child node + */ Node& getNode(size_t index); - + + /** + * Get a const reference to the child node with a given index. + * @param[in] index Valid index of a child node + * @return Matching child node + */ [[nodiscard]] const Node& getNode(size_t index) const; public: + /** + * Destructor of a scene node. + */ ~Node(); - + + /** + * Copy-constructor of a scene node. + * @param[in] other Other scene node + */ Node(const Node& other) = default; + + /** + * Move-constructor of a scene node. + * @param[in,out] other Other scene node + */ Node(Node&& other) = default; - + + /** + * Copy-operator of a scene node. + * @param[in] other Other scene node + * @return Reference of this node + */ Node& operator=(const Node& other); + + /** + * Move-operator of a scene node. + * @param[in,out] other Other scene node + * @return Reference of this node + */ Node& operator=(Node&& other) noexcept; - + + /** + * Return the axis aligned bounding box of the + * scene node. + * @return Axis aligned bounding box of this node + */ [[nodiscard]] const Bounds& getBounds() const; }; + + /** @} */ } diff --git a/modules/scene/include/vkcv/scene/Scene.hpp b/modules/scene/include/vkcv/scene/Scene.hpp index 095c5e278e9e3f76544e884bdb87cea10770307a..c482b464a8a24e83f1ba12d8294749d7b0cae48a 100644 --- a/modules/scene/include/vkcv/scene/Scene.hpp +++ b/modules/scene/include/vkcv/scene/Scene.hpp @@ -11,50 +11,159 @@ #include "Node.hpp" namespace vkcv::scene { - + + /** + * @defgroup vkcv_scene Scene Module + * A module to manage basic scene rendering with CPU-side frustum culling. + * @{ + */ + + /** + * A class to represent a scene graph. + */ class Scene { friend class MeshPart; private: + /** + * A nested structure to manage material storage. + */ struct Material { + /** + * The amount of active usages of the material. + */ size_t m_usages; + + /** + * The actual material data. + */ material::Material m_data; }; - + + /** + * A pointer to the current Core instance. + */ Core* m_core; - + + /** + * A list of currently used materials. + */ std::vector<Material> m_materials; + + /** + * A list of nodes in the first level of the scene graph. + */ std::vector<Node> m_nodes; - + + /** + * Constructor of a scene instance with a given Core instance. + * @param[in,out] core Pointer to valid Core instance + */ explicit Scene(Core* core); - + + /** + * Add a new node to the first level of the scene graph with + * this scene as parent and return its index. + * @return Index of the new node + */ size_t addNode(); - + + /** + * Get a reference to the first-level node with a given index. + * @param[in] index Valid index of a first-level node + * @return Matching first-level node + */ Node& getNode(size_t index); - + + /** + * Get a const reference to the first-level node with a given index. + * @param[in] index Valid index of a first-level node + * @return Matching first-level node + */ + [[nodiscard]] const Node& getNode(size_t index) const; - + + /** + * Increase the amount of usages for a certain material via its index. + * @param[in] index Index of a material + */ void increaseMaterialUsage(size_t index); - + + /** + * Decrease the amount of usages for a certain material via its index. + * @param[in] index Index of a material + */ void decreaseMaterialUsage(size_t index); - + + /** + * Load a material from a scene preloaded with the asset loader via + * its index. + * @param[in] index Valid index of a material + * @param[in] scene Scene structure from asset loader + * @param[in] material Material structure from asset loader + */ void loadMaterial(size_t index, const asset::Scene& scene, const asset::Material& material); public: + /** + * Destructor of a scene instance. + */ ~Scene(); - + + /** + * Copy-constructor of a scene instance. + * @param[in] other Other scene instance + */ Scene(const Scene& other); - Scene(Scene&& other) noexcept; - + + /** + * Move-constructor of a scene instance. + * @param[in,out] other Other scene instance + */ + Scene(Scene&& other) noexcept; + + /** + * Copy-operator of a scene instance. + * @param[in] other Other scene instance + * @return Reference to this scene + */ Scene& operator=(const Scene& other); - Scene& operator=(Scene&& other) noexcept; - + + /** + * Move-operator of a scene instance. + * @param[in,out] other Other scene instance + * @return Reference to this scene + */ + Scene& operator=(Scene&& other) noexcept; + + /** + * Return the amount of materials managed by this scene. + * @return Amount of materials + */ + [[nodiscard]] size_t getMaterialCount() const; - + + /** + * Get the material data by its certain index. + * The material can still be invalid if it was not loaded properly. + * @param[in] index Valid index of material + * @return Material + */ [[nodiscard]] const material::Material& getMaterial(size_t index) const; - + + /** + * Record drawcalls of all meshes of this scene with CPU-side frustum culling. + * @param cmdStream Command stream handle + * @param camera Scene viewing camera + * @param pass Render pass handle + * @param pipeline Graphics pipeline handle + * @param pushConstantsSizePerDrawcall Size of push constants per drawcall + * @param record Drawcall recording event function + * @param renderTargets Actual render targets + * @param windowHandle Window handle to use + */ void recordDrawcalls(CommandStreamHandle &cmdStream, const camera::Camera &camera, const PassHandle &pass, @@ -63,11 +172,25 @@ namespace vkcv::scene { const RecordMeshDrawcallFunction &record, const std::vector<ImageHandle> &renderTargets, const WindowHandle &windowHandle); - + + /** + * Instantiation function to create a new scene instance. + * @param core Current Core instance + * @return New scene instance + */ static Scene create(Core& core); - + + /** + * Load function to create a new scene instance with materials and meshes + * loaded from a file using the asset loader. + * @param core Current Core instance + * @param path Path of a valid file to load via asset loader + * @return New scene instance + */ static Scene load(Core& core, const std::filesystem::path &path); }; + + /** @} */ } \ No newline at end of file diff --git a/modules/scene/src/vkcv/scene/Bounds.cpp b/modules/scene/src/vkcv/scene/Bounds.cpp index 731d81e928deae4c27f5c857de5b94dc3180888b..9614208d2d523117eef09e1432ff755005b5c51f 100644 --- a/modules/scene/src/vkcv/scene/Bounds.cpp +++ b/modules/scene/src/vkcv/scene/Bounds.cpp @@ -7,6 +7,11 @@ namespace vkcv::scene { m_min(glm::vec3(0)), m_max(glm::vec3(0)) {} + Bounds::Bounds(const glm::vec3 &point) : + m_min(point), + m_max(point) + {} + Bounds::Bounds(const glm::vec3 &min, const glm::vec3 &max) : m_min(min), m_max(max) diff --git a/modules/scene/src/vkcv/scene/Frustum.cpp b/modules/scene/src/vkcv/scene/Frustum.cpp index 1f63eb1d07002d24add81872627777048642dcdb..10af3bc44e4f585f990577bd9d95ecfade7acca8 100644 --- a/modules/scene/src/vkcv/scene/Frustum.cpp +++ b/modules/scene/src/vkcv/scene/Frustum.cpp @@ -3,10 +3,9 @@ namespace vkcv::scene { - static glm::vec3 transformPoint(const glm::mat4& transform, const glm::vec3& point, bool* negative_w) { + static glm::vec3 transformPoint(const glm::mat4& transform, const glm::vec3& point, bool& negative_w) { const glm::vec4 position = transform * glm::vec4(point, 1.0f); - /* * We divide by the absolute of the 4th coorditnate because * clipping is weird and points have to move to the other @@ -16,39 +15,35 @@ namespace vkcv::scene { * to know if all corners are behind the camera. So these can * be culled as well */ - if (negative_w) { - const float perspective = std::abs(position[3]); - - *negative_w &= (position[3] < 0.0f); - - return glm::vec3( - position[0] / perspective, - position[1] / perspective, - position[2] / perspective - ); - } else { - return glm::vec3( - position[0], - position[1], - position[2] - ); - } + const float perspective = std::abs(position[3]); + negative_w &= (position[3] < 0.0f); + return glm::vec3( + position[0] / perspective, + position[1] / perspective, + position[2] / perspective + ); } - Bounds transformBounds(const glm::mat4& transform, const Bounds& bounds, bool* negative_w) { + Bounds transformBounds(const glm::mat4& transform, const Bounds& bounds) { const auto corners = bounds.getCorners(); - if (negative_w) { - *negative_w = true; + Bounds result (glm::vec3(transform * glm::vec4(corners[0], 1.0f))); + + for (size_t j = 1; j < corners.size(); j++) { + result.extend(glm::vec3(transform * glm::vec4(corners[j], 1.0f))); } - auto projected = transformPoint(transform, corners[0], negative_w); + return result; + } + + Bounds transformBounds(const glm::mat4& transform, const Bounds& bounds, bool& negative_w) { + const auto corners = bounds.getCorners(); + negative_w = true; - Bounds result (projected, projected); + Bounds result (transformPoint(transform, corners[0], negative_w)); for (size_t j = 1; j < corners.size(); j++) { - projected = transformPoint(transform, corners[j], negative_w); - result.extend(projected); + result.extend(transformPoint(transform, corners[j], negative_w)); } return result; @@ -61,7 +56,7 @@ namespace vkcv::scene { ); bool negative_w; - auto box = transformBounds(transform, bounds, &negative_w); + auto box = transformBounds(transform, bounds, negative_w); if (negative_w) { return false; diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp index c334cc3649550b33d9ecffd18c10865429e51591..50d14ed49d43496ada3853034be1455b044bd902 100644 --- a/modules/scene/src/vkcv/scene/MeshPart.cpp +++ b/modules/scene/src/vkcv/scene/MeshPart.cpp @@ -108,7 +108,7 @@ namespace vkcv::scene { m_scene.increaseMaterialUsage(m_materialIndex); } - MeshPart::MeshPart(MeshPart &&other) : + MeshPart::MeshPart(MeshPart &&other) noexcept : m_scene(other.m_scene), m_vertices(other.m_vertices), m_vertexBindings(other.m_vertexBindings), diff --git a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp index cabc2a2628557254f0faed222b6b9f5c27429ad1..f62190753ec440c7d732551b6229276c5a42cfc1 100644 --- a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp @@ -9,33 +9,93 @@ #include <vkcv/ShaderProgram.hpp> namespace vkcv::shader { - + + /** + * @defgroup vkcv_shader Shader Compiler Module + * A module to use runtime shader compilation. + * @{ + */ + + /** + * An event function type to be called on compilation completion. + */ typedef typename event_function<ShaderStage, const std::filesystem::path&>::type ShaderCompiledFunction; + + /** + * An event function type to be called on program compilation completion. + */ typedef typename event_function<ShaderProgram&>::type ShaderProgramCompiledFunction; + /** + * An abstract class to handle runtime shader compilation. + */ class Compiler { private: protected: + /** + * A map containing macros for shader compilation. + */ std::unordered_map<std::string, std::string> m_defines; public: + /** + * Compile a shader from source for a target stage with a custom shader + * include path and an event function called if the compilation completes. + * @param[in] shaderStage Shader pipeline stage + * @param[in] shaderSource Source of shader + * @param[in] compiled Shader compilation event + * @param[in] includePath Include path for shaders + * @return Result if the compilation succeeds + */ virtual bool compileSource(ShaderStage shaderStage, const char* shaderSource, const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath) = 0; - + + /** + * Compile a shader from a specific file path for a target stage with + * a custom shader include path and an event function called if the + * compilation completes. + * @param[in] shaderStage Shader pipeline stage + * @param[in] shaderPath Filepath of shader + * @param[in] compiled Shader compilation event + * @param[in] includePath Include path for shaders + * @param[in] update Flag to update shaders during runtime + */ virtual void compile(ShaderStage shaderStage, const std::filesystem::path& shaderPath, const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath, bool update) = 0; + /** + * Compile a shader program from a specific map of given file paths for + * target pipeline stages with a custom shader include path and an event + * function called if the compilation completes. + * @param[in,out] program Shader program + * @param[in] stages Shader pipeline stages + * @param[in] compiled Shader program compilation event + * @param[in] includePath Include path for shaders + * @param[in] update Flag to update shaders during runtime + */ void compileProgram(ShaderProgram& program, const std::unordered_map<ShaderStage, const std::filesystem::path>& stages, const ShaderProgramCompiledFunction& compiled, const std::filesystem::path& includePath = "", bool update = false); + /** + * Return the definition value of a macro for shader compilation. + * @param[in] name Macro definition name + * @return Macro definition value + */ std::string getDefine(const std::string& name) const; - + + /** + * Set a macro for shader compilation. + * @param[in] name Macro definition name + * @param[in] value Macro definition value + */ void setDefine(const std::string& name, const std::string& value); }; + + /** @} */ } diff --git a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp index eca84def118625e21df1c645cfc71b6bcddf7393..e457874ad2abc4cc3bfe9ab74fdb8d35446b5db1 100644 --- a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp @@ -6,28 +6,83 @@ #include "Compiler.hpp" namespace vkcv::shader { - + + /** + * @addtogroup vkcv_shader + * @{ + */ + + /** + * A class to handle GLSL runtime shader compilation. + */ class GLSLCompiler : public Compiler { private: public: + /** + * The constructor of a runtime GLSL shader compiler instance. + */ GLSLCompiler(); - + + /** + * The copy-constructor of a runtime GLSL shader compiler instance. + * @param[in] other Other instance of a GLSL shader compiler instance + */ GLSLCompiler(const GLSLCompiler& other); + + /** + * The move-constructor of a runtime GLSL shader compiler instance. + * @param[out] other Other instance of a GLSL shader compiler instance + */ GLSLCompiler(GLSLCompiler&& other) = default; - + + /** + * The destructor of a runtime GLSL shader compiler instance. + */ ~GLSLCompiler(); - + + /** + * The copy-operator of a runtime GLSL shader compiler instance. + * @param[in] other Other instance of a GLSL shader compiler instance + * @return Reference to this instance + */ GLSLCompiler& operator=(const GLSLCompiler& other); - GLSLCompiler& operator=(GLSLCompiler&& other) = default; - + + /** + * The copy-operator of a runtime GLSL shader compiler instance. + * @param[out] other Other instance of a GLSL shader compiler instance + * @return Reference to this instance + */ + GLSLCompiler& operator=(GLSLCompiler&& other) = default; + + /** + * Compile a GLSL shader from source for a target stage with a custom shader + * include path and an event function called if the compilation completes. + * @param[in] shaderStage Shader pipeline stage + * @param[in] shaderSource Source of shader + * @param[in] compiled Shader compilation event + * @param[in] includePath Include path for shaders + * @return Result if the compilation succeeds + */ bool compileSource(ShaderStage shaderStage, const char* shaderSource, const ShaderCompiledFunction& compiled, - const std::filesystem::path& includePath); - + const std::filesystem::path& includePath) override; + + /** + * Compile a GLSL shader from a specific file path for a target stage with + * a custom shader include path and an event function called if the + * compilation completes. + * @param[in] shaderStage Shader pipeline stage + * @param[in] shaderPath Filepath of shader + * @param[in] compiled Shader compilation event + * @param[in] includePath Include path for shaders + * @param[in] update Flag to update shaders during runtime + */ void compile(ShaderStage shaderStage, const std::filesystem::path& shaderPath, const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath = "", bool update = false) override; }; + + /** @} */ } diff --git a/modules/upscaling/include/vkcv/upscaling/BilinearUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/BilinearUpscaling.hpp index 522b9f7e2798c194969112c984b59a832801d0ad..52569467e07a5155e1cf3619755bd092ecf6979b 100644 --- a/modules/upscaling/include/vkcv/upscaling/BilinearUpscaling.hpp +++ b/modules/upscaling/include/vkcv/upscaling/BilinearUpscaling.hpp @@ -3,16 +3,38 @@ #include "Upscaling.hpp" namespace vkcv::upscaling { - + + /** + * @addtogroup vkcv_upscaling + * @{ + */ + + /** + * A class to handle upscaling via bilinear interpolation. + */ class BilinearUpscaling : public Upscaling { private: public: + /** + * Constructor to create instance for bilinear upscaling. + * @param[in,out] core Reference to a Core instance + */ explicit BilinearUpscaling(Core& core); - + + /** + * Record the comands of the bilinear upscaling instance to + * scale the image of the input handle to the resolution of + * the output image handle via bilinear interpolation. + * @param[in] cmdStream Command stream handle to record commands + * @param[in] input Input image handle + * @param[in] output Output image handle + */ void recordUpscaling(const CommandStreamHandle& cmdStream, const ImageHandle& input, const ImageHandle& output) override; }; + /** @} */ + } diff --git a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp index 7b2e96bb62544db29775faa4473d0feccd2e813c..04f9ea72ffad7510f62163e045c89140b6fdecf7 100644 --- a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp +++ b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp @@ -5,46 +5,162 @@ #include <vkcv/ShaderProgram.hpp> namespace vkcv::upscaling { - + + /** + * @addtogroup vkcv_upscaling + * @{ + */ + + /** + * Enum to set the mode of quality for + * FSR upscaling. + */ enum class FSRQualityMode : int { + /** + * Don't upscale anything. + */ NONE = 0, + + /** + * Highest quality of FSR upscaling: + * 1.3x per dimension + */ ULTRA_QUALITY = 1, + + /** + * High quality of FSR upscaling: + * 1.5x per dimension + */ QUALITY = 2, + + /** + * Medium quality of FSR upscaling: + * 1.7x per dimension + */ BALANCED = 3, + + /** + * Low quality of FSR upscaling: + * 2.0x per dimension + */ PERFORMANCE = 4 }; - + + /** + * Calculates the internal resolution for actual rendering if + * a specific mode of quality is used for upscaling with FSR. + * @param[in] mode Mode of quality + * @param[in] outputWidth Final resolution width + * @param[in] outputHeight Final resolution height + * @param[out] inputWidth Internal resolution width + * @param[out] inputHeight Internal resolution height + */ void getFSRResolution(FSRQualityMode mode, uint32_t outputWidth, uint32_t outputHeight, uint32_t &inputWidth, uint32_t &inputHeight); - + + /** + * Returns the matching negative lod bias to reduce artifacts + * upscaling with FSR under a given mode of quality. + * @param mode Mode of quality + * @return Lod bias + */ float getFSRLodBias(FSRQualityMode mode); - + + /** + * A structure to exchange required configuration + * with the shaders used by FSR upscaling. + */ struct FSRConstants { + /** + * 0th FSR constant. + */ uint32_t Const0 [4]; - uint32_t Const1 [4]; - uint32_t Const2 [4]; - uint32_t Const3 [4]; - uint32_t Sample [4]; + + /** + * 1st FSR constant. + */ + uint32_t Const1 [4]; + + /** + * 2nd FSR constant. + */ + uint32_t Const2 [4]; + + /** + * 3rd FSR constant. + */ + uint32_t Const3 [4]; + + /** + * 4th FSR constant. + */ + uint32_t Sample [4]; }; - + + /** + * A class to handle upscaling via FidelityFX Super Resolution. + * https://github.com/GPUOpen-Effects/FidelityFX-FSR + */ class FSRUpscaling : public Upscaling { private: + /** + * The EASU compute pipeline of the FSR upscaling. + */ ComputePipelineHandle m_easuPipeline; + + /** + * The RCAS compute pipeline of the FSR upscaling. + */ ComputePipelineHandle m_rcasPipeline; + /** + * The descriptor set layout of the EASU pipeline. + */ DescriptorSetLayoutHandle m_easuDescriptorSetLayout; + /** + * The descriptor set for the EASU pipeline. + */ DescriptorSetHandle m_easuDescriptorSet; + /** + * The descriptor set layout of the RCAS pipeline. + */ DescriptorSetLayoutHandle m_rcasDescriptorSetLayout; + + /** + * The descriptor set for the RCAS pipeline. + */ DescriptorSetHandle m_rcasDescriptorSet; - + + /** + * The buffer template to handle FSR constants for + * the EASU pipeline. + */ Buffer<FSRConstants> m_easuConstants; + + /** + * The buffer template to handle FSR constants for + * the RCAS pipeline. + */ Buffer<FSRConstants> m_rcasConstants; + + /** + * The image handle to store the intermidiate state of + * the FSR upscaling. + */ ImageHandle m_intermediateImage; + + /** + * The sampler handle to use for accessing the images + * in the FSR upscaling process. + */ SamplerHandle m_sampler; - + + /** + * Current state of HDR support. + */ bool m_hdr; /** @@ -61,22 +177,54 @@ namespace vkcv::upscaling { float m_sharpness; public: + /** + * Constructor to create instance for FSR upscaling. + * @param[in,out] core Reference to a Core instance + */ explicit FSRUpscaling(Core& core); - + + /** + * Record the comands of the FSR upscaling instance to + * scale the image of the input handle to the resolution of + * the output image handle via FidelityFX Super Resolution. + * @param[in] cmdStream Command stream handle to record commands + * @param[in] input Input image handle + * @param[in] output Output image handle + */ void recordUpscaling(const CommandStreamHandle& cmdStream, const ImageHandle& input, const ImageHandle& output) override; - + + /** + * Checks if HDR support is enabled and returns the status as boolean. + * @return true if HDR is supported, otherwise false + */ [[nodiscard]] bool isHdrEnabled() const; - + + /** + * Changes the status of HDR support of the FSR upscaling instance. + * @param[in] enabled New status of HDR support + */ void setHdrEnabled(bool enabled); - + + /** + * Returns the amount of sharpness the FSR upscaling instance is using. + * @return The amount of sharpness + */ [[nodiscard]] float getSharpness() const; - + + /** + * Changes the amount of sharpness of the FSR upscaling instance. + * The new sharpness value is restricted by 0.0f as lower and 1.0f + * as upper boundary. + * @param[in] sharpness New sharpness value + */ void setSharpness(float sharpness); }; + /** @} */ + } diff --git a/modules/upscaling/include/vkcv/upscaling/Upscaling.hpp b/modules/upscaling/include/vkcv/upscaling/Upscaling.hpp index da6d5426237ee8e92d62f3755180d28bf316d4f5..12ba21a8576b3c638510b58341810df7aa039bfa 100644 --- a/modules/upscaling/include/vkcv/upscaling/Upscaling.hpp +++ b/modules/upscaling/include/vkcv/upscaling/Upscaling.hpp @@ -4,20 +4,46 @@ #include <vkcv/Handles.hpp> namespace vkcv::upscaling { - + + /** + * @defgroup vkcv_upscaling Upscaling Module + * A module to upscale an image from an internal resolution to a final resolution in realtime. + * @{ + */ + + /** + * An abstract class to handle upscaling of images in realtime. + */ class Upscaling { protected: + /** + * Reference to the current Core instance. + */ Core& m_core; public: + /** + * Constructor to create an upscaling instance. + * @param[in,out] core Reference to a Core instance + */ explicit Upscaling(Core& core); ~Upscaling() = default; - + + /** + * Record the comands of the given upscaling instance to + * scale the image of the input handle to the resolution of + * the output image handle. + * @param[in] cmdStream Command stream handle to record commands + * @param[in] input Input image handle + * @param[in] output Output image handle + */ virtual void recordUpscaling(const CommandStreamHandle& cmdStream, const ImageHandle& input, const ImageHandle& output) = 0; }; + + /** @} */ } diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index 0a5e08acfd543ac8b2f439b423e97823d272e473..a2009440acffd1e9a82c4832b0d2cf4e1c92b34b 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -1,8 +1,8 @@ #include "vkcv/upscaling/FSRUpscaling.hpp" -#include <stdint.h> -#include <math.h> +#include <cstdint> +#include <cmath> #define A_CPU 1 #include <ffx_a.h> @@ -240,11 +240,11 @@ namespace vkcv::upscaling { DescriptorWrites writes; - writes.uniformBufferWrites.emplace_back( + writes.writeUniformBuffer( 0, m_easuConstants.getHandle(),true ); - writes.samplerWrites.emplace_back(3, m_sampler); + writes.writeSampler(3, m_sampler); m_core.writeDescriptorSet(m_easuDescriptorSet, writes); } @@ -261,11 +261,11 @@ namespace vkcv::upscaling { }}); DescriptorWrites writes; - writes.uniformBufferWrites.emplace_back( + writes.writeUniformBuffer( 0, m_rcasConstants.getHandle(),true ); - writes.samplerWrites.emplace_back(3, m_sampler); + writes.writeSampler(3, m_sampler); m_core.writeDescriptorSet(m_rcasDescriptorSet, writes); } @@ -329,15 +329,15 @@ namespace vkcv::upscaling { if (rcasEnabled) { { DescriptorWrites writes; - writes.sampledImageWrites.emplace_back(1, input); - writes.storageImageWrites.emplace_back(2, m_intermediateImage); + writes.writeSampledImage(1, input); + writes.writeStorageImage(2, m_intermediateImage); m_core.writeDescriptorSet(m_easuDescriptorSet, writes); } { DescriptorWrites writes; - writes.sampledImageWrites.emplace_back(1, m_intermediateImage); - writes.storageImageWrites.emplace_back(2, output); + writes.writeSampledImage(1, m_intermediateImage); + writes.writeStorageImage(2, output); m_core.writeDescriptorSet(m_rcasDescriptorSet, writes); } @@ -374,8 +374,8 @@ namespace vkcv::upscaling { } else { { DescriptorWrites writes; - writes.sampledImageWrites.emplace_back(1, input); - writes.storageImageWrites.emplace_back(2, output); + writes.writeSampledImage(1, input); + writes.writeStorageImage(2, output); m_core.writeDescriptorSet(m_easuDescriptorSet, writes); } diff --git a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp index 998d7f83e7a05d456dfe544a87953769181eada4..2fd8e23f6c0a3c615ec6085ad1abfdad1a9794ab 100644 --- a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp @@ -186,13 +186,13 @@ namespace vkcv::upscaling { DescriptorWrites writes; - writes.uniformBufferWrites.emplace_back( + writes.writeUniformBuffer( 0, m_scalerConstants.getHandle(), true ); - writes.samplerWrites.emplace_back(1, m_sampler); - writes.sampledImageWrites.emplace_back(4, m_coefScaleImage); - writes.sampledImageWrites.emplace_back(5, m_coefUsmImage); + writes.writeSampler(1, m_sampler); + writes.writeSampledImage(4, m_coefScaleImage); + writes.writeSampledImage(5, m_coefUsmImage); m_core.writeDescriptorSet(m_scalerDescriptorSet, writes); } @@ -242,8 +242,8 @@ namespace vkcv::upscaling { { DescriptorWrites writes; - writes.sampledImageWrites.emplace_back(2, input); - writes.storageImageWrites.emplace_back(3, output); + writes.writeSampledImage(2, input); + writes.writeStorageImage(3, output); m_core.writeDescriptorSet(m_scalerDescriptorSet, writes); } diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp index f8fa8db91fb9566771862b59ad9314c9fae2e288..0986b0910b6e7486c2dc3fc244269672a58d0730 100644 --- a/projects/bindless_textures/src/main.cpp +++ b/projects/bindless_textures/src/main.cpp @@ -109,7 +109,7 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat ); - vkcv::PassConfig firstMeshPassDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassConfig firstMeshPassDefinition({ present_color_attachment, depth_attachment }, vkcv::Multisampling::None); vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition); if (!firstMeshPass) { @@ -134,11 +134,10 @@ int main(int argc, const char** argv) { const std::vector<vkcv::VertexAttachment> vertexAttachments = firstMeshProgram.getVertexAttachments(); std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + bindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } - const vkcv::VertexLayout firstMeshLayout (bindings); - + const vkcv::VertexLayout firstMeshLayout { bindings }; const std::unordered_map<uint32_t, vkcv::DescriptorBinding> &descriptorBindings = firstMeshProgram.getReflectedDescriptors().at(0); std::unordered_map<uint32_t, vkcv::DescriptorBinding> adjustedBindings = descriptorBindings; @@ -188,18 +187,20 @@ int main(int argc, const char** argv) { vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; vkcv::DescriptorWrites setWrites; - std::vector<vkcv::SampledImageDescriptorWrite> texturesArrayWrites; + for(uint32_t i = 0; i < 6; i++) { - texturesArrayWrites.push_back(vkcv::SampledImageDescriptorWrite(1, - texturesArray[i].getHandle(), - 0, - false, - i)); + + setWrites.writeSampledImage( + 1, + texturesArray[i].getHandle(), + 0, + false, + i + ); } - setWrites.sampledImageWrites = texturesArrayWrites; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(0, sampler) }; + setWrites.writeSampler(0, sampler); core.writeDescriptorSet(descriptorSet, setWrites); diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index c8da98abd87579c2b91b2422dda544dd257b03af..fe8acb3cfbb65de71763c2c30b50daf5f598234d 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -59,7 +59,11 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat ); - vkcv::PassConfig firstMeshPassDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassConfig firstMeshPassDefinition( + { present_color_attachment, depth_attachment }, + vkcv::Multisampling::None + ); + vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition); if (!firstMeshPass) { @@ -84,11 +88,10 @@ int main(int argc, const char** argv) { const std::vector<vkcv::VertexAttachment> vertexAttachments = firstMeshProgram.getVertexAttachments(); std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + bindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } - const vkcv::VertexLayout firstMeshLayout (bindings); - + const vkcv::VertexLayout firstMeshLayout { bindings }; // since we only use one descriptor set (namely, desc set 0), directly address it // recreate copies of the bindings and the handles (to check whether they are properly reused instead of actually recreated) @@ -140,8 +143,8 @@ int main(int argc, const char** argv) { vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; + setWrites.writeSampledImage(0, texture.getHandle()); + setWrites.writeSampler(1, sampler); core.writeDescriptorSet(descriptorSet, setWrites); diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 3e424919d2289c45e129c6b476ff026455403982..3c4f51bb119f585e449aa48de2aef086d0789dd7 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -50,7 +50,11 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat ); - vkcv::PassConfig scenePassDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassConfig scenePassDefinition( + { present_color_attachment, depth_attachment }, + vkcv::Multisampling::None + ); + vkcv::PassHandle scenePass = core.createPass(scenePassDefinition); if (!scenePass) { @@ -68,12 +72,12 @@ int main(int argc, const char** argv) { const std::vector<vkcv::VertexAttachment> vertexAttachments = sceneShaderProgram.getVertexAttachments(); std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + bindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } - const vkcv::VertexLayout sceneLayout(bindings); - + const vkcv::VertexLayout sceneLayout { bindings }; const auto& material0 = scene.getMaterial(0); const vkcv::GraphicsPipelineConfig scenePipelineDefinition{ diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 3bdefe3ae55fc89879461ed37025f8fe00e39a8a..c2d8bf817dd1d6b2c7cc069f2037ee090abc4415 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -33,7 +33,7 @@ int main(int argc, const char** argv) { vkcv::AttachmentOperation::CLEAR, core.getSwapchain(windowHandle).getFormat()); - vkcv::PassConfig trianglePassDefinition({ present_color_attachment }); + vkcv::PassConfig trianglePassDefinition({ present_color_attachment }, vkcv::Multisampling::None); vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); if (!trianglePass) @@ -51,8 +51,6 @@ int main(int argc, const char** argv) { {vkcv::ShaderStage::VERTEX, "shaders/shader.vert"}, { vkcv::ShaderStage::FRAGMENT, "shaders/shader.frag" } }, nullptr); - - const auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); const vkcv::GraphicsPipelineConfig trianglePipelineDefinition { triangleShaderProgram, diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp index 3eeec03a47d8051385523e8f3e3e146e0829aeda..89fb5e08d1c4a5ceec8c43f3c4043f8978d5d404 100644 --- a/projects/head_demo/src/main.cpp +++ b/projects/head_demo/src/main.cpp @@ -66,10 +66,18 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat ); - vkcv::PassConfig linePassDefinition({ color_attachment0, depth_attachment0 }); + vkcv::PassConfig linePassDefinition( + { color_attachment0, depth_attachment0 }, + vkcv::Multisampling::None + ); + vkcv::PassHandle linePass = core.createPass(linePassDefinition); - vkcv::PassConfig scenePassDefinition({ color_attachment1, depth_attachment1 }); + vkcv::PassConfig scenePassDefinition( + { color_attachment1, depth_attachment1 }, + vkcv::Multisampling::None + ); + vkcv::PassHandle scenePass = core.createPass(scenePassDefinition); if ((!scenePass) || (!linePass)) { @@ -95,8 +103,9 @@ int main(int argc, const char** argv) { const std::vector<vkcv::VertexAttachment> vertexAttachments = sceneShaderProgram.getVertexAttachments(); std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + bindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } const auto& clipBindings = sceneShaderProgram.getReflectedDescriptors().at(1); @@ -113,9 +122,7 @@ int main(int argc, const char** argv) { clipBuffer.fill({ clipLimit, -clipX, -clipY, -clipZ }); vkcv::DescriptorWrites clipWrites; - clipWrites.uniformBufferWrites = { - vkcv::BufferDescriptorWrite(0, clipBuffer.getHandle()) - }; + clipWrites.writeUniformBuffer(0, clipBuffer.getHandle()); core.writeDescriptorSet(clipDescriptorSet, clipWrites); @@ -141,8 +148,7 @@ int main(int argc, const char** argv) { } }); - const vkcv::VertexLayout sceneLayout(bindings); - + const vkcv::VertexLayout sceneLayout { bindings }; const auto& material0 = scene.getMaterial(0); const vkcv::GraphicsPipelineConfig scenePipelineDefinition{ diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index cc897e68651de65c7122188b52598535e6637335..e6885b8e7dfa71c00335dbb2cee5c5994ce4eccc 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -73,8 +73,8 @@ bool App::initialize() { m_cameraManager.getCamera(cameraIndex).setNearFar(0.1f, 30.f); vkcv::DescriptorWrites meshPassDescriptorWrites; - meshPassDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, m_gridTexture) }; - meshPassDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, m_linearSampler) }; + meshPassDescriptorWrites.writeSampledImage(0, m_gridTexture); + meshPassDescriptorWrites.writeSampler(1, m_linearSampler); m_core.writeDescriptorSet(m_meshPass.descriptorSet, meshPassDescriptorWrites); return true; @@ -317,12 +317,9 @@ void App::run() { // gamma correction vkcv::DescriptorWrites gammaCorrectionDescriptorWrites; - gammaCorrectionDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, motionBlurOutput) }; - gammaCorrectionDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(1, m_linearSampler) }; - gammaCorrectionDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(2, swapchainInput) }; + gammaCorrectionDescriptorWrites.writeSampledImage(0, motionBlurOutput); + gammaCorrectionDescriptorWrites.writeSampler(1, m_linearSampler); + gammaCorrectionDescriptorWrites.writeStorageImage(2, swapchainInput); m_core.writeDescriptorSet(m_gammaCorrectionPass.descriptorSet, gammaCorrectionDescriptorWrites); diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp index 1d40204b1ab7c6cd49a0c7924fa1fdbf6c2cc24e..342d2d705f831bc98705c9ecaaa5b369befda7b6 100644 --- a/projects/indirect_dispatch/src/AppSetup.cpp +++ b/projects/indirect_dispatch/src/AppSetup.cpp @@ -115,10 +115,10 @@ bool loadGraphicPass( const std::vector<vkcv::VertexAttachment> vertexAttachments = shaderProgram.getVertexAttachments(); std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + bindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } - const vkcv::VertexLayout vertexLayout(bindings); + const vkcv::VertexLayout vertexLayout { bindings }; const auto descriptorBindings = shaderProgram.getReflectedDescriptors(); const bool hasDescriptor = descriptorBindings.size() > 0; @@ -169,7 +169,10 @@ bool loadMeshPass(vkcv::Core& core, GraphicPassHandles* outHandles) { core, "assets/shaders/mesh.vert", "assets/shaders/mesh.frag", - vkcv::PassConfig({ colorAttachment, depthAttachment }), + vkcv::PassConfig( + { colorAttachment, depthAttachment }, + vkcv::Multisampling::None + ), vkcv::DepthTest::Equal, outHandles); } @@ -192,7 +195,10 @@ bool loadSkyPass(vkcv::Core& core, GraphicPassHandles* outHandles) { core, "assets/shaders/sky.vert", "assets/shaders/sky.frag", - vkcv::PassConfig({ colorAttachment, depthAttachment }), + vkcv::PassConfig( + { colorAttachment, depthAttachment }, + vkcv::Multisampling::None + ), vkcv::DepthTest::Equal, outHandles); } @@ -214,7 +220,10 @@ bool loadPrePass(vkcv::Core& core, GraphicPassHandles* outHandles) { core, "assets/shaders/prepass.vert", "assets/shaders/prepass.frag", - vkcv::PassConfig({ motionAttachment, depthAttachment }), + vkcv::PassConfig( + { motionAttachment, depthAttachment }, + vkcv::Multisampling::None + ), vkcv::DepthTest::LessEqual, outHandles); } @@ -236,7 +245,10 @@ bool loadSkyPrePass(vkcv::Core& core, GraphicPassHandles* outHandles) { core, "assets/shaders/skyPrepass.vert", "assets/shaders/skyPrepass.frag", - vkcv::PassConfig({ motionAttachment, depthAttachment }), + vkcv::PassConfig( + { motionAttachment, depthAttachment }, + vkcv::Multisampling::None + ), vkcv::DepthTest::LessEqual, outHandles); } diff --git a/projects/indirect_dispatch/src/MotionBlur.cpp b/projects/indirect_dispatch/src/MotionBlur.cpp index 30116c84b79ae71c683ee865dbf93dd1a37923e9..c9345684225e64f792a13ade2e5d11297ab7c444 100644 --- a/projects/indirect_dispatch/src/MotionBlur.cpp +++ b/projects/indirect_dispatch/src/MotionBlur.cpp @@ -75,14 +75,16 @@ bool MotionBlur::initialize(vkcv::Core* corePtr, const uint32_t targetWidth, con true).getHandle(); vkcv::DescriptorWrites tileResetDescriptorWrites; - tileResetDescriptorWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(0, m_fullPathWorkTileBuffer), - vkcv::BufferDescriptorWrite(1, m_copyPathWorkTileBuffer), - vkcv::BufferDescriptorWrite(2, m_fastPathWorkTileBuffer) }; + tileResetDescriptorWrites.writeStorageBuffer( + 0, m_fullPathWorkTileBuffer + ).writeStorageBuffer( + 1, m_copyPathWorkTileBuffer + ).writeStorageBuffer( + 2, m_fastPathWorkTileBuffer + ); m_core->writeDescriptorSet(m_tileResetPass.descriptorSet, tileResetDescriptorWrites); - m_renderTargets = MotionBlurSetup::createRenderTargets(targetWidth, targetHeight, *m_core); m_nearestSampler = m_core->createSampler( @@ -129,15 +131,20 @@ vkcv::ImageHandle MotionBlur::render( // work tile classification vkcv::DescriptorWrites tileClassificationDescriptorWrites; - tileClassificationDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, m_renderTargets.motionMaxNeighbourhood), - vkcv::SampledImageDescriptorWrite(1, m_renderTargets.motionMinNeighbourhood) }; - tileClassificationDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(2, m_nearestSampler) }; - tileClassificationDescriptorWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(3, m_fullPathWorkTileBuffer), - vkcv::BufferDescriptorWrite(4, m_copyPathWorkTileBuffer), - vkcv::BufferDescriptorWrite(5, m_fastPathWorkTileBuffer) }; + tileClassificationDescriptorWrites.writeSampledImage( + 0, m_renderTargets.motionMaxNeighbourhood + ).writeSampledImage( + 1, m_renderTargets.motionMinNeighbourhood + ); + + tileClassificationDescriptorWrites.writeSampler(2, m_nearestSampler); + tileClassificationDescriptorWrites.writeStorageBuffer( + 3, m_fullPathWorkTileBuffer + ).writeStorageBuffer( + 4, m_copyPathWorkTileBuffer + ).writeStorageBuffer( + 5, m_fastPathWorkTileBuffer + ); m_core->writeDescriptorSet(m_tileClassificationPass.descriptorSet, tileClassificationDescriptorWrites); @@ -174,44 +181,41 @@ vkcv::ImageHandle MotionBlur::render( m_core->recordBufferMemoryBarrier(cmdStream, m_fastPathWorkTileBuffer); vkcv::DescriptorWrites motionBlurDescriptorWrites; - motionBlurDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, colorBuffer), - vkcv::SampledImageDescriptorWrite(1, depthBuffer), - vkcv::SampledImageDescriptorWrite(2, motionBufferFullRes), - vkcv::SampledImageDescriptorWrite(3, m_renderTargets.motionMaxNeighbourhood) }; - motionBlurDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(4, m_nearestSampler) }; - motionBlurDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(5, m_renderTargets.outputColor) }; - motionBlurDescriptorWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(6, m_fullPathWorkTileBuffer)}; + motionBlurDescriptorWrites.writeSampledImage( + 0, colorBuffer + ).writeSampledImage( + 1, depthBuffer + ).writeSampledImage( + 2, motionBufferFullRes + ).writeSampledImage( + 3, m_renderTargets.motionMaxNeighbourhood + ); + + motionBlurDescriptorWrites.writeSampler(4, m_nearestSampler); + motionBlurDescriptorWrites.writeStorageImage(5, m_renderTargets.outputColor); + motionBlurDescriptorWrites.writeStorageBuffer(6, m_fullPathWorkTileBuffer); m_core->writeDescriptorSet(m_motionBlurPass.descriptorSet, motionBlurDescriptorWrites); - vkcv::DescriptorWrites colorCopyDescriptorWrites; - colorCopyDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, colorBuffer) }; - colorCopyDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(1, m_nearestSampler) }; - colorCopyDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(2, m_renderTargets.outputColor) }; - colorCopyDescriptorWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(3, m_copyPathWorkTileBuffer) }; + colorCopyDescriptorWrites.writeSampledImage(0, colorBuffer); + colorCopyDescriptorWrites.writeSampler(1, m_nearestSampler); + colorCopyDescriptorWrites.writeStorageImage(2, m_renderTargets.outputColor); + colorCopyDescriptorWrites.writeStorageBuffer(3, m_copyPathWorkTileBuffer); m_core->writeDescriptorSet(m_colorCopyPass.descriptorSet, colorCopyDescriptorWrites); vkcv::DescriptorWrites fastPathDescriptorWrites; - fastPathDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, colorBuffer), - vkcv::SampledImageDescriptorWrite(1, m_renderTargets.motionMaxNeighbourhood) }; - fastPathDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(2, m_nearestSampler) }; - fastPathDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(3, m_renderTargets.outputColor) }; - fastPathDescriptorWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(4, m_fastPathWorkTileBuffer) }; + fastPathDescriptorWrites.writeSampledImage( + 0, colorBuffer + ).writeSampledImage( + 1, m_renderTargets.motionMaxNeighbourhood + ); + + fastPathDescriptorWrites.writeSampler(2, m_nearestSampler); + fastPathDescriptorWrites.writeStorageImage(3, m_renderTargets.outputColor); + fastPathDescriptorWrites.writeStorageBuffer(4, m_fastPathWorkTileBuffer); m_core->writeDescriptorSet(m_motionBlurFastPathPass.descriptorSet, fastPathDescriptorWrites); @@ -279,16 +283,17 @@ vkcv::ImageHandle MotionBlur::render( else if (mode == eMotionBlurMode::TileVisualisation) { vkcv::DescriptorWrites visualisationDescriptorWrites; - visualisationDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, colorBuffer) }; - visualisationDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(1, m_nearestSampler) }; - visualisationDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(2, m_renderTargets.outputColor)}; - visualisationDescriptorWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(3, m_fullPathWorkTileBuffer), - vkcv::BufferDescriptorWrite(4, m_copyPathWorkTileBuffer), - vkcv::BufferDescriptorWrite(5, m_fastPathWorkTileBuffer) }; + visualisationDescriptorWrites.writeSampledImage(0, colorBuffer); + visualisationDescriptorWrites.writeSampler(1, m_nearestSampler); + visualisationDescriptorWrites.writeStorageImage(2, m_renderTargets.outputColor); + + visualisationDescriptorWrites.writeStorageBuffer( + 3, m_fullPathWorkTileBuffer + ).writeStorageBuffer( + 4, m_copyPathWorkTileBuffer + ).writeStorageBuffer( + 5, m_fastPathWorkTileBuffer + ); m_core->writeDescriptorSet(m_tileVisualisationPass.descriptorSet, visualisationDescriptorWrites); @@ -345,12 +350,9 @@ vkcv::ImageHandle MotionBlur::renderMotionVectorVisualisation( } vkcv::DescriptorWrites motionVectorVisualisationDescriptorWrites; - motionVectorVisualisationDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, visualisationInput) }; - motionVectorVisualisationDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(1, m_nearestSampler) }; - motionVectorVisualisationDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(2, m_renderTargets.outputColor) }; + motionVectorVisualisationDescriptorWrites.writeSampledImage(0, visualisationInput); + motionVectorVisualisationDescriptorWrites.writeSampler(1, m_nearestSampler); + motionVectorVisualisationDescriptorWrites.writeStorageImage(2, m_renderTargets.outputColor); m_core->writeDescriptorSet( m_motionVectorVisualisationPass.descriptorSet, @@ -383,13 +385,13 @@ void MotionBlur::computeMotionTiles( // motion vector min max tiles vkcv::DescriptorWrites motionVectorMaxTilesDescriptorWrites; - motionVectorMaxTilesDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, motionBufferFullRes) }; - motionVectorMaxTilesDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(1, m_nearestSampler) }; - motionVectorMaxTilesDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(2, m_renderTargets.motionMax), - vkcv::StorageImageDescriptorWrite(3, m_renderTargets.motionMin) }; + motionVectorMaxTilesDescriptorWrites.writeSampledImage(0, motionBufferFullRes); + motionVectorMaxTilesDescriptorWrites.writeSampler(1, m_nearestSampler); + motionVectorMaxTilesDescriptorWrites.writeStorageImage( + 2, m_renderTargets.motionMax + ).writeStorageImage( + 3, m_renderTargets.motionMin + ); m_core->writeDescriptorSet(m_motionVectorMinMaxPass.descriptorSet, motionVectorMaxTilesDescriptorWrites); @@ -411,14 +413,18 @@ void MotionBlur::computeMotionTiles( // motion vector min max neighbourhood vkcv::DescriptorWrites motionVectorMaxNeighbourhoodDescriptorWrites; - motionVectorMaxNeighbourhoodDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, m_renderTargets.motionMax), - vkcv::SampledImageDescriptorWrite(1, m_renderTargets.motionMin) }; - motionVectorMaxNeighbourhoodDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(2, m_nearestSampler) }; - motionVectorMaxNeighbourhoodDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(3, m_renderTargets.motionMaxNeighbourhood), - vkcv::StorageImageDescriptorWrite(4, m_renderTargets.motionMinNeighbourhood) }; + motionVectorMaxNeighbourhoodDescriptorWrites.writeSampledImage( + 0, m_renderTargets.motionMax + ).writeSampledImage( + 1, m_renderTargets.motionMin + ); + + motionVectorMaxNeighbourhoodDescriptorWrites.writeSampler(2, m_nearestSampler); + motionVectorMaxNeighbourhoodDescriptorWrites.writeStorageImage( + 3, m_renderTargets.motionMaxNeighbourhood + ).writeStorageImage( + 4, m_renderTargets.motionMinNeighbourhood + ); m_core->writeDescriptorSet(m_motionVectorMinMaxNeighbourhoodPass.descriptorSet, motionVectorMaxNeighbourhoodDescriptorWrites); diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp index 2a213a2ad7b8ecdaf4b4a51cf4327addc7a881a5..16e3e83994a1a7ca14fa2163799ee8d034eb8deb 100644 --- a/projects/indirect_draw/src/main.cpp +++ b/projects/indirect_draw/src/main.cpp @@ -334,7 +334,7 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat ); - vkcv::PassConfig passDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassConfig passDefinition({ present_color_attachment, depth_attachment }, vkcv::Multisampling::None); vkcv::PassHandle passHandle = core.createPass(passDefinition); if (!passHandle) { std::cerr << "Error. Could not create renderpass. Exiting." << std::endl; @@ -361,7 +361,9 @@ int main(int argc, const char** argv) { // vertex layout for the pipeline. (assumed to be) used by all sponza meshes. const std::vector<vkcv::VertexAttachment> vertexAttachments = sponzaProgram.getVertexAttachments(); - const vkcv::VertexLayout sponzaVertexLayout({ vkcv::VertexBinding(0, { vertexAttachments }) }); + const vkcv::VertexLayout sponzaVertexLayout { + { vkcv::createVertexBinding(0, { vertexAttachments }) } + }; std::vector<uint8_t> compiledVertexBuffer; // IGNORED, since the vertex buffer is not interleaved! @@ -444,18 +446,17 @@ int main(int argc, const char** argv) { vkcv::SamplerMipmapMode::LINEAR, vkcv::SamplerAddressMode::REPEAT ); - + + vkcv::DescriptorWrites setWrites; + std::vector<vkcv::SampledImageDescriptorWrite> textureArrayWrites; for(uint32_t i = 0; i < compiledMaterial.baseColor.size(); i++) { - vkcv::SampledImageDescriptorWrite baseColorWrite(2, compiledMaterial.baseColor[i].getHandle(), 0, false, i); - textureArrayWrites.push_back(baseColorWrite); + setWrites.writeSampledImage(2, compiledMaterial.baseColor[i].getHandle(), 0, false, i); } - - vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = textureArrayWrites; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(0, standardSampler) }; - setWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(1, modelBuffer.getHandle())}; + + setWrites.writeSampler(0, standardSampler); + setWrites.writeStorageBuffer(1, modelBuffer.getHandle()); core.writeDescriptorSet(descriptorSet, setWrites); const vkcv::GraphicsPipelineConfig sponzaPipelineConfig { @@ -481,29 +482,10 @@ int main(int argc, const char** argv) { vkcv::BufferType::UNIFORM, 1); - //Plane dummyPlane{}; - //dummyPlane.pointOnPlane = glm::vec3(0.0f); - //dummyPlane.padding0 = 0.0f; - //dummyPlane.normal = glm::vec3(0.0f); - //dummyPlane.padding1 = 0.0f; - - //CameraPlanes dummyCameraPlane{}; - //dummyCameraPlane.planes[0] = dummyPlane; - //dummyCameraPlane.planes[1] = dummyPlane; - //dummyCameraPlane.planes[2] = dummyPlane; - //dummyCameraPlane.planes[3] = dummyPlane; - //dummyCameraPlane.planes[4] = dummyPlane; - //dummyCameraPlane.planes[5] = dummyPlane; - - //cameraPlaneBuffer.fill(&dummyCameraPlane); - - vkcv::BufferDescriptorWrite cameraPlaneWrite(0, cameraPlaneBuffer.getHandle()); - vkcv::BufferDescriptorWrite drawCommandsWrite(1, indirectBuffer.getHandle()); - vkcv::BufferDescriptorWrite boundingBoxWrite(2, boundingBoxBuffer.getHandle()); - vkcv::DescriptorWrites cullingWrites; - cullingWrites.storageBufferWrites = {drawCommandsWrite, boundingBoxWrite}; - cullingWrites.uniformBufferWrites = {cameraPlaneWrite}; + cullingWrites.writeStorageBuffer(1, indirectBuffer.getHandle()); + cullingWrites.writeStorageBuffer(2, boundingBoxBuffer.getHandle()); + cullingWrites.writeUniformBuffer(0, cameraPlaneBuffer.getHandle()); core.writeDescriptorSet(cullingDescSet, cullingWrites); diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index afaec1a8ba5dded5f16bad65c68f25f442029091..a74561ca07f7a052fe71c9e1d1efc751c2ab258c 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -168,7 +168,11 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat ); - vkcv::PassConfig bunnyPassDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassConfig bunnyPassDefinition( + { present_color_attachment, depth_attachment }, + vkcv::Multisampling::None + ); + vkcv::PassHandle renderPass = core.createPass(bunnyPassDefinition); if (!renderPass) @@ -193,9 +197,9 @@ int main(int argc, const char** argv) { const std::vector<vkcv::VertexAttachment> vertexAttachments = bunnyShaderProgram.getVertexAttachments(); std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + bindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } - const vkcv::VertexLayout bunnyLayout (bindings); + const vkcv::VertexLayout bunnyLayout { bindings }; vkcv::DescriptorSetLayoutHandle vertexShaderDescriptorSetLayout = core.createDescriptorSetLayout(bunnyShaderProgram.getReflectedDescriptors().at(0)); vkcv::DescriptorSetHandle vertexShaderDescriptorSet = core.createDescriptorSet(vertexShaderDescriptorSetLayout); @@ -218,7 +222,7 @@ int main(int argc, const char** argv) { vkcv::Buffer<ObjectMatrices> matrixBuffer = core.createBuffer<ObjectMatrices>(vkcv::BufferType::STORAGE, objectCount); vkcv::DescriptorWrites vertexShaderDescriptorWrites; - vertexShaderDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, matrixBuffer.getHandle()) }; + vertexShaderDescriptorWrites.writeStorageBuffer(0, matrixBuffer.getHandle()); core.writeDescriptorSet(vertexShaderDescriptorSet, vertexShaderDescriptorWrites); vkcv::GraphicsPipelineHandle bunnyPipeline = core.createGraphicsPipeline(bunnyPipelineDefinition); @@ -271,16 +275,19 @@ int main(int argc, const char** argv) { vkcv::Buffer<CameraPlanes> cameraPlaneBuffer = core.createBuffer<CameraPlanes>(vkcv::BufferType::UNIFORM, 1); vkcv::DescriptorWrites meshShaderWrites; - meshShaderWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(0, meshShaderVertexBuffer.getHandle()), - vkcv::BufferDescriptorWrite(1, meshShaderIndexBuffer.getHandle()), - vkcv::BufferDescriptorWrite(2, meshletBuffer.getHandle()), - vkcv::BufferDescriptorWrite(4, matrixBuffer.getHandle()), - vkcv::BufferDescriptorWrite(5, meshletBuffer.getHandle()), - }; - meshShaderWrites.uniformBufferWrites = { - vkcv::BufferDescriptorWrite(3, cameraPlaneBuffer.getHandle()), - }; + meshShaderWrites.writeStorageBuffer( + 0, meshShaderVertexBuffer.getHandle() + ).writeStorageBuffer( + 1, meshShaderIndexBuffer.getHandle() + ).writeStorageBuffer( + 2, meshletBuffer.getHandle() + ).writeStorageBuffer( + 4, matrixBuffer.getHandle() + ).writeStorageBuffer( + 5, meshletBuffer.getHandle() + ); + + meshShaderWrites.writeUniformBuffer(3, cameraPlaneBuffer.getHandle()); core.writeDescriptorSet( meshShaderDescriptorSet, meshShaderWrites); diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp index f1490e6f035b1a378afcb59436814986b3aca51f..db538796201ee4c1cf5830bfd82036f16a82e693 100644 --- a/projects/particle_simulation/src/main.cpp +++ b/projects/particle_simulation/src/main.cpp @@ -39,7 +39,7 @@ int main(int argc, const char **argv) { colorFormat); - vkcv::PassConfig particlePassDefinition({present_color_attachment}); + vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None); vkcv::PassHandle particlePass = core.createPass(particlePassDefinition); vkcv::PassConfig computePassDefinition({}); @@ -83,9 +83,9 @@ int main(int argc, const char **argv) { std::vector<vkcv::VertexBinding> computeBindings; for (size_t i = 0; i < computeVertexAttachments.size(); i++) { - computeBindings.push_back(vkcv::VertexBinding(i, { computeVertexAttachments[i] })); + computeBindings.push_back(vkcv::createVertexBinding(i, { computeVertexAttachments[i] })); } - const vkcv::VertexLayout computeLayout(computeBindings); + const vkcv::VertexLayout computeLayout { computeBindings }; vkcv::ShaderProgram particleShaderProgram{}; compiler.compile(vkcv::ShaderStage::VERTEX, "shaders/shader.vert", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { @@ -110,10 +110,10 @@ int main(int argc, const char **argv) { std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, {vertexAttachments[i]})); + bindings.push_back(vkcv::createVertexBinding(i, {vertexAttachments[i]})); } - const vkcv::VertexLayout particleLayout(bindings); + const vkcv::VertexLayout particleLayout { bindings }; vkcv::GraphicsPipelineConfig particlePipelineDefinition{ particleShaderProgram, @@ -161,13 +161,12 @@ int main(int argc, const char **argv) { particleBuffer.fill(particleSystem.getParticles()); vkcv::DescriptorWrites setWrites; - setWrites.uniformBufferWrites = {vkcv::BufferDescriptorWrite(0,color.getHandle()), - vkcv::BufferDescriptorWrite(1,position.getHandle())}; - setWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(2,particleBuffer.getHandle())}; + setWrites.writeUniformBuffer(0, color.getHandle()).writeUniformBuffer(1, position.getHandle()); + setWrites.writeStorageBuffer(2, particleBuffer.getHandle()); core.writeDescriptorSet(descriptorSet, setWrites); vkcv::DescriptorWrites computeWrites; - computeWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0,particleBuffer.getHandle())}; + computeWrites.writeStorageBuffer(0, particleBuffer.getHandle()); core.writeDescriptorSet(computeDescriptorSet, computeWrites); if (!particlePipeline || !computePipeline) @@ -308,10 +307,12 @@ int main(int argc, const char **argv) { core.prepareImageForStorage(cmdStream, swapchainInput); vkcv::DescriptorWrites tonemappingDescriptorWrites; - tonemappingDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, colorBuffer), - vkcv::StorageImageDescriptorWrite(1, swapchainInput) - }; + tonemappingDescriptorWrites.writeStorageImage( + 0, colorBuffer + ).writeStorageImage( + 1, swapchainInput + ); + core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); uint32_t tonemappingDispatchCount[3]; diff --git a/projects/path_tracer/src/main.cpp b/projects/path_tracer/src/main.cpp index b7c495c070bd354dd58c0fad3f857489ad7408e7..670986fff81d4f308aa063e6275f41872bc8e878 100644 --- a/projects/path_tracer/src/main.cpp +++ b/projects/path_tracer/src/main.cpp @@ -11,7 +11,7 @@ int main(int argc, const char** argv) { // structs must match shader version struct Material { Material(const glm::vec3& emission, const glm::vec3& albedo, float ks, float roughness, const glm::vec3& f0) - : emission(emission), albedo(albedo), ks(ks), roughness(roughness), f0(f0){} + : emission(emission), ks(ks), albedo(albedo), roughness(roughness), f0(f0), padding() {} glm::vec3 emission; float ks; @@ -22,7 +22,8 @@ int main(int argc, const char** argv) { }; struct Sphere { - Sphere(const glm::vec3& c, const float& r, const int m) : center(c), radius(r), materialIndex(m) {} + Sphere(const glm::vec3& c, const float& r, const int m) + : center(c), radius(r), materialIndex(m), padding() {} glm::vec3 center; float radius; @@ -32,7 +33,7 @@ int main(int argc, const char** argv) { struct Plane { Plane(const glm::vec3& c, const glm::vec3& n, const glm::vec2 e, int m) - : center(c), normal(n), extent(e), materialIndex(m) {} + : center(c), materialIndex(m), normal(n), padding1(), extent(e), padding3() {} glm::vec3 center; uint32_t materialIndex; @@ -107,10 +108,7 @@ int main(int argc, const char** argv) { }); vkcv::DescriptorWrites imageCombineDescriptorWrites; - imageCombineDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, outputImage), - vkcv::StorageImageDescriptorWrite(1, meanImage) - }; + imageCombineDescriptorWrites.writeStorageImage(0, outputImage).writeStorageImage(1, meanImage); core.writeDescriptorSet(imageCombineDescriptorSet, imageCombineDescriptorWrites); // image present shader @@ -144,9 +142,7 @@ int main(int argc, const char** argv) { }); vkcv::DescriptorWrites imageClearDescriptorWrites; - imageClearDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, meanImage) - }; + imageClearDescriptorWrites.writeStorageImage(0, meanImage); core.writeDescriptorSet(imageClearDescriptorSet, imageClearDescriptorWrites); // buffers @@ -193,12 +189,15 @@ int main(int argc, const char** argv) { materialSettings.size()); vkcv::DescriptorWrites traceDescriptorWrites; - traceDescriptorWrites.storageBufferWrites = { - vkcv::BufferDescriptorWrite(0, sphereBuffer.getHandle()), - vkcv::BufferDescriptorWrite(1, planeBuffer.getHandle()), - vkcv::BufferDescriptorWrite(2, materialBuffer.getHandle())}; - traceDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(3, outputImage)}; + traceDescriptorWrites.writeStorageBuffer( + 0, sphereBuffer.getHandle() + ).writeStorageBuffer( + 1, planeBuffer.getHandle() + ).writeStorageBuffer( + 2, materialBuffer.getHandle() + ); + + traceDescriptorWrites.writeStorageImage(3, outputImage); core.writeDescriptorSet(traceDescriptorSet, traceDescriptorWrites); vkcv::ComputePipelineHandle tracePipeline = core.createComputePipeline({ @@ -271,21 +270,20 @@ int main(int argc, const char** argv) { true).getHandle(); // update descriptor sets - traceDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(3, outputImage) }; + traceDescriptorWrites.writeStorageImage(3, outputImage); core.writeDescriptorSet(traceDescriptorSet, traceDescriptorWrites); vkcv::DescriptorWrites imageCombineDescriptorWrites; - imageCombineDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, outputImage), - vkcv::StorageImageDescriptorWrite(1, meanImage) - }; + imageCombineDescriptorWrites.writeStorageImage( + 0, outputImage + ).writeStorageImage( + 1, meanImage + ); + core.writeDescriptorSet(imageCombineDescriptorSet, imageCombineDescriptorWrites); vkcv::DescriptorWrites imageClearDescriptorWrites; - imageClearDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, meanImage) - }; + imageClearDescriptorWrites.writeStorageImage(0, meanImage); core.writeDescriptorSet(imageClearDescriptorSet, imageClearDescriptorWrites); widthPrevious = swapchainWidth; @@ -396,9 +394,12 @@ int main(int argc, const char** argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); vkcv::DescriptorWrites presentDescriptorWrites; - presentDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, meanImage), - vkcv::StorageImageDescriptorWrite(1, swapchainInput) }; + presentDescriptorWrites.writeStorageImage( + 0, meanImage + ).writeStorageImage( + 1, swapchainInput + ); + core.writeDescriptorSet(presentDescriptorSet, presentDescriptorWrites); core.prepareImageForStorage(cmdStream, swapchainInput); diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp index 00533bc3668a54f245777c7bca4abb56afd3f056..47560b4d9fddb867dd5573c64fe57c24c69095ce 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp +++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp @@ -147,23 +147,23 @@ namespace vkcv::rtx { void RTXModule::createRTXPipelineAndLayout(uint32_t pushConstantSize, std::vector<DescriptorSetLayoutHandle> descriptorSetLayouts, ShaderProgram &rtxShader) { // -- process vkcv::ShaderProgram into vk::ShaderModule - std::vector<char> rayGenShaderCode = rtxShader.getShader(ShaderStage::RAY_GEN).shaderCode; + std::vector<uint32_t> rayGenShaderCode = rtxShader.getShaderBinary(ShaderStage::RAY_GEN); vk::ShaderModuleCreateInfo rayGenShaderModuleInfo( vk::ShaderModuleCreateFlags(), // vk::ShaderModuleCreateFlags flags_, - rayGenShaderCode.size(), // size_t codeSize - (const uint32_t*)rayGenShaderCode.data() // const uint32_t* pCode + rayGenShaderCode.size() * sizeof(uint32_t), // size_t codeSize + rayGenShaderCode.data() // const uint32_t* pCode ); vk::ShaderModule rayGenShaderModule = m_core->getContext().getDevice().createShaderModule(rayGenShaderModuleInfo); if (!rayGenShaderModule) { vkcv_log(LogLevel::ERROR, "The Ray Generation Shader Module could not be created!"); } - std::vector<char> rayMissShaderCode = rtxShader.getShader(ShaderStage::RAY_MISS).shaderCode; + std::vector<uint32_t> rayMissShaderCode = rtxShader.getShaderBinary(ShaderStage::RAY_MISS); vk::ShaderModuleCreateInfo rayMissShaderModuleInfo( vk::ShaderModuleCreateFlags(), // vk::ShaderModuleCreateFlags flags_, - rayMissShaderCode.size(), //size_t codeSize - (const uint32_t*)rayMissShaderCode.data() // const uint32_t* pCode + rayMissShaderCode.size() * sizeof(uint32_t), //size_t codeSize + rayMissShaderCode.data() // const uint32_t* pCode ); vk::ShaderModule rayMissShaderModule = m_core->getContext().getDevice().createShaderModule(rayMissShaderModuleInfo); @@ -171,11 +171,11 @@ namespace vkcv::rtx { vkcv_log(LogLevel::ERROR, "The Ray Miss Shader Module could not be created!"); } - std::vector<char> rayClosestHitShaderCode = rtxShader.getShader(ShaderStage::RAY_CLOSEST_HIT).shaderCode; + std::vector<uint32_t> rayClosestHitShaderCode = rtxShader.getShaderBinary(ShaderStage::RAY_CLOSEST_HIT); vk::ShaderModuleCreateInfo rayClosestHitShaderModuleInfo( vk::ShaderModuleCreateFlags(), // vk::ShaderModuleCreateFlags flags_, - rayClosestHitShaderCode.size(), //size_t codeSize - (const uint32_t*)rayClosestHitShaderCode.data() // const uint32_t* pCode_ + rayClosestHitShaderCode.size() * sizeof(uint32_t), //size_t codeSize + rayClosestHitShaderCode.data() // const uint32_t* pCode_ ); vk::ShaderModule rayClosestHitShaderModule = m_core->getContext().getDevice().createShaderModule(rayClosestHitShaderModuleInfo); if (!rayClosestHitShaderModule) { diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp index becd80c4e4478da38a8e3722cbf30d39fd159ca6..0276f05db5bece4416578d89da1fd7a7b31336ca 100644 --- a/projects/rtx_ambient_occlusion/src/main.cpp +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -135,7 +135,7 @@ int main(int argc, const char** argv) { auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - rtxWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(0, swapchainInput) }; + rtxWrites.writeStorageImage(0, swapchainInput); core.writeDescriptorSet(rtxShaderDescriptorSet, rtxWrites); core.prepareImageForStorage(cmdStream, swapchainInput); diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp index 84087c1eabe8aa32e3ac3f9ebe9c7d9936f52d9e..68bc546ded40e7f45454d62bfc4e8cd7227da4b7 100644 --- a/projects/saf_r/src/main.cpp +++ b/projects/saf_r/src/main.cpp @@ -5,10 +5,9 @@ #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> #include <chrono> -#include <limits> #include <cmath> #include <vector> -#include <string.h> // memcpy(3) +#include <cstring> #include "safrScene.hpp" @@ -87,9 +86,9 @@ int main(int argc, const char** argv) { std::vector<vkcv::VertexBinding> computeBindings; for (size_t i = 0; i < computeVertexAttachments.size(); i++) { - computeBindings.push_back(vkcv::VertexBinding(i, { computeVertexAttachments[i] })); + computeBindings.push_back(vkcv::createVertexBinding(i, { computeVertexAttachments[i] })); } - const vkcv::VertexLayout computeLayout(computeBindings); + const vkcv::VertexLayout computeLayout { computeBindings }; /* * create the scene @@ -146,8 +145,12 @@ int main(int argc, const char** argv) { sphereBuffer.fill(spheres); vkcv::DescriptorWrites computeWrites; - computeWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0,lightsBuffer.getHandle()), - vkcv::BufferDescriptorWrite(1,sphereBuffer.getHandle())}; + computeWrites.writeStorageBuffer( + 0, lightsBuffer.getHandle() + ).writeStorageBuffer( + 1, sphereBuffer.getHandle() + ); + core.writeDescriptorSet(computeDescriptorSet, computeWrites); auto safrIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, vkcv::BufferMemoryType::DEVICE_LOCAL); @@ -160,7 +163,7 @@ int main(int argc, const char** argv) { vkcv::AttachmentOperation::CLEAR, core.getSwapchain(windowHandle).getFormat()); - vkcv::PassConfig safrPassDefinition({ present_color_attachment }); + vkcv::PassConfig safrPassDefinition({ present_color_attachment }, vkcv::Multisampling::None); vkcv::PassHandle safrPass = core.createPass(safrPassDefinition); if (!safrPass) @@ -254,7 +257,7 @@ int main(int argc, const char** argv) { auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); //configure the outImage for compute shader (render into the swapchain image) - computeWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapchainInput)}; + computeWrites.writeStorageImage(2, swapchainInput); core.writeDescriptorSet(computeDescriptorSet, computeWrites); core.prepareImageForStorage (cmdStream, swapchainInput); diff --git a/projects/saf_r/src/safrScene.hpp b/projects/saf_r/src/safrScene.hpp index 33a298f82121971021d1912e6c1205e9c48a49f0..fc149a7b6ba11fd832cf7ec1040d57c401bab87a 100644 --- a/projects/saf_r/src/safrScene.hpp +++ b/projects/saf_r/src/safrScene.hpp @@ -28,7 +28,7 @@ public: */ struct Material { Material(const glm::vec4& a, const glm::vec3& color, const float& spec, const float& r) : albedo(a), diffuse_color(color), specular_exponent(spec), refractive_index(r) {} - Material() : refractive_index(1), albedo(1, 0, 0, 0), diffuse_color(), specular_exponent() {} + Material() : albedo(1, 0, 0, 0), diffuse_color(), specular_exponent(), refractive_index(1) {} glm::vec4 albedo; alignas(16) glm::vec3 diffuse_color; float specular_exponent; diff --git a/projects/sph/src/PipelineInit.cpp b/projects/sph/src/PipelineInit.cpp index 052c983cb094114853d19dac3e76149db99116db..e507f1edebf6e39fb65bf81dbd4cf4915602313b 100644 --- a/projects/sph/src/PipelineInit.cpp +++ b/projects/sph/src/PipelineInit.cpp @@ -15,9 +15,9 @@ vkcv::DescriptorSetHandle PipelineInit::ComputePipelineInit(vkcv::Core *pCore, v std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + bindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } - const vkcv::VertexLayout layout(bindings); + const vkcv::VertexLayout layout { bindings }; pipeline = pCore->createComputePipeline({ shaderProgram, diff --git a/projects/sph/src/PipelineInit.hpp b/projects/sph/src/PipelineInit.hpp index e628af0eef9c0558719b405790246946d8720d47..54979cfdaffb2aba0915f87552e75e6d2ad3a958 100644 --- a/projects/sph/src/PipelineInit.hpp +++ b/projects/sph/src/PipelineInit.hpp @@ -5,6 +5,14 @@ class PipelineInit{ public: + /** + * Helperfunction to initialize a compute Pipeline. Goal is to reduce repetitive code in main. + * @param pCore Pointer to core object + * @param shaderStage Type of shaderstage - currently only supports COMPUTE + * @param includePath filepath to shaderprogram + * @param pipeline handle of the pipeline that is to be initialized. This handle is replaced with the handle of the generated pipeline + * @return returns the descriptorset handle from the generated descriptorset of the reflected shader + */ static vkcv::DescriptorSetHandle ComputePipelineInit(vkcv::Core *pCore, vkcv::ShaderStage shaderStage, std::filesystem::path includePath, diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp index dafea94220345d0ec4b01b77fecd970d2a23c6b1..601075421a7bf2814e10514ae010fc83b7024f0a 100644 --- a/projects/sph/src/main.cpp +++ b/projects/sph/src/main.cpp @@ -1,13 +1,9 @@ #include <iostream> #include <vkcv/Core.hpp> -#include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <chrono> #include <random> -#include <glm/glm.hpp> -#include <glm/gtc/matrix_access.hpp> -#include <glm/gtc/matrix_transform.hpp> -#include <time.h> +#include <ctime> #include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/effects/BloomAndFlaresEffect.hpp> #include "PipelineInit.hpp" @@ -16,6 +12,7 @@ int main(int argc, const char **argv) { const char *applicationName = "SPH"; + // creating core object that will handle all vulkan objects vkcv::Core core = vkcv::Core::create( applicationName, VK_MAKE_VERSION(0, 0, 1), @@ -41,7 +38,7 @@ int main(int argc, const char **argv) { colorFormat); - vkcv::PassConfig particlePassDefinition({present_color_attachment}); + vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None); vkcv::PassHandle particlePass = core.createPass(particlePassDefinition); vkcv::PassConfig computePassDefinition({}); @@ -68,26 +65,26 @@ int main(int argc, const char **argv) { } vkcv::shader::GLSLCompiler compiler; -// comp shader 1 - vkcv::ComputePipelineHandle computePipeline1; - vkcv::DescriptorSetHandle computeDescriptorSet1 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, - "shaders/pressure.comp", computePipeline1); -// comp shader 2 - vkcv::ComputePipelineHandle computePipeline2; - vkcv::DescriptorSetHandle computeDescriptorSet2 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, - "shaders/force.comp", computePipeline2); - -//comp shader 3 - vkcv::ComputePipelineHandle computePipeline3; - vkcv::DescriptorSetHandle computeDescriptorSet3 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, - "shaders/updateData.comp", computePipeline3); - -//comp shader 4 - vkcv::ComputePipelineHandle computePipeline4; - vkcv::DescriptorSetHandle computeDescriptorSet4 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, - "shaders/flip.comp", computePipeline4); - -// shader + // pressure shader --> computes the pressure for all particles + vkcv::ComputePipelineHandle pressurePipeline; + vkcv::DescriptorSetHandle pressureDescriptorSet = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/pressure.comp", pressurePipeline); + // force shader --> computes the force that effects the particles + vkcv::ComputePipelineHandle forcePipeline; + vkcv::DescriptorSetHandle forceDescriptorSet = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/force.comp", forcePipeline); + + // update data shader --> applies the force on all particles and updates their position + vkcv::ComputePipelineHandle updateDataPipeline; + vkcv::DescriptorSetHandle updateDataDescriptorSet = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/updateData.comp", updateDataPipeline); + + // flip shader --> flips input and output buffer + vkcv::ComputePipelineHandle flipPipeline; + vkcv::DescriptorSetHandle flipDescriptorSet = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/flip.comp", flipPipeline); + + // particle rendering shaders vkcv::ShaderProgram particleShaderProgram{}; compiler.compile(vkcv::ShaderStage::VERTEX, "shaders/shader.vert", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { particleShaderProgram.addShader(shaderStage, path); @@ -96,6 +93,7 @@ int main(int argc, const char **argv) { particleShaderProgram.addShader(shaderStage, path); }); + // generating descriptorsets from shader reflection vkcv::DescriptorSetLayoutHandle descriptorSetLayout = core.createDescriptorSetLayout( particleShaderProgram.getReflectedDescriptors().at(0)); vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); @@ -111,11 +109,12 @@ int main(int argc, const char **argv) { std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, {vertexAttachments[i]})); + bindings.push_back(vkcv::createVertexBinding(i, {vertexAttachments[i]})); } - const vkcv::VertexLayout particleLayout(bindings); + const vkcv::VertexLayout particleLayout { bindings }; + // initializing graphics pipeline vkcv::GraphicsPipelineConfig particlePipelineDefinition{ particleShaderProgram, UINT32_MAX, @@ -145,6 +144,7 @@ int main(int argc, const char **argv) { 1 ); + // generating particles int numberParticles = 20000; std::vector<Particle> particles; for (int i = 0; i < numberParticles; i++) { @@ -164,6 +164,7 @@ int main(int argc, const char **argv) { particles.push_back(Particle(pos, vel)); } + // creating and filling particle buffer vkcv::Buffer<Particle> particleBuffer1 = core.createBuffer<Particle>( vkcv::BufferType::STORAGE, numberParticles * sizeof(glm::vec4) * 3 @@ -179,24 +180,26 @@ int main(int argc, const char **argv) { particleBuffer2.fill(particles); vkcv::DescriptorWrites setWrites; - setWrites.uniformBufferWrites = {vkcv::BufferDescriptorWrite(0,color.getHandle()), - vkcv::BufferDescriptorWrite(1,position.getHandle())}; - setWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(2,particleBuffer1.getHandle()), - vkcv::BufferDescriptorWrite(3,particleBuffer2.getHandle())}; + setWrites.writeUniformBuffer(0, color.getHandle()).writeUniformBuffer(1, position.getHandle()); + setWrites.writeStorageBuffer(2, particleBuffer1.getHandle()).writeStorageBuffer(3, particleBuffer2.getHandle()); core.writeDescriptorSet(descriptorSet, setWrites); vkcv::DescriptorWrites computeWrites; - computeWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0,particleBuffer1.getHandle()), - vkcv::BufferDescriptorWrite(1,particleBuffer2.getHandle())}; + computeWrites.writeStorageBuffer( + 0, particleBuffer1.getHandle() + ).writeStorageBuffer( + 1, particleBuffer2.getHandle() + ); - core.writeDescriptorSet(computeDescriptorSet1, computeWrites); - core.writeDescriptorSet(computeDescriptorSet2, computeWrites); - core.writeDescriptorSet(computeDescriptorSet3, computeWrites); - core.writeDescriptorSet(computeDescriptorSet4, computeWrites); + core.writeDescriptorSet(pressureDescriptorSet, computeWrites); + core.writeDescriptorSet(forceDescriptorSet, computeWrites); + core.writeDescriptorSet(updateDataDescriptorSet, computeWrites); + core.writeDescriptorSet(flipDescriptorSet, computeWrites); - if (!particlePipeline || !computePipeline1 || !computePipeline2 || !computePipeline3 || !computePipeline4) + // error message if creation of one pipeline failed + if (!particlePipeline || !pressurePipeline || !forcePipeline || !updateDataPipeline || !flipPipeline) { - std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + std::cout << "Error. Could not create at least one pipeline. Exiting." << std::endl; return EXIT_FAILURE; } @@ -340,38 +343,42 @@ int main(int argc, const char **argv) { pushConstantsCompute.appendDrawcall(pushData); uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(numberParticles/256.f)),1,1}; - + + // computing pressure pipeline core.recordComputeDispatchToCmdStream(cmdStream, - computePipeline1, + pressurePipeline, computeDispatchCount, - {vkcv::DescriptorSetUsage(0, computeDescriptorSet1)}, + {vkcv::DescriptorSetUsage(0, pressureDescriptorSet)}, pushConstantsCompute); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); + // computing force pipeline core.recordComputeDispatchToCmdStream(cmdStream, - computePipeline2, + forcePipeline, computeDispatchCount, - {vkcv::DescriptorSetUsage(0, computeDescriptorSet2)}, + {vkcv::DescriptorSetUsage(0, forceDescriptorSet)}, pushConstantsCompute); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); + // computing update data pipeline core.recordComputeDispatchToCmdStream(cmdStream, - computePipeline3, + updateDataPipeline, computeDispatchCount, - { vkcv::DescriptorSetUsage(0, computeDescriptorSet3) }, + { vkcv::DescriptorSetUsage(0, updateDataDescriptorSet) }, pushConstantsCompute); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); + // computing flip pipeline core.recordComputeDispatchToCmdStream(cmdStream, - computePipeline4, + flipPipeline, computeDispatchCount, - { vkcv::DescriptorSetUsage(0, computeDescriptorSet4) }, + { vkcv::DescriptorSetUsage(0, flipDescriptorSet) }, pushConstantsCompute); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); @@ -398,10 +405,12 @@ int main(int argc, const char **argv) { core.prepareImageForStorage(cmdStream, swapchainInput); vkcv::DescriptorWrites tonemappingDescriptorWrites; - tonemappingDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, colorBuffer), - vkcv::StorageImageDescriptorWrite(1, swapchainInput) - }; + tonemappingDescriptorWrites.writeStorageImage( + 0, colorBuffer + ).writeStorageImage( + 1, swapchainInput + ); + core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); uint32_t tonemappingDispatchCount[3]; diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp index 5ae7eb6047200b2cdb7a3ac38ce8512cdcaa3d53..53a11ceb1306c8a567834e943d70a8862a34afa8 100644 --- a/projects/voxelization/src/ShadowMapping.cpp +++ b/projects/voxelization/src/ShadowMapping.cpp @@ -195,9 +195,9 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert m_depthToMomentsPipe = corePtr->createComputePipeline({ depthToMomentsShader, { m_depthToMomentsDescriptorSetLayout }}); vkcv::DescriptorWrites depthToMomentDescriptorWrites; - depthToMomentDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, m_shadowMapDepth.getHandle()) }; - depthToMomentDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, m_shadowSampler) }; - depthToMomentDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, m_shadowMap.getHandle()) }; + depthToMomentDescriptorWrites.writeSampledImage(0, m_shadowMapDepth.getHandle()); + depthToMomentDescriptorWrites.writeSampler(1, m_shadowSampler); + depthToMomentDescriptorWrites.writeStorageImage(2, m_shadowMap.getHandle()); corePtr->writeDescriptorSet(m_depthToMomentsDescriptorSet, depthToMomentDescriptorWrites); // shadow blur X @@ -207,9 +207,9 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert m_shadowBlurXPipe = corePtr->createComputePipeline({ shadowBlurXShader, { m_shadowBlurXDescriptorSetLayout }}); vkcv::DescriptorWrites shadowBlurXDescriptorWrites; - shadowBlurXDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, m_shadowMap.getHandle()) }; - shadowBlurXDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, m_shadowSampler) }; - shadowBlurXDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, m_shadowMapIntermediate.getHandle()) }; + shadowBlurXDescriptorWrites.writeSampledImage(0, m_shadowMap.getHandle()); + shadowBlurXDescriptorWrites.writeSampler(1, m_shadowSampler); + shadowBlurXDescriptorWrites.writeStorageImage(2, m_shadowMapIntermediate.getHandle()); corePtr->writeDescriptorSet(m_shadowBlurXDescriptorSet, shadowBlurXDescriptorWrites); // shadow blur Y @@ -219,9 +219,9 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert m_shadowBlurYPipe = corePtr->createComputePipeline({ shadowBlurYShader, { m_shadowBlurYDescriptorSetLayout }}); vkcv::DescriptorWrites shadowBlurYDescriptorWrites; - shadowBlurYDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, m_shadowMapIntermediate.getHandle()) }; - shadowBlurYDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, m_shadowSampler) }; - shadowBlurYDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, m_shadowMap.getHandle()) }; + shadowBlurYDescriptorWrites.writeSampledImage(0, m_shadowMapIntermediate.getHandle()); + shadowBlurYDescriptorWrites.writeSampler(1, m_shadowSampler); + shadowBlurYDescriptorWrites.writeStorageImage(2, m_shadowMap.getHandle()); corePtr->writeDescriptorSet(m_shadowBlurYDescriptorSet, shadowBlurYDescriptorWrites); } diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp index faa03d38127d5a23c931fdef0470c1e24131d206..616eed83e0687e03c1d9bfe0ee3127a72457d241 100644 --- a/projects/voxelization/src/Voxelization.cpp +++ b/projects/voxelization/src/Voxelization.cpp @@ -92,10 +92,13 @@ Voxelization::Voxelization( const vkcv::ShaderProgram voxelizationShader = loadVoxelizationShader(); - const vkcv::PassConfig voxelizationPassConfig({vkcv::AttachmentDescription( - vkcv::AttachmentOperation::DONT_CARE, - vkcv::AttachmentOperation::DONT_CARE, - voxelizationDummyFormat) }); + const vkcv::PassConfig voxelizationPassConfig {{ + { + vkcv::AttachmentOperation::DONT_CARE, + vkcv::AttachmentOperation::DONT_CARE, + voxelizationDummyFormat + } + }, vkcv::Multisampling::None }; m_voxelizationPass = m_corePtr->createPass(voxelizationPassConfig); m_voxelizationDescriptorSetLayout = m_corePtr->createDescriptorSetLayout(voxelizationShader.getReflectedDescriptors().at(0)); @@ -117,14 +120,16 @@ Voxelization::Voxelization( m_voxelizationPipe = m_corePtr->createGraphicsPipeline(voxelizationPipeConfig); vkcv::DescriptorWrites voxelizationDescriptorWrites; - voxelizationDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; - voxelizationDescriptorWrites.uniformBufferWrites = { - vkcv::BufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()), - vkcv::BufferDescriptorWrite(3, lightInfoBuffer) - }; - voxelizationDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(4, shadowMap) }; - voxelizationDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(5, shadowSampler) }; - voxelizationDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, m_voxelImageIntermediate.getHandle()) }; + voxelizationDescriptorWrites.writeStorageBuffer(0, m_voxelBuffer.getHandle()); + voxelizationDescriptorWrites.writeUniformBuffer( + 1, m_voxelInfoBuffer.getHandle() + ).writeUniformBuffer( + 3, lightInfoBuffer + ); + + voxelizationDescriptorWrites.writeSampledImage(4, shadowMap); + voxelizationDescriptorWrites.writeSampler(5, shadowSampler); + voxelizationDescriptorWrites.writeStorageImage(2, m_voxelImageIntermediate.getHandle()); m_corePtr->writeDescriptorSet(m_voxelizationDescriptorSet, voxelizationDescriptorWrites); vkcv::ShaderProgram voxelVisualisationShader = loadVoxelVisualisationShader(); @@ -144,9 +149,11 @@ Voxelization::Voxelization( dependencies.depthBufferFormat ); - vkcv::PassConfig voxelVisualisationPassDefinition( - { voxelVisualisationColorAttachments, voxelVisualisationDepthAttachments }); - voxelVisualisationPassDefinition.msaa = msaa; + vkcv::PassConfig voxelVisualisationPassDefinition{ + { voxelVisualisationColorAttachments, voxelVisualisationDepthAttachments }, + msaa + }; + m_visualisationPass = m_corePtr->createPass(voxelVisualisationPassDefinition); vkcv::GraphicsPipelineConfig voxelVisualisationPipeConfig{ @@ -180,7 +187,7 @@ Voxelization::Voxelization( }); vkcv::DescriptorWrites resetVoxelWrites; - resetVoxelWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; + resetVoxelWrites.writeStorageBuffer(0, m_voxelBuffer.getHandle()); m_corePtr->writeDescriptorSet(m_voxelResetDescriptorSet, resetVoxelWrites); // buffer to image @@ -194,8 +201,8 @@ Voxelization::Voxelization( }); vkcv::DescriptorWrites bufferToImageDescriptorWrites; - bufferToImageDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; - bufferToImageDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(1, m_voxelImageIntermediate.getHandle()) }; + bufferToImageDescriptorWrites.writeStorageBuffer(0, m_voxelBuffer.getHandle()); + bufferToImageDescriptorWrites.writeStorageImage(1, m_voxelImageIntermediate.getHandle()); m_corePtr->writeDescriptorSet(m_bufferToImageDescriptorSet, bufferToImageDescriptorWrites); // secondary bounce @@ -209,11 +216,11 @@ Voxelization::Voxelization( }); vkcv::DescriptorWrites secondaryBounceDescriptorWrites; - secondaryBounceDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; - secondaryBounceDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(1, m_voxelImageIntermediate.getHandle()) }; - secondaryBounceDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(2, voxelSampler) }; - secondaryBounceDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(3, m_voxelImage.getHandle()) }; - secondaryBounceDescriptorWrites.uniformBufferWrites = { vkcv::BufferDescriptorWrite(4, m_voxelInfoBuffer.getHandle()) }; + secondaryBounceDescriptorWrites.writeStorageBuffer(0, m_voxelBuffer.getHandle()); + secondaryBounceDescriptorWrites.writeSampledImage(1, m_voxelImageIntermediate.getHandle()); + secondaryBounceDescriptorWrites.writeSampler(2, voxelSampler); + secondaryBounceDescriptorWrites.writeStorageImage(3, m_voxelImage.getHandle()); + secondaryBounceDescriptorWrites.writeUniformBuffer(4, m_voxelInfoBuffer.getHandle()); m_corePtr->writeDescriptorSet(m_secondaryBounceDescriptorSet, secondaryBounceDescriptorWrites); } @@ -345,10 +352,8 @@ void Voxelization::renderVoxelVisualisation( // write descriptor set vkcv::DescriptorWrites voxelVisualisationDescriptorWrite; - voxelVisualisationDescriptorWrite.storageImageWrites = - { vkcv::StorageImageDescriptorWrite(0, m_voxelImage.getHandle(), mipLevel) }; - voxelVisualisationDescriptorWrite.uniformBufferWrites = - { vkcv::BufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()) }; + voxelVisualisationDescriptorWrite.writeStorageImage(0, m_voxelImage.getHandle(), mipLevel); + voxelVisualisationDescriptorWrite.writeUniformBuffer(1, m_voxelInfoBuffer.getHandle()); m_corePtr->writeDescriptorSet(m_visualisationDescriptorSet, voxelVisualisationDescriptorWrite); uint32_t drawVoxelCount = voxelCount / exp2(mipLevel); diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index f01b87a79b287609822635ecc67f7541e1a8e3b6..02533e447724ad8d83c7af415b01acc2350126eb 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -195,9 +195,9 @@ int main(int argc, const char** argv) { std::vector<vkcv::VertexBinding> vertexBindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { - vertexBindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + vertexBindings.push_back(vkcv::createVertexBinding(i, { vertexAttachments[i] })); } - const vkcv::VertexLayout vertexLayout (vertexBindings); + const vkcv::VertexLayout vertexLayout { vertexBindings }; vkcv::DescriptorSetLayoutHandle forwardShadingDescriptorSetLayout = core.createDescriptorSetLayout(forwardProgram.getReflectedDescriptors().at(0)); vkcv::DescriptorSetHandle forwardShadingDescriptorSet = core.createDescriptorSet(forwardShadingDescriptorSetLayout); @@ -217,9 +217,9 @@ int main(int argc, const char** argv) { std::vector<vkcv::VertexBinding> prepassVertexBindings; for (size_t i = 0; i < prepassVertexAttachments.size(); i++) { - prepassVertexBindings.push_back(vkcv::VertexBinding(i, { prepassVertexAttachments[i] })); + prepassVertexBindings.push_back(vkcv::createVertexBinding(i, { prepassVertexAttachments[i] })); } - const vkcv::VertexLayout prepassVertexLayout(prepassVertexBindings); + const vkcv::VertexLayout prepassVertexLayout { prepassVertexBindings }; const vkcv::AttachmentDescription prepassAttachment( vkcv::AttachmentOperation::STORE, @@ -288,14 +288,15 @@ int main(int argc, const char** argv) { const vkcv::ImageHandle specularHandle = sceneImages.back().getHandle(); vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, albedoHandle), - vkcv::SampledImageDescriptorWrite(2, normalHandle), - vkcv::SampledImageDescriptorWrite(3, specularHandle) - }; - setWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(1, colorSampler), - }; + setWrites.writeSampledImage( + 0, albedoHandle + ).writeSampledImage( + 2, normalHandle + ).writeSampledImage( + 3, specularHandle + ); + + setWrites.writeSampler(1, colorSampler); core.writeDescriptorSet(materialDescriptorSets.back(), setWrites); } @@ -570,17 +571,28 @@ int main(int argc, const char** argv) { // write forward pass descriptor set vkcv::DescriptorWrites forwardDescriptorWrites; - forwardDescriptorWrites.uniformBufferWrites = { - vkcv::BufferDescriptorWrite(0, shadowMapping.getLightInfoBuffer()), - vkcv::BufferDescriptorWrite(3, cameraPosBuffer.getHandle()), - vkcv::BufferDescriptorWrite(6, voxelization.getVoxelInfoBufferHandle()), - vkcv::BufferDescriptorWrite(7, volumetricSettingsBuffer.getHandle())}; - forwardDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(1, shadowMapping.getShadowMap()), - vkcv::SampledImageDescriptorWrite(4, voxelization.getVoxelImageHandle()) }; - forwardDescriptorWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(2, shadowMapping.getShadowSampler()), - vkcv::SamplerDescriptorWrite(5, voxelSampler) }; + forwardDescriptorWrites.writeUniformBuffer( + 0, shadowMapping.getLightInfoBuffer() + ).writeUniformBuffer( + 3, cameraPosBuffer.getHandle() + ).writeUniformBuffer( + 6, voxelization.getVoxelInfoBufferHandle() + ).writeUniformBuffer( + 7, volumetricSettingsBuffer.getHandle() + ); + + forwardDescriptorWrites.writeSampledImage( + 1, shadowMapping.getShadowMap() + ).writeSampledImage( + 4, voxelization.getVoxelImageHandle() + ); + + forwardDescriptorWrites.writeSampler( + 2, shadowMapping.getShadowSampler() + ).writeSampler( + 5, voxelSampler + ); + core.writeDescriptorSet(forwardShadingDescriptorSet, forwardDescriptorWrites); vkcv::upscaling::FSRUpscaling upscaling (core); @@ -661,9 +673,7 @@ int main(int argc, const char** argv) { for (size_t i = 0; i < scene.materials.size(); i++) { vkcv::DescriptorWrites setWrites; - setWrites.samplerWrites = { - vkcv::SamplerDescriptorWrite(1, colorSampler), - }; + setWrites.writeSampler(1, colorSampler); core.writeDescriptorSet(materialDescriptorSets[i], setWrites); } @@ -709,25 +719,25 @@ int main(int argc, const char** argv) { // update descriptor sets which use swapchain image vkcv::DescriptorWrites tonemappingDescriptorWrites; - tonemappingDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, resolvedColorBuffer) }; - tonemappingDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, colorSampler) }; - tonemappingDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapBuffer) }; + tonemappingDescriptorWrites.writeSampledImage(0, resolvedColorBuffer); + tonemappingDescriptorWrites.writeSampler(1, colorSampler); + tonemappingDescriptorWrites.writeStorageImage(2, swapBuffer); core.writeDescriptorSet(tonemappingDescriptorSet, tonemappingDescriptorWrites); // update descriptor sets which use swapchain image vkcv::DescriptorWrites postEffectsDescriptorWrites; - postEffectsDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, swapBuffer2) }; - postEffectsDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, colorSampler) }; - postEffectsDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapchainInput) }; + postEffectsDescriptorWrites.writeSampledImage(0, swapBuffer2); + postEffectsDescriptorWrites.writeSampler(1, colorSampler); + postEffectsDescriptorWrites.writeStorageImage(2, swapchainInput); core.writeDescriptorSet(postEffectsDescriptorSet, postEffectsDescriptorWrites); // update resolve descriptor, color images could be changed vkcv::DescriptorWrites resolveDescriptorWrites; - resolveDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, colorBuffer) }; - resolveDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, resolveSampler) }; - resolveDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, resolvedColorBuffer) }; + resolveDescriptorWrites.writeSampledImage(0, colorBuffer); + resolveDescriptorWrites.writeSampler(1, resolveSampler); + resolveDescriptorWrites.writeStorageImage(2, resolvedColorBuffer); core.writeDescriptorSet(resolveDescriptorSet, resolveDescriptorWrites); start = end; diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp index 96c367f2f8e22ac65bf6ccf6a5c09eb238b5604d..d554687b503fa4460f27aa4db5374cc0e4d0acb9 100644 --- a/projects/wobble_bobble/src/main.cpp +++ b/projects/wobble_bobble/src/main.cpp @@ -369,14 +369,14 @@ int main(int argc, const char **argv) { { vkcv::DescriptorWrites writes; - writes.storageBufferWrites.push_back(vkcv::BufferDescriptorWrite(0, particlesHandle)); + writes.writeStorageBuffer(0, particlesHandle); core.writeDescriptorSet(initParticleWeightsSets[0], writes); } { vkcv::DescriptorWrites writes; - writes.sampledImageWrites.push_back(vkcv::SampledImageDescriptorWrite(0, grid.getHandle())); - writes.samplerWrites.push_back(vkcv::SamplerDescriptorWrite(1, gridSampler)); + writes.writeSampledImage(0, grid.getHandle()); + writes.writeSampler(1, gridSampler); core.writeDescriptorSet(initParticleWeightsSets[1], writes); } @@ -389,19 +389,19 @@ int main(int argc, const char **argv) { { vkcv::DescriptorWrites writes; - writes.storageBufferWrites.push_back(vkcv::BufferDescriptorWrite(0, particlesHandle)); + writes.writeStorageBuffer(0, particlesHandle); core.writeDescriptorSet(transformParticlesToGridSets[0], writes); } { vkcv::DescriptorWrites writes; - writes.uniformBufferWrites.push_back(vkcv::BufferDescriptorWrite(0, simulation.getHandle())); + writes.writeUniformBuffer(0, simulation.getHandle()); core.writeDescriptorSet(transformParticlesToGridSets[1], writes); } { vkcv::DescriptorWrites writes; - writes.storageImageWrites.push_back(vkcv::StorageImageDescriptorWrite(0, grid.getHandle())); + writes.writeStorageImage(0, grid.getHandle()); core.writeDescriptorSet(transformParticlesToGridSets[2], writes); } @@ -414,20 +414,20 @@ int main(int argc, const char **argv) { { vkcv::DescriptorWrites writes; - writes.storageBufferWrites.push_back(vkcv::BufferDescriptorWrite(0, particlesHandle)); + writes.writeStorageBuffer(0, particlesHandle); core.writeDescriptorSet(updateParticleVelocitiesSets[0], writes); } { vkcv::DescriptorWrites writes; - writes.uniformBufferWrites.push_back(vkcv::BufferDescriptorWrite(0, simulation.getHandle())); + writes.writeUniformBuffer(0, simulation.getHandle()); core.writeDescriptorSet(updateParticleVelocitiesSets[1], writes); } { vkcv::DescriptorWrites writes; - writes.sampledImageWrites.push_back(vkcv::SampledImageDescriptorWrite(0, grid.getHandle())); - writes.samplerWrites.push_back(vkcv::SamplerDescriptorWrite(1, gridSampler)); + writes.writeSampledImage(0, grid.getHandle()); + writes.writeSampler(1, gridSampler); core.writeDescriptorSet(updateParticleVelocitiesSets[2], writes); } @@ -452,7 +452,7 @@ int main(int argc, const char **argv) { { vkcv::ShaderStage::FRAGMENT, "shaders/lines.frag" } }, nullptr); - vkcv::PassConfig passConfigGrid ({ + vkcv::PassConfig passConfigGrid {{ vkcv::AttachmentDescription( vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, @@ -463,9 +463,9 @@ int main(int argc, const char **argv) { vkcv::AttachmentOperation::CLEAR, vk::Format::eD32Sfloat ) - }); + }, vkcv::Multisampling::None }; - vkcv::PassConfig passConfigParticles ({ + vkcv::PassConfig passConfigParticles {{ vkcv::AttachmentDescription( vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, @@ -476,9 +476,9 @@ int main(int argc, const char **argv) { vkcv::AttachmentOperation::CLEAR, vk::Format::eD32Sfloat ) - }); + }, vkcv::Multisampling::None }; - vkcv::PassConfig passConfigLines ({ + vkcv::PassConfig passConfigLines {{ vkcv::AttachmentDescription( vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::LOAD, @@ -489,7 +489,7 @@ int main(int argc, const char **argv) { vkcv::AttachmentOperation::LOAD, vk::Format::eD32Sfloat ) - }); + }, vkcv::Multisampling::None }; vkcv::DescriptorSetLayoutHandle gfxSetLayoutGrid = core.createDescriptorSetLayout( gfxProgramGrid.getReflectedDescriptors().at(0) @@ -499,9 +499,9 @@ int main(int argc, const char **argv) { { vkcv::DescriptorWrites writes; - writes.sampledImageWrites.push_back(vkcv::SampledImageDescriptorWrite(0, grid.getHandle())); - writes.samplerWrites.push_back(vkcv::SamplerDescriptorWrite(1, gridSampler)); - writes.uniformBufferWrites.push_back(vkcv::BufferDescriptorWrite(2, simulation.getHandle())); + writes.writeSampledImage(0, grid.getHandle()); + writes.writeSampler(1, gridSampler); + writes.writeUniformBuffer(2, simulation.getHandle()); core.writeDescriptorSet(gfxSetGrid, writes); } @@ -513,7 +513,7 @@ int main(int argc, const char **argv) { { vkcv::DescriptorWrites writes; - writes.storageBufferWrites.push_back(vkcv::BufferDescriptorWrite(0, particlesHandle)); + writes.writeStorageBuffer(0, particlesHandle); core.writeDescriptorSet(gfxSetParticles, writes); } @@ -522,7 +522,7 @@ int main(int argc, const char **argv) { vkcv::PassHandle gfxPassLines = core.createPass(passConfigLines); vkcv::VertexLayout vertexLayoutGrid ({ - vkcv::VertexBinding(0, gfxProgramGrid.getVertexAttachments()) + vkcv::createVertexBinding(0, gfxProgramGrid.getVertexAttachments()) }); vkcv::GraphicsPipelineConfig gfxPipelineConfigGrid; @@ -535,7 +535,7 @@ int main(int argc, const char **argv) { gfxPipelineConfigGrid.m_UseDynamicViewport = true; vkcv::VertexLayout vertexLayoutParticles ({ - vkcv::VertexBinding(0, gfxProgramParticles.getVertexAttachments()) + vkcv::createVertexBinding(0, gfxProgramParticles.getVertexAttachments()) }); vkcv::GraphicsPipelineConfig gfxPipelineConfigParticles; @@ -548,7 +548,7 @@ int main(int argc, const char **argv) { gfxPipelineConfigParticles.m_UseDynamicViewport = true; vkcv::VertexLayout vertexLayoutLines ({ - vkcv::VertexBinding(0, gfxProgramLines.getVertexAttachments()) + vkcv::createVertexBinding(0, gfxProgramLines.getVertexAttachments()) }); vkcv::GraphicsPipelineConfig gfxPipelineConfigLines; @@ -883,7 +883,7 @@ int main(int argc, const char **argv) { ); vkcv::DescriptorWrites writes; - writes.storageBufferWrites.push_back(vkcv::BufferDescriptorWrite(0, particlesHandle)); + writes.writeStorageBuffer(0, particlesHandle); core.writeDescriptorSet(initParticleWeightsSets[0], writes); core.writeDescriptorSet(transformParticlesToGridSets[0], writes); diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index 52915ff04800ef3b6cb1e6caefdb3f25f6568aac..2d29719f4a34d305f90c1b76db6b56277eb3def5 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -111,6 +111,9 @@ namespace vkcv { return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); }); } + /** + * @brief Structure to store details required for a staging process. + */ struct StagingStepInfo { const void* data; size_t size; diff --git a/src/vkcv/CommandResources.cpp b/src/vkcv/CommandResources.cpp index a31e6967d85bd099fe5cbbc865b0e062212ca16e..d5c97946aa97ba897710dda412b6f71bd2ed54c8 100644 --- a/src/vkcv/CommandResources.cpp +++ b/src/vkcv/CommandResources.cpp @@ -40,7 +40,7 @@ namespace vkcv { } } - vk::CommandBuffer allocateCommandBuffer(const vk::Device& device, const vk::CommandPool cmdPool) { + vk::CommandBuffer allocateCommandBuffer(const vk::Device& device, const vk::CommandPool &cmdPool) { const vk::CommandBufferAllocateInfo info(cmdPool, vk::CommandBufferLevel::ePrimary, 1); return device.allocateCommandBuffers(info).front(); } @@ -49,7 +49,7 @@ namespace vkcv { return cmdResources.cmdPoolPerQueueFamily[queue.familyIndex]; } - Queue getQueueForSubmit(const QueueType type, const QueueManager& queueManager) { + Queue getQueueForSubmit(QueueType type, const QueueManager& queueManager) { if (type == QueueType::Graphics) { return queueManager.getGraphicsQueues().front(); } @@ -68,17 +68,17 @@ namespace vkcv { } } - void beginCommandBuffer(const vk::CommandBuffer cmdBuffer, const vk::CommandBufferUsageFlags flags) { + void beginCommandBuffer(const vk::CommandBuffer &cmdBuffer, vk::CommandBufferUsageFlags flags) { const vk::CommandBufferBeginInfo beginInfo(flags); cmdBuffer.begin(beginInfo); } void submitCommandBufferToQueue( - const vk::Queue queue, - const vk::CommandBuffer cmdBuffer, - const vk::Fence fence, - const std::vector<vk::Semaphore>& waitSemaphores, - const std::vector<vk::Semaphore>& signalSemaphores) { + vk::Queue queue, + const vk::CommandBuffer &cmdBuffer, + const vk::Fence &fence, + const std::vector<vk::Semaphore> &waitSemaphores, + const std::vector<vk::Semaphore> &signalSemaphores) { const std::vector<vk::PipelineStageFlags> waitDstStageMasks(waitSemaphores.size(), vk::PipelineStageFlagBits::eAllCommands); const vk::SubmitInfo queueSubmitInfo(waitSemaphores, waitDstStageMasks, cmdBuffer, signalSemaphores); diff --git a/src/vkcv/CommandStreamManager.cpp b/src/vkcv/CommandStreamManager.cpp index 52b73213dbc5837f6be4a2aa25c28615dccf5969..872e91c54b1b64616ad5867926e6f656f44ccded 100644 --- a/src/vkcv/CommandStreamManager.cpp +++ b/src/vkcv/CommandStreamManager.cpp @@ -1,4 +1,4 @@ -#include "vkcv/CommandStreamManager.hpp" +#include "CommandStreamManager.hpp" #include "vkcv/Core.hpp" #include "vkcv/Logger.hpp" @@ -22,7 +22,7 @@ namespace vkcv { } CommandStreamHandle CommandStreamManager::createCommandStream( - const vk::Queue queue, + const vk::Queue &queue, vk::CommandPool cmdPool) { const vk::CommandBuffer cmdBuffer = allocateCommandBuffer(m_core->getContext().getDevice(), cmdPool); @@ -53,8 +53,8 @@ namespace vkcv { } void CommandStreamManager::recordCommandsToStream( - const CommandStreamHandle handle, - const RecordCommandFunction record) { + const CommandStreamHandle &handle, + const RecordCommandFunction &record) { const size_t id = handle.getId(); if (id >= m_commandStreams.size()) { @@ -67,8 +67,8 @@ namespace vkcv { } void CommandStreamManager::addFinishCallbackToStream( - const CommandStreamHandle handle, - const FinishCommandFunction finish) { + const CommandStreamHandle &handle, + const FinishCommandFunction &finish) { const size_t id = handle.getId(); if (id >= m_commandStreams.size()) { @@ -81,7 +81,7 @@ namespace vkcv { } void CommandStreamManager::submitCommandStreamSynchronous( - const CommandStreamHandle handle, + const CommandStreamHandle &handle, std::vector<vk::Semaphore> &waitSemaphores, std::vector<vk::Semaphore> &signalSemaphores) { @@ -109,7 +109,7 @@ namespace vkcv { } } - vk::CommandBuffer CommandStreamManager::getStreamCommandBuffer(const CommandStreamHandle handle) { + vk::CommandBuffer CommandStreamManager::getStreamCommandBuffer(const CommandStreamHandle &handle) { const size_t id = handle.getId(); if (id >= m_commandStreams.size()) { vkcv_log(LogLevel::ERROR, "Requires valid handle"); diff --git a/src/vkcv/CommandStreamManager.hpp b/src/vkcv/CommandStreamManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9a8eb3d02143c20532275d5a61ca3cc68aa03778 --- /dev/null +++ b/src/vkcv/CommandStreamManager.hpp @@ -0,0 +1,97 @@ +#pragma once +#include <vulkan/vulkan.hpp> +#include <vector> +#include "vkcv/Event.hpp" +#include "vkcv/Handles.hpp" +#include "vkcv/CommandRecordingFunctionTypes.hpp" + +namespace vkcv { + + class Core; + + /** + * @brief Responsible for creation, deletion, callbacks and recording of command streams + */ + class CommandStreamManager + { + friend class Core; + private: + /** + * @brief Represents one command stream, into which commands can be recorded into. + * Consists of a command buffer, the command buffer's command pool and a queue, as well as some callbacks. + */ + struct CommandStream { + inline CommandStream(vk::CommandBuffer cmdBuffer, vk::Queue queue, vk::CommandPool cmdPool) + : cmdBuffer(cmdBuffer), cmdPool(cmdPool), queue(queue) {}; + vk::CommandBuffer cmdBuffer; + vk::CommandPool cmdPool; + vk::Queue queue; + std::vector<FinishCommandFunction> callbacks; + }; + + Core* m_core; + std::vector<CommandStream> m_commandStreams; + + CommandStreamManager() noexcept; + + void init(Core* core); + + public: + ~CommandStreamManager() noexcept; + + CommandStreamManager(CommandStreamManager&& other) = delete; + CommandStreamManager(const CommandStreamManager& other) = delete; + + CommandStreamManager& operator=(CommandStreamManager&& other) = delete; + CommandStreamManager& operator=(const CommandStreamManager& other) = delete; + + /** + * @brief Creates a new command stream + * + * @param queue Queue the command buffer will be submitted to + * @param cmdPool Command pool the command buffer will be allocated from + * @return Handle that represents the #CommandStream + */ + CommandStreamHandle createCommandStream( + const vk::Queue &queue, + vk::CommandPool cmdPool); + + /** + * @brief Record vulkan commands to a #CommandStream, using a record function + * + * @param handle Command stream handle + * @param record Function that records the vulkan commands + */ + void recordCommandsToStream(const CommandStreamHandle &handle, const RecordCommandFunction &record); + + /** + * @brief Add a callback to a #CommandStream that is called + * every time the command stream is submitted and finished + * + * @param handle Command stream handle + * @param finish Callback that is called when a command stream submission is finished + */ + void addFinishCallbackToStream(const CommandStreamHandle &handle, const FinishCommandFunction &finish); + + /** + * @brief Submits a #CommandStream to it's queue and returns after execution is finished + * + * @param handle Command stream handle + * @param waitSemaphores Semaphores that are waited upon before executing the recorded commands + * @param signalSemaphores Semaphores that are signaled when execution of the recorded commands is finished + */ + void submitCommandStreamSynchronous( + const CommandStreamHandle &handle, + std::vector<vk::Semaphore> &waitSemaphores, + std::vector<vk::Semaphore> &signalSemaphores); + + /** + * @brief Returns the underlying vulkan handle of a #CommandStream to be used for manual command recording + * + * @param handle Command stream handle + * @return Vulkan handle of the #CommandStream + */ + vk::CommandBuffer getStreamCommandBuffer(const CommandStreamHandle &handle); + }; + +} \ No newline at end of file diff --git a/src/vkcv/ComputePipelineManager.cpp b/src/vkcv/ComputePipelineManager.cpp index a599001d3c60e126cfa0a52a1347abfe48b961a9..264389ca9b5ed118666911b07158ab589a4ca0ee 100644 --- a/src/vkcv/ComputePipelineManager.cpp +++ b/src/vkcv/ComputePipelineManager.cpp @@ -59,9 +59,9 @@ namespace vkcv vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo({}, descriptorSetLayouts); - const size_t pushConstantSize = shaderProgram.getPushConstantSize(); - vk::PushConstantRange pushConstantRange(vk::ShaderStageFlagBits::eCompute, 0, pushConstantSize); - if (pushConstantSize > 0) { + const size_t pushConstantsSize = shaderProgram.getPushConstantsSize(); + vk::PushConstantRange pushConstantRange(vk::ShaderStageFlagBits::eCompute, 0, pushConstantsSize); + if (pushConstantsSize > 0) { pipelineLayoutCreateInfo.setPushConstantRangeCount(1); pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRange); } @@ -112,8 +112,8 @@ namespace vkcv vk::Result ComputePipelineManager::createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, const ShaderStage stage) { - std::vector<char> code = shaderProgram.getShader(stage).shaderCode; - vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data())); + std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); + vk::ShaderModuleCreateInfo moduleInfo({}, code.size() * sizeof(uint32_t), code.data()); return m_Device.createShaderModule(&moduleInfo, nullptr, &module); } } \ No newline at end of file diff --git a/src/vkcv/ComputePipelineManager.hpp b/src/vkcv/ComputePipelineManager.hpp index acb50bbdef99d037374c140836d25bb161132b2b..4c186ac7508a0cb8ff98d691d25cd8c3b1726f47 100644 --- a/src/vkcv/ComputePipelineManager.hpp +++ b/src/vkcv/ComputePipelineManager.hpp @@ -16,6 +16,9 @@ namespace vkcv { + /** + * @brief Class to manage compute pipelines. + */ class ComputePipelineManager { public: diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index 8988e479f0f57693c49ab3dbfc40f056a4cc4d8c..4a5b314f0bca5aa7af820c7bc876b954bf1ca0f3 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -185,6 +185,166 @@ namespace vkcv return extensions; } + + /** + * Given the @p physicalDevice and the @p queuePriorities, the @p queueCreateInfos are computed. First, the requested + * queues are sorted by priority depending on the availability of queues in the queue families of the given + * @p physicalDevice. Then check, if all requested queues are creatable. If so, the @p queueCreateInfos will be computed. + * Furthermore, lists of index pairs (queueFamilyIndex, queueIndex) for later referencing of the separate queues will + * be computed. + * @param[in] physicalDevice The physical device + * @param[in] queuePriorities The queue priorities used for the computation of @p queueCreateInfos + * @param[in] queueFlags The queue flags requesting the queues + * @param[in,out] queueCreateInfos The queue create info structures to be created + * @param[in,out] queuePairsGraphics The list of index pairs (queueFamilyIndex, queueIndex) of queues of type + * vk::QueueFlagBits::eGraphics + * @param[in,out] queuePairsCompute The list of index pairs (queueFamilyIndex, queueIndex) of queues of type + * vk::QueueFlagBits::eCompute + * @param[in,out] queuePairsTransfer The list of index pairs (queueFamilyIndex, queueIndex) of queues of type + * vk::QueueFlagBits::eTransfer + * @throws std::runtime_error If the requested queues from @p queueFlags are not creatable due to insufficient availability. + */ + static void queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice, + const std::vector<float> &queuePriorities, + const std::vector<vk::QueueFlagBits> &queueFlags, + std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos, + std::vector<std::pair<int, int>> &queuePairsGraphics, + std::vector<std::pair<int, int>> &queuePairsCompute, + std::vector<std::pair<int, int>> &queuePairsTransfer) + { + queueCreateInfos = {}; + queuePairsGraphics = {}; + queuePairsCompute = {}; + queuePairsTransfer = {}; + std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties(); + + //check priorities of flags -> the lower prioCount the higher the priority + std::vector<int> prios; + for(auto flag: queueFlags) { + int prioCount = 0; + for (size_t i = 0; i < qFamilyProperties.size(); i++) { + prioCount += (static_cast<uint32_t>(flag & qFamilyProperties[i].queueFlags) != 0) * qFamilyProperties[i].queueCount; + } + prios.push_back(prioCount); + } + //resort flags with heighest priority before allocating the queues + std::vector<vk::QueueFlagBits> newFlags; + for(size_t i = 0; i < prios.size(); i++) { + auto minElem = std::min_element(prios.begin(), prios.end()); + int index = minElem - prios.begin(); + newFlags.push_back(queueFlags[index]); + prios[index] = std::numeric_limits<int>::max(); + } + + // create requested queues and check if more requested queues are supported + // herefore: create vector that updates available queues in each queue family + // structure: [qFamily_0, ..., qFamily_n] where + // - qFamily_i = [GraphicsCount, ComputeCount, TransferCount], 0 <= i <= n + std::vector<std::vector<int>> queueFamilyStatus, initialQueueFamilyStatus; + + for (auto qFamily : qFamilyProperties) { + auto graphicsCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0? qFamily.queueCount : 0; + auto computeCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0? qFamily.queueCount : 0; + auto transferCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0? qFamily.queueCount : 0; + queueFamilyStatus.push_back({ + static_cast<int>(graphicsCount), + static_cast<int>(computeCount), + static_cast<int>(transferCount) + }); + } + + initialQueueFamilyStatus = queueFamilyStatus; + // check if every queue with the specified queue flag can be created + // this automatically checks for queue flag support! + for (auto qFlag : newFlags) { + bool found; + switch (qFlag) { + case vk::QueueFlagBits::eGraphics: + found = false; + for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { + if (queueFamilyStatus[i][0] > 0) { + queuePairsGraphics.emplace_back(std::pair(i, initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0])); + queueFamilyStatus[i][0]--; + queueFamilyStatus[i][1]--; + queueFamilyStatus[i][2]--; + found = true; + } + } + if (!found) { + for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { + if (initialQueueFamilyStatus[i][0] > 0) { + queuePairsGraphics.emplace_back(std::pair(i, 0)); + found = true; + } + } + + vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); + } + break; + case vk::QueueFlagBits::eCompute: + found = false; + for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { + if (queueFamilyStatus[i][1] > 0) { + queuePairsCompute.emplace_back(std::pair(i, initialQueueFamilyStatus[i][1] - queueFamilyStatus[i][1])); + queueFamilyStatus[i][0]--; + queueFamilyStatus[i][1]--; + queueFamilyStatus[i][2]--; + found = true; + } + } + if (!found) { + for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { + if (initialQueueFamilyStatus[i][1] > 0) { + queuePairsCompute.emplace_back(std::pair(i, 0)); + found = true; + } + } + + vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); + } + break; + case vk::QueueFlagBits::eTransfer: + found = false; + for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { + if (queueFamilyStatus[i][2] > 0) { + queuePairsTransfer.emplace_back(std::pair(i, initialQueueFamilyStatus[i][2] - queueFamilyStatus[i][2])); + queueFamilyStatus[i][0]--; + queueFamilyStatus[i][1]--; + queueFamilyStatus[i][2]--; + found = true; + } + } + if (!found) { + for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { + if (initialQueueFamilyStatus[i][2] > 0) { + queuePairsTransfer.emplace_back(std::pair(i, 0)); + found = true; + } + } + + vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); + } + break; + default: + vkcv_log(LogLevel::ERROR, "Invalid input for queue flag bits: %s", vk::to_string(qFlag).c_str()); + break; + } + } + + // create all requested queues + for (size_t i = 0; i < qFamilyProperties.size(); i++) { + uint32_t create = std::abs(initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]); + if (create > 0) { + vk::DeviceQueueCreateInfo qCreateInfo( + vk::DeviceQueueCreateFlags(), + i, + create, + queuePriorities.data() + ); + queueCreateInfos.push_back(qCreateInfo); + } + } + } Context Context::create(const char *applicationName, uint32_t applicationVersion, @@ -306,7 +466,15 @@ namespace vkcv qPriorities.resize(queueFlags.size(), 1.f); std::vector<std::pair<int, int>> queuePairsGraphics, queuePairsCompute, queuePairsTransfer; - QueueManager::queueCreateInfosQueueHandles(physicalDevice, qPriorities, queueFlags, qCreateInfos, queuePairsGraphics, queuePairsCompute, queuePairsTransfer); + queueCreateInfosQueueHandles( + physicalDevice, + qPriorities, + queueFlags, + qCreateInfos, + queuePairsGraphics, + queuePairsCompute, + queuePairsTransfer + ); vk::DeviceCreateInfo deviceCreateInfo( vk::DeviceCreateFlags(), @@ -327,10 +495,6 @@ namespace vkcv deviceCreateInfo.setPNext(&(featureManager.getFeatures())); vk::Device device = physicalDevice.createDevice(deviceCreateInfo); - - if (featureManager.isExtensionActive(VK_NV_MESH_SHADER_EXTENSION_NAME)) { - InitMeshShaderDrawFunctions(device); - } QueueManager queueManager = QueueManager::create( device, diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index a44ee97821e4fbf6241e74b9f010fcf46970e91f..df3170d1524b69d23a67c91d1ec94829bcc08c8c 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -16,7 +16,7 @@ #include "DescriptorManager.hpp" #include "WindowManager.hpp" #include "ImageLayoutTransitions.hpp" -#include "vkcv/CommandStreamManager.hpp" +#include "CommandStreamManager.hpp" #include <cmath> #include "vkcv/Logger.hpp" @@ -152,7 +152,7 @@ namespace vkcv width = extent.width; height = extent.height; - if ((width < MIN_SWAPCHAIN_SIZE) || (height < MIN_SWAPCHAIN_SIZE)) { + if ((width < MIN_SURFACE_SIZE) || (height < MIN_SURFACE_SIZE)) { return false; } @@ -271,11 +271,15 @@ namespace vkcv vk::IndexType getIndexType(IndexBitCount indexByteCount){ switch (indexByteCount) { - case IndexBitCount::Bit16: return vk::IndexType::eUint16; - case IndexBitCount::Bit32: return vk::IndexType::eUint32; - default: - vkcv_log(LogLevel::ERROR, "unknown Enum"); + case IndexBitCount::Bit8: + return vk::IndexType::eUint8EXT; + case IndexBitCount::Bit16: return vk::IndexType::eUint16; + case IndexBitCount::Bit32: + return vk::IndexType::eUint32; + default: + vkcv_log(LogLevel::ERROR, "unknown Enum"); + return vk::IndexType::eNoneKHR; } } @@ -893,9 +897,9 @@ namespace vkcv return getSwapchain(swapchainHandle); } - DescriptorSetLayoutHandle Core::createDescriptorSetLayout(const DescriptorBindings &bindingsMap) + DescriptorSetLayoutHandle Core::createDescriptorSetLayout(const DescriptorBindings &bindings) { - return m_DescriptorManager->createDescriptorSetLayout(bindingsMap); + return m_DescriptorManager->createDescriptorSetLayout(bindings); } DescriptorSetLayout Core::getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const @@ -1067,7 +1071,7 @@ namespace vkcv static void setDebugObjectLabel(const vk::Device& device, const vk::ObjectType& type, uint64_t handle, const std::string& label) { -#ifndef VULKAN_DEBUG_LABELS +#ifdef VULKAN_DEBUG_LABELS static PFN_vkSetDebugUtilsObjectNameEXT setDebugLabel = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>( device.getProcAddr("vkSetDebugUtilsObjectNameEXT") ); diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp index 8343fde6650bd811d85fb44f867c8d832a9380d6..d12a5287e2317bdfc21fb15872681138b4f0d64f 100644 --- a/src/vkcv/DescriptorManager.cpp +++ b/src/vkcv/DescriptorManager.cpp @@ -35,6 +35,8 @@ namespace vkcv } for (uint64_t id = 0; id < m_DescriptorSetLayouts.size(); id++) { + // Resets the usage count to zero for destruction. + m_DescriptorSetLayouts[id].layoutUsageCount = 0; destroyDescriptorSetLayoutById(id); } @@ -48,15 +50,16 @@ namespace vkcv } } - DescriptorSetLayoutHandle DescriptorManager::createDescriptorSetLayout(const DescriptorBindings &setBindingsMap) + DescriptorSetLayoutHandle DescriptorManager::createDescriptorSetLayout(const DescriptorBindings &bindings) { for (size_t i = 0; i < m_DescriptorSetLayouts.size(); i++) { - if(m_DescriptorSetLayouts[i].descriptorBindings.size() != setBindingsMap.size()) + if(m_DescriptorSetLayouts[i].descriptorBindings.size() != bindings.size()) continue; - if (m_DescriptorSetLayouts[i].descriptorBindings == setBindingsMap) + if (m_DescriptorSetLayouts[i].descriptorBindings == bindings) { + m_DescriptorSetLayouts[i].layoutUsageCount++; return DescriptorSetLayoutHandle(i, [&](uint64_t id) { destroyDescriptorSetLayoutById(id); }); } } @@ -65,7 +68,7 @@ namespace vkcv std::vector<vk::DescriptorSetLayoutBinding> bindingsVector = {}; std::vector<vk::DescriptorBindingFlags> bindingsFlags = {}; - for (auto bindingElem : setBindingsMap) + for (auto bindingElem : bindings) { DescriptorBinding binding = bindingElem.second; uint32_t bindingID = bindingElem.first; @@ -104,14 +107,14 @@ namespace vkcv }; const uint64_t id = m_DescriptorSetLayouts.size(); - m_DescriptorSetLayouts.push_back({vulkanHandle, setBindingsMap}); + m_DescriptorSetLayouts.push_back({vulkanHandle, bindings, 1}); return DescriptorSetLayoutHandle(id, [&](uint64_t id) { destroyDescriptorSetLayoutById(id); }); } - DescriptorSetHandle DescriptorManager::createDescriptorSet(const DescriptorSetLayoutHandle &setLayoutHandle) + DescriptorSetHandle DescriptorManager::createDescriptorSet(const DescriptorSetLayoutHandle &layout) { //create and allocate the set based on the layout provided - DescriptorSetLayout setLayout = m_DescriptorSetLayouts[setLayoutHandle.getId()]; + DescriptorSetLayout setLayout = m_DescriptorSetLayouts[layout.getId()]; vk::DescriptorSet vulkanHandle; vk::DescriptorSetAllocateInfo allocInfo(m_Pools.back(), 1, &setLayout.vulkanHandle); @@ -148,10 +151,13 @@ namespace vkcv size_t poolIndex = (m_Pools.size() - 1); const uint64_t id = m_DescriptorSets.size(); - m_DescriptorSets.push_back({vulkanHandle, setLayoutHandle, poolIndex}); + m_DescriptorSets.push_back({ vulkanHandle, layout, poolIndex }); return DescriptorSetHandle(id, [&](uint64_t id) { destroyDescriptorSetById(id); }); } + /** + * @brief Structure to store details to write to a descriptor set. + */ struct WriteDescriptorSetInfo { size_t imageInfoIndex; size_t bufferInfoIndex; @@ -173,7 +179,7 @@ namespace vkcv std::vector<WriteDescriptorSetInfo> writeInfos; - for (const auto& write : writes.sampledImageWrites) + for (const auto& write : writes.getSampledImageWrites()) { vk::ImageLayout layout = write.useGeneralLayout ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal; const vk::DescriptorImageInfo imageInfo( @@ -195,7 +201,7 @@ namespace vkcv writeInfos.push_back(vulkanWrite); } - for (const auto& write : writes.storageImageWrites) { + for (const auto& write : writes.getStorageImageWrites()) { const vk::DescriptorImageInfo imageInfo( nullptr, imageManager.getVulkanImageView(write.image, write.mipLevel), @@ -215,7 +221,7 @@ namespace vkcv writeInfos.push_back(vulkanWrite); } - for (const auto& write : writes.uniformBufferWrites) { + for (const auto& write : writes.getUniformBufferWrites()) { const size_t size = bufferManager.getBufferSize(write.buffer); const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size); @@ -242,7 +248,7 @@ namespace vkcv writeInfos.push_back(vulkanWrite); } - for (const auto& write : writes.storageBufferWrites) { + for (const auto& write : writes.getStorageBufferWrites()) { const size_t size = bufferManager.getBufferSize(write.buffer); const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size); @@ -269,7 +275,7 @@ namespace vkcv writeInfos.push_back(vulkanWrite); } - for (const auto& write : writes.samplerWrites) { + for (const auto& write : writes.getSamplerWrites()) { const vk::Sampler& sampler = samplerManager.getVulkanSampler(write.sampler); const vk::DescriptorImageInfo imageInfo( @@ -341,6 +347,13 @@ namespace vkcv } auto& layout = m_DescriptorSetLayouts[id]; + + if (layout.layoutUsageCount > 1) { + layout.layoutUsageCount--; + return; + } else { + layout.layoutUsageCount = 0; + } if (layout.vulkanHandle){ m_Device.destroy(layout.vulkanHandle); diff --git a/src/vkcv/DescriptorManager.hpp b/src/vkcv/DescriptorManager.hpp index d60a6d5c6eb1a66db07487c888505e8b3731b046..c996e8c94f6dbb6f45f173f60f59f344a9a58623 100644 --- a/src/vkcv/DescriptorManager.hpp +++ b/src/vkcv/DescriptorManager.hpp @@ -1,7 +1,7 @@ #pragma once /** - * @authors Artur Wasmut, Susanne D�tsch, Simeon Hermann + * @authors Artur Wasmut, Susanne D�tsch, Simeon Hermann, Tobias Frisch * @file src/vkcv/DescriptorManager.cpp * @brief Creation and handling of descriptor sets and the respective descriptor pools */ @@ -17,24 +17,60 @@ namespace vkcv { + + /** + * @brief Class to manage descriptor sets and descriptor set layouts. + */ class DescriptorManager { public: + /** + * @brief Constructor of the descriptor manager + * + * @param[in,out] device Vulkan device + */ explicit DescriptorManager(vk::Device device) noexcept; + + /** + * @brief Destructor of the descriptor manager + */ ~DescriptorManager() noexcept; - DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &setBindingsMap); - DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &setLayoutHandle); + /** + * @brief Creates a descriptor set layout with given descriptor bindings + * or returns a matching handle. + * + * @param[in] bindings Descriptor bindings + * @return Handle of descriptor set layout + */ + DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); + + /** + * @brief Creates a descriptor set using a given descriptor set layout. + * + * @param[in] layout Handle of descriptor set layout + * @return Handle of descriptor set + */ + DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layout); - void writeDescriptorSet( - const DescriptorSetHandle &handle, - const DescriptorWrites &writes, - const ImageManager &imageManager, - const BufferManager &bufferManager, - const SamplerManager &samplerManager); + /** + * @brief Writes to a descriptor set using writes and all required managers. + * + * @param[in] handle Handle of descriptor set + * @param[in] writes Descriptor set writes + * @param[in] imageManager Image manager + * @param[in] bufferManager Buffer manager + * @param[in] samplerManager Sampler manager + */ + void writeDescriptorSet(const DescriptorSetHandle &handle, + const DescriptorWrites &writes, + const ImageManager &imageManager, + const BufferManager &bufferManager, + const SamplerManager &samplerManager); [[nodiscard]] DescriptorSetLayout getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const; + [[nodiscard]] DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const; @@ -45,34 +81,40 @@ namespace vkcv vk::DescriptorPoolCreateInfo m_PoolInfo; /** - * Contains all the descriptor set layout descriptions - * that were requested by the user in calls of createDescriptorSetLayout. - */ + * Contains all the descriptor set layout descriptions + * that were requested by the user in calls of createDescriptorSetLayout. + */ std::vector<DescriptorSetLayout> m_DescriptorSetLayouts; /** - * Contains all the descriptor sets that were created by the user in calls of createDescriptorSet. - */ + * Contains all the descriptor sets that were created by the user in calls of createDescriptorSet. + */ std::vector<DescriptorSet> m_DescriptorSets; /** - * Destroys a specific descriptor set - * @param[in] the DescriptorSetHandle - */ + * @brief Destroys a specific descriptor set. + * + * @param[in] the DescriptorSetHandle + */ void destroyDescriptorSetById(uint64_t id); /** - * Destroys a specific descriptor set LAYOUT (not the set) - * @param[in] the DescriptorSetLayoutHandle - */ + * @brief Revokes the usage of a specific descriptor set layout and + * destroys it once the usage count is at zero. + * + * @param[in] the DescriptorSetLayoutHandle + */ void destroyDescriptorSetLayoutById(uint64_t id); /** - * creates a descriptor pool based on the poolSizes and poolInfo defined in the constructor - * is called initially in the constructor and then every time the pool runs out memory - * @return a DescriptorPool object - */ + * @brief Creates a descriptor pool based on the poolSizes and poolInfo defined in the + * constructor is called initially in the constructor and then every time the pool runs + * out memory. + * + * @return a DescriptorPool object + */ vk::DescriptorPool allocateDescriptorPool(); }; + } \ No newline at end of file diff --git a/src/vkcv/DescriptorWrites.cpp b/src/vkcv/DescriptorWrites.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2dbf1b253d45c32ee1d7883aa0363c5640d023bb --- /dev/null +++ b/src/vkcv/DescriptorWrites.cpp @@ -0,0 +1,75 @@ + +#include "vkcv/DescriptorWrites.hpp" + +namespace vkcv { + + DescriptorWrites &DescriptorWrites::writeSampledImage(uint32_t binding, + ImageHandle image, + uint32_t mipLevel, + bool useGeneralLayout, + uint32_t arrayIndex) { + m_sampledImageWrites.emplace_back(binding, image, mipLevel, useGeneralLayout, arrayIndex); + return *this; + } + + DescriptorWrites &DescriptorWrites::writeStorageImage(uint32_t binding, + ImageHandle image, + uint32_t mipLevel) { + m_storageImageWrites.emplace_back(binding, image, mipLevel); + return *this; + } + + DescriptorWrites &DescriptorWrites::writeUniformBuffer(uint32_t binding, + BufferHandle buffer, + bool dynamic, + uint32_t offset, + uint32_t size) { + m_uniformBufferWrites.emplace_back(binding, buffer, dynamic, offset, size); + return *this; + } + + DescriptorWrites &DescriptorWrites::writeStorageBuffer(uint32_t binding, + BufferHandle buffer, + bool dynamic, + uint32_t offset, + uint32_t size) { + m_storageBufferWrites.emplace_back(binding, buffer, dynamic, offset, size); + return *this; + } + + DescriptorWrites &DescriptorWrites::writeSampler(uint32_t binding, + SamplerHandle sampler) { + m_samplerWrites.emplace_back(binding, sampler); + return *this; + } + + DescriptorWrites &DescriptorWrites::writeAcceleration(uint32_t binding) { + m_accelerationWrites.emplace_back(binding); + return *this; + } + + const std::vector<SampledImageDescriptorWrite> &DescriptorWrites::getSampledImageWrites() const { + return m_sampledImageWrites; + } + + const std::vector<StorageImageDescriptorWrite> &DescriptorWrites::getStorageImageWrites() const { + return m_storageImageWrites; + } + + const std::vector<BufferDescriptorWrite> &DescriptorWrites::getUniformBufferWrites() const { + return m_uniformBufferWrites; + } + + const std::vector<BufferDescriptorWrite> &DescriptorWrites::getStorageBufferWrites() const { + return m_storageBufferWrites; + } + + const std::vector<SamplerDescriptorWrite> &DescriptorWrites::getSamplerWrites() const { + return m_samplerWrites; + } + + const std::vector<AccelerationDescriptorWrite> &DescriptorWrites::getAccelerationWrites() const { + return m_accelerationWrites; + } + +} diff --git a/src/vkcv/DrawcallRecording.cpp b/src/vkcv/DrawcallRecording.cpp index e13b4d24148e9d76d8be4ad7fd3db0db87249c59..eef87ca65d5f461f1c37b678634cf3e6f8973397 100644 --- a/src/vkcv/DrawcallRecording.cpp +++ b/src/vkcv/DrawcallRecording.cpp @@ -5,28 +5,21 @@ namespace vkcv { - struct MeshShaderFunctions - { - PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks = nullptr; - PFN_vkCmdDrawMeshTasksIndirectNV cmdDrawMeshTasksIndirect = nullptr; - PFN_vkCmdDrawMeshTasksIndirectCountNV cmdDrawMeshTasksIndirectCount = nullptr; - } MeshShaderFunctions; - - void InitMeshShaderDrawFunctions(vk::Device device) - { - MeshShaderFunctions.cmdDrawMeshTasks = PFN_vkCmdDrawMeshTasksNV(device.getProcAddr("vkCmdDrawMeshTasksNV")); - MeshShaderFunctions.cmdDrawMeshTasksIndirect = PFN_vkCmdDrawMeshTasksIndirectNV(device.getProcAddr("vkCmdDrawMeshTasksIndirectNV")); - MeshShaderFunctions.cmdDrawMeshTasksIndirectCount = PFN_vkCmdDrawMeshTasksIndirectCountNV (device.getProcAddr( "vkCmdDrawMeshTasksIndirectCountNV")); - } - - void recordMeshShaderDrawcall( - const Core& core, - vk::CommandBuffer cmdBuffer, - vk::PipelineLayout pipelineLayout, - const PushConstants& pushConstantData, - const uint32_t pushConstantOffset, - const MeshShaderDrawcall& drawcall, - const uint32_t firstTask) { + void recordMeshShaderDrawcall(const Core& core, + vk::CommandBuffer cmdBuffer, + vk::PipelineLayout pipelineLayout, + const PushConstants& pushConstantData, + uint32_t pushConstantOffset, + const MeshShaderDrawcall& drawcall, + uint32_t firstTask) { + static PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks = reinterpret_cast<PFN_vkCmdDrawMeshTasksNV>( + core.getContext().getDevice().getProcAddr("vkCmdDrawMeshTasksNV") + ); + + if (!cmdDrawMeshTasks) { + vkcv_log(LogLevel::ERROR, "Mesh shader drawcalls are not supported"); + return; + } for (const auto& descriptorUsage : drawcall.descriptorSets) { cmdBuffer.bindDescriptorSets( @@ -48,7 +41,7 @@ namespace vkcv { pushConstantData.getSizePerDrawcall(), drawcallPushConstantData); } - - MeshShaderFunctions.cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.taskCount, firstTask); + + cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.taskCount, firstTask); } } diff --git a/src/vkcv/FeatureManager.cpp b/src/vkcv/FeatureManager.cpp index f89eb0717b82e40b10f98673e6d42fc07e67a8fd..af4426252d840bdffd7d210d900be64d6b74f6f3 100644 --- a/src/vkcv/FeatureManager.cpp +++ b/src/vkcv/FeatureManager.cpp @@ -1,9 +1,12 @@ #include "vkcv/FeatureManager.hpp" -#include <stddef.h> -#include <string.h> +#include <cstddef> +#include <cstring> + +#ifdef _MSVC_LANG #include <type_traits> +#endif namespace vkcv { diff --git a/src/vkcv/File.cpp b/src/vkcv/File.cpp index 6006b90f74e0a41f83483f2a1efbe5bda4c4e9f8..871dc06611903d5fb5cc8a9e3d53233510125826 100644 --- a/src/vkcv/File.cpp +++ b/src/vkcv/File.cpp @@ -1,7 +1,7 @@ #include "vkcv/File.hpp" -#include <stdlib.h> +#include <cstdlib> #ifdef _WIN32 #include <io.h> diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index ab0d9f26fdf482698f679b598d5b087e3674c638..2ebc84ad476bf911e42fc71bbc575db6b16db081 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -110,8 +110,8 @@ namespace vkcv vk::PipelineShaderStageCreateInfo* outCreateInfo) { assert(outCreateInfo); - std::vector<char> code = shaderProgram.getShader(stage).shaderCode; - vk::ShaderModuleCreateInfo vertexModuleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data())); + std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); + vk::ShaderModuleCreateInfo vertexModuleInfo({}, code.size() * sizeof(uint32_t), code.data()); vk::ShaderModule shaderModule; if (device.createShaderModule(&vertexModuleInfo, nullptr, &shaderModule) != vk::Result::eSuccess) return false; @@ -263,6 +263,9 @@ namespace vkcv case CullMode::Back: cullMode = vk::CullModeFlagBits::eBack; break; + case CullMode::Both: + cullMode = vk::CullModeFlagBits::eFrontAndBack; + break; default: vkcv_log(LogLevel::ERROR, "Unknown CullMode"); cullMode = vk::CullModeFlagBits::eNone; @@ -365,9 +368,9 @@ namespace vkcv const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts) { static vk::PushConstantRange pushConstantRange; - const size_t pushConstantSize = config.m_ShaderProgram.getPushConstantSize(); + const size_t pushConstantsSize = config.m_ShaderProgram.getPushConstantsSize(); pushConstantRange = vk::PushConstantRange( - vk::ShaderStageFlagBits::eAll, 0, pushConstantSize + vk::ShaderStageFlagBits::eAll, 0, pushConstantsSize ); vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo( @@ -376,7 +379,7 @@ namespace vkcv (pushConstantRange) ); - if (pushConstantSize == 0) { + if (pushConstantsSize == 0) { pipelineLayoutCreateInfo.pushConstantRangeCount = 0; } diff --git a/src/vkcv/GraphicsPipelineManager.hpp b/src/vkcv/GraphicsPipelineManager.hpp index 09900c37760f07d1967aa56a75cfc8b94aa289d5..511dcf47988028617712c191f79bdf1f292a200a 100644 --- a/src/vkcv/GraphicsPipelineManager.hpp +++ b/src/vkcv/GraphicsPipelineManager.hpp @@ -17,6 +17,10 @@ namespace vkcv { + + /** + * @brief Class to manage graphics pipelines. + */ class GraphicsPipelineManager { public: @@ -82,4 +86,5 @@ namespace vkcv void destroyPipelineById(uint64_t id); }; + } diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index 124508d5e36711a13ad49ae289b9de98600e0d6e..aedf726031ef43ac723b93f3dbd1276d92f3f704 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -14,8 +14,19 @@ namespace vkcv { + /** + * @brief Determine whether an image format is valid + * for depth buffers. + * + * @param[in] format Image format + * @return True, if the format is usable for depth buffers, otherwise false. + */ bool isDepthImageFormat(vk::Format format); + /** + * @brief Class to manage the creation, destruction, allocation + * and filling of images. + */ class ImageManager { friend class Core; diff --git a/src/vkcv/PassConfig.cpp b/src/vkcv/PassConfig.cpp deleted file mode 100644 index b203fab4f02afcc8f51b468ab4504480a8e60e4e..0000000000000000000000000000000000000000 --- a/src/vkcv/PassConfig.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "vkcv/PassConfig.hpp" - -#include <utility> - -namespace vkcv -{ - AttachmentDescription::AttachmentDescription( - AttachmentOperation store_op, - AttachmentOperation load_op, - vk::Format format) noexcept : - store_operation{store_op}, - load_operation{load_op}, - format(format) - {} - - PassConfig::PassConfig(std::vector<AttachmentDescription> attachments, Multisampling msaa) noexcept : - attachments{std::move(attachments) }, msaa(msaa) - {} -} \ No newline at end of file diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp index 661a8b277ecb446c4bbaeeb63560ffde28c31d99..1ef976e0482ea39afad33346068f2a168eac70d8 100644 --- a/src/vkcv/PassManager.hpp +++ b/src/vkcv/PassManager.hpp @@ -7,6 +7,10 @@ namespace vkcv { + + /** + * @brief Class to manage the creation and destruction of passes. + */ class PassManager { private: @@ -40,4 +44,5 @@ namespace vkcv const PassConfig& getPassConfig(const PassHandle &handle) const; }; + } diff --git a/src/vkcv/QueueManager.cpp b/src/vkcv/QueueManager.cpp index ff134041bdc6279d312df668cab448a50750f1c3..d2a4d593b6a3648e9d0f01404643999ed406c26d 100644 --- a/src/vkcv/QueueManager.cpp +++ b/src/vkcv/QueueManager.cpp @@ -9,166 +9,6 @@ namespace vkcv { - /** - * Given the @p physicalDevice and the @p queuePriorities, the @p queueCreateInfos are computed. First, the requested - * queues are sorted by priority depending on the availability of queues in the queue families of the given - * @p physicalDevice. Then check, if all requested queues are creatable. If so, the @p queueCreateInfos will be computed. - * Furthermore, lists of index pairs (queueFamilyIndex, queueIndex) for later referencing of the separate queues will - * be computed. - * @param[in] physicalDevice The physical device - * @param[in] queuePriorities The queue priorities used for the computation of @p queueCreateInfos - * @param[in] queueFlags The queue flags requesting the queues - * @param[in,out] queueCreateInfos The queue create info structures to be created - * @param[in,out] queuePairsGraphics The list of index pairs (queueFamilyIndex, queueIndex) of queues of type - * vk::QueueFlagBits::eGraphics - * @param[in,out] queuePairsCompute The list of index pairs (queueFamilyIndex, queueIndex) of queues of type - * vk::QueueFlagBits::eCompute - * @param[in,out] queuePairsTransfer The list of index pairs (queueFamilyIndex, queueIndex) of queues of type - * vk::QueueFlagBits::eTransfer - * @throws std::runtime_error If the requested queues from @p queueFlags are not creatable due to insufficient availability. - */ - void QueueManager::queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice, - const std::vector<float> &queuePriorities, - const std::vector<vk::QueueFlagBits> &queueFlags, - std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos, - std::vector<std::pair<int, int>> &queuePairsGraphics, - std::vector<std::pair<int, int>> &queuePairsCompute, - std::vector<std::pair<int, int>> &queuePairsTransfer) - { - queueCreateInfos = {}; - queuePairsGraphics = {}; - queuePairsCompute = {}; - queuePairsTransfer = {}; - std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties(); - - //check priorities of flags -> the lower prioCount the higher the priority - std::vector<int> prios; - for(auto flag: queueFlags) { - int prioCount = 0; - for (size_t i = 0; i < qFamilyProperties.size(); i++) { - prioCount += (static_cast<uint32_t>(flag & qFamilyProperties[i].queueFlags) != 0) * qFamilyProperties[i].queueCount; - } - prios.push_back(prioCount); - } - //resort flags with heighest priority before allocating the queues - std::vector<vk::QueueFlagBits> newFlags; - for(size_t i = 0; i < prios.size(); i++) { - auto minElem = std::min_element(prios.begin(), prios.end()); - int index = minElem - prios.begin(); - newFlags.push_back(queueFlags[index]); - prios[index] = std::numeric_limits<int>::max(); - } - - // create requested queues and check if more requested queues are supported - // herefore: create vector that updates available queues in each queue family - // structure: [qFamily_0, ..., qFamily_n] where - // - qFamily_i = [GraphicsCount, ComputeCount, TransferCount], 0 <= i <= n - std::vector<std::vector<int>> queueFamilyStatus, initialQueueFamilyStatus; - - for (auto qFamily : qFamilyProperties) { - auto graphicsCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0? qFamily.queueCount : 0; - auto computeCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0? qFamily.queueCount : 0; - auto transferCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0? qFamily.queueCount : 0; - queueFamilyStatus.push_back({ - static_cast<int>(graphicsCount), - static_cast<int>(computeCount), - static_cast<int>(transferCount) - }); - } - - initialQueueFamilyStatus = queueFamilyStatus; - // check if every queue with the specified queue flag can be created - // this automatically checks for queue flag support! - for (auto qFlag : newFlags) { - bool found; - switch (qFlag) { - case vk::QueueFlagBits::eGraphics: - found = false; - for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { - if (queueFamilyStatus[i][0] > 0) { - queuePairsGraphics.emplace_back(std::pair(i, initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0])); - queueFamilyStatus[i][0]--; - queueFamilyStatus[i][1]--; - queueFamilyStatus[i][2]--; - found = true; - } - } - if (!found) { - for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { - if (initialQueueFamilyStatus[i][0] > 0) { - queuePairsGraphics.emplace_back(std::pair(i, 0)); - found = true; - } - } - - vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); - } - break; - case vk::QueueFlagBits::eCompute: - found = false; - for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { - if (queueFamilyStatus[i][1] > 0) { - queuePairsCompute.emplace_back(std::pair(i, initialQueueFamilyStatus[i][1] - queueFamilyStatus[i][1])); - queueFamilyStatus[i][0]--; - queueFamilyStatus[i][1]--; - queueFamilyStatus[i][2]--; - found = true; - } - } - if (!found) { - for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { - if (initialQueueFamilyStatus[i][1] > 0) { - queuePairsCompute.emplace_back(std::pair(i, 0)); - found = true; - } - } - - vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); - } - break; - case vk::QueueFlagBits::eTransfer: - found = false; - for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { - if (queueFamilyStatus[i][2] > 0) { - queuePairsTransfer.emplace_back(std::pair(i, initialQueueFamilyStatus[i][2] - queueFamilyStatus[i][2])); - queueFamilyStatus[i][0]--; - queueFamilyStatus[i][1]--; - queueFamilyStatus[i][2]--; - found = true; - } - } - if (!found) { - for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) { - if (initialQueueFamilyStatus[i][2] > 0) { - queuePairsTransfer.emplace_back(std::pair(i, 0)); - found = true; - } - } - - vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); - } - break; - default: - vkcv_log(LogLevel::ERROR, "Invalid input for queue flag bits: %s", vk::to_string(qFlag).c_str()); - break; - } - } - - // create all requested queues - for (size_t i = 0; i < qFamilyProperties.size(); i++) { - uint32_t create = std::abs(initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]); - if (create > 0) { - vk::DeviceQueueCreateInfo qCreateInfo( - vk::DeviceQueueCreateFlags(), - i, - create, - queuePriorities.data() - ); - queueCreateInfos.push_back(qCreateInfo); - } - } - } - /** * Computes the queue handles from @p queuePairs * @param device The device @@ -190,9 +30,9 @@ namespace vkcv { QueueManager QueueManager::create(vk::Device device, - std::vector<std::pair<int, int>> &queuePairsGraphics, - std::vector<std::pair<int, int>> &queuePairsCompute, - std::vector<std::pair<int, int>> &queuePairsTransfer) { + const std::vector<std::pair<int, int>> &queuePairsGraphics, + const std::vector<std::pair<int, int>> &queuePairsCompute, + const std::vector<std::pair<int, int>> &queuePairsTransfer) { std::vector<Queue> graphicsQueues = getQueues(device, queuePairsGraphics); std::vector<Queue> computeQueues = getQueues(device, queuePairsCompute); @@ -201,10 +41,8 @@ namespace vkcv { return QueueManager( std::move(graphicsQueues), std::move(computeQueues), std::move(transferQueues), 0); } - uint32_t QueueManager::checkSurfaceSupport( - const vk::PhysicalDevice &physicalDevice, - vk::SurfaceKHR &surface - ) { + uint32_t QueueManager::checkSurfaceSupport(const vk::PhysicalDevice &physicalDevice, + const vk::SurfaceKHR &surface) { std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties(); for(uint32_t i = 0; i < qFamilyProperties.size(); i++) { diff --git a/src/vkcv/SamplerManager.hpp b/src/vkcv/SamplerManager.hpp index 128faa711993ac052cf774a1d31144d19362658f..24d89f0d6af151ff009a2f2bb64953d48a9e7213 100644 --- a/src/vkcv/SamplerManager.hpp +++ b/src/vkcv/SamplerManager.hpp @@ -10,6 +10,9 @@ namespace vkcv { class Core; + /** + * @brief Class to manage the creation and destruction of samplers. + */ class SamplerManager { friend class Core; private: diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp index 504d8fcdbd84935db339370b15c31ccefe26e02b..97eea880cbc38fee1a71d52a1e154471344d7758 100644 --- a/src/vkcv/ShaderProgram.cpp +++ b/src/vkcv/ShaderProgram.cpp @@ -14,19 +14,25 @@ namespace vkcv { * @param[in] relative path to the shader code * @return vector of chars as a buffer for the code */ - std::vector<char> readShaderCode(const std::filesystem::path &shaderPath) { + std::vector<uint32_t> readShaderCode(const std::filesystem::path &shaderPath) { std::ifstream file (shaderPath.string(), std::ios::ate | std::ios::binary); if (!file.is_open()) { - vkcv_log(LogLevel::ERROR, "The file could not be opened"); - return std::vector<char>{}; + vkcv_log(LogLevel::ERROR, "The file could not be opened: %s", shaderPath.c_str()); + return std::vector<uint32_t>(); } size_t fileSize = (size_t)file.tellg(); - std::vector<char> buffer(fileSize); + + if (fileSize % sizeof(uint32_t) != 0) { + vkcv_log(LogLevel::ERROR, "The file is not a valid shader: %s", shaderPath.c_str()); + return std::vector<uint32_t>(); + } + + std::vector<uint32_t> buffer(fileSize / sizeof(uint32_t)); file.seekg(0); - file.read(buffer.data(), fileSize); + file.read(reinterpret_cast<char*>(buffer.data()), fileSize); file.close(); return buffer; @@ -76,32 +82,31 @@ namespace vkcv { m_DescriptorSets{} {} - bool ShaderProgram::addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath) + bool ShaderProgram::addShader(ShaderStage stage, const std::filesystem::path &path) { - if(m_Shaders.find(shaderStage) != m_Shaders.end()) { + if(m_Shaders.find(stage) != m_Shaders.end()) { vkcv_log(LogLevel::WARNING, "Overwriting existing shader stage"); } - const std::vector<char> shaderCode = readShaderCode(shaderPath); + const std::vector<uint32_t> shaderCode = readShaderCode(path); if (shaderCode.empty()) { return false; } else { - Shader shader{shaderCode, shaderStage}; - m_Shaders.insert(std::make_pair(shaderStage, shader)); - reflectShader(shaderStage); + m_Shaders.insert(std::make_pair(stage, shaderCode)); + reflectShader(stage); return true; } } - const Shader &ShaderProgram::getShader(ShaderStage shaderStage) const + const std::vector<uint32_t> &ShaderProgram::getShaderBinary(ShaderStage stage) const { - return m_Shaders.at(shaderStage); + return m_Shaders.at(stage); } - bool ShaderProgram::existsShader(ShaderStage shaderStage) const + bool ShaderProgram::existsShader(ShaderStage stage) const { - if(m_Shaders.find(shaderStage) == m_Shaders.end()) + if(m_Shaders.find(stage) == m_Shaders.end()) return false; else return true; @@ -109,13 +114,9 @@ namespace vkcv { void ShaderProgram::reflectShader(ShaderStage shaderStage) { - auto shaderCodeChar = m_Shaders.at(shaderStage).shaderCode; - std::vector<uint32_t> shaderCode; - - for (uint32_t i = 0; i < shaderCodeChar.size()/4; i++) - shaderCode.push_back(((uint32_t*) shaderCodeChar.data())[i]); + auto shaderCode = m_Shaders.at(shaderStage); - spirv_cross::Compiler comp(move(shaderCode)); + spirv_cross::Compiler comp(shaderCode); spirv_cross::ShaderResources resources = comp.get_shader_resources(); //reflect vertex input @@ -135,7 +136,12 @@ namespace vkcv { // vertex input format (implies its size) const VertexAttachmentFormat attachment_format = convertFormat(base_type.basetype, base_type.vecsize); - m_VertexAttachments.emplace_back(attachment_loc, attachment_name, attachment_format); + m_VertexAttachments.push_back({ + attachment_loc, + attachment_name, + attachment_format, + 0 + }); } } @@ -346,12 +352,12 @@ namespace vkcv { for (const auto &range : comp.get_active_buffer_ranges(pushConstantBuffer.id)) { const size_t size = range.range + range.offset; - m_pushConstantSize = std::max(m_pushConstantSize, size); + m_pushConstantsSize = std::max(m_pushConstantsSize, size); } } } - const std::vector<VertexAttachment> &ShaderProgram::getVertexAttachments() const + const VertexAttachments &ShaderProgram::getVertexAttachments() const { return m_VertexAttachments; } @@ -361,8 +367,8 @@ namespace vkcv { return m_DescriptorSets; } - size_t ShaderProgram::getPushConstantSize() const + size_t ShaderProgram::getPushConstantsSize() const { - return m_pushConstantSize; + return m_pushConstantsSize; } } diff --git a/src/vkcv/Surface.cpp b/src/vkcv/Surface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fa601b7bed751b1eb70538a0e2cf10c0b7b50f7 --- /dev/null +++ b/src/vkcv/Surface.cpp @@ -0,0 +1,258 @@ + +#include <vkcv/Surface.hpp> +#include <vkcv/Logger.hpp> + +#include <GLFW/glfw3.h> + +namespace vkcv { + + /** + * @brief Creates vulkan surface and checks availability. + * + * @param[in,out] window Current window for the surface + * @param[in,out] instance Vulkan-Instance + * @param[in,out] physicalDevice Vulkan-PhysicalDevice + * @param[out] surface Vulkan-Surface + * @return Created vulkan surface + */ + bool createVulkanSurface(GLFWwindow* window, + const vk::Instance& instance, + const vk::PhysicalDevice& physicalDevice, + vk::SurfaceKHR& surface) { + VkSurfaceKHR api_surface; + + if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &api_surface) != VK_SUCCESS) { + vkcv_log(LogLevel::ERROR, "Failed to create a window surface"); + return false; + } + + vk::Bool32 surfaceSupport = false; + surface = vk::SurfaceKHR(api_surface); + + if ((physicalDevice.getSurfaceSupportKHR(0, surface, &surfaceSupport) != vk::Result::eSuccess) || + (!surfaceSupport)) { + vkcv_log(LogLevel::ERROR, "Surface is not supported by the device"); + instance.destroy(surface); + surface = nullptr; + return false; + } + + return true; + } + + /** + * @brief Chooses an Extent and clamps values to the available capabilities. + * + * @param physicalDevice Vulkan-PhysicalDevice + * @param surface Vulkan-Surface of the swapchain + * @param window Window of the current application + * @return Chosen Extent for the surface + */ + vk::Extent2D chooseExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window) { + int fb_width, fb_height; + window.getFramebufferSize(fb_width, fb_height); + + VkExtent2D extent2D = { + static_cast<uint32_t>(fb_width), + static_cast<uint32_t>(fb_height) + }; + + vk::SurfaceCapabilitiesKHR surfaceCapabilities; + if(physicalDevice.getSurfaceCapabilitiesKHR(surface, &surfaceCapabilities) != vk::Result::eSuccess) { + vkcv_log(LogLevel::WARNING, "The capabilities of the surface can not be retrieved"); + + extent2D.width = std::max(MIN_SURFACE_SIZE, extent2D.width); + extent2D.height = std::max(MIN_SURFACE_SIZE, extent2D.height); + } else { + extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width)); + extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height)); + } + + return extent2D; + } + + /** + * @brief Chooses Surface Format for the current surface + * + * @param physicalDevice Vulkan-PhysicalDevice + * @param surface Vulkan-Surface of the swapchain + * @return Available Format + */ + vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { + std::vector<vk::SurfaceFormatKHR> availableFormats = physicalDevice.getSurfaceFormatsKHR(surface); + + for (const auto& availableFormat : availableFormats) { + if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { + return availableFormat; + } + } + + return availableFormats[0]; + } + + /** + * @brief Returns vk::PresentModeKHR::eMailbox if available or + * vk::PresentModeKHR::eFifo otherwise + * + * @param physicalDevice Vulkan-PhysicalDevice + * @param surface Vulkan-Surface of the swapchain + * @return Available PresentationMode + */ + vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { + std::vector<vk::PresentModeKHR> availablePresentModes = physicalDevice.getSurfacePresentModesKHR(surface); + + for (const auto& availablePresentMode : availablePresentModes) { + if (availablePresentMode == vk::PresentModeKHR::eMailbox) { + return availablePresentMode; + } + } + // The FIFO present mode is guaranteed by the spec to be supported + return vk::PresentModeKHR::eFifo; + } + + /** + * @brief Returns the minImageCount +1 for at least double buffering, + * if it's greater than maxImageCount return maxImageCount + * + * @param physicalDevice Vulkan-PhysicalDevice + * @param surface Vulkan-Surface of the swapchain + * @return Available image count + */ + uint32_t chooseImageCount(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { + vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface); + + // minImageCount should always be at least 2; set to 3 for triple buffering + uint32_t imageCount = surfaceCapabilities.minImageCount + 1; + + // check if requested image count is supported + if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) { + imageCount = surfaceCapabilities.maxImageCount; + } + + return imageCount; + } + + Surface::Surface(const Context &context, + const vk::SurfaceKHR &handle, + uint32_t presentQueueIndex, + const vk::Extent2D &extent, + vk::Format format, + vk::ColorSpaceKHR colorSpace) + : m_Context(&context), + m_Handle(handle), + m_PresentQueueIndex(presentQueueIndex), + m_Extent(extent), + m_Format(format), + m_ColorSpace(colorSpace) { + } + + vk::SwapchainKHR Surface::createVulkanSwapchain(const Window &window, + const vk::SwapchainKHR &oldSwapchain) { + if ((!m_Context) || (!m_Handle)) + return nullptr; + + const vk::PhysicalDevice& physicalDevice = m_Context->getPhysicalDevice(); + const vk::Device& device = m_Context->getDevice(); + + m_Extent = chooseExtent(physicalDevice, m_Handle, window); + + if ((m_Extent.width < MIN_SURFACE_SIZE) || (m_Extent.height < MIN_SURFACE_SIZE)) { + return nullptr; + } + + vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, m_Handle); + vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, m_Handle); + uint32_t chosenImageCount = chooseImageCount(physicalDevice, m_Handle); + + m_Format = chosenSurfaceFormat.format; + m_ColorSpace = chosenSurfaceFormat.colorSpace; + + vk::SwapchainCreateInfoKHR swapchainCreateInfo ( + vk::SwapchainCreateFlagsKHR(), + m_Handle, + chosenImageCount, + m_Format, + m_ColorSpace, + m_Extent, + 1, + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage, + vk::SharingMode::eExclusive, + 0, + nullptr, + vk::SurfaceTransformFlagBitsKHR::eIdentity, + vk::CompositeAlphaFlagBitsKHR::eOpaque, + chosenPresentMode, + true, + oldSwapchain + ); + + return device.createSwapchainKHR(swapchainCreateInfo); + } + + Surface::Surface(Surface &&other) noexcept + : m_Context(other.m_Context), + m_Handle(other.m_Handle), + m_PresentQueueIndex(other.m_PresentQueueIndex), + m_Extent(other.m_Extent), + m_Format(other.m_Format), + m_ColorSpace(other.m_ColorSpace) { + other.m_Context = nullptr; + other.m_Handle = nullptr; + } + + Surface &Surface::operator=(Surface &&other) noexcept { + m_Context = other.m_Context; + m_Handle = other.m_Handle; + m_PresentQueueIndex = other.m_PresentQueueIndex; + m_Extent = other.m_Extent; + m_Format = other.m_Format; + m_ColorSpace = other.m_ColorSpace; + + other.m_Context = nullptr; + other.m_Handle = nullptr; + return *this; + } + + Surface::~Surface() { + // needs to be destroyed by creator + } + + Surface Surface::create(const Window &window, const Context &context) { + const vk::Instance& instance = context.getInstance(); + const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice(); + + uint32_t presentQueueIndex = 0; + + vk::SurfaceKHR surfaceHandle; + if (!createVulkanSurface(window.getWindow(), instance, physicalDevice, surfaceHandle)) + surfaceHandle = nullptr; + else + presentQueueIndex = QueueManager::checkSurfaceSupport(physicalDevice, surfaceHandle); + + const vk::Extent2D extent = chooseExtent(physicalDevice, surfaceHandle, window); + const vk::SurfaceFormatKHR format = chooseSurfaceFormat(physicalDevice, surfaceHandle); + + return { context, surfaceHandle, presentQueueIndex, extent, format.format, format.colorSpace }; + } + + vk::SurfaceKHR Surface::getSurface() const { + return m_Handle; + } + + uint32_t Surface::getPresentQueueIndex() const { + return m_PresentQueueIndex; + } + + const vk::Extent2D& Surface::getExtent() const { + return m_Extent; + } + + vk::Format Surface::getFormat() const { + return m_Format; + } + + vk::ColorSpaceKHR Surface::getColorSpace() const { + return m_ColorSpace; + } + +} diff --git a/src/vkcv/Swapchain.cpp b/src/vkcv/Swapchain.cpp index 483732927bc2cc507f0868226b65bf4d49e27048..2ca69e7d58991ee67d8e72261e1cddf65de60ed0 100644 --- a/src/vkcv/Swapchain.cpp +++ b/src/vkcv/Swapchain.cpp @@ -5,203 +5,43 @@ namespace vkcv { - /** - * creates surface and checks availability - * @param window current window for the surface - * @param instance Vulkan-Instance - * @param physicalDevice Vulkan-PhysicalDevice - * @return created surface - */ - vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice) { - //create surface - VkSurfaceKHR surface; - if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) { - throw std::runtime_error("failed to create a window surface!"); - } - vk::Bool32 surfaceSupport = false; - if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) { - throw std::runtime_error("surface is not supported by the device!"); - } - return vk::SurfaceKHR(surface); - } - - Swapchain::Swapchain(const Surface &surface, - vk::SwapchainKHR swapchain, - vk::Format format, - vk::ColorSpaceKHR colorSpace, - vk::PresentModeKHR presentMode, - uint32_t imageCount, - vk::Extent2D extent) noexcept : - m_Surface(surface), - m_Swapchain(swapchain), - m_Format(format), - m_ColorSpace(colorSpace), - m_PresentMode(presentMode), - m_ImageCount(imageCount), - m_Extent(extent), - m_RecreationRequired(false) - {} + Swapchain::Swapchain(const Context &context, + const Surface &surface, + vk::SwapchainKHR swapchain) noexcept + : m_Context(&context), + m_Surface(surface), + m_Swapchain(swapchain), + m_RecreationRequired(false) { + } Swapchain::Swapchain(const Swapchain &other) : - m_Surface(other.m_Surface), - m_Swapchain(other.m_Swapchain), - m_Format(other.m_Format), - m_ColorSpace(other.m_ColorSpace), - m_PresentMode(other.m_PresentMode), - m_ImageCount(other.m_ImageCount), - m_Extent(other.m_Extent), - m_RecreationRequired(other.m_RecreationRequired.load()) - {} + m_Context(other.m_Context), + m_Surface(other.m_Surface), + m_Swapchain(other.m_Swapchain), + m_RecreationRequired(other.m_RecreationRequired.load()) { + } const vk::SwapchainKHR& Swapchain::getSwapchain() const { return m_Swapchain; } - vk::SurfaceKHR Swapchain::getSurface() const { - return m_Surface.handle; + const Surface& Swapchain::getSurface() const { + return m_Surface; } vk::Format Swapchain::getFormat() const{ - return m_Format; + return m_Surface.getFormat(); } - /** - * chooses Extent and clapms values to the available - * @param physicalDevice Vulkan-PhysicalDevice - * @param surface of the swapchain - * @param window of the current application - * @return chosen Extent for the surface - */ - vk::Extent2D chooseExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window) { - int fb_width, fb_height; - window.getFramebufferSize(fb_width, fb_height); - - VkExtent2D extent2D = { - static_cast<uint32_t>(fb_width), - static_cast<uint32_t>(fb_height) - }; - - vk::SurfaceCapabilitiesKHR surfaceCapabilities; - if(physicalDevice.getSurfaceCapabilitiesKHR(surface, &surfaceCapabilities) != vk::Result::eSuccess) { - vkcv_log(LogLevel::WARNING, "The capabilities of the surface can not be retrieved"); - - extent2D.width = std::max(MIN_SWAPCHAIN_SIZE, extent2D.width); - extent2D.height = std::max(MIN_SWAPCHAIN_SIZE, extent2D.height); - } else { - extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width)); - extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height)); - } - - return extent2D; - } - - /** - * chooses Surface Format for the current surface - * @param physicalDevice Vulkan-PhysicalDevice - * @param surface of the swapchain - * @return available Format - */ - vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { - std::vector<vk::SurfaceFormatKHR> availableFormats = physicalDevice.getSurfaceFormatsKHR(surface); - - for (const auto& availableFormat : availableFormats) { - if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { - return availableFormat; - } - } - - return availableFormats[0]; - } - - /** - * returns vk::PresentModeKHR::eMailbox if available or vk::PresentModeKHR::eFifo otherwise - * @param physicalDevice Vulkan-PhysicalDevice - * @param surface of the swapchain - * @return available PresentationMode - */ - vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { - std::vector<vk::PresentModeKHR> availablePresentModes = physicalDevice.getSurfacePresentModesKHR(surface); - - for (const auto& availablePresentMode : availablePresentModes) { - if (availablePresentMode == vk::PresentModeKHR::eMailbox) { - return availablePresentMode; - } - } - // The FIFO present mode is guaranteed by the spec to be supported - return vk::PresentModeKHR::eFifo; - } - - /** - * returns the minImageCount +1 for at least doublebuffering, if it's greater than maxImageCount return maxImageCount - * @param physicalDevice Vulkan-PhysicalDevice - * @param surface of the swapchain - * @return available ImageCount - */ - uint32_t chooseImageCount(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { - vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface); - - // minImageCount should always be at least 2; set to 3 for triple buffering - uint32_t imageCount = surfaceCapabilities.minImageCount + 1; - - // check if requested image count is supported - if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) { - imageCount = surfaceCapabilities.maxImageCount; - } - - return imageCount; - } - /** - * creates and returns a swapchain with default specs - * @param window of the current application - * @param context that keeps instance, physicalDevice and a device. - * @return swapchain - */ Swapchain Swapchain::create(const Window &window, const Context &context) { - const vk::Instance& instance = context.getInstance(); - const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice(); - const vk::Device& device = context.getDevice(); - - Surface surface; - surface.handle = createSurface(window.getWindow(), instance, physicalDevice); - surface.formats = physicalDevice.getSurfaceFormatsKHR(surface.handle); - surface.capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.handle); - surface.presentModes = physicalDevice.getSurfacePresentModesKHR(surface.handle); - surface.presentQueueIndex = QueueManager::checkSurfaceSupport(physicalDevice, surface.handle); + Surface surface = Surface::create(window, context); - vk::Extent2D chosenExtent = chooseExtent(physicalDevice, surface.handle, window); - vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, surface.handle); - vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, surface.handle); - uint32_t chosenImageCount = chooseImageCount(physicalDevice, surface.handle); + vk::SwapchainKHR swapchain = surface.createVulkanSwapchain( + window, nullptr + ); - vk::SwapchainCreateInfoKHR swapchainCreateInfo( - vk::SwapchainCreateFlagsKHR(), //flags - surface.handle, // surface - chosenImageCount, // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard) - chosenSurfaceFormat.format, // imageFormat - chosenSurfaceFormat.colorSpace, // imageColorSpace - chosenExtent, // imageExtent - 1, // imageArrayLayers TODO: should we only allow non-stereoscopic applications? yes -> 1, no -> ? "must be greater than 0, less or equal to maxImageArrayLayers" - vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage, // imageUsage TODO: what attachments? only color? depth? - vk::SharingMode::eExclusive, // imageSharingMode TODO: which sharing mode? "VK_SHARING_MODE_EXCLUSIV access exclusive to a single queue family, better performance", "VK_SHARING_MODE_CONCURRENT access from multiple queues" - 0, // queueFamilyIndexCount, the number of queue families having access to the image(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT - nullptr, // pQueueFamilyIndices, the pointer to an array of queue family indices having access to the images(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT - vk::SurfaceTransformFlagBitsKHR::eIdentity, // preTransform, transformations applied onto the image before display - vk::CompositeAlphaFlagBitsKHR::eOpaque, // compositeAlpha, TODO: how to handle transparent pixels? do we need transparency? If no -> opaque - chosenPresentMode, // presentMode - true, // clipped - nullptr // oldSwapchain - ); - - vk::SwapchainKHR swapchain = device.createSwapchainKHR(swapchainCreateInfo); - - return Swapchain(surface, - swapchain, - chosenSurfaceFormat.format, - chosenSurfaceFormat.colorSpace, - chosenPresentMode, - chosenImageCount, - chosenExtent); + return { context, surface, swapchain }; } bool Swapchain::shouldUpdateSwapchain() const { @@ -214,40 +54,18 @@ namespace vkcv } vk::SwapchainKHR oldSwapchain = m_Swapchain; - vk::Extent2D extent2D = chooseExtent(context.getPhysicalDevice(), m_Surface.handle, window); - if ((extent2D.width >= MIN_SWAPCHAIN_SIZE) && (extent2D.height >= MIN_SWAPCHAIN_SIZE)) { - vk::SwapchainCreateInfoKHR swapchainCreateInfo( - vk::SwapchainCreateFlagsKHR(), - m_Surface.handle, - m_ImageCount, - m_Format, - m_ColorSpace, - extent2D, - 1, - vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage, - vk::SharingMode::eExclusive, - 0, - nullptr, - vk::SurfaceTransformFlagBitsKHR::eIdentity, - vk::CompositeAlphaFlagBitsKHR::eOpaque, - m_PresentMode, - true, - oldSwapchain - ); - - m_Swapchain = context.getDevice().createSwapchainKHR(swapchainCreateInfo); - } else { - m_Swapchain = nullptr; - + m_Swapchain = m_Surface.createVulkanSwapchain( + window, oldSwapchain + ); + + if (!m_Swapchain) { signalSwapchainRecreation(); } if (oldSwapchain) { context.getDevice().destroySwapchainKHR(oldSwapchain); } - - m_Extent = extent2D; } void Swapchain::signalSwapchainRecreation() { @@ -255,7 +73,7 @@ namespace vkcv } const vk::Extent2D& Swapchain::getExtent() const { - return m_Extent; + return m_Surface.getExtent(); } Swapchain::~Swapchain() { @@ -263,10 +81,16 @@ namespace vkcv } uint32_t Swapchain::getImageCount() const { - return m_ImageCount; + uint32_t imageCount = 0; + + if (vk::Result::eSuccess != m_Context->getDevice().getSwapchainImagesKHR(m_Swapchain, &imageCount, nullptr)) + return 0; + else + return imageCount; } - const uint32_t &Swapchain::getPresentQueueIndex() const { - return m_Surface.presentQueueIndex; + uint32_t Swapchain::getPresentQueueIndex() const { + return m_Surface.getPresentQueueIndex(); } + } diff --git a/src/vkcv/SwapchainManager.cpp b/src/vkcv/SwapchainManager.cpp index 0caea9fd0fe47b4f51a53adac9134fb7f81a205a..369e077aabc7a5a80bc4dd668d9c6eea1277e66f 100644 --- a/src/vkcv/SwapchainManager.cpp +++ b/src/vkcv/SwapchainManager.cpp @@ -40,9 +40,9 @@ namespace vkcv { swapchain.m_Swapchain = nullptr; } - if (swapchain.m_Surface.handle) { - m_context->getInstance().destroySurfaceKHR(swapchain.m_Surface.handle); - swapchain.m_Surface.handle = nullptr; + if (swapchain.m_Surface.m_Handle) { + m_context->getInstance().destroySurfaceKHR(swapchain.m_Surface.m_Handle); + swapchain.m_Surface.m_Handle = nullptr; } } diff --git a/src/vkcv/SwapchainManager.hpp b/src/vkcv/SwapchainManager.hpp index 58478ef09af1734bef7df217550d43af74fd8424..285641db25f98d1e3dd8d8ed1375fa27e7db5708 100644 --- a/src/vkcv/SwapchainManager.hpp +++ b/src/vkcv/SwapchainManager.hpp @@ -8,8 +8,13 @@ #include "vkcv/Handles.hpp" namespace vkcv { + class Core; - + + /** + * @brief Class to manage the creation, destruction and + * allocation of swapchains. + */ class SwapchainManager { friend class Core; @@ -20,11 +25,18 @@ namespace vkcv { Context *m_context; + /** + * destroys a specific swapchain by a given id + * @param id of the swapchain to be destroyed + */ void destroySwapchainById(uint64_t id); public: SwapchainManager() noexcept; + /** + * destroys every swapchain + */ ~SwapchainManager() noexcept; SwapchainManager(SwapchainManager &&other) = delete; @@ -69,4 +81,5 @@ namespace vkcv { */ std::vector<vk::ImageView> createSwapchainImageViews(SwapchainHandle& handle); }; + } \ No newline at end of file diff --git a/src/vkcv/SyncResources.cpp b/src/vkcv/SyncResources.cpp index 9c27fe32452e0ae648565020d92891764ececb3f..8bd53c85e8cdede55d5b1db71d44bf483e24acb1 100644 --- a/src/vkcv/SyncResources.cpp +++ b/src/vkcv/SyncResources.cpp @@ -26,7 +26,7 @@ namespace vkcv { return device.createFence(fenceInfo, nullptr, {}); } - void waitForFence(const vk::Device& device, const vk::Fence fence) { + void waitForFence(const vk::Device& device, const vk::Fence& fence) { const auto result = device.waitForFences(fence, true, UINT64_MAX); assert(result == vk::Result::eSuccess); } diff --git a/src/vkcv/VertexLayout.cpp b/src/vkcv/VertexLayout.cpp index 0edced571502bbaf0e89ff6d45d338ca38b229ca..73e3885bf8f97854712d5b202123c7f7202042d1 100644 --- a/src/vkcv/VertexLayout.cpp +++ b/src/vkcv/VertexLayout.cpp @@ -6,6 +6,7 @@ #include "vkcv/Logger.hpp" namespace vkcv { + uint32_t getFormatSize(VertexAttachmentFormat format) { switch (format) { case VertexAttachmentFormat::FLOAT: @@ -29,34 +30,18 @@ namespace vkcv { return 0; } } + + VertexBinding createVertexBinding(uint32_t bindingLocation, const VertexAttachments &attachments) { + VertexBinding binding { bindingLocation, 0, attachments }; + uint32_t offset = 0; + + for (auto& attachment : binding.vertexAttachments) { + attachment.offset = offset; + offset += getFormatSize(attachment.format); + } + + binding.stride = offset; + return binding; + } - VertexAttachment::VertexAttachment(uint32_t inputLocation, const std::string &name, VertexAttachmentFormat format) noexcept: - inputLocation{inputLocation}, - name{name}, - format{format}, - offset{0} - {} - - - VertexBinding::VertexBinding(uint32_t bindingLocation, const std::vector<VertexAttachment> &attachments) noexcept : - bindingLocation{bindingLocation}, - stride{0}, - vertexAttachments{attachments} - { - uint32_t offset = 0; - for (auto &attachment : vertexAttachments) - { - attachment.offset = offset; - offset += getFormatSize(attachment.format); - } - stride = offset; - } - - VertexLayout::VertexLayout() noexcept : - vertexBindings{} - {} - - VertexLayout::VertexLayout(const std::vector<VertexBinding> &bindings) noexcept : - vertexBindings{bindings} - {} } \ No newline at end of file diff --git a/src/vkcv/WindowManager.hpp b/src/vkcv/WindowManager.hpp index 66186c494c38a5af46ffe34cc31b2e86bbbc95db..81658c241174c62359457c04e143accf07253edb 100644 --- a/src/vkcv/WindowManager.hpp +++ b/src/vkcv/WindowManager.hpp @@ -9,21 +9,35 @@ #include "SwapchainManager.hpp" namespace vkcv { + class Context; class SwapchainManager; + /** + * @brief Class to manage the windows of applications. + */ class WindowManager { friend class Core; private: + /** + * vector of all managed windows + */ std::vector<Window*> m_windows; + /** + * destroys a specific window by a given id + * @param id of the window to be destroyed + */ void destroyWindowById(uint64_t id); public: WindowManager() noexcept; + /** + * destroys every window + */ ~WindowManager() noexcept; WindowManager(WindowManager &&other) = delete; @@ -55,4 +69,5 @@ namespace vkcv { Window &getWindow(const WindowHandle handle) const; }; + } \ No newline at end of file