3
0

ImageAttachmentPreviewPass.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  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/FrameScheduler.h>
  10. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  11. #include <Atom/RPI.Public/Buffer/BufferSystemInterface.h>
  12. #include <Atom/RPI.Public/Buffer/Buffer.h>
  13. #include <Atom/RPI.Public/Image/AttachmentImagePool.h>
  14. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  15. #include <Atom/RPI.Public/Pass/AttachmentReadback.h>
  16. #include <Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h>
  17. #include <Atom/RPI.Public/Pass/ParentPass.h>
  18. #include <Atom/RPI.Public/RenderPipeline.h>
  19. #include <Atom/RPI.Public/RPIUtils.h>
  20. #include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
  21. namespace AZ
  22. {
  23. namespace RPI
  24. {
  25. void ImageAttachmentCopy::SetImageAttachment(RHI::AttachmentId srcAttachmentId, RHI::AttachmentId destAttachmentId)
  26. {
  27. m_srcAttachmentId = srcAttachmentId;
  28. m_destAttachmentId = destAttachmentId;
  29. // Use the unique destination attachment id as scope id
  30. InitScope(m_destAttachmentId);
  31. // Clear the previous attachment and copy item
  32. m_copyItem = {};
  33. m_destImage = nullptr;
  34. }
  35. void ImageAttachmentCopy::Reset()
  36. {
  37. m_srcAttachmentId = RHI::AttachmentId{};
  38. m_destAttachmentId = RHI::AttachmentId{};
  39. m_copyItem = {};
  40. m_destImage = nullptr;
  41. }
  42. void ImageAttachmentCopy::InvalidateDestImage()
  43. {
  44. m_destImage = nullptr;
  45. }
  46. void ImageAttachmentCopy::FrameBegin(Pass::FramePrepareParams params)
  47. {
  48. RHI::FrameGraphAttachmentInterface attachmentDatabase = params.m_frameGraphBuilder->GetAttachmentDatabase();
  49. if (m_srcAttachmentId.IsEmpty())
  50. {
  51. return;
  52. }
  53. // Return if the source attachment is not imported
  54. if (!attachmentDatabase.IsAttachmentValid(m_srcAttachmentId))
  55. {
  56. Reset();
  57. return;
  58. }
  59. if (!m_destImage)
  60. {
  61. Data::Instance<AttachmentImagePool> pool = ImageSystemInterface::Get()->GetSystemAttachmentPool();
  62. RHI::ImageDescriptor imageDesc = attachmentDatabase.GetImageDescriptor(m_srcAttachmentId);
  63. // add read flag since the image will always be read by ImageAttachmentPreviewPass
  64. imageDesc.m_bindFlags |= RHI::ImageBindFlags::ShaderRead;
  65. imageDesc.m_arraySize = 1;
  66. Name copyName = Name( AZStd::string::format("%s_%s", m_srcAttachmentId.GetCStr(), "Copy") );
  67. m_destImage = AttachmentImage::Create(*pool.get(), imageDesc, copyName, nullptr, nullptr);
  68. }
  69. if (!m_destImage)
  70. {
  71. AZ_Warning("ImageAttachmentCopy", false, "Failed to create a copy to preview attachment [%s]", m_srcAttachmentId.GetCStr());
  72. Reset();
  73. return;
  74. }
  75. // Import this scope producer
  76. params.m_frameGraphBuilder->ImportScopeProducer(*this);
  77. attachmentDatabase.ImportImage(m_destAttachmentId, m_destImage->GetRHIImage());
  78. }
  79. void ImageAttachmentCopy::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
  80. {
  81. RHI::ImageScopeAttachmentDescriptor srcDescriptor{ m_srcAttachmentId };
  82. frameGraph.UseCopyAttachment(srcDescriptor, RHI::ScopeAttachmentAccess::Read);
  83. RHI::ImageScopeAttachmentDescriptor destDescriptor{ m_destAttachmentId };
  84. frameGraph.UseCopyAttachment(destDescriptor, RHI::ScopeAttachmentAccess::Write);
  85. frameGraph.SetEstimatedItemCount(1);
  86. }
  87. void ImageAttachmentCopy::CompileResources(const RHI::FrameGraphCompileContext& context)
  88. {
  89. // copy descriptor for copying image
  90. RHI::CopyImageDescriptor copyImage;
  91. const AZ::RHI::Image* image = context.GetImage(m_srcAttachmentId);
  92. copyImage.m_sourceImage = image;
  93. copyImage.m_sourceSize = image->GetDescriptor().m_size;
  94. copyImage.m_sourceSubresource.m_arraySlice = m_sourceArraySlice;
  95. copyImage.m_destinationImage = context.GetImage(m_destAttachmentId);
  96. m_copyItem = copyImage;
  97. }
  98. void ImageAttachmentCopy::BuildCommandList(const RHI::FrameGraphExecuteContext& context)
  99. {
  100. context.GetCommandList()->Submit(m_copyItem.GetDeviceCopyItem(context.GetDeviceIndex()));
  101. }
  102. Ptr<ImageAttachmentPreviewPass> ImageAttachmentPreviewPass::Create(const PassDescriptor& descriptor)
  103. {
  104. Ptr<ImageAttachmentPreviewPass> imageAttachmentPreviewPass = aznew ImageAttachmentPreviewPass(descriptor);
  105. return imageAttachmentPreviewPass;
  106. }
  107. ImageAttachmentPreviewPass::ImageAttachmentPreviewPass(const PassDescriptor& descriptor)
  108. : Pass(descriptor)
  109. {
  110. InitScope(RHI::ScopeId(GetPathName()));
  111. }
  112. ImageAttachmentPreviewPass::~ImageAttachmentPreviewPass()
  113. {
  114. Data::AssetBus::Handler::BusDisconnect();
  115. }
  116. void ImageAttachmentPreviewPass::PreviewImageAttachmentForPass(Pass* pass, const PassAttachment* passAttachment, RenderPipeline* previewOutputPipeline, u32 imageArraySlice)
  117. {
  118. if (passAttachment->GetAttachmentType() != RHI::AttachmentType::Image)
  119. {
  120. return;
  121. }
  122. ClearPreviewAttachment();
  123. // find the attachment in pass's attachment binding
  124. uint32_t bindingIndex = 0;
  125. for (auto& binding : pass->GetAttachmentBindings())
  126. {
  127. if (passAttachment == binding.GetAttachment())
  128. {
  129. RHI::AttachmentId attachmentId = binding.GetAttachment()->GetAttachmentId();
  130. // Append slot index and pass name so the read back's name won't be same as the attachment used in other passes.
  131. AZStd::string readbackName = AZStd::string::format("%s_%d_%s", attachmentId.GetCStr(),
  132. bindingIndex, GetName().GetCStr());
  133. m_attachmentCopy = AZStd::make_shared<AZ::RPI::ImageAttachmentCopy>();
  134. m_attachmentCopy->SetImageAttachment(attachmentId, AZ::Name(readbackName));
  135. pass->m_attachmentCopy = m_attachmentCopy;
  136. break;
  137. }
  138. bindingIndex++;
  139. }
  140. if (bindingIndex == pass->GetAttachmentBindings().size())
  141. {
  142. AZ_Warning("RPI", false, "failed to find the attachment %s", passAttachment->GetAttachmentId().GetCStr());
  143. return;
  144. }
  145. m_updateDrawData = true;
  146. m_imageAttachmentId = m_attachmentCopy->m_destAttachmentId;
  147. m_attachmentCopy->m_sourceArraySlice = u16(imageArraySlice);
  148. // Set the output of this pass to write to the pipeline output
  149. if (!m_outputColorAttachment)
  150. {
  151. RenderPipeline* pipeline = previewOutputPipeline ? previewOutputPipeline : pass->GetRenderPipeline();
  152. if (pipeline)
  153. {
  154. Pass* pipelinePass = pipeline->GetRootPass().get();
  155. PassAttachmentBinding* binding = nullptr;
  156. // Get either first output or first input/output
  157. if (pipelinePass->GetOutputCount() > 0)
  158. {
  159. binding = &pipelinePass->GetOutputBinding(0);
  160. }
  161. else if (pipelinePass->GetInputOutputCount() > 0)
  162. {
  163. binding = &pipelinePass->GetInputOutputBinding(0);
  164. }
  165. if (binding)
  166. {
  167. SetOutputColorAttachment(binding->GetAttachment());
  168. }
  169. AZ_Warning("PassSystem", binding != nullptr, "ImageAttachmentPreviewPass couldn't find a color attachment on pipeline");
  170. }
  171. }
  172. }
  173. void ImageAttachmentPreviewPass::ClearPreviewAttachment()
  174. {
  175. ClearDrawData();
  176. // Allocate and release the copy scope only when there is an attachment to preview.
  177. // So we only need a weak ptr in the RenderPass and don't need to worry about releasing.
  178. m_attachmentCopy = nullptr;
  179. m_imageAttachmentId = RHI::AttachmentId{};
  180. m_updateDrawData = true;
  181. m_outputColorAttachment = nullptr;
  182. }
  183. void ImageAttachmentPreviewPass::SetPreviewLocation(AZ::Vector2 position, AZ::Vector2 size, bool keepAspectRatio)
  184. {
  185. m_position = position;
  186. m_size = size;
  187. m_keepAspectRatio = keepAspectRatio;
  188. }
  189. void ImageAttachmentPreviewPass::ClearDrawData()
  190. {
  191. if (m_needsShaderLoad)
  192. {
  193. return;
  194. }
  195. // update pass srg
  196. for (auto& previewInfo : m_imageTypePreviewInfo)
  197. {
  198. // unbind previous binded image views
  199. m_passSrg->SetImageView(previewInfo.m_imageInput, nullptr, 0);
  200. previewInfo.m_item.SetPipelineState(nullptr);
  201. previewInfo.m_imageCount = 0;
  202. }
  203. m_passSrgChanged = true;
  204. }
  205. void ImageAttachmentPreviewPass::SetOutputColorAttachment(RHI::Ptr<PassAttachment> outputImageAttachment)
  206. {
  207. m_outputColorAttachment = outputImageAttachment;
  208. m_updateDrawData = true;
  209. }
  210. void ImageAttachmentPreviewPass::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
  211. {
  212. Data::Asset<ShaderAsset> shaderAsset = Data::static_pointer_cast<ShaderAsset>(asset);
  213. if (shaderAsset)
  214. {
  215. m_needsShaderLoad = true;
  216. m_updateDrawData = true;
  217. }
  218. }
  219. void ImageAttachmentPreviewPass::LoadShader()
  220. {
  221. m_needsShaderLoad = false;
  222. // Load Shader
  223. constexpr const char* ShaderPath = "shaders/imagepreview.azshader";
  224. Data::Asset<ShaderAsset> shaderAsset = RPI::FindShaderAsset(ShaderPath);
  225. if (!shaderAsset.IsReady())
  226. {
  227. AZ_Error("PassSystem", false, "[ImageAttachmentsPreviewPass]: Failed to load shader '%s'!", GetPathName().GetCStr(), ShaderPath);
  228. return;
  229. }
  230. m_shader = Shader::FindOrCreate(shaderAsset);
  231. if (m_shader == nullptr)
  232. {
  233. AZ_Error("PassSystem", false, "[ImageAttachmentsPreviewPass]: Failed to create shader instance from asset '%s'!", ShaderPath);
  234. return;
  235. }
  236. // Load SRG
  237. const auto srgLayout = m_shader->FindShaderResourceGroupLayout(SrgBindingSlot::Pass);
  238. if (srgLayout)
  239. {
  240. m_passSrg = ShaderResourceGroup::Create(shaderAsset, m_shader->GetSupervariantIndex(), srgLayout->GetName());
  241. if (!m_passSrg)
  242. {
  243. AZ_Error("PassSystem", false, "Failed to create SRG from shader asset '%s'", ShaderPath);
  244. return;
  245. }
  246. }
  247. // Find srg input indexes
  248. m_imageTypePreviewInfo[static_cast<uint32_t>(ImageType::Image2d)].m_imageInput = m_passSrg->FindShaderInputImageIndex(Name("m_image"));
  249. m_imageTypePreviewInfo[static_cast<uint32_t>(ImageType::Image2dMs)].m_imageInput = m_passSrg->FindShaderInputImageIndex(Name("m_msImage"));
  250. m_colorRangeMinMaxInput = m_passSrg->FindShaderInputConstantIndex(Name("m_colorRangeMinMax"));
  251. // Setup initial data for pipeline state descriptors. The rest of the data will be set when the draw data is updated
  252. // option names from the azsl file
  253. const char* optionValues[] =
  254. {
  255. "ImageType::Image2d",
  256. "ImageType::Image2dMs"
  257. };
  258. const char* optionName = "o_imageType";
  259. ShaderOptionGroup shaderOption = m_shader->CreateShaderOptionGroup();
  260. RHI::InputStreamLayout inputStreamLayout;
  261. inputStreamLayout.SetTopology(RHI::PrimitiveTopology::TriangleStrip);
  262. inputStreamLayout.Finalize();
  263. RHI::RenderAttachmentLayout attachmentsLayout;
  264. RHI::RenderAttachmentLayoutBuilder attachmentsLayoutBuilder;
  265. attachmentsLayoutBuilder.AddSubpass()
  266. ->RenderTargetAttachment(RHI::Format::R8G8B8A8_UNORM); // Set any format to avoid errors when building the layout.
  267. attachmentsLayoutBuilder.End(attachmentsLayout);
  268. for (uint32_t index = 0; index < static_cast<uint32_t>(ImageType::ImageTypeCount); index++)
  269. {
  270. ImageTypePreviewInfo& previewInfo = m_imageTypePreviewInfo[index];
  271. auto& pipelineDesc = previewInfo.m_pipelineStateDescriptor;
  272. shaderOption.SetValue(AZ::Name(optionName), AZ::Name(optionValues[index]));
  273. m_shader->GetVariant(shaderOption.GetShaderVariantId()).ConfigurePipelineState(pipelineDesc, shaderOption);
  274. pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout = attachmentsLayout;
  275. pipelineDesc.m_inputStreamLayout = inputStreamLayout;
  276. previewInfo.m_shaderVariantKeyFallback = shaderOption.GetShaderVariantKeyFallbackValue();
  277. }
  278. Data::AssetBus::Handler::BusDisconnect();
  279. Data::AssetBus::Handler::BusConnect(shaderAsset.GetId());
  280. }
  281. void ImageAttachmentPreviewPass::BuildInternal()
  282. {
  283. m_updateDrawData = true;
  284. }
  285. void ImageAttachmentPreviewPass::FrameBeginInternal(FramePrepareParams params)
  286. {
  287. bool scopeImported = false;
  288. if (!m_imageAttachmentId.IsEmpty() && m_outputColorAttachment)
  289. {
  290. // Only import the scope if the attachment is valid
  291. auto attachmentDatabase = params.m_frameGraphBuilder->GetAttachmentDatabase();
  292. bool isAttachmentValid = attachmentDatabase.IsAttachmentValid(m_imageAttachmentId);
  293. if (!isAttachmentValid)
  294. {
  295. // Import the cached copy dest image if it exists (copied)
  296. // So the attachment can be still previewed when the pass is disabled.
  297. if (m_attachmentCopy && m_attachmentCopy->m_destImage)
  298. {
  299. attachmentDatabase.ImportImage(m_attachmentCopy->m_destAttachmentId, m_attachmentCopy->m_destImage->GetRHIImage());
  300. isAttachmentValid = true;
  301. }
  302. }
  303. if (isAttachmentValid)
  304. {
  305. if (m_needsShaderLoad)
  306. {
  307. LoadShader();
  308. }
  309. params.m_frameGraphBuilder->ImportScopeProducer(*this);
  310. scopeImported = true;
  311. }
  312. }
  313. // If the scope is not imported, we need compile the updated pass srg here
  314. if (m_passSrgChanged && !scopeImported)
  315. {
  316. m_passSrg->Compile();
  317. m_passSrgChanged = false;
  318. }
  319. }
  320. bool ImageAttachmentPreviewPass::ReadbackOutput(AZStd::shared_ptr<AttachmentReadback> readback)
  321. {
  322. if (m_outputColorAttachment)
  323. {
  324. m_readbackOption = PassAttachmentReadbackOption::Output;
  325. m_attachmentReadback = readback;
  326. AZStd::string readbackName = AZStd::string::format("%s_%s", m_outputColorAttachment->GetAttachmentId().GetCStr(), GetName().GetCStr());
  327. return m_attachmentReadback->ReadPassAttachment(m_outputColorAttachment.get(), AZ::Name(readbackName));
  328. }
  329. return false;
  330. }
  331. void ImageAttachmentPreviewPass::SetColorTransformRange(float colorTransformRange[2])
  332. {
  333. m_attachmentColorTranformRange[0] = AZ::GetMin(colorTransformRange[0], colorTransformRange[1]);
  334. m_attachmentColorTranformRange[1] = AZ::GetMax(colorTransformRange[0], colorTransformRange[1]);
  335. m_updateDrawData = true;
  336. }
  337. void ImageAttachmentPreviewPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
  338. {
  339. // add attachments to the scope
  340. // input attachment
  341. RHI::FrameGraphAttachmentInterface attachmentDatabase = frameGraph.GetAttachmentDatabase();
  342. RHI::ImageDescriptor imageDesc = attachmentDatabase.GetImageDescriptor(m_imageAttachmentId);
  343. // only preview mip 0 and array 0
  344. RHI::ImageViewDescriptor imageViewDesc = RHI::ImageViewDescriptor::Create(
  345. RHI::Format::Unknown, // no overwrite
  346. 0, //mipSliceMin
  347. 0, //mipSliceMax
  348. 0, //arraySliceMin
  349. 0 //arraySliceMax
  350. );
  351. // If the format contains depth, set m_aspectFlags to depth, otherwise set it to color
  352. imageViewDesc.m_aspectFlags = RHI::CheckBitsAny(RHI::GetImageAspectFlags(imageDesc.m_format), RHI::ImageAspectFlags::Depth) ?
  353. RHI::ImageAspectFlags::Depth : RHI::ImageAspectFlags::Color;
  354. auto scopeAttachmentDesc = RHI::ImageScopeAttachmentDescriptor{ m_imageAttachmentId, imageViewDesc};
  355. frameGraph.UseAttachment(scopeAttachmentDesc, RHI::ScopeAttachmentAccess::Read, RHI::ScopeAttachmentUsage::Shader, RHI::ScopeAttachmentStage::FragmentShader);
  356. // output attachment
  357. frameGraph.UseColorAttachment(RHI::ImageScopeAttachmentDescriptor{ m_outputColorAttachment->GetAttachmentId() });
  358. frameGraph.SetEstimatedItemCount(aznumeric_cast<uint32_t>(m_imageTypePreviewInfo.size()));
  359. }
  360. void ImageAttachmentPreviewPass::CompileResources(const RHI::FrameGraphCompileContext& context)
  361. {
  362. // setup srg data and draw item
  363. if (m_updateDrawData)
  364. {
  365. m_updateDrawData = false;
  366. // clear some old data
  367. ClearDrawData();
  368. ImageType imageType = ImageType::Unsupported;
  369. float aspectRatio = 1;
  370. // Find image type
  371. const RHI::ImageView* inputImageView = context.GetImageView(m_imageAttachmentId);
  372. if (!inputImageView)
  373. {
  374. AZ_Warning("RPI", false, "Image attachment [%s] doesn't have image view in current context", m_imageAttachmentId.GetCStr());
  375. }
  376. else
  377. {
  378. const RHI::ImageDescriptor& desc = inputImageView->GetImage()->GetDescriptor();
  379. aspectRatio = desc.m_size.m_width / static_cast<float>(desc.m_size.m_height);
  380. if (desc.m_dimension == RHI::ImageDimension::Image2D)
  381. {
  382. if (desc.m_multisampleState.m_samples == 1)
  383. {
  384. imageType = ImageType::Image2d;
  385. }
  386. else if (desc.m_multisampleState.m_samples > 1)
  387. {
  388. imageType = ImageType::Image2dMs;
  389. }
  390. }
  391. if (imageType != ImageType::Unsupported)
  392. {
  393. const uint32_t typeIndex = static_cast<uint32_t>(imageType);
  394. auto& previewInfo = m_imageTypePreviewInfo[typeIndex];
  395. m_passSrg->SetShaderVariantKeyFallbackValue(previewInfo.m_shaderVariantKeyFallback);
  396. m_passSrg->SetImageView(previewInfo.m_imageInput, inputImageView, 0);
  397. m_passSrg->SetConstant(m_colorRangeMinMaxInput, m_attachmentColorTranformRange);
  398. m_passSrgChanged = true;
  399. previewInfo.m_imageCount = 1;
  400. }
  401. else
  402. {
  403. AZ_Warning("RPI", false, "Image attachment [%s] with format %d is not supported", m_imageAttachmentId.GetCStr(),
  404. static_cast<uint32_t>(desc.m_format));
  405. }
  406. }
  407. // config pipeline states related to output attachment
  408. const RHI::ImageView* outputImageView = context.GetImageView(m_outputColorAttachment->GetAttachmentId());
  409. RHI::Format outputFormat = outputImageView->GetDescriptor().m_overrideFormat;
  410. if (outputFormat == RHI::Format::Unknown)
  411. {
  412. outputFormat = outputImageView->GetImage()->GetDescriptor().m_format;
  413. }
  414. // Base viewport and scissor off of output attachment
  415. RHI::Size targetImageSize = outputImageView->GetImage()->GetDescriptor().m_size;
  416. float width = m_size.GetX() * targetImageSize.m_width;
  417. float height = m_size.GetY() * targetImageSize.m_height;
  418. if (m_keepAspectRatio)
  419. {
  420. if (width/height > aspectRatio)
  421. {
  422. width = height * aspectRatio;
  423. }
  424. else
  425. {
  426. height = width / aspectRatio;
  427. }
  428. }
  429. float xMin = m_position.GetX() * targetImageSize.m_width;
  430. float yMin = m_position.GetY() * targetImageSize.m_height;
  431. m_viewport = RHI::Viewport(xMin, xMin + width, yMin, yMin + height);
  432. m_scissor = RHI::Scissor(0, 0, targetImageSize.m_width, targetImageSize.m_height);
  433. // compile
  434. if (m_passSrgChanged)
  435. {
  436. m_passSrg->Compile();
  437. m_passSrgChanged = false;
  438. }
  439. // rebuild draw item
  440. for (auto& previewInfo : m_imageTypePreviewInfo)
  441. {
  442. if (previewInfo.m_imageCount == 0)
  443. {
  444. continue;
  445. }
  446. previewInfo.m_pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout.m_attachmentFormats[0] = outputFormat;
  447. previewInfo.m_pipelineStateDescriptor.m_renderStates.m_multisampleState = outputImageView->GetImage()->GetDescriptor().m_multisampleState;
  448. // draw each image by using instancing
  449. RHI::DrawLinear drawLinear;
  450. drawLinear.m_vertexCount = 4;
  451. drawLinear.m_instanceCount = previewInfo.m_imageCount;
  452. previewInfo.m_item.SetArguments(RHI::DrawArguments(drawLinear));
  453. previewInfo.m_item.SetPipelineState(m_shader->AcquirePipelineState(previewInfo.m_pipelineStateDescriptor));
  454. }
  455. }
  456. }
  457. void ImageAttachmentPreviewPass::BuildCommandList(const RHI::FrameGraphExecuteContext& context)
  458. {
  459. RHI::CommandList* commandList = context.GetCommandList();
  460. commandList->SetViewport(m_viewport);
  461. commandList->SetScissor(m_scissor);
  462. // submit srg
  463. commandList->SetShaderResourceGroupForDraw(*m_passSrg->GetRHIShaderResourceGroup()->GetDeviceShaderResourceGroup(context.GetDeviceIndex()));
  464. // submit draw call
  465. for (uint32_t index = context.GetSubmitRange().m_startIndex; index < context.GetSubmitRange().m_endIndex; ++index)
  466. {
  467. const ImageTypePreviewInfo& previewInfo = m_imageTypePreviewInfo[index];
  468. if (previewInfo.m_imageCount > 0)
  469. {
  470. commandList->Submit(previewInfo.m_item.GetDeviceDrawItem(context.GetDeviceIndex()), index);
  471. }
  472. }
  473. }
  474. }
  475. }