StencilExampleComponent.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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 = RHI::Factory::Get().CreateBufferPool();
  45. RHI::BufferPoolDescriptor bufferPoolDesc;
  46. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  47. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  48. m_inputAssemblyBufferPool->Init(*device, 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 = RHI::Factory::Get().CreateBuffer();
  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_streamBufferViews[0] =
  88. {
  89. *m_inputAssemblyBuffer,
  90. offsetof(BufferData, m_positions),
  91. sizeof(BufferData::m_positions),
  92. sizeof(VertexPosition)
  93. };
  94. m_streamBufferViews[1] =
  95. {
  96. *m_inputAssemblyBuffer,
  97. offsetof(BufferData, m_colors),
  98. sizeof(BufferData::m_colors),
  99. sizeof(VertexColor)
  100. };
  101. RHI::InputStreamLayoutBuilder layoutBuilder;
  102. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  103. layoutBuilder.AddBuffer()->Channel("COLOR", RHI::Format::R32G32B32A32_FLOAT);
  104. pipelineStateDescriptor.m_inputStreamLayout = layoutBuilder.End();
  105. RHI::ValidateStreamBufferViews(pipelineStateDescriptor.m_inputStreamLayout, m_streamBufferViews);
  106. }
  107. {
  108. const char* stencilShaderFilePath = "Shaders/RHI/stencil.azshader";
  109. const char* sampleName = "StencilExample";
  110. auto shader = LoadShader(stencilShaderFilePath, sampleName);
  111. if (shader == nullptr)
  112. return;
  113. shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId).ConfigurePipelineState(pipelineStateDescriptor);
  114. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  115. attachmentsBuilder.AddSubpass()
  116. ->RenderTargetAttachment(m_outputFormat)
  117. ->DepthStencilAttachment(depthStencilFormat);
  118. [[maybe_unused]] AZ::RHI::ResultCode result = attachmentsBuilder.End(pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  119. AZ_Assert(result == AZ::RHI::ResultCode::Success, "Failed to create render attachment layout");
  120. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_enable = 1;
  121. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_frontFace.m_passOp = RHI::StencilOp::Increment;
  122. m_pipelineStateBasePass = shader->AcquirePipelineState(pipelineStateDescriptor);
  123. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_frontFace.m_passOp = RHI::StencilOp::Keep;
  124. for (uint32_t i = uint32_t(RHI::ComparisonFunc::Never); i <= uint32_t(RHI::ComparisonFunc::Always); ++i)
  125. {
  126. pipelineStateDescriptor.m_renderStates.m_depthStencilState.m_stencil.m_frontFace.m_func = RHI::ComparisonFunc(i);
  127. m_pipelineStateStencil[i] = shader->AcquirePipelineState(pipelineStateDescriptor);
  128. }
  129. }
  130. // Creates a scope for rendering the triangle.
  131. {
  132. struct ScopeData
  133. {
  134. };
  135. const auto prepareFunction = [this, depthStencilFormat](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  136. {
  137. // Binds the swap chain as a color attachment.
  138. {
  139. RHI::ImageScopeAttachmentDescriptor descriptor;
  140. descriptor.m_attachmentId = m_outputAttachmentId;
  141. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  142. frameGraph.UseColorAttachment(descriptor);
  143. }
  144. // Create & Binds DepthStencil image
  145. {
  146. const RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2D(
  147. RHI::ImageBindFlags::DepthStencil, (uint32_t)GetViewportWidth(), (uint32_t)GetViewportHeight(), depthStencilFormat);
  148. const RHI::TransientImageDescriptor transientImageDescriptor(m_depthStencilID, imageDescriptor);
  149. frameGraph.GetAttachmentDatabase().CreateTransientImage(transientImageDescriptor);
  150. RHI::ImageScopeAttachmentDescriptor dsDesc;
  151. dsDesc.m_attachmentId = m_depthStencilID;
  152. dsDesc.m_imageViewDescriptor.m_overrideFormat = depthStencilFormat;
  153. dsDesc.m_loadStoreAction.m_clearValue = m_depthClearValue;
  154. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  155. dsDesc.m_loadStoreAction.m_loadActionStencil = RHI::AttachmentLoadAction::Clear;
  156. frameGraph.UseDepthStencilAttachment(dsDesc, RHI::ScopeAttachmentAccess::ReadWrite);
  157. }
  158. // 1 color triangles draw item + 8 white triangles draw items
  159. uint32_t itemCount = static_cast<uint32_t>(1 + m_pipelineStateStencil.size());
  160. frameGraph.SetEstimatedItemCount(itemCount);
  161. };
  162. RHI::EmptyCompileFunction<ScopeData> compileFunction;
  163. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  164. {
  165. RHI::CommandList* commandList = context.GetCommandList();
  166. // Set persistent viewport and scissor state.
  167. commandList->SetViewports(&m_viewport, 1);
  168. commandList->SetScissors(&m_scissor, 1);
  169. const RHI::IndexBufferView indexBufferView =
  170. {
  171. *m_inputAssemblyBuffer,
  172. offsetof(BufferData, m_indices),
  173. sizeof(BufferData::m_indices),
  174. RHI::IndexFormat::Uint16
  175. };
  176. RHI::DrawIndexed drawIndexed;
  177. drawIndexed.m_indexCount = s_numberOfVertices / 2;
  178. drawIndexed.m_instanceCount = 1;
  179. // Draw color triangles
  180. RHI::DrawItem drawItem;
  181. drawItem.m_arguments = drawIndexed;
  182. drawItem.m_pipelineState = m_pipelineStateBasePass.get();
  183. drawItem.m_indexBufferView = &indexBufferView;
  184. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_streamBufferViews.size());
  185. drawItem.m_streamBufferViews = m_streamBufferViews.data();
  186. commandList->Submit(drawItem);
  187. // Draw white triangles
  188. drawIndexed.m_indexOffset = s_numberOfVertices / 2;
  189. drawIndexed.m_indexCount = 3;
  190. drawItem.m_stencilRef = 1;
  191. for (int i = 0; i < m_pipelineStateStencil.size(); ++i)
  192. {
  193. drawItem.m_arguments = drawIndexed;
  194. drawItem.m_pipelineState = m_pipelineStateStencil[i].get();
  195. commandList->Submit(drawItem);
  196. drawIndexed.m_indexOffset += 3;
  197. }
  198. };
  199. m_scopeProducers.emplace_back(
  200. aznew RHI::ScopeProducerFunction<
  201. ScopeData,
  202. decltype(prepareFunction),
  203. decltype(compileFunction),
  204. decltype(executeFunction)>(
  205. AZ::RHI::ScopeId{"Stencil"},
  206. ScopeData{},
  207. prepareFunction,
  208. compileFunction,
  209. executeFunction));
  210. }
  211. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  212. }
  213. void StencilExampleComponent::Deactivate()
  214. {
  215. m_inputAssemblyBuffer = nullptr;
  216. m_inputAssemblyBufferPool = nullptr;
  217. m_pipelineStateBasePass = nullptr;
  218. m_pipelineStateStencil.fill(nullptr);
  219. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  220. m_windowContext = nullptr;
  221. m_scopeProducers.clear();
  222. }
  223. // set triangle vertices
  224. void StencilExampleComponent::SetTriangleVertices(int startIndex, VertexPosition* vertexData, AZ::Vector3 center, float offset)
  225. {
  226. SetVertexPosition(vertexData, startIndex + 0, center.GetX(), center.GetY() + offset, center.GetZ());
  227. SetVertexPosition(vertexData, startIndex + 1, center.GetX() - offset, center.GetY() - offset, center.GetZ());
  228. SetVertexPosition(vertexData, startIndex + 2, center.GetX() + offset, center.GetY() - offset, center.GetZ());
  229. }
  230. }