MRTExampleComponent.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Atom/RHI/CommandList.h>
  9. #include <Atom/RHI/Factory.h>
  10. #include <Atom/RHI/FrameScheduler.h>
  11. #include <Atom/RHI/Image.h>
  12. #include <Atom/RHI/ImagePool.h>
  13. #include <Atom/RHI/ScopeProducerFunction.h>
  14. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  15. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  16. #include <Atom/RPI.Public/Image/AttachmentImagePool.h>
  17. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  18. #include <Atom/RPI.Public/Image/StreamingImage.h>
  19. #include <Atom/RPI.Public/Image/StreamingImagePool.h>
  20. #include <Atom/RPI.Public/Shader/Shader.h>
  21. #include <Atom/RPI.Reflect/Image/AttachmentImageAssetCreator.h>
  22. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  23. #include <AzCore/Math/Vector2.h>
  24. #include <AzCore/Math/Vector4.h>
  25. #include <AzCore/Serialization/SerializeContext.h>
  26. #include <RHI/MRTExampleComponent.h>
  27. #include <SampleComponentConfig.h>
  28. #include <SampleComponentManager.h>
  29. #include <Utils/Utils.h>
  30. namespace AtomSampleViewer
  31. {
  32. MRTExampleComponent::MRTExampleComponent()
  33. {
  34. m_time = 0.0f;
  35. m_attachmentID[0] = AZ::RHI::AttachmentId("redAttachemntID");
  36. m_attachmentID[1] = AZ::RHI::AttachmentId("greenAttachemntID");
  37. m_attachmentID[2] = AZ::RHI::AttachmentId("blueAttachemntID");
  38. m_clearValue = AZ::RHI::ClearValue::CreateVector4Float(0.0f, 0.0f, 0.0f, 0.0f);
  39. m_supportRHISamplePipeline = true;
  40. }
  41. void MRTExampleComponent::Reflect(AZ::ReflectContext* context)
  42. {
  43. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  44. {
  45. serializeContext->Class<MRTExampleComponent, AZ::Component>()
  46. ->Version(0);
  47. }
  48. }
  49. void MRTExampleComponent::OnFramePrepare(AZ::RHI::FrameGraphBuilder& frameGraphBuilder)
  50. {
  51. m_time += 0.002f;
  52. float r = cosf(m_time);
  53. float g = sinf(m_time);
  54. float b = cosf(m_time + AZ::Constants::Pi);
  55. m_shaderResourceGroups[0]->SetConstant(m_shaderInputConstantIndices[0], AZ::Vector4(r, 0 ,0, 1));
  56. m_shaderResourceGroups[0]->SetConstant(m_shaderInputConstantIndices[1], AZ::Vector2(g, 0));
  57. m_shaderResourceGroups[0]->SetConstant(m_shaderInputConstantIndices[2], b);
  58. m_shaderResourceGroups[0]->Compile();
  59. BasicRHIComponent::OnFramePrepare(frameGraphBuilder);
  60. }
  61. void MRTExampleComponent::Activate()
  62. {
  63. // Init buffers & views
  64. CreateInputAssemblyBuffersAndViews();
  65. // Init render targets
  66. InitRenderTargets();
  67. // init pipeline state
  68. ReadRenderTargetShader();
  69. ReadScreenShader();
  70. CreateRenderTargetScope();
  71. CreateScreenScope();
  72. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  73. }
  74. void MRTExampleComponent::Deactivate()
  75. {
  76. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  77. m_windowContext = nullptr;
  78. m_bufferPool = nullptr;
  79. m_inputAssemblyBuffer = nullptr;
  80. m_renderTargetImageDescriptors.fill({});
  81. m_shaderResourceGroups.fill(nullptr);
  82. m_pipelineStates.fill(nullptr);
  83. m_scopeProducers.clear();
  84. }
  85. void MRTExampleComponent::ReadRenderTargetShader()
  86. {
  87. using namespace AZ;
  88. const char* MRTTargetShaderFilePath = "Shaders/RHI/MRTTarget.azshader";
  89. const char* sampleName = "MRTExample";
  90. auto shader = LoadShader(MRTTargetShaderFilePath, sampleName);
  91. if (shader == nullptr)
  92. return;
  93. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  94. shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId).ConfigurePipelineState(pipelineDesc);
  95. pipelineDesc.m_inputStreamLayout = m_inputStreamLayout;
  96. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  97. attachmentsBuilder.AddSubpass()
  98. ->RenderTargetAttachment(RHI::Format::R8G8B8A8_UNORM_SRGB)
  99. ->RenderTargetAttachment(RHI::Format::R16G16_FLOAT)
  100. ->RenderTargetAttachment(RHI::Format::R32_FLOAT);
  101. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  102. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  103. m_pipelineStates[0] = shader->AcquirePipelineState(pipelineDesc);
  104. if (!m_pipelineStates[0])
  105. {
  106. AZ_Error(sampleName, false, "Failed to acquire default pipeline state for shader '%s'", MRTTargetShaderFilePath);
  107. return;
  108. }
  109. m_shaderResourceGroups[0] = CreateShaderResourceGroup(shader, "MrtTargetSrg", sampleName);
  110. FindShaderInputIndex(&m_shaderInputConstantIndices[0], m_shaderResourceGroups[0], AZ::Name{"rValue"}, sampleName);
  111. FindShaderInputIndex(&m_shaderInputConstantIndices[1], m_shaderResourceGroups[0], AZ::Name{"gValue"}, sampleName);
  112. FindShaderInputIndex(&m_shaderInputConstantIndices[2], m_shaderResourceGroups[0], AZ::Name{"bValue"}, sampleName);
  113. }
  114. void MRTExampleComponent::ReadScreenShader()
  115. {
  116. using namespace AZ;
  117. const char* MRTScreenShaderFilePath = "Shaders/RHI/MRTScreen.azshader";
  118. const char* sampleName = "MRTExample";
  119. auto shader = LoadShader(MRTScreenShaderFilePath, sampleName);
  120. if (shader == nullptr)
  121. return;
  122. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  123. shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId).ConfigurePipelineState(pipelineDesc);
  124. pipelineDesc.m_inputStreamLayout = m_inputStreamLayout;
  125. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  126. attachmentsBuilder.AddSubpass()
  127. ->RenderTargetAttachment(m_outputFormat);
  128. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  129. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  130. m_pipelineStates[1] = shader->AcquirePipelineState(pipelineDesc);
  131. if (!m_pipelineStates[1])
  132. {
  133. AZ_Error(sampleName, false, "Failed to acquire default pipeline state for shader '%s'", MRTScreenShaderFilePath);
  134. return;
  135. }
  136. m_shaderResourceGroups[1] = CreateShaderResourceGroup(shader, "MrtScreenInstanceSrg", sampleName);
  137. FindShaderInputIndex(&m_shaderInputImageIndices[0], m_shaderResourceGroups[1], AZ::Name{"rMap"}, sampleName);
  138. FindShaderInputIndex(&m_shaderInputImageIndices[1], m_shaderResourceGroups[1], AZ::Name{"gMap"}, sampleName);
  139. FindShaderInputIndex(&m_shaderInputImageIndices[2], m_shaderResourceGroups[1], AZ::Name{"bMap"}, sampleName);
  140. }
  141. void MRTExampleComponent::CreateInputAssemblyBuffersAndViews()
  142. {
  143. using namespace AZ;
  144. const RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  145. m_bufferPool = RHI::Factory::Get().CreateBufferPool();
  146. RHI::BufferPoolDescriptor bufferPoolDesc;
  147. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  148. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  149. m_bufferPool->Init(*device, bufferPoolDesc);
  150. BufferData bufferData;
  151. SetFullScreenRect(bufferData.m_positions.data(), bufferData.m_uvs.data(), bufferData.m_indices.data());
  152. m_inputAssemblyBuffer = RHI::Factory::Get().CreateBuffer();
  153. RHI::ResultCode result = RHI::ResultCode::Success;
  154. RHI::BufferInitRequest request;
  155. request.m_buffer = m_inputAssemblyBuffer.get();
  156. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, sizeof(bufferData) };
  157. request.m_initialData = &bufferData;
  158. result = m_bufferPool->InitBuffer(request);
  159. if (result != RHI::ResultCode::Success)
  160. {
  161. AZ_Error("MRTExample", false, "Failed to initialize buffer with error code %d", result);
  162. return;
  163. }
  164. m_streamBufferViews[0] =
  165. {
  166. *m_inputAssemblyBuffer,
  167. offsetof(BufferData, m_positions),
  168. sizeof(BufferData::m_positions),
  169. sizeof(VertexPosition)
  170. };
  171. m_streamBufferViews[1] =
  172. {
  173. *m_inputAssemblyBuffer,
  174. offsetof(BufferData, m_uvs),
  175. sizeof(BufferData::m_uvs),
  176. sizeof(VertexUV)
  177. };
  178. m_indexBufferView =
  179. {
  180. *m_inputAssemblyBuffer,
  181. offsetof(BufferData, m_indices),
  182. sizeof(BufferData::m_indices),
  183. RHI::IndexFormat::Uint16
  184. };
  185. RHI::InputStreamLayoutBuilder layoutBuilder;
  186. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  187. layoutBuilder.AddBuffer()->Channel("UV", RHI::Format::R32G32_FLOAT);
  188. m_inputStreamLayout = layoutBuilder.End();
  189. RHI::ValidateStreamBufferViews(m_inputStreamLayout, m_streamBufferViews);
  190. }
  191. void MRTExampleComponent::InitRenderTargets()
  192. {
  193. using namespace AZ;
  194. RHI::ImageDescriptor imageDesc;
  195. imageDesc = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite, 8, 8, RHI::Format::R8G8B8A8_UNORM_SRGB);
  196. m_renderTargetImageDescriptors[0] = RHI::TransientImageDescriptor(m_attachmentID[0], imageDesc);
  197. imageDesc = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite, 8, 8, RHI::Format::R16G16_FLOAT);
  198. m_renderTargetImageDescriptors[1] = RHI::TransientImageDescriptor(m_attachmentID[1], imageDesc);
  199. imageDesc = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite, 8, 8, RHI::Format::R32_FLOAT);
  200. m_renderTargetImageDescriptors[2] = RHI::TransientImageDescriptor(m_attachmentID[2], imageDesc);
  201. }
  202. void MRTExampleComponent::CreateRenderTargetScope()
  203. {
  204. using namespace AZ;
  205. const auto prepareFunctionRenderTarget = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  206. {
  207. // Create & Binds RenderTarget images
  208. {
  209. frameGraph.GetAttachmentDatabase().CreateTransientImage(m_renderTargetImageDescriptors[0]);
  210. RHI::ImageScopeAttachmentDescriptor descR;
  211. descR.m_attachmentId = m_attachmentID[0];
  212. descR.m_loadStoreAction.m_clearValue = m_clearValue;
  213. descR.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  214. frameGraph.GetAttachmentDatabase().CreateTransientImage(m_renderTargetImageDescriptors[1]);
  215. RHI::ImageScopeAttachmentDescriptor descG;
  216. descG.m_attachmentId = m_attachmentID[1];
  217. descG.m_loadStoreAction.m_clearValue = m_clearValue;
  218. descG.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  219. frameGraph.GetAttachmentDatabase().CreateTransientImage(m_renderTargetImageDescriptors[2]);
  220. RHI::ImageScopeAttachmentDescriptor descB;
  221. descB.m_attachmentId = m_attachmentID[2];
  222. descB.m_loadStoreAction.m_clearValue = m_clearValue;
  223. descB.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  224. const AZStd::array<RHI::ImageScopeAttachmentDescriptor, 3> imageScopeArray{{descR, descG, descB}};
  225. frameGraph.UseColorAttachments(imageScopeArray);
  226. }
  227. frameGraph.SetEstimatedItemCount(1);
  228. };
  229. RHI::EmptyCompileFunction<ScopeData> compileFunctionRenderTarget;
  230. const auto executeFunctionRenderTarget = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  231. {
  232. RHI::CommandList* commandList = context.GetCommandList();
  233. // Set persistent viewport and scissor state.
  234. const auto& imageSize = m_renderTargetImageDescriptors[0].m_imageDescriptor.m_size;
  235. RHI::Viewport viewport(0, static_cast<float>(imageSize.m_width), 0, static_cast<float>(imageSize.m_height));
  236. RHI::Scissor scissor(0, 0, static_cast<int32_t>(imageSize.m_width), static_cast<int32_t>(imageSize.m_height));
  237. commandList->SetViewports(&viewport, 1);
  238. commandList->SetScissors(&scissor, 1);
  239. RHI::DrawIndexed drawIndexed;
  240. drawIndexed.m_indexCount = 6;
  241. drawIndexed.m_instanceCount = 1;
  242. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroups[0]->GetRHIShaderResourceGroup() };
  243. RHI::DrawItem drawItem;
  244. drawItem.m_arguments = drawIndexed;
  245. drawItem.m_pipelineState = m_pipelineStates[0].get();
  246. drawItem.m_indexBufferView = &m_indexBufferView;
  247. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  248. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  249. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_streamBufferViews.size());
  250. drawItem.m_streamBufferViews = m_streamBufferViews.data();
  251. commandList->Submit(drawItem);
  252. };
  253. m_scopeProducers.emplace_back(aznew RHI::ScopeProducerFunction<
  254. ScopeData,
  255. decltype(prepareFunctionRenderTarget),
  256. decltype(compileFunctionRenderTarget),
  257. decltype(executeFunctionRenderTarget)>(
  258. RHI::ScopeId{"MRTTarget"},
  259. ScopeData{},
  260. prepareFunctionRenderTarget,
  261. compileFunctionRenderTarget,
  262. executeFunctionRenderTarget));
  263. }
  264. void MRTExampleComponent::CreateScreenScope()
  265. {
  266. using namespace AZ;
  267. const auto prepareFunctionScreen = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  268. {
  269. // Binds the swap chain as a color attachment.
  270. {
  271. RHI::ImageScopeAttachmentDescriptor descriptor;
  272. descriptor.m_attachmentId = m_outputAttachmentId;
  273. frameGraph.UseColorAttachment(descriptor);
  274. }
  275. // Bind shader attachments which are rendered by RenderTargetScope.
  276. {
  277. frameGraph.UseShaderAttachment(RHI::ImageScopeAttachmentDescriptor(m_attachmentID[0]), RHI::ScopeAttachmentAccess::Read);
  278. frameGraph.UseShaderAttachment(RHI::ImageScopeAttachmentDescriptor(m_attachmentID[1]), RHI::ScopeAttachmentAccess::Read);
  279. frameGraph.UseShaderAttachment(RHI::ImageScopeAttachmentDescriptor(m_attachmentID[2]), RHI::ScopeAttachmentAccess::Read);
  280. }
  281. // We will submit a single draw item.
  282. frameGraph.SetEstimatedItemCount(1);
  283. };
  284. const auto compileFunctionScreen = [this](const AZ::RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  285. {
  286. const AZ::RHI::ImageView* imageViewR = context.GetImageView(m_attachmentID[0]);
  287. const AZ::RHI::ImageView* imageViewG = context.GetImageView(m_attachmentID[1]);
  288. const AZ::RHI::ImageView* imageViewB = context.GetImageView(m_attachmentID[2]);
  289. m_shaderResourceGroups[1]->SetImageView(m_shaderInputImageIndices[0], imageViewR);
  290. m_shaderResourceGroups[1]->SetImageView(m_shaderInputImageIndices[1], imageViewG);
  291. m_shaderResourceGroups[1]->SetImageView(m_shaderInputImageIndices[2], imageViewB);
  292. m_shaderResourceGroups[1]->Compile();
  293. };
  294. const auto executeFunctionScreen = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  295. {
  296. RHI::CommandList* commandList = context.GetCommandList();
  297. // Set persistent viewport and scissor state.
  298. commandList->SetViewports(&m_viewport, 1);
  299. commandList->SetScissors(&m_scissor, 1);
  300. RHI::DrawIndexed drawIndexed;
  301. drawIndexed.m_indexCount = 6;
  302. drawIndexed.m_instanceCount = 1;
  303. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroups[1]->GetRHIShaderResourceGroup() };
  304. RHI::DrawItem drawItem;
  305. drawItem.m_arguments = drawIndexed;
  306. drawItem.m_pipelineState = m_pipelineStates[1].get();
  307. drawItem.m_indexBufferView = &m_indexBufferView;
  308. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  309. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  310. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_streamBufferViews.size());
  311. drawItem.m_streamBufferViews = m_streamBufferViews.data();
  312. commandList->Submit(drawItem);
  313. };
  314. m_scopeProducers.emplace_back(
  315. aznew RHI::ScopeProducerFunction<
  316. ScopeData,
  317. decltype(prepareFunctionScreen),
  318. decltype(compileFunctionScreen),
  319. decltype(executeFunctionScreen)>(
  320. RHI::ScopeId{"MRTScreen"},
  321. ScopeData{},
  322. prepareFunctionScreen,
  323. compileFunctionScreen,
  324. executeFunctionScreen));
  325. }
  326. }