oculus1

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