OVR_Linux_HMDDevice.cpp
Go to the documentation of this file.
00001 /************************************************************************************
00002 
00003 Filename    :   OVR_Linux_HMDDevice.h
00004 Content     :   Linux HMDDevice implementation
00005 Created     :   June 17, 2013
00006 Authors     :   Brant Lewis
00007 
00008 Copyright   :   Copyright 2013 Oculus VR, Inc. All Rights reserved.
00009 
00010 Use of this software is subject to the terms of the Oculus license
00011 agreement provided at the time of installation or download, or which
00012 otherwise accompanies this software in either electronic or hard copy form.
00013 
00014 *************************************************************************************/
00015 
00016 #include "OVR_Linux_HMDDevice.h"
00017 
00018 #include "OVR_Linux_DeviceManager.h"
00019 
00020 #include "OVR_Profile.h"
00021 
00022 #include <X11/Xlib.h>
00023 #include <X11/extensions/Xinerama.h>
00024 
00025 namespace OVR { namespace Linux {
00026 
00027 //-------------------------------------------------------------------------------------
00028 
00029 HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory, const String& displayDeviceName, long dispId)
00030         : DeviceCreateDesc(factory, Device_HMD),
00031           DisplayDeviceName(displayDeviceName),
00032           DesktopX(0), DesktopY(0), Contents(0),
00033           HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
00034           DisplayId(dispId)
00035 {
00036     DeviceId = DisplayDeviceName;
00037 }
00038 
00039 HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
00040         : DeviceCreateDesc(other.pFactory, Device_HMD),
00041           DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
00042           DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
00043           HResolution(other.HResolution), VResolution(other.VResolution),
00044           HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize),
00045           DisplayId(other.DisplayId)
00046 {
00047 }
00048 
00049 HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
00050                                                                   DeviceCreateDesc** pcandidate) const
00051 {
00052     if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
00053         return Match_None;
00054 
00055     // There are several reasons we can come in here:
00056     //   a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
00057     //          - Require exact device DeviceId/DeviceName match
00058     //   b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
00059     //          - This DeviceId is empty; becomes candidate
00060     //   c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
00061     //          - This other.DeviceId is empty; becomes candidate
00062 
00063     const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
00064 
00065     if ((DeviceId == s2.DeviceId) &&
00066         (DisplayId == s2.DisplayId))
00067     {
00068         // Non-null DeviceId may match while size is different if screen size was overwritten
00069         // by SensorDisplayInfo in prior iteration.
00070         if (!DeviceId.IsEmpty() ||
00071              ((HScreenSize == s2.HScreenSize) &&
00072               (VScreenSize == s2.VScreenSize)) )
00073         {            
00074             *pcandidate = 0;
00075             return Match_Found;
00076         }
00077     }
00078 
00079 
00080     // DisplayInfo takes precedence, although we try to match it first.
00081     if ((HResolution == s2.HResolution) &&
00082         (VResolution == s2.VResolution) &&
00083         (HScreenSize == s2.HScreenSize) &&
00084         (VScreenSize == s2.VScreenSize))
00085     {
00086         if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
00087         {
00088             *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
00089             return Match_Candidate;
00090         }
00091 
00092         *pcandidate = 0;
00093         return Match_Found;
00094     }
00095     
00096     // SensorDisplayInfo may override resolution settings, so store as candidate.
00097     if (s2.DeviceId.IsEmpty())
00098     {        
00099         *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
00100         return Match_Candidate;
00101     }
00102     // OTHER HMD Monitor desc may initialize DeviceName/Id
00103     else if (DeviceId.IsEmpty())
00104     {
00105         *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
00106         return Match_Candidate;
00107     }
00108     
00109     return Match_None;
00110 }
00111 
00112 
00113 bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other, 
00114                                                  bool* newDeviceFlag)
00115 {
00116     // This candidate was the the "best fit" to apply sensor DisplayInfo to.
00117     OVR_ASSERT(other.Type == Device_HMD);
00118     
00119     const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
00120 
00121     // Force screen size on resolution from SensorDisplayInfo.
00122     // We do this because USB detection is more reliable as compared to HDMI EDID,
00123     // which may be corrupted by splitter reporting wrong monitor 
00124     if (s2.DeviceId.IsEmpty())
00125     {
00126         HScreenSize = s2.HScreenSize;
00127         VScreenSize = s2.VScreenSize;
00128         Contents |= Contents_Screen;
00129 
00130         if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
00131         {
00132             memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
00133             Contents |= Contents_Distortion;
00134         }
00135         DeviceId          = s2.DeviceId;
00136         DisplayId         = s2.DisplayId;
00137         DisplayDeviceName = s2.DisplayDeviceName;
00138         if (newDeviceFlag) *newDeviceFlag = true;
00139     }
00140     else if (DeviceId.IsEmpty())
00141     {
00142         DeviceId          = s2.DeviceId;
00143         DisplayId         = s2.DisplayId;
00144         DisplayDeviceName = s2.DisplayDeviceName;
00145 
00146                 // ScreenSize and Resolution are NOT assigned here, since they may have
00147                 // come from a sensor DisplayInfo (which has precedence over HDMI).
00148 
00149         if (newDeviceFlag) *newDeviceFlag = true;
00150     }
00151     else
00152     {
00153         if (newDeviceFlag) *newDeviceFlag = false;
00154     }
00155 
00156     return true;
00157 }
00158 
00159 bool HMDDeviceCreateDesc::MatchDevice(const String& path)
00160 {
00161     return DeviceId.CompareNoCase(path) == 0;
00162 }
00163 
00164 //-------------------------------------------------------------------------------------
00165 // ***** HMDDeviceFactory
00166 
00167 HMDDeviceFactory HMDDeviceFactory::Instance;
00168 
00169 void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
00170 {
00171     // For now we'll assume the Rift DK1 is attached in extended monitor mode. Ultimately we need to
00172     // use XFree86 to enumerate X11 screens in case the Rift is attached as a separate screen. We also
00173     // need to be able to read the EDID manufacturer product code to be able to differentiate between
00174     // Rift models.
00175 
00176     bool foundHMD = false;
00177 
00178     Display* display = XOpenDisplay(NULL);
00179     if (display)
00180     {
00181         int numberOfScreens;
00182         XineramaScreenInfo* screens = XineramaQueryScreens(display, &numberOfScreens);
00183 
00184         for (int i = 0; i < numberOfScreens; i++)
00185         {
00186             XineramaScreenInfo screenInfo = screens[i];
00187 
00188             if (screenInfo.width == 1280 && screenInfo.height == 800)
00189             {
00190                 String deviceName = "OVR0001";
00191 
00192                 HMDDeviceCreateDesc hmdCreateDesc(this, deviceName, i);
00193                 hmdCreateDesc.SetScreenParameters(screenInfo.x_org, screenInfo.y_org, 1280, 800, 0.14976f, 0.0936f);
00194 
00195                 OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %d\n",
00196                                     deviceName.ToCStr(), i));
00197 
00198                 // Notify caller about detected device. This will call EnumerateAddDevice
00199                 // if the this is the first time device was detected.
00200                 visitor.Visit(hmdCreateDesc);
00201                 foundHMD = true;
00202                 break;
00203             }
00204         }
00205 
00206         XFree(screens);
00207     }
00208 
00209 
00210     // Real HMD device is not found; however, we still may have a 'fake' HMD
00211     // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
00212     // Need to find it and set 'Enumerated' to true to avoid Removal notification.
00213     if (!foundHMD)
00214     {
00215         Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
00216         if (hmdDevDesc)
00217             hmdDevDesc->Enumerated = true;
00218     }
00219 }
00220 
00221 DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
00222 {
00223     return new HMDDevice(this);
00224 }
00225 
00226 bool HMDDeviceCreateDesc::Is7Inch() const
00227 {
00228     return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
00229 }
00230 
00231 Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
00232 {
00233     // Create device may override profile name, so get it from there is possible.
00234     ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
00235     ProfileType     profileType    = GetProfileType();
00236     const char *    profileName    = pDevice ?
00237                         ((HMDDevice*)pDevice)->GetProfileName() :
00238                         profileManager->GetDefaultProfileName(profileType);
00239     
00240     return profileName ? 
00241         profileManager->LoadProfile(profileType, profileName) :
00242         profileManager->GetDeviceDefaultProfile(profileType);
00243 }
00244 
00245 
00246 bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
00247 {
00248     if ((info->InfoClassType != Device_HMD) &&
00249         (info->InfoClassType != Device_None))
00250         return false;
00251 
00252     bool is7Inch = Is7Inch();
00253 
00254     OVR_strcpy(info->ProductName,  DeviceInfo::MaxNameLength,
00255                is7Inch ? "Oculus Rift DK1" :
00256                            ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
00257     OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
00258     info->Type    = Device_HMD;
00259     info->Version = 0;
00260 
00261     // Display detection.
00262     if (info->InfoClassType == Device_HMD)
00263     {
00264         HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
00265 
00266         hmdInfo->DesktopX               = DesktopX;
00267         hmdInfo->DesktopY               = DesktopY;
00268         hmdInfo->HResolution            = HResolution;
00269         hmdInfo->VResolution            = VResolution;
00270         hmdInfo->HScreenSize            = HScreenSize;
00271         hmdInfo->VScreenSize            = VScreenSize;
00272         hmdInfo->VScreenCenter          = VScreenSize * 0.5f;
00273         hmdInfo->InterpupillaryDistance = 0.064f;  // Default IPD; should be configurable.
00274         hmdInfo->LensSeparationDistance = 0.0635f;
00275 
00276         // Obtain IPD from profile.
00277         Ptr<Profile> profile = *GetProfileAddRef();
00278 
00279         if (profile)
00280         {
00281             hmdInfo->InterpupillaryDistance = profile->GetIPD();
00282             // TBD: Switch on EyeCup type.
00283         }
00284 
00285         if (Contents & Contents_Distortion)
00286         {
00287             memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
00288         }
00289         else
00290         {                                               
00291                         if (is7Inch)
00292             {
00293                 // 7" screen.
00294                 hmdInfo->DistortionK[0]      = 1.0f;
00295                 hmdInfo->DistortionK[1]      = 0.22f;
00296                 hmdInfo->DistortionK[2]      = 0.24f;
00297                 hmdInfo->EyeToScreenDistance = 0.041f;
00298             }
00299             else
00300             {
00301                 hmdInfo->DistortionK[0]      = 1.0f;
00302                 hmdInfo->DistortionK[1]      = 0.18f;
00303                 hmdInfo->DistortionK[2]      = 0.115f;
00304 
00305                                 if (HResolution == 1920)
00306                                         hmdInfo->EyeToScreenDistance = 0.040f;
00307                                 else
00308                                         hmdInfo->EyeToScreenDistance = 0.0387f;
00309             }
00310 
00311                         hmdInfo->ChromaAbCorrection[0] = 0.996f;
00312                         hmdInfo->ChromaAbCorrection[1] = -0.004f;
00313                         hmdInfo->ChromaAbCorrection[2] = 1.014f;
00314                         hmdInfo->ChromaAbCorrection[3] = 0.0f;
00315         }
00316 
00317         OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
00318                    DisplayDeviceName.ToCStr());
00319         hmdInfo->DisplayId = DisplayId;
00320     }
00321 
00322     return true;
00323 }
00324 
00325 //-------------------------------------------------------------------------------------
00326 // ***** HMDDevice
00327 
00328 HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
00329     : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
00330 {
00331 }
00332 HMDDevice::~HMDDevice()
00333 {
00334 }
00335 
00336 bool HMDDevice::Initialize(DeviceBase* parent)
00337 {
00338     pParent = parent;
00339 
00340     // Initialize user profile to default for device.
00341     ProfileManager* profileManager = GetManager()->GetProfileManager();    
00342     ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
00343 
00344     return true;
00345 }
00346 void HMDDevice::Shutdown()
00347 {
00348     ProfileName.Clear();
00349     pCachedProfile.Clear();
00350     pParent.Clear();
00351 }
00352 
00353 Profile* HMDDevice::GetProfile() const
00354 {    
00355     if (!pCachedProfile)
00356         pCachedProfile = *getDesc()->GetProfileAddRef();
00357     return pCachedProfile.GetPtr();
00358 }
00359 
00360 const char* HMDDevice::GetProfileName() const
00361 {
00362     return ProfileName.ToCStr();
00363 }
00364 
00365 bool HMDDevice::SetProfileName(const char* name)
00366 {
00367     pCachedProfile.Clear();
00368     if (!name)
00369     {
00370         ProfileName.Clear();
00371         return 0;
00372     }
00373     if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
00374     {
00375         ProfileName = name;
00376         return true;
00377     }
00378     return false;
00379 }
00380 
00381 OVR::SensorDevice* HMDDevice::GetSensor()
00382 {
00383     // Just return first sensor found since we have no way to match it yet.
00384     OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
00385     if (sensor)
00386         sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
00387     return sensor;
00388 }
00389 
00390 }} // namespace OVR::Linux
00391 
00392 


oculus_sdk
Author(s):
autogenerated on Fri Aug 28 2015 11:53:11