#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; }