oculus1

view libovr/Src/win32/OVR_Win32_HMDDevice.cpp @ 24:8419d8a13cee

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 04 Oct 2013 14:50:26 +0300
parents
children
line source
1 /************************************************************************************
3 Filename : OVR_Win32_HMDDevice.cpp
4 Content : Win32 Interface to HMD - detects HMD display
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_HMDDevice.h"
18 #include "OVR_Win32_DeviceManager.h"
20 #include <tchar.h>
22 namespace OVR { namespace Win32 {
24 //-------------------------------------------------------------------------------------
26 HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory,
27 const String& deviceId, const String& displayDeviceName)
28 : DeviceCreateDesc(factory, Device_HMD),
29 DeviceId(deviceId), DisplayDeviceName(displayDeviceName),
30 DesktopX(0), DesktopY(0), Contents(0),
31 HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0)
32 {
33 }
34 HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
35 : DeviceCreateDesc(other.pFactory, Device_HMD),
36 DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
37 DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
38 HResolution(other.HResolution), VResolution(other.VResolution),
39 HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize)
40 {
41 }
43 HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
44 DeviceCreateDesc** pcandidate) const
45 {
46 if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
47 return Match_None;
49 // There are several reasons we can come in here:
50 // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
51 // - Require exact device DeviceId/DeviceName match
52 // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
53 // - This DeviceId is empty; becomes candidate
54 // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
55 // - This other.DeviceId is empty; becomes candidate
57 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
59 if ((DeviceId == s2.DeviceId) &&
60 (DisplayDeviceName == s2.DisplayDeviceName))
61 {
62 // Non-null DeviceId may match while size is different if screen size was overwritten
63 // by SensorDisplayInfo in prior iteration.
64 if (!DeviceId.IsEmpty() ||
65 ((HScreenSize == s2.HScreenSize) &&
66 (VScreenSize == s2.VScreenSize)) )
67 {
68 *pcandidate = 0;
69 return Match_Found;
70 }
71 }
74 // DisplayInfo takes precedence, although we try to match it first.
75 if ((HResolution == s2.HResolution) &&
76 (VResolution == s2.VResolution) &&
77 (HScreenSize == s2.HScreenSize) &&
78 (VScreenSize == s2.VScreenSize))
79 {
80 if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
81 {
82 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
83 return Match_Candidate;
84 }
86 *pcandidate = 0;
87 return Match_Found;
88 }
90 // SensorDisplayInfo may override resolution settings, so store as candidate.
91 if (s2.DeviceId.IsEmpty())
92 {
93 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
94 return Match_Candidate;
95 }
96 // OTHER HMD Monitor desc may initialize DeviceName/Id
97 else if (DeviceId.IsEmpty())
98 {
99 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
100 return Match_Candidate;
101 }
103 return Match_None;
104 }
107 bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other,
108 bool* newDeviceFlag)
109 {
110 // This candidate was the the "best fit" to apply sensor DisplayInfo to.
111 OVR_ASSERT(other.Type == Device_HMD);
113 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
115 // Force screen size on resolution from SensorDisplayInfo.
116 // We do this because USB detection is more reliable as compared to HDMI EDID,
117 // which may be corrupted by splitter reporting wrong monitor
118 if (s2.DeviceId.IsEmpty())
119 {
120 HScreenSize = s2.HScreenSize;
121 VScreenSize = s2.VScreenSize;
122 Contents |= Contents_Screen;
124 if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
125 {
126 memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
127 Contents |= Contents_Distortion;
128 }
129 DeviceId = s2.DeviceId;
130 DisplayDeviceName = s2.DisplayDeviceName;
131 DesktopX = s2.DesktopX;
132 DesktopY = s2.DesktopY;
133 if (newDeviceFlag) *newDeviceFlag = true;
134 }
135 else if (DeviceId.IsEmpty())
136 {
137 DeviceId = s2.DeviceId;
138 DisplayDeviceName = s2.DisplayDeviceName;
139 DesktopX = s2.DesktopX;
140 DesktopY = s2.DesktopY;
142 // ScreenSize and Resolution are NOT assigned here, since they may have
143 // come from a sensor DisplayInfo (which has precedence over HDMI).
145 if (newDeviceFlag) *newDeviceFlag = true;
146 }
147 else
148 {
149 if (newDeviceFlag) *newDeviceFlag = false;
150 }
152 return true;
153 }
155 bool HMDDeviceCreateDesc::MatchDevice(const String& path)
156 {
157 return DeviceId.CompareNoCase(path) == 0;
158 }
160 //-------------------------------------------------------------------------------------
163 const wchar_t* FormatDisplayStateFlags(wchar_t* buff, int length, DWORD flags)
164 {
165 buff[0] = 0;
166 if (flags & DISPLAY_DEVICE_ACTIVE)
167 wcscat_s(buff, length, L"Active ");
168 if (flags & DISPLAY_DEVICE_MIRRORING_DRIVER)
169 wcscat_s(buff, length, L"Mirroring_Driver ");
170 if (flags & DISPLAY_DEVICE_MODESPRUNED)
171 wcscat_s(buff, length, L"ModesPruned ");
172 if (flags & DISPLAY_DEVICE_PRIMARY_DEVICE)
173 wcscat_s(buff, length, L"Primary ");
174 if (flags & DISPLAY_DEVICE_REMOVABLE)
175 wcscat_s(buff, length, L"Removable ");
176 if (flags & DISPLAY_DEVICE_VGA_COMPATIBLE)
177 wcscat_s(buff, length, L"VGA_Compatible ");
178 return buff;
179 }
182 //-------------------------------------------------------------------------------------
183 // Callback for monitor enumeration to store all the monitor handles
185 // Used to capture all the active monitor handles
186 struct MonitorSet
187 {
188 enum { MaxMonitors = 8 };
189 HMONITOR Monitors[MaxMonitors];
190 int MonitorCount;
191 };
193 BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
194 {
195 MonitorSet* monitorSet = (MonitorSet*)dwData;
196 if (monitorSet->MonitorCount > MonitorSet::MaxMonitors)
197 return FALSE;
199 monitorSet->Monitors[monitorSet->MonitorCount] = hMonitor;
200 monitorSet->MonitorCount++;
201 return TRUE;
202 };
204 //-------------------------------------------------------------------------------------
205 // ***** HMDDeviceFactory
207 HMDDeviceFactory HMDDeviceFactory::Instance;
209 void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
210 {
211 MonitorSet monitors;
212 monitors.MonitorCount = 0;
213 // Get all the monitor handles
214 EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
216 bool foundHMD = false;
218 // DeviceManager* manager = getManager();
219 DISPLAY_DEVICE dd, ddm;
220 UINT i, j;
222 for (i = 0;
223 (ZeroMemory(&dd, sizeof(dd)), dd.cb = sizeof(dd),
224 EnumDisplayDevices(0, i, &dd, 0)) != 0; i++)
225 {
227 /*
228 wchar_t buff[500], flagsBuff[200];
230 swprintf_s(buff, 500, L"\nDEV: \"%s\" \"%s\" 0x%08x=%s\n \"%s\" \"%s\"\n",
231 dd.DeviceName, dd.DeviceString,
232 dd.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, dd.StateFlags),
233 dd.DeviceID, dd.DeviceKey);
234 ::OutputDebugString(buff);
235 */
237 for (j = 0;
238 (ZeroMemory(&ddm, sizeof(ddm)), ddm.cb = sizeof(ddm),
239 EnumDisplayDevices(dd.DeviceName, j, &ddm, 0)) != 0; j++)
240 {
241 /*
242 wchar_t mbuff[500];
243 swprintf_s(mbuff, 500, L"MON: \"%s\" \"%s\" 0x%08x=%s\n \"%s\" \"%s\"\n",
244 ddm.DeviceName, ddm.DeviceString,
245 ddm.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, ddm.StateFlags),
246 ddm.DeviceID, ddm.DeviceKey);
247 ::OutputDebugString(mbuff);
248 */
250 // Our monitor hardware has string "RTD2205" in it
251 // Nate's device "CVT0003"
252 if (wcsstr(ddm.DeviceID, L"RTD2205") ||
253 wcsstr(ddm.DeviceID, L"CVT0003") ||
254 wcsstr(ddm.DeviceID, L"MST0030") ||
255 wcsstr(ddm.DeviceID, L"OVR00") ) // Part of Oculus EDID.
256 {
257 String deviceId(ddm.DeviceID);
258 String displayDeviceName(ddm.DeviceName);
260 // The default monitor coordinates
261 int mx = 0;
262 int my = 0;
263 int mwidth = 1280;
264 int mheight = 800;
266 // Find the matching MONITORINFOEX for this device so we can get the
267 // screen coordinates
268 MONITORINFOEX info;
269 for (int m=0; m < monitors.MonitorCount; m++)
270 {
271 info.cbSize = sizeof(MONITORINFOEX);
272 GetMonitorInfo(monitors.Monitors[m], &info);
273 if (_tcsstr(ddm.DeviceName, info.szDevice) == ddm.DeviceName)
274 { // If the device name starts with the monitor name
275 // then we found the matching DISPLAY_DEVICE and MONITORINFO
276 // so we can gather the monitor coordinates
277 mx = info.rcMonitor.left;
278 my = info.rcMonitor.top;
279 //mwidth = info.rcMonitor.right - info.rcMonitor.left;
280 //mheight = info.rcMonitor.bottom - info.rcMonitor.top;
281 break;
282 }
283 }
285 HMDDeviceCreateDesc hmdCreateDesc(this, deviceId, displayDeviceName);
287 if (wcsstr(ddm.DeviceID, L"OVR0002"))
288 {
289 hmdCreateDesc.SetScreenParameters(mx, my, 1920, 1080, 0.12096f, 0.06804f);
290 }
291 else
292 {
293 if (hmdCreateDesc.Is7Inch())
294 {
295 // Physical dimension of SLA screen.
296 hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.14976f, 0.0936f);
297 }
298 else
299 {
300 hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.12096f, 0.0756f);
301 }
302 }
305 OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %s\n",
306 deviceId.ToCStr(), displayDeviceName.ToCStr()));
308 // Notify caller about detected device. This will call EnumerateAddDevice
309 // if the this is the first time device was detected.
310 visitor.Visit(hmdCreateDesc);
311 foundHMD = true;
312 break;
313 }
314 }
315 }
317 // Real HMD device is not found; however, we still may have a 'fake' HMD
318 // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
319 // Need to find it and set 'Enumerated' to true to avoid Removal notification.
320 if (!foundHMD)
321 {
322 Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
323 if (hmdDevDesc)
324 hmdDevDesc->Enumerated = true;
325 }
326 }
328 DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
329 {
330 return new HMDDevice(this);
331 }
333 bool HMDDeviceCreateDesc::Is7Inch() const
334 {
335 return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
336 }
338 Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
339 {
340 // Create device may override profile name, so get it from there is possible.
341 ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
342 ProfileType profileType = GetProfileType();
343 const char * profileName = pDevice ?
344 ((HMDDevice*)pDevice)->GetProfileName() :
345 profileManager->GetDefaultProfileName(profileType);
347 return profileName ?
348 profileManager->LoadProfile(profileType, profileName) :
349 profileManager->GetDeviceDefaultProfile(profileType);
350 }
353 bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
354 {
355 if ((info->InfoClassType != Device_HMD) &&
356 (info->InfoClassType != Device_None))
357 return false;
359 bool is7Inch = Is7Inch();
361 OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
362 is7Inch ? "Oculus Rift DK1" :
363 ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
364 OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
365 info->Type = Device_HMD;
366 info->Version = 0;
368 // Display detection.
369 if (info->InfoClassType == Device_HMD)
370 {
371 HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
373 hmdInfo->DesktopX = DesktopX;
374 hmdInfo->DesktopY = DesktopY;
375 hmdInfo->HResolution = HResolution;
376 hmdInfo->VResolution = VResolution;
377 hmdInfo->HScreenSize = HScreenSize;
378 hmdInfo->VScreenSize = VScreenSize;
379 hmdInfo->VScreenCenter = VScreenSize * 0.5f;
380 hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
381 hmdInfo->LensSeparationDistance = 0.0635f;
383 // Obtain IPD from profile.
384 Ptr<Profile> profile = *GetProfileAddRef();
386 if (profile)
387 {
388 hmdInfo->InterpupillaryDistance = profile->GetIPD();
389 // TBD: Switch on EyeCup type.
390 }
392 if (Contents & Contents_Distortion)
393 {
394 memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
395 }
396 else
397 {
398 if (is7Inch)
399 {
400 // 7" screen.
401 hmdInfo->DistortionK[0] = 1.0f;
402 hmdInfo->DistortionK[1] = 0.22f;
403 hmdInfo->DistortionK[2] = 0.24f;
404 hmdInfo->EyeToScreenDistance = 0.041f;
405 }
406 else
407 {
408 hmdInfo->DistortionK[0] = 1.0f;
409 hmdInfo->DistortionK[1] = 0.18f;
410 hmdInfo->DistortionK[2] = 0.115f;
412 if (HResolution == 1920)
413 hmdInfo->EyeToScreenDistance = 0.040f;
414 else
415 hmdInfo->EyeToScreenDistance = 0.0387f;
416 }
418 hmdInfo->ChromaAbCorrection[0] = 0.996f;
419 hmdInfo->ChromaAbCorrection[1] = -0.004f;
420 hmdInfo->ChromaAbCorrection[2] = 1.014f;
421 hmdInfo->ChromaAbCorrection[3] = 0.0f;
422 }
424 OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
425 DisplayDeviceName.ToCStr());
426 }
428 return true;
429 }
431 //-------------------------------------------------------------------------------------
432 // ***** HMDDevice
434 HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
435 : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
436 {
437 }
438 HMDDevice::~HMDDevice()
439 {
440 }
442 bool HMDDevice::Initialize(DeviceBase* parent)
443 {
444 pParent = parent;
446 // Initialize user profile to default for device.
447 ProfileManager* profileManager = GetManager()->GetProfileManager();
448 ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
450 return true;
451 }
452 void HMDDevice::Shutdown()
453 {
454 ProfileName.Clear();
455 pCachedProfile.Clear();
456 pParent.Clear();
457 }
459 Profile* HMDDevice::GetProfile() const
460 {
461 if (!pCachedProfile)
462 pCachedProfile = *getDesc()->GetProfileAddRef();
463 return pCachedProfile.GetPtr();
464 }
466 const char* HMDDevice::GetProfileName() const
467 {
468 return ProfileName.ToCStr();
469 }
471 bool HMDDevice::SetProfileName(const char* name)
472 {
473 pCachedProfile.Clear();
474 if (!name)
475 {
476 ProfileName.Clear();
477 return 0;
478 }
479 if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
480 {
481 ProfileName = name;
482 return true;
483 }
484 return false;
485 }
487 OVR::SensorDevice* HMDDevice::GetSensor()
488 {
489 // Just return first sensor found since we have no way to match it yet.
490 OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
491 if (sensor)
492 sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
493 return sensor;
494 }
496 }} // namespace OVR::Win32