mirror of
https://github.com/mii443/rust-openvr.git
synced 2025-08-22 16:25:36 +00:00
795 lines
23 KiB
C++
795 lines
23 KiB
C++
/************************************************************************************
|
|
|
|
Filename : OVR_DeviceImpl.h
|
|
Content : Partial back-end independent implementation of Device interfaces
|
|
Created : October 10, 2012
|
|
Authors : Michael Antonov
|
|
|
|
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
|
|
|
|
Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
|
|
you may not use the Oculus VR Rift SDK except in compliance with the License,
|
|
which is provided at the time of installation or download, or which
|
|
otherwise accompanies this software in either electronic or hard copy form.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.oculusvr.com/licenses/LICENSE-3.1
|
|
|
|
Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
*************************************************************************************/
|
|
|
|
#include "OVR_DeviceImpl.h"
|
|
#include "Kernel/OVR_Atomic.h"
|
|
#include "Kernel/OVR_Log.h"
|
|
#include "Kernel/OVR_System.h"
|
|
|
|
#include "OVR_DeviceImpl.h"
|
|
#include "OVR_SensorImpl.h"
|
|
#include "OVR_Profile.h"
|
|
|
|
namespace OVR {
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// ***** MessageHandler
|
|
|
|
// Threading notes:
|
|
// The OnMessage() handler and SetMessageHandler are currently synchronized
|
|
// through a separately stored shared Lock object to avoid calling the handler
|
|
// from background thread while it's being removed.
|
|
|
|
static SharedLock MessageHandlerSharedLock;
|
|
|
|
|
|
class MessageHandlerImpl
|
|
{
|
|
public:
|
|
enum
|
|
{
|
|
MaxHandlerRefsCount = 4
|
|
};
|
|
|
|
MessageHandlerImpl()
|
|
: pLock(MessageHandlerSharedLock.GetLockAddRef()), HandlerRefsCount(0)
|
|
{
|
|
}
|
|
~MessageHandlerImpl()
|
|
{
|
|
MessageHandlerSharedLock.ReleaseLock(pLock);
|
|
pLock = 0;
|
|
}
|
|
|
|
static MessageHandlerImpl* FromHandler(MessageHandler* handler)
|
|
{ return (MessageHandlerImpl*)&handler->Internal; }
|
|
static const MessageHandlerImpl* FromHandler(const MessageHandler* handler)
|
|
{ return (const MessageHandlerImpl*)&handler->Internal; }
|
|
|
|
// This lock is held while calling a handler and when we are applied/
|
|
// removed from a device.
|
|
Lock* pLock;
|
|
// List of devices we are applied to.
|
|
int HandlerRefsCount;
|
|
MessageHandlerRef* pHandlerRefs[MaxHandlerRefsCount];
|
|
};
|
|
|
|
|
|
MessageHandlerRef::MessageHandlerRef(DeviceBase* device)
|
|
: pLock(MessageHandlerSharedLock.GetLockAddRef()), pDevice(device), HandlersCount(0)
|
|
{
|
|
}
|
|
|
|
MessageHandlerRef::~MessageHandlerRef()
|
|
{
|
|
{
|
|
Lock::Locker lockScope(pLock);
|
|
|
|
while (HandlersCount > 0)
|
|
removeHandler(0);
|
|
}
|
|
MessageHandlerSharedLock.ReleaseLock(pLock);
|
|
pLock = 0;
|
|
}
|
|
|
|
void MessageHandlerRef::Call(const Message& msg)
|
|
{
|
|
Lock::Locker lockScope(pLock);
|
|
|
|
for (int i = 0; i < HandlersCount; i++)
|
|
pHandlers[i]->OnMessage(msg);
|
|
}
|
|
|
|
void MessageHandlerRef::AddHandler(MessageHandler* handler)
|
|
{
|
|
OVR_ASSERT(!handler ||
|
|
MessageHandlerImpl::FromHandler(handler)->pLock == pLock);
|
|
Lock::Locker lockScope(pLock);
|
|
AddHandler_NTS(handler);
|
|
}
|
|
|
|
void MessageHandlerRef::AddHandler_NTS(MessageHandler* handler)
|
|
{
|
|
OVR_ASSERT(handler != NULL);
|
|
|
|
OVR_ASSERT(HandlersCount < MaxHandlersCount);
|
|
for (int i = 0; i < HandlersCount; i++)
|
|
if (pHandlers[i] == handler)
|
|
// handler already installed - do nothing
|
|
return;
|
|
pHandlers[HandlersCount] = handler;
|
|
HandlersCount++;
|
|
|
|
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(handler);
|
|
OVR_ASSERT(handlerImpl->HandlerRefsCount < MessageHandlerImpl::MaxHandlerRefsCount);
|
|
handlerImpl->pHandlerRefs[handlerImpl->HandlerRefsCount] = this;
|
|
handlerImpl->HandlerRefsCount++;
|
|
|
|
// TBD: Call notifier on device?
|
|
}
|
|
|
|
bool MessageHandlerRef::RemoveHandler(MessageHandler* handler)
|
|
{
|
|
Lock::Locker lockScope(pLock);
|
|
|
|
for (int i = 0; i < HandlersCount; i++)
|
|
{
|
|
if (pHandlers[i] == handler)
|
|
return removeHandler(i);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool MessageHandlerRef::removeHandler(int idx)
|
|
{
|
|
OVR_ASSERT(idx < HandlersCount);
|
|
|
|
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(pHandlers[idx]);
|
|
for (int i = 0; i < handlerImpl->HandlerRefsCount; i++)
|
|
if (handlerImpl->pHandlerRefs[i] == this)
|
|
{
|
|
handlerImpl->pHandlerRefs[i] = handlerImpl->pHandlerRefs[handlerImpl->HandlerRefsCount - 1];
|
|
handlerImpl->HandlerRefsCount--;
|
|
|
|
pHandlers[idx] = pHandlers[HandlersCount - 1];
|
|
HandlersCount--;
|
|
|
|
return true;
|
|
}
|
|
|
|
// couldn't find a link in the opposite direction, assert in Debug
|
|
OVR_ASSERT(0);
|
|
|
|
pHandlers[idx] = pHandlers[HandlersCount - 1];
|
|
HandlersCount--;
|
|
|
|
return true;
|
|
}
|
|
|
|
MessageHandler::MessageHandler()
|
|
{
|
|
OVR_COMPILER_ASSERT(sizeof(Internal) > sizeof(MessageHandlerImpl));
|
|
Construct<MessageHandlerImpl>(Internal);
|
|
}
|
|
|
|
MessageHandler::~MessageHandler()
|
|
{
|
|
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
|
|
{
|
|
Lock::Locker lockedScope(handlerImpl->pLock);
|
|
OVR_ASSERT_LOG(handlerImpl->HandlerRefsCount == 0,
|
|
("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this));
|
|
}
|
|
|
|
Destruct<MessageHandlerImpl>(handlerImpl);
|
|
}
|
|
|
|
bool MessageHandler::IsHandlerInstalled() const
|
|
{
|
|
const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
|
|
Lock::Locker lockedScope(handlerImpl->pLock);
|
|
|
|
return handlerImpl->HandlerRefsCount > 0;
|
|
}
|
|
|
|
void MessageHandler::RemoveHandlerFromDevices()
|
|
{
|
|
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
|
|
Lock::Locker lockedScope(handlerImpl->pLock);
|
|
|
|
while (handlerImpl->HandlerRefsCount > 0)
|
|
{
|
|
MessageHandlerRef* use = handlerImpl->pHandlerRefs[0];
|
|
use->RemoveHandler(this);
|
|
}
|
|
}
|
|
|
|
Lock* MessageHandler::GetHandlerLock() const
|
|
{
|
|
const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
|
|
return handlerImpl->pLock;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// ***** DeviceBase
|
|
|
|
|
|
// Delegate relevant implementation to DeviceRectord to avoid re-implementation in
|
|
// every derived Device.
|
|
void DeviceBase::AddRef()
|
|
{
|
|
getDeviceCommon()->DeviceAddRef();
|
|
}
|
|
void DeviceBase::Release()
|
|
{
|
|
getDeviceCommon()->DeviceRelease();
|
|
}
|
|
DeviceBase* DeviceBase::GetParent() const
|
|
{
|
|
return getDeviceCommon()->pParent.GetPtr();
|
|
}
|
|
DeviceManager* DeviceBase::GetManager() const
|
|
{
|
|
return getDeviceCommon()->pCreateDesc->GetManagerImpl();
|
|
}
|
|
|
|
void DeviceBase::AddMessageHandler(MessageHandler* handler)
|
|
{
|
|
getDeviceCommon()->HandlerRef.AddHandler(handler);
|
|
}
|
|
|
|
DeviceType DeviceBase::GetType() const
|
|
{
|
|
return getDeviceCommon()->pCreateDesc->Type;
|
|
}
|
|
|
|
bool DeviceBase::GetDeviceInfo(DeviceInfo* info) const
|
|
{
|
|
return getDeviceCommon()->pCreateDesc->GetDeviceInfo(info);
|
|
//info->Name[0] = 0;
|
|
//return false;
|
|
}
|
|
|
|
// Returns true if device is connected and usable
|
|
bool DeviceBase::IsConnected()
|
|
{
|
|
return getDeviceCommon()->ConnectedFlag;
|
|
}
|
|
|
|
// returns the MessageHandler's lock
|
|
Lock* DeviceBase::GetHandlerLock() const
|
|
{
|
|
return getDeviceCommon()->HandlerRef.GetLock();
|
|
}
|
|
|
|
// Derive DeviceManagerCreateDesc to provide abstract function implementation.
|
|
class DeviceManagerCreateDesc : public DeviceCreateDesc
|
|
{
|
|
public:
|
|
DeviceManagerCreateDesc(DeviceFactory* factory)
|
|
: DeviceCreateDesc(factory, Device_Manager) { }
|
|
|
|
// We don't need there on Manager since it isn't assigned to DeviceHandle.
|
|
virtual DeviceCreateDesc* Clone() const { return 0; }
|
|
virtual MatchResult MatchDevice(const DeviceCreateDesc&,
|
|
DeviceCreateDesc**) const { return Match_None; }
|
|
virtual DeviceBase* NewDeviceInstance() { return 0; }
|
|
virtual bool GetDeviceInfo(DeviceInfo*) const { return false; }
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// ***** DeviceManagerImpl
|
|
|
|
DeviceManagerImpl::DeviceManagerImpl()
|
|
: DeviceImpl<OVR::DeviceManager>(CreateManagerDesc(), 0)
|
|
//,DeviceCreateDescList(pCreateDesc ? pCreateDesc->pLock : 0)
|
|
{
|
|
if (pCreateDesc)
|
|
{
|
|
pCreateDesc->pLock->pManager = this;
|
|
}
|
|
}
|
|
|
|
DeviceManagerImpl::~DeviceManagerImpl()
|
|
{
|
|
// Shutdown must've been called.
|
|
OVR_ASSERT(!pCreateDesc->pDevice);
|
|
|
|
// Remove all factories
|
|
while(!Factories.IsEmpty())
|
|
{
|
|
DeviceFactory* factory = Factories.GetFirst();
|
|
factory->RemovedFromManager();
|
|
factory->RemoveNode();
|
|
}
|
|
}
|
|
|
|
DeviceCreateDesc* DeviceManagerImpl::CreateManagerDesc()
|
|
{
|
|
DeviceCreateDesc* managerDesc = new DeviceManagerCreateDesc(0);
|
|
if (managerDesc)
|
|
{
|
|
managerDesc->pLock = *new DeviceManagerLock;
|
|
}
|
|
return managerDesc;
|
|
}
|
|
|
|
bool DeviceManagerImpl::Initialize(DeviceBase* parent)
|
|
{
|
|
OVR_UNUSED(parent);
|
|
if (!pCreateDesc || !pCreateDesc->pLock)
|
|
return false;
|
|
|
|
pProfileManager = *ProfileManager::Create();
|
|
|
|
return true;
|
|
}
|
|
|
|
void DeviceManagerImpl::Shutdown()
|
|
{
|
|
// Remove all device descriptors from list while the lock is held.
|
|
// Some descriptors may survive longer due to handles.
|
|
while(!Devices.IsEmpty())
|
|
{
|
|
DeviceCreateDesc* devDesc = Devices.GetFirst();
|
|
OVR_ASSERT(!devDesc->pDevice); // Manager shouldn't be dying while Device exists.
|
|
devDesc->Enumerated = false;
|
|
devDesc->RemoveNode();
|
|
devDesc->pNext = devDesc->pPrev = 0;
|
|
|
|
if (devDesc->HandleCount == 0)
|
|
{
|
|
delete devDesc;
|
|
}
|
|
}
|
|
Devices.Clear();
|
|
|
|
// These must've been cleared by caller.
|
|
OVR_ASSERT(pCreateDesc->pDevice == 0);
|
|
OVR_ASSERT(pCreateDesc->pLock->pManager == 0);
|
|
|
|
pProfileManager.Clear();
|
|
}
|
|
|
|
|
|
// Callbacks for DeviceCreation/Release
|
|
DeviceBase* DeviceManagerImpl::CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent)
|
|
{
|
|
// Calls to DeviceManagerImpl::CreateDevice are enqueued with wait while holding pManager,
|
|
// so 'this' must remain valid.
|
|
OVR_ASSERT(createDesc->pLock->pManager);
|
|
|
|
Lock::Locker devicesLock(GetLock());
|
|
|
|
// If device already exists, just AddRef to it.
|
|
if (createDesc->pDevice)
|
|
{
|
|
createDesc->pDevice->AddRef();
|
|
return createDesc->pDevice;
|
|
}
|
|
|
|
if (!parent)
|
|
parent = this;
|
|
|
|
DeviceBase* device = createDesc->NewDeviceInstance();
|
|
|
|
if (device)
|
|
{
|
|
if (device->getDeviceCommon()->Initialize(parent))
|
|
{
|
|
createDesc->pDevice = device;
|
|
}
|
|
else
|
|
{
|
|
// Don't go through Release() to avoid PushCall behaviour,
|
|
// as it is not needed here.
|
|
delete device;
|
|
device = 0;
|
|
}
|
|
}
|
|
|
|
return device;
|
|
}
|
|
|
|
Void DeviceManagerImpl::ReleaseDevice_MgrThread(DeviceBase* device)
|
|
{
|
|
// descKeepAlive will keep ManagerLock object alive as well,
|
|
// allowing us to exit gracefully.
|
|
Ptr<DeviceCreateDesc> descKeepAlive;
|
|
Lock::Locker devicesLock(GetLock());
|
|
DeviceCommon* devCommon = device->getDeviceCommon();
|
|
|
|
while(1)
|
|
{
|
|
UInt32 refCount = devCommon->RefCount;
|
|
|
|
if (refCount > 1)
|
|
{
|
|
if (devCommon->RefCount.CompareAndSet_NoSync(refCount, refCount-1))
|
|
{
|
|
// We decreented from initial count higher then 1;
|
|
// nothing else to do.
|
|
return 0;
|
|
}
|
|
}
|
|
else if (devCommon->RefCount.CompareAndSet_NoSync(1, 0))
|
|
{
|
|
// { 1 -> 0 } decrement succeded. Destroy this device.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// At this point, may be releasing the device manager itself.
|
|
// This does not matter, however, since shutdown logic is the same
|
|
// in both cases. DeviceManager::Shutdown with begin shutdown process for
|
|
// the internal manager thread, which will eventually destroy itself.
|
|
// TBD: Clean thread shutdown.
|
|
descKeepAlive = devCommon->pCreateDesc;
|
|
descKeepAlive->pDevice = 0;
|
|
devCommon->Shutdown();
|
|
delete device;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
Void DeviceManagerImpl::EnumerateAllFactoryDevices()
|
|
{
|
|
// 1. Mark matching devices as NOT enumerated.
|
|
// 2. Call factory to enumerate all HW devices, adding any device that
|
|
// was not matched.
|
|
// 3. Remove non-matching devices.
|
|
|
|
Lock::Locker deviceLock(GetLock());
|
|
|
|
DeviceCreateDesc* devDesc, *nextdevDesc;
|
|
|
|
// 1.
|
|
for(devDesc = Devices.GetFirst();
|
|
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
|
|
{
|
|
//if (devDesc->pFactory == factory)
|
|
devDesc->Enumerated = false;
|
|
}
|
|
|
|
// 2.
|
|
DeviceFactory* factory = Factories.GetFirst();
|
|
while(!Factories.IsNull(factory))
|
|
{
|
|
EnumerateFactoryDevices(factory);
|
|
factory = factory->pNext;
|
|
}
|
|
|
|
|
|
// 3.
|
|
for(devDesc = Devices.GetFirst();
|
|
!Devices.IsNull(devDesc); devDesc = nextdevDesc)
|
|
{
|
|
// In case 'devDesc' gets removed.
|
|
nextdevDesc = devDesc->pNext;
|
|
|
|
// Note, device might be not enumerated since it is opened and
|
|
// in use! Do NOT notify 'device removed' in this case (!AB)
|
|
if (!devDesc->Enumerated)
|
|
{
|
|
// This deletes the devDesc for HandleCount == 0 due to Release in DeviceHandle.
|
|
CallOnDeviceRemoved(devDesc);
|
|
|
|
/*
|
|
if (devDesc->HandleCount == 0)
|
|
{
|
|
// Device must be dead if it ever existed, since it AddRefs to us.
|
|
// ~DeviceCreateDesc removes its node from list.
|
|
OVR_ASSERT(!devDesc->pDevice);
|
|
delete devDesc;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Ptr<DeviceCreateDesc> DeviceManagerImpl::AddDevice_NeedsLock(
|
|
const DeviceCreateDesc& createDesc)
|
|
{
|
|
// If found, mark as enumerated and we are done.
|
|
DeviceCreateDesc* descCandidate = 0;
|
|
|
|
for(DeviceCreateDesc* devDesc = Devices.GetFirst();
|
|
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
|
|
{
|
|
DeviceCreateDesc::MatchResult mr = devDesc->MatchDevice(createDesc, &descCandidate);
|
|
if (mr == DeviceCreateDesc::Match_Found)
|
|
{
|
|
devDesc->Enumerated = true;
|
|
if (!devDesc->pDevice)
|
|
CallOnDeviceAdded(devDesc);
|
|
return devDesc;
|
|
}
|
|
}
|
|
|
|
// Update candidate (this may involve writing fields to HMDDevice createDesc).
|
|
if (descCandidate)
|
|
{
|
|
bool newDevice = false;
|
|
if (descCandidate->UpdateMatchedCandidate(createDesc, &newDevice))
|
|
{
|
|
descCandidate->Enumerated = true;
|
|
if (!descCandidate->pDevice || newDevice)
|
|
CallOnDeviceAdded(descCandidate);
|
|
return descCandidate;
|
|
}
|
|
}
|
|
|
|
// If not found, add new device.
|
|
// - This stores a new descriptor with
|
|
// {pDevice = 0, HandleCount = 1, Enumerated = true}
|
|
DeviceCreateDesc* desc = createDesc.Clone();
|
|
desc->pLock = pCreateDesc->pLock;
|
|
Devices.PushBack(desc);
|
|
desc->Enumerated = true;
|
|
|
|
CallOnDeviceAdded(desc);
|
|
|
|
return desc;
|
|
}
|
|
|
|
Ptr<DeviceCreateDesc> DeviceManagerImpl::FindDevice(
|
|
const String& path,
|
|
DeviceType deviceType)
|
|
{
|
|
Lock::Locker deviceLock(GetLock());
|
|
DeviceCreateDesc* devDesc;
|
|
|
|
for (devDesc = Devices.GetFirst();
|
|
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
|
|
{
|
|
if ((deviceType == Device_None || deviceType == devDesc->Type) &&
|
|
devDesc->MatchDevice(path))
|
|
return devDesc;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
Ptr<DeviceCreateDesc> DeviceManagerImpl::FindHIDDevice(const HIDDeviceDesc& hidDevDesc, bool created)
|
|
{
|
|
Lock::Locker deviceLock(GetLock());
|
|
DeviceCreateDesc* devDesc;
|
|
|
|
for (devDesc = Devices.GetFirst();
|
|
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
|
|
{
|
|
if (created)
|
|
{ // Search for matching device that is created
|
|
if (devDesc->MatchHIDDevice(hidDevDesc) && devDesc->pDevice)
|
|
return devDesc;
|
|
}
|
|
else
|
|
{ // Search for any matching device
|
|
if (devDesc->MatchHIDDevice(hidDevDesc))
|
|
return devDesc;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void DeviceManagerImpl::DetectHIDDevice(const HIDDeviceDesc& hidDevDesc)
|
|
{
|
|
Lock::Locker deviceLock(GetLock());
|
|
DeviceFactory* factory = Factories.GetFirst();
|
|
while(!Factories.IsNull(factory))
|
|
{
|
|
if (factory->DetectHIDDevice(this, hidDevDesc))
|
|
break;
|
|
factory = factory->pNext;
|
|
}
|
|
|
|
}
|
|
|
|
// Enumerates devices for a particular factory.
|
|
Void DeviceManagerImpl::EnumerateFactoryDevices(DeviceFactory* factory)
|
|
{
|
|
|
|
class FactoryEnumerateVisitor : public DeviceFactory::EnumerateVisitor
|
|
{
|
|
DeviceManagerImpl* pManager;
|
|
DeviceFactory* pFactory;
|
|
public:
|
|
FactoryEnumerateVisitor(DeviceManagerImpl* manager, DeviceFactory* factory)
|
|
: pManager(manager), pFactory(factory) { }
|
|
|
|
virtual void Visit(const DeviceCreateDesc& createDesc)
|
|
{
|
|
pManager->AddDevice_NeedsLock(createDesc);
|
|
}
|
|
};
|
|
|
|
FactoryEnumerateVisitor newDeviceVisitor(this, factory);
|
|
factory->EnumerateDevices(newDeviceVisitor);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DeviceEnumerator<> DeviceManagerImpl::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
|
|
{
|
|
Lock::Locker deviceLock(GetLock());
|
|
|
|
if (Devices.IsEmpty())
|
|
return DeviceEnumerator<>();
|
|
|
|
DeviceCreateDesc* firstDeviceDesc = Devices.GetFirst();
|
|
DeviceEnumerator<> e = enumeratorFromHandle(DeviceHandle(firstDeviceDesc), args);
|
|
|
|
if (!args.MatchRule(firstDeviceDesc->Type, firstDeviceDesc->Enumerated))
|
|
{
|
|
e.Next();
|
|
}
|
|
|
|
return e;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// ***** DeviceCommon
|
|
|
|
void DeviceCommon::DeviceAddRef()
|
|
{
|
|
RefCount++;
|
|
}
|
|
|
|
void DeviceCommon::DeviceRelease()
|
|
{
|
|
while(1)
|
|
{
|
|
UInt32 refCount = RefCount;
|
|
OVR_ASSERT(refCount > 0);
|
|
|
|
if (refCount == 1)
|
|
{
|
|
DeviceManagerImpl* manager = pCreateDesc->GetManagerImpl();
|
|
ThreadCommandQueue* queue = manager->GetThreadQueue();
|
|
|
|
// Enqueue ReleaseDevice for {1 -> 0} transition with no wait.
|
|
// We pass our reference ownership into the queue to destroy.
|
|
// It's in theory possible for another thread to re-steal our device reference,
|
|
// but that is checked for atomically in DeviceManagerImpl::ReleaseDevice.
|
|
if (!queue->PushCall(manager, &DeviceManagerImpl::ReleaseDevice_MgrThread,
|
|
pCreateDesc->pDevice))
|
|
{
|
|
// PushCall shouldn't fail because background thread runs while manager is
|
|
// alive and we are holding Manager alive through pParent chain.
|
|
OVR_ASSERT(false);
|
|
}
|
|
|
|
// Warning! At his point everything, including manager, may be dead.
|
|
break;
|
|
}
|
|
else if (RefCount.CompareAndSet_NoSync(refCount, refCount-1))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// ***** DeviceCreateDesc
|
|
|
|
|
|
void DeviceCreateDesc::AddRef()
|
|
{
|
|
// Technically, HandleCount { 0 -> 1 } transition can only happen during Lock,
|
|
// but we leave this to caller to worry about (happens during enumeration).
|
|
HandleCount++;
|
|
}
|
|
|
|
void DeviceCreateDesc::Release()
|
|
{
|
|
while(1)
|
|
{
|
|
UInt32 handleCount = HandleCount;
|
|
// HandleCount must obviously be >= 1, since we are releasing it.
|
|
OVR_ASSERT(handleCount > 0);
|
|
|
|
// {1 -> 0} transition may cause us to be destroyed, so require a lock.
|
|
if (handleCount == 1)
|
|
{
|
|
Ptr<DeviceManagerLock> lockKeepAlive;
|
|
Lock::Locker deviceLockScope(GetLock());
|
|
|
|
if (!HandleCount.CompareAndSet_NoSync(handleCount, 0))
|
|
continue;
|
|
|
|
OVR_ASSERT(pDevice == 0);
|
|
|
|
// Destroy *this if the manager was destroyed already, or Enumerated
|
|
// is false (device no longer available).
|
|
if (!GetManagerImpl() || !Enumerated)
|
|
{
|
|
lockKeepAlive = pLock;
|
|
|
|
// Remove from manager list (only matters for !Enumerated).
|
|
if (pNext)
|
|
{
|
|
RemoveNode();
|
|
pNext = pPrev = 0;
|
|
}
|
|
|
|
delete this;
|
|
}
|
|
|
|
// Available DeviceCreateDesc may survive with { HandleCount == 0 },
|
|
// in case it might be enumerated again later.
|
|
break;
|
|
}
|
|
else if (HandleCount.CompareAndSet_NoSync(handleCount, handleCount-1))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
HMDDevice* HMDDevice::Disconnect(SensorDevice* psensor)
|
|
{
|
|
if (!psensor)
|
|
return NULL;
|
|
|
|
OVR::DeviceManager* manager = GetManager();
|
|
if (manager)
|
|
{
|
|
//DeviceManagerImpl* mgrImpl = static_cast<DeviceManagerImpl*>(manager);
|
|
Ptr<DeviceCreateDesc> desc = getDeviceCommon()->pCreateDesc;
|
|
if (desc)
|
|
{
|
|
class Visitor : public DeviceFactory::EnumerateVisitor
|
|
{
|
|
Ptr<DeviceCreateDesc> Desc;
|
|
public:
|
|
Visitor(DeviceCreateDesc* desc) : Desc(desc) {}
|
|
virtual void Visit(const DeviceCreateDesc& createDesc)
|
|
{
|
|
Lock::Locker lock(Desc->GetLock());
|
|
Desc->UpdateMatchedCandidate(createDesc);
|
|
}
|
|
} visitor(desc);
|
|
//SensorDeviceImpl* sImpl = static_cast<SensorDeviceImpl*>(psensor);
|
|
|
|
SensorDisplayInfoImpl displayInfo;
|
|
|
|
if (psensor->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
|
|
{
|
|
displayInfo.Unpack();
|
|
|
|
// If we got display info, try to match / create HMDDevice as well
|
|
// so that sensor settings give preference.
|
|
if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
|
|
{
|
|
SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, visitor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
bool HMDDevice::IsDisconnected() const
|
|
{
|
|
OVR::HMDInfo info;
|
|
GetDeviceInfo(&info);
|
|
// if strlen(info.DisplayDeviceName) == 0 then
|
|
// this HMD is 'fake' (created using sensor).
|
|
return (strlen(info.DisplayDeviceName) == 0);
|
|
}
|
|
|
|
|
|
} // namespace OVR
|
|
|