Add initial support for compute pipelines
This commit is contained in:
committed by
Jérôme Leclercq
parent
e4064997d8
commit
9578ba3ef5
@@ -54,11 +54,20 @@ namespace Nz
|
||||
deviceInfo.name = physDevice.properties.deviceName;
|
||||
|
||||
deviceInfo.features.anisotropicFiltering = physDevice.features.samplerAnisotropy;
|
||||
deviceInfo.features.computeShaders = true;
|
||||
deviceInfo.features.depthClamping = physDevice.features.depthClamp;
|
||||
deviceInfo.features.nonSolidFaceFilling = physDevice.features.fillModeNonSolid;
|
||||
deviceInfo.features.storageBuffers = true;
|
||||
deviceInfo.features.textureRead = true;
|
||||
deviceInfo.features.textureReadWithoutFormat = physDevice.features.shaderStorageImageReadWithoutFormat;
|
||||
deviceInfo.features.textureWrite = true;
|
||||
deviceInfo.features.textureWriteWithoutFormat = physDevice.features.shaderStorageImageWriteWithoutFormat;
|
||||
deviceInfo.features.unrestrictedTextureViews = true;
|
||||
|
||||
deviceInfo.limits.maxComputeSharedMemorySize = physDevice.properties.limits.maxComputeSharedMemorySize;
|
||||
deviceInfo.limits.maxComputeWorkGroupCount = { physDevice.properties.limits.maxComputeWorkGroupCount[0], physDevice.properties.limits.maxComputeWorkGroupCount[1], physDevice.properties.limits.maxComputeWorkGroupCount[2] };
|
||||
deviceInfo.limits.maxComputeWorkGroupSize = { physDevice.properties.limits.maxComputeWorkGroupSize[0], physDevice.properties.limits.maxComputeWorkGroupSize[1], physDevice.properties.limits.maxComputeWorkGroupSize[2] };
|
||||
deviceInfo.limits.maxComputeWorkGroupInvocations = physDevice.properties.limits.maxComputeWorkGroupInvocations;
|
||||
deviceInfo.limits.maxStorageBufferSize = physDevice.properties.limits.maxStorageBufferRange;
|
||||
deviceInfo.limits.maxUniformBufferSize = physDevice.properties.limits.maxUniformBufferRange;
|
||||
deviceInfo.limits.minStorageBufferOffsetAlignment = physDevice.properties.limits.minStorageBufferOffsetAlignment;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
||||
@@ -72,6 +73,13 @@ namespace Nz
|
||||
m_currentSubpassIndex = 0;
|
||||
}
|
||||
|
||||
void VulkanCommandBufferBuilder::BindComputePipeline(const ComputePipeline& pipeline)
|
||||
{
|
||||
const VulkanComputePipeline& vkPipeline = static_cast<const VulkanComputePipeline&>(pipeline);
|
||||
|
||||
m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vkPipeline.GetPipeline());
|
||||
}
|
||||
|
||||
void VulkanCommandBufferBuilder::BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset)
|
||||
{
|
||||
const VulkanBuffer& vkBuffer = static_cast<const VulkanBuffer&>(indexBuffer);
|
||||
@@ -79,14 +87,14 @@ namespace Nz
|
||||
m_commandBuffer.BindIndexBuffer(vkBuffer.GetBuffer(), offset, ToVulkan(indexType));
|
||||
}
|
||||
|
||||
void VulkanCommandBufferBuilder::BindPipeline(const RenderPipeline& pipeline)
|
||||
void VulkanCommandBufferBuilder::BindRenderPipeline(const RenderPipeline& pipeline)
|
||||
{
|
||||
if (!m_currentRenderPass)
|
||||
throw std::runtime_error("BindPipeline must be called in a RenderPass");
|
||||
|
||||
const VulkanRenderPipeline& vkBinding = static_cast<const VulkanRenderPipeline&>(pipeline);
|
||||
const VulkanRenderPipeline& vkPipeline = static_cast<const VulkanRenderPipeline&>(pipeline);
|
||||
|
||||
m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(*m_currentRenderPass, m_currentSubpassIndex));
|
||||
m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline.Get(*m_currentRenderPass, m_currentSubpassIndex));
|
||||
}
|
||||
|
||||
void VulkanCommandBufferBuilder::BindShaderBinding(UInt32 set, const ShaderBinding& binding)
|
||||
@@ -207,6 +215,11 @@ namespace Nz
|
||||
m_commandBuffer.CopyImage(vkFromTexture.GetImage(), ToVulkan(fromLayout), vkToTexture.GetImage(), ToVulkan(toLayout), region);
|
||||
}
|
||||
|
||||
void VulkanCommandBufferBuilder::Dispatch(UInt32 workgroupX, UInt32 workgroupY, UInt32 workgroupZ)
|
||||
{
|
||||
m_commandBuffer.Dispatch(workgroupX, workgroupY, workgroupZ);
|
||||
}
|
||||
|
||||
void VulkanCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
|
||||
{
|
||||
m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance);
|
||||
|
||||
61
src/Nazara/VulkanRenderer/VulkanComputePipeline.cpp
Normal file
61
src/Nazara/VulkanRenderer/VulkanComputePipeline.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Vulkan renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/VulkanRenderer/Utils.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanShaderModule.hpp>
|
||||
#include <cassert>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
VulkanComputePipeline::VulkanComputePipeline(VulkanDevice& device, ComputePipelineInfo pipelineInfo) :
|
||||
m_pipelineInfo(std::move(pipelineInfo))
|
||||
{
|
||||
if (device.GetEnabledFeatures().computeShaders)
|
||||
throw std::runtime_error("compute shaders are not enabled on the device");
|
||||
|
||||
VulkanShaderModule& vulkanModule = static_cast<VulkanShaderModule&>(*m_pipelineInfo.shaderModule);
|
||||
const VulkanShaderModule::Stage* computeStage = nullptr;
|
||||
for (const auto& stage : vulkanModule.GetStages())
|
||||
{
|
||||
if (stage.stage != nzsl::ShaderStageType::Compute)
|
||||
continue;
|
||||
|
||||
if (computeStage)
|
||||
throw std::runtime_error("multiple compute stages found in shader module");
|
||||
|
||||
computeStage = &stage;
|
||||
}
|
||||
|
||||
if (!computeStage)
|
||||
throw std::runtime_error("no compute stages found in shader module");
|
||||
|
||||
VkComputePipelineCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
createInfo.stage.module = vulkanModule.GetHandle();
|
||||
createInfo.stage.pName = computeStage->name.data();
|
||||
createInfo.stage.stage = ToVulkan(computeStage->stage);
|
||||
|
||||
VulkanRenderPipelineLayout& pipelineLayout = *static_cast<VulkanRenderPipelineLayout*>(m_pipelineInfo.pipelineLayout.get());
|
||||
createInfo.layout = pipelineLayout.GetPipelineLayout();
|
||||
|
||||
if (!m_pipeline.CreateCompute(device, createInfo))
|
||||
throw std::runtime_error("failed to create compute pipeline: " + TranslateVulkanError(m_pipeline.GetLastErrorCode()));
|
||||
}
|
||||
|
||||
void VulkanComputePipeline::UpdateDebugName(std::string_view name)
|
||||
{
|
||||
m_pipeline.SetDebugName(name);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Core/AntiWindows.hpp>
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
||||
@@ -37,6 +38,11 @@ namespace Nz
|
||||
return std::make_shared<VulkanCommandPool>(*this, queueType);
|
||||
}
|
||||
|
||||
std::shared_ptr<ComputePipeline> VulkanDevice::InstantiateComputePipeline(ComputePipelineInfo pipelineInfo)
|
||||
{
|
||||
return std::make_shared<VulkanComputePipeline>(*this, std::move(pipelineInfo));
|
||||
}
|
||||
|
||||
std::shared_ptr<Framebuffer> VulkanDevice::InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments)
|
||||
{
|
||||
return std::make_shared<VulkanTextureFramebuffer>(*this, width, height, renderPass, attachments);
|
||||
@@ -111,6 +117,10 @@ namespace Nz
|
||||
flags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
break;
|
||||
|
||||
case TextureUsage::ShaderReadWrite:
|
||||
flags = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
|
||||
break;
|
||||
|
||||
case TextureUsage::TransferSource:
|
||||
flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
|
||||
break;
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace Nz
|
||||
|
||||
if constexpr (std::is_same_v<T, StorageBufferBinding> || std::is_same_v<T, UniformBufferBinding>)
|
||||
bufferBindingCount++;
|
||||
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||
else if constexpr (std::is_same_v<T, SampledTextureBinding> || std::is_same_v<T, TextureBinding>)
|
||||
imageBindingCount++;
|
||||
else if constexpr (std::is_same_v<T, TextureBindings>)
|
||||
else if constexpr (std::is_same_v<T, SampledTextureBindings>)
|
||||
imageBindingCount += arg.arraySize;
|
||||
else
|
||||
static_assert(AlwaysFalse<T>(), "non-exhaustive visitor");
|
||||
@@ -58,20 +58,7 @@ namespace Nz
|
||||
{
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, StorageBufferBinding>)
|
||||
{
|
||||
VulkanBuffer* vkBuffer = SafeCast<VulkanBuffer*>(arg.buffer);
|
||||
|
||||
VkDescriptorBufferInfo& bufferInfo = bufferBinding.emplace_back();
|
||||
bufferInfo.buffer = (vkBuffer) ? vkBuffer->GetBuffer() : VK_NULL_HANDLE;
|
||||
bufferInfo.offset = arg.offset;
|
||||
bufferInfo.range = arg.range;
|
||||
|
||||
writeOp.descriptorCount = 1;
|
||||
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
writeOp.pBufferInfo = &bufferInfo;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||
if constexpr (std::is_same_v<T, SampledTextureBinding>)
|
||||
{
|
||||
const VulkanTexture* vkTexture = SafeCast<const VulkanTexture*>(arg.texture);
|
||||
const VulkanTextureSampler* vkSampler = SafeCast<const VulkanTextureSampler*>(arg.sampler);
|
||||
@@ -85,7 +72,7 @@ namespace Nz
|
||||
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeOp.pImageInfo = &imageInfo;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, TextureBindings>)
|
||||
else if constexpr (std::is_same_v<T, SampledTextureBindings>)
|
||||
{
|
||||
for (UInt32 i = 0; i < arg.arraySize; ++i)
|
||||
{
|
||||
@@ -102,6 +89,32 @@ namespace Nz
|
||||
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeOp.pImageInfo = &imageBinding[imageBinding.size() - arg.arraySize];
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, StorageBufferBinding>)
|
||||
{
|
||||
VulkanBuffer* vkBuffer = SafeCast<VulkanBuffer*>(arg.buffer);
|
||||
|
||||
VkDescriptorBufferInfo& bufferInfo = bufferBinding.emplace_back();
|
||||
bufferInfo.buffer = (vkBuffer) ? vkBuffer->GetBuffer() : VK_NULL_HANDLE;
|
||||
bufferInfo.offset = arg.offset;
|
||||
bufferInfo.range = arg.range;
|
||||
|
||||
writeOp.descriptorCount = 1;
|
||||
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
writeOp.pBufferInfo = &bufferInfo;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||
{
|
||||
const VulkanTexture* vkTexture = SafeCast<const VulkanTexture*>(arg.texture);
|
||||
|
||||
VkDescriptorImageInfo& imageInfo = imageBinding.emplace_back();
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imageInfo.imageView = (vkTexture) ? vkTexture->GetImageView() : VK_NULL_HANDLE;
|
||||
imageInfo.sampler = VK_NULL_HANDLE;
|
||||
|
||||
writeOp.descriptorCount = 1;
|
||||
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
writeOp.pImageInfo = &imageInfo;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, UniformBufferBinding>)
|
||||
{
|
||||
VulkanBuffer* vkBuffer = static_cast<VulkanBuffer*>(arg.buffer);
|
||||
|
||||
Reference in New Issue
Block a user