MorphTargetDispatchItem.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 <MorphTargets/MorphTargetDispatchItem.h>
  9. #include <SkinnedMesh/SkinnedMeshFeatureProcessor.h>
  10. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  11. #include <Atom/RPI.Public/Shader/Shader.h>
  12. #include <Atom/RPI.Public/Model/ModelLod.h>
  13. #include <Atom/RPI.Public/Buffer/Buffer.h>
  14. #include <Atom/RPI.Public/RPIUtils.h>
  15. #include <Atom/RHI/Factory.h>
  16. #include <Atom/RHI/DeviceBufferView.h>
  17. #include <limits>
  18. namespace AZ
  19. {
  20. namespace Render
  21. {
  22. MorphTargetDispatchItem::MorphTargetDispatchItem(
  23. const AZStd::intrusive_ptr<MorphTargetInputBuffers> inputBuffers,
  24. const MorphTargetComputeMetaData& morphTargetComputeMetaData,
  25. SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor,
  26. MorphTargetInstanceMetaData morphInstanceMetaData,
  27. float morphDeltaIntegerEncoding)
  28. : m_dispatchItem(RHI::MultiDevice::AllDevices)
  29. , m_inputBuffers(inputBuffers)
  30. , m_morphTargetComputeMetaData(morphTargetComputeMetaData)
  31. , m_morphInstanceMetaData(morphInstanceMetaData)
  32. , m_accumulatedDeltaIntegerEncoding(morphDeltaIntegerEncoding)
  33. {
  34. m_morphTargetShader = skinnedMeshFeatureProcessor->GetMorphTargetShader();
  35. RPI::ShaderReloadNotificationBus::Handler::BusConnect(m_morphTargetShader->GetAssetId());
  36. }
  37. MorphTargetDispatchItem::~MorphTargetDispatchItem()
  38. {
  39. RPI::ShaderReloadNotificationBus::Handler::BusDisconnect();
  40. }
  41. bool MorphTargetDispatchItem::Init()
  42. {
  43. if (!m_morphTargetShader)
  44. {
  45. AZ_Error("MorphTargetDispatchItem", false, "Cannot initialize a MorphTargetDispatchItem with a null shader");
  46. return false;
  47. }
  48. AZ::RPI::ShaderOptionGroup shaderOptionGroup = m_morphTargetShader->CreateShaderOptionGroup();
  49. // In case there are several options you don't care about, it's good practice to initialize them with default values.
  50. shaderOptionGroup.SetUnspecifiedToDefaultValues();
  51. // Get the shader variant and instance SRG
  52. RPI::ShaderReloadNotificationBus::Handler::BusConnect(m_morphTargetShader->GetAssetId());
  53. const RPI::ShaderVariant& shaderVariant = m_morphTargetShader->GetVariant(shaderOptionGroup.GetShaderVariantId());
  54. if (!InitPerInstanceSRG())
  55. {
  56. return false;
  57. }
  58. if (shaderVariant.UseKeyFallback() && m_instanceSrg->HasShaderVariantKeyFallbackEntry())
  59. {
  60. m_instanceSrg->SetShaderVariantKeyFallbackValue(shaderOptionGroup.GetShaderVariantKeyFallbackValue());
  61. }
  62. RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor;
  63. shaderVariant.ConfigurePipelineState(pipelineStateDescriptor, shaderOptionGroup);
  64. InitRootConstants(pipelineStateDescriptor.m_pipelineLayoutDescriptor->GetRootConstantsLayout());
  65. m_dispatchItem.SetPipelineState(m_morphTargetShader->AcquirePipelineState(pipelineStateDescriptor));
  66. // Get the threads-per-group values from the compute shader [numthreads(x,y,z)]
  67. RHI::DispatchDirect arguments;
  68. const auto outcome = RPI::GetComputeShaderNumThreads(m_morphTargetShader->GetAsset(), arguments);
  69. if (!outcome.IsSuccess())
  70. {
  71. AZ_Error("MorphTargetDispatchItem", false, outcome.GetError().c_str());
  72. }
  73. arguments.m_totalNumberOfThreadsX = m_morphTargetComputeMetaData.m_vertexCount;
  74. arguments.m_totalNumberOfThreadsY = 1;
  75. arguments.m_totalNumberOfThreadsZ = 1;
  76. m_dispatchItem.SetArguments(arguments);
  77. return true;
  78. }
  79. bool MorphTargetDispatchItem::InitPerInstanceSRG()
  80. {
  81. auto perInstanceSrgLayout = m_morphTargetShader->FindShaderResourceGroupLayout(AZ::Name{ "MorphTargetInstanceSrg" });
  82. if (!perInstanceSrgLayout)
  83. {
  84. AZ_Error("MorphTargetDispatchItem", false, "Failed to get shader resource group layout");
  85. return false;
  86. }
  87. m_instanceSrg = RPI::ShaderResourceGroup::Create(m_morphTargetShader->GetAsset(), m_morphTargetShader->GetSupervariantIndex(), perInstanceSrgLayout->GetName());
  88. if (!m_instanceSrg)
  89. {
  90. AZ_Error("MorphTargetDispatchItem", false, "Failed to create shader resource group for morph target");
  91. return false;
  92. }
  93. m_inputBuffers->SetBufferViewsOnShaderResourceGroup(m_instanceSrg);
  94. m_instanceSrg->Compile();
  95. m_dispatchItem.SetUniqueShaderResourceGroup(m_instanceSrg->GetRHIShaderResourceGroup());
  96. return true;
  97. }
  98. void MorphTargetDispatchItem::InitRootConstants(const RHI::ConstantsLayout* rootConstantsLayout)
  99. {
  100. auto vertexCountIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_vertexCount" });
  101. AZ_Error("MorphTargetDispatchItem", vertexCountIndex.IsValid(), "Could not find root constant 's_vertexCount' in the shader");
  102. auto positionOffsetIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_targetPositionOffset" });
  103. AZ_Error("MorphTargetDispatchItem", positionOffsetIndex.IsValid(), "Could not find root constant 's_targetPositionOffset' in the shader");
  104. auto normalOffsetIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_targetNormalOffset" });
  105. AZ_Error("MorphTargetDispatchItem", normalOffsetIndex.IsValid(), "Could not find root constant 's_targetNormalOffset' in the shader");
  106. auto tangentOffsetIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_targetTangentOffset" });
  107. AZ_Error("MorphTargetDispatchItem", tangentOffsetIndex.IsValid(), "Could not find root constant 's_targetTangentOffset' in the shader");
  108. auto bitangentOffsetIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_targetBitangentOffset" });
  109. AZ_Error("MorphTargetDispatchItem", bitangentOffsetIndex.IsValid(), "Could not find root constant 's_targetBitangentOffset' in the shader");
  110. auto minIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_min" });
  111. AZ_Error("MorphTargetDispatchItem", minIndex.IsValid(), "Could not find root constant 's_min' in the shader");
  112. auto maxIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_max" });
  113. AZ_Error("MorphTargetDispatchItem", maxIndex.IsValid(), "Could not find root constant 's_max' in the shader");
  114. auto morphDeltaIntegerEncodingIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_accumulatedDeltaIntegerEncoding" });
  115. AZ_Error("MorphTargetDispatchItem", morphDeltaIntegerEncodingIndex.IsValid(), "Could not find root constant 's_accumulatedDeltaIntegerEncoding' in the shader");
  116. m_weightIndex = rootConstantsLayout->FindShaderInputIndex(AZ::Name{ "s_weight" });
  117. AZ_Error("MorphTargetDispatchItem", m_weightIndex.IsValid(), "Could not find root constant 's_weight' in the shader");
  118. m_rootConstantData = AZ::RHI::ConstantsData(rootConstantsLayout);
  119. m_rootConstantData.SetConstant(minIndex, m_morphTargetComputeMetaData.m_minDelta);
  120. m_rootConstantData.SetConstant(maxIndex, m_morphTargetComputeMetaData.m_maxDelta);
  121. m_rootConstantData.SetConstant(morphDeltaIntegerEncodingIndex, m_accumulatedDeltaIntegerEncoding);
  122. m_rootConstantData.SetConstant(m_weightIndex, 0.0f);
  123. m_rootConstantData.SetConstant(vertexCountIndex, m_morphTargetComputeMetaData.m_vertexCount);
  124. // The buffer is using 32-bit integers, so divide the offset by 4 here so it doesn't have to be done in the shader
  125. m_rootConstantData.SetConstant(positionOffsetIndex, m_morphInstanceMetaData.m_accumulatedPositionDeltaOffsetInBytes / 4);
  126. m_rootConstantData.SetConstant(normalOffsetIndex, m_morphInstanceMetaData.m_accumulatedNormalDeltaOffsetInBytes / 4);
  127. m_rootConstantData.SetConstant(tangentOffsetIndex, m_morphInstanceMetaData.m_accumulatedTangentDeltaOffsetInBytes / 4);
  128. m_rootConstantData.SetConstant(bitangentOffsetIndex, m_morphInstanceMetaData.m_accumulatedBitangentDeltaOffsetInBytes / 4);
  129. m_dispatchItem.SetRootConstantSize(static_cast<uint8_t>(m_rootConstantData.GetConstantData().size()));
  130. m_dispatchItem.SetRootConstants(m_rootConstantData.GetConstantData().data());
  131. }
  132. void MorphTargetDispatchItem::SetWeight(float weight)
  133. {
  134. m_rootConstantData.SetConstant(m_weightIndex, weight);
  135. m_dispatchItem.SetRootConstants(m_rootConstantData.GetConstantData().data());
  136. }
  137. float MorphTargetDispatchItem::GetWeight() const
  138. {
  139. return m_rootConstantData.GetConstant<float>(m_weightIndex);
  140. }
  141. const RHI::DispatchItem& MorphTargetDispatchItem::GetRHIDispatchItem() const
  142. {
  143. return m_dispatchItem;
  144. }
  145. void MorphTargetDispatchItem::OnShaderReinitialized([[maybe_unused]] const RPI::Shader& shader)
  146. {
  147. if (!Init())
  148. {
  149. AZ_Error("MorphTargetDispatchItem", false, "Failed to re-initialize after the shader was re-loaded.");
  150. }
  151. }
  152. void MorphTargetDispatchItem::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset<RPI::ShaderAsset>& shaderAsset)
  153. {
  154. if (!Init())
  155. {
  156. AZ_Error("MorphTargetDispatchItem", false, "Failed to re-initialize after the shader asset was re-loaded.");
  157. }
  158. }
  159. void MorphTargetDispatchItem::OnShaderVariantReinitialized(const RPI::ShaderVariant&)
  160. {
  161. if (!Init())
  162. {
  163. AZ_Error("MorphTargetDispatchItem", false, "Failed to re-initialize after the shader variant was loaded.");
  164. }
  165. }
  166. } // namespace Render
  167. } // namespace AZ