3
0

DynamicDrawContext.cpp 32 KB

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