TextureExampleComponent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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/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 TextureExampleComponent::Reflect(AZ::ReflectContext* context)
  26. {
  27. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  28. {
  29. serializeContext->Class<TextureExampleComponent, AZ::Component>()
  30. ->Version(0)
  31. ;
  32. }
  33. }
  34. TextureExampleComponent::TextureExampleComponent()
  35. {
  36. m_supportRHISamplePipeline = true;
  37. }
  38. void TextureExampleComponent::Activate()
  39. {
  40. using namespace AZ;
  41. const RHI::Ptr<RHI::Device> device = Utils::GetRHIDevice();
  42. BufferData bufferData;
  43. const auto positionBufSize = static_cast<uint32_t>(bufferData.m_positions.size() * sizeof(VertexPosition));
  44. const auto indexBufSize = static_cast<uint32_t>(bufferData.m_indices.size() * sizeof(uint16_t));
  45. const auto uvBufSize = static_cast<uint32_t>(bufferData.m_uvs.size() * sizeof(VertexUV));
  46. AZ::RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
  47. {
  48. m_bufferPool = RHI::Factory::Get().CreateBufferPool();
  49. RHI::BufferPoolDescriptor bufferPoolDesc;
  50. bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  51. bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  52. m_bufferPool->Init(*device, bufferPoolDesc);
  53. SetFullScreenRect(bufferData.m_positions.data(), bufferData.m_uvs.data(), bufferData.m_indices.data());
  54. m_positionBuffer = RHI::Factory::Get().CreateBuffer();
  55. m_indexBuffer = RHI::Factory::Get().CreateBuffer();
  56. m_uvBuffer = RHI::Factory::Get().CreateBuffer();
  57. RHI::ResultCode result = RHI::ResultCode::Success;
  58. RHI::BufferInitRequest request;
  59. request.m_buffer = m_positionBuffer.get();
  60. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, positionBufSize };
  61. request.m_initialData = bufferData.m_positions.data();
  62. result = m_bufferPool->InitBuffer(request);
  63. if (result != RHI::ResultCode::Success)
  64. {
  65. AZ_Error("TextureExample", false, "Failed to initialize position buffer with error code %d", result);
  66. return;
  67. }
  68. request.m_buffer = m_indexBuffer.get();
  69. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, indexBufSize };
  70. request.m_initialData = bufferData.m_indices.data();
  71. result = m_bufferPool->InitBuffer(request);
  72. if (result != RHI::ResultCode::Success)
  73. {
  74. AZ_Error("TextureExample", false, "Failed to initialize index buffer with error code %d", result);
  75. return;
  76. }
  77. request.m_buffer = m_uvBuffer.get();
  78. request.m_descriptor = RHI::BufferDescriptor{ RHI::BufferBindFlags::InputAssembly, uvBufSize };
  79. request.m_initialData = bufferData.m_uvs.data();
  80. result = m_bufferPool->InitBuffer(request);
  81. if (result != RHI::ResultCode::Success)
  82. {
  83. AZ_Error("TextureExample", false, "Failed to initialize uv buffer with error code %d", result);
  84. return;
  85. }
  86. m_streamBufferViews[0] = {
  87. *m_positionBuffer,
  88. 0,
  89. positionBufSize,
  90. sizeof(VertexPosition)
  91. };
  92. m_streamBufferViews[1] = {
  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_streamBufferViews);
  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::IndexBufferView indexBufferView =
  184. {
  185. *m_indexBuffer,
  186. 0,
  187. indexBufSize,
  188. RHI::IndexFormat::Uint16
  189. };
  190. RHI::DrawIndexed drawIndexed;
  191. drawIndexed.m_indexCount = 6;
  192. drawIndexed.m_instanceCount = 1;
  193. const RHI::ShaderResourceGroup* shaderResourceGroups[] = { m_shaderResourceGroup->GetRHIShaderResourceGroup() };
  194. RHI::DrawItem drawItem;
  195. drawItem.m_arguments = drawIndexed;
  196. drawItem.m_pipelineState = m_pipelineState.get();
  197. drawItem.m_indexBufferView = &indexBufferView;
  198. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  199. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  200. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(m_streamBufferViews.size());
  201. drawItem.m_streamBufferViews = m_streamBufferViews.data();
  202. commandList->Submit(drawItem);
  203. };
  204. m_scopeProducers.emplace_back(aznew RHI::ScopeProducerFunction<
  205. ScopeData,
  206. decltype(prepareFunction),
  207. decltype(compileFunction),
  208. decltype(executeFunction)>(
  209. RHI::ScopeId{"Texture"},
  210. ScopeData{},
  211. prepareFunction,
  212. compileFunction,
  213. executeFunction));
  214. }
  215. AZ::TickBus::Handler::BusConnect();
  216. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  217. m_imguiSidebar.Activate();
  218. }
  219. void TextureExampleComponent::Deactivate()
  220. {
  221. m_positionBuffer = nullptr;
  222. m_indexBuffer = nullptr;
  223. m_uvBuffer = nullptr;
  224. m_bufferPool = nullptr;
  225. m_pipelineState = nullptr;
  226. m_shaderResourceGroup = nullptr;
  227. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  228. AZ::TickBus::Handler::BusDisconnect();
  229. m_windowContext = nullptr;
  230. m_scopeProducers.clear();
  231. m_imguiSidebar.Deactivate();
  232. }
  233. void TextureExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  234. {
  235. if (m_imguiSidebar.Begin())
  236. {
  237. DrawSamplerSettings();
  238. }
  239. }
  240. void TextureExampleComponent::DrawSamplerSettings()
  241. {
  242. ImGui::Text("UV Settings");
  243. float vec2[2];
  244. m_uvOffset.StoreToFloat2(vec2);
  245. if (ScriptableImGui::SliderFloat2("UV Offset", vec2, -2.0f, 2.0, "%.1f"))
  246. {
  247. m_uvOffset.Set(vec2[0], vec2[1]);
  248. m_updateSRG = true;
  249. }
  250. m_uvScale.StoreToFloat2(vec2);
  251. if (ScriptableImGui::SliderFloat2("UV Scale", vec2, 0, 2, "%.1f"))
  252. {
  253. m_uvScale.Set(vec2[0], vec2[1]);
  254. m_updateSRG = true;
  255. }
  256. ImGui::Separator();
  257. ImGui::NewLine();
  258. ImGui::Text("Dynamic Sampler");
  259. if (ScriptableImGui::Checkbox("Use static sampler", &m_useStaticSampler))
  260. {
  261. m_updateSRG = true;
  262. }
  263. if (!m_useStaticSampler)
  264. {
  265. const AZStd::vector<const char*> addressMode = { "Wrap", "Mirror", "Clamp", "Border", "MirrorOnce" };
  266. int current_item = static_cast<int>(m_samplerState.m_addressU);
  267. if (ScriptableImGui::Combo("Address Mode", &current_item, addressMode.data(), static_cast<int>(addressMode.size())))
  268. {
  269. m_samplerState.m_addressU = m_samplerState.m_addressV = m_samplerState.m_addressW = static_cast<AZ::RHI::AddressMode>(current_item);
  270. m_updateSRG = true;
  271. }
  272. if (m_samplerState.m_addressU == AZ::RHI::AddressMode::Border)
  273. {
  274. const AZStd::vector<const char*> borderColor = { "OpaqueBlack", "TransparentBlack", "OpaqueWhite" };
  275. current_item = static_cast<int>(m_samplerState.m_borderColor);
  276. if (ScriptableImGui::Combo("BorderColor", &current_item, borderColor.data(), static_cast<int>(borderColor.size())))
  277. {
  278. m_samplerState.m_borderColor = static_cast<AZ::RHI::BorderColor>(current_item);
  279. m_updateSRG = true;
  280. }
  281. }
  282. }
  283. m_imguiSidebar.End();
  284. }
  285. }