#pragma once /** * @authors Alexander Gauggel, Tobias Frisch, Sebastian Gaida, Artur Wasmut, Lars Hoerttrich, * Mara Vogt, Mark Mints, Simeon Hermann, Alex Laptop, Katharina Krämer, Vanessa Karolek * @file vkcv/Core.hpp * @brief Handling of global states regarding dependencies. */ #include <memory> #include <vulkan/vulkan.hpp> #include "Context.hpp" #include "Swapchain.hpp" #include "Window.hpp" #include "PassConfig.hpp" #include "Handles.hpp" #include "Buffer.hpp" #include "Image.hpp" #include "GraphicsPipelineConfig.hpp" #include "ComputePipelineConfig.hpp" #include "CommandResources.hpp" #include "SyncResources.hpp" #include "Result.hpp" #include "vkcv/DescriptorConfig.hpp" #include "Sampler.hpp" #include "DescriptorWrites.hpp" #include "Event.hpp" #include "DrawcallRecording.hpp" #include "CommandRecordingFunctionTypes.hpp" #define VKCV_FRAMEWORK_NAME "VkCV" #define VKCV_FRAMEWORK_VERSION (VK_MAKE_VERSION(0, 1, 0)) namespace vkcv { // forward declarations class PassManager; class GraphicsPipelineManager; class ComputePipelineManager; class DescriptorManager; class BufferManager; class SamplerManager; class ImageManager; class CommandStreamManager; class WindowManager; class SwapchainManager; struct SubmitInfo { QueueType queueType; std::vector<vk::Semaphore> waitSemaphores; std::vector<vk::Semaphore> signalSemaphores; }; /** * @brief Class to handle the core functionality of the framework. * * The class handles the core functionality of the framework with most * calls addressing resource management via more simplified abstraction. */ class Core final { private: /** * Constructor of #Core requires an @p context. * * @param context encapsulates various Vulkan objects */ Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept; // explicit destruction of default constructor Core() = delete; Result acquireSwapchainImage(const SwapchainHandle &swapchainHandle); 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; /** * Sets up swapchain images * @param handle Handle of swapchain */ void setSwapchainImages(SwapchainHandle handle); public: /** * Destructor of #Core destroys the Vulkan objects contained in the core's context. */ ~Core() noexcept; /** * Copy-constructor of #Core is deleted! * * @param other Other instance of #Context */ Core(const Core& other) = delete; /** * Move-constructor of #Core uses default behavior! * * @param other Other instance of #Context */ Core(Core &&other) = delete; // move-ctor /** * Copy assignment operator of #Core is deleted! * * @param other Other instance of Context * @return Reference to itself */ Core & operator=(const Core &other) = delete; /** * Move assignment operator of #Core uses default behavior! * * @param other Other instance of Context * @return Reference to itself */ Core & operator=(Core &&other) = delete; /** * Returns the context of a Core instance. * * @return Current Context */ [[nodiscard]] const Context &getContext() const; /** * Creates a #Core with given @p applicationName and @p applicationVersion for your application. * * It is also possible to require a specific amount of queues, ask for specific queue-flags or * extensions. This function will take care of the required arguments as best as possible. * * To pass a valid version for your application, you should use #VK_MAKE_VERSION(). * * @param[in] applicationName Name of the application * @param[in] applicationVersion Version of the application * @param[in] queueFlags (optional) Requested flags of queues * @param[in] instanceExtensions (optional) Requested instance extensions * @param[in] deviceExtensions (optional) Requested device extensions * @return New instance of #Context */ static Core create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags = {}, const Features& features = {}, const std::vector<const char *>& instanceExtensions = {}); /** * Creates a basic vulkan graphics pipeline using @p config from the pipeline config class and returns it using the @p handle. * Fixed Functions for pipeline are set with standard values. * * @param config a pipeline config object from the pipeline config class * @param handle a handle to return the created vulkan handle * @return True if pipeline creation was successful, False if not */ [[nodiscard]] GraphicsPipelineHandle createGraphicsPipeline(const GraphicsPipelineConfig &config); /** * Creates a basic vulkan compute pipeline using @p shader program and returns it using the @p handle. * Fixed Functions for pipeline are set with standard values. * * @param config Contains the compiles compute shader and the corresponding descriptor set layout * @return True if pipeline creation was successful, False if not */ [[nodiscard]] ComputePipelineHandle createComputePipeline(const ComputePipelineConfig &config); /** * 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 * @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) { return Buffer<T>::create(m_BufferManager.get(), type, count, memoryType, supportIndirect); } /** * 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 * @return Sampler handle */ [[nodiscard]] SamplerHandle createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter, SamplerMipmapMode mipmapMode, SamplerAddressMode addressMode, float mipLodBias = 0.0f, SamplerBorderColor borderColor = SamplerBorderColor::INT_ZERO_OPAQUE); /** * Creates an #Image with a given format, width, height and depth. * * @param format Image format * @param width Image width * @param height Image height * @param depth Image depth * @return Image-Object */ [[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); /** * Creates a new window and returns it's handle * @param applicationName window name * @param windowWidth * @param windowHeight * @param resizeable resizeability bool * @return windowHandle */ [[nodiscard]] WindowHandle createWindow( const char *applicationName, uint32_t windowWidth, uint32_t windowHeight, bool resizeable); /** * Getter for window reference * @param handle of the window * @return the window */ [[nodiscard]] Window& getWindow(const WindowHandle& handle ); /** * Gets the swapchain of the current focused window * @return swapchain */ [[nodiscard]] Swapchain& getSwapchainOfCurrentWindow(); /** * Returns the swapchain reference * @param handle of the swapchain * @return swapchain */ [[nodiscard]] Swapchain& getSwapchain(const SwapchainHandle &handle); /** * Gets the swapchain handle from the window * @param handle of the window * @return the swapchain from getSwapchain( SwapchainHandle ) */ [[nodiscard]] Swapchain& getSwapchain(const WindowHandle &handle); /** * Returns the image width * @param image handle * @return imageWidth */ [[nodiscard]] uint32_t getImageWidth(const ImageHandle &image); /** * Returns the image height * @param image handle * @return imageHeight */ [[nodiscard]] uint32_t getImageHeight(const ImageHandle &image); /** * Returns the image format of the image * @param image handle * @return imageFormat */ [[nodiscard]] vk::Format getImageFormat(const ImageHandle &image); /** * @brief Returns the images amount of mip levels. * * @param image Image handle * @return Amount of mip levels */ [[nodiscard]] uint32_t getImageMipLevels(const ImageHandle &image); /** * @brief Creates a descriptor set layout handle by a set of descriptor bindings. * * @param bindings Descriptor bindings * @return Descriptor set layout handle */ [[nodiscard]] DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); /** * @brief Returns the descriptor set layout of a descriptor set layout handle. * * @param handle Descriptor set layout handle * @return Descriptor set layout */ DescriptorSetLayout getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const; /** * @brief Creates a new descriptor set * * @param layoutHandle Handle to the layout that the descriptor set will use * @return Handle that represents the descriptor set */ [[nodiscard]] DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layoutHandle); /** * @brief Writes resources bindings to a descriptor set * * @param handle Handle of the descriptor set * @param writes Struct containing the resource bindings to be written * must be compatible with the descriptor set's layout */ void writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites& writes); /** * @brief Returns information about a descriptor set * * @param handle Handle of the descriptor set * @return Struct containing the descriptor set's vulkan handle, layout handle and descriptor pool index */ DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const; /** * @brief Start recording command buffers and increment frame index */ bool beginFrame(uint32_t& width, uint32_t& height, const WindowHandle &windowHandle); /** * @brief Records drawcalls to a command stream * * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into * @param renderpassHandle Handle of the renderpass that is used for the drawcalls * @param pipelineHandle Handle of the pipeline that is used for the drawcalls * @param pushConstants Push constants that are used for the drawcalls, ignored if constant size is set to 0 * @param drawcalls Information about each drawcall, consisting of mesh handle, descriptor set bindings and instance count * @param renderTargets Image handles that are used as render targets * @param windowHandle Window handle that is used to retrieve the corresponding swapchain */ void recordDrawcallsToCmdStream( const CommandStreamHandle& cmdStreamHandle, const PassHandle& renderpassHandle, const GraphicsPipelineHandle &pipelineHandle, const PushConstants &pushConstants, const std::vector<DrawcallInfo> &drawcalls, const std::vector<ImageHandle> &renderTargets, const WindowHandle &windowHandle); /** * @brief Records indirect drawcalls to a command stream * * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into * @param renderpassHandle Handle of the renderpass that is used for the drawcalls * @param pipelineHandle Handle of the pipeline that is used for the drawcalls * @param pushConstantData Push constants that are used for the drawcalls, ignored if constant size is set to 0 * @param compiledDescriptorSet TODO * @param compiledMesh TODO * @param drawcalls Information about each drawcall, consisting of mesh handle, descriptor set bindings and instance count * @param renderTargets Image handles that are used as render targets * @param indirectBuffer TODO * @param drawCount TODO * @param windowHandle Window handle that is used to retrieve the corresponding swapchain */ void recordIndexedIndirectDrawcallsToCmdStream( const CommandStreamHandle cmdStreamHandle, const PassHandle renderpassHandle, 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); /** * @brief Records mesh shader drawcalls to a command stream * * @param cmdStreamHandle Handle of the command stream that the drawcalls are recorded into * @param renderpassHandle Handle of the renderpass that is used for the drawcalls * @param pipelineHandle Handle of the pipeline that is used for the drawcalls * @param pushConstantData Push constants that are used for the drawcalls, ignored if constant size is set to 0 * @param drawcalls Information about each drawcall, consisting of descriptor set bindings and task shader dispatch count * @param renderTargets Image handles that are used as render targets * @param windowHandle Window handle that is used to retrieve the corresponding swapchain */ void recordMeshShaderDrawcalls( const CommandStreamHandle& cmdStreamHandle, const PassHandle& renderpassHandle, const GraphicsPipelineHandle &pipelineHandle, const PushConstants& pushConstantData, const std::vector<MeshShaderDrawcall>& drawcalls, const std::vector<ImageHandle>& renderTargets, const WindowHandle& windowHandle); /** * Records the rtx ray generation to the @p cmdStreamHandle. * Currently only supports @p closestHit, @p rayGen and @c miss shaderstages @c. * * @param cmdStreamHandle The command stream handle which receives relevant commands for drawing. * @param rtxPipeline The raytracing pipeline from the RTXModule. * @param rtxPipelineLayout The raytracing pipeline layout from the RTXModule. * @param rgenRegion The shader binding table region for ray generation shaders. * @param rmissRegion The shader binding table region for ray miss shaders. * @param rchitRegion The shader binding table region for ray closest hit shaders. * @param rcallRegion The shader binding table region for callable shaders. * @param descriptorSetUsages The descriptor set usages. * @param pushConstants The push constants. * @param windowHandle The window handle defining in which window to render. */ void 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); /** * @brief Record a compute shader dispatch into a command stream * * @param cmdStream Handle of the command stream that the dispatch is recorded into * @param computePipeline Handle of the pipeline that is used for the dispatch * @param dispatchCount How many work groups are dispatched * @param descriptorSetUsages Descriptor set bindings of the dispatch * @param pushConstants Push constant data for the dispatch */ void recordComputeDispatchToCmdStream( CommandStreamHandle cmdStream, ComputePipelineHandle computePipeline, const uint32_t dispatchCount[3], const std::vector<DescriptorSetUsage> &descriptorSetUsages, const PushConstants& pushConstants); /** * @brief Record the start of a debug label into a command stream. * Debug labels are displayed in GPU debuggers, such as RenderDoc * * @param cmdStream Handle of the command stream that the label start is recorded into * @param label Label name, which is displayed in a debugger * @param color Display color for the label in a debugger */ void recordBeginDebugLabel(const CommandStreamHandle &cmdStream, const std::string& label, const std::array<float, 4>& color); /** * @brief Record the end of a debug label into a command stream * @param cmdStream Handle of the command stream that the label end is recorded into */ void recordEndDebugLabel(const CommandStreamHandle &cmdStream); /** * @brief Record an indirect compute shader dispatch into a command stream * * @param cmdStream Handle of the command stream that the indirect dispatch is recorded into * @param computePipeline Handle of the pipeline that is used for the indirect dispatch * @param buffer GPU Buffer from which the dispatch counts are read * @param bufferArgOffset Offset into the GPU Buffer from where the dispatch counts are read * @param descriptorSetUsages Descriptor set bindings of the indirect dispatch * @param pushConstants Push constant data for the indirect dispatch */ void recordComputeIndirectDispatchToCmdStream( const CommandStreamHandle cmdStream, const ComputePipelineHandle computePipeline, const vkcv::BufferHandle buffer, const size_t bufferArgOffset, const std::vector<DescriptorSetUsage>& descriptorSetUsages, const PushConstants& pushConstants); /** * @brief End recording and present image */ 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 * * @param queueType The type of queue to which the command stream will be submitted to * @return Handle which represents the command stream */ CommandStreamHandle createCommandStream(QueueType queueType); /** * @brief Record commands to a command stream by providing a function * * @param cmdStreamHandle Handle of the command stream to record to * @param record Recording function * @param finish Finish function, called after execution of commands is finished */ void recordCommandsToStream( const CommandStreamHandle cmdStreamHandle, const RecordCommandFunction &record, const FinishCommandFunction &finish); /** * @brief Submit command stream to GPU for actual execution * * @param handle command stream to submit */ void submitCommandStream(const CommandStreamHandle& handle); /** * @brief Prepare swapchain image for presentation to screen. * Handles internal state such as image format, also acts as a memory barrier * * @param handle Handle of the command stream to record the preparation commands to */ void prepareSwapchainImageForPresent(const CommandStreamHandle& handle); /** * @brief Prepare image for use as a sampled image. * Handles internal state such as image format, also acts as a memory barrier * * @param cmdStream Handle of the command stream to record the preparation commands to * @param image Handle of the image to prepare */ void prepareImageForSampling(const CommandStreamHandle& cmdStream, const ImageHandle& image); /** * @brief Prepare image for use as a storage image. * Handles internal state such as image format, also acts as a memory barrier * * @param cmdStream Handle of the command stream to record the preparation commands to * @param image Handle of the image to prepare */ void prepareImageForStorage(const CommandStreamHandle& cmdStream, const ImageHandle& image); /** * @brief Manual trigger to record commands to prepare an image for use as an attachment * * normally layout transitions for attachments are handled by the core * however for manual vulkan use, e.g. ImGui integration, this function is exposed * this is also why the command buffer is passed directly, instead of the command stream handle * * @param cmdBuffer The vulkan command buffer to record to * @param image Handle of the image to prepare */ void prepareImageForAttachmentManually(const vk::CommandBuffer& cmdBuffer, const ImageHandle& image); /** * @brief Indicate an external change of an image's layout * * if manual vulkan work, e.g. ImGui integration, changes an image layout this function must be used * to update the internal image state * * @param image Handle of the image whose layout was changed * @param layout The current layout of the image */ void updateImageLayoutManual(const vkcv::ImageHandle& image, const vk::ImageLayout layout); /** * @brief Records a memory barrier to synchronize subsequent accesses to the image's data * * @param cmdStream Handle of the command stream to record the barrier to * @param image Handle of the image the barrier belongs to */ void recordImageMemoryBarrier(const CommandStreamHandle& cmdStream, const ImageHandle& image); /** * @brief Records a buffer barrier to synchronize subsequent accesses to the buffer's data * * @param cmdStream Handle of the command stream to record the barrier to * @param buffer Handle of the buffer the barrier belongs to */ void recordBufferMemoryBarrier(const CommandStreamHandle& cmdStream, const BufferHandle& buffer); /** * @brief Resolve a source MSAA image into a destination image for further use * * @param cmdStream Handle of the command stream to record the resolve to * @param src The MSAA image that is resolved * @param dst The target non-MSAA image that is resolved into */ void resolveMSAAImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst); /** * @return Vulkan image view of the current swapchain image */ [[nodiscard]] vk::ImageView getSwapchainImageView() const; /** * @brief Records a generic memory barrier to a command stream * * @param cmdStream Handle of the command stream the barrier is recorded to */ void recordMemoryBarrier(const CommandStreamHandle& cmdStream); /** * @brief Record a blit (bit block image transfer) of a source image into a destination image, * mip 0 is used for both * * @param cmdStream Handle of the command stream the blit operation is recorded into * @param src The source image that is read from * @param dst The destination image that is written into * @param filterType The type of interpolation that is used */ void recordBlitImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst, SamplerFilterType filterType); /** * @brief Sets a debug label to a buffer handle. * * @param handle Buffer handle * @param label Debug label */ void setDebugLabel(const BufferHandle &handle, const std::string &label); /** * @brief Sets a debug label to a pass handle. * * @param handle Pass handle * @param label Debug label */ void setDebugLabel(const PassHandle &handle, const std::string &label); /** * @brief Sets a debug label to a graphics pipeline handle. * * @param handle Graphics pipeline handle * @param label Debug label */ void setDebugLabel(const GraphicsPipelineHandle &handle, const std::string &label); /** * @brief Sets a debug label to a compute pipeline handle. * * @param handle Compute pipeline handle * @param label Debug label */ void setDebugLabel(const ComputePipelineHandle &handle, const std::string &label); /** * @brief Sets a debug label to a descriptor set handle. * * @param handle Descriptor set handle * @param label Debug label */ void setDebugLabel(const DescriptorSetHandle &handle, const std::string &label); /** * @brief Sets a debug label to a sampler handle. * * @param handle Sampler handle * @param label Debug label */ void setDebugLabel(const SamplerHandle &handle, const std::string &label); /** * @brief Sets a debug label to an image handle. * * @param handle Image handle * @param label Debug label */ void setDebugLabel(const ImageHandle &handle, const std::string &label); /** * @brief Sets a debug label to a command stream handle. * * @param handle Command stream handle * @param label Debug label */ void setDebugLabel(const CommandStreamHandle &handle, const std::string &label); }; }