aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Displays
diff options
context:
space:
mode:
authorBrad Davis <[email protected]>2014-09-04 14:32:18 -0700
committerBrad Davis <[email protected]>2014-09-04 14:32:18 -0700
commit32dc394487af8e4fb1b43fb852f1d5448eaf7f31 (patch)
treebe53f49e96e8e2bba1dada04197cf508b60b4eaf /LibOVR/Src/Displays
parent85d370840fa4d49a63331a203460fe763288d417 (diff)
Updating to windows 0.4.2
Diffstat (limited to 'LibOVR/Src/Displays')
-rw-r--r--LibOVR/Src/Displays/OVR_Display.cpp6
-rw-r--r--LibOVR/Src/Displays/OVR_Display.h4
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_Display.cpp422
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h22
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp2
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_FocusReader.h2
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp337
-rw-r--r--LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp5
8 files changed, 622 insertions, 178 deletions
diff --git a/LibOVR/Src/Displays/OVR_Display.cpp b/LibOVR/Src/Displays/OVR_Display.cpp
index 65f0b30..c7a624f 100644
--- a/LibOVR/Src/Displays/OVR_Display.cpp
+++ b/LibOVR/Src/Displays/OVR_Display.cpp
@@ -29,4 +29,8 @@ limitations under the License.
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
index 3184182..bcba4bc 100644
--- a/LibOVR/Src/Displays/OVR_Display.h
+++ b/LibOVR/Src/Displays/OVR_Display.h
@@ -189,6 +189,10 @@ public:
// 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();
};
diff --git a/LibOVR/Src/Displays/OVR_Win32_Display.cpp b/LibOVR/Src/Displays/OVR_Win32_Display.cpp
index 8300468..6bebc7b 100644
--- a/LibOVR/Src/Displays/OVR_Win32_Display.cpp
+++ b/LibOVR/Src/Displays/OVR_Win32_Display.cpp
@@ -37,10 +37,14 @@ limitations under the License.
#include <SetupAPI.h>
#include <Mmsystem.h>
#include <conio.h>
+
+#ifdef OVR_COMPAT_EDID_VIA_WMI
# pragma comment(lib, "wbemuuid.lib")
#include <wbemidl.h>
-#include <AtlBase.h>
-#include <AtlConv.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
@@ -56,7 +60,8 @@ typedef struct
UINT ExpectedWidth;
UINT ExpectedHeight;
HWND hWindow;
- bool InCompatibilityMode;
+ bool CompatibilityMode;
+ bool HideDK1Mode;
} ContextStruct;
static ContextStruct GlobalDisplayContext = {0};
@@ -89,7 +94,7 @@ ULONG getRift( HANDLE hDevice, int index )
{
ULONG riftCount = getRiftCount( hDevice );
DWORD bytesReturned = 0;
- BOOL result;
+ BOOL result;
if( riftCount >= (ULONG)index )
{
@@ -334,11 +339,10 @@ static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwDa
return TRUE;
};
+#ifdef OVR_COMPAT_EDID_VIA_WMI
static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, String& userFriendlyNameStr )
{
- USES_CONVERSION;
-
IWbemLocator *pLoc = NULL;
IWbemServices *pSvc = NULL;
HRESULT hres;
@@ -350,8 +354,10 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
- OVR_DEBUG_LOG_TEXT(("Failed to initialize COM library. Error code = 0x%x\n", hres));
- return false;
+
+ LogError("{ERR-082} [Display] WARNING: Failed to initialize COM library. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ return false;
}
hres = CoInitializeSecurity(
@@ -368,10 +374,9 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
if (FAILED(hres))
{
- OVR_DEBUG_LOG_TEXT(("Failed to initialize security. Error code = 0x%x\n", hres));
- //CoUninitialize();
- //return false;
- selfInitialized = false;
+ LogError("{ERR-083} [Display] WARNING: Failed to initialize security. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ selfInitialized = false;
}
initialized = true;
@@ -385,8 +390,9 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
if (FAILED(hres))
{
- OVR_DEBUG_LOG_TEXT(("Failed to create IWbemLocator object. Err code = 0x%x\n", hres));
- return false;
+ 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");
@@ -407,8 +413,9 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
if (FAILED(hres))
{
- OVR_DEBUG_LOG_TEXT(("Could not connect. Error code = 0x%x\n", hres));
- pLoc->Release();
+ LogError("{ERR-085} [Display] WARNING: Could not connect to root\\WMI. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ pLoc->Release();
return false;
}
@@ -425,8 +432,9 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
if (FAILED(hres))
{
- OVR_DEBUG_LOG_TEXT(("Could not set proxy blanket. Error code = 0x%x\n", hres));
- pSvc->Release();
+ LogError("{ERR-086} [Display] WARNING: Could not set proxy blanket. Error code = 0x%x", hres);
+ OVR_ASSERT(false);
+ pSvc->Release();
pLoc->Release();
return false;
}
@@ -446,12 +454,16 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
if (FAILED(hres))
{
- OVR_DEBUG_LOG_TEXT(( "Query for operating system name failed. Error code = 0x%x\n", hres ));
- pSvc->Release();
+ 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)
{
@@ -463,29 +475,31 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
break;
}
- VARIANT vtProp;
- hr = pclsObj->Get(L"InstanceName", 0, &vtProp, 0, 0);
+ ++enumeratedCount;
+
+ VARIANT vtProp;
+ hr = pclsObj->Get(L"InstanceName", 0, &vtProp, 0, 0);
- WCHAR* instanceName = vtProp.bstrVal;
- WCHAR* nextToken = NULL;
- if (SUCCEEDED(hr) &&
+ WCHAR* instanceName = vtProp.bstrVal;
+ WCHAR* nextToken = NULL;
+ if (SUCCEEDED(hr) &&
wcstok_s(instanceName, L"\\", &nextToken) != NULL)
- {
- WCHAR* aToken = wcstok_s(NULL, L"\\", &nextToken);
+ {
+ WCHAR* aToken = wcstok_s(NULL, L"\\", &nextToken);
- if (aToken != NULL)
- {
- VariantClear(&vtProp);
+ if (aToken != NULL)
+ {
+ VariantClear(&vtProp);
- if (wcscmp(aToken, displayName) != 0)
- {
+ if (wcscmp(aToken, displayName) != 0)
+ {
pclsObj->Release();
continue;
- }
+ }
- // Read serial
+ // Read serial
- hr = pclsObj->Get(L"SerialNumberID", 0, &vtProp, 0, 0);
+ hr = pclsObj->Get(L"SerialNumberID", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr))
{
@@ -505,21 +519,21 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
}
else
{
- OVR_DEBUG_LOG(("[Win32Display] WARNING: Wrong data format for SerialNumberID"));
+ LogError("{ERR-088} [Display] WARNING: Wrong data format for SerialNumberID");
}
VariantClear(&vtProp);
}
else
{
- OVR_DEBUG_LOG(("[Win32Display] WARNING: Failure getting display SerialNumberID: %d", (int)hr));
+ LogError("{ERR-089} [Display] WARNING: Failure getting display SerialNumberID: %d", (int)hr);
}
- // Read length of name
+ // Read length of name
int userFriendlyNameLen = 0;
- hr = pclsObj->Get(L"UserFriendlyNameLength", 0, &vtProp, 0, 0);
+ hr = pclsObj->Get(L"UserFriendlyNameLength", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr))
{
@@ -531,24 +545,24 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
{
userFriendlyNameLen = 0;
- OVR_DEBUG_LOG(("[Win32Display] WARNING: UserFriendlyNameLength = 0"));
+ LogError("{ERR-090} [Display] WARNING: UserFriendlyNameLength = 0");
}
}
else
{
- OVR_DEBUG_LOG(("[Win32Display] WARNING: Wrong data format for UserFriendlyNameLength"));
+ LogError("{ERR-091} [Display] WARNING: Wrong data format for UserFriendlyNameLength");
}
VariantClear(&vtProp);
}
else
{
- OVR_DEBUG_LOG(("[Win32Display] WARNING: Failure getting display UserFriendlyNameLength: %d", (int)hr));
+ LogError("{ERR-092} [Display] WARNING: Failure getting display UserFriendlyNameLength: %d", (int)hr);
}
- // Read name
+ // Read name
- hr = pclsObj->Get(L"UserFriendlyName", 0, &vtProp, 0, 0);
+ hr = pclsObj->Get(L"UserFriendlyName", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && userFriendlyNameLen > 0)
{
@@ -570,20 +584,23 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
{
// See: https://developer.oculusvr.com/forums/viewtopic.php?f=34&t=10961
// This can happen if someone has an EDID override in the registry.
- OVR_DEBUG_LOG(("[Win32Display] WARNING: Wrong data format for UserFriendlyName"));
+ LogError("{ERR-093} [Display] WARNING: Wrong data format for UserFriendlyName");
}
VariantClear(&vtProp);
}
else
{
- OVR_DEBUG_LOG(("[Win32Display] WARNING: Failure getting display UserFriendlyName: %d", (int)hr));
+ LogError("{ERR-094} [Display] WARNING: Failure getting display UserFriendlyName: %d", (int)hr);
}
- }
+ }
+
+ found = true;
+ pclsObj->Release();
+ break;
}
- pclsObj->Release();
- break;
+ pclsObj->Release();
}
HMODULE hModule = GetModuleHandleA("wbemuuid");
@@ -596,9 +613,201 @@ static bool getCompatDisplayEDID( WCHAR* displayName, String& serialNumberStr, S
pLoc->Release();
pEnumerator->Release();
- return true;
+ 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 (FAILED(retValue))
+ {
+ if (retValue == ERROR_NO_MORE_ITEMS)
+ {
+ break;
+ }
+
+ 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()
{
@@ -797,27 +1006,28 @@ bool Display::InCompatibilityMode( bool displaySearch )
bool result = false;
if( displaySearch )
{
- OVR::Win32::DisplayDesc displayArray[8];
+ OVR::Win32::DisplayDesc displayArray[8];
- int extendedRiftCount = discoverExtendedRifts(displayArray, 8, false);
- if( extendedRiftCount )
- {
- result = true;
- }
- else
- {
- result = GlobalDisplayContext.InCompatibilityMode;
+ int extendedRiftCount = discoverExtendedRifts(displayArray, 8, false);
+ if( extendedRiftCount )
+ {
+ result = true;
+ }
+ else
+ {
+ result = GlobalDisplayContext.CompatibilityMode;
}
}
else
{
- result = GlobalDisplayContext.InCompatibilityMode;
+ result = GlobalDisplayContext.CompatibilityMode;
}
return result;
}
#define OVR_FLAG_COMPATIBILITY_MODE 1
+#define OVR_FLAG_HIDE_DK1 2
bool Display::Initialize()
{
@@ -830,7 +1040,7 @@ bool Display::Initialize()
if (hDevice != NULL && hDevice != INVALID_HANDLE_VALUE)
{
GlobalDisplayContext.hDevice = hDevice;
- GlobalDisplayContext.InCompatibilityMode = FALSE;
+ GlobalDisplayContext.CompatibilityMode = false;
DWORD bytesReturned = 0;
LONG compatiblityResult = OVR_STATUS_SUCCESS;
@@ -839,16 +1049,16 @@ bool Display::Initialize()
&compatiblityResult, sizeof( LONG ), &bytesReturned, NULL );
if (result)
{
- if( compatiblityResult & OVR_FLAG_COMPATIBILITY_MODE )
- GlobalDisplayContext.InCompatibilityMode = TRUE;
- }
+ 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.InCompatibilityMode = TRUE;
+ GlobalDisplayContext.CompatibilityMode = true;
}
- if (!GlobalDisplayContext.InCompatibilityMode)
+ if (!GlobalDisplayContext.CompatibilityMode)
{
Ptr<DisplaySearchHandle> searchHandle = *Display::GetDisplaySearchHandle();
@@ -861,19 +1071,89 @@ bool Display::Initialize()
}
else
{
- GlobalDisplayContext.InCompatibilityMode = TRUE;
+ GlobalDisplayContext.CompatibilityMode = true;
}
}
}
else
{
- GlobalDisplayContext.InCompatibilityMode = TRUE;
+ 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();
@@ -950,10 +1230,8 @@ Ptr<Display> Display::GetDisplay(int index, DisplaySearchHandle* handle)
}
// FIXME: We have the EDID. Let's just use that instead.
- uint32_t nativeWidth = 1080;
- uint32_t nativeHeight = 1920;
- uint32_t logicalWidth = 1920;
- uint32_t logicalHeight = 1080;
+ uint32_t nativeWidth = 1080, nativeHeight = 1920;
+ uint32_t logicalWidth = 1920, logicalHeight = 1080;
uint32_t rotation = 0;
switch (dEdid.ModelNumber)
diff --git a/LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h b/LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h
index ab1582c..bdcd813 100644
--- a/LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h
+++ b/LibOVR/Src/Displays/OVR_Win32_Dxgi_Display.h
@@ -372,19 +372,31 @@ typedef struct _RIFT_STATUS_ARRAY
// Enable or disable compatibility mode. Entering compatibility mode will fail if
// the Rift is already actively scanning out a surface
-// Input Buffer: BOOL - Nonzero if compatibility mode is desired, zero if it's not
+// 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 - Result value
-// 0 = Not in compatibility mode
-// Non-zero = In compatibility mode
+// 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)
@@ -410,4 +422,4 @@ typedef struct _RIFT_STATUS_ARRAY
#define IOCTL_RIFTMGR_GETEDID CTL_CODE(FILE_DEVICE_VIDEO, \
FUNCTION_INDEX + 11, METHOD_NEITHER, FILE_ANY_ACCESS)
-#endif \ No newline at end of file
+#endif
diff --git a/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp b/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp
index 852e29e..d665546 100644
--- a/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp
+++ b/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp
@@ -75,6 +75,4 @@ void RenderFocusReader::OnSystemDestroy()
}
-
-
}} // namespace OVR::Win32
diff --git a/LibOVR/Src/Displays/OVR_Win32_FocusReader.h b/LibOVR/Src/Displays/OVR_Win32_FocusReader.h
index f62b8de..1d58264 100644
--- a/LibOVR/Src/Displays/OVR_Win32_FocusReader.h
+++ b/LibOVR/Src/Displays/OVR_Win32_FocusReader.h
@@ -64,7 +64,7 @@ typedef SharedObjectReader< LocklessFocusState > SharedFocusReader;
//-----------------------------------------------------------------------------
// RenderFocusReader
-class RenderFocusReader : public OVR::SystemSingletonBase<RenderFocusReader>
+class RenderFocusReader : public OVR::SystemSingletonBase<RenderFocusReader>, public NewOverrideBase
{
OVR_DECLARE_SINGLETON(RenderFocusReader);
diff --git a/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp b/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp
index a58e40d..80b33a2 100644
--- a/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp
+++ b/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp
@@ -16,8 +16,7 @@ otherwise accompanies this software in either electronic or hard copy form.
#include <windows.h>
#include <DbgHelp.h>
-#include <AtlBase.h>
-#include <AtlConv.h>
+#include <malloc.h>
#include "OVR_Win32_Dxgi_Display.h"
@@ -30,6 +29,12 @@ otherwise accompanies this software in either electronic or hard copy form.
#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.
@@ -114,22 +119,63 @@ TryAgainWOW64:
#define OLD_DATA_BACKUP_SIZE 16
-WinLoadLibraryA oldProcA = NULL;
-WinLoadLibraryExA oldProcExA = NULL;
-WinLoadLibraryW oldProcW = NULL;
-WinLoadLibraryExW oldProcExW = NULL;
-WinGetModuleHandleExA oldProcModExA = NULL;
-WinGetModuleHandleExW oldProcModExW = NULL;
-WinDirect3DCreate9 oldDirectX9Create = NULL;
-BYTE oldDirectX9CreateData[OLD_DATA_BACKUP_SIZE];
-WinDirect3DCreate9Ex oldDirectX9ExCreate = NULL;
-BYTE oldDirectX9ExCreateData[OLD_DATA_BACKUP_SIZE];
-WinCreateDXGIFactory oldCreateDXGIFactory = NULL;
-BYTE oldCreateDXGIFactoryData[OLD_DATA_BACKUP_SIZE];
-WinCreateDXGIFactory1 oldCreateDXGIFactory1 = NULL;
-BYTE oldCreateDXGIFactory1Data[OLD_DATA_BACKUP_SIZE];
-WinCreateDXGIFactory2 oldCreateDXGIFactory2 = NULL;
-BYTE oldCreateDXGIFactory2Data[OLD_DATA_BACKUP_SIZE];
+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 )
{
@@ -249,15 +295,15 @@ static HMODULE
__in LPCWSTR lpLibFileName
)
{
- USES_CONVERSION;
+ WIDE_TO_MB(lpLibFileName); // Convert lpLibFileName -> lpLibFileName_cstr
OVRTargetAPI targetAPI = DirectX;
- bool needShim = checkForOverride( W2A( lpLibFileName ), targetAPI );
+ bool needShim = checkForOverride( lpLibFileName_cstr, targetAPI );
if( !needShim )
return (*oldProcW)( lpLibFileName );
- return createShim( W2A( lpLibFileName ), targetAPI );
+ return createShim( lpLibFileName_cstr, targetAPI );
}
static HMODULE
@@ -287,16 +333,16 @@ static HMODULE
__in DWORD dwFlags
)
{
- USES_CONVERSION;
+ WIDE_TO_MB(lpLibFileName); // Convert lpLibFileName -> lpLibFileName_cstr
OVRTargetAPI targetAPI = DirectX;
- bool needShim = checkForOverride( W2A( lpLibFileName ), targetAPI );
+ bool needShim = checkForOverride( lpLibFileName_cstr, targetAPI );
if( !needShim )
return (*oldProcExW)( lpLibFileName, hFile, dwFlags );
// FIXME: Don't throw away the flags parameter
- return createShim( W2A( lpLibFileName ), targetAPI );
+ return createShim( lpLibFileName_cstr, targetAPI );
}
static BOOL WINAPI OVRGetModuleHandleExA(
@@ -324,17 +370,17 @@ static BOOL WINAPI OVRGetModuleHandleExW(
__out HMODULE *phModule
)
{
- USES_CONVERSION;
+ WIDE_TO_MB(lpModuleName); // Convert lpModuleName -> lpModuleName_cstr
- OVRTargetAPI targetAPI = DirectX;
+ OVRTargetAPI targetAPI = DirectX;
- bool needShim = checkForOverride( W2A( lpModuleName ), targetAPI );
+ bool needShim = checkForOverride( lpModuleName_cstr, targetAPI );
if( !needShim )
{
return (*oldProcModExW)( dwFlags, lpModuleName, phModule );
}
- *phModule = createShim( W2A( lpModuleName ), targetAPI );
+ *phModule = createShim( lpModuleName_cstr, targetAPI );
return TRUE;
}
@@ -465,7 +511,6 @@ HRESULT APIENTRY OVRDirect3DCreate9Ex(UINT SDKVersion, void** aDevice)
}
else
{
- HMODULE rtFilterModule = (*oldProcA)(RTFilter);
WinDirect3DCreate9Ex createFunction = (WinDirect3DCreate9Ex)GetProcAddress(rtFilterModule, "Direct3DCreate9Ex");
result = (*createFunction)(SDKVersion, aDevice);
}
@@ -501,7 +546,6 @@ HRESULT APIENTRY OVRCreateDXGIFactory(
}
else
{
- HMODULE rtFilterModule = (*oldProcA)(RTFilter);
WinCreateDXGIFactory createFunction = (WinCreateDXGIFactory)GetProcAddress(rtFilterModule, "CreateDXGIFactory");
result = (*createFunction)(riid, ppFactory);
}
@@ -528,7 +572,6 @@ HRESULT APIENTRY OVRCreateDXGIFactory1(
}
else
{
- HMODULE rtFilterModule = (*oldProcA)(RTFilter);
WinCreateDXGIFactory1 createFunction = (WinCreateDXGIFactory1)GetProcAddress(rtFilterModule, "CreateDXGIFactory1");
result = (*createFunction)(riid, ppFactory);
}
@@ -556,7 +599,6 @@ HRESULT APIENTRY OVRCreateDXGIFactory2(
}
else
{
- HMODULE rtFilterModule = (*oldProcA)(RTFilter);
WinCreateDXGIFactory2 createFunction = (WinCreateDXGIFactory2)GetProcAddress(rtFilterModule, "CreateDXGIFactory2");
result = (*createFunction)(flags, riid, ppFactory);
}
@@ -659,43 +701,27 @@ static PROC SetProcAddressA(
return pfnHookAPIAddr;
}
-enum ShimedLibraries
-{
- ShimLibDXGI = 0,
- ShimLibD3D9 = 1,
- ShimLibD3D11 = 2,
- ShimLibDXGIDebug = 3,
- ShimLibD3D10Core = 4,
- ShimLibD3D10 = 5,
- ShimLibGL = 6,
- ShimCountMax = 7
-};
-void checkUMDriverOverrides( void* context )
+void checkUMDriverOverrides(void* context)
{
lastContext = context;
if( oldProcA == NULL )
{
- char* dllList[ShimCountMax] = { "dxgi.dll", "d3d9.dll", "d3d11.dll", "dxgidebug.dll", "d3d10core.dll", "d3d10.dll", "opengl32.dll" };
-
PreloadLibraryRTFn loadFunc = NULL;
for( int i = 0; i < ShimCountMax; ++i )
{
- HINSTANCE hInst = GetModuleHandleA( dllList[i] );
- if( hInst == NULL )
+ HINSTANCE hInst = NULL;
+ try
+ {
+ hInst = LoadLibraryA(dllList[i]);
+ }
+ catch(...)
{
- try
- {
- hInst = LoadLibraryA(dllList[i]);
- }
- catch(...)
- {
-
- }
-
}
+ oldLoaderInstances[i] = hInst;
+
if( hInst )
{
ShimedLibraries libCount = (ShimedLibraries)i;
@@ -714,52 +740,75 @@ void checkUMDriverOverrides( void* context )
break;
}
- char* loaderLibraryList[4] = {"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"};
-
- for( int j = 0; j < 4; ++j )
- {
- char* loaderLibrary = loaderLibraryList[j];
+ 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;
-
- temp = SetProcAddressA( hInst, loaderLibrary, "LoadLibraryW", (PROC)OVRLoadLibraryW );
- if( !oldProcW )
- oldProcW = (WinLoadLibraryW)temp;
-
- temp = SetProcAddressA( hInst, loaderLibrary, "LoadLibraryExA", (PROC)OVRLoadLibraryExA );
- if( !oldProcExA )
- oldProcExA = (WinLoadLibraryExA)temp;
-
- temp = SetProcAddressA( hInst, loaderLibrary, "LoadLibraryExW", (PROC)OVRLoadLibraryExW );
- if( !oldProcExW )
- oldProcExW = (WinLoadLibraryExW)temp;
-
- temp = SetProcAddressA( hInst, loaderLibrary, "GetModuleHandleExA", (PROC)OVRGetModuleHandleExA );
- if( !oldProcModExA )
- oldProcModExA = (WinGetModuleHandleExA)temp;
-
- temp = SetProcAddressA( hInst, loaderLibrary, "GetModuleHandleExW", (PROC)OVRGetModuleHandleExW );
- if( !oldProcModExW )
- oldProcModExW = (WinGetModuleHandleExW)temp;
- }
-
- if( loadFunc == NULL )
- loadFunc = (PreloadLibraryRTFn)GetProcAddress( hInst, "PreloadLibraryRT" );
+ 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");
+ }
}
}
- HMODULE rtFilterModule = (*oldProcA)( RTFilter );
+ rtFilterModule = (*oldProcA)( RTFilter );
- if( loadFunc == NULL )
- loadFunc = (PreloadLibraryRTFn)GetProcAddress( rtFilterModule, "PreloadLibraryRT" );
- IsCreatingBackBuffer backBufferFunc = (IsCreatingBackBuffer)GetProcAddress( rtFilterModule, "OVRIsCreatingBackBuffer" );
- ShouldVSync shouldVSyncFunc = (ShouldVSync)GetProcAddress( rtFilterModule, "OVRShouldVSync" );
+ IsCreatingBackBuffer backBufferFunc = NULL;
+ ShouldVSync shouldVSyncFunc = NULL;
- if( loadFunc )
- {
+ if (rtFilterModule != NULL)
+ {
+ loadFunc = (PreloadLibraryRTFn)GetProcAddress(rtFilterModule, "PreloadLibraryRT");
+ backBufferFunc = (IsCreatingBackBuffer)GetProcAddress(rtFilterModule, "OVRIsCreatingBackBuffer");
+ shouldVSyncFunc = (ShouldVSync)GetProcAddress(rtFilterModule, "OVRShouldVSync");
+ }
+
+ if (loadFunc != NULL)
+ {
appDriver.version = 1;
appDriver.context = lastContext;
@@ -786,3 +835,99 @@ void checkUMDriverOverrides( void* context )
}
}
}
+
+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
index 9e5442c..907dc13 100644
--- a/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp
+++ b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp
@@ -31,7 +31,8 @@ limitations under the License.
#include "OVR_Win32_FocusReader.h"
// Exported
-extern void checkUMDriverOverrides( void* context );
+extern void checkUMDriverOverrides(void* context);
+extern void clearUMDriverOverrides();
#include <stdio.h>
#include <tchar.h>
@@ -203,6 +204,8 @@ bool DisplayShim::Initialize( bool inCompatibility )
bool DisplayShim::Shutdown()
{
+ clearUMDriverOverrides();
+
return true;
}