]> git.tdb.fi Git - ext/openal.git/blob - core/context.cpp
Tweak some types to work around an MSVC compile error
[ext/openal.git] / core / context.cpp
1
2 #include "config.h"
3
4 #include <cassert>
5 #include <memory>
6
7 #include "async_event.h"
8 #include "context.h"
9 #include "device.h"
10 #include "effectslot.h"
11 #include "logging.h"
12 #include "ringbuffer.h"
13 #include "voice.h"
14 #include "voice_change.h"
15
16
17 #ifdef __cpp_lib_atomic_is_always_lock_free
18 static_assert(std::atomic<ContextBase::AsyncEventBitset>::is_always_lock_free, "atomic<bitset> isn't lock-free");
19 #endif
20
21 ContextBase::ContextBase(DeviceBase *device) : mDevice{device}
22 { assert(mEnabledEvts.is_lock_free()); }
23
24 ContextBase::~ContextBase()
25 {
26     size_t count{0};
27     ContextProps *cprops{mParams.ContextUpdate.exchange(nullptr, std::memory_order_relaxed)};
28     if(cprops)
29     {
30         ++count;
31         delete cprops;
32     }
33     cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire);
34     while(cprops)
35     {
36         std::unique_ptr<ContextProps> old{cprops};
37         cprops = old->next.load(std::memory_order_relaxed);
38         ++count;
39     }
40     TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s");
41
42     count = 0;
43     EffectSlotProps *eprops{mFreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)};
44     while(eprops)
45     {
46         std::unique_ptr<EffectSlotProps> old{eprops};
47         eprops = old->next.load(std::memory_order_relaxed);
48         ++count;
49     }
50     TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
51
52     if(EffectSlotArray *curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)})
53     {
54         al::destroy_n(curarray->end(), curarray->size());
55         delete curarray;
56     }
57
58     delete mVoices.exchange(nullptr, std::memory_order_relaxed);
59
60     if(mAsyncEvents)
61     {
62         count = 0;
63         auto evt_vec = mAsyncEvents->getReadVector();
64         if(evt_vec.first.len > 0)
65         {
66             al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), evt_vec.first.len);
67             count += evt_vec.first.len;
68         }
69         if(evt_vec.second.len > 0)
70         {
71             al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.second.buf), evt_vec.second.len);
72             count += evt_vec.second.len;
73         }
74         if(count > 0)
75             TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s");
76         mAsyncEvents->readAdvance(count);
77     }
78 }
79
80
81 void ContextBase::allocVoiceChanges()
82 {
83     constexpr size_t clustersize{128};
84
85     VoiceChangeCluster cluster{std::make_unique<VoiceChange[]>(clustersize)};
86     for(size_t i{1};i < clustersize;++i)
87         cluster[i-1].mNext.store(std::addressof(cluster[i]), std::memory_order_relaxed);
88     cluster[clustersize-1].mNext.store(mVoiceChangeTail, std::memory_order_relaxed);
89
90     mVoiceChangeClusters.emplace_back(std::move(cluster));
91     mVoiceChangeTail = mVoiceChangeClusters.back().get();
92 }
93
94 void ContextBase::allocVoiceProps()
95 {
96     constexpr size_t clustersize{32};
97
98     TRACE("Increasing allocated voice properties to %zu\n",
99         (mVoicePropClusters.size()+1) * clustersize);
100
101     VoicePropsCluster cluster{std::make_unique<VoicePropsItem[]>(clustersize)};
102     for(size_t i{1};i < clustersize;++i)
103         cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
104     mVoicePropClusters.emplace_back(std::move(cluster));
105
106     VoicePropsItem *oldhead{mFreeVoiceProps.load(std::memory_order_acquire)};
107     do {
108         mVoicePropClusters.back()[clustersize-1].next.store(oldhead, std::memory_order_relaxed);
109     } while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back().get(),
110         std::memory_order_acq_rel, std::memory_order_acquire) == false);
111 }
112
113 void ContextBase::allocVoices(size_t addcount)
114 {
115     constexpr size_t clustersize{32};
116     /* Convert element count to cluster count. */
117     addcount = (addcount+(clustersize-1)) / clustersize;
118
119     if(addcount >= std::numeric_limits<int>::max()/clustersize - mVoiceClusters.size())
120         throw std::runtime_error{"Allocating too many voices"};
121     const size_t totalcount{(mVoiceClusters.size()+addcount) * clustersize};
122     TRACE("Increasing allocated voices to %zu\n", totalcount);
123
124     auto newarray = VoiceArray::Create(totalcount);
125     while(addcount)
126     {
127         mVoiceClusters.emplace_back(std::make_unique<Voice[]>(clustersize));
128         --addcount;
129     }
130
131     auto voice_iter = newarray->begin();
132     for(VoiceCluster &cluster : mVoiceClusters)
133     {
134         for(size_t i{0};i < clustersize;++i)
135             *(voice_iter++) = &cluster[i];
136     }
137
138     if(auto *oldvoices = mVoices.exchange(newarray.release(), std::memory_order_acq_rel))
139     {
140         mDevice->waitForMix();
141         delete oldvoices;
142     }
143 }
144
145
146 EffectSlot *ContextBase::getEffectSlot()
147 {
148     for(auto& cluster : mEffectSlotClusters)
149     {
150         for(size_t i{0};i < EffectSlotClusterSize;++i)
151         {
152             if(!cluster[i].InUse)
153                 return &cluster[i];
154         }
155     }
156
157     if(1 >= std::numeric_limits<int>::max()/EffectSlotClusterSize - mEffectSlotClusters.size())
158         throw std::runtime_error{"Allocating too many effect slots"};
159     const size_t totalcount{(mEffectSlotClusters.size()+1) * EffectSlotClusterSize};
160     TRACE("Increasing allocated effect slots to %zu\n", totalcount);
161
162     mEffectSlotClusters.emplace_back(std::make_unique<EffectSlot[]>(EffectSlotClusterSize));
163     return getEffectSlot();
164 }