3
0

FullscreenTrianglePass.cpp 12 KB

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