StencilExampleComponent.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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 <AzCore/Serialization/SerializeContext.h>
  9. #include <Atom/RHI/CommandList.h>
  10. #include <Atom/RHI/FrameGraphBuilder.h>
  11. #include <Atom/RHI/FrameGraphAttachmentInterface.h>
  12. #include <Atom/RHI/Factory.h>
  13. #include <Atom/RHI.Reflect/ImagePoolDescriptor.h>
  14. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  15. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  16. #include <Atom/RPI.Public/Shader/Shader.h>
  17. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  18. #include <RHI/StencilExampleComponent.h>
  19. #include <SampleComponentManager.h>
  20. #include <Utils/Utils.h>
  21. namespace AtomSampleViewer
  22. {
  23. StencilExampleComponent::StencilExampleComponent()
  24. {
  25. m_depthStencilID = AZ::RHI::AttachmentId{ "DepthStencilID" };
  26. m_depthClearValue = AZ::RHI::ClearValue::CreateDepthStencil(1.0f, 0);
  27. m_supportRHISamplePipeline = true;
  28. }
  29. void StencilExampleComponent::Reflect(AZ::ReflectContext* context)
  30. {
  31. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  32. {
  33. serializeContext->Class<StencilExampleComponent, AZ::Component>()
  34. ->Version(0);
  35. }
  36. }
  37. void StencilExampleComponent::Activate()
  38. {
  39. using namespace AZ;
  40. RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  41. RHI::Format depthStencilFormat = device->GetNearestSupportedFormat(RHI::Format::D24_UNORM_S8_UINT, AZ::RHI::FormatCapabilities::DepthStencil);
  42. RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
  43. {
  44. m_inputAssemblyBufferPool = aznew RHI::BufferPool();
  45. RHI::BufferPoolDescriptor bufferPoolDesc;
  46. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  47. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  48. m_inputAssemblyBufferPool->Init(bufferPoolDesc);
  49. BufferData bufferData;
  50. // color triangles
  51. SetTriangleVertices(0, bufferData.m_positions.data(), AZ::Vector3(-0.65f, 0.65f, 0.0f), 0.1f);
  52. SetTriangleVertices(3, bufferData.m_positions.data(), AZ::Vector3( 0.0f, 0.65f, 0.0f), 0.1f);
  53. SetTriangleVertices(6, bufferData.m_positions.data(), AZ::Vector3( 0.65f, 0.65f, 0.0f), 0.1f);
  54. SetTriangleVertices(9, bufferData.m_positions.data(), AZ::Vector3(-0.3f, 0.0f, 0.0f), 0.1f);
  55. SetTriangleVertices(12, bufferData.m_positions.data(), AZ::Vector3( 0.3f, 0.0f, 0.0f), 0.1f);
  56. SetTriangleVertices(15, bufferData.m_positions.data(), AZ::Vector3(-0.65f,-0.65f, 0.0f), 0.1f);
  57. SetTriangleVertices(18, bufferData.m_positions.data(), AZ::Vector3( 0.0f, -0.65f, 0.0f), 0.1f);
  58. SetTriangleVertices(21, bufferData.m_positions.data(), AZ::Vector3( 0.65f,-0.65f, 0.0f), 0.1f);
  59. // white triangles
  60. SetTriangleVertices(24, bufferData.m_positions.data(), AZ::Vector3(-0.65f, 0.65f, 0.0f), 0.2f);
  61. SetTriangleVertices(27, bufferData.m_positions.data(), AZ::Vector3( 0.0f, 0.65f, 0.0f), 0.2f);
  62. SetTriangleVertices(30, bufferData.m_positions.data(), AZ::Vector3( 0.65f, 0.65f, 0.0f), 0.2f);
  63. SetTriangleVertices(33, bufferData.m_positions.data(), AZ::Vector3(-0.3f, 0.0f, 0.0f), 0.2f);
  64. SetTriangleVertices(36, bufferData.m_positions.data(), AZ::Vector3( 0.3f, 0.0f, 0.0f), 0.2f);
  65. SetTriangleVertices(39, bufferData.m_positions.data(), AZ::Vector3(-0.65f,-0.65f, 0.0f), 0.2f);
  66. SetTriangleVertices(42, bufferData.m_positions.data(), AZ::Vector3( 0.0f, -0.65f, 0.0f), 0.2f);
  67. SetTriangleVertices(45, bufferData.m_positions.data(), AZ::Vector3( 0.65f,-0.65f, 0.0f), 0.2f);
  68. // Triangles color
  69. for (int i = 0; i < s_numberOfVertices / 2; i+=3)
  70. {
  71. SetVertexColor(bufferData.m_colors.data(), i + 0, 1.0f, 0.0f, 0.0f, 1.0f);
  72. SetVertexColor(bufferData.m_colors.data(), i + 1, 0.0f, 1.0f, 0.0f, 1.0f);
  73. SetVertexColor(bufferData.m_colors.data(), i + 2, 0.0f, 0.0f, 1.0f, 1.0f);
  74. }
  75. for (int i = s_numberOfVertices / 2; i < s_numberOfVertices; i++)
  76. {
  77. SetVertexColor(bufferData.m_colors.data(), i , 1.0f, 1.0f, 1.0f, 1.0f);
  78. }
  79. // Triangles index
  80. SetVertexIndexIncreasing(bufferData.m_indices.data(), s_numberOfVertices);
  81. m_inputAssemblyBuffer = aznew RHI::Buffer();
  82. RHI::BufferInitRequest request;
  83. request.m_buffer = m_inputAssemblyBuffer.get();
  84. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, sizeof(bufferData) };
  85. request.m_initialData = &bufferData;
  86. m_inputAssemblyBufferPool->InitBuffer(request);
  87. m_geometryView.SetIndexBufferView({
  88. *m_inputAssemblyBuffer,
  89. offsetof(BufferData, m_indices),
  90. sizeof(BufferData::m_indices),
  91. RHI::IndexFormat::Uint16
  92. });
  93. m_geometryView.AddStreamBufferView({
  94. *m_inputAssemblyBuffer,
  95. offsetof(BufferData, m_positions),
  96. sizeof(BufferData::m_positions),
  97. sizeof(VertexPosition)
  98. });
  99. m_geometryView.AddStreamBufferView({
  100. *m_inputAssemblyBuffer,
  101. offsetof(BufferData, m_colors),
  102. sizeof(BufferData::m_colors),
  103. sizeof(VertexColor)
  104. });
  105. m_geometryView.SetDrawArguments(RHI::DrawIndexed(0, s_numberOfVertices / 2, 0));
  106. m_geometryView2 = m_geometryView;
  107. m_geometryView2.SetDrawArguments(RHI::DrawIndexed(0, 3, s_numberOfVertices / 2));
  108. RHI::InputStreamLayoutBuilder layoutBuilder;
  109. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  110. layoutBuilder.AddBuffer()->Channel("COLOR", RHI::Format::R32G32B32A32_FLOAT);
  111. pipelineStateDescriptor.m_inputStreamLayout = layoutBuilder.End();
  112. RHI::ValidateStreamBufferViews(pipelineStateDescriptor.m_inputStreamLayout, m_geometryView, m_geometryView.GetFullStreamBufferIndices());
  113. }
  114. {
  115. const char* stencilShaderFilePath = "Shaders/RHI/stencil.azshader";
  116. const char* sampleName = "StencilExample";
  117. auto shader = LoadShader(stencilShaderFilePath, sampleName);
  118. if (shader == nullptr)
  119. return;
  120. shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId).ConfigurePipelineState(pipelineStateDescriptor);
  121. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  122. attachmentsBuilder.AddSubpass()
  123. ->RenderTargetAttachment(m_outputFormat)
  124. ->DepthStencilAttachment(depthStencilFormat);
  125. [[maybe_unused]] AZ::RHI::ResultCode result = attachmentsBuilder.End(pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  126. AZ_Assert(result == AZ::RHI::ResultCode::Success, "Failed to create render attachment layout");
  127. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_enable = 1;
  128. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_frontFace.m_passOp = RHI::StencilOp::Increment;
  129. m_pipelineStateBasePass = shader->AcquirePipelineState(pipelineStateDescriptor);
  130. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_frontFace.m_passOp = RHI::StencilOp::Keep;
  131. for (uint32_t i = uint32_t(RHI::ComparisonFunc::Never); i <= uint32_t(RHI::ComparisonFunc::Always); ++i)
  132. {
  133. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_frontFace.m_func = RHI::ComparisonFunc(i);
  134. m_pipelineStateStencil[i] = shader->AcquirePipelineState(pipelineStateDescriptor);
  135. }
  136. }
  137. // Creates a scope for rendering the triangle.
  138. {
  139. struct ScopeData
  140. {
  141. };
  142. const auto prepareFunction = [this, depthStencilFormat](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  143. {
  144. // Binds the swap chain as a color attachment.
  145. {
  146. RHI::ImageScopeAttachmentDescriptor descriptor;
  147. descriptor.m_attachmentId = m_outputAttachmentId;
  148. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  149. frameGraph.UseColorAttachment(descriptor);
  150. }
  151. // Create & Binds DepthStencil image
  152. {
  153. const RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2D(
  154. RHI::ImageBindFlags::DepthStencil, (uint32_t)GetViewportWidth(), (uint32_t)GetViewportHeight(), depthStencilFormat);
  155. const RHI::TransientImageDescriptor transientImageDescriptor(m_depthStencilID, imageDescriptor);
  156. frameGraph.GetAttachmentDatabase().CreateTransientImage(transientImageDescriptor);
  157. RHI::ImageScopeAttachmentDescriptor dsDesc;
  158. dsDesc.m_attachmentId = m_depthStencilID;
  159. dsDesc.m_imageViewDescriptor.m_overrideFormat = depthStencilFormat;
  160. dsDesc.m_loadStoreAction.m_clearValue = m_depthClearValue;
  161. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  162. dsDesc.m_loadStoreAction.m_loadActionStencil = RHI::AttachmentLoadAction::Clear;
  163. frameGraph.UseDepthStencilAttachment(
  164. dsDesc, RHI::ScopeAttachmentAccess::ReadWrite,
  165. RHI::ScopeAttachmentStage::EarlyFragmentTest | RHI::ScopeAttachmentStage::LateFragmentTest);
  166. }
  167. // 1 color triangles draw item + 8 white triangles draw items
  168. uint32_t itemCount = static_cast<uint32_t>(1 + m_pipelineStateStencil.size());
  169. frameGraph.SetEstimatedItemCount(itemCount);
  170. };
  171. RHI::EmptyCompileFunction<ScopeData> compileFunction;
  172. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  173. {
  174. RHI::CommandList* commandList = context.GetCommandList();
  175. // Set persistent viewport and scissor state.
  176. commandList->SetViewports(&m_viewport, 1);
  177. commandList->SetScissors(&m_scissor, 1);
  178. RHI::DeviceDrawItem drawItem;
  179. drawItem.m_geometryView = m_geometryView.GetDeviceGeometryView(context.GetDeviceIndex());
  180. drawItem.m_streamIndices = m_geometryView.GetFullStreamBufferIndices();
  181. for (uint32_t i = context.GetSubmitRange().m_startIndex; i < context.GetSubmitRange().m_endIndex; ++i)
  182. {
  183. if (i == 0)
  184. {
  185. // Draw color triangles
  186. drawItem.m_geometryView = m_geometryView.GetDeviceGeometryView(context.GetDeviceIndex());
  187. drawItem.m_pipelineState = m_pipelineStateBasePass->GetDevicePipelineState(context.GetDeviceIndex()).get();
  188. commandList->Submit(drawItem, i);
  189. }
  190. else
  191. {
  192. // Draw white triangles
  193. drawItem.m_stencilRef = 1;
  194. drawItem.m_geometryView = m_geometryView2.GetDeviceGeometryView(context.GetDeviceIndex());
  195. drawItem.m_pipelineState = m_pipelineStateStencil[i-1]->GetDevicePipelineState(context.GetDeviceIndex()).get();
  196. commandList->Submit(drawItem, i);
  197. }
  198. }
  199. };
  200. m_scopeProducers.emplace_back(
  201. aznew RHI::ScopeProducerFunction<
  202. ScopeData,
  203. decltype(prepareFunction),
  204. decltype(compileFunction),
  205. decltype(executeFunction)>(
  206. AZ::RHI::ScopeId{"Stencil"},
  207. ScopeData{},
  208. prepareFunction,
  209. compileFunction,
  210. executeFunction));
  211. }
  212. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  213. }
  214. void StencilExampleComponent::Deactivate()
  215. {
  216. m_inputAssemblyBuffer = nullptr;
  217. m_inputAssemblyBufferPool = nullptr;
  218. m_pipelineStateBasePass = nullptr;
  219. m_pipelineStateStencil.fill(nullptr);
  220. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  221. m_windowContext = nullptr;
  222. m_scopeProducers.clear();
  223. }
  224. // set triangle vertices
  225. void StencilExampleComponent::SetTriangleVertices(int startIndex, VertexPosition* vertexData, AZ::Vector3 center, float offset)
  226. {
  227. SetVertexPosition(vertexData, startIndex + 0, center.GetX(), center.GetY() + offset, center.GetZ());
  228. SetVertexPosition(vertexData, startIndex + 1, center.GetX() - offset, center.GetY() - offset, center.GetZ());
  229. SetVertexPosition(vertexData, startIndex + 2, center.GetX() + offset, center.GetY() - offset, center.GetZ());
  230. }
  231. }