MeshInstanceGroupList.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 <Mesh/MeshFeatureProcessor.h>
  9. #include <Mesh/MeshInstanceGroupList.h>
  10. #include <AzCore/std/numeric.h>
  11. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  12. namespace AZ::Render
  13. {
  14. bool MeshInstanceGroupData::UpdateDrawPacket(const RPI::Scene& parentScene, bool forceUpdate)
  15. {
  16. if (m_drawPacket.Update(parentScene, forceUpdate))
  17. {
  18. // Clear any cached draw packets, since they need to be re-created
  19. m_perViewDrawPackets.clear();
  20. for (auto modelDataInstance : m_associatedInstances)
  21. {
  22. modelDataInstance->HandleDrawPacketUpdate(m_key.m_lodIndex, m_key.m_meshIndex, m_drawPacket);
  23. }
  24. return true;
  25. }
  26. return false;
  27. }
  28. bool MeshInstanceGroupData::UpdateShaderOptionFlags()
  29. {
  30. // Shader options are either set or being unspecified (which means use the global value).
  31. // We only set a shader option if ALL instances have the same value. Otherwise, we leave it unspecified.
  32. uint32_t newShaderOptionFlagMask = ~0u; // Defaults to all shaders options being specified.
  33. // We only disable one if we find a different between the instances.
  34. uint32_t newShaderOptionFlags = m_shaderOptionFlags;
  35. if (auto it = m_associatedInstances.begin(); it != m_associatedInstances.end())
  36. {
  37. newShaderOptionFlags = (*it)->GetCullable().m_shaderOptionFlags;
  38. uint32_t lastShaderOptionFlags = newShaderOptionFlags;
  39. for (++it; it != m_associatedInstances.end(); ++it)
  40. {
  41. ModelDataInstance* modelDataInstance = *it;
  42. // If the shader option flag of different intances are different, the mask for the flag is 0, which means the flag is
  43. // unspecified.
  44. newShaderOptionFlagMask &= ~(lastShaderOptionFlags ^ modelDataInstance->GetCullable().m_shaderOptionFlags);
  45. // if the option flag has same value, keep the value.
  46. lastShaderOptionFlags = modelDataInstance->GetCullable().m_shaderOptionFlags;
  47. newShaderOptionFlags &= lastShaderOptionFlags;
  48. }
  49. }
  50. // return ture if the shader option flags or mask changed.
  51. if (newShaderOptionFlags != m_shaderOptionFlags || newShaderOptionFlagMask != m_shaderOptionFlagMask)
  52. {
  53. m_shaderOptionFlags = newShaderOptionFlags;
  54. m_shaderOptionFlagMask = newShaderOptionFlagMask;
  55. return true;
  56. }
  57. return false;
  58. }
  59. void MeshInstanceGroupData::AddAssociatedInstance(ModelDataInstance* instance)
  60. {
  61. AZStd::scoped_lock<AZStd::mutex> scopedLock(m_eventLock);
  62. m_associatedInstances.insert(instance);
  63. }
  64. void MeshInstanceGroupData::RemoveAssociatedInstance(ModelDataInstance* instance)
  65. {
  66. AZStd::scoped_lock<AZStd::mutex> scopedLock(m_eventLock);
  67. m_associatedInstances.erase(instance);
  68. }
  69. MeshInstanceGroupList::InsertResult MeshInstanceGroupList::Add(const MeshInstanceGroupKey& key)
  70. {
  71. // It is not safe to have multiple threads Add and/or Remove at the same time
  72. m_instanceDataConcurrencyChecker.soft_lock();
  73. typename DataMap::iterator it = m_dataMap.find(key);
  74. if (it == m_dataMap.end())
  75. {
  76. // Add the data map entry containing the handle and reference count
  77. IndexMapEntry entry;
  78. entry.m_handle = m_instanceGroupData.emplace();
  79. entry.m_count = 1;
  80. it = m_dataMap.emplace(AZStd::make_pair(key, AZStd::move(entry))).first;
  81. }
  82. else
  83. {
  84. // Data is already known, update the reference count and return the index
  85. it->second.m_count++;
  86. }
  87. // Keep track of the count from the map in the data itself
  88. it->second.m_handle->m_count = it->second.m_count;
  89. m_instanceDataConcurrencyChecker.soft_unlock();
  90. return MeshInstanceGroupList::InsertResult{ it->second.m_handle.GetWeakHandle(), it->second.m_count, static_cast<uint32_t>(m_instanceGroupData.GetPageIndex(it->second.m_handle))};
  91. }
  92. void MeshInstanceGroupList::Remove(const MeshInstanceGroupKey& key)
  93. {
  94. // It is not safe to have multiple threads Add and/or Remove at the same time
  95. m_instanceDataConcurrencyChecker.soft_lock();
  96. typename DataMap::iterator it = m_dataMap.find(key);
  97. if (it == m_dataMap.end())
  98. {
  99. AZ_Assert(false, "Unable to find key in the DataMap");
  100. m_instanceDataConcurrencyChecker.soft_unlock();
  101. return;
  102. }
  103. it->second.m_count--;
  104. if (it->second.m_count == 0)
  105. {
  106. // Remove it from the data map
  107. // The owning handle will go out of scope, which will erase it from the underlying array as well
  108. m_dataMap.erase(it);
  109. }
  110. m_instanceDataConcurrencyChecker.soft_unlock();
  111. }
  112. uint32_t MeshInstanceGroupList::GetInstanceGroupCount() const
  113. {
  114. return static_cast<uint32_t>(m_instanceGroupData.size());
  115. }
  116. auto MeshInstanceGroupList::GetParallelRanges() -> ParallelRanges
  117. {
  118. return m_instanceGroupData.GetParallelRanges();
  119. }
  120. MeshInstanceGroupData& MeshInstanceGroupList::operator[](WeakHandle handle)
  121. {
  122. return *handle;
  123. }
  124. const MeshInstanceGroupData& MeshInstanceGroupList::operator[](WeakHandle handle) const
  125. {
  126. return *handle;
  127. }
  128. } // namespace AZ::Render