aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Displays
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-03-21 21:19:34 +0100
committerSven Gothel <[email protected]>2015-03-21 21:19:34 +0100
commite490c3c7f7bb5461cfa78a214827aa534fb43a3e (patch)
treeb86b0291ef529ec6b75cc548d73599fa9c283cd6 /LibOVR/Src/Displays
parent05bb4364bfd9930fb1902efec86446ef035ee07a (diff)
Bump OculusVR RIFT SDK to 0.4.4
Diffstat (limited to 'LibOVR/Src/Displays')
-rw-r--r--LibOVR/Src/Displays/OVR_Display.cpp36
-rw-r--r--LibOVR/Src/Displays/OVR_Display.h203
-rw-r--r--LibOVR/Src/Displays/OVR_Linux_Display.cpp494
-rw-r--r--LibOVR/Src/Displays/OVR_Linux_Display.h133
-rw-r--r--LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp649
-rw-r--r--LibOVR/Src/Displays/OVR_Linux_SDKWindow.h147
-rw-r--r--LibOVR/Src/Displays/OVR_OSX_Display.cpp372
-rw-r--r--LibOVR/Src/Displays/OVR_OSX_Display.h139
-rw-r--r--LibOVR/Src/Displays/OVR_OSX_FocusObserver.h75
-rw-r--r--LibOVR/Src/Displays/OVR_OSX_FocusObserver.mm245
-rw-r--r--LibOVR/Src/Displays/OVR_OSX_FocusReader.h45
-rw-r--r--LibOVR/Src/Displays/OVR_OSX_FocusReader.mm75
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_Display.cpp1323
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_Display.h182
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h429
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp79
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_FocusReader.h81
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp974
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp234
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h79
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_ShimVersion.h47
21 files changed, 6041 insertions, 0 deletions
diff --git a/LibOVR/Src/Displays/OVR_Display.cpp b/LibOVR/Src/Displays/OVR_Display.cpp
new file mode 100644
index 0000000..55eb8a9
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Display.cpp
@@ -0,0 +1,36 @@
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_Display.cpp
+Content : Common implementation for display device
+Created : May 6, 2014
+Notes :
+
+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_Display.h"
+
+namespace OVR {
+
+
+// Place platform-independent code here
+
+
+} // namespace OVR
diff --git a/LibOVR/Src/Displays/OVR_Display.h b/LibOVR/Src/Displays/OVR_Display.h
new file mode 100644
index 0000000..46e9f13
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Display.h
@@ -0,0 +1,203 @@
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_Display.h
+Content : Contains platform independent display management
+Created : May 6, 2014
+Notes :
+
+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.
+
+************************************************************************************/
+
+#ifndef OVR_Display_h
+#define OVR_Display_h
+
+#include "../Sensors/OVR_DeviceConstants.h" // Required for HmdTypeEnum
+
+#include "../Kernel/OVR_Types.h"
+#include "../Kernel/OVR_Atomic.h"
+#include "../Kernel/OVR_RefCount.h"
+#include "../Kernel/OVR_Array.h"
+#include "../Kernel/OVR_String.h"
+#include "../Kernel/OVR_Math.h"
+
+namespace OVR {
+
+
+class DisplaySearchHandle : virtual public RefCountBaseV<DisplaySearchHandle>
+{
+public:
+ DisplaySearchHandle() {}
+
+ virtual ~DisplaySearchHandle() {}
+
+ void operator= (const DisplaySearchHandle&) {}
+};
+
+//-------------------------------------------------------------------------------------
+// ***** Display
+
+// Display object describes an Oculus HMD screen in LibOVR, providing information such
+// as EDID serial number and resolution in platform-independent manner.
+//
+// Display is an abstract base class to support OS and driver specific implementations.
+// It support HMD screen enumeration through GetDisplayCount/GetDisplay static functions.
+//
+// Examples of implementations of Display are the following:
+// Display_Win32_Generic - Compatibly mode implementation that maintains operation on
+// systems without drivers.
+// Display_Win32_Driver - Driver-Based display
+// Display_OSX_Generic - Additional compatibility mode implementation for OS X
+
+class Display : public RefCountBase<Display>
+{
+protected:
+ enum MirrorMode
+ {
+ MirrorEnabled = 0,
+ MirrorDisabled = 1
+ };
+
+ MirrorMode mirrorMode;
+
+ Display(
+ HmdTypeEnum deviceTypeGuess,
+#ifdef OVR_OS_MAC
+ uint32_t displayID,
+#else
+ const String& displayID,
+#endif
+ const String& modelName,
+ const String& editSerial,
+ const Sizei& logicalRes,
+ const Sizei& nativeRes,
+ const Vector2i& displayOffset,
+ const uint64_t devNumber,
+ const uint32_t rotation,
+ const bool appExclusive):
+ mirrorMode(MirrorDisabled),
+ DeviceTypeGuess(deviceTypeGuess),
+ DisplayID(displayID),
+ ModelName(modelName),
+ EdidSerialNumber(editSerial),
+ LogicalResolutionInPixels(logicalRes),
+ NativeResolutionInPixels(nativeRes),
+ DesktopDisplayOffset(displayOffset),
+ DeviceNumber(devNumber),
+ Rotation(rotation),
+ ApplicationExclusive(appExclusive)
+ {
+ }
+
+ void operator = (const Display&) { } // Quiet warning.
+
+public:
+ virtual ~Display() { }
+
+ // ----- Platform specific static Display functionality -----
+
+ // Mandatory function that sets up the display environment with
+ // any necessary shimming and function hooks. This should be one
+ // of the very first things your application does when it
+ // initializes LibOVR
+ static bool Initialize();
+
+ // Returns a count of the detected displays. These are Rift displays
+ // attached directly to an active display port
+ static int GetDisplayCount( DisplaySearchHandle* handle = NULL, bool extended = true, bool applicationOnly = true, bool extendedEDIDSerials = false );
+ // Returns a specific index of a display. Displays are sorted in no particular order.
+ static Ptr<Display> GetDisplay( int index = 0, DisplaySearchHandle* handle = NULL );
+
+
+ // Returns true if we are referencing the same display; useful for matching display
+ // objects with the ones already detected.
+ bool MatchDisplay(const Display* other)
+ {
+ // Note this is not checking the DeviceName, which corresponds to which monitor the device is.
+ // This allows matching to match a display that has changed how it is plugged in.
+ return (DisplayID == other->DisplayID) &&
+ (EdidSerialNumber == other->EdidSerialNumber) &&
+ (NativeResolutionInPixels == other->NativeResolutionInPixels) &&
+ (DesktopDisplayOffset == other->DesktopDisplayOffset) &&
+ (ApplicationExclusive == other->ApplicationExclusive);
+ }
+
+
+ // ----- Device independent instance based Display functionality -----
+
+ // Device type guess based on display info.
+ const HmdTypeEnum DeviceTypeGuess;
+#if defined(OVR_OS_MAC)
+ // CGDirectDisplayID for the rift.
+ const uint32_t DisplayID;
+#else
+ // A string denoting the display device name so that apps can recognize the monitor
+ const String DisplayID;
+#endif
+ // A literal string containing the name of the model, i.e. Rift DK2
+ const String ModelName;
+ // Part of the serial number encoded in Edid, used for monitor <-> sensor matching.
+ const String EdidSerialNumber;
+ // Logical resolution is the display resolution in presentation terms.
+ // That is to say, the resolution that represents the orientation the
+ // display is projected to the user. For DK2, while being a portrait display
+ // the display is held in landscape and therefore the logical resolution
+ // is 1920x1080
+ const Sizei LogicalResolutionInPixels;
+ // Native resolution is the resolution reported by the EDID and represents the
+ // exact hardware resolution of the Rift. For example, on DK2
+ // this is 1080x1920
+ // In theory, an OS rotated Rift's native and logical resolutions should match
+ const Sizei NativeResolutionInPixels;
+ // For displays that are attached to the desktop, this return value has meaning.
+ // Otherwise it should always return origin
+ const Vector2i DesktopDisplayOffset;
+ // For Windows machines this value stores the ChildUid used to identify this display
+ const uint64_t DeviceNumber;
+ // Stores the device specific default rotation of the screen
+ // E.g. DK2 is rotated 90 degrees as it is a portrait display
+ const uint32_t Rotation;
+ // Is set if the Display is capable in Application-Only mode
+ const bool ApplicationExclusive;
+
+ // Functionality for rendering within the window
+ virtual MirrorMode SetMirrorMode( MirrorMode newMode ) = 0;
+
+ // Functionality for enabling/disabling display
+ virtual bool SetDisplaySleep(bool off)
+ {
+ // Override to implement if supported
+ OVR_UNUSED(off);
+ return false;
+ }
+
+ // Check if right now the current rendering application should be in compatibility mode
+ static bool InCompatibilityMode( bool displaySearch = true );
+
+ // Get/set the mode for all applications
+ static bool GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode);
+ static bool SetDriverMode(bool compatMode, bool hideDK1Mode);
+
+ static DisplaySearchHandle* GetDisplaySearchHandle();
+};
+
+
+} // namespace OVR
+
+#endif
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
diff --git a/LibOVR/Src/Displays/OVR_Linux_Display.h b/LibOVR/Src/Displays/OVR_Linux_Display.h
new file mode 100644
index 0000000..f685e6b
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Linux_Display.h
@@ -0,0 +1,133 @@
+/************************************************************************************
+
+Filename : OVR_Linux_Display.h
+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.
+
+*************************************************************************************/
+
+#ifndef OVR_Linux_Display_h
+#define OVR_Linux_Display_h
+
+#include "OVR_Display.h"
+
+namespace OVR { namespace Linux {
+
+
+//-------------------------------------------------------------------------------------
+// DisplayDesc
+
+// Display information enumerable through OS .
+// TBD: Should we just move this to public header, so it's a const member of Display?
+struct DisplayDesc
+{
+ HmdTypeEnum DeviceTypeGuess;
+ String DisplayID; // This is the device identifier string from MONITORINFO (for app usage)
+ String ModelName; // This is a "DK2" type string
+ String EdidSerialNumber;
+ Sizei LogicalResolutionInPixels;
+ Sizei NativeResolutionInPixels;
+ Vector2i DesktopDisplayOffset;
+};
+
+
+//-------------------------------------------------------------------------------------
+// DisplayEDID
+
+// Describes EDID information as reported from our display driver.
+struct DisplayEDID
+{
+ DisplayEDID() :
+ ModelNumber(0)
+ {}
+
+ String MonitorName;
+ UInt16 ModelNumber;
+ String VendorName;
+ String SerialNumber;
+};
+
+
+//-------------------------------------------------------------------------------------
+// Linux Display Search Handle
+class LinuxDisplaySearchHandle : public DisplaySearchHandle
+{
+public:
+ LinuxDisplaySearchHandle() :
+ extended(false),
+ application(false),
+ extendedDisplayCount(0),
+ applicationDisplayCount(0),
+ displayCount(0)
+ {}
+ virtual ~LinuxDisplaySearchHandle() {}
+
+ static const int DescArraySize = 16;
+
+ Linux::DisplayDesc cachedDescriptorArray[DescArraySize];
+ bool extended;
+ bool application;
+ int extendedDisplayCount;
+ int applicationDisplayCount;
+ int displayCount;
+};
+
+//-------------------------------------------------------------------------------------
+// LinuxDisplayGeneric
+
+// Describes Linux display in Compatibility mode, containing basic data
+class LinuxDisplayGeneric : public Display
+{
+public:
+ LinuxDisplayGeneric( const DisplayDesc& dd ) :
+ Display(dd.DeviceTypeGuess,
+ dd.DisplayID,
+ dd.ModelName,
+ dd.EdidSerialNumber,
+ dd.LogicalResolutionInPixels,
+ dd.NativeResolutionInPixels,
+ dd.DesktopDisplayOffset,
+ 0,
+ 0,
+ false)
+ {
+ }
+
+ virtual ~LinuxDisplayGeneric()
+ {
+ }
+
+ virtual bool InCompatibilityMode() const
+ {
+ return true;
+ }
+
+ // Generic displays are not capable of mirroring
+ virtual MirrorMode SetMirrorMode( MirrorMode newMode )
+ {
+ OVR_UNUSED( newMode );
+ return MirrorDisabled;
+ }
+};
+
+}} // namespace OVR::Linux
+
+#endif // OVR_Linux_Display_h
diff --git a/LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp
new file mode 100644
index 0000000..3d76f69
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp
@@ -0,0 +1,649 @@
+/*******************************************************************************
+
+Filename : OVR_Linux_SDKWindow.cpp
+Content : SDK generated Linux window.
+Created : October 1, 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_SDKWindow.h"
+#include "../Kernel/OVR_Log.h"
+#include "../Kernel/OVR_Log.h"
+#include "../../../3rdParty/EDID/edid.h"
+
+namespace OVR {
+
+// Forward declarations
+static Window constructWindow(struct _XDisplay* display, int xscreen,
+ XVisualInfo* xvisual,
+ const LinuxDeviceScreen& screen);
+
+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;
+}
+
+/// Retrieves a list of available device screens on which we can build
+/// SDK windows. Returns number of devices found.
+/// screens Array which this function will populate.
+/// maxNumScreens Maximum number of screens to store in screens.
+static int getDeviceScreens(LinuxDeviceScreen* screens, int maxNumDevices)
+{
+ struct _XDisplay* disp = XOpenDisplay(NULL);
+ if (!disp)
+ {
+ OVR::LogError("[SDKWindow] Unable to open X Display.");
+ return 0;
+ }
+
+ int numDevices = 0;
+ int numScreens = XScreenCount(disp);
+ for (int i = 0; i < numScreens; ++i)
+ {
+ // Screen root is used to detect what video output the crtc is using.
+ Window sr = XRootWindow(disp, i);
+ XRRScreenResources* screen = XRRGetScreenResources(disp, sr);
+
+ for (int ii = 0; ii < screen->ncrtc; ++ii)
+ {
+ XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(disp, 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(disp, 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(disp, screen, output);
+ if (RR_Connected != outputInfo->connection)
+ {
+ XRRFreeOutputInfo(outputInfo);
+ XRRFreeCrtcInfo(crtcInfo);
+ continue;
+ }
+
+ // Read EDID associated with crtc.
+ MonitorInfo* mi = read_edid_data(disp, output);
+ if (mi == NULL)
+ {
+ XRRFreeOutputInfo(outputInfo);
+ XRRFreeCrtcInfo(crtcInfo);
+ continue;
+ }
+
+ if (strcmp(mi->manufacturer_code, "OVR") == 0)
+ {
+ XRRModeInfo* modeInfo = findModeByXID(screen, crtcInfo->mode);
+
+ DistortionRotation desiredRot = DistRotateNone;
+ if (mi->product_code == 3)
+ {
+ // This is a DK2, we may have to rotate our output.
+ // If we don't have to, we should alert the user that
+ // rotating the display using the DM or graphics
+ // card settings is highly non-optimal.
+ desiredRot = DistRotateCCW90;
+ if (crtcInfo->rotation != RR_Rotate_0)
+ {
+ OVR::LogError("Please do not rotate your rift's screen.");
+
+ if (crtcInfo->rotation == RR_Rotate_90)
+ {
+ // The user has manually rotated the screen.
+ // So apply no rotation on our end.
+ desiredRot = DistRotateNone;
+ }
+ }
+ }
+ else
+ {
+ if (crtcInfo->rotation != RR_Rotate_0)
+ {
+ OVR::LogError("Please do not rotate your rift's screen.");
+ }
+ }
+
+ int width = modeInfo->width;
+ int height = modeInfo->height;
+
+ // Swap width / height if display is rotated (shouldn't be on linux).
+ if ( crtcInfo->rotation == RR_Rotate_90
+ || crtcInfo->rotation == RR_Rotate_270)
+ {
+ width = modeInfo->height;
+ height = modeInfo->width;
+ }
+
+ // Push detected monitor.
+ screens[numDevices].set(i, screen->crtcs[ii], desiredRot,
+ mi->product_code, width, height,
+ crtcInfo->x, crtcInfo->y);
+ ++numDevices;
+ }
+
+ delete mi;
+
+ if (numDevices == maxNumDevices)
+ {
+ XRRFreeOutputInfo(outputInfo);
+ XRRFreeCrtcInfo(crtcInfo);
+ XRRFreeScreenResources(screen);
+ OVR::LogError("[SDKWindow] Maxed out number of devices..");
+ XCloseDisplay(disp);
+ return numDevices;
+ }
+
+ XRRFreeOutputInfo(outputInfo);
+ XRRFreeCrtcInfo(crtcInfo);
+ }
+
+ XRRFreeScreenResources(screen);
+ }
+ XCloseDisplay(disp);
+ return numDevices;
+}
+
+
+LinuxDeviceScreen SDKWindow::findDevScreenForHMD(const ovrHmd& hmd)
+{
+ return findDevScreenForDevID(hmd->DisplayDeviceName);
+}
+
+LinuxDeviceScreen SDKWindow::findDevScreenForDevID(const char* deviceIDIn)
+{
+ const int maxNumDevices = 5;
+ LinuxDeviceScreen screens[maxNumDevices];
+ int numDevices = getDeviceScreens(screens, maxNumDevices);
+
+ if (numDevices > 0)
+ {
+ // Identify target for SDK window via hmd info.
+ for (int i = 0; i < numDevices; ++i)
+ {
+ LinuxDeviceScreen& screen = screens[i];
+
+ char deviceID[32];
+ OVR_sprintf(deviceID, 32, "OVR%04d-%d",
+ screen.productCode, screen.crtcid);
+
+ if (strcmp(deviceIDIn, deviceID) == 0)
+ {
+ return screen;
+ }
+ }
+ }
+
+ return LinuxDeviceScreen();
+}
+
+DistortionRotation SDKWindow::getRotation(const ovrHmd& hmd)
+{
+ LinuxDeviceScreen screen = findDevScreenForHMD(hmd);
+ if (screen.isValid())
+ {
+ return screen.rotation;
+ }
+ else
+ {
+ return DistRotateNone;
+ }
+}
+
+
+bool SDKWindow::getVisualFromDrawable(GLXDrawable drawable, XVisualInfo* vinfoOut)
+{
+ struct _XDisplay* display = glXGetCurrentDisplay();
+
+ unsigned int value;
+ glXQueryDrawable(display, drawable, GLX_FBCONFIG_ID, &value);
+ const int attribs[] = {GLX_FBCONFIG_ID, (int)value, None};
+ int screen;
+ glXQueryContext(display, glXGetCurrentContext(), GLX_SCREEN, &screen);
+ int numElems;
+ GLXFBConfig* config = glXChooseFBConfig(display, screen, attribs, &numElems);
+ if (numElems > 0)
+ {
+ XVisualInfo* chosen = glXGetVisualFromFBConfig(display, *config);
+ *vinfoOut = *chosen;
+ XFree(config);
+ return true;
+ }
+ return false;
+}
+
+SDKWindow::SDKWindow(const ovrHmd& hmd) :
+ mXDisplay(NULL),
+ mXScreen(-1),
+ mXVisual(NULL),
+ mXUniqueContext(-1),
+ mXWindow(0),
+ mFBConfigID(0)
+{
+ OVR_UNUSED(hmd);
+}
+
+SDKWindow::~SDKWindow()
+{
+ if (mXWindow)
+ {
+ XDeleteContext(mXDisplay, mXWindow, mXUniqueContext);
+ XUnmapWindow(mXDisplay, mXWindow);
+ XDestroyWindow(mXDisplay, mXWindow);
+ mXWindow = static_cast<Window>(0);
+ }
+
+ if (mXVisual)
+ {
+ XFree(mXVisual);
+ mXVisual = NULL;
+ }
+
+ if (mXDisplay)
+ {
+ XCloseDisplay(mXDisplay);
+ }
+}
+
+void SDKWindow::buildVisualAndWindow(const LinuxDeviceScreen& devScreen)
+{
+ mXDisplay = XOpenDisplay(NULL);
+ mXUniqueContext = XUniqueContext();
+ mXScreen = devScreen.screen;
+ mFBConfigID = chooseFBConfigID(mXDisplay, mXScreen);
+
+ mXVisual = getVisual(mXDisplay, mFBConfigID, mXScreen);
+ if (mXVisual != NULL)
+ {
+ mXWindow = constructWindow(mXDisplay, mXScreen, mXVisual, devScreen);
+ mDeviceScreen = devScreen;
+ }
+}
+
+// Used in chooseVisual. May need to expose this to the end use so they can
+// choose an appropriate framebuffer configuration.
+struct FBConfig
+{
+ FBConfig() :
+ redBits(8),
+ greenBits(8),
+ blueBits(8),
+ alphaBits(8),
+ depthBits(8),
+ stencilBits(-1),
+ doubleBuffer(true),
+ auxBuffers(-1)
+ {}
+
+ int redBits;
+ int greenBits;
+ int blueBits;
+ int alphaBits;
+ int depthBits;
+ int stencilBits;
+ bool doubleBuffer;
+ int auxBuffers;
+
+ int xcfg;
+};
+
+static int fbCalcContrib(int desired, int current)
+{
+ int diff = desired - current;
+ if (current != -1) { return diff * diff; }
+ else { return 0; }
+}
+
+// Choose frame buffer configuration and return fbConfigID.
+int SDKWindow::chooseFBConfigID(struct _XDisplay* display, int xscreen)
+{
+ int nativeCount = 0;
+ GLXFBConfig* nativeConfigs =
+ glXGetFBConfigs(display, xscreen, &nativeCount);
+ if (!nativeCount)
+ {
+ OVR::LogError("[SDKWindow] No valid frame buffer configurations found.");
+ return 0;
+ }
+
+ FBConfig* usables = static_cast<FBConfig*>(calloc(nativeCount, sizeof(FBConfig)));
+ int numUsables = 0;
+
+ for (int i = 0; i < nativeCount; ++i)
+ {
+ GLXFBConfig native = nativeConfigs[i];
+ FBConfig* usable = &usables[numUsables];
+ int v = 0;
+
+ // Only frame buffer configcs with attached visuals.
+ glXGetFBConfigAttrib(display, native, GLX_VISUAL_ID, &v);
+ if (!v) { continue; }
+
+ // Only RGBA frame buffers.
+ glXGetFBConfigAttrib(display, native, GLX_RENDER_TYPE, &v);
+ if (!(v & GLX_RGBA_BIT)) { continue; }
+
+ glXGetFBConfigAttrib(display, native, GLX_DRAWABLE_TYPE, &v);
+ if (!(v & GLX_WINDOW_BIT)) { continue; }
+
+ glXGetFBConfigAttrib(display, native, GLX_DEPTH_SIZE, &usable->depthBits);
+ glXGetFBConfigAttrib(display, native, GLX_STENCIL_SIZE, &usable->stencilBits);
+
+ glXGetFBConfigAttrib(display, native, GLX_RED_SIZE, &usable->redBits);
+ glXGetFBConfigAttrib(display, native, GLX_GREEN_SIZE, &usable->greenBits);
+ glXGetFBConfigAttrib(display, native, GLX_BLUE_SIZE, &usable->blueBits);
+ glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->alphaBits);
+
+ glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->auxBuffers);
+
+ glXGetFBConfigAttrib(display, native, GLX_DOUBLEBUFFER, &v);
+ usable->doubleBuffer = v ? true : false;
+
+ glXGetFBConfigAttrib(display, native, GLX_FBCONFIG_ID, &usable->xcfg);
+
+ ++numUsables;
+ }
+
+ // We really want std::numeric_limits<int>::max() instead of hardcoded vals.
+ const int MostMissing = 100;
+ int leastMissing = MostMissing;
+ int leastBias = MostMissing;
+
+ const FBConfig* closest = NULL;
+
+ // Desired is currently the default config built by constructor.
+ FBConfig desired;
+
+ for (int i = 0; i < numUsables; ++i)
+ {
+ const FBConfig* cur = &usables[i];
+
+ if (desired.doubleBuffer != cur->doubleBuffer) { continue; }
+
+ int missing = 0;
+ if (desired.alphaBits > 0 && cur->alphaBits == 0) { ++missing; }
+ if (desired.depthBits > 0 && cur->depthBits == 0) { ++missing; }
+ if (desired.stencilBits > 0 && cur->stencilBits == 0) { ++missing; }
+ if (desired.redBits > 0 && desired.redBits != cur->redBits) { ++missing; }
+ if (desired.greenBits > 0 && desired.greenBits != cur->greenBits) { ++missing; }
+ if (desired.blueBits > 0 && desired.blueBits != cur->blueBits) { ++missing; }
+
+ int bias = fbCalcContrib(desired.redBits, cur->redBits)
+ + fbCalcContrib(desired.greenBits, cur->greenBits)
+ + fbCalcContrib(desired.blueBits, cur->blueBits)
+ + fbCalcContrib(desired.alphaBits, cur->alphaBits)
+ + fbCalcContrib(desired.depthBits, cur->depthBits)
+ + fbCalcContrib(desired.stencilBits, cur->stencilBits);
+
+ if (missing < leastMissing)
+ {
+ closest = cur;
+ }
+ else if (missing == leastMissing)
+ {
+ // Now select against squared differences.
+ if (bias < leastBias)
+ {
+ closest = cur;
+ }
+ }
+
+ if (closest == cur)
+ {
+ leastMissing = missing;
+ leastBias = bias;
+ }
+ }
+
+ if (closest == NULL)
+ {
+ OVR::LogError("[SDKWindow] Failed to select appropriate frame buffer.");
+ XFree(nativeConfigs);
+ free(usables);
+ return 0;
+ }
+
+ int retVal = closest->xcfg;
+
+ XFree(nativeConfigs);
+ free(usables);
+
+ return retVal;
+}
+
+// Obtain visual from frame buffer configuration ID.
+XVisualInfo* SDKWindow::getVisual(struct _XDisplay* display,
+ int fbConfigID, int xscreen)
+{
+ GLXFBConfig* cfg = getGLXFBConfig(display, fbConfigID, xscreen);
+ XVisualInfo* viOut = NULL;
+ if (cfg != NULL)
+ {
+ viOut = glXGetVisualFromFBConfig(display, *cfg);
+ XFree(cfg);
+ cfg = NULL;
+ }
+ else
+ {
+ OVR::LogError("Unable to find fb config ID.");
+ }
+ return viOut;
+}
+
+// GLXFBConfig pointer from frame buffer configuration ID. You must call
+// XFree on the GLXFBConfig pointer.
+GLXFBConfig* SDKWindow::getGLXFBConfig(struct _XDisplay* display,
+ int fbConfigID, int xscreen)
+{
+ const int attribs[] = {GLX_FBCONFIG_ID, (int)fbConfigID, None};
+ int numElems;
+
+ GLXFBConfig* config = glXChooseFBConfig(display, xscreen, attribs, &numElems);
+ if (numElems > 0)
+ {
+ return config;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+static int gXLastError = -1;
+static int handleXError(struct _XDisplay* display, XErrorEvent* event)
+{
+ OVR_UNUSED(display);
+ gXLastError = event->error_code;
+ return 0;
+}
+
+static void obtainXErrorHandler()
+{
+ gXLastError = Success;
+ XSetErrorHandler(handleXError);
+}
+
+static void releaseXErrorHandler(struct _XDisplay* display)
+{
+ XSync(display, False);
+ XSetErrorHandler(NULL);
+}
+
+// Returns 0 on error, otherwise a valid X window is returned.
+static Window constructWindow(struct _XDisplay* xDisp, int xScreen,
+ XVisualInfo* xVisual,
+ const LinuxDeviceScreen& devScreen)
+{
+ XSetWindowAttributes wa;
+
+ Window root = XRootWindow(xDisp, xScreen);
+ Window xWindowOut = 0;
+
+ // Create Window
+ {
+ Colormap xWinColorMapOut = XCreateColormap(
+ xDisp, root, xVisual->visual, AllocNone);
+ unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask;
+
+ wa.colormap = xWinColorMapOut;
+ wa.border_pixel = 0;
+ wa.event_mask = StructureNotifyMask | ExposureMask | FocusChangeMask
+ | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask
+ | PropertyChangeMask;
+
+ obtainXErrorHandler();
+
+ xWindowOut = XCreateWindow(xDisp, root,
+ 0, 0,
+ devScreen.width, devScreen.height,
+ 0,
+ xVisual->depth,
+ InputOutput,
+ xVisual->visual,
+ wamask,
+ &wa);
+
+ releaseXErrorHandler(xDisp);
+
+ if (!xWindowOut)
+ {
+ OVR::LogError("[SDKWindow] Failed to create SDK window.");
+ return 0;
+ }
+
+ XFreeColormap(xDisp, xWinColorMapOut);
+ }
+
+ // OVERRIDE REDIRECT.
+ XSetWindowAttributes attributes;
+ attributes.override_redirect = True;
+ XChangeWindowAttributes(xDisp, xWindowOut,
+ CWOverrideRedirect, &attributes);
+
+ // Show the window (do this in full screen or windowed).
+ XMapRaised(xDisp, xWindowOut);
+ XFlush(xDisp);
+
+ // Position ourselves manually since there should be no WM managing us.
+ XRaiseWindow(xDisp, xWindowOut);
+ XMoveWindow(xDisp, xWindowOut, devScreen.offsetX, devScreen.offsetY);
+ XResizeWindow(xDisp, xWindowOut, devScreen.width, devScreen.height);
+
+ XFlush(xDisp);
+
+ // WM Backup in case there still exists a WM managing us...
+ Atom NET_WM_BYPASS_COMPOSITOR =
+ XInternAtom(xDisp, "_NET_WM_BYPASS_COMPOSITOR", False);
+ Atom NET_WM_STATE =
+ XInternAtom(xDisp, "_NET_WM_STATE", False);
+ Atom NET_WM_STATE_FULLSCREEN =
+ XInternAtom(xDisp, "_NET_WM_STATE_FULLSCREEN", False);
+ Atom NET_ACTIVE_WINDOW =
+ XInternAtom(xDisp, "_NET_ACTIVE_WINDOW", False);
+
+ // Bypass compositor if we are under a compositing WM.
+ // Just in case a WM ignores our override_redirect.
+ if (NET_WM_BYPASS_COMPOSITOR)
+ {
+ const unsigned long bypass = 1;
+ XChangeProperty(xDisp, xWindowOut,
+ NET_WM_BYPASS_COMPOSITOR,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char*)&bypass, 1);
+ }
+
+ if (NET_WM_STATE && NET_WM_STATE_FULLSCREEN)
+ {
+ // BACKUP: If we are still managed by a WM we want fullscreen.
+ const int EWMH_STATE_ADD = 1;
+
+ if (NET_ACTIVE_WINDOW)
+ {
+ XEvent event;
+ memset(&event, 0, sizeof(event));
+
+ event.type = ClientMessage;
+ event.xclient.window = xWindowOut;
+ event.xclient.format = 32;
+ event.xclient.message_type = NET_ACTIVE_WINDOW;
+ event.xclient.data.l[0] = 1;
+ event.xclient.data.l[1] = 0;
+
+ XSendEvent(xDisp, root, False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &event);
+ }
+
+ XEvent event;
+ memset(&event, 0, sizeof(event));
+
+ event.type = ClientMessage;
+ event.xclient.window = xWindowOut;
+ event.xclient.format = 32;
+ event.xclient.message_type = NET_WM_STATE;
+ event.xclient.data.l[0] = EWMH_STATE_ADD;
+ event.xclient.data.l[1] = NET_WM_STATE_FULLSCREEN;
+ event.xclient.data.l[2] = 0;
+ event.xclient.data.l[3] = 1;
+
+ XSendEvent(xDisp, root, False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &event);
+ }
+
+ return xWindowOut;
+}
+
+} // namespace OVR
+
diff --git a/LibOVR/Src/Displays/OVR_Linux_SDKWindow.h b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.h
new file mode 100644
index 0000000..70b95dd
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.h
@@ -0,0 +1,147 @@
+/*******************************************************************************
+
+Filename : OVR_Linux_SDKWindow.h
+Content : SDK generated Linux window.
+Created : October 1, 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.
+
+*******************************************************************************/
+
+#ifndef OVR_Linux_SDKWindow_h
+#define OVR_Linux_SDKWindow_h
+
+#include "../OVR_CAPI.h"
+#include "../CAPI/GL/CAPI_GL_Util.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/Xresource.h>
+#include <GL/glx.h>
+
+namespace OVR {
+
+enum DistortionRotation
+{
+ DistRotateNone,
+ DistRotateCCW90
+};
+
+struct LinuxDeviceScreen
+{
+ LinuxDeviceScreen() :
+ screen(-1),
+ crtcid(0),
+ rotation(DistRotateNone),
+ productCode(-1),
+ width(-1),
+ height(-1),
+ offsetX(-1),
+ offsetY(-1)
+ {}
+
+ void set(int xScreen, XID xid, DistortionRotation rot, int prodCode,
+ int w, int h, int x, int y)
+ {
+ screen = xScreen;
+ crtcid = xid;
+ rotation = rot;
+ productCode = prodCode;
+
+ width = w;
+ height = h;
+ offsetX = x;
+ offsetY = y;
+ }
+
+ bool isValid() {return (screen != -1);}
+
+ int screen; ///< X Screen this device occupies.
+ XID crtcid; ///< XID uniquely identifying this device on XDisplay.
+ DistortionRotation rotation;
+ int productCode;
+
+ // Actual width and height of screen.
+ int width;
+ int height;
+
+ // Offset if using twinview
+ int offsetX;
+ int offsetY;
+};
+
+class SDKWindow
+{
+public:
+
+ SDKWindow(const ovrHmd& hmd);
+ ~SDKWindow();
+
+ /// Rotation necessary to correctly orient this SDK window.
+ DistortionRotation GetDistortionRotation() {return mDeviceScreen.rotation;}
+
+ struct _XDisplay* GetDisplay() {return mXDisplay;}
+ XVisualInfo* GetVisual() {return mXVisual;}
+ Window GetDrawable() {return mXWindow;}
+ bool HasValidWindow() {return (mXWindow != 0);}
+
+ // Choose frame buffer configuration and return fbConfigID. Returns -1 if
+ // a failure occurs.
+ static int chooseFBConfigID(struct _XDisplay* display, int xscreen);
+
+ // Obtain visual from frame buffer configuration ID. You must call XFree
+ // on the XVisualInfo* pointer.
+ static XVisualInfo* getVisual(struct _XDisplay* display,
+ int fbConfigID, int xscreen);
+
+ // GLXFBConfig pointer from frame buffer configuration ID. You must call
+ // XFree on the GLXFBConfig pointer.
+ static GLXFBConfig* getGLXFBConfig(struct _XDisplay* display,
+ int fbConfigID, int xscreen);
+
+ static LinuxDeviceScreen findDevScreenForHMD(const ovrHmd& hmd);
+ static LinuxDeviceScreen findDevScreenForDevID(const char* deviceID);
+
+ static DistortionRotation getRotation(const ovrHmd& hmd);
+
+ // Obtains XVisualInfo for currently bound context. Returns true if a
+ // visual was successfully obtained. False otherwise.
+ static bool getVisualFromDrawable(GLXDrawable drawable, XVisualInfo* vinfoOut);
+
+private:
+
+ /// Constructs SDK window on the given device screen.
+ void buildVisualAndWindow(const LinuxDeviceScreen& devScreen);
+
+ // Added m in front of variables so as to not conflict with X names.
+ struct _XDisplay* mXDisplay;
+ int mXScreen;
+ XVisualInfo* mXVisual;
+ XContext mXUniqueContext;
+ Window mXWindow;
+ int mFBConfigID;
+
+ LinuxDeviceScreen mDeviceScreen;
+};
+
+
+} // namespace OVR
+
+#endif // OVR_Linux_SDKWindow_h
diff --git a/LibOVR/Src/Displays/OVR_OSX_Display.cpp b/LibOVR/Src/Displays/OVR_OSX_Display.cpp
new file mode 100644
index 0000000..67df51d
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_OSX_Display.cpp
@@ -0,0 +1,372 @@
+/************************************************************************************
+
+Filename : OVR_OSX_Display.cpp
+Content : OSX-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_OSX_Display.h"
+#include "../Kernel/OVR_Log.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFString.h>
+#include <IOKit/graphics/IOGraphicsLib.h>
+
+//-------------------------------------------------------------------------------------
+// ***** Display enumeration Helpers
+
+namespace OVR {
+
+// FIXME Code duplication with windows.
+#define EDID_LENGTH 0x80
+
+#define EDID_HEADER 0x00
+#define EDID_HEADER_END 0x07
+
+#define ID_MANUFACTURER_NAME 0x08
+#define ID_MANUFACTURER_NAME_END 0x09
+
+#define EDID_STRUCT_VERSION 0x12
+#define EDID_STRUCT_REVISION 0x13
+
+#define ESTABLISHED_TIMING_1 0x23
+#define ESTABLISHED_TIMING_2 0x24
+#define MANUFACTURERS_TIMINGS 0x25
+
+#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
+#define DETAILED_TIMING_DESCRIPTION_SIZE 18
+#define NO_DETAILED_TIMING_DESCRIPTIONS 4
+
+#define DETAILED_TIMING_DESCRIPTION_1 0x36
+#define DETAILED_TIMING_DESCRIPTION_2 0x48
+#define DETAILED_TIMING_DESCRIPTION_3 0x5a
+#define DETAILED_TIMING_DESCRIPTION_4 0x6c
+
+#define MONITOR_NAME 0xfc
+#define MONITOR_LIMITS 0xfd
+#define MONITOR_SERIAL 0xff
+
+#define UNKNOWN_DESCRIPTOR -1
+#define DETAILED_TIMING_BLOCK -2
+
+#define DESCRIPTOR_DATA 5
+
+const UByte edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00 };
+
+const UByte edid_v1_descriptor_flag[] = { 0x00, 0x00 };
+
+// FIXME Code duplication with windows. Refactor.
+static int blockType( UByte* block )
+{
+ if ( !strncmp( (const char*)edid_v1_descriptor_flag, (const char*)block, 2 ) )
+ {
+ // descriptor
+ if ( block[ 2 ] != 0 )
+ return UNKNOWN_DESCRIPTOR;
+ return block[ 3 ];
+ }
+ else
+ {
+ return DETAILED_TIMING_BLOCK;
+ }
+}
+
+static char* getMonitorName( UByte const* block )
+{
+ static char name[ 13 ];
+ unsigned i;
+ UByte const* ptr = block + DESCRIPTOR_DATA;
+
+ for( i = 0; i < 13; i++, ptr++ )
+ {
+ if ( *ptr == 0xa )
+ {
+ name[ i ] = 0;
+ return name;
+ }
+
+ name[ i ] = *ptr;
+ }
+
+ return name;
+}
+
+// FIXME Code duplication with windows. Refactor.
+static bool parseEdid( UByte* edid, OVR::OSX::DisplayEDID& edidResult )
+{
+ unsigned i;
+ UByte* block;
+ const char* monitor_name = "Unknown";
+ UByte checksum = 0;
+
+ for( i = 0; i < EDID_LENGTH; i++ )
+ checksum += edid[ i ];
+
+ // Bad checksum, fail EDID
+ if ( checksum != 0 )
+ return false;
+
+ 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 false;
+ }
+
+
+ // OVR_DEBUG_LOG_TEXT(( "\n# EDID version %d revision %d\n",
+ // (int)edid[EDID_STRUCT_VERSION],(int)edid[EDID_STRUCT_REVISION] ));
+
+ // Monitor name and timings
+
+ char serialNumber[14];
+ memset( serialNumber, 0, 14 );
+
+ block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+ for( i = 0; i < NO_DETAILED_TIMING_DESCRIPTIONS; i++,
+ block += DETAILED_TIMING_DESCRIPTION_SIZE )
+ {
+
+ if ( blockType( block ) == MONITOR_NAME )
+ {
+ monitor_name = getMonitorName( block );
+ }
+
+ if( blockType( block ) == MONITOR_SERIAL )
+ {
+ memcpy( serialNumber, block + 5, 13 );
+ break;
+ }
+ }
+
+ UByte 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*)&edid[10];
+ edidResult.MonitorName = OVR::String(monitor_name);
+ edidResult.VendorName = OVR::String((const char*)vendorString);
+ edidResult.SerialNumber = OVR::String(serialNumber);
+
+ // printf( "\tIdentifier \"%s\"\n", monitor_name );
+ // printf( "\tVendorName \"%s\"\n", vendorString );
+ // printf( "\tModelName \"%s\"\n", monitor_name );
+ // printf( "\tModelNumber %d\n", edidResult.ModelNumber );
+ // printf( "\tSerialNumber \"%s\"\n", edidResult.SerialNumber.ToCStr() );
+
+ // FIXME: Get timings as well, though they aren't very useful here
+ // except for the vertical refresh rate, presumably
+
+ return true;
+}
+
+static int discoverExtendedRifts(OVR::OSX::DisplayDesc* descriptorArray, int inputArraySize, bool edidInfo)
+{
+ OVR_UNUSED(edidInfo);
+ int result = 0;
+
+ static bool reportDiscovery = true;
+ OVR_UNUSED(reportDiscovery);
+
+ CGDirectDisplayID Displays[32];
+ uint32_t NDisplays = 0;
+ CGGetOnlineDisplayList(32, Displays, &NDisplays);
+
+ for (unsigned int i = 0; i < NDisplays; i++)
+ {
+ io_service_t port = CGDisplayIOServicePort(Displays[i]);
+ CFDictionaryRef DispInfo = IODisplayCreateInfoDictionary(port, kNilOptions);
+
+ // Display[i]
+
+ uint32_t vendor = CGDisplayVendorNumber(Displays[i]);
+ uint32_t product = CGDisplayModelNumber(Displays[i]);
+
+ CGRect desktop = CGDisplayBounds(Displays[i]);
+ Vector2i desktopOffset(desktop.origin.x, desktop.origin.y);
+
+ if (vendor == 16082 && ( (product == 1)||(product == 2)||(product == 3) ) ) // 7" or HD
+ {
+ if( result >= inputArraySize )
+ {
+ CFRelease(DispInfo);
+ return result;
+ }
+
+ Sizei monitorResolution(1280, 800);
+
+ // Obtain and parse EDID data.
+ CFDataRef data =
+ (CFDataRef)CFDictionaryGetValue(DispInfo, CFSTR(kIODisplayEDIDKey));
+ if (!data)
+ {
+ CFRelease(DispInfo);
+ OVR::LogError("[OSX Display] Unable to obtain EDID for Oculus product %d", product);
+ continue;
+ }
+ UByte* edid = (UByte*)CFDataGetBytePtr(data);
+ OSX::DisplayEDID edidResult;
+ parseEdid( edid, edidResult );
+
+ OVR::OSX::DisplayDesc& desc = descriptorArray[result++];
+ desc.DisplayID = Displays[i];
+ desc.ModelName = edidResult.MonitorName; // User friendly string.
+ desc.EdidSerialNumber = edidResult.SerialNumber;
+ desc.LogicalResolutionInPixels = monitorResolution;
+ desc.DesktopDisplayOffset = desktopOffset;
+
+ switch (product)
+ {
+ 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 (product == 3 || product == 2)
+ {
+ desc.LogicalResolutionInPixels = Sizei(1920, 1080);
+ desc.NativeResolutionInPixels = Sizei(1080, 1920);
+ }
+ else
+ {
+ desc.LogicalResolutionInPixels = monitorResolution;
+ desc.NativeResolutionInPixels = monitorResolution;
+ }
+
+ //OVR_DEBUG_LOG_TEXT(("Display Found %x:%x\n", vendor, product));
+ }
+ CFRelease(DispInfo);
+ }
+
+ 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 OSX::OSXDisplaySearchHandle();
+}
+
+bool Display::InCompatibilityMode( bool displaySearch )
+{
+ OVR_UNUSED( displaySearch );
+ return true;
+}
+
+int Display::GetDisplayCount( DisplaySearchHandle* handle, bool extended, bool applicationOnly, bool edidInfo )
+{
+ OVR_UNUSED(applicationOnly);
+
+ static int extendedCount = -1;
+
+ OSX::OSXDisplaySearchHandle* localHandle = (OSX::OSXDisplaySearchHandle*)handle;
+ if (localHandle == NULL)
+ {
+ OVR::LogError("[OSX Display] No search handle passed into GetDisplayCount. Return 0 rifts.");
+ return 0;
+ }
+
+ if (extendedCount == -1 || extended)
+ {
+ extendedCount = discoverExtendedRifts(localHandle->cachedDescriptorArray, OSX::OSXDisplaySearchHandle::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("[OSX Display] Invalid index given to GetDisplay.");
+ return NULL;
+ }
+
+ OSX::OSXDisplaySearchHandle* localHandle = (OSX::OSXDisplaySearchHandle*)handle;
+ if (localHandle == NULL)
+ {
+ OVR::LogError("[OSX Display] No search handle passed into GetDisplay. Return 0 rifts.");
+ return NULL;
+ }
+
+ if (localHandle->extended)
+ {
+ if (index >= 0 && index < (int)localHandle->extendedDisplayCount)
+ {
+ return *new OSX::OSXDisplayGeneric(localHandle->cachedDescriptorArray[index]);
+ }
+
+ // index -= localHandle->extendedDisplayCount;
+ }
+
+ if (localHandle->application)
+ {
+ OVR::LogError("[OSX Display] Mac does not support application displays.");
+ }
+
+ return result;
+}
+} // namespace OVR
diff --git a/LibOVR/Src/Displays/OVR_OSX_Display.h b/LibOVR/Src/Displays/OVR_OSX_Display.h
new file mode 100644
index 0000000..a69c955
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_OSX_Display.h
@@ -0,0 +1,139 @@
+/************************************************************************************
+
+Filename : OVR_OSX_Display.h
+Content : OSX-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.
+
+*************************************************************************************/
+
+#ifndef OVR_OSX_Display_h
+#define OVR_OSX_Display_h
+
+#include "OVR_Display.h"
+
+namespace OVR { namespace OSX {
+
+
+//-------------------------------------------------------------------------------------
+// DisplayDesc
+
+// Display information enumerable through OS .
+// TBD: Should we just move this to public header, so it's a const member of Display?
+struct DisplayDesc
+{
+ DisplayDesc() :
+ DeviceTypeGuess(HmdType_None),
+ DisplayID(0),
+ LogicalResolutionInPixels(0),
+ NativeResolutionInPixels(0)
+ {}
+
+ HmdTypeEnum DeviceTypeGuess;
+ uint32_t DisplayID; // This is the device identifier string from MONITORINFO (for app usage)
+ String ModelName; // This is a "DK2" type string
+ String EdidSerialNumber;
+ Sizei LogicalResolutionInPixels;
+ Sizei NativeResolutionInPixels;
+ Vector2i DesktopDisplayOffset;
+};
+
+
+//-------------------------------------------------------------------------------------
+// DisplayEDID
+
+// Describes EDID information as reported from our display driver.
+struct DisplayEDID
+{
+ DisplayEDID() :
+ ModelNumber(0)
+ {}
+
+ String MonitorName;
+ UInt16 ModelNumber;
+ String VendorName;
+ String SerialNumber;
+};
+
+//-------------------------------------------------------------------------------------
+// OSX Display Search Handle
+class OSXDisplaySearchHandle : public DisplaySearchHandle
+{
+public:
+ OSXDisplaySearchHandle() :
+ extended(false),
+ application(false),
+ extendedDisplayCount(0),
+ applicationDisplayCount(0),
+ displayCount(0)
+ {}
+ virtual ~OSXDisplaySearchHandle() {}
+
+ static const int DescArraySize = 16;
+
+ OSX::DisplayDesc cachedDescriptorArray[DescArraySize];
+ bool extended;
+ bool application;
+ int extendedDisplayCount;
+ int applicationDisplayCount;
+ int displayCount;
+};
+
+//-------------------------------------------------------------------------------------
+// OSXDisplayGeneric
+
+// Describes OSX display in Compatibility mode, containing basic data
+class OSXDisplayGeneric : public Display
+{
+public:
+ OSXDisplayGeneric( const DisplayDesc& dd ) :
+ Display(dd.DeviceTypeGuess,
+ dd.DisplayID,
+ dd.ModelName,
+ dd.EdidSerialNumber,
+ dd.LogicalResolutionInPixels,
+ dd.NativeResolutionInPixels,
+ dd.DesktopDisplayOffset,
+ 0,
+ 0,
+ false)
+ {
+ }
+
+ virtual ~OSXDisplayGeneric()
+ {
+ }
+
+ virtual bool InCompatibilityMode() const
+ {
+ return true;
+ }
+
+ // Generic displays are not capable of mirroring
+ virtual MirrorMode SetMirrorMode( MirrorMode newMode )
+ {
+ OVR_UNUSED( newMode );
+ return MirrorDisabled;
+ }
+};
+
+}} // namespace OVR::OSX
+
+#endif // OVR_OSX_Display_h
diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusObserver.h b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.h
new file mode 100644
index 0000000..e2f28e3
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.h
@@ -0,0 +1,75 @@
+/************************************************************************************
+
+Filename : OVR_OSX_FocusObserver.h
+Content : Observer for app focus on OSX
+Created : August 5, 2014
+Authors : Jordan Tritell
+
+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.
+
+*************************************************************************************/
+
+OVR_PRIVATE_FILE
+
+#ifndef OVR_OSX_FocusObserver_h
+#define OVR_OSX_FocusObserver_h
+
+#include "../Kernel/OVR_Threads.h"
+#include "../Kernel/OVR_System.h"
+#include "../Kernel/OVR_Lockless.h"
+
+#include "../Service/Service_NetServer.h"
+
+namespace OVR { namespace OSX{
+
+ struct FocusNotifierImpl;
+
+class AppFocusObserver : public SystemSingletonBase<AppFocusObserver>
+{
+ OVR_DECLARE_SINGLETON(AppFocusObserver);
+
+public:
+ Lock ListLock;
+ Array<pid_t> AppList;
+ Service::NetServerListener *listener;
+ FocusNotifierImpl* impl;
+
+ void OnProcessFocus(pid_t pid);
+ void SetListener(Service::NetServerListener *_listener);
+
+ pid_t LastProcessId;
+ pid_t ActiveProcessId;
+ void AddProcess(pid_t pid);
+ void nextProcess();
+ void RemoveProcess(pid_t pid);
+
+
+protected:
+ void onAppFocus(pid_t pid);
+
+ pid_t LastAppFocus;
+
+};
+
+
+
+}} // namespace OVR, OSX
+
+
+#endif /* OVR_OSX_FocusObserver_h */
+
diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusObserver.mm b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.mm
new file mode 100644
index 0000000..3dd77a8
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.mm
@@ -0,0 +1,245 @@
+/************************************************************************************
+
+Filename : OVR_OSX_FocusObserver.mm
+Content : Observer for app focus on OSX
+Created : August 5, 2014
+Authors : Jordan Tritell
+
+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.
+
+*************************************************************************************/
+
+OVR_PRIVATE_FILE
+
+#include "OVR_OSX_FocusObserver.h"
+
+#include "../Service/Service_NetServer.h"
+#include "OVR_DisplayEnumerator.h"
+
+#include <Cocoa/Cocoa.h>
+
+OVR_DEFINE_SINGLETON(OVR::OSX::AppFocusObserver);
+
+extern bool ServiceRunningFlag;
+
+@interface FocusNotifier : NSObject <NSApplicationDelegate>{
+ NSWindow *window;
+}
+
+- (void)start;
+
+@property (assign) IBOutlet NSWindow *window;
+
+@end
+
+
+@implementation FocusNotifier
+
+@synthesize window;
+
+- (void) addActivationObserver
+{
+ //subscribe to focus notifications from the workspace
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
+ selector:@selector(activated:)
+ name:NSWorkspaceDidActivateApplicationNotification
+ object:nil];
+
+ //subscribe to termination notifications from the workspace
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
+ selector:@selector(terminated:)
+ name:NSWorkspaceDidTerminateApplicationNotification
+ object:nil];
+}
+
+-(void) activated:(NSNotification *)notification
+{
+ NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"];
+ pid_t pid = [app processIdentifier];
+ OVR::OSX::AppFocusObserver::GetInstance()->OnProcessFocus(pid);
+ // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]);
+}
+
+-(void) terminated:(NSNotification *)notification
+{
+ NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"];
+ pid_t pid = [app processIdentifier];
+ OVR::OSX::AppFocusObserver::GetInstance()->RemoveProcess(pid);
+ // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]);
+}
+
+- (void)start
+{
+ //initialize with relevant variables
+ [self addActivationObserver];
+}
+
+@end
+
+
+namespace OVR { namespace OSX{
+
+struct FocusNotifierImpl
+{
+ FocusNotifier* wrapped;
+};
+
+AppFocusObserver::AppFocusObserver():
+ impl(new FocusNotifierImpl),
+ listener(NULL)
+{
+ //initialize with correct values
+ impl->wrapped = [[FocusNotifier alloc] init];
+ [impl->wrapped start];
+ ActiveProcessId = 0;
+}
+
+AppFocusObserver::~AppFocusObserver()
+{
+ [impl->wrapped dealloc];
+ delete impl;
+}
+
+void AppFocusObserver::SetListener(Service::NetServerListener *_listener)
+{
+ listener = _listener;
+}
+
+void AppFocusObserver::OnSystemDestroy()
+{
+}
+
+void AppFocusObserver::OnProcessFocus(pid_t pid)
+{
+ // If the process changed,
+ if (pid != LastProcessId)
+ {
+ LastProcessId = pid;
+
+ Lock::Locker locker(&ListLock);
+
+ // Find the process id in the list
+ const int count = AppList.GetSizeI();
+ for (int i = 0; i < count; ++i)
+ {
+ // If it is a rift process,
+ if (AppList[i] == pid)
+ {
+ onAppFocus(pid);
+ OVR_DEBUG_LOG(("[AppFocusObserver] Oculus Process getting focus: pid=%d", pid));
+ return;
+ }
+ }
+
+ OVR_DEBUG_LOG(("[AppFocusObserver] Focus change: %d (non-Oculus process)", pid));
+ }
+}
+
+void AppFocusObserver::AddProcess(pid_t pid)
+{
+ Lock::Locker locker(&ListLock);
+
+ // If it already exists in the array,
+ const int count = AppList.GetSizeI();
+ for (int i = 0; i < count; ++i)
+ {
+ // If we found it,
+ if (AppList[i] == pid)
+ {
+ return;
+ }
+ }
+
+ // If the process being added is already in focus,
+ if (pid == LastProcessId)
+ {
+ // Set the active process
+ OVR_DEBUG_LOG(("[AppFocusObserver] AddProcess: Recognizing the newly added process as in-focus pid=%d", pid));
+ }
+
+ // Add it to the list
+ AppList.PushBack(pid);
+}
+
+void AppFocusObserver::nextProcess()
+{
+ Lock::Locker locker(&ListLock);
+
+ int count = AppList.GetSizeI();
+
+ // Pick the next available rift process
+ if (count > 0)
+ {
+ ActiveProcessId = AppList[0];
+ OVR_DEBUG_LOG(("[AppFocusObserver] NextProcess: Switching active rift process to pid=%d", ActiveProcessId));
+ onAppFocus(ActiveProcessId);
+ return;
+ }
+
+ // No process to use
+ onAppFocus(ActiveProcessId);
+ OVR_DEBUG_LOG(("[AppFocusObserver] NextProcess: No remaining rift processes"));
+}
+
+
+void AppFocusObserver::onAppFocus(pid_t pid)
+{
+ // Note: This is not necessarily the same as the FocusState->ActiveProcessId.
+
+ ActiveProcessId = pid;
+
+ if (ActiveProcessId == 0) return;
+
+ if (pid != LastAppFocus)
+ {
+ LastAppFocus = pid;
+ if(listener){
+ listener->onFocusChange(pid);
+ }
+// FocusSubject->Call(pid);
+ }
+}
+
+void AppFocusObserver::RemoveProcess(pid_t pid)
+{
+ Lock::Locker locker(&ListLock);
+
+ // Find the pid in the app list:
+ const int count = AppList.GetSizeI();
+ for (int i = 0; i < count; ++i)
+ {
+ // If the app was found,
+ if (AppList[i] == pid)
+ {
+ // Remove from list here
+ AppList.RemoveAtUnordered(i);
+
+ // If the removed process is the active one,
+ if (ActiveProcessId == pid)
+ {
+ OVR_DEBUG_LOG(("[AppFocusObserver] RemoveProcess: Active process going away"));
+ // Find a new active process
+ nextProcess();
+ }
+
+ break;
+ }
+ }
+}
+}} //namespace OVR::OSX
+
diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusReader.h b/LibOVR/Src/Displays/OVR_OSX_FocusReader.h
new file mode 100644
index 0000000..dbfe9f6
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_OSX_FocusReader.h
@@ -0,0 +1,45 @@
+/************************************************************************************
+
+Filename : OVR_OSX_FocusReader.h
+Content : Reader for current app with focus on OSX
+Created : August 5, 2014
+Authors : Jordan Tritell
+
+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.
+
+*************************************************************************************/
+
+OVR_PRIVATE_FILE
+
+#ifndef OVR_OSX_FocusReader_h
+#define OVR_OSX_FocusReader_h
+
+#import <Cocoa/Cocoa.h>
+
+@interface FocusReader : NSObject <NSApplicationDelegate>{
+ NSWindow *window;
+}
+
+- (void)start;
+
+@property (assign) IBOutlet NSWindow *window;
+
+@end
+
+#endif /* OVR_OSX_FocusReader_h */
+
diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusReader.mm b/LibOVR/Src/Displays/OVR_OSX_FocusReader.mm
new file mode 100644
index 0000000..bed95d6
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_OSX_FocusReader.mm
@@ -0,0 +1,75 @@
+/************************************************************************************
+
+Filename : OVR_OSX_FocusReader.mm
+Content : Reader for current app with focus on OSX
+Created : August 5, 2014
+Authors : Jordan Tritell
+
+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.
+
+*************************************************************************************/
+
+OVR_PRIVATE_FILE
+
+#import "OVR_OSX_FocusReader.h"
+#import "OVR_OSX_FocusObserver.h"
+
+@implementation FocusReader
+
+@synthesize window;
+
+- (void) addActivationObserver
+{
+ //subscribe to focus notifications from the workspace
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
+ selector:@selector(activated:)
+ name:NSWorkspaceDidActivateApplicationNotification
+ object:nil];
+
+ //subscribe to focus notifications from the workspace
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
+ selector:@selector(terminated:)
+ name:NSWorkspaceDidTerminateApplicationNotification
+ object:nil];
+}
+
+-(void) activated:(NSNotification *)notification
+{
+ NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"];
+ pid_t pid = [app processIdentifier];
+ OVR::OSX::AppFocusObserver::GetInstance()->OnProcessFocus(pid);
+ // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]);
+}
+
+-(void) terminated:(NSNotification *)notification
+{
+ NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"];
+ pid_t pid = [app processIdentifier];
+ OVR::OSX::AppFocusObserver::GetInstance()->RemoveProcess(pid);
+ // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]);
+}
+
+- (void)start
+{
+ //initialize with relevant variables
+ [self addActivationObserver];
+}
+
+@end
+
+
diff --git a/LibOVR/Src/Displays/OVR_Win32_Display.cpp b/LibOVR/Src/Displays/OVR_Win32_Display.cpp
new file mode 100644
index 0000000..677c619
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_Display.cpp
@@ -0,0 +1,1323 @@
+/************************************************************************************
+
+Filename : OVR_Win32_Display.cpp
+Content : Win32 Display implementation
+Created : May 6, 2014
+Authors : Dean Beeler
+
+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 <Windows.h>
+
+#include "OVR_Win32_Display.h"
+#include "OVR_Win32_Dxgi_Display.h"
+
+#include <stdio.h>
+#include <tchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <winioctl.h>
+#include <SetupAPI.h>
+#include <Mmsystem.h>
+#include <conio.h>
+
+#ifdef OVR_COMPAT_EDID_VIA_WMI
+# pragma comment(lib, "wbemuuid.lib")
+#include <wbemidl.h>
+#else // OVR_COMPAT_EDID_VIA_WMI
+#include <setupapi.h>
+#include <initguid.h>
+#endif // OVR_COMPAT_EDID_VIA_WMI
+
+// WIN32_LEAN_AND_MEAN included in OVR_Atomic.h may break 'byte' declaration.
+#ifdef WIN32_LEAN_AND_MEAN
+ typedef unsigned char byte;
+#endif
+
+#include "../Kernel/OVR_String.h"
+#include "../Kernel/OVR_Log.h"
+
+typedef struct
+{
+ HANDLE hDevice;
+ UINT ExpectedWidth;
+ UINT ExpectedHeight;
+ HWND hWindow;
+ bool CompatibilityMode;
+ bool HideDK1Mode;
+} ContextStruct;
+
+static ContextStruct GlobalDisplayContext = {0};
+
+
+//-------------------------------------------------------------------------------------
+// ***** Display enumeration Helpers
+
+// THere are two ways to enumerate display: through our driver (DeviceIoControl)
+// and through Win32 EnumDisplayMonitors (compatibility mode).
+
+
+namespace OVR {
+
+ULONG getRiftCount( HANDLE hDevice )
+{
+ ULONG riftCount = 0;
+ DWORD bytesReturned = 0;
+
+ BOOL result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GET_RIFT_COUNT, NULL, 0,
+ &riftCount, sizeof( ULONG ), &bytesReturned, NULL );
+
+ if( result )
+ return riftCount;
+ else
+ return 0;
+}
+
+ULONG getRift( HANDLE hDevice, int index )
+{
+ ULONG riftCount = getRiftCount( hDevice );
+ DWORD bytesReturned = 0;
+ BOOL result;
+
+ if( riftCount >= (ULONG)index )
+ {
+ RIFT_STATUS riftStatus[16] = {0};
+
+ result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GET_RIFT_ARRAY, riftStatus,
+ riftCount * sizeof( RIFT_STATUS ), &riftCount,
+ sizeof( ULONG ), &bytesReturned, NULL );
+ if( result )
+ {
+ PRIFT_STATUS tmpRift;
+ unsigned int i;
+ for( i = 0, tmpRift = riftStatus; i < riftCount; ++i, ++tmpRift )
+ {
+ if( i == (unsigned int)index )
+ return tmpRift->childUid;
+ }
+ }
+ else
+ {
+ printf("Failed to get array of rift devices\n");
+ }
+ }
+
+ return 0;
+}
+
+#define EDID_LENGTH 0x80
+
+#define EDID_HEADER 0x00
+#define EDID_HEADER_END 0x07
+
+#define ID_MANUFACTURER_NAME 0x08
+#define ID_MANUFACTURER_NAME_END 0x09
+
+#define EDID_STRUCT_VERSION 0x12
+#define EDID_STRUCT_REVISION 0x13
+
+#define ESTABLISHED_TIMING_1 0x23
+#define ESTABLISHED_TIMING_2 0x24
+#define MANUFACTURERS_TIMINGS 0x25
+
+#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
+#define DETAILED_TIMING_DESCRIPTION_SIZE 18
+#define NO_DETAILED_TIMING_DESCRIPTIONS 4
+
+#define DETAILED_TIMING_DESCRIPTION_1 0x36
+#define DETAILED_TIMING_DESCRIPTION_2 0x48
+#define DETAILED_TIMING_DESCRIPTION_3 0x5a
+#define DETAILED_TIMING_DESCRIPTION_4 0x6c
+
+#define MONITOR_NAME 0xfc
+#define MONITOR_LIMITS 0xfd
+#define MONITOR_SERIAL 0xff
+
+#define UNKNOWN_DESCRIPTOR -1
+#define DETAILED_TIMING_BLOCK -2
+
+#define DESCRIPTOR_DATA 5
+
+const byte edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00 };
+
+const byte edid_v1_descriptor_flag[] = { 0x00, 0x00 };
+
+
+static int blockType( byte* block )
+{
+ if ( !strncmp( (const char*)edid_v1_descriptor_flag, (const char*)block, 2 ) )
+ {
+ // descriptor
+ if ( block[ 2 ] != 0 )
+ return UNKNOWN_DESCRIPTOR;
+ return block[ 3 ];
+ }
+ else
+ {
+ return DETAILED_TIMING_BLOCK;
+ }
+}
+
+static char* getMonitorName( byte const* block )
+{
+ static char name[ 13 ];
+ unsigned i;
+ byte const* ptr = block + DESCRIPTOR_DATA;
+
+ for( i = 0; i < 13; i++, ptr++ )
+ {
+ if ( *ptr == 0xa )
+ {
+ name[ i ] = 0;
+ return name;
+ }
+
+ name[ i ] = *ptr;
+ }
+
+ return name;
+}
+
+
+static bool parseEdid( byte* edid, OVR::Win32::DisplayEDID& edidResult )
+{
+ unsigned i;
+ byte* block;
+ char* monitor_name = "Unknown";
+ byte checksum = 0;
+
+ for( i = 0; i < EDID_LENGTH; i++ )
+ checksum += edid[ i ];
+
+ // Bad checksum, fail EDID
+ if ( checksum != 0 )
+ return false;
+
+ 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 false;
+ }
+
+ //printf( "\n# EDID version %d revision %d\n", (int)edid[EDID_STRUCT_VERSION],(int)edid[EDID_STRUCT_REVISION] );
+
+ // Monitor name and timings
+
+ char serialNumber[14];
+ memset( serialNumber, 0, 14 );
+
+ block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+ for( i = 0; i < NO_DETAILED_TIMING_DESCRIPTIONS; i++,
+ block += DETAILED_TIMING_DESCRIPTION_SIZE )
+ {
+
+ if ( blockType( block ) == MONITOR_NAME )
+ {
+ monitor_name = getMonitorName( block );
+ }
+
+ if( blockType( block ) == MONITOR_SERIAL )
+ {
+ memcpy( serialNumber, block + 5, 13 );
+ break;
+ }
+ }
+
+ BYTE 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*)&edid[10];
+ edidResult.MonitorName = OVR::String(monitor_name);
+ edidResult.VendorName = OVR::String((const char*)vendorString);
+ edidResult.SerialNumber = OVR::String(serialNumber);
+
+#if 0
+ printf( "\tIdentifier \"%s\"\n", monitor_name );
+ printf( "\tVendorName \"%s\"\n", vendorString );
+ printf( "\tModelName \"%s\"\n", monitor_name );
+ printf( "\tModelNumber %d\n", modelNumber );
+ printf( "\tSerialNumber \"%x\"\n", *serialPointer );
+#endif
+
+ // FIXME: Get timings as well, though they aren't very useful here
+ // except for the vertical refresh rate, presumably
+
+ return true;
+}
+
+static bool getEdid(HANDLE hDevice, ULONG uid, OVR::Win32::DisplayEDID& edidResult)
+{
+ ULONG riftCount = 0;
+ DWORD bytesReturned = 0;
+ RIFT_STATUS riftStatus[16] = {0};
+
+ BOOL result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GET_RIFT_COUNT, NULL, 0,
+ &riftCount, sizeof( ULONG ), &bytesReturned, NULL );
+
+ if (!result)
+ {
+ return false;
+ }
+
+ result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GET_RIFT_ARRAY, &riftStatus,
+ riftCount * sizeof( RIFT_STATUS ), &riftCount, sizeof(ULONG),
+ &bytesReturned, NULL );
+ if (!result)
+ {
+ return false;
+ }
+
+ for (ULONG i = 0; i < riftCount; ++i)
+ {
+ ULONG riftUid = riftStatus[i].childUid;
+ if (riftUid == uid)
+ {
+ char edidBuffer[512];
+
+ result = DeviceIoControl(hDevice, IOCTL_RIFTMGR_GETEDID, &riftUid, sizeof(ULONG),
+ edidBuffer, 512, &bytesReturned, NULL);
+
+ if (result)
+ {
+ if (parseEdid((byte*)edidBuffer, edidResult))
+ {
+ return true;
+ }
+ else
+ {
+ OVR_DEBUG_LOG(("[Win32Display] WARNING: The driver was not able to return EDID for a display"));
+ }
+ }
+
+ break;
+ }
+ }
+
+ return false;
+}
+
+
+// Used to capture all the active monitor handles
+struct MonitorSet
+{
+ enum { MaxMonitors = 8 };
+ HMONITOR Monitors[MaxMonitors];
+ int MonitorCount;
+ int PrimaryCount;
+};
+
+static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
+{
+ MonitorSet* monitorSet = (MonitorSet*)dwData;
+ if (monitorSet->MonitorCount >= MonitorSet::MaxMonitors)
+ return FALSE;
+
+ monitorSet->Monitors[monitorSet->MonitorCount] = hMonitor;
+ monitorSet->MonitorCount++;
+ return TRUE;
+};
+
+#ifdef OVR_COMPAT_EDID_VIA_WMI
+
+static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, String& userFriendlyNameStr )
+{
+ IWbemLocator *pLoc = NULL;
+ IWbemServices *pSvc = NULL;
+ HRESULT hres;
+
+ static bool initialized = false;
+ static bool selfInitialized = true;
+ if (!initialized)
+ {
+ hres = CoInitializeEx(0, COINIT_MULTITHREADED);
+ if (FAILED(hres))
+ {
+
+ LogError("{ERR-082} [Display] WARNING: Failed to initialize COM library. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ hres = CoInitializeSecurity(
+ NULL,
+ -1, // COM authentication
+ NULL, // Authentication services
+ NULL, // Reserved
+ RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
+ RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
+ NULL, // Authentication info
+ EOAC_NONE, // Additional capabilities
+ NULL // Reserved
+ );
+
+ if (FAILED(hres))
+ {
+ LogError("{ERR-083} [Display] WARNING: Failed to initialize security. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ selfInitialized = false;
+ }
+
+ initialized = true;
+ }
+
+ hres = CoCreateInstance(
+ CLSID_WbemLocator,
+ 0,
+ CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID *)&pLoc);
+
+ if (FAILED(hres))
+ {
+ LogError("{ERR-084} [Display] WARNING: Failed to create IWbemLocator object.Err code = 0x%x", hres);
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ BSTR AbackB = SysAllocString(L"root\\WMI");
+ // Connect to the root\cimv2 namespace with
+ // the current user and obtain pointer pSvc
+ // to make IWbemServices calls.
+ hres = pLoc->ConnectServer(
+ AbackB, // Object path of WMI namespace
+ NULL, // User name. NULL = current user
+ NULL, // User password. NULL = current
+ 0, // Locale. NULL indicates current
+ NULL, // Security flags.
+ 0, // Authority (e.g. Kerberos)
+ 0, // Context object
+ &pSvc // pointer to IWbemServices proxy
+ );
+ SysFreeString(AbackB);
+
+ if (FAILED(hres))
+ {
+ LogError("{ERR-085} [Display] WARNING: Could not connect to root\\WMI. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ pLoc->Release();
+ return false;
+ }
+
+ hres = CoSetProxyBlanket(
+ pSvc, // Indicates the proxy to set
+ RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
+ RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
+ NULL, // Server principal name
+ RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
+ RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
+ NULL, // client identity
+ EOAC_NONE // proxy capabilities
+ );
+
+ if (FAILED(hres))
+ {
+ LogError("{ERR-086} [Display] WARNING: Could not set proxy blanket. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ pSvc->Release();
+ pLoc->Release();
+ return false;
+ }
+
+
+ BSTR wql = SysAllocString(L"WQL");
+ BSTR select = SysAllocString(L"SELECT * FROM WmiMonitorID");
+ IEnumWbemClassObject* pEnumerator = NULL;
+ hres = pSvc->ExecQuery(
+ wql,
+ select,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL,
+ &pEnumerator);
+ SysFreeString(wql);
+ SysFreeString(select);
+
+ if (FAILED(hres))
+ {
+ LogError("{ERR-087} [Display] WARNING: Query for operating system name failed. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ pSvc->Release();
+ pLoc->Release();
+ return false;
+ }
+
+ int enumeratedCount = 0;
+ bool found = false;
+
+ IWbemClassObject *pclsObj = 0;
+ while (pEnumerator)
+ {
+ ULONG uReturn = 0;
+ HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
+
+ if (FAILED(hr) || !uReturn)
+ {
+ break;
+ }
+
+ ++enumeratedCount;
+
+ VARIANT vtProp;
+ hr = pclsObj->Get(L"InstanceName", 0, &vtProp, 0, 0);
+
+ WCHAR* instanceName = vtProp.bstrVal;
+ WCHAR* nextToken = NULL;
+ if (SUCCEEDED(hr) &&
+ wcstok_s(instanceName, L"\\", &nextToken) != NULL)
+ {
+ WCHAR* aToken = wcstok_s(NULL, L"\\", &nextToken);
+
+ if (aToken != NULL)
+ {
+ VariantClear(&vtProp);
+
+ if (wcscmp(aToken, displayName) != 0)
+ {
+ pclsObj->Release();
+ continue;
+ }
+
+ // Read serial
+
+ hr = pclsObj->Get(L"SerialNumberID", 0, &vtProp, 0, 0);
+
+ if (SUCCEEDED(hr))
+ {
+ if (vtProp.vt != VT_NULL && vtProp.parray != NULL)
+ {
+ static const int MaxSerialBytes = 14;
+ char serialNumber[MaxSerialBytes] = { 0 };
+
+ UINT32* serialArray = (UINT32*)vtProp.parray->pvData;
+ for (int i = 0; i < MaxSerialBytes; ++i)
+ {
+ serialNumber[i] = (BYTE)(serialArray[i] & 0xff);
+ }
+
+ serialNumber[sizeof(serialNumber)-1] = '\0';
+ serialNumberStr = serialNumber;
+ }
+ else
+ {
+ LogError("{ERR-088} [Display] WARNING: Wrong data format for SerialNumberID");
+ }
+
+ VariantClear(&vtProp);
+ }
+ else
+ {
+ LogError("{ERR-089} [Display] WARNING: Failure getting display SerialNumberID: %d", (int)hr);
+ }
+
+ // Read length of name
+
+ int userFriendlyNameLen = 0;
+
+ hr = pclsObj->Get(L"UserFriendlyNameLength", 0, &vtProp, 0, 0);
+
+ if (SUCCEEDED(hr))
+ {
+ if (vtProp.vt != VT_NULL)
+ {
+ userFriendlyNameLen = vtProp.iVal;
+
+ if (userFriendlyNameLen <= 0)
+ {
+ userFriendlyNameLen = 0;
+
+ LogError("{ERR-090} [Display] WARNING: UserFriendlyNameLength = 0");
+ }
+ }
+ else
+ {
+ LogError("{ERR-091} [Display] WARNING: Wrong data format for UserFriendlyNameLength");
+ }
+
+ VariantClear(&vtProp);
+ }
+ else
+ {
+ LogError("{ERR-092} [Display] WARNING: Failure getting display UserFriendlyNameLength: %d", (int)hr);
+ }
+
+ // Read name
+
+ hr = pclsObj->Get(L"UserFriendlyName", 0, &vtProp, 0, 0);
+
+ if (SUCCEEDED(hr) && userFriendlyNameLen > 0)
+ {
+ if (vtProp.vt != VT_NULL && vtProp.parray != NULL)
+ {
+ static const int MaxNameBytes = 64;
+ char userFriendlyName[MaxNameBytes] = { 0 };
+
+ UINT32* nameArray = (UINT32*)vtProp.parray->pvData;
+ for (int i = 0; i < MaxNameBytes && i < userFriendlyNameLen; ++i)
+ {
+ userFriendlyName[i] = (BYTE)(nameArray[i] & 0xff);
+ }
+
+ userFriendlyName[sizeof(userFriendlyName)-1] = '\0';
+ userFriendlyNameStr = userFriendlyName;
+ }
+ else
+ {
+ // See: https://developer.oculusvr.com/forums/viewtopic.php?f=34&t=10961
+ // This can happen if someone has an EDID override in the registry.
+ LogError("{ERR-093} [Display] WARNING: Wrong data format for UserFriendlyName");
+ }
+
+ VariantClear(&vtProp);
+ }
+ else
+ {
+ LogError("{ERR-094} [Display] WARNING: Failure getting display UserFriendlyName: %d", (int)hr);
+ }
+ }
+
+ found = true;
+ pclsObj->Release();
+ break;
+ }
+
+ pclsObj->Release();
+ }
+
+ HMODULE hModule = GetModuleHandleA("wbemuuid");
+ if (hModule)
+ {
+ DisableThreadLibraryCalls(hModule);
+ }
+
+ pSvc->Release();
+ pLoc->Release();
+ pEnumerator->Release();
+
+ if (!found)
+ {
+ LogError("{ERR-095} [Display] WARNING: Unable to enumerate the rift via WMI (found %d monitors). This is not normally an issue. Running as a user with Administrator privileges has fixed this problem in the past.", enumeratedCount);
+ OVR_ASSERT(false);
+ }
+
+ return found;
+}
+
+#else // OVR_COMPAT_EDID_VIA_WMI
+
+#define NAME_SIZE 128
+
+DEFINE_GUID(GUID_CLASS_MONITOR,
+ 0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1,
+ 0x03, 0x18);
+
+static void truncateNonalphanum(char* str, int len)
+{
+ for (int i = 0; i < len; ++i)
+ {
+ char ch = str[i];
+
+ if ((ch < 'A' || ch > 'Z') &&
+ (ch < 'a' || ch > 'z') &&
+ (ch < '0' || ch > '9') &&
+ ch != ' ')
+ {
+ str[i] = '\0';
+ break;
+ }
+ }
+}
+
+static bool AccessDeviceRegistry(IN HDEVINFO devInfo, IN PSP_DEVINFO_DATA devInfoData,
+ const WCHAR* displayName, String& serialNumberStr, String& userFriendlyNameStr)
+{
+ // Match hardware id to display name
+ WCHAR hardwareId[128];
+ if (!SetupDiGetDeviceRegistryProperty(
+ devInfo,
+ devInfoData,
+ SPDRP_HARDWAREID,
+ NULL,
+ (PBYTE)hardwareId,
+ sizeof(hardwareId),
+ NULL))
+ {
+ LogError("{ERR-096} [Display] WARNING: SetupDiGetDeviceRegistryProperty for SPDRP_HARDWAREID failed. LastErr=%d", GetLastError());
+ OVR_ASSERT(false);
+ return false;
+ }
+ hardwareId[127] = 0;
+
+ // If the hardware id did not match,
+ if (!wcsstr(hardwareId, displayName))
+ {
+ // Stop here
+ return false;
+ }
+
+ // Grab hardware info registry key
+ HKEY hDevRegKey = SetupDiOpenDevRegKey(
+ devInfo,
+ devInfoData,
+ DICS_FLAG_GLOBAL,
+ 0,
+ DIREG_DEV,
+ KEY_READ); // Only read permissions so it can be run without Administrator privs
+
+ if (hDevRegKey == INVALID_HANDLE_VALUE)
+ {
+ LogError("{ERR-097} [Display] WARNING: SetupDiOpenDevRegKey failed. LastErr=%d", GetLastError());
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ // Enumerate keys in registry
+ bool found = false;
+
+ // For each key,
+ for (int i = 0;; i++)
+ {
+ BYTE EDIDdata[1024];
+ DWORD edidsize = sizeof(EDIDdata);
+
+ DWORD dwType, ActualValueNameLength = NAME_SIZE;
+ CHAR valueName[NAME_SIZE];
+
+ // Read the key value data
+ LSTATUS retValue = RegEnumValueA(
+ hDevRegKey,
+ i,
+ &valueName[0],
+ &ActualValueNameLength,
+ NULL,
+ &dwType,
+ EDIDdata,
+ &edidsize);
+
+ // If no more items in the enumeration,
+ if (retValue == ERROR_NO_MORE_ITEMS)
+ {
+ // Stop here
+ break;
+ }
+
+ // If the request failed,
+ if (FAILED(retValue))
+ {
+ LogError("{ERR-098} [Display] WARNING: RegEnumValueA failed to read a key. LastErr=%d", retValue);
+ OVR_ASSERT(false);
+ }
+ else if (0 == strcmp(valueName, "EDID")) // Value is EDID:
+ {
+ // Tested working for DK1 and DK2:
+
+ char friendlyString[9];
+ memcpy(friendlyString, EDIDdata + 77, 8);
+ truncateNonalphanum(friendlyString, 8);
+ friendlyString[8] = '\0';
+
+ char edidString[14];
+ memcpy(edidString, EDIDdata + 95, 13);
+ truncateNonalphanum(edidString, 13);
+ edidString[13] = '\0';
+
+ serialNumberStr = edidString;
+ userFriendlyNameStr = friendlyString;
+
+ found = true;
+ break;
+ }
+ }
+
+ RegCloseKey(hDevRegKey);
+
+ return found;
+}
+
+static bool getCompatDisplayEDID(const WCHAR* displayName, String& serialNumberStr, String& userFriendlyNameStr)
+{
+ HDEVINFO devInfo = NULL;
+
+ devInfo = SetupDiGetClassDevsEx(
+ &GUID_CLASS_MONITOR, //class GUID
+ NULL, //enumerator
+ NULL, //HWND
+ DIGCF_PRESENT, // Flags //DIGCF_ALLCLASSES|
+ NULL, // device info, create a new one.
+ NULL, // machine name, local machine
+ NULL);// reserved
+
+ if (NULL == devInfo)
+ {
+ return false;
+ }
+
+ DWORD lastError = 0;
+
+ // For each display,
+ for (int i = 0;; i++)
+ {
+ SP_DEVINFO_DATA devInfoData = {};
+ devInfoData.cbSize = sizeof(devInfoData);
+
+ // Grab device info
+ if (SetupDiEnumDeviceInfo(devInfo, i, &devInfoData))
+ {
+ // Access device info from registry
+ if (AccessDeviceRegistry(devInfo, &devInfoData, displayName, serialNumberStr, userFriendlyNameStr))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ lastError = GetLastError();
+
+ // If no more items found,
+ if (lastError != ERROR_NO_MORE_ITEMS)
+ {
+ LogError("{ERR-099} [Display] WARNING: SetupDiEnumDeviceInfo failed. LastErr=%d", lastError);
+ OVR_ASSERT(false);
+ }
+
+ break;
+ }
+ }
+
+ LogError("{ERR-100} [Display] WARNING: SetupDiEnumDeviceInfo did not return the rift display. LastErr=%d", lastError);
+ OVR_ASSERT(false);
+
+ return false;
+}
+
+#endif // OVR_COMPAT_EDID_VIA_WMI
+
+// This is function that's used
+bool anyRiftsInExtendedMode()
+{
+ bool result = false;
+
+ MonitorSet monitors;
+ monitors.MonitorCount = 0;
+ // Get all the monitor handles
+ EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
+
+ DISPLAY_DEVICE dd, ddm;
+ UINT i, j;
+
+ for( i = 0;
+ (ZeroMemory(&dd, sizeof(dd)), dd.cb = sizeof(dd),
+ EnumDisplayDevices(0, i, &dd, 0)) != 0; i++ )
+ {
+ for( j = 0;
+ (ZeroMemory(&ddm, sizeof(ddm)), ddm.cb = sizeof(ddm),
+ EnumDisplayDevices(dd.DeviceName, j, &ddm, 0)) != 0; j++ )
+ {
+ // Our monitor hardware has string "RTD2205" in it
+ // Nate's device "CVT0003"
+ if( wcsstr(ddm.DeviceID, L"RTD2205") ||
+ wcsstr(ddm.DeviceID, L"CVT0003") ||
+ wcsstr(ddm.DeviceID, L"MST0030") ||
+ wcsstr(ddm.DeviceID, L"OVR00") ) // Part of Oculus EDID.
+ {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+static int discoverExtendedRifts(OVR::Win32::DisplayDesc* descriptorArray, int inputArraySize, bool includeEDID)
+{
+ static bool reportDiscovery = true;
+
+ int result = 0;
+
+ MonitorSet monitors;
+ monitors.MonitorCount = 0;
+ // Get all the monitor handles
+ EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
+
+ DISPLAY_DEVICE dd, ddm;
+ UINT i, j;
+
+ for (i = 0;
+ (ZeroMemory(&dd, sizeof(dd)), dd.cb = sizeof(dd),
+ EnumDisplayDevices(0, i, &dd, 0)) != 0; i++)
+ {
+ for (j = 0;
+ (ZeroMemory(&ddm, sizeof(ddm)), ddm.cb = sizeof(ddm),
+ EnumDisplayDevices(dd.DeviceName, j, &ddm, 0)) != 0; j++)
+ {
+ if( result >= inputArraySize )
+ return result;
+
+ // Our monitor hardware has string "RTD2205" in it
+ // Nate's device "CVT0003"
+ if (wcsstr(ddm.DeviceID, L"RTD2205") ||
+ wcsstr(ddm.DeviceID, L"CVT0003") ||
+ wcsstr(ddm.DeviceID, L"MST0030") ||
+ wcsstr(ddm.DeviceID, L"OVR00") ) // Part of Oculus EDID.
+ {
+ String deviceId(ddm.DeviceID);
+ String displayDeviceName(ddm.DeviceName);
+ Vector2i desktopOffset(0, 0);
+ Sizei monitorResolution(1280, 800);
+
+ // Make a device type guess
+ HmdTypeEnum deviceTypeGuess = HmdType_Unknown;
+ if (wcsstr(ddm.DeviceID, L"OVR0003"))
+ {
+ // DK2 prototypes and variants
+ deviceTypeGuess = HmdType_DK2;
+ // Could also be:
+ // HmdType_CrystalCoveProto
+ }
+ else if (wcsstr(ddm.DeviceID, L"OVR0002"))
+ { // HD Prototypes
+ deviceTypeGuess = HmdType_DKHDProto;
+ // Could also be:
+ // HmdType_DKHD2Proto
+ // HmdType_DKHDProto566Mi
+ }
+ else if (wcsstr(ddm.DeviceID, L"OVR0001"))
+ { // DK1
+ deviceTypeGuess = HmdType_DK1;
+ }
+ else if (wcsstr(ddm.DeviceID, L"OVR00"))
+ { // Future Oculus HMD devices
+ deviceTypeGuess = HmdType_Unknown;
+ }
+ else
+ {
+ deviceTypeGuess = HmdType_DKProto;
+ }
+
+ // Find the matching MONITORINFOEX for this device so we can get the
+ // screen coordinates
+ MONITORINFOEX info;
+ for (int m=0; m < monitors.MonitorCount; m++)
+ {
+ info.cbSize = sizeof(MONITORINFOEX);
+ GetMonitorInfo(monitors.Monitors[m], &info);
+ if (_tcsstr(ddm.DeviceName, info.szDevice) == ddm.DeviceName)
+ { // If the device name starts with the monitor name
+ // then we found the matching DISPLAY_DEVICE and MONITORINFO
+ // so we can gather the monitor coordinates
+ desktopOffset = Vector2i(info.rcMonitor.left, info.rcMonitor.top);
+ break;
+ }
+ }
+
+ WCHAR* instanceBuffer = (WCHAR*)calloc(wcslen(ddm.DeviceID) + 1, sizeof(WCHAR));
+ wcscpy_s(instanceBuffer, wcslen(ddm.DeviceID) + 1, ddm.DeviceID);
+ WCHAR* instanceName = instanceBuffer;
+ WCHAR* nextToken = NULL;
+ if (wcstok_s(instanceName, L"\\", &nextToken))
+ {
+ WCHAR* aToken = wcstok_s(NULL, L"\\", &nextToken);
+
+ if (aToken)
+ {
+ String serialNumberStr, userFriendlyNameStr;
+ if (!includeEDID || getCompatDisplayEDID(aToken, serialNumberStr, userFriendlyNameStr))
+ {
+ // Set descriptor
+ OVR::Win32::DisplayDesc& desc = descriptorArray[result++];
+
+ // If not including EDID,
+ if (!includeEDID)
+ {
+ // If DK2 id,
+ if (wcsstr(ddm.DeviceID, L"OVR0003"))
+ {
+ userFriendlyNameStr = "Rift DK2";
+ }
+ else // Assume DK1 for now:
+ {
+ userFriendlyNameStr = "Rift DK1";
+ }
+ }
+
+ desc.DeviceTypeGuess = deviceTypeGuess;
+ desc.DisplayID = displayDeviceName;
+ desc.ModelName = userFriendlyNameStr;
+ desc.EdidSerialNumber = serialNumberStr;
+ desc.LogicalResolutionInPixels = monitorResolution;
+ desc.DesktopDisplayOffset = desktopOffset;
+
+ // Hard-coded defaults in case the device doesn't have the data itself.
+ // DK2 prototypes (0003) or DK HD Prototypes (0002)
+ if (wcsstr(ddm.DeviceID, L"OVR0003") || wcsstr(ddm.DeviceID, L"OVR0002"))
+ {
+ desc.LogicalResolutionInPixels = Sizei(1920, 1080);
+ desc.NativeResolutionInPixels = Sizei(1080, 1920);
+ }
+ else
+ {
+ desc.LogicalResolutionInPixels = monitorResolution;
+ desc.NativeResolutionInPixels = monitorResolution;
+ }
+ }
+ }
+ }
+
+ if (reportDiscovery)
+ {
+ // Only report once per run
+ OVR_DEBUG_LOG_TEXT(("Display Found %s - %s\n",
+ deviceId.ToCStr(), displayDeviceName.ToCStr()));
+ reportDiscovery = false;
+ }
+
+ free(instanceBuffer);
+
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** Display
+
+bool Display::InCompatibilityMode( bool displaySearch )
+{
+ bool result = false;
+ if( displaySearch )
+ {
+ OVR::Win32::DisplayDesc displayArray[8];
+
+ int extendedRiftCount = discoverExtendedRifts(displayArray, 8, false);
+ if( extendedRiftCount )
+ {
+ result = true;
+ }
+ else
+ {
+ result = GlobalDisplayContext.CompatibilityMode;
+ }
+ }
+ else
+ {
+ result = GlobalDisplayContext.CompatibilityMode;
+ }
+
+ return result;
+}
+
+#define OVR_FLAG_COMPATIBILITY_MODE 1
+#define OVR_FLAG_HIDE_DK1 2
+
+bool Display::Initialize()
+{
+ HANDLE hDevice = INVALID_HANDLE_VALUE;
+
+ if (GlobalDisplayContext.hDevice == 0)
+ {
+ hDevice = CreateFile( L"\\\\.\\ovr_video" ,
+ GENERIC_READ | GENERIC_WRITE, NULL,
+ NULL, OPEN_EXISTING, NULL, NULL);
+ }
+ else
+ { // The device has already been created
+ hDevice = GlobalDisplayContext.hDevice;
+ }
+
+ if (hDevice != NULL && hDevice != INVALID_HANDLE_VALUE)
+ {
+ GlobalDisplayContext.hDevice = hDevice;
+ GlobalDisplayContext.CompatibilityMode = false;
+
+ DWORD bytesReturned = 0;
+ LONG compatiblityResult = OVR_STATUS_SUCCESS;
+
+ BOOL result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GETCOMPATIBILITYMODE, NULL, 0,
+ &compatiblityResult, sizeof( LONG ), &bytesReturned, NULL );
+ if (result)
+ {
+ GlobalDisplayContext.CompatibilityMode = (compatiblityResult & OVR_FLAG_COMPATIBILITY_MODE) != 0;
+ GlobalDisplayContext.HideDK1Mode = (compatiblityResult & OVR_FLAG_HIDE_DK1) != 0;
+ }
+ else
+ {
+ // If calling our driver fails in any way, assume compatibility mode as well
+ GlobalDisplayContext.CompatibilityMode = true;
+ }
+
+ if (!GlobalDisplayContext.CompatibilityMode)
+ {
+ Ptr<DisplaySearchHandle> searchHandle = *Display::GetDisplaySearchHandle();
+
+ // If a display is actually connected, bring up the shim layers so we can actually use it
+ if (GetDisplayCount(searchHandle) > 0)
+ {
+ // FIXME: Initializing DX9 with landscape numbers rather than portrait
+ GlobalDisplayContext.ExpectedWidth = 1080;
+ GlobalDisplayContext.ExpectedHeight = 1920;
+ }
+ else
+ {
+ GlobalDisplayContext.CompatibilityMode = true;
+ }
+
+ }
+ }
+ else
+ {
+ GlobalDisplayContext.CompatibilityMode = true;
+ }
+
+ return true;
+}
+
+bool Display::GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode)
+{
+ if (GlobalDisplayContext.hDevice == NULL)
+ {
+ driverInstalled = false;
+ compatMode = true;
+ hideDK1Mode = false;
+ }
+ else
+ {
+ driverInstalled = true;
+ compatMode = GlobalDisplayContext.CompatibilityMode;
+ hideDK1Mode = GlobalDisplayContext.HideDK1Mode;
+ }
+
+ return true;
+}
+
+bool Display::SetDriverMode(bool compatMode, bool hideDK1Mode)
+{
+ // If device is not initialized,
+ if (GlobalDisplayContext.hDevice == NULL)
+ {
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ // If no change,
+ if ((compatMode == GlobalDisplayContext.CompatibilityMode) &&
+ (hideDK1Mode == GlobalDisplayContext.HideDK1Mode))
+ {
+ return true;
+ }
+
+ LONG mode_flags = 0;
+ if (compatMode)
+ {
+ mode_flags |= OVR_FLAG_COMPATIBILITY_MODE;
+ }
+ if (hideDK1Mode)
+ {
+ mode_flags |= OVR_FLAG_HIDE_DK1;
+ }
+
+ DWORD bytesReturned = 0;
+ LONG err = 1;
+
+ if (!DeviceIoControl(GlobalDisplayContext.hDevice,
+ IOCTL_RIFTMGR_SETCOMPATIBILITYMODE,
+ &mode_flags,
+ sizeof(LONG),
+ &err,
+ sizeof(LONG),
+ &bytesReturned,
+ NULL) ||
+ (err != 0 && err != -3))
+ {
+ LogError("{ERR-001w} [Win32Display] Unable to set device mode to (compat=%d dk1hide=%d): err=%d",
+ (int)compatMode, (int)hideDK1Mode, (int)err);
+ return false;
+ }
+
+ OVR_DEBUG_LOG(("[Win32Display] Set device mode to (compat=%d dk1hide=%d)",
+ (int)compatMode, (int)hideDK1Mode));
+
+ GlobalDisplayContext.HideDK1Mode = hideDK1Mode;
+ GlobalDisplayContext.CompatibilityMode = compatMode;
+ return true;
+}
+
+DisplaySearchHandle* Display::GetDisplaySearchHandle()
+{
+ return new Win32::Win32DisplaySearchHandle();
+}
+
+// FIXME: The handle parameter will be used to unify GetDisplayCount and GetDisplay calls
+// The handle will be written to the 64-bit value pointed and will store the enumerated
+// display list. This will allow the indexes to be meaningful between obtaining
+// the count. With a single handle the count should be stable
+int Display::GetDisplayCount(DisplaySearchHandle* handle, bool extended, bool applicationOnly, bool extendedEDIDSerials)
+{
+ static int extendedCount = -1;
+ static int applicationCount = -1;
+
+ Win32::Win32DisplaySearchHandle* localHandle = (Win32::Win32DisplaySearchHandle*)handle;
+
+ if( localHandle == NULL )
+ return 0;
+
+ if( extendedCount == -1 || extended )
+ {
+ extendedCount = discoverExtendedRifts(localHandle->cachedDescriptorArray, 16, extendedEDIDSerials);
+ }
+
+ localHandle->extended = true;
+ localHandle->extendedDisplayCount = extendedCount;
+ int totalCount = extendedCount;
+
+ if( applicationCount == -1 || applicationOnly )
+ {
+ applicationCount = getRiftCount(GlobalDisplayContext.hDevice);
+ localHandle->application = true;
+ }
+
+ totalCount += applicationCount;
+ localHandle->applicationDisplayCount = applicationCount;
+ localHandle->displayCount = totalCount;
+
+ return totalCount;
+}
+
+Ptr<Display> Display::GetDisplay(int index, DisplaySearchHandle* handle)
+{
+ Ptr<Display> result;
+
+ if( index < 0 )
+ return result;
+
+ Win32::Win32DisplaySearchHandle* localHandle = (Win32::Win32DisplaySearchHandle*)handle;
+
+ if( localHandle == NULL )
+ return NULL;
+
+ if (localHandle->extended)
+ {
+ if (index >= 0 && index < (int)localHandle->extendedDisplayCount)
+ {
+ return *new Win32::Win32DisplayGeneric(localHandle->cachedDescriptorArray[index]);
+ }
+
+ index -= localHandle->extendedDisplayCount;
+ }
+
+ if(localHandle->application)
+ {
+ if (index >= 0 && index < (int)getRiftCount(GlobalDisplayContext.hDevice))
+ {
+ ULONG riftChildId = getRift(GlobalDisplayContext.hDevice, index);
+ Win32::DisplayEDID dEdid;
+
+ if (!getEdid(GlobalDisplayContext.hDevice, riftChildId, dEdid))
+ {
+ return NULL;
+ }
+
+ // FIXME: We have the EDID. Let's just use that instead.
+ uint32_t nativeWidth = 1080, nativeHeight = 1920;
+ uint32_t logicalWidth = 1920, logicalHeight = 1080;
+ uint32_t rotation = 0;
+
+ switch (dEdid.ModelNumber)
+ {
+ case 0:
+ case 1:
+ nativeWidth = 1280;
+ nativeHeight = 800;
+ logicalWidth = nativeWidth;
+ logicalHeight = nativeHeight;
+ break;
+ case 2:
+ case 3:
+ default:
+ rotation = 90;
+ break;
+ }
+
+ HmdTypeEnum deviceTypeGuess = HmdType_Unknown;
+ switch (dEdid.ModelNumber)
+ {
+ case 3: deviceTypeGuess = HmdType_DK2; break;
+ case 2: deviceTypeGuess = HmdType_DKHDProto; break;
+ case 1: deviceTypeGuess = HmdType_DK1; break;
+ default: break;
+ }
+
+ result = *new Win32::Win32DisplayDriver(
+ deviceTypeGuess,
+ "",
+ dEdid.MonitorName,
+ dEdid.SerialNumber,
+ Sizei(logicalWidth, logicalHeight),
+ Sizei(nativeWidth, nativeHeight),
+ Vector2i(0),
+ dEdid,
+ GlobalDisplayContext.hDevice,
+ riftChildId,
+ rotation);
+ }
+ }
+ return result;
+}
+
+Display::MirrorMode Win32::Win32DisplayDriver::SetMirrorMode( Display::MirrorMode newMode )
+{
+ return newMode;
+}
+
+static bool SetDisplayPower(HANDLE hDevice, ULONG childId, int mode)
+{
+ ULONG_PTR longArray[2];
+
+ longArray[0] = childId;
+ longArray[1] = mode;
+
+ ULONG localResult = 0;
+ DWORD bytesReturned = 0;
+
+ BOOL result = DeviceIoControl(hDevice,
+ IOCTL_RIFTMGR_DISPLAYPOWER,
+ longArray,
+ 2 * sizeof(ULONG_PTR),
+ &localResult,
+ sizeof(ULONG),
+ &bytesReturned,
+ NULL);
+
+ // Note: bytesReturned does not seem to be set
+ return result != FALSE /* && bytesReturned == sizeof(ULONG) */ && mode == (int)localResult;
+}
+
+bool Win32::Win32DisplayDriver::SetDisplaySleep(bool sleep)
+{
+ return SetDisplayPower(hDevice, ChildId, sleep ? 2 : 1);
+}
+
+
+} // namespace OVR
diff --git a/LibOVR/Src/Displays/OVR_Win32_Display.h b/LibOVR/Src/Displays/OVR_Win32_Display.h
new file mode 100644
index 0000000..4517d44
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_Display.h
@@ -0,0 +1,182 @@
+/************************************************************************************
+
+Filename : OVR_Win32_Display.h
+Content : Win32-specific Display declarations
+Created : May 6, 2014
+Authors : Dean Beeler
+
+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.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_Display_h
+#define OVR_Win32_Display_h
+
+#include "OVR_Display.h"
+
+OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized
+
+namespace OVR { namespace Win32 {
+
+
+//-------------------------------------------------------------------------------------
+// DisplayDesc
+
+// Display information enumerable through Win32.
+// TBD: Should we just move this to public header, so it's a const member of Display?
+struct DisplayDesc
+{
+ HmdTypeEnum DeviceTypeGuess; // This is a guess about what type of HMD it is connected to
+ String DisplayID; // This is the device identifier string from MONITORINFO (for app usage)
+ String ModelName; // This is a "DK2" type string
+ String EdidSerialNumber;
+ Sizei LogicalResolutionInPixels;
+ Sizei NativeResolutionInPixels;
+ Vector2i DesktopDisplayOffset;
+};
+
+
+//-------------------------------------------------------------------------------------
+// DisplayEDID
+
+// Describes EDID information as reported from our display driver.
+struct DisplayEDID
+{
+ String MonitorName;
+ UINT16 ModelNumber;
+ String VendorName;
+ String SerialNumber;
+};
+
+class Win32DisplaySearchHandle : public DisplaySearchHandle
+{
+public:
+ static const int ArraySize = 16;
+
+ Win32::DisplayDesc cachedDescriptorArray[ArraySize];
+ bool extended;
+ bool application;
+ int extendedDisplayCount;
+ int applicationDisplayCount;
+ int displayCount;
+
+ Win32DisplaySearchHandle()
+ : cachedDescriptorArray(),
+ extended(),
+ application(false),
+ extendedDisplayCount(0),
+ applicationDisplayCount(0),
+ displayCount(0)
+ {
+ }
+
+ virtual ~Win32DisplaySearchHandle()
+ {
+ }
+};
+
+//-------------------------------------------------------------------------------------
+// Win32DisplayGeneric
+
+// Describes Win32 display in Compatibility mode, containing basic data
+class Win32DisplayGeneric : public Display
+{
+public:
+ Win32DisplayGeneric( const DisplayDesc& dd ) :
+ Display(dd.DeviceTypeGuess,
+ dd.DisplayID,
+ dd.ModelName,
+ dd.EdidSerialNumber,
+ dd.LogicalResolutionInPixels,
+ dd.NativeResolutionInPixels,
+ dd.DesktopDisplayOffset,
+ 0,
+ 0,
+ false)
+ {
+ }
+
+ virtual ~Win32DisplayGeneric()
+ {
+ }
+
+ // Generic displays are not capable of mirroring
+ virtual MirrorMode SetMirrorMode( MirrorMode newMode )
+ {
+ OVR_UNUSED( newMode );
+ return MirrorDisabled;
+ }
+};
+
+
+//-------------------------------------------------------------------------------------
+// Win32DisplayDriver
+
+// Oculus driver based display object.
+class Win32DisplayDriver : public Display
+{
+ HANDLE hDevice;
+ ULONG ChildId;
+ DisplayEDID Edid;
+
+public:
+ Win32DisplayDriver(const HmdTypeEnum deviceTypeGuess,
+ const String& displayID,
+ const String& modelName,
+ const String& edidSerial,
+ const Sizei& logicalRes,
+ const Sizei& nativeRes,
+ const Vector2i& displayOffset,
+ const DisplayEDID& edid,
+ HANDLE hdevice,
+ ULONG child,
+ uint32_t rotation) :
+ Display(deviceTypeGuess,
+ displayID,
+ modelName,
+ edidSerial,
+ logicalRes,
+ nativeRes,
+ displayOffset,
+ child,
+ rotation,
+ true),
+ hDevice(hdevice),
+ ChildId(child),
+ Edid(edid)
+ {
+ }
+
+ virtual ~Win32DisplayDriver()
+ {
+ }
+
+ virtual MirrorMode SetMirrorMode( MirrorMode newMode );
+
+ // Support sleep/wake
+ virtual bool SetDisplaySleep(bool off);
+};
+
+
+}} // namespace OVR::Win32
+
+
+OVR_RESTORE_MSVC_WARNING()
+
+
+#endif // OVR_Win32_Display_h
diff --git a/LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h b/LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h
new file mode 100644
index 0000000..e801f4a
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h
@@ -0,0 +1,429 @@
+/************************************************************************************
+
+PublicHeader: None
+Filename : dxgi_ovr_filter.h
+Content : Shared usermode/kernel mode definitions for IOCTL functionality.
+ Also used from LibOVR to access the driver.
+Created : January 27, 2014
+Authors : Dean Beeler
+
+Copyright : Copyright 2013 Oculus, LLC. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus LLC license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+/************************************************************************************/
+
+#ifndef OVR_dxgi_ovr_filter_h
+#define OVR_dxgi_ovr_filter_h
+
+#include <Windows.h>
+#include <InitGuid.h>
+
+#define USERMODE_TEST_ROTATION 1
+
+#if USERMODE_TEST_ROTATION // Used only by the um test application
+#define USERMODE_SURFACE_WIDTH 1920
+#define USERMODE_SURFACE_HEIGHT 1080
+#else
+#define USERMODE_SURFACE_WIDTH 1080
+#define USERMODE_SURFACE_HEIGHT 1920
+#endif
+
+#define TEST_ROTATION 0 // Kernel-mode parameters
+
+#if TEST_ROTATION
+#define SURFACE_WIDTH 1920
+#define SURFACE_HEIGHT 1080
+#else
+#define SURFACE_WIDTH 1080
+#define SURFACE_HEIGHT 1920
+#endif
+
+// {46231713-49FD-4922-84E3-9FF907C06803}
+DEFINE_GUID(GUID_DEVINTERFACE_OVRRIFTMGR,
+ 0x46231713, 0x49fd, 0x4922, 0x84, 0xe3, 0x9f, 0xf9, 0x7, 0xc0, 0x68, 0x3);
+
+#define QUERYADAPTER_MAGICSIZE 17836
+#define QUERYADAPTER_MAGICHEADER 0x4f565246 // OVRF
+#define QUERYADAPTER_MAXPATH 2048
+
+#define FUNCTION_INDEX 0xb800
+
+#pragma pack(push,1)
+
+#define OVR_RIFT_MODE_OFF 0 // Disabled
+#define OVR_RIFT_MODE_ENABLED 1 // Enabled
+#define OVR_RIFT_MODE_EXTEND 2 // Extending 2D displays. Without this flag
+ // 2D displays are disabled when the Rift
+ // is active
+#define OVR_RIFT_MODE_FRONTBUFFER 4 // Enable front buffer only for Rift
+#define OVR_RIFT_MODE_LOCKMOUSE 8 // Prevent mouse from entering bounds
+
+#define OVR_ESCAPE_TYPE_HANDLE 1 // Escape to notify driver of our collected handles
+
+#define OVR_FlipImmediate 0x2
+#define OVR_FlipOnNextVSync 0x4
+
+//-----------------------------------------------------------------------------------
+// Structures for application to UM driver
+
+// Kernel32.dll functionality
+typedef HMODULE (WINAPI *WinLoadLibraryA) ( LPCSTR );
+typedef HMODULE (WINAPI *WinLoadLibraryW) ( LPCWSTR );
+typedef HMODULE (WINAPI *WinLoadLibraryExA) ( LPCSTR, HANDLE, DWORD );
+typedef HMODULE (WINAPI *WinLoadLibraryExW) ( LPCWSTR, HANDLE, DWORD );
+typedef BOOL (WINAPI *WinGetModuleHandleExA)( DWORD, LPCSTR, HMODULE* );
+typedef BOOL (WINAPI *WinGetModuleHandleExW)( DWORD, LPCWSTR, HMODULE* );
+
+// Overridden DirectX 9 entry points
+typedef void* (WINAPI *WinDirect3DCreate9)(UINT SDKVersion);
+typedef HRESULT (WINAPI *WinDirect3DCreate9Ex)(UINT SDKVersion, void** aDevice);
+
+// Overridden DXGI entry points
+typedef HRESULT (WINAPI *WinCreateDXGIFactory)(
+ __in REFIID riid,
+ __out void **ppFactory
+ );
+
+typedef HRESULT (WINAPI *WinCreateDXGIFactory1)(
+ __in REFIID riid,
+ __out void **ppFactory
+ );
+
+typedef HRESULT (WINAPI *WinCreateDXGIFactory2)(
+ __in UINT flags,
+ __in const IID &riid,
+ __out void **ppFactory
+ );
+
+// Application usermode callbacks from usermode driver. These
+// functions are all provided by the calling application that uses
+// the filter mode driver
+
+// IsInitializingDisplay is used at runtime to validate that
+// the created resource (RT or bind_present) matches the resolution
+// of our expected backbuffer. If the application returns true,
+// our usermode driver will convert this to a primary
+typedef BOOL (WINAPI *IsInitializingDisplay) ( PVOID, UINT, UINT );
+// RiftForContext is a function that will return the Rift device of
+// the concerned context. This is for targeting a particular
+// device instance with a particular Rift for rendering
+typedef ULONG (WINAPI *RiftForContext)( PVOID, HANDLE );
+// CloseRiftForContext is a function that informs the application
+// the created device is shutting down and the context
+// can freedly disassociate with the particular
+typedef BOOL (WINAPI *CloseRiftForContext)( PVOID, HANDLE, ULONG );
+typedef BOOL (WINAPI *WindowDisplayResolution)( PVOID, UINT*, UINT*, UINT*, UINT*, BOOL* );
+// IsCreatingBackBuffer is a function directed at the runtime shim
+// to confirm that the runtime is actively creating the additional
+// swapchain for rotation and display out to the rift.
+// When creating the original swapchain this function should return false
+// so the orignal swapchain isn't inadvertantly coopted.
+typedef BOOL (WINAPI *IsCreatingBackBuffer)( PVOID );
+// Callback from the usermode driver to obtain the desire to see debug statements from
+// the usermode drivers on the output console. Only called one per usermode driver shim
+// and usermode runtime.
+typedef BOOL (WINAPI *ShouldEnableDebug)( VOID );
+// Callback from the usermode driver to the runtime obtain the vsync status
+typedef BOOL (WINAPI *ShouldVSync)( VOID );
+// Callback from usermode mode and runtime driver to obtain expected native width,
+// height and degrees rotation of the rift
+typedef BOOL (WINAPI *ExpectedResolution)( PVOID, UINT*, UINT*, UINT* );
+// Usermode callback that reports whether or not mirroring is enabled
+typedef BOOL (WINAPI *MirroringEnabled)( PVOID );
+// Callback from the shim for Unity and other plugins used to
+// report the swapchain that was created by the application
+typedef void* (WINAPI *GetDX11SwapChain)( PVOID );
+// Callback to report the HWND associated with this context
+typedef HWND (WINAPI* GetWindowForContext)( PVOID );
+// Should present Rift on context
+typedef BOOL (WINAPI* PresentRiftOnContext)( PVOID );
+// Used by a pre-loaded shim (d3d9, dxgi, opengl32) to
+// identify which api version we loaded
+// 1 = OpenGL
+// 9 = DirectX 9
+// 10 = DirectX 1X
+typedef int (WINAPI* ActiveAPIVersion)( PVOID );
+
+// Get the version of the runtime filter.
+typedef ULONG (WINAPI* GetRTFilterVersion)();
+
+#pragma warning(push)
+#pragma warning(disable: 4201)
+
+typedef struct _LINK_APPLICATION_DRIVER
+{
+ UINT32 version;
+ PVOID context;
+
+ union
+ {
+ struct
+ {
+ IsInitializingDisplay pfnInitializingDisplay;
+ RiftForContext pfnRiftForContext;
+ CloseRiftForContext pfnCloseRiftForContext;
+ WindowDisplayResolution pfnWindowDisplayResolution;
+ IsCreatingBackBuffer pfnIsCreatingBackBuffer;
+ ShouldEnableDebug pfnShouldEnableDebug;
+ ShouldVSync pfnShouldVSync;
+ ExpectedResolution pfnExpectedResolution;
+ MirroringEnabled pfnMirroringEnabled;
+ GetDX11SwapChain pfnGetDX11SwapChain;
+ GetWindowForContext pfnGetWindowForContext;
+ PresentRiftOnContext pfnPresentRiftOnContext;
+ ActiveAPIVersion pfnActiveAPIVersion;
+ };
+
+ PROC placeholders[128];
+ };
+
+
+ // Used by Runtime filter for linking with original libraries
+ WinDirect3DCreate9 pfnDirect3DCreate9;
+ WinDirect3DCreate9Ex pfnDirect3DCreate9Ex;
+ WinCreateDXGIFactory pfnCreateDXGIFactory;
+ WinCreateDXGIFactory1 pfnCreateDXGIFactory1;
+ WinCreateDXGIFactory2 pfnCreateDXGIFactory2;
+} LINK_APPLICATION_DRIVER, *PLINK_APPLICATION_DRIVER;
+
+#pragma warning(pop)
+
+
+// OVRDisplay.dll functionality
+typedef HRESULT (WINAPI *PreloadLibraryFn) ( WinLoadLibraryA , LPCSTR, PLINK_APPLICATION_DRIVER appDriver );
+typedef HRESULT (WINAPI *PreloadLibraryRTFn) ( PLINK_APPLICATION_DRIVER appDriver );
+
+//-----------------------------------------------------------------------------------
+// Structures for UM driver to KM driver
+
+typedef struct _QUERY_KM_DRIVER
+{
+ UINT32 magic; // Friend or foe identifier for our filter driver
+ // See: QUERYADAPTER_MAGICHEADER
+ UINT32 maxVidPnSources; // Returns the maximum number of video present network sources
+} QUERY_KM_DRIVER, *PQUERY_KM_DRIVER;
+
+#ifndef _D3DUKMDT_H_
+typedef UINT D3DKMT_HANDLE;
+#endif
+
+typedef struct _HandleNotepad
+{
+ // These are assigned around CreateResource
+ HANDLE hUsermodeInResource;
+ HANDLE hUsermodeOutResource;
+
+ // These are assigned within the kernel with
+ // DxgkDdiCreateAllocation and
+ // DxgkDdiOpenAllocation
+ D3DKMT_HANDLE hAllocation;
+ PVOID hDeviceSpecificHandle;
+ PVOID hKernelDriverHandle;
+
+ // These are assigned around pfnAllocateCb
+ HANDLE hUsermodeSharedResource;
+ D3DKMT_HANDLE hKernelModeSharedResource;
+
+ ULONG childUid;
+
+ UINT pitch;
+
+} HandleNotepad, *PHandleNotepad;
+
+
+typedef struct _ALLOC_PRIVATE_STRUCTURE
+{
+ UINT32 magic; // Friend or foe identifier for our filter driver
+
+ PVOID originalPrivataDataPtr; // Location in usermode of the original private data structure
+ UINT originalPrivateSize; // Size of private data structure at the end of this header
+
+ PVOID hAllocationHandle; // User-mode-assigned allocation handle for CreateAllocation
+ PVOID hDeviceSpecificHandle; // Assigned in kernal OpenAllocation
+ PVOID hInternalHandle; // Assigned in kernal CreateAllocation
+ UINT pitch; // Hinted surface pitch
+
+ BYTE originalPrivateData[1]; // Variable length
+
+
+} ALLOC_PRIVATE_STRUCTURE, *PALLOC_PRIVATE_STRUCTURE;
+
+typedef struct _ESCAPE_STRUCTURE
+{
+ UINT32 magic; // Friend or foe identifier for our filter driver
+
+ UINT32 escapeType; // Specifier for individual type of escape message
+ // Type 1 for notepad
+ union {
+ HandleNotepad notepad;
+ };
+} ESCAPE_STRUCTURE, *PESCAPE_STRUCTURE;
+
+// Structures for internal operation of KM driver
+
+typedef struct _RIFT_SYNC
+{
+ ULONG childUid; // ChildUid as reported by RIFT_STATUS
+ ULONG vsync; // 1 for vsync, 0 for immediate
+} RIFT_SYNC, *PRIFT_SYNC;
+
+typedef struct _RIFT_MODE
+{
+ ULONG childUid; // ChildUid as reported by RIFT_STATUS
+ ULONG mode; // Bitmap of mode values, defined by OVR_RIFT_HOME_*
+ HANDLE userModeHandle; // Handle of render target created in user mode
+ // that's usable as a primary
+} RIFT_MODE, *PRIFT_MODE;
+
+typedef struct _RIFT_STATUS
+{
+ ULONG childUid; // Display driver assigned Uid for this display
+ ULONG mode; // Active rift mode, see OVR_RIFT_MODE_*
+ ULONG serialNumber; // Serial number as reported in the Rift's EDID
+ ULONG textureHandle; // Handle of shared render resource -- NULL if not shared
+} RIFT_STATUS, *PRIFT_STATUS;
+
+typedef struct _RIFT_STATUS_ARRAY
+{
+ ULONG arraySize; // Size of pre-allocated RIFT_STATUS structures.
+ RIFT_STATUS status[1]; // Array of status blocks containing connection information on each Rift
+} RIFT_STATUS_ARRAY, *PRIFT_STATUS_ARRAY;
+
+#pragma pack(pop)
+
+// IOCTL for UM application to KM driver
+
+#define OVR_STATUS_SUCCESS 0
+#define OVR_STATUS_FAIL -1
+#define OVR_STATUS_DRIVER_IN_USE -2
+#define OVR_STATUS_MODE_ALREADY_ACTIVE -3
+#define OVR_STATUS_RIFT_NOT_PRESENT -4
+
+//
+// Returns the number of Rift displays attached to the video adapter
+// If 0, no Rift displays have been connected.
+// If greater than 0, use this size to pre-allocate space for an array
+// of rift statuses
+//
+// Input Buffer: Nothing
+// Output Buffer: LONG - count of Rift displays attached to video adapter
+//
+#define IOCTL_RIFTMGR_GET_RIFT_COUNT CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+//
+// Fills out a pre-allocated array with information on the individually attached
+// screens.
+//
+// On Input, specify the arraySize as the size of the allocation.
+//
+// On Output, the arraySize will be updated with the actual number of Rifts
+// reported. Use IOCTL_RIFTMGR_GET_RIFT_COUNT to query the number of Rifts.
+// If the count changes (added or removed) between calls, the function will either fail
+// due to the buffer being too small, or the arraySize count will be updated
+// with a new count of devices along with their respective parameters.
+//
+// Input Buffer: PRIFT_STATUS - Pointer to allocated status array
+// Output Buffer: LONG - Count of Rift displays reported in the structure. -1 if out of
+// memory
+//
+#define IOCTL_RIFTMGR_GET_RIFT_ARRAY CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 1, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Changes the mode of an attached Rift (DEPRECATED)
+// Input Buffer: PRIFT_MODE - Pointer to a mode structure specifying the childUid and
+// mode for a particular Rift
+// Output Buffer: LONG - Non-zero on error, 0 on successful mode change
+//
+#define IOCTL_RIFTMGR_SET_RIFT_MODE CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 2, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Lock the primary of the rift and obtain an address
+// Input Buffer: ULONG - ChildUid of a Rift as previously discovered
+// Output Buffer: ULONG_PTR - Pointer to a usermode mapped address of the primary
+#define IOCTL_RIFTMGR_GET_RIFT_PRIMARY CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 3, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Release Rift primary
+// Input Buffer: PULONG_PTR - ChildUid of a Rift as previously discovered and virtual pointer
+// Output Buffer: NOTHING
+#define IOCTL_RIFTMGR_RELEASE_RIFT_PRIMARY CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 4, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+
+// Point the rift to another render target
+// Input Buffer: PHANDLE - Array of handles, rift and the render target resource
+// Output Buffer: NOTHING
+#define IOCTL_RIFTMGR_SETRIFTBUFFER CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 5, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Enable or disable vsync on Rift present
+// Input Buffer: PRIFT_SYNC - Pointer to a mode structure specifying the childUid and
+// and sync
+// Output Buffer: NOTHING
+#define IOCTL_RIFTMGR_SETVSYNCMODE CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 6, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Get scan line
+// Input Buffer: ULONG - ChildUid of a Rift as previously discovered
+// Output Buffer: ULONG - 31st bit is set if in vertical blank, high 15 bits has per second
+// frame number (0-74), low 16 bits has scanline (0-1919)
+#define IOCTL_RIFTMGR_GETSCANLINE CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 7, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Enable or disable compatibility mode. Entering compatibility mode will fail if
+// the Rift is already actively scanning out a surface
+// Input Buffer: LONG - Bit assignments:
+// LSB (bit 0) is a flag for compatibility mode itself.
+// 1 means compatibility mode.
+// 0 means application direct mode.
+// Bit 1 means "Hide DK1's".
+// 1 means operate DK1's in synchronous with the compatibility mode exactly.
+// 0 means operate in DK1 legacy mode.
+// Output Buffer: LONG - Result value (see OVR statuses)
+// 0 = success
+// -1 = general failure
+// -2 = failure, rift scanning out
+// -3 = already active
+// -4 = rift not present
+#define IOCTL_RIFTMGR_SETCOMPATIBILITYMODE CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 8, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Call to obtain the current status of compatibility mode
+// Input Buffer: NOTHING
+// Output Buffer: LONG - Bit assignments:
+// LSB (bit 0) is a flag for compatibility mode itself.
+// 1 means compatibility mode.
+// 0 means application direct mode.
+// Bit 1 means "Hide DK1's".
+// 1 means operate DK1's in synchronous with the compatibility mode exactly.
+// 0 means operate in DK1 legacy mode.
+#define IOCTL_RIFTMGR_GETCOMPATIBILITYMODE CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 9, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Call to set the power mode of a particular Rift
+// Input Buffer: PULONG_PTR - ChildUid of a Rift as previously discovered and ULONG value
+// second ULONG has value of
+// 0 to simply obtain the power status of the display
+// 1 to set the display into a full power state (needs a primary to fully scan out)
+// 2 to set the display into sleep mode
+// 3 to set the display into full power off mode (WARNING: Will potentially trash primary)
+// Output Buffer: LONG - Result value
+// 0 = Failure to obtain power status
+// 1 = Full power
+// 2 = Sleep
+// 3 = Power off
+#define IOCTL_RIFTMGR_DISPLAYPOWER CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 10, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+// Return the EDID of the display in the output buffer. The driver
+// will copy as many bytes as possible to fill the buffer.
+// Input Buffer: ULONG - ChildUid of a Rift as previously discovered
+// Output Buffer: PCHAR - Preallocated buffer of a variable size to store the EDID from the display
+#define IOCTL_RIFTMGR_GETEDID CTL_CODE(FILE_DEVICE_VIDEO, \
+ FUNCTION_INDEX + 11, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#endif
diff --git a/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp b/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp
new file mode 100644
index 0000000..7c3c7a3
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp
@@ -0,0 +1,79 @@
+/************************************************************************************
+
+Filename : OVR_Win32_FocusReader.cpp
+Content : Reader for current app with focus on Windows
+Created : July 2, 2014
+Authors : Chris Taylor
+
+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_Win32_FocusReader.h"
+#include "../Kernel/OVR_Log.h"
+#include "../Service/Service_NetClient.h"
+
+OVR_DEFINE_SINGLETON(OVR::Win32::RenderFocusReader);
+
+namespace OVR { namespace Win32 {
+
+
+HWND RenderFocusReader::ReadActiveWindow()
+{
+ const LocklessFocusState* focusState = Reader.Get();
+
+ if (!focusState || NoSharedMemory)
+ {
+ if (!Reader.Open(OVR_FOCUS_OBSERVER_SHARE_NAME))
+ {
+ OVR_DEBUG_LOG(("[Win32ShimFunctions] Unable to open the shared memory space"));
+ // Note: This should only warn and not assert because it is normal behavior when the server is not running.
+ NoSharedMemory = true;
+ return 0;
+ }
+
+ focusState = Reader.Get();
+ if (!focusState)
+ {
+ OVR_DEBUG_LOG(("[Win32ShimFunctions] Unable to get the shared memory space"));
+ NoSharedMemory = true;
+ return 0;
+ }
+ }
+
+ return (HWND)Ptr64ToPtr(focusState->ActiveWindowHandle);
+}
+
+RenderFocusReader::RenderFocusReader() :
+ NoSharedMemory(false)
+{
+ // Must be at end of function
+ PushDestroyCallbacks();
+}
+
+RenderFocusReader::~RenderFocusReader()
+{
+}
+
+void RenderFocusReader::OnSystemDestroy()
+{
+ delete this;
+}
+
+
+}} // namespace OVR::Win32
diff --git a/LibOVR/Src/Displays/OVR_Win32_FocusReader.h b/LibOVR/Src/Displays/OVR_Win32_FocusReader.h
new file mode 100644
index 0000000..358ab38
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_FocusReader.h
@@ -0,0 +1,81 @@
+/************************************************************************************
+
+Filename : OVR_Win32_FocusReader.h
+Content : Reader for current app with focus on Windows
+Created : July 2, 2014
+Authors : Chris Taylor
+
+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.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_FocusReader_h
+#define OVR_Win32_FocusReader_h
+
+#include "../Kernel/OVR_System.h"
+#include "../Kernel/OVR_Lockless.h"
+#include "../Kernel/OVR_Array.h"
+#include "../Kernel/OVR_SharedMemory.h"
+
+namespace OVR { namespace Win32 {
+
+
+#define OVR_FOCUS_OBSERVER_SHARE_NAME "OVRAppFocus"
+
+//-----------------------------------------------------------------------------
+// LocklessFocusState
+
+#pragma pack(push, 8)
+
+// Focus state data
+struct LocklessFocusState
+{
+ LocklessFocusState(DWORD pid = 0) :
+ ActiveProcessId(pid),
+ ActiveWindowHandle(NULL)
+ {
+ }
+
+ DWORD ActiveProcessId;
+ void * POINTER_64 ActiveWindowHandle;
+};
+
+#pragma pack(pop)
+
+typedef SharedObjectWriter< LocklessFocusState > SharedFocusWriter;
+typedef SharedObjectReader< LocklessFocusState > SharedFocusReader;
+
+
+//-----------------------------------------------------------------------------
+// RenderFocusReader
+
+class RenderFocusReader : public OVR::SystemSingletonBase<RenderFocusReader>, public NewOverrideBase
+{
+ OVR_DECLARE_SINGLETON(RenderFocusReader);
+
+ SharedFocusReader Reader; // Shared memory reader
+ bool NoSharedMemory; // Flag reporting that no shared memory has been detected;
+
+public:
+ HWND ReadActiveWindow();
+};
+
+
+}} // namespace OVR::Win32
+
+#endif // OVR_Win32_FocusReader_h
diff --git a/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp b/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp
new file mode 100644
index 0000000..a74ab75
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp
@@ -0,0 +1,974 @@
+/************************************************************************************
+
+Filename : OVR_Win32_DisplayShim.cpp
+Content : Shared static functions for inclusion that allow for an application
+ to inject the usermode driver into an application
+Created : March 21, 2014
+Authors : Dean Beeler
+
+Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus Inc license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "../../Include/OVR_Version.h"
+
+#ifndef AVOID_LIB_OVR
+#include "../Kernel/OVR_Types.h" // Without this we can get warnings (due to VC++ bugs) about _malloca being redefined, and miss LibOVR overrides.
+#endif
+
+#include <windows.h>
+#include <DbgHelp.h>
+#include <malloc.h>
+
+#include "OVR_Win32_Dxgi_Display.h"
+#include "OVR_Win32_ShimVersion.h"
+
+#if AVOID_LIB_OVR
+#define IN_COMPATIBILITY_MODE() (0)
+#else
+#include "OVR_Win32_Display.h"
+#define IN_COMPATIBILITY_MODE() OVR::Display::InCompatibilityMode()
+#endif
+
+#pragma comment(lib, "DbgHelp.lib")
+
+#define WIDE_TO_MB(wideString) \
+ int wideString ## _slen = (int)wcslen(wideString); \
+ char* wideString ## _cstr = (char*)alloca(wideString ## _slen * 2); \
+ int count = WideCharToMultiByte(GetACP(), 0, wideString, -1, wideString ## _cstr, wideString ## _slen * 2, NULL, NULL); \
+ wideString ## _cstr[count] = '\0';
+
+// Forward declarations
+// These functions are implemented in OVR_Win32_DisplayDevice.cpp.
+
+BOOL WINAPI OVRIsInitializingDisplay( PVOID context, UINT width, UINT height );
+BOOL WINAPI OVRIsCreatingBackBuffer( PVOID context );
+BOOL WINAPI OVRShouldVSync( );
+ULONG WINAPI OVRRiftForContext( PVOID context, HANDLE driverHandle );
+BOOL WINAPI OVRCloseRiftForContext( PVOID context, HANDLE driverHandle, ULONG rift );
+BOOL WINAPI OVRWindowDisplayResolution( PVOID context, UINT* width, UINT* height,
+ UINT* titleHeight, UINT* borderWidth,
+ BOOL* vsyncEnabled );
+BOOL WINAPI OVRExpectedResolution( PVOID context, UINT* width, UINT* height, UINT* rotationInDegrees );
+BOOL WINAPI OVRShouldEnableDebug();
+BOOL WINAPI OVRMirroringEnabled( PVOID context );
+HWND WINAPI OVRGetWindowForContext(PVOID context);
+BOOL WINAPI OVRShouldPresentOnContext(PVOID context);
+
+static const char* GFX_DRIVER_KEY_FMT = "SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\%04d";
+#ifdef _WIN64
+static const char* RTFilter = "OVRDisplayRT64.dll";
+static const char* UMFilter = "OVRDisplay64.dll";
+#else
+static const char* RTFilter = "OVRDisplayRT32.dll";
+static const char* UMFilter = "OVRDisplay32.dll";
+#endif
+static const char* OptimusDrivers = "nvumdshimx.dll nvumdshim.dll";
+
+typedef enum OVRTargetAPI
+{
+ DirectX,
+ OpenGL
+};
+
+static PVOID lastContext = NULL;
+LINK_APPLICATION_DRIVER appDriver = {0};
+static INT apiVersion = 10;
+
+static CHAR* ReadRegStr(HKEY keySub, const char* keyName, const char* valName)
+{
+ CHAR *val = NULL;
+ REGSAM access = KEY_READ;
+ HKEY hKey;
+
+TryAgainWOW64:
+ NTSTATUS res = RegOpenKeyExA( keySub, keyName, 0, access, &hKey );
+ if ( res == ERROR_SUCCESS )
+ {
+ DWORD valLen;
+ res = RegQueryValueExA( hKey, valName, NULL, NULL, NULL, &valLen );
+ if( res == ERROR_SUCCESS ) {
+ val = (CHAR*)calloc( valLen + 1, sizeof(CHAR) );
+ res = RegQueryValueExA( hKey, valName, NULL, NULL, (LPBYTE)val, &valLen );
+
+ if( res == ERROR_SUCCESS )
+ {
+ CHAR* byte = val;
+ for( DWORD j = 0; j < valLen; ++j )
+ {
+ if( byte[j] == 0 )
+ byte[j] = ' ';
+ }
+ }
+ else
+ {
+ free( val );
+ val = NULL;
+ }
+ }
+ RegCloseKey( hKey );
+ }
+
+ if( res == ERROR_FILE_NOT_FOUND && keySub == HKEY_LOCAL_MACHINE && access == KEY_READ ) {
+#ifdef _WIN64
+ access = KEY_READ | KEY_WOW64_32KEY;
+#else
+ access = KEY_READ | KEY_WOW64_64KEY;
+#endif
+ goto TryAgainWOW64;
+ }
+ return val;
+}
+
+#define OLD_DATA_BACKUP_SIZE 16
+
+static WinLoadLibraryA oldProcA = NULL; // Note: This is used to indicate that the shim is in place
+static WinLoadLibraryExA oldProcExA = NULL;
+static WinLoadLibraryW oldProcW = NULL;
+static WinLoadLibraryExW oldProcExW = NULL;
+static WinGetModuleHandleExA oldProcModExA = NULL;
+static WinGetModuleHandleExW oldProcModExW = NULL;
+static WinDirect3DCreate9 oldDirectX9Create = NULL;
+static BYTE oldDirectX9CreateData[OLD_DATA_BACKUP_SIZE];
+static WinDirect3DCreate9Ex oldDirectX9ExCreate = NULL;
+static BYTE oldDirectX9ExCreateData[OLD_DATA_BACKUP_SIZE];
+static WinCreateDXGIFactory oldCreateDXGIFactory = NULL;
+static BYTE oldCreateDXGIFactoryData[OLD_DATA_BACKUP_SIZE];
+static WinCreateDXGIFactory1 oldCreateDXGIFactory1 = NULL;
+static BYTE oldCreateDXGIFactory1Data[OLD_DATA_BACKUP_SIZE];
+static WinCreateDXGIFactory2 oldCreateDXGIFactory2 = NULL;
+static BYTE oldCreateDXGIFactory2Data[OLD_DATA_BACKUP_SIZE];
+
+#define NUM_LOADER_LIBS 4
+
+static const char* loaderLibraryList[NUM_LOADER_LIBS] = {
+ "kernel32.dll",
+ "api-ms-win-core-libraryloader-l1-2-0.dll",
+ "api-ms-win-core-libraryloader-l1-1-0.dll",
+ "api-ms-win-core-libraryloader-l1-1-1.dll"
+};
+
+enum ShimedLibraries
+{
+ ShimLibDXGI = 0,
+ ShimLibD3D9 = 1,
+ ShimLibD3D11 = 2,
+ ShimLibDXGIDebug = 3,
+ ShimLibD3D10Core = 4,
+ ShimLibD3D10 = 5,
+ ShimLibGL = 6,
+ ShimCountMax = 7
+};
+
+static const char* dllList[ShimCountMax] = {
+ "dxgi.dll",
+ "d3d9.dll",
+ "d3d11.dll",
+ "dxgidebug.dll",
+ "d3d10core.dll",
+ "d3d10.dll",
+ "opengl32.dll"
+};
+
+static HINSTANCE oldLoaderInstances[ShimCountMax] = { NULL };
+static PROC oldLoaderProcA[ShimCountMax][NUM_LOADER_LIBS] = { { NULL } };
+static PROC oldLoaderProcW[ShimCountMax][NUM_LOADER_LIBS] = { { NULL } };
+static PROC oldLoaderProcExA[ShimCountMax][NUM_LOADER_LIBS] = { { NULL } };
+static PROC oldLoaderProcExW[ShimCountMax][NUM_LOADER_LIBS] = { { NULL } };
+static PROC oldLoaderProcModExA[ShimCountMax][NUM_LOADER_LIBS] = { { NULL } };
+static PROC oldLoaderProcModExW[ShimCountMax][NUM_LOADER_LIBS] = { { NULL } };
+
+static HMODULE rtFilterModule = NULL;
+
+static bool checkForOverride( LPCSTR libFileName, OVRTargetAPI& targetApi )
+{
+ for (int i=0; ; i++)
+ {
+ CHAR keyString[256] = {0};
+
+ sprintf_s( keyString, 256, GFX_DRIVER_KEY_FMT, i );
+
+ CHAR* infSection = ReadRegStr( HKEY_LOCAL_MACHINE, keyString, "InfSection" );
+
+ // No provider name means we're out of display enumerations
+ if( infSection == NULL )
+ break;
+
+ free(infSection);
+
+ // Check 64-bit driver names followed by 32-bit driver names
+ const char* driverKeys[] = {"UserModeDriverName", "UserModeDriverNameWoW", "OpenGLDriverName", "OpenGLDriverNameWoW", "InstalledDisplayDrivers" };
+ for( int j = 0; j < 6; ++j )
+ {
+ CHAR userModeList[4096] = {0};
+
+ switch(j)
+ {
+ case 5:
+ strcpy_s( userModeList, 4095, OptimusDrivers );
+ break;
+ default:
+ {
+ CHAR* regString = ReadRegStr( HKEY_LOCAL_MACHINE, keyString, driverKeys[j] );
+ if( regString )
+ {
+ strcpy_s( userModeList, 4095, regString );
+ free( regString );
+ }
+
+ }
+ break;
+ }
+
+ char *nextToken = NULL;
+
+ if( userModeList )
+ {
+ char* first = strtok_s( userModeList, " ", &nextToken );
+ while( first )
+ {
+ if( strstr( libFileName, first ) != 0 )
+ {
+ if( j < 2 )
+ targetApi = DirectX;
+ else
+ targetApi = OpenGL;
+
+ return true;
+ }
+ first = strtok_s( NULL, " ", &nextToken );
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static HMODULE createShim( LPCSTR lpLibFileName, OVRTargetAPI targetAPI )
+{
+ //Sleep(10000);
+ if( IN_COMPATIBILITY_MODE() )
+ {
+ return (*oldProcA)( lpLibFileName );
+ }
+
+ UNREFERENCED_PARAMETER( targetAPI );
+
+ HMODULE result = NULL;
+
+ result = (*oldProcA)( UMFilter );
+
+ if( result )
+ {
+ PreloadLibraryFn loadFunc = (PreloadLibraryFn)GetProcAddress( result, "PreloadLibrary" );
+ if( loadFunc )
+ {
+ HRESULT localRes = (*loadFunc)( oldProcA, lpLibFileName, &appDriver );
+ if( localRes != S_OK )
+ result = NULL;
+ }
+ }
+
+ if( !result )
+ {
+ MessageBox(nullptr, L"Unable to find the Rift Display Driver.", L"Configuration Error", MB_OK | MB_ICONERROR);
+ result = (*oldProcA)( lpLibFileName );
+ }
+ return result;
+}
+
+static HMODULE
+ WINAPI
+ OVRLoadLibraryA(
+ __in LPCSTR lpLibFileName
+ )
+{
+ OVRTargetAPI targetAPI = DirectX;
+ bool needShim = checkForOverride( lpLibFileName, targetAPI );
+ if( !needShim )
+ return (*oldProcA)( lpLibFileName );
+
+ return createShim( lpLibFileName, targetAPI );
+}
+
+static HMODULE
+ WINAPI
+ OVRLoadLibraryW(
+ __in LPCWSTR lpLibFileName
+ )
+{
+ WIDE_TO_MB(lpLibFileName); // Convert lpLibFileName -> lpLibFileName_cstr
+
+ OVRTargetAPI targetAPI = DirectX;
+
+ bool needShim = checkForOverride( lpLibFileName_cstr, targetAPI );
+ if( !needShim )
+ return (*oldProcW)( lpLibFileName );
+
+ return createShim( lpLibFileName_cstr, targetAPI );
+}
+
+static HMODULE
+ WINAPI
+ OVRLoadLibraryExA(
+ __in LPCSTR lpLibFileName,
+ __reserved HANDLE hFile,
+ __in DWORD dwFlags
+
+ )
+{
+ OVRTargetAPI targetAPI = DirectX;
+
+ bool needShim = checkForOverride( lpLibFileName, targetAPI );
+ if( !needShim )
+ return (*oldProcExA)( lpLibFileName, hFile, dwFlags );
+
+ // FIXME: Don't throw away the flags parameter
+ return createShim( lpLibFileName, targetAPI );
+}
+
+static HMODULE
+ WINAPI
+ OVRLoadLibraryExW(
+ __in LPCWSTR lpLibFileName,
+ __reserved HANDLE hFile,
+ __in DWORD dwFlags
+ )
+{
+ WIDE_TO_MB(lpLibFileName); // Convert lpLibFileName -> lpLibFileName_cstr
+
+ OVRTargetAPI targetAPI = DirectX;
+
+ bool needShim = checkForOverride( lpLibFileName_cstr, targetAPI );
+ if( !needShim )
+ return (*oldProcExW)( lpLibFileName, hFile, dwFlags );
+
+ // FIXME: Don't throw away the flags parameter
+ return createShim( lpLibFileName_cstr, targetAPI );
+}
+
+static BOOL WINAPI OVRGetModuleHandleExA(
+ __in DWORD dwFlags,
+ __in_opt LPCSTR lpModuleName,
+ __out HMODULE *phModule
+ )
+{
+ OVRTargetAPI targetAPI = DirectX;
+
+ bool needShim = checkForOverride( lpModuleName, targetAPI );
+ if( !needShim )
+ {
+ return (*oldProcModExA)( dwFlags, lpModuleName, phModule );
+ }
+
+ *phModule = createShim( lpModuleName, targetAPI );
+
+ return TRUE;
+}
+
+static BOOL WINAPI OVRGetModuleHandleExW(
+ __in DWORD dwFlags,
+ __in_opt LPCWSTR lpModuleName,
+ __out HMODULE *phModule
+ )
+{
+ WIDE_TO_MB(lpModuleName); // Convert lpModuleName -> lpModuleName_cstr
+
+ OVRTargetAPI targetAPI = DirectX;
+
+ bool needShim = checkForOverride( lpModuleName_cstr, targetAPI );
+ if( !needShim )
+ {
+ return (*oldProcModExW)( dwFlags, lpModuleName, phModule );
+ }
+
+ *phModule = createShim( lpModuleName_cstr, targetAPI );
+
+ return TRUE;
+}
+
+#ifdef _AMD64_
+static void restoreFunction( PROC pfnHookAPIAddr, PBYTE oldData )
+{
+ static const LONGLONG addressSize = sizeof(PROC);
+ static const LONGLONG jmpSize = addressSize + 6;
+
+ DWORD oldProtect;
+ VirtualProtect((LPVOID)pfnHookAPIAddr, OLD_DATA_BACKUP_SIZE,
+ PAGE_EXECUTE_READWRITE, &oldProtect);
+
+ memcpy(pfnHookAPIAddr, oldData, OLD_DATA_BACKUP_SIZE);
+
+ VirtualProtect((LPVOID)pfnHookAPIAddr, OLD_DATA_BACKUP_SIZE, oldProtect, NULL);
+}
+
+static void setFunction( PROC pfnHookAPIAddr, PROC replacementFunction, PBYTE oldData )
+{
+ static const LONGLONG addressSize = sizeof(PROC);
+ static const LONGLONG jmpSize = addressSize + 6;
+
+ INT_PTR jumpOffset = (INT_PTR)replacementFunction;
+
+ DWORD oldProtect;
+ VirtualProtect((LPVOID)pfnHookAPIAddr, OLD_DATA_BACKUP_SIZE,
+ PAGE_EXECUTE_READWRITE, &oldProtect);
+
+ memcpy(oldData, pfnHookAPIAddr, OLD_DATA_BACKUP_SIZE);
+
+ PBYTE functionData = (PBYTE)pfnHookAPIAddr;
+ functionData[0] = 0xff; // JMP [RIP+0]
+ functionData[1] = 0x25; //
+ functionData[2] = 0x00; //
+ functionData[3] = 0x00; //
+ functionData[4] = 0x00; //
+ functionData[5] = 0x00; //
+ memcpy( functionData + 6, &jumpOffset, sizeof( INT_PTR ) );
+
+ VirtualProtect((LPVOID)pfnHookAPIAddr, OLD_DATA_BACKUP_SIZE, oldProtect, NULL);
+}
+#else
+static void restoreFunction( PROC pfnHookAPIAddr, PBYTE oldData )
+{
+ static const LONGLONG addressSize = sizeof(PROC);
+ static const LONGLONG jmpSize = addressSize + 1;
+
+ DWORD oldProtect;
+ VirtualProtect((LPVOID)pfnHookAPIAddr, jmpSize,
+ PAGE_EXECUTE_READWRITE, &oldProtect);
+
+ memcpy(pfnHookAPIAddr, oldData, jmpSize);
+
+ VirtualProtect((LPVOID)pfnHookAPIAddr, jmpSize, oldProtect, NULL);
+}
+
+static void setFunction( PROC pfnHookAPIAddr, PROC replacementFunction, PBYTE oldData )
+{
+ static const LONGLONG addressSize = sizeof(PROC);
+ static const LONGLONG jmpSize = addressSize + 1;
+
+ INT_PTR jumpOffset = (INT_PTR)replacementFunction - (INT_PTR)pfnHookAPIAddr - jmpSize;
+
+ DWORD oldProtect;
+ VirtualProtect((LPVOID)pfnHookAPIAddr, jmpSize,
+ PAGE_EXECUTE_READWRITE, &oldProtect);
+
+ memcpy(oldData, pfnHookAPIAddr, jmpSize);
+
+ PBYTE functionData = (PBYTE)pfnHookAPIAddr;
+ memcpy( oldData, functionData, jmpSize );
+ functionData[0] = 0xe9;
+ memcpy( functionData + 1, &jumpOffset, sizeof( INT_PTR ) );
+
+ VirtualProtect((LPVOID)pfnHookAPIAddr, jmpSize, oldProtect, NULL);
+}
+#endif
+
+static BOOL WINAPI OVRLocalIsInitializingDisplay( PVOID context, UINT width, UINT height )
+{
+ UINT expectedWidth, expectedHeight, rotation;
+
+ OVRExpectedResolution( context, &expectedWidth, &expectedHeight, &rotation );
+
+ if( appDriver.pfnActiveAPIVersion )
+ apiVersion = (*appDriver.pfnActiveAPIVersion)( context );
+
+ switch( apiVersion )
+ {
+ case 1: // OpenGL
+ case 10: // DirectX 1X
+ if( width == expectedWidth && height == expectedHeight )
+ return TRUE;
+ break;
+ case 9: // DirectX 9
+ if( rotation == 90 || rotation == 270 )
+ {
+ if( width == expectedHeight && height == expectedWidth )
+ return TRUE;
+ }
+ else
+ {
+ if( width == expectedWidth && height == expectedHeight )
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+HRESULT APIENTRY OVRDirect3DCreate9Ex(UINT SDKVersion, void** aDevice)
+{
+ apiVersion = 9;
+
+ HRESULT result = S_OK;
+
+ restoreFunction( (PROC)oldDirectX9ExCreate, oldDirectX9ExCreateData );
+
+ if (IN_COMPATIBILITY_MODE())
+ {
+ result = (*oldDirectX9ExCreate)(SDKVersion, aDevice);
+ }
+ else
+ {
+ WinDirect3DCreate9Ex createFunction = (WinDirect3DCreate9Ex)GetProcAddress(rtFilterModule, "Direct3DCreate9Ex");
+ result = (*createFunction)(SDKVersion, aDevice);
+ }
+
+ setFunction( (PROC)oldDirectX9ExCreate, (PROC)OVRDirect3DCreate9Ex, oldDirectX9ExCreateData );
+
+ printf("%s result 0x%x\n", __FUNCTION__, result);
+
+ return result;
+}
+
+void* APIENTRY OVRDirect3DCreate9(UINT SDKVersion)
+{
+ void* result = NULL;
+
+ OVRDirect3DCreate9Ex( SDKVersion, &result );
+
+ return result;
+}
+
+HRESULT APIENTRY OVRCreateDXGIFactory(
+ __in REFIID riid,
+ __out void **ppFactory
+ )
+{
+ HRESULT result = E_FAIL;
+
+ restoreFunction( (PROC)oldCreateDXGIFactory, oldCreateDXGIFactoryData );
+
+ if (IN_COMPATIBILITY_MODE())
+ {
+ result = (*oldCreateDXGIFactory)(riid, ppFactory);
+ }
+ else
+ {
+ WinCreateDXGIFactory createFunction = (WinCreateDXGIFactory)GetProcAddress(rtFilterModule, "CreateDXGIFactory");
+ result = (*createFunction)(riid, ppFactory);
+ }
+
+ setFunction( (PROC)oldCreateDXGIFactory, (PROC)OVRCreateDXGIFactory, oldCreateDXGIFactoryData );
+
+ printf("%s result 0x%x\n", __FUNCTION__, result);
+
+ return result;
+}
+
+HRESULT APIENTRY OVRCreateDXGIFactory1(
+ __in REFIID riid,
+ __out void **ppFactory
+ )
+{
+ HRESULT result = E_FAIL;
+
+ restoreFunction( (PROC)oldCreateDXGIFactory1, oldCreateDXGIFactory1Data );
+
+ if (IN_COMPATIBILITY_MODE())
+ {
+ result = (*oldCreateDXGIFactory1)(riid, ppFactory);
+ }
+ else
+ {
+ WinCreateDXGIFactory1 createFunction = (WinCreateDXGIFactory1)GetProcAddress(rtFilterModule, "CreateDXGIFactory1");
+ result = (*createFunction)(riid, ppFactory);
+ }
+
+ setFunction( (PROC)oldCreateDXGIFactory1, (PROC)OVRCreateDXGIFactory1, oldCreateDXGIFactory1Data );
+
+ printf("%s result 0x%x\n", __FUNCTION__, result);
+
+ return result;
+}
+
+HRESULT APIENTRY OVRCreateDXGIFactory2(
+ __in UINT flags,
+ __in const IID &riid,
+ __out void **ppFactory
+ )
+{
+ HRESULT result = E_FAIL;
+
+ restoreFunction( (PROC)oldCreateDXGIFactory2, oldCreateDXGIFactory2Data );
+
+ if (IN_COMPATIBILITY_MODE())
+ {
+ result = (*oldCreateDXGIFactory2)(flags, riid, ppFactory);
+ }
+ else
+ {
+ WinCreateDXGIFactory2 createFunction = (WinCreateDXGIFactory2)GetProcAddress(rtFilterModule, "CreateDXGIFactory2");
+ result = (*createFunction)(flags, riid, ppFactory);
+ }
+
+ setFunction( (PROC)oldCreateDXGIFactory2, (PROC)OVRCreateDXGIFactory2, oldCreateDXGIFactory2Data );
+
+ printf("%s result 0x%x\n", __FUNCTION__, result);
+
+ return result;
+}
+
+static PROC SetProcAddressDirect(
+ __in HINSTANCE hInstance,
+ __in LPCSTR lpProcName,
+ __in PROC newFunction,
+ __inout BYTE* oldData
+ )
+{
+ static const LONGLONG addressSize = sizeof(PROC);
+ static const LONGLONG jmpSize = addressSize + 1;
+
+ PROC result = NULL;
+
+ PROC pfnHookAPIAddr = GetProcAddress( hInstance, lpProcName );
+
+ if( pfnHookAPIAddr )
+ {
+ result = pfnHookAPIAddr;
+
+ setFunction( pfnHookAPIAddr, newFunction, oldData );
+ }
+
+ return result;
+}
+
+static PROC SetProcAddressA(
+ __in HINSTANCE targetModule,
+ __in LPCSTR lpLibFileName,
+ __in LPCSTR lpProcName,
+ __in PROC newFunction
+ )
+{
+ HMODULE hModule = LoadLibraryA( lpLibFileName );
+ if(hModule == NULL)
+ return NULL;
+
+ // To do: call FreeLibrary(hModule) at the appropriate time.
+ PROC pfnHookAPIAddr = GetProcAddress(hModule, lpProcName );
+
+ HINSTANCE hInstance = targetModule;
+
+ ULONG ulSize;
+ PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
+ (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
+ hInstance,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &ulSize
+ );
+
+ while (pImportDesc->Name)
+ {
+ PSTR pszModName = (PSTR)((PBYTE) hInstance + pImportDesc->Name);
+ if (_stricmp(pszModName, lpLibFileName) == 0)
+ break;
+ pImportDesc++;
+ }
+
+ PIMAGE_THUNK_DATA pThunk =
+ (PIMAGE_THUNK_DATA)((PBYTE) hInstance + pImportDesc->FirstThunk);
+
+ while (pThunk->u1.Function)
+ {
+ PROC* ppfn = (PROC*) &pThunk->u1.Function;
+ BOOL bFound = (*ppfn == pfnHookAPIAddr);
+
+ if (bFound)
+ {
+ MEMORY_BASIC_INFORMATION mbi;
+ VirtualQuery(
+ ppfn,
+ &mbi,
+ sizeof(MEMORY_BASIC_INFORMATION)
+ );
+ VirtualProtect(
+ mbi.BaseAddress,
+ mbi.RegionSize,
+ PAGE_READWRITE,
+ &mbi.Protect);
+
+ *ppfn = *newFunction;
+
+ DWORD dwOldProtect;
+ VirtualProtect(
+ mbi.BaseAddress,
+ mbi.RegionSize,
+ mbi.Protect,
+ &dwOldProtect
+ );
+ break;
+ }
+ pThunk++;
+ }
+
+ return pfnHookAPIAddr;
+}
+
+
+bool checkUMDriverOverrides(void* context)
+{
+ lastContext = context;
+ if (oldProcA != NULL)
+ return true;
+
+ PreloadLibraryRTFn loadFunc = NULL;
+ for( int i = 0; i < ShimCountMax; ++i )
+ {
+ HINSTANCE hInst = NULL;
+ try
+ {
+ hInst = LoadLibraryA(dllList[i]);
+ }
+ catch(...)
+ {
+ }
+
+ oldLoaderInstances[i] = hInst;
+
+ if (hInst == NULL)
+ continue;
+
+ ShimedLibraries libCount = (ShimedLibraries)i;
+ switch( libCount )
+ {
+ case ShimLibDXGI:
+ oldCreateDXGIFactory = (WinCreateDXGIFactory)SetProcAddressDirect( hInst, "CreateDXGIFactory", (PROC)OVRCreateDXGIFactory, oldCreateDXGIFactoryData );
+ oldCreateDXGIFactory1 = (WinCreateDXGIFactory1)SetProcAddressDirect( hInst, "CreateDXGIFactory1", (PROC)OVRCreateDXGIFactory1, oldCreateDXGIFactory1Data );
+ oldCreateDXGIFactory2 = (WinCreateDXGIFactory2)SetProcAddressDirect( hInst, "CreateDXGIFactory2", (PROC)OVRCreateDXGIFactory2, oldCreateDXGIFactory2Data );
+ break;
+ case ShimLibD3D9:
+ oldDirectX9Create = (WinDirect3DCreate9)SetProcAddressDirect( hInst, "Direct3DCreate9", (PROC)OVRDirect3DCreate9, oldDirectX9CreateData );
+ oldDirectX9ExCreate = (WinDirect3DCreate9Ex)SetProcAddressDirect( hInst, "Direct3DCreate9Ex", (PROC)OVRDirect3DCreate9Ex, oldDirectX9ExCreateData );
+ break;
+ default:
+ break;
+ }
+
+ for (int j = 0; j < NUM_LOADER_LIBS; ++j)
+ {
+ const char* loaderLibrary = loaderLibraryList[j];
+
+ PROC temp = NULL;
+ temp = SetProcAddressA(hInst, loaderLibrary, "LoadLibraryA", (PROC)OVRLoadLibraryA);
+ if (!oldProcA)
+ {
+ oldProcA = (WinLoadLibraryA)temp;
+ }
+ oldLoaderProcA[i][j] = temp;
+
+ temp = SetProcAddressA(hInst, loaderLibrary, "LoadLibraryW", (PROC)OVRLoadLibraryW);
+ if (!oldProcW)
+ {
+ oldProcW = (WinLoadLibraryW)temp;
+ }
+ oldLoaderProcW[i][j] = temp;
+
+ temp = SetProcAddressA(hInst, loaderLibrary, "LoadLibraryExA", (PROC)OVRLoadLibraryExA);
+ if (!oldProcExA)
+ {
+ oldProcExA = (WinLoadLibraryExA)temp;
+ }
+ oldLoaderProcExA[i][j] = temp;
+
+ temp = SetProcAddressA(hInst, loaderLibrary, "LoadLibraryExW", (PROC)OVRLoadLibraryExW);
+ if (!oldProcExW)
+ {
+ oldProcExW = (WinLoadLibraryExW)temp;
+ }
+ oldLoaderProcExW[i][j] = temp;
+
+ temp = SetProcAddressA(hInst, loaderLibrary, "GetModuleHandleExA", (PROC)OVRGetModuleHandleExA);
+ if (!oldProcModExA)
+ {
+ oldProcModExA = (WinGetModuleHandleExA)temp;
+ }
+ oldLoaderProcModExA[i][j] = temp;
+
+ temp = SetProcAddressA(hInst, loaderLibrary, "GetModuleHandleExW", (PROC)OVRGetModuleHandleExW);
+ if (!oldProcModExW)
+ {
+ oldProcModExW = (WinGetModuleHandleExW)temp;
+ }
+ oldLoaderProcModExW[i][j] = temp;
+ }
+
+ if (loadFunc == NULL)
+ {
+ loadFunc = (PreloadLibraryRTFn)GetProcAddress(hInst, "PreloadLibraryRT");
+ }
+ }
+
+ rtFilterModule = oldProcA ? (*oldProcA)(RTFilter) : NULL;
+
+ IsCreatingBackBuffer backBufferFunc = NULL;
+ ShouldVSync shouldVSyncFunc = NULL;
+ GetRTFilterVersion getRTFilterVersionFunc = NULL;
+
+ if (rtFilterModule != NULL)
+ {
+ loadFunc = (PreloadLibraryRTFn)GetProcAddress(rtFilterModule, "PreloadLibraryRT");
+ backBufferFunc = (IsCreatingBackBuffer)GetProcAddress(rtFilterModule, "OVRIsCreatingBackBuffer");
+ shouldVSyncFunc = (ShouldVSync)GetProcAddress(rtFilterModule, "OVRShouldVSync");
+ getRTFilterVersionFunc = (GetRTFilterVersion)GetProcAddress(rtFilterModule, "OVRGetRTFilterVersion");
+ }
+
+ if (loadFunc == NULL)
+ {
+ MessageBox(nullptr, L"Unable to load the Oculus Display Driver. Please reinstall the Oculus Runtime.", L"Configuration Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+
+ if (getRTFilterVersionFunc == NULL)
+ {
+ WCHAR message[1000] = {};
+ swprintf_s(message, L"This app requires the %d.%d.%d version of the Oculus Runtime.", OVR_MAJOR_VERSION, OVR_MINOR_VERSION, OVR_BUILD_VERSION);
+ MessageBox(nullptr, message, L"Configuration Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+
+ // Verify that we are running with the appropriate display driver
+ {
+ const ULONG rtFilterVersion = (*getRTFilterVersionFunc)();
+ const ULONG rtFilterMajor = OVR_GET_VERSION_MAJOR(rtFilterVersion);
+ const ULONG rtFilterMinor = OVR_GET_VERSION_MINOR(rtFilterVersion);
+
+ if ((rtFilterMajor != OVR_RTFILTER_VERSION_MAJOR) || (rtFilterMinor < OVR_RTFILTER_VERSION_MINOR))
+ {
+ WCHAR message[1000] = {};
+ swprintf_s(message, L"This app requires the %d.%d.%d version of the Oculus Runtime.", OVR_MAJOR_VERSION, OVR_MINOR_VERSION, OVR_BUILD_VERSION);
+ MessageBox(nullptr, message, L"Configuration Error", MB_OK | MB_ICONERROR);
+ return false;
+ }
+ }
+
+ appDriver.version = OVR_RENDER_SHIM_VERSION_MAJOR;
+ appDriver.context = lastContext;
+
+// appDriver.pfnInitializingDisplay = OVRIsInitializingDisplay;
+ appDriver.pfnInitializingDisplay = OVRLocalIsInitializingDisplay;
+ appDriver.pfnRiftForContext = OVRRiftForContext;
+ appDriver.pfnCloseRiftForContext = OVRCloseRiftForContext;
+ appDriver.pfnWindowDisplayResolution = OVRWindowDisplayResolution;
+ appDriver.pfnShouldEnableDebug = OVRShouldEnableDebug;
+ appDriver.pfnIsCreatingBackBuffer = (backBufferFunc == NULL) ? OVRIsCreatingBackBuffer : backBufferFunc;
+ appDriver.pfnShouldVSync = (shouldVSyncFunc == NULL) ? OVRShouldVSync : shouldVSyncFunc;
+ appDriver.pfnExpectedResolution = OVRExpectedResolution;
+ appDriver.pfnMirroringEnabled = OVRMirroringEnabled;
+ appDriver.pfnGetWindowForContext = OVRGetWindowForContext;
+ appDriver.pfnPresentRiftOnContext = OVRShouldPresentOnContext;
+
+ appDriver.pfnDirect3DCreate9 = oldDirectX9Create;
+ appDriver.pfnDirect3DCreate9Ex = oldDirectX9ExCreate;
+ appDriver.pfnCreateDXGIFactory = oldCreateDXGIFactory;
+ appDriver.pfnCreateDXGIFactory1 = oldCreateDXGIFactory1;
+ appDriver.pfnCreateDXGIFactory2 = oldCreateDXGIFactory2;
+
+ (*loadFunc)( &appDriver );
+
+ return true;
+}
+
+void clearUMDriverOverrides()
+{
+ if (oldProcA != NULL)
+ {
+ // Unpatch all the things.
+
+ if (oldCreateDXGIFactory)
+ {
+ restoreFunction((PROC)oldCreateDXGIFactory, oldCreateDXGIFactoryData);
+ }
+ if (oldCreateDXGIFactory1)
+ {
+ restoreFunction((PROC)oldCreateDXGIFactory1, oldCreateDXGIFactory1Data);
+ }
+ if (oldCreateDXGIFactory2)
+ {
+ restoreFunction((PROC)oldCreateDXGIFactory2, oldCreateDXGIFactory2Data);
+ }
+ if (oldDirectX9Create)
+ {
+ restoreFunction((PROC)oldDirectX9Create, oldDirectX9CreateData);
+ }
+ if (oldDirectX9ExCreate)
+ {
+ restoreFunction((PROC)oldDirectX9ExCreate, oldDirectX9ExCreateData);
+ }
+ if (oldCreateDXGIFactory2)
+ {
+ restoreFunction((PROC)oldCreateDXGIFactory2, oldCreateDXGIFactory2Data);
+ }
+
+ for (int i = 0; i < ShimCountMax; ++i)
+ {
+ HINSTANCE hInst = oldLoaderInstances[i];
+
+ if (hInst != NULL)
+ {
+ for (int j = 0; j < NUM_LOADER_LIBS; ++j)
+ {
+ const char* loaderLibrary = loaderLibraryList[j];
+
+ if (oldLoaderProcA[j])
+ {
+ SetProcAddressA(hInst, loaderLibrary, "LoadLibraryA", oldLoaderProcA[i][j]);
+ }
+ if (oldLoaderProcW[j])
+ {
+ SetProcAddressA(hInst, loaderLibrary, "LoadLibraryW", oldLoaderProcW[i][j]);
+ }
+ if (oldLoaderProcExA[j])
+ {
+ SetProcAddressA(hInst, loaderLibrary, "LoadLibraryExA", oldLoaderProcExA[i][j]);
+ }
+ if (oldLoaderProcExW[j])
+ {
+ SetProcAddressA(hInst, loaderLibrary, "LoadLibraryExW", oldLoaderProcExW[i][j]);
+ }
+ if (oldLoaderProcModExA[j])
+ {
+ SetProcAddressA(hInst, loaderLibrary, "GetModuleHandleExA", oldLoaderProcModExA[i][j]);
+ }
+ if (oldLoaderProcModExW[j])
+ {
+ SetProcAddressA(hInst, loaderLibrary, "GetModuleHandleExW", oldLoaderProcModExW[i][j]);
+ }
+ }
+
+ FreeLibrary(hInst);
+ }
+ }
+
+ if (rtFilterModule != NULL)
+ {
+ LPFNCANUNLOADNOW pfnCanUnloadNow = (LPFNCANUNLOADNOW)GetProcAddress(rtFilterModule, "DllCanUnloadNow");
+ if (pfnCanUnloadNow && pfnCanUnloadNow() == S_OK)
+ {
+ FreeLibrary(rtFilterModule);
+ rtFilterModule = NULL;
+ }
+ }
+
+ oldProcA = NULL;
+ oldProcExA = NULL;
+ oldProcW = NULL;
+ oldProcExW = NULL;
+ oldProcModExA = NULL;
+ oldProcModExW = NULL;
+ oldDirectX9Create = NULL;
+ oldDirectX9ExCreate = NULL;
+ oldCreateDXGIFactory = NULL;
+ oldCreateDXGIFactory1 = NULL;
+ oldCreateDXGIFactory2 = NULL;
+ lastContext = NULL;
+ }
+}
diff --git a/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp
new file mode 100644
index 0000000..602df98
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp
@@ -0,0 +1,234 @@
+/************************************************************************************
+
+Filename : OVR_Win32_ShimFunctions.cpp
+Content : Client-side shim callbacks for usermode/rt hooks
+Created : May 6, 2014
+Authors : Dean Beeler
+
+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_Win32_Display.h"
+#include "OVR_Win32_ShimFunctions.h"
+#include "OVR_Win32_Dxgi_Display.h"
+#include "../OVR_Stereo.h"
+#include "OVR_Win32_FocusReader.h"
+
+// Exported
+extern bool checkUMDriverOverrides(void* context);
+extern void clearUMDriverOverrides();
+
+#include <stdio.h>
+#include <tchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <WinSock2.h>
+#include <WS2tcpip.h>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <winioctl.h>
+#include <SetupAPI.h>
+#include <Mmsystem.h>
+#include <conio.h>
+
+
+//-------------------------------------------------------------------------------------
+// ***** User-mode Callbacks
+//
+// See IsInitializingDisplay, etc in Dxgi_Display.h for details
+//
+
+extern LINK_APPLICATION_DRIVER appDriver;
+
+BOOL WINAPI OVRIsInitializingDisplay(PVOID context, UINT width, UINT height)
+{
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+ if (con->ExpectedWidth == (int)width && con->ExpectedHeight == (int)height)
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL WINAPI OVRExpectedResolution( PVOID context, UINT* width, UINT* height, UINT* rotationInDegrees )
+{
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+
+ *width = con->ExpectedWidth;
+ *height = con->ExpectedHeight;
+ *rotationInDegrees = con->Rotation;
+ return TRUE;
+}
+
+BOOL WINAPI OVRIsCreatingBackBuffer(PVOID context)
+{
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+ if( con->ExpectedWidth != -1 && con->ExpectedHeight != -1 )
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL WINAPI OVRShouldVSync( )
+{
+ return FALSE;
+}
+
+
+ULONG WINAPI OVRRiftForContext(PVOID context, HANDLE driverHandle)
+{
+ OVR_UNUSED( driverHandle );
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+
+ return con->ChildUid;
+}
+
+HWND WINAPI OVRGetWindowForContext(PVOID context)
+{
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+
+ if( con->Active )
+ {
+ return con->hWindow;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+BOOL WINAPI OVRShouldPresentOnContext(PVOID context)
+{
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+
+ return con->Active && ( con->hWindow == OVR::Win32::RenderFocusReader::GetInstance()->ReadActiveWindow() );
+}
+
+BOOL WINAPI OVRCloseRiftForContext( PVOID context, HANDLE driverHandle, ULONG rift )
+{
+ OVR_UNUSED( context ); OVR_UNUSED( driverHandle ); OVR_UNUSED( rift );
+ // TODO
+ return TRUE;
+}
+
+BOOL WINAPI OVRWindowDisplayResolution( PVOID context, UINT* width, UINT* height,
+ UINT* titleHeight, UINT* borderWidth,
+ BOOL* vsyncEnabled )
+{
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+ void* handle = con->hWindow;
+
+ if( handle )
+ {
+ RECT winRect = { 0 };
+ GetWindowRect( (HWND)handle, &winRect );
+
+ RECT rect = {0};
+ if( GetClientRect( (HWND)handle, &rect ) )
+ {
+ LONG barHeight = (winRect.bottom - winRect.top) - (rect.bottom - rect.top);
+ LONG borderSize = (winRect.right - winRect.left) - (rect.right - rect.left);
+
+ *titleHeight = barHeight - borderSize + (borderSize / 2 );
+ *borderWidth = borderSize / 2;
+ *width = rect.right - rect.left + (borderSize / 2);
+ *height = rect.bottom - rect.top + *titleHeight;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ *vsyncEnabled = TRUE;
+
+ return TRUE;
+}
+
+BOOL WINAPI OVRShouldEnableDebug()
+{
+ return FALSE;
+}
+
+BOOL WINAPI OVRMirroringEnabled( PVOID context )
+{
+ OVR::Win32::DisplayShim* con = (OVR::Win32::DisplayShim*)context;
+
+ return con->UseMirroring;
+}
+
+namespace OVR { namespace Win32 {
+
+DisplayShim::DisplayShim() :
+ ChildUid( 0 ),
+ ExpectedWidth( 1280 ),
+ ExpectedHeight( 800 ),
+ Rotation( 0 ),
+ hWindow( 0 ),
+ UseMirroring( true ),
+ Active( false )
+{
+
+}
+
+DisplayShim::~DisplayShim()
+{
+
+}
+
+bool DisplayShim::Initialize( bool inCompatibility )
+{
+ if (inCompatibility)
+ return false;
+
+ return checkUMDriverOverrides( this );
+}
+
+bool DisplayShim::Shutdown()
+{
+ clearUMDriverOverrides();
+
+ return true;
+}
+
+bool DisplayShim::Update(Win32ShimInfo* shimInfo)
+{
+ ChildUid = shimInfo->DeviceNumber;
+ ExpectedWidth = shimInfo->NativeWidth;
+ ExpectedHeight = shimInfo->NativeHeight;
+ Rotation = shimInfo->Rotation;
+ UseMirroring = shimInfo->UseMirroring != 0;
+ return true;
+}
+
+void* DisplayShim::GetDX11SwapChain()
+{
+ if( appDriver.pfnGetDX11SwapChain )
+ {
+ return (*appDriver.pfnGetDX11SwapChain)(this);
+ }
+
+ return NULL;
+}
+
+
+} } // OVR::Win32
diff --git a/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h
new file mode 100644
index 0000000..1339de4
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h
@@ -0,0 +1,79 @@
+/************************************************************************************
+
+Filename : OVR_Win32_ShimFunctions.h
+Content : Client-side shim callbacks for usermode/rt hooks
+Created : May 6, 2014
+Authors : Dean Beeler
+
+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.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_ShimFunctions_h
+#define OVR_Win32_ShimFunctions_h
+
+#include "OVR_Win32_Display.h"
+
+namespace OVR {
+
+struct Win32ShimInfo;
+
+namespace Win32 {
+
+
+class DisplayShim
+{
+public:
+
+public:
+ static DisplayShim& GetInstance()
+ {
+ static DisplayShim instance;
+ return instance;
+ }
+
+ bool Initialize( bool inCompatibility );
+ bool Shutdown();
+
+ bool Update( Win32ShimInfo* shimInfo );
+
+ void* GetDX11SwapChain();
+
+ ULONG ChildUid;
+ int ExpectedWidth;
+ int ExpectedHeight;
+ int Rotation;
+ HWND hWindow;
+ bool UseMirroring;
+ bool Active;
+
+private:
+
+ DisplayShim();
+
+ virtual ~DisplayShim();
+
+ DisplayShim(DisplayShim const&); // Don't Implement
+ void operator=(DisplayShim const&); // Don't implement
+
+};
+
+
+}} // namespace OVR::Win32
+
+#endif
diff --git a/LibOVR/Src/Displays/OVR_Win32_ShimVersion.h b/LibOVR/Src/Displays/OVR_Win32_ShimVersion.h
new file mode 100644
index 0000000..f5eaa7c
--- /dev/null
+++ b/LibOVR/Src/Displays/OVR_Win32_ShimVersion.h
@@ -0,0 +1,47 @@
+/************************************************************************************
+
+Filename : OVR_Win32_ShimVersion.h
+Content : Versioning info for our display shim
+Created : Nov 4, 2014
+Authors : Scott Bassett
+
+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.
+
+*************************************************************************************/
+
+#define STRINGIZE_(x) #x
+#define STRINGIZE(x) STRINGIZE_(x)
+
+#define OVR_MAKE_VERSION(major, minor, patch) (ULONG)(((major) << 24) | ((minor) << 16) | patch)
+#define OVR_GET_VERSION_MAJOR(x) (ULONG)(((x) >> 24) & 0x000000FF)
+#define OVR_GET_VERSION_MINOR(x) (ULONG)(((x) >> 16) & 0x000000FF)
+#define OVR_GET_VERSION_PATCH(x) (ULONG)((x) & 0x0000FFFF)
+
+#define OVR_RENDER_SHIM_VERSION_MAJOR 1
+#define OVR_RENDER_SHIM_VERSION_MINOR 0
+#define OVR_RENDER_SHIM_VERSION_PATCH 0
+#define OVR_RENDER_SHIM_VERSION OVR_MAKE_VERSION(OVR_RENDER_SHIM_VERSION_MAJOR, OVR_RENDER_SHIM_VERSION_MINOR, OVR_RENDER_SHIM_VERSION_PATCH)
+#define OVR_RENDER_SHIM_VERSION_STRING (STRINGIZE(OVR_RENDER_SHIM_VERSION_MAJOR) "." STRINGIZE(OVR_RENDER_SHIM_VERSION_MINOR) "." STRINGIZE(OVR_RENDER_SHIM_VERSION_PATCH))
+
+// IF YOU CHANGE ANY OF THESE NUMBERS YOU MUST UPDATE MULTIPLE FILES.
+// PLEASE LOOK AT CHANGELIST 31947 TO SEE THE FULL LIST.
+#define OVR_RTFILTER_VERSION_MAJOR 1
+#define OVR_RTFILTER_VERSION_MINOR 2
+#define OVR_RTFILTER_VERSION_PATCH 2
+#define OVR_RTFILTER_VERSION OVR_MAKE_VERSION(OVR_RTFILTER_VERSION_MAJOR, OVR_RTFILTER_VERSION_MINOR, OVR_RTFILTER_VERSION_PATCH)
+#define OVR_RTFILTER_VERSION_STRING (STRINGIZE(OVR_RTFILTER_VERSION_MAJOR) "." STRINGIZE(OVR_RTFILTER_VERSION_MINOR) "." STRINGIZE(OVR_RTFILTER_VERSION_PATCH))