TriangleExampleComponent.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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 <RHI/TriangleExampleComponent.h>
  9. #include <Utils/Utils.h>
  10. #include <SampleComponentManager.h>
  11. #include <Atom/RHI/CommandList.h>
  12. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  13. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  14. #include <Atom/RPI.Public/Shader/Shader.h>
  15. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  16. #include <AzCore/Serialization/SerializeContext.h>
  17. namespace AtomSampleViewer
  18. {
  19. void TriangleExampleComponent::Reflect(AZ::ReflectContext* context)
  20. {
  21. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  22. {
  23. serializeContext->Class<TriangleExampleComponent, AZ::Component>()
  24. ->Version(0)
  25. ;
  26. }
  27. }
  28. void TriangleExampleComponent::OnFramePrepare(AZ::RHI::FrameGraphBuilder& frameGraphBuilder)
  29. {
  30. using namespace AZ;
  31. {
  32. static float time = 0.0f;
  33. time += 0.005f;
  34. // Move the triangle around.
  35. AZ::Vector3 translation(
  36. sinf(time) * 0.25f,
  37. cosf(time) * 0.25f,
  38. 0.0f);
  39. [[maybe_unused]] bool success = m_shaderResourceGroup->SetConstant(m_objectMatrixConstantIndex, AZ::Matrix4x4::CreateTranslation(translation));
  40. AZ_Warning("TriangleExampleComponent", success, "Failed to set SRG Constant m_objectMatrix");
  41. m_shaderResourceGroup->Compile();
  42. }
  43. BasicRHIComponent::OnFramePrepare(frameGraphBuilder);
  44. }
  45. TriangleExampleComponent::TriangleExampleComponent()
  46. {
  47. m_supportRHISamplePipeline = true;
  48. }
  49. void TriangleExampleComponent::Activate()
  50. {
  51. using namespace AZ;
  52. AZ::RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
  53. {
  54. m_inputAssemblyBufferPool = aznew RHI::BufferPool();
  55. RHI::BufferPoolDescriptor bufferPoolDesc;
  56. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  57. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  58. m_inputAssemblyBufferPool->Init(bufferPoolDesc);
  59. BufferData bufferData;
  60. SetVertexPosition(bufferData.m_positions.data(), 0, 0.0, 0.5, 0.0);
  61. SetVertexPosition(bufferData.m_positions.data(), 1, -0.5, -0.5, 0.0);
  62. SetVertexPosition(bufferData.m_positions.data(), 2, 0.5, -0.5, 0.0);
  63. SetVertexColor(bufferData.m_colors.data(), 0, 1.0, 0.0, 0.0, 1.0);
  64. SetVertexColor(bufferData.m_colors.data(), 1, 0.0, 1.0, 0.0, 1.0);
  65. SetVertexColor(bufferData.m_colors.data(), 2, 0.0, 0.0, 1.0, 1.0);
  66. SetVertexIndexIncreasing(bufferData.m_indices.data(), bufferData.m_indices.size());
  67. m_inputAssemblyBuffer = aznew RHI::Buffer();
  68. RHI::BufferInitRequest request;
  69. request.m_buffer = m_inputAssemblyBuffer.get();
  70. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, sizeof(bufferData) };
  71. request.m_initialData = &bufferData;
  72. m_inputAssemblyBufferPool->InitBuffer(request);
  73. m_geometryView.SetDrawArguments(RHI::DrawIndexed(0, 3, 0));
  74. m_geometryView.SetIndexBufferView({
  75. *m_inputAssemblyBuffer,
  76. offsetof(BufferData, m_indices),
  77. sizeof(BufferData::m_indices),
  78. RHI::IndexFormat::Uint16
  79. });
  80. m_geometryView.AddStreamBufferView({
  81. *m_inputAssemblyBuffer,
  82. offsetof(BufferData, m_positions),
  83. sizeof(BufferData::m_positions),
  84. sizeof(VertexPosition)
  85. });
  86. m_geometryView.AddStreamBufferView({
  87. *m_inputAssemblyBuffer,
  88. offsetof(BufferData, m_colors),
  89. sizeof(BufferData::m_colors),
  90. sizeof(VertexColor)
  91. });
  92. RHI::InputStreamLayoutBuilder layoutBuilder;
  93. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  94. layoutBuilder.AddBuffer()->Channel("COLOR", RHI::Format::R32G32B32A32_FLOAT);
  95. pipelineStateDescriptor.m_inputStreamLayout = layoutBuilder.End();
  96. RHI::ValidateStreamBufferViews(pipelineStateDescriptor.m_inputStreamLayout, m_geometryView, m_geometryView.GetFullStreamBufferIndices());
  97. }
  98. {
  99. const char* triangeShaderFilePath = "Shaders/RHI/triangle.azshader";
  100. const char* sampleName = "TriangleExample";
  101. auto shader = LoadShader(triangeShaderFilePath, sampleName);
  102. if (shader == nullptr)
  103. return;
  104. auto shaderOptionGroup = shader->CreateShaderOptionGroup();
  105. shaderOptionGroup.SetUnspecifiedToDefaultValues();
  106. // This is an example of how to set different shader options when searching for the shader variant you want to display
  107. // Searching by id is simple, but suboptimal. Here it's only used to demonstrate the principle,
  108. // but in practice the ShaderOptionIndex and the ShaderOptionValue should be cached for better performance
  109. // You can also try DrawMode::Green, DrawMode::Blue or DrawMode::White. The specified color will appear on top of the triangle.
  110. shaderOptionGroup.SetValue(AZ::Name("o_drawMode"), AZ::Name("DrawMode::Red"));
  111. auto shaderVariant = shader->GetVariant(shaderOptionGroup.GetShaderVariantId());
  112. shaderVariant.ConfigurePipelineState(pipelineStateDescriptor);
  113. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  114. attachmentsBuilder.AddSubpass()
  115. ->RenderTargetAttachment(m_outputFormat);
  116. [[maybe_unused]] AZ::RHI::ResultCode result = attachmentsBuilder.End(pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  117. AZ_Assert(result == AZ::RHI::ResultCode::Success, "Failed to create render attachment layout");
  118. m_pipelineState = shader->AcquirePipelineState(pipelineStateDescriptor);
  119. if (!m_pipelineState)
  120. {
  121. AZ_Error(sampleName, false, "Failed to acquire default pipeline state for shader '%s'", triangeShaderFilePath);
  122. return;
  123. }
  124. m_shaderResourceGroup = CreateShaderResourceGroup(shader, "TriangleInstanceSrg", sampleName);
  125. const Name objectMatrixConstantId{ "m_objectMatrix" };
  126. FindShaderInputIndex(&m_objectMatrixConstantIndex, m_shaderResourceGroup, objectMatrixConstantId, sampleName);
  127. // In practice m_shaderResourceGroup should be one of the cached SRGs owned by the DrawItem
  128. if (!shaderVariant.IsFullyBaked() && m_shaderResourceGroup->HasShaderVariantKeyFallbackEntry())
  129. {
  130. // Normally if the requested variant isn't an exact match we have to set it by SetShaderVariantKeyFallbackValue
  131. // In most cases this should be the preferred behavior:
  132. m_shaderResourceGroup->SetShaderVariantKeyFallbackValue(shaderOptionGroup.GetShaderVariantKeyFallbackValue());
  133. AZ_Warning(sampleName, false, "Check the Triangle.shader file - some program variants haven't been baked ('%s')", triangeShaderFilePath);
  134. }
  135. }
  136. // Creates a scope for rendering the triangle.
  137. {
  138. struct ScopeData
  139. {
  140. };
  141. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  142. {
  143. // Binds the swap chain as a color attachment. Clears it to white.
  144. {
  145. RHI::ImageScopeAttachmentDescriptor descriptor;
  146. descriptor.m_attachmentId = m_outputAttachmentId;
  147. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  148. frameGraph.UseColorAttachment(descriptor);
  149. }
  150. // We will submit a single draw item.
  151. frameGraph.SetEstimatedItemCount(1);
  152. };
  153. RHI::EmptyCompileFunction<ScopeData> compileFunction;
  154. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  155. {
  156. RHI::CommandList* commandList = context.GetCommandList();
  157. // Set persistent viewport and scissor state.
  158. commandList->SetViewports(&m_viewport, 1);
  159. commandList->SetScissors(&m_scissor, 1);
  160. const RHI::DeviceShaderResourceGroup* shaderResourceGroups[] = {
  161. m_shaderResourceGroup->GetRHIShaderResourceGroup()->GetDeviceShaderResourceGroup(context.GetDeviceIndex()).get()
  162. };
  163. RHI::DeviceDrawItem drawItem;
  164. drawItem.m_geometryView = m_geometryView.GetDeviceGeometryView(context.GetDeviceIndex());
  165. drawItem.m_streamIndices = m_geometryView.GetFullStreamBufferIndices();
  166. drawItem.m_pipelineState = m_pipelineState->GetDevicePipelineState(context.GetDeviceIndex()).get();
  167. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  168. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  169. // Submit the triangle draw item.
  170. commandList->Submit(drawItem);
  171. };
  172. m_scopeProducers.emplace_back(
  173. aznew RHI::ScopeProducerFunction<
  174. ScopeData,
  175. decltype(prepareFunction),
  176. decltype(compileFunction),
  177. decltype(executeFunction)>(
  178. RHI::ScopeId{"Triangle"},
  179. ScopeData{},
  180. prepareFunction,
  181. compileFunction,
  182. executeFunction));
  183. }
  184. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  185. }
  186. void TriangleExampleComponent::Deactivate()
  187. {
  188. m_inputAssemblyBuffer = nullptr;
  189. m_inputAssemblyBufferPool = nullptr;
  190. m_pipelineState = nullptr;
  191. m_shaderResourceGroup = nullptr;
  192. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  193. m_windowContext = nullptr;
  194. m_scopeProducers.clear();
  195. }
  196. } // namespace AtomSampleViewer