context.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #include "config.h"
  2. #include <cassert>
  3. #include <functional>
  4. #include <limits>
  5. #include <memory>
  6. #include <stdexcept>
  7. #include <utility>
  8. #include "async_event.h"
  9. #include "context.h"
  10. #include "device.h"
  11. #include "effectslot.h"
  12. #include "logging.h"
  13. #include "ringbuffer.h"
  14. #include "voice.h"
  15. #include "voice_change.h"
  16. #ifdef __cpp_lib_atomic_is_always_lock_free
  17. static_assert(std::atomic<ContextBase::AsyncEventBitset>::is_always_lock_free, "atomic<bitset> isn't lock-free");
  18. #endif
  19. ContextBase::ContextBase(DeviceBase *device) : mDevice{device}
  20. { assert(mEnabledEvts.is_lock_free()); }
  21. ContextBase::~ContextBase()
  22. {
  23. mActiveAuxSlots.store(nullptr, std::memory_order_relaxed);
  24. mVoices.store(nullptr, std::memory_order_relaxed);
  25. if(mAsyncEvents)
  26. {
  27. size_t count{0};
  28. auto evt_vec = mAsyncEvents->getReadVector();
  29. if(evt_vec.first.len > 0)
  30. {
  31. std::destroy_n(std::launder(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)),
  32. evt_vec.first.len);
  33. count += evt_vec.first.len;
  34. }
  35. if(evt_vec.second.len > 0)
  36. {
  37. std::destroy_n(std::launder(reinterpret_cast<AsyncEvent*>(evt_vec.second.buf)),
  38. evt_vec.second.len);
  39. count += evt_vec.second.len;
  40. }
  41. if(count > 0)
  42. TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s");
  43. mAsyncEvents->readAdvance(count);
  44. }
  45. }
  46. void ContextBase::allocVoiceChanges()
  47. {
  48. static constexpr size_t clustersize{std::tuple_size_v<VoiceChangeCluster::element_type>};
  49. VoiceChangeCluster clusterptr{std::make_unique<VoiceChangeCluster::element_type>()};
  50. const auto cluster = al::span{*clusterptr};
  51. for(size_t i{1};i < clustersize;++i)
  52. cluster[i-1].mNext.store(std::addressof(cluster[i]), std::memory_order_relaxed);
  53. cluster[clustersize-1].mNext.store(mVoiceChangeTail, std::memory_order_relaxed);
  54. mVoiceChangeClusters.emplace_back(std::move(clusterptr));
  55. mVoiceChangeTail = mVoiceChangeClusters.back()->data();
  56. }
  57. void ContextBase::allocVoiceProps()
  58. {
  59. static constexpr size_t clustersize{std::tuple_size_v<VoicePropsCluster::element_type>};
  60. TRACE("Increasing allocated voice properties to %zu\n",
  61. (mVoicePropClusters.size()+1) * clustersize);
  62. auto clusterptr = std::make_unique<VoicePropsCluster::element_type>();
  63. auto cluster = al::span{*clusterptr};
  64. for(size_t i{1};i < clustersize;++i)
  65. cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
  66. mVoicePropClusters.emplace_back(std::move(clusterptr));
  67. VoicePropsItem *oldhead{mFreeVoiceProps.load(std::memory_order_acquire)};
  68. do {
  69. mVoicePropClusters.back()->back().next.store(oldhead, std::memory_order_relaxed);
  70. } while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back()->data(),
  71. std::memory_order_acq_rel, std::memory_order_acquire) == false);
  72. }
  73. void ContextBase::allocVoices(size_t addcount)
  74. {
  75. static constexpr size_t clustersize{std::tuple_size_v<VoiceCluster::element_type>};
  76. /* Convert element count to cluster count. */
  77. addcount = (addcount+(clustersize-1)) / clustersize;
  78. if(!addcount)
  79. {
  80. if(!mVoiceClusters.empty())
  81. return;
  82. ++addcount;
  83. }
  84. if(addcount >= std::numeric_limits<int>::max()/clustersize - mVoiceClusters.size())
  85. throw std::runtime_error{"Allocating too many voices"};
  86. const size_t totalcount{(mVoiceClusters.size()+addcount) * clustersize};
  87. TRACE("Increasing allocated voices to %zu\n", totalcount);
  88. while(addcount)
  89. {
  90. mVoiceClusters.emplace_back(std::make_unique<VoiceCluster::element_type>());
  91. --addcount;
  92. }
  93. auto newarray = VoiceArray::Create(totalcount);
  94. auto voice_iter = newarray->begin();
  95. for(VoiceCluster &cluster : mVoiceClusters)
  96. voice_iter = std::transform(cluster->begin(), cluster->end(), voice_iter,
  97. [](Voice &voice) noexcept -> Voice* { return &voice; });
  98. if(auto oldvoices = mVoices.exchange(std::move(newarray), std::memory_order_acq_rel))
  99. std::ignore = mDevice->waitForMix();
  100. }
  101. void ContextBase::allocEffectSlotProps()
  102. {
  103. static constexpr size_t clustersize{std::tuple_size_v<EffectSlotPropsCluster::element_type>};
  104. TRACE("Increasing allocated effect slot properties to %zu\n",
  105. (mEffectSlotPropClusters.size()+1) * clustersize);
  106. auto clusterptr = std::make_unique<EffectSlotPropsCluster::element_type>();
  107. auto cluster = al::span{*clusterptr};
  108. for(size_t i{1};i < clustersize;++i)
  109. cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
  110. auto *newcluster = mEffectSlotPropClusters.emplace_back(std::move(clusterptr)).get();
  111. EffectSlotProps *oldhead{mFreeEffectSlotProps.load(std::memory_order_acquire)};
  112. do {
  113. newcluster->back().next.store(oldhead, std::memory_order_relaxed);
  114. } while(mFreeEffectSlotProps.compare_exchange_weak(oldhead, newcluster->data(),
  115. std::memory_order_acq_rel, std::memory_order_acquire) == false);
  116. }
  117. EffectSlot *ContextBase::getEffectSlot()
  118. {
  119. for(auto& clusterptr : mEffectSlotClusters)
  120. {
  121. const auto cluster = al::span{*clusterptr};
  122. auto iter = std::find_if_not(cluster.begin(), cluster.end(),
  123. std::mem_fn(&EffectSlot::InUse));
  124. if(iter != cluster.end()) return al::to_address(iter);
  125. }
  126. auto clusterptr = std::make_unique<EffectSlotCluster::element_type>();
  127. if(1 >= std::numeric_limits<int>::max()/clusterptr->size() - mEffectSlotClusters.size())
  128. throw std::runtime_error{"Allocating too many effect slots"};
  129. const size_t totalcount{(mEffectSlotClusters.size()+1) * clusterptr->size()};
  130. TRACE("Increasing allocated effect slots to %zu\n", totalcount);
  131. mEffectSlotClusters.emplace_back(std::move(clusterptr));
  132. return mEffectSlotClusters.back()->data();
  133. }
  134. void ContextBase::allocContextProps()
  135. {
  136. static constexpr size_t clustersize{std::tuple_size_v<ContextPropsCluster::element_type>};
  137. TRACE("Increasing allocated context properties to %zu\n",
  138. (mContextPropClusters.size()+1) * clustersize);
  139. auto clusterptr = std::make_unique<ContextPropsCluster::element_type>();
  140. auto cluster = al::span{*clusterptr};
  141. for(size_t i{1};i < clustersize;++i)
  142. cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
  143. auto *newcluster = mContextPropClusters.emplace_back(std::move(clusterptr)).get();
  144. ContextProps *oldhead{mFreeContextProps.load(std::memory_order_acquire)};
  145. do {
  146. newcluster->back().next.store(oldhead, std::memory_order_relaxed);
  147. } while(mFreeContextProps.compare_exchange_weak(oldhead, newcluster->data(),
  148. std::memory_order_acq_rel, std::memory_order_acquire) == false);
  149. }