DynamicPrimitiveProcessor.cpp 20 KB

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