3
0

CopyPass.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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/DrawListTagRegistry.h>
  10. #include <Atom/RHI/FrameGraphBuilder.h>
  11. #include <Atom/RHI/RHISystemInterface.h>
  12. #include <Atom/RHI/ScopeProducerFunction.h>
  13. #include <Atom/RPI.Public/Pass/CopyPass.h>
  14. #include <Atom/RPI.Public/Pass/PassUtils.h>
  15. #include <Atom/RPI.Public/Pass/RenderPass.h>
  16. #include <Atom/RPI.Public/RPISystemInterface.h>
  17. #include <Atom/RPI.Public/RPIUtils.h>
  18. #include <Atom/RPI.Public/RenderPipeline.h>
  19. #include <Atom/RPI.Public/Scene.h>
  20. #include <Atom/RPI.Public/View.h>
  21. namespace AZ
  22. {
  23. namespace RPI
  24. {
  25. // --- Creation & Initialization ---
  26. CopyPass::~CopyPass()
  27. {
  28. ResetInternal();
  29. }
  30. Ptr<CopyPass> CopyPass::Create(const PassDescriptor& descriptor)
  31. {
  32. Ptr<CopyPass> pass = aznew CopyPass(descriptor);
  33. return pass;
  34. }
  35. CopyPass::CopyPass(const PassDescriptor& descriptor)
  36. : Pass(descriptor)
  37. {
  38. const CopyPassData* copyData = PassUtils::GetPassData<CopyPassData>(descriptor);
  39. if (copyData)
  40. {
  41. m_data = *copyData;
  42. if (copyData->m_useCopyQueue)
  43. {
  44. m_hardwareQueueClass = RHI::HardwareQueueClass::Copy;
  45. }
  46. }
  47. }
  48. RHI::CopyItemType CopyPass::GetCopyItemType()
  49. {
  50. RHI::AttachmentType inputType = GetInputBinding(0).GetAttachment()->GetAttachmentType();
  51. RHI::AttachmentType outputType = GetOutputBinding(0).GetAttachment()->GetAttachmentType();
  52. RHI::CopyItemType copyType = RHI::CopyItemType::Invalid;
  53. if (inputType == RHI::AttachmentType::Buffer && outputType == RHI::AttachmentType::Buffer)
  54. {
  55. copyType = RHI::CopyItemType::Buffer;
  56. }
  57. else if (inputType == RHI::AttachmentType::Image && outputType == RHI::AttachmentType::Image)
  58. {
  59. copyType = RHI::CopyItemType::Image;
  60. }
  61. else if (inputType == RHI::AttachmentType::Buffer && outputType == RHI::AttachmentType::Image)
  62. {
  63. copyType = RHI::CopyItemType::BufferToImage;
  64. }
  65. else if (inputType == RHI::AttachmentType::Image && outputType == RHI::AttachmentType::Buffer)
  66. {
  67. copyType = RHI::CopyItemType::ImageToBuffer;
  68. }
  69. return copyType;
  70. }
  71. // --- Pass behavior overrides ---
  72. void CopyPass::BuildInternal()
  73. {
  74. AZ_Assert(GetInputCount() == 1 && GetOutputCount() == 1,
  75. "CopyPass has %d inputs and %d outputs. It should have exactly one of each.",
  76. GetInputCount(), GetOutputCount());
  77. AZ_Assert(m_attachmentBindings.size() == 2,
  78. "CopyPass must have exactly 2 bindings: 1 input and 1 output. %s has %d bindings.",
  79. GetPathName().GetCStr(), m_attachmentBindings.size());
  80. bool sameDevice = (m_data.m_sourceDeviceIndex == -1 && m_data.m_destinationDeviceIndex == -1) ||
  81. m_data.m_sourceDeviceIndex == m_data.m_destinationDeviceIndex;
  82. AZ_Assert(
  83. sameDevice || (m_data.m_sourceDeviceIndex != -1 && m_data.m_destinationDeviceIndex != -1),
  84. "CopyPass: Either source and destination device indices must be invalid, or both must be valid");
  85. m_copyMode = sameDevice ? CopyMode::SameDevice : CopyMode::DifferentDevicesIntermediateHost;
  86. if (m_copyMode == CopyMode::SameDevice)
  87. {
  88. m_copyScopeProducerSameDevice = AZStd::make_shared<RHI::ScopeProducerFunctionNoData>(
  89. RHI::ScopeId{ GetPathName() },
  90. AZStd::bind(&CopyPass::SetupFrameGraphDependenciesSameDevice, this, AZStd::placeholders::_1),
  91. AZStd::bind(&CopyPass::CompileResourcesSameDevice, this, AZStd::placeholders::_1),
  92. AZStd::bind(&CopyPass::BuildCommandListInternalSameDevice, this, AZStd::placeholders::_1),
  93. m_hardwareQueueClass);
  94. }
  95. else if (m_copyMode == CopyMode::DifferentDevicesIntermediateHost)
  96. {
  97. [[maybe_unused]] auto* device1 =
  98. RHI::RHISystemInterface::Get()->GetDevice(m_data.m_sourceDeviceIndex != RHI::MultiDevice::InvalidDeviceIndex ? m_data.m_sourceDeviceIndex : RHI::MultiDevice::DefaultDeviceIndex);
  99. AZ_Assert(
  100. device1->GetFeatures().m_signalFenceFromCPU,
  101. "CopyPass: Device to device copy is only possible if all devices support signalling fences from the CPU");
  102. [[maybe_unused]] auto* device2 =
  103. RHI::RHISystemInterface::Get()->GetDevice(m_data.m_destinationDeviceIndex != RHI::MultiDevice::InvalidDeviceIndex ? m_data.m_destinationDeviceIndex : RHI::MultiDevice::DefaultDeviceIndex);
  104. AZ_Assert(
  105. device2->GetFeatures().m_signalFenceFromCPU,
  106. "CopyPass: Device to device copy is only possible if all devices support signalling fences from the CPU");
  107. // Initialize #MaxFrames fences that are signaled on device 1 and perform the copy between the host staging buffers from device 1 to device 2
  108. for (auto& fence : m_device1SignalFence)
  109. {
  110. fence = new RHI::Fence();
  111. AZ_Assert(fence != nullptr, "CopyPass failed to create a fence");
  112. [[maybe_unused]] RHI::ResultCode result = fence->Init(RHI::MultiDevice::AllDevices, RHI::FenceState::Signaled);
  113. AZ_Assert(result == RHI::ResultCode::Success, "CopyPass failed to init fence");
  114. }
  115. // Initialize #MaxFrames fences that can be waited for on device 2 before data is uploaded to device 2
  116. for (auto& fence : m_device2WaitFence)
  117. {
  118. fence = new RHI::Fence();
  119. AZ_Assert(fence != nullptr, "CopyPass failed to create a fence");
  120. [[maybe_unused]] auto result = fence->Init(RHI::MultiDevice::AllDevices, RHI::FenceState::Signaled);
  121. AZ_Assert(result == RHI::ResultCode::Success, "CopyPass failed to init fence");
  122. }
  123. m_copyScopeProducerDeviceToHost = AZStd::make_shared<RHI::ScopeProducerFunctionNoData>(
  124. RHI::ScopeId{ AZStd::string(GetPathName().GetStringView()) },
  125. AZStd::bind(&CopyPass::SetupFrameGraphDependenciesDeviceToHost, this, AZStd::placeholders::_1),
  126. AZStd::bind(&CopyPass::CompileResourcesDeviceToHost, this, AZStd::placeholders::_1),
  127. AZStd::bind(&CopyPass::BuildCommandListInternalDeviceToHost, this, AZStd::placeholders::_1),
  128. m_hardwareQueueClass,
  129. m_data.m_sourceDeviceIndex);
  130. m_copyScopeProducerHostToDevice = AZStd::make_shared<RHI::ScopeProducerFunctionNoData>(
  131. RHI::ScopeId{ AZStd::string(GetPathName().GetStringView()) + "_2" },
  132. AZStd::bind(&CopyPass::SetupFrameGraphDependenciesHostToDevice, this, AZStd::placeholders::_1),
  133. AZStd::bind(&CopyPass::CompileResourcesHostToDevice, this, AZStd::placeholders::_1),
  134. AZStd::bind(&CopyPass::BuildCommandListInternalHostToDevice, this, AZStd::placeholders::_1),
  135. m_hardwareQueueClass,
  136. m_data.m_destinationDeviceIndex);
  137. }
  138. // Create transient attachment based on input if required
  139. if (m_data.m_cloneInput)
  140. {
  141. const Ptr<PassAttachment>& source = GetInputBinding(0).GetAttachment();
  142. Ptr<PassAttachment> dest = source->Clone();
  143. // Set bind flags to CopyWrite. Other bind flags will be auto-inferred by pass system
  144. if (dest->m_descriptor.m_type == RHI::AttachmentType::Image)
  145. {
  146. dest->m_descriptor.m_image.m_bindFlags = RHI::ImageBindFlags::CopyWrite;
  147. }
  148. else if (dest->m_descriptor.m_type == RHI::AttachmentType::Buffer)
  149. {
  150. dest->m_descriptor.m_buffer.m_bindFlags = RHI::BufferBindFlags::CopyWrite;
  151. }
  152. // Set path name for the new attachment and add it to our attachment list
  153. dest->ComputePathName(GetPathName());
  154. m_ownedAttachments.push_back(dest);
  155. // Set the output binding to the new attachment
  156. GetOutputBinding(0).SetAttachment(dest);
  157. }
  158. }
  159. void CopyPass::FrameBeginInternal(Pass::FramePrepareParams params)
  160. {
  161. if (m_copyMode == CopyMode::SameDevice)
  162. {
  163. params.m_frameGraphBuilder->ImportScopeProducer(*m_copyScopeProducerSameDevice);
  164. }
  165. else if (m_copyMode == CopyMode::DifferentDevicesIntermediateHost)
  166. {
  167. params.m_frameGraphBuilder->ImportScopeProducer(*m_copyScopeProducerDeviceToHost);
  168. params.m_frameGraphBuilder->ImportScopeProducer(*m_copyScopeProducerHostToDevice);
  169. m_currentBufferIndex = (m_currentBufferIndex + 1) % MaxFrames;
  170. m_device1SignalFence[m_currentBufferIndex]->Reset();
  171. m_device2WaitFence[m_currentBufferIndex]->Reset();
  172. }
  173. }
  174. void CopyPass::ResetInternal()
  175. {
  176. Pass::ResetInternal();
  177. if (m_copyMode == CopyMode::DifferentDevicesIntermediateHost)
  178. {
  179. for (auto& fence : m_device1SignalFence)
  180. {
  181. fence
  182. ->GetDeviceFence(
  183. m_data.m_sourceDeviceIndex != RHI::MultiDevice::InvalidDeviceIndex ? m_data.m_sourceDeviceIndex
  184. : RHI::MultiDevice::DefaultDeviceIndex)
  185. ->WaitOnCpu();
  186. }
  187. for (auto& fence : m_device2WaitFence)
  188. {
  189. fence
  190. ->GetDeviceFence(
  191. m_data.m_destinationDeviceIndex != RHI::MultiDevice::InvalidDeviceIndex ? m_data.m_destinationDeviceIndex
  192. : RHI::MultiDevice::DefaultDeviceIndex)
  193. ->WaitOnCpu();
  194. }
  195. }
  196. }
  197. // --- Scope producer functions ---
  198. void CopyPass::SetupFrameGraphDependenciesSameDevice(RHI::FrameGraphInterface frameGraph)
  199. {
  200. DeclareAttachmentsToFrameGraph(frameGraph);
  201. }
  202. void CopyPass::CompileResourcesSameDevice(const RHI::FrameGraphCompileContext& context)
  203. {
  204. RHI::CopyItemType copyType = GetCopyItemType();
  205. switch (copyType)
  206. {
  207. case AZ::RHI::CopyItemType::Buffer:
  208. CopyBuffer(context);
  209. break;
  210. case AZ::RHI::CopyItemType::Image:
  211. CopyImage(context);
  212. break;
  213. case AZ::RHI::CopyItemType::BufferToImage:
  214. CopyBufferToImage(context);
  215. break;
  216. case AZ::RHI::CopyItemType::ImageToBuffer:
  217. CopyImageToBuffer(context);
  218. break;
  219. default:
  220. break;
  221. }
  222. }
  223. void CopyPass::BuildCommandListInternalSameDevice(const RHI::FrameGraphExecuteContext& context)
  224. {
  225. if (m_copyItemSameDevice.m_type != RHI::CopyItemType::Invalid)
  226. {
  227. context.GetCommandList()->Submit(m_copyItemSameDevice.GetDeviceCopyItem(context.GetDeviceIndex()));
  228. }
  229. }
  230. void CopyPass::SetupFrameGraphDependenciesDeviceToHost(RHI::FrameGraphInterface frameGraph)
  231. {
  232. // We need the size of the output image when copying from image to image, so we need all attachments (even the output ones)
  233. // We also need it so the framegraph knows the two scopes depend on each other
  234. DeclareAttachmentsToFrameGraph(frameGraph);
  235. frameGraph.SignalFence(*m_device1SignalFence[m_currentBufferIndex]);
  236. }
  237. void CopyPass::CompileResourcesDeviceToHost(const RHI::FrameGraphCompileContext& context)
  238. {
  239. RHI::CopyItemType copyType = GetCopyItemType();
  240. auto inputId = GetInputBinding(0).GetAttachment()->GetAttachmentId();
  241. switch (copyType)
  242. {
  243. case AZ::RHI::CopyItemType::Image:
  244. [[fallthrough]];
  245. case AZ::RHI::CopyItemType::ImageToBuffer:
  246. {
  247. // copy image to read back buffer since only buffer can be accessed by host
  248. const auto* sourceImage = context.GetImage(inputId);
  249. if (!sourceImage)
  250. {
  251. AZ_Warning("AttachmentReadback", false, "Failed to find attachment image %s for copy to buffer", inputId.GetCStr());
  252. return;
  253. }
  254. const auto& sourceImageDescriptor = sourceImage->GetDescriptor();
  255. const uint16_t sourceMipSlice = m_data.m_imageSourceSubresource.m_mipSlice;
  256. RHI::ImageSubresourceRange sourceRange(sourceMipSlice, sourceMipSlice, 0, 0);
  257. sourceRange.m_aspectFlags = RHI::ImageAspectFlags::Color;
  258. RHI::ImageAspect sourceImageAspect = RHI::ImageAspect::Color;
  259. RHI::ImageAspectFlags sourceImageAspectFlags = RHI::GetImageAspectFlags(sourceImageDescriptor.m_format);
  260. if (RHI::CheckBitsAll(sourceImageAspectFlags, RHI::ImageAspectFlags::Depth))
  261. {
  262. sourceImageAspect = RHI::ImageAspect::Depth;
  263. sourceRange.m_aspectFlags = RHI::ImageAspectFlags::Depth;
  264. }
  265. AZStd::vector<RHI::DeviceImageSubresourceLayout> sourceImageSubResourcesLayouts;
  266. sourceImageSubResourcesLayouts.resize_no_construct(sourceImageDescriptor.m_mipLevels);
  267. size_t sourceTotalSizeInBytes = 0;
  268. sourceImage->GetDeviceImage(m_data.m_sourceDeviceIndex)
  269. ->GetSubresourceLayouts(sourceRange, sourceImageSubResourcesLayouts.data(), &sourceTotalSizeInBytes);
  270. AZ::u64 sourceByteCount = sourceTotalSizeInBytes;
  271. if(m_deviceHostBufferByteCount[m_currentBufferIndex] != sourceByteCount)
  272. {
  273. m_deviceHostBufferByteCount[m_currentBufferIndex] = sourceByteCount;
  274. RPI::CommonBufferDescriptor desc;
  275. desc.m_poolType = RPI::CommonBufferPoolType::ReadBack;
  276. desc.m_bufferName = AZStd::string(GetPathName().GetStringView()) + "_hostbuffer";
  277. desc.m_byteCount = m_deviceHostBufferByteCount[m_currentBufferIndex];
  278. m_device1HostBuffer[m_currentBufferIndex] = BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  279. desc.m_bufferName = AZStd::string(GetPathName().GetStringView()) + "_hostbuffer2";
  280. desc.m_poolType = RPI::CommonBufferPoolType::Staging;
  281. m_device2HostBuffer[m_currentBufferIndex] = BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  282. }
  283. // copy descriptor for copying image to buffer
  284. RHI::CopyImageToBufferDescriptor copyImageToBufferDesc;
  285. copyImageToBufferDesc.m_sourceImage = sourceImage;
  286. copyImageToBufferDesc.m_sourceSize = sourceImageSubResourcesLayouts[sourceMipSlice].m_size;
  287. copyImageToBufferDesc.m_sourceSubresource = RHI::ImageSubresource(sourceMipSlice, 0 /*arraySlice*/, sourceImageAspect);
  288. copyImageToBufferDesc.m_destinationOffset = 0;
  289. if (copyType == RHI::CopyItemType::ImageToBuffer)
  290. {
  291. copyImageToBufferDesc.m_destinationBytesPerRow = sourceImageSubResourcesLayouts[sourceMipSlice].m_bytesPerRow;
  292. copyImageToBufferDesc.m_destinationBytesPerImage = sourceImageSubResourcesLayouts[sourceMipSlice].m_bytesPerImage;
  293. copyImageToBufferDesc.m_destinationBuffer = m_device1HostBuffer[m_currentBufferIndex]->GetRHIBuffer();
  294. copyImageToBufferDesc.m_destinationFormat = FindFormatForAspect(sourceImageDescriptor.m_format, sourceImageAspect);
  295. }
  296. else
  297. {
  298. auto outputId = GetOutputBinding(0).GetAttachment()->GetAttachmentId();
  299. const auto* destImage = context.GetImage(outputId);
  300. if (!destImage)
  301. {
  302. AZ_Warning(
  303. "AttachmentReadback", false, "Failed to find attachment image %s for copy to buffer", inputId.GetCStr());
  304. return;
  305. }
  306. const auto& destImageDescriptor = destImage->GetDescriptor();
  307. const uint16_t destMipSlice = m_data.m_imageSourceSubresource.m_mipSlice;
  308. RHI::ImageSubresourceRange destRange(destMipSlice, destMipSlice, 0, 0);
  309. destRange.m_aspectFlags = RHI::ImageAspectFlags::Color;
  310. destRange.m_aspectFlags = RHI::ImageAspectFlags::Color;
  311. RHI::ImageAspect destImageAspect = RHI::ImageAspect::Color;
  312. RHI::ImageAspectFlags destImageAspectFlags = RHI::GetImageAspectFlags(destImageDescriptor.m_format);
  313. if (RHI::CheckBitsAll(destImageAspectFlags, RHI::ImageAspectFlags::Depth))
  314. {
  315. destImageAspect = RHI::ImageAspect::Depth;
  316. destRange.m_aspectFlags = RHI::ImageAspectFlags::Depth;
  317. }
  318. AZStd::vector<RHI::DeviceImageSubresourceLayout> destImageSubResourcesLayouts;
  319. destImageSubResourcesLayouts.resize_no_construct(destImageDescriptor.m_mipLevels);
  320. size_t destTotalSizeInBytes = 0;
  321. destImage->GetDeviceImage(m_data.m_sourceDeviceIndex)
  322. ->GetSubresourceLayouts(destRange, destImageSubResourcesLayouts.data(), &destTotalSizeInBytes);
  323. copyImageToBufferDesc.m_destinationBytesPerRow = destImageSubResourcesLayouts[destMipSlice].m_bytesPerRow;
  324. copyImageToBufferDesc.m_destinationBytesPerImage = destImageSubResourcesLayouts[destMipSlice].m_bytesPerImage;
  325. copyImageToBufferDesc.m_destinationBuffer = m_device1HostBuffer[m_currentBufferIndex]->GetRHIBuffer();
  326. copyImageToBufferDesc.m_destinationFormat = FindFormatForAspect(destImageDescriptor.m_format, destImageAspect);
  327. }
  328. m_inputImageLayout = sourceImageSubResourcesLayouts[sourceMipSlice];
  329. m_copyItemDeviceToHost = copyImageToBufferDesc;
  330. }
  331. break;
  332. case AZ::RHI::CopyItemType::Buffer:
  333. [[fallthrough]];
  334. case AZ::RHI::CopyItemType::BufferToImage:
  335. {
  336. const auto* buffer = context.GetBuffer(inputId);
  337. if(m_deviceHostBufferByteCount[m_currentBufferIndex] != buffer->GetDescriptor().m_byteCount)
  338. {
  339. m_deviceHostBufferByteCount[m_currentBufferIndex] = buffer->GetDescriptor().m_byteCount;
  340. RPI::CommonBufferDescriptor desc;
  341. desc.m_poolType = RPI::CommonBufferPoolType::ReadBack;
  342. desc.m_bufferName = AZStd::string(GetPathName().GetStringView()) + "_hostbuffer";
  343. desc.m_byteCount = m_deviceHostBufferByteCount[m_currentBufferIndex];
  344. m_device1HostBuffer[m_currentBufferIndex] = BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  345. desc.m_bufferName = AZStd::string(GetPathName().GetStringView()) + "_hostbuffer2";
  346. m_device2HostBuffer[m_currentBufferIndex] = BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  347. }
  348. // copy buffer
  349. RHI::CopyBufferDescriptor copyBuffer;
  350. copyBuffer.m_sourceBuffer = buffer;
  351. copyBuffer.m_destinationBuffer = m_device1HostBuffer[m_currentBufferIndex]->GetRHIBuffer();
  352. copyBuffer.m_size = aznumeric_cast<uint32_t>(m_deviceHostBufferByteCount[m_currentBufferIndex]);
  353. m_copyItemDeviceToHost = copyBuffer;
  354. }
  355. break;
  356. default:
  357. break;
  358. }
  359. }
  360. void CopyPass::BuildCommandListInternalDeviceToHost(const RHI::FrameGraphExecuteContext& context)
  361. {
  362. if (m_copyItemDeviceToHost.m_type != RHI::CopyItemType::Invalid)
  363. {
  364. context.GetCommandList()->Submit(m_copyItemDeviceToHost.GetDeviceCopyItem(context.GetDeviceIndex()));
  365. }
  366. // Once signaled on device 1, we can map the host staging buffers on device 1 and 2 and copy data from 1 -> 2 and then signal the upload on device 2
  367. m_device1SignalFence[m_currentBufferIndex]
  368. ->GetDeviceFence(context.GetDeviceIndex())
  369. ->WaitOnCpuAsync(
  370. [this, bufferIndex = m_currentBufferIndex]()
  371. {
  372. auto bufferSize = m_device2HostBuffer[bufferIndex]->GetBufferSize();
  373. void* data1 = m_device1HostBuffer[bufferIndex]->Map(bufferSize, 0)[m_data.m_sourceDeviceIndex];
  374. void* data2 = m_device2HostBuffer[bufferIndex]->Map(bufferSize, 0)[m_data.m_destinationDeviceIndex];
  375. memcpy(data2, data1, bufferSize);
  376. m_device1HostBuffer[bufferIndex]->Unmap();
  377. m_device2HostBuffer[bufferIndex]->Unmap();
  378. m_device2WaitFence[bufferIndex]->GetDeviceFence(m_data.m_destinationDeviceIndex)->SignalOnCpu();
  379. });
  380. }
  381. void CopyPass::SetupFrameGraphDependenciesHostToDevice(RHI::FrameGraphInterface frameGraph)
  382. {
  383. DeclareAttachmentsToFrameGraph(frameGraph, PassSlotType::Output);
  384. frameGraph.ExecuteAfter(m_copyScopeProducerHostToDevice->GetScopeId());
  385. for (Pass* pass : m_executeBeforePasses)
  386. {
  387. RenderPass* renderPass = azrtti_cast<RenderPass*>(pass);
  388. if (renderPass)
  389. {
  390. frameGraph.ExecuteBefore(renderPass->GetScopeId());
  391. }
  392. }
  393. frameGraph.WaitFence(*m_device2WaitFence[m_currentBufferIndex]);
  394. }
  395. void CopyPass::CompileResourcesHostToDevice(const RHI::FrameGraphCompileContext& context)
  396. {
  397. m_copyItemHostToDevice = {};
  398. m_copyItemHostToDevice.m_type = RHI::CopyItemType::Invalid;
  399. PassAttachmentBinding& copyDest = GetOutputBinding(0);
  400. auto outputId = copyDest.GetAttachment()->GetAttachmentId();
  401. RHI::CopyItemType copyType = GetCopyItemType();
  402. switch (copyType)
  403. {
  404. case AZ::RHI::CopyItemType::Buffer:
  405. [[fallthrough]];
  406. case AZ::RHI::CopyItemType::ImageToBuffer:
  407. {
  408. const auto* buffer = context.GetBuffer(outputId);
  409. RHI::CopyBufferDescriptor copyBuffer;
  410. copyBuffer.m_sourceBuffer = m_device2HostBuffer[m_currentBufferIndex]->GetRHIBuffer();
  411. copyBuffer.m_destinationBuffer = buffer;
  412. copyBuffer.m_size = aznumeric_cast<uint32_t>(m_device2HostBuffer[m_currentBufferIndex]->GetBufferSize());
  413. m_copyItemHostToDevice = copyBuffer;
  414. }
  415. break;
  416. case AZ::RHI::CopyItemType::Image:
  417. [[fallthrough]];
  418. case AZ::RHI::CopyItemType::BufferToImage:
  419. {
  420. RHI::CopyBufferToImageDescriptor copyDesc;
  421. const auto* sourceBuffer = m_device2HostBuffer[m_currentBufferIndex]->GetRHIBuffer();
  422. copyDesc.m_sourceBuffer = sourceBuffer;
  423. copyDesc.m_sourceOffset = 0;
  424. if (copyType == RHI::CopyItemType::BufferToImage)
  425. {
  426. copyDesc.m_sourceBytesPerRow = m_data.m_bufferSourceBytesPerRow;
  427. copyDesc.m_sourceBytesPerImage = m_data.m_bufferSourceBytesPerImage;
  428. copyDesc.m_sourceSize = m_data.m_sourceSize;
  429. }
  430. else
  431. {
  432. copyDesc.m_sourceBytesPerRow = m_inputImageLayout.m_bytesPerRow;
  433. copyDesc.m_sourceBytesPerImage = m_inputImageLayout.m_bytesPerImage;
  434. copyDesc.m_sourceSize = m_inputImageLayout.m_size;
  435. }
  436. // Destination Image
  437. copyDesc.m_destinationImage = context.GetImage(copyDest.GetAttachment()->GetAttachmentId());
  438. copyDesc.m_destinationOrigin = m_data.m_imageDestinationOrigin;
  439. copyDesc.m_destinationSubresource = m_data.m_imageDestinationSubresource;
  440. m_copyItemHostToDevice = copyDesc;
  441. }
  442. break;
  443. default:
  444. break;
  445. }
  446. }
  447. void CopyPass::BuildCommandListInternalHostToDevice(const RHI::FrameGraphExecuteContext& context)
  448. {
  449. if (m_copyItemHostToDevice.m_type != RHI::CopyItemType::Invalid)
  450. {
  451. context.GetCommandList()->Submit(m_copyItemHostToDevice.GetDeviceCopyItem(context.GetDeviceIndex()));
  452. }
  453. }
  454. // --- Copy setup functions ---
  455. void CopyPass::CopyBuffer(const RHI::FrameGraphCompileContext& context)
  456. {
  457. RHI::CopyBufferDescriptor copyDesc;
  458. // Source Buffer
  459. PassAttachmentBinding& copySource = GetInputBinding(0);
  460. const auto* sourceBuffer = context.GetBuffer(copySource.GetAttachment()->GetAttachmentId());
  461. copyDesc.m_sourceBuffer = sourceBuffer;
  462. copyDesc.m_size = static_cast<uint32_t>(sourceBuffer->GetDescriptor().m_byteCount);
  463. copyDesc.m_sourceOffset = m_data.m_bufferSourceOffset;
  464. // Destination Buffer
  465. PassAttachmentBinding& copyDest = GetOutputBinding(0);
  466. copyDesc.m_destinationBuffer = context.GetBuffer(copyDest.GetAttachment()->GetAttachmentId());
  467. copyDesc.m_destinationBuffer = context.GetBuffer(copyDest.GetAttachment()->GetAttachmentId());
  468. copyDesc.m_destinationOffset = m_data.m_bufferDestinationOffset;
  469. m_copyItemSameDevice = copyDesc;
  470. }
  471. void CopyPass::CopyImage(const RHI::FrameGraphCompileContext& context)
  472. {
  473. RHI::CopyImageDescriptor copyDesc;
  474. // Source Image
  475. PassAttachmentBinding& copySource = GetInputBinding(0);
  476. const auto* sourceImage = context.GetImage(copySource.GetAttachment()->GetAttachmentId());
  477. copyDesc.m_sourceImage = sourceImage;
  478. copyDesc.m_sourceSize = sourceImage->GetDescriptor().m_size;
  479. copyDesc.m_sourceOrigin = m_data.m_imageSourceOrigin;
  480. copyDesc.m_sourceSubresource = m_data.m_imageSourceSubresource;
  481. // Destination Image
  482. PassAttachmentBinding& copyDest = GetOutputBinding(0);
  483. copyDesc.m_destinationImage = context.GetImage(copyDest.GetAttachment()->GetAttachmentId());
  484. copyDesc.m_destinationOrigin = m_data.m_imageDestinationOrigin;
  485. copyDesc.m_destinationSubresource = m_data.m_imageDestinationSubresource;
  486. m_copyItemSameDevice = copyDesc;
  487. }
  488. void CopyPass::CopyBufferToImage(const RHI::FrameGraphCompileContext& context)
  489. {
  490. RHI::CopyBufferToImageDescriptor copyDesc;
  491. // Source Buffer
  492. PassAttachmentBinding& copySource = GetInputBinding(0);
  493. const auto* sourceBuffer = context.GetBuffer(copySource.GetAttachment()->GetAttachmentId());
  494. copyDesc.m_sourceBuffer = sourceBuffer;
  495. copyDesc.m_sourceSize = m_data.m_sourceSize;
  496. copyDesc.m_sourceOffset = m_data.m_bufferSourceOffset;
  497. copyDesc.m_sourceBytesPerRow = m_data.m_bufferSourceBytesPerRow;
  498. copyDesc.m_sourceBytesPerImage = m_data.m_bufferSourceBytesPerImage;
  499. // Destination Image
  500. PassAttachmentBinding& copyDest = GetOutputBinding(0);
  501. copyDesc.m_destinationImage = context.GetImage(copyDest.GetAttachment()->GetAttachmentId());
  502. copyDesc.m_destinationOrigin = m_data.m_imageDestinationOrigin;
  503. copyDesc.m_destinationSubresource = m_data.m_imageDestinationSubresource;
  504. m_copyItemSameDevice = copyDesc;
  505. }
  506. void CopyPass::CopyImageToBuffer(const RHI::FrameGraphCompileContext& context)
  507. {
  508. RHI::CopyImageToBufferDescriptor copyDesc;
  509. // Source Image
  510. PassAttachmentBinding& copySource = GetInputBinding(0);
  511. const auto* sourceImage = context.GetImage(copySource.GetAttachment()->GetAttachmentId());
  512. copyDesc.m_sourceImage = sourceImage;
  513. copyDesc.m_sourceSize = sourceImage->GetDescriptor().m_size;
  514. copyDesc.m_sourceOrigin = m_data.m_imageSourceOrigin;
  515. copyDesc.m_sourceSubresource = m_data.m_imageSourceSubresource;
  516. // Destination Buffer
  517. PassAttachmentBinding& copyDest = GetOutputBinding(0);
  518. copyDesc.m_destinationBuffer = context.GetBuffer(copyDest.GetAttachment()->GetAttachmentId());
  519. copyDesc.m_destinationOffset = m_data.m_bufferDestinationOffset;
  520. copyDesc.m_destinationBytesPerRow = m_data.m_bufferDestinationBytesPerRow;
  521. copyDesc.m_destinationBytesPerImage = m_data.m_bufferDestinationBytesPerImage;
  522. m_copyItemSameDevice = copyDesc;
  523. }
  524. } // namespace RPI
  525. } // namespace AZ