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 {
|
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.
|
/// Upload a DDS file to a Vulkan image.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -21,57 +21,6 @@
|
||||||
using namespace LSFG;
|
using namespace LSFG;
|
||||||
using namespace LSFG::Utils;
|
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,
|
void Utils::uploadImage(const Core::Device& device, const Core::CommandPool& commandPool,
|
||||||
Core::Image& image, const std::string& path) {
|
Core::Image& image, const std::string& path) {
|
||||||
// read image bytecode
|
// read image bytecode
|
||||||
|
|
@ -50,7 +50,6 @@ namespace VK::Core {
|
||||||
/// Get the size of the buffer.
|
/// Get the size of the buffer.
|
||||||
[[nodiscard]] auto getSize() const { return this->size; }
|
[[nodiscard]] auto getSize() const { return this->size; }
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<VkBuffer> buffer;
|
std::shared_ptr<VkBuffer> buffer;
|
||||||
std::shared_ptr<VkDeviceMemory> memory;
|
std::shared_ptr<VkDeviceMemory> memory;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "vk/core/commandpool.hpp"
|
|
||||||
#include "vk/core/descriptorset.hpp"
|
#include "vk/core/descriptorset.hpp"
|
||||||
|
#include "vk/core/commandpool.hpp"
|
||||||
#include "vk/core/semaphore.hpp"
|
#include "vk/core/semaphore.hpp"
|
||||||
#include "vk/core/pipeline.hpp"
|
#include "vk/core/pipeline.hpp"
|
||||||
#include "vk/core/device.hpp"
|
#include "vk/core/device.hpp"
|
||||||
|
|
@ -76,8 +76,27 @@ namespace VK::Core {
|
||||||
///
|
///
|
||||||
void bindDescriptorSet(const Pipeline& pipeline, const DescriptorSet& set) const;
|
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 copying a buffer to an image
|
||||||
// TODO: Method for clearing an image to a color
|
// TODO: Method for clearing an image to a color
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace VK::Core {
|
||||||
Image(const Device& device, VkExtent2D extent,
|
Image(const Device& device, VkExtent2D extent,
|
||||||
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
|
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
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.
|
/// Create the image with shared backing memory.
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "vk/core/commandbuffer.hpp"
|
#include "vk/core/commandbuffer.hpp"
|
||||||
|
#include "vk/core/descriptorset.hpp"
|
||||||
#include "vk/core/commandpool.hpp"
|
#include "vk/core/commandpool.hpp"
|
||||||
#include "vk/core/semaphore.hpp"
|
#include "vk/core/semaphore.hpp"
|
||||||
#include "vk/core/pipeline.hpp"
|
#include "vk/core/pipeline.hpp"
|
||||||
|
|
@ -72,6 +73,79 @@ void CommandBuffer::bindDescriptorSet(const Pipeline& pipeline, const Descriptor
|
||||||
0, 1, &descriptorSetHandle, 0, nullptr);
|
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 {
|
void CommandBuffer::dispatch(uint32_t x, uint32_t y, uint32_t z) const {
|
||||||
if (*this->state != CommandBufferState::Recording)
|
if (*this->state != CommandBufferState::Recording)
|
||||||
throw std::logic_error("Command buffer is not in Recording state");
|
throw std::logic_error("Command buffer is not in Recording state");
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
#include <cstddef>
|
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include "vk/core/descriptorset.hpp"
|
|
||||||
#include "vk/core/device.hpp"
|
|
||||||
#include "vk/core/descriptorpool.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 "vk/exception.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace VK::Core;
|
using namespace VK::Core;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue