/* * 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 * */ #include #include #include #include #include #include #include #include #include namespace AZ { namespace Render { constexpr AZStd::string_view DiffuseProbeGridPrepareShaderProductAssetPath = "shaders/diffuseglobalillumination/diffuseprobegridprepare.azshader"; RPI::Ptr DiffuseProbeGridPreparePass::Create(const RPI::PassDescriptor& descriptor) { RPI::Ptr pass = aznew DiffuseProbeGridPreparePass(descriptor); return AZStd::move(pass); } DiffuseProbeGridPreparePass::DiffuseProbeGridPreparePass(const RPI::PassDescriptor& descriptor) : RPI::RenderPass(descriptor) { if (!AZ_TRAIT_DIFFUSE_GI_PASSES_SUPPORTED) { // GI is not supported on this platform SetEnabled(false); } else { LoadShader(); } } void DiffuseProbeGridPreparePass::LoadShader() { // load shader // Note: the shader may not be available on all platforms m_shader = RPI::LoadCriticalShader(DiffuseProbeGridPrepareShaderProductAssetPath); if (m_shader == nullptr) { return; } // load pipeline state RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; const auto& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); // load Pass Srg asset m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); if (!outcome.IsSuccess()) { AZ_Error("PassSystem", false, "[DiffuseProbeGridPreparePass '%s']: Shader '" AZ_STRING_FORMAT "' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), AZ_STRING_ARG(DiffuseProbeGridPrepareShaderProductAssetPath), outcome.GetError().c_str()); } } bool DiffuseProbeGridPreparePass::IsEnabled() const { if (!RenderPass::IsEnabled()) { return false; } RPI::Scene* scene = m_pipeline->GetScene(); if (!scene) { return false; } DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids().empty()) { // no diffuse probe grids return false; } return true; } void DiffuseProbeGridPreparePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) { RenderPass::SetupFrameGraphDependencies(frameGraph); RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); frameGraph.SetEstimatedItemCount(aznumeric_cast(diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids().size())); for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) { // grid data buffer { [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportBuffer(diffuseProbeGrid->GetGridDataBufferAttachmentId(), diffuseProbeGrid->GetGridDataBuffer()); AZ_Assert(result == RHI::ResultCode::Success, "Failed to import grid data buffer"); RHI::BufferScopeAttachmentDescriptor desc; desc.m_attachmentId = diffuseProbeGrid->GetGridDataBufferAttachmentId(); desc.m_bufferViewDescriptor = diffuseProbeGrid->GetRenderData()->m_gridDataBufferViewDescriptor; desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; frameGraph.UseShaderAttachment( desc, RHI::ScopeAttachmentAccess::ReadWrite, RHI::ScopeAttachmentStage::ComputeShader); } } } void DiffuseProbeGridPreparePass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context) { RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()) { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) diffuseProbeGrid->UpdatePrepareSrg(m_shader, m_srgLayout); diffuseProbeGrid->GetPrepareSrg()->Compile(); } } void DiffuseProbeGridPreparePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) { RHI::CommandList* commandList = context.GetCommandList(); RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); // submit the DispatchItems for each DiffuseProbeGrid in this range for (uint32_t index = context.GetSubmitRange().m_startIndex; index < context.GetSubmitRange().m_endIndex; ++index) { AZStd::shared_ptr diffuseProbeGrid = diffuseProbeGridFeatureProcessor->GetVisibleProbeGrids()[index]; const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetPrepareSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup->GetDeviceShaderResourceGroup(context.GetDeviceIndex())); RHI::DeviceDispatchItem dispatchItem; dispatchItem.m_arguments = m_dispatchArgs; dispatchItem.m_pipelineState = m_pipelineState->GetDevicePipelineState(context.GetDeviceIndex()).get(); dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = 1; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = 1; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1; commandList->Submit(dispatchItem, index); } } } // namespace Render } // namespace AZ