RenderPass.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  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 <Atom/RHI/CommandList.h>
  9. #include <Atom/RHI/FrameGraphAttachmentInterface.h>
  10. #include <Atom/RHI/FrameGraphBuilder.h>
  11. #include <Atom/RHI/FrameGraphCompileContext.h>
  12. #include <Atom/RHI/FrameGraphExecuteContext.h>
  13. #include <Atom/RHI/RHIUtils.h>
  14. #include <Atom/RHI.Reflect/ImageScopeAttachmentDescriptor.h>
  15. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  16. #include <Atom/RHI.Reflect/Size.h>
  17. #include <Atom/RPI.Public/Base.h>
  18. #include <Atom/RPI.Reflect/Pass/RenderPassData.h>
  19. #include <Atom/RPI.Public/GpuQuery/Query.h>
  20. #include <Atom/RPI.Public/Pass/PassUtils.h>
  21. #include <Atom/RPI.Public/Pass/RenderPass.h>
  22. #include <Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h>
  23. #include <Atom/RPI.Public/RenderPipeline.h>
  24. #include <Atom/RPI.Public/Scene.h>
  25. #include <Atom/RPI.Public/View.h>
  26. namespace AZ
  27. {
  28. namespace RPI
  29. {
  30. RenderPass::RenderPass(const PassDescriptor& descriptor)
  31. : Pass(descriptor)
  32. {
  33. // Read view tag from pass data
  34. const RenderPassData* passData = PassUtils::GetPassData<RenderPassData>(descriptor);
  35. if (passData && !passData->m_pipelineViewTag.IsEmpty())
  36. {
  37. SetPipelineViewTag(passData->m_pipelineViewTag);
  38. }
  39. if (passData && passData->m_bindViewSrg)
  40. {
  41. m_flags.m_bindViewSrg = true;
  42. }
  43. }
  44. RenderPass::~RenderPass()
  45. {
  46. }
  47. RHI::RenderAttachmentConfiguration RenderPass::GetRenderAttachmentConfiguration() const
  48. {
  49. RHI::RenderAttachmentLayoutBuilder builder;
  50. auto* layoutBuilder = builder.AddSubpass();
  51. for (size_t slotIndex = 0; slotIndex < m_attachmentBindings.size(); ++slotIndex)
  52. {
  53. const PassAttachmentBinding& binding = m_attachmentBindings[slotIndex];
  54. if (!binding.GetAttachment())
  55. {
  56. continue;
  57. }
  58. // Handle the depth-stencil attachment. There should be only one.
  59. if (binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::DepthStencil)
  60. {
  61. layoutBuilder->DepthStencilAttachment(binding.GetAttachment()->m_descriptor.m_image.m_format);
  62. continue;
  63. }
  64. // Handle shading rate attachment. There should be only one.
  65. if (binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::ShadingRate)
  66. {
  67. layoutBuilder->ShadingRateAttachment(binding.GetAttachment()->m_descriptor.m_image.m_format);
  68. continue;
  69. }
  70. // Skip bindings that aren't outputs or inputOutputs
  71. if (binding.m_slotType != PassSlotType::Output && binding.m_slotType != PassSlotType::InputOutput)
  72. {
  73. continue;
  74. }
  75. if (binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::RenderTarget)
  76. {
  77. RHI::Format format = binding.GetAttachment()->m_descriptor.m_image.m_format;
  78. layoutBuilder->RenderTargetAttachment(format);
  79. }
  80. }
  81. RHI::RenderAttachmentLayout layout;
  82. [[maybe_unused]] RHI::ResultCode result = builder.End(layout);
  83. AZ_Assert(result == RHI::ResultCode::Success, "RenderPass [%s] failed to create render attachment layout", GetPathName().GetCStr());
  84. return RHI::RenderAttachmentConfiguration{ layout, 0 };
  85. }
  86. RHI::MultisampleState RenderPass::GetMultisampleState() const
  87. {
  88. RHI::MultisampleState outputMultiSampleState;
  89. bool wasSet = false;
  90. for (size_t slotIndex = 0; slotIndex < m_attachmentBindings.size(); ++slotIndex)
  91. {
  92. const PassAttachmentBinding& binding = m_attachmentBindings[slotIndex];
  93. if (binding.m_slotType != PassSlotType::Output && binding.m_slotType != PassSlotType::InputOutput)
  94. {
  95. continue;
  96. }
  97. if (!binding.GetAttachment())
  98. {
  99. continue;
  100. }
  101. if (binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::RenderTarget
  102. || binding.m_scopeAttachmentUsage == RHI::ScopeAttachmentUsage::DepthStencil)
  103. {
  104. if (!wasSet)
  105. {
  106. // save multi-sample state found in the first output color attachment
  107. outputMultiSampleState = binding.GetAttachment()->m_descriptor.m_image.m_multisampleState;
  108. wasSet = true;
  109. }
  110. else if (PassValidation::IsEnabled())
  111. {
  112. // return false directly if the current output color attachment has different multi-sample state then previous ones
  113. if (outputMultiSampleState != binding.GetAttachment()->m_descriptor.m_image.m_multisampleState)
  114. {
  115. AZ_Error("RPI", false, "Pass %s has different multi-sample states within its color attachments", GetPathName().GetCStr());
  116. break;
  117. }
  118. }
  119. else
  120. {
  121. break;
  122. }
  123. }
  124. }
  125. return outputMultiSampleState;
  126. }
  127. void RenderPass::InitializeInternal()
  128. {
  129. if (m_shaderResourceGroup != nullptr)
  130. {
  131. Name autoBind = Name("AutoBind");
  132. Name noBind = Name("NoBind");
  133. for (PassAttachmentBinding& binding : m_attachmentBindings)
  134. {
  135. const Name& shaderName = binding.m_shaderInputName;
  136. PassAttachment* attachment = binding.GetAttachment().get();
  137. if (shaderName == autoBind)
  138. {
  139. binding.m_shaderInputIndex = PassAttachmentBinding::ShaderInputAutoBind;
  140. }
  141. else if (shaderName == noBind)
  142. {
  143. binding.m_shaderInputIndex = PassAttachmentBinding::ShaderInputNoBind;
  144. }
  145. else if (attachment)
  146. {
  147. if (attachment->GetAttachmentType() == RHI::AttachmentType::Image)
  148. {
  149. RHI::ShaderInputImageIndex idx = m_shaderResourceGroup->FindShaderInputImageIndex(shaderName);
  150. AZ_Error("Pass System", idx.IsValid(), "[Pass %s] Could not retrieve Shader Image Index for SRG variable'%s'", GetName().GetCStr(), shaderName.GetCStr());
  151. binding.m_shaderInputIndex = idx.IsValid() ? static_cast<int16_t>(idx.GetIndex()) : PassAttachmentBinding::ShaderInputNoBind;
  152. }
  153. else if (attachment->GetAttachmentType() == RHI::AttachmentType::Buffer)
  154. {
  155. RHI::ShaderInputBufferIndex idx = m_shaderResourceGroup->FindShaderInputBufferIndex(shaderName);
  156. AZ_Error("Pass System", idx.IsValid(), "[Pass %s] Could not retrieve Shader Buffer Index for SRG variable '%s'", GetName().GetCStr(), shaderName.GetCStr());
  157. binding.m_shaderInputIndex = idx.IsValid() ? static_cast<int16_t>(idx.GetIndex()) : PassAttachmentBinding::ShaderInputNoBind;
  158. }
  159. }
  160. else
  161. {
  162. AZ_Error( "Pass System", AZ::RHI::IsNullRHI(), "[Pass %s] Could not bind shader buffer index '%s' because it has no attachment.", GetName().GetCStr(), shaderName.GetCStr());
  163. binding.m_shaderInputIndex = PassAttachmentBinding::ShaderInputNoBind;
  164. }
  165. }
  166. }
  167. }
  168. void RenderPass::FrameBeginInternal(FramePrepareParams params)
  169. {
  170. m_timestampResult = AZ::RPI::TimestampResult();
  171. if (GetScopeId().IsEmpty())
  172. {
  173. InitScope(RHI::ScopeId(GetPathName()), m_hardwareQueueClass);
  174. }
  175. params.m_frameGraphBuilder->ImportScopeProducer(*this);
  176. // Read back the ScopeQueries submitted from previous frames
  177. ReadbackScopeQueryResults();
  178. CollectSrgs();
  179. PassSystemInterface::Get()->IncrementFrameRenderPassCount();
  180. }
  181. void RenderPass::FrameEndInternal()
  182. {
  183. ResetSrgs();
  184. }
  185. void RenderPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
  186. {
  187. DeclareAttachmentsToFrameGraph(frameGraph);
  188. DeclarePassDependenciesToFrameGraph(frameGraph);
  189. AddScopeQueryToFrameGraph(frameGraph);
  190. }
  191. void RenderPass::BuildCommandList(const RHI::FrameGraphExecuteContext& context)
  192. {
  193. BeginScopeQuery(context);
  194. BuildCommandListInternal(context);
  195. EndScopeQuery(context);
  196. }
  197. void RenderPass::DeclareAttachmentsToFrameGraph(RHI::FrameGraphInterface frameGraph) const
  198. {
  199. for (const PassAttachmentBinding& attachmentBinding : m_attachmentBindings)
  200. {
  201. if (attachmentBinding.GetAttachment() != nullptr &&
  202. frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentBinding.GetAttachment()->GetAttachmentId()))
  203. {
  204. switch (attachmentBinding.m_unifiedScopeDesc.GetType())
  205. {
  206. case RHI::AttachmentType::Image:
  207. {
  208. frameGraph.UseAttachment(attachmentBinding.m_unifiedScopeDesc.GetAsImage(), attachmentBinding.GetAttachmentAccess(), attachmentBinding.m_scopeAttachmentUsage);
  209. break;
  210. }
  211. case RHI::AttachmentType::Buffer:
  212. {
  213. frameGraph.UseAttachment(attachmentBinding.m_unifiedScopeDesc.GetAsBuffer(), attachmentBinding.GetAttachmentAccess(), attachmentBinding.m_scopeAttachmentUsage);
  214. break;
  215. }
  216. default:
  217. AZ_Assert(false, "Error, trying to bind an attachment that is neither an image nor a buffer!");
  218. break;
  219. }
  220. }
  221. }
  222. }
  223. void RenderPass::DeclarePassDependenciesToFrameGraph(RHI::FrameGraphInterface frameGraph) const
  224. {
  225. for (Pass* pass : m_executeAfterPasses)
  226. {
  227. RenderPass* renderPass = azrtti_cast<RenderPass*>(pass);
  228. if (renderPass)
  229. {
  230. frameGraph.ExecuteAfter(renderPass->GetScopeId());
  231. }
  232. }
  233. for (Pass* pass : m_executeBeforePasses)
  234. {
  235. RenderPass* renderPass = azrtti_cast<RenderPass*>(pass);
  236. if (renderPass)
  237. {
  238. frameGraph.ExecuteBefore(renderPass->GetScopeId());
  239. }
  240. }
  241. }
  242. void RenderPass::BindAttachment(const RHI::FrameGraphCompileContext& context, PassAttachmentBinding& binding, int16_t& imageIndex, int16_t& bufferIndex)
  243. {
  244. PassAttachment* attachment = binding.GetAttachment().get();
  245. if (attachment)
  246. {
  247. int16_t inputIndex = binding.m_shaderInputIndex;
  248. uint16_t arrayIndex = binding.m_shaderInputArrayIndex;
  249. if (attachment->GetAttachmentType() == RHI::AttachmentType::Image)
  250. {
  251. if (inputIndex == PassAttachmentBinding::ShaderInputAutoBind)
  252. {
  253. inputIndex = imageIndex;
  254. }
  255. const RHI::ImageView* imageView =
  256. context.GetImageView(attachment->GetAttachmentId(), binding.m_unifiedScopeDesc.GetImageViewDescriptor(), binding.m_scopeAttachmentUsage);
  257. if (binding.m_shaderImageDimensionsNameIndex.HasName())
  258. {
  259. RHI::Size size = attachment->m_descriptor.m_image.m_size;
  260. AZ::Vector4 imageDimensions;
  261. imageDimensions.SetX(float(size.m_width));
  262. imageDimensions.SetY(float(size.m_height));
  263. imageDimensions.SetZ(1.0f / float(size.m_width));
  264. imageDimensions.SetW(1.0f / float(size.m_height));
  265. [[maybe_unused]]
  266. bool success = m_shaderResourceGroup->SetConstant(binding.m_shaderImageDimensionsNameIndex, imageDimensions);
  267. AZ_Assert(success, "Pass [%s] Could not find float4 constant [%s] in Shader Resource Group [%s]",
  268. GetPathName().GetCStr(),
  269. binding.m_shaderImageDimensionsNameIndex.GetNameForDebug().GetCStr(),
  270. m_shaderResourceGroup->GetDatabaseName());
  271. }
  272. if (binding.m_shaderInputIndex != PassAttachmentBinding::ShaderInputNoBind &&
  273. binding.m_scopeAttachmentUsage != RHI::ScopeAttachmentUsage::RenderTarget &&
  274. binding.m_scopeAttachmentUsage != RHI::ScopeAttachmentUsage::DepthStencil)
  275. {
  276. m_shaderResourceGroup->SetImageView(RHI::ShaderInputImageIndex(inputIndex), imageView, arrayIndex);
  277. ++imageIndex;
  278. }
  279. }
  280. else if (attachment->GetAttachmentType() == RHI::AttachmentType::Buffer)
  281. {
  282. if (binding.m_shaderInputIndex == PassAttachmentBinding::ShaderInputNoBind)
  283. {
  284. return;
  285. }
  286. if (inputIndex == PassAttachmentBinding::ShaderInputAutoBind)
  287. {
  288. inputIndex = bufferIndex;
  289. }
  290. const RHI::BufferView* bufferView = context.GetBufferView(attachment->GetAttachmentId(), binding.m_scopeAttachmentUsage);
  291. m_shaderResourceGroup->SetBufferView(RHI::ShaderInputBufferIndex(inputIndex), bufferView, arrayIndex);
  292. ++bufferIndex;
  293. }
  294. }
  295. }
  296. void RenderPass::BindPassSrg(const RHI::FrameGraphCompileContext& context, [[maybe_unused]] Data::Instance<ShaderResourceGroup>& shaderResourceGroup)
  297. {
  298. AZ_Assert(m_shaderResourceGroup != nullptr, "Passing a null shader resource group to RenderPass::BindPassSrg");
  299. int16_t imageIndex = 0;
  300. int16_t bufferIndex = 0;
  301. // Bind the input attachments to the SRG
  302. for (uint32_t idx = 0; idx < GetInputCount(); ++idx)
  303. {
  304. PassAttachmentBinding& binding = GetInputBinding(idx);
  305. AZ_Assert(binding.m_scopeAttachmentUsage != RHI::ScopeAttachmentUsage::RenderTarget,
  306. "Attachment bindings that are inputs cannot have their type set to 'RenderTarget'. Binding in question is %s on pass %s.",
  307. binding.m_name.GetCStr(),
  308. GetPathName().GetCStr());
  309. BindAttachment(context, binding, imageIndex, bufferIndex);
  310. }
  311. // Bind the input/output attachments to the SRG
  312. for (uint32_t idx = 0; idx < GetInputOutputCount(); ++idx)
  313. {
  314. PassAttachmentBinding& binding = GetInputOutputBinding(idx);
  315. BindAttachment(context, binding, imageIndex, bufferIndex);
  316. }
  317. // Bind the output attachments to the SRG
  318. for (uint32_t idx = 0; idx < GetOutputCount(); ++idx)
  319. {
  320. PassAttachmentBinding& binding = GetOutputBinding(idx);
  321. BindAttachment(context, binding, imageIndex, bufferIndex);
  322. }
  323. }
  324. ViewPtr RenderPass::GetView() const
  325. {
  326. if (m_pipeline)
  327. {
  328. return m_pipeline->GetFirstView(GetPipelineViewTag());
  329. }
  330. return nullptr;
  331. }
  332. void RenderPass::CollectSrgs()
  333. {
  334. // Scene srg
  335. const RHI::ShaderResourceGroup* sceneSrg = m_pipeline->GetScene()->GetRHIShaderResourceGroup();
  336. BindSrg(sceneSrg);
  337. // View srg
  338. if (m_flags.m_bindViewSrg)
  339. {
  340. ViewPtr view = GetView();
  341. if (view)
  342. {
  343. BindSrg(view->GetRHIShaderResourceGroup());
  344. }
  345. }
  346. // Pass srg
  347. if (m_shaderResourceGroup)
  348. {
  349. BindSrg(m_shaderResourceGroup->GetRHIShaderResourceGroup());
  350. }
  351. }
  352. void RenderPass::ResetSrgs()
  353. {
  354. m_shaderResourceGroupsToBind.clear();
  355. }
  356. void RenderPass::BindSrg(const RHI::ShaderResourceGroup* srg)
  357. {
  358. if (srg)
  359. {
  360. m_shaderResourceGroupsToBind[aznumeric_caster(srg->GetBindingSlot())] = srg;
  361. }
  362. }
  363. void RenderPass::SetSrgsForDraw(RHI::CommandList* commandList)
  364. {
  365. for (auto itr : m_shaderResourceGroupsToBind)
  366. {
  367. commandList->SetShaderResourceGroupForDraw(*(itr.second));
  368. }
  369. }
  370. void RenderPass::SetSrgsForDispatch(RHI::CommandList* commandList)
  371. {
  372. for (auto itr : m_shaderResourceGroupsToBind)
  373. {
  374. commandList->SetShaderResourceGroupForDispatch(*(itr.second));
  375. }
  376. }
  377. void RenderPass::SetPipelineViewTag(const PipelineViewTag& viewTag)
  378. {
  379. if (m_viewTag != viewTag)
  380. {
  381. m_viewTag = viewTag;
  382. if (m_pipeline)
  383. {
  384. m_pipeline->MarkPipelinePassChanges(PipelinePassChanges::PipelineViewTagChanged);
  385. }
  386. }
  387. m_flags.m_bindViewSrg = !viewTag.IsEmpty();
  388. }
  389. TimestampResult RenderPass::GetTimestampResultInternal() const
  390. {
  391. return m_timestampResult;
  392. }
  393. PipelineStatisticsResult RenderPass::GetPipelineStatisticsResultInternal() const
  394. {
  395. return m_statisticsResult;
  396. }
  397. Data::Instance<RPI::ShaderResourceGroup> RenderPass::GetShaderResourceGroup()
  398. {
  399. return m_shaderResourceGroup;
  400. }
  401. RHI::Ptr<Query> RenderPass::GetQuery(ScopeQueryType queryType)
  402. {
  403. uint32_t typeIndex = static_cast<uint32_t>(queryType);
  404. if (!m_scopeQueries[typeIndex])
  405. {
  406. RHI::Ptr<Query> query;
  407. switch (queryType)
  408. {
  409. case ScopeQueryType::Timestamp:
  410. query = GpuQuerySystemInterface::Get()->CreateQuery(
  411. RHI::QueryType::Timestamp, RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  412. break;
  413. case ScopeQueryType::PipelineStatistics:
  414. query = GpuQuerySystemInterface::Get()->CreateQuery(
  415. RHI::QueryType::PipelineStatistics, RHI::QueryPoolScopeAttachmentType::Global, RHI::ScopeAttachmentAccess::Write);
  416. break;
  417. }
  418. m_scopeQueries[typeIndex] = query;
  419. }
  420. return m_scopeQueries[typeIndex];
  421. }
  422. template<typename Func>
  423. inline void RenderPass::ExecuteOnTimestampQuery(Func&& func)
  424. {
  425. if (IsTimestampQueryEnabled())
  426. {
  427. auto query = GetQuery(ScopeQueryType::Timestamp);
  428. if (query)
  429. {
  430. func(query);
  431. }
  432. }
  433. }
  434. template<typename Func>
  435. inline void RenderPass::ExecuteOnPipelineStatisticsQuery(Func&& func)
  436. {
  437. if (IsPipelineStatisticsQueryEnabled())
  438. {
  439. auto query = GetQuery(ScopeQueryType::PipelineStatistics);
  440. if (query)
  441. {
  442. func(query);
  443. }
  444. }
  445. }
  446. void RenderPass::AddScopeQueryToFrameGraph(RHI::FrameGraphInterface frameGraph)
  447. {
  448. const auto addToFrameGraph = [&frameGraph](RHI::Ptr<Query> query)
  449. {
  450. query->AddToFrameGraph(frameGraph);
  451. };
  452. ExecuteOnTimestampQuery(addToFrameGraph);
  453. ExecuteOnPipelineStatisticsQuery(addToFrameGraph);
  454. }
  455. void RenderPass::BeginScopeQuery(const RHI::FrameGraphExecuteContext& context)
  456. {
  457. const auto beginQuery = [&context, this](RHI::Ptr<Query> query)
  458. {
  459. if (query->BeginQuery(context) == QueryResultCode::Fail)
  460. {
  461. AZ_UNUSED(this); // Prevent unused warning in release builds
  462. AZ_WarningOnce("RenderPass", false, "BeginScopeQuery failed. Make sure AddScopeQueryToFrameGraph was called in SetupFrameGraphDependencies"
  463. " for this pass: %s", this->RTTI_GetTypeName());
  464. }
  465. };
  466. if (context.GetCommandListIndex() == 0)
  467. {
  468. ExecuteOnTimestampQuery(beginQuery);
  469. ExecuteOnPipelineStatisticsQuery(beginQuery);
  470. }
  471. }
  472. void RenderPass::EndScopeQuery(const RHI::FrameGraphExecuteContext& context)
  473. {
  474. const auto endQuery = [&context](RHI::Ptr<Query> query)
  475. {
  476. query->EndQuery(context);
  477. };
  478. // This scope query implementation should be replaced by
  479. // [ATOM-5407] [RHI][Core] - Add GPU timestamp and pipeline statistic support for scopes
  480. // For timestamp query, it's okay to execute across different command lists
  481. if (context.GetCommandListIndex() == context.GetCommandListCount() - 1)
  482. {
  483. ExecuteOnTimestampQuery(endQuery);
  484. }
  485. // For all the other types of queries except timestamp, the query start and end has to be in the same command list
  486. // Here only tracks the PipelineStatistics for the first command list due to that we don't know how many queries are
  487. // needed when AddScopeQueryToFrameGraph is called.
  488. // This implementation leads to an issue that we may not get accurate pipeline statistic data
  489. // for passes which were executed with more than one command list
  490. if (context.GetCommandListIndex() == 0)
  491. {
  492. ExecuteOnPipelineStatisticsQuery(endQuery);
  493. }
  494. }
  495. void RenderPass::ReadbackScopeQueryResults()
  496. {
  497. ExecuteOnTimestampQuery([this](RHI::Ptr<Query> query)
  498. {
  499. const uint32_t TimestampResultQueryCount = 2u;
  500. uint64_t timestampResult[TimestampResultQueryCount] = {0};
  501. query->GetLatestResult(&timestampResult, sizeof(uint64_t) * TimestampResultQueryCount);
  502. m_timestampResult = TimestampResult(timestampResult[0], timestampResult[1], RHI::HardwareQueueClass::Graphics);
  503. });
  504. ExecuteOnPipelineStatisticsQuery([this](RHI::Ptr<Query> query)
  505. {
  506. query->GetLatestResult(&m_statisticsResult, sizeof(PipelineStatisticsResult));
  507. });
  508. }
  509. } // namespace RPI
  510. } // namespace AZ