From 3e5639002ccdbe689c0cc702b740be735831e8ba Mon Sep 17 00:00:00 2001 From: Alexander Gauggel <agauggel@uni-koblenz.de> Date: Sat, 21 Aug 2021 18:04:15 +0200 Subject: [PATCH] [#106] Very basic indirect dispatch implementation --- include/vkcv/Buffer.hpp | 4 +- include/vkcv/BufferManager.hpp | 2 +- include/vkcv/Core.hpp | 12 +++++- .../shaders/motionBlurIndirectArguments.comp | 20 ++++++++++ projects/indirect_dispatch/src/MotionBlur.cpp | 40 +++++++++++++++---- projects/indirect_dispatch/src/MotionBlur.hpp | 3 ++ src/vkcv/BufferManager.cpp | 6 ++- src/vkcv/Core.cpp | 36 +++++++++++++++++ src/vkcv/ImageManager.cpp | 2 +- 9 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 projects/indirect_dispatch/resources/shaders/motionBlurIndirectArguments.comp diff --git a/include/vkcv/Buffer.hpp b/include/vkcv/Buffer.hpp index ae935ba9..f5cd183d 100644 --- a/include/vkcv/Buffer.hpp +++ b/include/vkcv/Buffer.hpp @@ -76,8 +76,8 @@ namespace vkcv { {} [[nodiscard]] - static Buffer<T> create(BufferManager* manager, BufferType type, size_t count, BufferMemoryType memoryType) { - return Buffer<T>(manager, manager->createBuffer(type, count * sizeof(T), memoryType), type, count, memoryType); + static Buffer<T> create(BufferManager* manager, BufferType type, size_t count, BufferMemoryType memoryType, bool supportIndirect) { + return Buffer<T>(manager, manager->createBuffer(type, count * sizeof(T), memoryType, supportIndirect), type, count, memoryType); } }; diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp index c7f32d9f..7bec33d8 100644 --- a/include/vkcv/BufferManager.hpp +++ b/include/vkcv/BufferManager.hpp @@ -70,7 +70,7 @@ namespace vkcv * @param memoryType Type of buffers memory * @return New buffer handle */ - BufferHandle createBuffer(BufferType type, size_t size, BufferMemoryType memoryType); + BufferHandle createBuffer(BufferType type, size_t size, BufferMemoryType memoryType, bool supportIndirect); /** * Returns the Vulkan buffer handle of a buffer diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 5677dbf6..7b5c1d94 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -185,8 +185,8 @@ namespace vkcv * return Buffer-Object */ template<typename T> - Buffer<T> createBuffer(vkcv::BufferType type, size_t count, BufferMemoryType memoryType = BufferMemoryType::DEVICE_LOCAL) { - return Buffer<T>::create(m_BufferManager.get(), type, count, memoryType); + Buffer<T> createBuffer(vkcv::BufferType type, size_t count, BufferMemoryType memoryType = BufferMemoryType::DEVICE_LOCAL, bool supportIndirect = false) { + return Buffer<T>::create(m_BufferManager.get(), type, count, memoryType, supportIndirect); } /** @@ -271,6 +271,14 @@ namespace vkcv const std::vector<DescriptorSetUsage> &descriptorSetUsages, const PushConstants& pushConstants); + void recordComputeIndirectDispatchToCmdStream( + const CommandStreamHandle cmdStream, + const PipelineHandle computePipeline, + const vkcv::BufferHandle buffer, + const size_t bufferArgOffset, + const std::vector<DescriptorSetUsage>& descriptorSetUsages, + const PushConstants& pushConstants); + /** * @brief end recording and present image */ diff --git a/projects/indirect_dispatch/resources/shaders/motionBlurIndirectArguments.comp b/projects/indirect_dispatch/resources/shaders/motionBlurIndirectArguments.comp new file mode 100644 index 00000000..1d225cf8 --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/motionBlurIndirectArguments.comp @@ -0,0 +1,20 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +layout(set=0, binding=0) buffer indirectArgumentBuffer { + uint dispatchArgs[3]; +}; + +layout( push_constant ) uniform constants{ + uint width; + uint height; +}; + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +void main(){ + + dispatchArgs[0] = (width + 7) / 8; + dispatchArgs[1] = (height + 7) / 8; + dispatchArgs[2] = 1; +} \ No newline at end of file diff --git a/projects/indirect_dispatch/src/MotionBlur.cpp b/projects/indirect_dispatch/src/MotionBlur.cpp index 49e8b288..9aae3f00 100644 --- a/projects/indirect_dispatch/src/MotionBlur.cpp +++ b/projects/indirect_dispatch/src/MotionBlur.cpp @@ -36,6 +36,16 @@ bool MotionBlur::initialize(vkcv::Core* corePtr, const uint32_t targetWidth, con if (!loadComputePass(*m_core, "resources/shaders/motionVectorVisualisation.comp", &m_motionVectorVisualisationPass)) return false; + if (!loadComputePass(*m_core, "resources/shaders/motionBlurIndirectArguments.comp", &m_indirectArgumentPass)) + return false; + + m_indirectArgumentBuffer = m_core->createBuffer<uint32_t>(vkcv::BufferType::STORAGE, 3, vkcv::BufferMemoryType::DEVICE_LOCAL, true).getHandle(); + + vkcv::DescriptorWrites indirectArgumentDescriptorWrites; + indirectArgumentDescriptorWrites.storageBufferWrites = + { vkcv::BufferDescriptorWrite(0, m_indirectArgumentBuffer) }; + m_core->writeDescriptorSet(m_indirectArgumentPass.descriptorSet, indirectArgumentDescriptorWrites); + m_renderTargets = MotionBlurSetup::createRenderTargets(targetWidth, targetHeight, *m_core); m_nearestSampler = m_core->createSampler( @@ -63,6 +73,26 @@ vkcv::ImageHandle MotionBlur::render( computeMotionTiles(cmdStream, motionBufferFullRes); + // write indirect dispatch argument buffer + struct IndirectArgumentConstants { + uint32_t width; + uint32_t height; + }; + vkcv::PushConstants indirectArgumentPassPushConstants(sizeof(IndirectArgumentConstants)); + IndirectArgumentConstants indirectArgumentConstants; + indirectArgumentConstants.width = m_core->getImageWidth( m_renderTargets.outputColor); + indirectArgumentConstants.height = m_core->getImageHeight(m_renderTargets.outputColor); + indirectArgumentPassPushConstants.appendDrawcall(indirectArgumentConstants); + + const uint32_t dispatchSizeOne[3] = { 1, 1, 1 }; + + m_core->recordComputeDispatchToCmdStream( + cmdStream, + m_indirectArgumentPass.pipeline, + dispatchSizeOne, + { vkcv::DescriptorSetUsage(0, m_core->getDescriptorSet(m_indirectArgumentPass.descriptorSet).vulkanHandle) }, + indirectArgumentPassPushConstants); + // usually this is the neighbourhood max, but other modes can be used for comparison/debugging vkcv::ImageHandle inputMotionTiles; if (motionVectorMode == eMotionVectorMode::FullResolution) @@ -113,15 +143,11 @@ vkcv::ImageHandle MotionBlur::render( m_core->prepareImageForSampling(cmdStream, depthBuffer); m_core->prepareImageForSampling(cmdStream, inputMotionTiles); - const auto fullscreenDispatchSizes = computeFullscreenDispatchSize( - m_core->getImageWidth(m_renderTargets.outputColor), - m_core->getImageHeight(m_renderTargets.outputColor), - 8); - - m_core->recordComputeDispatchToCmdStream( + m_core->recordComputeIndirectDispatchToCmdStream( cmdStream, m_motionBlurPass.pipeline, - fullscreenDispatchSizes.data(), + m_indirectArgumentBuffer, + 0, { vkcv::DescriptorSetUsage(0, m_core->getDescriptorSet(m_motionBlurPass.descriptorSet).vulkanHandle) }, motionBlurPushConstants); diff --git a/projects/indirect_dispatch/src/MotionBlur.hpp b/projects/indirect_dispatch/src/MotionBlur.hpp index b90cdfa4..7fede9d9 100644 --- a/projects/indirect_dispatch/src/MotionBlur.hpp +++ b/projects/indirect_dispatch/src/MotionBlur.hpp @@ -55,4 +55,7 @@ private: ComputePassHandles m_motionVectorMaxPass; ComputePassHandles m_motionVectorMaxNeighbourhoodPass; ComputePassHandles m_motionVectorVisualisationPass; + ComputePassHandles m_indirectArgumentPass; + + vkcv::BufferHandle m_indirectArgumentBuffer; }; \ No newline at end of file diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index cfa23329..3d955016 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -19,7 +19,7 @@ namespace vkcv { return; } - m_stagingBuffer = createBuffer(BufferType::STAGING, 1024 * 1024, BufferMemoryType::HOST_VISIBLE); + m_stagingBuffer = createBuffer(BufferType::STAGING, 1024 * 1024, BufferMemoryType::HOST_VISIBLE, false); } BufferManager::~BufferManager() noexcept { @@ -28,7 +28,7 @@ namespace vkcv { } } - BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) { + BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType, bool supportIndirect) { vk::BufferCreateFlags createFlags; vk::BufferUsageFlags usageFlags; @@ -56,6 +56,8 @@ namespace vkcv { if (memoryType == BufferMemoryType::DEVICE_LOCAL) { usageFlags |= vk::BufferUsageFlagBits::eTransferDst; } + if (supportIndirect) + usageFlags |= vk::BufferUsageFlagBits::eIndirectBuffer; const vma::Allocator& allocator = m_core->getContext().getAllocator(); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index e8e172dd..92e2df4f 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -507,6 +507,42 @@ namespace vkcv recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); } + void Core::recordComputeIndirectDispatchToCmdStream( + const CommandStreamHandle cmdStream, + const PipelineHandle computePipeline, + const vkcv::BufferHandle buffer, + const size_t bufferArgOffset, + const std::vector<DescriptorSetUsage>& descriptorSetUsages, + const PushConstants& pushConstants) { + + auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { + + const auto pipelineLayout = m_PipelineManager->getVkPipelineLayout(computePipeline); + + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, m_PipelineManager->getVkPipeline(computePipeline)); + for (const auto& usage : descriptorSetUsages) { + cmdBuffer.bindDescriptorSets( + vk::PipelineBindPoint::eCompute, + pipelineLayout, + usage.setLocation, + { usage.vulkanHandle }, + usage.dynamicOffsets + ); + } + if (pushConstants.getSizePerDrawcall() > 0) { + cmdBuffer.pushConstants( + pipelineLayout, + vk::ShaderStageFlagBits::eCompute, + 0, + pushConstants.getSizePerDrawcall(), + pushConstants.getData()); + } + cmdBuffer.dispatchIndirect(m_BufferManager->getBuffer(buffer), bufferArgOffset); + }; + + recordCommandsToStream(cmdStream, submitFunction, nullptr); + } + void Core::endFrame() { if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 1cb6ad3a..4ddd7f8c 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -387,7 +387,7 @@ namespace vkcv { const size_t max_size = std::min(size, image_size); BufferHandle bufferHandle = m_bufferManager.createBuffer( - BufferType::STAGING, max_size, BufferMemoryType::HOST_VISIBLE + BufferType::STAGING, max_size, BufferMemoryType::HOST_VISIBLE, false ); m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0); -- GitLab