/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace AtomSampleViewer { //! This samples demonstrates the use of indirect rendering. //! It uses an indirect buffer that contains a list of commands //! to be executed by the GPU in an indirect manner. //! The commands are generated at initialization by the CPU. Each frame //! a compute shader culls the commands that are outside a designated area //! and the remaining commands are draw using indirect calls. //! The sample has two user control variables: //! - The number of primitives to render //! - The cull area. //! //! Depending on the capabilities of the platform the sample can run the following indirect commands: //! 1) - Inline Constants Command //! - Set Vertex View Command //! - Set Index View Command //! - Draw Indexed Command //! //! 2) - Draw Indexed command //! //! Depending on capabilities, the samples may use a count buffer. //! The number of indirect draw calls is also determinate by device capabilities. //! class IndirectRenderingExampleComponent final : public BasicRHIComponent , public AZ::TickBus::Handler , public AzFramework::WindowNotificationBus::Handler , public AZ::RPI::ShaderReloadNotificationBus::MultiHandler { public: AZ_COMPONENT(IndirectRenderingExampleComponent, "{B799BEFC-52AF-47FF-A806-29E38A5BDF12}", AZ::Component); AZ_DISABLE_COPY(IndirectRenderingExampleComponent); static void Reflect(AZ::ReflectContext* context); IndirectRenderingExampleComponent(); ~IndirectRenderingExampleComponent() override = default; static constexpr char LogName[] = "IndirectRenderingExampleComponent"; static constexpr char IndirectDrawShaderFilePath[] = "Shaders/RHI/IndirectDraw.azshader"; static constexpr char IndirectDispatchShaderFilePath[] = "Shaders/RHI/IndirectDispatch.azshader"; static constexpr char IndirectDrawVariantLabel[] = "IndirectDraw variant"; static constexpr char IndirectDispatchVariantLabel[] = "IndirectDispatch variant"; private: /// Max number of objects to render. static const uint32_t s_maxNumberOfObjects = 4096; /// Data to be use for Input Assembly. struct BufferData { AZStd::array m_trianglePositions; AZStd::array m_quadPositions; AZStd::array m_triangleIndices; AZStd::array m_quadIndices; AZStd::array m_instanceIndices; }; /// Data specific to an object. struct InstanceData { AZ::Color m_color; AZ::Vector4 m_offset; AZ::Vector4 m_scale; AZ::Vector4 m_velocity; }; struct ScopeData { //UserDataParam - Empty for this samples }; /// The indirect commands that the indirect buffer will contain. enum class SequenceType: uint8_t { DrawOnly = 0, // The buffer will contain only a draw indexed command. IARootConstantsDraw, // The buffer will contain a set vertex buffer, set index buffer, set // root constants and a draw indexed command. Count }; static const uint32_t NumSequencesType = static_cast(SequenceType::Count); // AZ::Component void Activate() override; void Deactivate() override; // AZ::TickBus::Handler void OnTick(float deltaTime, AZ::ScriptTimePoint time); // RHISystemNotificationBus::Handler void OnFramePrepare(AZ::RHI::FrameGraphBuilder& frameGraphBuilder) override; // AzFramework::WindowNotificationBus::Handler void OnWindowResized(uint32_t width, uint32_t height) override; /////////////////////////////////////////////////////////////////////// // ShaderReloadNotificationBus overrides void OnShaderVariantReinitialized(const AZ::RPI::ShaderVariant& shaderVariant) override; /////////////////////////////////////////////////////////////////////// void InitRequestsForShaderVariants(); void OnAllAssetsReadyActivate(); void InitInputAssemblyResources(); void InitShaderResources(); void InitIndirectRenderingResources(); void InitInstancesDataResources(); void CreateResetCounterBufferScope(); void CreateCullingScope(); void CreateDrawingScope(); void DrawSampleSettings(); void UpdateInstancesData(float deltaTime); void UpdateIndirectDispatchArguments(); AZ::RHI::InputStreamLayout m_inputStreamLayout; AZ::RHI::Ptr m_inputAssemblyBufferPool; AZ::RHI::Ptr m_shaderBufferPool; AZ::RHI::Ptr m_instancesBufferPool; AZ::RHI::Ptr m_copyBufferPool; AZ::RHI::Ptr m_inputAssemblyBuffer; AZ::RHI::Ptr m_sourceIndirectBuffer; AZ::RHI::Ptr m_instancesDataBuffer; AZ::RHI::Ptr m_resetCounterBuffer; AZ::RHI::Ptr m_indirectDispatchBuffer; AZ::RHI::ConstPtr m_drawPipelineState; AZ::RHI::ConstPtr m_cullPipelineState; AZ::Data::Instance m_sceneShaderResourceGroup; AZ::Data::Instance m_cullShaderResourceGroup; AZStd::array, NumSequencesType> m_indirectCommandsShaderResourceGroups; AZStd::vector m_geometryViews; AZStd::array m_streamBufferViews; AZStd::array m_indexBufferViews; AZ::RHI::IndirectBufferView m_indirectDrawBufferView; AZ::RHI::IndirectBufferView m_indirectDispatchBufferView; AZ::RHI::Ptr m_sourceIndirectBufferView; AZ::RHI::Ptr m_instancesDataBufferView; AZ::RHI::IndirectBufferLayout m_indirectDrawBufferLayout; AZ::RHI::IndirectBufferLayout m_indirectDispatchBufferLayout; AZ::RHI::Ptr m_indirectDrawBufferSignature; AZ::RHI::Ptr m_indirectDispatchBufferSignature; AZ::RHI::ShaderInputBufferIndex m_sceneInstancesDataBufferIndex; AZ::RHI::ShaderInputConstantIndex m_sceneMatrixInputIndex; AZ::RHI::ShaderInputBufferIndex m_cullingCountBufferIndex; AZ::RHI::ShaderInputConstantIndex m_cullingOffsetIndex; AZ::RHI::ShaderInputConstantIndex m_cullingNumCommandsIndex; AZ::RHI::ShaderInputConstantIndex m_cullingMaxCommandsIndex; AZStd::array m_cullingInputIndirectBufferIndices; AZStd::array m_cullingOutputIndirectBufferIndices; AZ::RHI::Ptr m_indirectDispatchWriter; AZ::RHI::DrawIndirect m_drawIndirect; AZ::RHI::CopyBufferDescriptor m_copyDescriptor; ImGuiSidebar m_imguiSidebar; float m_cullOffset = 1.0f; uint32_t m_numObjects = 0; AZStd::vector m_instancesData; SequenceType m_mode = SequenceType::DrawOnly; bool m_updateIndirectDispatchArguments = false; bool m_deviceSupportsCountBuffer = false; // REMARK: This example requires static shader options to run properly. // We use notifications from ShaderVariantFinderNotificationBus & this flag to get the // green light to proceed into full activation. bool m_doneLoadingShaders = false; AZStd::unique_ptr m_assetLoadManager; ImGuiProgressList m_imguiProgressList; AZ::Data::Instance m_indirectDrawShader; AZ::RPI::ShaderOptionGroup m_indirectDrawShaderOptionGroup; AZ::RPI::ShaderVariantStableId m_indirectDrawShaderVariantStableId; AZ::Data::Instance m_indirectDispatchShader; AZ::RPI::ShaderOptionGroup m_indirectDispatchShaderOptionGroup; AZ::RPI::ShaderVariantStableId m_indirectDispatchShaderVariantStableId; }; } // namespace AtomSampleViewer