Texture3dExampleComponent.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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/Texture3dExampleComponent.h>
  9. #include <Utils/Utils.h>
  10. #include <SampleComponentManager.h>
  11. #include <Atom/RHI/Factory.h>
  12. #include <Atom/RHI/CommandList.h>
  13. #include <Atom/RHI/FrameScheduler.h>
  14. #include <Atom/RHI/Image.h>
  15. #include <Atom/RHI/ImagePool.h>
  16. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  17. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  18. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  19. #include <Atom/RPI.Public/Image/StreamingImagePool.h>
  20. #include <Atom/RPI.Public/Shader/Shader.h>
  21. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  22. #include <AzCore/Serialization/SerializeContext.h>
  23. namespace AtomSampleViewer
  24. {
  25. void Texture3dExampleComponent::Reflect(AZ::ReflectContext* context)
  26. {
  27. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  28. {
  29. serializeContext->Class<Texture3dExampleComponent, AZ::Component>()
  30. ->Version(0)
  31. ;
  32. }
  33. }
  34. Texture3dExampleComponent::Texture3dExampleComponent()
  35. {
  36. m_supportRHISamplePipeline = true;
  37. }
  38. void Texture3dExampleComponent::Activate()
  39. {
  40. using namespace AZ;
  41. const RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  42. // Get the window size
  43. AzFramework::NativeWindowHandle windowHandle = nullptr;
  44. AzFramework::WindowSystemRequestBus::BroadcastResult(
  45. windowHandle,
  46. &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
  47. AzFramework::WindowRequestBus::EventResult(
  48. m_windowSize,
  49. windowHandle,
  50. &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
  51. // Create image pool
  52. {
  53. AZ::RHI::Factory& factory = RHI::Factory::Get();
  54. m_imagePool = factory.CreateImagePool();
  55. m_imagePool->SetName(Name("Texture3DPool"));
  56. RHI::ImagePoolDescriptor imagePoolDesc = {};
  57. imagePoolDesc.m_bindFlags = RHI::ImageBindFlags::ShaderRead;
  58. const uint64_t imagePoolBudget = 1 << 24; // 16 Megabyte
  59. imagePoolDesc.m_budgetInBytes = imagePoolBudget;
  60. const RHI::ResultCode resultCode = m_imagePool->Init(*device, imagePoolDesc);
  61. if (resultCode != RHI::ResultCode::Success)
  62. {
  63. AZ_Error("Texture3dExampleComponent", false, "Failed to initialize image pool.");
  64. return;
  65. }
  66. }
  67. // Create image
  68. {
  69. // Create the 3d image data
  70. AZStd::vector<uint8_t> imageData;
  71. RHI::Format format = {};
  72. BasicRHIComponent::CreateImage3dData(imageData, m_imageLayout, format, {
  73. "textures/streaming/streaming13.dds.streamingimage",
  74. "textures/streaming/streaming14.dds.streamingimage",
  75. "textures/streaming/streaming15.dds.streamingimage",
  76. "textures/streaming/streaming16.dds.streamingimage",
  77. "textures/streaming/streaming17.dds.streamingimage",
  78. "textures/streaming/streaming19.dds.streamingimage" });
  79. // Create the image resource
  80. m_image = RHI::Factory::Get().CreateImage();
  81. m_image->SetName(Name("Texture3D"));
  82. RHI::ImageInitRequest imageRequest;
  83. imageRequest.m_image = m_image.get();
  84. imageRequest.m_descriptor = RHI::ImageDescriptor::Create3D(RHI::ImageBindFlags::ShaderRead, m_imageLayout.m_size.m_width, m_imageLayout.m_size.m_height, m_imageLayout.m_size.m_depth, format);
  85. RHI::ResultCode resultCode = m_imagePool->InitImage(imageRequest);
  86. if (resultCode != RHI::ResultCode::Success)
  87. {
  88. AZ_Error("Texture3dExampleComponent", false, "Failed to initialize image.");
  89. return;
  90. }
  91. // Create image view resource
  92. RHI::ImageViewDescriptor imageViewDescriptor = {};
  93. imageViewDescriptor = RHI::ImageViewDescriptor::Create(format, 0, 0);
  94. imageViewDescriptor.m_overrideBindFlags = RHI::ImageBindFlags::ShaderRead;
  95. m_imageView = m_image->GetImageView(imageViewDescriptor);
  96. m_imageView->SetName(Name("Texture3DView"));
  97. if(!m_imageView.get())
  98. {
  99. AZ_Error("Texture3dExampleComponent", false, "Failed to initialize image view.");
  100. return;
  101. }
  102. // Update/stage the image with data
  103. RHI::ImageSubresourceLayoutPlaced imageSubresourceLayout;
  104. RHI::ImageSubresourceRange range(0, 0, 0, 0);
  105. m_image->GetSubresourceLayouts(range, &imageSubresourceLayout, nullptr);
  106. RHI::ImageUpdateRequest updateRequest;
  107. updateRequest.m_image = m_image.get();
  108. updateRequest.m_sourceSubresourceLayout = imageSubresourceLayout;
  109. updateRequest.m_sourceData = imageData.data();
  110. updateRequest.m_imageSubresourcePixelOffset = RHI::Origin(0, 0, 0);
  111. resultCode = m_imagePool->UpdateImageContents(updateRequest);
  112. if (resultCode != RHI::ResultCode::Success)
  113. {
  114. AZ_Error("Texture3dExampleComponent", false, "Failed to update/stage the image.");
  115. return;
  116. }
  117. }
  118. // Create the pipeline object
  119. {
  120. const char* texture3dShaderFilePath = "Shaders/RHI/texture3d.azshader";
  121. const char* sampleName = "Texture3DExample";
  122. auto shader = LoadShader(texture3dShaderFilePath, sampleName);
  123. if (shader == nullptr)
  124. {
  125. return;
  126. }
  127. // Setup the pipeline state descriptor
  128. AZ::RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
  129. const RPI::ShaderVariant& shaderVariant = shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
  130. shaderVariant.ConfigurePipelineState(pipelineStateDescriptor);
  131. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  132. attachmentsBuilder.AddSubpass()
  133. ->RenderTargetAttachment(m_outputFormat);
  134. [[maybe_unused]] AZ::RHI::ResultCode result = attachmentsBuilder.End(pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  135. AZ_Assert(result == AZ::RHI::ResultCode::Success, "Failed to create render attachment layout");
  136. pipelineStateDescriptor.m_inputStreamLayout.SetTopology(AZ::RHI::PrimitiveTopology::TriangleStrip);
  137. pipelineStateDescriptor.m_inputStreamLayout.Finalize();
  138. m_pipelineState = shader->AcquirePipelineState(pipelineStateDescriptor);
  139. if (!m_pipelineState)
  140. {
  141. AZ_Error("Render", false, "Failed to acquire default pipeline state for shader %s", texture3dShaderFilePath);
  142. }
  143. // Create the SRG
  144. m_shaderResourceGroup = CreateShaderResourceGroup(shader, "ImageSrg", sampleName);
  145. // Set the shader input indices
  146. FindShaderInputIndex(&m_texture3dInputIndex, m_shaderResourceGroup, Name("m_texture3D"), sampleName);
  147. FindShaderInputIndex(&m_sliceIndexInputIndex, m_shaderResourceGroup, Name("m_sliceIndex"), sampleName);
  148. FindShaderInputIndex(&m_positionInputIndex, m_shaderResourceGroup, Name("m_position"), sampleName);
  149. FindShaderInputIndex(&m_sizeInputIndex, m_shaderResourceGroup, Name("m_size"), sampleName);
  150. }
  151. // Create the scope producer
  152. {
  153. struct ScopeData
  154. {
  155. };
  156. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  157. {
  158. {
  159. RHI::ImageScopeAttachmentDescriptor desc;
  160. desc.m_attachmentId = m_outputAttachmentId;
  161. frameGraph.UseColorAttachment(desc);
  162. }
  163. frameGraph.SetEstimatedItemCount(1);
  164. };
  165. const auto compileFunction = [this]([[maybe_unused]] const AZ::RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  166. {
  167. // Compile the srg
  168. AZStd::array<float, 2> position = { {0.00f, 0.1f} };
  169. const float ratioYtoX = m_windowSize.m_height / static_cast<float>(m_windowSize.m_width);
  170. AZStd::array<float, 2> size = { {0.7f * ratioYtoX, 0.7f} };
  171. m_shaderResourceGroup->SetImageView(m_texture3dInputIndex, m_imageView.get());
  172. m_shaderResourceGroup->SetConstant<uint32_t>(m_sliceIndexInputIndex, static_cast<uint32_t>(m_sliceIndex));
  173. m_shaderResourceGroup->SetConstant(m_positionInputIndex, position);
  174. m_shaderResourceGroup->SetConstant(m_sizeInputIndex, size);
  175. m_shaderResourceGroup->Compile();
  176. };
  177. const auto executeFunction = [=]([[maybe_unused]] const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  178. {
  179. RHI::CommandList* commandList = context.GetCommandList();
  180. commandList->SetViewports(&m_viewport, 1);
  181. commandList->SetScissors(&m_scissor, 1);
  182. RHI::DrawLinear drawIndexed;
  183. drawIndexed.m_vertexCount = 4;
  184. drawIndexed.m_instanceCount = 1;
  185. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroup->GetRHIShaderResourceGroup() };
  186. // Create the draw item
  187. RHI::DrawItem drawItem;
  188. drawItem.m_arguments = drawIndexed;
  189. drawItem.m_pipelineState = m_pipelineState.get();
  190. drawItem.m_indexBufferView = nullptr;
  191. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  192. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  193. drawItem.m_streamBufferViewCount = 0;
  194. drawItem.m_streamBufferViews = nullptr;
  195. // Add the draw item to the commandlist
  196. commandList->Submit(drawItem);
  197. };
  198. // Create and add the scope producer
  199. m_scopeProducers.emplace_back(aznew RHI::ScopeProducerFunction<
  200. ScopeData,
  201. decltype(prepareFunction),
  202. decltype(compileFunction),
  203. decltype(executeFunction)>(
  204. RHI::ScopeId{ "Texture3d" },
  205. ScopeData{},
  206. prepareFunction,
  207. compileFunction,
  208. executeFunction));
  209. }
  210. AZ::TickBus::Handler::BusConnect();
  211. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  212. m_imguiSidebar.Activate();
  213. }
  214. void Texture3dExampleComponent::Deactivate()
  215. {
  216. m_imguiSidebar.Deactivate();
  217. AZ::TickBus::Handler::BusDisconnect();
  218. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  219. m_scopeProducers.clear();
  220. m_windowContext = nullptr;
  221. m_imageView = nullptr;
  222. m_image = nullptr;
  223. m_imagePool = nullptr;
  224. m_shaderResourceGroup = nullptr;
  225. m_pipelineState = nullptr;
  226. }
  227. void Texture3dExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  228. {
  229. if (m_imguiSidebar.Begin())
  230. {
  231. ImGui::Text("3D image slice index");
  232. for (int32_t i = 0; i < static_cast<int32_t>(m_imageLayout.m_size.m_depth); i++)
  233. {
  234. const AZStd::string label = AZStd::string::format("Image Slice %d", i);
  235. ScriptableImGui::RadioButton(label.c_str(), &m_sliceIndex, i);
  236. }
  237. m_imguiSidebar.End();
  238. }
  239. }
  240. }