oculus1
view libovr/Src/win32/OVR_Win32_DeviceManager.cpp @ 1:e2f9e4603129
added LibOVR and started a simple vr wrapper.
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 14 Sep 2013 16:14:59 +0300 |
parents | |
children |
line source
1 /************************************************************************************
3 Filename : OVR_Win32_DeviceManager.cpp
4 Content : Win32 implementation of DeviceManager.
5 Created : September 21, 2012
6 Authors : Michael Antonov
8 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
10 Use of this software is subject to the terms of the Oculus license
11 agreement provided at the time of installation or download, or which
12 otherwise accompanies this software in either electronic or hard copy form.
14 *************************************************************************************/
16 #include "OVR_Win32_DeviceManager.h"
18 // Sensor & HMD Factories
19 #include "OVR_SensorImpl.h"
20 #include "OVR_LatencyTestImpl.h"
21 #include "OVR_Win32_HMDDevice.h"
22 #include "OVR_Win32_DeviceStatus.h"
23 #include "OVR_Win32_HIDDevice.h"
25 #include "Kernel/OVR_Timer.h"
26 #include "Kernel/OVR_Std.h"
27 #include "Kernel/OVR_Log.h"
29 DWORD Debug_WaitedObjectCount = 0;
31 namespace OVR { namespace Win32 {
34 //-------------------------------------------------------------------------------------
35 // **** Win32::DeviceManager
37 DeviceManager::DeviceManager()
38 {
39 HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
40 }
42 DeviceManager::~DeviceManager()
43 {
44 // make sure Shutdown was called.
45 OVR_ASSERT(!pThread);
46 }
48 bool DeviceManager::Initialize(DeviceBase*)
49 {
50 if (!DeviceManagerImpl::Initialize(0))
51 return false;
53 pThread = *new DeviceManagerThread(this);
54 if (!pThread || !pThread->Start())
55 return false;
57 pCreateDesc->pDevice = this;
58 LogText("OVR::DeviceManager - initialized.\n");
59 return true;
60 }
62 void DeviceManager::Shutdown()
63 {
64 LogText("OVR::DeviceManager - shutting down.\n");
66 // Set Manager shutdown marker variable; this prevents
67 // any existing DeviceHandle objects from accessing device.
68 pCreateDesc->pLock->pManager = 0;
70 // Push for thread shutdown *WITH NO WAIT*.
71 // This will have the following effect:
72 // - Exit command will get enqueued, which will be executed later on the thread itself.
73 // - Beyond this point, this DeviceManager object may be deleted by our caller.
74 // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
75 // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
76 // after pManager is null.
77 // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
78 // reference to the thread object.
79 pThread->PushExitCommand(false);
80 pThread->DetachDeviceManager();
81 pThread.Clear();
83 DeviceManagerImpl::Shutdown();
84 }
86 ThreadCommandQueue* DeviceManager::GetThreadQueue()
87 {
88 return pThread;
89 }
91 bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
92 {
93 if ((info->InfoClassType != Device_Manager) &&
94 (info->InfoClassType != Device_None))
95 return false;
97 info->Type = Device_Manager;
98 info->Version = 0;
99 OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
100 OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");
101 return true;
102 }
104 DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
105 {
106 // TBD: Can this be avoided in the future, once proper device notification is in place?
107 if (GetThreadId() != OVR::GetCurrentThreadId())
108 {
109 pThread->PushCall((DeviceManagerImpl*)this,
110 &DeviceManager::EnumerateAllFactoryDevices, true);
111 }
112 else
113 DeviceManager::EnumerateAllFactoryDevices();
115 return DeviceManagerImpl::EnumerateDevicesEx(args);
116 }
118 ThreadId DeviceManager::GetThreadId() const
119 {
120 return pThread->GetThreadId();
121 }
123 bool DeviceManager::GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const
124 {
125 if (GetHIDDeviceManager())
126 return static_cast<HIDDeviceManager*>(GetHIDDeviceManager())->GetHIDDeviceDesc(path, pdevDesc);
127 return false;
128 }
131 //-------------------------------------------------------------------------------------
132 // ***** DeviceManager Thread
134 DeviceManagerThread::DeviceManagerThread(DeviceManager* pdevMgr)
135 : Thread(ThreadStackSize), hCommandEvent(0), pDeviceMgr(pdevMgr)
136 {
137 // Create a non-signaled manual-reset event.
138 hCommandEvent = ::CreateEvent(0, TRUE, FALSE, 0);
139 if (!hCommandEvent)
140 return;
142 // Must add event before starting.
143 AddOverlappedEvent(0, hCommandEvent);
145 // Create device messages object.
146 pStatusObject = *new DeviceStatus(this);
147 }
149 DeviceManagerThread::~DeviceManagerThread()
150 {
151 // Remove overlapped event [0], after thread service exit.
152 if (hCommandEvent)
153 {
154 RemoveOverlappedEvent(0, hCommandEvent);
155 ::CloseHandle(hCommandEvent);
156 hCommandEvent = 0;
157 }
158 }
160 int DeviceManagerThread::Run()
161 {
162 ThreadCommand::PopBuffer command;
164 SetThreadName("OVR::DeviceManagerThread");
165 LogText("OVR::DeviceManagerThread - running (ThreadId=0x%X).\n", GetThreadId());
167 if (!pStatusObject->Initialize())
168 {
169 LogText("OVR::DeviceManagerThread - failed to initialize MessageObject.\n");
170 }
172 while(!IsExiting())
173 {
174 // PopCommand will reset event on empty queue.
175 if (PopCommand(&command))
176 {
177 command.Execute();
178 }
179 else
180 {
181 DWORD eventIndex = 0;
182 do {
183 UPInt numberOfWaitHandles = WaitHandles.GetSize();
184 Debug_WaitedObjectCount = (DWORD)numberOfWaitHandles;
186 DWORD waitMs = INFINITE;
188 // If devices have time-dependent logic registered, get the longest wait
189 // allowed based on current ticks.
190 if (!TicksNotifiers.IsEmpty())
191 {
192 UInt64 ticksMks = Timer::GetTicks();
193 DWORD waitAllowed;
195 for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
196 {
197 waitAllowed = (DWORD)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
198 if (waitAllowed < waitMs)
199 waitMs = waitAllowed;
200 }
201 }
203 // Wait for event signals or window messages.
204 eventIndex = MsgWaitForMultipleObjects((DWORD)numberOfWaitHandles, &WaitHandles[0], FALSE, waitMs, QS_ALLINPUT);
206 if (eventIndex != WAIT_FAILED)
207 {
208 if (eventIndex == WAIT_TIMEOUT)
209 continue;
211 // TBD: Does this ever apply?
212 OVR_ASSERT(eventIndex < WAIT_ABANDONED_0);
214 if (eventIndex == WAIT_OBJECT_0)
215 {
216 // Handle [0] services commands.
217 break;
218 }
219 else if (eventIndex == WAIT_OBJECT_0 + numberOfWaitHandles)
220 {
221 // Handle Windows messages.
222 pStatusObject->ProcessMessages();
223 }
224 else
225 {
226 // Notify waiting device that its event is signaled.
227 unsigned i = eventIndex - WAIT_OBJECT_0;
228 OVR_ASSERT(i < numberOfWaitHandles);
229 if (WaitNotifiers[i])
230 WaitNotifiers[i]->OnOverlappedEvent(WaitHandles[i]);
231 }
232 }
234 } while(eventIndex != WAIT_FAILED);
236 }
237 }
239 pStatusObject->ShutDown();
241 LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%X).\n", GetThreadId());
242 return 0;
243 }
245 bool DeviceManagerThread::AddOverlappedEvent(Notifier* notify, HANDLE hevent)
246 {
247 WaitNotifiers.PushBack(notify);
248 WaitHandles.PushBack(hevent);
250 OVR_ASSERT(WaitNotifiers.GetSize() <= MAXIMUM_WAIT_OBJECTS);
251 return true;
252 }
254 bool DeviceManagerThread::RemoveOverlappedEvent(Notifier* notify, HANDLE hevent)
255 {
256 // [0] is reserved for thread commands with notify of null, but we still
257 // can use this function to remove it.
258 for (UPInt i = 0; i < WaitNotifiers.GetSize(); i++)
259 {
260 if ((WaitNotifiers[i] == notify) && (WaitHandles[i] == hevent))
261 {
262 WaitNotifiers.RemoveAt(i);
263 WaitHandles.RemoveAt(i);
264 return true;
265 }
266 }
267 return false;
268 }
270 bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
271 {
272 TicksNotifiers.PushBack(notify);
273 return true;
274 }
276 bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
277 {
278 for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
279 {
280 if (TicksNotifiers[i] == notify)
281 {
282 TicksNotifiers.RemoveAt(i);
283 return true;
284 }
285 }
286 return false;
287 }
289 bool DeviceManagerThread::AddMessageNotifier(Notifier* notify)
290 {
291 MessageNotifiers.PushBack(notify);
292 return true;
293 }
295 bool DeviceManagerThread::RemoveMessageNotifier(Notifier* notify)
296 {
297 for (UPInt i = 0; i < MessageNotifiers.GetSize(); i++)
298 {
299 if (MessageNotifiers[i] == notify)
300 {
301 MessageNotifiers.RemoveAt(i);
302 return true;
303 }
304 }
305 return false;
306 }
308 bool DeviceManagerThread::OnMessage(MessageType type, const String& devicePath)
309 {
310 Notifier::DeviceMessageType notifierMessageType = Notifier::DeviceMessage_DeviceAdded;
311 if (type == DeviceAdded)
312 {
313 }
314 else if (type == DeviceRemoved)
315 {
316 notifierMessageType = Notifier::DeviceMessage_DeviceRemoved;
317 }
318 else
319 {
320 OVR_ASSERT(false);
321 }
323 bool error = false;
324 bool deviceFound = false;
325 for (UPInt i = 0; i < MessageNotifiers.GetSize(); i++)
326 {
327 if (MessageNotifiers[i] &&
328 MessageNotifiers[i]->OnDeviceMessage(notifierMessageType, devicePath, &error))
329 {
330 // The notifier belonged to a device with the specified device name so we're done.
331 deviceFound = true;
332 break;
333 }
334 }
335 if (type == DeviceAdded && !deviceFound)
336 {
337 Lock::Locker devMgrLock(&DevMgrLock);
338 // a new device was connected. Go through all device factories and
339 // try to detect the device using HIDDeviceDesc.
340 HIDDeviceDesc devDesc;
341 if (pDeviceMgr->GetHIDDeviceDesc(devicePath, &devDesc))
342 {
343 Lock::Locker deviceLock(pDeviceMgr->GetLock());
344 DeviceFactory* factory = pDeviceMgr->Factories.GetFirst();
345 while(!pDeviceMgr->Factories.IsNull(factory))
346 {
347 if (factory->DetectHIDDevice(pDeviceMgr, devDesc))
348 {
349 deviceFound = true;
350 break;
351 }
352 factory = factory->pNext;
353 }
354 }
355 }
357 if (!deviceFound && strstr(devicePath.ToCStr(), "#OVR00"))
358 {
359 Ptr<DeviceManager> pmgr;
360 {
361 Lock::Locker devMgrLock(&DevMgrLock);
362 pmgr = pDeviceMgr;
363 }
364 // HMD plugged/unplugged
365 // This is not a final solution to enumerate HMD devices and get
366 // a first available handle. This won't work with multiple rifts.
367 // @TODO (!AB)
368 pmgr->EnumerateDevices<HMDDevice>();
369 }
371 return !error;
372 }
374 void DeviceManagerThread::DetachDeviceManager()
375 {
376 Lock::Locker devMgrLock(&DevMgrLock);
377 pDeviceMgr = NULL;
378 }
380 } // namespace Win32
383 //-------------------------------------------------------------------------------------
384 // ***** Creation
387 // Creates a new DeviceManager and initializes OVR.
388 DeviceManager* DeviceManager::Create()
389 {
391 if (!System::IsInitialized())
392 {
393 // Use custom message, since Log is not yet installed.
394 OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
395 LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
396 return 0;
397 }
399 Ptr<Win32::DeviceManager> manager = *new Win32::DeviceManager;
401 if (manager)
402 {
403 if (manager->Initialize(0))
404 {
405 manager->AddFactory(&SensorDeviceFactory::Instance);
406 manager->AddFactory(&LatencyTestDeviceFactory::Instance);
407 manager->AddFactory(&Win32::HMDDeviceFactory::Instance);
409 manager->AddRef();
410 }
411 else
412 {
413 manager.Clear();
414 }
416 }
418 return manager.GetPtr();
419 }
422 } // namespace OVR