Skip to content

Commit

Permalink
Rework SharedDevice management a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
kcat committed Apr 16, 2023
1 parent a146cac commit 85aadb8
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 79 deletions.
91 changes: 45 additions & 46 deletions src/dsoundoal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ std::optional<DWORD> GetSpeakerConfig(IMMDevice *device, const GUID &devid)
return speakerconf;
}

ds::expected<std::unique_ptr<SharedDevice>,HRESULT> CreateDeviceShare(GUID &guid)
ds::expected<std::unique_ptr<SharedDevice>,HRESULT> CreateDeviceShare(const GUID &guid)
{
TRACE("CreateDeviceShare Creating shared device %s\n", GuidPrinter{guid}.c_str());

Expand Down Expand Up @@ -220,8 +220,7 @@ ds::expected<std::unique_ptr<SharedDevice>,HRESULT> CreateDeviceShare(GUID &guid

const DWORD maxHw{totalSources > MaxHwSources*2 ? MaxHwSources : (MaxHwSources/2)};

auto shared = std::make_unique<SharedDevice>();
shared->mId = guid;
auto shared = std::make_unique<SharedDevice>(guid);
shared->mSpeakerConfig = speakerconf;
shared->mMaxHwSources = maxHw;
shared->mMaxSwSources = totalSources - maxHw;
Expand All @@ -233,9 +232,30 @@ ds::expected<std::unique_ptr<SharedDevice>,HRESULT> CreateDeviceShare(GUID &guid

} // namespace

#define PREFIX "SharedDevice::"
std::mutex SharedDevice::sDeviceListMutex;
std::vector<std::unique_ptr<SharedDevice>> SharedDevice::sDeviceList;

std::mutex DSound8OAL::sDeviceListMutex;
std::vector<std::unique_ptr<SharedDevice>> DSound8OAL::sDeviceList;
auto SharedDevice::GetById(const GUID &deviceId) noexcept
-> ds::expected<ComPtr<SharedDevice>,HRESULT>
{
auto find_id = [&deviceId](std::unique_ptr<SharedDevice> &device)
{ return deviceId == device->mId; };

std::unique_lock listlock{sDeviceListMutex};
auto sharediter = std::find_if(sDeviceList.begin(), sDeviceList.end(), find_id);
if(sharediter != sDeviceList.end())
{
(*sharediter)->AddRef();
return ComPtr<SharedDevice>{(*sharediter).get()};
}

auto shared = CreateDeviceShare(deviceId);
if(!shared) return ds::unexpected(shared.error());

sDeviceList.emplace_back(std::move(shared).value());
return ComPtr<SharedDevice>{sDeviceList.back().get()};
}

SharedDevice::~SharedDevice()
{
Expand All @@ -249,6 +269,22 @@ SharedDevice::~SharedDevice()
alcCloseDevice(mDevice.release());
}

void SharedDevice::dispose() noexcept
{
std::lock_guard listlock{sDeviceListMutex};

auto find_shared = [this](std::unique_ptr<SharedDevice> &shared)
{ return this == shared.get(); };

auto shared_iter = std::find_if(sDeviceList.begin(), sDeviceList.end(), find_shared);
if(shared_iter != sDeviceList.end())
{
TRACE(PREFIX "dispose Freeing shared device %s\n",
GuidPrinter{(*shared_iter)->mId}.c_str());
sDeviceList.erase(shared_iter);
}
}
#undef PREFIX

BufferSubList::~BufferSubList()
{
Expand Down Expand Up @@ -277,27 +313,7 @@ DSound8OAL::DSound8OAL(bool is8) : mPrimaryBuffer{*this}, mIs8{is8}
{
}

DSound8OAL::~DSound8OAL()
{
if(!mShared)
return;

std::lock_guard listlock{sDeviceListMutex};

auto find_shared = [this](std::unique_ptr<SharedDevice> &shared)
{ return mShared == shared.get(); };

auto shared_iter = std::find_if(sDeviceList.begin(), sDeviceList.end(), find_shared);
if(shared_iter == sDeviceList.end()) return;

(*shared_iter)->mUseCount -= 1;
if((*shared_iter)->mUseCount == 0)
{
TRACE(PREFIX "~DSound8OAL Freeing shared device %s\n",
GuidPrinter{(*shared_iter)->mId}.c_str());
sDeviceList.erase(shared_iter);
}
}
DSound8OAL::~DSound8OAL() = default;


HRESULT STDMETHODCALLTYPE DSound8OAL::QueryInterface(REFIID riid, void** ppvObject) noexcept
Expand Down Expand Up @@ -647,26 +663,9 @@ HRESULT STDMETHODCALLTYPE DSound8OAL::Initialize(const GUID *deviceId) noexcept
HRESULT hr{GetDeviceID(*deviceId, devid)};
if(FAILED(hr)) return hr;

{
auto find_id = [devid](std::unique_ptr<SharedDevice> &device)
{ return devid == device->mId; };

std::unique_lock listlock{sDeviceListMutex};
auto sharediter = std::find_if(sDeviceList.begin(), sDeviceList.end(), find_id);
if(sharediter != sDeviceList.end())
{
(*sharediter)->mUseCount += 1;
mShared = sharediter->get();
}
else
{
auto shared = CreateDeviceShare(devid);
if(!shared) return shared.error();

sDeviceList.emplace_back(std::move(shared).value());
mShared = sDeviceList.back().get();
}
}
auto shared = SharedDevice::GetById(devid);
if(!shared) return shared.error();
mShared = std::move(shared).value();

mPrimaryBuffer.setContext(mShared->mContext.get());

Expand Down
65 changes: 32 additions & 33 deletions src/dsoundoal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,82 +10,84 @@
#include "AL/alc.h"
#include "comptr.h"
#include "dsoal.h"
#include "expected.h"
#include "primarybuffer.h"


class Buffer;

struct SharedDevice {
static std::mutex sDeviceListMutex;
static std::vector<std::unique_ptr<SharedDevice>> sDeviceList;

struct NoDeleter {
template<typename T>
void operator()(T*) noexcept { }
};

SharedDevice() = default;
SharedDevice(const GUID &id) : mId{id} { }
SharedDevice(const SharedDevice&) = delete;
SharedDevice(SharedDevice&& rhs) = default;
~SharedDevice();

SharedDevice& operator=(const SharedDevice&) = delete;
SharedDevice& operator=(SharedDevice&&) = delete;

void dispose() noexcept;

ULONG AddRef() noexcept { return mRef.fetch_add(1u, std::memory_order_relaxed)+1; }
ULONG Release() noexcept
{
const auto ret = mRef.fetch_sub(1u, std::memory_order_relaxed)-1;
if(ret == 0) dispose();
return ret;
}

DWORD mMaxHwSources{};
DWORD mMaxSwSources{};
DWORD mCurrentHwSources{};
DWORD mCurrentSwSources{};
std::atomic<DWORD> mCurrentHwSources{};
std::atomic<DWORD> mCurrentSwSources{};

GUID mId{};
const GUID mId;
DWORD mSpeakerConfig{};

std::unique_ptr<ALCdevice,NoDeleter> mDevice;
std::unique_ptr<ALCcontext,NoDeleter> mContext;

size_t mUseCount{1u};
std::atomic<ULONG> mRef{1u};

DWORD getCurrentHwCount() const noexcept
{ return static_cast<const volatile DWORD&>(mCurrentHwSources); }
{ return mCurrentHwSources.load(std::memory_order_relaxed); }

DWORD getCurrentSwCount() const noexcept
{ return static_cast<const volatile DWORD&>(mCurrentSwSources); }
{ return mCurrentSwSources.load(std::memory_order_relaxed); }

/* Increment mCurrentHwSources up to mMaxHwSources. Returns false is the
* current is already at max, or true if it was successfully incremented.
*/
bool incHwSources() noexcept
{
/* Can't use standard atomics here since they break the move
* constructor.
*/
DWORD current;
DWORD previous{static_cast<volatile DWORD&>(mCurrentHwSources)};
DWORD cur{mCurrentHwSources.load(std::memory_order_relaxed)};
do {
if(previous == mMaxHwSources)
if(cur == mMaxHwSources)
return false;
current = previous;
previous = InterlockedCompareExchange(&mCurrentHwSources, current+1, current);
} while(previous != current);
} while(!mCurrentHwSources.compare_exchange_weak(cur, cur+1, std::memory_order_relaxed));
return true;
}

/* Increment mCurrentSwSources up to mMaxSwSources. */
bool incSwSources() noexcept
{
/* Can't use standard atomics here since they break the move
* constructor.
*/
DWORD current;
DWORD previous{static_cast<volatile DWORD&>(mCurrentSwSources)};
DWORD cur{mCurrentSwSources.load(std::memory_order_relaxed)};
do {
if(previous == mMaxSwSources)
if(cur == mMaxSwSources)
return false;
current = previous;
previous = InterlockedCompareExchange(&mCurrentSwSources, current+1, current);
} while(previous != current);
} while(!mCurrentSwSources.compare_exchange_weak(cur, cur+1, std::memory_order_relaxed));
return true;
}

void decHwSources() noexcept { InterlockedDecrement(&mCurrentHwSources); }
void decSwSources() noexcept { InterlockedDecrement(&mCurrentSwSources); }
void decHwSources() noexcept { mCurrentHwSources.fetch_sub(1u, std::memory_order_relaxed); }
void decSwSources() noexcept { mCurrentSwSources.fetch_sub(1u, std::memory_order_relaxed); }

static auto GetById(const GUID &deviceId) noexcept -> ds::expected<ComPtr<SharedDevice>,HRESULT>;
};


Expand Down Expand Up @@ -114,9 +116,6 @@ class DSound8OAL final : IDirectSound8 {
DSound8OAL(bool is8);
~DSound8OAL();

static std::mutex sDeviceListMutex;
static std::vector<std::unique_ptr<SharedDevice>> sDeviceList;

class UnknownImpl final : IUnknown {
DSound8OAL *impl_from_base() noexcept
{
Expand Down Expand Up @@ -145,7 +144,7 @@ class DSound8OAL final : IDirectSound8 {
std::mutex mDsMutex;
DWORD mPrioLevel{};

SharedDevice *mShared{};
ComPtr<SharedDevice> mShared;

std::vector<BufferSubList> mSecondaryBuffers;
PrimaryBuffer mPrimaryBuffer;
Expand Down

0 comments on commit 85aadb8

Please sign in to comment.