oculus1

view libovr/Src/linux/OVR_Linux_HMDDevice.cpp @ 10:b2abb08c8f94

proper FPS-style vr tracking
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 20 Sep 2013 06:49:39 +0300
parents
children
line source
1 /************************************************************************************
3 Filename : OVR_Linux_HMDDevice.h
4 Content : Linux HMDDevice implementation
5 Created : June 17, 2013
6 Authors : Brant Lewis
8 Copyright : Copyright 2013 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_Linux_HMDDevice.h"
18 #include "OVR_Linux_DeviceManager.h"
20 #include "OVR_Profile.h"
22 #include <X11/Xlib.h>
23 #include <X11/extensions/Xinerama.h>
25 namespace OVR { namespace Linux {
27 //-------------------------------------------------------------------------------------
29 HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory, const String& displayDeviceName, long dispId)
30 : DeviceCreateDesc(factory, Device_HMD),
31 DisplayDeviceName(displayDeviceName),
32 DesktopX(0), DesktopY(0), Contents(0),
33 HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
34 DisplayId(dispId)
35 {
36 DeviceId = DisplayDeviceName;
37 }
39 HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
40 : DeviceCreateDesc(other.pFactory, Device_HMD),
41 DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
42 DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
43 HResolution(other.HResolution), VResolution(other.VResolution),
44 HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize),
45 DisplayId(other.DisplayId)
46 {
47 }
49 HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
50 DeviceCreateDesc** pcandidate) const
51 {
52 if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
53 return Match_None;
55 // There are several reasons we can come in here:
56 // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
57 // - Require exact device DeviceId/DeviceName match
58 // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
59 // - This DeviceId is empty; becomes candidate
60 // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
61 // - This other.DeviceId is empty; becomes candidate
63 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
65 if ((DeviceId == s2.DeviceId) &&
66 (DisplayId == s2.DisplayId))
67 {
68 // Non-null DeviceId may match while size is different if screen size was overwritten
69 // by SensorDisplayInfo in prior iteration.
70 if (!DeviceId.IsEmpty() ||
71 ((HScreenSize == s2.HScreenSize) &&
72 (VScreenSize == s2.VScreenSize)) )
73 {
74 *pcandidate = 0;
75 return Match_Found;
76 }
77 }
80 // DisplayInfo takes precedence, although we try to match it first.
81 if ((HResolution == s2.HResolution) &&
82 (VResolution == s2.VResolution) &&
83 (HScreenSize == s2.HScreenSize) &&
84 (VScreenSize == s2.VScreenSize))
85 {
86 if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
87 {
88 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
89 return Match_Candidate;
90 }
92 *pcandidate = 0;
93 return Match_Found;
94 }
96 // SensorDisplayInfo may override resolution settings, so store as candidate.
97 if (s2.DeviceId.IsEmpty())
98 {
99 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
100 return Match_Candidate;
101 }
102 // OTHER HMD Monitor desc may initialize DeviceName/Id
103 else if (DeviceId.IsEmpty())
104 {
105 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
106 return Match_Candidate;
107 }
109 return Match_None;
110 }
113 bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other,
114 bool* newDeviceFlag)
115 {
116 // This candidate was the the "best fit" to apply sensor DisplayInfo to.
117 OVR_ASSERT(other.Type == Device_HMD);
119 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
121 // Force screen size on resolution from SensorDisplayInfo.
122 // We do this because USB detection is more reliable as compared to HDMI EDID,
123 // which may be corrupted by splitter reporting wrong monitor
124 if (s2.DeviceId.IsEmpty())
125 {
126 HScreenSize = s2.HScreenSize;
127 VScreenSize = s2.VScreenSize;
128 Contents |= Contents_Screen;
130 if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
131 {
132 memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
133 Contents |= Contents_Distortion;
134 }
135 DeviceId = s2.DeviceId;
136 DisplayId = s2.DisplayId;
137 DisplayDeviceName = s2.DisplayDeviceName;
138 if (newDeviceFlag) *newDeviceFlag = true;
139 }
140 else if (DeviceId.IsEmpty())
141 {
142 DeviceId = s2.DeviceId;
143 DisplayId = s2.DisplayId;
144 DisplayDeviceName = s2.DisplayDeviceName;
146 // ScreenSize and Resolution are NOT assigned here, since they may have
147 // come from a sensor DisplayInfo (which has precedence over HDMI).
149 if (newDeviceFlag) *newDeviceFlag = true;
150 }
151 else
152 {
153 if (newDeviceFlag) *newDeviceFlag = false;
154 }
156 return true;
157 }
159 bool HMDDeviceCreateDesc::MatchDevice(const String& path)
160 {
161 return DeviceId.CompareNoCase(path) == 0;
162 }
164 //-------------------------------------------------------------------------------------
165 // ***** HMDDeviceFactory
167 HMDDeviceFactory HMDDeviceFactory::Instance;
169 void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
170 {
171 // For now we'll assume the Rift DK1 is attached in extended monitor mode. Ultimately we need to
172 // use XFree86 to enumerate X11 screens in case the Rift is attached as a separate screen. We also
173 // need to be able to read the EDID manufacturer product code to be able to differentiate between
174 // Rift models.
176 bool foundHMD = false;
178 Display* display = XOpenDisplay(NULL);
179 if (display && XineramaIsActive(display))
180 {
181 int numberOfScreens;
182 XineramaScreenInfo* screens = XineramaQueryScreens(display, &numberOfScreens);
184 for (int i = 0; i < numberOfScreens; i++)
185 {
186 XineramaScreenInfo screenInfo = screens[i];
188 if (screenInfo.width == 1280 && screenInfo.height == 800)
189 {
190 String deviceName = "OVR0001";
192 HMDDeviceCreateDesc hmdCreateDesc(this, deviceName, i);
193 hmdCreateDesc.SetScreenParameters(screenInfo.x_org, screenInfo.y_org, 1280, 800, 0.14976f, 0.0936f);
195 OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %d\n",
196 deviceName.ToCStr(), i));
198 // Notify caller about detected device. This will call EnumerateAddDevice
199 // if the this is the first time device was detected.
200 visitor.Visit(hmdCreateDesc);
201 foundHMD = true;
202 break;
203 }
204 }
206 XFree(screens);
207 }
210 // Real HMD device is not found; however, we still may have a 'fake' HMD
211 // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
212 // Need to find it and set 'Enumerated' to true to avoid Removal notification.
213 if (!foundHMD)
214 {
215 Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
216 if (hmdDevDesc)
217 hmdDevDesc->Enumerated = true;
218 }
219 }
221 DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
222 {
223 return new HMDDevice(this);
224 }
226 bool HMDDeviceCreateDesc::Is7Inch() const
227 {
228 return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
229 }
231 Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
232 {
233 // Create device may override profile name, so get it from there is possible.
234 ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
235 ProfileType profileType = GetProfileType();
236 const char * profileName = pDevice ?
237 ((HMDDevice*)pDevice)->GetProfileName() :
238 profileManager->GetDefaultProfileName(profileType);
240 return profileName ?
241 profileManager->LoadProfile(profileType, profileName) :
242 profileManager->GetDeviceDefaultProfile(profileType);
243 }
246 bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
247 {
248 if ((info->InfoClassType != Device_HMD) &&
249 (info->InfoClassType != Device_None))
250 return false;
252 bool is7Inch = Is7Inch();
254 OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
255 is7Inch ? "Oculus Rift DK1" :
256 ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
257 OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
258 info->Type = Device_HMD;
259 info->Version = 0;
261 // Display detection.
262 if (info->InfoClassType == Device_HMD)
263 {
264 HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
266 hmdInfo->DesktopX = DesktopX;
267 hmdInfo->DesktopY = DesktopY;
268 hmdInfo->HResolution = HResolution;
269 hmdInfo->VResolution = VResolution;
270 hmdInfo->HScreenSize = HScreenSize;
271 hmdInfo->VScreenSize = VScreenSize;
272 hmdInfo->VScreenCenter = VScreenSize * 0.5f;
273 hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
274 hmdInfo->LensSeparationDistance = 0.0635f;
276 // Obtain IPD from profile.
277 Ptr<Profile> profile = *GetProfileAddRef();
279 if (profile)
280 {
281 hmdInfo->InterpupillaryDistance = profile->GetIPD();
282 // TBD: Switch on EyeCup type.
283 }
285 if (Contents & Contents_Distortion)
286 {
287 memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
288 }
289 else
290 {
291 if (is7Inch)
292 {
293 // 7" screen.
294 hmdInfo->DistortionK[0] = 1.0f;
295 hmdInfo->DistortionK[1] = 0.22f;
296 hmdInfo->DistortionK[2] = 0.24f;
297 hmdInfo->EyeToScreenDistance = 0.041f;
298 }
299 else
300 {
301 hmdInfo->DistortionK[0] = 1.0f;
302 hmdInfo->DistortionK[1] = 0.18f;
303 hmdInfo->DistortionK[2] = 0.115f;
305 if (HResolution == 1920)
306 hmdInfo->EyeToScreenDistance = 0.040f;
307 else
308 hmdInfo->EyeToScreenDistance = 0.0387f;
309 }
311 hmdInfo->ChromaAbCorrection[0] = 0.996f;
312 hmdInfo->ChromaAbCorrection[1] = -0.004f;
313 hmdInfo->ChromaAbCorrection[2] = 1.014f;
314 hmdInfo->ChromaAbCorrection[3] = 0.0f;
315 }
317 OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
318 DisplayDeviceName.ToCStr());
319 hmdInfo->DisplayId = DisplayId;
320 }
322 return true;
323 }
325 //-------------------------------------------------------------------------------------
326 // ***** HMDDevice
328 HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
329 : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
330 {
331 }
332 HMDDevice::~HMDDevice()
333 {
334 }
336 bool HMDDevice::Initialize(DeviceBase* parent)
337 {
338 pParent = parent;
340 // Initialize user profile to default for device.
341 ProfileManager* profileManager = GetManager()->GetProfileManager();
342 ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
344 return true;
345 }
346 void HMDDevice::Shutdown()
347 {
348 ProfileName.Clear();
349 pCachedProfile.Clear();
350 pParent.Clear();
351 }
353 Profile* HMDDevice::GetProfile() const
354 {
355 if (!pCachedProfile)
356 pCachedProfile = *getDesc()->GetProfileAddRef();
357 return pCachedProfile.GetPtr();
358 }
360 const char* HMDDevice::GetProfileName() const
361 {
362 return ProfileName.ToCStr();
363 }
365 bool HMDDevice::SetProfileName(const char* name)
366 {
367 pCachedProfile.Clear();
368 if (!name)
369 {
370 ProfileName.Clear();
371 return 0;
372 }
373 if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
374 {
375 ProfileName = name;
376 return true;
377 }
378 return false;
379 }
381 OVR::SensorDevice* HMDDevice::GetSensor()
382 {
383 // Just return first sensor found since we have no way to match it yet.
384 OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
385 if (sensor)
386 sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
387 return sensor;
388 }
390 }} // namespace OVR::Linux