3
0

DynamicDrawContext.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  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{{RHI::MultiDevice::AllDevices}};
  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.SetArguments(drawIndexed);
  428. // Get RHI pipeline state from cached RHI pipeline states based on current draw state options
  429. drawItem.SetPipelineState(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. drawItemInfo.m_vertexBufferViewIndex = static_cast<BufferViewIndexType>(m_cachedStreamBufferViews.size() - 1);
  435. // Write data to index buffer and set up index buffer view for DrawItem
  436. indexBuffer->Write(indexData, indexDataSize);
  437. m_cachedIndexBufferViews.push_back(indexBuffer->GetIndexBufferView(indexFormat));
  438. drawItemInfo.m_indexBufferViewIndex = static_cast<BufferViewIndexType>(m_cachedIndexBufferViews.size() - 1);
  439. // Setup per context srg if it exists
  440. if (m_srgPerContext)
  441. {
  442. drawItem.SetShaderResourceGroups(m_srgGroups, 1);
  443. }
  444. // Setup per draw srg
  445. if (drawSrg)
  446. {
  447. drawItem.SetUniqueShaderResourceGroup(drawSrg->GetRHIShaderResourceGroup());
  448. }
  449. // Set scissor per draw if scissor is enabled.
  450. if (m_useScissor)
  451. {
  452. drawItem.SetScissors(&m_scissor, 1);
  453. }
  454. // Set viewport per draw if viewport is enabled.
  455. if (m_useViewport)
  456. {
  457. drawItem.SetViewports(&m_viewport, 1);
  458. }
  459. // Set stencil reference. Used when stencil is enabled.
  460. drawItem.SetStencilRef(m_stencilRef);
  461. drawItemInfo.m_sortKey = m_sortKey++;
  462. m_cachedDrawItems.emplace_back(AZStd::move(drawItemInfo));
  463. }
  464. void DynamicDrawContext::DrawLinear(const void* vertexData, uint32_t vertexCount, Data::Instance<ShaderResourceGroup> drawSrg)
  465. {
  466. if (!m_initialized)
  467. {
  468. AZ_WarningOnce("DynamicDrawContext", false, "%s This function has been disabled because of failed initialization.\n", __FUNCTION__);
  469. return;
  470. }
  471. if (m_drawFinalized)
  472. {
  473. AZ_Assert(false, "Can't add draw calls after draw data was finalized");
  474. return;
  475. }
  476. if (m_drawSrgLayout && !drawSrg)
  477. {
  478. AZ_Assert(false, "drawSrg need to be provided since the shader requires it");
  479. return;
  480. }
  481. if (vertexData == nullptr || vertexCount == 0)
  482. {
  483. AZ_Assert(false, "Failed to draw due to invalid vertex data");
  484. return;
  485. }
  486. // Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers
  487. uint32_t vertexDataSize = vertexCount * m_perVertexDataSize;
  488. RHI::Ptr<DynamicBuffer> vertexBuffer;
  489. vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly);
  490. if (vertexBuffer == nullptr)
  491. {
  492. return;
  493. }
  494. DrawItemInfo drawItemInfo{{RHI::MultiDevice::AllDevices}};
  495. RHI::DrawItem& drawItem = drawItemInfo.m_drawItem;
  496. // Draw argument
  497. RHI::DrawLinear drawLinear;
  498. drawLinear.m_instanceCount = 1;
  499. drawLinear.m_vertexCount = vertexCount;
  500. drawItem.SetArguments(drawLinear);
  501. // Get RHI pipeline state from cached RHI pipeline states based on current draw state options
  502. drawItem.SetPipelineState(GetCurrentPipelineState());
  503. // Write data to vertex buffer and set up stream buffer views for DrawItem
  504. // The stream buffer view need to be cached before the frame is end
  505. vertexBuffer->Write(vertexData, vertexDataSize);
  506. m_cachedStreamBufferViews.push_back(vertexBuffer->GetStreamBufferView(m_perVertexDataSize));
  507. drawItemInfo.m_vertexBufferViewIndex = uint32_t(m_cachedStreamBufferViews.size() - 1);
  508. // Setup per context srg if it exists
  509. if (m_srgPerContext)
  510. {
  511. drawItem.SetShaderResourceGroups(m_srgGroups, 1);
  512. }
  513. // Setup per draw srg
  514. if (drawSrg)
  515. {
  516. drawItem.SetUniqueShaderResourceGroup(drawSrg->GetRHIShaderResourceGroup());
  517. }
  518. // Set scissor per draw if scissor is enabled.
  519. if (m_useScissor)
  520. {
  521. drawItem.SetScissors(&m_scissor, 1);
  522. }
  523. // Set viewport per draw if viewport is enabled.
  524. if (m_useViewport)
  525. {
  526. drawItem.SetViewports(&m_viewport, 1);
  527. }
  528. drawItemInfo.m_sortKey = m_sortKey++;
  529. m_cachedDrawItems.emplace_back(AZStd::move(drawItemInfo));
  530. }
  531. Data::Instance<ShaderResourceGroup> DynamicDrawContext::NewDrawSrg()
  532. {
  533. if (!m_drawSrgLayout)
  534. {
  535. return nullptr;
  536. }
  537. Data::Instance<ShaderResourceGroup> drawSrg;
  538. if (m_nextDrawSrgIdx == m_cachedDrawSrg.size())
  539. {
  540. drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName());
  541. m_cachedDrawSrg.push_back(drawSrg);
  542. }
  543. else if (m_nextDrawSrgIdx < m_cachedDrawSrg.size())
  544. {
  545. drawSrg = m_cachedDrawSrg[m_nextDrawSrgIdx];
  546. }
  547. else
  548. {
  549. AZ_Assert(false, "Unexpected next draw srg index");
  550. }
  551. m_nextDrawSrgIdx++;
  552. // Set fallback value for shader variant if draw srg contains constant for shader variant fallback
  553. if (m_hasShaderVariantKeyFallbackEntry)
  554. {
  555. // If the dynamic draw context support multiple shader variants, it uses m_currentShaderVariantId to setup srg shader variant fallback key
  556. if (m_supportShaderVariants)
  557. {
  558. drawSrg->SetShaderVariantKeyFallbackValue(m_currentShaderVariantId.m_key);
  559. }
  560. // otherwise use the m_pipelineState to config the fallback
  561. else
  562. {
  563. m_pipelineState->UpdateSrgVariantFallback(drawSrg);
  564. }
  565. }
  566. return drawSrg;
  567. }
  568. Data::Instance<ShaderResourceGroup> DynamicDrawContext::GetPerContextSrg()
  569. {
  570. return m_srgPerContext;
  571. }
  572. bool DynamicDrawContext::IsVertexSizeValid(uint32_t vertexSize)
  573. {
  574. return m_perVertexDataSize == vertexSize;
  575. }
  576. RHI::DrawListTag DynamicDrawContext::GetDrawListTag()
  577. {
  578. return m_drawListTag;
  579. }
  580. const Data::Instance<Shader>& DynamicDrawContext::GetShader() const
  581. {
  582. return m_shader;
  583. }
  584. void DynamicDrawContext::SetSortKey(RHI::DrawItemSortKey key)
  585. {
  586. m_sortKey = key;
  587. }
  588. RHI::DrawItemSortKey DynamicDrawContext::GetSortKey() const
  589. {
  590. return m_sortKey;
  591. }
  592. void DynamicDrawContext::FinalizeDrawList()
  593. {
  594. if (m_drawFinalized)
  595. {
  596. return;
  597. }
  598. AZ_Assert(m_cachedDrawList.size() == 0, "m_cachedDrawList should be cleared ine the end of last frame ");
  599. for (auto& drawItemInfo : m_cachedDrawItems)
  600. {
  601. if (drawItemInfo.m_indexBufferViewIndex != InvalidIndex)
  602. {
  603. drawItemInfo.m_drawItem.SetIndexBufferView(&m_cachedIndexBufferViews[drawItemInfo.m_indexBufferViewIndex]);
  604. }
  605. if (drawItemInfo.m_vertexBufferViewIndex != InvalidIndex)
  606. {
  607. drawItemInfo.m_drawItem.SetStreamBufferViews(&m_cachedStreamBufferViews[drawItemInfo.m_vertexBufferViewIndex], 1);
  608. }
  609. RHI::DrawItemProperties drawItemProperties;
  610. drawItemProperties.m_sortKey = drawItemInfo.m_sortKey;
  611. drawItemProperties.m_Item = &drawItemInfo.m_drawItem;
  612. drawItemProperties.m_drawFilterMask = m_drawFilter;
  613. m_cachedDrawList.emplace_back(drawItemProperties);
  614. }
  615. m_drawFinalized = true;
  616. }
  617. void DynamicDrawContext::SubmitDrawList(ViewPtr view)
  618. {
  619. if (!m_initialized || m_outputScope == OutputScopeType::RasterPass)
  620. {
  621. return;
  622. }
  623. if (!view->HasDrawListTag(m_drawListTag))
  624. {
  625. return;
  626. }
  627. for (auto& drawItemProperties : m_cachedDrawList)
  628. {
  629. view->AddDrawItem(m_drawListTag, drawItemProperties);
  630. }
  631. }
  632. RHI::DrawListView DynamicDrawContext::GetDrawList()
  633. {
  634. return m_cachedDrawList;
  635. }
  636. void DynamicDrawContext::FrameEnd()
  637. {
  638. m_sortKey = 0;
  639. m_cachedDrawItems.clear();
  640. m_cachedStreamBufferViews.clear();
  641. m_cachedIndexBufferViews.clear();
  642. m_cachedDrawList.clear();
  643. m_nextDrawSrgIdx = 0;
  644. m_drawFinalized = false;
  645. for (auto srg:m_cachedDrawSrg)
  646. {
  647. srg->ResetViews();
  648. }
  649. }
  650. const RHI::PipelineState* DynamicDrawContext::GetCurrentPipelineState()
  651. {
  652. // If m_currentStates wasn't changed, it's safe to return m_rhiPipelineState directly.
  653. if (!m_currentStates.m_isDirty)
  654. {
  655. return m_rhiPipelineState;
  656. }
  657. // m_currentStates is dirty. need to update m_currentStates's hash
  658. m_currentStates.UpdateHash(m_drawStateOptions);
  659. // search for cached pipeline state by using the updated hash
  660. auto findResult = m_cachedRhiPipelineStates.find(m_currentStates.m_hash);
  661. if (findResult == m_cachedRhiPipelineStates.end())
  662. {
  663. // Create pipelineState for current m_currentStates
  664. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::PrimitiveType))
  665. {
  666. if (m_pipelineState->ConstDescriptor().m_inputStreamLayout.GetTopology() != m_currentStates.m_topology)
  667. {
  668. RHI::InputStreamLayout& inputStreamLayout = m_pipelineState->InputStreamLayout();
  669. inputStreamLayout.SetTopology(m_currentStates.m_topology);
  670. inputStreamLayout.Finalize();
  671. }
  672. }
  673. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::DepthState))
  674. {
  675. m_pipelineState->RenderStatesOverlay().m_depthStencilState.m_depth = m_currentStates.m_depthState;
  676. }
  677. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::StencilState))
  678. {
  679. m_pipelineState->RenderStatesOverlay().m_depthStencilState.m_stencil = m_currentStates.m_stencilState;
  680. }
  681. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::FaceCullMode))
  682. {
  683. m_pipelineState->RenderStatesOverlay().m_rasterState.m_cullMode = m_currentStates.m_cullMode;
  684. }
  685. if (RHI::CheckBitsAny(m_drawStateOptions, DrawStateOptions::BlendMode))
  686. {
  687. m_pipelineState->RenderStatesOverlay().m_blendState.m_targets[0] = m_currentStates.m_blendState0;
  688. }
  689. const RHI::PipelineState* pipelineState = m_pipelineState->Finalize();
  690. m_cachedRhiPipelineStates[m_currentStates.m_hash] = pipelineState;
  691. m_rhiPipelineState = pipelineState;
  692. }
  693. else
  694. {
  695. m_rhiPipelineState = findResult->second;
  696. }
  697. return m_rhiPipelineState;
  698. }
  699. }
  700. }