From e490c3c7f7bb5461cfa78a214827aa534fb43a3e Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Sat, 21 Mar 2015 21:19:34 +0100
Subject: Bump OculusVR RIFT SDK to 0.4.4

---
 LibOVR/Src/Displays/OVR_Linux_Display.cpp | 494 ++++++++++++++++++++++++++++++
 1 file changed, 494 insertions(+)
 create mode 100644 LibOVR/Src/Displays/OVR_Linux_Display.cpp

(limited to 'LibOVR/Src/Displays/OVR_Linux_Display.cpp')

diff --git a/LibOVR/Src/Displays/OVR_Linux_Display.cpp b/LibOVR/Src/Displays/OVR_Linux_Display.cpp
new file mode 100644
index 0000000..4b840dd
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Linux_Display.cpp
@@ -0,0 +1,494 @@
+/************************************************************************************
+
+Filename    :   OVR_Linux_Display.cpp
+Content     :   Linux-specific Display declarations
+Created     :   July 2, 2014
+Authors     :   James Hughes
+
+Copyright   :   Copyright 2014 Oculus VR, LLC All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
+you may not use the Oculus VR Rift SDK except in compliance with the License, 
+which is provided at the time of installation or download, or which 
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.2 
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#include "OVR_Linux_Display.h"
+#include "../Kernel/OVR_Log.h"
+
+#include "../../../3rdParty/EDID/edid.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/Xatom.h>
+
+//-------------------------------------------------------------------------------------
+// ***** Display enumeration Helpers
+
+namespace OVR { 
+
+static const uint8_t edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
+                                          0xff, 0xff, 0xff, 0x00 };
+
+static const uint8_t edid_v1_descriptor_flag[] = { 0x00, 0x00 };
+
+static const int DESCRIPTOR_DATA       =  5;
+static const int UNKNOWN_DESCRIPTOR    = -1;
+static const int DETAILED_TIMING_BLOCK = -2;
+
+// The following three functions were pulled from OVR_Linux_Display.cpp
+// and modified slightly.
+static int blockType(uint8_t* block)
+{
+  if (!strncmp((const char*)edid_v1_descriptor_flag, (const char*)block, 2))
+  {
+    if (block[2] != 0)
+    {
+      return UNKNOWN_DESCRIPTOR;
+    }
+    else
+    {
+      return block[3];
+    }
+  }
+  else
+  {
+    return DETAILED_TIMING_BLOCK;
+  }
+}
+
+static char* getMonitorName(const uint8_t* block)
+{
+  static char     name[13];
+  uint8_t const*  ptr = block + DESCRIPTOR_DATA;
+
+  for (int i = 0; i < 13; i++, ptr++)
+  {
+    if (*ptr == 0xa)
+    {
+      name[i] = 0;
+      return name;
+    }
+
+    name[i] = *ptr;
+  }
+
+  return name;
+}
+
+// Returns -1 on failure, 0 otherwise.
+static int parseEdid(uint8_t* edid, Linux::DisplayEDID& edidResult)
+{
+  const int EDID_LENGTH                        = 0x80;
+  const int EDID_HEADER                        = 0x00;
+  const int EDID_HEADER_END                    = 0x07;
+
+  // const int EDID_STRUCT_VERSION                = 0x12;
+  // const int EDID_STRUCT_REVISION               = 0x13;
+
+  const int MONITOR_NAME                       = 0xfc;
+  // const int MONITOR_LIMITS                     = 0xfd;
+  const int MONITOR_SERIAL                     = 0xff;
+
+  // const int ESTABLISHED_TIMING_1               = 0x23;
+  // const int ESTABLISHED_TIMING_2               = 0x24;
+  // const int MANUFACTURERS_TIMINGS              = 0x25;
+
+  const int DETAILED_TIMING_DESCRIPTIONS_START = 0x36;
+  const int DETAILED_TIMING_DESCRIPTION_SIZE   = 18;
+  const int NO_DETAILED_TIMING_DESCRIPTIONS    = 4;
+
+  // const int DETAILED_TIMING_DESCRIPTION_1      = 0x36;
+  // const int DETAILED_TIMING_DESCRIPTION_2      = 0x48;
+  // const int DETAILED_TIMING_DESCRIPTION_3      = 0x5a;
+  // const int DETAILED_TIMING_DESCRIPTION_4      = 0x6c;
+
+  const char* monitorName = "Unknown";
+  uint8_t*    block       = NULL;
+  uint8_t     checksum    = 0;
+
+  for (int i = 0; i < EDID_LENGTH; i++)
+  {
+    checksum += edid[i];
+  }
+
+  // Bad checksum, fail EDID
+  if (checksum != 0)
+  {
+    return -1;
+  }
+
+  if (strncmp((const char*)edid + EDID_HEADER,
+              (const char*)edid_v1_header, EDID_HEADER_END + 1))
+  {
+    // First bytes don't match EDID version 1 header
+    return -1;
+  }
+
+  // Monitor name and timings
+  char serialNumber[14];
+  memset(serialNumber, 0, 14);
+
+  block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+  for (int i = 0; i < NO_DETAILED_TIMING_DESCRIPTIONS;
+       i++, block += DETAILED_TIMING_DESCRIPTION_SIZE)
+  {
+
+    if (blockType(block) == MONITOR_NAME)
+    {
+      monitorName = getMonitorName(block);
+    }
+
+    if (blockType(block) == MONITOR_SERIAL)
+    {
+      memcpy(serialNumber, block + 5, 13);
+      break;
+    }
+  }
+
+  uint8_t vendorString[4] = {0};
+
+  vendorString[0] = (edid[8] >> 2 & 31) + 64;
+  vendorString[1] = (((edid[8] & 3) << 3) | (edid[9] >> 5)) + 64;
+  vendorString[2] = (edid[9] & 31) + 64;
+
+  edidResult.ModelNumber  = *(uint16_t*)&edid[10];
+  edidResult.MonitorName  = monitorName;
+  edidResult.VendorName   = reinterpret_cast<const char*>(vendorString);
+  edidResult.SerialNumber = serialNumber;
+
+  // FIXME: Get timings as well
+
+  // std::cout << "# EDID version " << static_cast<int>(edid[EDID_STRUCT_VERSION])
+  //           << " revision "      << static_cast<int>(edid[EDID_STRUCT_REVISION])
+  //           << std::endl;
+
+  return 0;
+}
+
+
+// Returns -1 in the case of failure, 0 otherwise.
+// Parameters:
+//  data    OUT This pointer is modified to point to the output from
+//              XRRGetOutputProperty. You *must* call XFree on this pointer.
+//  dataLen OUT The length of the data returned in 'data'.
+static int getXRRProperty(struct _XDisplay* display, RROutput output, Atom atom,
+                          uint8_t** data, int* dataLen)
+{
+  unsigned long nitems;
+  unsigned long bytesAfter;
+  int           actualFormat;
+  Atom          actualType;
+
+  int ret = XRRGetOutputProperty(display, output, atom, 0, 100,
+                                 False, False, AnyPropertyType,
+                                 &actualType, &actualFormat, &nitems,
+                                 &bytesAfter, data);
+
+  if (None != ret)
+  {
+    *dataLen = nitems;
+    return 0;
+  }
+  else
+  {
+    return -1;
+  }
+}
+
+static XRRModeInfo* findModeByXID(XRRScreenResources* screen, RRMode xid)
+{
+  for (int m = 0; m < screen->nmode; ++m)
+  {
+    XRRModeInfo* mode = &screen->modes[m];
+    if (xid == mode->id)
+    {
+      return mode;
+    }
+  }
+  return NULL;
+}
+
+static int discoverExtendedRifts(OVR::Linux::DisplayDesc* descriptorArray, int inputArraySize, bool /*edidInfo*/)
+{
+    int result = 0;
+
+    struct _XDisplay* display = XOpenDisplay(NULL);
+
+    if (display == NULL)
+    {
+        OVR::LogError("[Linux Display] Unable to open X Display!");
+        return 0;
+    }
+
+    Atom EDIDAtom = XInternAtom(display, RR_PROPERTY_RANDR_EDID, False);
+    int numScreens = XScreenCount(display);
+    for (int i = 0; i < numScreens; ++i)
+    {
+        Window sr                       = XRootWindow(display, i);
+        XRRScreenResources* screen      = XRRGetScreenResources(display, sr);
+
+        for (int ii = 0; ii < screen->ncrtc; ++ii)
+        {
+            XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(display, screen, screen->crtcs[ii]);
+
+            if (0 == crtcInfo->noutput)
+            {
+                XRRFreeCrtcInfo(crtcInfo);
+                continue;
+            }
+
+            bool foundOutput = false;
+            RROutput output = crtcInfo->outputs[0];
+            for (int k = 0; k < crtcInfo->noutput; ++k)
+            {
+                XRROutputInfo* outputInfo =
+                    XRRGetOutputInfo(display, screen, crtcInfo->outputs[k]);
+
+                for (int kk = 0; kk < outputInfo->nmode; ++kk)
+                {
+                    if (outputInfo->modes[kk] == crtcInfo->mode)
+                    {
+                        output = crtcInfo->outputs[k];
+                        foundOutput = true;
+                        break;
+                    }
+                }
+                XRRFreeOutputInfo(outputInfo);
+                if (foundOutput)
+                {
+                    break;
+                }
+            }
+
+            if (!foundOutput)
+            {
+                XRRFreeCrtcInfo(crtcInfo);
+                continue;
+            }
+
+            XRROutputInfo* outputInfo = XRRGetOutputInfo(display, screen, output);
+            if (RR_Connected != outputInfo->connection)
+            {
+                XRRFreeOutputInfo(outputInfo);
+                XRRFreeCrtcInfo(crtcInfo);
+                continue;
+            }
+
+            // Read EDID associated with crtc.
+            uint8_t* data    = NULL;
+            int      dataLen = 0;
+            if (getXRRProperty(display, output, EDIDAtom, &data, &dataLen) != 0)
+            {
+                // Identify rifts based on EDID.
+                Linux::DisplayEDID edid;
+                parseEdid(data, edid);
+                XFree(data);
+                data = NULL;
+
+                // TODO: Remove either this 3rdParty call to read EDID data
+                //       or remove our own parsing of the EDID. Probably opt
+                //       to remove our parsing.
+                MonitorInfo* mi = read_edid_data(display, output);
+                if (mi == NULL)
+                {
+                    XRRFreeOutputInfo(outputInfo);
+                    XRRFreeCrtcInfo(crtcInfo);
+                    continue;
+                }
+
+                if (edid.VendorName == "OVR")
+                {
+                    if( result >= inputArraySize )
+                    {
+                        delete mi;
+                        XRRFreeOutputInfo(outputInfo);
+                        XRRFreeCrtcInfo(crtcInfo);
+                        return result;
+                    }
+
+                    XRRModeInfo* modeInfo = findModeByXID(screen, crtcInfo->mode);
+
+                    int width = modeInfo->width;
+                    int height = modeInfo->height;
+
+                    if (   crtcInfo->rotation == RR_Rotate_90
+                        || crtcInfo->rotation == RR_Rotate_270 )
+                    {
+                        width  = modeInfo->height;
+                        height = modeInfo->width;
+                    }
+
+                    int x = crtcInfo->x;
+                    int y = crtcInfo->y;
+
+                    // Generate a device ID string similar Windows does it
+                    char device_id[32];
+                    OVR_sprintf(device_id, 32, "%s%04d-%d",
+                                mi->manufacturer_code, mi->product_code,
+                                screen->crtcs[ii]);
+
+                    OVR::Linux::DisplayDesc& desc = descriptorArray[result++];
+                    desc.DisplayID                 = device_id;
+                    desc.ModelName                 = edid.MonitorName;
+                    desc.EdidSerialNumber          = edid.SerialNumber;
+                    desc.LogicalResolutionInPixels = Sizei(width, height);
+                    desc.DesktopDisplayOffset      = Vector2i(x, y);
+
+                    switch (mi->product_code)
+                    {
+                        case 3: desc.DeviceTypeGuess = HmdType_DK2;       break;
+                        case 2: desc.DeviceTypeGuess = HmdType_DKHDProto; break;
+                        case 1: desc.DeviceTypeGuess = HmdType_DK1;       break;
+
+                        default:
+                        case 0: desc.DeviceTypeGuess = HmdType_Unknown;   break;
+                    }
+
+                    // Hard-coded defaults in case the device doesn't have the
+                    // data itself. DK2 prototypes (0003) or DK HD Prototypes (0002).
+                    if (   desc.DeviceTypeGuess == HmdType_DK2
+                        || desc.DeviceTypeGuess == HmdType_DKHDProto)
+                    {
+                        desc.LogicalResolutionInPixels = Sizei(1920, 1080);
+                        desc.NativeResolutionInPixels  = Sizei(1080, 1920);
+                    }
+                    else
+                    {
+                        desc.LogicalResolutionInPixels = Sizei(width, height);
+                        desc.NativeResolutionInPixels  = Sizei(width, height);
+                    }
+                }
+
+                delete mi;
+                mi = NULL;
+            }
+
+            XRRFreeOutputInfo(outputInfo);
+            XRRFreeCrtcInfo(crtcInfo);
+        }
+
+        XRRFreeScreenResources(screen);
+    }
+
+    XCloseDisplay(display);
+
+    return result;
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** Display 
+
+bool Display::Initialize()
+{
+    // Nothing to initialize. OS X only supports compatibility mode.
+    return true;
+}
+
+bool Display::GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode)
+{
+    driverInstalled = false;
+    compatMode = true;
+    hideDK1Mode = false;
+    return true;
+}
+
+bool Display::SetDriverMode(bool /*compatMode*/, bool /*hideDK1Mode*/)
+{
+    return false;
+}
+
+DisplaySearchHandle* Display::GetDisplaySearchHandle()
+{
+	return new Linux::LinuxDisplaySearchHandle();
+}
+
+bool Display::InCompatibilityMode( bool displaySearch )
+{
+	OVR_UNUSED( displaySearch );
+    return true;
+}
+
+int Display::GetDisplayCount(DisplaySearchHandle* handle, bool extended, bool applicationOnly, bool edidInfo)
+{
+    OVR_UNUSED4(handle, extended, applicationOnly, edidInfo);
+
+	static int extendedCount = -1;
+
+	Linux::LinuxDisplaySearchHandle* localHandle = (Linux::LinuxDisplaySearchHandle*)handle;
+    if (localHandle == NULL)
+    {
+        OVR::LogError("[Linux Display] No search handle passed into GetDisplayCount. Return 0 rifts.");
+        return 0;
+    }
+
+    if (extendedCount == -1 || extended)
+    {
+        extendedCount = discoverExtendedRifts(localHandle->cachedDescriptorArray, Linux::LinuxDisplaySearchHandle::DescArraySize, edidInfo);
+    }
+
+	localHandle->extended = true;
+	localHandle->extendedDisplayCount = extendedCount;
+	int totalCount = extendedCount;
+
+    /// FIXME: Implement application mode for OS X.
+    localHandle->application = false;
+    localHandle->applicationDisplayCount = 0;
+
+    localHandle->displayCount = totalCount;
+
+    return totalCount;
+}
+
+
+Ptr<Display> Display::GetDisplay( int index, DisplaySearchHandle* handle )
+{
+    Ptr<Display> result = NULL;
+
+    if (index < 0)
+    {
+        OVR::LogError("[Linux Display] Invalid index given to GetDisplay.");
+        return NULL;
+    }
+
+	Linux::LinuxDisplaySearchHandle* localHandle = (Linux::LinuxDisplaySearchHandle*)handle;
+    if (localHandle == NULL)
+    {
+        OVR::LogError("[Linux Display] No search handle passed into GetDisplay. Return 0 rifts.");
+        return NULL;
+    }
+
+    if (localHandle->extended)
+    {
+        if (index >= 0 && index < (int)localHandle->extendedDisplayCount)
+        {
+            return *new Linux::LinuxDisplayGeneric(localHandle->cachedDescriptorArray[index]);
+        }
+
+        index -= localHandle->extendedDisplayCount;
+    }
+
+    if (localHandle->application)
+    {
+        OVR::LogError("[Linux Display] Mac does not support application displays.");
+    }
+
+    return result;
+}
+
+
+} // namespace OVR
-- 
cgit v1.2.3