From 4207f9c279e832e3afcb3f5fc6cd8d84cb4cfe4c Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 28 Mar 2015 01:43:35 +0100 Subject: Bump OculusVR RIFT SDK to 0.5.0.1 --- LibOVR/Src/Displays/OVR_Win32_Display.cpp | 2043 ++++++++++------------------- 1 file changed, 720 insertions(+), 1323 deletions(-) (limited to 'LibOVR/Src/Displays/OVR_Win32_Display.cpp') 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 - -#include "OVR_Win32_Display.h" -#include "OVR_Win32_Dxgi_Display.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef OVR_COMPAT_EDID_VIA_WMI -# pragma comment(lib, "wbemuuid.lib") -#include -#else // OVR_COMPAT_EDID_VIA_WMI -#include -#include -#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 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::GetDisplay(int index, DisplaySearchHandle* handle) -{ - Ptr 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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 factory; + HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&factory.GetRawRef())); + OVR_D3D_CHECK_RET_FALSE(hr); + + Ptr adapter; + uint32_t iAdapter = 0; + while (adapter = nullptr, + SUCCEEDED(factory->EnumAdapters(iAdapter++, &adapter.GetRawRef()))) + { + Ptr 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 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::GetDisplay(int index, DisplaySearchHandle* handle) +{ + Ptr 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 -- cgit v1.2.3