2
0

TextureArrayExampleComponent.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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/TextureArrayExampleComponent.h>
  9. #include <SampleComponentManager.h>
  10. #include <SampleComponentConfig.h>
  11. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  12. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  13. #include <AzCore/Math/Random.h>
  14. #include <Utils/Utils.h>
  15. namespace AtomSampleViewer
  16. {
  17. using namespace AZ;
  18. using namespace RPI;
  19. namespace InternalTA
  20. {
  21. const char* const SampleName = "TextureArray";
  22. const char* const ShaderFilePath = "Shaders/RHI/TextureArray.azshader";
  23. // Texture limit for this sample. This is set in the shader, if more textures need to be presented, this value
  24. // needs to be adjusted on the application side, and in the shader
  25. const uint32_t TextureCount = 8u;
  26. // The current index of the TextureArray.
  27. uint32_t g_textureIndex = 0u;
  28. };
  29. void TextureArrayExampleComponent::Reflect(ReflectContext* context)
  30. {
  31. if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
  32. {
  33. serializeContext->Class<TextureArrayExampleComponent, AZ::Component>()
  34. ->Version(0)
  35. ;
  36. }
  37. }
  38. TextureArrayExampleComponent::TextureArrayExampleComponent()
  39. {
  40. m_supportRHISamplePipeline = true;
  41. }
  42. void TextureArrayExampleComponent::Activate()
  43. {
  44. struct RectangleBufferData
  45. {
  46. AZStd::array<VertexPosition, 4> m_positions;
  47. AZStd::array<VertexUV, 4> m_uvs;
  48. AZStd::array<uint16_t, 6> m_indices;
  49. };
  50. RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  51. m_inputAssemblyBufferPool = aznew RHI::BufferPool();
  52. // Load the shader
  53. {
  54. m_shader = LoadShader(InternalTA::ShaderFilePath, InternalTA::SampleName);
  55. AZ_Error(InternalTA::SampleName, m_shader, "Failed to load shader.");
  56. }
  57. // Create the shader resource groups
  58. {
  59. m_textureArraySrg = CreateShaderResourceGroup(m_shader, "TextureArraySrg", InternalTA::SampleName);
  60. m_textureIndexSrg = CreateShaderResourceGroup(m_shader, "TextureIndexSrg", InternalTA::SampleName);
  61. }
  62. // Cache the shader input indices
  63. {
  64. FindShaderInputIndex(&m_textureArray, m_textureArraySrg, Name{"m_textureArray"}, InternalTA::SampleName);
  65. FindShaderInputIndex(&m_textureIndex, m_textureIndexSrg, Name{"m_textureArrayIndex"}, InternalTA::SampleName);
  66. // Set the shader constants
  67. {
  68. const char* filePath[InternalTA::TextureCount] = {
  69. "textures/streaming/streaming0.dds.streamingimage",
  70. "textures/streaming/streaming1.dds.streamingimage",
  71. "textures/streaming/streaming2.dds.streamingimage",
  72. "textures/streaming/streaming3.dds.streamingimage",
  73. "textures/streaming/streaming4.dds.streamingimage",
  74. "textures/streaming/streaming5.dds.streamingimage",
  75. "textures/streaming/streaming6.dds.streamingimage",
  76. "textures/streaming/streaming7.dds.streamingimage",
  77. };
  78. for (uint32_t textuerIdx = 0u; textuerIdx < InternalTA::TextureCount; textuerIdx++)
  79. {
  80. AZ::Data::Instance<AZ::RPI::StreamingImage> image = LoadStreamingImage(filePath[textuerIdx], InternalTA::SampleName);
  81. [[maybe_unused]] bool result = m_textureArraySrg->SetImage(m_textureArray, image, textuerIdx);
  82. AZ_Error(InternalTA::SampleName, result, "Failed to set image into shader resource group.");
  83. }
  84. m_textureArraySrg->Compile();
  85. }
  86. }
  87. // Setup pipeline state
  88. {
  89. RHI::InputStreamLayoutBuilder layoutBuilder;
  90. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  91. layoutBuilder.AddBuffer()->Channel("UV", RHI::Format::R32G32_FLOAT);
  92. m_rectangleInputStreamLayout = layoutBuilder.End();
  93. AZ::RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
  94. pipelineStateDescriptor.m_inputStreamLayout = m_rectangleInputStreamLayout;
  95. auto shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
  96. shaderVariant.ConfigurePipelineState(pipelineStateDescriptor);
  97. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  98. attachmentsBuilder.AddSubpass()
  99. ->RenderTargetAttachment(m_outputFormat);
  100. [[maybe_unused]] AZ::RHI::ResultCode result = attachmentsBuilder.End(pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  101. AZ_Assert(result == AZ::RHI::ResultCode::Success, "Failed to create render attachment layout");
  102. m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor);
  103. AZ_Error(InternalTA::SampleName, m_pipelineState, "Failed for the appropriate acquire default pipeline state for shader '%s'", InternalTA::ShaderFilePath);
  104. }
  105. // Setup input buffer stream
  106. {
  107. RectangleBufferData bufferData;
  108. SetFullScreenRect(bufferData.m_positions.data(), bufferData.m_uvs.data(), bufferData.m_indices.data());
  109. RHI::BufferPoolDescriptor bufferPoolDesc;
  110. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  111. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  112. m_inputAssemblyBufferPool->Init(bufferPoolDesc);
  113. m_rectangleInputAssemblyBuffer = aznew RHI::Buffer();
  114. RHI::ResultCode result = RHI::ResultCode::Success;
  115. RHI::BufferInitRequest request;
  116. request.m_buffer = m_rectangleInputAssemblyBuffer.get();
  117. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, sizeof(bufferData) };
  118. request.m_initialData = &bufferData;
  119. result = m_inputAssemblyBufferPool->InitBuffer(request);
  120. if (result != RHI::ResultCode::Success)
  121. {
  122. AZ_Error(InternalTA::SampleName, false, "Failed to initialize position buffer with error code %d", result);
  123. return;
  124. }
  125. m_geometryView.SetDrawArguments(RHI::DrawIndexed(0, 6, 0));
  126. m_geometryView.SetIndexBufferView({
  127. *m_rectangleInputAssemblyBuffer,
  128. offsetof(RectangleBufferData, m_indices),
  129. sizeof(RectangleBufferData::m_indices),
  130. RHI::IndexFormat::Uint16
  131. });
  132. m_geometryView.AddStreamBufferView({
  133. *m_rectangleInputAssemblyBuffer,
  134. offsetof(RectangleBufferData, m_positions),
  135. sizeof(RectangleBufferData::m_positions),
  136. sizeof(VertexPosition)
  137. });
  138. m_geometryView.AddStreamBufferView({
  139. *m_rectangleInputAssemblyBuffer,
  140. offsetof(RectangleBufferData, m_uvs),
  141. sizeof(RectangleBufferData::m_uvs),
  142. sizeof(VertexUV)
  143. });
  144. RHI::ValidateStreamBufferViews(m_rectangleInputStreamLayout, m_rectangleStreamBufferViews);
  145. }
  146. // Creates a scope for rendering the triangle.
  147. {
  148. struct ScopeData
  149. {
  150. };
  151. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  152. {
  153. // Binds the swap chain as a color attachment.
  154. {
  155. RHI::ImageScopeAttachmentDescriptor descriptor;
  156. descriptor.m_attachmentId = m_outputAttachmentId;
  157. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  158. frameGraph.UseColorAttachment(descriptor);
  159. }
  160. // We will submit a single draw item.
  161. frameGraph.SetEstimatedItemCount(1u);
  162. };
  163. const auto compileFunction = [this]([[maybe_unused]] const AZ::RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  164. {
  165. [[maybe_unused]] bool success = m_textureIndexSrg->SetConstant(m_textureIndex, InternalTA::g_textureIndex);
  166. AZ_Warning("TriangleExampleComponent", success, "Failed to set SRG Constant m_objectMatrix");
  167. m_textureIndexSrg->Compile();
  168. };
  169. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  170. {
  171. RHI::CommandList* commandList = context.GetCommandList();
  172. // Set persistent viewport and scissor state.
  173. // NOTE: set a hard coded offset so that the ImGUI features are still accessible.
  174. RHI::Viewport viewport = m_viewport;
  175. Vector2 viewportOffset = Vector2(m_viewport.m_maxX / 2.0f, 18.0f);
  176. viewport.m_minX = viewportOffset.GetX();
  177. viewport.m_minY = viewportOffset.GetY();
  178. commandList->SetViewports(&viewport, 1u);
  179. commandList->SetScissors(&m_scissor, 1u);
  180. const RHI::DeviceShaderResourceGroup* shaderResourceGroups[] = {
  181. m_textureArraySrg->GetRHIShaderResourceGroup()->GetDeviceShaderResourceGroup(context.GetDeviceIndex()).get(),
  182. m_textureIndexSrg->GetRHIShaderResourceGroup()->GetDeviceShaderResourceGroup(context.GetDeviceIndex()).get()
  183. };
  184. RHI::DeviceDrawItem drawItem;
  185. drawItem.m_geometryView = m_geometryView.GetDeviceGeometryView(context.GetDeviceIndex());
  186. drawItem.m_streamIndices = m_geometryView.GetFullStreamBufferIndices();
  187. drawItem.m_pipelineState = m_pipelineState->GetDevicePipelineState(context.GetDeviceIndex()).get();
  188. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  189. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  190. // Submit the triangle draw item.
  191. commandList->Submit(drawItem);
  192. };
  193. m_scopeProducers.emplace_back(
  194. aznew RHI::ScopeProducerFunction<
  195. ScopeData,
  196. decltype(prepareFunction),
  197. decltype(compileFunction),
  198. decltype(executeFunction)>(
  199. RHI::ScopeId{"TextureArray"},
  200. ScopeData{ },
  201. prepareFunction,
  202. compileFunction,
  203. executeFunction));
  204. }
  205. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  206. TickBus::Handler::BusConnect();
  207. }
  208. void TextureArrayExampleComponent::Deactivate()
  209. {
  210. m_inputAssemblyBufferPool = nullptr;
  211. m_rectangleInputAssemblyBuffer = nullptr;
  212. m_pipelineState = nullptr;
  213. m_shader = nullptr;
  214. m_textureArraySrg = nullptr;
  215. m_textureIndexSrg = nullptr;
  216. }
  217. void TextureArrayExampleComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint scriptTime)
  218. {
  219. static float time = 0.0f;
  220. time += deltaTime;
  221. if (time > 1.0f)
  222. {
  223. time = 0.0f;
  224. InternalTA::g_textureIndex = (InternalTA::g_textureIndex + 1u) % InternalTA::TextureCount;
  225. }
  226. }
  227. };