FullscreenTrianglePass.cpp 13 KB

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