Texture3dExampleComponent.cpp 12 KB

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