TextureExampleComponent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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/TextureExampleComponent.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.Reflect/InputStreamLayoutBuilder.h>
  15. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  16. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  17. #include <Atom/RPI.Public/Image/StreamingImagePool.h>
  18. #include <Atom/RPI.Public/Shader/Shader.h>
  19. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  20. #include <AzCore/Serialization/SerializeContext.h>
  21. namespace AtomSampleViewer
  22. {
  23. void TextureExampleComponent::Reflect(AZ::ReflectContext* context)
  24. {
  25. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  26. {
  27. serializeContext->Class<TextureExampleComponent, AZ::Component>()
  28. ->Version(0)
  29. ;
  30. }
  31. }
  32. TextureExampleComponent::TextureExampleComponent()
  33. {
  34. m_supportRHISamplePipeline = true;
  35. }
  36. void TextureExampleComponent::Activate()
  37. {
  38. using namespace AZ;
  39. const RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  40. BufferData bufferData;
  41. const auto positionBufSize = static_cast<uint32_t>(bufferData.m_positions.size() * sizeof(VertexPosition));
  42. const auto indexBufSize = static_cast<uint32_t>(bufferData.m_indices.size() * sizeof(uint16_t));
  43. const auto uvBufSize = static_cast<uint32_t>(bufferData.m_uvs.size() * sizeof(VertexUV));
  44. AZ::RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
  45. {
  46. m_bufferPool = aznew RHI::BufferPool();
  47. RHI::BufferPoolDescriptor bufferPoolDesc;
  48. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  49. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  50. m_bufferPool->Init(bufferPoolDesc);
  51. SetFullScreenRect(bufferData.m_positions.data(), bufferData.m_uvs.data(), bufferData.m_indices.data());
  52. m_positionBuffer = aznew RHI::Buffer();
  53. m_indexBuffer = aznew RHI::Buffer();
  54. m_uvBuffer = aznew RHI::Buffer();
  55. RHI::ResultCode result = RHI::ResultCode::Success;
  56. RHI::BufferInitRequest request;
  57. request.m_buffer = m_positionBuffer.get();
  58. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, positionBufSize };
  59. request.m_initialData = bufferData.m_positions.data();
  60. result = m_bufferPool->InitBuffer(request);
  61. if (result != RHI::ResultCode::Success)
  62. {
  63. AZ_Error("TextureExample", false, "Failed to initialize position buffer with error code %d", result);
  64. return;
  65. }
  66. request.m_buffer = m_indexBuffer.get();
  67. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, indexBufSize };
  68. request.m_initialData = bufferData.m_indices.data();
  69. result = m_bufferPool->InitBuffer(request);
  70. if (result != RHI::ResultCode::Success)
  71. {
  72. AZ_Error("TextureExample", false, "Failed to initialize index buffer with error code %d", result);
  73. return;
  74. }
  75. request.m_buffer = m_uvBuffer.get();
  76. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, uvBufSize };
  77. request.m_initialData = bufferData.m_uvs.data();
  78. result = m_bufferPool->InitBuffer(request);
  79. if (result != RHI::ResultCode::Success)
  80. {
  81. AZ_Error("TextureExample", false, "Failed to initialize uv buffer with error code %d", result);
  82. return;
  83. }
  84. m_geometryView.SetDrawArguments(RHI::DrawIndexed(0, 6, 0));
  85. m_geometryView.SetIndexBufferView({ *m_indexBuffer, 0, indexBufSize, RHI::IndexFormat::Uint16 });
  86. m_geometryView.AddStreamBufferView({
  87. *m_positionBuffer,
  88. 0,
  89. positionBufSize,
  90. sizeof(VertexPosition)
  91. });
  92. m_geometryView.AddStreamBufferView({
  93. *m_uvBuffer,
  94. 0,
  95. uvBufSize,
  96. sizeof(VertexUV)
  97. });
  98. RHI::InputStreamLayoutBuilder layoutBuilder;
  99. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  100. layoutBuilder.AddBuffer()->Channel("UV", RHI::Format::R32G32_FLOAT);
  101. pipelineStateDescriptor.m_inputStreamLayout = layoutBuilder.End();
  102. RHI::ValidateStreamBufferViews(pipelineStateDescriptor.m_inputStreamLayout, m_geometryView, m_geometryView.GetFullStreamBufferIndices());
  103. }
  104. {
  105. const char* triangeShaderFilePath = "Shaders/RHI/texture.azshader";
  106. const char* sampleName = "TextureExample";
  107. auto shader = LoadShader(triangeShaderFilePath, sampleName);
  108. if (shader == nullptr)
  109. return;
  110. auto shaderVariant = shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId);
  111. shaderVariant.ConfigurePipelineState(pipelineStateDescriptor);
  112. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  113. attachmentsBuilder.AddSubpass()
  114. ->RenderTargetAttachment(m_outputFormat);
  115. [[maybe_unused]] AZ::RHI::ResultCode result = attachmentsBuilder.End(pipelineStateDescriptor.m_renderAttachmentConfiguration.m_renderAttachmentLayout);
  116. AZ_Assert(result == AZ::RHI::ResultCode::Success, "Failed to create render attachment layout");
  117. m_pipelineState = shader->AcquirePipelineState(pipelineStateDescriptor);
  118. if (!m_pipelineState)
  119. {
  120. AZ_Error(sampleName, false, "Failed to acquire default pipeline state for shader '%s'", triangeShaderFilePath);
  121. return;
  122. }
  123. const AZ::Name albedoMapShaderInput{ "m_albedoMap" };
  124. const AZ::Name dynamicSamplerShaderInput{ "m_dynamicSampler" };
  125. const AZ::Name useStaticSamplerShaderInput{ "m_useStaticSampler" };
  126. const AZ::Name objectMatrixShaderInput{ "m_objectMatrix" };
  127. const AZ::Name uvMatrixShaderInput{ "m_uvMatrix" };
  128. m_shaderResourceGroup = CreateShaderResourceGroup(shader, "TextureInstanceSrg", sampleName);
  129. FindShaderInputIndex(&m_textureInputIndex, m_shaderResourceGroup, albedoMapShaderInput, sampleName);
  130. FindShaderInputIndex(&m_samplerInputIndex, m_shaderResourceGroup, dynamicSamplerShaderInput, sampleName);
  131. FindShaderInputIndex(&m_useStaticSamplerInputIndex, m_shaderResourceGroup, useStaticSamplerShaderInput, sampleName);
  132. FindShaderInputIndex(&m_objectMatrixInputIndex, m_shaderResourceGroup, objectMatrixShaderInput, sampleName);
  133. FindShaderInputIndex(&m_uvMatrixInputIndex, m_shaderResourceGroup, uvMatrixShaderInput, sampleName);
  134. // Scale and translate the texture quad so we can fit the ImGuiSideBar with the samplers options.
  135. constexpr float scale = 0.7f;
  136. AZ::Matrix4x4 matrix = AZ::Matrix4x4::CreateScale(Vector3(scale, scale, scale)) * AZ::Matrix4x4::CreateTranslation(Vector3(scale - 1.0f, 0, 0));
  137. m_shaderResourceGroup->SetConstant(m_objectMatrixInputIndex, matrix);
  138. }
  139. {
  140. // Load a texture asset from the cache
  141. const char* filePath = "textures/streaming/streaming10.dds.streamingimage";
  142. const char* sampleName = "TextureExample";
  143. auto image = LoadStreamingImage(filePath, sampleName);
  144. if (!m_shaderResourceGroup->SetImage(m_textureInputIndex, image))
  145. {
  146. AZ_Error(sampleName, false, "Failed to set image into shader resource group");
  147. return;
  148. }
  149. }
  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. if (m_updateSRG)
  166. {
  167. AZ::Matrix3x3 uvMatrix = AZ::Matrix3x3::CreateScale(Vector3(m_uvScale.GetX(), m_uvScale.GetY(), 1.0));
  168. uvMatrix.SetElement(0, 2, m_uvOffset.GetX());
  169. uvMatrix.SetElement(1, 2, m_uvOffset.GetY());
  170. // Need to cast to "int" since the SRG is expecting a 4 byte object.
  171. m_shaderResourceGroup->SetConstant(m_useStaticSamplerInputIndex, static_cast<int>(m_useStaticSampler));
  172. m_shaderResourceGroup->SetConstant(m_uvMatrixInputIndex, uvMatrix);
  173. m_shaderResourceGroup->SetSampler(m_samplerInputIndex, m_samplerState);
  174. m_shaderResourceGroup->Compile();
  175. m_updateSRG = false;
  176. }
  177. };
  178. const auto executeFunction = [=](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  179. {
  180. RHI::CommandList* commandList = context.GetCommandList();
  181. commandList->SetViewports(&m_viewport, 1);
  182. commandList->SetScissors(&m_scissor, 1);
  183. const RHI::DeviceShaderResourceGroup* shaderResourceGroups[] = {
  184. m_shaderResourceGroup->GetRHIShaderResourceGroup()->GetDeviceShaderResourceGroup(context.GetDeviceIndex()).get()
  185. };
  186. RHI::DeviceDrawItem drawItem;
  187. drawItem.m_geometryView = m_geometryView.GetDeviceGeometryView(context.GetDeviceIndex());
  188. drawItem.m_streamIndices = m_geometryView.GetFullStreamBufferIndices();
  189. drawItem.m_pipelineState = m_pipelineState->GetDevicePipelineState(context.GetDeviceIndex()).get();
  190. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  191. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  192. commandList->Submit(drawItem);
  193. };
  194. m_scopeProducers.emplace_back(aznew RHI::ScopeProducerFunction<
  195. ScopeData,
  196. decltype(prepareFunction),
  197. decltype(compileFunction),
  198. decltype(executeFunction)>(
  199. RHI::ScopeId{"Texture"},
  200. ScopeData{},
  201. prepareFunction,
  202. compileFunction,
  203. executeFunction));
  204. }
  205. AZ::TickBus::Handler::BusConnect();
  206. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  207. m_imguiSidebar.Activate();
  208. }
  209. void TextureExampleComponent::Deactivate()
  210. {
  211. m_positionBuffer = nullptr;
  212. m_indexBuffer = nullptr;
  213. m_uvBuffer = nullptr;
  214. m_bufferPool = nullptr;
  215. m_pipelineState = nullptr;
  216. m_shaderResourceGroup = nullptr;
  217. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  218. AZ::TickBus::Handler::BusDisconnect();
  219. m_windowContext = nullptr;
  220. m_scopeProducers.clear();
  221. m_imguiSidebar.Deactivate();
  222. }
  223. void TextureExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  224. {
  225. if (m_imguiSidebar.Begin())
  226. {
  227. DrawSamplerSettings();
  228. }
  229. }
  230. void TextureExampleComponent::DrawSamplerSettings()
  231. {
  232. ImGui::Text("UV Settings");
  233. float vec2[2];
  234. m_uvOffset.StoreToFloat2(vec2);
  235. if (ScriptableImGui::SliderFloat2("UV Offset", vec2, -2.0f, 2.0, "%.1f"))
  236. {
  237. m_uvOffset.Set(vec2[0], vec2[1]);
  238. m_updateSRG = true;
  239. }
  240. m_uvScale.StoreToFloat2(vec2);
  241. if (ScriptableImGui::SliderFloat2("UV Scale", vec2, 0, 2, "%.1f"))
  242. {
  243. m_uvScale.Set(vec2[0], vec2[1]);
  244. m_updateSRG = true;
  245. }
  246. ImGui::Separator();
  247. ImGui::NewLine();
  248. ImGui::Text("Dynamic Sampler");
  249. if (ScriptableImGui::Checkbox("Use static sampler", &m_useStaticSampler))
  250. {
  251. m_updateSRG = true;
  252. }
  253. if (!m_useStaticSampler)
  254. {
  255. const AZStd::vector<const char*> addressMode = { "Wrap", "Mirror", "Clamp", "Border", "MirrorOnce" };
  256. int current_item = static_cast<int>(m_samplerState.m_addressU);
  257. if (ScriptableImGui::Combo("Address Mode", &current_item, addressMode.data(), static_cast<int>(addressMode.size())))
  258. {
  259. m_samplerState.m_addressU = m_samplerState.m_addressV = m_samplerState.m_addressW = static_cast<AZ::RHI::AddressMode>(current_item);
  260. m_updateSRG = true;
  261. }
  262. if (m_samplerState.m_addressU == AZ::RHI::AddressMode::Border)
  263. {
  264. const AZStd::vector<const char*> borderColor = { "OpaqueBlack", "TransparentBlack", "OpaqueWhite" };
  265. current_item = static_cast<int>(m_samplerState.m_borderColor);
  266. if (ScriptableImGui::Combo("BorderColor", &current_item, borderColor.data(), static_cast<int>(borderColor.size())))
  267. {
  268. m_samplerState.m_borderColor = static_cast<AZ::RHI::BorderColor>(current_item);
  269. m_updateSRG = true;
  270. }
  271. }
  272. }
  273. m_imguiSidebar.End();
  274. }
  275. }