AsyncComputeExampleComponent.cpp 70 KB

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