diff options
author | Sven Gothel <[email protected]> | 2015-03-28 01:43:35 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-03-28 01:43:35 +0100 |
commit | 4207f9c279e832e3afcb3f5fc6cd8d84cb4cfe4c (patch) | |
tree | cf3671058d55b47ab6cb6f36f369928606137628 /LibOVR/Src/Displays/OVR_Win32_Display.cpp | |
parent | c29cd1a2fbff6282bab956ad61661ac9d48c4e6e (diff) |
Bump OculusVR RIFT SDK to 0.5.0.1vanilla_0.5.0.1
Diffstat (limited to 'LibOVR/Src/Displays/OVR_Win32_Display.cpp')
-rw-r--r-- | LibOVR/Src/Displays/OVR_Win32_Display.cpp | 2043 |
1 files changed, 720 insertions, 1323 deletions
diff --git a/LibOVR/Src/Displays/OVR_Win32_Display.cpp b/LibOVR/Src/Displays/OVR_Win32_Display.cpp index 677c619..f45dacc 100644 --- a/LibOVR/Src/Displays/OVR_Win32_Display.cpp +++ b/LibOVR/Src/Displays/OVR_Win32_Display.cpp @@ -1,1323 +1,720 @@ -/************************************************************************************
-
-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
+/************************************************************************************ + +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 "Kernel/OVR_Win32_IncludeWindows.h" + +#include "OVR_Win32_Display.h" +#include "OVR_Win32_Dxgi_Display.h" +#include "OVR_Win32_ShimFunctions.h" +#include "Util/Util_Direct3D.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> + +#include <setupapi.h> +#include <initguid.h> +#pragma comment(lib, "setupapi.lib") // SetupDiGetDeviceRegistryProperty et al +#pragma comment(lib, "dxgi.lib") // D3D11 adapter/output enumeration + +// 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 = {}; + + +//------------------------------------------------------------------------------------- +// ***** Display enumeration Helpers + +// THere are two ways to enumerate display: through our driver (DeviceIoControl) +// and through Win32 EnumDisplayMonitors (compatibility mode). + + +namespace OVR { + + +//----------------------------------------------------------------------------- +// Direct Mode + +ULONG getRiftCount( HANDLE hDevice ) +{ + ULONG riftCount = 0; + DWORD bytesReturned = 0; + + BOOL result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GET_RIFT_COUNT, nullptr, 0, + &riftCount, sizeof( ULONG ), &bytesReturned, nullptr ); + + 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, nullptr ); + 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; + } + } + } + + return 0; +} + +static bool getEdid(HANDLE hDevice, ULONG uid, DisplayEDID& edid) +{ + ULONG riftCount = 0; + DWORD bytesReturned = 0; + RIFT_STATUS riftStatus[16] = {0}; + + BOOL result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GET_RIFT_COUNT, nullptr, 0, + &riftCount, sizeof( ULONG ), &bytesReturned, nullptr ); + + if (!result) + { + return false; + } + + result = DeviceIoControl( hDevice, IOCTL_RIFTMGR_GET_RIFT_ARRAY, &riftStatus, + riftCount * sizeof( RIFT_STATUS ), &riftCount, sizeof(ULONG), + &bytesReturned, nullptr ); + 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, nullptr); + + if (result) + { + if (edid.Parse((unsigned char*)edidBuffer)) + { + return true; + } + else + { + LogError(("[Win32Display] WARNING: The driver was not able to return EDID for a display")); + } + } + + break; + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Rift Monitors + +static bool GetMonitorEDID(const wchar_t* deviceID, DisplayEDID& edid) +{ + // Find second slash and split there + const wchar_t* pSlash1 = wcschr(deviceID, L'\\'); + if (!pSlash1) + return false; + + // And the second one + const wchar_t* pSlash2 = wcschr(pSlash1 + 1, L'\\'); + if (!pSlash2) + return false; + + wchar_t hardwareID[128] = {}; + wcsncpy_s(hardwareID, pSlash1 + 1, (pSlash2 - pSlash1 - 1)); + + wchar_t driverID[128] = {}; + wcscpy_s(driverID, pSlash2 + 1); + + ScopedHKEY displayKey; + if (RegOpenKey(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\DISPLAY", + &displayKey.GetRawRef()) == 0) + { + wchar_t keyName[MAX_PATH] = {}; + DWORD iKey = 0; + while (RegEnumKey(displayKey.Get(), iKey++, keyName, _countof(keyName)) == 0) + { + if (_wcsicmp(keyName, hardwareID) == 0) + { + ScopedHKEY devKey; + if (RegOpenKey(displayKey.Get(), keyName, &devKey.GetRawRef()) == 0) + { + wchar_t nodeName[MAX_PATH] = {}; + DWORD iNode = 0; + while (RegEnumKey(devKey.Get(), iNode++, nodeName, _countof(nodeName)) == 0) + { + wchar_t devDriverID[MAX_PATH] = {}; + DWORD cbDriverID = sizeof(devDriverID); + if (RegGetValue(devKey.Get(), nodeName, L"Driver", RRF_RT_REG_SZ, nullptr, + devDriverID, &cbDriverID) == 0) + { + // Check if DriverID matches + if (_wcsicmp(devDriverID, driverID) == 0) + { + ScopedHKEY nodeKey; + if (RegOpenKey(devKey.Get(), nodeName, &nodeKey.GetRawRef()) == 0) + { + BYTE edidBytes[512] = {}; + DWORD cbEDID = sizeof(edidBytes); + if (RegGetValue(nodeKey.Get(), L"Device Parameters", L"EDID", RRF_RT_REG_BINARY, + nullptr, edidBytes, &cbEDID) == 0) + { + return edid.Parse(edidBytes); + } + } + } + } + } + } + } + } + } + + return true; +} + +static bool FillDisplayDesc(DXGI_OUTPUT_DESC const& outputDesc, DISPLAY_DEVICEW& dispDev, DisplayEDID const& edid, DisplayDesc& result) +{ + // EdidSerialNumber + static_assert(sizeof(result.EdidSerialNumber) == sizeof(edid.SerialNumber), "sizes need to match"); + memcpy(result.EdidSerialNumber, edid.SerialNumber, sizeof(result.EdidSerialNumber)); + + // DisplayID + size_t converted = 0; + if (0 != wcstombs_s(&converted, result.DisplayID, dispDev.DeviceName, _TRUNCATE)) + return false; + + // DesktopDisplayOffset + result.DesktopDisplayOffset = Vector2i(outputDesc.DesktopCoordinates.left, + outputDesc.DesktopCoordinates.top); + + // ModelName + static_assert(sizeof(result.ModelName) == sizeof(edid.MonitorName), "sizes need to match"); + memcpy(result.ModelName, edid.MonitorName, sizeof(result.ModelName)); + + // Resolution + result.ResolutionInPixels.w = edid.Width; + result.ResolutionInPixels.h = edid.Height; + + // DK2 Landscape = DXGI_MODE_ROTATION_IDENTITY -> DXGI_MODE_ROTATION_ROTATE90 + // DK2 Portrait = DXGI_MODE_ROTATION_ROTATE90 -> DXGI_MODE_ROTATION_IDENTITY + // DK2 Landscape(Flipped) = DXGI_MODE_ROTATION_ROTATE180 -> DXGI_MODE_ROTATION_ROTATE270 + // DK2 Portrait(Flipped) = DXGI_MODE_ROTATION_ROTATE270 -> DXGI_MODE_ROTATION_ROTATE180 + bool tallScreen = result.ResolutionInPixels.w < result.ResolutionInPixels.h; + + // Rotation + // This is the rotation from portrait mode, and the DK2 (for example) is naturally landscape, + // so we need to adjust the rotation value based on the HMD type. + switch (outputDesc.Rotation) + { + case DXGI_MODE_ROTATION_IDENTITY: + default: + result.Rotation = tallScreen ? 270 : 0; + break; + case DXGI_MODE_ROTATION_ROTATE90: + result.Rotation = tallScreen ? 0 : 90; + break; + case DXGI_MODE_ROTATION_ROTATE180: + result.Rotation = tallScreen ? 90 : 180; + break; + case DXGI_MODE_ROTATION_ROTATE270: + result.Rotation = tallScreen ? 180 : 270; + break; + } + + // DeviceTypeGuess + result.DeviceTypeGuess = HmdTypeFromModelNumber(edid.ModelNumber); + + return true; +} + +// Pass in 0 if only an existence check is requested. +static int DiscoverRiftMonitors(DisplayDesc* descriptorArray = nullptr, int inputArraySize = 0) +{ + int outputArraySize = 0; + + Ptr<IDXGIFactory1> factory; + HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&factory.GetRawRef())); + OVR_D3D_CHECK_RET_FALSE(hr); + + Ptr<IDXGIAdapter> adapter; + uint32_t iAdapter = 0; + while (adapter = nullptr, + SUCCEEDED(factory->EnumAdapters(iAdapter++, &adapter.GetRawRef()))) + { + Ptr<IDXGIAdapter1> adapter1; + hr = adapter->QueryInterface(IID_PPV_ARGS(&adapter1.GetRawRef())); + if (!OVR_D3D_CHECK(hr)) + continue; + + DXGI_ADAPTER_DESC1 adapterDesc = {}; + adapter1->GetDesc1(&adapterDesc); + + if (adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) + { + // Don't bother with software adapters (WARP, BasicRender, etc...) + continue; + } + + Ptr<IDXGIOutput> output; + uint32_t iOutput = 0; + while (output = nullptr, + SUCCEEDED(adapter->EnumOutputs(iOutput++, &output.GetRawRef()))) + { + // Get DeviceName for each output + DXGI_OUTPUT_DESC outputDesc; + hr = output->GetDesc(&outputDesc); + if (!OVR_D3D_CHECK(hr)) + continue; + + // Get DeviceID from DeviceName + DISPLAY_DEVICEW dispDev = {}; + dispDev.cb = sizeof(dispDev); + if (!::EnumDisplayDevicesW(outputDesc.DeviceName, 0, &dispDev, 0)) + continue; + + // If it is a Rift monitor, + if (wcsstr(dispDev.DeviceID, L"RTD2205") || + wcsstr(dispDev.DeviceID, L"CVT0003") || + wcsstr(dispDev.DeviceID, L"MST0030") || + wcsstr(dispDev.DeviceID, L"OVR00")) // Part of Oculus EDID. + { + DisplayEDID edid = {}; + + // If monitor existence is the goal, + if (!descriptorArray || inputArraySize <= 0) + return 1; + + if (outputArraySize < inputArraySize) + { + if (GetMonitorEDID(dispDev.DeviceID, edid) && + FillDisplayDesc(outputDesc, dispDev, edid, descriptorArray[outputArraySize])) + { + outputArraySize++; + } + } + } + } + } + + return outputArraySize; +} + +bool Display::ExtendedModeDevicesExist() +{ + return DiscoverRiftMonitors() > 0; +} + + +//------------------------------------------------------------------------------------- +// ***** Display + +bool Display::InCompatibilityMode(bool displaySearch) +{ + return (displaySearch && ExtendedModeDevicesExist()) || + GlobalDisplayContext.CompatibilityMode; +} + +#define OVR_FLAG_COMPATIBILITY_MODE 1 +#define OVR_FLAG_HIDE_DK1 2 + + +void Display::Shutdown() +{ + Win32::DisplayShim::GetInstance().Shutdown(); + OVR::Display::SetDirectDisplayInitialized(false); +} + +bool Display::Initialize() +{ + // This function is re-entrant because it may be called again to + // patch-up comatibility mode by the Config Util (Hack in HMDView::SetupGraphics). + // For this reason, the GetDirectDisplayInitialized() check is only done for + // shim initialization below. + + HANDLE hDevice = INVALID_HANDLE_VALUE; + + if (GlobalDisplayContext.hDevice == 0) + { + hDevice = CreateFile(L"\\\\.\\ovr_video" , + GENERIC_READ | GENERIC_WRITE, 0, + nullptr, OPEN_EXISTING, 0, nullptr); + } + else + { // The device has already been created + hDevice = GlobalDisplayContext.hDevice; + } + + if (hDevice != nullptr && 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, nullptr, 0, + &compatiblityResult, sizeof( LONG ), &bytesReturned, nullptr ); + 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) + { + // If a display is actually connected, bring up the shim layers so we can actually use it + // TBD: Do we care about extended mode displays? -cat + if (OVR::Display::ExtendedModeDevicesExist() || + getRiftCount(GlobalDisplayContext.hDevice) > 0) + { + // FIXME: Initializing DX9 with landscape numbers rather than portrait + GlobalDisplayContext.ExpectedWidth = 1080; + GlobalDisplayContext.ExpectedHeight = 1920; + } + else + { + GlobalDisplayContext.CompatibilityMode = true; + } + } + } + else + { + GlobalDisplayContext.CompatibilityMode = true; + } + + + + // Set up display code for Windows + Win32::DisplayShim::GetInstance(); + + // This code will look for the first display. If it's a display + // that's extending the desktop, the code will assume we're in + // compatibility mode. Compatibility mode prevents shim loading + // and renders only to extended Rifts. + // If we find a display and it's application exclusive, + // we load the shim so we can render to it. + // If no display is available, we revert to whatever the + // driver tells us we're in + + bool anyExtendedRifts = OVR::Display::ExtendedModeDevicesExist() || + GlobalDisplayContext.CompatibilityMode; + + if (!OVR::Display::GetDirectDisplayInitialized()) + { + OVR::Display::SetDirectDisplayInitialized( + Win32::DisplayShim::GetInstance().Initialize(anyExtendedRifts)); + } + + return true; +} + +bool Display::GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode) +{ + if (GlobalDisplayContext.hDevice == nullptr) + { + 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 == nullptr) + { + 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, + nullptr) || + (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) +{ + OVR_UNUSED(extendedEDIDSerials); + static int extendedCount = -1; + static int applicationCount = -1; + + Win32::Win32DisplaySearchHandle* localHandle = (Win32::Win32DisplaySearchHandle*)handle; + + if( localHandle == nullptr ) + return 0; + + if( extendedCount == -1 || extended ) + { + extendedCount = DiscoverRiftMonitors(localHandle->cachedDescriptorArray, 16); + } + + 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 == nullptr ) + return nullptr; + + 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); + DisplayEDID dEdid; + + if (!getEdid(GlobalDisplayContext.hDevice, riftChildId, dEdid)) + { + return nullptr; + } + + uint32_t nativeWidth = dEdid.Width, nativeHeight = dEdid.Height; + uint32_t rotation = (dEdid.ModelNumber == 2 || + dEdid.ModelNumber == 3) ? 90 : 0; + + uint32_t logicalWidth, logicalHeight; + if (rotation == 0) + { + logicalWidth = nativeWidth; + logicalHeight = nativeHeight; + } + else + { + logicalWidth = nativeHeight; + logicalHeight = nativeWidth; + } + + result = *new Win32::Win32DisplayDriver( + HmdTypeFromModelNumber(dEdid.ModelNumber), + "", + 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) +{ +#ifdef OVR_OS_WIN64 + BOOL is64BitOS = TRUE; +#else + BOOL is64BitOS = FALSE; + BOOL res = IsWow64Process(GetCurrentProcess(), &is64BitOS); + OVR_ASSERT_AND_UNUSED(res == TRUE,res); +#endif + ULONG localResult = 0; + DWORD bytesReturned = 0; + BOOL result; + if (is64BitOS) + { + ULONG64 longArray[2]; + longArray[0] = childId; + longArray[1] = mode; + result = DeviceIoControl(hDevice, + IOCTL_RIFTMGR_DISPLAYPOWER, + longArray, + 2 * sizeof(ULONG64), + &localResult, + sizeof(ULONG), + &bytesReturned, + nullptr); + } + else + { + ULONG32 longArray[2]; + longArray[0] = childId; + longArray[1] = mode; + result = DeviceIoControl(hDevice, + IOCTL_RIFTMGR_DISPLAYPOWER, + longArray, + 2 * sizeof(ULONG32), + &localResult, + sizeof(ULONG), + &bytesReturned, + nullptr); + } + + // 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 |