mirror of
				https://github.com/PancakeTAS/lsfg-vk.git
				synced 2025-10-30 07:01:10 +00:00 
			
		
		
		
	refactor: implement new, more basic barrier system
This commit is contained in:
		
							parent
							
								
									c3cccb4967
								
							
						
					
					
						commit
						5d9660c1eb
					
				
					 7 changed files with 103 additions and 104 deletions
				
			
		|  | @ -19,51 +19,6 @@ | |||
| 
 | ||||
| namespace LSFG::Utils { | ||||
| 
 | ||||
|     ///
 | ||||
|     /// Insert memory barriers for images in a command buffer.
 | ||||
|     ///
 | ||||
|     /// @throws std::logic_error if the command buffer is not in Recording state
 | ||||
|     ///
 | ||||
|     class BarrierBuilder { | ||||
|     public: | ||||
|         /// Create a barrier builder.
 | ||||
|         BarrierBuilder(const Core::CommandBuffer& buffer) | ||||
|                 : commandBuffer(&buffer) { | ||||
|             this->barriers.reserve(16); // this is performance critical
 | ||||
|         } | ||||
| 
 | ||||
|         // Add a resource to the barrier builder.
 | ||||
|         BarrierBuilder& addR2W(Core::Image& image); | ||||
|         BarrierBuilder& addW2R(Core::Image& image); | ||||
| 
 | ||||
|         // Add an optional resource to the barrier builder.
 | ||||
|         BarrierBuilder& addR2W(std::optional<Core::Image>& image) { | ||||
|             if (image.has_value()) this->addR2W(*image); return *this; } | ||||
|         BarrierBuilder& addW2R(std::optional<Core::Image>& image) { | ||||
|             if (image.has_value()) this->addW2R(*image); return *this; } | ||||
| 
 | ||||
|         /// Add a list of resources to the barrier builder.
 | ||||
|         BarrierBuilder& addR2W(std::vector<Core::Image>& images) { | ||||
|             for (auto& image : images) this->addR2W(image); return *this; } | ||||
|         BarrierBuilder& addW2R(std::vector<Core::Image>& images) { | ||||
|             for (auto& image : images) this->addW2R(image); return *this; } | ||||
| 
 | ||||
|         /// Add an array of resources to the barrier builder.
 | ||||
|         template<std::size_t N> | ||||
|         BarrierBuilder& addR2W(std::array<Core::Image, N>& images) { | ||||
|             for (auto& image : images) this->addR2W(image); return *this; } | ||||
|         template<std::size_t N> | ||||
|         BarrierBuilder& addW2R(std::array<Core::Image, N>& images) { | ||||
|             for (auto& image : images) this->addW2R(image); return *this; } | ||||
| 
 | ||||
|         /// Finish building the barrier
 | ||||
|         void build() const; | ||||
|     private: | ||||
|         const Core::CommandBuffer* commandBuffer; | ||||
| 
 | ||||
|         std::vector<VkImageMemoryBarrier2> barriers; | ||||
|     }; | ||||
| 
 | ||||
|     ///
 | ||||
|     /// Upload a DDS file to a Vulkan image.
 | ||||
|     ///
 | ||||
|  |  | |||
|  | @ -21,57 +21,6 @@ | |||
| using namespace LSFG; | ||||
| using namespace LSFG::Utils; | ||||
| 
 | ||||
| BarrierBuilder& BarrierBuilder::addR2W(Core::Image& image) { | ||||
|     this->barriers.emplace_back(VkImageMemoryBarrier2 { | ||||
|         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, | ||||
|         .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, | ||||
|         .srcAccessMask = VK_ACCESS_2_SHADER_READ_BIT, | ||||
|         .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, | ||||
|         .dstAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, | ||||
|         .oldLayout = image.getLayout(), | ||||
|         .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||||
|         .image = image.handle(), | ||||
|         .subresourceRange = { | ||||
|             .aspectMask = image.getAspectFlags(), | ||||
|             .levelCount = 1, | ||||
|             .layerCount = 1 | ||||
|         } | ||||
|     }); | ||||
|     image.setLayout(VK_IMAGE_LAYOUT_GENERAL); | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| BarrierBuilder& BarrierBuilder::addW2R(Core::Image& image) { | ||||
|     this->barriers.emplace_back(VkImageMemoryBarrier2 { | ||||
|         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, | ||||
|         .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, | ||||
|         .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT, | ||||
|         .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, | ||||
|         .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT, | ||||
|         .oldLayout = image.getLayout(), | ||||
|         .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||||
|         .image = image.handle(), | ||||
|         .subresourceRange = { | ||||
|             .aspectMask = image.getAspectFlags(), | ||||
|             .levelCount = 1, | ||||
|             .layerCount = 1 | ||||
|         } | ||||
|     }); | ||||
|     image.setLayout(VK_IMAGE_LAYOUT_GENERAL); | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| void BarrierBuilder::build() const { | ||||
|     const VkDependencyInfo dependencyInfo = { | ||||
|         .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, | ||||
|         .imageMemoryBarrierCount = static_cast<uint32_t>(this->barriers.size()), | ||||
|         .pImageMemoryBarriers = this->barriers.data() | ||||
|     }; | ||||
|     vkCmdPipelineBarrier2(this->commandBuffer->handle(), &dependencyInfo); | ||||
| } | ||||
| 
 | ||||
| void Utils::uploadImage(const Core::Device& device, const Core::CommandPool& commandPool, | ||||
|         Core::Image& image, const std::string& path) { | ||||
|     // read image bytecode
 | ||||
|  | @ -50,7 +50,6 @@ namespace VK::Core { | |||
|         /// Get the size of the buffer.
 | ||||
|         [[nodiscard]] auto getSize() const { return this->size; } | ||||
|     private: | ||||
| 
 | ||||
|         std::shared_ptr<VkBuffer> buffer; | ||||
|         std::shared_ptr<VkDeviceMemory> memory; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "vk/core/commandpool.hpp" | ||||
| #include "vk/core/descriptorset.hpp" | ||||
| #include "vk/core/commandpool.hpp" | ||||
| #include "vk/core/semaphore.hpp" | ||||
| #include "vk/core/pipeline.hpp" | ||||
| #include "vk/core/device.hpp" | ||||
|  | @ -76,8 +76,27 @@ namespace VK::Core { | |||
|         ///
 | ||||
|         void bindDescriptorSet(const Pipeline& pipeline, const DescriptorSet& set) const; | ||||
| 
 | ||||
|         // TODO: Method for inserting a pipeline barrier.
 | ||||
|         //   TODO: Rework abstraction for barriers.
 | ||||
|         ///
 | ||||
|         /// Insert memory barriers transitioning images into the general layout.
 | ||||
|         ///
 | ||||
|         /// @param images Images to transition to general layout
 | ||||
|         ///
 | ||||
|         /// @throws std::logic_error if the command buffer is not in Recording state
 | ||||
|         ///
 | ||||
|         void insertBarrier(const std::vector<VkImage>& images) const; | ||||
| 
 | ||||
|         ///
 | ||||
|         /// Insert memory barriers for images in the command buffer.
 | ||||
|         ///
 | ||||
|         /// @param readableImages Images that will be transitioned from rw to read-only
 | ||||
|         /// @param writableImages Images that will be transitioned from read-only to rw
 | ||||
|         ///
 | ||||
|         /// @throws std::logic_error if the command buffer is not in Recording state
 | ||||
|         ///
 | ||||
|         void insertBarrier( | ||||
|             const std::vector<VkImage>& readableImages, | ||||
|             const std::vector<VkImage>& writableImages) const; | ||||
| 
 | ||||
|         // TODO: Method for copying a buffer to an image
 | ||||
|         // TODO: Method for clearing an image to a color
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ namespace VK::Core { | |||
|         Image(const Device& device, VkExtent2D extent, | ||||
|             VkFormat format = VK_FORMAT_R8G8B8A8_UNORM, | ||||
|             VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, | ||||
|             VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT); | ||||
|             VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT); // TODO: get rid
 | ||||
| 
 | ||||
|         ///
 | ||||
|         /// Create the image with shared backing memory.
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include "vk/core/commandbuffer.hpp" | ||||
| #include "vk/core/descriptorset.hpp" | ||||
| #include "vk/core/commandpool.hpp" | ||||
| #include "vk/core/semaphore.hpp" | ||||
| #include "vk/core/pipeline.hpp" | ||||
|  | @ -72,6 +73,79 @@ void CommandBuffer::bindDescriptorSet(const Pipeline& pipeline, const Descriptor | |||
|         0, 1, &descriptorSetHandle, 0, nullptr); | ||||
| } | ||||
| 
 | ||||
| void CommandBuffer::insertBarrier( | ||||
|         const std::vector<VkImage>& images) const { | ||||
|     if (*this->state != CommandBufferState::Recording) | ||||
|         throw std::logic_error("Command buffer is not in Recording state"); | ||||
| 
 | ||||
|     std::vector<VkImageMemoryBarrier2> barriers(images.size()); | ||||
|     for (size_t i = 0; i < images.size(); i++) { | ||||
|         barriers[i] = { | ||||
|             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, | ||||
|             .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||||
|             .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||||
|             .image = images[i], | ||||
|             .subresourceRange = { | ||||
|                 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||||
|                 .levelCount = 1, | ||||
|                 .layerCount = 1 | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     const VkDependencyInfo dependencyInfo = { | ||||
|         .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, | ||||
|         .imageMemoryBarrierCount = static_cast<uint32_t>(barriers.size()), | ||||
|         .pImageMemoryBarriers = barriers.data() | ||||
|     }; | ||||
|     vkCmdPipelineBarrier2(*this->commandBuffer, &dependencyInfo); | ||||
| } | ||||
| 
 | ||||
| void CommandBuffer::insertBarrier( | ||||
|         const std::vector<VkImage>& readableImages, | ||||
|         const std::vector<VkImage>& writableImages) const { | ||||
|     if (*this->state != CommandBufferState::Recording) | ||||
|         throw std::logic_error("Command buffer is not in Recording state"); | ||||
| 
 | ||||
|     // create barriers
 | ||||
|     const VkImageMemoryBarrier2 dummyBarrier{ | ||||
|         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, | ||||
|         .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, | ||||
|         .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, | ||||
|         .subresourceRange = { | ||||
|             .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||||
|             .levelCount = 1, | ||||
|             .layerCount = 1 | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     const size_t totalImages = | ||||
|         readableImages.size() + writableImages.size(); | ||||
|     std::vector<VkImageMemoryBarrier2> barriers(totalImages); | ||||
| 
 | ||||
|     for (const auto& image : readableImages) { | ||||
|         VkImageMemoryBarrier2& barrier = barriers.emplace_back(dummyBarrier); | ||||
|         barrier.srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT; | ||||
|         barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT; | ||||
|         barrier.image = image; | ||||
|     } | ||||
| 
 | ||||
|     for (const auto& image : writableImages) { | ||||
|         VkImageMemoryBarrier2& barrier = barriers.emplace_back(dummyBarrier); | ||||
|         barrier.srcAccessMask = VK_ACCESS_2_SHADER_READ_BIT; | ||||
|         barrier.dstAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT; | ||||
|         barrier.image = image; | ||||
|     } | ||||
| 
 | ||||
|     // insert barriers
 | ||||
|     const VkDependencyInfo dependencyInfo = { | ||||
|         .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, | ||||
|         .imageMemoryBarrierCount = static_cast<uint32_t>(barriers.size()), | ||||
|         .pImageMemoryBarriers = barriers.data() | ||||
|     }; | ||||
|     vkCmdPipelineBarrier2(*this->commandBuffer, &dependencyInfo); | ||||
| } | ||||
| 
 | ||||
| void CommandBuffer::dispatch(uint32_t x, uint32_t y, uint32_t z) const { | ||||
|     if (*this->state != CommandBufferState::Recording) | ||||
|         throw std::logic_error("Command buffer is not in Recording state"); | ||||
|  |  | |||
|  | @ -1,13 +1,16 @@ | |||
| #include <cstddef> | ||||
| #include <volk.h> | ||||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include "vk/core/descriptorset.hpp" | ||||
| #include "vk/core/device.hpp" | ||||
| #include "vk/core/descriptorpool.hpp" | ||||
| #include "vk/core/descriptorset.hpp" | ||||
| #include "vk/core/shadermodule.hpp" | ||||
| #include "vk/core/device.hpp" | ||||
| #include "vk/exception.hpp" | ||||
| 
 | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| 
 | ||||
| using namespace VK::Core; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 PancakeTAS
						PancakeTAS