aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--alc/alc.cpp20
-rw-r--r--alc/alu.cpp29
-rw-r--r--alc/backends/base.h10
-rw-r--r--core/device.cpp3
-rw-r--r--core/device.h18
5 files changed, 55 insertions, 25 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp
index 6017e743..ab4cc7ba 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -976,10 +976,18 @@ std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const f
*/
inline void UpdateClockBase(ALCdevice *device)
{
- IncrementRef(device->MixCount);
- device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
- device->SamplesDone = 0;
- IncrementRef(device->MixCount);
+ const auto mixCount = device->MixCount.load(std::memory_order_relaxed);
+ device->MixCount.store(mixCount+1, std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_release);
+
+ auto samplesDone = device->mSamplesDone.load(std::memory_order_relaxed);
+ auto clockBase = device->mClockBase.load(std::memory_order_relaxed);
+
+ clockBase += nanoseconds{seconds{samplesDone}} / device->Frequency;
+ device->mClockBase.store(clockBase, std::memory_order_relaxed);
+ device->mSamplesDone.store(0, std::memory_order_relaxed);
+
+ device->MixCount.store(mixCount+2, std::memory_order_release);
}
/**
@@ -2504,8 +2512,8 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
nanoseconds basecount;
do {
refcount = dev->waitForMix();
- basecount = dev->ClockBase;
- samplecount = dev->SamplesDone;
+ basecount = dev->mClockBase.load(std::memory_order_relaxed);
+ samplecount = dev->mSamplesDone.load(std::memory_order_relaxed);
} while(refcount != ReadRef(dev->MixCount));
basecount += nanoseconds{seconds{samplecount}} / dev->Frequency;
*values = basecount.count();
diff --git a/alc/alu.cpp b/alc/alu.cpp
index e0858b18..23518fa9 100644
--- a/alc/alu.cpp
+++ b/alc/alu.cpp
@@ -1910,8 +1910,9 @@ void ProcessContexts(DeviceBase *device, const uint SamplesToDo)
{
ASSUME(SamplesToDo > 0);
- const nanoseconds curtime{device->ClockBase +
- nanoseconds{seconds{device->SamplesDone}}/device->Frequency};
+ const nanoseconds curtime{device->mClockBase.load(std::memory_order_relaxed) +
+ nanoseconds{seconds{device->mSamplesDone.load(std::memory_order_relaxed)}}/
+ device->Frequency};
for(ContextBase *ctx : *device->mContexts.load(std::memory_order_acquire))
{
@@ -2135,7 +2136,9 @@ uint DeviceBase::renderSamples(const uint numSamples)
buffer.fill(0.0f);
/* Increment the mix count at the start (lsb should now be 1). */
- IncrementRef(MixCount);
+ const auto mixCount = MixCount.load(std::memory_order_relaxed);
+ MixCount.store(mixCount+1, std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_release);
/* Process and mix each context's sources and effects. */
ProcessContexts(this, samplesToDo);
@@ -2144,12 +2147,16 @@ uint DeviceBase::renderSamples(const uint numSamples)
* and added to clock base so that large sample counts don't overflow
* during conversion. This also guarantees a stable conversion.
*/
- SamplesDone += samplesToDo;
- ClockBase += std::chrono::seconds{SamplesDone / Frequency};
- SamplesDone %= Frequency;
+ {
+ auto samplesDone = mSamplesDone.load(std::memory_order_relaxed) + samplesToDo;
+ auto clockBase = mClockBase.load(std::memory_order_relaxed) +
+ std::chrono::seconds{samplesDone/Frequency};
+ mSamplesDone.store(samplesDone%Frequency, std::memory_order_relaxed);
+ mClockBase.store(clockBase, std::memory_order_relaxed);
+ }
/* Increment the mix count at the end (lsb should now be 0). */
- IncrementRef(MixCount);
+ MixCount.store(mixCount+2, std::memory_order_release);
/* Apply any needed post-process for finalizing the Dry mix to the RealOut
* (Ambisonic decode, UHJ encode, etc).
@@ -2225,7 +2232,10 @@ void DeviceBase::renderSamples(void *outBuffer, const uint numSamples, const siz
void DeviceBase::handleDisconnect(const char *msg, ...)
{
- IncrementRef(MixCount);
+ const auto mixCount = MixCount.load(std::memory_order_relaxed);
+ MixCount.store(mixCount+1, std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_release);
+
if(Connected.exchange(false, std::memory_order_acq_rel))
{
AsyncEvent evt{std::in_place_type<AsyncDisconnectEvent>};
@@ -2267,5 +2277,6 @@ void DeviceBase::handleDisconnect(const char *msg, ...)
std::for_each(voicelist.begin(), voicelist.end(), stop_voice);
}
}
- IncrementRef(MixCount);
+
+ MixCount.store(mixCount+2, std::memory_order_release);
}
diff --git a/alc/backends/base.h b/alc/backends/base.h
index e1f53405..f38c1d45 100644
--- a/alc/backends/base.h
+++ b/alc/backends/base.h
@@ -55,14 +55,8 @@ enum class BackendType {
/* Helper to get the current clock time from the device's ClockBase, and
* SamplesDone converted from the sample rate.
*/
-inline std::chrono::nanoseconds GetDeviceClockTime(DeviceBase *device)
-{
- using std::chrono::seconds;
- using std::chrono::nanoseconds;
-
- auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
- return device->ClockBase + ns;
-}
+inline std::chrono::nanoseconds GetDeviceClockTime(const DeviceBase *device) noexcept
+{ return device->getClockTime(); }
/* Helper to get the device latency from the backend, including any fixed
* latency from post-processing.
diff --git a/core/device.cpp b/core/device.cpp
index 2766c5e4..a5edf63c 100644
--- a/core/device.cpp
+++ b/core/device.cpp
@@ -9,6 +9,9 @@
#include "mastering.h"
+static_assert(std::atomic<std::chrono::nanoseconds>::is_always_lock_free);
+
+
al::FlexArray<ContextBase*> DeviceBase::sEmptyContextArray{0u};
diff --git a/core/device.h b/core/device.h
index 8abbef21..842f1d82 100644
--- a/core/device.h
+++ b/core/device.h
@@ -218,8 +218,8 @@ struct DeviceBase {
*/
NfcFilter mNFCtrlFilter{};
- uint SamplesDone{0u};
- std::chrono::nanoseconds ClockBase{0};
+ std::atomic<uint> mSamplesDone{0u};
+ std::atomic<std::chrono::nanoseconds> mClockBase{std::chrono::nanoseconds{}};
std::chrono::nanoseconds FixedLatency{0};
AmbiRotateMatrix mAmbiRotateMatrix{};
@@ -307,6 +307,20 @@ struct DeviceBase {
return refcount;
}
+ /**
+ * Helper to get the current clock time from the device's ClockBase, and
+ * SamplesDone converted from the sample rate. Should only be called while
+ * watching the MixCount.
+ */
+ std::chrono::nanoseconds getClockTime() const noexcept
+ {
+ using std::chrono::seconds;
+ using std::chrono::nanoseconds;
+
+ auto ns = nanoseconds{seconds{mSamplesDone.load(std::memory_order_relaxed)}} / Frequency;
+ return mClockBase.load(std::memory_order_relaxed) + ns;
+ }
+
void ProcessHrtf(const size_t SamplesToDo);
void ProcessAmbiDec(const size_t SamplesToDo);
void ProcessAmbiDecStablized(const size_t SamplesToDo);