3
0

FullscreenTrianglePass.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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);
  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. RHI::DrawLinear draw = RHI::DrawLinear();
  153. draw.m_vertexCount = 3;
  154. m_item.SetArguments(RHI::DrawArguments(draw));
  155. m_item.SetPipelineState(m_pipelineStateForDraw.Finalize());
  156. m_item.SetStencilRef(static_cast<uint8_t>(m_stencilRef));
  157. }
  158. void FullscreenTrianglePass::UpdateShaderOptions(const ShaderOptionList& shaderOptions)
  159. {
  160. if (m_shader)
  161. {
  162. m_pipelineStateForDraw.Init(m_shader, &shaderOptions);
  163. UpdateShaderOptionsCommon();
  164. }
  165. }
  166. void FullscreenTrianglePass::UpdateShaderOptions(const ShaderVariantId& shaderVariantId)
  167. {
  168. if (m_shader)
  169. {
  170. m_pipelineStateForDraw.Init(m_shader, shaderVariantId);
  171. UpdateShaderOptionsCommon();
  172. }
  173. }
  174. void FullscreenTrianglePass::InitializeInternal()
  175. {
  176. RenderPass::InitializeInternal();
  177. ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::InitializeInternal", this);
  178. if (m_shader == nullptr)
  179. {
  180. AZ_Error("PassSystem", false, "[FullscreenTrianglePass]: Shader not loaded!");
  181. return;
  182. }
  183. BuildDrawItem();
  184. }
  185. void FullscreenTrianglePass::FrameBeginInternal(FramePrepareParams params)
  186. {
  187. const PassAttachment* outputAttachment = nullptr;
  188. if (GetOutputCount() > 0)
  189. {
  190. outputAttachment = GetOutputBinding(0).GetAttachment().get();
  191. }
  192. else if(GetInputOutputCount() > 0)
  193. {
  194. outputAttachment = GetInputOutputBinding(0).GetAttachment().get();
  195. }
  196. AZ_Assert(outputAttachment != nullptr, "[FullscreenTrianglePass %s] has no valid output or input/output attachments.", GetPathName().GetCStr());
  197. AZ_Assert(outputAttachment->GetAttachmentType() == RHI::AttachmentType::Image,
  198. "[FullscreenTrianglePass %s] output of FullScreenTrianglePass must be an image", GetPathName().GetCStr());
  199. RHI::Size targetImageSize = outputAttachment->m_descriptor.m_image.m_size;
  200. m_viewportState.m_maxX = static_cast<float>(targetImageSize.m_width);
  201. m_viewportState.m_maxY = static_cast<float>(targetImageSize.m_height);
  202. m_scissorState.m_maxX = static_cast<int32_t>(targetImageSize.m_width);
  203. m_scissorState.m_maxY = static_cast<int32_t>(targetImageSize.m_height);
  204. RenderPass::FrameBeginInternal(params);
  205. }
  206. // Scope producer functions
  207. void FullscreenTrianglePass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
  208. {
  209. RenderPass::SetupFrameGraphDependencies(frameGraph);
  210. // Update scissor/viewport regions based on the mip level of the render target that is being written into
  211. uint16_t viewMinMip = RHI::ImageSubresourceRange::HighestSliceIndex;
  212. for (const PassAttachmentBinding& attachmentBinding : m_attachmentBindings)
  213. {
  214. if (attachmentBinding.GetAttachment() != nullptr &&
  215. frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentBinding.GetAttachment()->GetAttachmentId()) &&
  216. attachmentBinding.m_unifiedScopeDesc.GetType() == RHI::AttachmentType::Image &&
  217. RHI::CheckBitsAny(attachmentBinding.GetAttachmentAccess(), RHI::ScopeAttachmentAccess::Write) &&
  218. attachmentBinding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::RenderTarget)
  219. {
  220. RHI::ImageViewDescriptor viewDesc = attachmentBinding.m_unifiedScopeDesc.GetAsImage().m_imageViewDescriptor;
  221. viewMinMip = AZStd::min(viewMinMip, viewDesc.m_mipSliceMin);
  222. }
  223. }
  224. if(viewMinMip < RHI::ImageSubresourceRange::HighestSliceIndex)
  225. {
  226. uint32_t viewportStateMaxX = static_cast<uint32_t>(m_viewportState.m_maxX);
  227. uint32_t viewportStateMaxY = static_cast<uint32_t>(m_viewportState.m_maxY);
  228. m_viewportState.m_maxX = static_cast<float>(viewportStateMaxX >> viewMinMip);
  229. m_viewportState.m_maxY = static_cast<float>(viewportStateMaxY >> viewMinMip);
  230. m_scissorState.m_maxX = static_cast<uint32_t>(m_scissorState.m_maxX) >> viewMinMip;
  231. m_scissorState.m_maxY = static_cast<uint32_t>(m_scissorState.m_maxY) >> viewMinMip;
  232. }
  233. frameGraph.SetEstimatedItemCount(1);
  234. }
  235. void FullscreenTrianglePass::CompileResources(const RHI::FrameGraphCompileContext& context)
  236. {
  237. if (m_shaderResourceGroup != nullptr)
  238. {
  239. BindPassSrg(context, m_shaderResourceGroup);
  240. m_shaderResourceGroup->Compile();
  241. }
  242. if (m_drawShaderResourceGroup != nullptr)
  243. {
  244. m_drawShaderResourceGroup->Compile();
  245. BindSrg(m_drawShaderResourceGroup->GetRHIShaderResourceGroup());
  246. }
  247. }
  248. void FullscreenTrianglePass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
  249. {
  250. RHI::CommandList* commandList = context.GetCommandList();
  251. SetSrgsForDraw(context);
  252. commandList->SetViewport(m_viewportState);
  253. commandList->SetScissor(m_scissorState);
  254. commandList->Submit(m_item.GetDeviceDrawItem(context.GetDeviceIndex()));
  255. }
  256. } // namespace RPI
  257. } // namespace AZ