AsyncComputeExampleComponent.cpp 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  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/Component/DebugCamera/ArcBallControllerComponent.h>
  9. #include <Atom/RHI/CommandList.h>
  10. #include <Atom/RHI/Factory.h>
  11. #include <Atom/RHI/FrameScheduler.h>
  12. #include <Atom/RHI/Image.h>
  13. #include <Atom/RHI/ImagePool.h>
  14. #include <Atom/RHI/ScopeProducerFunction.h>
  15. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  16. #include <AzCore/Math/MatrixUtils.h>
  17. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  18. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  19. #include <Atom/RPI.Public/Model/Model.h>
  20. #include <Atom/RPI.Public/View.h>
  21. #include <Atom/RPI.Public/ViewProviderBus.h>
  22. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  23. #include <Automation/ScriptRunnerBus.h>
  24. #include <AzCore/Asset/AssetCommon.h>
  25. #include <AzCore/Asset/AssetManagerBus.h>
  26. #include <AzCore/Math/Vector3.h>
  27. #include <AzCore/Math/Vector4.h>
  28. #include <AzCore/Serialization/SerializeContext.h>
  29. #include <RHI/AsyncComputeExampleComponent.h>
  30. #include <SampleComponentConfig.h>
  31. #include <SampleComponentManager.h>
  32. #include <Utils/Utils.h>
  33. namespace AtomSampleViewer
  34. {
  35. using namespace AZ;
  36. namespace AsyncCompute
  37. {
  38. static const char* sampleName = "AsyncComputeComponent";
  39. static constexpr uint32_t s_shadowMapSize = 1024;
  40. static constexpr uint32_t s_luminanceMapSize = 1024;
  41. }
  42. void AsyncComputeExampleComponent::Reflect(AZ::ReflectContext* context)
  43. {
  44. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  45. {
  46. serializeContext->Class<AsyncComputeExampleComponent, AZ::Component>()->Version(0);
  47. }
  48. }
  49. AsyncComputeExampleComponent::AsyncComputeExampleComponent()
  50. {
  51. m_supportRHISamplePipeline = true;
  52. }
  53. void AsyncComputeExampleComponent::FrameBeginInternal(RHI::FrameGraphBuilder& frameGraphBuilder)
  54. {
  55. if (!m_fullyActivated)
  56. {
  57. return;
  58. }
  59. RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  60. // Import non transient images
  61. for (uint32_t i = 0; i < m_sceneImages.size(); ++i)
  62. {
  63. frameGraphBuilder.GetAttachmentDatabase().ImportImage(m_sceneIds[i], m_sceneImages[i]);
  64. }
  65. // Generate transient images
  66. {
  67. const RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2D(
  68. RHI::ImageBindFlags::DepthStencil | RHI::ImageBindFlags::ShaderRead,
  69. AsyncCompute::s_shadowMapSize,
  70. AsyncCompute::s_shadowMapSize,
  71. RHI::Format::D32_FLOAT);
  72. frameGraphBuilder.GetAttachmentDatabase().CreateTransientImage(RHI::TransientImageDescriptor(m_shadowAttachmentId, imageDescriptor));
  73. }
  74. {
  75. RHI::Format depthStencilFormat = device->GetNearestSupportedFormat(RHI::Format::D24_UNORM_S8_UINT, AZ::RHI::FormatCapabilities::DepthStencil);
  76. const RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2D(
  77. RHI::ImageBindFlags::DepthStencil, m_outputWidth, m_outputHeight, depthStencilFormat);
  78. const RHI::TransientImageDescriptor transientImageDescriptor(m_forwardDepthStencilId, imageDescriptor);
  79. frameGraphBuilder.GetAttachmentDatabase().CreateTransientImage(transientImageDescriptor);
  80. }
  81. {
  82. const RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2D(
  83. RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderRead,
  84. AsyncCompute::s_luminanceMapSize,
  85. AsyncCompute::s_luminanceMapSize,
  86. RHI::Format::R32_FLOAT);
  87. frameGraphBuilder.GetAttachmentDatabase().CreateTransientImage(RHI::TransientImageDescriptor(m_luminanceMapAttachmentId, imageDescriptor));
  88. }
  89. // Swap scene image index
  90. AZStd::swap(m_currentSceneImageIndex, m_previousSceneImageIndex);
  91. }
  92. void AsyncComputeExampleComponent::OnTick([[maybe_unused]] float deltaTime, AZ::ScriptTimePoint time)
  93. {
  94. AZ_UNUSED(time);
  95. if (!m_fullyActivated)
  96. {
  97. return;
  98. }
  99. if (m_imguiSidebar.Begin())
  100. {
  101. ScriptableImGui::Checkbox("Enable/Disable Async Compute", &m_asyncComputeEnabled);
  102. m_imguiSidebar.End();
  103. }
  104. }
  105. void AsyncComputeExampleComponent::ResetCamera()
  106. {
  107. const float pitch = -AZ::Constants::QuarterPi / 2.0f;
  108. const float distance = 35.0f;
  109. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetCenter, AZ::Vector3(0.f));
  110. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetDistance, distance);
  111. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetMaxDistance, 50.0f);
  112. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetPitch, pitch);
  113. // Set the camera Transform so we don't have a jump on the first frame.
  114. AZ::Quaternion orientation = AZ::Quaternion::CreateRotationX(pitch);
  115. AZ::Vector3 position = orientation.TransformVector(AZ::Vector3(0, -distance, 0));
  116. AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position));
  117. }
  118. void AsyncComputeExampleComponent::CreateSceneRenderTargets()
  119. {
  120. const RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  121. m_imagePool = RHI::Factory::Get().CreateImagePool();
  122. RHI::ImagePoolDescriptor imagePoolDesc;
  123. imagePoolDesc.m_bindFlags = RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite;
  124. m_imagePool->Init(*device, imagePoolDesc);
  125. for (auto& image : m_sceneImages)
  126. {
  127. image = RHI::Factory::Get().CreateImage();
  128. RHI::ImageInitRequest initImageRequest;
  129. RHI::ClearValue clearValue = RHI::ClearValue::CreateVector4Float(0, 0, 0, 0);
  130. initImageRequest.m_image = image.get();
  131. initImageRequest.m_descriptor = RHI::ImageDescriptor::Create2D(
  132. RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite,
  133. m_outputWidth,
  134. m_outputHeight,
  135. RHI::Format::R16G16B16A16_FLOAT);
  136. initImageRequest.m_optimizedClearValue = &clearValue;
  137. m_imagePool->InitImage(initImageRequest);
  138. }
  139. }
  140. void AsyncComputeExampleComponent::CreateQuad()
  141. {
  142. const RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  143. m_quadBufferPool = RHI::Factory::Get().CreateBufferPool();
  144. RHI::BufferPoolDescriptor bufferPoolDesc;
  145. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  146. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  147. m_quadBufferPool->Init(*device, bufferPoolDesc);
  148. struct BufferData
  149. {
  150. AZStd::array<VertexPosition, 4> m_positions;
  151. AZStd::array<VertexUV, 4> m_uvs;
  152. AZStd::array<VertexNormal, 4> m_normals;
  153. AZStd::array<uint16_t, 6> m_indices;
  154. };
  155. BufferData bufferData;
  156. SetFullScreenRect(bufferData.m_positions.data(), bufferData.m_uvs.data(), bufferData.m_indices.data());
  157. bufferData.m_normals.fill({ { 0, 0, 1.0f } });
  158. for (auto& uv : bufferData.m_uvs)
  159. {
  160. uv.m_uv[1] = 1.0f - uv.m_uv[1];
  161. }
  162. m_quadInputAssemblyBuffer = RHI::Factory::Get().CreateBuffer();
  163. RHI::ResultCode result = RHI::ResultCode::Success;
  164. RHI::BufferInitRequest request;
  165. request.m_buffer = m_quadInputAssemblyBuffer.get();
  166. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, sizeof(bufferData) };
  167. request.m_initialData = &bufferData;
  168. result = m_quadBufferPool->InitBuffer(request);
  169. if (result != RHI::ResultCode::Success)
  170. {
  171. AZ_Error("AsyncComputeComponent", false, "Failed to initialize buffer with error code %d", result);
  172. return;
  173. }
  174. AZ::RHI::StreamBufferView positionsBufferView =
  175. {
  176. *m_quadInputAssemblyBuffer,
  177. offsetof(BufferData, m_positions),
  178. sizeof(BufferData::m_positions),
  179. sizeof(VertexPosition)
  180. };
  181. AZ::RHI::StreamBufferView normalsBufferView =
  182. {
  183. *m_quadInputAssemblyBuffer,
  184. offsetof(BufferData, m_normals),
  185. sizeof(BufferData::m_normals),
  186. sizeof(VertexNormal)
  187. };
  188. AZ::RHI::StreamBufferView uvsBufferView =
  189. {
  190. *m_quadInputAssemblyBuffer,
  191. offsetof(BufferData, m_uvs),
  192. sizeof(BufferData::m_uvs),
  193. sizeof(VertexUV)
  194. };
  195. m_quadStreamBufferViews[ShadowScope].push_back(positionsBufferView);
  196. m_quadStreamBufferViews[ForwardScope].push_back(positionsBufferView);
  197. m_quadStreamBufferViews[ForwardScope].push_back(normalsBufferView);
  198. m_quadStreamBufferViews[CopyTextureScope].push_back(positionsBufferView);
  199. m_quadStreamBufferViews[CopyTextureScope].push_back(uvsBufferView);
  200. m_quadStreamBufferViews[LuminanceMapScope] = m_quadStreamBufferViews[CopyTextureScope];
  201. m_quadIndexBufferView =
  202. {
  203. *m_quadInputAssemblyBuffer,
  204. offsetof(BufferData, m_indices),
  205. sizeof(BufferData::m_indices),
  206. RHI::IndexFormat::Uint16
  207. };
  208. }
  209. void AsyncComputeExampleComponent::LoadShaders()
  210. {
  211. AZStd::vector<const char*> shaders = {
  212. "Shaders/RHI/CopyQueue.azshader", // Vertex + Fragment
  213. "Shaders/RHI/MultipleViewsDepth.azshader", // Vertex
  214. "Shaders/RHI/AsyncComputeShadow.azshader", // Vertex + Fragment
  215. "Shaders/RHI/AsyncComputeLuminanceMap.azshader", // Vertex + Fragment
  216. "Shaders/RHI/AsyncComputeLuminanceReduce.azshader", // Compute
  217. "Shaders/RHI/AsyncComputeTonemapping.azshader"}; // Compute
  218. for (size_t i = 0; i < shaders.size(); ++i)
  219. {
  220. auto shader = LoadShader(*m_assetLoadManager.get(), shaders[i], AsyncCompute::sampleName);
  221. if (shader == nullptr)
  222. return;
  223. m_shaders[i] = shader;
  224. if (shader->GetPipelineStateType() == AZ::RHI::PipelineStateType::Dispatch)
  225. {
  226. const auto& numThreads = shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name("numthreads"));
  227. if (numThreads)
  228. {
  229. const RHI::ShaderStageAttributeArguments& args = *numThreads;
  230. m_numThreads[i].m_X = args[0].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[0]) : m_numThreads[i].m_X;
  231. m_numThreads[i].m_Y = args[1].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[1]) : m_numThreads[i].m_Y;
  232. m_numThreads[i].m_Z = args[2].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[2]) : m_numThreads[i].m_Z;
  233. }
  234. else
  235. {
  236. AZ_Error(AsyncCompute::sampleName, false, "Did not find expected numthreads attribute");
  237. }
  238. }
  239. }
  240. }
  241. void AsyncComputeExampleComponent::LoadModel()
  242. {
  243. // Load the asset
  244. auto modelAsset = m_assetLoadManager->GetAsset<AZ::RPI::ModelAsset>("objects/shaderball_simple.azmodel");
  245. AZ_Assert(modelAsset.IsReady(), "The model asset is supposed to be ready.");
  246. m_model = AZ::RPI::Model::FindOrCreate(modelAsset);
  247. AZ_Error(AsyncCompute::sampleName, m_model, "Failed to load model");
  248. }
  249. void AsyncComputeExampleComponent::CreatePipelines()
  250. {
  251. RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  252. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  253. {
  254. // Shadow Scope Pipelines
  255. const auto& shader = m_shaders[ShadowScope];
  256. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  257. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  258. variant.ConfigurePipelineState(pipelineDesc);
  259. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_enable = 1;
  260. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_func = RHI::ComparisonFunc::LessEqual;
  261. attachmentsBuilder.AddSubpass()
  262. ->DepthStencilAttachment(RHI::Format::D32_FLOAT);
  263. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  264. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  265. {
  266. // Terrain Pipeline
  267. RHI::InputStreamLayoutBuilder layoutBuilder;
  268. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  269. pipelineDesc.m_inputStreamLayout = layoutBuilder.End();
  270. if (!RHI::ValidateStreamBufferViews(
  271. pipelineDesc.m_inputStreamLayout,
  272. m_quadStreamBufferViews[ShadowScope]))
  273. {
  274. AZ_Error(AsyncCompute::sampleName, false, "Invalid stream buffer views for terrain");
  275. return;
  276. }
  277. m_terrainPipelineStates[ShadowScope] = shader->AcquirePipelineState(pipelineDesc);
  278. if (!m_terrainPipelineStates[ShadowScope])
  279. {
  280. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for shadow shader");
  281. return;
  282. }
  283. }
  284. {
  285. // Model Pipeline
  286. Data::Instance<AZ::RPI::ModelLod> modelLod = m_model->GetLods()[0];
  287. modelLod->GetStreamsForMesh(
  288. pipelineDesc.m_inputStreamLayout,
  289. m_modelStreamBufferViews[ShadowScope],
  290. nullptr,
  291. shader->GetInputContract(),
  292. 0);
  293. m_modelPipelineStates[ShadowScope] = shader->AcquirePipelineState(pipelineDesc);
  294. if (!m_modelPipelineStates[ShadowScope])
  295. {
  296. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for shader");
  297. return;
  298. }
  299. }
  300. }
  301. {
  302. // Forward Scope Pipelines
  303. const auto& shader = m_shaders[ForwardScope];
  304. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  305. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  306. variant.ConfigurePipelineState(pipelineDesc);
  307. pipelineDesc.m_renderStates.m_depthStencilState = RHI::DepthStencilState::CreateReverseDepth();
  308. attachmentsBuilder.Reset();
  309. RHI::Format depthStencilFormat = device->GetNearestSupportedFormat(RHI::Format::D24_UNORM_S8_UINT, AZ::RHI::FormatCapabilities::DepthStencil);
  310. attachmentsBuilder.AddSubpass()
  311. ->RenderTargetAttachment(RHI::Format::R16G16B16A16_FLOAT)
  312. ->DepthStencilAttachment(depthStencilFormat);
  313. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  314. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  315. {
  316. // Terrain Pipeline
  317. RHI::InputStreamLayoutBuilder layoutBuilder;
  318. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  319. layoutBuilder.AddBuffer()->Channel("NORMAL", RHI::Format::R32G32B32_FLOAT);
  320. pipelineDesc.m_inputStreamLayout = layoutBuilder.End();
  321. if (!RHI::ValidateStreamBufferViews(
  322. pipelineDesc.m_inputStreamLayout,
  323. m_quadStreamBufferViews[ForwardScope]))
  324. {
  325. AZ_Error(AsyncCompute::sampleName, false, "Invalid stream buffer views for terrain");
  326. return;
  327. }
  328. m_terrainPipelineStates[ForwardScope] = shader->AcquirePipelineState(pipelineDesc);
  329. if (!m_terrainPipelineStates[ForwardScope])
  330. {
  331. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for shadow shader");
  332. return;
  333. }
  334. }
  335. {
  336. // Model Pipeline
  337. Data::Instance<AZ::RPI::ModelLod> modelLod = m_model->GetLods()[0];
  338. modelLod->GetStreamsForMesh(
  339. pipelineDesc.m_inputStreamLayout,
  340. m_modelStreamBufferViews[ForwardScope],
  341. nullptr,
  342. shader->GetInputContract(),
  343. 0);
  344. m_modelPipelineStates[ForwardScope] = shader->AcquirePipelineState(pipelineDesc);
  345. if (!m_modelPipelineStates[ForwardScope])
  346. {
  347. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for shader");
  348. return;
  349. }
  350. }
  351. }
  352. {
  353. // Copy texture Pipeline
  354. const auto& shader = m_shaders[CopyTextureScope];
  355. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  356. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  357. variant.ConfigurePipelineState(pipelineDesc);
  358. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_enable = 0;
  359. attachmentsBuilder.Reset();
  360. attachmentsBuilder.AddSubpass()
  361. ->RenderTargetAttachment(m_outputFormat);
  362. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  363. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  364. RHI::TargetBlendState& blendstate = pipelineDesc.m_renderStates.m_blendState.m_targets[0];
  365. blendstate.m_enable = true;
  366. blendstate.m_blendDest = RHI::BlendFactor::AlphaSourceInverse;
  367. blendstate.m_blendSource = RHI::BlendFactor::AlphaSource;
  368. blendstate.m_blendOp = RHI::BlendOp::Add;
  369. RHI::InputStreamLayoutBuilder layoutBuilder;
  370. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  371. layoutBuilder.AddBuffer()->Channel("UV", RHI::Format::R32G32_FLOAT);
  372. pipelineDesc.m_inputStreamLayout = layoutBuilder.End();
  373. if (!RHI::ValidateStreamBufferViews(
  374. pipelineDesc.m_inputStreamLayout,
  375. m_quadStreamBufferViews[CopyTextureScope]))
  376. {
  377. AZ_Error(AsyncCompute::sampleName, false, "Invalid stream buffer views for LuminanceMap");
  378. return;
  379. }
  380. m_copyTexturePipelineState = shader->AcquirePipelineState(pipelineDesc);
  381. if (!m_copyTexturePipelineState)
  382. {
  383. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for copy texture");
  384. return;
  385. }
  386. }
  387. {
  388. // LuminanceMap pipeline
  389. const auto& shader = m_shaders[LuminanceMapScope];
  390. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  391. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  392. variant.ConfigurePipelineState(pipelineDesc);
  393. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_enable = 0;
  394. attachmentsBuilder.Reset();
  395. attachmentsBuilder.AddSubpass()
  396. ->RenderTargetAttachment(RHI::Format::R32_FLOAT);
  397. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  398. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  399. RHI::InputStreamLayoutBuilder layoutBuilder;
  400. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  401. layoutBuilder.AddBuffer()->Channel("UV", RHI::Format::R32G32_FLOAT);
  402. pipelineDesc.m_inputStreamLayout = layoutBuilder.End();
  403. if (!RHI::ValidateStreamBufferViews(
  404. pipelineDesc.m_inputStreamLayout,
  405. m_quadStreamBufferViews[LuminanceMapScope]))
  406. {
  407. AZ_Error(AsyncCompute::sampleName, false, "Invalid stream buffer views for LuminanceMap");
  408. return;
  409. }
  410. m_luminancePipelineState = shader->AcquirePipelineState(pipelineDesc);
  411. if (!m_luminancePipelineState)
  412. {
  413. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for luminance map");
  414. return;
  415. }
  416. }
  417. {
  418. // Luminance reduce pipelines
  419. const auto& shader = m_shaders[LuminanceReduceScope];
  420. RHI::PipelineStateDescriptorForDispatch pipelineDesc;
  421. shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId).ConfigurePipelineState(pipelineDesc);
  422. m_luminanceReducePipelineState = shader->AcquirePipelineState(pipelineDesc);
  423. if (!m_luminanceReducePipelineState)
  424. {
  425. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for luminance reduce");
  426. return;
  427. }
  428. }
  429. {
  430. // Tonemapping pipeline
  431. const auto& shader = m_shaders[TonemappingScope];
  432. RHI::PipelineStateDescriptorForDispatch pipelineDesc;
  433. shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId).ConfigurePipelineState(pipelineDesc);
  434. m_tonemappingPipelineState = shader->AcquirePipelineState(pipelineDesc);
  435. if (!m_tonemappingPipelineState)
  436. {
  437. AZ_Error(AsyncCompute::sampleName, false, "Failed to acquire default pipeline state for tonemapping");
  438. return;
  439. }
  440. }
  441. }
  442. void AsyncComputeExampleComponent::Activate()
  443. {
  444. m_assetLoadManager = AZStd::make_unique<AZ::AssetCollectionAsyncLoader>();
  445. m_forwardDepthStencilId = AZ::Name("ForwardDepthStencilId");
  446. m_shadowAttachmentId = AZ::Name("ShadowAttachmentId");
  447. m_luminanceMapAttachmentId = AZ::Name("LuminanceMapAttachmentId");
  448. m_averageLuminanceAttachmentId = AZ::Name("LuminanceReduce1");
  449. // List of all assets this example needs.
  450. AZStd::vector<AssetCollectionAsyncLoader::AssetToLoadInfo> assetList = {
  451. {"Shaders/RHI/CopyQueue.azshader", azrtti_typeid<RPI::ShaderAsset>()}, // Vertex + Fragment
  452. {"Shaders/RHI/MultipleViewsDepth.azshader", azrtti_typeid<RPI::ShaderAsset>()}, // Vertex
  453. {"Shaders/RHI/AsyncComputeShadow.azshader", azrtti_typeid<RPI::ShaderAsset>()}, // Vertex + Fragment
  454. {"Shaders/RHI/AsyncComputeLuminanceMap.azshader", azrtti_typeid<RPI::ShaderAsset>()}, // Vertex + Fragment
  455. {"Shaders/RHI/AsyncComputeLuminanceReduce.azshader", azrtti_typeid<RPI::ShaderAsset>()}, // Compute
  456. {"Shaders/RHI/AsyncComputeTonemapping.azshader", azrtti_typeid<RPI::ShaderAsset>()}, // Compute
  457. {"objects/shaderball_simple.azmodel", azrtti_typeid<AZ::RPI::ModelAsset>()}, // The model
  458. };
  459. // Configure the imgui progress list widget.
  460. auto onUserCancelledAction = [&]()
  461. {
  462. AZ_TracePrintf(AsyncCompute::sampleName, "Cancelled by user.\n");
  463. m_assetLoadManager->Cancel();
  464. SampleComponentManagerRequestBus::Broadcast(&SampleComponentManagerRequests::Reset);
  465. };
  466. m_imguiProgressList.OpenPopup("Waiting For Assets...", "Assets pending for processing:", {}, onUserCancelledAction, true /*automaticallyCloseOnAction*/, "Cancel");
  467. AZStd::for_each(assetList.begin(), assetList.end(),
  468. [&](const AssetCollectionAsyncLoader::AssetToLoadInfo& item) { m_imguiProgressList.AddItem(item.m_assetPath); });
  469. // Kickoff asynchronous asset loading, the activation will continue once all assets are available.
  470. m_assetLoadManager->LoadAssetsAsync(assetList, [&](AZStd::string_view assetName, [[maybe_unused]] bool success, size_t pendingAssetCount)
  471. {
  472. AZ_Error(AsyncCompute::sampleName, success, "Error loading asset %s, a crash will occur when OnAllAssetsReadyActivate() is called!", assetName.data());
  473. AZ_TracePrintf(AsyncCompute::sampleName, "Asset %s loaded %s. Wait for %zu more assets before full activation\n", assetName.data(), success ? "successfully" : "UNSUCCESSFULLY", pendingAssetCount);
  474. m_imguiProgressList.RemoveItem(assetName);
  475. if (!pendingAssetCount)
  476. {
  477. OnAllAssetsReadyActivate();
  478. }
  479. });
  480. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, 120.0f);
  481. }
  482. void AsyncComputeExampleComponent::OnAllAssetsReadyActivate()
  483. {
  484. AZ_Assert(!m_fullyActivated, "Full Activation should occur only once");
  485. CreateSceneRenderTargets();
  486. CreateQuad();
  487. LoadModel();
  488. LoadShaders();
  489. CreatePipelines();
  490. SetupScene();
  491. SetArcBallControllerParams();
  492. CreateLuminanceMapScope();
  493. CreateShadowScope();
  494. CreateLuminanceReduceScopes();
  495. CreateTonemappingScope();
  496. CreateForwardScope();
  497. CreateCopyTextureScope();
  498. m_imguiSidebar.Activate();
  499. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  500. ExampleComponentRequestBus::Handler::BusConnect(GetEntityId());
  501. AZ::TickBus::Handler::BusConnect();
  502. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
  503. m_fullyActivated = true;
  504. }
  505. void AsyncComputeExampleComponent::Deactivate()
  506. {
  507. m_assetLoadManager->Cancel();
  508. m_fullyActivated = false;
  509. m_quadBufferPool = nullptr;
  510. m_quadInputAssemblyBuffer = nullptr;
  511. m_quadStreamBufferViews.fill(AZStd::vector<AZ::RHI::StreamBufferView>());
  512. m_terrainPipelineStates.fill(nullptr);
  513. m_modelStreamBufferViews.fill(AZ::RPI::ModelLod::StreamBufferViewList());
  514. m_modelPipelineStates.fill(nullptr);
  515. m_model = nullptr;
  516. m_copyTexturePipelineState = nullptr;
  517. m_luminancePipelineState = nullptr;
  518. m_luminanceReducePipelineState = nullptr;
  519. m_tonemappingPipelineState = nullptr;
  520. m_shaderResourceGroups.fill(AZStd::vector<AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>>());
  521. m_viewShaderResourceGroup = nullptr;
  522. m_shaders.fill(nullptr);
  523. m_imagePool = nullptr;
  524. m_sceneImages.fill(nullptr);
  525. m_scopeProducers.clear();
  526. m_windowContext = nullptr;
  527. m_imguiSidebar.Deactivate();
  528. ExampleComponentRequestBus::Handler::BusDisconnect();
  529. AZ::TickBus::Handler::BusDisconnect();
  530. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  531. }
  532. void AsyncComputeExampleComponent::SetupScene()
  533. {
  534. // Shader inputs
  535. const Name shaderInputImageWorldMatrix{ "m_worldMatrix" };
  536. const Name shaderInputImageViewProjectionMatrix{ "m_viewProjectionMatrix" };
  537. const Name shaderInputImageLightViewProjectionMatrix{ "m_lightViewProjectionMatrix" };
  538. const Name shaderInputImageLightPosition{ "m_lightPosition" };
  539. const Name shaderInputImageAmbientColor{ "m_ambientColor" };
  540. const Name shaderInputImageDiffuseColor{ "m_diffuseColor" };
  541. const Name shaderInputImageDepthMapTexture{ "m_depthMapTexture" };
  542. const Name textureInputImageTexture{ "m_texture" };
  543. const Name luminanceReduceInputImageTexture{ "m_inputTexture" };
  544. const Name luminanceReduceOutputImageTexture{ "m_outputTexture" };
  545. const Name tonemappingImageTexture{ "m_inOutTexture" };
  546. const Name tonemappingLuminanceImageTexture{ "m_luminanceTexture" };
  547. // These are the model matrices. They contain the rotation, translation and scale of the objects that we are going to draw.
  548. AZStd::vector<AZ::Matrix4x4> objectMatrices =
  549. {
  550. AZ::Matrix4x4::CreateScale(AZ::Vector3(12.0f)),
  551. AZ::Matrix4x4::CreateRotationZ(AZ::Constants::Pi),
  552. AZ::Matrix4x4::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateRotationZ(AZ::Constants::QuarterPi * 3.0f), AZ::Vector3(5.0f, 8.0f, 0.0f)),
  553. AZ::Matrix4x4::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateRotationZ(-AZ::Constants::QuarterPi * 3.0f), AZ::Vector3(-6.0f, 6.0f, 0.0f)) * AZ::Matrix4x4::CreateScale(AZ::Vector3(1.5f)),
  554. AZ::Matrix4x4::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateRotationZ(-AZ::Constants::QuarterPi * 3.0f), AZ::Vector3(-7.0f, -4.0f, 0.0f)) * AZ::Matrix4x4::CreateScale(AZ::Vector3(0.6f)),
  555. AZ::Matrix4x4::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateRotationZ(AZ::Constants::QuarterPi * 2.0), AZ::Vector3(4.0f, -4.0f, 0.0f)) * AZ::Matrix4x4::CreateScale(AZ::Vector3(1.3f))
  556. };
  557. const float zNear = 1.0f, zFar = 100.0f;
  558. const AZ::Vector3 up = AZ::Vector3(0.0f, 0.0f, 1.0f);
  559. const AZ::Vector3 lookAt = AZ::Vector3(0.0f, 0.0f, 0.0f);
  560. auto ambientColor = AZ::Vector4(0.15f, 0.15f, 0.15f, 1.0f);
  561. auto diffuseColor = AZ::Vector4(1.0f, 1.0f, 1.0f, 1.0f);
  562. // Camera
  563. float fieldOfView = AZ::Constants::Pi / 4.0f;
  564. float screenAspect = GetViewportWidth() / GetViewportHeight();
  565. MakePerspectiveFovMatrixRH(m_projectionMatrix, fieldOfView, screenAspect, zNear, zFar);
  566. // Light
  567. float fovY = AZ::Constants::Pi / 2.0f;
  568. float aspectRatio = 1.0f;
  569. auto lightPosition = AZ::Vector3(-5.0f, -12.0f, 8.0f);
  570. AZ::Matrix4x4 lightProjectMatrix;
  571. MakePerspectiveFovMatrixRH(lightProjectMatrix, fovY, aspectRatio, zNear, zFar);
  572. AZ::Matrix4x4 worldToLight = lightProjectMatrix * CreateViewMatrix(lightPosition, up, lookAt);
  573. // Shadow generation SRGs
  574. m_shaderResourceGroups[ShadowScope].reserve(objectMatrices.size());
  575. for (const AZ::Matrix4x4& objectMatrix : objectMatrices)
  576. {
  577. auto shaderResourceGroup = CreateShaderResourceGroup(m_shaders[ShadowScope], "DepthViewSrg", AsyncCompute::sampleName);
  578. RHI::ShaderInputConstantIndex viewProjectionMatrixInput;
  579. RHI::ShaderInputConstantIndex modelMatrixInput;
  580. FindShaderInputIndex(&viewProjectionMatrixInput, shaderResourceGroup, shaderInputImageViewProjectionMatrix, AsyncCompute::sampleName);
  581. FindShaderInputIndex(&modelMatrixInput, shaderResourceGroup, shaderInputImageWorldMatrix, AsyncCompute::sampleName);
  582. shaderResourceGroup->SetConstant(viewProjectionMatrixInput, worldToLight);
  583. shaderResourceGroup->SetConstant(modelMatrixInput, objectMatrix);
  584. shaderResourceGroup->Compile();
  585. m_shaderResourceGroups[ShadowScope].push_back(shaderResourceGroup);
  586. }
  587. // Forward scope SRGs
  588. m_shaderResourceGroups[ForwardScope].reserve(objectMatrices.size());
  589. for (const AZ::Matrix4x4& objectMatrix : objectMatrices)
  590. {
  591. auto shaderResourceGroup = CreateShaderResourceGroup(m_shaders[ForwardScope], "ShadowSrg", AsyncCompute::sampleName);
  592. AZStd::array<RHI::ShaderInputConstantIndex, 5> shaderInputIndices;
  593. FindShaderInputIndex(&shaderInputIndices[0], shaderResourceGroup, shaderInputImageWorldMatrix, AsyncCompute::sampleName);
  594. FindShaderInputIndex(&shaderInputIndices[1], shaderResourceGroup, shaderInputImageLightViewProjectionMatrix, AsyncCompute::sampleName);
  595. FindShaderInputIndex(&shaderInputIndices[2], shaderResourceGroup, shaderInputImageLightPosition, AsyncCompute::sampleName);
  596. FindShaderInputIndex(&shaderInputIndices[3], shaderResourceGroup, shaderInputImageAmbientColor, AsyncCompute::sampleName);
  597. FindShaderInputIndex(&shaderInputIndices[4], shaderResourceGroup, shaderInputImageDiffuseColor, AsyncCompute::sampleName);
  598. FindShaderInputIndex(&m_shaderInputImageIndex, shaderResourceGroup, shaderInputImageDepthMapTexture, AsyncCompute::sampleName);
  599. shaderResourceGroup->SetConstant(shaderInputIndices[0], objectMatrix);
  600. shaderResourceGroup->SetConstant(shaderInputIndices[1], worldToLight);
  601. shaderResourceGroup->SetConstant(shaderInputIndices[2], AZ::Vector4::CreateFromVector3AndFloat(lightPosition, 1.0f));
  602. shaderResourceGroup->SetConstant(shaderInputIndices[3], ambientColor);
  603. shaderResourceGroup->SetConstant(shaderInputIndices[4], diffuseColor);
  604. m_shaderResourceGroups[ForwardScope].push_back(shaderResourceGroup);
  605. // Do not compile now since this SRG is updated every frame with the image input.
  606. }
  607. {
  608. // Copy texture SRG
  609. auto shaderResourceGroup = CreateShaderResourceGroup(m_shaders[CopyTextureScope], "CopyQueueSrg", AsyncCompute::sampleName);
  610. FindShaderInputIndex(&m_copyTextureShaderInputImageIndex, shaderResourceGroup, textureInputImageTexture, AsyncCompute::sampleName);
  611. m_shaderResourceGroups[CopyTextureScope].push_back(shaderResourceGroup);
  612. }
  613. {
  614. // Luminance map SRG
  615. auto shaderResourceGroup = CreateShaderResourceGroup(m_shaders[LuminanceMapScope], "TextureInstanceSrg", AsyncCompute::sampleName);
  616. FindShaderInputIndex(&m_luminanceShaderInputImageIndex, shaderResourceGroup, textureInputImageTexture, AsyncCompute::sampleName);
  617. m_shaderResourceGroups[LuminanceMapScope].push_back(shaderResourceGroup);
  618. }
  619. {
  620. // Luminance reduce SRGs
  621. AZ_Assert(m_numThreads[LuminanceReduceScope].m_X == m_numThreads[LuminanceReduceScope].m_Y, "If the shader source changes, this logic should change too.");
  622. AZ_Assert(m_numThreads[LuminanceReduceScope].m_Z == 1, "If the shader source changes, this logic should change too.");
  623. const auto luminanceMapThreadGroupSize = m_numThreads[LuminanceReduceScope].m_X;
  624. for (uint32_t size = AsyncCompute::s_luminanceMapSize; size > 1; size = AZStd::max(size / (luminanceMapThreadGroupSize * 2), 1u))
  625. {
  626. auto shaderResourceGroup = CreateShaderResourceGroup(m_shaders[LuminanceReduceScope], "TexturesSrg", AsyncCompute::sampleName);
  627. FindShaderInputIndex(&m_luminanceReduceShaderInputImageIndex, shaderResourceGroup, luminanceReduceInputImageTexture, AsyncCompute::sampleName);
  628. FindShaderInputIndex(&m_luminanceReduceShaderOutputImageIndex, shaderResourceGroup, luminanceReduceOutputImageTexture, AsyncCompute::sampleName);
  629. m_shaderResourceGroups[LuminanceReduceScope].push_back(shaderResourceGroup);
  630. }
  631. }
  632. {
  633. // Tonemapping SRGs
  634. auto shaderResourceGroup = CreateShaderResourceGroup(m_shaders[TonemappingScope], "TexturesSrg", AsyncCompute::sampleName);
  635. FindShaderInputIndex(&m_tonemappingShaderImageIndex, shaderResourceGroup, tonemappingImageTexture, AsyncCompute::sampleName);
  636. FindShaderInputIndex(&m_tonemappingLuminanceImageIndex, shaderResourceGroup, tonemappingLuminanceImageTexture, AsyncCompute::sampleName);
  637. m_shaderResourceGroups[TonemappingScope].push_back(shaderResourceGroup);
  638. }
  639. }
  640. void AsyncComputeExampleComponent::SetArcBallControllerParams()
  641. {
  642. AZ::Debug::CameraControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::CameraControllerRequestBus::Events::Enable,
  643. azrtti_typeid<AZ::Debug::ArcBallControllerComponent>());
  644. AZ::RPI::ViewPtr cameraView;
  645. // The RPI::View associated to this component can be obtained through the ViewProvider, by using Entity Id.
  646. AZ::RPI::ViewProviderBus::EventResult(cameraView, m_cameraEntityId, &AZ::RPI::ViewProvider::GetView);
  647. if (cameraView)
  648. {
  649. m_viewShaderResourceGroup = cameraView->GetShaderResourceGroup();
  650. }
  651. }
  652. void AsyncComputeExampleComponent::CreateCopyTextureScope()
  653. {
  654. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  655. {
  656. auto& source = m_sceneIds[m_previousSceneImageIndex];
  657. auto& destination = m_outputAttachmentId;
  658. {
  659. {
  660. RHI::ImageScopeAttachmentDescriptor descriptor;
  661. descriptor.m_attachmentId = destination;
  662. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  663. frameGraph.UseColorAttachment(descriptor);
  664. }
  665. {
  666. RHI::ImageScopeAttachmentDescriptor descriptor;
  667. descriptor.m_attachmentId = source;
  668. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  669. frameGraph.UseShaderAttachment(descriptor, RHI::ScopeAttachmentAccess::Read);
  670. }
  671. }
  672. frameGraph.SetEstimatedItemCount(1);
  673. };
  674. const auto compileFunction = [this](const RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  675. {
  676. auto& source = m_sceneIds[m_previousSceneImageIndex];
  677. auto& shaderResourceGroup = m_shaderResourceGroups[CopyTextureScope].front();
  678. const RHI::ImageView* imageView = context.GetImageView(source);
  679. shaderResourceGroup->SetImageView(m_copyTextureShaderInputImageIndex, imageView);
  680. shaderResourceGroup->Compile();
  681. };
  682. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  683. {
  684. RHI::CommandList* commandList = context.GetCommandList();
  685. commandList->SetViewports(&m_viewport, 1);
  686. commandList->SetScissors(&m_scissor, 1);
  687. {
  688. // Quad
  689. RHI::DrawIndexed drawIndexed;
  690. drawIndexed.m_indexCount = 6;
  691. drawIndexed.m_instanceCount = 1;
  692. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroups[CopyTextureScope].front()->GetRHIShaderResourceGroup() };
  693. RHI::DrawItem drawItem;
  694. drawItem.m_arguments = drawIndexed;
  695. drawItem.m_pipelineState = m_copyTexturePipelineState.get();
  696. drawItem.m_indexBufferView = &m_quadIndexBufferView;
  697. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  698. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  699. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_quadStreamBufferViews[CopyTextureScope].size());
  700. drawItem.m_streamBufferViews = m_quadStreamBufferViews[CopyTextureScope].data();
  701. commandList->Submit(drawItem);
  702. }
  703. };
  704. AZStd::string name = AZStd::string::format("CopyTextureToSwapchain");
  705. const RHI::ScopeId shadowScope(name);
  706. m_scopeProducers.emplace_back(aznew RHI::ScopeProducerFunction<
  707. ScopeData,
  708. decltype(prepareFunction),
  709. decltype(compileFunction),
  710. decltype(executeFunction)>(
  711. shadowScope,
  712. ScopeData{},
  713. prepareFunction,
  714. compileFunction,
  715. executeFunction));
  716. }
  717. void AsyncComputeExampleComponent::CreateShadowScope()
  718. {
  719. // Generate shadowmap texture.
  720. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  721. {
  722. // Create & Binds DepthStencil image
  723. {
  724. RHI::ImageScopeAttachmentDescriptor dsDesc;
  725. dsDesc.m_attachmentId = m_shadowAttachmentId;
  726. dsDesc.m_imageViewDescriptor.m_overrideFormat = RHI::Format::D32_FLOAT;
  727. dsDesc.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateDepthStencil(1.0f, 0);
  728. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  729. frameGraph.UseDepthStencilAttachment(dsDesc, RHI::ScopeAttachmentAccess::ReadWrite);
  730. }
  731. frameGraph.SetEstimatedItemCount(static_cast<uint32_t>(m_shaderResourceGroups[ShadowScope].size()));
  732. };
  733. RHI::EmptyCompileFunction<ScopeData> compileFunction;
  734. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  735. {
  736. RHI::CommandList* commandList = context.GetCommandList();
  737. float shadowMapSizeFloat = static_cast<float>(AsyncCompute::s_shadowMapSize);
  738. int32_t shadowMapSizeInt = static_cast<int32_t>(AsyncCompute::s_shadowMapSize);
  739. RHI::Viewport viewport = RHI::Viewport(0, shadowMapSizeFloat, 0, shadowMapSizeFloat);
  740. RHI::Scissor scissor(0, 0, shadowMapSizeInt, shadowMapSizeInt);
  741. commandList->SetViewports(&viewport, 1);
  742. commandList->SetScissors(&scissor, 1);
  743. {
  744. // Terrain
  745. RHI::DrawIndexed drawIndexed;
  746. drawIndexed.m_indexCount = 6;
  747. drawIndexed.m_instanceCount = 1;
  748. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroups[ShadowScope][0]->GetRHIShaderResourceGroup() };
  749. RHI::DrawItem drawItem;
  750. drawItem.m_arguments = drawIndexed;
  751. drawItem.m_pipelineState = m_terrainPipelineStates[ShadowScope].get();
  752. drawItem.m_indexBufferView = &m_quadIndexBufferView;
  753. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  754. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  755. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_quadStreamBufferViews[ShadowScope].size());
  756. drawItem.m_streamBufferViews = m_quadStreamBufferViews[ShadowScope].data();
  757. commandList->Submit(drawItem);
  758. }
  759. for(size_t i = 1; i < m_shaderResourceGroups[ShadowScope].size(); ++i)
  760. {
  761. // Models
  762. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroups[ShadowScope][i]->GetRHIShaderResourceGroup() };
  763. for (const auto& mesh : m_model->GetLods()[0]->GetMeshes())
  764. {
  765. RHI::DrawItem drawItem;
  766. drawItem.m_arguments = mesh.m_drawArguments;
  767. drawItem.m_pipelineState = m_modelPipelineStates[ShadowScope].get();
  768. drawItem.m_indexBufferView = &mesh.m_indexBufferView;
  769. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  770. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  771. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_modelStreamBufferViews[ShadowScope].size());
  772. drawItem.m_streamBufferViews = m_modelStreamBufferViews[ShadowScope].data();
  773. commandList->Submit(drawItem);
  774. }
  775. }
  776. };
  777. const RHI::ScopeId shadowScope("ShadowScope");
  778. m_scopeProducers.emplace_back(aznew RHI::ScopeProducerFunction<
  779. ScopeData,
  780. decltype(prepareFunction),
  781. decltype(compileFunction),
  782. decltype(executeFunction)>(
  783. shadowScope,
  784. ScopeData{},
  785. prepareFunction,
  786. compileFunction,
  787. executeFunction));
  788. }
  789. void AsyncComputeExampleComponent::CreateForwardScope()
  790. {
  791. // Render all objects with shadows.
  792. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  793. {
  794. // Binds the scene image. Clears it to black.
  795. {
  796. RHI::ImageScopeAttachmentDescriptor descriptor;
  797. descriptor.m_attachmentId = m_sceneIds[m_currentSceneImageIndex];
  798. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  799. descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  800. frameGraph.UseColorAttachment(descriptor);
  801. }
  802. // Binds depth buffer from depth pass
  803. {
  804. frameGraph.UseShaderAttachment(RHI::ImageScopeAttachmentDescriptor(m_shadowAttachmentId), RHI::ScopeAttachmentAccess::Read);
  805. }
  806. // Binds DepthStencil image
  807. {
  808. RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  809. RHI::ImageScopeAttachmentDescriptor dsDesc;
  810. dsDesc.m_attachmentId = m_forwardDepthStencilId;
  811. dsDesc.m_imageViewDescriptor.m_overrideFormat = device->GetNearestSupportedFormat(RHI::Format::D24_UNORM_S8_UINT, AZ::RHI::FormatCapabilities::DepthStencil);
  812. dsDesc.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateDepthStencil(0, 0);
  813. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  814. dsDesc.m_loadStoreAction.m_loadActionStencil = RHI::AttachmentLoadAction::Clear;
  815. frameGraph.UseDepthStencilAttachment(dsDesc, RHI::ScopeAttachmentAccess::Write);
  816. }
  817. frameGraph.SetEstimatedItemCount(static_cast<uint32_t>(m_shaderResourceGroups[ForwardScope].size()));
  818. };
  819. const auto compileFunction = [this](const RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  820. {
  821. const RHI::ImageView* imageView = context.GetImageView(m_shadowAttachmentId);
  822. for (const auto& shaderResourceGroup : m_shaderResourceGroups[ForwardScope])
  823. {
  824. shaderResourceGroup->SetImageView(m_shaderInputImageIndex, imageView);
  825. shaderResourceGroup->Compile();
  826. }
  827. };
  828. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  829. {
  830. RHI::CommandList* commandList = context.GetCommandList();
  831. // Bind ViewSrg
  832. commandList->SetShaderResourceGroupForDraw(*m_viewShaderResourceGroup->GetRHIShaderResourceGroup());
  833. // Set persistent viewport and scissor state.
  834. const auto& imageSize = m_sceneImages[m_currentSceneImageIndex]->GetDescriptor().m_size;
  835. RHI::Viewport viewport(0, static_cast<float>(imageSize.m_width), 0, static_cast<float>(imageSize.m_height));
  836. RHI::Scissor scissor(0, 0, static_cast<int32_t>(imageSize.m_width), static_cast<int32_t>(imageSize.m_height));
  837. commandList->SetViewports(&viewport, 1);
  838. commandList->SetScissors(&scissor, 1);
  839. {
  840. // Terrain
  841. const RHI::ShaderResourceGroup* shaderResourceGroups[] =
  842. {
  843. m_shaderResourceGroups[ForwardScope][0]->GetRHIShaderResourceGroup(),
  844. m_viewShaderResourceGroup->GetRHIShaderResourceGroup()
  845. };
  846. RHI::DrawIndexed drawIndexed;
  847. drawIndexed.m_indexCount = 6;
  848. drawIndexed.m_instanceCount = 1;
  849. RHI::DrawItem drawItem;
  850. drawItem.m_arguments = drawIndexed;
  851. drawItem.m_pipelineState = m_terrainPipelineStates[ForwardScope].get();
  852. drawItem.m_indexBufferView = &m_quadIndexBufferView;
  853. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  854. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  855. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_quadStreamBufferViews[ForwardScope].size());
  856. drawItem.m_streamBufferViews = m_quadStreamBufferViews[ForwardScope].data();
  857. commandList->Submit(drawItem);
  858. }
  859. for (size_t i = 1; i < m_shaderResourceGroups[ShadowScope].size(); ++i)
  860. {
  861. // Model
  862. const RHI::ShaderResourceGroup* shaderResourceGroups[] =
  863. {
  864. m_shaderResourceGroups[ForwardScope][i]->GetRHIShaderResourceGroup(),
  865. m_viewShaderResourceGroup->GetRHIShaderResourceGroup()
  866. };
  867. for (const auto& mesh : m_model->GetLods()[0]->GetMeshes())
  868. {
  869. RHI::DrawItem drawItem;
  870. drawItem.m_arguments = mesh.m_drawArguments;
  871. drawItem.m_pipelineState = m_modelPipelineStates[ForwardScope].get();
  872. drawItem.m_indexBufferView = &mesh.m_indexBufferView;
  873. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  874. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  875. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_modelStreamBufferViews[ForwardScope].size());
  876. drawItem.m_streamBufferViews = m_modelStreamBufferViews[ForwardScope].data();
  877. commandList->Submit(drawItem);
  878. }
  879. }
  880. };
  881. const RHI::ScopeId forwardScope("ForwardScope");
  882. m_scopeProducers.emplace_back(
  883. aznew RHI::ScopeProducerFunction<
  884. ScopeData,
  885. decltype(prepareFunction),
  886. decltype(compileFunction),
  887. decltype(executeFunction)>(
  888. forwardScope,
  889. ScopeData{},
  890. prepareFunction,
  891. compileFunction,
  892. executeFunction));
  893. }
  894. void AsyncComputeExampleComponent::CreateTonemappingScope()
  895. {
  896. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  897. {
  898. {
  899. RHI::ImageScopeAttachmentDescriptor inputOuputDescriptor;
  900. inputOuputDescriptor.m_attachmentId = m_sceneIds[m_previousSceneImageIndex];
  901. inputOuputDescriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  902. frameGraph.UseShaderAttachment(inputOuputDescriptor, RHI::ScopeAttachmentAccess::ReadWrite);
  903. RHI::ImageScopeAttachmentDescriptor luminanceDescriptor;
  904. luminanceDescriptor.m_attachmentId = m_averageLuminanceAttachmentId;
  905. luminanceDescriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  906. frameGraph.UseShaderAttachment(luminanceDescriptor, RHI::ScopeAttachmentAccess::Read);
  907. }
  908. frameGraph.SetEstimatedItemCount(1);
  909. frameGraph.SetHardwareQueueClass(m_asyncComputeEnabled ? RHI::HardwareQueueClass::Compute : RHI::HardwareQueueClass::Graphics);
  910. };
  911. const auto compileFunction = [this](const RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  912. {
  913. const RHI::ImageView* hdrSceneView = context.GetImageView(m_sceneIds[m_previousSceneImageIndex]);
  914. const RHI::ImageView* luminanceView = context.GetImageView(m_averageLuminanceAttachmentId);
  915. for (const auto& shaderResourceGroup : m_shaderResourceGroups[TonemappingScope])
  916. {
  917. shaderResourceGroup->SetImageView(m_tonemappingShaderImageIndex, hdrSceneView);
  918. shaderResourceGroup->SetImageView(m_tonemappingLuminanceImageIndex, luminanceView);
  919. shaderResourceGroup->Compile();
  920. }
  921. };
  922. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  923. {
  924. RHI::CommandList* commandList = context.GetCommandList();
  925. RHI::DispatchItem dispatchItem;
  926. decltype(dispatchItem.m_shaderResourceGroups) shaderResourceGroups = { { m_shaderResourceGroups[TonemappingScope][0]->GetRHIShaderResourceGroup() } };
  927. RHI::DispatchDirect dispatchArgs;
  928. dispatchArgs.m_totalNumberOfThreadsX = m_outputWidth;
  929. dispatchArgs.m_threadsPerGroupX = aznumeric_cast<uint16_t>(m_numThreads[TonemappingScope].m_X);
  930. dispatchArgs.m_totalNumberOfThreadsY = m_outputHeight;
  931. dispatchArgs.m_threadsPerGroupY = aznumeric_cast<uint16_t>(m_numThreads[TonemappingScope].m_Y);
  932. dispatchArgs.m_totalNumberOfThreadsZ = 1;
  933. dispatchArgs.m_threadsPerGroupZ = aznumeric_cast<uint16_t>(m_numThreads[TonemappingScope].m_Z);
  934. AZ_Assert(dispatchArgs.m_threadsPerGroupX == dispatchArgs.m_threadsPerGroupY, "If the shader source changes, this logic should change too.");
  935. AZ_Assert(dispatchArgs.m_threadsPerGroupZ == 1, "If the shader source changes, this logic should change too.");
  936. dispatchItem.m_arguments = dispatchArgs;
  937. dispatchItem.m_pipelineState = m_tonemappingPipelineState.get();
  938. dispatchItem.m_shaderResourceGroupCount = 1;
  939. dispatchItem.m_shaderResourceGroups = shaderResourceGroups;
  940. commandList->Submit(dispatchItem);
  941. };
  942. const RHI::ScopeId tonemappingScope("TonemappingScope");
  943. m_scopeProducers.emplace_back(
  944. aznew RHI::ScopeProducerFunction<
  945. ScopeData,
  946. decltype(prepareFunction),
  947. decltype(compileFunction),
  948. decltype(executeFunction)>(
  949. tonemappingScope,
  950. ScopeData{},
  951. prepareFunction,
  952. compileFunction,
  953. executeFunction));
  954. }
  955. void AsyncComputeExampleComponent::CreateLuminanceMapScope()
  956. {
  957. // Create a luminance map (that will be reduce) from the scene image.
  958. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  959. {
  960. {
  961. RHI::ImageScopeAttachmentDescriptor luminanceMapDesc;
  962. luminanceMapDesc.m_attachmentId = m_luminanceMapAttachmentId;
  963. luminanceMapDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::DontCare;
  964. frameGraph.UseColorAttachment(luminanceMapDesc);
  965. RHI::ImageScopeAttachmentDescriptor sceneDescriptor;
  966. sceneDescriptor.m_attachmentId = m_sceneIds[m_previousSceneImageIndex];
  967. sceneDescriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  968. frameGraph.UseShaderAttachment(sceneDescriptor, RHI::ScopeAttachmentAccess::Read);
  969. }
  970. frameGraph.SetEstimatedItemCount(1);
  971. };
  972. const auto compileFunction = [this](const RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  973. {
  974. const RHI::ImageView* imageView = context.GetImageView(m_sceneIds[m_previousSceneImageIndex]);
  975. for (const auto& shaderResourceGroup : m_shaderResourceGroups[LuminanceMapScope])
  976. {
  977. shaderResourceGroup->SetImageView(m_luminanceShaderInputImageIndex, imageView);
  978. shaderResourceGroup->Compile();
  979. }
  980. };
  981. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  982. {
  983. RHI::CommandList* commandList = context.GetCommandList();
  984. RHI::Viewport viewport(0, static_cast<float>(AsyncCompute::s_luminanceMapSize), 0, static_cast<float>(AsyncCompute::s_luminanceMapSize));
  985. RHI::Scissor scissor(0, 0, AsyncCompute::s_luminanceMapSize, AsyncCompute::s_luminanceMapSize);
  986. commandList->SetViewports(&viewport, 1);
  987. commandList->SetScissors(&scissor, 1);
  988. {
  989. // Quad
  990. RHI::DrawIndexed drawIndexed;
  991. drawIndexed.m_indexCount = 6;
  992. drawIndexed.m_instanceCount = 1;
  993. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroups[LuminanceMapScope][0]->GetRHIShaderResourceGroup() };
  994. RHI::DrawItem drawItem;
  995. drawItem.m_arguments = drawIndexed;
  996. drawItem.m_pipelineState = m_luminancePipelineState.get();
  997. drawItem.m_indexBufferView = &m_quadIndexBufferView;
  998. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  999. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  1000. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_quadStreamBufferViews[LuminanceMapScope].size());
  1001. drawItem.m_streamBufferViews = m_quadStreamBufferViews[LuminanceMapScope].data();
  1002. commandList->Submit(drawItem);
  1003. }
  1004. };
  1005. const RHI::ScopeId shadowScope("LuminanceMapScope");
  1006. m_scopeProducers.emplace_back(aznew RHI::ScopeProducerFunction<
  1007. ScopeData,
  1008. decltype(prepareFunction),
  1009. decltype(compileFunction),
  1010. decltype(executeFunction)>(
  1011. shadowScope,
  1012. ScopeData{},
  1013. prepareFunction,
  1014. compileFunction,
  1015. executeFunction));
  1016. }
  1017. void AsyncComputeExampleComponent::CreateLuminanceReduceScopes()
  1018. {
  1019. // We reduce the luminance map texture using multiple chained compute scopes
  1020. // until we get the 1x1 texture.
  1021. RHI::AttachmentId inputAttachmentId = m_luminanceMapAttachmentId;
  1022. // By design, the luminance reduce shader uses the same size for X and Y.
  1023. // If the shader code changes this logic should change too, otherwise taking numThreads.m_X is enough
  1024. const auto luminanceMapThreadGroupSize = m_numThreads[LuminanceReduceScope].m_X;
  1025. for(uint32_t inputSize = AsyncCompute::s_luminanceMapSize, i = 0; inputSize > 1; ++i)
  1026. {
  1027. uint32_t outputSize = AZStd::max(inputSize / (luminanceMapThreadGroupSize * 2), 1u);
  1028. AZStd::string outputAttachmentString = AZStd::string::format("LuminanceReduce%d", static_cast<int>(outputSize));
  1029. RHI::AttachmentId outputAttachmentId(outputAttachmentString);
  1030. const auto prepareFunction = [this, outputSize, inputAttachmentId, outputAttachmentId](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  1031. {
  1032. {
  1033. const RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2D(
  1034. RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::Color,
  1035. outputSize,
  1036. outputSize,
  1037. RHI::Format::R32_FLOAT);
  1038. frameGraph.GetAttachmentDatabase().CreateTransientImage(RHI::TransientImageDescriptor(outputAttachmentId, imageDescriptor));
  1039. }
  1040. {
  1041. RHI::ImageScopeAttachmentDescriptor inputDescriptor;
  1042. inputDescriptor.m_attachmentId = inputAttachmentId;
  1043. inputDescriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  1044. frameGraph.UseShaderAttachment(inputDescriptor, RHI::ScopeAttachmentAccess::Read);
  1045. RHI::ImageScopeAttachmentDescriptor outputDescriptor;
  1046. outputDescriptor.m_attachmentId = outputAttachmentId;
  1047. outputDescriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::DontCare;
  1048. frameGraph.UseShaderAttachment(outputDescriptor, RHI::ScopeAttachmentAccess::ReadWrite);
  1049. }
  1050. frameGraph.SetEstimatedItemCount(1);
  1051. frameGraph.SetHardwareQueueClass(m_asyncComputeEnabled ? RHI::HardwareQueueClass::Compute : RHI::HardwareQueueClass::Graphics);
  1052. };
  1053. const auto compileFunction = [this, inputAttachmentId, outputAttachmentId, i](const RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  1054. {
  1055. const RHI::ImageView* inputView = context.GetImageView(inputAttachmentId);
  1056. const RHI::ImageView* outputView = context.GetImageView(outputAttachmentId);
  1057. const auto& shaderResourceGroup = m_shaderResourceGroups[LuminanceReduceScope][i];
  1058. shaderResourceGroup->SetImageView(m_luminanceReduceShaderInputImageIndex, inputView);
  1059. shaderResourceGroup->SetImageView(m_luminanceReduceShaderOutputImageIndex, outputView);
  1060. shaderResourceGroup->Compile();
  1061. };
  1062. const auto executeFunction = [this, i, outputSize](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  1063. {
  1064. RHI::CommandList* commandList = context.GetCommandList();
  1065. RHI::DispatchItem dispatchItem;
  1066. decltype(dispatchItem.m_shaderResourceGroups) shaderResourceGroups = { { m_shaderResourceGroups[LuminanceReduceScope][i]->GetRHIShaderResourceGroup() } };
  1067. RHI::DispatchDirect dispatchArgs;
  1068. dispatchArgs.m_threadsPerGroupX = aznumeric_cast<uint16_t>(m_numThreads[LuminanceReduceScope].m_X);
  1069. dispatchArgs.m_threadsPerGroupY = aznumeric_cast<uint16_t>(m_numThreads[LuminanceReduceScope].m_Y);
  1070. dispatchArgs.m_threadsPerGroupZ = aznumeric_cast<uint16_t>(m_numThreads[LuminanceReduceScope].m_Z);
  1071. AZ_Assert(dispatchArgs.m_threadsPerGroupZ == 1, "If the shader source changes, this logic should change too.");
  1072. dispatchArgs.m_totalNumberOfThreadsX = outputSize * dispatchArgs.m_threadsPerGroupX;
  1073. dispatchArgs.m_totalNumberOfThreadsY = outputSize * dispatchArgs.m_threadsPerGroupY;
  1074. dispatchArgs.m_totalNumberOfThreadsZ = 1;
  1075. dispatchItem.m_arguments = dispatchArgs;
  1076. dispatchItem.m_pipelineState = m_luminanceReducePipelineState.get();
  1077. dispatchItem.m_shaderResourceGroupCount = 1;
  1078. dispatchItem.m_shaderResourceGroups = shaderResourceGroups;
  1079. commandList->Submit(dispatchItem);
  1080. };
  1081. AZStd::string scopeName = AZStd::string::format("LuminanceReduce%d", static_cast<int>(outputSize));
  1082. const RHI::ScopeId tonemappingScope(scopeName);
  1083. m_scopeProducers.emplace_back(
  1084. aznew RHI::ScopeProducerFunction<
  1085. ScopeData,
  1086. decltype(prepareFunction),
  1087. decltype(compileFunction),
  1088. decltype(executeFunction)>(
  1089. tonemappingScope,
  1090. ScopeData{},
  1091. prepareFunction,
  1092. compileFunction,
  1093. executeFunction));
  1094. inputAttachmentId = outputAttachmentId;
  1095. inputSize = outputSize;
  1096. }
  1097. }
  1098. bool AsyncComputeExampleComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
  1099. {
  1100. auto config = azrtti_cast<const SampleComponentConfig*>(baseConfig);
  1101. AZ_Assert(config && config->IsValid(), "SampleComponentConfig required for sample component configuration.");
  1102. m_cameraEntityId = config->m_cameraEntityId;
  1103. return BasicRHIComponent::ReadInConfig(baseConfig);
  1104. }
  1105. }