From 4605eed0dada41630abc945e8e29b80535ee9ddf Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sat, 24 Dec 2022 12:50:04 +0100 Subject: [PATCH] Add compute demo (WIP) + fixes creation of compute pipelines --- examples/ComputeTest/main.cpp | 132 ++++++++++++++++++ examples/ComputeTest/xmake.lua | 3 + include/Nazara/OpenGLRenderer.hpp | 1 + include/Nazara/Renderer.hpp | 1 + include/Nazara/VulkanRenderer.hpp | 1 + .../OpenGLRenderer/OpenGLComputePipeline.cpp | 6 +- .../VulkanRenderer/VulkanComputePipeline.cpp | 2 +- .../VulkanRenderer/VulkanShaderModule.cpp | 11 +- 8 files changed, 145 insertions(+), 12 deletions(-) create mode 100644 examples/ComputeTest/main.cpp create mode 100644 examples/ComputeTest/xmake.lua diff --git a/examples/ComputeTest/main.cpp b/examples/ComputeTest/main.cpp new file mode 100644 index 000000000..0dcd879cd --- /dev/null +++ b/examples/ComputeTest/main.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +NAZARA_REQUEST_DEDICATED_GPU() + +const char shaderSource[] = R"( +[nzsl_version("1.0")] +module; + +external +{ + [binding(0)] input_tex: texture2D[f32, readonly, rgba8], + [binding(1)] output_tex: texture2D[f32, writeonly, rgba8] +} + +struct Input +{ + [builtin(global_invocation_indices)] global_invocation_id: vec3[u32] +} + +[entry(compute)] +[workgroup(16, 16, 1)] +fn main(input: Input) +{ + let indices = vec2[i32](input.global_invocation_id.xy); + let color = input_tex.Read(indices); + output_tex.Write(indices, color); +} +)"; + +struct ComputePipeline +{ + std::shared_ptr layout; + std::shared_ptr pipeline; +}; + +ComputePipeline BuildComputePipeline(Nz::RenderDevice& device) +{ + try + { + nzsl::Ast::ModulePtr shaderModule = nzsl::Parse(std::string_view(shaderSource, sizeof(shaderSource))); + if (!shaderModule) + { + std::cout << "Failed to parse shader module" << std::endl; + std::abort(); + } + + nzsl::ShaderWriter::States states; + states.optimize = true; + + auto computeShader = device.InstantiateShaderModule(nzsl::ShaderStageType::Compute, *shaderModule, states); + if (!computeShader) + { + std::cout << "Failed to instantiate shader" << std::endl; + std::abort(); + } + + Nz::RenderPipelineLayoutInfo computePipelineLayoutInfo; + + auto& inputBinding = computePipelineLayoutInfo.bindings.emplace_back(); + inputBinding.setIndex = 0; + inputBinding.bindingIndex = 0; + inputBinding.shaderStageFlags = nzsl::ShaderStageType::Compute; + inputBinding.type = Nz::ShaderBindingType::Texture; + + auto& outputBinding = computePipelineLayoutInfo.bindings.emplace_back(); + outputBinding.setIndex = 0; + outputBinding.bindingIndex = 1; + outputBinding.shaderStageFlags = nzsl::ShaderStageType::Compute; + outputBinding.type = Nz::ShaderBindingType::Texture; + + std::shared_ptr pipelineLayout = device.InstantiateRenderPipelineLayout(computePipelineLayoutInfo); + + Nz::ComputePipelineInfo computePipelineInfo; + computePipelineInfo.pipelineLayout = pipelineLayout; + computePipelineInfo.shaderModule = computeShader; + + std::shared_ptr pipeline = device.InstantiateComputePipeline(computePipelineInfo); + if (!pipeline) + { + std::cout << "Failed to instantiate compute pipeline" << std::endl; + std::abort(); + } + + ComputePipeline result; + result.layout = std::move(pipelineLayout); + result.pipeline = std::move(pipeline); + return result; + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + std::abort(); + } +} + +int main() +{ + std::filesystem::path resourceDir = "assets/examples"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory("../.." / resourceDir)) + resourceDir = "../.." / resourceDir; + + Nz::Renderer::Config rendererConfig; + std::cout << "Run using Vulkan? (y/n)" << std::endl; + if (std::getchar() == 'y') + rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan; + else + rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL; + + Nz::Modules nazara(rendererConfig); + + Nz::RenderDeviceFeatures enabledFeatures; + enabledFeatures.computeShaders = true; + enabledFeatures.textureRead = true; + enabledFeatures.textureWrite = true; + + std::shared_ptr device = Nz::Renderer::Instance()->InstanciateRenderDevice(0, enabledFeatures); + + ComputePipeline result = BuildComputePipeline(*device); + + + return EXIT_SUCCESS; +} diff --git a/examples/ComputeTest/xmake.lua b/examples/ComputeTest/xmake.lua new file mode 100644 index 000000000..2158a8e9d --- /dev/null +++ b/examples/ComputeTest/xmake.lua @@ -0,0 +1,3 @@ +target("ComputeTest") + add_deps("NazaraRenderer") + add_files("main.cpp") diff --git a/include/Nazara/OpenGLRenderer.hpp b/include/Nazara/OpenGLRenderer.hpp index ee283d1f2..e4dadf2dd 100644 --- a/include/Nazara/OpenGLRenderer.hpp +++ b/include/Nazara/OpenGLRenderer.hpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 4a9823489..77af8b018 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/VulkanRenderer.hpp b/include/Nazara/VulkanRenderer.hpp index 606f43467..faf8cedc7 100644 --- a/include/Nazara/VulkanRenderer.hpp +++ b/include/Nazara/VulkanRenderer.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/src/Nazara/OpenGLRenderer/OpenGLComputePipeline.cpp b/src/Nazara/OpenGLRenderer/OpenGLComputePipeline.cpp index 1003fc389..5677317f7 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLComputePipeline.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLComputePipeline.cpp @@ -19,7 +19,7 @@ namespace Nz OpenGLComputePipeline::OpenGLComputePipeline(OpenGLDevice& device, ComputePipelineInfo pipelineInfo) : m_pipelineInfo(std::move(pipelineInfo)) { - if (device.GetEnabledFeatures().computeShaders) + if (!device.GetEnabledFeatures().computeShaders) throw std::runtime_error("compute shaders are not enabled on the device"); OpenGLRenderPipelineLayout& pipelineLayout = static_cast(*m_pipelineInfo.pipelineLayout); @@ -27,9 +27,9 @@ namespace Nz if (!m_program.Create(device)) throw std::runtime_error("failed to create program"); - NazaraAssert(pipelineInfo.shaderModule, "invalid shader module"); + NazaraAssert(m_pipelineInfo.shaderModule, "invalid shader module"); - OpenGLShaderModule& shaderModule = static_cast(*pipelineInfo.shaderModule); + OpenGLShaderModule& shaderModule = static_cast(*m_pipelineInfo.shaderModule); std::vector explicitBindings; nzsl::ShaderStageTypeFlags stageFlags = shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping(), &explicitBindings); diff --git a/src/Nazara/VulkanRenderer/VulkanComputePipeline.cpp b/src/Nazara/VulkanRenderer/VulkanComputePipeline.cpp index 3c878b57f..f81ab1abe 100644 --- a/src/Nazara/VulkanRenderer/VulkanComputePipeline.cpp +++ b/src/Nazara/VulkanRenderer/VulkanComputePipeline.cpp @@ -17,7 +17,7 @@ namespace Nz VulkanComputePipeline::VulkanComputePipeline(VulkanDevice& device, ComputePipelineInfo pipelineInfo) : m_pipelineInfo(std::move(pipelineInfo)) { - if (device.GetEnabledFeatures().computeShaders) + if (!device.GetEnabledFeatures().computeShaders) throw std::runtime_error("compute shaders are not enabled on the device"); VulkanShaderModule& vulkanModule = static_cast(*m_pipelineInfo.shaderModule); diff --git a/src/Nazara/VulkanRenderer/VulkanShaderModule.cpp b/src/Nazara/VulkanRenderer/VulkanShaderModule.cpp index cb851a3e0..f693320df 100644 --- a/src/Nazara/VulkanRenderer/VulkanShaderModule.cpp +++ b/src/Nazara/VulkanRenderer/VulkanShaderModule.cpp @@ -104,14 +104,9 @@ namespace Nz nzsl::ShaderStageType stageType; switch (entryPoint.executionModel) { - case nzsl::SpirvExecutionModel::Fragment: - stageType = nzsl::ShaderStageType::Fragment; - break; - - case nzsl::SpirvExecutionModel::Vertex: - stageType = nzsl::ShaderStageType::Vertex; - break; - + case nzsl::SpirvExecutionModel::GLCompute: stageType = nzsl::ShaderStageType::Compute; break; + case nzsl::SpirvExecutionModel::Fragment: stageType = nzsl::ShaderStageType::Fragment; break; + case nzsl::SpirvExecutionModel::Vertex: stageType = nzsl::ShaderStageType::Vertex; break; default: continue; //< Ignore }