3
0

ComputePass.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Asset/AssetCommon.h>
  9. #include <AzCore/Asset/AssetManagerBus.h>
  10. #include <Atom/RHI/CommandList.h>
  11. #include <Atom/RHI/Factory.h>
  12. #include <Atom/RHI/FrameScheduler.h>
  13. #include <Atom/RHI/DevicePipelineState.h>
  14. #include <Atom/RPI.Reflect/Pass/ComputePassData.h>
  15. #include <Atom/RPI.Reflect/Pass/PassTemplate.h>
  16. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  17. #include <Atom/RPI.Public/Pass/ComputePass.h>
  18. #include <Atom/RPI.Public/Pass/PassUtils.h>
  19. #include <Atom/RPI.Public/RPIUtils.h>
  20. #include <Atom/RPI.Public/Shader/Shader.h>
  21. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  22. namespace AZ
  23. {
  24. namespace RPI
  25. {
  26. ComputePass::~ComputePass()
  27. {
  28. ShaderReloadNotificationBus::Handler::BusDisconnect();
  29. }
  30. Ptr<ComputePass> ComputePass::Create(const PassDescriptor& descriptor)
  31. {
  32. Ptr<ComputePass> pass = aznew ComputePass(descriptor);
  33. return pass;
  34. }
  35. ComputePass::ComputePass(const PassDescriptor& descriptor, AZ::Name supervariant)
  36. : RenderPass(descriptor)
  37. , m_dispatchItem(RHI::MultiDevice::AllDevices)
  38. , m_passDescriptor(descriptor)
  39. {
  40. const ComputePassData* passData = PassUtils::GetPassData<ComputePassData>(m_passDescriptor);
  41. if (passData == nullptr)
  42. {
  43. AZ_Error(
  44. "PassSystem", false, "[ComputePass '%s']: Trying to construct without valid ComputePassData!", GetPathName().GetCStr());
  45. return;
  46. }
  47. RHI::DispatchDirect dispatchArgs;
  48. dispatchArgs.m_totalNumberOfThreadsX = passData->m_totalNumberOfThreadsX;
  49. dispatchArgs.m_totalNumberOfThreadsY = passData->m_totalNumberOfThreadsY;
  50. dispatchArgs.m_totalNumberOfThreadsZ = passData->m_totalNumberOfThreadsZ;
  51. m_dispatchItem.SetArguments(dispatchArgs);
  52. LoadShader(supervariant);
  53. m_defaultShaderAttachmentStage = RHI::ScopeAttachmentStage::ComputeShader;
  54. }
  55. void ComputePass::LoadShader(AZ::Name supervariant)
  56. {
  57. // Load ComputePassData...
  58. const ComputePassData* passData = PassUtils::GetPassData<ComputePassData>(m_passDescriptor);
  59. if (passData == nullptr)
  60. {
  61. AZ_Error("PassSystem", false, "[ComputePass '%s']: Trying to construct without valid ComputePassData!",
  62. GetPathName().GetCStr());
  63. return;
  64. }
  65. // Hardware Queue Class
  66. if (passData->m_useAsyncCompute)
  67. {
  68. m_hardwareQueueClass = RHI::HardwareQueueClass::Compute;
  69. }
  70. // Load Shader
  71. Data::Asset<ShaderAsset> shaderAsset;
  72. if (passData->m_shaderReference.m_assetId.IsValid())
  73. {
  74. shaderAsset = RPI::FindShaderAsset(passData->m_shaderReference.m_assetId, passData->m_shaderReference.m_filePath);
  75. }
  76. if (!shaderAsset.IsReady())
  77. {
  78. AZ_Error("PassSystem", false, "[ComputePass '%s']: Failed to load shader '%s'!",
  79. GetPathName().GetCStr(),
  80. passData->m_shaderReference.m_filePath.data());
  81. return;
  82. }
  83. m_shader = Shader::FindOrCreate(shaderAsset, supervariant);
  84. if (m_shader == nullptr)
  85. {
  86. AZ_Error("PassSystem", false, "[ComputePass '%s']: Failed to create shader instance from asset '%s'!",
  87. GetPathName().GetCStr(),
  88. passData->m_shaderReference.m_filePath.data());
  89. return;
  90. }
  91. // Load Pass SRG...
  92. const auto passSrgLayout = m_shader->FindShaderResourceGroupLayout(SrgBindingSlot::Pass);
  93. if (passSrgLayout)
  94. {
  95. m_shaderResourceGroup = ShaderResourceGroup::Create(shaderAsset, m_shader->GetSupervariantIndex(), passSrgLayout->GetName());
  96. AZ_Assert(m_shaderResourceGroup, "[ComputePass '%s']: Failed to create SRG from shader asset '%s'",
  97. GetPathName().GetCStr(),
  98. passData->m_shaderReference.m_filePath.data());
  99. PassUtils::BindDataMappingsToSrg(m_passDescriptor, m_shaderResourceGroup.get());
  100. }
  101. // Load Draw SRG...
  102. const bool compileDrawSrg = false; // The SRG will be compiled in CompileResources()
  103. m_drawSrg = m_shader->CreateDefaultDrawSrg(compileDrawSrg);
  104. if (m_dispatchItem.GetArguments().m_type == RHI::DispatchType::Direct)
  105. {
  106. auto arguments = m_dispatchItem.GetArguments();
  107. const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), arguments.m_direct);
  108. if (!outcome.IsSuccess())
  109. {
  110. AZ_Error(
  111. "PassSystem",
  112. false,
  113. "[ComputePass '%s']: Shader '%.*s' contains invalid numthreads arguments:\n%s",
  114. GetPathName().GetCStr(),
  115. passData->m_shaderReference.m_filePath.size(),
  116. passData->m_shaderReference.m_filePath.data(),
  117. outcome.GetError().c_str());
  118. }
  119. m_dispatchItem.SetArguments(arguments);
  120. }
  121. m_isFullscreenPass = passData->m_makeFullscreenPass;
  122. // Setup pipeline state...
  123. RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor;
  124. ShaderOptionGroup options = m_shader->GetDefaultShaderOptions();
  125. m_shader->GetDefaultVariant().ConfigurePipelineState(pipelineStateDescriptor, options);
  126. m_dispatchItem.SetPipelineState(m_shader->AcquirePipelineState(pipelineStateDescriptor));
  127. if (m_drawSrg && m_shader->GetDefaultVariant().UseKeyFallback())
  128. {
  129. m_drawSrg->SetShaderVariantKeyFallbackValue(options.GetShaderVariantKeyFallbackValue());
  130. }
  131. OnShaderReloadedInternal();
  132. ShaderReloadNotificationBus::Handler::BusDisconnect();
  133. ShaderReloadNotificationBus::Handler::BusConnect(passData->m_shaderReference.m_assetId);
  134. }
  135. // Scope producer functions
  136. void ComputePass::CompileResources(const RHI::FrameGraphCompileContext& context)
  137. {
  138. if (m_shaderResourceGroup != nullptr)
  139. {
  140. BindPassSrg(context, m_shaderResourceGroup);
  141. m_shaderResourceGroup->Compile();
  142. }
  143. if (m_drawSrg != nullptr)
  144. {
  145. BindSrg(m_drawSrg->GetRHIShaderResourceGroup());
  146. m_drawSrg->Compile();
  147. }
  148. }
  149. void ComputePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
  150. {
  151. RHI::CommandList* commandList = context.GetCommandList();
  152. SetSrgsForDispatch(context);
  153. commandList->Submit(m_dispatchItem.GetDeviceDispatchItem(context.GetDeviceIndex()));
  154. }
  155. void ComputePass::MatchDimensionsToOutput()
  156. {
  157. PassAttachment* outputAttachment = nullptr;
  158. if (GetOutputCount() > 0)
  159. {
  160. outputAttachment = GetOutputBinding(0).GetAttachment().get();
  161. }
  162. else if (GetInputOutputCount() > 0)
  163. {
  164. outputAttachment = GetInputOutputBinding(0).GetAttachment().get();
  165. }
  166. AZ_Assert(outputAttachment != nullptr, "[ComputePass '%s']: A fullscreen compute pass must have a valid output or input/output.",
  167. GetPathName().GetCStr());
  168. AZ_Assert(outputAttachment->GetAttachmentType() == RHI::AttachmentType::Image,
  169. "[ComputePass '%s']: The output of a fullscreen compute pass must be an image.",
  170. GetPathName().GetCStr());
  171. RHI::Size targetImageSize = outputAttachment->m_descriptor.m_image.m_size;
  172. SetTargetThreadCounts(targetImageSize.m_width, targetImageSize.m_height, targetImageSize.m_depth);
  173. }
  174. void ComputePass::SetTargetThreadCounts(uint32_t targetThreadCountX, uint32_t targetThreadCountY, uint32_t targetThreadCountZ)
  175. {
  176. auto arguments{m_dispatchItem.GetArguments()};
  177. arguments.m_direct.m_totalNumberOfThreadsX = targetThreadCountX;
  178. arguments.m_direct.m_totalNumberOfThreadsY = targetThreadCountY;
  179. arguments.m_direct.m_totalNumberOfThreadsZ = targetThreadCountZ;
  180. m_dispatchItem.SetArguments(arguments);
  181. }
  182. Data::Instance<ShaderResourceGroup> ComputePass::GetShaderResourceGroup() const
  183. {
  184. return m_shaderResourceGroup;
  185. }
  186. Data::Instance<Shader> ComputePass::GetShader() const
  187. {
  188. return m_shader;
  189. }
  190. void ComputePass::FrameBeginInternal(FramePrepareParams params)
  191. {
  192. if (m_isFullscreenPass)
  193. {
  194. MatchDimensionsToOutput();
  195. }
  196. RenderPass::FrameBeginInternal(params);
  197. }
  198. void ComputePass::OnShaderReinitialized(const Shader& shader)
  199. {
  200. AZ_UNUSED(shader);
  201. LoadShader();
  202. }
  203. void ComputePass::OnShaderAssetReinitialized(const Data::Asset<ShaderAsset>& shaderAsset)
  204. {
  205. AZ_UNUSED(shaderAsset);
  206. LoadShader();
  207. }
  208. void ComputePass::OnShaderVariantReinitialized(const ShaderVariant&)
  209. {
  210. LoadShader();
  211. }
  212. void ComputePass::SetComputeShaderReloadedCallback(ComputeShaderReloadedCallback callback)
  213. {
  214. m_shaderReloadedCallback = callback;
  215. }
  216. void ComputePass::UpdateShaderOptions(const ShaderVariantId& shaderVariantId)
  217. {
  218. const ShaderVariant& shaderVariant = m_shader->GetVariant(shaderVariantId);
  219. RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor;
  220. shaderVariant.ConfigurePipelineState(pipelineStateDescriptor, shaderVariantId);
  221. m_dispatchItem.SetPipelineState(m_shader->AcquirePipelineState(pipelineStateDescriptor));
  222. if (m_drawSrg && shaderVariant.UseKeyFallback())
  223. {
  224. m_drawSrg->SetShaderVariantKeyFallbackValue(shaderVariantId.m_key);
  225. }
  226. }
  227. void ComputePass::OnShaderReloadedInternal()
  228. {
  229. if (m_shaderReloadedCallback)
  230. {
  231. m_shaderReloadedCallback(this);
  232. }
  233. }
  234. } // namespace RPI
  235. } // namespace AZ