DualSourceBlendingComponent.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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.Reflect/InputStreamLayoutBuilder.h>
  9. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  10. #include <RHI/DualSourceBlendingComponent.h>
  11. #include <SampleComponentManager.h>
  12. #include <Utils/Utils.h>
  13. namespace AtomSampleViewer
  14. {
  15. const char* DualSourceBlendingComponent::s_dualSourceBlendingName = "DualSourceBlending";
  16. void DualSourceBlendingComponent::Reflect(AZ::ReflectContext* context)
  17. {
  18. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  19. {
  20. serializeContext->Class<DualSourceBlendingComponent, AZ::Component>()->Version(0);
  21. }
  22. }
  23. DualSourceBlendingComponent::DualSourceBlendingComponent()
  24. {
  25. m_supportRHISamplePipeline = true;
  26. }
  27. void DualSourceBlendingComponent::OnFramePrepare(AZ::RHI::FrameGraphBuilder& frameGraphBuilder)
  28. {
  29. float blendFactor = (sinf(m_time) + 1) * 0.5f;
  30. m_shaderResourceGroup->SetConstant(m_blendFactorIndex, blendFactor);
  31. m_shaderResourceGroup->Compile();
  32. BasicRHIComponent::OnFramePrepare(frameGraphBuilder);
  33. }
  34. void DualSourceBlendingComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
  35. {
  36. AZ_UNUSED(time);
  37. m_time += deltaTime;
  38. }
  39. void DualSourceBlendingComponent::Activate()
  40. {
  41. CreateInputAssemblyBuffersAndViews();
  42. LoadRasterShader();
  43. CreateRasterScope();
  44. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  45. AZ::TickBus::Handler::BusConnect();
  46. }
  47. void DualSourceBlendingComponent::Deactivate()
  48. {
  49. m_inputAssemblyBufferPool = nullptr;
  50. m_inputAssemblyBuffer = nullptr;
  51. m_pipelineState = nullptr;
  52. m_shaderResourceGroup = nullptr;
  53. m_scopeProducers.clear();
  54. m_windowContext = nullptr;
  55. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  56. AZ::TickBus::Handler::BusDisconnect();
  57. }
  58. void DualSourceBlendingComponent::CreateInputAssemblyBuffersAndViews()
  59. {
  60. using namespace AZ;
  61. RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  62. m_inputAssemblyBufferPool = RHI::Factory::Get().CreateBufferPool();
  63. RHI::BufferPoolDescriptor bufferPoolDesc;
  64. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  65. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  66. m_inputAssemblyBufferPool->Init(*device, bufferPoolDesc);
  67. BufferData bufferData;
  68. SetVertexPosition(bufferData.m_positions.data(), 0, -1.0f, -1.0f, 0.0f);
  69. SetVertexPosition(bufferData.m_positions.data(), 1, 1.0f, -1.0f, 0.0f);
  70. SetVertexPosition(bufferData.m_positions.data(), 2, 0.0f, 1.0f, 0.0f);
  71. SetVertexColor(bufferData.m_colors.data(), 0, 1.0, 0.0, 0.0, 1.0);
  72. SetVertexColor(bufferData.m_colors.data(), 1, 0.0, 1.0, 0.0, 1.0);
  73. SetVertexColor(bufferData.m_colors.data(), 2, 0.0, 0.0, 1.0, 1.0);
  74. SetVertexIndexIncreasing(bufferData.m_indices.data(), bufferData.m_indices.size());
  75. m_inputAssemblyBuffer = RHI::Factory::Get().CreateBuffer();
  76. RHI::BufferInitRequest request;
  77. request.m_buffer = m_inputAssemblyBuffer.get();
  78. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, sizeof(bufferData) };
  79. request.m_initialData = &bufferData;
  80. m_inputAssemblyBufferPool->InitBuffer(request);
  81. m_streamBufferViews[0] =
  82. {
  83. *m_inputAssemblyBuffer,
  84. offsetof(BufferData, m_positions),
  85. sizeof(BufferData::m_positions),
  86. sizeof(VertexPosition)
  87. };
  88. m_streamBufferViews[1] =
  89. {
  90. *m_inputAssemblyBuffer,
  91. offsetof(BufferData, m_colors),
  92. sizeof(BufferData::m_colors),
  93. sizeof(VertexColor)
  94. };
  95. m_indexBufferView =
  96. {
  97. *m_inputAssemblyBuffer,
  98. offsetof(BufferData, m_indices),
  99. sizeof(BufferData::m_indices),
  100. RHI::IndexFormat::Uint16
  101. };
  102. RHI::InputStreamLayoutBuilder layoutBuilder;
  103. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  104. layoutBuilder.AddBuffer()->Channel("COLOR", RHI::Format::R32G32B32A32_FLOAT);
  105. m_inputStreamLayout = layoutBuilder.End();
  106. RHI::ValidateStreamBufferViews(m_inputStreamLayout, m_streamBufferViews);
  107. }
  108. void DualSourceBlendingComponent::LoadRasterShader()
  109. {
  110. using namespace AZ;
  111. const char* shaderFilePath = "Shaders/RHI/dualsourceblending.azshader";
  112. auto shader = LoadShader(shaderFilePath, s_dualSourceBlendingName);
  113. if (shader == nullptr)
  114. {
  115. return;
  116. }
  117. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  118. shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId).ConfigurePipelineState(pipelineDesc);
  119. pipelineDesc.m_inputStreamLayout = m_inputStreamLayout;
  120. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  121. attachmentsBuilder.AddSubpass()
  122. ->RenderTargetAttachment(m_outputFormat);
  123. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  124. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  125. pipelineDesc.m_renderStates.m_blendState.m_targets[0].m_enable = 1;
  126. pipelineDesc.m_renderStates.m_blendState.m_targets[0].m_blendSource = RHI::BlendFactor::ColorSource1;
  127. pipelineDesc.m_renderStates.m_blendState.m_targets[0].m_blendDest = RHI::BlendFactor::ColorSource1Inverse;
  128. pipelineDesc.m_renderStates.m_blendState.m_targets[0].m_blendOp = RHI::BlendOp::Add;
  129. m_pipelineState = shader->AcquirePipelineState(pipelineDesc);
  130. if (!m_pipelineState)
  131. {
  132. AZ_Error(s_dualSourceBlendingName, false, "Failed to acquire default pipeline state for shader '%s'", shaderFilePath);
  133. return;
  134. }
  135. m_shaderResourceGroup = CreateShaderResourceGroup(shader, "DualSourceBlendingSrg", s_dualSourceBlendingName);
  136. FindShaderInputIndex(&m_blendFactorIndex, m_shaderResourceGroup, AZ::Name{"m_blendFactor"}, s_dualSourceBlendingName);
  137. }
  138. void DualSourceBlendingComponent::CreateRasterScope()
  139. {
  140. using namespace AZ;
  141. struct ScopeData
  142. {
  143. //UserDataParam - Empty for this samples
  144. };
  145. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] const ScopeData& scopeData)
  146. {
  147. // Binds the swap chain as a color attachment.
  148. {
  149. RHI::ImageScopeAttachmentDescriptor descriptor;
  150. descriptor.m_attachmentId = m_outputAttachmentId;
  151. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  152. frameGraph.UseColorAttachment(descriptor);
  153. }
  154. // We will submit a single draw item.
  155. frameGraph.SetEstimatedItemCount(1);
  156. };
  157. RHI::EmptyCompileFunction<ScopeData> compileFunction;
  158. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  159. {
  160. RHI::CommandList* commandList = context.GetCommandList();
  161. // Set persistent viewport and scissor state.
  162. commandList->SetViewports(&m_viewport, 1);
  163. commandList->SetScissors(&m_scissor, 1);
  164. RHI::DrawIndexed drawIndexed;
  165. drawIndexed.m_indexCount = 3;
  166. drawIndexed.m_instanceCount = 1;
  167. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroup->GetRHIShaderResourceGroup() };
  168. RHI::DrawItem drawItem;
  169. drawItem.m_arguments = drawIndexed;
  170. drawItem.m_pipelineState = m_pipelineState.get();
  171. drawItem.m_indexBufferView = &m_indexBufferView;
  172. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_streamBufferViews.size());
  173. drawItem.m_streamBufferViews = m_streamBufferViews.data();
  174. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  175. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  176. // Submit the triangle draw item.
  177. commandList->Submit(drawItem);
  178. };
  179. m_scopeProducers.emplace_back(
  180. aznew RHI::ScopeProducerFunction<
  181. ScopeData,
  182. decltype(prepareFunction),
  183. decltype(compileFunction),
  184. decltype(executeFunction)>(
  185. AZ::RHI::ScopeId(s_dualSourceBlendingName),
  186. ScopeData{},
  187. prepareFunction,
  188. compileFunction,
  189. executeFunction));
  190. }
  191. }