#pragma once #include "vulkanobjects.h" #include #include class VulkanCompatibleDevice; class VulkanInstanceBuilder { public: VulkanInstanceBuilder(); VulkanInstanceBuilder& ApiVersionsToTry(const std::vector& versions); VulkanInstanceBuilder& RequireExtension(const std::string& extensionName); VulkanInstanceBuilder& RequireSurfaceExtensions(bool enable = true); VulkanInstanceBuilder& OptionalExtension(const std::string& extensionName); VulkanInstanceBuilder& DebugLayer(bool enable = true); std::shared_ptr Create(); private: std::vector apiVersionsToTry; std::set requiredExtensions; std::set optionalExtensions; bool debugLayer = false; }; #ifdef VK_USE_PLATFORM_WIN32_KHR class VulkanSurfaceBuilder { public: VulkanSurfaceBuilder(); VulkanSurfaceBuilder& Win32Window(HWND handle); std::shared_ptr Create(std::shared_ptr instance); private: HWND hwnd = {}; }; #endif class VulkanDeviceBuilder { public: VulkanDeviceBuilder(); VulkanDeviceBuilder& RequireExtension(const std::string& extensionName); VulkanDeviceBuilder& OptionalExtension(const std::string& extensionName); VulkanDeviceBuilder& OptionalRayQuery(); VulkanDeviceBuilder& OptionalDescriptorIndexing(); VulkanDeviceBuilder& Surface(std::shared_ptr surface); VulkanDeviceBuilder& SelectDevice(int index); std::vector FindDevices(const std::shared_ptr& instance); std::shared_ptr Create(std::shared_ptr instance); private: std::set requiredDeviceExtensions; std::set optionalDeviceExtensions; std::shared_ptr surface; int deviceIndex = 0; }; class VulkanSwapChainBuilder { public: VulkanSwapChainBuilder(); std::shared_ptr Create(VulkanDevice* device); }; class CommandPoolBuilder { public: CommandPoolBuilder(); CommandPoolBuilder& QueueFamily(int index); CommandPoolBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice* device); private: const char* debugName = nullptr; int queueFamilyIndex = -1; }; class SemaphoreBuilder { public: SemaphoreBuilder(); SemaphoreBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice* device); private: const char* debugName = nullptr; }; class FenceBuilder { public: FenceBuilder(); FenceBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice* device); private: const char* debugName = nullptr; }; class ImageBuilder { public: ImageBuilder(); ImageBuilder& Size(int width, int height, int miplevels = 1, int arrayLayers = 1); ImageBuilder& Samples(VkSampleCountFlagBits samples); ImageBuilder& Format(VkFormat format); ImageBuilder& Usage(VkImageUsageFlags imageUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0); ImageBuilder& MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0); ImageBuilder& LinearTiling(); ImageBuilder& DebugName(const char* name) { debugName = name; return *this; } bool IsFormatSupported(VulkanDevice *device, VkFormatFeatureFlags bufferFeatures = 0); std::unique_ptr Create(VulkanDevice *device, VkDeviceSize* allocatedBytes = nullptr); std::unique_ptr TryCreate(VulkanDevice *device); private: VkImageCreateInfo imageInfo = {}; VmaAllocationCreateInfo allocInfo = {}; const char* debugName = nullptr; }; class ImageViewBuilder { public: ImageViewBuilder(); ImageViewBuilder& Type(VkImageViewType type); ImageViewBuilder& Image(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int mipLevel = 0, int arrayLayer = 0, int levelCount = 0, int layerCount = 0); ImageViewBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkImageViewCreateInfo viewInfo = {}; const char* debugName = nullptr; }; class SamplerBuilder { public: SamplerBuilder(); SamplerBuilder& AddressMode(VkSamplerAddressMode addressMode); SamplerBuilder& AddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w); SamplerBuilder& MinFilter(VkFilter minFilter); SamplerBuilder& MagFilter(VkFilter magFilter); SamplerBuilder& MipmapMode(VkSamplerMipmapMode mode); SamplerBuilder& Anisotropy(float maxAnisotropy); SamplerBuilder& MipLodBias(float bias); SamplerBuilder& MaxLod(float value); SamplerBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkSamplerCreateInfo samplerInfo = {}; const char* debugName = nullptr; }; class BufferBuilder { public: BufferBuilder(); BufferBuilder& Size(size_t size); BufferBuilder& Usage(VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0); BufferBuilder& MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0); BufferBuilder& MinAlignment(VkDeviceSize memoryAlignment); BufferBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkBufferCreateInfo bufferInfo = {}; VmaAllocationCreateInfo allocInfo = {}; const char* debugName = nullptr; VkDeviceSize minAlignment = 0; }; enum class ShaderType { Vertex, TessControl, TessEvaluation, Geometry, Fragment, Compute }; class ShaderIncludeResult { public: ShaderIncludeResult(std::string name, std::string text) : name(std::move(name)), text(std::move(text)) { } ShaderIncludeResult(std::string error) : text(std::move(error)) { } std::string name; // fully resolved name of the included header file std::string text; // the file contents - or include error message if name is empty }; class ShaderBuilder { public: ShaderBuilder(); static void Init(); static void Deinit(); ShaderBuilder& Type(ShaderType type); ShaderBuilder& AddSource(const std::string& name, const std::string& code); ShaderBuilder& OnIncludeSystem(std::function onIncludeSystem); ShaderBuilder& OnIncludeLocal(std::function onIncludeLocal); ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(const char *shadername, VulkanDevice *device); private: std::vector> sources; std::function onIncludeSystem; std::function onIncludeLocal; int stage = 0; const char* debugName = nullptr; friend class ShaderBuilderIncluderImpl; }; class AccelerationStructureBuilder { public: AccelerationStructureBuilder(); AccelerationStructureBuilder& Type(VkAccelerationStructureTypeKHR type); AccelerationStructureBuilder& Buffer(VulkanBuffer* buffer, VkDeviceSize size); AccelerationStructureBuilder& Buffer(VulkanBuffer* buffer, VkDeviceSize offset, VkDeviceSize size); AccelerationStructureBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice* device); private: VkAccelerationStructureCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR }; const char* debugName = nullptr; }; class ComputePipelineBuilder { public: ComputePipelineBuilder(); ComputePipelineBuilder& Cache(VulkanPipelineCache* cache); ComputePipelineBuilder& Layout(VulkanPipelineLayout *layout); ComputePipelineBuilder& ComputeShader(VulkanShader *shader); ComputePipelineBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkComputePipelineCreateInfo pipelineInfo = {}; VkPipelineShaderStageCreateInfo stageInfo = {}; VulkanPipelineCache* cache = nullptr; const char* debugName = nullptr; }; class DescriptorSetLayoutBuilder { public: DescriptorSetLayoutBuilder(); DescriptorSetLayoutBuilder& Flags(VkDescriptorSetLayoutCreateFlags flags); DescriptorSetLayoutBuilder& AddBinding(int binding, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags, VkDescriptorBindingFlags flags = 0); DescriptorSetLayoutBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkDescriptorSetLayoutCreateInfo layoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT }; std::vector bindings; std::vector bindingFlags; const char* debugName = nullptr; }; class DescriptorPoolBuilder { public: DescriptorPoolBuilder(); DescriptorPoolBuilder& Flags(VkDescriptorPoolCreateFlags flags); DescriptorPoolBuilder& MaxSets(int value); DescriptorPoolBuilder& AddPoolSize(VkDescriptorType type, int count); DescriptorPoolBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: std::vector poolSizes; VkDescriptorPoolCreateInfo poolInfo = {}; const char* debugName = nullptr; }; class QueryPoolBuilder { public: QueryPoolBuilder(); QueryPoolBuilder& QueryType(VkQueryType type, int count, VkQueryPipelineStatisticFlags pipelineStatistics = 0); QueryPoolBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkQueryPoolCreateInfo poolInfo = {}; const char* debugName = nullptr; }; class FramebufferBuilder { public: FramebufferBuilder(); FramebufferBuilder& RenderPass(VulkanRenderPass *renderPass); FramebufferBuilder& AddAttachment(VulkanImageView *view); FramebufferBuilder& AddAttachment(VkImageView view); FramebufferBuilder& Size(int width, int height, int layers = 1); FramebufferBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkFramebufferCreateInfo framebufferInfo = {}; std::vector attachments; const char* debugName = nullptr; }; class ColorBlendAttachmentBuilder { public: ColorBlendAttachmentBuilder(); ColorBlendAttachmentBuilder& ColorWriteMask(VkColorComponentFlags mask); ColorBlendAttachmentBuilder& AdditiveBlendMode(); ColorBlendAttachmentBuilder& AlphaBlendMode(); ColorBlendAttachmentBuilder& BlendMode(VkBlendOp op, VkBlendFactor src, VkBlendFactor dst); VkPipelineColorBlendAttachmentState Create() { return colorBlendAttachment; } private: VkPipelineColorBlendAttachmentState colorBlendAttachment = { }; }; class GraphicsPipelineBuilder { public: GraphicsPipelineBuilder(); GraphicsPipelineBuilder& Cache(VulkanPipelineCache* cache); GraphicsPipelineBuilder& Subpass(int subpass); GraphicsPipelineBuilder& Layout(VulkanPipelineLayout *layout); GraphicsPipelineBuilder& RenderPass(VulkanRenderPass *renderPass); GraphicsPipelineBuilder& Topology(VkPrimitiveTopology topology); GraphicsPipelineBuilder& Viewport(float x, float y, float width, float height, float minDepth = 0.0f, float maxDepth = 1.0f); GraphicsPipelineBuilder& Scissor(int x, int y, int width, int height); GraphicsPipelineBuilder& RasterizationSamples(VkSampleCountFlagBits samples); GraphicsPipelineBuilder& Cull(VkCullModeFlags cullMode, VkFrontFace frontFace); GraphicsPipelineBuilder& DepthStencilEnable(bool test, bool write, bool stencil); GraphicsPipelineBuilder& DepthFunc(VkCompareOp func); GraphicsPipelineBuilder& DepthClampEnable(bool value); GraphicsPipelineBuilder& DepthBias(bool enable, float biasConstantFactor, float biasClamp, float biasSlopeFactor); GraphicsPipelineBuilder& Stencil(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp, uint32_t compareMask, uint32_t writeMask, uint32_t reference); GraphicsPipelineBuilder& AddColorBlendAttachment(VkPipelineColorBlendAttachmentState state); GraphicsPipelineBuilder& AddVertexShader(VulkanShader *shader); GraphicsPipelineBuilder& AddFragmentShader(VulkanShader *shader); GraphicsPipelineBuilder& AddVertexBufferBinding(int index, size_t stride); GraphicsPipelineBuilder& AddVertexAttribute(int location, int binding, VkFormat format, size_t offset); GraphicsPipelineBuilder& AddDynamicState(VkDynamicState state); GraphicsPipelineBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkGraphicsPipelineCreateInfo pipelineInfo = { }; VkPipelineVertexInputStateCreateInfo vertexInputInfo = { }; VkPipelineInputAssemblyStateCreateInfo inputAssembly = { }; VkViewport viewport = { }; VkRect2D scissor = { }; VkPipelineViewportStateCreateInfo viewportState = { }; VkPipelineRasterizationStateCreateInfo rasterizer = { }; VkPipelineMultisampleStateCreateInfo multisampling = { }; VkPipelineColorBlendStateCreateInfo colorBlending = { }; VkPipelineDepthStencilStateCreateInfo depthStencil = { }; VkPipelineDynamicStateCreateInfo dynamicState = {}; std::vector shaderStages; std::vector colorBlendAttachments; std::vector vertexInputBindings; std::vector vertexInputAttributes; std::vector dynamicStates; VulkanPipelineCache* cache = nullptr; const char* debugName = nullptr; }; class PipelineLayoutBuilder { public: PipelineLayoutBuilder(); PipelineLayoutBuilder& AddSetLayout(VulkanDescriptorSetLayout *setLayout); PipelineLayoutBuilder& AddPushConstantRange(VkShaderStageFlags stageFlags, size_t offset, size_t size); PipelineLayoutBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; std::vector setLayouts; std::vector pushConstantRanges; const char* debugName = nullptr; }; class PipelineCacheBuilder { public: PipelineCacheBuilder(); PipelineCacheBuilder& InitialData(const void* data, size_t size); PipelineCacheBuilder& Flags(VkPipelineCacheCreateFlags flags); PipelineCacheBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice* device); private: VkPipelineCacheCreateInfo pipelineCacheInfo = {}; std::vector initData; const char* debugName = nullptr; }; class RenderPassBuilder { public: RenderPassBuilder(); RenderPassBuilder& AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkImageLayout initialLayout, VkImageLayout finalLayout); RenderPassBuilder& AddDepthStencilAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load, VkAttachmentStoreOp store, VkAttachmentLoadOp stencilLoad, VkAttachmentStoreOp stencilStore, VkImageLayout initialLayout, VkImageLayout finalLayout); RenderPassBuilder& AddExternalSubpassDependency(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); RenderPassBuilder& AddSubpass(); RenderPassBuilder& AddSubpassColorAttachmentRef(uint32_t index, VkImageLayout layout); RenderPassBuilder& AddSubpassDepthStencilAttachmentRef(uint32_t index, VkImageLayout layout); RenderPassBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: VkRenderPassCreateInfo renderPassInfo = { }; std::vector attachments; std::vector dependencies; std::vector subpasses; struct SubpassData { std::vector colorRefs; VkAttachmentReference depthRef = { }; }; std::vector> subpassData; const char* debugName = nullptr; }; class PipelineBarrier { public: PipelineBarrier& AddMemory(VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); PipelineBarrier& AddBuffer(VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); PipelineBarrier& AddBuffer(VulkanBuffer *buffer, VkDeviceSize offset, VkDeviceSize size, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); PipelineBarrier& AddImage(VulkanImage *image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1, int baseArrayLayer = 0, int layerCount = 1); PipelineBarrier& AddImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1, int baseArrayLayer = 0, int layerCount = 1); PipelineBarrier& AddQueueTransfer(int srcFamily, int dstFamily, VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); PipelineBarrier& AddQueueTransfer(int srcFamily, int dstFamily, VulkanImage *image, VkImageLayout layout, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); void Execute(VulkanCommandBuffer *commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags = 0); private: std::vector memoryBarriers; std::vector bufferMemoryBarriers; std::vector imageMemoryBarriers; }; class QueueSubmit { public: QueueSubmit(); QueueSubmit& AddCommandBuffer(VulkanCommandBuffer *buffer); QueueSubmit& AddWait(VkPipelineStageFlags waitStageMask, VulkanSemaphore *semaphore); QueueSubmit& AddSignal(VulkanSemaphore *semaphore); void Execute(VulkanDevice *device, VkQueue queue, VulkanFence *fence = nullptr); private: VkSubmitInfo submitInfo = {}; std::vector waitSemaphores; std::vector waitStages; std::vector signalSemaphores; std::vector commandBuffers; }; class WriteDescriptors { public: WriteDescriptors& AddBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer); WriteDescriptors& AddBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer, size_t offset, size_t range); WriteDescriptors& AddStorageImage(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VkImageLayout imageLayout); WriteDescriptors& AddCombinedImageSampler(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VulkanSampler *sampler, VkImageLayout imageLayout); WriteDescriptors& AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, int arrayIndex, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout); WriteDescriptors& AddAccelerationStructure(VulkanDescriptorSet* descriptorSet, int binding, VulkanAccelerationStructure* accelStruct); void Execute(VulkanDevice *device); private: struct WriteExtra { VkDescriptorImageInfo imageInfo; VkDescriptorBufferInfo bufferInfo; VkBufferView bufferView; VkWriteDescriptorSetAccelerationStructureKHR accelStruct; }; std::vector writes; std::vector> writeExtras; }; class BufferTransfer { public: BufferTransfer& AddBuffer(VulkanBuffer* buffer, size_t offset, const void* data, size_t size); BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data, size_t size); BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data0, size_t size0, const void* data1, size_t size1); std::unique_ptr Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer); private: struct BufferCopy { VulkanBuffer* buffer; size_t offset; const void* data0; size_t size0; const void* data1; size_t size1; }; std::vector bufferCopies; };