MRTExampleComponent.cpp 17 KB

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