3
0

FullscreenTrianglePass.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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 <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
  9. #include <Atom/RPI.Public/Pass/PassUtils.h>
  10. #include <Atom/RPI.Public/RPIUtils.h>
  11. #include <Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h>
  12. #include <Atom/RPI.Reflect/Pass/FullscreenTrianglePassData.h>
  13. #include <Atom/RPI.Reflect/Pass/PassTemplate.h>
  14. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  15. #include <Atom/RHI/Factory.h>
  16. #include <Atom/RHI/FrameScheduler.h>
  17. #include <Atom/RHI/PipelineState.h>
  18. #include <AzCore/Asset/AssetCommon.h>
  19. #include <AzCore/Asset/AssetManagerBus.h>
  20. #include <AzCore/std/algorithm.h>
  21. namespace AZ
  22. {
  23. namespace RPI
  24. {
  25. Ptr<FullscreenTrianglePass> FullscreenTrianglePass::Create(const PassDescriptor& descriptor)
  26. {
  27. Ptr<FullscreenTrianglePass> pass = aznew FullscreenTrianglePass(descriptor);
  28. return pass;
  29. }
  30. FullscreenTrianglePass::FullscreenTrianglePass(const PassDescriptor& descriptor)
  31. : RenderPass(descriptor)
  32. , m_passDescriptor(descriptor)
  33. {
  34. LoadShader();
  35. }
  36. FullscreenTrianglePass::~FullscreenTrianglePass()
  37. {
  38. ShaderReloadNotificationBus::Handler::BusDisconnect();
  39. }
  40. Data::Instance<Shader> FullscreenTrianglePass::GetShader() const
  41. {
  42. return m_shader;
  43. }
  44. void FullscreenTrianglePass::OnShaderReinitialized(const Shader&)
  45. {
  46. LoadShader();
  47. }
  48. void FullscreenTrianglePass::OnShaderAssetReinitialized(const Data::Asset<ShaderAsset>&)
  49. {
  50. LoadShader();
  51. }
  52. void FullscreenTrianglePass::OnShaderVariantReinitialized(const ShaderVariant&)
  53. {
  54. LoadShader();
  55. }
  56. void FullscreenTrianglePass::LoadShader()
  57. {
  58. AZ_Assert(GetPassState() != PassState::Rendering, "FullscreenTrianglePass - Reloading shader during Rendering phase!");
  59. // Load FullscreenTrianglePassData
  60. const FullscreenTrianglePassData* passData = PassUtils::GetPassData<FullscreenTrianglePassData>(m_passDescriptor);
  61. if (passData == nullptr)
  62. {
  63. AZ_Error("PassSystem", false, "[FullscreenTrianglePass '%s']: Trying to construct without valid FullscreenTrianglePassData!",
  64. GetPathName().GetCStr());
  65. return;
  66. }
  67. AZ::Data::AssetId shaderAssetId = passData->m_shaderAsset.m_assetId;
  68. if (!shaderAssetId.IsValid())
  69. {
  70. // This case may happen when PassData comes from a PassRequest defined inside an *.azasset.
  71. // Unlike the PassBuilder, the AnyAssetBuilder doesn't record the AssetId, so we have to discover the asset id at runtime.
  72. AZStd::string azshaderPath = passData->m_shaderAsset.m_filePath;
  73. AZ::StringFunc::Path::ReplaceExtension(azshaderPath, "azshader");
  74. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  75. shaderAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, azshaderPath.c_str(),
  76. azrtti_typeid<ShaderAsset>(), false /*autoRegisterIfNotFound*/);
  77. }
  78. // Load Shader
  79. Data::Asset<ShaderAsset> shaderAsset;
  80. if (shaderAssetId.IsValid())
  81. {
  82. shaderAsset = RPI::FindShaderAsset(shaderAssetId, passData->m_shaderAsset.m_filePath);
  83. }
  84. if (!shaderAsset.IsReady())
  85. {
  86. AZ_Error("PassSystem", false, "[FullscreenTrianglePass '%s']: Failed to load shader '%s'!",
  87. GetPathName().GetCStr(),
  88. passData->m_shaderAsset.m_filePath.data());
  89. return;
  90. }
  91. m_shader = Shader::FindOrCreate(shaderAsset);
  92. if (m_shader == nullptr)
  93. {
  94. AZ_Error("PassSystem", false, "[FullscreenTrianglePass '%s']: Failed to create shader instance from asset '%s'!",
  95. GetPathName().GetCStr(),
  96. passData->m_shaderAsset.m_filePath.data());
  97. return;
  98. }
  99. // Store stencil reference value for the draw call
  100. m_stencilRef = passData->m_stencilRef;
  101. m_pipelineStateForDraw.Init(m_shader);
  102. UpdateSrgs();
  103. QueueForInitialization();
  104. ShaderReloadNotificationBus::Handler::BusDisconnect();
  105. ShaderReloadNotificationBus::Handler::BusConnect(shaderAsset.GetId());
  106. }
  107. void FullscreenTrianglePass::UpdateSrgs()
  108. {
  109. if (!m_shader)
  110. {
  111. return;
  112. }
  113. // Load Pass SRG
  114. const auto passSrgLayout = m_shader->FindShaderResourceGroupLayout(SrgBindingSlot::Pass);
  115. if (passSrgLayout)
  116. {
  117. m_shaderResourceGroup = ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), passSrgLayout->GetName());
  118. [[maybe_unused]] const FullscreenTrianglePassData* passData = PassUtils::GetPassData<FullscreenTrianglePassData>(m_passDescriptor);
  119. AZ_Assert(m_shaderResourceGroup, "[FullscreenTrianglePass '%s']: Failed to create SRG from shader asset '%s'",
  120. GetPathName().GetCStr(),
  121. passData->m_shaderAsset.m_filePath.data());
  122. PassUtils::BindDataMappingsToSrg(m_passDescriptor, m_shaderResourceGroup.get());
  123. }
  124. // Load Draw SRG
  125. // this is necessary since the shader may have options, which require a default draw SRG
  126. const bool compileDrawSrg = false; // The SRG will be compiled in CompileResources()
  127. m_drawShaderResourceGroup = m_shader->CreateDefaultDrawSrg(compileDrawSrg);
  128. // It is valid for there to be no draw srg if there are no shader options, so check to see if it is null.
  129. if (m_drawShaderResourceGroup)
  130. {
  131. m_pipelineStateForDraw.UpdateSrgVariantFallback(m_shaderResourceGroup);
  132. }
  133. }
  134. void FullscreenTrianglePass::BuildDrawItem()
  135. {
  136. m_pipelineStateForDraw.SetOutputFromPass(this);
  137. // No streams required
  138. RHI::InputStreamLayout inputStreamLayout;
  139. inputStreamLayout.SetTopology(RHI::PrimitiveTopology::TriangleList);
  140. inputStreamLayout.Finalize();
  141. m_pipelineStateForDraw.SetInputStreamLayout(inputStreamLayout);
  142. // This draw item purposefully does not reference any geometry buffers.
  143. // Instead it's expected that the extended class uses a vertex shader
  144. // that generates a full-screen triangle completely from vertex ids.
  145. RHI::DrawLinear draw = RHI::DrawLinear();
  146. draw.m_vertexCount = 3;
  147. m_item.m_arguments = RHI::DrawArguments(draw);
  148. m_item.m_pipelineState = m_pipelineStateForDraw.Finalize();
  149. m_item.m_stencilRef = static_cast<uint8_t>(m_stencilRef);
  150. }
  151. void FullscreenTrianglePass::UpdateShaderOptions(const ShaderOptionList& shaderOptions)
  152. {
  153. if (m_shader)
  154. {
  155. m_pipelineStateForDraw.Init(m_shader, &shaderOptions);
  156. m_pipelineStateForDraw.UpdateSrgVariantFallback(m_shaderResourceGroup);
  157. BuildDrawItem();
  158. }
  159. }
  160. void FullscreenTrianglePass::InitializeInternal()
  161. {
  162. RenderPass::InitializeInternal();
  163. ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::InitializeInternal", this);
  164. if (m_shader == nullptr)
  165. {
  166. AZ_Error("PassSystem", false, "[FullscreenTrianglePass]: Shader not loaded!");
  167. return;
  168. }
  169. BuildDrawItem();
  170. }
  171. void FullscreenTrianglePass::FrameBeginInternal(FramePrepareParams params)
  172. {
  173. const PassAttachment* outputAttachment = nullptr;
  174. if (GetOutputCount() > 0)
  175. {
  176. outputAttachment = GetOutputBinding(0).GetAttachment().get();
  177. }
  178. else if(GetInputOutputCount() > 0)
  179. {
  180. outputAttachment = GetInputOutputBinding(0).GetAttachment().get();
  181. }
  182. AZ_Assert(outputAttachment != nullptr, "[FullscreenTrianglePass %s] has no valid output or input/output attachments.", GetPathName().GetCStr());
  183. AZ_Assert(outputAttachment->GetAttachmentType() == RHI::AttachmentType::Image,
  184. "[FullscreenTrianglePass %s] output of FullScreenTrianglePass must be an image", GetPathName().GetCStr());
  185. RHI::Size targetImageSize = outputAttachment->m_descriptor.m_image.m_size;
  186. m_viewportState.m_maxX = static_cast<float>(targetImageSize.m_width);
  187. m_viewportState.m_maxY = static_cast<float>(targetImageSize.m_height);
  188. m_scissorState.m_maxX = static_cast<int32_t>(targetImageSize.m_width);
  189. m_scissorState.m_maxY = static_cast<int32_t>(targetImageSize.m_height);
  190. RenderPass::FrameBeginInternal(params);
  191. }
  192. // Scope producer functions
  193. void FullscreenTrianglePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
  194. {
  195. RenderPass::SetupFrameGraphDependencies(frameGraph);
  196. // Update scissor/viewport regions based on the mip level of the render target that is being written into
  197. uint16_t viewMinMip = RHI::ImageSubresourceRange::HighestSliceIndex;
  198. for (const PassAttachmentBinding& attachmentBinding : m_attachmentBindings)
  199. {
  200. if (attachmentBinding.GetAttachment() != nullptr &&
  201. frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentBinding.GetAttachment()->GetAttachmentId()) &&
  202. attachmentBinding.m_unifiedScopeDesc.GetType() == RHI::AttachmentType::Image &&
  203. RHI::CheckBitsAny(attachmentBinding.GetAttachmentAccess(), RHI::ScopeAttachmentAccess::Write) &&
  204. attachmentBinding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::RenderTarget)
  205. {
  206. RHI::ImageViewDescriptor viewDesc = attachmentBinding.m_unifiedScopeDesc.GetAsImage().m_imageViewDescriptor;
  207. viewMinMip = AZStd::min(viewMinMip, viewDesc.m_mipSliceMin);
  208. }
  209. }
  210. if(viewMinMip < RHI::ImageSubresourceRange::HighestSliceIndex)
  211. {
  212. uint32_t viewportStateMaxX = static_cast<uint32_t>(m_viewportState.m_maxX);
  213. uint32_t viewportStateMaxY = static_cast<uint32_t>(m_viewportState.m_maxY);
  214. m_viewportState.m_maxX = static_cast<float>(viewportStateMaxX >> viewMinMip);
  215. m_viewportState.m_maxY = static_cast<float>(viewportStateMaxY >> viewMinMip);
  216. m_scissorState.m_maxX = static_cast<uint32_t>(m_scissorState.m_maxX) >> viewMinMip;
  217. m_scissorState.m_maxY = static_cast<uint32_t>(m_scissorState.m_maxY) >> viewMinMip;
  218. }
  219. frameGraph.SetEstimatedItemCount(1);
  220. }
  221. void FullscreenTrianglePass::CompileResources(const RHI::FrameGraphCompileContext& context)
  222. {
  223. if (m_shaderResourceGroup != nullptr)
  224. {
  225. BindPassSrg(context, m_shaderResourceGroup);
  226. m_shaderResourceGroup->Compile();
  227. }
  228. if (m_drawShaderResourceGroup != nullptr)
  229. {
  230. m_drawShaderResourceGroup->Compile();
  231. BindSrg(m_drawShaderResourceGroup->GetRHIShaderResourceGroup());
  232. }
  233. }
  234. void FullscreenTrianglePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
  235. {
  236. RHI::CommandList* commandList = context.GetCommandList();
  237. SetSrgsForDraw(commandList);
  238. commandList->SetViewport(m_viewportState);
  239. commandList->SetScissor(m_scissorState);
  240. commandList->Submit(m_item);
  241. }
  242. } // namespace RPI
  243. } // namespace AZ