DynamicDrawContext.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  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 <AzCore/Utils/TypeHash.h>
  9. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  10. #include <Atom/RPI.Public/DynamicDraw/DynamicBuffer.h>
  11. #include <Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h>
  12. #include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
  13. #include <Atom/RPI.Public/Pass/RasterPass.h>
  14. #include <Atom/RPI.Public/RenderPipeline.h>
  15. #include <Atom/RPI.Public/Scene.h>
  16. #include <Atom/RPI.Public/View.h>
  17. namespace AZ
  18. {
  19. namespace RPI
  20. {
  21. namespace
  22. {
  23. constexpr const char* PerContextSrgName = "PerContextSrg";
  24. }
  25. void DynamicDrawContext::MultiStates::UpdateHash(const DrawStateOptions& drawStateOptions)
  26. {
  27. if (!m_isDirty)
  28. {
  29. return;
  30. }
  31. HashValue64 seed = HashValue64{ 0 };
  32. if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::PrimitiveType))
  33. {
  34. seed = TypeHash64(m_topology, seed);
  35. }
  36. if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::DepthState))
  37. {
  38. seed = TypeHash64(m_depthState.m_enable, seed);
  39. seed = TypeHash64(m_depthState.m_func, seed);
  40. seed = TypeHash64(m_depthState.m_writeMask, seed);
  41. }
  42. if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::StencilState))
  43. {
  44. seed = TypeHash64(m_stencilState.m_enable, seed);
  45. seed = TypeHash64(m_stencilState.m_readMask, seed);
  46. seed = TypeHash64(m_stencilState.m_writeMask, seed);
  47. seed = TypeHash64(m_stencilState.m_frontFace.m_failOp, seed);
  48. seed = TypeHash64(m_stencilState.m_frontFace.m_depthFailOp, seed);
  49. seed = TypeHash64(m_stencilState.m_frontFace.m_passOp, seed);
  50. seed = TypeHash64(m_stencilState.m_frontFace.m_func, seed);
  51. seed = TypeHash64(m_stencilState.m_backFace.m_failOp, seed);
  52. seed = TypeHash64(m_stencilState.m_backFace.m_depthFailOp, seed);
  53. seed = TypeHash64(m_stencilState.m_backFace.m_passOp, seed);
  54. seed = TypeHash64(m_stencilState.m_backFace.m_func, seed);
  55. }
  56. if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::FaceCullMode))
  57. {
  58. seed = TypeHash64(m_cullMode, seed);
  59. }
  60. if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::BlendMode))
  61. {
  62. seed = TypeHash64(m_blendState0.m_enable, seed);
  63. seed = TypeHash64(m_blendState0.m_blendOp, seed);
  64. seed = TypeHash64(m_blendState0.m_blendSource, seed);
  65. seed = TypeHash64(m_blendState0.m_blendDest, seed);
  66. seed = TypeHash64(m_blendState0.m_blendAlphaOp, seed);
  67. seed = TypeHash64(m_blendState0.m_blendAlphaSource, seed);
  68. seed = TypeHash64(m_blendState0.m_blendAlphaDest, seed);
  69. }
  70. if (RHI::CheckBitsAny(drawStateOptions, DrawStateOptions::ShaderVariant))
  71. {
  72. seed = TypeHash64(m_shaderVariantId.m_key, seed);
  73. seed = TypeHash64(m_shaderVariantId.m_mask, seed);
  74. }
  75. m_hash = seed;
  76. m_isDirty = false;
  77. }
  78. void DynamicDrawContext::InitShader(Data::Asset<ShaderAsset> shaderAsset)
  79. {
  80. Data::Instance<Shader> shader = Shader::FindOrCreate(shaderAsset);
  81. InitShader(shader);
  82. }
  83. void DynamicDrawContext::InitShader(Data::Instance<Shader> shader)
  84. {
  85. InitShaderWithVariant(shader, nullptr);
  86. m_supportShaderVariants = true;
  87. }
  88. DynamicDrawContext::~DynamicDrawContext()
  89. {
  90. SceneNotificationBus::Handler::BusDisconnect();
  91. }
  92. void DynamicDrawContext::InitShaderWithVariant(Data::Asset<ShaderAsset> shaderAsset, const ShaderOptionList* optionAndValues)
  93. {
  94. Data::Instance<Shader> shader = Shader::FindOrCreate(shaderAsset);
  95. InitShaderWithVariant(shader, optionAndValues);
  96. }
  97. void DynamicDrawContext::InitShaderWithVariant(Data::Instance<Shader> shader, const ShaderOptionList* optionAndValues)
  98. {
  99. AZ_Assert(!m_initialized, "Can't call InitShader after context was initialized (EndInit was called)");
  100. if (shader == nullptr)
  101. {
  102. AZ_Error("RPI", false, "Initializing DynamicDrawContext with invalid shader");
  103. return;
  104. }
  105. m_supportShaderVariants = false;
  106. m_shader = shader;
  107. m_pipelineState = aznew RPI::PipelineStateForDraw;
  108. m_pipelineState->Init(shader, optionAndValues);
  109. // Set DrawListTag from shader only if it wasn't set
  110. if (!m_drawListTag.IsValid())
  111. {
  112. m_drawListTag = shader->GetDrawListTag();
  113. }
  114. // Create per context srg if it exist
  115. auto contextSrgLayout = m_shader->FindShaderResourceGroupLayout(Name { PerContextSrgName });
  116. if (contextSrgLayout)
  117. {
  118. m_srgPerContext = AZ::RPI::ShaderResourceGroup::Create(
  119. m_shader->GetAsset(), m_shader->GetSupervariantIndex(), Name { PerContextSrgName });
  120. m_srgGroups[0] = m_srgPerContext->GetRHIShaderResourceGroup();
  121. }
  122. // Save per draw srg asset which can be used to create draw srg later
  123. m_drawSrgLayout = m_shader->FindShaderResourceGroupLayout(SrgBindingSlot::Draw);
  124. m_hasShaderVariantKeyFallbackEntry = (m_drawSrgLayout && m_drawSrgLayout->HasShaderVariantKeyFallbackEntry());
  125. }
  126. void DynamicDrawContext::InitVertexFormat(const AZStd::vector<VertexChannel>& vertexChannels)
  127. {
  128. AZ_Assert(!m_initialized, "Can't call InitVertexFormat after context was initialized (EndInit was called)");
  129. AZ_Assert(m_pipelineState, "Can't call InitVertexFormat before InitShader is called with a valid shader");
  130. m_perVertexDataSize = 0;
  131. RHI::InputStreamLayoutBuilder layoutBuilder;
  132. RHI::InputStreamLayoutBuilder::BufferDescriptorBuilder* bufferBuilder = layoutBuilder.AddBuffer();
  133. for (auto& channel : vertexChannels)
  134. {
  135. bufferBuilder->Channel(channel.m_channel, channel.m_format);
  136. m_perVertexDataSize += RHI::GetFormatSize(channel.m_format);
  137. }
  138. if (m_pipelineState)
  139. {
  140. m_pipelineState->InputStreamLayout() = layoutBuilder.End();
  141. }
  142. }
  143. void DynamicDrawContext::InitDrawListTag(RHI::DrawListTag drawListTag)
  144. {
  145. AZ_Assert(!m_initialized, "Can't call InitDrawListTag after context was initialized (EndInit was called)");
  146. m_drawListTag = drawListTag;
  147. }
  148. void DynamicDrawContext::CustomizePipelineState(AZStd::function<void(Ptr<PipelineStateForDraw>)> updatePipelineState)
  149. {
  150. AZ_Assert(!m_initialized, "Can't call CustomizePipelineState after context was initialized (EndInit was called)");
  151. AZ_Assert(m_pipelineState, "Can't call CustomizePipelineState before InitShader is called");
  152. updatePipelineState(m_pipelineState);
  153. }
  154. uint32_t DynamicDrawContext::GetPerVertexDataSize()
  155. {
  156. return m_perVertexDataSize;
  157. }
  158. void DynamicDrawContext::EndInit()
  159. {
  160. AZ_Warning("RPI", m_pipelineState, "Failed to initialize shader for DynamicDrawContext");
  161. AZ_Warning("RPI", m_drawListTag.IsValid(), "DynamicDrawContext doesn't have a valid DrawListTag");
  162. if (!m_drawListTag.IsValid() || m_pipelineState == nullptr)
  163. {
  164. return;
  165. }
  166. if (m_outputScope == OutputScopeType::RenderPipeline || m_outputScope == OutputScopeType::Scene)
  167. {
  168. m_pipelineState->SetOutputFromScene(m_scene, m_drawListTag);
  169. }
  170. else if (m_outputScope == OutputScopeType::RasterPass)
  171. {
  172. m_pipelineState->SetOutputFromPass(m_pass);
  173. }
  174. else
  175. {
  176. AZ_Assert(false, "DynamicDrawContext need to set output scope before end initialization");
  177. return;
  178. }
  179. m_rhiPipelineState = m_pipelineState->Finalize();
  180. if (!m_rhiPipelineState)
  181. {
  182. AZ_Warning("RPI", false, "Failed to initialize PipelineState for DynamicDrawContext");
  183. return;
  184. }
  185. m_initialized = true;
  186. // Acquire MultiStates from m_pipelineState
  187. m_currentStates.m_cullMode = m_pipelineState->ConstDescriptor().m_renderStates.m_rasterState.m_cullMode;
  188. m_currentStates.m_topology = m_pipelineState->ConstDescriptor().m_inputStreamLayout.GetTopology();
  189. m_currentStates.m_depthState = m_pipelineState->ConstDescriptor().m_renderStates.m_depthStencilState.m_depth;
  190. m_currentStates.m_stencilState = m_pipelineState->ConstDescriptor().m_renderStates.m_depthStencilState.m_stencil;
  191. m_currentStates.m_blendState0 = m_pipelineState->ConstDescriptor().m_renderStates.m_blendState.m_targets[0];
  192. m_currentStates.m_shaderVariantId = m_pipelineState->GetShaderVariantId();
  193. // Force update of hash
  194. m_currentStates.m_isDirty = true;
  195. m_currentStates.UpdateHash(m_drawStateOptions);
  196. m_cachedRhiPipelineStates[m_currentStates.m_hash] = m_pipelineState->GetRHIPipelineState();
  197. m_rhiPipelineState = m_pipelineState->GetRHIPipelineState();
  198. }
  199. void DynamicDrawContext::SetOutputScope(Scene* scene)
  200. {
  201. AZ_Assert(scene, "SetOutputScope was called with an invalid Scene");
  202. if (!scene)
  203. {
  204. return;
  205. }
  206. m_outputScope = OutputScopeType::Scene;
  207. m_scene = scene;
  208. m_pass = nullptr;
  209. m_drawFilter = RHI::DrawFilterMaskDefaultValue;
  210. SceneNotificationBus::Handler::BusConnect(m_scene->GetId());
  211. ReInit();
  212. }
  213. void DynamicDrawContext::SetOutputScope(RenderPipeline* pipeline)
  214. {
  215. if (!pipeline)
  216. {
  217. return;
  218. }
  219. if (!pipeline->GetScene())
  220. {
  221. AZ_Error("DynamicDrawContext", false, "SetOutputScope called with a RenderPipeline without adding to a scene");
  222. return;
  223. }
  224. m_outputScope = OutputScopeType::RenderPipeline;
  225. m_scene = pipeline->GetScene();
  226. m_pass = nullptr;
  227. m_drawFilter = pipeline->GetDrawFilterMask();
  228. SceneNotificationBus::Handler::BusConnect(m_scene->GetId());
  229. ReInit();
  230. }
  231. void DynamicDrawContext::SetOutputScope(RasterPass* pass)
  232. {
  233. AZ_Assert(pass, "SetOutputScope was called with an invalid RasterPass");
  234. if (!pass)
  235. {
  236. return;
  237. }
  238. m_outputScope = OutputScopeType::RasterPass;
  239. m_scene = nullptr;
  240. m_pass = pass;
  241. m_drawFilter = RHI::DrawFilterMaskDefaultValue;
  242. SceneNotificationBus::Handler::BusDisconnect();
  243. ReInit();
  244. }
  245. void DynamicDrawContext::ReInit()
  246. {
  247. // Reinitialize if it was initialized
  248. if (m_initialized)
  249. {
  250. // Report warning if there were some draw data
  251. AZ_Warning(
  252. "DynamicDrawContext", m_cachedDrawItems.size() == 0,
  253. "DynamicDrawContext::SetForScene should be called"
  254. " when there is no cached draw data");
  255. // Clear some cached data
  256. FrameEnd();
  257. m_cachedRhiPipelineStates.clear();
  258. // Reinitialize
  259. EndInit();
  260. }
  261. }
  262. bool DynamicDrawContext::IsReady()
  263. {
  264. return m_initialized;
  265. }
  266. ShaderVariantId DynamicDrawContext::UseShaderVariant(const ShaderOptionList& optionAndValues)
  267. {
  268. ShaderVariantId variantId;
  269. if (!m_initialized || !m_supportShaderVariants)
  270. {
  271. AZ_WarningOnce("DynamicDrawContext", false, "%s DynamicDrawContext is not initialized or unable to support shader variants. "
  272. "Check if it was initialized with InitShaderWithVariant", __FUNCTION__);
  273. return variantId;
  274. }
  275. RPI::ShaderOptionGroup shaderOptionGroup = m_shader->CreateShaderOptionGroup();
  276. shaderOptionGroup.SetUnspecifiedToDefaultValues();
  277. for (const auto& optionAndValue : optionAndValues)
  278. {
  279. shaderOptionGroup.SetValue(optionAndValue.first, optionAndValue.second);
  280. }
  281. variantId = shaderOptionGroup.GetShaderVariantId();
  282. return variantId;
  283. }
  284. void DynamicDrawContext::AddDrawStateOptions(DrawStateOptions options)
  285. {
  286. AZ_Assert(!m_initialized, "Can't call AddDrawStateOptions after context was initialized (EndInit was called)");
  287. m_drawStateOptions |= options;
  288. }
  289. bool DynamicDrawContext::HasDrawStateOptions(DrawStateOptions options)
  290. {
  291. return RHI::CheckBitsAny(m_drawStateOptions, options);
  292. }
  293. void DynamicDrawContext::SetDepthState(RHI::DepthState depthState)
  294. {
  295. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::DepthState))
  296. {
  297. if (!(m_currentStates.m_depthState == depthState))
  298. {
  299. m_currentStates.m_depthState = depthState;
  300. m_currentStates.m_isDirty = true;
  301. }
  302. }
  303. else
  304. {
  305. AZ_Warning("RHI", false, "Can't set SetDepthState if DrawVariation::DepthState wasn't enabled");
  306. }
  307. }
  308. void DynamicDrawContext::SetStencilState(RHI::StencilState stencilState)
  309. {
  310. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::StencilState))
  311. {
  312. if (!(m_currentStates.m_stencilState == stencilState))
  313. {
  314. m_currentStates.m_stencilState = stencilState;
  315. m_currentStates.m_isDirty = true;
  316. }
  317. }
  318. else
  319. {
  320. AZ_Warning("RHI", false, "Can't set SetStencilState if DrawVariation::StencilState wasn't enabled");
  321. }
  322. }
  323. void DynamicDrawContext::SetCullMode(RHI::CullMode cullMode)
  324. {
  325. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::FaceCullMode))
  326. {
  327. if (m_currentStates.m_cullMode != cullMode)
  328. {
  329. m_currentStates.m_cullMode = cullMode;
  330. m_currentStates.m_isDirty = true;
  331. }
  332. }
  333. else
  334. {
  335. AZ_Warning("RHI", false, "Can't set CullMode if DrawVariation::FaceCullMode wasn't enabled");
  336. }
  337. }
  338. void DynamicDrawContext::SetTarget0BlendState(RHI::TargetBlendState blendState)
  339. {
  340. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::BlendMode))
  341. {
  342. if (!(m_currentStates.m_blendState0 == blendState))
  343. {
  344. m_currentStates.m_blendState0 = blendState;
  345. m_currentStates.m_isDirty = true;
  346. }
  347. }
  348. else
  349. {
  350. AZ_Warning("RHI", false, "Can't set TargetBlendState if DrawVariation::BlendMode wasn't enabled");
  351. }
  352. }
  353. void DynamicDrawContext::SetPrimitiveType(RHI::PrimitiveTopology topology)
  354. {
  355. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::PrimitiveType))
  356. {
  357. if (m_currentStates.m_topology != topology)
  358. {
  359. m_currentStates.m_topology = topology;
  360. m_currentStates.m_isDirty = true;
  361. }
  362. }
  363. else
  364. {
  365. AZ_Warning("RHI", false, "Can't set PrimitiveTopology if DrawVariation::PrimitiveType wasn't enabled");
  366. }
  367. }
  368. void DynamicDrawContext::SetScissor(RHI::Scissor scissor)
  369. {
  370. m_useScissor = true;
  371. m_scissor = scissor;
  372. }
  373. void DynamicDrawContext::UnsetScissor()
  374. {
  375. m_useScissor = false;
  376. }
  377. void DynamicDrawContext::SetViewport(RHI::Viewport viewport)
  378. {
  379. m_useViewport = true;
  380. m_viewport = viewport;
  381. }
  382. void DynamicDrawContext::UnsetViewport()
  383. {
  384. m_useViewport = false;
  385. }
  386. void DynamicDrawContext::SetStencilReference(uint8_t stencilRef)
  387. {
  388. m_stencilRef = stencilRef;
  389. }
  390. uint8_t DynamicDrawContext::GetStencilReference() const
  391. {
  392. return m_stencilRef;
  393. }
  394. void DynamicDrawContext::SetShaderVariant(ShaderVariantId shaderVariantId)
  395. {
  396. if (!m_initialized || !m_supportShaderVariants)
  397. {
  398. AZ_WarningOnce("DynamicDrawContext", false, "%s DynamicDrawContext is not initialized or unable to support shader variants. "
  399. "Check if it was initialized with InitShaderWithVariant.\n", __FUNCTION__);
  400. return;
  401. }
  402. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::ShaderVariant))
  403. {
  404. if (m_currentStates.m_shaderVariantId != shaderVariantId)
  405. {
  406. m_currentStates.m_shaderVariantId = shaderVariantId;
  407. m_currentStates.m_isDirty = true;
  408. }
  409. }
  410. else
  411. {
  412. AZ_Warning("RHI", false, "Can't set SetShaderVariant if DrawVariation::ShaderVariant wasn't enabled");
  413. }
  414. }
  415. void DynamicDrawContext::DrawIndexed(const void* vertexData, uint32_t vertexCount, const void* indexData, uint32_t indexCount, RHI::IndexFormat indexFormat, Data::Instance < ShaderResourceGroup> drawSrg)
  416. {
  417. if (!m_initialized)
  418. {
  419. AZ_WarningOnce("DynamicDrawContext", false, "%s This function has been disabled because of failed initialization.\n", __FUNCTION__);
  420. return;
  421. }
  422. if (m_drawFinalized)
  423. {
  424. AZ_Assert(false, "Can't add draw calls after draw data was finalized");
  425. return;
  426. }
  427. if (m_drawSrgLayout && !drawSrg)
  428. {
  429. AZ_Assert(false, "drawSrg need to be provided since the shader requires it");
  430. return;
  431. }
  432. // DrawIndexed requires vertex data and index data
  433. if (indexData == nullptr || indexCount == 0 || vertexData == nullptr || vertexCount == 0)
  434. {
  435. AZ_Assert(false, "Failed to draw due to invalid index or vertex data");
  436. return;
  437. }
  438. // Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers
  439. uint32_t vertexDataSize = vertexCount * m_perVertexDataSize;
  440. RHI::Ptr<DynamicBuffer> vertexBuffer;
  441. vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly);
  442. uint32_t indexDataSize = indexCount * RHI::GetIndexFormatSize(indexFormat);
  443. RHI::Ptr<DynamicBuffer> indexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(indexDataSize, RHI::Alignment::InputAssembly);
  444. if (indexBuffer == nullptr || vertexBuffer == nullptr)
  445. {
  446. return;
  447. }
  448. DrawItemInfo drawItemInfo{{RHI::MultiDevice::AllDevices}};
  449. RHI::DrawItem& drawItem = drawItemInfo.m_drawItem;
  450. // --- Geometry View ---
  451. RHI::GeometryView newGeometryView{ RHI::MultiDevice::AllDevices };
  452. RHI::DrawIndexed drawIndexed;
  453. drawIndexed.m_indexCount = indexCount;
  454. newGeometryView.SetDrawArguments(drawIndexed);
  455. // Write data to vertex buffer and set up stream buffer views for DrawItem
  456. // The stream buffer view need to be cached before the frame is end
  457. vertexBuffer->Write(vertexData, vertexDataSize);
  458. newGeometryView.AddStreamBufferView(vertexBuffer->GetStreamBufferView(m_perVertexDataSize));
  459. // Write data to index buffer and set up index buffer view for DrawItem
  460. indexBuffer->Write(indexData, indexDataSize);
  461. newGeometryView.SetIndexBufferView(indexBuffer->GetIndexBufferView(indexFormat));
  462. drawItem.SetStreamIndices(newGeometryView.GetFullStreamBufferIndices());
  463. drawItemInfo.m_cachedIndex = static_cast<u32>(m_cachedGeometryViews.size());
  464. m_cachedGeometryViews.emplace_back(AZStd::move(newGeometryView));
  465. // --- PSO & SRG ---
  466. // Get RHI pipeline state from cached RHI pipeline states based on current draw state options
  467. drawItem.SetPipelineState(GetCurrentPipelineState());
  468. // Setup per context srg if it exists
  469. if (m_srgPerContext)
  470. {
  471. drawItem.SetShaderResourceGroups(m_srgGroups, 1);
  472. }
  473. // Setup per draw srg
  474. if (drawSrg)
  475. {
  476. drawItem.SetUniqueShaderResourceGroup(drawSrg->GetRHIShaderResourceGroup());
  477. }
  478. // --- Scissor & Viewport ---
  479. // Set scissor per draw if scissor is enabled.
  480. if (m_useScissor)
  481. {
  482. drawItem.SetScissors(&m_scissor, 1);
  483. }
  484. // Set viewport per draw if viewport is enabled.
  485. if (m_useViewport)
  486. {
  487. drawItem.SetViewports(&m_viewport, 1);
  488. }
  489. // Set stencil reference. Used when stencil is enabled.
  490. drawItem.SetStencilRef(m_stencilRef);
  491. drawItemInfo.m_sortKey = m_sortKey++;
  492. m_cachedDrawItems.emplace_back(AZStd::move(drawItemInfo));
  493. }
  494. void DynamicDrawContext::DrawLinear(const void* vertexData, uint32_t vertexCount, Data::Instance<ShaderResourceGroup> drawSrg)
  495. {
  496. if (!m_initialized)
  497. {
  498. AZ_WarningOnce("DynamicDrawContext", false, "%s This function has been disabled because of failed initialization.\n", __FUNCTION__);
  499. return;
  500. }
  501. if (m_drawFinalized)
  502. {
  503. AZ_Assert(false, "Can't add draw calls after draw data was finalized");
  504. return;
  505. }
  506. if (m_drawSrgLayout && !drawSrg)
  507. {
  508. AZ_Assert(false, "drawSrg need to be provided since the shader requires it");
  509. return;
  510. }
  511. if (vertexData == nullptr || vertexCount == 0)
  512. {
  513. AZ_Assert(false, "Failed to draw due to invalid vertex data");
  514. return;
  515. }
  516. // Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers
  517. uint32_t vertexDataSize = vertexCount * m_perVertexDataSize;
  518. RHI::Ptr<DynamicBuffer> vertexBuffer;
  519. vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly);
  520. if (vertexBuffer == nullptr)
  521. {
  522. return;
  523. }
  524. DrawItemInfo drawItemInfo{{RHI::MultiDevice::AllDevices}};
  525. RHI::DrawItem& drawItem = drawItemInfo.m_drawItem;
  526. // --- Geometry View ---
  527. RHI::GeometryView newGeometryView{ RHI::MultiDevice::AllDevices };
  528. newGeometryView.SetDrawArguments(RHI::DrawLinear(vertexCount, 0));
  529. // Write data to vertex buffer and set up stream buffer views for DrawItem
  530. // The stream buffer view need to be cached before the frame is end
  531. vertexBuffer->Write(vertexData, vertexDataSize);
  532. newGeometryView.AddStreamBufferView(vertexBuffer->GetStreamBufferView(m_perVertexDataSize));
  533. drawItem.SetStreamIndices(newGeometryView.GetFullStreamBufferIndices());
  534. drawItemInfo.m_cachedIndex = static_cast<u32>(m_cachedGeometryViews.size());
  535. m_cachedGeometryViews.emplace_back(AZStd::move(newGeometryView));
  536. // --- PSO & SRG ---
  537. // Get RHI pipeline state from cached RHI pipeline states based on current draw state options
  538. drawItem.SetPipelineState(GetCurrentPipelineState());
  539. // Setup per context srg if it exists
  540. if (m_srgPerContext)
  541. {
  542. drawItem.SetShaderResourceGroups(m_srgGroups, 1);
  543. }
  544. // Setup per draw srg
  545. if (drawSrg)
  546. {
  547. drawItem.SetUniqueShaderResourceGroup(drawSrg->GetRHIShaderResourceGroup());
  548. }
  549. // --- Scissor & Viewport ---
  550. // Set scissor per draw if scissor is enabled.
  551. if (m_useScissor)
  552. {
  553. drawItem.SetScissors(&m_scissor, 1);
  554. }
  555. // Set viewport per draw if viewport is enabled.
  556. if (m_useViewport)
  557. {
  558. drawItem.SetViewports(&m_viewport, 1);
  559. }
  560. drawItemInfo.m_sortKey = m_sortKey++;
  561. m_cachedDrawItems.emplace_back(AZStd::move(drawItemInfo));
  562. }
  563. Data::Instance<ShaderResourceGroup> DynamicDrawContext::NewDrawSrg()
  564. {
  565. if (!m_drawSrgLayout)
  566. {
  567. return nullptr;
  568. }
  569. Data::Instance<ShaderResourceGroup> drawSrg;
  570. if (m_nextDrawSrgIdx == m_cachedDrawSrg.size())
  571. {
  572. drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName());
  573. m_cachedDrawSrg.push_back(drawSrg);
  574. }
  575. else if (m_nextDrawSrgIdx < m_cachedDrawSrg.size())
  576. {
  577. drawSrg = m_cachedDrawSrg[m_nextDrawSrgIdx];
  578. }
  579. else
  580. {
  581. AZ_Assert(false, "Unexpected next draw srg index");
  582. }
  583. m_nextDrawSrgIdx++;
  584. // Set fallback value for shader variant if draw srg contains constant for shader variant fallback
  585. if (m_hasShaderVariantKeyFallbackEntry)
  586. {
  587. // If the dynamic draw context support multiple shader variants, it uses m_currentShaderVariantId to setup srg shader variant fallback key
  588. if (m_supportShaderVariants)
  589. {
  590. drawSrg->SetShaderVariantKeyFallbackValue(m_currentStates.m_shaderVariantId.m_key);
  591. }
  592. // otherwise use the m_pipelineState to config the fallback
  593. else
  594. {
  595. m_pipelineState->UpdateSrgVariantFallback(drawSrg);
  596. }
  597. }
  598. return drawSrg;
  599. }
  600. Data::Instance<ShaderResourceGroup> DynamicDrawContext::GetPerContextSrg()
  601. {
  602. return m_srgPerContext;
  603. }
  604. bool DynamicDrawContext::IsVertexSizeValid(uint32_t vertexSize)
  605. {
  606. return m_perVertexDataSize == vertexSize;
  607. }
  608. RHI::DrawListTag DynamicDrawContext::GetDrawListTag()
  609. {
  610. return m_drawListTag;
  611. }
  612. const Data::Instance<Shader>& DynamicDrawContext::GetShader() const
  613. {
  614. return m_shader;
  615. }
  616. void DynamicDrawContext::SetSortKey(RHI::DrawItemSortKey key)
  617. {
  618. m_sortKey = key;
  619. }
  620. RHI::DrawItemSortKey DynamicDrawContext::GetSortKey() const
  621. {
  622. return m_sortKey;
  623. }
  624. void DynamicDrawContext::FinalizeDrawList()
  625. {
  626. if (m_drawFinalized)
  627. {
  628. return;
  629. }
  630. AZ_Assert(m_cachedDrawList.size() == 0, "m_cachedDrawList should be cleared ine the end of last frame ");
  631. for (auto& drawItemInfo : m_cachedDrawItems)
  632. {
  633. if (drawItemInfo.m_cachedIndex != InvalidIndex)
  634. {
  635. // Get the pointer to geometry view here after we've built all the mesh buffers and won't be resizing the array
  636. drawItemInfo.m_drawItem.SetGeometryView(&m_cachedGeometryViews[drawItemInfo.m_cachedIndex]);
  637. }
  638. RHI::DrawItemProperties drawItemProperties;
  639. drawItemProperties.m_sortKey = drawItemInfo.m_sortKey;
  640. drawItemProperties.m_item = &drawItemInfo.m_drawItem;
  641. drawItemProperties.m_drawFilterMask = m_drawFilter;
  642. m_cachedDrawList.emplace_back(drawItemProperties);
  643. }
  644. m_drawFinalized = true;
  645. }
  646. void DynamicDrawContext::SubmitDrawList(ViewPtr view)
  647. {
  648. if (!m_initialized || m_outputScope == OutputScopeType::RasterPass)
  649. {
  650. return;
  651. }
  652. if (!view->HasDrawListTag(m_drawListTag))
  653. {
  654. return;
  655. }
  656. for (auto& drawItemProperties : m_cachedDrawList)
  657. {
  658. view->AddDrawItem(m_drawListTag, drawItemProperties);
  659. }
  660. }
  661. RHI::DrawListView DynamicDrawContext::GetDrawList()
  662. {
  663. return m_cachedDrawList;
  664. }
  665. void DynamicDrawContext::FrameEnd()
  666. {
  667. m_sortKey = 0;
  668. m_cachedDrawItems.clear();
  669. m_cachedGeometryViews.clear();
  670. m_cachedDrawList.clear();
  671. m_nextDrawSrgIdx = 0;
  672. m_drawFinalized = false;
  673. for (auto srg:m_cachedDrawSrg)
  674. {
  675. srg->ResetViews();
  676. }
  677. }
  678. const RHI::PipelineState* DynamicDrawContext::GetCurrentPipelineState()
  679. {
  680. // If m_currentStates wasn't changed, it's safe to return m_rhiPipelineState directly.
  681. if (!m_currentStates.m_isDirty)
  682. {
  683. return m_rhiPipelineState;
  684. }
  685. // m_currentStates is dirty. need to update m_currentStates's hash
  686. m_currentStates.UpdateHash(m_drawStateOptions);
  687. // search for cached pipeline state by using the updated hash
  688. auto findResult = m_cachedRhiPipelineStates.find(m_currentStates.m_hash);
  689. if (findResult == m_cachedRhiPipelineStates.end())
  690. {
  691. // Create pipelineState for current m_currentStates
  692. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::PrimitiveType))
  693. {
  694. if (m_pipelineState->ConstDescriptor().m_inputStreamLayout.GetTopology() != m_currentStates.m_topology)
  695. {
  696. RHI::InputStreamLayout& inputStreamLayout = m_pipelineState->InputStreamLayout();
  697. inputStreamLayout.SetTopology(m_currentStates.m_topology);
  698. inputStreamLayout.Finalize();
  699. }
  700. }
  701. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::DepthState))
  702. {
  703. m_pipelineState->RenderStatesOverlay().m_depthStencilState.m_depth = m_currentStates.m_depthState;
  704. }
  705. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::StencilState))
  706. {
  707. m_pipelineState->RenderStatesOverlay().m_depthStencilState.m_stencil = m_currentStates.m_stencilState;
  708. }
  709. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::FaceCullMode))
  710. {
  711. m_pipelineState->RenderStatesOverlay().m_rasterState.m_cullMode = m_currentStates.m_cullMode;
  712. }
  713. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::BlendMode))
  714. {
  715. m_pipelineState->RenderStatesOverlay().m_blendState.m_targets[0] = m_currentStates.m_blendState0;
  716. }
  717. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::ShaderVariant))
  718. {
  719. m_pipelineState->UpdateShaderVaraintId(m_currentStates.m_shaderVariantId);
  720. }
  721. const RHI::PipelineState* pipelineState = m_pipelineState->Finalize();
  722. m_cachedRhiPipelineStates[m_currentStates.m_hash] = pipelineState;
  723. m_rhiPipelineState = pipelineState;
  724. }
  725. else
  726. {
  727. m_rhiPipelineState = findResult->second;
  728. }
  729. return m_rhiPipelineState;
  730. }
  731. void DynamicDrawContext::OnPipelineStateLookupRebuilt()
  732. {
  733. m_cachedRhiPipelineStates.clear();
  734. EndInit();
  735. }
  736. }
  737. }