HairGeometryRasterPass.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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/RHI/CommandList.h>
  9. #include <Atom/RHI/RHISystemInterface.h>
  10. #include <Atom/RHI/DeviceDrawPacketBuilder.h>
  11. #include <Atom/RHI/DevicePipelineState.h>
  12. #include <Atom/RPI.Public/View.h>
  13. #include <Atom/RPI.Public/RPIUtils.h>
  14. #include <Atom/RPI.Public/RenderPipeline.h>
  15. #include <Atom/RPI.Public/RPISystemInterface.h>
  16. #include <Atom/RPI.Public/Pass/PassUtils.h>
  17. #include <Atom/RPI.Public/Scene.h>
  18. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  19. #include <Atom/RPI.Reflect/Pass/RasterPassData.h>
  20. #include <Atom/RPI.Reflect/Pass/PassTemplate.h>
  21. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  22. #include <Passes/HairGeometryRasterPass.h>
  23. #include <Rendering/HairRenderObject.h>
  24. #include <Rendering/HairFeatureProcessor.h>
  25. namespace AZ
  26. {
  27. namespace Render
  28. {
  29. namespace Hair
  30. {
  31. // --- Creation & Initialization ---
  32. RPI::Ptr<HairGeometryRasterPass> HairGeometryRasterPass::Create(const RPI::PassDescriptor& descriptor)
  33. {
  34. RPI::Ptr<HairGeometryRasterPass> pass = aznew HairGeometryRasterPass(descriptor);
  35. return pass;
  36. }
  37. HairGeometryRasterPass::HairGeometryRasterPass(const RPI::PassDescriptor& descriptor)
  38. : RasterPass(descriptor),
  39. m_passDescriptor(descriptor)
  40. {
  41. // For inherited classes, override this method and set the proper path.
  42. // Example: "Shaders/hairrenderingfillppll.azshader"
  43. SetShaderPath("dummyShaderPath");
  44. }
  45. bool HairGeometryRasterPass::AcquireFeatureProcessor()
  46. {
  47. if (m_featureProcessor)
  48. {
  49. return true;
  50. }
  51. RPI::Scene* scene = GetScene();
  52. if (scene)
  53. {
  54. m_featureProcessor = scene->GetFeatureProcessor<HairFeatureProcessor>();
  55. }
  56. else
  57. {
  58. return false;
  59. }
  60. if (!m_featureProcessor)
  61. {
  62. AZ_Warning("Hair Gem", false,
  63. "HairGeometryRasterPass [%s] - Failed to retrieve Hair feature processor from the scene",
  64. GetName().GetCStr());
  65. return false;
  66. }
  67. return true;
  68. }
  69. void HairGeometryRasterPass::InitializeInternal()
  70. {
  71. if (GetScene())
  72. {
  73. RasterPass::InitializeInternal();
  74. }
  75. }
  76. bool HairGeometryRasterPass::IsEnabled() const
  77. {
  78. return (RPI::RasterPass::IsEnabled() && m_initialized) ? true : false;
  79. }
  80. bool HairGeometryRasterPass::UpdateShaderOptions(const RPI::ShaderVariantId& variantId)
  81. {
  82. m_currentShaderVariantId = variantId;
  83. const RPI::ShaderVariant& shaderVariant = m_shader->GetVariant(m_currentShaderVariantId);
  84. RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
  85. shaderVariant.ConfigurePipelineState(pipelineStateDescriptor, m_currentShaderVariantId);
  86. RPI::Scene* scene = GetScene();
  87. if (!scene)
  88. {
  89. AZ_Error("Hair Gem", false, "Scene could not be acquired");
  90. return false;
  91. }
  92. RHI::DrawListTag drawListTag = m_shader->GetDrawListTag();
  93. scene->ConfigurePipelineState(drawListTag, pipelineStateDescriptor);
  94. pipelineStateDescriptor.m_renderAttachmentConfiguration = GetRenderAttachmentConfiguration();
  95. pipelineStateDescriptor.m_inputStreamLayout.SetTopology(AZ::RHI::PrimitiveTopology::TriangleList);
  96. pipelineStateDescriptor.m_inputStreamLayout.Finalize();
  97. m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor);
  98. if (!m_pipelineState)
  99. {
  100. AZ_Error("Hair Gem", false, "Pipeline state could not be acquired");
  101. return false;
  102. }
  103. if (m_shaderResourceGroup->HasShaderVariantKeyFallbackEntry() && shaderVariant.UseKeyFallback())
  104. {
  105. m_shaderResourceGroup->SetShaderVariantKeyFallbackValue(m_currentShaderVariantId.m_key);
  106. }
  107. return true;
  108. }
  109. bool HairGeometryRasterPass::LoadShaderAndPipelineState()
  110. {
  111. RPI::ShaderReloadNotificationBus::Handler::BusDisconnect();
  112. const RPI::RasterPassData* passData = RPI::PassUtils::GetPassData<RPI::RasterPassData>(m_passDescriptor);
  113. // If we successfully retrieved our custom data, use it to set the DrawListTag
  114. if (!passData)
  115. {
  116. AZ_Error("Hair Gem", false, "Missing pass raster data");
  117. return false;
  118. }
  119. // Load Shader
  120. const char* shaderFilePath = m_shaderPath.c_str();
  121. Data::Asset<RPI::ShaderAsset> shaderAsset =
  122. RPI::AssetUtils::LoadAssetByProductPath<RPI::ShaderAsset>(shaderFilePath, RPI::AssetUtils::TraceLevel::Error);
  123. if (!shaderAsset.IsReady())
  124. {
  125. AZ_Error("Hair Gem", false, "Invalid shader asset for shader '%s'!", shaderFilePath);
  126. return false;
  127. }
  128. m_shader = RPI::Shader::FindOrCreate(shaderAsset);
  129. if (m_shader == nullptr)
  130. {
  131. AZ_Error("Hair Gem", false, "Pass failed to create shader instance from asset '%s'!", shaderFilePath);
  132. return false;
  133. }
  134. // Per Pass Srg
  135. {
  136. // Using 'PerPass' naming since currently RasterPass assumes that the pass Srg is always named 'PassSrg'
  137. // [To Do] - RasterPass should use srg slot index and not name - currently this will
  138. // result in a crash in one of the Atom existing MSAA passes that requires further dive.
  139. // m_shaderResourceGroup = UtilityClass::CreateShaderResourceGroup(m_shader, "HairPerPassSrg", "Hair Gem");
  140. m_shaderResourceGroup = UtilityClass::CreateShaderResourceGroup(m_shader, "PassSrg", "Hair Gem");
  141. if (!m_shaderResourceGroup)
  142. {
  143. AZ_Error("Hair Gem", false, "Failed to create the per pass srg");
  144. return false;
  145. }
  146. }
  147. if (!UpdateShaderOptions(m_shader->GetDefaultShaderOptions().GetShaderVariantId()))
  148. {
  149. AZ_Error("Hair Gem", false, "Failed to create pipeline state");
  150. return false;
  151. }
  152. RPI::ShaderReloadNotificationBus::Handler::BusConnect(shaderAsset.GetId());
  153. m_initialized = true;
  154. return true;
  155. }
  156. Data::Instance<RPI::Shader> HairGeometryRasterPass::GetShader()
  157. {
  158. if (!m_initialized || !m_shader)
  159. {
  160. AZ_Error("Hair Gem", LoadShaderAndPipelineState(), "HairGeometryRasterPass could not initialize pipeline or shader");
  161. }
  162. return m_shader;
  163. }
  164. void HairGeometryRasterPass::SchedulePacketBuild(HairRenderObject* hairObject)
  165. {
  166. m_newRenderObjects.insert(hairObject);
  167. BuildDrawPacket(hairObject);
  168. }
  169. bool HairGeometryRasterPass::BuildDrawPacket(HairRenderObject* hairObject)
  170. {
  171. if (!m_initialized)
  172. {
  173. return false;
  174. }
  175. RHI::DrawPacketBuilder::DrawRequest drawRequest;
  176. drawRequest.m_listTag = m_drawListTag;
  177. drawRequest.m_pipelineState = m_pipelineState;
  178. // drawRequest.m_streamBufferViews = // no explicit vertex buffer. shader is using the srg buffers
  179. drawRequest.m_stencilRef = 0;
  180. drawRequest.m_sortKey = 0;
  181. // Seems that the PerView and PerScene are gathered through RenderPass::CollectSrgs()
  182. // The PerPass is gathered through the RasterPass::m_shaderResourceGroup
  183. AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
  184. return hairObject->BuildDrawPacket(m_shader.get(), drawRequest);
  185. }
  186. bool HairGeometryRasterPass::AddDrawPackets(AZStd::list<Data::Instance<HairRenderObject>>& hairRenderObjects)
  187. {
  188. bool overallSuccess = true;
  189. if (!m_currentView &&
  190. (!(m_currentView = GetView()) || !m_currentView->HasDrawListTag(m_drawListTag)))
  191. {
  192. m_currentView = nullptr; // set it to nullptr to prevent further attempts this frame
  193. AZ_Warning("Hair Gem", false, "AddDrawPackets: failed to acquire or match the DrawListTag - check that your pass and shader tag name match");
  194. return false;
  195. }
  196. for (auto& renderObject : hairRenderObjects)
  197. {
  198. const RHI::DrawPacket* drawPacket = renderObject->GetGeometrylDrawPacket(m_shader.get());
  199. if (!drawPacket)
  200. { // might not be an error - the object might have just been added and the DrawPacket is
  201. // scheduled to be built when the render frame begins
  202. AZ_Warning("Hair Gem", !m_newRenderObjects.empty(), "HairGeometryRasterPass - DrawPacket wasn't built");
  203. overallSuccess = false;
  204. continue;
  205. }
  206. m_currentView->AddDrawPacket(drawPacket);
  207. }
  208. return overallSuccess;
  209. }
  210. void HairGeometryRasterPass::FrameBeginInternal(FramePrepareParams params)
  211. {
  212. {
  213. AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
  214. if (!m_initialized && AcquireFeatureProcessor())
  215. {
  216. LoadShaderAndPipelineState();
  217. m_featureProcessor->ForceRebuildRenderData();
  218. }
  219. }
  220. if (!m_initialized)
  221. {
  222. return;
  223. }
  224. // Bind the Per Object resources and trigger the RHI validation that will use attachment
  225. // for its validation. The attachments are invalidated outside the render begin/end frame.
  226. for (HairRenderObject* newObject : m_newRenderObjects)
  227. {
  228. newObject->BindPerObjectSrgForRaster();
  229. }
  230. // Clear the new added objects - BuildDrawPacket should only be carried out once per
  231. // object/shader lifetime
  232. m_newRenderObjects.clear();
  233. // Refresh current view every frame
  234. if (!(m_currentView = GetView()) || !m_currentView->HasDrawListTag(m_drawListTag))
  235. {
  236. m_currentView = nullptr; // set it to null if view exists but no tag match
  237. AZ_Warning("Hair Gem", false, "FrameBeginInternal: failed to acquire or match the DrawListTag - check that your pass and shader tag name match");
  238. return;
  239. }
  240. RPI::RasterPass::FrameBeginInternal(params);
  241. }
  242. void HairGeometryRasterPass::CompileResources(const RHI::FrameGraphCompileContext& context)
  243. {
  244. AZ_PROFILE_FUNCTION(AzRender);
  245. if (!m_featureProcessor)
  246. {
  247. return;
  248. }
  249. // Compilation of remaining srgs will be done by the parent class
  250. RPI::RasterPass::CompileResources(context);
  251. }
  252. void HairGeometryRasterPass::BuildShaderAndRenderData()
  253. {
  254. AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
  255. m_initialized = false; // make sure we initialize it even if not in this frame
  256. if (AcquireFeatureProcessor())
  257. {
  258. LoadShaderAndPipelineState();
  259. m_featureProcessor->ForceRebuildRenderData();
  260. }
  261. }
  262. void HairGeometryRasterPass::OnShaderReinitialized([[maybe_unused]] const RPI::Shader & shader)
  263. {
  264. BuildShaderAndRenderData();
  265. }
  266. void HairGeometryRasterPass::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset<RPI::ShaderAsset>& shaderAsset)
  267. {
  268. BuildShaderAndRenderData();
  269. }
  270. void HairGeometryRasterPass::OnShaderVariantReinitialized([[maybe_unused]] const AZ::RPI::ShaderVariant& shaderVariant)
  271. {
  272. BuildShaderAndRenderData();
  273. }
  274. } // namespace Hair
  275. } // namespace Render
  276. } // namespace AZ