RenderStateBucket.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Scene/RenderStateBucket.h>
  6. namespace anki {
  7. RenderStateBucketContainer::~RenderStateBucketContainer()
  8. {
  9. for(RenderingTechnique t : EnumIterable<RenderingTechnique>())
  10. {
  11. for([[maybe_unused]] ExtendedBucket& b : m_buckets[t])
  12. {
  13. ANKI_ASSERT(!b.m_program.isCreated() && b.m_userCount == 0 && b.m_lod0MeshletGroupCount == 0 && b.m_lod0MeshletCount == 0);
  14. }
  15. ANKI_ASSERT(m_bucketActiveUserCount[t] == 0);
  16. ANKI_ASSERT(m_activeBucketCount[t] == 0);
  17. ANKI_ASSERT(m_lod0MeshletGroupCount[t] == 0);
  18. }
  19. }
  20. RenderStateBucketIndex RenderStateBucketContainer::addUser(const RenderStateInfo& state, RenderingTechnique technique, U32 lod0MeshletCount)
  21. {
  22. // Compute state gash
  23. Array<U64, 3> toHash;
  24. toHash[0] = state.m_program->getUuid();
  25. toHash[1] = U64(state.m_primitiveTopology);
  26. toHash[2] = state.m_indexedDrawcall;
  27. const U64 hash = computeHash(toHash.getBegin(), toHash.getSizeInBytes());
  28. const U32 meshletGroupCount = (lod0MeshletCount + (kMeshletGroupSize - 1)) / kMeshletGroupSize;
  29. SceneDynamicArray<ExtendedBucket>& buckets = m_buckets[technique];
  30. RenderStateBucketIndex out;
  31. out.m_technique = technique;
  32. LockGuard lock(m_mtx);
  33. ++m_bucketActiveUserCount[technique];
  34. m_lod0MeshletGroupCount[technique] += meshletGroupCount;
  35. m_lod0MeshletCount[technique] += lod0MeshletCount;
  36. // Search bucket
  37. for(U32 i = 0; i < buckets.getSize(); ++i)
  38. {
  39. if(buckets[i].m_hash == hash)
  40. {
  41. ++buckets[i].m_userCount;
  42. buckets[i].m_lod0MeshletGroupCount += meshletGroupCount;
  43. buckets[i].m_lod0MeshletCount += lod0MeshletCount;
  44. if(buckets[i].m_userCount == 1)
  45. {
  46. ANKI_ASSERT(!buckets[i].m_program.isCreated());
  47. ANKI_ASSERT(buckets[i].m_lod0MeshletGroupCount == meshletGroupCount && buckets[i].m_lod0MeshletCount == lod0MeshletCount);
  48. buckets[i].m_program = state.m_program;
  49. ++m_activeBucketCount[technique];
  50. createPerfOrder(technique);
  51. }
  52. else
  53. {
  54. ANKI_ASSERT(buckets[i].m_program.isCreated());
  55. }
  56. out.m_index = i;
  57. out.m_lod0MeshletCount = lod0MeshletCount;
  58. return out;
  59. }
  60. }
  61. // Bucket not found, create one
  62. ExtendedBucket& newBucket = *buckets.emplaceBack();
  63. newBucket.m_hash = hash;
  64. newBucket.m_indexedDrawcall = state.m_indexedDrawcall;
  65. newBucket.m_primitiveTopology = state.m_primitiveTopology;
  66. newBucket.m_program = state.m_program;
  67. newBucket.m_userCount = 1;
  68. newBucket.m_lod0MeshletGroupCount = meshletGroupCount;
  69. newBucket.m_lod0MeshletCount = lod0MeshletCount;
  70. ++m_activeBucketCount[technique];
  71. createPerfOrder(technique);
  72. out.m_index = buckets.getSize() - 1;
  73. out.m_lod0MeshletCount = lod0MeshletCount;
  74. return out;
  75. }
  76. void RenderStateBucketContainer::removeUser(RenderStateBucketIndex& bucketIndex)
  77. {
  78. if(!bucketIndex.isValid())
  79. {
  80. return;
  81. }
  82. const RenderingTechnique technique = bucketIndex.m_technique;
  83. const U32 idx = bucketIndex.m_index;
  84. const U32 meshletGroupCount = (bucketIndex.m_lod0MeshletCount + (kMeshletGroupSize - 1)) / kMeshletGroupSize;
  85. const U32 meshletCount = bucketIndex.m_lod0MeshletCount;
  86. bucketIndex.invalidate();
  87. LockGuard lock(m_mtx);
  88. ANKI_ASSERT(idx < m_buckets[technique].getSize());
  89. ANKI_ASSERT(m_bucketActiveUserCount[technique] > 0);
  90. --m_bucketActiveUserCount[technique];
  91. ANKI_ASSERT(m_lod0MeshletGroupCount[technique] >= meshletGroupCount);
  92. m_lod0MeshletGroupCount[technique] -= meshletGroupCount;
  93. ANKI_ASSERT(m_lod0MeshletCount[technique] >= meshletCount);
  94. m_lod0MeshletCount[technique] -= meshletCount;
  95. ExtendedBucket& bucket = m_buckets[technique][idx];
  96. ANKI_ASSERT(bucket.m_userCount > 0 && bucket.m_program.isCreated() && bucket.m_lod0MeshletGroupCount >= meshletGroupCount
  97. && bucket.m_lod0MeshletCount >= meshletCount);
  98. --bucket.m_userCount;
  99. bucket.m_lod0MeshletGroupCount -= meshletGroupCount;
  100. bucket.m_lod0MeshletCount -= meshletCount;
  101. if(bucket.m_userCount == 0)
  102. {
  103. // No more users, make sure you release any references
  104. bucket.m_program.reset(nullptr);
  105. ANKI_ASSERT(m_activeBucketCount[technique] > 0);
  106. --m_activeBucketCount[technique];
  107. createPerfOrder(technique);
  108. }
  109. }
  110. void RenderStateBucketContainer::createPerfOrder(RenderingTechnique t)
  111. {
  112. const U32 bucketCount = m_buckets[t].getSize();
  113. m_bucketPerfOrder[t].resize(bucketCount);
  114. for(U32 i = 0; i < bucketCount; ++i)
  115. {
  116. m_bucketPerfOrder[t][i] = i;
  117. }
  118. std::sort(m_bucketPerfOrder[t].getBegin(), m_bucketPerfOrder[t].getBegin() + bucketCount, [&, this](U32 a, U32 b) {
  119. auto getProgramHeaviness = [](const ShaderProgram& p) {
  120. U64 size = U64(p.getShaderBinarySize(ShaderType::kFragment)) << 32u; // Fragment is more important
  121. if(!!(p.getShaderTypes() & ShaderTypeBit::kVertex))
  122. {
  123. size |= p.getShaderBinarySize(ShaderType::kVertex);
  124. }
  125. else
  126. {
  127. ANKI_ASSERT(!!(p.getShaderTypes() & ShaderTypeBit::kMesh));
  128. size |= p.getShaderBinarySize(ShaderType::kMesh);
  129. }
  130. return size;
  131. };
  132. const Bool aIsActive = m_buckets[t][a].m_program.isCreated();
  133. const Bool bIsActive = m_buckets[t][b].m_program.isCreated();
  134. const Bool aHasDiscard = (aIsActive) ? m_buckets[t][a].m_program->hasDiscard() : false;
  135. const Bool bHasDiscard = (bIsActive) ? m_buckets[t][b].m_program->hasDiscard() : false;
  136. const U64 aProgramHeaviness = (aIsActive) ? getProgramHeaviness(*m_buckets[t][a].m_program) : 0;
  137. const U64 bProgramHeaviness = (bIsActive) ? getProgramHeaviness(*m_buckets[t][b].m_program) : 0;
  138. if(aHasDiscard != bHasDiscard)
  139. {
  140. return !aHasDiscard;
  141. }
  142. else
  143. {
  144. return aProgramHeaviness < bProgramHeaviness;
  145. }
  146. });
  147. }
  148. } // end namespace anki