Skip to content
Snippets Groups Projects
Core.hpp 30.55 KiB
#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 "BufferTypes.hpp"
#include "Context.hpp"
#include "Window.hpp"
#include "PassConfig.hpp"
#include "Handles.hpp"
#include "Image.hpp"
#include "BlitDownsampler.hpp"
#include "GraphicsPipelineConfig.hpp"
#include "ComputePipelineConfig.hpp"
#include "Result.hpp"
#include "Sampler.hpp"
#include "DescriptorWrites.hpp"
#include "Event.hpp"
#include "DrawcallRecording.hpp"
#include "EventFunctionTypes.hpp"
#include "DispatchSize.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 DescriptorSetLayoutManager;
	class DescriptorSetManager;
    class BufferManager;
    class SamplerManager;
    class ImageManager;
	class CommandStreamManager;
	class WindowManager;
	class SwapchainManager;

	/**
	 * @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
         */
        explicit Core(Context &&context) 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_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;

		/**
		 * 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[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);
		
		/**
		 * 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[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]]
        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);
		
		/**
		 * @brief Returns the default blit-downsampler.
		 *
		 * @return Blit-downsampler
		 */
		[[nodiscard]]
		Downsampler& getDownsampler();

        /**
         * 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);
	
		/**
         * @brief Returns the image format for the current surface
         * of the swapchain.
         *
         * @param[in] handle Swapchain handle
         * @return Swapchain image format
         */
		[[nodiscard]]
		vk::Format getSwapchainFormat(const SwapchainHandle& swapchain) const;
	
		/**
		 * @brief Returns the amount of images for the swapchain.
		 *
		 * @param[in] handle Swapchain handle
		 * @return Number of images
		*/
		[[nodiscard]]
		uint32_t getSwapchainImageCount(const SwapchainHandle& swapchain) const;
	
		/**
         * @brief Returns the extent from the current surface of
         * the swapchain.
         *
         * @param[in] handle Swapchain handle
         * @return Extent of the swapchains surface
         */
		[[nodiscard]]
		vk::Extent2D getSwapchainExtent(const SwapchainHandle& swapchain) const;

		/**
		 * @brief Returns the image width.
		 *
		 * @param image Image handle
		 * @return imageWidth
		 */
        [[nodiscard]]
        uint32_t getImageWidth(const ImageHandle &image);

        /**
         * @brief Returns the image height.
         *
         * @param[in] image Image handle
         * @return imageHeight
         */
        [[nodiscard]]
        uint32_t getImageHeight(const ImageHandle &image);
	
		/**
         * @brief Returns the image depth.
         *
         * @param[in] image Image handle
         * @return imageDepth
         */
		[[nodiscard]]
		uint32_t getImageDepth(const ImageHandle &image);

        /**
         * @brief Returns the image format of the image.
         *
         * @param[in] image Image handle
         * @return imageFormat
         */
		[[nodiscard]]
		vk::Format getImageFormat(const ImageHandle &image);
	
		/**
		 * @brief Returns whether the image supports storage or not.
		 *
		 * @param[in] image Image handle
		 * @return True, if the image supports storage, otherwise false.
		 */
		[[nodiscard]]
		bool isImageSupportingStorage(const ImageHandle& image);
		
		/**
		 * @brief Returns the images amount of mip levels.
		 *
		 * @param[in] image Image handle
		 * @return Amount of mip levels
		 */
		[[nodiscard]]
		uint32_t getImageMipLevels(const ImageHandle &image);
		
		/**
		 * @brief Returns the images amount of array layers.
		 *
		 * @param[in] image Image handle
		 * @return Amount of array layers
		 */
		[[nodiscard]]
		uint32_t getImageArrayLayers(const ImageHandle &image);

		/**
		 * @brief Creates a descriptor set layout handle by a set of descriptor bindings.
		 *
		 * @param[in] bindings Descriptor bindings
		 * @return Descriptor set layout handle
		 */
		[[nodiscard]]
		DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings);

		/**
		 * @brief Creates a new descriptor set
		 * 
		 * @param[in] layout Handle to the layout that the descriptor set will use
		 * @return Handle that represents the descriptor set
		 */
        [[nodiscard]]
        DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layout);

		/**
		 * @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 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 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 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 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 GraphicsPipelineHandle                        &pipelineHandle,
				const PushConstants                                 &pushConstantData,
                const vkcv::DescriptorSetHandle                     &compiledDescriptorSet,
				const vkcv::Mesh                                    &compiledMesh,
				const std::vector<ImageHandle>                      &renderTargets,
				const BufferHandle  								&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 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 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 dispatchSize How many work groups are dispatched
		 * @param descriptorSetUsages Descriptor set bindings of the dispatch
		 * @param pushConstants Push constant data for the dispatch
		 */
		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. 
		 * 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 );

		/**
		 * @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   &stream,
			const RecordCommandFunction &record,
			const FinishCommandFunction &finish);

		/**
		 * @brief Submit command stream to GPU for actual execution
		 * 
		 * @param[in] handle Command stream to submit
		 * @param[in] signalRendering Flag to specify if the command stream finishes rendering
		 */
		void submitCommandStream(const CommandStreamHandle& stream,
								 bool signalRendering = true);

		/**
		 * @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[in] cmdStream Handle of the command stream to record the preparation commands to
		 * @param[in] image Handle of the image to prepare
		 * @param[in] mipLevelCount Count of mip levels to prepare
		 * @param[in] mipLevelOffset Offset to start preparing mip levels
		 */
		void prepareImageForSampling(const CommandStreamHandle& cmdStream,
									 const ImageHandle& image,
									 uint32_t mipLevelCount = 0,
									 uint32_t mipLevelOffset = 0);

		/**
		 * @brief Prepare image for use as a storage image.
		 * Handles internal state such as image format, also acts as a memory barrier
		 *
		 * @param[in] cmdStream Handle of the command stream to record the preparation commands to
		 * @param[in] image Handle of the image to prepare
		 * @param[in] mipLevelCount Count of mip levels to prepare
		 * @param[in] mipLevelOffset Offset to start preparing mip levels
		 */
		void prepareImageForStorage(const CommandStreamHandle& cmdStream,
									const ImageHandle& image,
									uint32_t mipLevelCount = 0,
									uint32_t mipLevelOffset = 0);
		
		/**
		 * @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);
		
    };
}