DynamicPrimitiveProcessor.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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 "DynamicPrimitiveProcessor.h"
  9. #include "AuxGeomDrawProcessorShared.h"
  10. #include <Atom/RHI/DrawPacketBuilder.h>
  11. #include <Atom/RHI/Factory.h>
  12. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  13. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  14. #include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
  15. #include <Atom/RPI.Public/RPIUtils.h>
  16. #include <Atom/RPI.Public/Scene.h>
  17. #include <Atom/RPI.Public/Shader/Shader.h>
  18. #include <Atom/RPI.Public/View.h>
  19. #include <AzCore/Debug/Profiler.h>
  20. namespace AZ
  21. {
  22. namespace Render
  23. {
  24. namespace
  25. {
  26. static const RHI::PrimitiveTopology PrimitiveTypeToTopology[PrimitiveType_Count] =
  27. {
  28. RHI::PrimitiveTopology::PointList,
  29. RHI::PrimitiveTopology::LineList,
  30. RHI::PrimitiveTopology::TriangleList,
  31. };
  32. }
  33. bool DynamicPrimitiveProcessor::Initialize(const AZ::RPI::Scene* scene)
  34. {
  35. for (int primitiveType = 0; primitiveType < PrimitiveType_Count; ++primitiveType)
  36. {
  37. SetupInputStreamLayout(m_inputStreamLayout[primitiveType], PrimitiveTypeToTopology[primitiveType]);
  38. m_streamBufferViewsValidatedForLayout[primitiveType] = false;
  39. }
  40. m_scene = scene;
  41. InitShader();
  42. return true;
  43. }
  44. void DynamicPrimitiveProcessor::Release()
  45. {
  46. m_drawPackets.clear();
  47. m_processSrgs.clear();
  48. m_shaderData.m_defaultSRG = nullptr;
  49. m_shader = nullptr;
  50. m_scene = nullptr;
  51. for (RPI::Ptr<RPI::PipelineStateForDraw>* pipelineState : m_createdPipelineStates)
  52. {
  53. pipelineState->reset();
  54. }
  55. m_createdPipelineStates.clear();
  56. }
  57. void DynamicPrimitiveProcessor::PrepareFrame()
  58. {
  59. if (m_needUpdatePipelineStates)
  60. {
  61. // for created pipeline state, re-set their data from scene
  62. for (RPI::Ptr<RPI::PipelineStateForDraw>* pipelineState : m_createdPipelineStates)
  63. {
  64. (*pipelineState)->SetOutputFromScene(m_scene);
  65. (*pipelineState)->Finalize();
  66. }
  67. m_needUpdatePipelineStates = false;
  68. }
  69. }
  70. void DynamicPrimitiveProcessor::FrameEnd()
  71. {
  72. m_processSrgs.clear();
  73. m_drawPackets.clear();
  74. }
  75. void DynamicPrimitiveProcessor::ProcessDynamicPrimitives(AuxGeomBufferData* bufferData, const RPI::FeatureProcessor::RenderPacket& fpPacket)
  76. {
  77. AZ_PROFILE_SCOPE(AzRender, "DynamicPrimitiveProcessor: ProcessDynamicPrimitives");
  78. RHI::DrawPacketBuilder drawPacketBuilder{RHI::MultiDevice::AllDevices};
  79. DynamicPrimitiveData& srcPrimitives = bufferData->m_primitiveData;
  80. // Update the buffers for the dynamic primitives and generate draw packets for them
  81. if (srcPrimitives.m_indexBuffer.size() > 0)
  82. {
  83. // Update the buffers for all dynamic primitives in this frame's data
  84. // There is just one index buffer and one vertex buffer for all dynamic primitives
  85. if (!UpdateIndexBuffer(srcPrimitives.m_indexBuffer)
  86. || !UpdateVertexBuffer(srcPrimitives.m_vertexBuffer))
  87. {
  88. // Skip adding render data if failed to update buffers
  89. // Note, the error would be already reported inside the Update* functions
  90. return;
  91. }
  92. // Validate the stream buffer views for all stream layout's if necessary
  93. for (int primitiveType = 0; primitiveType < PrimitiveType_Count; ++primitiveType)
  94. {
  95. ValidateStreamBufferViews(m_geometryView.GetStreamBufferViews(), m_streamBufferViewsValidatedForLayout, primitiveType);
  96. }
  97. // Loop over all the primitives and use one draw call for each AuxGeom API call
  98. // We have to create separate draw packets for each view that the AuxGeom is in (typically only one)
  99. AZStd::vector<RPI::ViewPtr> auxGeomViews;
  100. for (auto& view : fpPacket.m_views)
  101. {
  102. // If this view is ignoring packets with our draw list tag then skip this view
  103. if (!view->HasDrawListTag(m_shaderData.m_drawListTag))
  104. {
  105. continue;
  106. }
  107. auxGeomViews.emplace_back(view);
  108. }
  109. for (auto& primitive : srcPrimitives.m_primitiveBuffer)
  110. {
  111. bool useManualViewProjectionOverride = primitive.m_viewProjOverrideIndex != -1;
  112. PipelineStateOptions pipelineStateOptions;
  113. pipelineStateOptions.m_perpectiveType = useManualViewProjectionOverride? PerspectiveType_ManualOverride : PerspectiveType_ViewProjection;
  114. pipelineStateOptions.m_blendMode = primitive.m_blendMode;
  115. pipelineStateOptions.m_primitiveType = primitive.m_primitiveType;
  116. pipelineStateOptions.m_depthReadType = primitive.m_depthReadType;
  117. pipelineStateOptions.m_depthWriteType = primitive.m_depthWriteType;
  118. pipelineStateOptions.m_faceCullMode = primitive.m_faceCullMode;
  119. RPI::Ptr<RPI::PipelineStateForDraw> pipelineState = GetPipelineState(pipelineStateOptions);
  120. Data::Instance<RPI::ShaderResourceGroup> srg;
  121. if (useManualViewProjectionOverride || primitive.m_primitiveType == PrimitiveType_PointList)
  122. {
  123. srg = RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_shaderData.m_perDrawSrgLayout->GetName());
  124. if (!srg)
  125. {
  126. AZ_Warning("AuxGeom", false, "Failed to create a shader resource group for an AuxGeom draw, Ignoring the draw");
  127. continue; // failed to create an srg for this draw, just drop the draw.
  128. }
  129. if (useManualViewProjectionOverride)
  130. {
  131. srg->SetConstant(m_shaderData.m_viewProjectionOverrideIndex, bufferData->m_viewProjOverrides[primitive.m_viewProjOverrideIndex]);
  132. m_shaderData.m_viewProjectionOverrideIndex.AssertValid();
  133. }
  134. if (primitive.m_primitiveType == PrimitiveType_PointList)
  135. {
  136. srg->SetConstant(m_shaderData.m_pointSizeIndex, aznumeric_cast<float>(primitive.m_width));
  137. m_shaderData.m_pointSizeIndex.AssertValid();
  138. }
  139. pipelineState->UpdateSrgVariantFallback(srg);
  140. srg->Compile();
  141. }
  142. else
  143. {
  144. srg = m_shaderData.m_defaultSRG;
  145. }
  146. primitive.m_geometryView = m_geometryView;
  147. primitive.m_geometryView.SetDrawArguments(RHI::DrawIndexed(0, primitive.m_indexCount, primitive.m_indexOffset));
  148. for (auto& view : auxGeomViews)
  149. {
  150. RHI::DrawItemSortKey sortKey = primitive.m_blendMode == BlendMode_Off ? 0 : view->GetSortKeyForPosition(primitive.m_center);
  151. auto drawPacket = BuildDrawPacketForDynamicPrimitive(
  152. primitive.m_geometryView,
  153. pipelineState,
  154. srg,
  155. drawPacketBuilder,
  156. sortKey);
  157. if (drawPacket)
  158. {
  159. m_drawPackets.emplace_back(drawPacket);
  160. m_processSrgs.push_back(srg);
  161. view->AddDrawPacket(drawPacket.get());
  162. }
  163. }
  164. }
  165. }
  166. }
  167. bool DynamicPrimitiveProcessor::UpdateIndexBuffer(const IndexBuffer& source)
  168. {
  169. const size_t sourceByteSize = source.size() * sizeof(AuxGeomIndex);
  170. RHI::Ptr<RPI::DynamicBuffer> dynamicBuffer = RPI::DynamicDrawInterface::Get()->GetDynamicBuffer(static_cast<uint32_t>(sourceByteSize), RHI::Alignment::InputAssembly);
  171. if (!dynamicBuffer)
  172. {
  173. AZ_WarningOnce("AuxGeom", false, "Failed to allocate dynamic buffer of size %d.", sourceByteSize);
  174. return false;
  175. }
  176. dynamicBuffer->Write(source.data(), static_cast<uint32_t>(sourceByteSize));
  177. m_geometryView.SetIndexBufferView(dynamicBuffer->GetIndexBufferView(RHI::IndexFormat::Uint32));
  178. return true;
  179. }
  180. bool DynamicPrimitiveProcessor::UpdateVertexBuffer(const VertexBuffer& source)
  181. {
  182. const size_t sourceByteSize = source.size() * sizeof(AuxGeomDynamicVertex);
  183. RHI::Ptr<RPI::DynamicBuffer> dynamicBuffer = RPI::DynamicDrawInterface::Get()->GetDynamicBuffer(static_cast<uint32_t>(sourceByteSize), RHI::Alignment::InputAssembly);
  184. if (!dynamicBuffer)
  185. {
  186. AZ_WarningOnce("AuxGeom", false, "Failed to allocate dynamic buffer of size %d.", sourceByteSize);
  187. return false;
  188. }
  189. dynamicBuffer->Write(source.data(), static_cast<uint32_t>(sourceByteSize));
  190. if (m_geometryView.GetStreamBufferViews().empty())
  191. {
  192. m_geometryView.AddStreamBufferView(dynamicBuffer->GetStreamBufferView(sizeof(AuxGeomDynamicVertex)));
  193. }
  194. else
  195. {
  196. m_geometryView.SetStreamBufferView(0, dynamicBuffer->GetStreamBufferView(sizeof(AuxGeomDynamicVertex)));
  197. }
  198. return true;
  199. }
  200. void DynamicPrimitiveProcessor::ValidateStreamBufferViews(AZStd::span<const RHI::StreamBufferView> streamBufferViews, bool* isValidated, int primitiveType)
  201. {
  202. if (!isValidated[primitiveType])
  203. {
  204. if (!RHI::ValidateStreamBufferViews(m_inputStreamLayout[primitiveType], streamBufferViews))
  205. {
  206. AZ_Error("DynamicPrimitiveProcessor", false, "Failed to validate the stream buffer views");
  207. return;
  208. }
  209. else
  210. {
  211. isValidated[primitiveType] = true;
  212. }
  213. }
  214. }
  215. void DynamicPrimitiveProcessor::SetupInputStreamLayout(RHI::InputStreamLayout& inputStreamLayout, RHI::PrimitiveTopology topology)
  216. {
  217. RHI::InputStreamLayoutBuilder layoutBuilder;
  218. layoutBuilder.AddBuffer()
  219. ->Channel("POSITION", RHI::Format::R32G32B32_FLOAT)
  220. ->Channel("COLOR", RHI::Format::R8G8B8A8_UNORM);
  221. layoutBuilder.SetTopology(topology);
  222. inputStreamLayout = layoutBuilder.End();
  223. }
  224. RPI::Ptr<RPI::PipelineStateForDraw>& DynamicPrimitiveProcessor::GetPipelineState(const PipelineStateOptions& pipelineStateOptions)
  225. {
  226. // The declaration: m_pipelineStates[PerspectiveType_Count][BlendMode_Count][PrimitiveType_Count][DepthRead_Count][DepthWrite_Count][FaceCull_Count];
  227. return m_pipelineStates[pipelineStateOptions.m_perpectiveType][pipelineStateOptions.m_blendMode][pipelineStateOptions.m_primitiveType]
  228. [pipelineStateOptions.m_depthReadType][pipelineStateOptions.m_depthWriteType][pipelineStateOptions.m_faceCullMode];
  229. }
  230. void DynamicPrimitiveProcessor::SetUpdatePipelineStates()
  231. {
  232. m_needUpdatePipelineStates = true;
  233. }
  234. void DynamicPrimitiveProcessor::InitPipelineState(const PipelineStateOptions& pipelineStateOptions)
  235. {
  236. // Use the the pipeline state for PipelineStateOptions with default values and input perspective type as base pipeline state. Create one if it was empty.
  237. PipelineStateOptions defaultOptions;
  238. defaultOptions.m_perpectiveType = pipelineStateOptions.m_perpectiveType;
  239. RPI::Ptr<RPI::PipelineStateForDraw>& basePipelineState = GetPipelineState(defaultOptions);
  240. if (basePipelineState.get() == nullptr)
  241. {
  242. basePipelineState = aznew RPI::PipelineStateForDraw;
  243. Name perspectiveTypeViewProjection = Name("ViewProjectionMode::ViewProjection");
  244. Name perspectiveTypeManualOverride = Name("ViewProjectionMode::ManualOverride");
  245. Name optionViewProjectionModeName = Name("o_viewProjMode");
  246. RPI::ShaderOptionList shaderOptionAndValues;
  247. shaderOptionAndValues.push_back(RPI::ShaderOption(optionViewProjectionModeName,
  248. (pipelineStateOptions.m_perpectiveType == AuxGeomShapePerpectiveType::PerspectiveType_ViewProjection)?perspectiveTypeViewProjection: perspectiveTypeManualOverride));
  249. basePipelineState->Init(m_shader, &shaderOptionAndValues);
  250. m_createdPipelineStates.push_back(&basePipelineState);
  251. }
  252. RPI::Ptr<RPI::PipelineStateForDraw>& destPipelineState = GetPipelineState(pipelineStateOptions);
  253. // Copy from base pipeline state. Skip if it's the base pipeline state
  254. if (destPipelineState.get() == nullptr)
  255. {
  256. destPipelineState = aznew RPI::PipelineStateForDraw(*basePipelineState.get());
  257. m_createdPipelineStates.push_back(&destPipelineState);
  258. }
  259. // blendMode
  260. RHI::TargetBlendState& blendState = destPipelineState->RenderStatesOverlay().m_blendState.m_targets[0];
  261. blendState.m_enable = pipelineStateOptions.m_blendMode == AuxGeomBlendMode::BlendMode_Alpha;
  262. blendState.m_blendSource = RHI::BlendFactor::AlphaSource;
  263. blendState.m_blendDest = RHI::BlendFactor::AlphaSourceInverse;
  264. // primitiveType
  265. destPipelineState->InputStreamLayout() = m_inputStreamLayout[pipelineStateOptions.m_primitiveType];
  266. // depthReadType
  267. // Keep the default depth comparison function and only set it when depth read is off
  268. // Note: since the default PipelineStateOptions::m_depthReadType is DepthRead_On, the basePipelineState keeps the comparison function read from shader variant
  269. if (pipelineStateOptions.m_depthReadType == AuxGeomDepthReadType::DepthRead_Off)
  270. {
  271. destPipelineState->RenderStatesOverlay().m_depthStencilState.m_depth.m_func = RHI::ComparisonFunc::Always;
  272. }
  273. // depthWriteType
  274. destPipelineState->RenderStatesOverlay().m_depthStencilState.m_depth.m_writeMask =
  275. ConvertToRHIDepthWriteMask(pipelineStateOptions.m_depthWriteType);
  276. // faceCullMode
  277. destPipelineState->RenderStatesOverlay().m_rasterState.m_cullMode = ConvertToRHICullMode(pipelineStateOptions.m_faceCullMode);
  278. destPipelineState->SetOutputFromScene(m_scene);
  279. destPipelineState->Finalize();
  280. }
  281. void DynamicPrimitiveProcessor::InitShader()
  282. {
  283. const char* auxGeomWorldShaderFilePath = "Shaders/auxgeom/auxgeomworld.azshader";
  284. m_shader = RPI::LoadCriticalShader(auxGeomWorldShaderFilePath);
  285. if (!m_shader)
  286. {
  287. AZ_Error("DynamicPrimitiveProcessor", false, "Failed to get shader");
  288. return;
  289. }
  290. // Get the per-object SRG and store the indices of the data we need to set per object
  291. m_shaderData.m_perDrawSrgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Draw);
  292. if (!m_shaderData.m_perDrawSrgLayout)
  293. {
  294. AZ_Error("DynamicPrimitiveProcessor", false, "Failed to get shader resource group layout");
  295. return;
  296. }
  297. m_shaderData.m_viewProjectionOverrideIndex.Reset();
  298. m_shaderData.m_pointSizeIndex.Reset();
  299. // Remember the draw list tag
  300. m_shaderData.m_drawListTag = m_shader->GetDrawListTag();
  301. // Create a default SRG for draws that don't use a manual view projection override
  302. m_shaderData.m_defaultSRG = RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_shaderData.m_perDrawSrgLayout->GetName());
  303. AZ_Assert(m_shaderData.m_defaultSRG != nullptr, "Creating the default SRG unexpectedly failed");
  304. m_shaderData.m_defaultSRG->SetConstant(m_shaderData.m_pointSizeIndex, 10.0f);
  305. m_shaderData.m_defaultSRG->Compile();
  306. // Initialize all pipeline states
  307. PipelineStateOptions pipelineStateOptions;
  308. // initialize two base pipeline state first to preserve the blend functions
  309. pipelineStateOptions.m_perpectiveType = PerspectiveType_ViewProjection;
  310. InitPipelineState(pipelineStateOptions);
  311. pipelineStateOptions.m_perpectiveType = PerspectiveType_ManualOverride;
  312. InitPipelineState(pipelineStateOptions);
  313. // Initialize all pipeline states
  314. for (uint32_t perspectiveType = 0; perspectiveType < PerspectiveType_Count; perspectiveType++)
  315. {
  316. pipelineStateOptions.m_perpectiveType = (AuxGeomShapePerpectiveType)perspectiveType;
  317. for (uint32_t blendMode = 0; blendMode < BlendMode_Count; blendMode++)
  318. {
  319. pipelineStateOptions.m_blendMode = (AuxGeomBlendMode)blendMode;
  320. for (uint32_t primitiveType = 0; primitiveType < PrimitiveType_Count; primitiveType++)
  321. {
  322. pipelineStateOptions.m_primitiveType = (AuxGeomPrimitiveType)primitiveType;
  323. for (uint32_t depthRead = 0; depthRead < DepthRead_Count; depthRead++)
  324. {
  325. pipelineStateOptions.m_depthReadType = (AuxGeomDepthReadType)depthRead;
  326. for (uint32_t depthWrite = 0; depthWrite < DepthWrite_Count; depthWrite++)
  327. {
  328. pipelineStateOptions.m_depthWriteType = (AuxGeomDepthWriteType)depthWrite;
  329. for (uint32_t faceCullMode = 0; faceCullMode < FaceCull_Count; faceCullMode++)
  330. {
  331. pipelineStateOptions.m_faceCullMode = (AuxGeomFaceCullMode)faceCullMode;
  332. InitPipelineState(pipelineStateOptions);
  333. }
  334. }
  335. }
  336. }
  337. }
  338. }
  339. }
  340. RHI::ConstPtr<RHI::DrawPacket> DynamicPrimitiveProcessor::BuildDrawPacketForDynamicPrimitive(
  341. RHI::GeometryView& geometryView,
  342. const RPI::Ptr<RPI::PipelineStateForDraw>& pipelineState,
  343. Data::Instance<RPI::ShaderResourceGroup> srg,
  344. RHI::DrawPacketBuilder& drawPacketBuilder,
  345. RHI::DrawItemSortKey sortKey)
  346. {
  347. drawPacketBuilder.Begin(nullptr);
  348. drawPacketBuilder.SetGeometryView(&geometryView);
  349. drawPacketBuilder.AddShaderResourceGroup(srg->GetRHIShaderResourceGroup());
  350. RHI::DrawPacketBuilder::DrawRequest drawRequest;
  351. drawRequest.m_listTag = m_shaderData.m_drawListTag;
  352. drawRequest.m_streamIndices = geometryView.GetFullStreamBufferIndices();
  353. drawRequest.m_pipelineState = pipelineState->GetRHIPipelineState();
  354. drawRequest.m_sortKey = sortKey;
  355. drawPacketBuilder.AddDrawItem(drawRequest);
  356. return drawPacketBuilder.End();
  357. }
  358. } // namespace Render
  359. } // namespace AZ