mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2025-10-30 07:01:10 +00:00
bugfixes and pipeline barriers
This commit is contained in:
parent
dc11a64c0a
commit
f724229ae4
7 changed files with 146 additions and 51 deletions
|
|
@ -38,6 +38,8 @@ namespace Vulkan::Core {
|
||||||
[[nodiscard]] VkExtent2D getExtent() const { return this->extent; }
|
[[nodiscard]] VkExtent2D getExtent() const { return this->extent; }
|
||||||
/// Get the format of the image.
|
/// Get the format of the image.
|
||||||
[[nodiscard]] VkFormat getFormat() const { return this->format; }
|
[[nodiscard]] VkFormat getFormat() const { return this->format; }
|
||||||
|
/// Get the aspect flags of the image.
|
||||||
|
[[nodiscard]] VkImageAspectFlags getAspectFlags() const { return this->aspectFlags; }
|
||||||
|
|
||||||
/// Trivially copyable, moveable and destructible
|
/// Trivially copyable, moveable and destructible
|
||||||
Image(const Image&) noexcept = default;
|
Image(const Image&) noexcept = default;
|
||||||
|
|
@ -52,6 +54,7 @@ namespace Vulkan::Core {
|
||||||
|
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
VkFormat format;
|
VkFormat format;
|
||||||
|
VkImageAspectFlags aspectFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
40
include/utils/memorybarriers.hpp
Normal file
40
include/utils/memorybarriers.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef BARRIERS_HPP
|
||||||
|
#define BARRIERS_HPP
|
||||||
|
|
||||||
|
#include "core/commandbuffer.hpp"
|
||||||
|
#include "core/image.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
namespace Barriers {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Insert memory barriers for images in a command buffer.
|
||||||
|
///
|
||||||
|
/// @param buffer Command buffer to insert barriers into
|
||||||
|
/// @param r2wImages Images that are being read and will be written to
|
||||||
|
/// @param w2rImages Images that are being written to and will be read from
|
||||||
|
/// @param srcLayout Optional source layout for the images, defaults to VK_IMAGE_LAYOUT_GENERAL
|
||||||
|
///
|
||||||
|
/// @throws std::logic_error if the command buffer is not in Recording state
|
||||||
|
///
|
||||||
|
void insertBarrier(
|
||||||
|
const Vulkan::Core::CommandBuffer& buffer,
|
||||||
|
const std::vector<Vulkan::Core::Image>& r2wImages,
|
||||||
|
const std::vector<Vulkan::Core::Image>& w2rImages,
|
||||||
|
std::optional<VkImageLayout> srcLayout = std::nullopt);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Insert a global memory barrier in a command buffer.
|
||||||
|
///
|
||||||
|
/// @param buffer Command buffer to insert the barrier into
|
||||||
|
///
|
||||||
|
/// @throws std::logic_error if the command buffer is not in Recording state
|
||||||
|
///
|
||||||
|
void insertGlobalBarrier(const Vulkan::Core::CommandBuffer& buffer);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BARRIERS_HPP
|
||||||
|
|
@ -15,6 +15,7 @@ DescriptorPool::DescriptorPool(const Device& device) {
|
||||||
}};
|
}};
|
||||||
const VkDescriptorPoolCreateInfo desc{
|
const VkDescriptorPoolCreateInfo desc{
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||||
|
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||||
.maxSets = 16384,
|
.maxSets = 16384,
|
||||||
.poolSizeCount = static_cast<uint32_t>(pools.size()),
|
.poolSizeCount = static_cast<uint32_t>(pools.size()),
|
||||||
.pPoolSizes = pools.data()
|
.pPoolSizes = pools.data()
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ using namespace Vulkan::Core;
|
||||||
|
|
||||||
Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
|
Image::Image(const Device& device, VkExtent2D extent, VkFormat format,
|
||||||
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags)
|
VkImageUsageFlags usage, VkImageAspectFlags aspectFlags)
|
||||||
: extent(extent), format(format) {
|
: extent(extent), format(format), aspectFlags(aspectFlags) {
|
||||||
// create image
|
// create image
|
||||||
const VkImageCreateInfo desc{
|
const VkImageCreateInfo desc{
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
using namespace Vulkan;
|
using namespace Vulkan;
|
||||||
|
|
||||||
|
|
@ -49,10 +50,15 @@ Device::Device(const Instance& instance) {
|
||||||
|
|
||||||
// create logical device
|
// create logical device
|
||||||
const float queuePriority{1.0F}; // highest priority
|
const float queuePriority{1.0F}; // highest priority
|
||||||
const VkPhysicalDeviceVulkan12Features features{
|
VkPhysicalDeviceVulkan13Features features13{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
|
||||||
|
.synchronization2 = VK_TRUE
|
||||||
|
};
|
||||||
|
const VkPhysicalDeviceVulkan12Features features12{
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||||
|
.pNext = &features13,
|
||||||
.timelineSemaphore = VK_TRUE,
|
.timelineSemaphore = VK_TRUE,
|
||||||
.vulkanMemoryModel = VK_TRUE,
|
.vulkanMemoryModel = VK_TRUE
|
||||||
};
|
};
|
||||||
const VkDeviceQueueCreateInfo computeQueueDesc{
|
const VkDeviceQueueCreateInfo computeQueueDesc{
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||||
|
|
@ -62,7 +68,7 @@ Device::Device(const Instance& instance) {
|
||||||
};
|
};
|
||||||
const VkDeviceCreateInfo deviceCreateInfo{
|
const VkDeviceCreateInfo deviceCreateInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||||
.pNext = &features,
|
.pNext = &features12,
|
||||||
.queueCreateInfoCount = 1,
|
.queueCreateInfoCount = 1,
|
||||||
.pQueueCreateInfos = &computeQueueDesc
|
.pQueueCreateInfos = &computeQueueDesc
|
||||||
};
|
};
|
||||||
|
|
|
||||||
68
src/main.cpp
68
src/main.cpp
|
|
@ -10,6 +10,7 @@
|
||||||
#include "core/shadermodule.hpp"
|
#include "core/shadermodule.hpp"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
#include "instance.hpp"
|
#include "instance.hpp"
|
||||||
|
#include "utils/memorybarriers.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
@ -40,27 +41,22 @@ const static DataBuffer data{
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// initialize Vulkan
|
// initialize application
|
||||||
const Instance instance;
|
const Instance instance;
|
||||||
const Device device(instance);
|
const Device device(instance);
|
||||||
|
const Core::DescriptorPool descriptorPool(device);
|
||||||
|
const Core::CommandPool commandPool(device);
|
||||||
|
|
||||||
// load shader
|
|
||||||
const Core::ShaderModule computeShader(device, "shaders/downsample.spv",
|
const Core::ShaderModule computeShader(device, "shaders/downsample.spv",
|
||||||
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER},
|
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER},
|
||||||
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
||||||
{ 7, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE},
|
{ 7, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE},
|
||||||
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER} });
|
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER} });
|
||||||
|
|
||||||
// prepare render pass
|
|
||||||
const Core::CommandPool commandPool(device);
|
|
||||||
const Core::DescriptorPool descriptorPool(device);
|
|
||||||
const Core::Pipeline computePipeline(device, computeShader);
|
const Core::Pipeline computePipeline(device, computeShader);
|
||||||
const Core::DescriptorSet descriptorSet(device, descriptorPool, computeShader);
|
|
||||||
|
|
||||||
// create shader inputs
|
|
||||||
const Core::Sampler sampler(device, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
|
const Core::Sampler sampler(device, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
|
||||||
|
|
||||||
const std::vector<Core::Image> images(1, Core::Image(
|
const std::vector<Core::Image> inputImages(1, Core::Image(
|
||||||
device, { 2560, 1411 }, VK_FORMAT_R8G8B8A8_UNORM,
|
device, { 2560, 1411 }, VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
VK_IMAGE_ASPECT_COLOR_BIT
|
||||||
|
|
@ -72,51 +68,22 @@ int main() {
|
||||||
const Core::Buffer buffer(device, dataVec.size(), dataVec,
|
const Core::Buffer buffer(device, dataVec.size(), dataVec,
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
||||||
|
|
||||||
// create shader outputs
|
std::vector<Core::Image> outputImages;
|
||||||
const std::vector<Core::Image> outputImages = {
|
outputImages.reserve(7);
|
||||||
Core::Image(
|
for (size_t i = 0; i < 7; ++i)
|
||||||
device, { 1280, 705 }, VK_FORMAT_R8G8B8A8_UNORM,
|
outputImages.emplace_back(device,
|
||||||
|
VkExtent2D { .width = 2560U >> i, .height = 1411U >> i },
|
||||||
|
VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
),
|
|
||||||
Core::Image(
|
|
||||||
device, { 640, 352 }, VK_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
|
||||||
),
|
|
||||||
Core::Image(
|
|
||||||
device, { 320, 176 }, VK_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
|
||||||
),
|
|
||||||
Core::Image(
|
|
||||||
device, { 160, 88 }, VK_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
|
||||||
),
|
|
||||||
Core::Image(
|
|
||||||
device, { 80, 44 }, VK_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
|
||||||
),
|
|
||||||
Core::Image(
|
|
||||||
device, { 40, 22 }, VK_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
|
||||||
),
|
|
||||||
Core::Image(
|
|
||||||
device, { 20, 11 }, VK_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// load descriptor set
|
// load descriptor set
|
||||||
|
const Core::DescriptorSet descriptorSet(device, descriptorPool, computeShader);
|
||||||
descriptorSet.update(
|
descriptorSet.update(
|
||||||
device,
|
device,
|
||||||
{
|
{
|
||||||
{{ VK_DESCRIPTOR_TYPE_SAMPLER, sampler }},
|
{{ VK_DESCRIPTOR_TYPE_SAMPLER, sampler }},
|
||||||
{{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, images[0] }},
|
{{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, inputImages[0] }},
|
||||||
{
|
{
|
||||||
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outputImages[0] },
|
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outputImages[0] },
|
||||||
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outputImages[1] },
|
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outputImages[1] },
|
||||||
|
|
@ -137,6 +104,13 @@ int main() {
|
||||||
commandBuffer.begin();
|
commandBuffer.begin();
|
||||||
|
|
||||||
// render
|
// render
|
||||||
|
Barriers::insertBarrier(
|
||||||
|
commandBuffer,
|
||||||
|
inputImages,
|
||||||
|
outputImages,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED
|
||||||
|
);
|
||||||
|
|
||||||
computePipeline.bind(commandBuffer);
|
computePipeline.bind(commandBuffer);
|
||||||
descriptorSet.bind(commandBuffer, computePipeline);
|
descriptorSet.bind(commandBuffer, computePipeline);
|
||||||
commandBuffer.dispatch(40, 23, 1);
|
commandBuffer.dispatch(40, 23, 1);
|
||||||
|
|
|
||||||
71
src/utils/memorybarriers.cpp
Normal file
71
src/utils/memorybarriers.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include "utils/memorybarriers.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
using namespace Barriers;
|
||||||
|
|
||||||
|
void Barriers::insertBarrier(
|
||||||
|
const Vulkan::Core::CommandBuffer& buffer,
|
||||||
|
const std::vector<Vulkan::Core::Image>& r2wImages,
|
||||||
|
const std::vector<Vulkan::Core::Image>& w2rImages,
|
||||||
|
std::optional<VkImageLayout> srcLayout) {
|
||||||
|
std::vector<VkImageMemoryBarrier2> barriers(r2wImages.size() + w2rImages.size());
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
for (const auto& image : r2wImages) {
|
||||||
|
barriers[index++] = {
|
||||||
|
.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 = srcLayout.value_or(VK_IMAGE_LAYOUT_GENERAL),
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.image = image.handle(),
|
||||||
|
.subresourceRange = {
|
||||||
|
.aspectMask = image.getAspectFlags(),
|
||||||
|
.levelCount = 1,
|
||||||
|
.layerCount = 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (const auto& image : w2rImages) {
|
||||||
|
barriers[index++] = {
|
||||||
|
.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 = srcLayout.value_or(VK_IMAGE_LAYOUT_GENERAL),
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.image = image.handle(),
|
||||||
|
.subresourceRange = {
|
||||||
|
.aspectMask = image.getAspectFlags(),
|
||||||
|
.levelCount = 1,
|
||||||
|
.layerCount = 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const VkDependencyInfo dependencyInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||||
|
.imageMemoryBarrierCount = static_cast<uint32_t>(barriers.size()),
|
||||||
|
.pImageMemoryBarriers = barriers.data()
|
||||||
|
};
|
||||||
|
vkCmdPipelineBarrier2(buffer.handle(), &dependencyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Barriers::insertGlobalBarrier(const Vulkan::Core::CommandBuffer& buffer) {
|
||||||
|
const VkMemoryBarrier2 barrier = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
|
||||||
|
.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
.srcAccessMask = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT,
|
||||||
|
.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT
|
||||||
|
};
|
||||||
|
const VkDependencyInfo dependencyInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||||
|
.memoryBarrierCount = 1,
|
||||||
|
.pMemoryBarriers = &barrier
|
||||||
|
};
|
||||||
|
vkCmdPipelineBarrier2(buffer.handle(), &dependencyInfo);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue