diff --git a/Doxyfile b/Doxyfile index 706626db3e7d7710f4f6c9f1c6354e1dee087d32..a7c5c76bb52fe4a0cd4b2f982abff642af011f8f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -874,8 +874,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = src \ - include \ +INPUT = include \ modules # This tag can be used to specify the character encoding of the source files diff --git a/config/Sources.cmake b/config/Sources.cmake index f0fd0ed758ee8b7f4d8ce0940babf0e1142e6b60..db4b200fa99597af4f96432e35e80af387ae881a 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -15,23 +15,31 @@ set(vkcv_sources ${vkcv_include}/vkcv/File.hpp ${vkcv_source}/vkcv/File.cpp + + ${vkcv_include}/vkcv/Pass.hpp + ${vkcv_source}/vkcv/Pass.cpp ${vkcv_include}/vkcv/PassConfig.hpp + ${vkcv_source}/vkcv/PassConfig.cpp ${vkcv_source}/vkcv/PassManager.hpp ${vkcv_source}/vkcv/PassManager.cpp ${vkcv_include}/vkcv/Handles.hpp ${vkcv_source}/vkcv/Handles.cpp + + ${vkcv_source}/vkcv/HandleManager.hpp ${vkcv_include}/vkcv/Window.hpp ${vkcv_source}/vkcv/Window.cpp - + + ${vkcv_include}/vkcv/BufferTypes.hpp ${vkcv_include}/vkcv/Buffer.hpp ${vkcv_include}/vkcv/PushConstants.hpp + ${vkcv_source}/vkcv/PushConstants.cpp - ${vkcv_include}/vkcv/BufferManager.hpp + ${vkcv_source}/vkcv/BufferManager.hpp ${vkcv_source}/vkcv/BufferManager.cpp ${vkcv_include}/vkcv/Image.hpp @@ -40,13 +48,10 @@ set(vkcv_sources ${vkcv_source}/vkcv/ImageManager.hpp ${vkcv_source}/vkcv/ImageManager.cpp - ${vkcv_include}/vkcv/Logger.hpp + ${vkcv_include}/vkcv/PipelineConfig.hpp + ${vkcv_source}/vkcv/PipelineConfig.cpp - ${vkcv_include}/vkcv/Surface.hpp - ${vkcv_source}/vkcv/Surface.cpp - - ${vkcv_include}/vkcv/Swapchain.hpp - ${vkcv_source}/vkcv/Swapchain.cpp + ${vkcv_include}/vkcv/Logger.hpp ${vkcv_include}/vkcv/ShaderStage.hpp @@ -54,6 +59,8 @@ set(vkcv_sources ${vkcv_source}/vkcv/ShaderProgram.cpp ${vkcv_include}/vkcv/GraphicsPipelineConfig.hpp + ${vkcv_source}/vkcv/GraphicsPipelineConfig.cpp + ${vkcv_include}/vkcv/ComputePipelineConfig.hpp ${vkcv_source}/vkcv/ComputePipelineManager.hpp @@ -61,30 +68,35 @@ set(vkcv_sources ${vkcv_source}/vkcv/GraphicsPipelineManager.hpp ${vkcv_source}/vkcv/GraphicsPipelineManager.cpp - - ${vkcv_include}/vkcv/CommandResources.hpp - ${vkcv_source}/vkcv/CommandResources.cpp - - ${vkcv_include}/vkcv/SyncResources.hpp - ${vkcv_source}/vkcv/SyncResources.cpp ${vkcv_include}/vkcv/QueueManager.hpp ${vkcv_source}/vkcv/QueueManager.cpp ${vkcv_include}/vkcv/VertexLayout.hpp ${vkcv_source}/vkcv/VertexLayout.cpp + + ${vkcv_include}/vkcv/DispatchSize.hpp + ${vkcv_source}/vkcv/DispatchSize.cpp ${vkcv_include}/vkcv/Event.hpp + + ${vkcv_include}/vkcv/TypeGuard.hpp + ${vkcv_source}/vkcv/TypeGuard.cpp + + ${vkcv_include}/vkcv/DescriptorTypes.hpp - ${vkcv_source}/vkcv/DescriptorManager.hpp - ${vkcv_source}/vkcv/DescriptorManager.cpp - - ${vkcv_include}/vkcv/DescriptorConfig.hpp - ${vkcv_source}/vkcv/DescriptorConfig.cpp + ${vkcv_include}/vkcv/DescriptorBinding.hpp + ${vkcv_source}/vkcv/DescriptorBinding.cpp ${vkcv_include}/vkcv/DescriptorWrites.hpp ${vkcv_source}/vkcv/DescriptorWrites.cpp + ${vkcv_source}/vkcv/DescriptorSetLayoutManager.hpp + ${vkcv_source}/vkcv/DescriptorSetLayoutManager.cpp + + ${vkcv_source}/vkcv/DescriptorSetManager.hpp + ${vkcv_source}/vkcv/DescriptorSetManager.cpp + ${vkcv_source}/vkcv/SamplerManager.hpp ${vkcv_source}/vkcv/SamplerManager.cpp @@ -94,18 +106,13 @@ set(vkcv_sources ${vkcv_source}/vkcv/SwapchainManager.hpp ${vkcv_source}/vkcv/SwapchainManager.cpp - ${vkcv_include}/vkcv/DescriptorWrites.hpp - - ${vkcv_include}/vkcv/DrawcallRecording.hpp - ${vkcv_source}/vkcv/DrawcallRecording.cpp - ${vkcv_source}/vkcv/CommandStreamManager.hpp ${vkcv_source}/vkcv/CommandStreamManager.cpp - ${vkcv_include}/vkcv/CommandRecordingFunctionTypes.hpp + ${vkcv_include}/vkcv/EventFunctionTypes.hpp - ${vkcv_include}/vkcv/ImageConfig.hpp - ${vkcv_source}/vkcv/ImageConfig.cpp + ${vkcv_include}/vkcv/Multisampling.hpp + ${vkcv_source}/vkcv/Multisampling.cpp ${vkcv_include}/vkcv/Downsampler.hpp ${vkcv_source}/vkcv/Downsampler.cpp @@ -113,7 +120,19 @@ set(vkcv_sources ${vkcv_include}/vkcv/BlitDownsampler.hpp ${vkcv_source}/vkcv/BlitDownsampler.cpp + ${vkcv_include}/vkcv/SamplerTypes.hpp + ${vkcv_include}/vkcv/Sampler.hpp + ${vkcv_source}/vkcv/Sampler.cpp + + ${vkcv_include}/vkcv/DescriptorSetUsage.hpp + ${vkcv_source}/vkcv/DescriptorSetUsage.cpp + + ${vkcv_include}/vkcv/Drawcall.hpp + ${vkcv_source}/vkcv/Drawcall.cpp + + ${vkcv_include}/vkcv/VertexData.hpp + ${vkcv_source}/vkcv/VertexData.cpp ${vkcv_include}/vkcv/Result.hpp ) diff --git a/include/vkcv/Buffer.hpp b/include/vkcv/Buffer.hpp index 40821e68569397fce497426b66991fc38bb29859..5a4afb060c8ae9048fbd2edb65c6d8167976f810 100644 --- a/include/vkcv/Buffer.hpp +++ b/include/vkcv/Buffer.hpp @@ -7,8 +7,9 @@ #include <vector> +#include "BufferTypes.hpp" +#include "Core.hpp" #include "Handles.hpp" -#include "BufferManager.hpp" namespace vkcv { @@ -19,10 +20,18 @@ namespace vkcv { */ template<typename T> class Buffer { - friend class Core; public: - // explicit destruction of default constructor - Buffer() = delete; + Buffer() : m_core(nullptr), m_handle() {} + + Buffer(Core* core, const BufferHandle& handle) : m_core(core), m_handle(handle) {} + + Buffer(const Buffer& other) = default; + Buffer(Buffer&& other) noexcept = default; + + ~Buffer() = default; + + Buffer& operator=(const Buffer& other) = default; + Buffer& operator=(Buffer&& other) noexcept = default; /** * @brief Returns the buffers handle. @@ -41,9 +50,14 @@ namespace vkcv { */ [[nodiscard]] BufferType getType() const { - return m_type; + return m_core->getBufferType(m_handle); }; + [[nodiscard]] + BufferMemoryType getMemoryType() const { + return m_core->getBufferMemoryType(m_handle); + } + /** * @brief Returns the count of elements in the buffer. * @@ -51,7 +65,7 @@ namespace vkcv { */ [[nodiscard]] size_t getCount() const { - return m_count; + return m_core->getBufferSize(m_handle) / sizeof(T); } /** @@ -61,7 +75,7 @@ namespace vkcv { */ [[nodiscard]] size_t getSize() const { - return m_count * sizeof(T); + return m_core->getBufferSize(m_handle); } /** @@ -71,7 +85,7 @@ namespace vkcv { */ [[nodiscard]] vk::Buffer getVulkanHandle() const { - return m_manager->getBuffer(m_handle); + return m_core->getBuffer(m_handle); } /** @@ -84,7 +98,7 @@ namespace vkcv { 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)); + m_core->fillBuffer(m_handle, data, count * sizeof(T), offset * sizeof(T)); } /** @@ -108,7 +122,7 @@ namespace vkcv { void read(T* data, size_t count = 0, size_t offset = 0) { - m_manager->readBuffer(m_handle, data, count * sizeof(T), offset * sizeof(T)); + m_core->readBuffer(m_handle, data, count * sizeof(T), offset * sizeof(T)); } /** @@ -132,77 +146,29 @@ namespace vkcv { [[nodiscard]] 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))); + return reinterpret_cast<T*>(m_core->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); + m_core->unmapBuffer(m_handle); } private: - BufferManager* const m_manager; - const BufferHandle m_handle; - const BufferType m_type; - const size_t m_count; - const BufferMemoryType m_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), - m_count(count), - 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, - bool readable) { - return Buffer<T>( - manager, - manager->createBuffer( - type, - count * sizeof(T), - memoryType, - supportIndirect, - readable - ), - type, - count, - memoryType - ); - } + Core* m_core; + BufferHandle m_handle; }; + + template<typename T> + Buffer<T> buffer(Core& core, + BufferType type, + size_t count, + BufferMemoryType memoryType = BufferMemoryType::DEVICE_LOCAL, + bool readable = false) { + return Buffer<T>(&core, core.createBuffer(type, typeGuard<T>(), count, memoryType, readable)); + } + } diff --git a/include/vkcv/BufferTypes.hpp b/include/vkcv/BufferTypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8d2938af50efd1b57ddd131837cc2e1198edab4f --- /dev/null +++ b/include/vkcv/BufferTypes.hpp @@ -0,0 +1,34 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/BufferTypes.hpp + * @brief Enum classes to specify attributes of buffers. + */ + +namespace vkcv { + + /** + * @brief Enum class to specify types of buffers. + */ + enum class BufferType { + INDEX, + VERTEX, + UNIFORM, + STORAGE, + STAGING, + INDIRECT, + + UNKNOWN + }; + + /** + * @brief Enum class to specify types of buffer memory. + */ + enum class BufferMemoryType { + DEVICE_LOCAL, + HOST_VISIBLE, + + UNKNOWN + }; + +} diff --git a/include/vkcv/CommandResources.hpp b/include/vkcv/CommandResources.hpp deleted file mode 100644 index 8ec868c0a5a353cba2efb2313d4168450f30844b..0000000000000000000000000000000000000000 --- a/include/vkcv/CommandResources.hpp +++ /dev/null @@ -1,113 +0,0 @@ -#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; - }; - - /** - * @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); - - /** - * @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/ComputePipelineConfig.hpp b/include/vkcv/ComputePipelineConfig.hpp index ab458aa53704ccc1d5dbe2f1024d826b0b337f78..82f3eedf54bb80f11576a2aafcc7ba3b244e61ce 100644 --- a/include/vkcv/ComputePipelineConfig.hpp +++ b/include/vkcv/ComputePipelineConfig.hpp @@ -5,19 +5,15 @@ * @brief Compute pipeline config struct to hand over required information to pipeline creation. */ -#include <vector> - -#include "Handles.hpp" -#include "ShaderProgram.hpp" +#include "PipelineConfig.hpp" namespace vkcv { /** - * @brief Structure to configure a compute pipeline before its creation. + * @brief Class to configure a compute pipeline before its creation. */ - struct ComputePipelineConfig { - ShaderProgram& m_ShaderProgram; - std::vector<DescriptorSetLayoutHandle> m_DescriptorSetLayouts; - }; + class ComputePipelineConfig : public PipelineConfig { + using PipelineConfig::PipelineConfig; + }; } \ No newline at end of file diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp index d91855a54c83f17b8251aad7c6fe2cb2591f9add..5bdd354dcecd6375054537bdb4b4fc127b98d02e 100644 --- a/include/vkcv/Context.hpp +++ b/include/vkcv/Context.hpp @@ -8,8 +8,8 @@ #include <vulkan/vulkan.hpp> #include <vk_mem_alloc.hpp> +#include "Handles.hpp" #include "QueueManager.hpp" -#include "DrawcallRecording.hpp" #include "Features.hpp" namespace vkcv diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index be7cb6097acf2aa163c6e1ec8218a793caa6bd73..2f158b4bd4a1e73d0933145a76686db2c6bca659 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -9,25 +9,22 @@ #include <memory> #include <vulkan/vulkan.hpp> +#include "BufferTypes.hpp" #include "Context.hpp" -#include "Swapchain.hpp" #include "Window.hpp" #include "PassConfig.hpp" #include "Handles.hpp" -#include "Buffer.hpp" -#include "Image.hpp" #include "BlitDownsampler.hpp" #include "GraphicsPipelineConfig.hpp" #include "ComputePipelineConfig.hpp" -#include "CommandResources.hpp" -#include "SyncResources.hpp" #include "Result.hpp" -#include "vkcv/DescriptorConfig.hpp" -#include "Sampler.hpp" +#include "SamplerTypes.hpp" #include "DescriptorWrites.hpp" #include "Event.hpp" -#include "DrawcallRecording.hpp" -#include "CommandRecordingFunctionTypes.hpp" +#include "Drawcall.hpp" +#include "PushConstants.hpp" +#include "EventFunctionTypes.hpp" +#include "DispatchSize.hpp" #define VKCV_FRAMEWORK_NAME "VkCV" #define VKCV_FRAMEWORK_VERSION (VK_MAKE_VERSION(0, 1, 0)) @@ -39,7 +36,8 @@ namespace vkcv class PassManager; class GraphicsPipelineManager; class ComputePipelineManager; - class DescriptorManager; + class DescriptorSetLayoutManager; + class DescriptorSetManager; class BufferManager; class SamplerManager; class ImageManager; @@ -47,23 +45,13 @@ 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 - { + class Core final { private: /** @@ -71,7 +59,8 @@ namespace vkcv * * @param context encapsulates various Vulkan objects */ - Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept; + explicit Core(Context &&context) noexcept; + // explicit destruction of default constructor Core() = delete; @@ -79,20 +68,22 @@ namespace vkcv Context m_Context; - std::unique_ptr<PassManager> m_PassManager; - std::unique_ptr<GraphicsPipelineManager> m_PipelineManager; - std::unique_ptr<ComputePipelineManager> m_ComputePipelineManager; - std::unique_ptr<DescriptorManager> m_DescriptorManager; - std::unique_ptr<BufferManager> m_BufferManager; - std::unique_ptr<SamplerManager> m_SamplerManager; - std::unique_ptr<ImageManager> m_ImageManager; - std::unique_ptr<CommandStreamManager> m_CommandStreamManager; - std::unique_ptr<WindowManager> m_WindowManager; - std::unique_ptr<SwapchainManager> m_SwapchainManager; - - CommandResources m_CommandResources; - SyncResources m_SyncResources; - uint32_t m_currentSwapchainImageIndex; + std::unique_ptr<PassManager> m_PassManager; + std::unique_ptr<GraphicsPipelineManager> m_GraphicsPipelineManager; + std::unique_ptr<ComputePipelineManager> m_ComputePipelineManager; + std::unique_ptr<DescriptorSetLayoutManager> m_DescriptorSetLayoutManager; + std::unique_ptr<DescriptorSetManager> m_DescriptorSetManager; + std::unique_ptr<BufferManager> m_BufferManager; + std::unique_ptr<SamplerManager> m_SamplerManager; + std::unique_ptr<ImageManager> m_ImageManager; + std::unique_ptr<CommandStreamManager> m_CommandStreamManager; + std::unique_ptr<WindowManager> m_WindowManager; + std::unique_ptr<SwapchainManager> m_SwapchainManager; + + std::vector<vk::CommandPool> m_CommandPools; + vk::Semaphore m_RenderFinished; + vk::Semaphore m_SwapchainImageAcquired; + uint32_t m_currentSwapchainImageIndex; std::unique_ptr<Downsampler> m_downsampler; @@ -192,43 +183,147 @@ namespace vkcv * 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[in] config a render pass config object from the render pass config class * @return A handle to represent the created pass */ [[nodiscard]] PassHandle createPass(const PassConfig &config); - - /** - * Creates a #Buffer with data-type T and @p bufferType - * @param type Type of Buffer created - * @param count Count of elements of type T - * @param memoryType Type of Buffers memory - * return Buffer-Object - */ - template<typename T> - Buffer<T> createBuffer(vkcv::BufferType type, - size_t count, - BufferMemoryType memoryType = BufferMemoryType::DEVICE_LOCAL, - bool supportIndirect = false, - bool readable = false) { - return Buffer<T>::create( - m_BufferManager.get(), - type, - count, - memoryType, - supportIndirect, - readable - ); - } + + /** + * Returns the used configuration for a created render pass which is + * represented by the given handle. + * + * @param[in] pass Pass handle + * @return Pass configuration + */ + [[nodiscard]] + const PassConfig& getPassConfiguration(const PassHandle &pass); + + /** + * @brief Creates a buffer with given parameters and returns its handle. + * + * @param[in] type Type of buffer created + * @param[in] typeGuard Type guard for the buffer + * @param[in] count Count of elements of its guarded type + * @param[in] memoryType Type of buffers memory + * @param[in] readable Flag whether the buffer supports reading from it + * @return A handle to represent the created buffer + */ + BufferHandle createBuffer(BufferType type, + const TypeGuard& typeGuard, + size_t count, + BufferMemoryType memoryType = BufferMemoryType::DEVICE_LOCAL, + bool readable = false); + + /** + * @brief Creates a buffer with given parameters and returns its handle. + * + * @param[in] type Type of buffer created + * @param[in] size Size of the buffer + * @param[in] memoryType Type of buffers memory + * @param[in] readable Flag whether the buffer supports reading from it + * @return A handle to represent the created buffer + */ + BufferHandle createBuffer(BufferType type, + size_t size, + BufferMemoryType memoryType = BufferMemoryType::DEVICE_LOCAL, + bool readable = false); + + /** + * @brief Returns the vulkan buffer of a given buffer handle. + * + * @param[in] buffer Buffer handle + * @return Vulkan buffer + */ + vk::Buffer getBuffer(const BufferHandle& buffer) const; + + /** + * @brief Returns the buffer type of a buffer represented + * by a given buffer handle. + * + * @param[in] buffer Buffer handle + * @return Buffer type + */ + [[nodiscard]] + BufferType getBufferType(const BufferHandle& buffer) const; + + /** + * @brief Returns the buffer memory type of a buffer + * represented by a given buffer handle. + * + * @param[in] buffer Buffer handle + * @return Buffer memory type + */ + [[nodiscard]] + BufferMemoryType getBufferMemoryType(const BufferHandle& buffer) const; + + /** + * @brief Returns the size of a buffer represented + * by a given buffer handle. + * + * @param[in] buffer Buffer handle + * @return Size of the buffer + */ + [[nodiscard]] + size_t getBufferSize(const BufferHandle& buffer) const; + + /** + * @brief Fills a buffer represented by a given buffer + * handle with custom data. + * + * @param[in] buffer 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& buffer, + const void* data, + size_t size, + size_t offset); + + /** + * @brief Reads from a buffer represented by a given + * buffer handle to some data pointer. + * + * @param[in] buffer Buffer handle + * @param[in] data Pointer to data + * @param[in] size Size of data to read in bytes + * @param[in] offset Offset to read from buffer in bytes + */ + void readBuffer(const BufferHandle& buffer, + void* data, + size_t size, + size_t offset); + + /** + * @brief Maps memory to a buffer represented by a given + * buffer handle and returns it. + * + * @param[in] buffer 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& buffer, + size_t offset, + size_t size); + + /** + * @brief Unmaps memory from a buffer represented by a given + * buffer handle. + * + * @param[in] buffer Buffer handle + */ + void unmapBuffer(const BufferHandle& buffer); /** * Creates a Sampler with given attributes. * - * @param magFilter Magnifying filter - * @param minFilter Minimizing filter - * @param mipmapMode Mipmapping filter - * @param addressMode Address mode - * @param mipLodBias Mip level of detail bias + * @param[in] magFilter Magnifying filter + * @param[in] minFilter Minimizing filter + * @param[in] mipmapMode Mipmapping filter + * @param[in] addressMode Address mode + * @param[in] mipLodBias Mip level of detail bias * @return Sampler handle */ [[nodiscard]] @@ -237,24 +332,49 @@ namespace vkcv float mipLodBias = 0.0f, SamplerBorderColor borderColor = SamplerBorderColor::INT_ZERO_OPAQUE); /** - * Creates an #Image with a given format, width, height and depth. + * Creates an #Image with a given format, width, height, depth + * and a lot more optional parameters. * - * @param format Image format - * @param width Image width - * @param height Image height - * @param depth Image depth - * @return Image-Object + * @param[in] format Image format + * @param[in] width Image width + * @param[in] height Image height + * @param[in] depth Image depth + * @param[in] createMipChain Flag to create a mip chain + * @param[in] supportStorage Flag whether support storage + * @param[in] supportColorAttachment Flag whether attachment is supported + * @param[in] multisampling Multisampling + * @return Image handle */ [[nodiscard]] - Image createImage( - vk::Format format, - uint32_t width, - uint32_t height, - uint32_t depth = 1, - bool createMipChain = false, - bool supportStorage = false, - bool supportColorAttachment = false, - Multisampling multisampling = Multisampling::None); + ImageHandle createImage(vk::Format format, + uint32_t width, + uint32_t height, + uint32_t depth=1, + bool createMipChain=false, + bool supportStorage=false, + bool supportColorAttachment=false, + Multisampling multisampling=Multisampling::None); + + /** + * @brief Fills the image with given data of a specified size + * in bytes. + * + * @param[in] image Image handle + * @param[in] data Image data pointer + * @param[in] size Size of data + */ + void fillImage(const ImageHandle& image, + const void *data, + size_t size); + + /** + * @brief Switches the images layout synchronously if possible. + * + * @param[in] image Image handle + * @param[in] layout New image layout + */ + void switchImageLayout(const ImageHandle &image, + vk::ImageLayout layout); /** * @brief Returns the default blit-downsampler. @@ -266,10 +386,10 @@ namespace vkcv /** * Creates a new window and returns it's handle - * @param applicationName window name - * @param windowWidth - * @param windowHeight - * @param resizeable resizeability bool + * @param[in] applicationName Window title + * @param[in] windowWidth Window width + * @param[in] windowHeight Window height + * @param[in] resizeable resizeability bool * @return windowHandle */ [[nodiscard]] @@ -281,39 +401,45 @@ namespace vkcv /** * Getter for window reference - * @param handle of the window + * @param[in] handle of the window * @return the window */ [[nodiscard]] - Window& getWindow(const WindowHandle& handle ); - + Window& getWindow(const WindowHandle& handle); + /** - * Gets the swapchain of the current focused window - * @return swapchain - */ + * @brief Returns the image format for the current surface + * of the swapchain. + * + * @param[in] handle Swapchain handle + * @return Swapchain image format + */ [[nodiscard]] - Swapchain& getSwapchainOfCurrentWindow(); - + vk::Format getSwapchainFormat(const SwapchainHandle& swapchain) const; + /** - * Returns the swapchain reference - * @param handle of the swapchain - * @return swapchain - */ + * @brief Returns the amount of images for the swapchain. + * + * @param[in] handle Swapchain handle + * @return Number of images + */ [[nodiscard]] - Swapchain& getSwapchain(const SwapchainHandle &handle); - + uint32_t getSwapchainImageCount(const SwapchainHandle& swapchain) const; + /** - * Gets the swapchain handle from the window - * @param handle of the window - * @return the swapchain from getSwapchain( SwapchainHandle ) - */ + * @brief Returns the extent from the current surface of + * the swapchain. + * + * @param[in] handle Swapchain handle + * @return Extent of the swapchains surface + */ [[nodiscard]] - Swapchain& getSwapchain(const WindowHandle &handle); + vk::Extent2D getSwapchainExtent(const SwapchainHandle& swapchain) const; /** * @brief Returns the image width. * - * @param image Image handle + * @param[in] image Image handle * @return imageWidth */ [[nodiscard]] @@ -381,14 +507,6 @@ namespace vkcv */ [[nodiscard]] DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); - - /** - * @brief Returns the descriptor set layout of a descriptor set layout handle. - * - * @param[in] handle Descriptor set layout handle - * @return Descriptor set layout - */ - DescriptorSetLayout getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const; /** * @brief Creates a new descriptor set @@ -408,14 +526,6 @@ namespace vkcv */ 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 @@ -426,7 +536,6 @@ namespace vkcv * @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 @@ -434,60 +543,48 @@ namespace vkcv * @param windowHandle Window handle that is used to retrieve the corresponding swapchain */ void recordDrawcallsToCmdStream( - const CommandStreamHandle& cmdStreamHandle, - const PassHandle& renderpassHandle, - const GraphicsPipelineHandle &pipelineHandle, - const PushConstants &pushConstants, - const std::vector<DrawcallInfo> &drawcalls, - const std::vector<ImageHandle> &renderTargets, - const WindowHandle &windowHandle); + const CommandStreamHandle &cmdStreamHandle, + const GraphicsPipelineHandle &pipelineHandle, + const PushConstants &pushConstants, + const std::vector<InstanceDrawcall> &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 drawcalls Information about each drawcall, consisting of mesh handle, descriptor set bindings and draw 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( + void recordIndirectDrawcallsToCmdStream( const CommandStreamHandle cmdStreamHandle, - const PassHandle renderpassHandle, const GraphicsPipelineHandle &pipelineHandle, const PushConstants &pushConstantData, - const vkcv::DescriptorSetHandle &compiledDescriptorSet, - const vkcv::Mesh &compiledMesh, + const std::vector<IndirectDrawcall> &drawcalls, const std::vector<ImageHandle> &renderTargets, - 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 drawcalls Information about each drawcall, consisting of descriptor set bindings and task shader task 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, + const CommandStreamHandle &cmdStreamHandle, const GraphicsPipelineHandle &pipelineHandle, - const PushConstants& pushConstantData, - const std::vector<MeshShaderDrawcall>& drawcalls, - const std::vector<ImageHandle>& renderTargets, - const WindowHandle& windowHandle); + const PushConstants &pushConstantData, + const std::vector<TaskDrawcall> &drawcalls, + const std::vector<ImageHandle> &renderTargets, + const WindowHandle &windowHandle); /** * Records the rtx ray generation to the @p cmdStreamHandle. @@ -514,23 +611,22 @@ namespace vkcv vk::StridedDeviceAddressRegionKHR rcallRegion, const std::vector<DescriptorSetUsage>& descriptorSetUsages, const PushConstants& pushConstants, - const WindowHandle windowHandle); + 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 dispatchSize How many work groups are dispatched + * @param descriptorSetUsages Descriptor set usages of the dispatch * @param pushConstants Push constant data for the dispatch */ - void recordComputeDispatchToCmdStream( - CommandStreamHandle cmdStream, - ComputePipelineHandle computePipeline, - const uint32_t dispatchCount[3], - const std::vector<DescriptorSetUsage> &descriptorSetUsages, - const PushConstants& pushConstants); + void recordComputeDispatchToCmdStream(const CommandStreamHandle& cmdStream, + const ComputePipelineHandle& computePipeline, + const DispatchSize& dispatchSize, + const std::vector<DescriptorSetUsage> &descriptorSetUsages, + const PushConstants& pushConstants); /** * @brief Record the start of a debug label into a command stream. @@ -573,20 +669,6 @@ namespace vkcv */ void endFrame( const WindowHandle& windowHandle ); - /** - * Submit a command buffer to any queue of selected type. The recording can be customized by a - * custom record-command-function. If the command submission has finished, an optional finish-function - * will be called. - * - * @param submitInfo Submit information - * @param record Record-command-function - * @param finish Finish-command-function or nullptr - */ - void recordAndSubmitCommandsImmediate( - const SubmitInfo &submitInfo, - const RecordCommandFunction &record, - const FinishCommandFunction &finish); - /** * @brief Create a new command stream * @@ -603,7 +685,7 @@ namespace vkcv * @param finish Finish function, called after execution of commands is finished */ void recordCommandsToStream( - const CommandStreamHandle cmdStreamHandle, + const CommandStreamHandle &stream, const RecordCommandFunction &record, const FinishCommandFunction &finish); @@ -613,7 +695,7 @@ namespace vkcv * @param[in] handle Command stream to submit * @param[in] signalRendering Flag to specify if the command stream finishes rendering */ - void submitCommandStream(const CommandStreamHandle& handle, + void submitCommandStream(const CommandStreamHandle& stream, bool signalRendering = true); /** @@ -728,66 +810,185 @@ namespace vkcv /** * @brief Sets a debug label to a buffer handle. * - * @param handle Buffer handle - * @param label Debug label + * @param[in,out] handle Buffer handle + * @param[in] 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 + * @param[in,out] handle Pass handle + * @param[in] 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 + * @param[in,out] handle Graphics pipeline handle + * @param[in] 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 + * @param[in,out] handle Compute pipeline handle + * @param[in] 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 + * @param[in,out] handle Descriptor set handle + * @param[in] 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 + * @param[in,out] handle Sampler handle + * @param[in] 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 + * @param[in,out] handle Image handle + * @param[in] 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 + * @param[in,out] handle Command stream handle + * @param[in] label Debug label */ void setDebugLabel(const CommandStreamHandle &handle, const std::string &label); + /** + * @brief Runs the application in the current until all windows get closed. + * + * The frame callback will be called for each window every single frame. + * + * @param[in] frame Frame callback + */ + void run(const WindowFrameFunction &frame); + + /** + * @brief Return the underlying vulkan handle for a render pass + * by its given pass handle. + * + * @param[in] handle Pass handle + * @return Vulkan render pass + */ + [[nodiscard]] + vk::RenderPass getVulkanRenderPass(const PassHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a pipeline + * by its given graphics pipeline handle. + * + * @param[in] handle Graphics pipeline handle + * @return Vulkan pipeline + */ + [[nodiscard]] + vk::Pipeline getVulkanPipeline(const GraphicsPipelineHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a pipeline + * by its given compute pipeline handle. + * + * @param[in] handle Compute pipeline handle + * @return Vulkan pipeline + */ + [[nodiscard]] + vk::Pipeline getVulkanPipeline(const ComputePipelineHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a descriptor set layout + * by its given descriptor set layout handle. + * + * @param[in] handle Descriptor set layout handle + * @return Vulkan descriptor set layout + */ + [[nodiscard]] + vk::DescriptorSetLayout getVulkanDescriptorSetLayout(const DescriptorSetLayoutHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a descriptor set + * by its given descriptor set handle. + * + * @param[in] handle Descriptor set handle + * @return Vulkan descriptor set + */ + [[nodiscard]] + vk::DescriptorSet getVulkanDescriptorSet(const DescriptorSetHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a buffer + * by its given buffer handle. + * + * @param[in] handle Buffer handle + * @return Vulkan buffer + */ + [[nodiscard]] + vk::Buffer getVulkanBuffer(const BufferHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a sampler + * by its given sampler handle. + * + * @param[in] handle Sampler handle + * @return Vulkan sampler + */ + [[nodiscard]] + vk::Sampler getVulkanSampler(const SamplerHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a image + * by its given image handle. + * + * @param[in] handle Image handle + * @return Vulkan image + */ + [[nodiscard]] + vk::Image getVulkanImage(const ImageHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a image view + * by its given image handle. + * + * @param[in] handle Image handle + * @return Vulkan image view + */ + [[nodiscard]] + vk::ImageView getVulkanImageView(const ImageHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a device memory + * by its given buffer handle. + * + * @param[in] handle Buffer handle + * @return Vulkan device memory + */ + [[nodiscard]] + vk::DeviceMemory getVulkanDeviceMemory(const BufferHandle &handle) const; + + /** + * @brief Return the underlying vulkan handle for a device memory + * by its given image handle. + * + * @param[in] handle Image handle + * @return Vulkan device memory + */ + [[nodiscard]] + vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle &handle) const; + }; } diff --git a/include/vkcv/DescriptorBinding.hpp b/include/vkcv/DescriptorBinding.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c0a8a670779bd8342995f9287770b857f3373bc8 --- /dev/null +++ b/include/vkcv/DescriptorBinding.hpp @@ -0,0 +1,31 @@ +#pragma once +/** + * @authors Artur Wasmut, Tobias Frisch, Simeon Hermann, Alexander Gauggel, Vanessa Karolek + * @file vkcv/DescriptorConfig.hpp + * @brief Structures to handle descriptor bindings. + */ + +#include <unordered_map> + +#include "DescriptorTypes.hpp" +#include "ShaderStage.hpp" + +namespace vkcv { + + /** + * @brief Structure to store details from a descriptor binding. + */ + struct DescriptorBinding { + uint32_t bindingID; + DescriptorType descriptorType; + uint32_t descriptorCount; + ShaderStages shaderStages; + bool variableCount; + bool partialBinding; + + bool operator ==(const DescriptorBinding &other) const; + }; + + typedef std::unordered_map<uint32_t, DescriptorBinding> DescriptorBindings; + +} diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp deleted file mode 100644 index 8e4f3df2fad31f2a358f5f6b7f5ba4e0c14bd6e0..0000000000000000000000000000000000000000 --- a/include/vkcv/DescriptorConfig.hpp +++ /dev/null @@ -1,96 +0,0 @@ -#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 "Handles.hpp" -#include "ShaderStage.hpp" -#include "Logger.hpp" - -namespace vkcv -{ - - /** - * @brief Enum class to specify the type of a descriptor set binding. - */ - enum class DescriptorType { - UNIFORM_BUFFER, - STORAGE_BUFFER, - SAMPLER, - IMAGE_SAMPLED, - IMAGE_STORAGE, - UNIFORM_BUFFER_DYNAMIC, - STORAGE_BUFFER_DYNAMIC, - ACCELERATION_STRUCTURE_KHR - }; - - /** - * @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) - { - case DescriptorType::UNIFORM_BUFFER: - return vk::DescriptorType::eUniformBuffer; - case DescriptorType::UNIFORM_BUFFER_DYNAMIC: - return vk::DescriptorType::eUniformBufferDynamic; - case DescriptorType::STORAGE_BUFFER: - return vk::DescriptorType::eStorageBuffer; - case DescriptorType::STORAGE_BUFFER_DYNAMIC: - return vk::DescriptorType::eStorageBufferDynamic; - case DescriptorType::SAMPLER: - return vk::DescriptorType::eSampler; - case DescriptorType::IMAGE_SAMPLED: - return vk::DescriptorType::eSampledImage; - case DescriptorType::IMAGE_STORAGE: - return vk::DescriptorType::eStorageImage; - case DescriptorType::ACCELERATION_STRUCTURE_KHR: - return vk::DescriptorType::eAccelerationStructureKHR; - default: - return vk::DescriptorType::eMutableVALVE; - } - } - - /** - * @brief Structure to store details from a descriptor binding. - */ - struct DescriptorBinding { - uint32_t bindingID; - DescriptorType descriptorType; - uint32_t descriptorCount; - ShaderStages shaderStages; - bool variableCount; - bool partialBinding; - - bool operator ==(const DescriptorBinding &other) const; - }; - - typedef std::unordered_map<uint32_t, DescriptorBinding> DescriptorBindings; - - /** - * @brief Structure to store details about a descriptor set layout. - */ - struct DescriptorSetLayout { - vk::DescriptorSetLayout vulkanHandle; - DescriptorBindings descriptorBindings; - size_t layoutUsageCount; - }; - - /** - * @brief Structure to store details about a descriptor set. - */ - struct DescriptorSet { - vk::DescriptorSet vulkanHandle; - DescriptorSetLayoutHandle setLayoutHandle; - size_t poolIndex; - }; - -} diff --git a/include/vkcv/DescriptorSetUsage.hpp b/include/vkcv/DescriptorSetUsage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8bbf2c9625ae029665b20890a7978be867a81152 --- /dev/null +++ b/include/vkcv/DescriptorSetUsage.hpp @@ -0,0 +1,27 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/DescriptorUsage.hpp + * @brief Structures to handle descriptor usages. + */ + +#include <vector> + +#include "Handles.hpp" + +namespace vkcv { + + /** + * @brief Structure to configure a descriptor set usage. + */ + struct DescriptorSetUsage { + uint32_t location; + DescriptorSetHandle descriptorSet; + std::vector<uint32_t> dynamicOffsets; + }; + + DescriptorSetUsage useDescriptorSet(uint32_t location, + const DescriptorSetHandle &descriptorSet, + const std::vector<uint32_t> &dynamicOffsets = {}); + +} diff --git a/include/vkcv/DescriptorTypes.hpp b/include/vkcv/DescriptorTypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..eaa739d6d33359b7306254677e323fb1827ca5f0 --- /dev/null +++ b/include/vkcv/DescriptorTypes.hpp @@ -0,0 +1,57 @@ +#pragma once +/** + * @authors Artur Wasmut, Tobias Frisch, Simeon Hermann, Alexander Gauggel, Vanessa Karolek + * @file vkcv/DescriptorConfig.hpp + * @brief Enum classes to handle descriptor types. + */ + +#include <vulkan/vulkan.hpp> + +namespace vkcv { + + /** + * @brief Enum class to specify the type of a descriptor set binding. + */ + enum class DescriptorType { + UNIFORM_BUFFER, + STORAGE_BUFFER, + SAMPLER, + IMAGE_SAMPLED, + IMAGE_STORAGE, + UNIFORM_BUFFER_DYNAMIC, + STORAGE_BUFFER_DYNAMIC, + ACCELERATION_STRUCTURE_KHR + }; + + /** + * @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) + { + case DescriptorType::UNIFORM_BUFFER: + return vk::DescriptorType::eUniformBuffer; + case DescriptorType::UNIFORM_BUFFER_DYNAMIC: + return vk::DescriptorType::eUniformBufferDynamic; + case DescriptorType::STORAGE_BUFFER: + return vk::DescriptorType::eStorageBuffer; + case DescriptorType::STORAGE_BUFFER_DYNAMIC: + return vk::DescriptorType::eStorageBufferDynamic; + case DescriptorType::SAMPLER: + return vk::DescriptorType::eSampler; + case DescriptorType::IMAGE_SAMPLED: + return vk::DescriptorType::eSampledImage; + case DescriptorType::IMAGE_STORAGE: + return vk::DescriptorType::eStorageImage; + case DescriptorType::ACCELERATION_STRUCTURE_KHR: + return vk::DescriptorType::eAccelerationStructureKHR; + default: + return vk::DescriptorType::eMutableVALVE; + } + } + +} diff --git a/include/vkcv/DescriptorWrites.hpp b/include/vkcv/DescriptorWrites.hpp index eb532119fabe394202a410b9a166b0d190dabbf3..869b1061af8f8da217978f962fd68d41ba289cad 100644 --- a/include/vkcv/DescriptorWrites.hpp +++ b/include/vkcv/DescriptorWrites.hpp @@ -6,6 +6,7 @@ */ #include <vector> +#include <vulkan/vulkan.hpp> #include "Handles.hpp" @@ -60,6 +61,7 @@ namespace vkcv { */ struct AccelerationDescriptorWrite { uint32_t binding; + std::vector<vk::AccelerationStructureKHR> structures; }; /** @@ -162,9 +164,11 @@ namespace vkcv { * of a descriptor set. * * @param[in] binding Binding index + * @param[in] structures Acceleration structures * @return Instance of descriptor writes */ - DescriptorWrites& writeAcceleration(uint32_t binding); + DescriptorWrites& writeAcceleration(uint32_t binding, + const std::vector<vk::AccelerationStructureKHR> &structures); /** * @brief Returns the list of stored write entries for sampled images. diff --git a/include/vkcv/DispatchSize.hpp b/include/vkcv/DispatchSize.hpp new file mode 100644 index 0000000000000000000000000000000000000000..39f1195046dc2d7c47c9994f5beb34b732ffd218 --- /dev/null +++ b/include/vkcv/DispatchSize.hpp @@ -0,0 +1,115 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/DispatchSize.hpp + * @brief Class to handle dispatch sizes. + */ + +#include <array> +#include <vulkan/vulkan.hpp> + +namespace vkcv { + + /** + * @brief Class representing a dispatch size to invoke a compute pipeline with. + */ + class DispatchSize final { + private: + std::array<uint32_t, 3> m_Dispatch; + + public: + /** + * Implicit constructor to convert an unsigned integer to a + * one dimensional dispatch size. + * + * @param[in] count Count of invocations + */ + DispatchSize(uint32_t count); + + /** + * Explicit constructor to create a dispatch size with two or + * three dimensions setting each value specifically. + * + * @param[in] dimensionX Size of X dimension + * @param[in] dimentionY Size of Y dimension + * @param[in] dimensionZ Size of Z dimension (optional) + */ + DispatchSize(uint32_t dimensionX, uint32_t dimentionY, uint32_t dimensionZ = 1); + + DispatchSize(const DispatchSize& other) = default; + DispatchSize(DispatchSize&& other) = default; + + ~DispatchSize() = default; + + DispatchSize& operator=(const DispatchSize& other) = default; + DispatchSize& operator=(DispatchSize&& other) = default; + + /** + * Returns the raw data of the dispatch size as readonly unsigned + * integer pointer. + * + * @return Pointer to data + */ + [[nodiscard]] + const uint32_t* data() const; + + /** + * Returns the size value of the dispatch size by a given index. + * + * @param[in] index Size index + * @return Size value by index + */ + [[nodiscard]] + uint32_t operator[](size_t index) const; + + /** + * Returns the value for the X dimension of the dispatch size. + * + * @return Size of X dimension + */ + [[nodiscard]] + uint32_t x() const; + + /** + * Returns the value for the Y dimension of the dispatch size. + * + * @return Size of Y dimension + */ + [[nodiscard]] + uint32_t y() const; + + /** + * Returns the value for the Z dimension of the dispatch size. + * + * @return Size of Z dimension + */ + [[nodiscard]] + uint32_t z() const; + + /** + * Checks whether the dispatch size is valid for compute shader + * invocations and returns the result as boolean value. + * + * @return True if the dispatch size is valid, otherwise false. + */ + bool check() const; + + }; + + /** + * Returns the proper dispatch size by dividing a global amount of invocations + * as three dimensional dispatch size into invocations of a fixed group size + * for the used work groups of the compute shader. + * + * This function will generate over fitted results to make sure all global + * invocations get computed. So make sure the used compute shader handles those + * additional invocations out of bounds from the original global invocations. + * + * @param[in] globalInvocations Size of planned global invocations + * @param[in] groupSize Size of work group in compute stage + * @return Dispatch size respecting the actual work group size + */ + [[nodiscard]] + DispatchSize dispatchInvocations(DispatchSize globalInvocations, DispatchSize groupSize); + +} diff --git a/include/vkcv/Drawcall.hpp b/include/vkcv/Drawcall.hpp new file mode 100644 index 0000000000000000000000000000000000000000..50ba78d223faaaafee51b9a0a0af0650babfa341 --- /dev/null +++ b/include/vkcv/Drawcall.hpp @@ -0,0 +1,103 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Drawcall.hpp + * @brief Classes to define different drawcalls. + */ + +#include <vector> + +#include "DescriptorSetUsage.hpp" +#include "Handles.hpp" +#include "VertexData.hpp" + +namespace vkcv { + + /** + * @brief Base class to store details for a general drawcall. + */ + class Drawcall { + private: + std::vector<DescriptorSetUsage> m_usages; + + public: + Drawcall() = default; + + Drawcall(const Drawcall& other) = default; + Drawcall(Drawcall&& other) noexcept = default; + + ~Drawcall() = default; + + Drawcall& operator=(const Drawcall& other) = default; + Drawcall& operator=(Drawcall&& other) noexcept = default; + + [[nodiscard]] + const std::vector<DescriptorSetUsage>& getDescriptorSetUsages() const; + + void useDescriptorSet(uint32_t location, + const DescriptorSetHandle &descriptorSet, + const std::vector<uint32_t> &dynamicOffsets = {}); + + }; + + /** + * @brief Class to store details for an instance drawcall. + */ + class InstanceDrawcall : public Drawcall { + private: + VertexData m_vertexData; + uint32_t m_instanceCount; + + public: + explicit InstanceDrawcall(const VertexData& vertexData, + uint32_t instanceCount = 1); + + [[nodiscard]] + const VertexData& getVertexData() const; + + [[nodiscard]] + uint32_t getInstanceCount() const; + + }; + + /** + * @brief Class to store details for an indirect drawcall. + */ + class IndirectDrawcall : public Drawcall { + private: + BufferHandle m_indirectDrawBuffer; + VertexData m_vertexData; + uint32_t m_drawCount; + + public: + explicit IndirectDrawcall(const BufferHandle &indirectDrawBuffer, + const VertexData& vertexData, + uint32_t drawCount = 1); + + [[nodiscard]] + BufferHandle getIndirectDrawBuffer() const; + + [[nodiscard]] + const VertexData& getVertexData() const; + + [[nodiscard]] + uint32_t getDrawCount() const; + + }; + + /** + * @brief Class to store details for a task drawcall. + */ + class TaskDrawcall : public Drawcall { + private: + uint32_t m_taskCount; + + public: + explicit TaskDrawcall(uint32_t taskCount = 1); + + [[nodiscard]] + uint32_t getTaskCount() const; + + }; + +} diff --git a/include/vkcv/DrawcallRecording.hpp b/include/vkcv/DrawcallRecording.hpp deleted file mode 100644 index 76b94dc8b4f8595d98e87920329eb616d703f0db..0000000000000000000000000000000000000000 --- a/include/vkcv/DrawcallRecording.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#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 "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 { - vk::DeviceSize offset; - vk::Buffer buffer; - }; - - /** - * @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 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), - indexCount(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; - std::vector<DescriptorSetUsage> descriptorSets; - uint32_t instanceCount; - }; - - /** - * @brief Structure to store details for a mesh shader drawcall. - */ - struct MeshShaderDrawcall { - std::vector<DescriptorSetUsage> descriptorSets; - uint32_t taskCount; - }; - - 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/CommandRecordingFunctionTypes.hpp b/include/vkcv/EventFunctionTypes.hpp similarity index 61% rename from include/vkcv/CommandRecordingFunctionTypes.hpp rename to include/vkcv/EventFunctionTypes.hpp index d8cda4216e6fbd5686240f52fa0838650ef409df..5bfb29d6570c4666c13125fab0774ed264e20cb9 100644 --- a/include/vkcv/CommandRecordingFunctionTypes.hpp +++ b/include/vkcv/EventFunctionTypes.hpp @@ -2,12 +2,13 @@ /** * @authors Alexander Gauggel, Tobias Frisch * @file vkcv/CommandRecordingFunctionTypes.hpp - * @brief Abstract function types to handle command recording. + * @brief Abstract function types to handle command recording for example. */ #include <vulkan/vulkan.hpp> #include "Event.hpp" +#include "Handles.hpp" namespace vkcv { @@ -21,4 +22,10 @@ namespace vkcv { */ typedef typename event_function<>::type FinishCommandFunction; + /** + * @brief Function to be called each frame for every open window. + */ + typedef typename event_function<const WindowHandle&, double, double, uint32_t, uint32_t>::type + WindowFrameFunction; + } \ No newline at end of file diff --git a/include/vkcv/FeatureManager.hpp b/include/vkcv/FeatureManager.hpp index e15ad7670795d4ffaf879248612bbbc5cf8cfb74..0ed0d440e144032ec69f84f12d742d82a6849b8b 100644 --- a/include/vkcv/FeatureManager.hpp +++ b/include/vkcv/FeatureManager.hpp @@ -304,6 +304,16 @@ namespace vkcv { [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceRayTracingPipelineFeaturesKHR& features, bool required) const; + /** + * @brief Checks support of the @p vk::PhysicalDeviceVulkan13Features. + * + * @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::PhysicalDeviceVulkan13Features& features, bool required) const; + /** * @brief Searches for a base structure of a given structure type. * @@ -411,7 +421,7 @@ namespace vkcv { if (!checkSupport(features, required)) { if (required) { - throw std::runtime_error("Required feature is not supported!"); + vkcv_log_throw_error("Required feature is not supported!"); } return false; diff --git a/include/vkcv/GraphicsPipelineConfig.hpp b/include/vkcv/GraphicsPipelineConfig.hpp index 85cabc135ddfa8e6e6762c16c269741e232cff4d..91e9fa75cb553ed2b98edfb363192d071ec1bd09 100644 --- a/include/vkcv/GraphicsPipelineConfig.hpp +++ b/include/vkcv/GraphicsPipelineConfig.hpp @@ -2,16 +2,15 @@ /** * @authors Mara Vogt, Mark Mints, Tobias Frisch * @file vkcv/GraphicsPipelineConfig.hpp - * @brief Graphics Pipeline Config Struct to hand over required information to Pipeline Creation + * @brief Graphics pipeline config struct to hand over required information to pipeline creation. */ #include <vector> #include <cstdint> -#include "Handles.hpp" -#include "ShaderProgram.hpp" +#include "PipelineConfig.hpp" #include "VertexLayout.hpp" -#include "ImageConfig.hpp" +#include "Multisampling.hpp" namespace vkcv { @@ -58,26 +57,104 @@ namespace vkcv { }; /** - * @brief Structure to configure a graphics pipeline before its creation. + * @brief Class to configure a graphics pipeline before its creation. */ - struct GraphicsPipelineConfig { - ShaderProgram m_ShaderProgram; - uint32_t m_Width; - uint32_t m_Height; - PassHandle m_PassHandle; - VertexLayout m_VertexLayout; - std::vector<DescriptorSetLayoutHandle> m_DescriptorLayouts; - bool m_UseDynamicViewport; - bool m_UseConservativeRasterization = false; - PrimitiveTopology m_PrimitiveTopology = PrimitiveTopology::TriangleList; - BlendMode m_blendMode = BlendMode::None; - bool m_EnableDepthClamping = false; - Multisampling m_multisampling = Multisampling::None; - CullMode m_culling = CullMode::None; - DepthTest m_depthTest = DepthTest::LessEqual; - bool m_depthWrite = true; - bool m_alphaToCoverage = false; - uint32_t m_tessellationControlPoints = 0; + class GraphicsPipelineConfig : public PipelineConfig { + private: + PassHandle m_PassHandle; + VertexLayout m_VertexLayout; + + uint32_t m_Width; + uint32_t m_Height; + + bool m_UseConservativeRasterization = false; + PrimitiveTopology m_PrimitiveTopology = PrimitiveTopology::TriangleList; + BlendMode m_blendMode = BlendMode::None; + bool m_EnableDepthClamping = false; + CullMode m_Culling = CullMode::None; + DepthTest m_DepthTest = DepthTest::LessEqual; + bool m_DepthWrite = true; + bool m_AlphaToCoverage = false; + uint32_t m_TessellationControlPoints = 0; + + public: + GraphicsPipelineConfig(); + + GraphicsPipelineConfig(const ShaderProgram& program, + const PassHandle& pass, + const VertexLayout& vertexLayout, + const std::vector<DescriptorSetLayoutHandle>& layouts); + + GraphicsPipelineConfig(const GraphicsPipelineConfig &other) = default; + GraphicsPipelineConfig(GraphicsPipelineConfig &&other) = default; + + ~GraphicsPipelineConfig() = default; + + GraphicsPipelineConfig& operator=(const GraphicsPipelineConfig &other) = default; + GraphicsPipelineConfig& operator=(GraphicsPipelineConfig &&other) = default; + + [[nodiscard]] + const PassHandle& getPass() const; + + [[nodiscard]] + const VertexLayout& getVertexLayout() const; + + [[nodiscard]] + uint32_t getWidth() const; + + [[nodiscard]] + uint32_t getHeight() const; + + void setResolution(uint32_t width, uint32_t height); + + [[nodiscard]] + bool isViewportDynamic() const; + + [[nodiscard]] + bool isUsingConservativeRasterization() const; + + void setUsingConservativeRasterization(bool conservativeRasterization); + + [[nodiscard]] + PrimitiveTopology getPrimitiveTopology() const; + + void setPrimitiveTopology(PrimitiveTopology primitiveTopology); + + [[nodiscard]] + BlendMode getBlendMode() const; + + void setBlendMode(BlendMode blendMode); + + [[nodiscard]] + bool isDepthClampingEnabled() const; + + void setDepthClampingEnabled(bool depthClamping); + + [[nodiscard]] + CullMode getCulling() const; + + void setCulling(CullMode cullMode); + + [[nodiscard]] + DepthTest getDepthTest() const; + + void setDepthTest(DepthTest depthTest); + + [[nodiscard]] + bool isWritingDepth() const; + + void setWritingDepth(bool writingDepth); + + [[nodiscard]] + bool isWritingAlphaToCoverage() const; + + void setWritingAlphaToCoverage(bool alphaToCoverage); + + [[nodiscard]] + uint32_t getTesselationControlPoints() const; + + void setTesselationControlPoints(uint32_t tessellationControlPoints); + }; } \ No newline at end of file diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index dea1793871a320016cf7c0da3f3877fc66a6f616..52ccb7a84a5d82bf51c3285c6536d6ce9aa0bc48 100644 --- a/include/vkcv/Handles.hpp +++ b/include/vkcv/Handles.hpp @@ -130,23 +130,23 @@ namespace vkcv private: using Handle::Handle; }; - - /** - * @brief Handle class for descriptor sets. + + /** + * @brief Handle class for descriptor set layouts. */ - class DescriptorSetHandle : public Handle { - friend class DescriptorManager; + class DescriptorSetLayoutHandle : public Handle { + friend class DescriptorSetLayoutManager; private: using Handle::Handle; }; /** - * @brief Handle class for descriptor set layouts. + * @brief Handle class for descriptor sets. */ - class DescriptorSetLayoutHandle : public Handle { - friend class DescriptorManager; + class DescriptorSetHandle : public Handle { + friend class DescriptorSetManager; private: - using Handle::Handle; + using Handle::Handle; }; /** diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 6e7b6e57950b3ccdbc341d660a223bd7885ddb1b..542658ae6aeb56b5221ca5f97504e955eaf0e478 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -7,13 +7,14 @@ #include <vulkan/vulkan.hpp> +#include "BufferTypes.hpp" +#include "Core.hpp" #include "Handles.hpp" -#include "ImageConfig.hpp" +#include "Multisampling.hpp" namespace vkcv { class Downsampler; - class ImageManager; /** * @brief Returns whether an image format is usable as depth buffer. @@ -23,6 +24,15 @@ namespace vkcv { * otherwise false. */ bool isDepthFormat(const vk::Format format); + + /** + * @brief Returns whether an image format is usable as stencil buffer. + * + * @param format Vulkan image format + * @return True, if the format is valid to use as stencil buffer, + * otherwise false. + */ + bool isStencilFormat(const vk::Format format); /** * @brief Class for image handling and filling data. @@ -30,6 +40,17 @@ namespace vkcv { class Image { friend class Core; public: + Image() : m_core(nullptr), m_handle() {}; + + Image(Core* core, const ImageHandle& handle) : m_core(core), m_handle(handle) {} + + Image(const Image& other) = default; + Image(Image&& other) = default; + + ~Image() = default; + + Image& operator=(const Image& other) = default; + Image& operator=(Image&& other) = default; /** * @brief Returns the format of the image. @@ -77,7 +98,7 @@ namespace vkcv { * @return Number of mip levels */ [[nodiscard]] - uint32_t getMipCount() const; + uint32_t getMipLevels() const; /** * @brief Switches the image layout, @@ -107,39 +128,19 @@ namespace vkcv { Downsampler &downsampler); private: - // TODO: const qualifier removed, very hacky!!! - // Else you cannot recreate an image. Pls fix. - ImageManager* m_manager; + Core* m_core; 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, - uint32_t width, - uint32_t height, - uint32_t depth, - uint32_t mipCount, - bool supportStorage, - bool supportColorAttachment, - Multisampling msaa); - }; + Image image(Core &core, + vk::Format format, + uint32_t width, + uint32_t height, + uint32_t depth=1, + bool createMipChain=false, + bool supportStorage=false, + bool supportColorAttachment=false, + Multisampling multisampling=Multisampling::None); + } diff --git a/include/vkcv/Logger.hpp b/include/vkcv/Logger.hpp index 9d4fa86f2b42e8190e7dc57c2ad897a76f945126..a1805651323f8c9200d16a6a7e999c82c3dc3c90 100644 --- a/include/vkcv/Logger.hpp +++ b/include/vkcv/Logger.hpp @@ -6,6 +6,7 @@ */ #include <cstdio> +#include <exception> namespace vkcv { @@ -113,4 +114,39 @@ namespace vkcv { #define vkcv_log(level, ...) {} #endif +/** + * @brief Macro-function to log the message of any error + * or an exception. + * + * @param[in] error Error or exception + */ +#define vkcv_log_error(error) { \ + vkcv_log(LogLevel::ERROR, "%s", (error).what()); \ +} + +/** + * @brief Macro-function to throw and log any error or + * an exception. + * + * @param[in] error Error or exception + */ +#define vkcv_log_throw(error) { \ + try { \ + throw error; \ + } catch (const std::exception& e) { \ + vkcv_log_error(e); \ + throw; \ + } \ +} + +/** + * @brief Macro-function to throw and log an error + * with its custom message. + * + * @param[in] message Error message + */ +#define vkcv_log_throw_error(message) { \ + vkcv_log_throw(std::runtime_error(message)); \ +} + } diff --git a/include/vkcv/ImageConfig.hpp b/include/vkcv/Multisampling.hpp similarity index 81% rename from include/vkcv/ImageConfig.hpp rename to include/vkcv/Multisampling.hpp index d031f790622f1f0595c540c5bbcf0d8795f5fd95..3bcf5d7b2a8dd838fcb18817a611086f33b06b68 100644 --- a/include/vkcv/ImageConfig.hpp +++ b/include/vkcv/Multisampling.hpp @@ -9,7 +9,12 @@ namespace vkcv { - enum class Multisampling { None, MSAA2X, MSAA4X, MSAA8X }; + enum class Multisampling { + None, + MSAA2X, + MSAA4X, + MSAA8X + }; /** * @brief Returns the sample count flag bits of a given @@ -18,7 +23,7 @@ namespace vkcv { * @param[in] msaa MSAA mode * @return Sample count flag bits */ - vk::SampleCountFlagBits msaaToVkSampleCountFlag(Multisampling msaa); + vk::SampleCountFlagBits msaaToSampleCountFlagBits(Multisampling msaa); /** * @brief Returns the amount of samples of a given diff --git a/include/vkcv/Pass.hpp b/include/vkcv/Pass.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f931eef50d0c78d015ef08472b5513942773edc3 --- /dev/null +++ b/include/vkcv/Pass.hpp @@ -0,0 +1,31 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Pass.hpp + * @brief Support functions for basic pass creation. + */ + +#include "Core.hpp" +#include "Handles.hpp" +#include "PassConfig.hpp" + +namespace vkcv +{ + + PassHandle passFormats(Core &core, + const std::vector<vk::Format> formats, + bool clear = true, + Multisampling multisampling = Multisampling::None); + + PassHandle passFormat(Core &core, + vk::Format format, + bool clear = true, + Multisampling multisampling = Multisampling::None); + + PassHandle passSwapchain(Core &core, + const SwapchainHandle &swapchain, + const std::vector<vk::Format> formats, + bool clear = true, + Multisampling multisampling = Multisampling::None); + +} diff --git a/include/vkcv/PassConfig.hpp b/include/vkcv/PassConfig.hpp index ad3e3c0dff150f5ba41859477d4bb5a53c4365f8..849a6e837acd6321afed6c99dc3b608ba26766b7 100644 --- a/include/vkcv/PassConfig.hpp +++ b/include/vkcv/PassConfig.hpp @@ -8,29 +8,10 @@ #include <vector> #include <vulkan/vulkan.hpp> -#include "ImageConfig.hpp" +#include "Multisampling.hpp" namespace vkcv { - - /** - * @brief Enum class to specify kinds of attachment layouts. - */ - enum class AttachmentLayout { - UNDEFINED, - GENERAL, - - COLOR_ATTACHMENT, - SHADER_READ_ONLY, - - DEPTH_STENCIL_ATTACHMENT, - DEPTH_STENCIL_READ_ONLY, - - TRANSFER_SRC, - TRANSFER_DST, - - PRESENTATION - }; /** * @brief Enum class to specify types of attachment operations. @@ -43,20 +24,82 @@ namespace vkcv }; /** - * @brief Structure to store details about an attachment of a pass. + * @brief Class to store details about an attachment of a pass. */ - struct AttachmentDescription { - AttachmentOperation store_operation; - AttachmentOperation load_operation; - vk::Format format; + class AttachmentDescription { + private: + vk::Format m_format; + + AttachmentOperation m_load_op; + AttachmentOperation m_store_op; + + vk::ClearValue m_clear_value; + public: + AttachmentDescription(vk::Format format, + AttachmentOperation load, + AttachmentOperation store); + + AttachmentDescription(vk::Format format, + AttachmentOperation load, + AttachmentOperation store, + const vk::ClearValue &clear); + + AttachmentDescription(const AttachmentDescription &other) = default; + AttachmentDescription(AttachmentDescription &&other) = default; + + ~AttachmentDescription() = default; + + AttachmentDescription& operator=(const AttachmentDescription &other) = default; + AttachmentDescription& operator=(AttachmentDescription &&other) = default; + + [[nodiscard]] + vk::Format getFormat() const; + + [[nodiscard]] + AttachmentOperation getLoadOperation() const; + + [[nodiscard]] + AttachmentOperation getStoreOperation() const; + + void setClearValue(const vk::ClearValue &clear); + + [[nodiscard]] + const vk::ClearValue& getClearValue() const; + }; + + using AttachmentDescriptions = std::vector<AttachmentDescription>; /** - * @brief Structure to configure a pass for usage. + * @brief Class to configure a pass for usage. */ - struct PassConfig { - std::vector<AttachmentDescription> attachments; - Multisampling msaa; + class PassConfig { + private: + AttachmentDescriptions m_attachments; + Multisampling m_multisampling; + + public: + PassConfig(); + + explicit PassConfig(const AttachmentDescriptions &attachments, + Multisampling multisampling = Multisampling::None); + + PassConfig(const PassConfig &other) = default; + PassConfig(PassConfig &&other) = default; + + ~PassConfig() = default; + + PassConfig& operator=(const PassConfig &other) = default; + PassConfig& operator=(PassConfig &&other) = default; + + [[nodiscard]] + const AttachmentDescriptions& getAttachments() const; + + void setMultisampling(Multisampling multisampling); + + [[nodiscard]] + Multisampling getMultisampling() const; + }; } \ No newline at end of file diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e53985f77a454891dd4d1fc69abcb2c0eb344912 --- /dev/null +++ b/include/vkcv/PipelineConfig.hpp @@ -0,0 +1,51 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/PipelineConfig.hpp + * @brief Pipeline config class to hand over required information to pipeline creation + */ + +#include <vector> + +#include "Handles.hpp" +#include "ShaderProgram.hpp" + +namespace vkcv { + + /** + * @brief Class to configure a general pipeline before its creation. + */ + class PipelineConfig { + private: + ShaderProgram m_ShaderProgram; + std::vector<DescriptorSetLayoutHandle> m_DescriptorSetLayouts; + + public: + PipelineConfig(); + + PipelineConfig(const ShaderProgram& program, + const std::vector<DescriptorSetLayoutHandle>& layouts); + + PipelineConfig(const PipelineConfig &other) = default; + PipelineConfig(PipelineConfig &&other) = default; + + ~PipelineConfig() = default; + + PipelineConfig& operator=(const PipelineConfig &other) = default; + PipelineConfig& operator=(PipelineConfig &&other) = default; + + void setShaderProgram(const ShaderProgram& program); + + [[nodiscard]] + const ShaderProgram& getShaderProgram() const; + + void addDescriptorSetLayout(const DescriptorSetLayoutHandle& layout); + + void addDescriptorSetLayouts(const std::vector<DescriptorSetLayoutHandle>& layouts); + + [[nodiscard]] + const std::vector<DescriptorSetLayoutHandle>& getDescriptorSetLayouts() const; + + }; + +} diff --git a/include/vkcv/PushConstants.hpp b/include/vkcv/PushConstants.hpp index ca826ea52e9bcee72c14c26496c99937c27fb775..8d441bfcb57807eedc94d4cf839f6e99729d1cbe 100644 --- a/include/vkcv/PushConstants.hpp +++ b/include/vkcv/PushConstants.hpp @@ -9,24 +9,21 @@ #include <vulkan/vulkan.hpp> #include "Logger.hpp" +#include "TypeGuard.hpp" namespace vkcv { /** * @brief Class to handle push constants data per drawcall. */ - class PushConstants { + class PushConstants final { private: + TypeGuard m_typeGuard; std::vector<uint8_t> m_data; - size_t m_sizePerDrawcall; public: - template<typename T> - PushConstants() : PushConstants(sizeof(T)) {} - - explicit PushConstants(size_t sizePerDrawcall) : - m_data(), - m_sizePerDrawcall(sizePerDrawcall) {} + explicit PushConstants(size_t sizePerDrawcall); + explicit PushConstants(const TypeGuard &guard); PushConstants(const PushConstants& other) = default; PushConstants(PushConstants&& other) = default; @@ -43,9 +40,7 @@ namespace vkcv { * @return Size of data per drawcall */ [[nodiscard]] - size_t getSizePerDrawcall() const { - return m_sizePerDrawcall; - } + size_t getSizePerDrawcall() const; /** * @brief Returns the size of total data stored for @@ -54,9 +49,7 @@ namespace vkcv { * @return Total size of data */ [[nodiscard]] - size_t getFullSize() const { - return m_data.size(); - } + size_t getFullSize() const; /** * @brief Returns the number of drawcalls that data @@ -65,17 +58,13 @@ namespace vkcv { * @return Number of drawcalls */ [[nodiscard]] - size_t getDrawcallCount() const { - return (m_data.size() / m_sizePerDrawcall); - } + size_t getDrawcallCount() const; /** * @brief Clears the data for all drawcalls currently. * stored. */ - void clear() { - m_data.clear(); - } + void clear(); /** * @brief Appends data for a single drawcall to the @@ -87,9 +76,7 @@ namespace vkcv { */ template<typename T = uint8_t> bool appendDrawcall(const T& value) { - if (sizeof(T) != m_sizePerDrawcall) { - vkcv_log(LogLevel::WARNING, "Size (%lu) of value does not match the specified size per drawcall (%lu)", - sizeof(value), m_sizePerDrawcall); + if (!m_typeGuard.template check<T>()) { return false; } @@ -109,7 +96,7 @@ namespace vkcv { */ template<typename T = uint8_t> T& getDrawcall(size_t index) { - const size_t offset = (index * m_sizePerDrawcall); + const size_t offset = (index * getSizePerDrawcall()); return *reinterpret_cast<T*>(m_data.data() + offset); } @@ -123,7 +110,7 @@ namespace vkcv { */ template<typename T = uint8_t> const T& getDrawcall(size_t index) const { - const size_t offset = (index * m_sizePerDrawcall); + const size_t offset = (index * getSizePerDrawcall()); return *reinterpret_cast<const T*>(m_data.data() + offset); } @@ -135,10 +122,7 @@ namespace vkcv { * @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); - } + const void* getDrawcallData(size_t index) const; /** * @brief Returns the pointer to the entire drawcall data which @@ -147,14 +131,33 @@ namespace vkcv { * @return Pointer to the data */ [[nodiscard]] - const void* getData() const { - if (m_data.empty()) { - return nullptr; - } else { - return m_data.data(); + const void* getData() const; + + }; + + template<typename T> + PushConstants pushConstants() { + return PushConstants(typeGuard<T>()); + } + + template<typename T> + PushConstants pushConstants(const T& value) { + auto pc = pushConstants<T>(); + pc.template appendDrawcall(value); + return pc; + } + + template<typename T> + PushConstants pushConstants(const std::vector<T>& values) { + auto pc = pushConstants<T>(); + + for (const T& value : values) { + if (!(pc.template appendDrawcall(value))) { + break; } } - }; + return pc; + } } diff --git a/include/vkcv/Sampler.hpp b/include/vkcv/Sampler.hpp index c65ef8218ff209e6eeaf0e45f9309e21d85e782e..601370c71bfaa3a8eaad023cae532b083d78fa90 100644 --- a/include/vkcv/Sampler.hpp +++ b/include/vkcv/Sampler.hpp @@ -2,50 +2,21 @@ /** * @authors Tobias Frisch * @file vkcv/Sampler.hpp - * @brief Enums for different sampler attributes. + * @brief Support functions for basic sampler creation. */ -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 - }; +#include "Core.hpp" +#include "SamplerTypes.hpp" +#include "Handles.hpp" - /** - * @brief Enum class to specify a samplers mode to access via address space. - */ - enum class SamplerAddressMode { - REPEAT = 1, - MIRRORED_REPEAT = 2, - CLAMP_TO_EDGE = 3, - 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, - - FLOAT_ZERO_OPAQUE = 3, - FLOAT_ZERO_TRANSPARENT = 4, - - INT_ONE_OPAQUE = 5, - FLOAT_ONE_OPAQUE = 6 - }; +namespace vkcv { + + [[nodiscard]] + SamplerHandle samplerLinear(Core &core, + bool clampToEdge = false); + + [[nodiscard]] + SamplerHandle samplerNearest(Core &core, + bool clampToEdge = false); } diff --git a/include/vkcv/SamplerTypes.hpp b/include/vkcv/SamplerTypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4dc68930050ff955a251f701657462a8b5ebbb1f --- /dev/null +++ b/include/vkcv/SamplerTypes.hpp @@ -0,0 +1,51 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/SamplerTypes.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, + CLAMP_TO_EDGE = 3, + 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, + + FLOAT_ZERO_OPAQUE = 3, + FLOAT_ZERO_TRANSPARENT = 4, + + INT_ONE_OPAQUE = 5, + FLOAT_ONE_OPAQUE = 6 + }; + +} diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp index c815834a3d7a948df3307769f34abe94cbd2ff22..0cc4fed0d87195dec3b0eae345e206724d2f4060 100644 --- a/include/vkcv/ShaderProgram.hpp +++ b/include/vkcv/ShaderProgram.hpp @@ -13,8 +13,8 @@ #include <vulkan/vulkan.hpp> #include <spirv_cross.hpp> +#include "DescriptorBinding.hpp" #include "VertexLayout.hpp" -#include "DescriptorConfig.hpp" #include "ShaderStage.hpp" namespace vkcv { diff --git a/include/vkcv/ShaderStage.hpp b/include/vkcv/ShaderStage.hpp index 39b250e80be79cbb0f39261e69ab0d80a71d4f31..d143b776c876f9a5cf6e298e485acc354fdf2b12 100644 --- a/include/vkcv/ShaderStage.hpp +++ b/include/vkcv/ShaderStage.hpp @@ -33,6 +33,9 @@ namespace vkcv { } +/** + * @cond VULKAN_TYPES + */ namespace vk { template<> @@ -58,6 +61,9 @@ namespace vk { }; } +/** + * @endcond + */ namespace vkcv { diff --git a/include/vkcv/Surface.hpp b/include/vkcv/Surface.hpp deleted file mode 100644 index 47862b9c49661f434b64f9def17037cc5bcc110c..0000000000000000000000000000000000000000 --- a/include/vkcv/Surface.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#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 deleted file mode 100644 index 9380b97ca73e46d53e7dcfbb8ba804004698b5b3..0000000000000000000000000000000000000000 --- a/include/vkcv/Swapchain.hpp +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once -/** - * @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 -{ - - /** - * @brief Class to handle swapchains using a context. - */ - class Swapchain final { - private: - friend class Core; - friend class Window; - friend class SwapchainManager; - - const Context *m_Context; - Surface m_Surface; - vk::SwapchainKHR m_Swapchain; - std::atomic<bool> m_RecreationRequired; - - /** - * @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 Context &context, - const Surface &surface, - vk::SwapchainKHR swapchain) noexcept; - - /** - * @brief Checks whether the swapchain needs to be recreated. - * - * @return True, if the swapchain should be updated, - * otherwise false. - */ - bool shouldUpdateSwapchain() const; - - /** - * @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); - - /** - * @brief Signals the swapchain to be recreated. - */ - void signalSwapchainRecreation(); - - public: - 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 - */ - [[nodiscard]] - const vk::SwapchainKHR& getSwapchain() const; - - /** - * @brief Returns the current surface of the swapchain. - * - * @return Current surface - */ - [[nodiscard]] - const Surface& getSurface() const; - - /** - * @brief Returns the image format for the current surface - * of the swapchain. - * - * @return Swapchain image format - */ - [[nodiscard]] - vk::Format getFormat() const; - - /** - * @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 thw swapchain. - */ - virtual ~Swapchain(); - - /** - * @brief Returns the amount of images for the swapchain. - * - * @return Number of images - */ - uint32_t getImageCount() const; - - /** - * @brief Returns the extent from the current surface of - * the swapchain. - * - * @return Extent of the swapchains surface - */ - [[nodiscard]] - const vk::Extent2D& getExtent() const; - - /** - * @brief Returns the present queue index to be used with - * the swapchain and its current surface. - * - * @return Present queue family index - */ - [[nodiscard]] - uint32_t getPresentQueueIndex() const; - - }; - -} diff --git a/include/vkcv/SyncResources.hpp b/include/vkcv/SyncResources.hpp deleted file mode 100644 index 1683855b6b4f9046b0af5fb2df65f3bca895da2a..0000000000000000000000000000000000000000 --- a/include/vkcv/SyncResources.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#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; - }; - - /** - * @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/TypeGuard.hpp b/include/vkcv/TypeGuard.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cac170c0105c24c2c00758423e5c723758761ac7 --- /dev/null +++ b/include/vkcv/TypeGuard.hpp @@ -0,0 +1,154 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/TypeGuard.hpp + * @brief Support type safety for classes in debug compilation. + */ + +#include <stdlib.h> +#include <typeinfo> + +namespace vkcv { + + /** + * @brief Class bringing type safety during runtime to other classes. + */ + class TypeGuard { + private: +#ifndef NDEBUG + const char* m_typeName; + size_t m_typeHash; + + [[nodiscard]] + bool checkType(const char* name, size_t hash, size_t size) const; +#endif + size_t m_typeSize; + + [[nodiscard]] + bool checkTypeSize(size_t size) const; + + public: + /** + * Explicit constructor to create a type guard by a specific + * size only. The guard will not verify an individual type but + * whether its size matches the requirement. + * + * @param[in] size Size of type + */ + explicit TypeGuard(size_t size = 0); + + /** + * Explicit constructor to create a type guard by a types + * ID information and its size. The guard will verify a type + * by all available information in debug mode. + * + * @param[in] info ID information of type + * @param[in] size Size of type + */ + TypeGuard(const std::type_info &info, size_t size); + + TypeGuard(const TypeGuard &other) = default; + TypeGuard(TypeGuard &&other) noexcept = default; + + ~TypeGuard() = default; + + TypeGuard& operator=(const TypeGuard &other) = default; + TypeGuard& operator=(TypeGuard &&other) noexcept = default; + + /** + * Operator to compare two type guards and returns + * whether their stored type information and size + * match as boolean value. + * + * @param[in] other Other type guard + * @return True if the details match, otherwise false. + */ + bool operator==(const TypeGuard &other) const; + + /** + * Operator to compare two type guards and returns + * whether their stored type information and size + * do not match as boolean value. + * + * @param[in] other Other type guard + * @return True if the details differ, otherwise false. + */ + bool operator!=(const TypeGuard &other) const; + + /** + * Checks whether a type from a template parameter + * matches with the used type by the given guard. + * + * @tparam T Type to check against + * @return True if both types match, otherwise false. + */ + template<typename T> + [[nodiscard]] + bool check() const { +#ifndef NDEBUG + return checkType(typeid(T).name(), typeid(T).hash_code(), sizeof(T)); +#else + return checkTypeSize(sizeof(T)); +#endif + } + + /** + * Returns the size of this guards type in bytes. + * + * @return Size of type + */ + [[nodiscard]] + size_t typeSize() const; + + }; + + /** + * Creates a new type guard with a given type specified + * as template parameter. + * + * @tparam T Type + * @return New type guard + */ + template<typename T> + TypeGuard typeGuard() { + static TypeGuard guard (typeid(T), sizeof(T)); + return guard; + } + + /** + * Creates a new type guard with a given type specified + * as template parameter by the passed parameter. + * + * @tparam T Type + * @return New type guard + */ + template<typename T> + TypeGuard typeGuard(T) { + return typeGuard<T>(); + } + + /** + * Creates a new type guard with a given type specified + * as template parameter by the passed parameter. + * + * @tparam T Type + * @return New type guard + */ + template<typename T> + TypeGuard typeGuard(const T&) { + return typeGuard<T>(); + } + + /** + * Creates a new type guard with a given type specified + * as template parameter by the passed parameter. + * + * @tparam T Type + * @return New type guard + */ + template<typename T> + TypeGuard typeGuard(T&&) { + return typeGuard<T>(); + } + +} diff --git a/include/vkcv/VertexData.hpp b/include/vkcv/VertexData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..001dcfcf6e96f1e356316ef56bd7810583531239 --- /dev/null +++ b/include/vkcv/VertexData.hpp @@ -0,0 +1,73 @@ +#pragma once +/** + * @authors Sebastian Gaida, Alexander Gauggel, Artur Wasmut, Tobias Frisch + * @file vkcv/VertexData.hpp + * @brief Types to configure vertex data for drawcalls. + */ + +#include <vector> + +#include "Handles.hpp" + +namespace vkcv { + + /** + * @brief Structure to store details about a vertex buffer binding. + */ + struct VertexBufferBinding { + BufferHandle buffer; + size_t offset; + }; + + VertexBufferBinding vertexBufferBinding(const BufferHandle &buffer, + size_t offset = 0); + + typedef std::vector<VertexBufferBinding> VertexBufferBindings; + + /** + * @brief Enum class to specify the size of indexes. + */ + enum class IndexBitCount { + Bit8, + Bit16, + Bit32 + }; + + class VertexData { + private: + VertexBufferBindings m_bindings; + BufferHandle m_indices; + IndexBitCount m_indexBitCount; + size_t m_count; + + public: + explicit VertexData(const VertexBufferBindings &bindings = {}); + + VertexData(const VertexData& other) = default; + VertexData(VertexData&& other) noexcept = default; + + ~VertexData() = default; + + VertexData& operator=(const VertexData& other) = default; + VertexData& operator=(VertexData&& other) noexcept = default; + + [[nodiscard]] + const VertexBufferBindings& getVertexBufferBindings() const; + + void setIndexBuffer(const BufferHandle& indices, + IndexBitCount indexBitCount = IndexBitCount::Bit16); + + [[nodiscard]] + const BufferHandle& getIndexBuffer() const; + + [[nodiscard]] + IndexBitCount getIndexBitCount() const; + + void setCount(size_t count); + + [[nodiscard]] + size_t getCount() const; + + }; + +} diff --git a/include/vkcv/VertexLayout.hpp b/include/vkcv/VertexLayout.hpp index 330be708525b3e1a90e15919abb9f3f2f2ea1729..8e677d11dc49594416f7eedda9d2ef00edae830a 100644 --- a/include/vkcv/VertexLayout.hpp +++ b/include/vkcv/VertexLayout.hpp @@ -70,11 +70,20 @@ namespace vkcv { * * @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 + * @return Vertex binding with calculated stride */ VertexBinding createVertexBinding(uint32_t bindingLocation, const VertexAttachments &attachments); typedef std::vector<VertexBinding> VertexBindings; + + /** + * Creates vertex bindings in a very simplified way with one vertex binding for + * each attachment. + * + * @param[in] attachments The vertex input attachments. + * @return Vertex bindings with calculated stride + */ + VertexBindings createVertexBindings(const VertexAttachments &attachments); /** * @brief Structure to store the details of a vertex layout. diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp index d1db4bf438b95e9c96824bb6676a1d8bf020a35f..e7a27730140c50c791cd72b94d56488732770265 100644 --- a/include/vkcv/Window.hpp +++ b/include/vkcv/Window.hpp @@ -169,7 +169,8 @@ namespace vkcv { * * @return Swapchain handle */ - SwapchainHandle getSwapchainHandle() const; + SwapchainHandle getSwapchain() const; + }; } diff --git a/modules/algorithm/include/vkcv/algorithm/SinglePassDownsampler.hpp b/modules/algorithm/include/vkcv/algorithm/SinglePassDownsampler.hpp index c2d9721d5db6791b82bcf5a7d0a832fd9ab5db77..a46ab4fc4e7ff237af52ba629455a06758e54e0f 100644 --- a/modules/algorithm/include/vkcv/algorithm/SinglePassDownsampler.hpp +++ b/modules/algorithm/include/vkcv/algorithm/SinglePassDownsampler.hpp @@ -2,6 +2,7 @@ #include <vector> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> #include <vkcv/Downsampler.hpp> #include <vkcv/ShaderProgram.hpp> diff --git a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp index 0d344861824959eb482a076d7cc118841a434765..eee9f361493c35c5214ac661448f3cc80384e4ee 100644 --- a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp +++ b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp @@ -14,6 +14,7 @@ #include "SPDIntegration.glsl.hxx" #include "SPDIntegrationLinearSampler.glsl.hxx" +#include <vkcv/ComputePipelineConfig.hpp> #include <vkcv/File.hpp> #include <vkcv/Logger.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -150,7 +151,8 @@ namespace vkcv::algorithm { m_descriptorSetLayout(), m_descriptorSets(), - m_globalCounter(m_core.createBuffer<uint32_t>( + m_globalCounter(buffer<uint32_t>( + m_core, vkcv::BufferType::STORAGE, 6 )), @@ -231,10 +233,10 @@ namespace vkcv::algorithm { ); } - m_pipeline = m_core.createComputePipeline({ + m_pipeline = m_core.createComputePipeline(ComputePipelineConfig( program, { m_descriptorSetLayout } - }); + )); std::vector<uint32_t> zeroes; zeroes.resize(m_globalCounter.getCount()); @@ -307,12 +309,16 @@ namespace vkcv::algorithm { m_core.prepareImageForStorage(cmdStream, image); } - uint32_t dispatch [3]; - dispatch[0] = dispatchThreadGroupCountXY[0]; - dispatch[1] = dispatchThreadGroupCountXY[1]; - dispatch[2] = m_core.getImageArrayLayers(image); + vkcv::DispatchSize dispatch ( + dispatchThreadGroupCountXY[0], + dispatchThreadGroupCountXY[1], + m_core.getImageArrayLayers(image) + ); - vkcv::PushConstants pushConstants (m_sampler? sizeof(SPDConstantsSampler) : sizeof(SPDConstants)); + vkcv::PushConstants pushConstants = (m_sampler? + vkcv::pushConstants<SPDConstantsSampler>() : + vkcv::pushConstants<SPDConstants>() + ); if (m_sampler) { SPDConstantsSampler data; diff --git a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp index 2362e560516fee3bf392ef150a756a25aa2420a0..d6b5cf5d5382e0e03bd7950c1e87bf3c6a8ee445 100644 --- a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp +++ b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp @@ -11,6 +11,8 @@ #include <cstdint> #include <filesystem> +#include "vkcv/VertexData.hpp" + /* LOADING MESHES * The description of meshes is a hierarchy of structures with the Mesh at the * top. @@ -279,8 +281,8 @@ struct Scene { * Note that for URIs only (local) filesystem paths are supported, no * URLs using network protocols etc. * - * @param path must be the path to a glTF- or glb-file. - * @param scene is a reference to a Scene struct that will be filled with the + * @param[in] path must be the path to a glTF- or glb-file. + * @param[out] scene is a reference to a Scene struct that will be filled with the * meta-data of all objects described in the glTF file. * @return ASSET_ERROR on failure, otherwise ASSET_SUCCESS */ @@ -295,8 +297,8 @@ int probeScene(const std::filesystem::path &path, Scene &scene); * Besides the mesh, this function will also add any associated data to the * Scene struct such as Materials and Textures required by the Mesh. * - * @param path must be the path to a glTF- or glb-file. - * @param scene is the scene struct to which the results will be written. + * @param[in,out] scene is the scene struct to which the results will be written. + * @param[in] mesh_index Index of the mesh to load * @return ASSET_ERROR on failure, otherwise ASSET_SUCCESS */ int loadMesh(Scene &scene, int mesh_index); @@ -305,8 +307,8 @@ int loadMesh(Scene &scene, int mesh_index); * Load every mesh from the glTF file, as well as materials, textures and other * associated objects. * - * @param path must be the path to a glTF- or glb-file. - * @param scene is a reference to a Scene struct that will be filled with the + * @param[in] path must be the path to a glTF- or glb-file. + * @param[out] scene is a reference to a Scene struct that will be filled with the * content of the glTF file being loaded. * @return ASSET_ERROR on failure, otherwise ASSET_SUCCESS */ @@ -322,11 +324,25 @@ int loadScene(const std::filesystem::path &path, Scene &scene); * will be cleared to all 0 with path and data being empty; make sure to always * check that !data.empty() before using the struct. * - * @param path must be the path to an image file. + * @param[in] path must be the path to an image file. * @return Texture struct describing the loaded image. */ Texture loadTexture(const std::filesystem::path& path); +/** + * Loads up the vertex attributes and creates usable vertex buffer bindings + * to match the desired order of primitive types as used in the vertex + * shader. + * + * @param[in] attributes Vertex attributes + * @param[in] buffer Buffer handle + * @param[in] types Primitive type order + * @return Vertex buffer bindings + */ +VertexBufferBindings loadVertexBufferBindings(const std::vector<VertexAttribute> &attributes, + const BufferHandle &buffer, + const std::vector<PrimitiveType> &types); + /** @} */ } // 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 110a941ff6703e989174eaf311118b10b41491d4..d8f2563d867e5521bce29a3880650f0418ad9db8 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -856,5 +856,31 @@ namespace vkcv::asset { } return texture; } + + VertexBufferBindings loadVertexBufferBindings(const std::vector<VertexAttribute> &attributes, + const BufferHandle &buffer, + const std::vector<PrimitiveType> &types) { + VertexBufferBindings bindings; + + for (const auto& type : types) { + const VertexAttribute* attribute = nullptr; + + for (const auto& attr : attributes) { + if (type == attr.type) { + attribute = &(attr); + break; + } + } + + if (!attribute) { + vkcv_log(LogLevel::ERROR, "Missing primitive type in vertex attributes"); + break; + } + + bindings.push_back(vkcv::vertexBufferBinding(buffer, attribute->offset)); + } + + return bindings; + } } diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp index c8e51fe9716af0304687d6ae60fc0bea2a5d2cc6..f31596ae80c86a432f62a50621de949961e83d56 100644 --- a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp +++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp @@ -1,8 +1,9 @@ #include "vkcv/effects/BloomAndFlaresEffect.hpp" -#include <vkcv/DrawcallRecording.hpp> #include <vkcv/PushConstants.hpp> +#include <vkcv/Image.hpp> +#include <vkcv/Sampler.hpp> #include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/asset/asset_loader.hpp> @@ -125,7 +126,8 @@ namespace vkcv::effects { const std::string &texturePath) { const auto texture = vkcv::asset::loadTexture(texturePath); - Image image = core.createImage( + auto image = vkcv::image( + core, vk::Format::eR8G8B8A8Unorm, texture.width, texture.height @@ -188,12 +190,7 @@ namespace vkcv::effects { m_blurImage(), m_flaresImage(), - m_linearSampler(m_core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE - )), + m_linearSampler(samplerLinear(m_core, true)), m_radialLutSampler(), @@ -236,13 +233,7 @@ namespace vkcv::effects { ); if (m_advanced) { - m_radialLutSampler = m_core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); - + m_radialLutSampler = samplerLinear(m_core); m_radialLut = loadTexture(m_core, "assets/RadialLUT.png"); m_lensDirt = loadTexture(m_core, "assets/lensDirt.jpg"); } @@ -293,10 +284,10 @@ namespace vkcv::effects { static const uint32_t threadGroupWorkRegionDim = 8; - uint32_t dispatch[3]; - dispatch[0] = calcDispatchSize(downsampleSizeX, threadGroupWorkRegionDim); - dispatch[1] = calcDispatchSize(downsampleSizeY, threadGroupWorkRegionDim); - dispatch[2] = 1; + DispatchSize dispatch ( + calcDispatchSize(downsampleSizeX, threadGroupWorkRegionDim), + calcDispatchSize(downsampleSizeY, threadGroupWorkRegionDim) + ); // mip blur dispatch m_core.recordComputeDispatchToCmdStream( @@ -342,10 +333,10 @@ namespace vkcv::effects { static const uint32_t threadGroupWorkRegionDim = 8; - uint32_t dispatch[3]; - dispatch[0] = calcDispatchSize(upsampleSizeX, threadGroupWorkRegionDim); - dispatch[1] = calcDispatchSize(upsampleSizeY, threadGroupWorkRegionDim); - dispatch[2] = 1; + DispatchSize dispatch ( + calcDispatchSize(upsampleSizeX, threadGroupWorkRegionDim), + calcDispatchSize(upsampleSizeY, threadGroupWorkRegionDim) + ); m_core.recordComputeDispatchToCmdStream( cmdStream, @@ -385,13 +376,13 @@ namespace vkcv::effects { mipDivisor *= 2.0f; } - static const uint32_t threadGroupWorkRegionDim = 8.0f; + static const uint32_t threadGroupWorkRegionDim = 8; // lens feature generation dispatch - uint32_t dispatch[3]; - dispatch[0] = calcDispatchSize(sampleSizeX / mipDivisor, threadGroupWorkRegionDim); - dispatch[1] = calcDispatchSize(sampleSizeY / mipDivisor, threadGroupWorkRegionDim); - dispatch[2] = 1; + DispatchSize dispatch ( + calcDispatchSize(sampleSizeX / mipDivisor, threadGroupWorkRegionDim), + calcDispatchSize(sampleSizeY / mipDivisor, threadGroupWorkRegionDim) + ); m_core.recordComputeDispatchToCmdStream( cmdStream, @@ -451,12 +442,12 @@ namespace vkcv::effects { static const uint32_t threadGroupWorkRegionDim = 8; - uint32_t dispatch[3]; - dispatch[0] = calcDispatchSize(sampleWidth, threadGroupWorkRegionDim); - dispatch[1] = calcDispatchSize(sampleHeight, threadGroupWorkRegionDim); - dispatch[2] = 1; + DispatchSize dispatch ( + calcDispatchSize(sampleWidth, threadGroupWorkRegionDim), + calcDispatchSize(sampleHeight, threadGroupWorkRegionDim) + ); - PushConstants pushConstants (sizeof(m_cameraDirection)); + PushConstants pushConstants = vkcv::pushConstants<glm::vec3>(); pushConstants.appendDrawcall(m_cameraDirection); // bloom composite dispatch @@ -494,7 +485,7 @@ namespace vkcv::effects { 1, true, true - ).getHandle(); + ); m_downsampleDescriptorSets.clear(); m_upsampleDescriptorSets.clear(); @@ -524,7 +515,7 @@ namespace vkcv::effects { 1, true, true - ).getHandle(); + ); m_flaresDescriptorSets.clear(); diff --git a/modules/gui/src/vkcv/gui/GUI.cpp b/modules/gui/src/vkcv/gui/GUI.cpp index 7ee335379603b3e21ab4d95f0738097bd954cf71..15a1b049aa5496bdcb9ecb81c00f82b66ad86d71 100644 --- a/modules/gui/src/vkcv/gui/GUI.cpp +++ b/modules/gui/src/vkcv/gui/GUI.cpp @@ -71,7 +71,8 @@ namespace vkcv::gui { m_descriptor_pool = m_context.getDevice().createDescriptorPool(descriptorPoolCreateInfo); const vk::PhysicalDevice& physicalDevice = m_context.getPhysicalDevice(); - const Swapchain& swapchain = m_core.getSwapchain(m_windowHandle); + const SwapchainHandle& swapchainHandle = m_core.getWindow(m_windowHandle).getSwapchain(); + const uint32_t swapchainImageCount = m_core.getSwapchainImageCount(swapchainHandle); const uint32_t graphicsQueueFamilyIndex = ( m_context.getQueueManager().getGraphicsQueues()[0].familyIndex @@ -86,13 +87,13 @@ namespace vkcv::gui { init_info.PipelineCache = 0; init_info.DescriptorPool = static_cast<VkDescriptorPool>(m_descriptor_pool); init_info.Allocator = nullptr; - init_info.MinImageCount = swapchain.getImageCount(); - init_info.ImageCount = swapchain.getImageCount(); + init_info.MinImageCount = swapchainImageCount; + init_info.ImageCount = swapchainImageCount; init_info.CheckVkResultFn = checkVulkanResult; const vk::AttachmentDescription attachment ( vk::AttachmentDescriptionFlags(), - swapchain.getFormat(), + m_core.getSwapchainFormat(swapchainHandle), vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eStore, @@ -144,14 +145,15 @@ namespace vkcv::gui { ImGui_ImplVulkan_Init(&init_info, static_cast<VkRenderPass>(m_render_pass)); - const SubmitInfo submitInfo { QueueType::Graphics, {}, {} }; + auto stream = m_core.createCommandStream(QueueType::Graphics); - m_core.recordAndSubmitCommandsImmediate(submitInfo, [](const vk::CommandBuffer& commandBuffer) { + m_core.recordCommandsToStream(stream, [](const vk::CommandBuffer& commandBuffer) { ImGui_ImplVulkan_CreateFontsTexture(static_cast<VkCommandBuffer>(commandBuffer)); }, []() { ImGui_ImplVulkan_DestroyFontUploadObjects(); }); + m_core.submitCommandStream(stream, false); m_context.getDevice().waitIdle(); } @@ -177,11 +179,11 @@ namespace vkcv::gui { } void GUI::beginGUI() { - const Swapchain& swapchain = m_core.getSwapchain(m_windowHandle); - const auto extent = swapchain.getExtent(); + const auto swapchainHandle = m_core.getWindow(m_windowHandle).getSwapchain(); + const auto& extent = m_core.getSwapchainExtent(swapchainHandle); if ((extent.width > 0) && (extent.height > 0)) { - ImGui_ImplVulkan_SetMinImageCount(swapchain.getImageCount()); + ImGui_ImplVulkan_SetMinImageCount(m_core.getSwapchainImageCount(swapchainHandle)); } ImGui_ImplVulkan_NewFrame(); @@ -200,8 +202,8 @@ namespace vkcv::gui { return; } - const Swapchain& swapchain = m_core.getSwapchain(m_windowHandle); - const auto extent = swapchain.getExtent(); + const auto swapchainHandle = m_core.getWindow(m_windowHandle).getSwapchain(); + const auto& extent = m_core.getSwapchainExtent(swapchainHandle); const vk::ImageView swapchainImageView = m_core.getSwapchainImageView(); @@ -216,11 +218,9 @@ namespace vkcv::gui { ); const vk::Framebuffer framebuffer = m_context.getDevice().createFramebuffer(framebufferCreateInfo); + auto stream = m_core.createCommandStream(QueueType::Graphics); - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - - m_core.recordAndSubmitCommandsImmediate(submitInfo, [&](const vk::CommandBuffer& commandBuffer) { + m_core.recordCommandsToStream(stream, [&](const vk::CommandBuffer& commandBuffer) { assert(initialImageLayout == vk::ImageLayout::eColorAttachmentOptimal); m_core.prepareImageForAttachmentManually(commandBuffer, vkcv::ImageHandle::createSwapchainImageHandle()); @@ -251,6 +251,8 @@ namespace vkcv::gui { }, [&]() { m_context.getDevice().destroyFramebuffer(framebuffer); }); + + m_core.submitCommandStream(stream, false); } } diff --git a/modules/material/src/vkcv/material/Material.cpp b/modules/material/src/vkcv/material/Material.cpp index 8c3f3099cee731d24854d314fd7e3df4506a9aec..8187b5de9205ba18ca32cd23dba9d5b457696712 100644 --- a/modules/material/src/vkcv/material/Material.cpp +++ b/modules/material/src/vkcv/material/Material.cpp @@ -1,6 +1,9 @@ #include "vkcv/material/Material.hpp" +#include <vkcv/Image.hpp> +#include <vkcv/Sampler.hpp> + namespace vkcv::material { Material::Material() { @@ -112,83 +115,58 @@ namespace vkcv::material { }; if (!colorImg) { - vkcv::Image defaultColor = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); + vkcv::Image defaultColor = image(core, vk::Format::eR8G8B8A8Srgb, 2, 2); float colorData [4] = { 228, 51, 255, 1 }; fillImage(defaultColor, colorData); images[0] = defaultColor.getHandle(); } if (!normalImg) { - vkcv::Image defaultNormal = core.createImage(vk::Format::eR8G8B8A8Unorm, 2, 2); + vkcv::Image defaultNormal = image(core, vk::Format::eR8G8B8A8Unorm, 2, 2); float normalData [4] = { 0, 0, 1, 0 }; fillImage(defaultNormal, normalData); images[1] = defaultNormal.getHandle(); } if (!metRoughImg) { - vkcv::Image defaultRough = core.createImage(vk::Format::eR8G8B8A8Unorm, 2, 2); + vkcv::Image defaultRough = image(core, vk::Format::eR8G8B8A8Unorm, 2, 2); float roughData [4] = { 228, 51, 255, 1 }; fillImage(defaultRough, roughData); images[2] = defaultRough.getHandle(); } if (!occlusionImg) { - vkcv::Image defaultOcclusion = core.createImage(vk::Format::eR8G8B8A8Unorm, 2, 2); + vkcv::Image defaultOcclusion = image(core, vk::Format::eR8G8B8A8Unorm, 2, 2); float occlusionData [4] = { 228, 51, 255, 1 }; fillImage(defaultOcclusion, occlusionData); images[3] = defaultOcclusion.getHandle(); } if (!emissiveImg) { - vkcv::Image defaultEmissive = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); + vkcv::Image defaultEmissive = image(core, vk::Format::eR8G8B8A8Srgb, 2, 2); float emissiveData [4] = { 0, 0, 0, 1 }; fillImage(defaultEmissive, emissiveData); images[4] = defaultEmissive.getHandle(); } if (!colorSmp) { - samplers[0] = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + samplers[0] = samplerLinear(core); } if (!normalSmp) { - samplers[1] = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + samplers[1] = samplerLinear(core); } if (!metRoughSmp) { - samplers[2] = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + samplers[2] = samplerLinear(core); } if (!occlusionSmp) { - samplers[3] = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + samplers[3] = samplerLinear(core); } if (!emissiveSmp) { - samplers[4] = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + samplers[4] = samplerLinear(core); } Material material; diff --git a/modules/scene/include/vkcv/scene/Mesh.hpp b/modules/scene/include/vkcv/scene/Mesh.hpp index 3118696bdc270506bc6197e7d853148072294663..65cdb3a4ac7ebe69862874411ba38aae74d87a2f 100644 --- a/modules/scene/include/vkcv/scene/Mesh.hpp +++ b/modules/scene/include/vkcv/scene/Mesh.hpp @@ -17,7 +17,7 @@ namespace 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; + typedef typename event_function<const glm::mat4&, const glm::mat4&, PushConstants&, vkcv::Drawcall&>::type RecordMeshDrawcallFunction; class Node; @@ -41,7 +41,7 @@ namespace vkcv::scene { /** * List of the meshes drawcalls to render. */ - std::vector<DrawcallInfo> m_drawcalls; + std::vector<InstanceDrawcall> m_drawcalls; /** * Local transformation matrix of the mesh. @@ -55,6 +55,7 @@ namespace vkcv::scene { /** * Constructor of a new mesh with a given scene as parent. + * * @param[in,out] scene Scene */ explicit Mesh(Scene& scene); @@ -62,14 +63,18 @@ namespace vkcv::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 + * @param[in] types Primitive type order of vertex attributes */ void load(const asset::Scene& scene, - const asset::Mesh& mesh); + const asset::Mesh& mesh, + const std::vector<asset::PrimitiveType>& types); /** * 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 @@ -77,12 +82,13 @@ namespace vkcv::scene { */ void recordDrawcalls(const glm::mat4& viewProjection, PushConstants& pushConstants, - std::vector<DrawcallInfo>& drawcalls, + std::vector<InstanceDrawcall>& drawcalls, const RecordMeshDrawcallFunction& record); /** * Return the amount of drawcalls of the mesh * as sum of all its parts. + * * @return Amount of drawcalls */ [[nodiscard]] @@ -96,18 +102,21 @@ namespace vkcv::scene { /** * Copy-constructor of a mesh. + * * @param[in] other Other mesh instance */ Mesh(const 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 */ @@ -115,6 +124,7 @@ namespace vkcv::scene { /** * Move-operator of a mesh. + * * @param[in,out] other Other mesh instance * @return Reference to this mesh instance */ @@ -122,6 +132,7 @@ namespace vkcv::scene { /** * Return the axis aligned bounding box of the mesh. + * * @return Axis aligned bounding box of this mesh */ [[nodiscard]] diff --git a/modules/scene/include/vkcv/scene/MeshPart.hpp b/modules/scene/include/vkcv/scene/MeshPart.hpp index 8d77efd7a112ea92a6c4192e5a5cf43cea53e800..61ed8fc31dc1b6d17a4d2c4ef41db59f870e5ed6 100644 --- a/modules/scene/include/vkcv/scene/MeshPart.hpp +++ b/modules/scene/include/vkcv/scene/MeshPart.hpp @@ -64,6 +64,7 @@ namespace vkcv::scene { /** * Constructor of a new mesh part with a given scene as parent. + * * @param[in,out] scene Scene */ explicit MeshPart(Scene& scene); @@ -71,13 +72,16 @@ namespace vkcv::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[in] types Primitive type order of vertex attributes * @param[out] drawcalls List of drawcalls */ void load(const asset::Scene& scene, const asset::VertexGroup& vertexGroup, - std::vector<DrawcallInfo>& drawcalls); + const std::vector<asset::PrimitiveType>& types, + std::vector<InstanceDrawcall>& drawcalls); public: /** @@ -87,18 +91,21 @@ namespace vkcv::scene { /** * Copy-constructor of a mesh part. + * * @param[in] other Other mesh part */ MeshPart(const 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 */ @@ -106,6 +113,7 @@ namespace vkcv::scene { /** * Move-operator of a mesh part. + * * @param[in,out] other Other mesh part * @return Reference to this mesh part */ @@ -114,6 +122,7 @@ namespace vkcv::scene { /** * Get the material used by this specific part of * the mesh for rendering. + * * @return Material */ [[nodiscard]] @@ -122,6 +131,7 @@ namespace vkcv::scene { /** * Return the axis aligned bounding box of this * specific part of the mesh. + * * @return Axis aligned bounding box of this mesh part */ [[nodiscard]] @@ -130,6 +140,7 @@ namespace vkcv::scene { /** * 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; @@ -137,6 +148,7 @@ namespace vkcv::scene { /** * 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 51088f2564fb56a9d63d99238cb0665c6989bc9e..484e1c12caed05051598185fa284165624a0af17 100644 --- a/modules/scene/include/vkcv/scene/Node.hpp +++ b/modules/scene/include/vkcv/scene/Node.hpp @@ -45,25 +45,32 @@ namespace vkcv::scene { /** * 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 + * @param[in] types Primitive type order of vertex attributes */ - void loadMesh(const asset::Scene& asset_scene, const asset::Mesh& asset_mesh); + void loadMesh(const asset::Scene& asset_scene, + const asset::Mesh& asset_mesh, + const std::vector<asset::PrimitiveType>& types); /** * 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 @@ -71,19 +78,21 @@ namespace vkcv::scene { */ void recordDrawcalls(const glm::mat4& viewProjection, PushConstants& pushConstants, - std::vector<DrawcallInfo>& drawcalls, + std::vector<InstanceDrawcall>& 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]] @@ -92,12 +101,14 @@ namespace vkcv::scene { /** * 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 */ @@ -105,6 +116,7 @@ namespace vkcv::scene { /** * 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 */ @@ -119,18 +131,21 @@ namespace vkcv::scene { /** * 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 */ @@ -138,6 +153,7 @@ namespace vkcv::scene { /** * Move-operator of a scene node. + * * @param[in,out] other Other scene node * @return Reference of this node */ @@ -146,6 +162,7 @@ namespace vkcv::scene { /** * Return the axis aligned bounding box of the * scene node. + * * @return Axis aligned bounding box of this node */ [[nodiscard]] diff --git a/modules/scene/include/vkcv/scene/Scene.hpp b/modules/scene/include/vkcv/scene/Scene.hpp index c482b464a8a24e83f1ba12d8294749d7b0cae48a..74c5a50fe1db7ec7ba19a0757d922580b66ca67c 100644 --- a/modules/scene/include/vkcv/scene/Scene.hpp +++ b/modules/scene/include/vkcv/scene/Scene.hpp @@ -57,6 +57,7 @@ namespace vkcv::scene { /** * Constructor of a scene instance with a given Core instance. + * * @param[in,out] core Pointer to valid Core instance */ explicit Scene(Core* core); @@ -64,12 +65,14 @@ namespace vkcv::scene { /** * 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 */ @@ -77,6 +80,7 @@ namespace vkcv::scene { /** * 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 */ @@ -85,12 +89,14 @@ namespace vkcv::scene { /** * 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); @@ -98,6 +104,7 @@ namespace vkcv::scene { /** * 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 @@ -113,18 +120,21 @@ namespace vkcv::scene { /** * Copy-constructor of a scene instance. + * * @param[in] other Other scene instance */ Scene(const Scene& other); /** * 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 */ @@ -132,6 +142,7 @@ namespace vkcv::scene { /** * Move-operator of a scene instance. + * * @param[in,out] other Other scene instance * @return Reference to this scene */ @@ -139,6 +150,7 @@ namespace vkcv::scene { /** * Return the amount of materials managed by this scene. + * * @return Amount of materials */ [[nodiscard]] @@ -147,6 +159,7 @@ namespace vkcv::scene { /** * 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 */ @@ -155,6 +168,7 @@ namespace vkcv::scene { /** * 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 @@ -175,7 +189,8 @@ namespace vkcv::scene { /** * Instantiation function to create a new scene instance. - * @param core Current Core instance + * + * @param[in,out] core Current Core instance * @return New scene instance */ static Scene create(Core& core); @@ -183,11 +198,15 @@ namespace vkcv::scene { /** * 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 + * + * @param[in,out] core Current Core instance + * @param[in] path Path of a valid file to load via asset loader + * @param[in] types Primitive type order of vertex attributes * @return New scene instance */ - static Scene load(Core& core, const std::filesystem::path &path); + static Scene load(Core& core, + const std::filesystem::path &path, + const std::vector<asset::PrimitiveType>& types); }; diff --git a/modules/scene/src/vkcv/scene/Mesh.cpp b/modules/scene/src/vkcv/scene/Mesh.cpp index af02aedbd71ba4bdfcc30aa7fdcd82796af904f1..3c6249fb556c9c2d7e08b41636718be9ef80f829 100644 --- a/modules/scene/src/vkcv/scene/Mesh.cpp +++ b/modules/scene/src/vkcv/scene/Mesh.cpp @@ -20,7 +20,9 @@ namespace vkcv::scene { return matrix; } - void Mesh::load(const asset::Scene &scene, const asset::Mesh &mesh) { + void Mesh::load(const asset::Scene &scene, + const asset::Mesh &mesh, + const std::vector<asset::PrimitiveType>& types) { m_parts.clear(); m_drawcalls.clear(); @@ -32,7 +34,7 @@ namespace vkcv::scene { } MeshPart part (m_scene); - part.load(scene, scene.vertexGroups[vertexGroupIndex], m_drawcalls); + part.load(scene, scene.vertexGroups[vertexGroupIndex], types, m_drawcalls); if (!part) { continue; @@ -67,7 +69,7 @@ namespace vkcv::scene { m_parts[i] = other.m_parts[i]; } - m_drawcalls = std::vector<DrawcallInfo>(other.m_drawcalls); + m_drawcalls = std::vector<InstanceDrawcall>(other.m_drawcalls); m_transform = other.m_transform; m_bounds = other.m_bounds; @@ -90,7 +92,7 @@ namespace vkcv::scene { void Mesh::recordDrawcalls(const glm::mat4& viewProjection, PushConstants& pushConstants, - std::vector<DrawcallInfo>& drawcalls, + std::vector<InstanceDrawcall>& drawcalls, const RecordMeshDrawcallFunction& record) { const glm::mat4 transform = viewProjection * m_transform; diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp index 50d14ed49d43496ada3853034be1455b044bd902..d7ceacff91172fce1050ffe12aa250b89fcebf6a 100644 --- a/modules/scene/src/vkcv/scene/MeshPart.cpp +++ b/modules/scene/src/vkcv/scene/MeshPart.cpp @@ -2,6 +2,8 @@ #include "vkcv/scene/MeshPart.hpp" #include "vkcv/scene/Scene.hpp" +#include <vkcv/Buffer.hpp> + namespace vkcv::scene { MeshPart::MeshPart(Scene& scene) : @@ -15,28 +17,25 @@ namespace vkcv::scene { void MeshPart::load(const asset::Scene& scene, const asset::VertexGroup &vertexGroup, - std::vector<DrawcallInfo>& drawcalls) { + const std::vector<asset::PrimitiveType>& types, + std::vector<InstanceDrawcall>& drawcalls) { Core& core = *(m_scene.m_core); - auto vertexBuffer = core.createBuffer<uint8_t>( - BufferType::VERTEX, vertexGroup.vertexBuffer.data.size() + auto vertexBuffer = buffer<uint8_t>( + core, BufferType::VERTEX, vertexGroup.vertexBuffer.data.size() ); vertexBuffer.fill(vertexGroup.vertexBuffer.data); m_vertices = vertexBuffer.getHandle(); - auto attributes = vertexGroup.vertexBuffer.attributes; - - std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); - - for (const auto& attribute : attributes) { - m_vertexBindings.emplace_back(attribute.offset, vertexBuffer.getVulkanHandle()); - } + m_vertexBindings = asset::loadVertexBufferBindings( + vertexGroup.vertexBuffer.attributes, + vertexBuffer.getHandle(), + types + ); - auto indexBuffer = core.createBuffer<uint8_t>( - BufferType::INDEX, vertexGroup.indexBuffer.data.size() + auto indexBuffer = buffer<uint8_t>( + core, BufferType::INDEX, vertexGroup.indexBuffer.data.size() ); indexBuffer.fill(vertexGroup.indexBuffer.data); @@ -86,10 +85,14 @@ namespace vkcv::scene { break; } - drawcalls.push_back(DrawcallInfo( - vkcv::Mesh(m_vertexBindings, indexBuffer.getVulkanHandle(), m_indexCount, indexBitCount), - { DescriptorSetUsage(0, material.getDescriptorSet()) } - )); + VertexData vertexData (m_vertexBindings); + vertexData.setIndexBuffer(indexBuffer.getHandle(), indexBitCount); + vertexData.setCount(m_indexCount); + + InstanceDrawcall drawcall (vertexData); + drawcall.useDescriptorSet(0, material.getDescriptorSet()); + + drawcalls.push_back(drawcall); } } diff --git a/modules/scene/src/vkcv/scene/Node.cpp b/modules/scene/src/vkcv/scene/Node.cpp index 24f62d18e160c7d80f82384829a2130737737ba9..f5234dd461537c491c0fa5580c78fbfec695a310 100644 --- a/modules/scene/src/vkcv/scene/Node.cpp +++ b/modules/scene/src/vkcv/scene/Node.cpp @@ -69,9 +69,11 @@ namespace vkcv::scene { m_meshes.push_back(mesh); } - void Node::loadMesh(const asset::Scene &asset_scene, const asset::Mesh &asset_mesh) { + void Node::loadMesh(const asset::Scene &asset_scene, + const asset::Mesh &asset_mesh, + const std::vector<asset::PrimitiveType>& types) { Mesh mesh (m_scene); - mesh.load(asset_scene, asset_mesh); + mesh.load(asset_scene, asset_mesh, types); addMesh(mesh); } @@ -92,7 +94,7 @@ namespace vkcv::scene { void Node::recordDrawcalls(const glm::mat4& viewProjection, PushConstants& pushConstants, - std::vector<DrawcallInfo>& drawcalls, + std::vector<InstanceDrawcall>& drawcalls, const RecordMeshDrawcallFunction& record) { if (!checkFrustum(viewProjection, m_bounds)) { return; diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp index 9a8ded0f70880125ed1efeda9a6845e1dc735d22..90d457c9ea7d5c4a7a1e30dbddd7086ced496e31 100644 --- a/modules/scene/src/vkcv/scene/Scene.cpp +++ b/modules/scene/src/vkcv/scene/Scene.cpp @@ -1,7 +1,9 @@ #include "vkcv/scene/Scene.hpp" +#include <vkcv/Image.hpp> #include <vkcv/Logger.hpp> +#include <vkcv/Sampler.hpp> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/algorithm/SinglePassDownsampler.hpp> @@ -124,7 +126,7 @@ namespace vkcv::scene { }); PushConstants pushConstants (pushConstantsSizePerDrawcall); - std::vector<DrawcallInfo> drawcalls; + std::vector<InstanceDrawcall> drawcalls; size_t count = 0; const glm::mat4 viewProjection = camera.getMVP(); @@ -138,7 +140,6 @@ namespace vkcv::scene { m_core->recordDrawcallsToCmdStream( cmdStream, - pass, pipeline, pushConstants, drawcalls, @@ -157,26 +158,87 @@ namespace vkcv::scene { const asset::Texture& asset_texture, const vk::Format& format, ImageHandle& image, SamplerHandle& sampler) { - asset::Sampler* asset_sampler = nullptr; + const asset::Sampler* asset_sampler = nullptr; if ((asset_texture.sampler >= 0) && (asset_texture.sampler < asset_scene.samplers.size())) { - //asset_sampler = &(asset_scene.samplers[asset_texture.sampler]); // TODO + asset_sampler = &(asset_scene.samplers[asset_texture.sampler]); } - Image img = core.createImage(format, asset_texture.w, asset_texture.h, 1, true); + Image img = vkcv::image(core, format, asset_texture.w, asset_texture.h, 1, true); img.fill(asset_texture.data.data()); image = img.getHandle(); + SamplerFilterType magFilter = SamplerFilterType::LINEAR; + SamplerFilterType minFilter = SamplerFilterType::LINEAR; + SamplerMipmapMode mipmapMode = SamplerMipmapMode::LINEAR; + SamplerAddressMode addressMode = SamplerAddressMode::REPEAT; + + float mipLodBias = 0.0f; + if (asset_sampler) { - //sampler = core.createSampler(asset_sampler) // TODO - } else { - sampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + switch (asset_sampler->magFilter) { + case VK_FILTER_NEAREST: + magFilter = SamplerFilterType::NEAREST; + break; + case VK_FILTER_LINEAR: + magFilter = SamplerFilterType::LINEAR; + break; + default: + break; + } + + switch (asset_sampler->minFilter) { + case VK_FILTER_NEAREST: + minFilter = SamplerFilterType::NEAREST; + break; + case VK_FILTER_LINEAR: + minFilter = SamplerFilterType::LINEAR; + break; + default: + break; + } + + switch (asset_sampler->mipmapMode) { + case VK_SAMPLER_MIPMAP_MODE_NEAREST: + mipmapMode = SamplerMipmapMode::NEAREST; + break; + case VK_SAMPLER_MIPMAP_MODE_LINEAR: + mipmapMode = SamplerMipmapMode::LINEAR; + break; + default: + break; + } + + switch (asset_sampler->addressModeU) { + case VK_SAMPLER_ADDRESS_MODE_REPEAT: + addressMode = SamplerAddressMode::REPEAT; + break; + case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + addressMode = SamplerAddressMode::MIRRORED_REPEAT; + break; + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + addressMode = SamplerAddressMode::CLAMP_TO_EDGE; + break; + case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: + addressMode = SamplerAddressMode::MIRROR_CLAMP_TO_EDGE; + break; + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + addressMode = SamplerAddressMode::CLAMP_TO_BORDER; + break; + default: + break; + } + + mipLodBias = asset_sampler->minLOD; } + + sampler = core.createSampler( + magFilter, + minFilter, + mipmapMode, + addressMode, + mipLodBias + ); } void Scene::loadMaterial(size_t index, const asset::Scene& scene, @@ -254,7 +316,9 @@ namespace vkcv::scene { ); } - Scene Scene::load(Core& core, const std::filesystem::path &path) { + Scene Scene::load(Core& core, + const std::filesystem::path &path, + const std::vector<asset::PrimitiveType>& types) { asset::Scene asset_scene; if (!asset::loadScene(path.string(), asset_scene)) { @@ -273,15 +337,10 @@ namespace vkcv::scene { const size_t root = scene.addNode(); for (const auto& mesh : asset_scene.meshes) { - scene.getNode(root).loadMesh(asset_scene, mesh); + scene.getNode(root).loadMesh(asset_scene, mesh, types); } - vkcv::SamplerHandle sampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + vkcv::SamplerHandle sampler = samplerLinear(core); const vkcv::FeatureManager& featureManager = core.getContext().getFeatureManager(); diff --git a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp index fd5bbd3795d62aee7dac6e80a72066556a5ffe07..64bc78aca4fe42ff813d05fc016a70c7108bd557 100644 --- a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp +++ b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp @@ -2,6 +2,7 @@ #include "Upscaling.hpp" +#include <vkcv/Buffer.hpp> #include <vkcv/ShaderProgram.hpp> namespace vkcv::upscaling { diff --git a/modules/upscaling/include/vkcv/upscaling/NISUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/NISUpscaling.hpp index 9a35bfd57fd261587eea0d327d2eb3154b1cd38a..913983400808f3353adf3a1c653045345d36c6f1 100644 --- a/modules/upscaling/include/vkcv/upscaling/NISUpscaling.hpp +++ b/modules/upscaling/include/vkcv/upscaling/NISUpscaling.hpp @@ -2,6 +2,7 @@ #include "Upscaling.hpp" +#include <vkcv/Buffer.hpp> #include <vkcv/ShaderProgram.hpp> namespace vkcv::upscaling { diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index a470cd21aba04faf7087e883cadfecb322876553..247161e35718cde352da5461b51f30c4fe8570c7 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -164,12 +164,16 @@ namespace vkcv::upscaling { m_rcasDescriptorSetLayout(m_core.createDescriptorSetLayout(getDescriptorBindings())), m_rcasDescriptorSet(m_core.createDescriptorSet(m_rcasDescriptorSetLayout)), - m_easuConstants(m_core.createBuffer<FSRConstants>( - BufferType::UNIFORM,1, + m_easuConstants(buffer<FSRConstants>( + m_core, + BufferType::UNIFORM, + 1, BufferMemoryType::HOST_VISIBLE )), - m_rcasConstants(m_core.createBuffer<FSRConstants>( - BufferType::UNIFORM,1, + m_rcasConstants(buffer<FSRConstants>( + m_core, + BufferType::UNIFORM, + 1, BufferMemoryType::HOST_VISIBLE )), m_intermediateImage(), @@ -275,7 +279,7 @@ namespace vkcv::upscaling { outputWidth, outputHeight,1, false, true - ).getHandle(); + ); m_core.prepareImageForStorage(cmdStream, m_intermediateImage); } @@ -302,10 +306,10 @@ namespace vkcv::upscaling { static const uint32_t threadGroupWorkRegionDim = 16; - uint32_t dispatch[3]; - dispatch[0] = (outputWidth + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; - dispatch[1] = (outputHeight + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; - dispatch[2] = 1; + DispatchSize dispatch = dispatchInvocations( + DispatchSize(outputWidth, outputHeight), + DispatchSize(threadGroupWorkRegionDim, threadGroupWorkRegionDim) + ); m_core.recordBufferMemoryBarrier(cmdStream, m_easuConstants.getHandle()); diff --git a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp index 2fd8e23f6c0a3c615ec6085ad1abfdad1a9794ab..2b25c9132b20368f37568d95608b23b89645016e 100644 --- a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp @@ -7,6 +7,7 @@ #include "NIS_Scaler.h.hxx" #include <vkcv/File.hpp> +#include <vkcv/Image.hpp> #include <vkcv/Logger.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -77,14 +78,14 @@ namespace vkcv::upscaling { const size_t rowPitch = kFilterSize * 2; const size_t imageSize = rowPitch * kPhaseCount; - Image image = core.createImage( + Image image = vkcv::image( + core, vk::Format::eR16G16B16A16Sfloat, kFilterSize / 4, kPhaseCount ); image.fill(data, imageSize); - return image.getHandle(); } @@ -137,8 +138,10 @@ namespace vkcv::upscaling { m_scalerDescriptorSetLayout(m_core.createDescriptorSetLayout(getDescriptorBindings())), m_scalerDescriptorSet(m_core.createDescriptorSet(m_scalerDescriptorSetLayout)), - m_scalerConstants(m_core.createBuffer<uint8_t>( - BufferType::UNIFORM, sizeof(NISConfig), + m_scalerConstants(buffer<uint8_t>( + m_core, + BufferType::UNIFORM, + sizeof(NISConfig), BufferMemoryType::HOST_VISIBLE )), m_sampler(m_core.createSampler( @@ -233,10 +236,10 @@ namespace vkcv::upscaling { sizeof(config) ); - uint32_t dispatch[3]; - dispatch[0] = (outputWidth + (m_blockWidth - 1)) / m_blockWidth; - dispatch[1] = (outputHeight + (m_blockHeight - 1)) / m_blockHeight; - dispatch[2] = 1; + DispatchSize dispatch = dispatchInvocations( + DispatchSize(outputWidth, outputHeight), + DispatchSize(m_blockWidth, m_blockHeight) + ); m_core.recordBufferMemoryBarrier(cmdStream, m_scalerConstants.getHandle()); diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp index 811e1162588fa699b4d74045504dc9c3d4de4f4c..e4dd4916b6a83a35abb809ed30f38cec67a01062 100644 --- a/projects/bindless_textures/src/main.cpp +++ b/projects/bindless_textures/src/main.cpp @@ -1,5 +1,9 @@ #include <iostream> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Image.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <chrono> @@ -46,6 +50,7 @@ int main(int argc, const char** argv) { ); vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 600, true); + vkcv::Window& window = core.getWindow(windowHandle); vkcv::asset::Scene mesh; @@ -62,9 +67,14 @@ int main(int argc, const char** argv) { std::filesystem::path grassPath(grassPaths[i]); vkcv::asset::Texture grassTexture = vkcv::asset::loadTexture(grassPath); - vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, grassTexture.width, grassTexture.height); + vkcv::Image texture = vkcv::image( + core, + vk::Format::eR8G8B8A8Srgb, + grassTexture.width, + grassTexture.height + ); + texture.fill(grassTexture.data.data()); - texturesArray.push_back(texture); } @@ -79,7 +89,8 @@ int main(int argc, const char** argv) { } assert(!mesh.vertexGroups.empty()); - auto vertexBuffer = core.createBuffer<uint8_t>( + auto vertexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::VERTEX, mesh.vertexGroups[0].vertexBuffer.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL @@ -87,30 +98,21 @@ int main(int argc, const char** argv) { vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data); - auto indexBuffer = core.createBuffer<uint8_t>( + auto indexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::INDEX, mesh.vertexGroups[0].indexBuffer.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL ); indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data); - - // an example attachment for passes that output to the window - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat() - ); - const vkcv::AttachmentDescription depth_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat + vkcv::PassHandle firstMeshPass = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat } ); - vkcv::PassConfig firstMeshPassDefinition({ present_color_attachment, depth_attachment }, vkcv::Multisampling::None); - vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition); - if (!firstMeshPass) { std::cerr << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; @@ -123,18 +125,20 @@ int main(int argc, const char** argv) { { vkcv::ShaderStage::VERTEX, "resources/shaders/shader.vert" }, { vkcv::ShaderStage::FRAGMENT, "resources/shaders/shader.frag" } }, nullptr); - - auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; - std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); - - 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::createVertexBinding(i, { vertexAttachments[i] })); - } + const auto vertexBufferBindings = vkcv::asset::loadVertexBufferBindings( + mesh.vertexGroups[0].vertexBuffer.attributes, + vertexBuffer.getHandle(), + { + vkcv::asset::PrimitiveType::POSITION, + vkcv::asset::PrimitiveType::NORMAL, + vkcv::asset::PrimitiveType::TEXCOORD_0 + } + ); + + std::vector<vkcv::VertexBinding> bindings = vkcv::createVertexBindings( + firstMeshProgram.getVertexAttachments() + ); const vkcv::VertexLayout firstMeshLayout { bindings }; const std::unordered_map<uint32_t, vkcv::DescriptorBinding> &descriptorBindings = firstMeshProgram.getReflectedDescriptors().at(0); @@ -145,16 +149,14 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetLayoutHandle descriptorSetLayout = core.createDescriptorSetLayout(adjustedBindings); vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); - const vkcv::GraphicsPipelineConfig firstMeshPipelineConfig { - firstMeshProgram, - UINT32_MAX, - UINT32_MAX, - firstMeshPass, - {firstMeshLayout}, - { descriptorSetLayout }, - true - }; - vkcv::GraphicsPipelineHandle firstMeshPipeline = core.createGraphicsPipeline(firstMeshPipelineConfig); + vkcv::GraphicsPipelineHandle firstMeshPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + firstMeshProgram, + firstMeshPass, + { firstMeshLayout }, + { descriptorSetLayout } + ) + ); if (!firstMeshPipeline) { std::cerr << "Error. Could not create graphics pipeline. Exiting." << std::endl; @@ -168,7 +170,7 @@ int main(int argc, const char** argv) { { vkcv::asset::Texture &tex = mesh.textures[0]; - vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); + vkcv::Image texture = vkcv::image(core, vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); texture.fill(tex.data.data()); texturesArray.push_back(texture); } @@ -181,18 +183,7 @@ int main(int argc, const char** argv) { core.submitCommandStream(downsampleStream, false); - vkcv::SamplerHandle sampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); - - const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; - + vkcv::SamplerHandle sampler = vkcv::samplerLinear(core); vkcv::DescriptorWrites setWrites; for(uint32_t i = 0; i < 6; i++) @@ -214,31 +205,22 @@ int main(int argc, const char** argv) { vkcv::ImageHandle depthBuffer; const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::VertexData vertexData (vertexBufferBindings); + vertexData.setIndexBuffer(indexBuffer.getHandle()); + vertexData.setCount(mesh.vertexGroups[0].numIndices); + + vkcv::InstanceDrawcall drawcall (vertexData); + drawcall.useDescriptorSet(0, descriptorSet); - const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices); - - vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet); - vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage },1); - - vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + vkcv::camera::CameraManager cameraManager(window); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3)); - - auto start = std::chrono::system_clock::now(); - - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0) - continue; - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((!depthBuffer) || (swapchainWidth != core.getImageWidth(depthBuffer)) || (swapchainHeight != core.getImageHeight(depthBuffer))) { @@ -246,17 +228,13 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight - ).getHandle(); + ); } - - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - - start = end; - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + cameraManager.update(dt); glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); - vkcv::PushConstants pushConstants (sizeof(glm::mat4)); + vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>(); pushConstants.appendDrawcall(mvp); const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; @@ -264,16 +242,16 @@ int main(int argc, const char** argv) { core.recordDrawcallsToCmdStream( cmdStream, - firstMeshPass, firstMeshPipeline, pushConstants, { drawcall }, renderTargets, - windowHandle); + windowHandle + ); + core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/fire_works/src/main.cpp b/projects/fire_works/src/main.cpp index d430216f864ac3e7c5e4d4fa1f6339710b64cb93..738723ff7ee7974b33bc13d0f825258fb9f8048b 100644 --- a/projects/fire_works/src/main.cpp +++ b/projects/fire_works/src/main.cpp @@ -1,8 +1,11 @@ #include <array> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> -#include <vkcv/DrawcallRecording.hpp> +#include <vkcv/Image.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> #include <vkcv/camera/CameraManager.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -186,7 +189,7 @@ void InitializeNestedFireworkEvents(std::vector<event_t>& events) { } void ChangeColor(std::vector<event_t>& events, glm::vec3 color) { - for (int i = 0; i < events.size(); i++) { + for (size_t i = 0; i < events.size(); i++) { events [i].color = color; } } @@ -195,6 +198,9 @@ int main(int argc, const char **argv) { vkcv::Features features; features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + features.requireFeature([](vk::PhysicalDeviceFeatures& features) { + features.setGeometryShader(true); + }); vkcv::Core core = vkcv::Core::create( "Firework", @@ -318,7 +324,8 @@ int main(int argc, const char **argv) { { smokeDescriptorLayout } }); - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + auto swapchainHandle = core.getWindow(windowHandle).getSwapchain(); + auto swapchainExtent = core.getSwapchainExtent(swapchainHandle); const vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; @@ -329,7 +336,7 @@ int main(int argc, const char **argv) { swapchainExtent.width, swapchainExtent.height, 1, false, true, true - ).getHandle(); + ); } vkcv::ShaderProgram particleShaderProgram; @@ -361,18 +368,21 @@ int main(int argc, const char **argv) { particles.resize(PARTICLE_COUNT); InitializeParticles(particles); - vkcv::Buffer<particle_t> particleBuffer = core.createBuffer<particle_t>( - vkcv::BufferType::STORAGE, - particles.size(), - vkcv::BufferMemoryType::DEVICE_LOCAL, - false, - true + auto particleBuffer = vkcv::buffer<particle_t>( + core, + vkcv::BufferType::STORAGE, + particles.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL, + true ); particleBuffer.fill(particles); - vkcv::Buffer<particle_t> particleBufferCopy = - core.createBuffer<particle_t>(vkcv::BufferType::STORAGE, particles.size()); + auto particleBufferCopy = vkcv::buffer<particle_t>( + core, + vkcv::BufferType::STORAGE, + particles.size() + ); particleBufferCopy.fill(particles); @@ -392,9 +402,10 @@ int main(int argc, const char **argv) { ); } - vkcv::Buffer<float> randomBuffer = core.createBuffer<float>( - vkcv::BufferType::STORAGE, - randomData.size() + auto randomBuffer = vkcv::buffer<float>( + core, + vkcv::BufferType::STORAGE, + randomData.size() ); randomBuffer.fill(randomData); @@ -402,9 +413,10 @@ int main(int argc, const char **argv) { std::vector<event_t> events; InitializeFireworkEvents(events); - vkcv::Buffer<event_t> eventBuffer = core.createBuffer<event_t>( - vkcv::BufferType::STORAGE, - events.size() + auto eventBuffer = vkcv::buffer<event_t>( + core, + vkcv::BufferType::STORAGE, + events.size() ); eventBuffer.fill(events); @@ -416,8 +428,11 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(generationDescriptorSet, writes); } - vkcv::Buffer<uint32_t> startIndexBuffer = - core.createBuffer<uint32_t>(vkcv::BufferType::STORAGE, eventBuffer.getCount()); + auto startIndexBuffer = vkcv::buffer<uint32_t>( + core, + vkcv::BufferType::STORAGE, + eventBuffer.getCount() + ); { vkcv::DescriptorWrites writes; @@ -441,15 +456,19 @@ int main(int argc, const char **argv) { smokes.push_back(smoke); } - vkcv::Buffer<smoke_t> smokeBuffer = core.createBuffer<smoke_t>( - vkcv::BufferType::STORAGE, - smokes.size() + auto smokeBuffer = vkcv::buffer<smoke_t>( + core, + vkcv::BufferType::STORAGE, + smokes.size() ); smokeBuffer.fill(smokes); - vkcv::Buffer<uint32_t> smokeIndexBuffer = core.createBuffer<uint32_t>( - vkcv::BufferType::STORAGE, 3, vkcv::BufferMemoryType::HOST_VISIBLE + auto smokeIndexBuffer = vkcv::buffer<uint32_t>( + core, + vkcv::BufferType::STORAGE, + 3, + vkcv::BufferMemoryType::HOST_VISIBLE ); uint32_t* smokeIndices = smokeIndexBuffer.map(); @@ -478,9 +497,10 @@ int main(int argc, const char **argv) { trails.push_back(trail); } - vkcv::Buffer<trail_t> trailBuffer = core.createBuffer<trail_t>( - vkcv::BufferType::STORAGE, - trails.size() + auto trailBuffer = vkcv::buffer<trail_t>( + core, + vkcv::BufferType::STORAGE, + trails.size() ); trailBuffer.fill(trails); @@ -499,9 +519,10 @@ int main(int argc, const char **argv) { points.push_back(point); } - vkcv::Buffer<point_t> pointBuffer = core.createBuffer<point_t>( - vkcv::BufferType::STORAGE, - points.size() + auto pointBuffer = vkcv::buffer<point_t>( + core, + vkcv::BufferType::STORAGE, + points.size() ); pointBuffer.fill(points); @@ -513,7 +534,12 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(trailDescriptorSet, writes); } - vkcv::Buffer<glm::vec3> cubePositions = core.createBuffer<glm::vec3>(vkcv::BufferType::VERTEX, 8); + auto cubePositions = vkcv::buffer<glm::vec3>( + core, + vkcv::BufferType::VERTEX, + 8 + ); + cubePositions.fill({ glm::vec3(-1.0f, -1.0f, -1.0f), glm::vec3(+1.0f, -1.0f, -1.0f), @@ -525,7 +551,12 @@ int main(int argc, const char **argv) { glm::vec3(+1.0f, +1.0f, +1.0f) }); - vkcv::Buffer<uint16_t> cubeIndices = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 36); + auto cubeIndices = vkcv::buffer<uint16_t>( + core, + vkcv::BufferType::INDEX, + 36 + ); + cubeIndices.fill({ 0, 2, 3, 0, 3, 1, @@ -543,11 +574,9 @@ int main(int argc, const char **argv) { 1, 4, 0 }); - vkcv::Mesh cubeMesh ( - { vkcv::VertexBufferBinding(0, cubePositions.getVulkanHandle()) }, - cubeIndices.getVulkanHandle(), - cubeIndices.getCount() - ); + vkcv::VertexData cubeData ({ vkcv::vertexBufferBinding(cubePositions.getHandle()) }); + cubeData.setIndexBuffer(cubeIndices.getHandle()); + cubeData.setCount(cubeIndices.getCount()); const std::vector<vkcv::VertexAttachment> vaSmoke = smokeShaderProgram.getVertexAttachments(); @@ -558,28 +587,16 @@ int main(int argc, const char **argv) { const vkcv::VertexLayout smokeLayout { vbSmoke }; - vkcv::PassHandle renderPass = core.createPass(vkcv::PassConfig( - { - vkcv::AttachmentDescription( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - colorFormat - ) - }, - vkcv::Multisampling::None - )); - - vkcv::GraphicsPipelineConfig smokePipelineDefinition{ + vkcv::PassHandle renderPass = vkcv::passFormat(core, colorFormat); + + vkcv::GraphicsPipelineConfig smokePipelineDefinition ( smokeShaderProgram, - UINT32_MAX, - UINT32_MAX, renderPass, {smokeLayout}, - {smokeDescriptorLayout, generationDescriptorLayout}, - true - }; + {smokeDescriptorLayout, generationDescriptorLayout} + ); - smokePipelineDefinition.m_blendMode = vkcv::BlendMode::Additive; + smokePipelineDefinition.setBlendMode(vkcv::BlendMode::Additive); vkcv::GraphicsPipelineHandle smokePipeline = core.createGraphicsPipeline(smokePipelineDefinition); @@ -592,67 +609,56 @@ int main(int argc, const char **argv) { const vkcv::VertexLayout trailLayout { vbTrail }; - vkcv::GraphicsPipelineConfig trailPipelineDefinition{ + vkcv::GraphicsPipelineConfig trailPipelineDefinition ( trailShaderProgram, - UINT32_MAX, - UINT32_MAX, renderPass, {trailLayout}, - {trailDescriptorLayout, generationDescriptorLayout, descriptorSetLayout}, - true - }; + {trailDescriptorLayout, generationDescriptorLayout, descriptorSetLayout} + ); - trailPipelineDefinition.m_PrimitiveTopology = vkcv::PrimitiveTopology::PointList; - trailPipelineDefinition.m_blendMode = vkcv::BlendMode::Additive; + trailPipelineDefinition.setPrimitiveTopology(vkcv::PrimitiveTopology::PointList); + trailPipelineDefinition.setBlendMode(vkcv::BlendMode::Additive); vkcv::GraphicsPipelineHandle trailPipeline = core.createGraphicsPipeline(trailPipelineDefinition); - std::vector<vkcv::DrawcallInfo> drawcallsSmokes; + vkcv::InstanceDrawcall drawcallSmoke (cubeData, smokeBuffer.getCount()); + drawcallSmoke.useDescriptorSet(0, smokeDescriptorSet); + drawcallSmoke.useDescriptorSet(1, generationDescriptorSet); - drawcallsSmokes.push_back(vkcv::DrawcallInfo( - cubeMesh, - { - vkcv::DescriptorSetUsage(0, smokeDescriptorSet), - vkcv::DescriptorSetUsage(1, generationDescriptorSet), - }, - smokeBuffer.getCount() - )); + auto trianglePositions = vkcv::buffer<glm::vec2>( + core, + vkcv::BufferType::VERTEX, + 3 + ); - vkcv::Buffer<glm::vec2> trianglePositions = core.createBuffer<glm::vec2>(vkcv::BufferType::VERTEX, 3); trianglePositions.fill({ glm::vec2(-1.0f, -1.0f), glm::vec2(+0.0f, +1.5f), glm::vec2(+1.0f, -1.0f) }); - vkcv::Buffer<uint16_t> triangleIndices = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3); + auto triangleIndices = vkcv::buffer<uint16_t>( + core, + vkcv::BufferType::INDEX, + 3 + ); + triangleIndices.fill({ 0, 1, 2 }); - vkcv::Mesh triangleMesh ( - { vkcv::VertexBufferBinding(0, trianglePositions.getVulkanHandle()) }, - triangleIndices.getVulkanHandle(), - triangleIndices.getCount() - ); - - vkcv::Mesh trailMesh ( - {}, - triangleIndices.getVulkanHandle(), - 1 - ); + vkcv::VertexData triangleData ({ vkcv::vertexBufferBinding(trianglePositions.getHandle()) }); + triangleData.setIndexBuffer(triangleIndices.getHandle()); + triangleData.setCount(triangleIndices.getCount()); - std::vector<vkcv::DrawcallInfo> drawcallsTrails; + vkcv::VertexData trailData; + triangleData.setIndexBuffer(triangleIndices.getHandle()); + trailData.setCount(1); - drawcallsTrails.push_back(vkcv::DrawcallInfo( - trailMesh, - { - vkcv::DescriptorSetUsage(0, trailDescriptorSet), - vkcv::DescriptorSetUsage(1, generationDescriptorSet), - vkcv::DescriptorSetUsage(2, descriptorSet) - }, - trailBuffer.getCount() - )); + vkcv::InstanceDrawcall drawcallTrail (trailData, trailBuffer.getCount()); + drawcallTrail.useDescriptorSet(0, trailDescriptorSet); + drawcallTrail.useDescriptorSet(1, generationDescriptorSet); + drawcallTrail.useDescriptorSet(2, descriptorSet); const std::vector<vkcv::VertexAttachment> vaParticles = particleShaderProgram.getVertexAttachments(); @@ -663,27 +669,19 @@ int main(int argc, const char **argv) { const vkcv::VertexLayout particleLayout { vbParticles }; - vkcv::GraphicsPipelineConfig particlePipelineDefinition{ + vkcv::GraphicsPipelineConfig particlePipelineDefinition ( particleShaderProgram, - UINT32_MAX, - UINT32_MAX, renderPass, {particleLayout}, - {descriptorSetLayout}, - true - }; + {descriptorSetLayout} + ); - particlePipelineDefinition.m_blendMode = vkcv::BlendMode::Additive; + particlePipelineDefinition.setBlendMode(vkcv::BlendMode::Additive); vkcv::GraphicsPipelineHandle particlePipeline = core.createGraphicsPipeline(particlePipelineDefinition); - std::vector<vkcv::DrawcallInfo> drawcallsParticles; - - drawcallsParticles.push_back(vkcv::DrawcallInfo( - triangleMesh, - { vkcv::DescriptorSetUsage(0, descriptorSet) }, - particleBuffer.getCount() - )); + vkcv::InstanceDrawcall drawcallParticle (triangleData, particleBuffer.getCount()); + drawcallParticle.useDescriptorSet(0, descriptorSet); vkcv::ShaderProgram motionShader; compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/motion.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { @@ -702,36 +700,40 @@ int main(int argc, const char **argv) { std::vector<uint32_t> zeroVoxel; zeroVoxel.resize(voxelWidth * voxelHeight * voxelDepth, 0); - vkcv::Image voxelRed = core.createImage( - vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + vkcv::Image voxelRed = vkcv::image( + core, + vk::Format::eR32Uint, + voxelWidth, + voxelHeight, + voxelDepth, + false, true ); - vkcv::Image voxelGreen = core.createImage( - vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + vkcv::Image voxelGreen = vkcv::image( + core, + vk::Format::eR32Uint, + voxelWidth, + voxelHeight, + voxelDepth, + false, true ); - vkcv::Image voxelBlue = core.createImage( - vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + vkcv::Image voxelBlue = vkcv::image( + core, + vk::Format::eR32Uint, + voxelWidth, + voxelHeight, + voxelDepth, + false, true ); - vkcv::Image voxelDensity = core.createImage( - vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + vkcv::Image voxelDensity = vkcv::image( + core, + vk::Format::eR32Uint, + voxelWidth, + voxelHeight, + voxelDepth, + false, true ); std::array<vkcv::ImageHandle, 2> voxelData { @@ -741,29 +743,25 @@ int main(int argc, const char **argv) { voxelHeight, voxelDepth, false, true - ).getHandle(), + ), core.createImage( vk::Format::eR16G16B16A16Sfloat, voxelWidth, voxelHeight, voxelDepth, false, true - ).getHandle() + ) }; - vkcv::Image voxelSamples = core.createImage( - colorFormat, - voxelWidth, - voxelHeight, - 1, false, true + vkcv::Image voxelSamples = vkcv::image( + core, + colorFormat, + voxelWidth, + voxelHeight, + 1, false, true ); - vkcv::SamplerHandle voxelSampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE - ); + vkcv::SamplerHandle voxelSampler = vkcv::samplerLinear(core, true); vkcv::ShaderProgram voxelClearShader; compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/clear.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { @@ -944,7 +942,7 @@ int main(int argc, const char **argv) { swapchainWidth, swapchainHeight, 1, false, true, true - ).getHandle(); + ); } } @@ -963,10 +961,10 @@ int main(int argc, const char **argv) { auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - uint32_t voxelDispatchCount[3]; - voxelDispatchCount[0] = std::ceil(voxelWidth / 4.f); - voxelDispatchCount[1] = std::ceil(voxelHeight / 4.f); - voxelDispatchCount[2] = std::ceil(voxelDepth / 4.f); + auto voxelDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(voxelWidth, voxelHeight, voxelDepth), + vkcv::DispatchSize(4, 4, 4) + ); core.recordBeginDebugLabel(cmdStream, "Voxel clear", { 0.5f, 0.25f, 0.8f, 1.0f }); core.prepareImageForStorage(cmdStream, voxelRed.getHandle()); @@ -978,7 +976,7 @@ int main(int argc, const char **argv) { cmdStream, voxelClearPipeline, voxelDispatchCount, - { vkcv::DescriptorSetUsage(0, voxelDescriptorSet) }, + { vkcv::useDescriptorSet(0, voxelDescriptorSet) }, vkcv::PushConstants(0) ); core.recordEndDebugLabel(cmdStream); @@ -990,10 +988,7 @@ int main(int argc, const char **argv) { core.recordBufferMemoryBarrier(cmdStream, trailBuffer.getHandle()); core.recordBufferMemoryBarrier(cmdStream, pointBuffer.getHandle()); - uint32_t particleDispatchCount[3]; - particleDispatchCount[0] = std::ceil(particleBuffer.getCount() / 256.f); - particleDispatchCount[1] = 1; - particleDispatchCount[2] = 1; + auto particleDispatchCount = vkcv::dispatchInvocations(particleBuffer.getCount(), 256); vkcv::PushConstants pushConstantsTime (2 * sizeof(float)); pushConstantsTime.appendDrawcall(time_values); @@ -1004,10 +999,10 @@ int main(int argc, const char **argv) { generationPipeline, particleDispatchCount, { - vkcv::DescriptorSetUsage(0, descriptorSet), - vkcv::DescriptorSetUsage(1, generationDescriptorSet), - vkcv::DescriptorSetUsage(2, smokeDescriptorSet), - vkcv::DescriptorSetUsage(3, trailDescriptorSet) + vkcv::useDescriptorSet(0, descriptorSet), + vkcv::useDescriptorSet(1, generationDescriptorSet), + vkcv::useDescriptorSet(2, smokeDescriptorSet), + vkcv::useDescriptorSet(3, trailDescriptorSet) }, pushConstantsTime ); @@ -1015,17 +1010,14 @@ int main(int argc, const char **argv) { core.recordBufferMemoryBarrier(cmdStream, smokeBuffer.getHandle()); - uint32_t smokeDispatchCount[3]; - smokeDispatchCount[0] = std::ceil(smokeBuffer.getCount() / 256.f); - smokeDispatchCount[1] = 1; - smokeDispatchCount[2] = 1; + auto smokeDispatchCount = vkcv::dispatchInvocations(smokeBuffer.getCount(), 256); core.recordBeginDebugLabel(cmdStream, "Smoke scaling", { 0.0f, 0.0f, 1.0f, 1.0f }); core.recordComputeDispatchToCmdStream( cmdStream, scalePipeline, smokeDispatchCount, - { vkcv::DescriptorSetUsage(0, smokeDescriptorSet) }, + { vkcv::useDescriptorSet(0, smokeDescriptorSet) }, pushConstantsTime ); core.recordEndDebugLabel(cmdStream); @@ -1037,7 +1029,7 @@ int main(int argc, const char **argv) { cmdStream, motionPipeline, particleDispatchCount, - { vkcv::DescriptorSetUsage(0, descriptorSet) }, + { vkcv::useDescriptorSet(0, descriptorSet) }, pushConstantsTime ); core.recordEndDebugLabel(cmdStream); @@ -1046,10 +1038,7 @@ int main(int argc, const char **argv) { core.recordBufferMemoryBarrier(cmdStream, trailBuffer.getHandle()); core.recordBufferMemoryBarrier(cmdStream, pointBuffer.getHandle()); - uint32_t trailDispatchCount[3]; - trailDispatchCount[0] = std::ceil(trailBuffer.getCount() / 256.f); - trailDispatchCount[1] = 1; - trailDispatchCount[2] = 1; + auto trailDispatchCount = vkcv::dispatchInvocations(trailBuffer.getCount(), 256); core.recordBeginDebugLabel(cmdStream, "Trail update", { 0.0f, 0.0f, 1.0f, 1.0f }); core.recordComputeDispatchToCmdStream( @@ -1057,8 +1046,8 @@ int main(int argc, const char **argv) { trailComputePipeline, trailDispatchCount, { - vkcv::DescriptorSetUsage(0, descriptorSet), - vkcv::DescriptorSetUsage(1, trailDescriptorSet) + vkcv::useDescriptorSet(0, descriptorSet), + vkcv::useDescriptorSet(1, trailDescriptorSet) }, pushConstantsTime ); @@ -1082,10 +1071,9 @@ int main(int argc, const char **argv) { core.recordBeginDebugLabel(cmdStream, "Draw particles", { 1.0f, 0.0f, 1.0f, 1.0f }); core.recordDrawcallsToCmdStream( cmdStream, - renderPass, particlePipeline, pushConstantsDraw0, - { drawcallsParticles }, + { drawcallParticle }, { colorBuffers[0] }, windowHandle ); @@ -1105,8 +1093,8 @@ int main(int argc, const char **argv) { voxelParticlePipeline, particleDispatchCount, { - vkcv::DescriptorSetUsage(0, descriptorSet), - vkcv::DescriptorSetUsage(1, voxelDescriptorSet) + vkcv::useDescriptorSet(0, descriptorSet), + vkcv::useDescriptorSet(1, voxelDescriptorSet) }, pushConstantsVoxel ); @@ -1125,10 +1113,9 @@ int main(int argc, const char **argv) { core.recordDrawcallsToCmdStream( cmdStream, - renderPass, smokePipeline, pushConstantsDraw1, - { drawcallsSmokes }, + { drawcallSmoke }, { colorBuffers[1] }, windowHandle ); @@ -1145,8 +1132,8 @@ int main(int argc, const char **argv) { voxelSmokePipeline, smokeDispatchCount, { - vkcv::DescriptorSetUsage(0, smokeDescriptorSet), - vkcv::DescriptorSetUsage(1, voxelDescriptorSet) + vkcv::useDescriptorSet(0, smokeDescriptorSet), + vkcv::useDescriptorSet(1, voxelDescriptorSet) }, pushConstantsVoxel ); @@ -1158,10 +1145,9 @@ int main(int argc, const char **argv) { core.recordBeginDebugLabel(cmdStream, "Draw trails", { 0.75f, 0.5f, 1.0f, 1.0f }); core.recordDrawcallsToCmdStream( cmdStream, - renderPass, trailPipeline, pushConstantsDraw1, - { drawcallsTrails }, + { drawcallTrail }, { colorBuffers[2] }, windowHandle ); @@ -1178,8 +1164,8 @@ int main(int argc, const char **argv) { voxelTrailPipeline, trailDispatchCount, { - vkcv::DescriptorSetUsage(0, trailDescriptorSet), - vkcv::DescriptorSetUsage(1, voxelDescriptorSet) + vkcv::useDescriptorSet(0, trailDescriptorSet), + vkcv::useDescriptorSet(1, voxelDescriptorSet) }, pushConstantsVoxel ); @@ -1199,8 +1185,8 @@ int main(int argc, const char **argv) { voxelPipeline, voxelDispatchCount, { - vkcv::DescriptorSetUsage(0, voxelDescriptorSet), - vkcv::DescriptorSetUsage(1, voxelOutDescriptorSet) + vkcv::useDescriptorSet(0, voxelDescriptorSet), + vkcv::useDescriptorSet(1, voxelOutDescriptorSet) }, vkcv::PushConstants(0) ); @@ -1217,7 +1203,7 @@ int main(int argc, const char **argv) { cmdStream, fluidPipeline, voxelDispatchCount, - { vkcv::DescriptorSetUsage(0, fluidDescriptorSet[i % 2]) }, + { vkcv::useDescriptorSet(0, fluidDescriptorSet[i % 2]) }, vkcv::PushConstants(0) ); } @@ -1229,18 +1215,18 @@ int main(int argc, const char **argv) { core.prepareImageForStorage(cmdStream, voxelData[0]); core.prepareImageForStorage(cmdStream, voxelSamples.getHandle()); - uint32_t sampleDispatchCount[3]; - sampleDispatchCount[0] = std::ceil(voxelWidth / 8.f); - sampleDispatchCount[1] = std::ceil(voxelHeight / 8.f); - sampleDispatchCount[2] = 1; + auto sampleDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(voxelWidth, voxelHeight), + vkcv::DispatchSize(8, 8) + ); core.recordComputeDispatchToCmdStream( cmdStream, voxelSamplePipeline, sampleDispatchCount, { - vkcv::DescriptorSetUsage(0, voxelOutDescriptorSet), - vkcv::DescriptorSetUsage(1, samplesDescriptorSet) + vkcv::useDescriptorSet(0, voxelOutDescriptorSet), + vkcv::useDescriptorSet(1, samplesDescriptorSet) }, vkcv::PushConstants(0) ); @@ -1261,18 +1247,18 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(addDescriptor, addDescriptorWrites); core.prepareImageForSampling(cmdStream, voxelSamples.getHandle()); - uint32_t colorDispatchCount[3]; - colorDispatchCount[0] = std::ceil(swapchainWidth / 8.f); - colorDispatchCount[1] = std::ceil(swapchainHeight / 8.f); - colorDispatchCount[2] = 1; + auto colorDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(swapchainWidth, swapchainHeight), + vkcv::DispatchSize(8, 8) + ); core.recordComputeDispatchToCmdStream( cmdStream, addPipe, colorDispatchCount, { - vkcv::DescriptorSetUsage(0, addDescriptor), - vkcv::DescriptorSetUsage(1, generationDescriptorSet) + vkcv::useDescriptorSet(0, addDescriptor), + vkcv::useDescriptorSet(1, generationDescriptorSet) }, vkcv::PushConstants(0) ); @@ -1298,7 +1284,7 @@ int main(int argc, const char **argv) { cmdStream, tonemappingPipe, colorDispatchCount, - {vkcv::DescriptorSetUsage(0, tonemappingDescriptor) }, + { vkcv::useDescriptorSet(0, tonemappingDescriptor) }, vkcv::PushConstants(0) ); @@ -1310,11 +1296,15 @@ int main(int argc, const char **argv) { gui.beginGUI(); ImGui::Begin("Settings"); - bool listbox = ImGui::BeginListBox(" "); - bool firework = ImGui::Selectable("Firework"); - bool sparkler = ImGui::Selectable("Sparkler"); - bool nested = ImGui::Selectable("Nested Firework"); - ImGui::EndListBox(); + bool firework, sparkler, nested; + if (ImGui::BeginListBox(" ")) { + firework = ImGui::Selectable("Firework"); + sparkler = ImGui::Selectable("Sparkler"); + nested = ImGui::Selectable("Nested Firework"); + + ImGui::EndListBox(); + } + bool resetTime = ImGui::Button("Reset"); auto color = glm::vec3(0.0f); diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index fa671a5507a7621586497048128e8959f72cdf08..88ab4b70d72f30a3e622d8579cb75929039bc2cf 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -1,7 +1,10 @@ #include <iostream> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Image.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> #include <vkcv/camera/CameraManager.hpp> -#include <chrono> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -16,6 +19,7 @@ int main(int argc, const char** argv) { ); vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 600, true); + vkcv::Window& window = core.getWindow(windowHandle); vkcv::asset::Scene mesh; @@ -30,7 +34,8 @@ int main(int argc, const char** argv) { } assert(!mesh.vertexGroups.empty()); - auto vertexBuffer = core.createBuffer<uint8_t>( + auto vertexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::VERTEX, mesh.vertexGroups[0].vertexBuffer.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL @@ -38,7 +43,8 @@ int main(int argc, const char** argv) { vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data); - auto indexBuffer = core.createBuffer<uint8_t>( + auto indexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::INDEX, mesh.vertexGroups[0].indexBuffer.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL @@ -46,26 +52,12 @@ int main(int argc, const char** argv) { indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data); - // an example attachment for passes that output to the window - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat() - ); - - const vkcv::AttachmentDescription depth_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat - ); - - vkcv::PassConfig firstMeshPassDefinition( - { present_color_attachment, depth_attachment }, - vkcv::Multisampling::None + vkcv::PassHandle firstMeshPass = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat } ); - vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition); - if (!firstMeshPass) { std::cerr << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; @@ -78,18 +70,20 @@ int main(int argc, const char** argv) { { vkcv::ShaderStage::VERTEX, "assets/shaders/shader.vert" }, { vkcv::ShaderStage::FRAGMENT, "assets/shaders/shader.frag" } }, nullptr); - - auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; - std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); + const auto vertexBufferBindings = vkcv::asset::loadVertexBufferBindings( + mesh.vertexGroups[0].vertexBuffer.attributes, + vertexBuffer.getHandle(), + { + vkcv::asset::PrimitiveType::POSITION, + vkcv::asset::PrimitiveType::NORMAL, + vkcv::asset::PrimitiveType::TEXCOORD_0 + } + ); - 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::createVertexBinding(i, { vertexAttachments[i] })); - } + std::vector<vkcv::VertexBinding> bindings = vkcv::createVertexBindings( + firstMeshProgram.getVertexAttachments() + ); const vkcv::VertexLayout firstMeshLayout { bindings }; @@ -102,17 +96,15 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetLayoutHandle setLayoutHandleCopy = core.createDescriptorSetLayout(set0BindingsExplicitCopy); vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(setLayoutHandle); - - const vkcv::GraphicsPipelineConfig firstMeshPipelineConfig { - firstMeshProgram, - UINT32_MAX, - UINT32_MAX, - firstMeshPass, - {firstMeshLayout}, - { setLayoutHandle }, - true - }; - vkcv::GraphicsPipelineHandle firstMeshPipeline = core.createGraphicsPipeline(firstMeshPipelineConfig); + + vkcv::GraphicsPipelineHandle firstMeshPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + firstMeshProgram, + firstMeshPass, + { firstMeshLayout }, + { setLayoutHandle } + ) + ); if (!firstMeshPipeline) { std::cerr << "Error. Could not create graphics pipeline. Exiting." << std::endl; @@ -125,7 +117,7 @@ int main(int argc, const char** argv) { } vkcv::asset::Texture &tex = mesh.textures[0]; - vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); + vkcv::Image texture = vkcv::image(core, vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); texture.fill(tex.data.data()); { @@ -134,17 +126,7 @@ int main(int argc, const char** argv) { core.submitCommandStream(cmdStream, false); } - vkcv::SamplerHandle sampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); - - const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; + vkcv::SamplerHandle sampler = vkcv::samplerLinear(core); vkcv::DescriptorWrites setWrites; setWrites.writeSampledImage(0, texture.getHandle()); @@ -155,30 +137,21 @@ int main(int argc, const char** argv) { vkcv::ImageHandle depthBuffer; const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::VertexData vertexData (vertexBufferBindings); + vertexData.setIndexBuffer(indexBuffer.getHandle()); + vertexData.setCount(mesh.vertexGroups[0].numIndices); + + vkcv::InstanceDrawcall drawcall (vertexData); + drawcall.useDescriptorSet(0, descriptorSet); - const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices); - - vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet); - vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage },1); - - vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + vkcv::camera::CameraManager cameraManager(window); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3)); - - auto start = std::chrono::system_clock::now(); - - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0) - continue; - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((!depthBuffer) || (swapchainWidth != core.getImageWidth(depthBuffer)) || (swapchainHeight != core.getImageHeight(depthBuffer))) { @@ -186,17 +159,13 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight - ).getHandle(); + ); } - - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - start = end; - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + cameraManager.update(dt); glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); - vkcv::PushConstants pushConstants (sizeof(glm::mat4)); + vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>(); pushConstants.appendDrawcall(mvp); const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; @@ -204,16 +173,16 @@ int main(int argc, const char** argv) { core.recordDrawcallsToCmdStream( cmdStream, - firstMeshPass, firstMeshPipeline, pushConstants, { drawcall }, renderTargets, - windowHandle); + windowHandle + ); + core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index b09943e4b9432ac09c6eaaa5bbe06b0b28b59ab3..6b29b14bd92725af9439796c42012ba1d6bd4c80 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -1,5 +1,6 @@ #include <iostream> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <vkcv/gui/GUI.hpp> @@ -44,28 +45,21 @@ int main(int argc, const char** argv) { cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f); - vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path( - argc > 1 ? argv[1] : "assets/Sponza/Sponza.gltf" - )); - - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat() - ); - - const vkcv::AttachmentDescription depth_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat - ); - - vkcv::PassConfig scenePassDefinition( - { present_color_attachment, depth_attachment }, - vkcv::Multisampling::None + vkcv::scene::Scene scene = vkcv::scene::Scene::load( + core, + std::filesystem::path(argc > 1 ? argv[1] : "assets/Sponza/Sponza.gltf"), + { + vkcv::asset::PrimitiveType::POSITION, + vkcv::asset::PrimitiveType::NORMAL, + vkcv::asset::PrimitiveType::TEXCOORD_0 + } ); - vkcv::PassHandle scenePass = core.createPass(scenePassDefinition); + vkcv::PassHandle scenePass = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat } + ); if (!scenePass) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; @@ -89,17 +83,15 @@ int main(int argc, const char** argv) { const vkcv::VertexLayout sceneLayout { bindings }; const auto& material0 = scene.getMaterial(0); - - const vkcv::GraphicsPipelineConfig scenePipelineDefinition{ - sceneShaderProgram, - UINT32_MAX, - UINT32_MAX, - scenePass, - {sceneLayout}, - { material0.getDescriptorSetLayout() }, - true - }; - vkcv::GraphicsPipelineHandle scenePipeline = core.createGraphicsPipeline(scenePipelineDefinition); + + vkcv::GraphicsPipelineHandle scenePipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + sceneShaderProgram, + scenePass, + { sceneLayout }, + { material0.getDescriptorSetLayout() } + ) + ); if (!scenePipeline) { std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; @@ -110,18 +102,8 @@ int main(int argc, const char** argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); - auto start = std::chrono::system_clock::now(); - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - if(window.getHeight() == 0 || window.getWidth() == 0) - continue; - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { - continue; - } - + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((!depthBuffer) || (swapchainWidth != core.getImageWidth(depthBuffer)) || (swapchainHeight != core.getImageHeight(depthBuffer))) { @@ -129,49 +111,42 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight - ).getHandle(); + ); } - - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - start = end; - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + cameraManager.update(dt); const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); auto recordMesh = [](const glm::mat4& MVP, const glm::mat4& M, vkcv::PushConstants &pushConstants, - vkcv::DrawcallInfo& drawcallInfo) { + vkcv::Drawcall& drawcall) { pushConstants.appendDrawcall(MVP); }; - scene.recordDrawcalls(cmdStream, - cameraManager.getActiveCamera(), - scenePass, - scenePipeline, - sizeof(glm::mat4), - recordMesh, - renderTargets, - windowHandle); + scene.recordDrawcalls( + cmdStream, + cameraManager.getActiveCamera(), + scenePass, + scenePipeline, + sizeof(glm::mat4), + recordMesh, + renderTargets, + windowHandle + ); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - auto stop = std::chrono::system_clock::now(); - auto kektime = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); - gui.beginGUI(); ImGui::Begin("Settings"); - ImGui::Text("Deltatime %fms, %f", 0.001 * static_cast<double>(kektime.count()), 1/(0.000001 * static_cast<double>(kektime.count()))); + ImGui::Text("Deltatime %fms, %f", dt * 1000, 1/dt); ImGui::End(); gui.endGUI(); - - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index c2d8bf817dd1d6b2c7cc069f2037ee090abc4415..18c62285959775b2097f4b72fb13bf789480c914 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -1,9 +1,10 @@ #include <iostream> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <vkcv/shader/GLSLCompiler.hpp> -#include <chrono> int main(int argc, const char** argv) { const char* applicationName = "First Triangle"; @@ -21,23 +22,19 @@ int main(int argc, const char** argv) { vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); vkcv::Window& window = core.getWindow(windowHandle); - auto triangleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, vkcv::BufferMemoryType::DEVICE_LOCAL); + auto triangleIndexBuffer = vkcv::buffer<uint16_t>(core, vkcv::BufferType::INDEX, 3); uint16_t indices[3] = { 0, 1, 2 }; triangleIndexBuffer.fill(&indices[0], sizeof(indices)); core.setDebugLabel(triangleIndexBuffer.getHandle(), "Triangle Index Buffer"); - // an example attachment for passes that output to the window - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat()); - - vkcv::PassConfig trianglePassDefinition({ present_color_attachment }, vkcv::Multisampling::None); - vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); + vkcv::PassHandle trianglePass = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined } + ); - if (!trianglePass) - { + if (!trianglePass) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; } @@ -52,77 +49,56 @@ int main(int argc, const char** argv) { { vkcv::ShaderStage::FRAGMENT, "shaders/shader.frag" } }, nullptr); - const vkcv::GraphicsPipelineConfig trianglePipelineDefinition { - triangleShaderProgram, - UINT32_MAX, - UINT32_MAX, - trianglePass, - {}, - {}, - true - }; - - vkcv::GraphicsPipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition); + vkcv::GraphicsPipelineHandle trianglePipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + triangleShaderProgram, + trianglePass, + {}, + {} + ) + ); - if (!trianglePipeline) - { + if (!trianglePipeline) { std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; return EXIT_FAILURE; } core.setDebugLabel(trianglePipeline, "Triangle Pipeline"); - - auto start = std::chrono::system_clock::now(); - const vkcv::Mesh renderMesh({}, triangleIndexBuffer.getVulkanHandle(), 3); - vkcv::DrawcallInfo drawcall(renderMesh, {},1); + vkcv::VertexData vertexData; + vertexData.setIndexBuffer(triangleIndexBuffer.getHandle()); + vertexData.setCount(3); + + vkcv::InstanceDrawcall drawcall (vertexData); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); - core.setDebugLabel(swapchainInput, "Swapchain Image"); vkcv::camera::CameraManager cameraManager(window); - uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); - uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); - cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2)); - cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, 0.0f)); - cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, -1.0f)); + cameraManager.getCamera(camIndex).setPosition(glm::vec3(0, 0, -2)); - while (vkcv::Window::hasOpenWindow()) - { - vkcv::Window::pollEvents(); - - uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { + cameraManager.update(dt); - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - start = end; - - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); - glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); - - vkcv::PushConstants pushConstants (sizeof(glm::mat4)); - pushConstants.appendDrawcall(mvp); + glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); core.setDebugLabel(cmdStream, "Render Commands"); - + core.recordDrawcallsToCmdStream( - cmdStream, - trianglePass, - trianglePipeline, - pushConstants, - { drawcall }, - { swapchainInput }, - windowHandle); - + cmdStream, + trianglePipeline, + vkcv::pushConstants<glm::mat4>(mvp), + { drawcall }, + { swapchainInput }, + windowHandle + ); + core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - - core.endFrame(windowHandle); - } + }); + return 0; } diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp index 89fb5e08d1c4a5ceec8c43f3c4043f8978d5d404..69daa8ba7c98523f9b287b210d5144cb154ec40b 100644 --- a/projects/head_demo/src/main.cpp +++ b/projects/head_demo/src/main.cpp @@ -1,5 +1,7 @@ #include <iostream> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <vkcv/gui/GUI.hpp> @@ -36,49 +38,19 @@ int main(int argc, const char** argv) { cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f); - vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path( - argc > 1 ? argv[1] : "assets/skull_scaled/scene.gltf" - )); - - vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; - - const vkcv::AttachmentDescription color_attachment0( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - colorFormat - ); - - const vkcv::AttachmentDescription depth_attachment0( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat - ); - - const vkcv::AttachmentDescription color_attachment1( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - colorFormat - ); - - const vkcv::AttachmentDescription depth_attachment1( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - vk::Format::eD32Sfloat - ); - - vkcv::PassConfig linePassDefinition( - { color_attachment0, depth_attachment0 }, - vkcv::Multisampling::None + vkcv::scene::Scene scene = vkcv::scene::Scene::load( + core, + std::filesystem::path(argc > 1 ? argv[1] : "assets/skull_scaled/scene.gltf"), + { + vkcv::asset::PrimitiveType::POSITION, + vkcv::asset::PrimitiveType::NORMAL + } ); - vkcv::PassHandle linePass = core.createPass(linePassDefinition); - - vkcv::PassConfig scenePassDefinition( - { color_attachment1, depth_attachment1 }, - vkcv::Multisampling::None - ); + vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; - vkcv::PassHandle scenePass = core.createPass(scenePassDefinition); + vkcv::PassHandle linePass = vkcv::passFormats(core, { colorFormat, vk::Format::eD32Sfloat }); + vkcv::PassHandle scenePass = vkcv::passFormats(core, { colorFormat, vk::Format::eD32Sfloat }, false); if ((!scenePass) || (!linePass)) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; @@ -118,7 +90,7 @@ int main(int argc, const char** argv) { float clipY = 0.0f; float clipZ = 0.0f; - auto clipBuffer = core.createBuffer<float>(vkcv::BufferType::UNIFORM, 4); + auto clipBuffer = vkcv::buffer<float>(core, vkcv::BufferType::UNIFORM, 4); clipBuffer.fill({ clipLimit, -clipX, -clipY, -clipZ }); vkcv::DescriptorWrites clipWrites; @@ -151,85 +123,66 @@ int main(int argc, const char** argv) { const vkcv::VertexLayout sceneLayout { bindings }; const auto& material0 = scene.getMaterial(0); - const vkcv::GraphicsPipelineConfig scenePipelineDefinition{ - sceneShaderProgram, - UINT32_MAX, - UINT32_MAX, - scenePass, - {sceneLayout}, - { material0.getDescriptorSetLayout(), clipDescriptorSetLayout }, - true - }; - - const vkcv::GraphicsPipelineConfig linePipelineDefinition{ - lineShaderProgram, - UINT32_MAX, - UINT32_MAX, - linePass, - {sceneLayout}, - { material0.getDescriptorSetLayout(), clipDescriptorSetLayout }, - true - }; - - vkcv::GraphicsPipelineHandle scenePipeline = core.createGraphicsPipeline(scenePipelineDefinition); - vkcv::GraphicsPipelineHandle linePipeline = core.createGraphicsPipeline(linePipelineDefinition); + vkcv::GraphicsPipelineHandle scenePipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + sceneShaderProgram, + scenePass, + { sceneLayout }, + { material0.getDescriptorSetLayout(), clipDescriptorSetLayout } + ) + ); + + vkcv::GraphicsPipelineHandle linePipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + lineShaderProgram, + linePass, + { sceneLayout }, + { material0.getDescriptorSetLayout(), clipDescriptorSetLayout } + ) + ); if ((!scenePipeline) || (!linePipeline)) { std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; return EXIT_FAILURE; } - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain()); vkcv::ImageHandle depthBuffer = core.createImage( vk::Format::eD32Sfloat, swapchainExtent.width, swapchainExtent.height - ).getHandle(); + ); vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, swapchainExtent.width, swapchainExtent.height, 1, false, true, true - ).getHandle(); + ); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); vkcv::upscaling::FSRUpscaling upscaling (core); - auto start = std::chrono::system_clock::now(); - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - if(window.getHeight() == 0 || window.getWidth() == 0) - continue; - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { - continue; - } - + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight); colorBuffer = core.createImage( colorFormat, swapchainExtent.width, swapchainExtent.height, 1, false, true, true - ).getHandle(); + ); swapchainExtent.width = swapchainWidth; swapchainExtent.height = swapchainHeight; } - - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - - start = end; - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + cameraManager.update(dt); clipBuffer.fill({ clipLimit, -clipX, -clipY, -clipZ }); @@ -238,32 +191,34 @@ int main(int argc, const char** argv) { auto recordMesh = [&](const glm::mat4& MVP, const glm::mat4& M, vkcv::PushConstants &pushConstants, - vkcv::DrawcallInfo& drawcallInfo) { + vkcv::Drawcall& drawcall) { pushConstants.appendDrawcall(MVP); - drawcallInfo.descriptorSets.push_back( - vkcv::DescriptorSetUsage(1, clipDescriptorSet) - ); + drawcall.useDescriptorSet(1, clipDescriptorSet); }; - scene.recordDrawcalls(cmdStream, - cameraManager.getActiveCamera(), - linePass, - linePipeline, - sizeof(glm::mat4), - recordMesh, - renderTargets, - windowHandle); + scene.recordDrawcalls( + cmdStream, + cameraManager.getActiveCamera(), + linePass, + linePipeline, + sizeof(glm::mat4), + recordMesh, + renderTargets, + windowHandle + ); bloomAndFlares.recordEffect(cmdStream, colorBuffer, colorBuffer); - scene.recordDrawcalls(cmdStream, - cameraManager.getActiveCamera(), - scenePass, - scenePipeline, - sizeof(glm::mat4), - recordMesh, - renderTargets, - windowHandle); + scene.recordDrawcalls( + cmdStream, + cameraManager.getActiveCamera(), + scenePass, + scenePipeline, + sizeof(glm::mat4), + recordMesh, + renderTargets, + windowHandle + ); core.prepareImageForSampling(cmdStream, colorBuffer); core.prepareImageForStorage(cmdStream, swapchainInput); @@ -272,9 +227,6 @@ int main(int argc, const char** argv) { core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - auto stop = std::chrono::system_clock::now(); - auto kektime = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); - gui.beginGUI(); ImGui::Begin("Settings"); @@ -285,9 +237,7 @@ int main(int argc, const char** argv) { ImGui::End(); gui.endGUI(); - - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index e6885b8e7dfa71c00335dbb2cee5c5994ce4eccc..c52acec190bb1a6e405107b4b231922fc6bad846 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -1,7 +1,10 @@ #include "App.hpp" #include "AppConfig.hpp" -#include <chrono> + +#include <vkcv/Sampler.hpp> #include <vkcv/gui/GUI.hpp> + +#include <chrono> #include <functional> const char* MotionVectorVisualisationModeLabels[6] = { @@ -60,12 +63,7 @@ bool App::initialize() { if (!m_motionBlur.initialize(&m_core, m_windowWidth, m_windowHeight)) return false; - m_linearSampler = m_core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE); - + m_linearSampler = vkcv::samplerLinear(m_core, true); m_renderTargets = createRenderTargets(m_core, m_windowWidth, m_windowHeight); const int cameraIndex = m_cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); @@ -82,10 +80,10 @@ bool App::initialize() { void App::run() { - auto frameStartTime = std::chrono::system_clock::now(); - const auto appStartTime = std::chrono::system_clock::now(); - const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); - const vkcv::DrawcallInfo skyDrawcall(m_cubeMesh.mesh, {}, 1); + auto frameStartTime = std::chrono::system_clock::now(); + const auto appStartTime = std::chrono::system_clock::now(); + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + const vkcv::InstanceDrawcall skyDrawcall(m_cubeMesh.mesh); vkcv::gui::GUI gui(m_core, m_windowHandle); @@ -216,14 +214,13 @@ void App::run() { m_renderTargets.motionBuffer, m_renderTargets.depthBuffer }; - std::vector<vkcv::DrawcallInfo> prepassSceneDrawcalls; + std::vector<vkcv::InstanceDrawcall> prepassSceneDrawcalls; for (const Object& obj : sceneObjects) { - prepassSceneDrawcalls.push_back(vkcv::DrawcallInfo(obj.meshResources.mesh, {})); + prepassSceneDrawcalls.push_back(vkcv::InstanceDrawcall(obj.meshResources.mesh)); } m_core.recordDrawcallsToCmdStream( cmdStream, - m_prePass.renderPass, m_prePass.pipeline, prepassPushConstants, prepassSceneDrawcalls, @@ -239,7 +236,6 @@ void App::run() { m_core.recordDrawcallsToCmdStream( cmdStream, - m_skyPrePass.renderPass, m_skyPrePass.pipeline, skyPrepassPushConstants, { skyDrawcall }, @@ -257,16 +253,15 @@ void App::run() { meshPushConstants.appendDrawcall(matrices); } - std::vector<vkcv::DrawcallInfo> forwardSceneDrawcalls; + std::vector<vkcv::InstanceDrawcall> forwardSceneDrawcalls; for (const Object& obj : sceneObjects) { - forwardSceneDrawcalls.push_back(vkcv::DrawcallInfo( - obj.meshResources.mesh, - { vkcv::DescriptorSetUsage(0, m_meshPass.descriptorSet) })); + vkcv::InstanceDrawcall drawcall (obj.meshResources.mesh); + drawcall.useDescriptorSet(0, m_meshPass.descriptorSet); + forwardSceneDrawcalls.push_back(drawcall); } m_core.recordDrawcallsToCmdStream( cmdStream, - m_meshPass.renderPass, m_meshPass.pipeline, meshPushConstants, forwardSceneDrawcalls, @@ -274,12 +269,11 @@ void App::run() { m_windowHandle); // sky - vkcv::PushConstants skyPushConstants(sizeof(glm::mat4)); + vkcv::PushConstants skyPushConstants = vkcv::pushConstants<glm::mat4>(); skyPushConstants.appendDrawcall(viewProjection); m_core.recordDrawcallsToCmdStream( cmdStream, - m_skyPass.renderPass, m_skyPass.pipeline, skyPushConstants, { skyDrawcall }, @@ -303,7 +297,7 @@ void App::run() { cameraNear, cameraFar, fDeltaTimeSeconds, - cameraShutterSpeedInverse, + static_cast<float>(cameraShutterSpeedInverse), motionBlurTileOffsetLength, motionBlurFastPathThreshold); } @@ -326,16 +320,16 @@ void App::run() { m_core.prepareImageForSampling(cmdStream, motionBlurOutput); m_core.prepareImageForStorage (cmdStream, swapchainInput); - const uint32_t fullScreenImageDispatch[3] = { - static_cast<uint32_t>((m_windowWidth + 7) / 8), - static_cast<uint32_t>((m_windowHeight + 7) / 8), - static_cast<uint32_t>(1) }; + const auto fullScreenImageDispatch = vkcv::dispatchInvocations( + vkcv::DispatchSize(m_windowWidth, m_windowHeight), + vkcv::DispatchSize(8, 8) + ); m_core.recordComputeDispatchToCmdStream( cmdStream, m_gammaCorrectionPass.pipeline, fullScreenImageDispatch, - { vkcv::DescriptorSetUsage(0, m_gammaCorrectionPass.descriptorSet) }, + { vkcv::useDescriptorSet(0, m_gammaCorrectionPass.descriptorSet) }, vkcv::PushConstants(0)); m_core.prepareSwapchainImageForPresent(cmdStream); diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp index 933f20db73313e25bc9e4863f2bf4530df26a366..26cfbbc38e2a190326b8a17adde5b8e4f44ec1cc 100644 --- a/projects/indirect_dispatch/src/AppSetup.cpp +++ b/projects/indirect_dispatch/src/AppSetup.cpp @@ -1,5 +1,8 @@ #include "AppSetup.hpp" #include "AppConfig.hpp" + +#include <vkcv/Buffer.hpp> +#include <vkcv/Image.hpp> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -23,12 +26,14 @@ bool loadMesh(vkcv::Core& core, const std::filesystem::path& path, MeshResources auto& vertexData = scene.vertexGroups[0].vertexBuffer; auto& indexData = scene.vertexGroups[0].indexBuffer; - vkcv::Buffer vertexBuffer = core.createBuffer<uint8_t>( + vkcv::Buffer<uint8_t> vertexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::VERTEX, vertexData.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL); - vkcv::Buffer indexBuffer = core.createBuffer<uint8_t>( + vkcv::Buffer<uint8_t> indexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::INDEX, indexData.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL); @@ -38,20 +43,20 @@ bool loadMesh(vkcv::Core& core, const std::filesystem::path& path, MeshResources outMesh->vertexBuffer = vertexBuffer.getHandle(); outMesh->indexBuffer = indexBuffer.getHandle(); - - auto& attributes = vertexData.attributes; - - std::sort(attributes.begin(), attributes.end(), - [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); - - const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; - - outMesh->mesh = vkcv::Mesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), scene.vertexGroups[0].numIndices); + + const auto vertexBufferBindings = vkcv::asset::loadVertexBufferBindings( + vertexData.attributes, + vertexBuffer.getHandle(), + { + vkcv::asset::PrimitiveType::POSITION, + vkcv::asset::PrimitiveType::NORMAL, + vkcv::asset::PrimitiveType::TEXCOORD_0 + } + ); + + outMesh->mesh = vkcv::VertexData(vertexBufferBindings); + outMesh->mesh.setIndexBuffer(indexBuffer.getHandle()); + outMesh->mesh.setCount(scene.vertexGroups[0].numIndices); return true; } @@ -67,12 +72,14 @@ bool loadImage(vkcv::Core& core, const std::filesystem::path& path, vkcv::ImageH return false; } - vkcv::Image image = core.createImage( - vk::Format::eR8G8B8A8Srgb, - textureData.width, - textureData.height, - 1, - true); + vkcv::Image image = vkcv::image( + core, + vk::Format::eR8G8B8A8Srgb, + textureData.width, + textureData.height, + 1, + true + ); image.fill(textureData.data.data(), textureData.data.size()); @@ -133,19 +140,16 @@ bool loadGraphicPass( outPassHandles->descriptorSet = core.createDescriptorSet(outPassHandles->descriptorSetLayout); descriptorSetLayouts.push_back(outPassHandles->descriptorSetLayout); } - - - vkcv::GraphicsPipelineConfig pipelineConfig{ + + vkcv::GraphicsPipelineConfig pipelineConfig( shaderProgram, - UINT32_MAX, - UINT32_MAX, outPassHandles->renderPass, { vertexLayout }, - descriptorSetLayouts, - true - }; - pipelineConfig.m_depthTest = depthTest; - outPassHandles->pipeline = core.createGraphicsPipeline(pipelineConfig); + descriptorSetLayouts + ); + + pipelineConfig.setDepthTest(depthTest); + outPassHandles->pipeline = core.createGraphicsPipeline(pipelineConfig); if (!outPassHandles->pipeline) { vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create graphics pipeline"); @@ -160,14 +164,16 @@ bool loadMeshPass(vkcv::Core& core, GraphicPassHandles* outHandles) { assert(outHandles); vkcv::AttachmentDescription colorAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::DONT_CARE, - AppConfig::colorBufferFormat); + AppConfig::colorBufferFormat, + vkcv::AttachmentOperation::DONT_CARE, + vkcv::AttachmentOperation::STORE + ); vkcv::AttachmentDescription depthAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - AppConfig::depthBufferFormat); + AppConfig::depthBufferFormat, + vkcv::AttachmentOperation::LOAD, + vkcv::AttachmentOperation::STORE + ); return loadGraphicPass( core, @@ -186,14 +192,16 @@ bool loadSkyPass(vkcv::Core& core, GraphicPassHandles* outHandles) { assert(outHandles); vkcv::AttachmentDescription colorAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - AppConfig::colorBufferFormat); + AppConfig::colorBufferFormat, + vkcv::AttachmentOperation::LOAD, + vkcv::AttachmentOperation::STORE + ); vkcv::AttachmentDescription depthAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - AppConfig::depthBufferFormat); + AppConfig::depthBufferFormat, + vkcv::AttachmentOperation::LOAD, + vkcv::AttachmentOperation::STORE + ); return loadGraphicPass( core, @@ -211,14 +219,16 @@ bool loadPrePass(vkcv::Core& core, GraphicPassHandles* outHandles) { assert(outHandles); vkcv::AttachmentDescription motionAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - AppConfig::motionBufferFormat); + AppConfig::motionBufferFormat, + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE + ); vkcv::AttachmentDescription depthAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - AppConfig::depthBufferFormat); + AppConfig::depthBufferFormat, + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE + ); return loadGraphicPass( core, @@ -236,14 +246,16 @@ bool loadSkyPrePass(vkcv::Core& core, GraphicPassHandles* outHandles) { assert(outHandles); vkcv::AttachmentDescription motionAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - AppConfig::motionBufferFormat); + AppConfig::motionBufferFormat, + vkcv::AttachmentOperation::LOAD, + vkcv::AttachmentOperation::STORE + ); vkcv::AttachmentDescription depthAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - AppConfig::depthBufferFormat); + AppConfig::depthBufferFormat, + vkcv::AttachmentOperation::LOAD, + vkcv::AttachmentOperation::STORE + ); return loadGraphicPass( core, @@ -288,7 +300,6 @@ bool loadComputePass(vkcv::Core& core, const std::filesystem::path& path, Comput } AppRenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const uint32_t height) { - AppRenderTargets targets; targets.depthBuffer = core.createImage( @@ -296,7 +307,8 @@ AppRenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, con width, height, 1, - false).getHandle(); + false + ); targets.colorBuffer = core.createImage( AppConfig::colorBufferFormat, @@ -305,7 +317,8 @@ AppRenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, con 1, false, false, - true).getHandle(); + true + ); targets.motionBuffer = core.createImage( AppConfig::motionBufferFormat, @@ -314,7 +327,8 @@ AppRenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, con 1, false, false, - true).getHandle(); + true + ); return targets; } \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppSetup.hpp b/projects/indirect_dispatch/src/AppSetup.hpp index b0ade4317b125fea581016bf9924cd740a443c35..41e020c357a3d868775a581170596e1748e39700 100644 --- a/projects/indirect_dispatch/src/AppSetup.hpp +++ b/projects/indirect_dispatch/src/AppSetup.hpp @@ -21,7 +21,7 @@ struct ComputePassHandles { }; struct MeshResources { - vkcv::Mesh mesh; + vkcv::VertexData mesh; vkcv::BufferHandle vertexBuffer; vkcv::BufferHandle indexBuffer; }; diff --git a/projects/indirect_dispatch/src/MotionBlur.cpp b/projects/indirect_dispatch/src/MotionBlur.cpp index c9345684225e64f792a13ade2e5d11297ab7c444..fe55a5821b042feb709deffee806513b18ed06ba 100644 --- a/projects/indirect_dispatch/src/MotionBlur.cpp +++ b/projects/indirect_dispatch/src/MotionBlur.cpp @@ -1,19 +1,11 @@ #include "MotionBlur.hpp" #include "MotionBlurConfig.hpp" #include "MotionBlurSetup.hpp" -#include <array> -std::array<uint32_t, 3> computeFullscreenDispatchSize( - const uint32_t imageWidth, - const uint32_t imageHeight, - const uint32_t localGroupSize) { +#include <vkcv/Buffer.hpp> +#include <vkcv/Sampler.hpp> - // optimized divide and ceil - return std::array<uint32_t, 3>{ - static_cast<uint32_t>(imageWidth + (localGroupSize - 1)) / localGroupSize, - static_cast<uint32_t>(imageHeight + (localGroupSize - 1)) / localGroupSize, - static_cast<uint32_t>(1) }; -} +#include <array> bool MotionBlur::initialize(vkcv::Core* corePtr, const uint32_t targetWidth, const uint32_t targetHeight) { @@ -56,23 +48,23 @@ bool MotionBlur::initialize(vkcv::Core* corePtr, const uint32_t targetWidth, con ((MotionBlurConfig::maxWidth + MotionBlurConfig::maxMotionTileSize - 1) / MotionBlurConfig::maxMotionTileSize) * ((MotionBlurConfig::maxHeight + MotionBlurConfig::maxMotionTileSize - 1) / MotionBlurConfig::maxMotionTileSize)); - m_copyPathWorkTileBuffer = m_core->createBuffer<uint32_t>( - vkcv::BufferType::STORAGE, + m_copyPathWorkTileBuffer = vkcv::buffer<uint32_t>( + *m_core, + vkcv::BufferType::INDIRECT, workTileBufferSize, - vkcv::BufferMemoryType::DEVICE_LOCAL, - true).getHandle(); + vkcv::BufferMemoryType::DEVICE_LOCAL).getHandle(); - m_fullPathWorkTileBuffer = m_core->createBuffer<uint32_t>( - vkcv::BufferType::STORAGE, + m_fullPathWorkTileBuffer = vkcv::buffer<uint32_t>( + *m_core, + vkcv::BufferType::INDIRECT, workTileBufferSize, - vkcv::BufferMemoryType::DEVICE_LOCAL, - true).getHandle(); + vkcv::BufferMemoryType::DEVICE_LOCAL).getHandle(); - m_fastPathWorkTileBuffer = m_core->createBuffer<uint32_t>( - vkcv::BufferType::STORAGE, + m_fastPathWorkTileBuffer = vkcv::buffer<uint32_t>( + *m_core, + vkcv::BufferType::INDIRECT, workTileBufferSize, - vkcv::BufferMemoryType::DEVICE_LOCAL, - true).getHandle(); + vkcv::BufferMemoryType::DEVICE_LOCAL).getHandle(); vkcv::DescriptorWrites tileResetDescriptorWrites; tileResetDescriptorWrites.writeStorageBuffer( @@ -87,11 +79,7 @@ bool MotionBlur::initialize(vkcv::Core* corePtr, const uint32_t targetWidth, con m_renderTargets = MotionBlurSetup::createRenderTargets(targetWidth, targetHeight, *m_core); - m_nearestSampler = m_core->createSampler( - vkcv::SamplerFilterType::NEAREST, - vkcv::SamplerFilterType::NEAREST, - vkcv::SamplerMipmapMode::NEAREST, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE); + m_nearestSampler = vkcv::samplerNearest(*m_core, true); return true; } @@ -115,15 +103,13 @@ vkcv::ImageHandle MotionBlur::render( computeMotionTiles(cmdStream, motionBufferFullRes); - // work tile reset - const uint32_t dispatchSizeOne[3] = { 1, 1, 1 }; - m_core->recordComputeDispatchToCmdStream( cmdStream, m_tileResetPass.pipeline, - dispatchSizeOne, - { vkcv::DescriptorSetUsage(0, m_tileResetPass.descriptorSet) }, - vkcv::PushConstants(0)); + 1, + { vkcv::useDescriptorSet(0, m_tileResetPass.descriptorSet) }, + vkcv::PushConstants(0) + ); m_core->recordBufferMemoryBarrier(cmdStream, m_fullPathWorkTileBuffer); m_core->recordBufferMemoryBarrier(cmdStream, m_copyPathWorkTileBuffer); @@ -148,10 +134,13 @@ vkcv::ImageHandle MotionBlur::render( m_core->writeDescriptorSet(m_tileClassificationPass.descriptorSet, tileClassificationDescriptorWrites); - const auto tileClassificationDispatch = computeFullscreenDispatchSize( - m_core->getImageWidth(m_renderTargets.motionMaxNeighbourhood), - m_core->getImageHeight(m_renderTargets.motionMaxNeighbourhood), - 8); + const auto tileClassificationDispatch = vkcv::dispatchInvocations( + vkcv::DispatchSize( + m_core->getImageWidth(m_renderTargets.motionMaxNeighbourhood), + m_core->getImageHeight(m_renderTargets.motionMaxNeighbourhood) + ), + vkcv::DispatchSize(8, 8) + ); struct ClassificationConstants { uint32_t width; @@ -163,7 +152,7 @@ vkcv::ImageHandle MotionBlur::render( classificationConstants.height = m_core->getImageHeight(m_renderTargets.outputColor); classificationConstants.fastPathThreshold = fastPathThreshold; - vkcv::PushConstants classificationPushConstants(sizeof(ClassificationConstants)); + vkcv::PushConstants classificationPushConstants = vkcv::pushConstants<ClassificationConstants>(); classificationPushConstants.appendDrawcall(classificationConstants); m_core->prepareImageForSampling(cmdStream, m_renderTargets.motionMaxNeighbourhood); @@ -172,8 +161,8 @@ vkcv::ImageHandle MotionBlur::render( m_core->recordComputeDispatchToCmdStream( cmdStream, m_tileClassificationPass.pipeline, - tileClassificationDispatch.data(), - { vkcv::DescriptorSetUsage(0, m_tileClassificationPass.descriptorSet) }, + tileClassificationDispatch, + { vkcv::useDescriptorSet(0, m_tileClassificationPass.descriptorSet) }, classificationPushConstants); m_core->recordBufferMemoryBarrier(cmdStream, m_fullPathWorkTileBuffer); @@ -235,7 +224,7 @@ vkcv::ImageHandle MotionBlur::render( motionBlurConstantData.cameraFarPlane = cameraFar; motionBlurConstantData.motionTileOffsetLength = motionTileOffsetLength; - vkcv::PushConstants motionBlurPushConstants(sizeof(motionBlurConstantData)); + vkcv::PushConstants motionBlurPushConstants = vkcv::pushConstants<MotionBlurConstantData>(); motionBlurPushConstants.appendDrawcall(motionBlurConstantData); struct FastPathConstants { @@ -244,7 +233,7 @@ vkcv::ImageHandle MotionBlur::render( FastPathConstants fastPathConstants; fastPathConstants.motionFactor = motionBlurConstantData.motionFactor; - vkcv::PushConstants fastPathPushConstants(sizeof(FastPathConstants)); + vkcv::PushConstants fastPathPushConstants = vkcv::pushConstants<FastPathConstants>(); fastPathPushConstants.appendDrawcall(fastPathConstants); m_core->prepareImageForStorage(cmdStream, m_renderTargets.outputColor); @@ -258,7 +247,7 @@ vkcv::ImageHandle MotionBlur::render( m_motionBlurPass.pipeline, m_fullPathWorkTileBuffer, 0, - { vkcv::DescriptorSetUsage(0, m_motionBlurPass.descriptorSet) }, + { vkcv::useDescriptorSet(0, m_motionBlurPass.descriptorSet) }, motionBlurPushConstants); m_core->recordComputeIndirectDispatchToCmdStream( @@ -266,7 +255,7 @@ vkcv::ImageHandle MotionBlur::render( m_colorCopyPass.pipeline, m_copyPathWorkTileBuffer, 0, - { vkcv::DescriptorSetUsage(0, m_colorCopyPass.descriptorSet) }, + { vkcv::useDescriptorSet(0, m_colorCopyPass.descriptorSet) }, vkcv::PushConstants(0)); m_core->recordComputeIndirectDispatchToCmdStream( @@ -274,7 +263,7 @@ vkcv::ImageHandle MotionBlur::render( m_motionBlurFastPathPass.pipeline, m_fastPathWorkTileBuffer, 0, - { vkcv::DescriptorSetUsage(0, m_motionBlurFastPathPass.descriptorSet) }, + { vkcv::useDescriptorSet(0, m_motionBlurFastPathPass.descriptorSet) }, fastPathPushConstants); } else if(mode == eMotionBlurMode::Disabled) { @@ -301,16 +290,11 @@ vkcv::ImageHandle MotionBlur::render( (m_core->getImageWidth(m_renderTargets.outputColor) + MotionBlurConfig::maxMotionTileSize - 1) / MotionBlurConfig::maxMotionTileSize * (m_core->getImageHeight(m_renderTargets.outputColor) + MotionBlurConfig::maxMotionTileSize - 1) / MotionBlurConfig::maxMotionTileSize; - const uint32_t dispatchCounts[3] = { - tileCount, - 1, - 1 }; - m_core->recordComputeDispatchToCmdStream( cmdStream, m_tileVisualisationPass.pipeline, - dispatchCounts, - { vkcv::DescriptorSetUsage(0, m_tileVisualisationPass.descriptorSet) }, + tileCount, + { vkcv::useDescriptorSet(0, m_tileVisualisationPass.descriptorSet) }, vkcv::PushConstants(0)); } else { @@ -361,19 +345,22 @@ vkcv::ImageHandle MotionBlur::renderMotionVectorVisualisation( m_core->prepareImageForSampling(cmdStream, visualisationInput); m_core->prepareImageForStorage(cmdStream, m_renderTargets.outputColor); - vkcv::PushConstants motionVectorVisualisationPushConstants(sizeof(float)); + vkcv::PushConstants motionVectorVisualisationPushConstants = vkcv::pushConstants<float>(); motionVectorVisualisationPushConstants.appendDrawcall(velocityRange); - const auto dispatchSizes = computeFullscreenDispatchSize( - m_core->getImageWidth(m_renderTargets.outputColor), - m_core->getImageHeight(m_renderTargets.outputColor), - 8); + const auto dispatchSizes = vkcv::dispatchInvocations( + vkcv::DispatchSize( + m_core->getImageWidth(m_renderTargets.outputColor), + m_core->getImageHeight(m_renderTargets.outputColor) + ), + vkcv::DispatchSize(8, 8) + ); m_core->recordComputeDispatchToCmdStream( cmdStream, m_motionVectorVisualisationPass.pipeline, - dispatchSizes.data(), - { vkcv::DescriptorSetUsage(0, m_motionVectorVisualisationPass.descriptorSet) }, + dispatchSizes, + { vkcv::useDescriptorSet(0, m_motionVectorVisualisationPass.descriptorSet) }, motionVectorVisualisationPushConstants); return m_renderTargets.outputColor; @@ -399,16 +386,19 @@ void MotionBlur::computeMotionTiles( m_core->prepareImageForStorage(cmdStream, m_renderTargets.motionMax); m_core->prepareImageForStorage(cmdStream, m_renderTargets.motionMin); - const std::array<uint32_t, 3> motionTileDispatchCounts = computeFullscreenDispatchSize( - m_core->getImageWidth( m_renderTargets.motionMax), - m_core->getImageHeight(m_renderTargets.motionMax), - 8); + const auto motionTileDispatchCounts = vkcv::dispatchInvocations( + vkcv::DispatchSize( + m_core->getImageWidth( m_renderTargets.motionMax), + m_core->getImageHeight(m_renderTargets.motionMax) + ), + vkcv::DispatchSize(8, 8) + ); m_core->recordComputeDispatchToCmdStream( cmdStream, m_motionVectorMinMaxPass.pipeline, - motionTileDispatchCounts.data(), - { vkcv::DescriptorSetUsage(0, m_motionVectorMinMaxPass.descriptorSet) }, + motionTileDispatchCounts, + { vkcv::useDescriptorSet(0, m_motionVectorMinMaxPass.descriptorSet) }, vkcv::PushConstants(0)); // motion vector min max neighbourhood @@ -437,7 +427,7 @@ void MotionBlur::computeMotionTiles( m_core->recordComputeDispatchToCmdStream( cmdStream, m_motionVectorMinMaxNeighbourhoodPass.pipeline, - motionTileDispatchCounts.data(), - { vkcv::DescriptorSetUsage(0, m_motionVectorMinMaxNeighbourhoodPass.descriptorSet) }, + motionTileDispatchCounts, + { vkcv::useDescriptorSet(0, m_motionVectorMinMaxNeighbourhoodPass.descriptorSet) }, vkcv::PushConstants(0)); } \ No newline at end of file diff --git a/projects/indirect_dispatch/src/MotionBlurSetup.cpp b/projects/indirect_dispatch/src/MotionBlurSetup.cpp index 82d2593a5b976f9389b58dddac43e3a45d1db303..0244c4ae9519ea6c6f818e024930e70c15e7a289 100644 --- a/projects/indirect_dispatch/src/MotionBlurSetup.cpp +++ b/projects/indirect_dispatch/src/MotionBlurSetup.cpp @@ -17,7 +17,8 @@ MotionBlurRenderTargets createRenderTargets(const uint32_t width, const uint32_t motionMaxheight, 1, false, - true).getHandle(); + true + ); targets.motionMaxNeighbourhood = core.createImage( MotionBlurConfig::motionVectorTileFormat, @@ -25,7 +26,8 @@ MotionBlurRenderTargets createRenderTargets(const uint32_t width, const uint32_t motionMaxheight, 1, false, - true).getHandle(); + true + ); targets.motionMin = core.createImage( MotionBlurConfig::motionVectorTileFormat, @@ -33,7 +35,8 @@ MotionBlurRenderTargets createRenderTargets(const uint32_t width, const uint32_t motionMaxheight, 1, false, - true).getHandle(); + true + ); targets.motionMinNeighbourhood = core.createImage( MotionBlurConfig::motionVectorTileFormat, @@ -41,7 +44,8 @@ MotionBlurRenderTargets createRenderTargets(const uint32_t width, const uint32_t motionMaxheight, 1, false, - true).getHandle(); + true + ); targets.outputColor = core.createImage( MotionBlurConfig::outputColorFormat, @@ -49,7 +53,8 @@ MotionBlurRenderTargets createRenderTargets(const uint32_t width, const uint32_t height, 1, false, - true).getHandle(); + true + ); return targets; } diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp index 26f523958e9704d7fc090ceba818591d904a2e92..39c5621e2d1a062d86adbf77bef49cb3f639fdae 100644 --- a/projects/indirect_draw/src/main.cpp +++ b/projects/indirect_draw/src/main.cpp @@ -1,7 +1,10 @@ #include <iostream> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> +#include <vkcv/Image.hpp> #include <vkcv/camera/CameraManager.hpp> -#include <chrono> #include <vkcv/gui/GUI.hpp> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -87,28 +90,33 @@ struct CompiledMaterial void interleaveScene(vkcv::asset::Scene scene, std::vector<std::vector<Vertex>> &interleavedVertexBuffers, - std::vector<glm::vec4> &boundingBoxBuffers) -{ - for(const auto &mesh : scene.meshes) - { - for(auto vertexGroupIndex : mesh.vertexGroups) - { - // Sort attributes to fix it! - auto& attributes = scene.vertexGroups[vertexGroupIndex].vertexBuffer.attributes; + std::vector<glm::vec4> &boundingBoxBuffers) { - std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); - + for(const auto &mesh : scene.meshes) { + for(auto vertexGroupIndex : mesh.vertexGroups) { const auto &vertexGroup = scene.vertexGroups[vertexGroupIndex]; - const vkcv::asset::VertexAttribute positionAttribute = vertexGroup.vertexBuffer.attributes[0]; - const vkcv::asset::VertexAttribute normalAttribute = vertexGroup.vertexBuffer.attributes[1]; - const vkcv::asset::VertexAttribute uvAttribute = vertexGroup.vertexBuffer.attributes[2]; - - assert(positionAttribute.type == vkcv::asset::PrimitiveType::POSITION); - assert(normalAttribute.type == vkcv::asset::PrimitiveType::NORMAL); - assert(uvAttribute.type == vkcv::asset::PrimitiveType::TEXCOORD_0); + const vkcv::asset::VertexAttribute* positionAttribute = nullptr; + const vkcv::asset::VertexAttribute* normalAttribute = nullptr; + const vkcv::asset::VertexAttribute* uvAttribute = nullptr; + + for (const auto& attribute : vertexGroup.vertexBuffer.attributes) { + switch (attribute.type) { + case vkcv::asset::PrimitiveType::POSITION: + positionAttribute = &attribute; + break; + case vkcv::asset::PrimitiveType::NORMAL: + normalAttribute = &attribute; + break; + case vkcv::asset::PrimitiveType::TEXCOORD_0: + uvAttribute = &attribute; + break; + default: + break; + } + } + + assert(positionAttribute && normalAttribute && uvAttribute); const uint64_t &verticesCount = vertexGroup.numVertices; const std::vector<uint8_t> &vertexData = vertexGroup.vertexBuffer.data; @@ -116,18 +124,18 @@ void interleaveScene(vkcv::asset::Scene scene, std::vector<Vertex> vertices; vertices.reserve(verticesCount); - const size_t positionStride = positionAttribute.stride == 0 ? sizeof(glm::vec3) : positionAttribute.stride; - const size_t normalStride = normalAttribute.stride == 0 ? sizeof(glm::vec3) : normalAttribute.stride; - const size_t uvStride = uvAttribute.stride == 0 ? sizeof(glm::vec2) : uvAttribute.stride; + const size_t positionStride = positionAttribute->stride == 0 ? sizeof(glm::vec3) : positionAttribute->stride; + const size_t normalStride = normalAttribute->stride == 0 ? sizeof(glm::vec3) : normalAttribute->stride; + const size_t uvStride = uvAttribute->stride == 0 ? sizeof(glm::vec2) : uvAttribute->stride; glm::vec3 max_pos(-std::numeric_limits<float>::max()); glm::vec3 min_pos(std::numeric_limits<float>::max()); for(size_t i = 0; i < verticesCount; i++) { - const size_t positionOffset = positionAttribute.offset + positionStride * i; - const size_t normalOffset = normalAttribute.offset + normalStride * i; - const size_t uvOffset = uvAttribute.offset + uvStride * i; + const size_t positionOffset = positionAttribute->offset + positionStride * i; + const size_t normalOffset = normalAttribute->offset + normalStride * i; + const size_t uvOffset = uvAttribute->offset + uvStride * i; Vertex v; @@ -169,7 +177,7 @@ void compileMeshForIndirectDraw(vkcv::Core &core, CompiledMaterial &compiledMat, std::vector<vk::DrawIndexedIndirectCommand> &indexedIndirectCommands) { - vkcv::Image pseudoImg = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); + vkcv::Image pseudoImg = vkcv::image(core, vk::Format::eR8G8B8A8Srgb, 2, 2); std::vector<uint8_t> pseudoData = {0, 0, 0, 0}; pseudoImg.fill(pseudoData.data()); @@ -194,7 +202,7 @@ void compileMeshForIndirectDraw(vkcv::Core &core, { auto &baseColor = scene.textures[material.baseColor]; - vkcv::Image baseColorImg = core.createImage(vk::Format::eR8G8B8A8Srgb, baseColor.w, baseColor.h); + vkcv::Image baseColorImg = vkcv::image(core, vk::Format::eR8G8B8A8Srgb, baseColor.w, baseColor.h); baseColorImg.fill(baseColor.data.data()); baseColorImg.recordMipChainGeneration(mipStream, core.getDownsampler()); @@ -306,6 +314,7 @@ int main(int argc, const char** argv) { ); vkcv::WindowHandle windowHandle = core.createWindow(applicationName,800,600,true); + vkcv::Window& window = core.getWindow(windowHandle); vkcv::gui::GUI gui (core, windowHandle); @@ -326,19 +335,12 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat() - ); - const vkcv::AttachmentDescription depth_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat + vkcv::PassHandle passHandle = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat } ); - - 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; return EXIT_FAILURE; @@ -393,26 +395,29 @@ int main(int argc, const char** argv) { compiledInterleavedVertexBuffer.insert(compiledInterleavedVertexBuffer.end(),vertexGroup.begin(),vertexGroup.end()); } - auto vkCompiledVertexBuffer = core.createBuffer<Vertex>( + auto vkCompiledVertexBuffer = vkcv::buffer<Vertex>( + core, vkcv::BufferType::VERTEX, compiledInterleavedVertexBuffer.size(), - vkcv::BufferMemoryType::DEVICE_LOCAL - ); + vkcv::BufferMemoryType::DEVICE_LOCAL); vkCompiledVertexBuffer.fill(compiledInterleavedVertexBuffer.data()); - auto vkCompiledIndexBuffer = core.createBuffer<uint8_t>( + auto vkCompiledIndexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::INDEX, compiledIndexBuffer.size(), vkcv::BufferMemoryType::DEVICE_LOCAL); vkCompiledIndexBuffer.fill(compiledIndexBuffer.data()); - vkcv::Buffer<vk::DrawIndexedIndirectCommand> indirectBuffer = core.createBuffer<vk::DrawIndexedIndirectCommand>( + vkcv::Buffer<vk::DrawIndexedIndirectCommand> indirectBuffer = vkcv::buffer<vk::DrawIndexedIndirectCommand>( + core, vkcv::BufferType::INDIRECT, indexedIndirectCommands.size(), vkcv::BufferMemoryType::DEVICE_LOCAL); indirectBuffer.fill(indexedIndirectCommands); - auto boundingBoxBuffer = core.createBuffer<glm::vec4>( + auto boundingBoxBuffer = vkcv::buffer<glm::vec4>( + core, vkcv::BufferType::STORAGE, compiledBoundingBoxBuffer.size()); boundingBoxBuffer.fill(compiledBoundingBoxBuffer); @@ -422,7 +427,8 @@ int main(int argc, const char** argv) { { modelMatrix.push_back(glm::make_mat4(mesh.modelMatrix.data())); } - vkcv::Buffer<glm::mat4> modelBuffer = core.createBuffer<glm::mat4>( + vkcv::Buffer<glm::mat4> modelBuffer = vkcv::buffer<glm::mat4>( + core, vkcv::BufferType::STORAGE, modelMatrix.size(), vkcv::BufferMemoryType::DEVICE_LOCAL @@ -430,10 +436,11 @@ int main(int argc, const char** argv) { modelBuffer.fill(modelMatrix); const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize> (0), vkCompiledVertexBuffer.getVulkanHandle() ) + vkcv::vertexBufferBinding(vkCompiledVertexBuffer.getHandle()) }; - - const vkcv::Mesh compiledMesh(vertexBufferBindings, vkCompiledIndexBuffer.getVulkanHandle(), 0, vkcv::IndexBitCount::Bit32); + + vkcv::VertexData vertexData (vertexBufferBindings); + vertexData.setIndexBuffer(vkCompiledIndexBuffer.getHandle(), vkcv::IndexBitCount::Bit32); //assert(compiledMaterial.baseColor.size() == compiledMaterial.metalRough.size()); @@ -443,12 +450,7 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetLayoutHandle descriptorSetLayout = core.createDescriptorSetLayout(descriptorBindings); vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); - vkcv::SamplerHandle standardSampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + vkcv::SamplerHandle standardSampler = vkcv::samplerLinear(core); vkcv::DescriptorWrites setWrites; @@ -462,16 +464,15 @@ int main(int argc, const char** argv) { setWrites.writeStorageBuffer(1, modelBuffer.getHandle()); core.writeDescriptorSet(descriptorSet, setWrites); - const vkcv::GraphicsPipelineConfig sponzaPipelineConfig { - sponzaProgram, - UINT32_MAX, - UINT32_MAX, - passHandle, - {sponzaVertexLayout}, - { descriptorSetLayout }, - true - }; - vkcv::GraphicsPipelineHandle sponzaPipelineHandle = core.createGraphicsPipeline(sponzaPipelineConfig); + vkcv::GraphicsPipelineHandle sponzaPipelineHandle = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + sponzaProgram, + passHandle, + { sponzaVertexLayout }, + { descriptorSetLayout } + ) + ); + if (!sponzaPipelineHandle) { std::cerr << "Error. Could not create graphics pipeline. Exiting." << std::endl; return EXIT_FAILURE; @@ -481,7 +482,8 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetLayoutHandle cullingSetLayout = core.createDescriptorSetLayout(cullingBindings); vkcv::DescriptorSetHandle cullingDescSet = core.createDescriptorSet(cullingSetLayout); - vkcv::Buffer<CameraPlanes> cameraPlaneBuffer = core.createBuffer<CameraPlanes>( + vkcv::Buffer<CameraPlanes> cameraPlaneBuffer = vkcv::buffer<CameraPlanes>( + core, vkcv::BufferType::UNIFORM, 1); @@ -502,7 +504,7 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + vkcv::camera::CameraManager cameraManager (window); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3)); @@ -512,46 +514,30 @@ int main(int argc, const char** argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); - auto start = std::chrono::system_clock::now(); - float ceiledDispatchCount = static_cast<float>(indexedIndirectCommands.size()) / 64.0f; ceiledDispatchCount = std::ceil(ceiledDispatchCount); - const uint32_t dispatchCount[3] = {static_cast<uint32_t>(ceiledDispatchCount), 1, 1}; - + const vkcv::DispatchSize dispatchCount = static_cast<uint32_t>(ceiledDispatchCount); - vkcv::DescriptorSetUsage cullingUsage(0, cullingDescSet, {}); + vkcv::DescriptorSetUsage cullingUsage (0, cullingDescSet, {}); vkcv::PushConstants emptyPushConstant(0); bool updateFrustumPlanes = true; - - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0) - continue; - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((!depthBuffer) || (swapchainWidth != core.getImageWidth(depthBuffer)) || (swapchainHeight != core.getImageHeight(depthBuffer))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight); } - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + cameraManager.update(dt); - start = end; - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); vkcv::camera::Camera cam = cameraManager.getActiveCamera(); - vkcv::PushConstants pushConstants(sizeof(glm::mat4)); + vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>(); pushConstants.appendDrawcall(cam.getProjection() * cam.getView()); - if(updateFrustumPlanes) - { + if (updateFrustumPlanes) { const CameraPlanes cameraPlanes = computeCameraPlanes(cam); cameraPlaneBuffer.fill({ cameraPlanes }); } @@ -559,43 +545,46 @@ int main(int argc, const char** argv) { const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - core.recordComputeDispatchToCmdStream(cmdStream, - cullingPipelineHandle, - dispatchCount, - {cullingUsage}, - emptyPushConstant); + core.recordComputeDispatchToCmdStream( + cmdStream, + cullingPipelineHandle, + dispatchCount, + {cullingUsage}, + emptyPushConstant + ); core.recordBufferMemoryBarrier(cmdStream, indirectBuffer.getHandle()); - core.recordIndexedIndirectDrawcallsToCmdStream( + vkcv::IndirectDrawcall drawcall ( + indirectBuffer.getHandle(), + vertexData, + indexedIndirectCommands.size() + ); + + drawcall.useDescriptorSet(0, descriptorSet); + + core.recordIndirectDrawcallsToCmdStream( cmdStream, - passHandle, sponzaPipelineHandle, pushConstants, - descriptorSet, - compiledMesh, + { drawcall }, renderTargets, - indirectBuffer, - indexedIndirectCommands.size(), - windowHandle); + windowHandle + ); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - - auto stop = std::chrono::system_clock::now(); - auto kektime = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); + gui.beginGUI(); ImGui::Begin("Settings"); ImGui::Checkbox("Update frustum culling", &updateFrustumPlanes); - ImGui::Text("Deltatime %fms, %f", 0.001 * static_cast<double>(kektime.count()), 1/(0.000001 * static_cast<double>(kektime.count()))); + ImGui::Text("Deltatime %fms, %f", dt * 1000, 1/dt); ImGui::End(); gui.endGUI(); - - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index a74561ca07f7a052fe71c9e1d1efc751c2ab258c..034ae3c0de96d6ac434e3340cd6e4539626fbdba 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -1,5 +1,7 @@ #include <iostream> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <chrono> @@ -103,34 +105,57 @@ int main(int argc, const char** argv) { assert(!mesh.vertexGroups.empty()); - auto vertexBuffer = core.createBuffer<uint8_t>( + auto vertexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::VERTEX, mesh.vertexGroups[0].vertexBuffer.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL ); vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data); - auto indexBuffer = core.createBuffer<uint8_t>( + auto indexBuffer = vkcv::buffer<uint8_t>( + core, vkcv::BufferType::INDEX, mesh.vertexGroups[0].indexBuffer.data.size(), vkcv::BufferMemoryType::DEVICE_LOCAL ); indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data); - - // format data for mesh shader - auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; - - std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); - - const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; + + const auto vertexBufferBindings = vkcv::asset::loadVertexBufferBindings( + mesh.vertexGroups[0].vertexBuffer.attributes, + vertexBuffer.getHandle(), + { + vkcv::asset::PrimitiveType::POSITION, + vkcv::asset::PrimitiveType::NORMAL + } + ); + + const vkcv::asset::VertexAttribute* positionAttribute = nullptr; + const vkcv::asset::VertexAttribute* normalAttribute = nullptr; + + for (const auto& attribute : mesh.vertexGroups[0].vertexBuffer.attributes) { + switch (attribute.type) { + case vkcv::asset::PrimitiveType::POSITION: + positionAttribute = &attribute; + break; + case vkcv::asset::PrimitiveType::NORMAL: + normalAttribute = &attribute; + break; + default: + break; + } + } + + assert(positionAttribute && normalAttribute); const auto& bunny = mesh.vertexGroups[0]; - std::vector<vkcv::meshlet::Vertex> interleavedVertices = vkcv::meshlet::convertToVertices(bunny.vertexBuffer.data, bunny.numVertices, attributes[0], attributes[1]); + std::vector<vkcv::meshlet::Vertex> interleavedVertices = vkcv::meshlet::convertToVertices( + bunny.vertexBuffer.data, + bunny.numVertices, + *positionAttribute, + *normalAttribute + ); + // mesh shader buffers const auto& assetLoaderIndexBuffer = mesh.vertexGroups[0].indexBuffer; std::vector<uint32_t> indexBuffer32Bit = vkcv::meshlet::assetLoaderIndicesTo32BitIndices(assetLoaderIndexBuffer.data, assetLoaderIndexBuffer.type); @@ -139,41 +164,31 @@ int main(int argc, const char** argv) { const auto meshShaderModelData = createMeshShaderModelData(interleavedVertices, forsythResult.indexBuffer, forsythResult.skippedIndices); - auto meshShaderVertexBuffer = core.createBuffer<vkcv::meshlet::Vertex>( + auto meshShaderVertexBuffer = vkcv::buffer<vkcv::meshlet::Vertex>( + core, vkcv::BufferType::STORAGE, meshShaderModelData.vertices.size()); meshShaderVertexBuffer.fill(meshShaderModelData.vertices); - auto meshShaderIndexBuffer = core.createBuffer<uint32_t>( + auto meshShaderIndexBuffer = vkcv::buffer<uint32_t>( + core, vkcv::BufferType::STORAGE, meshShaderModelData.localIndices.size()); meshShaderIndexBuffer.fill(meshShaderModelData.localIndices); - auto meshletBuffer = core.createBuffer<vkcv::meshlet::Meshlet>( + auto meshletBuffer = vkcv::buffer<vkcv::meshlet::Meshlet>( + core, vkcv::BufferType::STORAGE, meshShaderModelData.meshlets.size(), vkcv::BufferMemoryType::DEVICE_LOCAL ); meshletBuffer.fill(meshShaderModelData.meshlets); - - // attachments - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat()); - - const vkcv::AttachmentDescription depth_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat - ); - - vkcv::PassConfig bunnyPassDefinition( - { present_color_attachment, depth_attachment }, - vkcv::Multisampling::None - ); - vkcv::PassHandle renderPass = core.createPass(bunnyPassDefinition); + vkcv::PassHandle renderPass = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat } + ); if (!renderPass) { @@ -203,29 +218,26 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetLayoutHandle vertexShaderDescriptorSetLayout = core.createDescriptorSetLayout(bunnyShaderProgram.getReflectedDescriptors().at(0)); vkcv::DescriptorSetHandle vertexShaderDescriptorSet = core.createDescriptorSet(vertexShaderDescriptorSetLayout); - - const vkcv::GraphicsPipelineConfig bunnyPipelineDefinition { - bunnyShaderProgram, - UINT32_MAX, - UINT32_MAX, - renderPass, - { bunnyLayout }, - { vertexShaderDescriptorSetLayout }, - true - }; struct ObjectMatrices { glm::mat4 model; glm::mat4 mvp; }; const size_t objectCount = 1; - vkcv::Buffer<ObjectMatrices> matrixBuffer = core.createBuffer<ObjectMatrices>(vkcv::BufferType::STORAGE, objectCount); + vkcv::Buffer<ObjectMatrices> matrixBuffer = vkcv::buffer<ObjectMatrices>(core, vkcv::BufferType::STORAGE, objectCount); vkcv::DescriptorWrites vertexShaderDescriptorWrites; vertexShaderDescriptorWrites.writeStorageBuffer(0, matrixBuffer.getHandle()); core.writeDescriptorSet(vertexShaderDescriptorSet, vertexShaderDescriptorWrites); - vkcv::GraphicsPipelineHandle bunnyPipeline = core.createGraphicsPipeline(bunnyPipelineDefinition); + vkcv::GraphicsPipelineHandle bunnyPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + bunnyShaderProgram, + renderPass, + { bunnyLayout }, + { vertexShaderDescriptorSetLayout } + ) + ); if (!bunnyPipeline) { @@ -254,17 +266,14 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetHandle meshShaderDescriptorSet = core.createDescriptorSet(meshShaderDescriptorSetLayout); const vkcv::VertexLayout meshShaderLayout(bindings); - const vkcv::GraphicsPipelineConfig meshShaderPipelineDefinition{ - meshShaderProgram, - UINT32_MAX, - UINT32_MAX, - renderPass, - {meshShaderLayout}, - {meshShaderDescriptorSetLayout}, - true - }; - - vkcv::GraphicsPipelineHandle meshShaderPipeline = core.createGraphicsPipeline(meshShaderPipelineDefinition); + vkcv::GraphicsPipelineHandle meshShaderPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + meshShaderProgram, + renderPass, + { meshShaderLayout }, + { meshShaderDescriptorSetLayout } + ) + ); if (!meshShaderPipeline) { @@ -272,7 +281,7 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::Buffer<CameraPlanes> cameraPlaneBuffer = core.createBuffer<CameraPlanes>(vkcv::BufferType::UNIFORM, 1); + vkcv::Buffer<CameraPlanes> cameraPlaneBuffer = vkcv::buffer<CameraPlanes>(core, vkcv::BufferType::UNIFORM, 1); vkcv::DescriptorWrites meshShaderWrites; meshShaderWrites.writeStorageBuffer( @@ -292,12 +301,11 @@ int main(int argc, const char** argv) { core.writeDescriptorSet( meshShaderDescriptorSet, meshShaderWrites); vkcv::ImageHandle depthBuffer; - - auto start = std::chrono::system_clock::now(); - vkcv::ImageHandle swapchainImageHandle = vkcv::ImageHandle::createSwapchainImageHandle(); - const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices, vkcv::IndexBitCount::Bit32); + vkcv::VertexData vertexData (vertexBufferBindings); + vertexData.setIndexBuffer(indexBuffer.getHandle(), vkcv::IndexBitCount::Bit32); + vertexData.setCount(mesh.vertexGroups[0].numIndices); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -308,16 +316,9 @@ int main(int argc, const char** argv) { bool useMeshShader = true; bool updateFrustumPlanes = true; - - while (vkcv::Window::hasOpenWindow()) - { - vkcv::Window::pollEvents(); - - uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem - if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((!depthBuffer) || (swapchainWidth != core.getImageWidth(depthBuffer)) || (swapchainHeight != core.getImageHeight(depthBuffer))) { @@ -325,14 +326,10 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight - ).getHandle(); + ); } - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - start = end; - - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + cameraManager.update(dt); const vkcv::camera::Camera& camera = cameraManager.getActiveCamera(); @@ -356,35 +353,35 @@ int main(int argc, const char** argv) { const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - vkcv::PushConstants pushConstantData(sizeof(pushConstants)); + vkcv::PushConstants pushConstantData = vkcv::pushConstants<PushConstants>(); pushConstantData.appendDrawcall(pushConstants); if (useMeshShader) { - - vkcv::DescriptorSetUsage descriptorUsage(0, meshShaderDescriptorSet); const uint32_t taskCount = (meshShaderModelData.meshlets.size() + 31) / 32; + + vkcv::TaskDrawcall drawcall (taskCount); + drawcall.useDescriptorSet(0, meshShaderDescriptorSet); core.recordMeshShaderDrawcalls( cmdStream, - renderPass, meshShaderPipeline, pushConstantData, - { vkcv::MeshShaderDrawcall({descriptorUsage}, taskCount)}, + { drawcall }, { renderTargets }, - windowHandle); - } - else { - - vkcv::DescriptorSetUsage descriptorUsage(0, vertexShaderDescriptorSet); + windowHandle + ); + } else { + vkcv::InstanceDrawcall drawcall (vertexData); + drawcall.useDescriptorSet(0, vertexShaderDescriptorSet); core.recordDrawcallsToCmdStream( cmdStream, - renderPass, bunnyPipeline, pushConstantData, - { vkcv::DrawcallInfo(renderMesh, { descriptorUsage }) }, + { drawcall }, { renderTargets }, - windowHandle); + windowHandle + ); } core.prepareSwapchainImageForPresent(cmdStream); @@ -397,10 +394,8 @@ int main(int argc, const char** argv) { ImGui::Checkbox("Update frustum culling", &updateFrustumPlanes); ImGui::End(); - gui.endGUI(); - - core.endFrame(windowHandle); - } + }); + return 0; } diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp index db538796201ee4c1cf5830bfd82036f16a82e693..62a61806b26b9cfea89ab453b2c2291bd55cacef 100644 --- a/projects/particle_simulation/src/main.cpp +++ b/projects/particle_simulation/src/main.cpp @@ -1,5 +1,7 @@ #include <iostream> +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <chrono> @@ -26,26 +28,15 @@ int main(int argc, const char **argv) { vkcv::Window& window = core.getWindow(windowHandle); vkcv::camera::CameraManager cameraManager(window); - auto particleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, - vkcv::BufferMemoryType::DEVICE_LOCAL); + auto particleIndexBuffer = vkcv::buffer<uint16_t>(core, vkcv::BufferType::INDEX, 3, + vkcv::BufferMemoryType::DEVICE_LOCAL); uint16_t indices[3] = {0, 1, 2}; particleIndexBuffer.fill(&indices[0], sizeof(indices)); vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; - // an example attachment for passes that output to the window - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - colorFormat); + vkcv::PassHandle particlePass = vkcv::passFormat(core, colorFormat); - - vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None); - vkcv::PassHandle particlePass = core.createPass(particlePassDefinition); - - vkcv::PassConfig computePassDefinition({}); - vkcv::PassHandle computePass = core.createPass(computePassDefinition); - - if (!particlePass || !computePass) + if (!particlePass) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; @@ -99,14 +90,16 @@ int main(int argc, const char **argv) { particleShaderProgram.getReflectedDescriptors().at(0)); vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); - vkcv::Buffer<glm::vec3> vertexBuffer = core.createBuffer<glm::vec3>( + vkcv::Buffer<glm::vec3> vertexBuffer = vkcv::buffer<glm::vec3>( + core, vkcv::BufferType::VERTEX, 3 ); const std::vector<vkcv::VertexAttachment> vertexAttachments = particleShaderProgram.getVertexAttachments(); const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(0, vertexBuffer.getVulkanHandle())}; + vkcv::vertexBufferBinding(vertexBuffer.getHandle()) + }; std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { @@ -115,16 +108,14 @@ int main(int argc, const char **argv) { const vkcv::VertexLayout particleLayout { bindings }; - vkcv::GraphicsPipelineConfig particlePipelineDefinition{ + vkcv::GraphicsPipelineConfig particlePipelineDefinition ( particleShaderProgram, - UINT32_MAX, - UINT32_MAX, particlePass, {particleLayout}, - {descriptorSetLayout}, - true - }; - particlePipelineDefinition.m_blendMode = vkcv::BlendMode::Additive; + {descriptorSetLayout} + ); + + particlePipelineDefinition.setBlendMode(vkcv::BlendMode::Additive); const std::vector<glm::vec3> vertices = {glm::vec3(-0.012, 0.012, 0), glm::vec3(0.012, 0.012, 0), @@ -138,12 +129,14 @@ int main(int argc, const char **argv) { computeShaderProgram, {computeDescriptorSetLayout} }); - vkcv::Buffer<glm::vec4> color = core.createBuffer<glm::vec4>( + vkcv::Buffer<glm::vec4> color = vkcv::buffer<glm::vec4>( + core, vkcv::BufferType::UNIFORM, 1 ); - vkcv::Buffer<glm::vec2> position = core.createBuffer<glm::vec2>( + vkcv::Buffer<glm::vec2> position = vkcv::buffer<glm::vec2>( + core, vkcv::BufferType::UNIFORM, 1 ); @@ -153,7 +146,8 @@ int main(int argc, const char **argv) { glm::vec2 lifeTime = glm::vec2(-1.f,8.f); ParticleSystem particleSystem = ParticleSystem( 100000 , minVelocity, maxVelocity, lifeTime); - vkcv::Buffer<Particle> particleBuffer = core.createBuffer<Particle>( + vkcv::Buffer<Particle> particleBuffer = vkcv::buffer<Particle>( + core, vkcv::BufferType::STORAGE, particleSystem.getParticles().size() ); @@ -177,8 +171,10 @@ int main(int argc, const char **argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); - const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(), - particleIndexBuffer.getCount()); + vkcv::VertexData vertexData (vertexBufferBindings); + vertexData.setIndexBuffer(particleIndexBuffer.getHandle()); + vertexData.setCount(particleIndexBuffer.getCount()); + vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet); auto pos = glm::vec2(0.f); @@ -193,11 +189,10 @@ int main(int argc, const char **argv) { }); std::vector<glm::mat4> modelMatrices; - std::vector<vkcv::DrawcallInfo> drawcalls; - drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage}, particleSystem.getParticles().size())); - - auto start = std::chrono::system_clock::now(); - + + vkcv::InstanceDrawcall drawcall (vertexData, particleSystem.getParticles().size()); + drawcall.useDescriptorSet(0, descriptorSet); + glm::vec4 colorData = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); @@ -211,14 +206,14 @@ int main(int argc, const char **argv) { cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.0f)); cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f)); - const auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + const auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain()); vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, swapchainExtent.width, swapchainExtent.height, 1, false, true, true - ).getHandle(); + ); vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); bloomAndFlares.setUpsamplingLimit(3); @@ -237,14 +232,9 @@ int main(int argc, const char **argv) { std::uniform_real_distribution<float> rdm = std::uniform_real_distribution<float>(0.95f, 1.05f); std::default_random_engine rdmEngine; - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((core.getImageWidth(colorBuffer) != swapchainWidth) || (core.getImageHeight(colorBuffer) != swapchainHeight)) { colorBuffer = core.createImage( @@ -252,17 +242,13 @@ int main(int argc, const char **argv) { swapchainWidth, swapchainHeight, 1, false, true, true - ).getHandle(); + ); } color.fill(&colorData); position.fill(&pos); - auto end = std::chrono::system_clock::now(); - float deltatime = 0.000001 * static_cast<float>( std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() ); - start = end; - - cameraManager.update(deltatime); + cameraManager.update(dt); // split view and projection to allow for easy billboarding in shader struct { @@ -275,17 +261,18 @@ int main(int argc, const char **argv) { auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); float random = rdm(rdmEngine); - glm::vec2 pushData = glm::vec2(deltatime, random); + glm::vec2 pushData = glm::vec2(dt, random); - vkcv::PushConstants pushConstantsCompute (sizeof(glm::vec2)); + vkcv::PushConstants pushConstantsCompute = vkcv::pushConstants<glm::vec2>(); pushConstantsCompute.appendDrawcall(pushData); - uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(particleSystem.getParticles().size()/256.f)),1,1}; - core.recordComputeDispatchToCmdStream(cmdStream, - computePipeline, - computeDispatchCount, - {vkcv::DescriptorSetUsage(0, computeDescriptorSet)}, - pushConstantsCompute); + core.recordComputeDispatchToCmdStream( + cmdStream, + computePipeline, + vkcv::dispatchInvocations(particleSystem.getParticles().size(), 256), + {vkcv::DescriptorSetUsage(0, computeDescriptorSet)}, + pushConstantsCompute + ); core.recordBufferMemoryBarrier(cmdStream, particleBuffer.getHandle()); @@ -294,12 +281,12 @@ int main(int argc, const char **argv) { core.recordDrawcallsToCmdStream( cmdStream, - particlePass, particlePipeline, pushConstantsDraw, - {drawcalls}, + { drawcall }, { colorBuffer }, - windowHandle); + windowHandle + ); bloomAndFlares.recordEffect(cmdStream, colorBuffer, colorBuffer); @@ -315,22 +302,22 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); - uint32_t tonemappingDispatchCount[3]; - tonemappingDispatchCount[0] = std::ceil(swapchainWidth / 8.f); - tonemappingDispatchCount[1] = std::ceil(swapchainHeight / 8.f); - tonemappingDispatchCount[2] = 1; + const auto tonemappingDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(swapchainWidth, swapchainHeight), + vkcv::DispatchSize(8, 8) + ); core.recordComputeDispatchToCmdStream( cmdStream, tonemappingPipe, tonemappingDispatchCount, - {vkcv::DescriptorSetUsage(0, tonemappingDescriptor) }, - vkcv::PushConstants(0)); + { vkcv::useDescriptorSet(0, tonemappingDescriptor) }, + vkcv::PushConstants(0) + ); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/path_tracer/src/main.cpp b/projects/path_tracer/src/main.cpp index 670986fff81d4f308aa063e6275f41872bc8e878..9a89696e82cf39bbb7281b6a489adc4afe66280a 100644 --- a/projects/path_tracer/src/main.cpp +++ b/projects/path_tracer/src/main.cpp @@ -1,4 +1,6 @@ +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> #include <vkcv/camera/CameraManager.hpp> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -69,7 +71,8 @@ int main(int argc, const char** argv) { initialHeight, 1, false, - true).getHandle(); + true + ); vkcv::ImageHandle meanImage = core.createImage( vk::Format::eR32G32B32A32Sfloat, @@ -77,7 +80,8 @@ int main(int argc, const char** argv) { initialHeight, 1, false, - true).getHandle(); + true + ); vkcv::shader::GLSLCompiler compiler; @@ -174,17 +178,20 @@ int main(int argc, const char** argv) { planes.emplace_back(Plane(glm::vec3( 0, 0, 2), glm::vec3( 0, 0, -1), glm::vec2(2), whiteMaterialIndex)); planes.emplace_back(Plane(glm::vec3( 0, 1.9, 0), glm::vec3( 0, -1, 0), glm::vec2(1), lightMaterialIndex)); - vkcv::Buffer<Sphere> sphereBuffer = core.createBuffer<Sphere>( + vkcv::Buffer<Sphere> sphereBuffer = vkcv::buffer<Sphere>( + core, vkcv::BufferType::STORAGE, spheres.size()); sphereBuffer.fill(spheres); - vkcv::Buffer<Plane> planeBuffer = core.createBuffer<Plane>( + vkcv::Buffer<Plane> planeBuffer = vkcv::buffer<Plane>( + core, vkcv::BufferType::STORAGE, planes.size()); planeBuffer.fill(planes); - vkcv::Buffer<Material> materialBuffer = core.createBuffer<Material>( + vkcv::Buffer<Material> materialBuffer = vkcv::buffer<Material>( + core, vkcv::BufferType::STORAGE, materialSettings.size()); @@ -215,9 +222,7 @@ int main(int argc, const char** argv) { uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2)); - - auto startTime = std::chrono::system_clock::now(); - float time = 0; + int frameIndex = 0; bool clearMeanImage = true; bool updateMaterials = true; @@ -240,16 +245,9 @@ int main(int argc, const char** argv) { glm::vec3 skyColor = glm::vec3(0.2, 0.7, 0.8); float skyColorMultiplier = 1; - - while (vkcv::Window::hasOpenWindow()) - { - vkcv::Window::pollEvents(); - - uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if (swapchainWidth != widthPrevious || swapchainHeight != heightPrevious) { // resize images @@ -259,7 +257,8 @@ int main(int argc, const char** argv) { swapchainHeight, 1, false, - true).getHandle(); + true + ); meanImage = core.createImage( vk::Format::eR32G32B32A32Sfloat, @@ -267,7 +266,8 @@ int main(int argc, const char** argv) { swapchainHeight, 1, false, - true).getHandle(); + true + ); // update descriptor sets traceDescriptorWrites.writeStorageImage(3, outputImage); @@ -292,20 +292,14 @@ int main(int argc, const char** argv) { clearMeanImage = true; } - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - startTime); - startTime = end; - - time += 0.000001f * static_cast<float>(deltatime.count()); - - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + cameraManager.update(dt); const vkcv::CommandStreamHandle cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - uint32_t fullscreenDispatchCount[3] = { - static_cast<uint32_t> (std::ceil(swapchainWidth / 8.f)), - static_cast<uint32_t> (std::ceil(swapchainHeight / 8.f)), - 1 }; + const auto fullscreenDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(swapchainWidth, swapchainHeight), + vkcv::DispatchSize(8, 8) + ); if (updateMaterials) { std::vector<Material> materials; @@ -340,7 +334,7 @@ int main(int argc, const char** argv) { core.recordComputeDispatchToCmdStream(cmdStream, imageClearPipeline, fullscreenDispatchCount, - { vkcv::DescriptorSetUsage(0, imageClearDescriptorSet) }, + { vkcv::useDescriptorSet(0, imageClearDescriptorSet) }, vkcv::PushConstants(0)); clearMeanImage = false; @@ -362,20 +356,20 @@ int main(int argc, const char** argv) { raytracingPushData.planeCount = planes.size(); raytracingPushData.frameIndex = frameIndex; - vkcv::PushConstants pushConstantsCompute(sizeof(RaytracingPushConstantData)); + vkcv::PushConstants pushConstantsCompute = vkcv::pushConstants<RaytracingPushConstantData>(); pushConstantsCompute.appendDrawcall(raytracingPushData); - - uint32_t traceDispatchCount[3] = { - static_cast<uint32_t> (std::ceil(swapchainWidth / 16.f)), - static_cast<uint32_t> (std::ceil(swapchainHeight / 16.f)), - 1 }; + + const auto traceDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(swapchainWidth, swapchainHeight), + vkcv::DispatchSize(16, 16) + ); core.prepareImageForStorage(cmdStream, outputImage); core.recordComputeDispatchToCmdStream(cmdStream, tracePipeline, traceDispatchCount, - { vkcv::DescriptorSetUsage(0, traceDescriptorSet) }, + { vkcv::useDescriptorSet(0, traceDescriptorSet) }, pushConstantsCompute); core.prepareImageForStorage(cmdStream, meanImage); @@ -385,7 +379,7 @@ int main(int argc, const char** argv) { core.recordComputeDispatchToCmdStream(cmdStream, imageCombinePipeline, fullscreenDispatchCount, - { vkcv::DescriptorSetUsage(0, imageCombineDescriptorSet) }, + { vkcv::useDescriptorSet(0, imageCombineDescriptorSet) }, vkcv::PushConstants(0)); core.recordImageMemoryBarrier(cmdStream, meanImage); @@ -407,7 +401,7 @@ int main(int argc, const char** argv) { core.recordComputeDispatchToCmdStream(cmdStream, presentPipeline, fullscreenDispatchCount, - { vkcv::DescriptorSetUsage(0, presentDescriptorSet) }, + { vkcv::useDescriptorSet(0, presentDescriptorSet) }, vkcv::PushConstants(0)); core.prepareSwapchainImageForPresent(cmdStream); @@ -449,9 +443,8 @@ int main(int argc, const char** argv) { gui.endGUI(); } - core.endFrame(windowHandle); - frameIndex++; - } + }); + return 0; } diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp index 8e19caaeda878d8b37b24069bbf752bae6dc41d0..fefd468067658cde88eefe02834b2e7328672af6 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp +++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp @@ -67,8 +67,9 @@ namespace vkcv::rtx { if (result != vk::Result::eSuccess) { vkcv_log(LogLevel::ERROR, "ASManager: command buffer for Acceleration Strucutre Build could not be allocated! (%s)", vk::to_string(result).c_str()); } - - beginCommandBuffer(commandBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + + const vk::CommandBufferBeginInfo beginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + commandBuffer.begin(beginInfo); return commandBuffer; } @@ -144,9 +145,6 @@ namespace vkcv::rtx { } void ASManager::copyFromCPUToGPU(RTXBuffer& cpuBuffer, RTXBuffer& gpuBuffer) { - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - vk::CommandPool commandPool= createCommandPool(); vk::CommandBuffer commandBuffer= createAndBeginCommandBuffer(commandPool); vk::BufferCopy bufferCopy; diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp index 47560b4d9fddb867dd5573c64fe57c24c69095ce..bd5453abae353eed6739c41dbff084a0c909aaca 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp +++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp @@ -104,7 +104,7 @@ namespace vkcv::rtx { vk::WriteDescriptorSet tlasWrite; tlasWrite.setPNext(&AccelerationDescriptor); - tlasWrite.setDstSet(m_core->getDescriptorSet(descriptorSetHandles[0]).vulkanHandle); + tlasWrite.setDstSet(m_core->getVulkanDescriptorSet(descriptorSetHandles[0])); tlasWrite.setDstBinding(1); tlasWrite.setDstArrayElement(0); tlasWrite.setDescriptorCount(1); @@ -123,7 +123,7 @@ namespace vkcv::rtx { vertexInfo.setRange(blas.vertexBuffer.deviceSize); //maybe check if size is correct vk::WriteDescriptorSet vertexWrite; - vertexWrite.setDstSet(m_core->getDescriptorSet(descriptorSetHandles[0]).vulkanHandle); + vertexWrite.setDstSet(m_core->getVulkanDescriptorSet(descriptorSetHandles[0])); vertexWrite.setDstBinding(3); vertexWrite.setDescriptorCount(1); vertexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer); @@ -137,7 +137,7 @@ namespace vkcv::rtx { indexInfo.setRange(blas.indexBuffer.deviceSize); //maybe check if size is correct vk::WriteDescriptorSet indexWrite; - indexWrite.setDstSet(m_core->getDescriptorSet(descriptorSetHandles[0]).vulkanHandle); + indexWrite.setDstSet(m_core->getVulkanDescriptorSet(descriptorSetHandles[0])); indexWrite.setDstBinding(4); indexWrite.setDescriptorCount(1); indexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer); @@ -245,7 +245,7 @@ namespace vkcv::rtx { std::vector<vk::DescriptorSetLayout> descriptorSetLayoutsVulkan; for (size_t i=0; i<descriptorSetLayouts.size(); i++) { - descriptorSetLayoutsVulkan.push_back(m_core->getDescriptorSetLayout(descriptorSetLayouts[i]).vulkanHandle); + descriptorSetLayoutsVulkan.push_back(m_core->getVulkanDescriptorSetLayout(descriptorSetLayouts[i])); } vk::PushConstantRange pushConstant( diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp index e1bfd2231bc8047f12ba7d71e6a176f1fd85d92c..d3d29049b8f64df1e00523c7beb55bd65dd46496 100644 --- a/projects/rtx_ambient_occlusion/src/main.cpp +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -93,19 +93,9 @@ int main(int argc, const char** argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); vkcv::DescriptorWrites rtxWrites; - - auto start = std::chrono::system_clock::now(); - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0) - continue; - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((!depthBuffer) || (swapchainWidth != core.getImageWidth(depthBuffer)) || ((swapchainHeight != core.getImageHeight(depthBuffer)))) { @@ -113,14 +103,10 @@ int main(int argc, const char** argv) { vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight - ).getHandle(); + ); } - - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - - start = end; - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + cameraManager.update(dt); const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; @@ -130,7 +116,7 @@ int main(int argc, const char** argv) { raytracingPushData.camera_up = glm::vec4(cameraManager.getActiveCamera().getUp(),0); raytracingPushData.camera_forward = glm::vec4(cameraManager.getActiveCamera().getFront(),0); - vkcv::PushConstants pushConstantsRTX(sizeof(RaytracingPushConstantData)); + vkcv::PushConstants pushConstantsRTX = vkcv::pushConstants<RaytracingPushConstantData>(); pushConstantsRTX.appendDrawcall(raytracingPushData); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); @@ -148,14 +134,13 @@ int main(int argc, const char** argv) { rtxRegions.rmissRegion, rtxRegions.rchitRegion, rtxRegions.rcallRegion, - { vkcv::DescriptorSetUsage(0, rtxShaderDescriptorSet)}, + { vkcv::useDescriptorSet(0, rtxShaderDescriptorSet) }, pushConstantsRTX, windowHandle); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp index 68bc546ded40e7f45454d62bfc4e8cd7227da4b7..1f446a8f5a4cd1bf5946328b5fe7e144f12f0d5f 100644 --- a/projects/saf_r/src/main.cpp +++ b/projects/saf_r/src/main.cpp @@ -1,15 +1,19 @@ #include <iostream> #include <vkcv/Core.hpp> -#include <GLFW/glfw3.h> +#include <vkcv/Buffer.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> + #include <vkcv/camera/CameraManager.hpp> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> -#include <chrono> + #include <cmath> #include <vector> #include <cstring> -#include "safrScene.hpp" +#include <GLFW/glfw3.h> +#include "safrScene.hpp" void createQuadraticLightCluster(std::vector<safrScene::Light>& lights, int countPerDimension, float dimension, float height, float intensity) { float distance = dimension/countPerDimension; @@ -39,16 +43,7 @@ int main(int argc, const char** argv) { ); vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); - - //configuring the compute Shader - vkcv::PassConfig computePassDefinition({}); - vkcv::PassHandle computePass = core.createPass(computePassDefinition); - - if (!computePass) - { - std::cout << "Error. Could not create renderpass. Exiting." << std::endl; - return EXIT_FAILURE; - } + vkcv::Window& window = core.getWindow(windowHandle); std::string shaderPathCompute = "shaders/raytracing.comp"; @@ -121,24 +116,19 @@ int main(int argc, const char** argv) { lights.push_back(safrScene::Light(glm::vec3(30, 20, 30), 1.7)); */ createQuadraticLightCluster(lights, 10, 2.5f, 20, 1.5f); - - - vkcv::SamplerHandle sampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); - + + vkcv::SamplerHandle sampler = vkcv::samplerLinear(core); //create Buffer for compute shader - vkcv::Buffer<safrScene::Light> lightsBuffer = core.createBuffer<safrScene::Light>( + vkcv::Buffer<safrScene::Light> lightsBuffer = vkcv::buffer<safrScene::Light>( + core, vkcv::BufferType::STORAGE, lights.size() ); lightsBuffer.fill(lights); - vkcv::Buffer<safrScene::Sphere> sphereBuffer = core.createBuffer<safrScene::Sphere>( + vkcv::Buffer<safrScene::Sphere> sphereBuffer = vkcv::buffer<safrScene::Sphere>( + core, vkcv::BufferType::STORAGE, spheres.size() ); @@ -153,44 +143,37 @@ int main(int argc, const char** argv) { core.writeDescriptorSet(computeDescriptorSet, computeWrites); - auto safrIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, vkcv::BufferMemoryType::DEVICE_LOCAL); + auto safrIndexBuffer = vkcv::buffer<uint16_t>(core, vkcv::BufferType::INDEX, 3); uint16_t indices[3] = { 0, 1, 2 }; safrIndexBuffer.fill(&indices[0], sizeof(indices)); + + vkcv::PassHandle safrPass = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined } + ); - // an example attachment for passes that output to the window - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat()); - - vkcv::PassConfig safrPassDefinition({ present_color_attachment }, vkcv::Multisampling::None); - vkcv::PassHandle safrPass = core.createPass(safrPassDefinition); - - if (!safrPass) - { + if (!safrPass) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; } //create the render pipeline + compute pipeline - const vkcv::GraphicsPipelineConfig safrPipelineDefinition{ - safrShaderProgram, - UINT32_MAX, - UINT32_MAX, - safrPass, - {}, - { descriptorSetLayout }, - true - }; - - vkcv::GraphicsPipelineHandle safrPipeline = core.createGraphicsPipeline(safrPipelineDefinition); - - const vkcv::ComputePipelineConfig computePipelineConfig{ - computeShaderProgram, - {computeDescriptorSetLayout} - }; + vkcv::GraphicsPipelineHandle safrPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + safrShaderProgram, + safrPass, + {}, + { descriptorSetLayout } + ) + ); - vkcv::ComputePipelineHandle computePipeline = core.createComputePipeline(computePipelineConfig); + vkcv::ComputePipelineHandle computePipeline = core.createComputePipeline( + vkcv::ComputePipelineConfig( + computeShaderProgram, + { computeDescriptorSetLayout } + ) + ); if (!safrPipeline || !computePipeline) { @@ -198,39 +181,24 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - auto start = std::chrono::system_clock::now(); - - const vkcv::Mesh renderMesh({}, safrIndexBuffer.getVulkanHandle(), 3); - vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet); - vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage }, 1); + vkcv::VertexData vertexData; + vertexData.setIndexBuffer(safrIndexBuffer.getHandle()); + vertexData.setCount(3); + + vkcv::InstanceDrawcall drawcall (vertexData); + drawcall.useDescriptorSet(0, descriptorSet); //create the camera - vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + vkcv::camera::CameraManager cameraManager(window); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, 2)); cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, 0.0f)); cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, -1.0f)); - - float time = 0; - while (vkcv::Window::hasOpenWindow()) - { - vkcv::Window::pollEvents(); - - uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } - - //configure timer - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - start = end; - - time += 0.000001f * static_cast<float>(deltatime.count()); - + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { //adjust light position /* 639a53157e7d3936caf7c3e40379159cbcf4c89e @@ -240,13 +208,13 @@ int main(int argc, const char** argv) { lightsBuffer.fill(lights); */ - spheres[0].center.y += std::cos(time * 0.5f * 3.141f) * 0.25f; - spheres[1].center.x += std::cos(time * 2.f) * 0.25f; - spheres[1].center.z += std::cos(time * 2.f + 0.5f * 3.141f) * 0.25f; + spheres[0].center.y += std::cos(t * 0.5f * 3.141f) * 0.25f; + spheres[1].center.x += std::cos(t * 2.f) * 0.25f; + spheres[1].center.z += std::cos(t * 2.f + 0.5f * 3.141f) * 0.25f; sphereBuffer.fill(spheres); //update camera - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + cameraManager.update(dt); glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); glm::mat4 proj = cameraManager.getActiveCamera().getProjection(); @@ -273,25 +241,27 @@ int main(int argc, const char** argv) { raytracingPushData.sphereCount = spheres.size(); raytracingPushData.viewToWorld = glm::inverse(cameraManager.getActiveCamera().getView()); - vkcv::PushConstants pushConstantsCompute(sizeof(RaytracingPushConstantData)); + vkcv::PushConstants pushConstantsCompute = vkcv::pushConstants<RaytracingPushConstantData>(); pushConstantsCompute.appendDrawcall(raytracingPushData); //dispatch compute shader - uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(swapchainWidth/16.f)), - static_cast<uint32_t> (std::ceil(swapchainHeight/16.f)), - 1 }; // Anzahl workgroups + const auto computeDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(swapchainWidth, swapchainHeight), + vkcv::DispatchSize(16, 16) + ); + core.recordComputeDispatchToCmdStream(cmdStream, computePipeline, computeDispatchCount, - { vkcv::DescriptorSetUsage(0, computeDescriptorSet) }, - pushConstantsCompute); + { vkcv::useDescriptorSet(0, computeDescriptorSet) }, + pushConstantsCompute + ); core.recordBufferMemoryBarrier(cmdStream, lightsBuffer.getHandle()); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - - core.endFrame(windowHandle); - } + }); + return 0; } diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp index 601075421a7bf2814e10514ae010fc83b7024f0a..4989b037375c3ca251411e957ea43030bba536c1 100644 --- a/projects/sph/src/main.cpp +++ b/projects/sph/src/main.cpp @@ -1,5 +1,7 @@ #include <iostream> #include <vkcv/Core.hpp> +#include <vkcv/Buffer.hpp> +#include <vkcv/Pass.hpp> #include <vkcv/camera/CameraManager.hpp> #include <chrono> #include <random> @@ -25,24 +27,12 @@ int main(int argc, const char **argv) { vkcv::camera::CameraManager cameraManager(window); - auto particleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, - vkcv::BufferMemoryType::DEVICE_LOCAL); + auto particleIndexBuffer = vkcv::buffer<uint16_t>(core, vkcv::BufferType::INDEX, 3); uint16_t indices[3] = {0, 1, 2}; particleIndexBuffer.fill(&indices[0], sizeof(indices)); vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; - // an example attachment for passes that output to the window - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - colorFormat); - - - vkcv::PassConfig particlePassDefinition({present_color_attachment}, vkcv::Multisampling::None); - vkcv::PassHandle particlePass = core.createPass(particlePassDefinition); - - vkcv::PassConfig computePassDefinition({}); - vkcv::PassHandle computePass = core.createPass(computePassDefinition); + vkcv::PassHandle particlePass = vkcv::passFormat(core, colorFormat); //rotation float rotationx = 0; @@ -58,7 +48,7 @@ int main(int argc, const char **argv) { float param_ABSORBTION = 0.5; float param_dt = 0.0005; - if (!particlePass || !computePass) + if (!particlePass) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; @@ -98,14 +88,16 @@ int main(int argc, const char **argv) { particleShaderProgram.getReflectedDescriptors().at(0)); vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); - vkcv::Buffer<glm::vec3> vertexBuffer = core.createBuffer<glm::vec3>( + vkcv::Buffer<glm::vec3> vertexBuffer = vkcv::buffer<glm::vec3>( + core, vkcv::BufferType::VERTEX, 3 ); const std::vector<vkcv::VertexAttachment> vertexAttachments = particleShaderProgram.getVertexAttachments(); const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(0, vertexBuffer.getVulkanHandle())}; + vkcv::vertexBufferBinding(vertexBuffer.getHandle()) + }; std::vector<vkcv::VertexBinding> bindings; for (size_t i = 0; i < vertexAttachments.size(); i++) { @@ -115,16 +107,14 @@ int main(int argc, const char **argv) { const vkcv::VertexLayout particleLayout { bindings }; // initializing graphics pipeline - vkcv::GraphicsPipelineConfig particlePipelineDefinition{ + vkcv::GraphicsPipelineConfig particlePipelineDefinition ( particleShaderProgram, - UINT32_MAX, - UINT32_MAX, particlePass, {particleLayout}, - {descriptorSetLayout}, - true - }; - particlePipelineDefinition.m_blendMode = vkcv::BlendMode::Additive; + {descriptorSetLayout} + ); + + particlePipelineDefinition.setBlendMode(vkcv::BlendMode::Additive); const std::vector<glm::vec3> vertices = {glm::vec3(-0.012, 0.012, 0), glm::vec3(0.012, 0.012, 0), @@ -134,12 +124,14 @@ int main(int argc, const char **argv) { vkcv::GraphicsPipelineHandle particlePipeline = core.createGraphicsPipeline(particlePipelineDefinition); - vkcv::Buffer<glm::vec4> color = core.createBuffer<glm::vec4>( + vkcv::Buffer<glm::vec4> color = vkcv::buffer<glm::vec4>( + core, vkcv::BufferType::UNIFORM, 1 ); - vkcv::Buffer<glm::vec2> position = core.createBuffer<glm::vec2>( + vkcv::Buffer<glm::vec2> position = vkcv::buffer<glm::vec2>( + core, vkcv::BufferType::UNIFORM, 1 ); @@ -165,15 +157,16 @@ int main(int argc, const char **argv) { } // creating and filling particle buffer - vkcv::Buffer<Particle> particleBuffer1 = core.createBuffer<Particle>( + vkcv::Buffer<Particle> particleBuffer1 = vkcv::buffer<Particle>( + core, vkcv::BufferType::STORAGE, - numberParticles * sizeof(glm::vec4) * 3 - + numberParticles ); - vkcv::Buffer<Particle> particleBuffer2 = core.createBuffer<Particle>( - vkcv::BufferType::STORAGE, - numberParticles * sizeof(glm::vec4) * 3 + vkcv::Buffer<Particle> particleBuffer2 = vkcv::buffer<Particle>( + core, + vkcv::BufferType::STORAGE, + numberParticles ); particleBuffer1.fill(particles); @@ -205,17 +198,15 @@ int main(int argc, const char **argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); - const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(), - particleIndexBuffer.getCount()); - vkcv::DescriptorSetUsage descriptorUsage(0, descriptorSet); + vkcv::VertexData vertexData (vertexBufferBindings); + vertexData.setIndexBuffer(particleIndexBuffer.getHandle()); + vertexData.setCount(particleIndexBuffer.getCount()); auto pos = glm::vec2(0.f); - - std::vector<vkcv::DrawcallInfo> drawcalls; - drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage}, numberParticles)); - - auto start = std::chrono::system_clock::now(); - + + vkcv::InstanceDrawcall drawcall (vertexData, numberParticles); + drawcall.useDescriptorSet(0, descriptorSet); + glm::vec4 colorData = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); @@ -229,14 +220,14 @@ int main(int argc, const char **argv) { cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.5f)); cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f)); - const auto swapchainExtent = core.getSwapchain(window.getSwapchainHandle()).getExtent(); + const auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain()); vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, swapchainExtent.width, swapchainExtent.height, 1, false, true, true - ).getHandle(); + ); vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); bloomAndFlares.setUpsamplingLimit(3); @@ -249,15 +240,9 @@ int main(int argc, const char **argv) { "shaders/tonemapping.comp", tonemappingPipe ); - - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((core.getImageWidth(colorBuffer) != swapchainWidth) || (core.getImageHeight(colorBuffer) != swapchainHeight)) { colorBuffer = core.createImage( @@ -265,17 +250,13 @@ int main(int argc, const char **argv) { swapchainWidth, swapchainHeight, 1, false, true, true - ).getHandle(); + ); } color.fill(&colorData); position.fill(&pos); - auto end = std::chrono::system_clock::now(); - float deltatime = 0.000001 * static_cast<float>( std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() ); - start = end; - - cameraManager.update(deltatime); + cameraManager.update(dt); // split view and projection to allow for easy billboarding in shader struct { @@ -293,35 +274,35 @@ int main(int argc, const char **argv) { // keybindings rotation if (glfwGetKey(window.getWindow(), GLFW_KEY_LEFT) == GLFW_PRESS) - rotationx += deltatime * 50; + rotationx += dt * 50; if (glfwGetKey(window.getWindow(), GLFW_KEY_RIGHT) == GLFW_PRESS) - rotationx -= deltatime * 50; + rotationx -= dt * 50; if (glfwGetKey(window.getWindow(), GLFW_KEY_UP) == GLFW_PRESS) - rotationy += deltatime * 50; + rotationy += dt * 50; if (glfwGetKey(window.getWindow(), GLFW_KEY_DOWN) == GLFW_PRESS) - rotationy -= deltatime * 50; + rotationy -= dt * 50; // keybindings params if (glfwGetKey(window.getWindow(), GLFW_KEY_T) == GLFW_PRESS) - param_h += deltatime * 0.2; + param_h += dt * 0.2; if (glfwGetKey(window.getWindow(), GLFW_KEY_G) == GLFW_PRESS) - param_h -= deltatime * 0.2; + param_h -= dt * 0.2; if (glfwGetKey(window.getWindow(), GLFW_KEY_Y) == GLFW_PRESS) - param_mass += deltatime * 0.2; + param_mass += dt * 0.2; if (glfwGetKey(window.getWindow(), GLFW_KEY_H) == GLFW_PRESS) - param_mass -= deltatime * 0.2; + param_mass -= dt * 0.2; if (glfwGetKey(window.getWindow(), GLFW_KEY_U) == GLFW_PRESS) - param_gasConstant += deltatime * 1500.0; + param_gasConstant += dt * 1500.0; if (glfwGetKey(window.getWindow(), GLFW_KEY_J) == GLFW_PRESS) - param_gasConstant -= deltatime * 1500.0; + param_gasConstant -= dt * 1500.0; if (glfwGetKey(window.getWindow(), GLFW_KEY_I) == GLFW_PRESS) - param_offset += deltatime * 400.0; + param_offset += dt * 400.0; if (glfwGetKey(window.getWindow(), GLFW_KEY_K) == GLFW_PRESS) - param_offset -= deltatime * 400.0; + param_offset -= dt * 400.0; if (glfwGetKey(window.getWindow(), GLFW_KEY_O) == GLFW_PRESS) param_viscosity = 50; @@ -342,44 +323,52 @@ int main(int argc, const char **argv) { vkcv::PushConstants pushConstantsCompute (sizeof(pushData)); pushConstantsCompute.appendDrawcall(pushData); - uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(numberParticles/256.f)),1,1}; + const auto computeDispatchCount = vkcv::dispatchInvocations(numberParticles, 256); // computing pressure pipeline - core.recordComputeDispatchToCmdStream(cmdStream, - pressurePipeline, - computeDispatchCount, - {vkcv::DescriptorSetUsage(0, pressureDescriptorSet)}, - pushConstantsCompute); + core.recordComputeDispatchToCmdStream( + cmdStream, + pressurePipeline, + computeDispatchCount, + { vkcv::useDescriptorSet(0, pressureDescriptorSet) }, + pushConstantsCompute + ); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); // computing force pipeline - core.recordComputeDispatchToCmdStream(cmdStream, - forcePipeline, - computeDispatchCount, - {vkcv::DescriptorSetUsage(0, forceDescriptorSet)}, - pushConstantsCompute); + core.recordComputeDispatchToCmdStream( + cmdStream, + forcePipeline, + computeDispatchCount, + { vkcv::useDescriptorSet(0, forceDescriptorSet) }, + pushConstantsCompute + ); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); // computing update data pipeline - core.recordComputeDispatchToCmdStream(cmdStream, - updateDataPipeline, - computeDispatchCount, - { vkcv::DescriptorSetUsage(0, updateDataDescriptorSet) }, - pushConstantsCompute); + core.recordComputeDispatchToCmdStream( + cmdStream, + updateDataPipeline, + computeDispatchCount, + { vkcv::useDescriptorSet(0, updateDataDescriptorSet) }, + pushConstantsCompute + ); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); // computing flip pipeline - core.recordComputeDispatchToCmdStream(cmdStream, - flipPipeline, - computeDispatchCount, - { vkcv::DescriptorSetUsage(0, flipDescriptorSet) }, - pushConstantsCompute); + core.recordComputeDispatchToCmdStream( + cmdStream, + flipPipeline, + computeDispatchCount, + { vkcv::useDescriptorSet(0, flipDescriptorSet) }, + pushConstantsCompute + ); core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); @@ -391,10 +380,9 @@ int main(int argc, const char **argv) { core.recordDrawcallsToCmdStream( cmdStream, - particlePass, particlePipeline, pushConstantsDraw, - {drawcalls}, + { drawcall }, { colorBuffer }, windowHandle ); @@ -413,22 +401,22 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); - uint32_t tonemappingDispatchCount[3]; - tonemappingDispatchCount[0] = std::ceil(swapchainWidth / 8.f); - tonemappingDispatchCount[1] = std::ceil(swapchainHeight / 8.f); - tonemappingDispatchCount[2] = 1; + const auto tonemappingDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(swapchainWidth, swapchainHeight), + vkcv::DispatchSize(8, 8) + ); core.recordComputeDispatchToCmdStream( cmdStream, tonemappingPipe, tonemappingDispatchCount, - {vkcv::DescriptorSetUsage(0, tonemappingDescriptor) }, - vkcv::PushConstants(0)); + { vkcv::useDescriptorSet(0, tonemappingDescriptor) }, + vkcv::PushConstants(0) + ); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp index a4b967b33f47110df42ca02849fbeb06b4a024f8..73f98cd3ea35d7f2bdf99d29f803df0abbc1adac 100644 --- a/projects/voxelization/src/ShadowMapping.cpp +++ b/projects/voxelization/src/ShadowMapping.cpp @@ -1,4 +1,6 @@ #include "ShadowMapping.hpp" + +#include <vkcv/Pass.hpp> #include <vkcv/shader/GLSLCompiler.hpp> const vk::Format shadowMapFormat = vk::Format::eR16G16B16A16Unorm; @@ -151,34 +153,28 @@ glm::mat4 computeShadowViewProjectionMatrix( ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vertexLayout) : m_corePtr(corePtr), - m_shadowMap(corePtr->createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1, true, true)), - m_shadowMapIntermediate(corePtr->createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1, false, true)), - m_shadowMapDepth(corePtr->createImage(shadowMapDepthFormat, shadowMapResolution, shadowMapResolution, 1, false, false, false, msaa)), - m_lightInfoBuffer(corePtr->createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3))){ + m_shadowMap(vkcv::image(*corePtr, shadowMapFormat, shadowMapResolution, shadowMapResolution, 1, true, true)), + m_shadowMapIntermediate(vkcv::image(*corePtr, shadowMapFormat, shadowMapResolution, shadowMapResolution, 1, false, true)), + m_shadowMapDepth(vkcv::image(*corePtr, shadowMapDepthFormat, shadowMapResolution, shadowMapResolution, 1, false, false, false, msaa)), + m_lightInfoBuffer(buffer<LightInfo>(*corePtr, vkcv::BufferType::UNIFORM, 1)){ vkcv::ShaderProgram shadowShader = loadShadowShader(); // pass - const std::vector<vkcv::AttachmentDescription> shadowAttachments = { - vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapDepthFormat) - }; - vkcv::PassConfig shadowPassConfig(shadowAttachments, msaa); - m_shadowMapPass = corePtr->createPass(shadowPassConfig); + m_shadowMapPass = vkcv::passFormat(*corePtr, shadowMapDepthFormat, true, msaa); // pipeline - vkcv::GraphicsPipelineConfig shadowPipeConfig{ + vkcv::GraphicsPipelineConfig shadowPipeConfig ( shadowShader, - shadowMapResolution, - shadowMapResolution, m_shadowMapPass, vertexLayout, - {}, - false - }; - shadowPipeConfig.m_multisampling = msaa; - shadowPipeConfig.m_EnableDepthClamping = true; - shadowPipeConfig.m_culling = vkcv::CullMode::Front; - m_shadowMapPipe = corePtr->createGraphicsPipeline(shadowPipeConfig); + {} + ); + + shadowPipeConfig.setResolution(shadowMapResolution, shadowMapResolution); + shadowPipeConfig.setDepthClampingEnabled(true); + shadowPipeConfig.setCulling(vkcv::CullMode::Front); + m_shadowMapPipe = corePtr->createGraphicsPipeline(shadowPipeConfig); m_shadowSampler = corePtr->createSampler( vkcv::SamplerFilterType::LINEAR, @@ -226,18 +222,18 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert } void ShadowMapping::recordShadowMapRendering( - const vkcv::CommandStreamHandle& cmdStream, - const glm::vec2& lightAngleRadian, - const glm::vec3& lightColor, - float lightStrength, - float maxShadowDistance, - const std::vector<vkcv::Mesh>& meshes, - const std::vector<glm::mat4>& modelMatrices, - const vkcv::camera::Camera& camera, - const glm::vec3& voxelVolumeOffset, - float voxelVolumeExtent, - const vkcv::WindowHandle& windowHandle, - vkcv::Downsampler& downsampler) { + const vkcv::CommandStreamHandle& cmdStream, + const glm::vec2& lightAngleRadian, + const glm::vec3& lightColor, + float lightStrength, + float maxShadowDistance, + const std::vector<vkcv::VertexData>& meshes, + const std::vector<glm::mat4>& modelMatrices, + const vkcv::camera::Camera& camera, + const glm::vec3& voxelVolumeOffset, + float voxelVolumeExtent, + const vkcv::WindowHandle& windowHandle, + vkcv::Downsampler& downsampler) { LightInfo lightInfo; lightInfo.sunColor = lightColor; @@ -255,38 +251,38 @@ void ShadowMapping::recordShadowMapRendering( voxelVolumeExtent); m_lightInfoBuffer.fill({ lightInfo }); - vkcv::PushConstants shadowPushConstants (sizeof(glm::mat4)); + vkcv::PushConstants shadowPushConstants = vkcv::pushConstants<glm::mat4>(); for (const auto& m : modelMatrices) { shadowPushConstants.appendDrawcall(lightInfo.lightMatrix * m); } - std::vector<vkcv::DrawcallInfo> drawcalls; + std::vector<vkcv::InstanceDrawcall> drawcalls; for (const auto& mesh : meshes) { - drawcalls.push_back(vkcv::DrawcallInfo(mesh, {})); + drawcalls.push_back(vkcv::InstanceDrawcall(mesh)); } m_corePtr->recordBeginDebugLabel(cmdStream, "Shadow map depth", {1, 1, 1, 1}); m_corePtr->recordDrawcallsToCmdStream( cmdStream, - m_shadowMapPass, m_shadowMapPipe, shadowPushConstants, drawcalls, { m_shadowMapDepth.getHandle() }, - windowHandle); + windowHandle + ); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapDepth.getHandle()); m_corePtr->recordEndDebugLabel(cmdStream); // depth to moments - uint32_t dispatchCount[3]; - dispatchCount[0] = static_cast<uint32_t>(std::ceil(shadowMapResolution / 8.f)); - dispatchCount[1] = static_cast<uint32_t>(std::ceil(shadowMapResolution / 8.f)); - dispatchCount[2] = 1; + const auto dispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(shadowMapResolution, shadowMapResolution), + vkcv::DispatchSize(8, 8) + ); - const uint32_t msaaSampleCount = msaaToSampleCount(msaa); + const uint32_t msaaSampleCount = vkcv::msaaToSampleCount(msaa); - vkcv::PushConstants msaaPushConstants (sizeof(msaaSampleCount)); + vkcv::PushConstants msaaPushConstants = vkcv::pushConstants<uint32_t>(); msaaPushConstants.appendDrawcall(msaaSampleCount); m_corePtr->recordBeginDebugLabel(cmdStream, "Depth to moments", { 1, 1, 1, 1 }); @@ -296,8 +292,9 @@ void ShadowMapping::recordShadowMapRendering( cmdStream, m_depthToMomentsPipe, dispatchCount, - { vkcv::DescriptorSetUsage(0, m_depthToMomentsDescriptorSet) }, - msaaPushConstants); + { vkcv::useDescriptorSet(0, m_depthToMomentsDescriptorSet) }, + msaaPushConstants + ); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); m_corePtr->recordEndDebugLabel(cmdStream); @@ -309,8 +306,9 @@ void ShadowMapping::recordShadowMapRendering( cmdStream, m_shadowBlurXPipe, dispatchCount, - { vkcv::DescriptorSetUsage(0, m_shadowBlurXDescriptorSet) }, - vkcv::PushConstants(0)); + { vkcv::useDescriptorSet(0, m_shadowBlurXDescriptorSet) }, + vkcv::PushConstants(0) + ); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapIntermediate.getHandle()); // blur Y @@ -319,8 +317,9 @@ void ShadowMapping::recordShadowMapRendering( cmdStream, m_shadowBlurYPipe, dispatchCount, - { vkcv::DescriptorSetUsage(0, m_shadowBlurYDescriptorSet) }, - vkcv::PushConstants(0)); + { vkcv::useDescriptorSet(0, m_shadowBlurYDescriptorSet) }, + vkcv::PushConstants(0) + ); m_shadowMap.recordMipChainGeneration(cmdStream, downsampler); m_corePtr->recordEndDebugLabel(cmdStream); diff --git a/projects/voxelization/src/ShadowMapping.hpp b/projects/voxelization/src/ShadowMapping.hpp index 14fef77df51632977f4c4eade4ebcdc28ba56b68..a843a7de9c9e4c731b16ae0c8d5bdfd2ac263711 100644 --- a/projects/voxelization/src/ShadowMapping.hpp +++ b/projects/voxelization/src/ShadowMapping.hpp @@ -1,7 +1,10 @@ #pragma once + +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> #include <vkcv/camera/Camera.hpp> #include <vkcv/Downsampler.hpp> +#include <vkcv/Image.hpp> #include <glm/glm.hpp> #define GLM_ENABLE_EXPERIMENTAL // use this before inclusion, else error! @@ -20,18 +23,18 @@ public: ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vertexLayout); void recordShadowMapRendering( - const vkcv::CommandStreamHandle& cmdStream, - const glm::vec2& lightAngleRadian, - const glm::vec3& lightColor, - float lightStrength, - float maxShadowDistance, - const std::vector<vkcv::Mesh>& meshes, - const std::vector<glm::mat4>& modelMatrices, - const vkcv::camera::Camera& camera, - const glm::vec3& voxelVolumeOffset, - float voxelVolumeExtent, - const vkcv::WindowHandle& windowHandle, - vkcv::Downsampler& downsampler); + const vkcv::CommandStreamHandle& cmdStream, + const glm::vec2& lightAngleRadian, + const glm::vec3& lightColor, + float lightStrength, + float maxShadowDistance, + const std::vector<vkcv::VertexData>& meshes, + const std::vector<glm::mat4>& modelMatrices, + const vkcv::camera::Camera& camera, + const glm::vec3& voxelVolumeOffset, + float voxelVolumeExtent, + const vkcv::WindowHandle& windowHandle, + vkcv::Downsampler& downsampler); vkcv::ImageHandle getShadowMap(); vkcv::SamplerHandle getShadowSampler(); diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp index b30d8a7fa1e9cb56158903de4b11c24ddc503b94..5c70b9dd0b3fe21118c4eddc32fca53e6e21c329 100644 --- a/projects/voxelization/src/Voxelization.cpp +++ b/projects/voxelization/src/Voxelization.cpp @@ -1,4 +1,6 @@ #include "Voxelization.hpp" + +#include <vkcv/Pass.hpp> #include <vkcv/shader/GLSLCompiler.hpp> #include <glm/gtc/matrix_transform.hpp> #include <algorithm> @@ -84,20 +86,20 @@ Voxelization::Voxelization( vkcv::Multisampling msaa) : m_corePtr(corePtr), - m_voxelImageIntermediate(m_corePtr->createImage(vk::Format::eR16G16B16A16Sfloat, voxelResolution, voxelResolution, voxelResolution, true, true)), - m_voxelImage(m_corePtr->createImage(vk::Format::eR16G16B16A16Sfloat, voxelResolution, voxelResolution, voxelResolution, true, true)), - m_voxelBuffer(m_corePtr->createBuffer<VoxelBufferContent>(vkcv::BufferType::STORAGE, voxelCount)), - m_dummyRenderTarget(m_corePtr->createImage(voxelizationDummyFormat, voxelResolution, voxelResolution, 1, false, false, true)), - m_voxelInfoBuffer(m_corePtr->createBuffer<VoxelizationInfo>(vkcv::BufferType::UNIFORM, 1)) { + m_voxelImageIntermediate(vkcv::image(*m_corePtr, vk::Format::eR16G16B16A16Sfloat, voxelResolution, voxelResolution, voxelResolution, true, true)), + m_voxelImage(vkcv::image(*m_corePtr, vk::Format::eR16G16B16A16Sfloat, voxelResolution, voxelResolution, voxelResolution, true, true)), + m_voxelBuffer(buffer<VoxelBufferContent>(*m_corePtr, vkcv::BufferType::STORAGE, voxelCount)), + m_dummyRenderTarget(vkcv::image(*m_corePtr, voxelizationDummyFormat, voxelResolution, voxelResolution, 1, false, false, true)), + m_voxelInfoBuffer(buffer<VoxelizationInfo>(*m_corePtr, vkcv::BufferType::UNIFORM, 1)) { const vkcv::ShaderProgram voxelizationShader = loadVoxelizationShader(); const vkcv::PassConfig voxelizationPassConfig {{ - { - vkcv::AttachmentOperation::DONT_CARE, + vkcv::AttachmentDescription( + voxelizationDummyFormat, vkcv::AttachmentOperation::DONT_CARE, - voxelizationDummyFormat - } + vkcv::AttachmentOperation::DONT_CARE + ) }, vkcv::Multisampling::None }; m_voxelizationPass = m_corePtr->createPass(voxelizationPassConfig); @@ -107,16 +109,16 @@ Voxelization::Voxelization( vkcv::DescriptorSetLayoutHandle dummyPerMeshDescriptorSetLayout = m_corePtr->createDescriptorSetLayout(voxelizationShader.getReflectedDescriptors().at(1)); vkcv::DescriptorSetHandle dummyPerMeshDescriptorSet = m_corePtr->createDescriptorSet(dummyPerMeshDescriptorSetLayout); - const vkcv::GraphicsPipelineConfig voxelizationPipeConfig{ + vkcv::GraphicsPipelineConfig voxelizationPipeConfig ( voxelizationShader, - voxelResolution, - voxelResolution, m_voxelizationPass, dependencies.vertexLayout, - { m_voxelizationDescriptorSetLayout, dummyPerMeshDescriptorSetLayout }, - false, - true - }; + { m_voxelizationDescriptorSetLayout, dummyPerMeshDescriptorSetLayout } + ); + + voxelizationPipeConfig.setResolution(voxelResolution, voxelResolution); + voxelizationPipeConfig.setUsingConservativeRasterization(true); + m_voxelizationPipe = m_corePtr->createGraphicsPipeline(voxelizationPipeConfig); vkcv::DescriptorWrites voxelizationDescriptorWrites; @@ -136,38 +138,22 @@ Voxelization::Voxelization( m_visualisationDescriptorSetLayout = m_corePtr->createDescriptorSetLayout(voxelVisualisationShader.getReflectedDescriptors().at(0)); m_visualisationDescriptorSet = m_corePtr->createDescriptorSet(m_visualisationDescriptorSetLayout); - - const vkcv::AttachmentDescription voxelVisualisationColorAttachments( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - dependencies.colorBufferFormat - ); - - const vkcv::AttachmentDescription voxelVisualisationDepthAttachments( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - dependencies.depthBufferFormat - ); - - vkcv::PassConfig voxelVisualisationPassDefinition{ - { voxelVisualisationColorAttachments, voxelVisualisationDepthAttachments }, - msaa - }; - m_visualisationPass = m_corePtr->createPass(voxelVisualisationPassDefinition); + m_visualisationPass = vkcv::passFormats( + *m_corePtr, + { dependencies.colorBufferFormat, dependencies.depthBufferFormat }, + false, + msaa + ); - vkcv::GraphicsPipelineConfig voxelVisualisationPipeConfig{ + vkcv::GraphicsPipelineConfig voxelVisualisationPipeConfig ( voxelVisualisationShader, - 0, - 0, m_visualisationPass, {}, - { m_visualisationDescriptorSetLayout }, - true, - false, - vkcv::PrimitiveTopology::PointList - }; // points are extended to cubes in the geometry shader - voxelVisualisationPipeConfig.m_multisampling = msaa; + { m_visualisationDescriptorSetLayout } + ); // points are extended to cubes in the geometry shader + + voxelVisualisationPipeConfig.setPrimitiveTopology(vkcv::PrimitiveTopology::PointList); m_visualisationPipe = m_corePtr->createGraphicsPipeline(voxelVisualisationPipeConfig); std::vector<uint16_t> voxelIndexData; @@ -175,7 +161,7 @@ Voxelization::Voxelization( voxelIndexData.push_back(static_cast<uint16_t>(i)); } - const vkcv::DescriptorSetUsage voxelizationDescriptorUsage(0, m_visualisationDescriptorSet); + const auto voxelizationDescriptorUsage = vkcv::useDescriptorSet(0, m_visualisationDescriptorSet); vkcv::ShaderProgram resetVoxelShader = loadVoxelResetShader(); @@ -226,7 +212,7 @@ Voxelization::Voxelization( void Voxelization::voxelizeMeshes( vkcv::CommandStreamHandle cmdStream, - const std::vector<vkcv::Mesh>& meshes, + const std::vector<vkcv::VertexData>& meshes, const std::vector<glm::mat4>& modelMatrices, const std::vector<vkcv::DescriptorSetHandle>& perMeshDescriptorSets, const vkcv::WindowHandle& windowHandle, @@ -254,61 +240,56 @@ void Voxelization::voxelizeMeshes( // reset voxels const uint32_t resetVoxelGroupSize = 64; - uint32_t resetVoxelDispatchCount[3]; - resetVoxelDispatchCount[0] = glm::ceil(voxelCount / float(resetVoxelGroupSize)); - resetVoxelDispatchCount[1] = 1; - resetVoxelDispatchCount[2] = 1; - vkcv::PushConstants voxelCountPushConstants (sizeof(voxelCount)); + vkcv::PushConstants voxelCountPushConstants = vkcv::pushConstants<uint32_t>(); voxelCountPushConstants.appendDrawcall(voxelCount); m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel reset", { 1, 1, 1, 1 }); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_voxelResetPipe, - resetVoxelDispatchCount, - { vkcv::DescriptorSetUsage(0, m_voxelResetDescriptorSet) }, - voxelCountPushConstants); + vkcv::dispatchInvocations(voxelCount, resetVoxelGroupSize), + { vkcv::useDescriptorSet(0, m_voxelResetDescriptorSet) }, + voxelCountPushConstants + ); m_corePtr->recordBufferMemoryBarrier(cmdStream, m_voxelBuffer.getHandle()); m_corePtr->recordEndDebugLabel(cmdStream); // voxelization - std::vector<vkcv::DrawcallInfo> drawcalls; + std::vector<vkcv::InstanceDrawcall> drawcalls; for (size_t i = 0; i < meshes.size(); i++) { - drawcalls.push_back(vkcv::DrawcallInfo( - meshes[i], - { - vkcv::DescriptorSetUsage(0, m_voxelizationDescriptorSet), - vkcv::DescriptorSetUsage(1, perMeshDescriptorSets[i]) - },1)); + vkcv::InstanceDrawcall drawcall (meshes[i]); + drawcall.useDescriptorSet(0, m_voxelizationDescriptorSet); + drawcall.useDescriptorSet(1, perMeshDescriptorSets[i]); + drawcalls.push_back(drawcall); } m_corePtr->recordBeginDebugLabel(cmdStream, "Voxelization", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImageIntermediate.getHandle()); m_corePtr->recordDrawcallsToCmdStream( cmdStream, - m_voxelizationPass, m_voxelizationPipe, voxelizationPushConstants, drawcalls, { m_dummyRenderTarget.getHandle() }, - windowHandle); + windowHandle + ); m_corePtr->recordEndDebugLabel(cmdStream); // buffer to image - const uint32_t bufferToImageGroupSize[3] = { 4, 4, 4 }; - uint32_t bufferToImageDispatchCount[3]; - for (int i = 0; i < 3; i++) { - bufferToImageDispatchCount[i] = glm::ceil(voxelResolution / float(bufferToImageGroupSize[i])); - } - + const auto bufferToImageDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(voxelResolution, voxelResolution, voxelResolution), + vkcv::DispatchSize(4, 4, 4) + ); + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel buffer to image", { 1, 1, 1, 1 }); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_bufferToImagePipe, bufferToImageDispatchCount, - { vkcv::DescriptorSetUsage(0, m_bufferToImageDescriptorSet) }, - vkcv::PushConstants(0)); + { vkcv::useDescriptorSet(0, m_bufferToImageDescriptorSet) }, + vkcv::PushConstants(0) + ); m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImageIntermediate.getHandle()); m_corePtr->recordEndDebugLabel(cmdStream); @@ -325,7 +306,7 @@ void Voxelization::voxelizeMeshes( cmdStream, m_secondaryBouncePipe, bufferToImageDispatchCount, - { vkcv::DescriptorSetUsage(0, m_secondaryBounceDescriptorSet) }, + { vkcv::useDescriptorSet(0, m_secondaryBounceDescriptorSet) }, vkcv::PushConstants(0)); m_voxelImage.recordMipChainGeneration(cmdStream, downsampler); m_corePtr->recordEndDebugLabel(cmdStream); @@ -343,10 +324,10 @@ void Voxelization::renderVoxelVisualisation( uint32_t mipLevel, const vkcv::WindowHandle& windowHandle) { - vkcv::PushConstants voxelVisualisationPushConstants (sizeof(glm::mat4)); + vkcv::PushConstants voxelVisualisationPushConstants = vkcv::pushConstants<glm::mat4>(); voxelVisualisationPushConstants.appendDrawcall(viewProjectin); - mipLevel = std::clamp(mipLevel, (uint32_t)0, m_voxelImage.getMipCount()-1); + mipLevel = std::clamp(mipLevel, (uint32_t) 0, m_voxelImage.getMipLevels() - 1); // write descriptor set vkcv::DescriptorWrites voxelVisualisationDescriptorWrite; @@ -355,21 +336,23 @@ void Voxelization::renderVoxelVisualisation( m_corePtr->writeDescriptorSet(m_visualisationDescriptorSet, voxelVisualisationDescriptorWrite); uint32_t drawVoxelCount = voxelCount / exp2(mipLevel); - - const auto drawcall = vkcv::DrawcallInfo( - vkcv::Mesh({}, nullptr, drawVoxelCount), - { vkcv::DescriptorSetUsage(0, m_visualisationDescriptorSet) },1); + + vkcv::VertexData voxelData; + voxelData.setCount(drawVoxelCount); + + vkcv::InstanceDrawcall drawcall (voxelData); + drawcall.useDescriptorSet(0, m_visualisationDescriptorSet); m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel visualisation", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); m_corePtr->recordDrawcallsToCmdStream( cmdStream, - m_visualisationPass, m_visualisationPipe, voxelVisualisationPushConstants, { drawcall }, renderTargets, - windowHandle); + windowHandle + ); m_corePtr->recordEndDebugLabel(cmdStream); } diff --git a/projects/voxelization/src/Voxelization.hpp b/projects/voxelization/src/Voxelization.hpp index 866efaf47354bc0a53ebd500d06dc4a49b0ed690..f624d03503b67cc2de0632367d90742fb975473e 100644 --- a/projects/voxelization/src/Voxelization.hpp +++ b/projects/voxelization/src/Voxelization.hpp @@ -1,5 +1,8 @@ #pragma once + +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Image.hpp> #include <glm/glm.hpp> #include <vkcv/camera/Camera.hpp> #include <vkcv/Downsampler.hpp> @@ -22,7 +25,7 @@ public: void voxelizeMeshes( vkcv::CommandStreamHandle cmdStream, - const std::vector<vkcv::Mesh>& meshes, + const std::vector<vkcv::VertexData>& meshes, const std::vector<glm::mat4>& modelMatrices, const std::vector<vkcv::DescriptorSetHandle>& perMeshDescriptorSets, const vkcv::WindowHandle& windowHandle, diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index 2868a4cc8901a346e5ee723444ace1ec83ae0b25..da2be34b3e174467392817efb6a4d4d0437b2257 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -1,5 +1,7 @@ #include <iostream> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> #include <GLFW/glfw3.h> #include <vkcv/camera/CameraManager.hpp> #include <chrono> @@ -135,25 +137,17 @@ int main(int argc, const char** argv) { std::vector<std::vector<uint8_t>> vBuffers; std::vector<std::vector<uint8_t>> iBuffers; - std::vector<vkcv::VertexBufferBinding> vBufferBindings; std::vector<std::vector<vkcv::VertexBufferBinding>> vertexBufferBindings; - std::vector<vkcv::asset::VertexAttribute> vAttributes; for (size_t i = 0; i < scene.vertexGroups.size(); i++) { - vBuffers.push_back(scene.vertexGroups[i].vertexBuffer.data); iBuffers.push_back(scene.vertexGroups[i].indexBuffer.data); - - auto& attributes = scene.vertexGroups[i].vertexBuffer.attributes; - - std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); } std::vector<vkcv::Buffer<uint8_t>> vertexBuffers; for (const vkcv::asset::VertexGroup& group : scene.vertexGroups) { - vertexBuffers.push_back(core.createBuffer<uint8_t>( + vertexBuffers.push_back(buffer<uint8_t>( + core, vkcv::BufferType::VERTEX, group.vertexBuffer.data.size())); vertexBuffers.back().fill(group.vertexBuffer.data); @@ -161,35 +155,38 @@ int main(int argc, const char** argv) { std::vector<vkcv::Buffer<uint8_t>> indexBuffers; for (const auto& dataBuffer : iBuffers) { - indexBuffers.push_back(core.createBuffer<uint8_t>( + indexBuffers.push_back(buffer<uint8_t>( + core, vkcv::BufferType::INDEX, dataBuffer.size())); indexBuffers.back().fill(dataBuffer); } - int vertexBufferIndex = 0; - for (const auto& vertexGroup : scene.vertexGroups) { - for (const auto& attribute : vertexGroup.vertexBuffer.attributes) { - vAttributes.push_back(attribute); - vBufferBindings.push_back(vkcv::VertexBufferBinding(attribute.offset, vertexBuffers[vertexBufferIndex].getVulkanHandle())); - } - vertexBufferBindings.push_back(vBufferBindings); - vBufferBindings.clear(); - vertexBufferIndex++; + for (size_t i = 0; i < scene.vertexGroups.size(); i++) { + vertexBufferBindings.push_back(vkcv::asset::loadVertexBufferBindings( + scene.vertexGroups[i].vertexBuffer.attributes, + vertexBuffers[i].getHandle(), + { + vkcv::asset::PrimitiveType::POSITION, + vkcv::asset::PrimitiveType::NORMAL, + vkcv::asset::PrimitiveType::TEXCOORD_0, + vkcv::asset::PrimitiveType::TANGENT + } + )); } const vk::Format colorBufferFormat = vk::Format::eB10G11R11UfloatPack32; - const vkcv::AttachmentDescription color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - colorBufferFormat + const vkcv::AttachmentDescription color_attachment ( + colorBufferFormat, + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE ); const vk::Format depthBufferFormat = vk::Format::eD32Sfloat; - const vkcv::AttachmentDescription depth_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - depthBufferFormat + const vkcv::AttachmentDescription depth_attachment ( + depthBufferFormat, + vkcv::AttachmentOperation::LOAD, + vkcv::AttachmentOperation::STORE ); // forward shading config @@ -237,22 +234,11 @@ int main(int argc, const char** argv) { prepassVertexBindings.push_back(vkcv::createVertexBinding(i, { prepassVertexAttachments[i] })); } const vkcv::VertexLayout prepassVertexLayout { prepassVertexBindings }; - - const vkcv::AttachmentDescription prepassAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - depthBufferFormat); - - vkcv::PassConfig prepassPassDefinition({ prepassAttachment }, msaa); - vkcv::PassHandle prepassPass = core.createPass(prepassPassDefinition); + + vkcv::PassHandle prepassPass = vkcv::passFormat(core, depthBufferFormat, true, msaa); // create descriptor sets - vkcv::SamplerHandle colorSampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); + vkcv::SamplerHandle colorSampler = vkcv::samplerLinear(core); std::vector<vkcv::DescriptorSetLayoutHandle> materialDescriptorSetLayouts; std::vector<vkcv::DescriptorSetHandle> materialDescriptorSets; @@ -288,19 +274,19 @@ int main(int argc, const char** argv) { vkcv::asset::Texture& specularTexture = scene.textures[specularIndex]; // albedo texture - sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Srgb, albedoTexture.w, albedoTexture.h, 1, true)); + sceneImages.push_back(vkcv::image(core, vk::Format::eR8G8B8A8Srgb, albedoTexture.w, albedoTexture.h, 1, true)); sceneImages.back().fill(albedoTexture.data.data()); sceneImages.back().recordMipChainGeneration(mipStream, spdDownsampler); const vkcv::ImageHandle albedoHandle = sceneImages.back().getHandle(); // normal texture - sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Unorm, normalTexture.w, normalTexture.h, 1, true, true)); + sceneImages.push_back(vkcv::image(core, vk::Format::eR8G8B8A8Unorm, normalTexture.w, normalTexture.h, 1, true, true)); sceneImages.back().fill(normalTexture.data.data()); sceneImages.back().recordMipChainGeneration(mipStream, spdDownsampler); const vkcv::ImageHandle normalHandle = sceneImages.back().getHandle(); // specular texture - sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Unorm, specularTexture.w, specularTexture.h, 1, true, true)); + sceneImages.push_back(vkcv::image(core, vk::Format::eR8G8B8A8Unorm, specularTexture.w, specularTexture.h, 1, true, true)); sceneImages.back().fill(specularTexture.data.data()); sceneImages.back().recordMipChainGeneration(mipStream, spdDownsampler); const vkcv::ImageHandle specularHandle = sceneImages.back().getHandle(); @@ -331,38 +317,32 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetLayoutHandle prepassDescriptorSetLayout = core.createDescriptorSetLayout({}); vkcv::DescriptorSetHandle prepassDescriptorSet = core.createDescriptorSet(prepassDescriptorSetLayout); - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain()); - vkcv::GraphicsPipelineConfig prepassPipelineConfig{ + vkcv::GraphicsPipelineConfig prepassPipelineConfig ( depthPrepassShader, - swapchainExtent.width, - swapchainExtent.height, prepassPass, vertexLayout, - { prepassDescriptorSetLayout, perMeshDescriptorSetLayouts[0] }, - true - }; - prepassPipelineConfig.m_culling = vkcv::CullMode::Back; - prepassPipelineConfig.m_multisampling = msaa; - prepassPipelineConfig.m_depthTest = vkcv::DepthTest::LessEqual; - prepassPipelineConfig.m_alphaToCoverage = true; + { prepassDescriptorSetLayout, perMeshDescriptorSetLayouts[0] } + ); + + prepassPipelineConfig.setCulling(vkcv::CullMode::Back); + prepassPipelineConfig.setDepthTest(vkcv::DepthTest::LessEqual); + prepassPipelineConfig.setWritingAlphaToCoverage(true); vkcv::GraphicsPipelineHandle prepassPipeline = core.createGraphicsPipeline(prepassPipelineConfig); // forward pipeline - vkcv::GraphicsPipelineConfig forwardPipelineConfig { + vkcv::GraphicsPipelineConfig forwardPipelineConfig ( forwardProgram, - swapchainExtent.width, - swapchainExtent.height, forwardPass, vertexLayout, - { forwardShadingDescriptorSetLayout, perMeshDescriptorSetLayouts[0] }, - true - }; - forwardPipelineConfig.m_culling = vkcv::CullMode::Back; - forwardPipelineConfig.m_multisampling = msaa; - forwardPipelineConfig.m_depthTest = vkcv::DepthTest::Equal; - forwardPipelineConfig.m_depthWrite = false; + { forwardShadingDescriptorSetLayout, perMeshDescriptorSetLayouts[0] } + ); + + forwardPipelineConfig.setCulling(vkcv::CullMode::Back); + forwardPipelineConfig.setDepthTest(vkcv::DepthTest::Equal); + forwardPipelineConfig.setWritingDepth(false); vkcv::GraphicsPipelineHandle forwardPipeline = core.createGraphicsPipeline(forwardPipelineConfig); @@ -379,19 +359,13 @@ int main(int argc, const char** argv) { SkySettings skySettings; skySettings.color = glm::vec3(0.15, 0.65, 1); skySettings.strength = 5; - - const vkcv::AttachmentDescription skyColorAttachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - colorBufferFormat); - - const vkcv::AttachmentDescription skyDepthAttachments( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - depthBufferFormat); - - vkcv::PassConfig skyPassConfig({ skyColorAttachment, skyDepthAttachments }, msaa); - vkcv::PassHandle skyPass = core.createPass(skyPassConfig); + + vkcv::PassHandle skyPass = vkcv::passFormats( + core, + { colorBufferFormat, depthBufferFormat }, + false, + msaa + ); vkcv::ShaderProgram skyShader; compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("assets/shaders/sky.vert"), @@ -403,34 +377,32 @@ int main(int argc, const char** argv) { skyShader.addShader(shaderStage, path); }); - vkcv::GraphicsPipelineConfig skyPipeConfig; - skyPipeConfig.m_ShaderProgram = skyShader; - skyPipeConfig.m_Width = swapchainExtent.width; - skyPipeConfig.m_Height = swapchainExtent.height; - skyPipeConfig.m_PassHandle = skyPass; - skyPipeConfig.m_VertexLayout = vkcv::VertexLayout(); - skyPipeConfig.m_DescriptorLayouts = {}; - skyPipeConfig.m_UseDynamicViewport = true; - skyPipeConfig.m_multisampling = msaa; - skyPipeConfig.m_depthWrite = false; + vkcv::GraphicsPipelineConfig skyPipeConfig ( + skyShader, + skyPass, + {}, + {} + ); + + skyPipeConfig.setWritingDepth(false); vkcv::GraphicsPipelineHandle skyPipe = core.createGraphicsPipeline(skyPipeConfig); // render targets - vkcv::ImageHandle depthBuffer = core.createImage( + vkcv::ImageHandle depthBuffer = core.createImage( depthBufferFormat, swapchainExtent.width, swapchainExtent.height, 1, false, false, false, msaa - ).getHandle(); + ); - const bool colorBufferRequiresStorage = !usingMsaa; - vkcv::ImageHandle colorBuffer = core.createImage( + const bool colorBufferRequiresStorage = !usingMsaa; + vkcv::ImageHandle colorBuffer = core.createImage( colorBufferFormat, swapchainExtent.width, swapchainExtent.height, 1, false, colorBufferRequiresStorage, true, msaa - ).getHandle(); + ); vkcv::ImageHandle resolvedColorBuffer; if (usingMsaa) { @@ -439,7 +411,7 @@ int main(int argc, const char** argv) { swapchainExtent.width, swapchainExtent.height, 1, false, true, true - ).getHandle(); + ); } else { resolvedColorBuffer = colorBuffer; @@ -450,14 +422,14 @@ int main(int argc, const char** argv) { swapchainExtent.width, swapchainExtent.height, 1, false, true - ).getHandle(); + ); vkcv::ImageHandle swapBuffer2 = core.createImage( colorBufferFormat, swapchainExtent.width, swapchainExtent.height, 1, false, true - ).getHandle(); + ); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -520,12 +492,7 @@ int main(int argc, const char** argv) { { resolveDescriptorSetLayout } }); - vkcv::SamplerHandle resolveSampler = core.createSampler( - vkcv::SamplerFilterType::NEAREST, - vkcv::SamplerFilterType::NEAREST, - vkcv::SamplerMipmapMode::NEAREST, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE - ); + vkcv::SamplerHandle resolveSampler = vkcv::samplerNearest(core, true); // model matrices per mesh std::vector<glm::mat4> modelMatrices; @@ -538,30 +505,30 @@ int main(int argc, const char** argv) { } // prepare meshes - std::vector<vkcv::Mesh> meshes; + std::vector<vkcv::VertexData> meshes; for (size_t i = 0; i < scene.vertexGroups.size(); i++) { - vkcv::Mesh mesh(vertexBufferBindings[i], indexBuffers[i].getVulkanHandle(), scene.vertexGroups[i].numIndices); + vkcv::VertexData mesh (vertexBufferBindings[i]); + mesh.setIndexBuffer(indexBuffers[i].getHandle()); + mesh.setCount(scene.vertexGroups[i].numIndices); meshes.push_back(mesh); } - std::vector<vkcv::DrawcallInfo> drawcalls; - std::vector<vkcv::DrawcallInfo> prepassDrawcalls; + std::vector<vkcv::InstanceDrawcall> drawcalls; + std::vector<vkcv::InstanceDrawcall> prepassDrawcalls; for (size_t i = 0; i < meshes.size(); i++) { - - drawcalls.push_back(vkcv::DrawcallInfo(meshes[i], { - vkcv::DescriptorSetUsage(0, forwardShadingDescriptorSet), - vkcv::DescriptorSetUsage(1, perMeshDescriptorSets[i]) })); - prepassDrawcalls.push_back(vkcv::DrawcallInfo(meshes[i], { - vkcv::DescriptorSetUsage(0, prepassDescriptorSet), - vkcv::DescriptorSetUsage(1, perMeshDescriptorSets[i]) })); + vkcv::InstanceDrawcall drawcall (meshes[i]); + drawcall.useDescriptorSet(0, forwardShadingDescriptorSet); + drawcall.useDescriptorSet(1, perMeshDescriptorSets[i]); + + vkcv::InstanceDrawcall prepassDrawcall (meshes[i]); + prepassDrawcall.useDescriptorSet(0, prepassDescriptorSet); + prepassDrawcall.useDescriptorSet(1, perMeshDescriptorSets[i]); + + drawcalls.push_back(drawcall); + prepassDrawcalls.push_back(prepassDrawcall); } - vkcv::SamplerHandle voxelSampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE - ); + vkcv::SamplerHandle voxelSampler = vkcv::samplerLinear(core, true); ShadowMapping shadowMapping(&core, vertexLayout); @@ -579,7 +546,7 @@ int main(int argc, const char** argv) { msaa); vkcv::effects::BloomAndFlaresEffect bloomFlares (core, true); - vkcv::Buffer<glm::vec3> cameraPosBuffer = core.createBuffer<glm::vec3>(vkcv::BufferType::UNIFORM, 1); + vkcv::Buffer<glm::vec3> cameraPosBuffer = buffer<glm::vec3>(core, vkcv::BufferType::UNIFORM, 1); struct VolumetricSettings { glm::vec3 scatteringCoefficient; @@ -587,7 +554,7 @@ int main(int argc, const char** argv) { glm::vec3 absorptionCoefficient; }; vkcv::Buffer<VolumetricSettings> volumetricSettingsBuffer - = core.createBuffer<VolumetricSettings>(vkcv::BufferType::UNIFORM ,1); + = buffer<VolumetricSettings>(core, vkcv::BufferType::UNIFORM ,1); // write forward pass descriptor set vkcv::DescriptorWrites forwardDescriptorWrites; @@ -660,17 +627,9 @@ int main(int argc, const char** argv) { glm::vec3 absorptionColor = glm::vec3(1); float absorptionDensity = 0.005; float volumetricAmbient = 0.2; - - auto start = std::chrono::system_clock::now(); - const auto appStartTime = start; - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } - + + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { uint32_t width, height; vkcv::upscaling::getFSRResolution( fsrMode, @@ -702,21 +661,21 @@ int main(int argc, const char** argv) { fsrWidth, fsrHeight, 1, false, false, false, msaa - ).getHandle(); + ); colorBuffer = core.createImage( colorBufferFormat, fsrWidth, fsrHeight, 1, false, colorBufferRequiresStorage, true, msaa - ).getHandle(); + ); if (usingMsaa) { resolvedColorBuffer = core.createImage( colorBufferFormat, fsrWidth, fsrHeight, 1, false, true, true - ).getHandle(); + ); } else { resolvedColorBuffer = colorBuffer; } @@ -725,18 +684,15 @@ int main(int argc, const char** argv) { colorBufferFormat, fsrWidth, fsrHeight, 1, false, true - ).getHandle(); + ); swapBuffer2 = core.createImage( colorBufferFormat, swapchainWidth, swapchainHeight, 1, false, true - ).getHandle(); + ); } - auto end = std::chrono::system_clock::now(); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - // update descriptor sets which use swapchain image vkcv::DescriptorWrites tonemappingDescriptorWrites; tonemappingDescriptorWrites.writeSampledImage(0, resolvedColorBuffer); @@ -760,8 +716,7 @@ int main(int argc, const char** argv) { resolveDescriptorWrites.writeStorageImage(2, resolvedColorBuffer); core.writeDescriptorSet(resolveDescriptorSet, resolveDescriptorWrites); - start = end; - cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + cameraManager.update(dt); cameraPosBuffer.fill({ cameraManager.getActiveCamera().getPosition() }); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); @@ -799,25 +754,24 @@ int main(int argc, const char** argv) { // depth prepass const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP(); - vkcv::PushConstants prepassPushConstants (sizeof(glm::mat4)); + vkcv::PushConstants prepassPushConstants = vkcv::pushConstants<glm::mat4>(); std::vector<glm::mat4> prepassMatrices; for (const auto& m : modelMatrices) { prepassPushConstants.appendDrawcall(viewProjectionCamera * m); } - const std::vector<vkcv::ImageHandle> prepassRenderTargets = { depthBuffer }; core.recordBeginDebugLabel(cmdStream, "Depth prepass", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, - prepassPass, prepassPipeline, prepassPushConstants, prepassDrawcalls, prepassRenderTargets, - windowHandle); + windowHandle + ); core.recordImageMemoryBarrier(cmdStream, depthBuffer); core.recordEndDebugLabel(cmdStream); @@ -840,46 +794,41 @@ int main(int argc, const char** argv) { core.recordBeginDebugLabel(cmdStream, "Forward rendering", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, - forwardPass, forwardPipeline, pushConstants, drawcalls, renderTargets, - windowHandle); + windowHandle + ); core.recordEndDebugLabel(cmdStream); if (renderVoxelVis) { voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip, windowHandle); } - vkcv::PushConstants skySettingsPushConstants (sizeof(skySettings)); + vkcv::PushConstants skySettingsPushConstants = vkcv::pushConstants<SkySettings>(); skySettingsPushConstants.appendDrawcall(skySettings); + + vkcv::VertexData skyData; + skyData.setCount(3); // sky core.recordBeginDebugLabel(cmdStream, "Sky", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, - skyPass, skyPipe, skySettingsPushConstants, - { vkcv::DrawcallInfo(vkcv::Mesh({}, nullptr, 3), {}) }, + { vkcv::InstanceDrawcall(skyData) }, renderTargets, - windowHandle); - core.recordEndDebugLabel(cmdStream); - - const uint32_t fullscreenLocalGroupSize = 8; - - uint32_t fulsscreenDispatchCount [3]; - - fulsscreenDispatchCount[0] = static_cast<uint32_t>( - glm::ceil(fsrWidth / static_cast<float>(fullscreenLocalGroupSize)) + windowHandle ); + core.recordEndDebugLabel(cmdStream); - fulsscreenDispatchCount[1] = static_cast<uint32_t>( - glm::ceil(fsrHeight / static_cast<float>(fullscreenLocalGroupSize)) + const uint32_t fullscreenLocalGroupSize = 8; + auto fullscreenDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(fsrWidth, fsrHeight), + vkcv::DispatchSize(fullscreenLocalGroupSize, fullscreenLocalGroupSize) ); - - fulsscreenDispatchCount[2] = 1; if (usingMsaa) { core.recordBeginDebugLabel(cmdStream, "MSAA resolve", { 1, 1, 1, 1 }); @@ -889,11 +838,12 @@ int main(int argc, const char** argv) { assert(msaa == vkcv::Multisampling::MSAA4X); // shaders is written for msaa 4x core.recordComputeDispatchToCmdStream( - cmdStream, - resolvePipeline, - fulsscreenDispatchCount, - { vkcv::DescriptorSetUsage(0, resolveDescriptorSet) }, - vkcv::PushConstants(0)); + cmdStream, + resolvePipeline, + fullscreenDispatchCount, + { vkcv::useDescriptorSet(0, resolveDescriptorSet) }, + vkcv::PushConstants(0) + ); core.recordImageMemoryBarrier(cmdStream, resolvedColorBuffer); } @@ -911,11 +861,11 @@ int main(int argc, const char** argv) { core.recordBeginDebugLabel(cmdStream, "Tonemapping", { 1, 1, 1, 1 }); core.recordComputeDispatchToCmdStream( - cmdStream, - tonemappingPipeline, - fulsscreenDispatchCount, - { vkcv::DescriptorSetUsage(0, tonemappingDescriptorSet) }, - vkcv::PushConstants(0) + cmdStream, + tonemappingPipeline, + fullscreenDispatchCount, + { vkcv::useDescriptorSet(0, tonemappingDescriptorSet) }, + vkcv::PushConstants(0) ); core.prepareImageForStorage(cmdStream, swapBuffer2); @@ -939,26 +889,20 @@ int main(int argc, const char** argv) { core.prepareImageForStorage(cmdStream, swapchainInput); core.prepareImageForSampling(cmdStream, swapBuffer2); - auto timeSinceStart = std::chrono::duration_cast<std::chrono::microseconds>(end - appStartTime); - float timeF = static_cast<float>(timeSinceStart.count()) * 0.01f; - - vkcv::PushConstants timePushConstants (sizeof(timeF)); - timePushConstants.appendDrawcall(timeF); - - fulsscreenDispatchCount[0] = static_cast<uint32_t>( - glm::ceil(swapchainWidth / static_cast<float>(fullscreenLocalGroupSize)) - ); + vkcv::PushConstants timePushConstants = vkcv::pushConstants<float>(); + timePushConstants.appendDrawcall(static_cast<float>(t * 100000.0)); - fulsscreenDispatchCount[1] = static_cast<uint32_t>( - glm::ceil(swapchainHeight / static_cast<float>(fullscreenLocalGroupSize)) + fullscreenDispatchCount = vkcv::dispatchInvocations( + vkcv::DispatchSize(swapchainWidth, swapchainHeight), + vkcv::DispatchSize(fullscreenLocalGroupSize, fullscreenLocalGroupSize) ); core.recordBeginDebugLabel(cmdStream, "Post Processing", { 1, 1, 1, 1 }); core.recordComputeDispatchToCmdStream( cmdStream, postEffectsPipeline, - fulsscreenDispatchCount, - { vkcv::DescriptorSetUsage(0, postEffectsDescriptorSet) }, + fullscreenDispatchCount, + { vkcv::useDescriptorSet(0, postEffectsDescriptorSet) }, timePushConstants ); core.recordEndDebugLabel(cmdStream); @@ -1021,7 +965,8 @@ int main(int argc, const char** argv) { [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { newForwardProgram.addShader(shaderStage, path); }); - forwardPipelineConfig.m_ShaderProgram = newForwardProgram; + + forwardPipelineConfig.setShaderProgram(newForwardProgram); vkcv::GraphicsPipelineHandle newPipeline = core.createGraphicsPipeline(forwardPipelineConfig); if (newPipeline) { @@ -1049,9 +994,7 @@ int main(int argc, const char** argv) { } gui.endGUI(); - - core.endFrame(windowHandle); - } + }); return 0; } diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp index 7c865fac55cc9c4a7185006b3b74b205f9ac9105..e4f02691f9a7d97c355b276c389296e486221f4a 100644 --- a/projects/wobble_bobble/src/main.cpp +++ b/projects/wobble_bobble/src/main.cpp @@ -1,5 +1,8 @@ +#include <vkcv/Buffer.hpp> #include <vkcv/Core.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Image.hpp> #include <vkcv/camera/CameraManager.hpp> #include <vkcv/gui/GUI.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -238,7 +241,8 @@ vkcv::ComputePipelineHandle createComputePipeline(vkcv::Core& core, vkcv::shader vkcv::BufferHandle resetParticles(vkcv::Core& core, size_t count, const glm::vec3& velocity, float density, float size, int form, int mode) { - vkcv::Buffer<Particle> particles = core.createBuffer<Particle>( + vkcv::Buffer<Particle> particles = vkcv::buffer<Particle>( + core, vkcv::BufferType::STORAGE, count ); @@ -301,15 +305,16 @@ int main(int argc, const char **argv) { cameraManager.getCamera(trackballIdx).setCenter(glm::vec3(0.5f, 0.5f, 0.5f)); // set camera to look at the center of the particle volume cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); - auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain()); vkcv::ImageHandle depthBuffer = core.createImage( vk::Format::eD32Sfloat, swapchainExtent.width, swapchainExtent.height - ).getHandle(); + ); - vkcv::Image grid = core.createImage( + vkcv::Image grid = vkcv::image( + core, vk::Format::eR16G16B16A16Sfloat, 32, 32, @@ -327,8 +332,8 @@ int main(int argc, const char **argv) { vkcv::SamplerBorderColor::FLOAT_ZERO_TRANSPARENT ); - vkcv::Buffer<Simulation> simulation = core.createBuffer<Simulation>( - vkcv::BufferType::UNIFORM, 1, vkcv::BufferMemoryType::HOST_VISIBLE + vkcv::Buffer<Simulation> simulation = vkcv::buffer<Simulation>( + core, vkcv::BufferType::UNIFORM, 1, vkcv::BufferMemoryType::HOST_VISIBLE ); Simulation* sim = simulation.map(); @@ -452,45 +457,6 @@ int main(int argc, const char **argv) { { vkcv::ShaderStage::FRAGMENT, "shaders/lines.frag" } }, nullptr); - vkcv::PassConfig passConfigGrid {{ - vkcv::AttachmentDescription( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat() - ), - vkcv::AttachmentDescription( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat - ) - }, vkcv::Multisampling::None }; - - vkcv::PassConfig passConfigParticles {{ - vkcv::AttachmentDescription( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain(windowHandle).getFormat() - ), - vkcv::AttachmentDescription( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - vk::Format::eD32Sfloat - ) - }, vkcv::Multisampling::None }; - - vkcv::PassConfig passConfigLines {{ - vkcv::AttachmentDescription( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - core.getSwapchain(windowHandle).getFormat() - ), - vkcv::AttachmentDescription( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::LOAD, - vk::Format::eD32Sfloat - ) - }, vkcv::Multisampling::None }; - vkcv::DescriptorSetLayoutHandle gfxSetLayoutGrid = core.createDescriptorSetLayout( gfxProgramGrid.getReflectedDescriptors().at(0) ); @@ -517,73 +483,75 @@ int main(int argc, const char **argv) { core.writeDescriptorSet(gfxSetParticles, writes); } - vkcv::PassHandle gfxPassGrid = core.createPass(passConfigGrid); - vkcv::PassHandle gfxPassParticles = core.createPass(passConfigParticles); - vkcv::PassHandle gfxPassLines = core.createPass(passConfigLines); + vkcv::PassHandle gfxPassGrid = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat } + ); + + vkcv::PassHandle gfxPassParticles = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat } + ); + + vkcv::PassHandle gfxPassLines = vkcv::passSwapchain( + core, + window.getSwapchain(), + { vk::Format::eUndefined, vk::Format::eD32Sfloat }, + false + ); vkcv::VertexLayout vertexLayoutGrid ({ vkcv::createVertexBinding(0, gfxProgramGrid.getVertexAttachments()) }); - vkcv::GraphicsPipelineConfig gfxPipelineConfigGrid; - gfxPipelineConfigGrid.m_ShaderProgram = gfxProgramGrid; - gfxPipelineConfigGrid.m_Width = windowWidth; - gfxPipelineConfigGrid.m_Height = windowHeight; - gfxPipelineConfigGrid.m_PassHandle = gfxPassGrid; - gfxPipelineConfigGrid.m_VertexLayout = vertexLayoutGrid; - gfxPipelineConfigGrid.m_DescriptorLayouts = { gfxSetLayoutGrid }; - gfxPipelineConfigGrid.m_UseDynamicViewport = true; + vkcv::GraphicsPipelineConfig gfxPipelineConfigGrid ( + gfxProgramGrid, + gfxPassGrid, + vertexLayoutGrid, + { gfxSetLayoutGrid } + ); vkcv::VertexLayout vertexLayoutParticles ({ vkcv::createVertexBinding(0, gfxProgramParticles.getVertexAttachments()) }); - vkcv::GraphicsPipelineConfig gfxPipelineConfigParticles; - gfxPipelineConfigParticles.m_ShaderProgram = gfxProgramParticles; - gfxPipelineConfigParticles.m_Width = windowWidth; - gfxPipelineConfigParticles.m_Height = windowHeight; - gfxPipelineConfigParticles.m_PassHandle = gfxPassParticles; - gfxPipelineConfigParticles.m_VertexLayout = vertexLayoutParticles; - gfxPipelineConfigParticles.m_DescriptorLayouts = { gfxSetLayoutParticles }; - gfxPipelineConfigParticles.m_UseDynamicViewport = true; + vkcv::GraphicsPipelineConfig gfxPipelineConfigParticles ( + gfxProgramParticles, + gfxPassParticles, + vertexLayoutParticles, + { gfxSetLayoutParticles } + ); vkcv::VertexLayout vertexLayoutLines ({ vkcv::createVertexBinding(0, gfxProgramLines.getVertexAttachments()) }); - vkcv::GraphicsPipelineConfig gfxPipelineConfigLines; - gfxPipelineConfigLines.m_ShaderProgram = gfxProgramLines; - gfxPipelineConfigLines.m_Width = windowWidth; - gfxPipelineConfigLines.m_Height = windowHeight; - gfxPipelineConfigLines.m_PassHandle = gfxPassLines; - gfxPipelineConfigLines.m_VertexLayout = vertexLayoutLines; - gfxPipelineConfigLines.m_DescriptorLayouts = {}; - gfxPipelineConfigLines.m_UseDynamicViewport = true; - gfxPipelineConfigLines.m_PrimitiveTopology = vkcv::PrimitiveTopology::LineList; + vkcv::GraphicsPipelineConfig gfxPipelineConfigLines ( + gfxProgramLines, + gfxPassLines, + vertexLayoutLines, + {} + ); + + gfxPipelineConfigLines.setPrimitiveTopology(vkcv::PrimitiveTopology::LineList); vkcv::GraphicsPipelineHandle gfxPipelineGrid = core.createGraphicsPipeline(gfxPipelineConfigGrid); vkcv::GraphicsPipelineHandle gfxPipelineParticles = core.createGraphicsPipeline(gfxPipelineConfigParticles); vkcv::GraphicsPipelineHandle gfxPipelineLines = core.createGraphicsPipeline(gfxPipelineConfigLines); - vkcv::Buffer<glm::vec2> trianglePositions = core.createBuffer<glm::vec2>(vkcv::BufferType::VERTEX, 3); + vkcv::Buffer<glm::vec2> trianglePositions = vkcv::buffer<glm::vec2>(core, vkcv::BufferType::VERTEX, 3); trianglePositions.fill({ glm::vec2(-1.0f, -1.0f), glm::vec2(+0.0f, +1.5f), glm::vec2(+1.0f, -1.0f) }); - vkcv::Buffer<uint16_t> triangleIndices = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3); - triangleIndices.fill({ - 0, 1, 2 - }); - - vkcv::Mesh triangleMesh ( - { vkcv::VertexBufferBinding(0, trianglePositions.getVulkanHandle()) }, - triangleIndices.getVulkanHandle(), - triangleIndices.getCount() - ); + vkcv::VertexData triangleData ({ vkcv::vertexBufferBinding(trianglePositions.getHandle()) }); + triangleData.setCount(trianglePositions.getCount()); - vkcv::Buffer<glm::vec3> linesPositions = core.createBuffer<glm::vec3>(vkcv::BufferType::VERTEX, 8); + vkcv::Buffer<glm::vec3> linesPositions = vkcv::buffer<glm::vec3>(core, vkcv::BufferType::VERTEX, 8); linesPositions.fill({ glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), @@ -595,7 +563,7 @@ int main(int argc, const char **argv) { glm::vec3(1.0f, 1.0f, 1.0f) }); - vkcv::Buffer<uint16_t> linesIndices = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 24); + vkcv::Buffer<uint16_t> linesIndices = vkcv::buffer<uint16_t>(core, vkcv::BufferType::INDEX, 24); linesIndices.fill({ 0, 1, 1, 3, @@ -613,90 +581,60 @@ int main(int argc, const char **argv) { 3, 7 }); - vkcv::Mesh linesMesh ( - { vkcv::VertexBufferBinding(0, linesPositions.getVulkanHandle()) }, - linesIndices.getVulkanHandle(), - linesIndices.getCount() - ); - - std::vector<vkcv::DrawcallInfo> drawcallsGrid; + vkcv::VertexData linesData ({ vkcv::vertexBufferBinding(linesPositions.getHandle()) }); + linesData.setIndexBuffer(linesIndices.getHandle()); + linesData.setCount(linesIndices.getCount()); - drawcallsGrid.push_back(vkcv::DrawcallInfo( - triangleMesh, - { vkcv::DescriptorSetUsage(0, gfxSetGrid) }, + vkcv::InstanceDrawcall drawcallGrid ( + triangleData, grid.getWidth() * grid.getHeight() * grid.getDepth() - )); - - std::vector<vkcv::DrawcallInfo> drawcallsParticles; + ); - drawcallsParticles.push_back(vkcv::DrawcallInfo( - triangleMesh, - { vkcv::DescriptorSetUsage(0, gfxSetParticles) }, - sim->count - )); + drawcallGrid.useDescriptorSet(0, gfxSetGrid); - std::vector<vkcv::DrawcallInfo> drawcallsLines; + vkcv::InstanceDrawcall drawcallParticle (triangleData, sim->count); + drawcallParticle.useDescriptorSet(0, gfxSetParticles); - drawcallsLines.push_back(vkcv::DrawcallInfo( - linesMesh, - {}, - 1 - )); + vkcv::InstanceDrawcall drawcallLines (linesData); bool renderGrid = true; - float speed_factor = 1.0f; - auto start = std::chrono::system_clock::now(); - auto current = start; - - while (vkcv::Window::hasOpenWindow()) { - vkcv::Window::pollEvents(); - - if (window.getHeight() == 0 || window.getWidth() == 0) - continue; - - uint32_t swapchainWidth, swapchainHeight; - if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { - continue; - } - + core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, + uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight - ).getHandle(); + ); swapchainExtent.width = swapchainWidth; swapchainExtent.height = swapchainHeight; } - auto next = std::chrono::system_clock::now(); - - auto time = std::chrono::duration_cast<std::chrono::microseconds>(next - start); - auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(next - current); - - current = next; - Physics physics; - physics.t = static_cast<float>(0.000001 * static_cast<double>(time.count())); - physics.dt = static_cast<float>(0.000001 * static_cast<double>(deltatime.count())); + physics.t = static_cast<float>(t); + physics.dt = static_cast<float>(dt); physics.speedfactor = speed_factor; - vkcv::PushConstants physicsPushConstants(sizeof(physics)); + vkcv::PushConstants physicsPushConstants = vkcv::pushConstants<Physics>(); physicsPushConstants.appendDrawcall(physics); cameraManager.update(physics.dt); glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); - vkcv::PushConstants cameraPushConstants(sizeof(glm::mat4)); + vkcv::PushConstants cameraPushConstants = vkcv::pushConstants<glm::mat4>(); cameraPushConstants.appendDrawcall(mvp); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - const uint32_t dispatchSizeGrid[3] = {grid.getWidth() / 4, grid.getHeight() / 4, grid.getDepth() / 4}; - const uint32_t dispatchSizeParticles[3] = {static_cast<uint32_t>(sim->count + 63) / 64, 1, 1}; + const auto dispatchSizeGrid = vkcv::dispatchInvocations( + vkcv::DispatchSize(grid.getWidth(), grid.getHeight(), grid.getDepth()), + vkcv::DispatchSize(4, 4, 4) + ); + + const auto dispatchSizeParticles = vkcv::dispatchInvocations(sim->count, 64); for (int step = 0; step < 1; step++) { core.recordBeginDebugLabel(cmdStream, "INIT PARTICLE WEIGHTS", {0.78f, 0.89f, 0.94f, 1.0f}); @@ -708,10 +646,10 @@ int main(int argc, const char **argv) { initParticleWeightsPipeline, dispatchSizeParticles, { - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 0, initParticleWeightsSets[0] ), - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 1, initParticleWeightsSets[1] ) }, @@ -730,13 +668,13 @@ int main(int argc, const char **argv) { transformParticlesToGridPipeline, dispatchSizeGrid, { - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 0, transformParticlesToGridSets[0] ), - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 1, transformParticlesToGridSets[1] ), - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 2, transformParticlesToGridSets[2] ) }, @@ -756,13 +694,13 @@ int main(int argc, const char **argv) { updateParticleVelocitiesPipeline, dispatchSizeParticles, { - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 0, updateParticleVelocitiesSets[0] ), - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 1, updateParticleVelocitiesSets[1] ), - vkcv::DescriptorSetUsage( + vkcv::useDescriptorSet( 2, updateParticleVelocitiesSets[2] ) }, @@ -785,10 +723,9 @@ int main(int argc, const char **argv) { core.recordDrawcallsToCmdStream( cmdStream, - gfxPassGrid, gfxPipelineGrid, cameraPushConstants, - drawcallsGrid, + { drawcallGrid }, renderTargets, windowHandle ); @@ -800,10 +737,9 @@ int main(int argc, const char **argv) { core.recordDrawcallsToCmdStream( cmdStream, - gfxPassParticles, gfxPipelineParticles, cameraPushConstants, - drawcallsParticles, + { drawcallParticle }, renderTargets, windowHandle ); @@ -815,10 +751,9 @@ int main(int argc, const char **argv) { core.recordDrawcallsToCmdStream( cmdStream, - gfxPassLines, gfxPipelineLines, cameraPushConstants, - drawcallsLines, + { drawcallLines }, renderTargets, windowHandle ); @@ -896,9 +831,7 @@ int main(int argc, const char **argv) { ImGui::End(); gui.endGUI(); - - core.endFrame(windowHandle); - } + }); simulation.unmap(); return 0; diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index e1b1a5097be2bd088d1ec1bd39b78695331899f3..da2a370fac7a6d72c762ef47f8316519264a8457 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -3,41 +3,62 @@ * @file vkcv/BufferManager.cpp */ -#include "vkcv/BufferManager.hpp" +#include "BufferManager.hpp" #include "vkcv/Core.hpp" #include <vkcv/Logger.hpp> namespace vkcv { - BufferManager::BufferManager() noexcept : - m_core(nullptr), m_buffers(), m_stagingBuffer(BufferHandle()) - { - } - - void BufferManager::init() { - if (!m_core) { - return; + bool BufferManager::init(Core& core) { + if (!HandleManager<BufferEntry, BufferHandle>::init(core)) { + return false; } m_stagingBuffer = createBuffer( + TypeGuard(1), BufferType::STAGING, - 1024 * 1024, BufferMemoryType::HOST_VISIBLE, - false, + 1024 * 1024, false ); + + return true; } - BufferManager::~BufferManager() noexcept { - for (uint64_t id = 0; id < m_buffers.size(); id++) { - destroyBufferById(id); + uint64_t BufferManager::getIdFrom(const BufferHandle &handle) const { + return handle.getId(); + } + + BufferHandle BufferManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return BufferHandle(id, destroy); + } + + void BufferManager::destroyById(uint64_t id) { + auto& buffer = getById(id); + + const vma::Allocator& allocator = getCore().getContext().getAllocator(); + + if (buffer.m_handle) { + allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation); + + buffer.m_handle = nullptr; + buffer.m_allocation = nullptr; } } - BufferHandle BufferManager::createBuffer(BufferType type, - size_t size, + BufferManager::BufferManager() noexcept : + HandleManager<BufferEntry, BufferHandle>(), + m_stagingBuffer(BufferHandle()) + {} + + BufferManager::~BufferManager() noexcept { + clear(); + } + + BufferHandle BufferManager::createBuffer(const TypeGuard &typeGuard, + BufferType type, BufferMemoryType memoryType, - bool supportIndirect, + size_t size, bool readable) { vk::BufferCreateFlags createFlags; vk::BufferUsageFlags usageFlags; @@ -60,7 +81,8 @@ namespace vkcv { usageFlags = vk::BufferUsageFlagBits::eIndexBuffer; break; case BufferType::INDIRECT: - usageFlags = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer ; + usageFlags = vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eIndirectBuffer ; break; default: vkcv_log(LogLevel::WARNING, "Unknown buffer type"); @@ -71,15 +93,11 @@ namespace vkcv { usageFlags |= vk::BufferUsageFlagBits::eTransferDst; } - if (supportIndirect) { - usageFlags |= vk::BufferUsageFlagBits::eIndirectBuffer; - } - if (readable) { usageFlags |= vk::BufferUsageFlagBits::eTransferSrc; } - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); vk::MemoryPropertyFlags memoryTypeFlags; vma::MemoryUsage memoryUsage; @@ -123,9 +141,15 @@ namespace vkcv { vk::Buffer buffer = bufferAllocation.first; vma::Allocation allocation = bufferAllocation.second; - const uint64_t id = m_buffers.size(); - m_buffers.push_back({ buffer, allocation, size, mappable }); - return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); }); + return add({ + typeGuard, + type, + memoryType, + size, + buffer, + allocation, + mappable + }); } /** @@ -154,21 +178,20 @@ namespace vkcv { * @param core Core instance * @param info Staging-info structure */ - static void fillFromStagingBuffer(Core* core, StagingWriteInfo& info) { + static void fillFromStagingBuffer(Core& core, StagingWriteInfo& info) { const size_t remaining = info.size - info.stagingPosition; const size_t mapped_size = std::min(remaining, info.stagingLimit); - const vma::Allocator& allocator = core->getContext().getAllocator(); + const vma::Allocator& allocator = core.getContext().getAllocator(); void* mapped = allocator.mapMemory(info.stagingAllocation); memcpy(mapped, reinterpret_cast<const char*>(info.data) + info.stagingPosition, mapped_size); allocator.unmapMemory(info.stagingAllocation); - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Transfer; + auto stream = core.createCommandStream(QueueType::Transfer); - core->recordAndSubmitCommandsImmediate( - submitInfo, + core.recordCommandsToStream( + stream, [&info, &mapped_size](const vk::CommandBuffer& commandBuffer) { const vk::BufferCopy region ( 0, @@ -189,6 +212,8 @@ namespace vkcv { } } ); + + core.submitCommandStream(stream, false); } /** @@ -217,15 +242,14 @@ namespace vkcv { * @param core Core instance * @param info Staging-info structure */ - static void readToStagingBuffer(Core* core, StagingReadInfo& info) { + static void readToStagingBuffer(Core& core, StagingReadInfo& info) { const size_t remaining = info.size - info.stagingPosition; const size_t mapped_size = std::min(remaining, info.stagingLimit); - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Transfer; + auto stream = core.createCommandStream(QueueType::Transfer); - core->recordAndSubmitCommandsImmediate( - submitInfo, + core.recordCommandsToStream( + stream, [&info, &mapped_size](const vk::CommandBuffer& commandBuffer) { const vk::BufferCopy region ( info.offset + info.stagingPosition, @@ -236,7 +260,7 @@ namespace vkcv { commandBuffer.copyBuffer(info.buffer, info.stagingBuffer, 1, ®ion); }, [&core, &info, &mapped_size, &remaining]() { - const vma::Allocator& allocator = core->getContext().getAllocator(); + const vma::Allocator& allocator = core.getContext().getAllocator(); const void* mapped = allocator.mapMemory(info.stagingAllocation); memcpy(reinterpret_cast<char*>(info.data) + info.stagingPosition, mapped, mapped_size); @@ -252,42 +276,44 @@ namespace vkcv { } } ); + + core.submitCommandStream(stream, false); } vk::Buffer BufferManager::getBuffer(const BufferHandle& handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return nullptr; - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; return buffer.m_handle; } - size_t BufferManager::getBufferSize(const BufferHandle &handle) const { - const uint64_t id = handle.getId(); + TypeGuard BufferManager::getTypeGuard(const BufferHandle &handle) const { + auto& buffer = (*this)[handle]; - if (id >= m_buffers.size()) { - return 0; - } + return buffer.m_typeGuard; + } + + BufferType BufferManager::getBufferType(const BufferHandle &handle) const { + auto& buffer = (*this)[handle]; + + return buffer.m_type; + } + + BufferMemoryType BufferManager::getBufferMemoryType(const BufferHandle &handle) const { + auto& buffer = (*this)[handle]; - auto& buffer = m_buffers[id]; + return buffer.m_memoryType; + } + + size_t BufferManager::getBufferSize(const BufferHandle &handle) const { + auto& buffer = (*this)[handle]; return buffer.m_size; } vk::DeviceMemory BufferManager::getDeviceMemory(const BufferHandle& handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return nullptr; - } + auto& buffer = (*this)[handle]; - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); auto info = allocator.getAllocationInfo( buffer.m_allocation @@ -300,19 +326,13 @@ namespace vkcv { const void *data, size_t size, size_t offset) { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; if (size == 0) { size = SIZE_MAX; } - if (id >= m_buffers.size()) { - return; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); if (offset > buffer.m_size) { return; @@ -325,7 +345,7 @@ namespace vkcv { memcpy(reinterpret_cast<char*>(mapped) + offset, data, max_size); allocator.unmapMemory(buffer.m_allocation); } else { - auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ]; + auto& stagingBuffer = (*this)[ m_stagingBuffer ]; StagingWriteInfo info; info.data = data; @@ -339,7 +359,7 @@ namespace vkcv { info.stagingLimit = stagingBuffer.m_size; info.stagingPosition = 0; - fillFromStagingBuffer(m_core, info); + fillFromStagingBuffer(getCore(), info); } } @@ -347,19 +367,13 @@ namespace vkcv { void *data, size_t size, size_t offset) { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; if (size == 0) { size = SIZE_MAX; } - if (id >= m_buffers.size()) { - return; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); if (offset > buffer.m_size) { return; @@ -372,7 +386,7 @@ namespace vkcv { memcpy(data, reinterpret_cast<const char*>(mapped) + offset, max_size); allocator.unmapMemory(buffer.m_allocation); } else { - auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ]; + auto& stagingBuffer = (*this)[ m_stagingBuffer ]; StagingReadInfo info; info.data = data; @@ -386,24 +400,18 @@ namespace vkcv { info.stagingLimit = stagingBuffer.m_size; info.stagingPosition = 0; - readToStagingBuffer(m_core, info); + readToStagingBuffer(getCore(), info); } } void* BufferManager::mapBuffer(const BufferHandle& handle, size_t offset, size_t size) { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; if (size == 0) { size = SIZE_MAX; } - if (id >= m_buffers.size()) { - return nullptr; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); if (offset > buffer.m_size) { return nullptr; @@ -413,46 +421,15 @@ namespace vkcv { } void BufferManager::unmapBuffer(const BufferHandle& handle) { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; - if (id >= m_buffers.size()) { - return; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); allocator.unmapMemory(buffer.m_allocation); } - - void BufferManager::destroyBufferById(uint64_t id) { - if (id >= m_buffers.size()) { - return; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); - - if (buffer.m_handle) { - allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation); - - buffer.m_handle = nullptr; - buffer.m_allocation = nullptr; - } - } void BufferManager ::recordBufferMemoryBarrier(const BufferHandle& handle, vk::CommandBuffer cmdBuffer) { - - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - vkcv_log(vkcv::LogLevel::ERROR, "Invalid buffer handle"); - return; - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; vk::BufferMemoryBarrier memoryBarrier( vk::AccessFlagBits::eMemoryWrite, diff --git a/include/vkcv/BufferManager.hpp b/src/vkcv/BufferManager.hpp similarity index 69% rename from include/vkcv/BufferManager.hpp rename to src/vkcv/BufferManager.hpp index 8da11cfea885471f490836bf24c8b5169d1ce401..e86438126fd6775c241fbcfb7a0e493d0885c775 100644 --- a/include/vkcv/BufferManager.hpp +++ b/src/vkcv/BufferManager.hpp @@ -9,57 +9,42 @@ #include <vulkan/vulkan.hpp> #include <vk_mem_alloc.hpp> -#include "Handles.hpp" +#include "vkcv/BufferTypes.hpp" +#include "vkcv/TypeGuard.hpp" -namespace vkcv -{ - - /** - * @brief Enum class to specify types of buffers. - */ - enum class BufferType { - INDEX, - VERTEX, - UNIFORM, - STORAGE, - STAGING, - INDIRECT - }; +#include "HandleManager.hpp" + +namespace vkcv { - /** - * @brief Enum class to specify types of buffer memory. - */ - enum class BufferMemoryType { - DEVICE_LOCAL, - HOST_VISIBLE + struct BufferEntry { + TypeGuard m_typeGuard; + + BufferType m_type; + BufferMemoryType m_memoryType; + size_t m_size; + + vk::Buffer m_handle; + vma::Allocation m_allocation; + + bool m_mappable; }; - class Core; - /** * @brief Class to manage the creation, destruction, allocation * and filling of buffers. */ - class BufferManager - { + class BufferManager : public HandleManager<BufferEntry, BufferHandle> { friend class Core; private: - - struct Buffer - { - vk::Buffer m_handle; - vma::Allocation m_allocation; - size_t m_size = 0; - bool m_mappable = false; - }; - - Core* m_core; - std::vector<Buffer> m_buffers; BufferHandle m_stagingBuffer; - BufferManager() noexcept; + bool init(Core& core) override; + + [[nodiscard]] + uint64_t getIdFrom(const BufferHandle& handle) const override; - void init(); + [[nodiscard]] + BufferHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; /** * Destroys and deallocates buffer represented by a given @@ -67,32 +52,30 @@ namespace vkcv * * @param id Buffer handle id */ - void destroyBufferById(uint64_t id); + void destroyById(uint64_t id) override; public: - ~BufferManager() noexcept; - - BufferManager(BufferManager&& other) = delete; - BufferManager(const BufferManager& other) = delete; + BufferManager() noexcept; - BufferManager& operator=(BufferManager&& other) = delete; - BufferManager& operator=(const BufferManager& other) = delete; + ~BufferManager() noexcept override; /** * @brief Creates and allocates a new buffer and returns its * unique buffer handle. * + * @param[in] typeGuard Type guard * @param[in] type Type of buffer - * @param[in] size Size of buffer in bytes * @param[in] memoryType Type of buffers memory + * @param[in] size Size of buffer in bytes * @param[in] supportIndirect Support of indirect usage * @param[in] readable Support read functionality * @return New buffer handle */ - BufferHandle createBuffer(BufferType type, - size_t size, + [[nodiscard]] + BufferHandle createBuffer(const TypeGuard &typeGuard, + BufferType type, BufferMemoryType memoryType, - bool supportIndirect, + size_t size, bool readable); /** @@ -105,6 +88,36 @@ namespace vkcv [[nodiscard]] vk::Buffer getBuffer(const BufferHandle& handle) const; + /** + * @brief Returns the type guard of a buffer represented + * by a given buffer handle. + * + * @param[in] handle Buffer handle + * @return Type guard + */ + [[nodiscard]] + TypeGuard getTypeGuard(const BufferHandle& handle) const; + + /** + * @brief Returns the buffer type of a buffer represented + * by a given buffer handle. + * + * @param[in] handle Buffer handle + * @return Buffer type + */ + [[nodiscard]] + BufferType getBufferType(const BufferHandle& handle) const; + + /** + * @brief Returns the buffer memory type of a buffer + * represented by a given buffer handle. + * + * @param[in] handle Buffer handle + * @return Buffer memory type + */ + [[nodiscard]] + BufferMemoryType getBufferMemoryType(const BufferHandle& handle) const; + /** * @brief Returns the size of a buffer represented * by a given buffer handle. diff --git a/src/vkcv/CommandResources.cpp b/src/vkcv/CommandResources.cpp deleted file mode 100644 index d5c97946aa97ba897710dda412b6f71bd2ed54c8..0000000000000000000000000000000000000000 --- a/src/vkcv/CommandResources.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "vkcv/CommandResources.hpp" -#include <iostream> - -#include "vkcv/Logger.hpp" - -namespace vkcv { - - std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager &queueManager) { - std::unordered_set<int> indexSet; - for (const auto& queue : queueManager.getGraphicsQueues()) { - indexSet.insert(queue.familyIndex); - } - for (const auto& queue : queueManager.getComputeQueues()) { - indexSet.insert(queue.familyIndex); - } - for (const auto& queue : queueManager.getTransferQueues()) { - indexSet.insert(queue.familyIndex); - } - indexSet.insert(queueManager.getPresentQueue().familyIndex); - return indexSet; - } - - CommandResources createCommandResources(const vk::Device& device, const std::unordered_set<int>& familyIndexSet) { - CommandResources resources; - const size_t queueFamiliesCount = familyIndexSet.size(); - resources.cmdPoolPerQueueFamily.resize(queueFamiliesCount); - - const vk::CommandPoolCreateFlags poolFlags = vk::CommandPoolCreateFlagBits::eTransient; - for (const int familyIndex : familyIndexSet) { - const vk::CommandPoolCreateInfo poolCreateInfo(poolFlags, familyIndex); - resources.cmdPoolPerQueueFamily[familyIndex] = device.createCommandPool(poolCreateInfo, nullptr, {}); - } - - return resources; - } - - void destroyCommandResources(const vk::Device& device, const CommandResources& resources) { - for (const vk::CommandPool &pool : resources.cmdPoolPerQueueFamily) { - device.destroyCommandPool(pool); - } - } - - 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(); - } - - vk::CommandPool chooseCmdPool(const Queue& queue, const CommandResources& cmdResources) { - return cmdResources.cmdPoolPerQueueFamily[queue.familyIndex]; - } - - Queue getQueueForSubmit(QueueType type, const QueueManager& queueManager) { - if (type == QueueType::Graphics) { - return queueManager.getGraphicsQueues().front(); - } - else if (type == QueueType::Compute) { - return queueManager.getComputeQueues().front(); - } - else if (type == QueueType::Transfer) { - return queueManager.getTransferQueues().front(); - } - else if (type == QueueType::Present) { - return queueManager.getPresentQueue(); - } - else { - vkcv_log(LogLevel::ERROR, "Unknown queue type"); - return queueManager.getGraphicsQueues().front(); // graphics is the most general queue - } - } - - void beginCommandBuffer(const vk::CommandBuffer &cmdBuffer, vk::CommandBufferUsageFlags flags) { - const vk::CommandBufferBeginInfo beginInfo(flags); - cmdBuffer.begin(beginInfo); - } - - 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) { - - const std::vector<vk::PipelineStageFlags> waitDstStageMasks(waitSemaphores.size(), vk::PipelineStageFlagBits::eAllCommands); - const vk::SubmitInfo queueSubmitInfo(waitSemaphores, waitDstStageMasks, cmdBuffer, signalSemaphores); - queue.submit(queueSubmitInfo, fence); - } -} \ No newline at end of file diff --git a/src/vkcv/CommandStreamManager.cpp b/src/vkcv/CommandStreamManager.cpp index 872e91c54b1b64616ad5867926e6f656f44ccded..5086d0248f87f91778aa7fcbb6f6a22326666227 100644 --- a/src/vkcv/CommandStreamManager.cpp +++ b/src/vkcv/CommandStreamManager.cpp @@ -4,105 +4,95 @@ #include "vkcv/Logger.hpp" namespace vkcv { - CommandStreamManager::CommandStreamManager() noexcept : m_core(nullptr){} - - CommandStreamManager::~CommandStreamManager() noexcept { - for (const auto& stream : m_commandStreams) { - if (stream.cmdBuffer && stream.cmdBuffer) { - m_core->getContext().getDevice().freeCommandBuffers(stream.cmdPool, stream.cmdBuffer); - } - } + + uint64_t CommandStreamManager::getIdFrom(const CommandStreamHandle &handle) const { + return handle.getId(); } - - void CommandStreamManager::init(Core* core) { - if (!core) { - vkcv_log(LogLevel::ERROR, "Requires valid core pointer"); + + CommandStreamHandle CommandStreamManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return CommandStreamHandle(id, destroy); + } + + void CommandStreamManager::destroyById(uint64_t id) { + auto& stream = getById(id); + + if (stream.cmdBuffer) { + getCore().getContext().getDevice().freeCommandBuffers(stream.cmdPool, stream.cmdBuffer); + stream.cmdBuffer = nullptr; + stream.callbacks.clear(); } - m_core = core; } + + CommandStreamManager::CommandStreamManager() noexcept : + HandleManager<CommandStreamEntry, CommandStreamHandle>() {} - CommandStreamHandle CommandStreamManager::createCommandStream( - const vk::Queue &queue, - vk::CommandPool cmdPool) { - - const vk::CommandBuffer cmdBuffer = allocateCommandBuffer(m_core->getContext().getDevice(), cmdPool); - - CommandStream stream(cmdBuffer, queue, cmdPool); - beginCommandBuffer(stream.cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + CommandStreamManager::~CommandStreamManager() noexcept { + clear(); + } - // find unused stream - int unusedStreamIndex = -1; - for (size_t i = 0; i < m_commandStreams.size(); i++) { - if (m_commandStreams[i].cmdBuffer) { - // still in use - } else { - unusedStreamIndex = i; - break; + CommandStreamHandle CommandStreamManager::createCommandStream(const vk::Queue &queue, + vk::CommandPool cmdPool) { + const vk::CommandBufferAllocateInfo info (cmdPool, vk::CommandBufferLevel::ePrimary, 1); + auto& device = getCore().getContext().getDevice(); + + const vk::CommandBuffer cmdBuffer = device.allocateCommandBuffers(info).front(); + + const vk::CommandBufferBeginInfo beginInfo (vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + cmdBuffer.begin(beginInfo); + + for (uint64_t id = 0; id < getCount(); id++) { + auto& stream = getById(id); + + if (!(stream.cmdBuffer)) { + stream.cmdBuffer = cmdBuffer; + stream.cmdPool = cmdPool; + stream.queue = queue; + + return createById(id, [&](uint64_t id) { destroyById(id); }); } } - - const bool foundUnusedStream = unusedStreamIndex >= 0; - if (foundUnusedStream) { - m_commandStreams[unusedStreamIndex] = stream; - return CommandStreamHandle(unusedStreamIndex); - } - - CommandStreamHandle handle(m_commandStreams.size()); - m_commandStreams.push_back(stream); - return handle; + + return add({ cmdBuffer, cmdPool, queue, {} }); } - void CommandStreamManager::recordCommandsToStream( - const CommandStreamHandle &handle, - const RecordCommandFunction &record) { - - const size_t id = handle.getId(); - if (id >= m_commandStreams.size()) { - vkcv_log(LogLevel::ERROR, "Requires valid handle"); - return; - } - - CommandStream& stream = m_commandStreams[id]; + void CommandStreamManager::recordCommandsToStream(const CommandStreamHandle &handle, + const RecordCommandFunction &record) { + auto& stream = (*this)[handle]; record(stream.cmdBuffer); } - void CommandStreamManager::addFinishCallbackToStream( - const CommandStreamHandle &handle, - const FinishCommandFunction &finish) { - - const size_t id = handle.getId(); - if (id >= m_commandStreams.size()) { - vkcv_log(LogLevel::ERROR, "Requires valid handle"); - return; - } - - CommandStream& stream = m_commandStreams[id]; + void CommandStreamManager::addFinishCallbackToStream(const CommandStreamHandle &handle, + const FinishCommandFunction &finish) { + auto& stream = (*this)[handle]; stream.callbacks.push_back(finish); } - void CommandStreamManager::submitCommandStreamSynchronous( - const CommandStreamHandle &handle, - std::vector<vk::Semaphore> &waitSemaphores, - std::vector<vk::Semaphore> &signalSemaphores) { - - const size_t id = handle.getId(); - if (id >= m_commandStreams.size()) { - vkcv_log(LogLevel::ERROR, "Requires valid handle"); - return; - } - CommandStream& stream = m_commandStreams[id]; + void CommandStreamManager::submitCommandStreamSynchronous(const CommandStreamHandle &handle, + std::vector<vk::Semaphore> &waitSemaphores, + std::vector<vk::Semaphore> &signalSemaphores) { + auto& stream = (*this)[handle]; stream.cmdBuffer.end(); - const auto device = m_core->getContext().getDevice(); - const vk::Fence waitFence = createFence(device); - submitCommandBufferToQueue(stream.queue, stream.cmdBuffer, waitFence, waitSemaphores, signalSemaphores); - waitForFence(device, waitFence); + const auto device = getCore().getContext().getDevice(); + const vk::Fence waitFence = device.createFence({}); + + const std::vector<vk::PipelineStageFlags> waitDstStageMasks ( + waitSemaphores.size(), + vk::PipelineStageFlagBits::eAllCommands + ); + + const vk::SubmitInfo queueSubmitInfo( + waitSemaphores, + waitDstStageMasks, + stream.cmdBuffer, + signalSemaphores + ); + + stream.queue.submit(queueSubmitInfo, waitFence); + assert(device.waitForFences(waitFence, true, UINT64_MAX) == vk::Result::eSuccess); + device.destroyFence(waitFence); - - device.freeCommandBuffers(stream.cmdPool, stream.cmdBuffer); - stream.cmdBuffer = nullptr; - stream.cmdPool = nullptr; - stream.queue = nullptr; + stream.queue = nullptr; for (const auto& finishCallback : stream.callbacks) { finishCallback(); @@ -110,11 +100,8 @@ namespace vkcv { } 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"); - return nullptr; - } - return m_commandStreams[id].cmdBuffer; + auto& stream = (*this)[handle]; + return stream.cmdBuffer; } + } \ No newline at end of file diff --git a/src/vkcv/CommandStreamManager.hpp b/src/vkcv/CommandStreamManager.hpp index 9a8eb3d02143c20532275d5a61ca3cc68aa03778..7913ca223ff78fdc3afb1f41f83d1b31728864df 100644 --- a/src/vkcv/CommandStreamManager.hpp +++ b/src/vkcv/CommandStreamManager.hpp @@ -1,49 +1,44 @@ #pragma once + #include <vulkan/vulkan.hpp> #include <vector> + #include "vkcv/Event.hpp" -#include "vkcv/Handles.hpp" -#include "vkcv/CommandRecordingFunctionTypes.hpp" +#include "vkcv/EventFunctionTypes.hpp" + +#include "HandleManager.hpp" namespace vkcv { - class Core; + /** + * @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 CommandStreamEntry { + vk::CommandBuffer cmdBuffer; + vk::CommandPool cmdPool; + vk::Queue queue; + std::vector<FinishCommandFunction> callbacks; + }; /** * @brief Responsible for creation, deletion, callbacks and recording of command streams */ - class CommandStreamManager - { + class CommandStreamManager : public HandleManager<CommandStreamEntry, CommandStreamHandle> { 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); + [[nodiscard]] + uint64_t getIdFrom(const CommandStreamHandle& handle) const override; + + [[nodiscard]] + CommandStreamHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + void destroyById(uint64_t id) override; public: - ~CommandStreamManager() noexcept; - - CommandStreamManager(CommandStreamManager&& other) = delete; - CommandStreamManager(const CommandStreamManager& other) = delete; - - CommandStreamManager& operator=(CommandStreamManager&& other) = delete; - CommandStreamManager& operator=(const CommandStreamManager& other) = delete; + CommandStreamManager() noexcept; + + ~CommandStreamManager() noexcept override; /** * @brief Creates a new command stream @@ -52,9 +47,8 @@ namespace vkcv { * @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); + CommandStreamHandle createCommandStream(const vk::Queue &queue, + vk::CommandPool cmdPool); /** * @brief Record vulkan commands to a #CommandStream, using a record function @@ -62,7 +56,8 @@ namespace vkcv { * @param handle Command stream handle * @param record Function that records the vulkan commands */ - void recordCommandsToStream(const CommandStreamHandle &handle, const RecordCommandFunction &record); + void recordCommandsToStream(const CommandStreamHandle &handle, + const RecordCommandFunction &record); /** * @brief Add a callback to a #CommandStream that is called @@ -71,7 +66,8 @@ namespace vkcv { * @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); + void addFinishCallbackToStream(const CommandStreamHandle &handle, + const FinishCommandFunction &finish); /** * @brief Submits a #CommandStream to it's queue and returns after execution is finished @@ -80,10 +76,9 @@ namespace vkcv { * @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); + 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 @@ -92,6 +87,7 @@ namespace vkcv { * @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 264389ca9b5ed118666911b07158ab589a4ca0ee..68836cdba92e4a28d6edfe4ee4e142043cde2c44 100644 --- a/src/vkcv/ComputePipelineManager.cpp +++ b/src/vkcv/ComputePipelineManager.cpp @@ -1,53 +1,62 @@ #include "ComputePipelineManager.hpp" -namespace vkcv -{ - - ComputePipelineManager::ComputePipelineManager(vk::Device device) noexcept : - m_Device{device}, - m_Pipelines{} - {} - - ComputePipelineManager::~ComputePipelineManager() noexcept - { - for (uint64_t id = 0; id < m_Pipelines.size(); id++) { - destroyPipelineById(id); - } +#include "vkcv/Core.hpp" + +namespace vkcv { + + uint64_t ComputePipelineManager::getIdFrom(const ComputePipelineHandle &handle) const { + return handle.getId(); + } + + ComputePipelineHandle ComputePipelineManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return ComputePipelineHandle(id, destroy); + } + + void ComputePipelineManager::destroyById(uint64_t id) { + auto& pipeline = getById(id); + + if (pipeline.m_handle) { + getCore().getContext().getDevice().destroy(pipeline.m_handle); + pipeline.m_handle = nullptr; + } + + if (pipeline.m_layout) { + getCore().getContext().getDevice().destroy(pipeline.m_layout); + pipeline.m_layout = nullptr; + } + } + + ComputePipelineManager::ComputePipelineManager() noexcept : + HandleManager<ComputePipelineEntry, ComputePipelineHandle>() {} + + vk::Result ComputePipelineManager::createShaderModule(vk::ShaderModule &module, + const ShaderProgram &shaderProgram, + const ShaderStage stage) { + std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); + vk::ShaderModuleCreateInfo moduleInfo({}, code.size() * sizeof(uint32_t), code.data()); + return getCore().getContext().getDevice().createShaderModule(&moduleInfo, nullptr, &module); + } + + ComputePipelineManager::~ComputePipelineManager() noexcept { + clear(); } - vk::Pipeline ComputePipelineManager::getVkPipeline(const ComputePipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::Pipeline ComputePipelineManager::getVkPipeline(const ComputePipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_handle; } - vk::PipelineLayout ComputePipelineManager::getVkPipelineLayout(const ComputePipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::PipelineLayout ComputePipelineManager::getVkPipelineLayout(const ComputePipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_layout; } ComputePipelineHandle ComputePipelineManager::createComputePipeline(const ShaderProgram& shaderProgram, const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts) { - // Temporally handing over the Shader Program instead of a pipeline config vk::ShaderModule computeModule{}; if (createShaderModule(computeModule, shaderProgram, ShaderStage::COMPUTE) != vk::Result::eSuccess) - return ComputePipelineHandle(); + return {}; vk::PipelineShaderStageCreateInfo pipelineComputeShaderStageInfo( {}, @@ -67,10 +76,11 @@ namespace vkcv } vk::PipelineLayout vkPipelineLayout{}; - if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != - vk::Result::eSuccess) { - m_Device.destroy(computeModule); - return ComputePipelineHandle(); + if (getCore().getContext().getDevice().createPipelineLayout(&pipelineLayoutCreateInfo, + nullptr, + &vkPipelineLayout) != vk::Result::eSuccess) { + getCore().getContext().getDevice().destroy(computeModule); + return {}; } vk::ComputePipelineCreateInfo computePipelineCreateInfo{}; @@ -78,42 +88,17 @@ namespace vkcv computePipelineCreateInfo.layout = vkPipelineLayout; vk::Pipeline vkPipeline; - if (m_Device.createComputePipelines(nullptr, 1, &computePipelineCreateInfo, nullptr, &vkPipeline) != - vk::Result::eSuccess) { - m_Device.destroy(computeModule); + if (getCore().getContext().getDevice().createComputePipelines(nullptr, + 1, + &computePipelineCreateInfo, + nullptr, + &vkPipeline) != vk::Result::eSuccess) { + getCore().getContext().getDevice().destroy(computeModule); return ComputePipelineHandle(); } - - m_Device.destroy(computeModule); - - const uint64_t id = m_Pipelines.size(); - m_Pipelines.push_back({vkPipeline, vkPipelineLayout}); - - return ComputePipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); }); + + getCore().getContext().getDevice().destroy(computeModule); + return add({ vkPipeline, vkPipelineLayout }); } - void vkcv::ComputePipelineManager::destroyPipelineById(uint64_t id) { - if (id >= m_Pipelines.size()) { - return; - } - - auto& pipeline = m_Pipelines[id]; - - if (pipeline.m_handle) { - m_Device.destroy(pipeline.m_handle); - pipeline.m_handle = nullptr; - } - - if (pipeline.m_layout) { - m_Device.destroy(pipeline.m_layout); - pipeline.m_layout = nullptr; - } - } - - vk::Result ComputePipelineManager::createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, const ShaderStage stage) - { - 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 4c186ac7508a0cb8ff98d691d25cd8c3b1726f47..860181c8745756bab37790dadfa37b13d9ac0eab 100644 --- a/src/vkcv/ComputePipelineManager.hpp +++ b/src/vkcv/ComputePipelineManager.hpp @@ -9,28 +9,45 @@ #include <vulkan/vulkan.hpp> #include <vector> -#include "vkcv/Handles.hpp" +#include "HandleManager.hpp" + #include "vkcv/ShaderProgram.hpp" #include "vkcv/ComputePipelineConfig.hpp" -namespace vkcv -{ +namespace vkcv { + + struct ComputePipelineEntry { + vk::Pipeline m_handle; + vk::PipelineLayout m_layout; + }; /** * @brief Class to manage compute pipelines. */ - class ComputePipelineManager - { + class ComputePipelineManager : public HandleManager<ComputePipelineEntry, ComputePipelineHandle> { + private: + [[nodiscard]] + uint64_t getIdFrom(const ComputePipelineHandle& handle) const override; + + [[nodiscard]] + ComputePipelineHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates compute pipeline represented by a given + * compute pipeline handle id. + * + * @param id Compute pipeline handle id + */ + void destroyById(uint64_t id) override; + + vk::Result createShaderModule(vk::ShaderModule &module, + const ShaderProgram &shaderProgram, + ShaderStage stage); + public: - ComputePipelineManager() = delete; // no default ctor - explicit ComputePipelineManager(vk::Device device) noexcept; // ctor - ~ComputePipelineManager() noexcept; // dtor - - ComputePipelineManager(const ComputePipelineManager &other) = delete; // copy-ctor - ComputePipelineManager(ComputePipelineManager &&other) = delete; // move-ctor; - - ComputePipelineManager & operator=(const ComputePipelineManager &other) = delete; // copy-assign op - ComputePipelineManager & operator=(ComputePipelineManager &&other) = delete; // move-assign op + ComputePipelineManager() noexcept; + + ~ComputePipelineManager() noexcept override; // dtor /** * Returns a vk::Pipeline object by handle. @@ -58,20 +75,7 @@ namespace vkcv */ ComputePipelineHandle createComputePipeline(const ShaderProgram& shaderProgram, const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts); - - private: - struct ComputePipeline { - vk::Pipeline m_handle; - vk::PipelineLayout m_layout; - }; - - vk::Device m_Device; - std::vector<ComputePipeline> m_Pipelines; - - void destroyPipelineById(uint64_t id); - - vk::Result createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, ShaderStage stage); - + }; } diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index f0520f0505b193e0e13d7f724242f1286f84634e..d6cc00f964f9f9549ae7d80e61de98932e00e30a 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -352,7 +352,7 @@ namespace vkcv }; if (!checkSupport(supportedLayers, validationLayers)) { - throw std::runtime_error("Validation layers requested but not available!"); + vkcv_log_throw_error("Validation layers requested but not available!"); } #endif @@ -377,7 +377,7 @@ namespace vkcv requiredExtensions.insert(requiredExtensions.end(), instanceExtensions.begin(), instanceExtensions.end()); if (!checkSupport(supportedExtensions, requiredExtensions)) { - throw std::runtime_error("The requested instance extensions are not supported!"); + vkcv_log_throw_error("The requested instance extensions are not supported!"); } const vk::ApplicationInfo applicationInfo( @@ -408,7 +408,7 @@ namespace vkcv vk::PhysicalDevice physicalDevice; if (!pickPhysicalDevice(instance, physicalDevice)) { - throw std::runtime_error("Picking suitable GPU as physical device failed!"); + vkcv_log_throw_error("Picking suitable GPU as physical device failed!"); } FeatureManager featureManager (physicalDevice); @@ -467,15 +467,14 @@ namespace vkcv nullptr, extensions.size(), extensions.data(), - nullptr + nullptr, + &(featureManager.getFeatures()) ); #ifndef NDEBUG deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); deviceCreateInfo.ppEnabledLayerNames = validationLayers.data(); #endif - - deviceCreateInfo.setPNext(&(featureManager.getFeatures())); vk::Device device = physicalDevice.createDevice(deviceCreateInfo); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 22cc66e7cb9c31d569f5d56fab59a7b17cd840a4..576ddc4d4126f258b82f008c23635d32ff374922 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -1,27 +1,78 @@ /** - * @authors Artur Wasmut + * @authors Artur Wasmut, Alexander Gauggel, Tobias Frisch * @file src/vkcv/Core.cpp * @brief Handling of global states regarding dependencies */ #include <GLFW/glfw3.h> +#include <cmath> #include "vkcv/Core.hpp" #include "PassManager.hpp" #include "GraphicsPipelineManager.hpp" #include "ComputePipelineManager.hpp" -#include "vkcv/BufferManager.hpp" +#include "BufferManager.hpp" #include "SamplerManager.hpp" #include "ImageManager.hpp" -#include "DescriptorManager.hpp" +#include "DescriptorSetLayoutManager.hpp" +#include "DescriptorSetManager.hpp" #include "WindowManager.hpp" #include "CommandStreamManager.hpp" -#include <cmath> +#include "vkcv/Image.hpp" #include "vkcv/Logger.hpp" #include "vkcv/BlitDownsampler.hpp" namespace vkcv { + + /** + * @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 + */ + static std::unordered_set<int> generateQueueFamilyIndexSet(const QueueManager &queueManager) { + std::unordered_set<int> indexSet; + + for (const auto& queue : queueManager.getGraphicsQueues()) { + indexSet.insert(queue.familyIndex); + } + + for (const auto& queue : queueManager.getComputeQueues()) { + indexSet.insert(queue.familyIndex); + } + + for (const auto& queue : queueManager.getTransferQueues()) { + indexSet.insert(queue.familyIndex); + } + + indexSet.insert(queueManager.getPresentQueue().familyIndex); + return indexSet; + } + + /** + * @brief Creates and returns 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 pools + */ + static std::vector<vk::CommandPool> createCommandPools(const vk::Device& device, + const std::unordered_set<int>& familyIndexSet) { + std::vector<vk::CommandPool> commandPoolsPerQueueFamily; + commandPoolsPerQueueFamily.resize(familyIndexSet.size()); + + const vk::CommandPoolCreateFlags poolFlags = vk::CommandPoolCreateFlagBits::eTransient; + for (const int familyIndex : familyIndexSet) { + const vk::CommandPoolCreateInfo poolCreateInfo(poolFlags, familyIndex); + commandPoolsPerQueueFamily[familyIndex] = device.createCommandPool(poolCreateInfo, nullptr, {}); + } + + return commandPoolsPerQueueFamily; + } + Core Core::create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags, @@ -35,82 +86,156 @@ namespace vkcv instanceExtensions ); - const auto& queueManager = context.getQueueManager(); - - const std::unordered_set<int> queueFamilySet = generateQueueFamilyIndexSet(queueManager); - const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet); - const auto defaultSyncResources = createSyncResources(context.getDevice()); - - return Core(std::move(context) , commandResources, defaultSyncResources); + return Core(std::move(context)); } - const Context &Core::getContext() const - { + const Context &Core::getContext() const { return m_Context; } - Core::Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : - m_Context(std::move(context)), - m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)}, - m_PipelineManager{std::make_unique<GraphicsPipelineManager>(m_Context.m_Device, m_Context.m_PhysicalDevice)}, - m_ComputePipelineManager{std::make_unique<ComputePipelineManager>(m_Context.m_Device)}, - m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)), - m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())}, - m_SamplerManager(std::unique_ptr<SamplerManager>(new SamplerManager(m_Context.m_Device))), - m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))}, - m_CommandStreamManager{std::unique_ptr<CommandStreamManager>(new CommandStreamManager)}, + Core::Core(Context &&context) noexcept : + m_Context(std::move(context)), + m_PassManager(std::make_unique<PassManager>()), + m_GraphicsPipelineManager(std::make_unique<GraphicsPipelineManager>()), + m_ComputePipelineManager(std::make_unique<ComputePipelineManager>()), + m_DescriptorSetLayoutManager(std::make_unique<DescriptorSetLayoutManager>()), + m_DescriptorSetManager(std::make_unique<DescriptorSetManager>()), + m_BufferManager(std::make_unique<BufferManager>()), + m_SamplerManager(std::make_unique<SamplerManager>()), + m_ImageManager(std::make_unique<ImageManager>()), + m_CommandStreamManager{std::make_unique<CommandStreamManager>()}, m_WindowManager(std::make_unique<WindowManager>()), m_SwapchainManager(std::make_unique<SwapchainManager>()), - m_CommandResources(commandResources), - m_SyncResources(syncResources), + m_CommandPools(), + m_RenderFinished(), + m_SwapchainImageAcquired(), m_downsampler(nullptr) { - m_BufferManager->m_core = this; - m_BufferManager->init(); - m_CommandStreamManager->init(this); - m_SwapchainManager->m_context = &m_Context; - m_ImageManager->m_core = this; + m_CommandPools = createCommandPools( + m_Context.getDevice(), + generateQueueFamilyIndexSet(m_Context.getQueueManager()) + ); + + m_RenderFinished = m_Context.getDevice().createSemaphore({}); + m_SwapchainImageAcquired = m_Context.getDevice().createSemaphore({}); + + m_PassManager->init(*this); + m_GraphicsPipelineManager->init(*this); + m_ComputePipelineManager->init(*this); + m_DescriptorSetLayoutManager->init(*this); + m_DescriptorSetManager->init(*this, *m_DescriptorSetLayoutManager); + m_BufferManager->init(*this); + m_SamplerManager->init(*this); + m_ImageManager->init(*this, *m_BufferManager); + m_CommandStreamManager->init(*this); + m_SwapchainManager->init(*this); m_downsampler = std::unique_ptr<Downsampler>(new BlitDownsampler(*this, *m_ImageManager)); } Core::~Core() noexcept { m_Context.getDevice().waitIdle(); - - destroyCommandResources(m_Context.getDevice(), m_CommandResources); - destroySyncResources(m_Context.getDevice(), m_SyncResources); + + for (const vk::CommandPool &pool : m_CommandPools) { + m_Context.getDevice().destroyCommandPool(pool); + } + + m_Context.getDevice().destroySemaphore(m_RenderFinished); + m_Context.getDevice().destroySemaphore(m_SwapchainImageAcquired); } - GraphicsPipelineHandle Core::createGraphicsPipeline(const GraphicsPipelineConfig &config) - { - return m_PipelineManager->createPipeline(config, *m_PassManager, *m_DescriptorManager); + GraphicsPipelineHandle Core::createGraphicsPipeline(const GraphicsPipelineConfig &config) { + return m_GraphicsPipelineManager->createPipeline(config, *m_PassManager, *m_DescriptorSetLayoutManager); } - ComputePipelineHandle Core::createComputePipeline(const ComputePipelineConfig &config) - { + ComputePipelineHandle Core::createComputePipeline(const ComputePipelineConfig &config) { std::vector<vk::DescriptorSetLayout> layouts; - layouts.resize(config.m_DescriptorSetLayouts.size()); + layouts.resize(config.getDescriptorSetLayouts().size()); for (size_t i = 0; i < layouts.size(); i++) { - layouts[i] = getDescriptorSetLayout(config.m_DescriptorSetLayouts[i]).vulkanHandle; + layouts[i] = m_DescriptorSetLayoutManager->getDescriptorSetLayout( + config.getDescriptorSetLayouts()[i] + ).vulkanHandle; } - return m_ComputePipelineManager->createComputePipeline(config.m_ShaderProgram, layouts); + return m_ComputePipelineManager->createComputePipeline(config.getShaderProgram(), layouts); } - PassHandle Core::createPass(const PassConfig &config) - { + PassHandle Core::createPass(const PassConfig &config) { return m_PassManager->createPass(config); } - + + const PassConfig &Core::getPassConfiguration(const vkcv::PassHandle &pass) { + return m_PassManager->getPassConfig(pass); + } + + BufferHandle Core::createBuffer(BufferType type, + const TypeGuard &typeGuard, + size_t count, + BufferMemoryType memoryType, + bool readable) { + return m_BufferManager->createBuffer( + typeGuard, + type, + memoryType, + count * typeGuard.typeSize(), + readable + ); + } + + BufferHandle Core::createBuffer(BufferType type, + size_t size, + BufferMemoryType memoryType, + bool readable) { + return m_BufferManager->createBuffer( + TypeGuard(1), + type, + memoryType, + size, + readable + ); + } + + vk::Buffer Core::getBuffer(const BufferHandle &buffer) const { + return m_BufferManager->getBuffer(buffer); + } + + BufferType Core::getBufferType(const BufferHandle &handle) const { + return m_BufferManager->getBufferType(handle); + } + + BufferMemoryType Core::getBufferMemoryType(const BufferHandle &handle) const { + return m_BufferManager->getBufferMemoryType(handle); + } + + size_t Core::getBufferSize(const BufferHandle &handle) const { + return m_BufferManager->getBufferSize(handle); + } + + void Core::fillBuffer(const BufferHandle &handle, const void *data, size_t size, size_t offset) { + m_BufferManager->fillBuffer(handle, data, size, offset); + } + + void Core::readBuffer(const BufferHandle &handle, void *data, size_t size, size_t offset) { + m_BufferManager->readBuffer(handle, data, size, offset); + } + + void* Core::mapBuffer(const BufferHandle &handle, size_t offset, size_t size) { + return m_BufferManager->mapBuffer(handle, offset, size); + } + + void Core::unmapBuffer(const BufferHandle &handle) { + m_BufferManager->unmapBuffer(handle); + } + Result Core::acquireSwapchainImage(const SwapchainHandle &swapchainHandle) { uint32_t imageIndex; vk::Result result; try { result = m_Context.getDevice().acquireNextImageKHR( - m_SwapchainManager->getSwapchain(swapchainHandle).getSwapchain(), + m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain, std::numeric_limits<uint64_t>::max(), - m_SyncResources.swapchainImageAcquired, + m_SwapchainImageAcquired, nullptr, &imageIndex, {} ); @@ -127,7 +252,7 @@ namespace vkcv } else if (result == vk::Result::eSuboptimalKHR) { vkcv_log(LogLevel::WARNING, "Acquired image is suboptimal"); - m_SwapchainManager->getSwapchain(swapchainHandle).signalSwapchainRecreation(); + m_SwapchainManager->signalRecreation(swapchainHandle); } m_currentSwapchainImageIndex = imageIndex; @@ -135,21 +260,22 @@ namespace vkcv } bool Core::beginFrame(uint32_t& width, uint32_t& height, const WindowHandle &windowHandle) { - const SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle(); + const Window& window = m_WindowManager->getWindow(windowHandle); + const SwapchainHandle swapchainHandle = window.getSwapchain(); - if (m_SwapchainManager->getSwapchain(swapchainHandle).shouldUpdateSwapchain()) { + if (m_SwapchainManager->shouldUpdateSwapchain(swapchainHandle)) { m_Context.getDevice().waitIdle(); - m_SwapchainManager->getSwapchain(swapchainHandle).updateSwapchain(m_Context, m_WindowManager->getWindow(windowHandle)); + m_SwapchainManager->updateSwapchain(swapchainHandle, window); - if (!m_SwapchainManager->getSwapchain(swapchainHandle).getSwapchain()) { + if (!m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain) { return false; } setSwapchainImages(swapchainHandle); } - const auto& extent = m_SwapchainManager->getSwapchain(swapchainHandle).getExtent(); + const auto& extent = m_SwapchainManager->getExtent(swapchainHandle); width = extent.width; height = extent.height; @@ -171,21 +297,18 @@ namespace vkcv return (m_currentSwapchainImageIndex != std::numeric_limits<uint32_t>::max()); } - std::array<uint32_t, 2> getWidthHeightFromRenderTargets( - const std::vector<ImageHandle>& renderTargets, - const Swapchain& swapchain, - const ImageManager& imageManager) { + static std::array<uint32_t, 2> getWidthHeightFromRenderTargets(const std::vector<ImageHandle>& renderTargets, + const vk::Extent2D& swapchainExtent, + const ImageManager& imageManager) { std::array<uint32_t, 2> widthHeight; if (renderTargets.size() > 0) { const vkcv::ImageHandle firstImage = renderTargets[0]; if (firstImage.isSwapchainImage()) { - const auto& swapchainExtent = swapchain.getExtent(); widthHeight[0] = swapchainExtent.width; widthHeight[1] = swapchainExtent.height; - } - else { + } else { widthHeight[0] = imageManager.getImageWidth(firstImage); widthHeight[1] = imageManager.getImageHeight(firstImage); } @@ -198,28 +321,26 @@ namespace vkcv return widthHeight; } - vk::Framebuffer createFramebuffer( - const std::vector<ImageHandle>& renderTargets, - const ImageManager& imageManager, - const Swapchain& swapchain, - vk::RenderPass renderpass, - vk::Device device) { + static vk::Framebuffer createFramebuffer(const std::vector<ImageHandle> &renderTargets, + const ImageManager &imageManager, + const vk::Extent2D &renderExtent, + const vk::RenderPass &renderpass, + const vk::Device &device) { std::vector<vk::ImageView> attachmentsViews; for (const ImageHandle& handle : renderTargets) { attachmentsViews.push_back(imageManager.getVulkanImageView(handle)); } - const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, swapchain, imageManager); - const vk::FramebufferCreateInfo createInfo( {}, renderpass, static_cast<uint32_t>(attachmentsViews.size()), attachmentsViews.data(), - widthHeight[0], - widthHeight[1], - 1); + renderExtent.width, + renderExtent.height, + 1 + ); return device.createFramebuffer(createInfo); } @@ -240,19 +361,8 @@ namespace vkcv std::vector<vk::ClearValue> createAttachmentClearValues(const std::vector<AttachmentDescription>& attachments) { std::vector<vk::ClearValue> clearValues; for (const auto& attachment : attachments) { - if (attachment.load_operation == AttachmentOperation::CLEAR) { - float clear = 0.0f; - - if (isDepthFormat(attachment.format)) { - clear = 1.0f; - } - - clearValues.emplace_back(std::array<float, 4>{ - clear, - clear, - clear, - 0.f - }); + if (attachment.getLoadOperation() == AttachmentOperation::CLEAR) { + clearValues.push_back(attachment.getClearValue()); } } return clearValues; @@ -285,26 +395,34 @@ namespace vkcv } } - void recordDrawcall( - const Core &core, - const DrawcallInfo &drawcall, - vk::CommandBuffer cmdBuffer, - vk::PipelineLayout pipelineLayout, - const PushConstants &pushConstants, - const size_t drawcallIndex) { + static void recordDrawcall(const DescriptorSetManager &descriptorSetManager, + const BufferManager &bufferManager, + const InstanceDrawcall &drawcall, + vk::CommandBuffer cmdBuffer, + vk::PipelineLayout pipelineLayout, + const PushConstants &pushConstants, + size_t drawcallIndex) { + + const auto& vertexData = drawcall.getVertexData(); - for (uint32_t i = 0; i < drawcall.mesh.vertexBufferBindings.size(); i++) { - const auto& vertexBinding = drawcall.mesh.vertexBufferBindings[i]; - cmdBuffer.bindVertexBuffers(i, vertexBinding.buffer, vertexBinding.offset); + for (uint32_t i = 0; i < vertexData.getVertexBufferBindings().size(); i++) { + const auto& vertexBinding = vertexData.getVertexBufferBindings()[i]; + + cmdBuffer.bindVertexBuffers( + i, + bufferManager.getBuffer(vertexBinding.buffer), + vertexBinding.offset + ); } - for (const auto& descriptorUsage : drawcall.descriptorSets) { + for (const auto& usage : drawcall.getDescriptorSetUsages()) { cmdBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, pipelineLayout, - descriptorUsage.setLocation, - core.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle, - nullptr); + usage.location, + descriptorSetManager.getDescriptorSet(usage.descriptorSet).vulkanHandle, + usage.dynamicOffsets + ); } if (pushConstants.getSizePerDrawcall() > 0) { @@ -313,271 +431,363 @@ namespace vkcv vk::ShaderStageFlagBits::eAll, 0, pushConstants.getSizePerDrawcall(), - pushConstants.getDrawcallData(drawcallIndex)); + pushConstants.getDrawcallData(drawcallIndex) + ); } - if (drawcall.mesh.indexBuffer) { - cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, getIndexType(drawcall.mesh.indexBitCount)); - cmdBuffer.drawIndexed(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {}); - } - else { - cmdBuffer.draw(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {}); + if (vertexData.getIndexBuffer()) { + cmdBuffer.bindIndexBuffer( + bufferManager.getBuffer(vertexData.getIndexBuffer()), + 0, + getIndexType(vertexData.getIndexBitCount()) + ); + + cmdBuffer.drawIndexed(vertexData.getCount(), drawcall.getInstanceCount(), 0, 0, {}); + } else { + cmdBuffer.draw(vertexData.getCount(), drawcall.getInstanceCount(), 0, 0, {}); } } - - void Core::recordDrawcallsToCmdStream( - const CommandStreamHandle& cmdStreamHandle, - const PassHandle& renderpassHandle, - const GraphicsPipelineHandle &pipelineHandle, - const PushConstants &pushConstantData, - const std::vector<DrawcallInfo> &drawcalls, - const std::vector<ImageHandle> &renderTargets, - const WindowHandle &windowHandle) { - - SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle(); - - if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { + + static void recordGraphicsPipeline(Core& core, + CommandStreamManager &cmdStreamManager, + GraphicsPipelineManager &pipelineManager, + PassManager &passManager, + ImageManager &imageManager, + const CommandStreamHandle &cmdStreamHandle, + const GraphicsPipelineHandle &pipelineHandle, + const PushConstants &pushConstants, + const std::vector<ImageHandle> &renderTargets, + const WindowHandle &windowHandle, + const RecordCommandFunction &record) { + + const SwapchainHandle swapchainHandle = core.getWindow(windowHandle).getSwapchain(); + + const std::array<uint32_t, 2> extent = getWidthHeightFromRenderTargets( + renderTargets, + core.getSwapchainExtent(swapchainHandle), + imageManager + ); + + const auto width = extent[0]; + const auto height = extent[1]; + + const PassHandle &passHandle = pipelineManager.getPipelineConfig(pipelineHandle).getPass(); + + const vk::RenderPass renderPass = passManager.getVkPass(passHandle); + const PassConfig passConfig = passManager.getPassConfig(passHandle); + + const auto& attachments = passConfig.getAttachments(); + const auto& layouts = passManager.getLayouts(passHandle); + + if (renderTargets.size() != layouts.size()) { + vkcv_log(LogLevel::ERROR, "Amount of render targets does not match specified pipeline"); return; } - - const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_SwapchainManager->getSwapchain(swapchainHandle), *m_ImageManager); - const auto width = widthHeight[0]; - const auto height = widthHeight[1]; - - const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); - const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); - - const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); - const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); - const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); - - vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); - transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer); - - const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_SwapchainManager->getSwapchain(swapchainHandle), renderpass, m_Context.m_Device); - + + const vk::Pipeline pipeline = pipelineManager.getVkPipeline(pipelineHandle); + const vk::Rect2D renderArea (vk::Offset2D(0, 0), vk::Extent2D(width, height)); + + vk::CommandBuffer cmdBuffer = cmdStreamManager.getStreamCommandBuffer(cmdStreamHandle); + transitionRendertargetsToAttachmentLayout(renderTargets, imageManager, cmdBuffer); + + for (size_t i = 0; i < layouts.size(); i++) { + imageManager.recordImageLayoutTransition(renderTargets[i], 0, 0, layouts[i], cmdBuffer); + } + + const vk::Framebuffer framebuffer = createFramebuffer( + renderTargets, + imageManager, + renderArea.extent, + renderPass, + core.getContext().getDevice() + ); + if (!framebuffer) { vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer"); return; } - - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; - - auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { - const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); - - const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); + + auto submitFunction = [&](const vk::CommandBuffer &cmdBuffer) { + const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(attachments); + + const vk::RenderPassBeginInfo beginInfo( + renderPass, + framebuffer, + renderArea, + clearValues.size(), + clearValues.data() + ); + cmdBuffer.beginRenderPass(beginInfo, {}, {}); - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); - - const GraphicsPipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); - if (pipeConfig.m_UseDynamicViewport) { + + const GraphicsPipelineConfig &pipeConfig = pipelineManager.getPipelineConfig(pipelineHandle); + + if (pipeConfig.isViewportDynamic()) { recordDynamicViewport(cmdBuffer, width, height); } - - for (size_t i = 0; i < drawcalls.size(); i++) { - recordDrawcall(*this, drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i); + + if (record) { + record(cmdBuffer); } - + cmdBuffer.endRenderPass(); }; - - auto finishFunction = [framebuffer, this]() - { - m_Context.m_Device.destroy(framebuffer); + + auto finishFunction = [framebuffer, &core]() { + core.getContext().getDevice().destroy(framebuffer); }; - - recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction); + + core.recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction); } - void Core::recordIndexedIndirectDrawcallsToCmdStream( - const CommandStreamHandle cmdStreamHandle, - const PassHandle renderpassHandle, - const GraphicsPipelineHandle &pipelineHandle, - const PushConstants &pushConstantData, - const vkcv::DescriptorSetHandle &compiledDescriptorSet, - const vkcv::Mesh &compiledMesh, - const std::vector<ImageHandle> &renderTargets, - const vkcv::Buffer<vk::DrawIndexedIndirectCommand> &indirectBuffer, - const uint32_t drawCount, - const WindowHandle &windowHandle) { - - if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { - return; - } - SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle(); - const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_SwapchainManager->getSwapchain(swapchainHandle), - *m_ImageManager); - const auto width = widthHeight[0]; - const auto height = widthHeight[1]; - - const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); - const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); - - const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); - const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); - const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); - - vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); - transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer); - - const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_SwapchainManager->getSwapchain(swapchainHandle), renderpass, - m_Context.m_Device); - - if (!framebuffer) { - vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer"); - return; - } - - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - submitInfo.signalSemaphores = {m_SyncResources.renderFinished}; - - auto submitFunction = [&](const vk::CommandBuffer &cmdBuffer) { - - const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); - - const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), - clearValues.data()); - cmdBuffer.beginRenderPass(beginInfo, {}, {}); - - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); + void Core::recordDrawcallsToCmdStream(const CommandStreamHandle &cmdStreamHandle, + const GraphicsPipelineHandle &pipelineHandle, + const PushConstants &pushConstantData, + const std::vector<InstanceDrawcall> &drawcalls, + const std::vector<ImageHandle> &renderTargets, + const WindowHandle &windowHandle) { + + if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { + return; + } + + const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout( + pipelineHandle + ); - const GraphicsPipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); - if (pipeConfig.m_UseDynamicViewport) { - recordDynamicViewport(cmdBuffer, width, height); - } + auto recordFunction = [&](const vk::CommandBuffer& cmdBuffer) { + for (size_t i = 0; i < drawcalls.size(); i++) { + recordDrawcall( + *m_DescriptorSetManager, + *m_BufferManager, + drawcalls[i], + cmdBuffer, + pipelineLayout, + pushConstantData, + i + ); + } + }; - if (pushConstantData.getSizePerDrawcall() > 0) - { - cmdBuffer.pushConstants( + recordGraphicsPipeline( + *this, + *m_CommandStreamManager, + *m_GraphicsPipelineManager, + *m_PassManager, + *m_ImageManager, + cmdStreamHandle, + pipelineHandle, + pushConstantData, + renderTargets, + windowHandle, + recordFunction + ); + } + + static void recordIndirectDrawcall(const Core& core, + const DescriptorSetManager &descriptorSetManager, + const BufferManager &bufferManager, + vk::CommandBuffer cmdBuffer, + vk::PipelineLayout pipelineLayout, + const PushConstants& pushConstantData, + size_t drawcallIndex, + const IndirectDrawcall& drawcall) { + for (const auto& usage : drawcall.getDescriptorSetUsages()) { + cmdBuffer.bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, + pipelineLayout, + usage.location, + descriptorSetManager.getDescriptorSet(usage.descriptorSet).vulkanHandle, + usage.dynamicOffsets + ); + } + + const auto& vertexData = drawcall.getVertexData(); + + for (uint32_t i = 0; i < vertexData.getVertexBufferBindings().size(); i++) { + const auto& vertexBinding = vertexData.getVertexBufferBindings()[i]; + + cmdBuffer.bindVertexBuffers( + i, + bufferManager.getBuffer(vertexBinding.buffer), + vertexBinding.offset + ); + } + + if (pushConstantData.getSizePerDrawcall() > 0) { + cmdBuffer.pushConstants( pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantData.getSizePerDrawcall(), - pushConstantData.getDrawcallData(0)); - } - - vkcv::DescriptorSet descSet = m_DescriptorManager->getDescriptorSet(compiledDescriptorSet); - - cmdBuffer.bindDescriptorSets( - vk::PipelineBindPoint::eGraphics, - pipelineLayout, - 0, - descSet.vulkanHandle, - nullptr); - - vk::DeviceSize deviceSize = 0; - cmdBuffer.bindVertexBuffers(0, 1, &compiledMesh.vertexBufferBindings[0].buffer,&deviceSize); - cmdBuffer.bindIndexBuffer(compiledMesh.indexBuffer, 0, getIndexType(compiledMesh.indexBitCount)); - - cmdBuffer.drawIndexedIndirect( - indirectBuffer.getVulkanHandle(), - 0, - drawCount, - sizeof(vk::DrawIndexedIndirectCommand)); - - cmdBuffer.endRenderPass(); - }; + pushConstantData.getDrawcallData(0) + ); + } + + if (vertexData.getIndexBuffer()) { + cmdBuffer.bindIndexBuffer( + bufferManager.getBuffer(vertexData.getIndexBuffer()), + 0, + getIndexType(vertexData.getIndexBitCount()) + ); + + cmdBuffer.drawIndexedIndirect( + bufferManager.getBuffer(drawcall.getIndirectDrawBuffer()), + 0, + drawcall.getDrawCount(), + sizeof(vk::DrawIndexedIndirectCommand) + ); + } else { + cmdBuffer.drawIndirect( + bufferManager.getBuffer(drawcall.getIndirectDrawBuffer()), + 0, + drawcall.getDrawCount(), + sizeof(vk::DrawIndirectCommand) + ); + } + } - auto finishFunction = [framebuffer, this]() { - m_Context.m_Device.destroy(framebuffer); - }; + void Core::recordIndirectDrawcallsToCmdStream(const vkcv::CommandStreamHandle cmdStreamHandle, + const vkcv::GraphicsPipelineHandle &pipelineHandle, + const vkcv::PushConstants &pushConstantData, + const std::vector<IndirectDrawcall> &drawcalls, + const std::vector<ImageHandle> &renderTargets, + const vkcv::WindowHandle &windowHandle) { - recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction); + if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { + return; + } + + const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout( + pipelineHandle + ); + + auto recordFunction = [&](const vk::CommandBuffer& cmdBuffer) { + for (size_t i = 0; i < drawcalls.size(); i++) { + recordIndirectDrawcall( + *this, + *m_DescriptorSetManager, + *m_BufferManager, + cmdBuffer, + pipelineLayout, + pushConstantData, + i, + drawcalls[i] + ); + } + }; + + recordGraphicsPipeline( + *this, + *m_CommandStreamManager, + *m_GraphicsPipelineManager, + *m_PassManager, + *m_ImageManager, + cmdStreamHandle, + pipelineHandle, + pushConstantData, + renderTargets, + windowHandle, + recordFunction + ); } - - void Core::recordMeshShaderDrawcalls( - const CommandStreamHandle& cmdStreamHandle, - const PassHandle& renderpassHandle, - const GraphicsPipelineHandle &pipelineHandle, - const PushConstants& pushConstantData, - const std::vector<MeshShaderDrawcall>& drawcalls, - const std::vector<ImageHandle>& renderTargets, - const WindowHandle& windowHandle) { - - SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle(); - - if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { + + static void recordMeshShaderDrawcall(const Core& core, + const DescriptorSetManager &descriptorSetManager, + vk::CommandBuffer cmdBuffer, + vk::PipelineLayout pipelineLayout, + const PushConstants& pushConstantData, + size_t drawcallIndex, + const TaskDrawcall& drawcall) { + + 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.getDescriptorSetUsages()) { + cmdBuffer.bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, + pipelineLayout, + descriptorUsage.location, + descriptorSetManager.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle, + descriptorUsage.dynamicOffsets + ); + } + + if (pushConstantData.getData()) { + cmdBuffer.pushConstants( + pipelineLayout, + vk::ShaderStageFlagBits::eAll, + 0, + pushConstantData.getSizePerDrawcall(), + pushConstantData.getDrawcallData(drawcallIndex) + ); + } + + cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.getTaskCount(), 0); + } - const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_SwapchainManager->getSwapchain(swapchainHandle), *m_ImageManager); - const auto width = widthHeight[0]; - const auto height = widthHeight[1]; - - const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); - const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); - - const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); - const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); - const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); - - vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); - transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer); - - const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_SwapchainManager->getSwapchain(swapchainHandle), renderpass, m_Context.m_Device); - - if (!framebuffer) { - vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer"); + void Core::recordMeshShaderDrawcalls(const CommandStreamHandle &cmdStreamHandle, + const GraphicsPipelineHandle &pipelineHandle, + const PushConstants &pushConstantData, + const std::vector<TaskDrawcall> &drawcalls, + const std::vector<ImageHandle> &renderTargets, + const WindowHandle &windowHandle) { + + if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; } + + const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout( + pipelineHandle + ); - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; - - auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { - const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); - - const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); - cmdBuffer.beginRenderPass(beginInfo, {}, {}); - - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); - - const GraphicsPipelineConfig& pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); - if (pipeConfig.m_UseDynamicViewport) { - recordDynamicViewport(cmdBuffer, width, height); - } - + auto recordFunction = [&](const vk::CommandBuffer& cmdBuffer) { for (size_t i = 0; i < drawcalls.size(); i++) { - const uint32_t pushConstantOffset = i * pushConstantData.getSizePerDrawcall(); recordMeshShaderDrawcall( *this, + *m_DescriptorSetManager, cmdBuffer, pipelineLayout, pushConstantData, - pushConstantOffset, - drawcalls[i], - 0 + i, + drawcalls[i] ); } - - cmdBuffer.endRenderPass(); }; - - auto finishFunction = [framebuffer, this]() { - m_Context.m_Device.destroy(framebuffer); - }; - - recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction); + + recordGraphicsPipeline( + *this, + *m_CommandStreamManager, + *m_GraphicsPipelineManager, + *m_PassManager, + *m_ImageManager, + cmdStreamHandle, + pipelineHandle, + pushConstantData, + renderTargets, + windowHandle, + recordFunction + ); } - void Core::recordRayGenerationToCmdStream( - CommandStreamHandle cmdStreamHandle, - vk::Pipeline rtxPipeline, - vk::PipelineLayout rtxPipelineLayout, - vk::StridedDeviceAddressRegionKHR rgenRegion, - vk::StridedDeviceAddressRegionKHR rmissRegion, - vk::StridedDeviceAddressRegionKHR rchitRegion, - vk::StridedDeviceAddressRegionKHR rcallRegion, - const std::vector<DescriptorSetUsage>& descriptorSetUsages, - const PushConstants& pushConstants, - const WindowHandle windowHandle) { + void Core::recordRayGenerationToCmdStream(CommandStreamHandle cmdStreamHandle, + vk::Pipeline rtxPipeline, + vk::PipelineLayout rtxPipelineLayout, + vk::StridedDeviceAddressRegionKHR rgenRegion, + vk::StridedDeviceAddressRegionKHR rmissRegion, + vk::StridedDeviceAddressRegionKHR rchitRegion, + vk::StridedDeviceAddressRegionKHR rcallRegion, + const std::vector<DescriptorSetUsage>& descriptorSetUsages, + const PushConstants& pushConstants, + const WindowHandle& windowHandle) { auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { cmdBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, rtxPipeline); @@ -585,8 +795,8 @@ namespace vkcv cmdBuffer.bindDescriptorSets( vk::PipelineBindPoint::eRayTracingKHR, rtxPipelineLayout, - usage.setLocation, - { getDescriptorSet(usage.descriptorSet).vulkanHandle }, + usage.location, + { m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle }, usage.dynamicOffsets ); } @@ -610,15 +820,12 @@ namespace vkcv recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); } - void Core::recordComputeDispatchToCmdStream( - CommandStreamHandle cmdStreamHandle, - ComputePipelineHandle computePipeline, - const uint32_t dispatchCount[3], - const std::vector<DescriptorSetUsage>& descriptorSetUsages, - const PushConstants& pushConstants) { - + void Core::recordComputeDispatchToCmdStream(const CommandStreamHandle& cmdStreamHandle, + const ComputePipelineHandle& computePipeline, + const DispatchSize& dispatchSize, + const std::vector<DescriptorSetUsage>& descriptorSetUsages, + const PushConstants& pushConstants) { auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { - const auto pipelineLayout = m_ComputePipelineManager->getVkPipelineLayout(computePipeline); cmdBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, m_ComputePipelineManager->getVkPipeline(computePipeline)); @@ -626,8 +833,8 @@ namespace vkcv cmdBuffer.bindDescriptorSets( vk::PipelineBindPoint::eCompute, pipelineLayout, - usage.setLocation, - { getDescriptorSet(usage.descriptorSet).vulkanHandle }, + usage.location, + { m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle }, usage.dynamicOffsets ); } @@ -639,7 +846,8 @@ namespace vkcv pushConstants.getSizePerDrawcall(), pushConstants.getData()); } - cmdBuffer.dispatch(dispatchCount[0], dispatchCount[1], dispatchCount[2]); + + cmdBuffer.dispatch(dispatchSize.x(), dispatchSize.y(), dispatchSize.z()); }; recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); @@ -705,8 +913,8 @@ namespace vkcv cmdBuffer.bindDescriptorSets( vk::PipelineBindPoint::eCompute, pipelineLayout, - usage.setLocation, - { getDescriptorSet(usage.descriptorSet).vulkanHandle }, + usage.location, + { m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle }, usage.dynamicOffsets ); } @@ -725,19 +933,18 @@ namespace vkcv } void Core::endFrame(const WindowHandle& windowHandle) { - - SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle(); + SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain(); if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; } - std::array<vk::Semaphore, 2> waitSemaphores{ - m_SyncResources.renderFinished, - m_SyncResources.swapchainImageAcquired + const std::array<vk::Semaphore, 2> waitSemaphores { + m_RenderFinished, + m_SwapchainImageAcquired }; - const vk::SwapchainKHR& swapchain = m_SwapchainManager->getSwapchain(swapchainHandle).getSwapchain(); + const vk::SwapchainKHR& swapchain = m_SwapchainManager->getSwapchain(swapchainHandle).m_Swapchain; const vk::PresentInfoKHR presentInfo( waitSemaphores, swapchain, @@ -747,7 +954,7 @@ namespace vkcv vk::Result result; try { - result = m_Context.getDevice().getQueue(m_SwapchainManager->getSwapchain(swapchainHandle).getPresentQueueIndex(),0).presentKHR(presentInfo); + result = m_Context.getDevice().getQueue(m_SwapchainManager->getPresentQueueIndex(swapchainHandle),0).presentKHR(presentInfo); } catch (const vk::OutOfDateKHRError& e) { result = vk::Result::eErrorOutOfDateKHR; } catch (const vk::DeviceLostError& e) { @@ -764,67 +971,60 @@ namespace vkcv } } - void Core::recordAndSubmitCommandsImmediate( - const SubmitInfo &submitInfo, - const RecordCommandFunction &record, - const FinishCommandFunction &finish) - { - const vk::Device& device = m_Context.getDevice(); - - const vkcv::Queue queue = getQueueForSubmit(submitInfo.queueType, m_Context.getQueueManager()); - const vk::CommandPool cmdPool = chooseCmdPool(queue, m_CommandResources); - const vk::CommandBuffer cmdBuffer = allocateCommandBuffer(device, cmdPool); - - beginCommandBuffer(cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); - record(cmdBuffer); - cmdBuffer.end(); - - vk::Fence waitFence = createFence(device); - - submitCommandBufferToQueue(queue.handle, cmdBuffer, waitFence, submitInfo.waitSemaphores, submitInfo.signalSemaphores); - waitForFence(device, waitFence); - - device.destroyFence(waitFence); - - device.freeCommandBuffers(cmdPool, cmdBuffer); - - if (finish) { - finish(); + /** + * @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 + */ + static Queue getQueueForSubmit(QueueType type, const QueueManager& queueManager) { + switch (type) { + case QueueType::Graphics: + return queueManager.getGraphicsQueues().front(); + case QueueType::Compute: + return queueManager.getComputeQueues().front(); + case QueueType::Transfer: + return queueManager.getTransferQueues().front(); + case QueueType::Present: + return queueManager.getPresentQueue(); + default: { + vkcv_log(LogLevel::ERROR, "Unknown queue type"); + return queueManager.getGraphicsQueues().front(); // graphics is the most general queue + } } } - + CommandStreamHandle Core::createCommandStream(QueueType queueType) { - const vkcv::Queue queue = getQueueForSubmit(queueType, m_Context.getQueueManager()); - const vk::CommandPool cmdPool = chooseCmdPool(queue, m_CommandResources); + const vkcv::Queue queue = getQueueForSubmit(queueType, m_Context.getQueueManager()); + const vk::CommandPool cmdPool = m_CommandPools[queue.familyIndex]; return m_CommandStreamManager->createCommandStream(queue.handle, cmdPool); } - void Core::recordCommandsToStream( - const CommandStreamHandle cmdStreamHandle, - const RecordCommandFunction &record, - const FinishCommandFunction &finish) { - + void Core::recordCommandsToStream(const CommandStreamHandle &stream, + const RecordCommandFunction &record, + const FinishCommandFunction &finish) { if (record) { - m_CommandStreamManager->recordCommandsToStream(cmdStreamHandle, record); + m_CommandStreamManager->recordCommandsToStream(stream, record); } if (finish) { - m_CommandStreamManager->addFinishCallbackToStream(cmdStreamHandle, finish); + m_CommandStreamManager->addFinishCallbackToStream(stream, finish); } } - void Core::submitCommandStream(const CommandStreamHandle& handle, + void Core::submitCommandStream(const CommandStreamHandle& stream, bool signalRendering) { std::vector<vk::Semaphore> waitSemaphores; // FIXME: add proper user controllable sync std::vector<vk::Semaphore> signalSemaphores; if (signalRendering) { - signalSemaphores.push_back(m_SyncResources.renderFinished); + signalSemaphores.push_back(m_RenderFinished); } - m_CommandStreamManager->submitCommandStreamSynchronous(handle, waitSemaphores, signalSemaphores); + m_CommandStreamManager->submitCommandStreamSynchronous(stream, waitSemaphores, signalSemaphores); } SamplerHandle Core::createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter, @@ -833,46 +1033,52 @@ namespace vkcv return m_SamplerManager->createSampler(magFilter, minFilter, mipmapMode, addressMode, mipLodBias, borderColor); } - Image Core::createImage( - vk::Format format, - uint32_t width, - uint32_t height, - uint32_t depth, - bool createMipChain, - bool supportStorage, - bool supportColorAttachment, - Multisampling multisampling) - { - + ImageHandle Core::createImage(vk::Format format, + uint32_t width, + uint32_t height, + uint32_t depth, + bool createMipChain, + bool supportStorage, + bool supportColorAttachment, + Multisampling multisampling) { uint32_t mipCount = 1; if (createMipChain) { mipCount = 1 + (uint32_t)std::floor(std::log2(std::max(width, std::max(height, depth)))); } - - return Image::create( - m_ImageManager.get(), - format, - width, - height, - depth, - mipCount, - supportStorage, - supportColorAttachment, - multisampling); + + return m_ImageManager->createImage( + width, + height, + depth, + format, + mipCount, + supportStorage, + supportColorAttachment, + multisampling + ); + } + + void Core::fillImage(const ImageHandle &image, + const void *data, + size_t size) { + m_ImageManager->fillImage(image, data, size); + } + + void Core::switchImageLayout(const ImageHandle &image, + vk::ImageLayout layout) { + m_ImageManager->switchImageLayoutImmediate(image, layout); } Downsampler &Core::getDownsampler() { return *m_downsampler; } - WindowHandle Core::createWindow( - const char *applicationName, - uint32_t windowWidth, - uint32_t windowHeight, - bool resizeable) { - + WindowHandle Core::createWindow(const char *applicationName, + uint32_t windowWidth, + uint32_t windowHeight, + bool resizeable) { WindowHandle windowHandle = m_WindowManager->createWindow(*m_SwapchainManager ,applicationName, windowWidth, windowHeight, resizeable); - SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchainHandle(); + SwapchainHandle swapchainHandle = m_WindowManager->getWindow(windowHandle).getSwapchain(); setSwapchainImages( swapchainHandle ); return windowHandle; } @@ -880,7 +1086,19 @@ namespace vkcv Window& Core::getWindow(const WindowHandle& handle) { return m_WindowManager->getWindow(handle); } - + + vk::Format Core::getSwapchainFormat(const SwapchainHandle &swapchain) const { + return m_SwapchainManager->getFormat(swapchain); + } + + uint32_t Core::getSwapchainImageCount(const SwapchainHandle &swapchain) const { + return m_SwapchainManager->getImageCount(swapchain); + } + + vk::Extent2D Core::getSwapchainExtent(const SwapchainHandle& swapchain) const { + return m_SwapchainManager->getExtent(swapchain); + } + uint32_t Core::getImageWidth(const ImageHandle& image) { return m_ImageManager->getImageWidth(image); @@ -912,45 +1130,22 @@ namespace vkcv return m_ImageManager->getImageArrayLayers(image); } - Swapchain& Core::getSwapchainOfCurrentWindow() { - return m_SwapchainManager->getSwapchain(Window::getFocusedWindow().getSwapchainHandle()); - } - - Swapchain& Core::getSwapchain(const SwapchainHandle& handle) { - return m_SwapchainManager->getSwapchain(handle); - } - - Swapchain& Core::getSwapchain(const WindowHandle& handle) { - SwapchainHandle swapchainHandle = m_WindowManager->getWindow(handle).getSwapchainHandle(); - return getSwapchain(swapchainHandle); - } - - DescriptorSetLayoutHandle Core::createDescriptorSetLayout(const DescriptorBindings &bindings) - { - return m_DescriptorManager->createDescriptorSetLayout(bindings); - } - - DescriptorSetLayout Core::getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const - { - return m_DescriptorManager->getDescriptorSetLayout(handle); + DescriptorSetLayoutHandle Core::createDescriptorSetLayout(const DescriptorBindings &bindings) { + return m_DescriptorSetLayoutManager->createDescriptorSetLayout(bindings); } - DescriptorSetHandle Core::createDescriptorSet(const DescriptorSetLayoutHandle &layout) - { - return m_DescriptorManager->createDescriptorSet(layout); + DescriptorSetHandle Core::createDescriptorSet(const DescriptorSetLayoutHandle &layout) { + return m_DescriptorSetManager->createDescriptorSet(layout); } void Core::writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites &writes) { - m_DescriptorManager->writeDescriptorSet( + m_DescriptorSetManager->writeDescriptorSet( handle, writes, *m_ImageManager, *m_BufferManager, - *m_SamplerManager); - } - - DescriptorSet Core::getDescriptorSet(const DescriptorSetHandle handle) const { - return m_DescriptorManager->getDescriptorSet(handle); + *m_SamplerManager + ); } void Core::prepareSwapchainImageForPresent(const CommandStreamHandle& cmdStream) { @@ -1108,16 +1303,16 @@ namespace vkcv } void Core::setSwapchainImages( SwapchainHandle handle ) { - Swapchain swapchain = m_SwapchainManager->getSwapchain(handle); + const auto& swapchain = m_SwapchainManager->getSwapchain(handle); const auto swapchainImages = m_SwapchainManager->getSwapchainImages(handle); const auto swapchainImageViews = m_SwapchainManager->createSwapchainImageViews(handle); m_ImageManager->setSwapchainImages( swapchainImages, swapchainImageViews, - swapchain.getExtent().width, - swapchain.getExtent().height, - swapchain.getFormat() + swapchain.m_Extent.width, + swapchain.m_Extent.height, + swapchain.m_Format ); } @@ -1184,7 +1379,7 @@ namespace vkcv m_Context.getDevice(), vk::ObjectType::ePipeline, uint64_t(static_cast<VkPipeline>( - m_PipelineManager->getVkPipeline(handle) + m_GraphicsPipelineManager->getVkPipeline(handle) )), label ); @@ -1216,7 +1411,7 @@ namespace vkcv m_Context.getDevice(), vk::ObjectType::eDescriptorSet, uint64_t(static_cast<VkDescriptorSet>( - m_DescriptorManager->getDescriptorSet(handle).vulkanHandle + m_DescriptorSetManager->getDescriptorSet(handle).vulkanHandle )), label ); @@ -1273,4 +1468,79 @@ namespace vkcv label ); } + + void Core::run(const vkcv::WindowFrameFunction &frame) { + auto start = std::chrono::system_clock::now(); + double t = 0.0; + + if (!frame) + return; + + while (Window::hasOpenWindow()) { + vkcv::Window::pollEvents(); + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + start = end; + + double dt = 0.000001 * static_cast<double>(deltatime.count()); + + for (const auto &window : m_WindowManager->getWindowHandles()) { + uint32_t swapchainWidth, swapchainHeight; + if (!beginFrame(swapchainWidth, swapchainHeight, window)) { + continue; + } + + frame(window, t, dt, swapchainWidth, swapchainHeight); + endFrame(window); + } + + t += dt; + } + } + + vk::RenderPass Core::getVulkanRenderPass(const PassHandle &handle) const { + return m_PassManager->getVkPass(handle); + } + + vk::Pipeline Core::getVulkanPipeline(const GraphicsPipelineHandle &handle) const { + return m_GraphicsPipelineManager->getVkPipeline(handle); + } + + vk::Pipeline Core::getVulkanPipeline(const ComputePipelineHandle &handle) const { + return m_ComputePipelineManager->getVkPipeline(handle); + } + + vk::DescriptorSetLayout Core::getVulkanDescriptorSetLayout(const DescriptorSetLayoutHandle &handle) const { + return m_DescriptorSetLayoutManager->getDescriptorSetLayout(handle).vulkanHandle; + } + + vk::DescriptorSet Core::getVulkanDescriptorSet(const DescriptorSetHandle &handle) const { + return m_DescriptorSetManager->getDescriptorSet(handle).vulkanHandle; + } + + vk::Buffer Core::getVulkanBuffer(const BufferHandle &handle) const { + return m_BufferManager->getBuffer(handle); + } + + vk::Sampler Core::getVulkanSampler(const SamplerHandle &handle) const { + return m_SamplerManager->getVulkanSampler(handle); + } + + vk::Image Core::getVulkanImage(const ImageHandle &handle) const { + return m_ImageManager->getVulkanImage(handle); + } + + vk::ImageView Core::getVulkanImageView(const vkcv::ImageHandle &handle) const { + return m_ImageManager->getVulkanImageView(handle); + } + + vk::DeviceMemory Core::getVulkanDeviceMemory(const BufferHandle &handle) const { + return m_BufferManager->getDeviceMemory(handle); + } + + vk::DeviceMemory Core::getVulkanDeviceMemory(const ImageHandle &handle) const { + return m_ImageManager->getVulkanDeviceMemory(handle); + } + } diff --git a/src/vkcv/DescriptorConfig.cpp b/src/vkcv/DescriptorBinding.cpp similarity index 86% rename from src/vkcv/DescriptorConfig.cpp rename to src/vkcv/DescriptorBinding.cpp index 15bb05fd9cb3e5430b2a9909a682c468dfcde342..0ed0144e29942630bd3627a2eac086e82a8b3da6 100644 --- a/src/vkcv/DescriptorConfig.cpp +++ b/src/vkcv/DescriptorBinding.cpp @@ -1,7 +1,7 @@ -#include "vkcv/DescriptorConfig.hpp" +#include "vkcv/DescriptorBinding.hpp" -namespace vkcv -{ +namespace vkcv { + bool DescriptorBinding::operator==(const DescriptorBinding &other) const { return (this->bindingID == other.bindingID) && @@ -10,4 +10,5 @@ namespace vkcv (this->shaderStages == other.shaderStages) && (this->variableCount == other.variableCount); } + } diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp deleted file mode 100644 index a9cabbd4b65bd8e460bc3506338497992ded890a..0000000000000000000000000000000000000000 --- a/src/vkcv/DescriptorManager.cpp +++ /dev/null @@ -1,399 +0,0 @@ -#include "DescriptorManager.hpp" - -namespace vkcv -{ - DescriptorManager::DescriptorManager(vk::Device device) noexcept: - m_Device{ device } - { - /** - * Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type below. - * Finally, create an initial pool. - */ - m_PoolSizes = { - vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), // for RTX - vk::DescriptorPoolSize(vk::DescriptorType::eAccelerationStructureKHR, 1000) // for RTX - }; - - m_PoolInfo = vk::DescriptorPoolCreateInfo( - vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, - 1000, - static_cast<uint32_t>(m_PoolSizes.size()), - m_PoolSizes.data()); - - allocateDescriptorPool(); - } - - DescriptorManager::~DescriptorManager() noexcept - { - for (uint64_t id = 0; id < m_DescriptorSets.size(); id++) { - destroyDescriptorSetById(id); - } - - 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); - } - - m_DescriptorSets.clear(); - m_DescriptorSetLayouts.clear(); - - for (const auto &pool : m_Pools) { - if (pool) { - m_Device.destroy(pool); - } - } - } - - DescriptorSetLayoutHandle DescriptorManager::createDescriptorSetLayout(const DescriptorBindings &bindings) - { - for (size_t i = 0; i < m_DescriptorSetLayouts.size(); i++) - { - if(m_DescriptorSetLayouts[i].descriptorBindings.size() != bindings.size()) - continue; - - if (m_DescriptorSetLayouts[i].descriptorBindings == bindings) - { - m_DescriptorSetLayouts[i].layoutUsageCount++; - return DescriptorSetLayoutHandle(i, [&](uint64_t id) { destroyDescriptorSetLayoutById(id); }); - } - } - - //create the descriptor set's layout and binding flags by iterating over its bindings - std::vector<vk::DescriptorSetLayoutBinding> bindingsVector = {}; - std::vector<vk::DescriptorBindingFlags> bindingsFlags = {}; - - for (auto bindingElem : bindings) - { - DescriptorBinding binding = bindingElem.second; - uint32_t bindingID = bindingElem.first; - - bindingsVector.emplace_back( - bindingID, - getVkDescriptorType(binding.descriptorType), - binding.descriptorCount, - getShaderStageFlags(binding.shaderStages), - nullptr - ); - - vk::DescriptorBindingFlags flags; - - if (binding.variableCount) - flags |= vk::DescriptorBindingFlagBits::eVariableDescriptorCount; - - if (binding.partialBinding) - flags |= vk::DescriptorBindingFlagBits::ePartiallyBound; - - bindingsFlags.push_back(flags); - } - - vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo ( - bindingsFlags.size(), bindingsFlags.data() - ); - - //create the descriptor set's layout from the binding data gathered above - vk::DescriptorSetLayout vulkanHandle; - vk::DescriptorSetLayoutCreateInfo layoutInfo(vk::DescriptorSetLayoutCreateFlags(), bindingsVector); - layoutInfo.setPNext(&bindingFlagsInfo); - - auto result = m_Device.createDescriptorSetLayout(&layoutInfo, nullptr, &vulkanHandle); - if (result != vk::Result::eSuccess) { - vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout"); - return DescriptorSetLayoutHandle(); - }; - - const uint64_t id = m_DescriptorSetLayouts.size(); - m_DescriptorSetLayouts.push_back({vulkanHandle, bindings, 1}); - return DescriptorSetLayoutHandle(id, [&](uint64_t id) { destroyDescriptorSetLayoutById(id); }); - } - - DescriptorSetHandle DescriptorManager::createDescriptorSet(const DescriptorSetLayoutHandle &layout) - { - //create and allocate the set based on the layout provided - DescriptorSetLayout setLayout = m_DescriptorSetLayouts[layout.getId()]; - vk::DescriptorSet vulkanHandle; - vk::DescriptorSetAllocateInfo allocInfo(m_Pools.back(), 1, &setLayout.vulkanHandle); - - uint32_t sumVariableDescriptorCounts = 0; - for (auto bindingElem : setLayout.descriptorBindings) - { - auto binding = bindingElem.second; - if(binding.variableCount) - sumVariableDescriptorCounts += binding.descriptorCount; - } - - vk::DescriptorSetVariableDescriptorCountAllocateInfo variableAllocInfo(1, &sumVariableDescriptorCounts); - - if (sumVariableDescriptorCounts > 0) { - allocInfo.setPNext(&variableAllocInfo); - } - - auto result = m_Device.allocateDescriptorSets(&allocInfo, &vulkanHandle); - if(result != vk::Result::eSuccess) - { - //create a new descriptor pool if the previous one ran out of memory - if (result == vk::Result::eErrorOutOfPoolMemory) { - allocateDescriptorPool(); - allocInfo.setDescriptorPool(m_Pools.back()); - result = m_Device.allocateDescriptorSets(&allocInfo, &vulkanHandle); - } - - if (result != vk::Result::eSuccess) { - vkcv_log(LogLevel::ERROR, "Failed to create descriptor set (%s)", - vk::to_string(result).c_str()); - return DescriptorSetHandle(); - } - }; - - size_t poolIndex = (m_Pools.size() - 1); - const uint64_t id = m_DescriptorSets.size(); - 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; - uint32_t binding; - uint32_t arrayElementIndex; - uint32_t descriptorCount; - vk::DescriptorType type; - }; - - void DescriptorManager::writeDescriptorSet( - const DescriptorSetHandle &handle, - const DescriptorWrites &writes, - const ImageManager &imageManager, - const BufferManager &bufferManager, - const SamplerManager &samplerManager) { - vk::DescriptorSet set = m_DescriptorSets[handle.getId()].vulkanHandle; - - std::vector<vk::DescriptorImageInfo> imageInfos; - std::vector<vk::DescriptorBufferInfo> bufferInfos; - - std::vector<WriteDescriptorSetInfo> writeInfos; - - for (const auto& write : writes.getSampledImageWrites()) - { - const vk::ImageLayout layout = (write.useGeneralLayout? - vk::ImageLayout::eGeneral : - vk::ImageLayout::eShaderReadOnlyOptimal - ); - - for (uint32_t i = 0; i < write.mipCount; i++) { - const vk::DescriptorImageInfo imageInfo( - nullptr, - imageManager.getVulkanImageView( - write.image, - write.mipLevel + i, - write.arrayView - ), - layout - ); - - imageInfos.push_back(imageInfo); - } - - WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size() + 1 - write.mipCount, - 0, - write.binding, - write.arrayIndex, - write.mipCount, - vk::DescriptorType::eSampledImage, - }; - - writeInfos.push_back(vulkanWrite); - } - - for (const auto& write : writes.getStorageImageWrites()) { - for (uint32_t i = 0; i < write.mipCount; i++) { - const vk::DescriptorImageInfo imageInfo( - nullptr, - imageManager.getVulkanImageView( - write.image, - write.mipLevel + i, - write.arrayView - ), - vk::ImageLayout::eGeneral - ); - - imageInfos.push_back(imageInfo); - } - - WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size() + 1 - write.mipCount, - 0, - write.binding, - 0, - write.mipCount, - vk::DescriptorType::eStorageImage - }; - - writeInfos.push_back(vulkanWrite); - } - - 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); - - const vk::DescriptorBufferInfo bufferInfo( - bufferManager.getBuffer(write.buffer), - offset, - write.size == 0? size : std::min<uint32_t>( - write.size, size - offset - ) - ); - - bufferInfos.push_back(bufferInfo); - - WriteDescriptorSetInfo vulkanWrite = { - 0, - bufferInfos.size(), - write.binding, - 0, - 1, - write.dynamic? - vk::DescriptorType::eUniformBufferDynamic : - vk::DescriptorType::eUniformBuffer - }; - - writeInfos.push_back(vulkanWrite); - } - - 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); - - const vk::DescriptorBufferInfo bufferInfo( - bufferManager.getBuffer(write.buffer), - offset, - write.size == 0? size : std::min<uint32_t>( - write.size, size - offset - ) - ); - - bufferInfos.push_back(bufferInfo); - - WriteDescriptorSetInfo vulkanWrite = { - 0, - bufferInfos.size(), - write.binding, - 0, - 1, - write.dynamic? - vk::DescriptorType::eStorageBufferDynamic : - vk::DescriptorType::eStorageBuffer - }; - - writeInfos.push_back(vulkanWrite); - } - - for (const auto& write : writes.getSamplerWrites()) { - const vk::Sampler& sampler = samplerManager.getVulkanSampler(write.sampler); - - const vk::DescriptorImageInfo imageInfo( - sampler, - nullptr, - vk::ImageLayout::eGeneral - ); - - imageInfos.push_back(imageInfo); - - WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size(), - 0, - write.binding, - 0, - 1, - vk::DescriptorType::eSampler - }; - - writeInfos.push_back(vulkanWrite); - } - - std::vector<vk::WriteDescriptorSet> vulkanWrites; - - for (const auto& write : writeInfos) { - vk::WriteDescriptorSet vulkanWrite( - set, - write.binding, - write.arrayElementIndex, - write.descriptorCount, - write.type, - (write.imageInfoIndex > 0? &(imageInfos[write.imageInfoIndex - 1]) : nullptr), - (write.bufferInfoIndex > 0? &(bufferInfos[write.bufferInfoIndex - 1]) : nullptr) - ); - - vulkanWrites.push_back(vulkanWrite); - } - - m_Device.updateDescriptorSets(vulkanWrites, nullptr); - } - - DescriptorSetLayout DescriptorManager::getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const - { - return m_DescriptorSetLayouts[handle.getId()]; - } - - DescriptorSet DescriptorManager::getDescriptorSet(const DescriptorSetHandle handle) const { - return m_DescriptorSets[handle.getId()]; - } - - void DescriptorManager::destroyDescriptorSetById(uint64_t id) { - if (id >= m_DescriptorSets.size()) { - vkcv_log(LogLevel::ERROR, "Invalid id"); - return; - } - - auto& set = m_DescriptorSets[id]; - - if (set.vulkanHandle) { - m_Device.freeDescriptorSets(m_Pools[set.poolIndex], 1, &(set.vulkanHandle)); - set.setLayoutHandle = DescriptorSetLayoutHandle(); - set.vulkanHandle = nullptr; - } - } - - void DescriptorManager::destroyDescriptorSetLayoutById(uint64_t id) { - if (id >= m_DescriptorSetLayouts.size()) { - vkcv_log(LogLevel::ERROR, "Invalid id"); - return; - } - - auto& layout = m_DescriptorSetLayouts[id]; - - if (layout.layoutUsageCount > 1) { - layout.layoutUsageCount--; - return; - } else { - layout.layoutUsageCount = 0; - } - - if (layout.vulkanHandle){ - m_Device.destroy(layout.vulkanHandle); - layout.vulkanHandle = nullptr; - } - } - - vk::DescriptorPool DescriptorManager::allocateDescriptorPool() { - vk::DescriptorPool pool; - if (m_Device.createDescriptorPool(&m_PoolInfo, nullptr, &pool) != vk::Result::eSuccess) { - vkcv_log(LogLevel::WARNING, "Failed to allocate descriptor pool"); - pool = nullptr; - } else { - m_Pools.push_back(pool); - } - - return pool; - } - -} diff --git a/src/vkcv/DescriptorManager.hpp b/src/vkcv/DescriptorManager.hpp deleted file mode 100644 index c996e8c94f6dbb6f45f173f60f59f344a9a58623..0000000000000000000000000000000000000000 --- a/src/vkcv/DescriptorManager.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -/** - * @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 - */ -#include <vulkan/vulkan.hpp> - -#include "vkcv/Handles.hpp" -#include "vkcv/DescriptorConfig.hpp" -#include "vkcv/DescriptorWrites.hpp" - -#include "ImageManager.hpp" -#include "vkcv/BufferManager.hpp" -#include "SamplerManager.hpp" - -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; - - /** - * @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); - - /** - * @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; - - private: - vk::Device m_Device; - std::vector<vk::DescriptorPool> m_Pools; - std::vector<vk::DescriptorPoolSize> m_PoolSizes; - vk::DescriptorPoolCreateInfo m_PoolInfo; - - /** - * 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. - */ - std::vector<DescriptorSet> m_DescriptorSets; - - /** - * @brief Destroys a specific descriptor set. - * - * @param[in] the DescriptorSetHandle - */ - void destroyDescriptorSetById(uint64_t id); - - /** - * @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); - - /** - * @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/DescriptorSetLayoutManager.cpp b/src/vkcv/DescriptorSetLayoutManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3122964036e793f1f49f23fd56253e7fc3c9464 --- /dev/null +++ b/src/vkcv/DescriptorSetLayoutManager.cpp @@ -0,0 +1,109 @@ +#include "DescriptorSetLayoutManager.hpp" + +#include "vkcv/Core.hpp" + +namespace vkcv { + + uint64_t DescriptorSetLayoutManager::getIdFrom(const DescriptorSetLayoutHandle &handle) const { + return handle.getId(); + } + + DescriptorSetLayoutHandle DescriptorSetLayoutManager::createById(uint64_t id, + const HandleDestroyFunction &destroy) { + return DescriptorSetLayoutHandle(id, destroy); + } + + void DescriptorSetLayoutManager::destroyById(uint64_t id) { + auto& layout = getById(id); + + if (layout.layoutUsageCount > 1) { + layout.layoutUsageCount--; + return; + } else { + layout.layoutUsageCount = 0; + } + + if (layout.vulkanHandle){ + getCore().getContext().getDevice().destroy(layout.vulkanHandle); + layout.vulkanHandle = nullptr; + } + } + + DescriptorSetLayoutManager::DescriptorSetLayoutManager() noexcept : + HandleManager<DescriptorSetLayoutEntry, DescriptorSetLayoutHandle>() {} + + DescriptorSetLayoutManager::~DescriptorSetLayoutManager() noexcept { + for (uint64_t id = 0; id < getCount(); id++) { + // Resets the usage count to zero for destruction. + getById(id).layoutUsageCount = 0; + } + + clear(); + } + + DescriptorSetLayoutHandle DescriptorSetLayoutManager::createDescriptorSetLayout(const DescriptorBindings &bindings) { + for (uint64_t id = 0; id < getCount(); id++) { + auto& layout = getById(id); + + if (layout.descriptorBindings.size() != bindings.size()) + continue; + + if (layout.descriptorBindings == bindings) { + layout.layoutUsageCount++; + return createById(id, [&](uint64_t id) { destroyById(id); }); + } + } + + //create the descriptor set's layout and binding flags by iterating over its bindings + std::vector<vk::DescriptorSetLayoutBinding> bindingsVector = {}; + std::vector<vk::DescriptorBindingFlags> bindingsFlags = {}; + + for (auto bindingElem : bindings) + { + DescriptorBinding binding = bindingElem.second; + uint32_t bindingID = bindingElem.first; + + bindingsVector.emplace_back( + bindingID, + getVkDescriptorType(binding.descriptorType), + binding.descriptorCount, + getShaderStageFlags(binding.shaderStages), + nullptr + ); + + vk::DescriptorBindingFlags flags; + + if (binding.variableCount) + flags |= vk::DescriptorBindingFlagBits::eVariableDescriptorCount; + + if (binding.partialBinding) + flags |= vk::DescriptorBindingFlagBits::ePartiallyBound; + + bindingsFlags.push_back(flags); + } + + vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo ( + bindingsFlags.size(), bindingsFlags.data() + ); + + //create the descriptor set's layout from the binding data gathered above + vk::DescriptorSetLayout vulkanHandle; + vk::DescriptorSetLayoutCreateInfo layoutInfo(vk::DescriptorSetLayoutCreateFlags(), bindingsVector); + layoutInfo.setPNext(&bindingFlagsInfo); + + auto result = getCore().getContext().getDevice().createDescriptorSetLayout(&layoutInfo, + nullptr, + &vulkanHandle); + if (result != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout"); + return DescriptorSetLayoutHandle(); + }; + + return add({ vulkanHandle, bindings, 1 }); + } + + const DescriptorSetLayoutEntry& DescriptorSetLayoutManager::getDescriptorSetLayout(const DescriptorSetLayoutHandle& handle) const { + return (*this)[handle]; + } + +} diff --git a/src/vkcv/DescriptorSetLayoutManager.hpp b/src/vkcv/DescriptorSetLayoutManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0dd2598c70fdeb6aeb3e9da1adc48b1a480e71c5 --- /dev/null +++ b/src/vkcv/DescriptorSetLayoutManager.hpp @@ -0,0 +1,70 @@ +#pragma once +/** + * @authors Artur Wasmut, Susanne D�tsch, Simeon Hermann, Tobias Frisch + * @file src/vkcv/DescriptorManager.cpp + * @brief Creation and handling of descriptor set layouts. + */ +#include <vulkan/vulkan.hpp> + +#include "vkcv/DescriptorBinding.hpp" + +#include "HandleManager.hpp" + +namespace vkcv { + + /** + * @brief Structure to store details about a descriptor set layout. + */ + struct DescriptorSetLayoutEntry { + vk::DescriptorSetLayout vulkanHandle; + DescriptorBindings descriptorBindings; + size_t layoutUsageCount; + }; + + /** + * @brief Class to manage descriptor set layouts. + */ + class DescriptorSetLayoutManager : public HandleManager<DescriptorSetLayoutEntry, DescriptorSetLayoutHandle> { + friend class Core; + private: + [[nodiscard]] + uint64_t getIdFrom(const DescriptorSetLayoutHandle& handle) const override; + + [[nodiscard]] + DescriptorSetLayoutHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates descriptor set layout represented by a given + * descriptor set layout handle id. + * + * @param id Descriptor set layout handle id + */ + void destroyById(uint64_t id) override; + + public: + /** + * @brief Constructor of the descriptor set layout manager + */ + DescriptorSetLayoutManager() noexcept; + + /** + * @brief Destructor of the descriptor set layout manager + */ + ~DescriptorSetLayoutManager() noexcept override; + + /** + * @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 + */ + [[nodiscard]] + DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); + + [[nodiscard]] + const DescriptorSetLayoutEntry& getDescriptorSetLayout(const DescriptorSetLayoutHandle& handle) const; + + }; + +} diff --git a/src/vkcv/DescriptorSetManager.cpp b/src/vkcv/DescriptorSetManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7d680d9a3d72d694bd1cafa83c7c4f92bf2825f --- /dev/null +++ b/src/vkcv/DescriptorSetManager.cpp @@ -0,0 +1,347 @@ +#include "DescriptorSetManager.hpp" + +#include "vkcv/Core.hpp" + +namespace vkcv { + + bool DescriptorSetManager::init(Core &core, DescriptorSetLayoutManager& descriptorSetLayoutManager) { + if (!HandleManager<DescriptorSetEntry, DescriptorSetHandle>::init(core)) { + return false; + } + + m_DescriptorSetLayoutManager = &descriptorSetLayoutManager; + + /** + * Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type below. + * Finally, create an initial pool. + */ + m_PoolSizes = { + vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), // for RTX + vk::DescriptorPoolSize(vk::DescriptorType::eAccelerationStructureKHR, 1000) // for RTX + }; + + m_PoolInfo = vk::DescriptorPoolCreateInfo( + vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, + 1000, + static_cast<uint32_t>(m_PoolSizes.size()), + m_PoolSizes.data() + ); + + return allocateDescriptorPool(); + } + + uint64_t DescriptorSetManager::getIdFrom(const DescriptorSetHandle &handle) const { + return handle.getId(); + } + + DescriptorSetHandle DescriptorSetManager::createById(uint64_t id, + const HandleDestroyFunction &destroy) { + return DescriptorSetHandle(id, destroy); + } + + void DescriptorSetManager::destroyById(uint64_t id) { + auto& set = getById(id); + + if (set.vulkanHandle) { + getCore().getContext().getDevice().freeDescriptorSets(m_Pools[set.poolIndex], 1, + &(set.vulkanHandle)); + set.setLayoutHandle = DescriptorSetLayoutHandle(); + set.vulkanHandle = nullptr; + } + } + + vk::DescriptorPool DescriptorSetManager::allocateDescriptorPool() { + vk::DescriptorPool pool; + if (getCore().getContext().getDevice().createDescriptorPool(&m_PoolInfo, + nullptr, + &pool) != vk::Result::eSuccess) { + vkcv_log(LogLevel::WARNING, "Failed to allocate descriptor pool"); + pool = nullptr; + } else { + m_Pools.push_back(pool); + } + + return pool; + } + + DescriptorSetManager::DescriptorSetManager() noexcept : + HandleManager<DescriptorSetEntry, DescriptorSetHandle>() { + + } + + DescriptorSetManager::~DescriptorSetManager() noexcept { + clear(); + + for (const auto &pool : m_Pools) { + if (pool) { + getCore().getContext().getDevice().destroy(pool); + } + } + } + + DescriptorSetHandle DescriptorSetManager::createDescriptorSet(const DescriptorSetLayoutHandle &layout) { + //create and allocate the set based on the layout provided + const auto& setLayout = m_DescriptorSetLayoutManager->getDescriptorSetLayout(layout); + + vk::DescriptorSet vulkanHandle; + vk::DescriptorSetAllocateInfo allocInfo(m_Pools.back(), 1, &setLayout.vulkanHandle); + + uint32_t sumVariableDescriptorCounts = 0; + for (auto bindingElem : setLayout.descriptorBindings) { + auto binding = bindingElem.second; + + if(binding.variableCount) + sumVariableDescriptorCounts += binding.descriptorCount; + } + + vk::DescriptorSetVariableDescriptorCountAllocateInfo variableAllocInfo(1, &sumVariableDescriptorCounts); + + if (sumVariableDescriptorCounts > 0) { + allocInfo.setPNext(&variableAllocInfo); + } + + auto result = getCore().getContext().getDevice().allocateDescriptorSets(&allocInfo, &vulkanHandle); + if(result != vk::Result::eSuccess) + { + //create a new descriptor pool if the previous one ran out of memory + if (result == vk::Result::eErrorOutOfPoolMemory) { + allocateDescriptorPool(); + allocInfo.setDescriptorPool(m_Pools.back()); + result = getCore().getContext().getDevice().allocateDescriptorSets(&allocInfo, &vulkanHandle); + } + + if (result != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "Failed to create descriptor set (%s)", + vk::to_string(result).c_str()); + return {}; + } + }; + + size_t poolIndex = (m_Pools.size() - 1); + return add({ vulkanHandle, layout, poolIndex }); + } + + /** + * @brief Structure to store details to write to a descriptor set. + */ + struct WriteDescriptorSetInfo { + size_t imageInfoIndex; + size_t bufferInfoIndex; + size_t structureIndex; + uint32_t binding; + uint32_t arrayElementIndex; + uint32_t descriptorCount; + vk::DescriptorType type; + }; + + void DescriptorSetManager::writeDescriptorSet(const DescriptorSetHandle &handle, + const DescriptorWrites &writes, + const ImageManager &imageManager, + const BufferManager &bufferManager, + const SamplerManager &samplerManager) { + auto& set = (*this)[handle]; + + std::vector<vk::DescriptorImageInfo> imageInfos; + std::vector<vk::DescriptorBufferInfo> bufferInfos; + + std::vector<vk::WriteDescriptorSetAccelerationStructureKHR> writeStructures; + + std::vector<WriteDescriptorSetInfo> writeInfos; + + for (const auto& write : writes.getSampledImageWrites()) { + const vk::ImageLayout layout = (write.useGeneralLayout? + vk::ImageLayout::eGeneral : + vk::ImageLayout::eShaderReadOnlyOptimal + ); + + for (uint32_t i = 0; i < write.mipCount; i++) { + const vk::DescriptorImageInfo imageInfo( + nullptr, + imageManager.getVulkanImageView( + write.image, + write.mipLevel + i, + write.arrayView + ), + layout + ); + + imageInfos.push_back(imageInfo); + } + + WriteDescriptorSetInfo vulkanWrite = { + imageInfos.size() + 1 - write.mipCount, + 0, + 0, + write.binding, + write.arrayIndex, + write.mipCount, + vk::DescriptorType::eSampledImage, + }; + + writeInfos.push_back(vulkanWrite); + } + + for (const auto& write : writes.getStorageImageWrites()) { + for (uint32_t i = 0; i < write.mipCount; i++) { + const vk::DescriptorImageInfo imageInfo( + nullptr, + imageManager.getVulkanImageView( + write.image, + write.mipLevel + i, + write.arrayView + ), + vk::ImageLayout::eGeneral + ); + + imageInfos.push_back(imageInfo); + } + + WriteDescriptorSetInfo vulkanWrite = { + imageInfos.size() + 1 - write.mipCount, + 0, + 0, + write.binding, + 0, + write.mipCount, + vk::DescriptorType::eStorageImage + }; + + writeInfos.push_back(vulkanWrite); + } + + 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); + + const vk::DescriptorBufferInfo bufferInfo( + bufferManager.getBuffer(write.buffer), + offset, + write.size == 0? size : std::min<uint32_t>( + write.size, size - offset + ) + ); + + bufferInfos.push_back(bufferInfo); + + WriteDescriptorSetInfo vulkanWrite = { + 0, + bufferInfos.size(), + 0, + write.binding, + 0, + 1, + write.dynamic? + vk::DescriptorType::eUniformBufferDynamic : + vk::DescriptorType::eUniformBuffer + }; + + writeInfos.push_back(vulkanWrite); + } + + 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); + + const vk::DescriptorBufferInfo bufferInfo( + bufferManager.getBuffer(write.buffer), + offset, + write.size == 0? size : std::min<uint32_t>( + write.size, size - offset + ) + ); + + bufferInfos.push_back(bufferInfo); + + WriteDescriptorSetInfo vulkanWrite = { + 0, + bufferInfos.size(), + 0, + write.binding, + 0, + 1, + write.dynamic? + vk::DescriptorType::eStorageBufferDynamic : + vk::DescriptorType::eStorageBuffer + }; + + writeInfos.push_back(vulkanWrite); + } + + for (const auto& write : writes.getSamplerWrites()) { + const vk::Sampler& sampler = samplerManager.getVulkanSampler(write.sampler); + + const vk::DescriptorImageInfo imageInfo( + sampler, + nullptr, + vk::ImageLayout::eGeneral + ); + + imageInfos.push_back(imageInfo); + + WriteDescriptorSetInfo vulkanWrite = { + imageInfos.size(), + 0, + 0, + write.binding, + 0, + 1, + vk::DescriptorType::eSampler + }; + + writeInfos.push_back(vulkanWrite); + } + + for (const auto& write : writes.getAccelerationWrites()) { + const vk::WriteDescriptorSetAccelerationStructureKHR structureWrite ( + write.structures.size(), + write.structures.data() + ); + + writeStructures.push_back(structureWrite); + + WriteDescriptorSetInfo vulkanWrite = { + 0, + 0, + writeStructures.size(), + write.binding, + 0, + 1, + vk::DescriptorType::eAccelerationStructureKHR + }; + + writeInfos.push_back(vulkanWrite); + } + + std::vector<vk::WriteDescriptorSet> vulkanWrites; + + for (const auto& write : writeInfos) { + vk::WriteDescriptorSet vulkanWrite ( + set.vulkanHandle, + write.binding, + write.arrayElementIndex, + write.descriptorCount, + write.type, + (write.imageInfoIndex > 0? &(imageInfos[write.imageInfoIndex - 1]) : nullptr), + (write.bufferInfoIndex > 0? &(bufferInfos[write.bufferInfoIndex - 1]) : nullptr) + ); + + if (write.structureIndex > 0) { + vulkanWrite.setPNext(&(writeStructures[write.structureIndex - 1])); + } + + vulkanWrites.push_back(vulkanWrite); + } + + getCore().getContext().getDevice().updateDescriptorSets(vulkanWrites, nullptr); + } + + const DescriptorSetEntry& DescriptorSetManager::getDescriptorSet(const DescriptorSetHandle& handle) const { + return (*this)[handle]; + } + +} diff --git a/src/vkcv/DescriptorSetManager.hpp b/src/vkcv/DescriptorSetManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f3c13aff26832888b2f43e33a03feb1ace77fb93 --- /dev/null +++ b/src/vkcv/DescriptorSetManager.hpp @@ -0,0 +1,106 @@ +#pragma once +/** + * @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. + */ +#include <vulkan/vulkan.hpp> + +#include "vkcv/DescriptorBinding.hpp" +#include "vkcv/DescriptorWrites.hpp" + +#include "HandleManager.hpp" +#include "BufferManager.hpp" +#include "DescriptorSetLayoutManager.hpp" +#include "ImageManager.hpp" +#include "SamplerManager.hpp" + +namespace vkcv { + + /** + * @brief Structure to store details about a descriptor set. + */ + struct DescriptorSetEntry { + vk::DescriptorSet vulkanHandle; + DescriptorSetLayoutHandle setLayoutHandle; + size_t poolIndex; + }; + + /** + * @brief Class to manage descriptor sets. + */ + class DescriptorSetManager : public HandleManager<DescriptorSetEntry, DescriptorSetHandle> { + friend class Core; + private: + DescriptorSetLayoutManager* m_DescriptorSetLayoutManager; + + std::vector<vk::DescriptorPool> m_Pools; + std::vector<vk::DescriptorPoolSize> m_PoolSizes; + vk::DescriptorPoolCreateInfo m_PoolInfo; + + bool init(Core& core, DescriptorSetLayoutManager& descriptorSetLayoutManager); + + [[nodiscard]] + uint64_t getIdFrom(const DescriptorSetHandle& handle) const override; + + [[nodiscard]] + DescriptorSetHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates descriptor set represented by a given + * descriptor set handle id. + * + * @param id Descriptor set handle id + */ + void destroyById(uint64_t id) override; + + /** + * @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(); + + public: + /** + * @brief Constructor of the descriptor set manager + */ + DescriptorSetManager() noexcept; + + /** + * @brief Destructor of the descriptor set manager + */ + ~DescriptorSetManager() noexcept override; + + /** + * @brief Creates a descriptor set using a given descriptor set layout. + * + * @param[in] layout Handle of descriptor set layout + * @return Handle of descriptor set + */ + [[nodiscard]] + DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layout); + + /** + * @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]] + const DescriptorSetEntry& getDescriptorSet(const DescriptorSetHandle& handle) const; + + }; + +} diff --git a/src/vkcv/DescriptorSetUsage.cpp b/src/vkcv/DescriptorSetUsage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d1ab2ec752dde1047fd736fd6e300bdb586b238 --- /dev/null +++ b/src/vkcv/DescriptorSetUsage.cpp @@ -0,0 +1,12 @@ + +#include "vkcv/DescriptorSetUsage.hpp" + +namespace vkcv { + + DescriptorSetUsage useDescriptorSet(uint32_t location, const DescriptorSetHandle &descriptorSet, + const std::vector<uint32_t> &dynamicOffsets) { + DescriptorSetUsage usage (location, descriptorSet, dynamicOffsets); + return usage; + } + +} diff --git a/src/vkcv/DescriptorWrites.cpp b/src/vkcv/DescriptorWrites.cpp index c64eeb5c4037018e949436d984c112d10e44a434..4f9c50ea1ac4628659b18decab6573b73fbdcb38 100644 --- a/src/vkcv/DescriptorWrites.cpp +++ b/src/vkcv/DescriptorWrites.cpp @@ -63,8 +63,9 @@ namespace vkcv { return *this; } - DescriptorWrites &DescriptorWrites::writeAcceleration(uint32_t binding) { - m_accelerationWrites.emplace_back(binding); + DescriptorWrites &DescriptorWrites::writeAcceleration(uint32_t binding, + const std::vector<vk::AccelerationStructureKHR> &structures) { + m_accelerationWrites.emplace_back(binding, structures); return *this; } diff --git a/src/vkcv/DispatchSize.cpp b/src/vkcv/DispatchSize.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf34d2de9668fb90a61208cce9f10abe57a64682 --- /dev/null +++ b/src/vkcv/DispatchSize.cpp @@ -0,0 +1,65 @@ + +#include "vkcv/DispatchSize.hpp" +#include "vkcv/Logger.hpp" + +#include <cmath> + +namespace vkcv { + + DispatchSize::DispatchSize(uint32_t count) + : DispatchSize(count, 1, 1) {} + + DispatchSize::DispatchSize(uint32_t dimensionX, uint32_t dimentionY, uint32_t dimensionZ) + : m_Dispatch({ dimensionX, dimentionY, dimensionZ }) { + check(); + } + + const uint32_t *DispatchSize::data() const { + return m_Dispatch.data(); + } + + uint32_t DispatchSize::operator[](size_t index) const { + return m_Dispatch.at(index); + } + + uint32_t DispatchSize::x() const { + return m_Dispatch[0]; + } + + uint32_t DispatchSize::y() const { + return m_Dispatch[1]; + } + + uint32_t DispatchSize::z() const { + return m_Dispatch[2]; + } + + bool DispatchSize::check() const { + const uint32_t dimensionX = x(); + const uint32_t dimensionY = y(); + const uint32_t dimensionZ = z(); + + if ((dimensionX <= 0) || (dimensionY <= 0) || (dimensionZ <= 0)) { + vkcv_log( + LogLevel::WARNING, + "Dispatch size invalid: x = %u, y = %u, z = %u", + dimensionX, + dimensionY, + dimensionZ + ); + + return false; + } else { + return true; + } + } + + DispatchSize dispatchInvocations(DispatchSize globalInvocations, DispatchSize groupSize) { + const uint32_t dimensionX = std::ceil(1.0f * globalInvocations.x() / groupSize.x()); + const uint32_t dimensionY = std::ceil(1.0f * globalInvocations.y() / groupSize.y()); + const uint32_t dimensionZ = std::ceil(1.0f * globalInvocations.z() / groupSize.z()); + + return DispatchSize(dimensionX, dimensionY, dimensionZ); + } + +} diff --git a/src/vkcv/Drawcall.cpp b/src/vkcv/Drawcall.cpp new file mode 100644 index 0000000000000000000000000000000000000000..657481eb4648602e81f554292abaeec4a70c509d --- /dev/null +++ b/src/vkcv/Drawcall.cpp @@ -0,0 +1,60 @@ +/** + * @authors Tobias Frisch + * @file src/vkcv/Drawcall.cpp + */ + +#include "vkcv/Drawcall.hpp" + +namespace vkcv { + + const std::vector<DescriptorSetUsage> &Drawcall::getDescriptorSetUsages() const { + return m_usages; + } + + void Drawcall::useDescriptorSet(uint32_t location, const DescriptorSetHandle &descriptorSet, + const std::vector<uint32_t>& dynamicOffsets) { + m_usages.emplace_back(location, descriptorSet, dynamicOffsets); + } + + InstanceDrawcall::InstanceDrawcall(const VertexData &vertexData, + uint32_t instanceCount) + : Drawcall(), + m_vertexData(vertexData), + m_instanceCount(instanceCount) {} + + const VertexData &InstanceDrawcall::getVertexData() const { + return m_vertexData; + } + + uint32_t InstanceDrawcall::getInstanceCount() const { + return m_instanceCount; + } + + IndirectDrawcall::IndirectDrawcall(const BufferHandle &indirectDrawBuffer, + const VertexData &vertexData, + uint32_t drawCount) + : Drawcall(), + m_indirectDrawBuffer(indirectDrawBuffer), + m_vertexData(vertexData), + m_drawCount(drawCount) {} + + BufferHandle IndirectDrawcall::getIndirectDrawBuffer() const { + return m_indirectDrawBuffer; + } + + const VertexData &IndirectDrawcall::getVertexData() const { + return m_vertexData; + } + + uint32_t IndirectDrawcall::getDrawCount() const { + return m_drawCount; + } + + TaskDrawcall::TaskDrawcall(uint32_t taskCount) + : Drawcall(), m_taskCount(taskCount) {} + + uint32_t TaskDrawcall::getTaskCount() const { + return m_taskCount; + } + +} diff --git a/src/vkcv/DrawcallRecording.cpp b/src/vkcv/DrawcallRecording.cpp deleted file mode 100644 index eef87ca65d5f461f1c37b678634cf3e6f8973397..0000000000000000000000000000000000000000 --- a/src/vkcv/DrawcallRecording.cpp +++ /dev/null @@ -1,47 +0,0 @@ - -#include "vkcv/DrawcallRecording.hpp" -#include "vkcv/Logger.hpp" -#include "vkcv/Core.hpp" - -namespace vkcv { - - 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( - vk::PipelineBindPoint::eGraphics, - pipelineLayout, - descriptorUsage.setLocation, - core.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle, - nullptr); - } - - // char* cast because void* does not support pointer arithmetic - const void* drawcallPushConstantData = pushConstantOffset + (char*)pushConstantData.getData(); - - if (pushConstantData.getData()) { - cmdBuffer.pushConstants( - pipelineLayout, - vk::ShaderStageFlagBits::eAll, - 0, - pushConstantData.getSizePerDrawcall(), - drawcallPushConstantData); - } - - cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.taskCount, firstTask); - } -} diff --git a/src/vkcv/FeatureManager.cpp b/src/vkcv/FeatureManager.cpp index bfceeb6300ece6dd3387d0785d8611a7289aa82c..502b07971bf0e20a3f02d94506a55ab0dcfcd5cf 100644 --- a/src/vkcv/FeatureManager.cpp +++ b/src/vkcv/FeatureManager.cpp @@ -431,6 +431,28 @@ m_physicalDevice.getFeatures2(&query) return true; } + bool FeatureManager::checkSupport(const vk::PhysicalDeviceVulkan13Features &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceVulkan13Features); + + vkcv_check_feature(robustImageAccess); + vkcv_check_feature(inlineUniformBlock); + vkcv_check_feature(descriptorBindingInlineUniformBlockUpdateAfterBind); + vkcv_check_feature(pipelineCreationCacheControl); + vkcv_check_feature(privateData); + vkcv_check_feature(shaderDemoteToHelperInvocation); + vkcv_check_feature(shaderTerminateInvocation); + vkcv_check_feature(subgroupSizeControl); + vkcv_check_feature(computeFullSubgroups); + vkcv_check_feature(synchronization2); + vkcv_check_feature(textureCompressionASTC_HDR); + vkcv_check_feature(shaderZeroInitializeWorkgroupMemory); + vkcv_check_feature(dynamicRendering); + vkcv_check_feature(shaderIntegerDotProduct); + vkcv_check_feature(maintenance4); + + return true; + } + vk::BaseOutStructure* FeatureManager::findFeatureStructure(vk::StructureType type) const { for (auto& base : m_featuresExtensions) { if (base->sType == type) { @@ -535,7 +557,7 @@ m_physicalDevice.getFeatures2(&query) delete[] clone; if (required) { - throw std::runtime_error("Required extension is not supported!"); + vkcv_log_throw_error("Required extension is not supported!"); } return false; diff --git a/src/vkcv/GraphicsPipelineConfig.cpp b/src/vkcv/GraphicsPipelineConfig.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37e86240e782460fe317c91e71c1ddcb5880fff0 --- /dev/null +++ b/src/vkcv/GraphicsPipelineConfig.cpp @@ -0,0 +1,121 @@ + +#include "vkcv/GraphicsPipelineConfig.hpp" + +namespace vkcv { + + GraphicsPipelineConfig::GraphicsPipelineConfig() + : PipelineConfig(), + m_PassHandle(), + m_VertexLayout(), + m_Width(std::numeric_limits<uint32_t>::max()), + m_Height(std::numeric_limits<uint32_t>::max()) {} + + GraphicsPipelineConfig::GraphicsPipelineConfig(const ShaderProgram &program, + const PassHandle &pass, + const VertexLayout &vertexLayout, + const std::vector<DescriptorSetLayoutHandle> &layouts) + : PipelineConfig(program, layouts), + m_PassHandle(pass), + m_VertexLayout(vertexLayout), + m_Width(std::numeric_limits<uint32_t>::max()), + m_Height(std::numeric_limits<uint32_t>::max()) {} + + const PassHandle &GraphicsPipelineConfig::getPass() const { + return m_PassHandle; + } + + const VertexLayout &GraphicsPipelineConfig::getVertexLayout() const { + return m_VertexLayout; + } + + uint32_t GraphicsPipelineConfig::getWidth() const { + return m_Width; + } + + uint32_t GraphicsPipelineConfig::getHeight() const { + return m_Height; + } + + void GraphicsPipelineConfig::setResolution(uint32_t width, uint32_t height) { + m_Width = width; + m_Height = height; + } + + bool GraphicsPipelineConfig::isViewportDynamic() const { + return ((m_Width == std::numeric_limits<uint32_t>::max()) && + (m_Height == std::numeric_limits<uint32_t>::max())); + } + + bool GraphicsPipelineConfig::isUsingConservativeRasterization() const { + return m_UseConservativeRasterization; + } + + void GraphicsPipelineConfig::setUsingConservativeRasterization(bool conservativeRasterization) { + m_UseConservativeRasterization = conservativeRasterization; + } + + PrimitiveTopology GraphicsPipelineConfig::getPrimitiveTopology() const { + return m_PrimitiveTopology; + } + + void GraphicsPipelineConfig::setPrimitiveTopology(PrimitiveTopology primitiveTopology) { + m_PrimitiveTopology = primitiveTopology; + } + + BlendMode GraphicsPipelineConfig::getBlendMode() const { + return m_blendMode; + } + + void GraphicsPipelineConfig::setBlendMode(BlendMode blendMode) { + m_blendMode = blendMode; + } + + bool GraphicsPipelineConfig::isDepthClampingEnabled() const { + return m_EnableDepthClamping; + } + + void GraphicsPipelineConfig::setDepthClampingEnabled(bool depthClamping) { + m_EnableDepthClamping = depthClamping; + } + + CullMode GraphicsPipelineConfig::getCulling() const { + return m_Culling; + } + + void GraphicsPipelineConfig::setCulling(CullMode cullMode) { + m_Culling = cullMode; + } + + DepthTest GraphicsPipelineConfig::getDepthTest() const { + return m_DepthTest; + } + + void GraphicsPipelineConfig::setDepthTest(DepthTest depthTest) { + m_DepthTest = depthTest; + } + + bool GraphicsPipelineConfig::isWritingDepth() const { + return m_DepthWrite; + } + + void GraphicsPipelineConfig::setWritingDepth(bool writingDepth) { + m_DepthWrite = writingDepth; + } + + bool GraphicsPipelineConfig::isWritingAlphaToCoverage() const { + return m_AlphaToCoverage; + } + + void GraphicsPipelineConfig::setWritingAlphaToCoverage(bool alphaToCoverage) { + m_AlphaToCoverage = alphaToCoverage; + } + + uint32_t GraphicsPipelineConfig::getTesselationControlPoints() const { + return m_TessellationControlPoints; + } + + void GraphicsPipelineConfig::setTesselationControlPoints(uint32_t tessellationControlPoints) { + m_TessellationControlPoints = tessellationControlPoints; + } + +} diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index 2ebc84ad476bf911e42fc71bbc575db6b16db081..2a495fa18950f7b48e2b082853d1b31b5a7cf9c9 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -1,21 +1,39 @@ #include "GraphicsPipelineManager.hpp" + +#include "vkcv/Core.hpp" #include "vkcv/Image.hpp" #include "vkcv/Logger.hpp" +#include "vkcv/Multisampling.hpp" -namespace vkcv -{ +namespace vkcv { - GraphicsPipelineManager::GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept : - m_Device(device), - m_physicalDevice(physicalDevice), - m_Pipelines{} - {} + uint64_t GraphicsPipelineManager::getIdFrom(const GraphicsPipelineHandle &handle) const { + return handle.getId(); + } - GraphicsPipelineManager::~GraphicsPipelineManager() noexcept - { - for (uint64_t id = 0; id < m_Pipelines.size(); id++) { - destroyPipelineById(id); - } + GraphicsPipelineHandle GraphicsPipelineManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return GraphicsPipelineHandle(id, destroy); + } + + void GraphicsPipelineManager::destroyById(uint64_t id) { + auto& pipeline = getById(id); + + if (pipeline.m_handle) { + getCore().getContext().getDevice().destroy(pipeline.m_handle); + pipeline.m_handle = nullptr; + } + + if (pipeline.m_layout) { + getCore().getContext().getDevice().destroy(pipeline.m_layout); + pipeline.m_layout = nullptr; + } + } + + GraphicsPipelineManager::GraphicsPipelineManager() noexcept : + HandleManager<GraphicsPipelineEntry, GraphicsPipelineHandle>() {} + + GraphicsPipelineManager::~GraphicsPipelineManager() noexcept { + clear(); } // currently assuming default 32 bit formats, no lower precision or normalized variants supported @@ -141,7 +159,7 @@ namespace vkcv const GraphicsPipelineConfig &config) { if (existsVertexShader) { - const VertexLayout& layout = config.m_VertexLayout; + const VertexLayout& layout = config.getVertexLayout(); // iterate over the layout's specified, mutually exclusive buffer bindings that make up a vertex buffer for (const auto& vertexBinding : layout.vertexBindings) @@ -190,7 +208,7 @@ namespace vkcv vk::PipelineInputAssemblyStateCreateInfo createPipelineInputAssemblyStateCreateInfo(const GraphicsPipelineConfig &config) { vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo( {}, - primitiveTopologyToVulkanPrimitiveTopology(config.m_PrimitiveTopology), + primitiveTopologyToVulkanPrimitiveTopology(config.getPrimitiveTopology()), false ); @@ -200,7 +218,7 @@ namespace vkcv vk::PipelineTessellationStateCreateInfo createPipelineTessellationStateCreateInfo(const GraphicsPipelineConfig &config) { vk::PipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo( {}, - config.m_tessellationControlPoints + config.getTesselationControlPoints() ); return pipelineTessellationStateCreateInfo; @@ -217,14 +235,14 @@ namespace vkcv viewport = vk::Viewport( 0.f, 0.f, - static_cast<float>(config.m_Width), - static_cast<float>(config.m_Height), + static_cast<float>(config.getWidth()), + static_cast<float>(config.getHeight()), 0.f, 1.f ); scissor = vk::Rect2D( { 0,0 }, - { config.m_Width, config.m_Height } + { config.getWidth(), config.getHeight() } ); vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo( @@ -253,7 +271,7 @@ namespace vkcv const GraphicsPipelineConfig &config, const vk::PhysicalDeviceConservativeRasterizationPropertiesEXT& conservativeRasterProperties) { vk::CullModeFlags cullMode; - switch (config.m_culling) { + switch (config.getCulling()) { case CullMode::None: cullMode = vk::CullModeFlagBits::eNone; break; @@ -273,7 +291,7 @@ namespace vkcv vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo ( {}, - config.m_EnableDepthClamping, + config.isDepthClampingEnabled(), false, vk::PolygonMode::eFill, cullMode, @@ -287,7 +305,7 @@ namespace vkcv static vk::PipelineRasterizationConservativeStateCreateInfoEXT conservativeRasterization; - if (config.m_UseConservativeRasterization) { + if (config.isUsingConservativeRasterization()) { const float overestimationSize = 1.0f - conservativeRasterProperties.primitiveOverestimationSize; const float maxOverestimationSize = conservativeRasterProperties.maxExtraPrimitiveOverestimationSize; @@ -308,14 +326,15 @@ namespace vkcv * @param config set MSAA Sample Count Flag * @return Pipeline Multisample State Create Info Struct */ - vk::PipelineMultisampleStateCreateInfo createPipelineMultisampleStateCreateInfo(const GraphicsPipelineConfig &config) { + vk::PipelineMultisampleStateCreateInfo createPipelineMultisampleStateCreateInfo(const GraphicsPipelineConfig &config, + const PassConfig &passConfig) { vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo( {}, - msaaToVkSampleCountFlag(config.m_multisampling), + msaaToSampleCountFlagBits(passConfig.getMultisampling()), false, 0.f, nullptr, - config.m_alphaToCoverage, + config.isWritingAlphaToCoverage(), false ); @@ -332,7 +351,7 @@ namespace vkcv // currently set to additive, if not disabled // BlendFactors must be set as soon as additional BlendModes are added static vk::PipelineColorBlendAttachmentState colorBlendAttachmentState ( - config.m_blendMode != BlendMode::None, + config.getBlendMode() != BlendMode::None, vk::BlendFactor::eOne, vk::BlendFactor::eOne, vk::BlendOp::eAdd, @@ -368,7 +387,7 @@ namespace vkcv const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts) { static vk::PushConstantRange pushConstantRange; - const size_t pushConstantsSize = config.m_ShaderProgram.getPushConstantsSize(); + const size_t pushConstantsSize = config.getShaderProgram().getPushConstantsSize(); pushConstantRange = vk::PushConstantRange( vk::ShaderStageFlagBits::eAll, 0, pushConstantsSize ); @@ -394,9 +413,9 @@ namespace vkcv vk::PipelineDepthStencilStateCreateInfo createPipelineDepthStencilStateCreateInfo(const GraphicsPipelineConfig &config) { const vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilCreateInfo( vk::PipelineDepthStencilStateCreateFlags(), - config.m_depthTest != DepthTest::None, - config.m_depthWrite, - depthTestToVkCompareOp(config.m_depthTest), + config.getDepthTest() != DepthTest::None, + config.isWritingDepth(), + depthTestToVkCompareOp(config.getDepthTest()), false, false, {}, @@ -417,7 +436,7 @@ namespace vkcv static std::vector<vk::DynamicState> dynamicStates; dynamicStates.clear(); - if(config.m_UseDynamicViewport) { + if(config.isViewportDynamic()) { dynamicStates.push_back(vk::DynamicState::eViewport); dynamicStates.push_back(vk::DynamicState::eScissor); } @@ -433,37 +452,38 @@ namespace vkcv GraphicsPipelineHandle GraphicsPipelineManager::createPipeline(const GraphicsPipelineConfig &config, const PassManager& passManager, - const DescriptorManager& descriptorManager) { - const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle); - - const bool existsTaskShader = config.m_ShaderProgram.existsShader(ShaderStage::TASK); - const bool existsMeshShader = config.m_ShaderProgram.existsShader(ShaderStage::MESH); - const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX); - const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT); - const bool existsGeometryShader = config.m_ShaderProgram.existsShader(ShaderStage::GEOMETRY); - const bool existsTessellationControlShader = config.m_ShaderProgram.existsShader(ShaderStage::TESS_CONTROL); - const bool existsTessellationEvaluationShader = config.m_ShaderProgram.existsShader(ShaderStage::TESS_EVAL); + const DescriptorSetLayoutManager& descriptorManager) { + const vk::RenderPass &pass = passManager.getVkPass(config.getPass()); + + const auto& program = config.getShaderProgram(); + + const bool existsTaskShader = program.existsShader(ShaderStage::TASK); + const bool existsMeshShader = program.existsShader(ShaderStage::MESH); + const bool existsVertexShader = program.existsShader(ShaderStage::VERTEX); + const bool existsFragmentShader = program.existsShader(ShaderStage::FRAGMENT); + const bool existsGeometryShader = program.existsShader(ShaderStage::GEOMETRY); + const bool existsTessellationControlShader = program.existsShader(ShaderStage::TESS_CONTROL); + const bool existsTessellationEvaluationShader = program.existsShader(ShaderStage::TESS_EVAL); const bool validGeometryStages = ( (existsVertexShader && (existsTessellationControlShader == existsTessellationEvaluationShader)) || (existsTaskShader && existsMeshShader) ); - if (!validGeometryStages) - { + if (!validGeometryStages) { vkcv_log(LogLevel::ERROR, "Requires vertex or task and mesh shader"); - return GraphicsPipelineHandle(); + return {}; } if (!existsFragmentShader) { vkcv_log(LogLevel::ERROR, "Requires fragment shader code"); - return GraphicsPipelineHandle(); + return {}; } std::vector<vk::PipelineShaderStageCreateInfo> shaderStages; auto destroyShaderModules = [&shaderStages, this] { for (auto stage : shaderStages) { - m_Device.destroyShaderModule(stage.module); + getCore().getContext().getDevice().destroyShaderModule(stage.module); } shaderStages.clear(); }; @@ -471,121 +491,116 @@ namespace vkcv if (existsVertexShader) { vk::PipelineShaderStageCreateInfo createInfo; const bool success = createPipelineShaderStageCreateInfo( - config.m_ShaderProgram, + program, ShaderStage::VERTEX, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } if (existsTaskShader) { vk::PipelineShaderStageCreateInfo createInfo; const bool success = createPipelineShaderStageCreateInfo( - config.m_ShaderProgram, + program, ShaderStage::TASK, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } if (existsMeshShader) { vk::PipelineShaderStageCreateInfo createInfo; const bool success = createPipelineShaderStageCreateInfo( - config.m_ShaderProgram, + program, ShaderStage::MESH, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } { vk::PipelineShaderStageCreateInfo createInfo; const bool success = createPipelineShaderStageCreateInfo( - config.m_ShaderProgram, + program, ShaderStage::FRAGMENT, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } if (existsGeometryShader) { vk::PipelineShaderStageCreateInfo createInfo; const bool success = createPipelineShaderStageCreateInfo( - config.m_ShaderProgram, + program, ShaderStage::GEOMETRY, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } if (existsTessellationControlShader) { vk::PipelineShaderStageCreateInfo createInfo; const bool success = createPipelineShaderStageCreateInfo( - config.m_ShaderProgram, + program, ShaderStage::TESS_CONTROL, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } if (existsTessellationEvaluationShader) { vk::PipelineShaderStageCreateInfo createInfo; const bool success = createPipelineShaderStageCreateInfo( - config.m_ShaderProgram, + program, ShaderStage::TESS_EVAL, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } + + const PassConfig& passConfig = passManager.getPassConfig(config.getPass()); // vertex input state // Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers @@ -615,13 +630,13 @@ namespace vkcv vk::PhysicalDeviceProperties deviceProperties; vk::PhysicalDeviceProperties2 deviceProperties2(deviceProperties); deviceProperties2.pNext = &conservativeRasterProperties; - m_physicalDevice.getProperties2(&deviceProperties2); + getCore().getContext().getPhysicalDevice().getProperties2(&deviceProperties2); vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo = createPipelineRasterizationStateCreateInfo(config, conservativeRasterProperties); // multisample state vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = - createPipelineMultisampleStateCreateInfo(config); + createPipelineMultisampleStateCreateInfo(config, passConfig); // color blend state vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo = @@ -632,8 +647,8 @@ namespace vkcv createPipelineDynamicStateCreateInfo(config); std::vector<vk::DescriptorSetLayout> descriptorSetLayouts; - descriptorSetLayouts.reserve(config.m_DescriptorLayouts.size()); - for (const auto& handle : config.m_DescriptorLayouts) { + descriptorSetLayouts.reserve(config.getDescriptorSetLayouts().size()); + for (const auto& handle : config.getDescriptorSetLayouts()) { descriptorSetLayouts.push_back(descriptorManager.getDescriptorSetLayout(handle).vulkanHandle); } @@ -642,9 +657,11 @@ namespace vkcv createPipelineLayoutCreateInfo(config, descriptorSetLayouts); vk::PipelineLayout vkPipelineLayout{}; - if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess) { + if (getCore().getContext().getDevice().createPipelineLayout(&pipelineLayoutCreateInfo, + nullptr, + &vkPipelineLayout) != vk::Result::eSuccess) { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } // Depth Stencil @@ -652,10 +669,10 @@ namespace vkcv createPipelineDepthStencilStateCreateInfo(config); const vk::PipelineDepthStencilStateCreateInfo* p_depthStencilCreateInfo = nullptr; - const PassConfig& passConfig = passManager.getPassConfig(config.m_PassHandle); - for (const auto& attachment : passConfig.attachments) { - if (isDepthFormat(attachment.format)) { + for (const auto& attachment : passConfig.getAttachments()) { + if ((isDepthFormat(attachment.getFormat())) || + (isStencilFormat(attachment.getFormat()))) { p_depthStencilCreateInfo = &depthStencilCreateInfo; break; } @@ -683,77 +700,38 @@ namespace vkcv ); vk::Pipeline vkPipeline{}; - if (m_Device.createGraphicsPipelines(nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) != vk::Result::eSuccess) + if (getCore().getContext().getDevice().createGraphicsPipelines(nullptr, + 1, + &graphicsPipelineCreateInfo, + nullptr, + &vkPipeline) != vk::Result::eSuccess) { // Catch runtime error if the creation of the pipeline fails. // Destroy everything to keep the memory clean. destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } // Clean Up destroyShaderModules(); // Hand over Handler to main Application - const uint64_t id = m_Pipelines.size(); - m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config }); - return GraphicsPipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); }); + return add({ vkPipeline, vkPipelineLayout, config }); } - vk::Pipeline GraphicsPipelineManager::getVkPipeline(const GraphicsPipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::Pipeline GraphicsPipelineManager::getVkPipeline(const GraphicsPipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_handle; } - vk::PipelineLayout GraphicsPipelineManager::getVkPipelineLayout(const GraphicsPipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::PipelineLayout GraphicsPipelineManager::getVkPipelineLayout(const GraphicsPipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_layout; } - void GraphicsPipelineManager::destroyPipelineById(uint64_t id) { - if (id >= m_Pipelines.size()) { - return; - } - - auto& pipeline = m_Pipelines[id]; - - if (pipeline.m_handle) { - m_Device.destroy(pipeline.m_handle); - pipeline.m_handle = nullptr; - } - - if (pipeline.m_layout) { - m_Device.destroy(pipeline.m_layout); - pipeline.m_layout = nullptr; - } - } - - const GraphicsPipelineConfig& GraphicsPipelineManager::getPipelineConfig(const GraphicsPipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - static GraphicsPipelineConfig dummyConfig; - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return dummyConfig; - } - - return m_Pipelines[id].m_config; + const GraphicsPipelineConfig& GraphicsPipelineManager::getPipelineConfig(const GraphicsPipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; + return pipeline.m_config; } + } diff --git a/src/vkcv/GraphicsPipelineManager.hpp b/src/vkcv/GraphicsPipelineManager.hpp index 511dcf47988028617712c191f79bdf1f292a200a..be18a4c983696eea177fbe6842e6f6ff57426b3a 100644 --- a/src/vkcv/GraphicsPipelineManager.hpp +++ b/src/vkcv/GraphicsPipelineManager.hpp @@ -10,23 +10,42 @@ #include <vulkan/vulkan.hpp> #include <vector> -#include "vkcv/Handles.hpp" +#include "HandleManager.hpp" #include "vkcv/GraphicsPipelineConfig.hpp" #include "PassManager.hpp" -#include "DescriptorManager.hpp" +#include "DescriptorSetLayoutManager.hpp" -namespace vkcv -{ +namespace vkcv { + + struct GraphicsPipelineEntry { + vk::Pipeline m_handle; + vk::PipelineLayout m_layout; + GraphicsPipelineConfig m_config; + }; /** * @brief Class to manage graphics pipelines. */ - class GraphicsPipelineManager - { + class GraphicsPipelineManager : public HandleManager<GraphicsPipelineEntry, GraphicsPipelineHandle> { + private: + [[nodiscard]] + uint64_t getIdFrom(const GraphicsPipelineHandle& handle) const override; + + [[nodiscard]] + GraphicsPipelineHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates graphics pipeline represented by a given + * graphics pipeline handle id. + * + * @param id Graphics pipeline handle id + */ + void destroyById(uint64_t id) override; + public: - GraphicsPipelineManager() = delete; // no default ctor - explicit GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept; // ctor - ~GraphicsPipelineManager() noexcept; // dtor + GraphicsPipelineManager() noexcept; + + ~GraphicsPipelineManager() noexcept override; // dtor GraphicsPipelineManager(const GraphicsPipelineManager &other) = delete; // copy-ctor GraphicsPipelineManager(GraphicsPipelineManager &&other) = delete; // move-ctor; @@ -46,7 +65,7 @@ namespace vkcv */ GraphicsPipelineHandle createPipeline(const GraphicsPipelineConfig &config, const PassManager& passManager, - const DescriptorManager& descriptorManager); + const DescriptorSetLayoutManager& descriptorManager); /** * Returns a vk::Pipeline object by handle. @@ -71,20 +90,7 @@ namespace vkcv */ [[nodiscard]] const GraphicsPipelineConfig &getPipelineConfig(const GraphicsPipelineHandle &handle) const; - - private: - struct GraphicsPipeline { - vk::Pipeline m_handle; - vk::PipelineLayout m_layout; - GraphicsPipelineConfig m_config; - }; - - vk::Device m_Device; - vk::PhysicalDevice m_physicalDevice; // needed to get infos to configure conservative rasterization - std::vector<GraphicsPipeline> m_Pipelines; - - void destroyPipelineById(uint64_t id); - + }; } diff --git a/src/vkcv/HandleManager.hpp b/src/vkcv/HandleManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..13213dc2a4ff5975458690ddc41e5a879580ee16 --- /dev/null +++ b/src/vkcv/HandleManager.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include <optional> +#include <vector> + +#include "vkcv/Handles.hpp" +#include "vkcv/Logger.hpp" + +namespace vkcv { + + class Core; + + template<typename T, typename H = Handle> + class HandleManager { + friend class Core; + private: + Core* m_core; + std::vector<T> m_entries; + + protected: + HandleManager() noexcept : m_core(nullptr), m_entries() {} + + virtual bool init(Core& core) { + if (m_core) { + vkcv_log(vkcv::LogLevel::ERROR, "Manager is already initialized"); + return false; + } + + if (!m_entries.empty()) { + vkcv_log(vkcv::LogLevel::WARNING, "Entries added before initialization will be erased"); + } + + m_core = &core; + m_entries.clear(); + return true; + } + + [[nodiscard]] + const Core& getCore() const { + return *m_core; + } + + [[nodiscard]] + Core& getCore() { + return *m_core; + } + + [[nodiscard]] + size_t getCount() const { + return m_entries.size(); + } + + [[nodiscard]] + const T& getById(uint64_t id) const { + if (id >= m_entries.size()) { + static T invalid; + vkcv_log(vkcv::LogLevel::ERROR, "Invalid handle id"); + return invalid; + } + + return m_entries[id]; + } + + [[nodiscard]] + T& getById(uint64_t id) { + if (id >= m_entries.size()) { + static T invalid; + vkcv_log(vkcv::LogLevel::ERROR, "Invalid handle id"); + return invalid; + } + + return m_entries[id]; + } + + virtual uint64_t getIdFrom(const H& handle) const = 0; + + [[nodiscard]] + virtual const T& operator[](const H& handle) const { + const Handle& _handle = handle; + return getById(getIdFrom(static_cast<const H&>(_handle))); + } + + [[nodiscard]] + virtual T& operator[](const H& handle) { + const Handle& _handle = handle; + return getById(getIdFrom(static_cast<const H&>(_handle))); + } + + H add(const T &entry) { + const uint64_t id = m_entries.size(); + m_entries.push_back(entry); + return createById(id, [&](uint64_t id) { destroyById(id); }); + } + + virtual H createById(uint64_t id, const HandleDestroyFunction& destroy) = 0; + + virtual void destroyById(uint64_t id) = 0; + + void clear() { + for (uint64_t id = 0; id < m_entries.size(); id++) { + destroyById(id); + } + } + + public: + HandleManager(HandleManager&& other) = delete; + HandleManager(const HandleManager& other) = delete; + + HandleManager& operator=(HandleManager&& other) = delete; + HandleManager& operator=(const HandleManager& other) = delete; + + virtual ~HandleManager() noexcept = default; + + }; + +} diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp index 84a706f83a8f256b976f7b58546fbd7f2580f9f5..e17b95fe719805faa5b200686e529fc700400dd4 100644 --- a/src/vkcv/Image.cpp +++ b/src/vkcv/Image.cpp @@ -12,62 +12,59 @@ namespace vkcv{ bool isDepthFormat(const vk::Format format) { switch (format) { - case(vk::Format::eD16Unorm): return true; - case(vk::Format::eD16UnormS8Uint): return true; - case(vk::Format::eD24UnormS8Uint): return true; - case(vk::Format::eD32Sfloat): return true; - case(vk::Format::eD32SfloatS8Uint): return true; - default: return false; + case(vk::Format::eD16Unorm): + case(vk::Format::eD16UnormS8Uint): + case(vk::Format::eD24UnormS8Uint): + case(vk::Format::eD32Sfloat): + case(vk::Format::eD32SfloatS8Uint): + return true; + default: + return false; } } - - Image Image::create( - ImageManager* manager, - vk::Format format, - uint32_t width, - uint32_t height, - uint32_t depth, - uint32_t mipCount, - bool supportStorage, - bool supportColorAttachment, - Multisampling msaa) - { - return Image( - manager, - manager->createImage(width, height, depth, format, mipCount, supportStorage, supportColorAttachment, msaa)); + + bool isStencilFormat(const vk::Format format) { + switch (format) { + case(vk::Format::eS8Uint): + case(vk::Format::eD16UnormS8Uint): + case(vk::Format::eD24UnormS8Uint): + case(vk::Format::eD32SfloatS8Uint): + return true; + default: + return false; + } } vk::Format Image::getFormat() const { - return m_manager->getImageFormat(m_handle); + return m_core->getImageFormat(m_handle); } uint32_t Image::getWidth() const { - return m_manager->getImageWidth(m_handle); + return m_core->getImageWidth(m_handle); } uint32_t Image::getHeight() const { - return m_manager->getImageHeight(m_handle); + return m_core->getImageHeight(m_handle); } uint32_t Image::getDepth() const { - return m_manager->getImageDepth(m_handle); + return m_core->getImageDepth(m_handle); } - void Image::switchLayout(vk::ImageLayout newLayout) - { - m_manager->switchImageLayoutImmediate(m_handle, newLayout); + void Image::switchLayout(vk::ImageLayout newLayout) { + m_core->switchImageLayout(m_handle, newLayout); } const vkcv::ImageHandle& Image::getHandle() const { return m_handle; } - uint32_t Image::getMipCount() const { - return m_manager->getImageMipCount(m_handle); + uint32_t Image::getMipLevels() const { + return m_core->getImageMipLevels(m_handle); } void Image::fill(const void *data, size_t size) { - m_manager->fillImage(m_handle, data, size); + m_core->fillImage(m_handle, data, size); } void Image::recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream, @@ -75,9 +72,25 @@ namespace vkcv{ downsampler.recordDownsampling(cmdStream, m_handle); } - Image::Image(ImageManager* manager, const ImageHandle& handle) : - m_manager(manager), - m_handle(handle) - {} + Image image(Core &core, + vk::Format format, + uint32_t width, + uint32_t height, + uint32_t depth, + bool createMipChain, + bool supportStorage, + bool supportColorAttachment, + Multisampling multisampling) { + return Image(&core, core.createImage( + format, + width, + height, + depth, + createMipChain, + supportStorage, + supportColorAttachment, + multisampling + )); + } } diff --git a/src/vkcv/ImageConfig.cpp b/src/vkcv/ImageConfig.cpp deleted file mode 100644 index 80aeac3d0f702467c8edc1b0f7378d0d7f15b3db..0000000000000000000000000000000000000000 --- a/src/vkcv/ImageConfig.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include <vkcv/ImageConfig.hpp> -#include <vkcv/Logger.hpp> - -namespace vkcv { - vk::SampleCountFlagBits msaaToVkSampleCountFlag(Multisampling msaa) { - switch (msaa) { - case Multisampling::None: return vk::SampleCountFlagBits::e1; - case Multisampling::MSAA2X: return vk::SampleCountFlagBits::e2; - case Multisampling::MSAA4X: return vk::SampleCountFlagBits::e4; - case Multisampling::MSAA8X: return vk::SampleCountFlagBits::e8; - default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown Multisampling enum setting"); return vk::SampleCountFlagBits::e1; - } - } - - uint32_t msaaToSampleCount(Multisampling msaa) { - switch (msaa) { - case Multisampling::None: return 1; - case Multisampling::MSAA2X: return 2; - case Multisampling::MSAA4X: return 4; - case Multisampling::MSAA8X: return 8; - default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown Multisampling enum setting"); return 1; - } - } -} \ No newline at end of file diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 8783752834e95747ff462dfb1a3bec40d91bc175..fbe109da5ee10d43d011c0120abcdff78934a7d7 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -5,51 +5,147 @@ */ #include "ImageManager.hpp" #include "vkcv/Core.hpp" +#include "vkcv/Image.hpp" #include "vkcv/Logger.hpp" +#include "vkcv/Multisampling.hpp" +#include "vkcv/TypeGuard.hpp" #include <algorithm> namespace vkcv { - - /** - * @brief searches memory type index for image allocation, combines requirements of image and application - * @param physicalMemoryProperties Memory Properties of physical device - * @param typeBits Bit field for suitable memory types - * @param requirements Property flags that are required - * @return memory type index for image - */ - uint32_t searchImageMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) { - const uint32_t memoryCount = physicalMemoryProperties.memoryTypeCount; - for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) { - const uint32_t memoryTypeBits = (1 << memoryIndex); - const bool isRequiredMemoryType = typeBits & memoryTypeBits; - - const vk::MemoryPropertyFlags properties = - physicalMemoryProperties.memoryTypes[memoryIndex].propertyFlags; - const bool hasRequiredProperties = - (properties & requirements) == requirements; - - if (isRequiredMemoryType && hasRequiredProperties) - return static_cast<int32_t>(memoryIndex); + + bool ImageManager::init(Core &core, BufferManager &bufferManager) { + if (!HandleManager<ImageEntry, ImageHandle>::init(core)) { + return false; } - - // failed to find memory type - return -1; + + m_bufferManager = &bufferManager; + m_swapchainImages.clear(); + return true; } - - ImageManager::ImageManager(BufferManager& bufferManager) noexcept : - m_core(nullptr), m_bufferManager(bufferManager), m_images() - { + + uint64_t ImageManager::getIdFrom(const ImageHandle &handle) const { + return handle.getId(); } - - ImageManager::~ImageManager() noexcept { - for (uint64_t id = 0; id < m_images.size(); id++) { - destroyImageById(id); + + ImageHandle ImageManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return ImageHandle(id, destroy); + } + + void ImageManager::destroyById(uint64_t id) { + auto& image = getById(id); + + const vk::Device& device = getCore().getContext().getDevice(); + + for (auto& view : image.m_viewPerMip) { + if (view) { + device.destroyImageView(view); + view = nullptr; + } + } + + for (auto& view : image.m_arrayViewPerMip) { + if (view) { + device.destroyImageView(view); + view = nullptr; + } + } + + const vma::Allocator& allocator = getCore().getContext().getAllocator(); + + if (image.m_handle) { + allocator.destroyImage(image.m_handle, image.m_allocation); + + image.m_handle = nullptr; + image.m_allocation = nullptr; + } + } + + const BufferManager &ImageManager::getBufferManager() const { + return *m_bufferManager; + } + + BufferManager &ImageManager::getBufferManager() { + return *m_bufferManager; + } + + void ImageManager::recordImageMipGenerationToCmdBuffer(vk::CommandBuffer cmdBuffer, + const ImageHandle& handle) { + auto& image = (*this)[handle]; + recordImageLayoutTransition(handle, 0, 0, vk::ImageLayout::eGeneral, cmdBuffer); + + vk::ImageAspectFlags aspectMask = isDepthImageFormat(image.m_format) ? + vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor; + + uint32_t srcWidth = image.m_width; + uint32_t srcHeight = image.m_height; + uint32_t srcDepth = image.m_depth; + + auto half = [](uint32_t in) { + return std::max<uint32_t>(in / 2, 1); + }; + + uint32_t dstWidth = half(srcWidth); + uint32_t dstHeight = half(srcHeight); + uint32_t dstDepth = half(srcDepth); + + for (uint32_t srcMip = 0; srcMip < image.m_viewPerMip.size() - 1; srcMip++) { + uint32_t dstMip = srcMip + 1; + vk::ImageBlit region( + vk::ImageSubresourceLayers(aspectMask, srcMip, 0, 1), + { vk::Offset3D(0, 0, 0), vk::Offset3D(srcWidth, srcHeight, srcDepth) }, + vk::ImageSubresourceLayers(aspectMask, dstMip, 0, 1), + { vk::Offset3D(0, 0, 0), vk::Offset3D(dstWidth, dstHeight, dstDepth) }); + + cmdBuffer.blitImage( + image.m_handle, + vk::ImageLayout::eGeneral, + image.m_handle, + vk::ImageLayout::eGeneral, + region, + vk::Filter::eLinear); + + srcWidth = dstWidth; + srcHeight = dstHeight; + srcDepth = dstDepth; + + dstWidth = half(dstWidth); + dstHeight = half(dstHeight); + dstDepth = half(dstDepth); + + recordImageMemoryBarrier(handle, cmdBuffer); + } + } + + const ImageEntry &ImageManager::operator[](const ImageHandle &handle) const { + if (handle.isSwapchainImage()) { + return m_swapchainImages[m_currentSwapchainInputImage]; } + return HandleManager<ImageEntry, ImageHandle>::operator[](handle); + } + + ImageEntry &ImageManager::operator[](const ImageHandle &handle) { + if (handle.isSwapchainImage()) { + return m_swapchainImages[m_currentSwapchainInputImage]; + } + + return HandleManager<ImageEntry, ImageHandle>::operator[](handle); + } + + ImageManager::ImageManager() noexcept : + HandleManager<ImageEntry, ImageHandle>(), + m_bufferManager(nullptr), + m_swapchainImages(), + m_currentSwapchainInputImage(0) + {} + + ImageManager::~ImageManager() noexcept { + clear(); + for (const auto& swapchainImage : m_swapchainImages) { for (const auto view : swapchainImage.m_viewPerMip) { - m_core->getContext().getDevice().destroy(view); + getCore().getContext().getDevice().destroy(view); } } } @@ -72,9 +168,8 @@ namespace vkcv { uint32_t mipCount, bool supportStorage, bool supportColorAttachment, - Multisampling msaa) - { - const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice(); + Multisampling msaa) { + const vk::PhysicalDevice& physicalDevice = getCore().getContext().getPhysicalDevice(); const vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(format); @@ -94,7 +189,7 @@ namespace vkcv { imageTiling = vk::ImageTiling::eLinear; if (!(formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eStorageImage)) - return ImageHandle(); + return {}; } } @@ -108,7 +203,7 @@ namespace vkcv { imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment; } - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); vk::ImageType imageType = vk::ImageType::e3D; vk::ImageViewType imageViewType = vk::ImageViewType::e3D; @@ -134,7 +229,7 @@ namespace vkcv { if (!formatProperties.optimalTilingFeatures) { if (!formatProperties.linearTilingFeatures) - return ImageHandle(); + return {}; imageTiling = vk::ImageTiling::eLinear; } @@ -148,8 +243,6 @@ namespace vkcv { const uint32_t arrayLayers = std::min<uint32_t>(1, imageFormatProperties.maxArrayLayers); - vk::SampleCountFlagBits sampleCountFlag = msaaToVkSampleCountFlag(msaa); - const vk::ImageCreateInfo imageCreateInfo ( createFlags, imageType, @@ -157,7 +250,7 @@ namespace vkcv { vk::Extent3D(width, height, depth), mipCount, arrayLayers, - sampleCountFlag, + msaaToSampleCountFlagBits(msaa), imageTiling, imageUsageFlags, vk::SharingMode::eExclusive, @@ -189,7 +282,7 @@ namespace vkcv { aspectFlags = vk::ImageAspectFlagBits::eColor; } - const vk::Device& device = m_core->getContext().getDevice(); + const vk::Device& device = getCore().getContext().getDevice(); std::vector<vk::ImageView> views; std::vector<vk::ImageView> arrayViews; @@ -242,25 +335,22 @@ namespace vkcv { arrayViews.push_back(device.createImageView(imageViewCreateInfo)); } - const uint64_t id = m_images.size(); - m_images.push_back({ + return add({ image, allocation, views, arrayViews, - + width, height, depth, - + format, arrayLayers, vk::ImageLayout::eUndefined, supportStorage }); - - return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); }); } ImageHandle ImageManager::createSwapchainImage() const { @@ -268,38 +358,18 @@ namespace vkcv { } vk::Image ImageManager::getVulkanImage(const ImageHandle &handle) const { - - if (handle.isSwapchainImage()) { - m_swapchainImages[m_currentSwapchainInputImage].m_handle; - } - - const uint64_t id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return nullptr; - } - - auto& image = m_images[id]; - + auto& image = (*this)[handle]; return image.m_handle; } vk::DeviceMemory ImageManager::getVulkanDeviceMemory(const ImageHandle &handle) const { - if (handle.isSwapchainImage()) { vkcv_log(LogLevel::ERROR, "Swapchain image has no memory"); return nullptr; } - - const uint64_t id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return nullptr; - } - auto& image = m_images[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + auto& image = (*this)[handle]; + const vma::Allocator& allocator = getCore().getContext().getAllocator(); auto info = allocator.getAllocationInfo( image.m_allocation @@ -311,18 +381,11 @@ namespace vkcv { vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, size_t mipLevel, bool arrayView) const { - if (handle.isSwapchainImage()) { return m_swapchainImages[m_currentSwapchainInputImage].m_viewPerMip[0]; } - - const uint64_t id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return nullptr; - } - const auto& image = m_images[id]; + const auto& image = (*this)[handle]; const auto& views = arrayView? image.m_arrayViewPerMip : image.m_viewPerMip; if (mipLevel >= views.size()) { @@ -333,7 +396,7 @@ namespace vkcv { return views[mipLevel]; } - static vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageManager::Image &image, + static vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageEntry &image, uint32_t mipLevelCount, uint32_t mipLevelOffset, vk::ImageLayout newLayout) { @@ -374,23 +437,14 @@ namespace vkcv { } void ImageManager::switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout) { - uint64_t id = handle.getId(); - - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; + auto& image = (*this)[handle]; const auto transitionBarrier = createImageLayoutTransitionBarrier(image, 0, 0, newLayout); - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; + auto& core = getCore(); + auto stream = core.createCommandStream(QueueType::Graphics); - m_core->recordAndSubmitCommandsImmediate( - submitInfo, + core.recordCommandsToStream( + stream, [transitionBarrier](const vk::CommandBuffer& commandBuffer) { // TODO: precise PipelineStageFlagBits, will require a lot of context commandBuffer.pipelineBarrier( @@ -405,6 +459,7 @@ namespace vkcv { nullptr ); + core.submitCommandStream(stream, false); image.m_layout = newLayout; } @@ -413,15 +468,7 @@ namespace vkcv { uint32_t mipLevelOffset, vk::ImageLayout newLayout, vk::CommandBuffer cmdBuffer) { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; + auto& image = (*this)[handle]; const auto transitionBarrier = createImageLayoutTransitionBarrier( image, mipLevelCount, @@ -441,19 +488,9 @@ namespace vkcv { image.m_layout = newLayout; } - void ImageManager::recordImageMemoryBarrier( - const ImageHandle& handle, - vk::CommandBuffer cmdBuffer) { - - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - std::cerr << "Error: ImageManager::recordImageMemoryBarrier invalid handle" << std::endl; - return; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; + void ImageManager::recordImageMemoryBarrier(const ImageHandle& handle, + vk::CommandBuffer cmdBuffer) { + auto& image = (*this)[handle]; const auto transitionBarrier = createImageLayoutTransitionBarrier(image, 0, 0, image.m_layout); cmdBuffer.pipelineBarrier( @@ -486,25 +523,14 @@ namespace vkcv { } } - void ImageManager::fillImage(const ImageHandle& handle, const void* data, size_t size) - { - const uint64_t id = handle.getId(); - + void ImageManager::fillImage(const ImageHandle& handle, const void* data, size_t size) { if (handle.isSwapchainImage()) { vkcv_log(LogLevel::ERROR, "Swapchain image cannot be filled"); return; } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - auto& image = m_images[id]; - - switchImageLayoutImmediate( - handle, - vk::ImageLayout::eTransferDstOptimal); + auto& image = (*this)[handle]; + switchImageLayoutImmediate(handle, vk::ImageLayout::eTransferDstOptimal); const size_t image_size = ( image.m_width * image.m_height * image.m_depth * @@ -513,23 +539,23 @@ namespace vkcv { const size_t max_size = std::min(size, image_size); - BufferHandle bufferHandle = m_bufferManager.createBuffer( + BufferHandle bufferHandle = getBufferManager().createBuffer( + TypeGuard(1), BufferType::STAGING, - max_size, BufferMemoryType::DEVICE_LOCAL, - false, + max_size, false ); - m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0); + getBufferManager().fillBuffer(bufferHandle, data, max_size, 0); - vk::Buffer stagingBuffer = m_bufferManager.getBuffer(bufferHandle); + vk::Buffer stagingBuffer = getBufferManager().getBuffer(bufferHandle); - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Transfer; + auto& core = getCore(); + auto stream = core.createCommandStream(QueueType::Transfer); - m_core->recordAndSubmitCommandsImmediate( - submitInfo, + core.recordCommandsToStream( + stream, [&image, &stagingBuffer](const vk::CommandBuffer& commandBuffer) { vk::ImageAspectFlags aspectFlags; @@ -562,97 +588,28 @@ namespace vkcv { ); }, [&]() { - switchImageLayoutImmediate( - handle, - vk::ImageLayout::eShaderReadOnlyOptimal - ); + switchImageLayoutImmediate(handle,vk::ImageLayout::eShaderReadOnlyOptimal); } ); + + core.submitCommandStream(stream, false); } - void ImageManager::recordImageMipGenerationToCmdBuffer(vk::CommandBuffer cmdBuffer, const ImageHandle& handle) { - - const auto id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(vkcv::LogLevel::ERROR, "Invalid image handle"); - return; - } - - auto& image = m_images[id]; - recordImageLayoutTransition(handle, 0, 0, vk::ImageLayout::eGeneral, cmdBuffer); - - vk::ImageAspectFlags aspectMask = isDepthImageFormat(image.m_format) ? - vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor; - - uint32_t srcWidth = image.m_width; - uint32_t srcHeight = image.m_height; - uint32_t srcDepth = image.m_depth; - - auto half = [](uint32_t in) { - return std::max<uint32_t>(in / 2, 1); - }; - - uint32_t dstWidth = half(srcWidth); - uint32_t dstHeight = half(srcHeight); - uint32_t dstDepth = half(srcDepth); - - for (uint32_t srcMip = 0; srcMip < image.m_viewPerMip.size() - 1; srcMip++) { - uint32_t dstMip = srcMip + 1; - vk::ImageBlit region( - vk::ImageSubresourceLayers(aspectMask, srcMip, 0, 1), - { vk::Offset3D(0, 0, 0), vk::Offset3D(srcWidth, srcHeight, srcDepth) }, - vk::ImageSubresourceLayers(aspectMask, dstMip, 0, 1), - { vk::Offset3D(0, 0, 0), vk::Offset3D(dstWidth, dstHeight, dstDepth) }); - - cmdBuffer.blitImage( - image.m_handle, - vk::ImageLayout::eGeneral, - image.m_handle, - vk::ImageLayout::eGeneral, - region, - vk::Filter::eLinear); - - srcWidth = dstWidth; - srcHeight = dstHeight; - srcDepth = dstDepth; - - dstWidth = half(dstWidth); - dstHeight = half(dstHeight); - dstDepth = half(dstDepth); - - recordImageMemoryBarrier(handle, cmdBuffer); - } - } - - void ImageManager::recordImageMipChainGenerationToCmdStream( - const vkcv::CommandStreamHandle& cmdStream, - const ImageHandle& handle) { - + void ImageManager::recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, + const ImageHandle& handle) { const auto record = [this, handle](const vk::CommandBuffer cmdBuffer) { recordImageMipGenerationToCmdBuffer(cmdBuffer, handle); }; - m_core->recordCommandsToStream(cmdStream, record, nullptr); + + getCore().recordCommandsToStream(cmdStream, record, nullptr); } - void ImageManager::recordMSAAResolve(vk::CommandBuffer cmdBuffer, ImageHandle src, ImageHandle dst) { - - const uint64_t srcId = src.getId(); - const uint64_t dstId = dst.getId(); - - const bool isSrcSwapchainImage = src.isSwapchainImage(); - const bool isDstSwapchainImage = dst.isSwapchainImage(); - - const bool isSrcHandleInvalid = srcId >= m_images.size() && !isSrcSwapchainImage; - const bool isDstHandleInvalid = dstId >= m_images.size() && !isDstSwapchainImage; - - if (isSrcHandleInvalid || isDstHandleInvalid) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& srcImage = isSrcSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[srcId]; - auto& dstImage = isDstSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[dstId]; - + void ImageManager::recordMSAAResolve(vk::CommandBuffer cmdBuffer, + const ImageHandle& src, + const ImageHandle& dst) { + auto& srcImage = (*this)[src]; + auto& dstImage = (*this)[dst]; + vk::ImageResolve region( vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), @@ -672,152 +629,62 @@ namespace vkcv { } uint32_t ImageManager::getImageWidth(const ImageHandle &handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - + auto& image = (*this)[handle]; return image.m_width; } uint32_t ImageManager::getImageHeight(const ImageHandle &handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - + auto& image = (*this)[handle]; return image.m_height; } uint32_t ImageManager::getImageDepth(const ImageHandle &handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - + auto& image = (*this)[handle]; return image.m_depth; } - - void ImageManager::destroyImageById(uint64_t id) - { - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& image = m_images[id]; - - const vk::Device& device = m_core->getContext().getDevice(); - - for (auto& view : image.m_viewPerMip) { - if (view) { - device.destroyImageView(view); - view = nullptr; - } - } - - for (auto& view : image.m_arrayViewPerMip) { - if (view) { - device.destroyImageView(view); - view = nullptr; - } - } - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); - - if (image.m_handle) { - allocator.destroyImage(image.m_handle, image.m_allocation); - - image.m_handle = nullptr; - image.m_allocation = nullptr; - } - } vk::Format ImageManager::getImageFormat(const ImageHandle& handle) const { - - const uint64_t id = handle.getId(); - const bool isSwapchainFormat = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainFormat) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return vk::Format::eUndefined; - } - - return isSwapchainFormat ? m_swapchainImages[m_currentSwapchainInputImage].m_format : m_images[id].m_format; + auto& image = (*this)[handle]; + return image.m_format; } bool ImageManager::isImageSupportingStorage(const ImageHandle& handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainFormat = handle.isSwapchainImage(); - - if (isSwapchainFormat) { - return false; - } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); + if (handle.isSwapchainImage()) { return false; } - return m_images[id].m_storage; + auto& image = (*this)[handle]; + return image.m_storage; } uint32_t ImageManager::getImageMipCount(const ImageHandle& handle) const { - const uint64_t id = handle.getId(); - if (handle.isSwapchainImage()) { return 1; } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - return m_images[id].m_viewPerMip.size(); + + auto& image = (*this)[handle]; + return image.m_viewPerMip.size(); } uint32_t ImageManager::getImageArrayLayers(const ImageHandle& handle) const { - const uint64_t id = handle.getId(); - - if (handle.isSwapchainImage()) { - return m_swapchainImages[0].m_layers; - } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - return m_images[id].m_layers; + auto& image = (*this)[handle]; + return image.m_layers; } void ImageManager::setCurrentSwapchainImageIndex(int index) { m_currentSwapchainInputImage = index; } - void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, - uint32_t width, uint32_t height, vk::Format format) { + void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, + const std::vector<vk::ImageView>& views, + uint32_t width, + uint32_t height, + vk::Format format) { // destroy old views for (const auto& image : m_swapchainImages) { for (const auto& view : image.m_viewPerMip) { - m_core->getContext().getDevice().destroyImageView(view); + getCore().getContext().getDevice().destroyImageView(view); } } @@ -840,20 +707,10 @@ namespace vkcv { } } - void ImageManager::updateImageLayoutManual(const vkcv::ImageHandle& handle, const vk::ImageLayout layout) { - const uint64_t id = handle.getId(); - - if (handle.isSwapchainImage()) { - m_swapchainImages[m_currentSwapchainInputImage].m_layout = layout; - } - else { - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - m_swapchainImages[id].m_layout = layout; - } - + void ImageManager::updateImageLayoutManual(const vkcv::ImageHandle& handle, + const vk::ImageLayout layout) { + auto& image = (*this)[handle]; + image.m_layout = layout; } } \ No newline at end of file diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index 3e577fd9a61fea6334faaf136386bf845ca387e8..de91245c76a76ea0658a1fb69472d5f9059215e6 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -8,9 +8,9 @@ #include <vulkan/vulkan.hpp> #include <vk_mem_alloc.hpp> -#include "vkcv/BufferManager.hpp" -#include "vkcv/Handles.hpp" -#include "vkcv/ImageConfig.hpp" +#include "BufferManager.hpp" +#include "HandleManager.hpp" +#include "vkcv/Multisampling.hpp" namespace vkcv { @@ -22,44 +22,44 @@ namespace vkcv { * @return True, if the format is usable for depth buffers, otherwise false. */ bool isDepthImageFormat(vk::Format format); + + struct ImageEntry { + vk::Image m_handle; + vma::Allocation m_allocation; + + std::vector<vk::ImageView> m_viewPerMip; + std::vector<vk::ImageView> m_arrayViewPerMip; + + uint32_t m_width; + uint32_t m_height; + uint32_t m_depth; + + vk::Format m_format; + uint32_t m_layers; + vk::ImageLayout m_layout; + bool m_storage; + }; /** * @brief Class to manage the creation, destruction, allocation * and filling of images. */ - class ImageManager + class ImageManager : HandleManager<ImageEntry, ImageHandle> { friend class Core; - public: - struct Image - { - vk::Image m_handle; - vma::Allocation m_allocation; - - std::vector<vk::ImageView> m_viewPerMip; - std::vector<vk::ImageView> m_arrayViewPerMip; - - uint32_t m_width; - uint32_t m_height; - uint32_t m_depth; - - vk::Format m_format; - uint32_t m_layers; - vk::ImageLayout m_layout; - bool m_storage; - private: - friend ImageManager; - }; private: + BufferManager* m_bufferManager; - Core* m_core; - BufferManager& m_bufferManager; - - std::vector<Image> m_images; - std::vector<Image> m_swapchainImages; + std::vector<ImageEntry> m_swapchainImages; int m_currentSwapchainInputImage; - explicit ImageManager(BufferManager& bufferManager) noexcept; + bool init(Core& core, BufferManager& bufferManager); + + [[nodiscard]] + uint64_t getIdFrom(const ImageHandle& handle) const override; + + [[nodiscard]] + ImageHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; /** * Destroys and deallocates image represented by a given @@ -67,18 +67,29 @@ namespace vkcv { * * @param id Image handle id */ - void destroyImageById(uint64_t id); + void destroyById(uint64_t id) override; + + [[nodiscard]] + const BufferManager& getBufferManager() const; + + [[nodiscard]] + BufferManager& getBufferManager(); void recordImageMipGenerationToCmdBuffer(vk::CommandBuffer cmdBuffer, const ImageHandle& handle); - + + protected: + [[nodiscard]] + virtual const ImageEntry& operator[](const ImageHandle& handle) const override; + + [[nodiscard]] + virtual ImageEntry& operator[](const ImageHandle& handle) override; + public: - ~ImageManager() noexcept; - ImageManager(ImageManager&& other) = delete; - ImageManager(const ImageManager& other) = delete; - - ImageManager& operator=(ImageManager&& other) = delete; - ImageManager& operator=(const ImageManager& other) = delete; + ImageManager() noexcept; + + ~ImageManager() noexcept override; + [[nodiscard]] ImageHandle createImage( uint32_t width, uint32_t height, @@ -103,22 +114,28 @@ namespace vkcv { size_t mipLevel = 0, bool arrayView = false) const; - void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout); - - void recordImageLayoutTransition( - const ImageHandle& handle, - uint32_t mipLevelCount, - uint32_t mipLevelOffset, - vk::ImageLayout newLayout, - vk::CommandBuffer cmdBuffer); + void switchImageLayoutImmediate(const ImageHandle& handle, + vk::ImageLayout newLayout); + + void recordImageLayoutTransition(const ImageHandle& handle, + uint32_t mipLevelCount, + uint32_t mipLevelOffset, + vk::ImageLayout newLayout, + vk::CommandBuffer cmdBuffer); - void recordImageMemoryBarrier( - const ImageHandle& handle, - vk::CommandBuffer cmdBuffer); + void recordImageMemoryBarrier(const ImageHandle& handle, + vk::CommandBuffer cmdBuffer); - void fillImage(const ImageHandle& handle, const void* data, size_t size); - void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, const ImageHandle& handle); - void recordMSAAResolve(vk::CommandBuffer cmdBuffer, ImageHandle src, ImageHandle dst); + void fillImage(const ImageHandle& handle, + const void* data, + size_t size); + + void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, + const ImageHandle& handle); + + void recordMSAAResolve(vk::CommandBuffer cmdBuffer, + const ImageHandle& src, + const ImageHandle& dst); [[nodiscard]] uint32_t getImageWidth(const ImageHandle& handle) const; @@ -143,12 +160,16 @@ namespace vkcv { void setCurrentSwapchainImageIndex(int index); - void setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, - uint32_t width, uint32_t height, vk::Format format); + void setSwapchainImages(const std::vector<vk::Image>& images, + const std::vector<vk::ImageView>& views, + uint32_t width, + uint32_t height, + vk::Format format); // if manual vulkan work, e.g. ImGui integration, changes an image layout this function must be used // to update the internal image state - void updateImageLayoutManual(const vkcv::ImageHandle& handle, const vk::ImageLayout layout); + void updateImageLayoutManual(const vkcv::ImageHandle& handle, + const vk::ImageLayout layout); }; } \ No newline at end of file diff --git a/src/vkcv/Multisampling.cpp b/src/vkcv/Multisampling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b64dd06cbfbabf74ca777a840512d6eeffeb1ed --- /dev/null +++ b/src/vkcv/Multisampling.cpp @@ -0,0 +1,38 @@ +#include <vkcv/Multisampling.hpp> +#include <vkcv/Logger.hpp> + +namespace vkcv { + + vk::SampleCountFlagBits msaaToSampleCountFlagBits(Multisampling msaa) { + switch (msaa) { + case Multisampling::None: + return vk::SampleCountFlagBits::e1; + case Multisampling::MSAA2X: + return vk::SampleCountFlagBits::e2; + case Multisampling::MSAA4X: + return vk::SampleCountFlagBits::e4; + case Multisampling::MSAA8X: + return vk::SampleCountFlagBits::e8; + default: + vkcv_log(vkcv::LogLevel::ERROR, "Unknown Multisampling enum setting"); + return vk::SampleCountFlagBits::e1; + } + } + + uint32_t msaaToSampleCount(Multisampling msaa) { + switch (msaa) { + case Multisampling::None: + return 1; + case Multisampling::MSAA2X: + return 2; + case Multisampling::MSAA4X: + return 4; + case Multisampling::MSAA8X: + return 8; + default: + vkcv_log(vkcv::LogLevel::ERROR, "Unknown Multisampling enum setting"); + return 1; + } + } + +} \ No newline at end of file diff --git a/src/vkcv/Pass.cpp b/src/vkcv/Pass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54482cd9d3189fd1e4ed5a15a07163b079105db4 --- /dev/null +++ b/src/vkcv/Pass.cpp @@ -0,0 +1,47 @@ + +#include "vkcv/Pass.hpp" + +namespace vkcv { + + PassHandle passFormats(Core &core, + const std::vector<vk::Format> formats, + bool clear, + Multisampling multisampling) { + AttachmentDescriptions attachments; + + for (const auto format : formats) { + attachments.emplace_back( + format, + clear? AttachmentOperation::CLEAR : AttachmentOperation::LOAD, + AttachmentOperation::STORE + ); + } + + const PassConfig config (attachments, multisampling); + return core.createPass(config); + } + + PassHandle passFormat(Core &core, + vk::Format format, + bool clear, + Multisampling multisampling) { + return passFormats(core, { format }, clear, multisampling); + } + + PassHandle passSwapchain(Core &core, + const SwapchainHandle &swapchain, + const std::vector<vk::Format> formats, + bool clear, + Multisampling multisampling) { + std::vector<vk::Format> swapchainFormats (formats); + + for (auto& format : swapchainFormats) { + if (vk::Format::eUndefined == format) { + format = core.getSwapchainFormat(swapchain); + } + } + + return passFormats(core, swapchainFormats, clear, multisampling); + } + +} diff --git a/src/vkcv/PassConfig.cpp b/src/vkcv/PassConfig.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54f3f17f080ec01207a162532dc140e9abd92dd3 --- /dev/null +++ b/src/vkcv/PassConfig.cpp @@ -0,0 +1,82 @@ + +#include "vkcv/PassConfig.hpp" +#include "vkcv/Image.hpp" + +namespace vkcv +{ + + AttachmentDescription::AttachmentDescription(vk::Format format, + AttachmentOperation load, + AttachmentOperation store) + : m_format(format), + m_load_op(load), + m_store_op(store), + m_clear_value() + { + if (isDepthFormat(format)) { + setClearValue(vk::ClearValue( + vk::ClearDepthStencilValue(1.0f, 0) + )); + } else { + setClearValue(vk::ClearValue( + vk::ClearColorValue(std::array<float, 4>{ + 0.0f, 0.0f, 0.0f, 0.0f + }) + )); + } + } + + AttachmentDescription::AttachmentDescription(vk::Format format, + AttachmentOperation load, + AttachmentOperation store, + const vk::ClearValue &clear) + : m_format(format), + m_load_op(load), + m_store_op(store), + m_clear_value(clear) + {} + + vk::Format AttachmentDescription::getFormat() const { + return m_format; + } + + AttachmentOperation AttachmentDescription::getLoadOperation() const { + return m_load_op; + } + + AttachmentOperation AttachmentDescription::getStoreOperation() const { + return m_store_op; + } + + void AttachmentDescription::setClearValue(const vk::ClearValue &clear) { + m_clear_value = clear; + } + + const vk::ClearValue &AttachmentDescription::getClearValue() const { + return m_clear_value; + } + + PassConfig::PassConfig() + : m_attachments(), + m_multisampling(Multisampling::None) + {} + + PassConfig::PassConfig(const AttachmentDescriptions &attachments, + Multisampling multisampling) + : m_attachments(attachments), + m_multisampling(multisampling) + {} + + const AttachmentDescriptions &PassConfig::getAttachments() const { + return m_attachments; + } + + void PassConfig::setMultisampling(Multisampling multisampling) { + m_multisampling = multisampling; + } + + Multisampling PassConfig::getMultisampling() const { + return m_multisampling; + } + +} diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp index 5eb727c75f9ec7e6f4cc3fa8fd8118a1a05f036f..75343f4cecea4ac3d46180ccab4cf09d7a43a2a3 100644 --- a/src/vkcv/PassManager.cpp +++ b/src/vkcv/PassManager.cpp @@ -1,5 +1,6 @@ #include "PassManager.hpp" #include "vkcv/Image.hpp" +#include "vkcv/Core.hpp" namespace vkcv { @@ -27,129 +28,147 @@ namespace vkcv return vk::AttachmentLoadOp::eDontCare; } } - - PassManager::PassManager(vk::Device device) noexcept : - m_Device{device}, - m_Passes{} - {} - - PassManager::~PassManager() noexcept - { - for (uint64_t id = 0; id < m_Passes.size(); id++) { - destroyPassById(id); - } + + uint64_t PassManager::getIdFrom(const PassHandle &handle) const { + return handle.getId(); + } + + PassHandle PassManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return PassHandle(id, destroy); + } + + void PassManager::destroyById(uint64_t id) { + auto& pass = getById(id); + + if (pass.m_Handle) { + getCore().getContext().getDevice().destroy(pass.m_Handle); + pass.m_Handle = nullptr; + } + } + + PassManager::PassManager() noexcept : HandleManager<PassEntry, PassHandle>() {} + + PassManager::~PassManager() noexcept { + clear(); } - PassHandle PassManager::createPass(const PassConfig &config) - { + PassHandle PassManager::createPass(const PassConfig &config) { // description of all {color, input, depth/stencil} attachments of the render pass std::vector<vk::AttachmentDescription> attachmentDescriptions{}; // individual references to color attachments (of a subpass) std::vector<vk::AttachmentReference> colorAttachmentReferences{}; // individual reference to depth attachment (of a subpass) - vk::AttachmentReference depthAttachmentReference{}; - vk::AttachmentReference *pDepthAttachment = nullptr; //stays nullptr if no depth attachment used + vk::AttachmentReference depthStencilAttachmentRef; + + // stays nullptr if no depth attachment used + vk::AttachmentReference *pDepthStencil = nullptr; + + const auto &featureManager = getCore().getContext().getFeatureManager(); + + const bool separateDepthStencil = ( + featureManager.checkFeatures<vk::PhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR>( + vk::StructureType::ePhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR, + [](const vk::PhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR& features) { + return features.separateDepthStencilLayouts; + } + ) + ); + + const auto& attachments = config.getAttachments(); + + std::vector<vk::ImageLayout> layouts; + layouts.reserve(attachments.size()); - for (uint32_t i = 0; i < config.attachments.size(); i++) - { - // TODO: Renderpass struct should hold proper format information - vk::Format format = config.attachments[i].format; + for (uint32_t i = 0; i < attachments.size(); i++) { + vk::Format format = attachments[i].getFormat(); vk::ImageLayout layout; - - if (isDepthFormat(config.attachments[i].format)) - { - layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; - depthAttachmentReference.attachment = i; - depthAttachmentReference.layout = layout; - pDepthAttachment = &depthAttachmentReference; - } - else - { - layout = vk::ImageLayout::eColorAttachmentOptimal; - vk::AttachmentReference attachmentRef(i, layout); + + bool depthFormat = isDepthFormat(attachments[i].getFormat()); + bool stencilFormat = isStencilFormat(attachments[i].getFormat()); + + if ((separateDepthStencil) && (depthFormat) && (!stencilFormat)) { + layout = vk::ImageLayout::eDepthAttachmentOptimal; + } else + if ((separateDepthStencil) && (!depthFormat) && (stencilFormat)) { + layout = vk::ImageLayout::eStencilAttachmentOptimal; + } else + if ((depthFormat) || (stencilFormat)) { + layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; + } else { + layout = vk::ImageLayout::eColorAttachmentOptimal; + } + + if ((depthFormat) || (stencilFormat)) { + depthStencilAttachmentRef = vk::AttachmentReference(i, layout); + pDepthStencil = &depthStencilAttachmentRef; + } else { + vk::AttachmentReference attachmentRef (i, layout); colorAttachmentReferences.push_back(attachmentRef); } - vk::AttachmentDescription attachmentDesc( - {}, - format, - msaaToVkSampleCountFlag(config.msaa), - getVKLoadOpFromAttachOp(config.attachments[i].load_operation), - getVkStoreOpFromAttachOp(config.attachments[i].store_operation), - vk::AttachmentLoadOp::eDontCare, - vk::AttachmentStoreOp::eDontCare, - layout, - layout); + vk::AttachmentDescription attachmentDesc ( + {}, + format, + msaaToSampleCountFlagBits(config.getMultisampling()), + getVKLoadOpFromAttachOp(attachments[i].getLoadOperation()), + getVkStoreOpFromAttachOp(attachments[i].getStoreOperation()), + vk::AttachmentLoadOp::eDontCare, + vk::AttachmentStoreOp::eDontCare, + layout, + layout + ); + + if (stencilFormat) { + attachmentDesc.setStencilLoadOp(attachmentDesc.loadOp); + attachmentDesc.setStencilStoreOp(attachmentDesc.storeOp); + } attachmentDescriptions.push_back(attachmentDesc); + layouts.push_back(layout); } - const vk::SubpassDescription subpassDescription( - {}, - vk::PipelineBindPoint::eGraphics, - 0, - {}, - static_cast<uint32_t>(colorAttachmentReferences.size()), - colorAttachmentReferences.data(), - {}, - pDepthAttachment, - 0, - {}); + const vk::SubpassDescription subpassDescription ( + {}, + vk::PipelineBindPoint::eGraphics, + 0, + {}, + static_cast<uint32_t>(colorAttachmentReferences.size()), + colorAttachmentReferences.data(), + {}, + pDepthStencil, + 0, + {} + ); - const vk::RenderPassCreateInfo passInfo( - {}, - static_cast<uint32_t>(attachmentDescriptions.size()), - attachmentDescriptions.data(), - 1, - &subpassDescription, - 0, - {}); + const vk::RenderPassCreateInfo passInfo ( + {}, + static_cast<uint32_t>(attachmentDescriptions.size()), + attachmentDescriptions.data(), + 1, + &subpassDescription, + 0, + {} + ); - vk::RenderPass renderPass = m_Device.createRenderPass(passInfo); + vk::RenderPass renderPass = getCore().getContext().getDevice().createRenderPass(passInfo); - const uint64_t id = m_Passes.size(); - m_Passes.push_back({ renderPass, config }); - return PassHandle(id, [&](uint64_t id) { destroyPassById(id); }); + return add({ renderPass, config, layouts }); } - vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Passes.size()) { - return nullptr; - } - - auto& pass = m_Passes[id]; - + vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const { + auto& pass = (*this)[handle]; return pass.m_Handle; } const PassConfig& PassManager::getPassConfig(const PassHandle &handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_Passes.size()) { - static PassConfig emptyConfig = PassConfig({}); - return emptyConfig; - } - - auto& pass = m_Passes[id]; - + auto& pass = (*this)[handle]; return pass.m_Config; } - - void PassManager::destroyPassById(uint64_t id) { - if (id >= m_Passes.size()) { - return; - } - - auto& pass = m_Passes[id]; - if (pass.m_Handle) { - m_Device.destroy(pass.m_Handle); - pass.m_Handle = nullptr; - } - } + const std::vector<vk::ImageLayout>& PassManager::getLayouts(const PassHandle &handle) const { + auto& pass = (*this)[handle]; + return pass.m_Layouts; + } } diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp index 1ef976e0482ea39afad33346068f2a168eac70d8..f8dc653c1017ff776d70f09415a3a10fff209695 100644 --- a/src/vkcv/PassManager.hpp +++ b/src/vkcv/PassManager.hpp @@ -2,39 +2,45 @@ #include <vulkan/vulkan.hpp> #include <vector> -#include "vkcv/Handles.hpp" + +#include "HandleManager.hpp" #include "vkcv/PassConfig.hpp" namespace vkcv { + struct PassEntry { + vk::RenderPass m_Handle; + PassConfig m_Config; + std::vector<vk::ImageLayout> m_Layouts; + }; + /** * @brief Class to manage the creation and destruction of passes. */ - class PassManager - { + class PassManager : public HandleManager<PassEntry, PassHandle> { + friend class Core; private: - struct Pass { - vk::RenderPass m_Handle; - PassConfig m_Config; - }; - - vk::Device m_Device; - std::vector<Pass> m_Passes; - - void destroyPassById(uint64_t id); + [[nodiscard]] + uint64_t getIdFrom(const PassHandle& handle) const override; + + [[nodiscard]] + PassHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates pass represented by a given + * pass handle id. + * + * @param id Pass handle id + */ + void destroyById(uint64_t id) override; public: - PassManager() = delete; // no default ctor - explicit PassManager(vk::Device device) noexcept; // ctor - ~PassManager() noexcept; // dtor - - PassManager(const PassManager &other) = delete; // copy-ctor - PassManager(PassManager &&other) = delete; // move-ctor; - - PassManager & operator=(const PassManager &other) = delete; // copy-assign op - PassManager & operator=(PassManager &&other) = delete; // move-assign op - + PassManager() noexcept; + + ~PassManager() noexcept override; // dtor + + [[nodiscard]] PassHandle createPass(const PassConfig &config); [[nodiscard]] @@ -42,6 +48,9 @@ namespace vkcv [[nodiscard]] const PassConfig& getPassConfig(const PassHandle &handle) const; + + [[nodiscard]] + const std::vector<vk::ImageLayout>& getLayouts(const PassHandle &handle) const; }; diff --git a/src/vkcv/PipelineConfig.cpp b/src/vkcv/PipelineConfig.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7585f9fe6d95eaf0409eb187d9da43162770719f --- /dev/null +++ b/src/vkcv/PipelineConfig.cpp @@ -0,0 +1,36 @@ + +#include "vkcv/PipelineConfig.hpp" + +namespace vkcv { + + PipelineConfig::PipelineConfig() : m_ShaderProgram(), m_DescriptorSetLayouts() {} + + PipelineConfig::PipelineConfig(const ShaderProgram &program, + const std::vector<DescriptorSetLayoutHandle> &layouts) + : m_ShaderProgram(program), m_DescriptorSetLayouts(layouts) {} + + void PipelineConfig::setShaderProgram(const ShaderProgram& program) { + m_ShaderProgram = program; + } + + const ShaderProgram &PipelineConfig::getShaderProgram() const { + return m_ShaderProgram; + } + + void PipelineConfig::addDescriptorSetLayout(const DescriptorSetLayoutHandle &layout) { + m_DescriptorSetLayouts.push_back(layout); + } + + void PipelineConfig::addDescriptorSetLayouts(const std::vector<DescriptorSetLayoutHandle> &layouts) { + m_DescriptorSetLayouts.reserve(m_DescriptorSetLayouts.size() + layouts.size()); + + for (const auto& layout : layouts) { + m_DescriptorSetLayouts.push_back(layout); + } + } + + const std::vector<DescriptorSetLayoutHandle> &PipelineConfig::getDescriptorSetLayouts() const { + return m_DescriptorSetLayouts; + } + +} diff --git a/src/vkcv/PushConstants.cpp b/src/vkcv/PushConstants.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5492ba2e93df1eeceaf70a8dcca4841f6243cc43 --- /dev/null +++ b/src/vkcv/PushConstants.cpp @@ -0,0 +1,44 @@ +#include <vkcv/PushConstants.hpp> + +namespace vkcv { + + PushConstants::PushConstants(size_t sizePerDrawcall) : + m_typeGuard(sizePerDrawcall), + m_data() + {} + + PushConstants::PushConstants(const TypeGuard &guard) : + m_typeGuard(guard), + m_data() + {} + + size_t PushConstants::getSizePerDrawcall() const { + return m_typeGuard.typeSize(); + } + + size_t PushConstants::getFullSize() const { + return m_data.size(); + } + + size_t PushConstants::getDrawcallCount() const { + return getFullSize() / getSizePerDrawcall(); + } + + void PushConstants::clear() { + m_data.clear(); + } + + const void* PushConstants::getDrawcallData(size_t index) const { + const size_t offset = (index * getSizePerDrawcall()); + return reinterpret_cast<const void*>(m_data.data() + offset); + } + + const void* PushConstants::getData() const { + if (m_data.empty()) { + return nullptr; + } else { + return m_data.data(); + } + } + +} diff --git a/src/vkcv/QueueManager.cpp b/src/vkcv/QueueManager.cpp index d2a4d593b6a3648e9d0f01404643999ed406c26d..c818769e3ddca9b23134db1cf638f8852b554253 100644 --- a/src/vkcv/QueueManager.cpp +++ b/src/vkcv/QueueManager.cpp @@ -5,7 +5,6 @@ #include "vkcv/QueueManager.hpp" #include "vkcv/Logger.hpp" -#include "vkcv/Swapchain.hpp" namespace vkcv { diff --git a/src/vkcv/Sampler.cpp b/src/vkcv/Sampler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f122608afa6445bd59735be5c3d2cedc2a5e3d08 --- /dev/null +++ b/src/vkcv/Sampler.cpp @@ -0,0 +1,28 @@ + +#include "vkcv/Sampler.hpp" + +namespace vkcv { + + SamplerHandle samplerLinear(Core &core, bool clampToEdge) { + return core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + clampToEdge? + vkcv::SamplerAddressMode::CLAMP_TO_EDGE : + vkcv::SamplerAddressMode::REPEAT + ); + } + + SamplerHandle samplerNearest(Core &core, bool clampToEdge) { + return core.createSampler( + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerMipmapMode::NEAREST, + clampToEdge? + vkcv::SamplerAddressMode::CLAMP_TO_EDGE : + vkcv::SamplerAddressMode::REPEAT + ); + } + +} diff --git a/src/vkcv/SamplerManager.cpp b/src/vkcv/SamplerManager.cpp index 9a80635744e5a3dd0b6bd8db476cec841b1c317d..49accf6892560c1c8d3cd856cd1dd207bb214399 100644 --- a/src/vkcv/SamplerManager.cpp +++ b/src/vkcv/SamplerManager.cpp @@ -4,16 +4,29 @@ namespace vkcv { - SamplerManager::SamplerManager(const vk::Device& device) noexcept : - m_device(device), m_samplers() - {} + uint64_t SamplerManager::getIdFrom(const SamplerHandle &handle) const { + return handle.getId(); + } + + SamplerHandle SamplerManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return SamplerHandle(id, destroy); + } - SamplerManager::~SamplerManager() { - for (uint64_t id = 0; id < m_samplers.size(); id++) { - destroySamplerById(id); + void SamplerManager::destroyById(uint64_t id) { + auto& sampler = getById(id); + + if (sampler) { + getCore().getContext().getDevice().destroySampler(sampler); + sampler = nullptr; } } + SamplerManager::SamplerManager() noexcept : HandleManager<vk::Sampler, SamplerHandle>() {} + + SamplerManager::~SamplerManager() noexcept { + clear(); + } + SamplerHandle SamplerManager::createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter, SamplerMipmapMode mipmapMode, @@ -121,34 +134,15 @@ namespace vkcv { false ); - const vk::Sampler sampler = m_device.createSampler(samplerCreateInfo); + const vk::Sampler sampler = getCore().getContext().getDevice().createSampler( + samplerCreateInfo + ); - const uint64_t id = m_samplers.size(); - m_samplers.push_back(sampler); - return SamplerHandle(id, [&](uint64_t id) { destroySamplerById(id); }); + return add(sampler); } vk::Sampler SamplerManager::getVulkanSampler(const SamplerHandle &handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_samplers.size()) { - return nullptr; - } - - return m_samplers[id]; - } - - void SamplerManager::destroySamplerById(uint64_t id) { - if (id >= m_samplers.size()) { - return; - } - - auto& sampler = m_samplers[id]; - - if (sampler) { - m_device.destroySampler(sampler); - sampler = nullptr; - } + return (*this)[handle]; } } diff --git a/src/vkcv/SamplerManager.hpp b/src/vkcv/SamplerManager.hpp index 24d89f0d6af151ff009a2f2bb64953d48a9e7213..3852d3be559b679710a64176ebe96c271ca92298 100644 --- a/src/vkcv/SamplerManager.hpp +++ b/src/vkcv/SamplerManager.hpp @@ -3,34 +3,30 @@ #include <vector> #include <vulkan/vulkan.hpp> -#include "vkcv/Handles.hpp" +#include "HandleManager.hpp" + #include "vkcv/Sampler.hpp" namespace vkcv { - class Core; - /** * @brief Class to manage the creation and destruction of samplers. */ - class SamplerManager { + class SamplerManager : public HandleManager<vk::Sampler, SamplerHandle> { friend class Core; private: - vk::Device m_device; - std::vector<vk::Sampler> m_samplers; + [[nodiscard]] + uint64_t getIdFrom(const SamplerHandle& handle) const override; - explicit SamplerManager(const vk::Device& device) noexcept; + [[nodiscard]] + SamplerHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; - void destroySamplerById(uint64_t id); + void destroyById(uint64_t id) override; public: - ~SamplerManager(); - - SamplerManager(const SamplerManager& other) = delete; - SamplerManager(SamplerManager&& other) = delete; + SamplerManager() noexcept; - SamplerManager& operator=(const SamplerManager& other) = delete; - SamplerManager& operator=(SamplerManager&& other) = delete; + ~SamplerManager() noexcept override; SamplerHandle createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter, diff --git a/src/vkcv/Surface.cpp b/src/vkcv/Surface.cpp deleted file mode 100644 index 3fa601b7bed751b1eb70538a0e2cf10c0b7b50f7..0000000000000000000000000000000000000000 --- a/src/vkcv/Surface.cpp +++ /dev/null @@ -1,258 +0,0 @@ - -#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 deleted file mode 100644 index 2ca69e7d58991ee67d8e72261e1cddf65de60ed0..0000000000000000000000000000000000000000 --- a/src/vkcv/Swapchain.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include <vkcv/Swapchain.hpp> -#include <utility> - -#include <GLFW/glfw3.h> - -namespace vkcv -{ - - 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_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; - } - - const Surface& Swapchain::getSurface() const { - return m_Surface; - } - - vk::Format Swapchain::getFormat() const{ - return m_Surface.getFormat(); - } - - Swapchain Swapchain::create(const Window &window, const Context &context) { - Surface surface = Surface::create(window, context); - - vk::SwapchainKHR swapchain = surface.createVulkanSwapchain( - window, nullptr - ); - - return { context, surface, swapchain }; - } - - bool Swapchain::shouldUpdateSwapchain() const { - return m_RecreationRequired; - } - - void Swapchain::updateSwapchain(const Context &context, const Window &window) { - if (!m_RecreationRequired.exchange(false)) { - return; - } - - vk::SwapchainKHR oldSwapchain = m_Swapchain; - - m_Swapchain = m_Surface.createVulkanSwapchain( - window, oldSwapchain - ); - - if (!m_Swapchain) { - signalSwapchainRecreation(); - } - - if (oldSwapchain) { - context.getDevice().destroySwapchainKHR(oldSwapchain); - } - } - - void Swapchain::signalSwapchainRecreation() { - m_RecreationRequired = true; - } - - const vk::Extent2D& Swapchain::getExtent() const { - return m_Surface.getExtent(); - } - - Swapchain::~Swapchain() { - // needs to be destroyed by creator - } - - uint32_t Swapchain::getImageCount() const { - uint32_t imageCount = 0; - - if (vk::Result::eSuccess != m_Context->getDevice().getSwapchainImagesKHR(m_Swapchain, &imageCount, nullptr)) - return 0; - else - return imageCount; - } - - uint32_t Swapchain::getPresentQueueIndex() const { - return m_Surface.getPresentQueueIndex(); - } - -} diff --git a/src/vkcv/SwapchainManager.cpp b/src/vkcv/SwapchainManager.cpp index 369e077aabc7a5a80bc4dd668d9c6eea1277e66f..f16a4c30e9479bfcbc177e77783985d6d6a54f60 100644 --- a/src/vkcv/SwapchainManager.cpp +++ b/src/vkcv/SwapchainManager.cpp @@ -1,62 +1,309 @@ #include "SwapchainManager.hpp" -namespace vkcv { +#include <GLFW/glfw3.h> + +#include "vkcv/Core.hpp" - SwapchainManager::SwapchainManager() noexcept { +namespace vkcv { + + uint64_t SwapchainManager::getIdFrom(const SwapchainHandle &handle) const { + return handle.getId(); + } + + SwapchainHandle SwapchainManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return SwapchainHandle(id, destroy); + } + + void SwapchainManager::destroyById(uint64_t id) { + auto& swapchain = getById(id); + + if (swapchain.m_Swapchain) { + getCore().getContext().getDevice().destroySwapchainKHR(swapchain.m_Swapchain); + swapchain.m_Swapchain = nullptr; + } + + if (swapchain.m_Surface) { + getCore().getContext().getInstance().destroySurfaceKHR(swapchain.m_Surface); + swapchain.m_Surface = nullptr; + } } + + SwapchainManager::SwapchainManager() noexcept : HandleManager<SwapchainEntry, SwapchainHandle>() {} SwapchainManager::~SwapchainManager() noexcept { - for (uint64_t id = 0; id < m_swapchains.size(); id++) { - destroySwapchainById(id); + clear(); + } + + /** + * @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 + */ + static 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 + */ + static 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 + */ + static 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 + */ + static 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; + } } - m_swapchains.clear(); + // 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 + */ + static 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; + } + + static bool createVulkanSwapchain(const Context& context, + const Window &window, + SwapchainEntry& entry) { + const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice(); + const vk::Device& device = context.getDevice(); + + entry.m_Extent = chooseExtent(physicalDevice, entry.m_Surface, window); + + if ((entry.m_Extent.width < MIN_SURFACE_SIZE) || (entry.m_Extent.height < MIN_SURFACE_SIZE)) { + return false; + } + + vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, entry.m_Surface); + vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, entry.m_Surface); + uint32_t chosenImageCount = chooseImageCount(physicalDevice, entry.m_Surface); + + entry.m_Format = chosenSurfaceFormat.format; + entry.m_ColorSpace = chosenSurfaceFormat.colorSpace; + + vk::SwapchainCreateInfoKHR swapchainCreateInfo ( + vk::SwapchainCreateFlagsKHR(), + entry.m_Surface, + chosenImageCount, + entry.m_Format, + entry.m_ColorSpace, + entry.m_Extent, + 1, + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage, + vk::SharingMode::eExclusive, + 0, + nullptr, + vk::SurfaceTransformFlagBitsKHR::eIdentity, + vk::CompositeAlphaFlagBitsKHR::eOpaque, + chosenPresentMode, + true, + entry.m_Swapchain + ); + + entry.m_Swapchain = device.createSwapchainKHR(swapchainCreateInfo); + return true; } SwapchainHandle SwapchainManager::createSwapchain(Window &window) { - const uint64_t id = m_swapchains.size(); - - Swapchain swapchain = Swapchain::create(window, *m_context); - - m_swapchains.push_back(swapchain); - SwapchainHandle swapchainHandle = SwapchainHandle(id, [&](uint64_t id) { destroySwapchainById(id); }); - window.m_swapchainHandle = swapchainHandle; - return swapchainHandle; + const vk::Instance& instance = getCore().getContext().getInstance(); + const vk::PhysicalDevice& physicalDevice = getCore().getContext().getPhysicalDevice(); + + vk::SurfaceKHR surfaceHandle; + if (!createVulkanSurface(window.getWindow(), instance, physicalDevice, surfaceHandle)) { + return {}; + } + + uint32_t presentQueueIndex = QueueManager::checkSurfaceSupport(physicalDevice, surfaceHandle); + + const vk::Extent2D extent = chooseExtent(physicalDevice, surfaceHandle, window); + const vk::SurfaceFormatKHR format = chooseSurfaceFormat(physicalDevice, surfaceHandle); + + SwapchainEntry entry { + nullptr, + false, + + surfaceHandle, + presentQueueIndex, + extent, + format.format, + format.colorSpace + }; + + if (!createVulkanSwapchain(getCore().getContext(), window, entry)) { + instance.destroySurfaceKHR(surfaceHandle); + return {}; + } + + window.m_swapchainHandle = add(entry); + return window.m_swapchainHandle; } - Swapchain& SwapchainManager::getSwapchain(const SwapchainHandle& handle) { - return m_swapchains[handle.getId()]; + SwapchainEntry& SwapchainManager::getSwapchain(const SwapchainHandle& handle) { + return (*this)[handle]; } - - void SwapchainManager::destroySwapchainById(uint64_t id) { - - if (id >= m_swapchains.size()) { - vkcv_log(LogLevel::ERROR, "Invalid id"); + + bool SwapchainManager::shouldUpdateSwapchain(const SwapchainHandle &handle) const { + return (*this)[handle].m_RecreationRequired; + } + + void SwapchainManager::updateSwapchain(const SwapchainHandle &handle, const Window &window) { + auto& swapchain = (*this)[handle]; + + if (!swapchain.m_RecreationRequired) { return; + } else { + swapchain.m_RecreationRequired = false; } - Swapchain &swapchain = m_swapchains[id]; - - if (swapchain.m_Swapchain) { - m_context->getDevice().destroySwapchainKHR(swapchain.m_Swapchain); - swapchain.m_Swapchain = nullptr; - } - if (swapchain.m_Surface.m_Handle) { - m_context->getInstance().destroySurfaceKHR(swapchain.m_Surface.m_Handle); - swapchain.m_Surface.m_Handle = nullptr; + vk::SwapchainKHR oldSwapchain = swapchain.m_Swapchain; + + if (createVulkanSwapchain(getCore().getContext(), window, swapchain)) { + if (oldSwapchain) { + getCore().getContext().getDevice().destroySwapchainKHR(oldSwapchain); + } + } else { + signalRecreation(handle); } } - + void SwapchainManager::signalRecreation(const SwapchainHandle& handle) { - m_swapchains[handle.getId()].signalSwapchainRecreation(); + (*this)[handle].m_RecreationRequired = true; } - - std::vector<vk::Image> SwapchainManager::getSwapchainImages(const SwapchainHandle& handle) { - return m_context->getDevice().getSwapchainImagesKHR(m_swapchains[handle.getId()].getSwapchain()); + + vk::Format SwapchainManager::getFormat(const SwapchainHandle &handle) const { + return (*this)[handle].m_Format; + } + + uint32_t SwapchainManager::getImageCount(const SwapchainHandle &handle) const { + auto& swapchain = (*this)[handle]; + + uint32_t imageCount; + if (vk::Result::eSuccess != getCore().getContext().getDevice().getSwapchainImagesKHR(swapchain.m_Swapchain, + &imageCount, + nullptr)) { + return 0; + } else { + return imageCount; + } + } + + const vk::Extent2D &SwapchainManager::getExtent(const SwapchainHandle &handle) const { + return (*this)[handle].m_Extent; + } + + uint32_t SwapchainManager::getPresentQueueIndex(const SwapchainHandle &handle) const { + return (*this)[handle].m_PresentQueueIndex; + } + + vk::ColorSpaceKHR SwapchainManager::getSurfaceColorSpace(const SwapchainHandle &handle) const { + return (*this)[handle].m_ColorSpace; + } + + std::vector<vk::Image> SwapchainManager::getSwapchainImages(const SwapchainHandle& handle) const { + return getCore().getContext().getDevice().getSwapchainImagesKHR((*this)[handle].m_Swapchain); } std::vector<vk::ImageView> SwapchainManager::createSwapchainImageViews(SwapchainHandle& handle) { std::vector<vk::Image> images = getSwapchainImages(handle); - Swapchain &swapchain = m_swapchains[handle.getId()]; + auto& swapchain = (*this)[handle]; std::vector<vk::ImageView> imageViews; imageViews.reserve(images.size()); @@ -74,12 +321,13 @@ namespace vkcv { vk::ImageViewCreateFlags(), image, vk::ImageViewType::e2D, - swapchain.getFormat(), + swapchain.m_Format, componentMapping, subResourceRange); - imageViews.push_back(m_context->getDevice().createImageView(imageViewCreateInfo)); + imageViews.push_back(getCore().getContext().getDevice().createImageView(imageViewCreateInfo)); } + return imageViews; } } \ No newline at end of file diff --git a/src/vkcv/SwapchainManager.hpp b/src/vkcv/SwapchainManager.hpp index 285641db25f98d1e3dd8d8ed1375fa27e7db5708..d9ba37aacaea1adc2587534e444a178cb701c95e 100644 --- a/src/vkcv/SwapchainManager.hpp +++ b/src/vkcv/SwapchainManager.hpp @@ -1,35 +1,55 @@ #pragma once +/** + * @authors Tobias Frisch + * @file vkcv/SwapchainManager.hpp + * @brief Class to manage the swapchains and their surfaces. + */ +#include <atomic> #include <vector> -#include <GLFW/glfw3.h> +#include <vulkan/vulkan.hpp> -#include "WindowManager.hpp" -#include "vkcv/Swapchain.hpp" -#include "vkcv/Handles.hpp" +#include "vkcv/Window.hpp" + +#include "HandleManager.hpp" namespace vkcv { - class Core; + const uint32_t MIN_SURFACE_SIZE = 2; + + /** + * @brief Structure to handle swapchains. + */ + struct SwapchainEntry { + vk::SwapchainKHR m_Swapchain; + bool m_RecreationRequired; + + vk::SurfaceKHR m_Surface; + uint32_t m_PresentQueueIndex; + vk::Extent2D m_Extent; + vk::Format m_Format; + vk::ColorSpaceKHR m_ColorSpace; + }; /** * @brief Class to manage the creation, destruction and * allocation of swapchains. */ - class SwapchainManager { + class SwapchainManager : public HandleManager<SwapchainEntry, SwapchainHandle> { friend class Core; - - friend class WindowManager; - private: - std::vector<Swapchain> m_swapchains; - - Context *m_context; - + [[nodiscard]] + uint64_t getIdFrom(const SwapchainHandle& handle) const override; + + [[nodiscard]] + SwapchainHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + /** - * destroys a specific swapchain by a given id - * @param id of the swapchain to be destroyed + * @brief Destroys a specific swapchain by a given id + * + * @param[in] id ID of the swapchain to be destroyed */ - void destroySwapchainById(uint64_t id); + void destroyById(uint64_t id) override; public: SwapchainManager() noexcept; @@ -37,15 +57,7 @@ namespace vkcv { /** * destroys every swapchain */ - ~SwapchainManager() noexcept; - - SwapchainManager(SwapchainManager &&other) = delete; - - SwapchainManager(const SwapchainManager &other) = delete; - - SwapchainManager &operator=(SwapchainManager &&other) = delete; - - SwapchainManager &operator=(const SwapchainManager &other) = delete; + ~SwapchainManager() noexcept override; /** * creates a swapchain and returns the handle @@ -59,27 +71,96 @@ namespace vkcv { * @return the reference of the swapchain */ [[nodiscard]] - Swapchain &getSwapchain(const SwapchainHandle& handle); - + SwapchainEntry& getSwapchain(const SwapchainHandle& handle); + + /** + * @brief Checks whether the swapchain needs to be recreated. + * + * @param[in] handle Swapchain handle + * @return True, if the swapchain should be updated, + * otherwise false. + */ + bool shouldUpdateSwapchain(const SwapchainHandle& handle) const; + + /** + * @brief Updates and recreates the swapchain. + * + * @param[in] handle Swapchain handle + * @param[in] window that the new swapchain gets bound to + */ + void updateSwapchain(const SwapchainHandle& handle, const Window &window); + /** - * sets the recreation flag fot the swapchain - * @param handle of the swapchain that should be recreated + * @brief Signals the swapchain to be recreated. + * + * @param[in] handle Swapchain handle */ void signalRecreation(const SwapchainHandle& handle); + + /** + * @brief Returns the image format for the current surface + * of the swapchain. + * + * @param[in] handle Swapchain handle + * @return Swapchain image format + */ + [[nodiscard]] + vk::Format getFormat(const SwapchainHandle& handle) const; + + /** + * @brief Returns the amount of images for the swapchain. + * + * @param[in] handle Swapchain handle + * @return Number of images + */ + uint32_t getImageCount(const SwapchainHandle& handle) const; + + /** + * @brief Returns the extent from the current surface of + * the swapchain. + * + * @param[in] handle Swapchain handle + * @return Extent of the swapchains surface + */ + [[nodiscard]] + const vk::Extent2D& getExtent(const SwapchainHandle& handle) const; + + /** + * @brief Returns the present queue index to be used with + * the swapchain and its current surface. + * + * @param[in] handle Swapchain handle + * @return Present queue family index + */ + [[nodiscard]] + uint32_t getPresentQueueIndex(const SwapchainHandle& handle) const; + + /** + * @brief Returns the color space of the surface from + * a swapchain. + * + * @param[in] handle Swapchain handle + * @return Color space + */ + [[nodiscard]] + vk::ColorSpaceKHR getSurfaceColorSpace(const SwapchainHandle& handle) const; /** * gets the swapchain images * @param handle of the swapchain * @return a vector of the swapchain images */ - std::vector<vk::Image> getSwapchainImages(const SwapchainHandle& handle); + [[nodiscard]] + std::vector<vk::Image> getSwapchainImages(const SwapchainHandle& handle) const; /** * creates the swapchain imageViews for the swapchain * @param handle of the swapchain which ImageViews should be created * @return a ov ImageViews of the swapchain */ + [[nodiscard]] 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 deleted file mode 100644 index 8bd53c85e8cdede55d5b1db71d44bf483e24acb1..0000000000000000000000000000000000000000 --- a/src/vkcv/SyncResources.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "vkcv/SyncResources.hpp" - -namespace vkcv { - SyncResources createSyncResources(const vk::Device& device) { - SyncResources resources; - - const vk::SemaphoreCreateFlags semaphoreFlags = vk::SemaphoreCreateFlagBits(); - const vk::SemaphoreCreateInfo semaphoreInfo(semaphoreFlags); - resources.renderFinished = device.createSemaphore(semaphoreInfo, nullptr, {}); - resources.swapchainImageAcquired = device.createSemaphore(semaphoreInfo); - - resources.presentFinished = createFence(device); - - return resources; - } - - void destroySyncResources(const vk::Device& device, const SyncResources& resources) { - device.destroySemaphore(resources.renderFinished); - device.destroySemaphore(resources.swapchainImageAcquired); - device.destroyFence(resources.presentFinished); - } - - vk::Fence createFence(const vk::Device& device) { - const vk::FenceCreateFlags fenceFlags = vk::FenceCreateFlagBits(); - vk::FenceCreateInfo fenceInfo(fenceFlags); - return device.createFence(fenceInfo, nullptr, {}); - } - - void waitForFence(const vk::Device& device, const vk::Fence& fence) { - const auto result = device.waitForFences(fence, true, UINT64_MAX); - assert(result == vk::Result::eSuccess); - } -} \ No newline at end of file diff --git a/src/vkcv/TypeGuard.cpp b/src/vkcv/TypeGuard.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31a758913e4fea5bdef5d91e9519b67eefdd1e93 --- /dev/null +++ b/src/vkcv/TypeGuard.cpp @@ -0,0 +1,93 @@ +#include <vkcv/TypeGuard.hpp> + +#include <vkcv/Logger.hpp> +#include <string.h> + +namespace vkcv { + +#ifndef NDEBUG + bool TypeGuard::checkType(const char* name, size_t hash, size_t size) const { + if (!checkTypeSize(size)) { + return false; + } + + if ((!m_typeName) || (!name)) { + return true; + } + + if (m_typeHash != hash) { + vkcv_log( + LogLevel::WARNING, + "Hash (%lu) does not match the specified hash of the type guard (%lu)", + hash, + m_typeHash + ); + + return false; + } + + if (strcmp(m_typeName, name) != 0) { + vkcv_log( + LogLevel::WARNING, + "Name (%s) does not match the specified name of the type guard (%s)", + name, + m_typeName + ); + + return false; + } else { + return true; + } + } +#endif + + bool TypeGuard::checkTypeSize(size_t size) const { + if (m_typeSize != size) { + vkcv_log( + LogLevel::WARNING, + "Size (%lu) does not match the specified size of the type guard (%lu)", + size, + m_typeSize + ); + + return false; + } else { + return true; + } + } + + TypeGuard::TypeGuard(size_t size) : +#ifndef NDEBUG + m_typeName(nullptr), m_typeHash(0), +#endif + m_typeSize(size) + {} + + TypeGuard::TypeGuard(const std::type_info &info, size_t size) : +#ifndef NDEBUG + m_typeName(info.name()), m_typeHash(info.hash_code()), +#endif + m_typeSize(size) + {} + + bool TypeGuard::operator==(const TypeGuard &other) const { +#ifndef NDEBUG + return checkType(other.m_typeName, other.m_typeHash, other.m_typeSize); +#else + return checkTypeSize(other.m_typeSize); +#endif + } + + bool TypeGuard::operator!=(const TypeGuard &other) const { +#ifndef NDEBUG + return !checkType(other.m_typeName, other.m_typeHash, other.m_typeSize); +#else + return !checkTypeSize(other.m_typeSize); +#endif + } + + size_t TypeGuard::typeSize() const { + return m_typeSize; + } + +} diff --git a/src/vkcv/VertexData.cpp b/src/vkcv/VertexData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bea3b700549f2951987f148f537461c9ca7f9041 --- /dev/null +++ b/src/vkcv/VertexData.cpp @@ -0,0 +1,42 @@ + +#include "vkcv/VertexData.hpp" + +namespace vkcv { + + VertexBufferBinding vertexBufferBinding(const BufferHandle &buffer, size_t offset) { + VertexBufferBinding binding (buffer, offset); + return binding; + } + + VertexData::VertexData(const std::vector<VertexBufferBinding> &bindings) + : m_bindings(bindings), + m_indices(), + m_indexBitCount(IndexBitCount::Bit16), + m_count(0) {} + + const std::vector<VertexBufferBinding> &VertexData::getVertexBufferBindings() const { + return m_bindings; + } + + void VertexData::setIndexBuffer(const BufferHandle &indices, IndexBitCount indexBitCount) { + m_indices = indices; + m_indexBitCount = indexBitCount; + } + + const BufferHandle &VertexData::getIndexBuffer() const { + return m_indices; + } + + IndexBitCount VertexData::getIndexBitCount() const { + return m_indexBitCount; + } + + void VertexData::setCount(size_t count) { + m_count = count; + } + + size_t VertexData::getCount() const { + return m_count; + } + +} diff --git a/src/vkcv/VertexLayout.cpp b/src/vkcv/VertexLayout.cpp index 73e3885bf8f97854712d5b202123c7f7202042d1..1409fee0e485eb389fbd4697a4da98c0cdae2813 100644 --- a/src/vkcv/VertexLayout.cpp +++ b/src/vkcv/VertexLayout.cpp @@ -43,5 +43,16 @@ namespace vkcv { binding.stride = offset; return binding; } - + + VertexBindings createVertexBindings(const VertexAttachments &attachments) { + VertexBindings bindings; + bindings.reserve(attachments.size()); + + for (uint32_t i = 0; i < attachments.size(); i++) { + bindings.push_back(createVertexBinding(i, { attachments[i] })); + } + + return bindings; + } + } \ No newline at end of file diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp index f6f9aa6950b767c31bdd1608782c5b7b7f7071ed..8787053dd046d625961cc26c995fec28dc43d74b 100644 --- a/src/vkcv/Window.cpp +++ b/src/vkcv/Window.cpp @@ -284,7 +284,7 @@ namespace vkcv { return window; } - SwapchainHandle Window::getSwapchainHandle() const { + SwapchainHandle Window::getSwapchain() const { return m_swapchainHandle; } } diff --git a/src/vkcv/WindowManager.cpp b/src/vkcv/WindowManager.cpp index 3179b219e9e93905d7202cf8e11dbbf0e019020f..930c5f3a1d5b6c405f83fc94fdc9998efc9c1fea 100644 --- a/src/vkcv/WindowManager.cpp +++ b/src/vkcv/WindowManager.cpp @@ -2,26 +2,40 @@ namespace vkcv { - WindowManager::WindowManager() noexcept { + uint64_t WindowManager::getIdFrom(const WindowHandle &handle) const { + return handle.getId(); } + + WindowHandle WindowManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return WindowHandle(id, destroy); + } + + void WindowManager::destroyById(uint64_t id) { + auto& window = getById(id); - WindowManager::~WindowManager() noexcept { - for (uint64_t id = 0; id < m_windows.size(); id++) { - destroyWindowById(id); + if (window) { + delete window; + window = nullptr; } - - m_windows.clear(); } + + WindowManager::WindowManager() noexcept : HandleManager<Window *, WindowHandle>() {} - WindowHandle WindowManager::createWindow( - SwapchainManager &swapchainManager, - const char *applicationName, - uint32_t windowWidth, - uint32_t windowHeight, - bool resizeable) { - const uint64_t id = m_windows.size(); + WindowManager::~WindowManager() noexcept { + clear(); + } - auto window = new Window(applicationName, windowWidth, windowHeight, resizeable); + WindowHandle WindowManager::createWindow(SwapchainManager &swapchainManager, + const char *applicationName, + uint32_t windowWidth, + uint32_t windowHeight, + bool resizeable) { + auto window = new Window( + applicationName, + static_cast<int>(windowWidth), + static_cast<int>(windowHeight), + resizeable + ); SwapchainHandle swapchainHandle = swapchainManager.createSwapchain(*window); @@ -30,27 +44,27 @@ namespace vkcv { // copy handle because it would run out of scope and be invalid swapchainManager.signalRecreation(handle); }); + window->m_resizeHandle = resizeHandle; } - m_windows.push_back(window); - return WindowHandle(id, [&](uint64_t id) { destroyWindowById(id); }); + return add(window); } - Window &WindowManager::getWindow(const WindowHandle handle) const { - return *m_windows[handle.getId()]; + Window &WindowManager::getWindow(const WindowHandle& handle) const { + return *(*this)[handle]; } - - void WindowManager::destroyWindowById(uint64_t id) { - - if (id >= m_windows.size()) { - vkcv_log(LogLevel::ERROR, "Invalid id"); - return; - } - - if (m_windows[id] != nullptr) { - delete m_windows[id]; - m_windows[id] = nullptr; + + std::vector<WindowHandle> WindowManager::getWindowHandles() const { + std::vector<WindowHandle> handles; + + for (size_t id = 0; id < getCount(); id++) { + if (getById(id)->isOpen()) { + handles.push_back(WindowHandle(id)); + } } + + return handles; } + } \ No newline at end of file diff --git a/src/vkcv/WindowManager.hpp b/src/vkcv/WindowManager.hpp index 81658c241174c62359457c04e143accf07253edb..172cec2a1c9ee5a5c437c8e25f4daec4965fa9e9 100644 --- a/src/vkcv/WindowManager.hpp +++ b/src/vkcv/WindowManager.hpp @@ -5,32 +5,31 @@ #include <GLFW/glfw3.h> #include "vkcv/Window.hpp" -#include "vkcv/Handles.hpp" + +#include "HandleManager.hpp" #include "SwapchainManager.hpp" namespace vkcv { - - class Context; - - class SwapchainManager; /** * @brief Class to manage the windows of applications. */ - class WindowManager { + class WindowManager : public HandleManager<Window*, WindowHandle> { friend class Core; private: + [[nodiscard]] + uint64_t getIdFrom(const WindowHandle& handle) const override; + + [[nodiscard]] + WindowHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + /** - * 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 + * Destroys a specific window by a given id. + * + * @param[in] id ID of the window to be destroyed */ - void destroyWindowById(uint64_t id); + void destroyById(uint64_t id) override; public: WindowManager() noexcept; @@ -38,15 +37,7 @@ namespace vkcv { /** * destroys every window */ - ~WindowManager() noexcept; - - WindowManager(WindowManager &&other) = delete; - - WindowManager(const WindowManager &other) = delete; - - WindowManager &operator=(WindowManager &&other) = delete; - - WindowManager &operator=(const WindowManager &other) = delete; + ~WindowManager() noexcept override; /** * creates a window and returns it's handle @@ -57,7 +48,9 @@ namespace vkcv { * @param resizeable if the window is resizable * @return window handle */ - WindowHandle createWindow(SwapchainManager &swapchainManager, const char *applicationName, uint32_t windowWidth, + WindowHandle createWindow(SwapchainManager &swapchainManager, + const char *applicationName, + uint32_t windowWidth, uint32_t windowHeight, bool resizeable); @@ -66,7 +59,16 @@ namespace vkcv { * @return the reference of the window */ [[nodiscard]] - Window &getWindow(const WindowHandle handle) const; + Window &getWindow(const WindowHandle& handle) const; + + /** + * Returns a list of window handles for current active + * and open windows. + * + * @return List of window handles + */ + [[nodiscard]] + std::vector<WindowHandle> getWindowHandles() const; };